diff --git a/Content.Shared/Clothing/ClothingSpeedModifierComponent.cs b/Content.Shared/Clothing/ClothingSpeedModifierComponent.cs index 866ce38a57..8dc496ec25 100644 --- a/Content.Shared/Clothing/ClothingSpeedModifierComponent.cs +++ b/Content.Shared/Clothing/ClothingSpeedModifierComponent.cs @@ -15,6 +15,13 @@ public sealed partial class ClothingSpeedModifierComponent : Component [DataField] public float SprintModifier = 1.0f; + + /// + /// An optional required standing state. + /// Set to true if you need to be standing, false if you need to not be standing, null if you don't care. + /// + [DataField] + public bool? Standing; } [Serializable, NetSerializable] diff --git a/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs b/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs index 608c9bc8f5..6b2acfcb1d 100644 --- a/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs +++ b/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Inventory; using Content.Shared.Item.ItemToggle; using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Movement.Systems; +using Content.Shared.Standing; using Content.Shared.Verbs; using Robust.Shared.Containers; using Robust.Shared.GameStates; @@ -13,10 +14,11 @@ namespace Content.Shared.Clothing; public sealed class ClothingSpeedModifierSystem : EntitySystem { - [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; - [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; [Dependency] private readonly ItemToggleSystem _toggle = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly StandingStateSystem _standing = default!; public override void Initialize() { @@ -55,10 +57,11 @@ public sealed class ClothingSpeedModifierSystem : EntitySystem private void OnRefreshMoveSpeed(EntityUid uid, ClothingSpeedModifierComponent component, InventoryRelayedEvent args) { - // DeltaV Start - Introduce ClothingSlowResistance to Species if (!_toggle.IsActivated(uid)) return; + + // DeltaV Start - Introduce ClothingSlowResistance to Species if (_container.TryGetContainingContainer((uid, null), out var container)) { var ev = new ModifyClothingSlowdownEvent(component.WalkModifier, component.SprintModifier); @@ -71,6 +74,11 @@ public sealed class ClothingSpeedModifierSystem : EntitySystem args.Args.ModifySpeed(component.WalkModifier, component.SprintModifier); } // DeltaV End - Introduce ClothingSlowResistance to Species + + if (component.Standing != null && !_standing.IsMatchingState(args.Owner, component.Standing.Value)) + return; + + args.Args.ModifySpeed(component.WalkModifier, component.SprintModifier); } private void OnClothingVerbExamine(EntityUid uid, ClothingSpeedModifierComponent component, GetVerbsEvent args) diff --git a/Content.Shared/Clothing/EntitySystems/AntiGravityClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/AntiGravityClothingSystem.cs index 636a21533e..554db51a23 100644 --- a/Content.Shared/Clothing/EntitySystems/AntiGravityClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/AntiGravityClothingSystem.cs @@ -1,23 +1,33 @@ using Content.Shared.Clothing.Components; using Content.Shared.Gravity; using Content.Shared.Inventory; +using Content.Shared.Standing; namespace Content.Shared.Clothing.EntitySystems; +/// +/// We check standing state on all clothing because we don't want you to have anti-gravity unless you're standing. +/// This is for balance reasons as it prevents you from wearing anti-grav clothing to cheese being stun cuffed, as +/// well as other worse things. +/// public sealed class AntiGravityClothingSystem : EntitySystem { - [Dependency] SharedGravitySystem _gravity = default!; + [Dependency] private readonly StandingStateSystem _standing = default!; + [Dependency] private readonly SharedGravitySystem _gravity = default!; + /// public override void Initialize() { SubscribeLocalEvent>(OnIsWeightless); SubscribeLocalEvent(OnEquipped); SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent>(OnDowned); + SubscribeLocalEvent>(OnStood); } private void OnIsWeightless(Entity ent, ref InventoryRelayedEvent args) { - if (args.Args.Handled) + if (args.Args.Handled || _standing.IsDown(args.Owner)) return; args.Args.Handled = true; @@ -26,11 +36,29 @@ public sealed class AntiGravityClothingSystem : EntitySystem private void OnEquipped(Entity entity, ref ClothingGotEquippedEvent args) { + // This clothing item does nothing if we're not standing + if (_standing.IsDown(args.Wearer)) + return; + _gravity.RefreshWeightless(args.Wearer, true); } private void OnUnequipped(Entity entity, ref ClothingGotUnequippedEvent args) { + // This clothing item does nothing if we're not standing + if (_standing.IsDown(args.Wearer)) + return; + _gravity.RefreshWeightless(args.Wearer, false); } + + private void OnDowned(Entity entity, ref InventoryRelayedEvent args) + { + _gravity.RefreshWeightless(args.Owner, false); + } + + private void OnStood(Entity entity, ref InventoryRelayedEvent args) + { + _gravity.RefreshWeightless(args.Owner, true); + } } diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs index a228bffb3a..08dc524b0f 100644 --- a/Content.Shared/Inventory/InventorySystem.Relay.cs +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -25,6 +25,7 @@ using Content.Shared.Overlays; using Content.Shared.Projectiles; using Content.Shared.Radio; using Content.Shared.Slippery; +using Content.Shared.Standing; using Content.Shared.Strip.Components; using Content.Shared.Temperature; using Content.Shared.Verbs; @@ -58,6 +59,8 @@ public partial class InventorySystem SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); // by-ref events SubscribeLocalEvent(RefRelayInventoryEvent); @@ -116,7 +119,7 @@ public partial class InventorySystem return; // this copies the by-ref event if it is a struct - var ev = new InventoryRelayedEvent(args); + var ev = new InventoryRelayedEvent(args, inventory.Owner); var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots); while (enumerator.NextItem(out var item)) { @@ -132,7 +135,7 @@ public partial class InventorySystem if (args.TargetSlots == SlotFlags.NONE) return; - var ev = new InventoryRelayedEvent(args); + var ev = new InventoryRelayedEvent(args, inventory.Owner); var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots); while (enumerator.NextItem(out var item)) { @@ -143,7 +146,7 @@ public partial class InventorySystem private void OnGetEquipmentVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent args) { // Automatically relay stripping related verbs to all equipped clothing. - var ev = new InventoryRelayedEvent>(args); + var ev = new InventoryRelayedEvent>(args, uid); var enumerator = new InventorySlotEnumerator(component); while (enumerator.NextItem(out var item, out var slotDef)) { @@ -155,7 +158,7 @@ public partial class InventorySystem private void OnGetInnateVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent args) { // Automatically relay stripping related verbs to all equipped clothing. - var ev = new InventoryRelayedEvent>(args); + var ev = new InventoryRelayedEvent>(args, uid); var enumerator = new InventorySlotEnumerator(component, SlotFlags.WITHOUT_POCKET); while (enumerator.NextItem(out var item)) { @@ -178,9 +181,12 @@ public sealed class InventoryRelayedEvent : EntityEventArgs { public TEvent Args; - public InventoryRelayedEvent(TEvent args) + public EntityUid Owner; + + public InventoryRelayedEvent(TEvent args, EntityUid owner) { Args = args; + Owner = owner; } } diff --git a/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs b/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs index 630135f36a..d11695321b 100644 --- a/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs +++ b/Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs @@ -21,7 +21,7 @@ public sealed class EntityStorageLayingDownOverrideSystem : EntitySystem { // Explicitly check for standing state component, as entities without it will return false for IsDown() // which prevents inserting any kind of non-mobs into this container (which is unintended) - if (TryComp(ent, out var standingState) && !_standing.IsDown(ent, standingState)) + if (TryComp(ent, out var standingState) && !_standing.IsDown((ent, standingState))) args.Contents.Remove(ent); } } diff --git a/Content.Shared/Standing/StandingStateSystem.cs b/Content.Shared/Standing/StandingStateSystem.cs index ad7c58870a..7e63de71c3 100644 --- a/Content.Shared/Standing/StandingStateSystem.cs +++ b/Content.Shared/Standing/StandingStateSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Climbing.Events; using Content.Shared.Hands.Components; +using Content.Shared.Inventory; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; using Content.Shared.Physics; @@ -68,12 +69,17 @@ public sealed class StandingStateSystem : EntitySystem ChangeLayers(entity); } - public bool IsDown(EntityUid uid, StandingStateComponent? standingState = null) + public bool IsMatchingState(Entity entity, bool standing) { - if (!Resolve(uid, ref standingState, false)) + return standing != IsDown(entity); + } + + public bool IsDown(Entity entity) + { + if (!Resolve(entity, ref entity.Comp, false)) return false; - return !standingState.Standing; + return !entity.Comp.Standing; } public bool Down(EntityUid uid, bool playSound = true, bool dropHeldItems = true, @@ -210,26 +216,27 @@ public record struct DropHandItemsEvent(); /// /// Subscribe if you can potentially block a down attempt. /// -public sealed class DownAttemptEvent : CancellableEntityEventArgs -{ -} +public sealed class DownAttemptEvent : CancellableEntityEventArgs; + /// /// Subscribe if you can potentially block a stand attempt. /// -public sealed class StandAttemptEvent : CancellableEntityEventArgs -{ -} +public sealed class StandAttemptEvent : CancellableEntityEventArgs; + /// /// Raised when an entity becomes standing /// -public sealed class StoodEvent : EntityEventArgs +public sealed class StoodEvent : EntityEventArgs, IInventoryRelayEvent { -} + public SlotFlags TargetSlots { get; } = SlotFlags.FEET; +}; + /// /// Raised when an entity is not standing /// -public sealed class DownedEvent : EntityEventArgs +public sealed class DownedEvent : EntityEventArgs, IInventoryRelayEvent { + public SlotFlags TargetSlots { get; } = SlotFlags.FEET; } diff --git a/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs b/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs index 098e3176d9..1a7bc88ec3 100644 --- a/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs +++ b/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs @@ -501,7 +501,7 @@ public abstract partial class SharedStunSystem // Targeted moth attack CancelKnockdownDoAfter((entity, entity.Comp)); - RemComp(entity); + RemCompDeferred(entity); } private void OnKnockdownAttempt(Entity entity, ref KnockDownAttemptEvent args) diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml index 3813431087..787fa41784 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml @@ -139,6 +139,7 @@ - type: ClothingSpeedModifier walkModifier: 1.7 # DeltaV sprintModifier: 1.7 # DeltaV + standing: true - type: Appearance - type: GenericVisualizer visuals: