From 1b03779569d11f3d416dfbcedddf33fb5f602d28 Mon Sep 17 00:00:00 2001
From: Sidzaru <110207359+Sidzaru@users.noreply.github.com>
Date: Sat, 27 Sep 2025 00:24:03 +0300
Subject: [PATCH] Weapon block component during selection (#3110)
---
.../Weapons/Melee/MeleeWeaponComponent.cs | 6 ---
.../Weapons/Melee/SharedMeleeWeaponSystem.cs | 41 +++++++++++-----
.../Weapons/Misc/EquipDelayComponent.cs | 13 +++++
.../Weapons/Ranged/Components/GunComponent.cs | 8 +---
.../Systems/SharedGunSystem.Interactions.cs | 47 ++++++++++++-------
.../Entities/Objects/Misc/handcuffs.yml | 1 -
6 files changed, 73 insertions(+), 43 deletions(-)
create mode 100644 Content.Shared/Weapons/Misc/EquipDelayComponent.cs
diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
index 84e88156ad..6ae4857547 100644
--- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
+++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
@@ -34,12 +34,6 @@ public sealed partial class MeleeWeaponComponent : Component
[AutoPausedField]
public TimeSpan NextAttack;
- ///
- /// Starts attack cooldown when equipped if true.
- ///
- [DataField, AutoNetworkedField]
- public bool ResetOnHandSelected = true;
-
/*
* Melee combat works based around 2 types of attacks:
* 1. Click attacks with left-click. This attacks whatever is under your mnouse
diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
index c032b8b926..98a6e746c0 100644
--- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
+++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
@@ -129,27 +129,44 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
}
}
- private void OnMeleeSelected(EntityUid uid, MeleeWeaponComponent component, HandSelectedEvent args)
+ private void OnMeleeSelected(Entity ent, ref HandSelectedEvent args)
{
- var attackRate = GetAttackRate(uid, args.User, component);
- if (attackRate.Equals(0f))
- return;
+ var uid = ent.Owner;
- if (!component.ResetOnHandSelected)
+ var attackRate = GetAttackRate(uid, args.User, ent);
+ if (attackRate == 0f)
return;
if (Paused(uid))
return;
- // If someone swaps to this weapon then reset its cd.
- var curTime = Timing.CurTime;
- var minimum = curTime + TimeSpan.FromSeconds(1 / attackRate);
+ if (TryComp(uid, out var delayComp))
+ {
+ var delay = delayComp.EquipDelayTime;
+ var curTime = Timing.CurTime;
- if (minimum < component.NextAttack)
- return;
+ var minimum = curTime + TimeSpan.FromSeconds(delay);
- component.NextAttack = minimum;
- DirtyField(uid, component, nameof(MeleeWeaponComponent.NextAttack));
+ if (minimum < ent.Comp.NextAttack)
+ return;
+
+ ent.Comp.NextAttack = minimum;
+
+ DirtyField(uid, ent.Comp, nameof(MeleeWeaponComponent.NextAttack));
+ }
+ else
+ {
+ var curTime = Timing.CurTime;
+
+ var minimum = curTime + TimeSpan.FromSeconds(0.3);
+
+ if (minimum < ent.Comp.NextAttack)
+ return;
+
+ ent.Comp.NextAttack = minimum;
+
+ DirtyField(uid, ent.Comp, nameof(MeleeWeaponComponent.NextAttack));
+ }
}
private void OnGetBonusMeleeDamage(EntityUid uid, BonusMeleeDamageComponent component, ref GetMeleeDamageEvent args)
diff --git a/Content.Shared/Weapons/Misc/EquipDelayComponent.cs b/Content.Shared/Weapons/Misc/EquipDelayComponent.cs
new file mode 100644
index 0000000000..d198aca5f2
--- /dev/null
+++ b/Content.Shared/Weapons/Misc/EquipDelayComponent.cs
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Weapons;
+
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class EquipDelayComponent : Component
+{
+ ///
+ /// Delay before the next attack after picking up a weapon, in seconds.
+ ///
+ [DataField("delay"), AutoNetworkedField]
+ public float EquipDelayTime = 0.3f;
+}
\ No newline at end of file
diff --git a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs
index 86e6ec777f..3e9828badd 100644
--- a/Content.Shared/Weapons/Ranged/Components/GunComponent.cs
+++ b/Content.Shared/Weapons/Ranged/Components/GunComponent.cs
@@ -209,12 +209,6 @@ public sealed partial class GunComponent : Component
[AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
public float FireRateModified;
- ///
- /// Starts fire cooldown when equipped if true.
- ///
- [DataField]
- public bool ResetOnHandSelected = true;
-
///
/// The base value for how fast the projectile moves.
///
@@ -232,7 +226,7 @@ public sealed partial class GunComponent : Component
/// When the gun is next available to be shot.
/// Can be set multiple times in a single tick due to guns firing faster than a single tick time.
///
- [DataField(customTypeSerializer:typeof(TimeOffsetSerializer))]
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoNetworkedField]
[AutoPausedField]
public TimeSpan NextFire = TimeSpan.Zero;
diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs
index 2fece720f9..0f02f83cd7 100644
--- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs
+++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs
@@ -66,7 +66,7 @@ public abstract partial class SharedGunSystem
if (component.SelectedMode == fire)
return;
- DebugTools.Assert((component.AvailableModes & fire) != 0x0);
+ DebugTools.Assert((component.AvailableModes & fire) != 0x0);
component.SelectedMode = fire;
if (!Paused(uid))
@@ -110,32 +110,45 @@ public abstract partial class SharedGunSystem
SelectFire(uid, component, args.Mode, args.Performer);
}
- private void OnGunSelected(EntityUid uid, GunComponent component, HandSelectedEvent args)
+ private void OnGunSelected(Entity ent, ref HandSelectedEvent args)
{
+ var uid = ent.Owner;
+
if (Timing.ApplyingState)
- return;
-
- if (component.FireRateModified <= 0)
return;
- var fireDelay = 1f / component.FireRateModified;
- if (fireDelay.Equals(0f))
- return;
-
- if (!component.ResetOnHandSelected)
+ if (ent.Comp.FireRateModified <= 0)
return;
if (Paused(uid))
return;
- // If someone swaps to this weapon then reset its cd.
- var curTime = Timing.CurTime;
- var minimum = curTime + TimeSpan.FromSeconds(fireDelay);
+ if (TryComp(uid, out var delayComp))
+ {
+ var delay = delayComp.EquipDelayTime;
+ var curTime = Timing.CurTime;
- if (minimum < component.NextFire)
- return;
+ var minimum = curTime + TimeSpan.FromSeconds(delay);
- component.NextFire = minimum;
- Dirty(uid, component);
+ if (minimum < ent.Comp.NextFire)
+ return;
+
+ ent.Comp.NextFire = minimum;
+
+ DirtyField(uid, ent.Comp, nameof(GunComponent.NextFire));
+ }
+ else
+ {
+ var curTime = Timing.CurTime;
+
+ var minimum = curTime + TimeSpan.FromSeconds(0.3);
+
+ if (minimum < ent.Comp.NextFire)
+ return;
+
+ ent.Comp.NextFire = minimum;
+
+ DirtyField(uid, ent.Comp, nameof(GunComponent.NextFire));
+ }
}
}
diff --git a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml
index 66ab826ac2..3c5fd8039d 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml
@@ -19,7 +19,6 @@
- Handcuffs
- type: MeleeWeapon
wideAnimationRotation: 90
- resetOnHandSelected: false
animation: WeaponArcDisarm
damage:
types: