From 96f9e1fe2db5d5c3ea6f4fdebbfccfc45b0b936b Mon Sep 17 00:00:00 2001
From: Princess Cheeseballs
<66055347+Princess-Cheeseballs@users.noreply.github.com>
Date: Wed, 20 Aug 2025 04:08:31 -0700
Subject: [PATCH] Prevent shoe buffs while crawling (#39648)
Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
---
.../ClothingSpeedModifierComponent.cs | 7 ++++
.../Clothing/ClothingSpeedModifierSystem.cs | 14 ++++++--
.../AntiGravityClothingSystem.cs | 32 +++++++++++++++++--
.../Inventory/InventorySystem.Relay.cs | 16 +++++++---
.../EntityStorageLayingDownOverrideSystem.cs | 2 +-
.../Standing/StandingStateSystem.cs | 31 +++++++++++-------
.../Stunnable/SharedStunSystem.Knockdown.cs | 2 +-
.../Entities/Clothing/Shoes/misc.yml | 1 +
8 files changed, 81 insertions(+), 24 deletions(-)
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: