]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Prevent shoe buffs while crawling (#39648)
authorPrincess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com>
Wed, 20 Aug 2025 11:08:31 +0000 (04:08 -0700)
committerGitHub <noreply@github.com>
Wed, 20 Aug 2025 11:08:31 +0000 (13:08 +0200)
Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
Content.Shared/Clothing/ClothingSpeedModifierComponent.cs
Content.Shared/Clothing/ClothingSpeedModifierSystem.cs
Content.Shared/Clothing/EntitySystems/AntiGravityClothingSystem.cs
Content.Shared/Inventory/InventorySystem.Relay.cs
Content.Shared/Morgue/EntityStorageLayingDownOverrideSystem.cs
Content.Shared/Standing/StandingStateSystem.cs
Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs
Resources/Prototypes/Entities/Clothing/Shoes/misc.yml

index 866ce38a5721b7a3e7dc492688ce7e6c4112d5f1..8dc496ec25db00230f1957475bd3a9a22c8c7c1b 100644 (file)
@@ -15,6 +15,13 @@ public sealed partial class ClothingSpeedModifierComponent : Component
 
     [DataField]
     public float SprintModifier = 1.0f;
+
+    /// <summary>
+    /// 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.
+    /// </summary>
+    [DataField]
+    public bool? Standing;
 }
 
 [Serializable, NetSerializable]
index 56758654ed88a644b4b81068a8e0ebfc30d0e237..29f063c7fab821fa268d91255b8cf82264c9f33e 100644 (file)
@@ -3,6 +3,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;
@@ -12,10 +13,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()
     {
@@ -54,8 +56,13 @@ public sealed class ClothingSpeedModifierSystem : EntitySystem
 
     private void OnRefreshMoveSpeed(EntityUid uid, ClothingSpeedModifierComponent component, InventoryRelayedEvent<RefreshMovementSpeedModifiersEvent> args)
     {
-        if (_toggle.IsActivated(uid))
-            args.Args.ModifySpeed(component.WalkModifier, component.SprintModifier);
+        if (!_toggle.IsActivated(uid))
+            return;
+
+        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<ExamineVerb> args)
index 636a21533eb028e87b1f69154ff744971f6267a8..554db51a234fd9fc56e231fa8a8e08f49a864026 100644 (file)
@@ -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;
 
+/// <remarks>
+/// 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.
+/// </remarks>
 public sealed class AntiGravityClothingSystem : EntitySystem
 {
-    [Dependency] SharedGravitySystem _gravity = default!;
+    [Dependency] private readonly StandingStateSystem _standing = default!;
+    [Dependency] private readonly SharedGravitySystem _gravity = default!;
+
     /// <inheritdoc/>
     public override void Initialize()
     {
         SubscribeLocalEvent<AntiGravityClothingComponent, InventoryRelayedEvent<IsWeightlessEvent>>(OnIsWeightless);
         SubscribeLocalEvent<AntiGravityClothingComponent, ClothingGotEquippedEvent>(OnEquipped);
         SubscribeLocalEvent<AntiGravityClothingComponent, ClothingGotUnequippedEvent>(OnUnequipped);
+        SubscribeLocalEvent<AntiGravityClothingComponent, InventoryRelayedEvent<DownedEvent>>(OnDowned);
+        SubscribeLocalEvent<AntiGravityClothingComponent, InventoryRelayedEvent<StoodEvent>>(OnStood);
     }
 
     private void OnIsWeightless(Entity<AntiGravityClothingComponent> ent, ref InventoryRelayedEvent<IsWeightlessEvent> 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<AntiGravityClothingComponent> 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<AntiGravityClothingComponent> 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<AntiGravityClothingComponent> entity, ref InventoryRelayedEvent<DownedEvent> args)
+    {
+        _gravity.RefreshWeightless(args.Owner, false);
+    }
+
+    private void OnStood(Entity<AntiGravityClothingComponent> entity, ref InventoryRelayedEvent<StoodEvent> args)
+    {
+        _gravity.RefreshWeightless(args.Owner, true);
+    }
 }
index f4a0ccb5de1c14bbea4055c4910798726b2ccfa0..5109930a2ddb0b8173f91c1586708fd3bef6045f 100644 (file)
@@ -24,6 +24,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;
@@ -57,6 +58,8 @@ public partial class InventorySystem
         SubscribeLocalEvent<InventoryComponent, IsUnequippingTargetAttemptEvent>(RelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, ChameleonControllerOutfitSelectedEvent>(RelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, BeforeEmoteEvent>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, StoodEvent>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, DownedEvent>(RelayInventoryEvent);
 
         // by-ref events
         SubscribeLocalEvent<InventoryComponent, RefreshFrictionModifiersEvent>(RefRelayInventoryEvent);
@@ -114,7 +117,7 @@ public partial class InventorySystem
             return;
 
         // this copies the by-ref event if it is a struct
-        var ev = new InventoryRelayedEvent<T>(args);
+        var ev = new InventoryRelayedEvent<T>(args, inventory.Owner);
         var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
         while (enumerator.NextItem(out var item))
         {
@@ -130,7 +133,7 @@ public partial class InventorySystem
         if (args.TargetSlots == SlotFlags.NONE)
             return;
 
-        var ev = new InventoryRelayedEvent<T>(args);
+        var ev = new InventoryRelayedEvent<T>(args, inventory.Owner);
         var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
         while (enumerator.NextItem(out var item))
         {
@@ -141,7 +144,7 @@ public partial class InventorySystem
     private void OnGetEquipmentVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent<EquipmentVerb> args)
     {
         // Automatically relay stripping related verbs to all equipped clothing.
-        var ev = new InventoryRelayedEvent<GetVerbsEvent<EquipmentVerb>>(args);
+        var ev = new InventoryRelayedEvent<GetVerbsEvent<EquipmentVerb>>(args, uid);
         var enumerator = new InventorySlotEnumerator(component);
         while (enumerator.NextItem(out var item, out var slotDef))
         {
@@ -153,7 +156,7 @@ public partial class InventorySystem
     private void OnGetInnateVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent<InnateVerb> args)
     {
         // Automatically relay stripping related verbs to all equipped clothing.
-        var ev = new InventoryRelayedEvent<GetVerbsEvent<InnateVerb>>(args);
+        var ev = new InventoryRelayedEvent<GetVerbsEvent<InnateVerb>>(args, uid);
         var enumerator = new InventorySlotEnumerator(component, SlotFlags.WITHOUT_POCKET);
         while (enumerator.NextItem(out var item))
         {
@@ -176,9 +179,12 @@ public sealed class InventoryRelayedEvent<TEvent> : EntityEventArgs
 {
     public TEvent Args;
 
-    public InventoryRelayedEvent(TEvent args)
+    public EntityUid Owner;
+
+    public InventoryRelayedEvent(TEvent args, EntityUid owner)
     {
         Args = args;
+        Owner = owner;
     }
 }
 
index 630135f36ae9b9cd56e5f6b3f9e2cc8f27c313c1..d11695321b98b643c35417b3e6a3458888209fe5 100644 (file)
@@ -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<StandingStateComponent>(ent, out var standingState) && !_standing.IsDown(ent, standingState))
+            if (TryComp<StandingStateComponent>(ent, out var standingState) && !_standing.IsDown((ent, standingState)))
                 args.Contents.Remove(ent);
         }
     }
index 7f3b8c9aacc0b38e6783c3d9dc22ae3d3fa25150..ffe8f2c156ee54cbaccecb8c737c061cad2f6ada 100644 (file)
@@ -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;
@@ -69,12 +70,17 @@ public sealed class StandingStateSystem : EntitySystem
         ChangeLayers(entity);
     }
 
-    public bool IsDown(EntityUid uid, StandingStateComponent? standingState = null)
+    public bool IsMatchingState(Entity<StandingStateComponent?> entity, bool standing)
     {
-        if (!Resolve(uid, ref standingState, false))
+        return standing != IsDown(entity);
+    }
+
+    public bool IsDown(Entity<StandingStateComponent?> entity)
+    {
+        if (!Resolve(entity, ref entity.Comp, false))
             return false;
 
-        return !standingState.Standing;
+        return !entity.Comp.Standing;
     }
 
     public bool Down(EntityUid uid,
@@ -213,29 +219,27 @@ public record struct DropHandItemsEvent();
 /// <summary>
 /// Subscribe if you can potentially block a down attempt.
 /// </summary>
-public sealed class DownAttemptEvent : CancellableEntityEventArgs
-{
-}
+public sealed class DownAttemptEvent : CancellableEntityEventArgs;
 
 /// <summary>
 /// Subscribe if you can potentially block a stand attempt.
 /// </summary>
-public sealed class StandAttemptEvent : CancellableEntityEventArgs
-{
-}
+public sealed class StandAttemptEvent : CancellableEntityEventArgs;
 
 /// <summary>
 /// Raised when an entity becomes standing
 /// </summary>
-public sealed class StoodEvent : EntityEventArgs
+public sealed class StoodEvent : EntityEventArgs, IInventoryRelayEvent
 {
-}
+    public SlotFlags TargetSlots { get; } = SlotFlags.FEET;
+};
 
 /// <summary>
 /// Raised when an entity is not standing
 /// </summary>
-public sealed class DownedEvent : EntityEventArgs
+public sealed class DownedEvent : EntityEventArgs, IInventoryRelayEvent
 {
+    public SlotFlags TargetSlots { get; } = SlotFlags.FEET;
 }
 
 /// <summary>
index 098e3176d9ec521c72de209e39218c7e888d9820..1a7bc88ec325bd0c240f499c21cc07e68139305c 100644 (file)
@@ -501,7 +501,7 @@ public abstract partial class SharedStunSystem
 
         // Targeted moth attack
         CancelKnockdownDoAfter((entity, entity.Comp));
-        RemComp<KnockedDownComponent>(entity);
+        RemCompDeferred<KnockedDownComponent>(entity);
     }
 
     private void OnKnockdownAttempt(Entity<GravityAffectedComponent> entity, ref KnockDownAttemptEvent args)
index 26fbc0c7ae58f9d1082d55ee799d2a7d776b3398..69c167051bbb2cba89db25ae05a19a1401113127 100644 (file)
   - type: ClothingSpeedModifier
     walkModifier: 1.5
     sprintModifier: 1.5
+    standing: true
   - type: Appearance
   - type: GenericVisualizer
     visuals:
     price: 75
   - type: Tag
     tags: [ ]
-   
+
 - type: entity
   parent: ClothingShoesBase
   id: ClothingShoesBootsJump
     jumpSound: /Audio/Effects/stealthoff.ogg
   - type: ActionGrant
     actions:
-    - ActionGravityJump 
+    - ActionGravityJump
   - type: ItemActionGrant
     actions:
     - ActionGravityJump