]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Make StaminaModifier into a status effect, apply to Hyperzine (#41902)
authorSlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com>
Thu, 18 Dec 2025 19:41:08 +0000 (20:41 +0100)
committerGitHub <noreply@github.com>
Thu, 18 Dec 2025 19:41:08 +0000 (19:41 +0000)
* Initial commit

* Probably better this way.

* Review fixes

* cleanup

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
21 files changed:
Content.Shared/Damage/Components/StaminaComponent.cs
Content.Shared/Damage/Components/StaminaModifierStatusEffectComponent.cs [moved from Content.Shared/Damage/Components/StaminaModifierComponent.cs with 90% similarity]
Content.Shared/Damage/Events/RefreshStaminaCritThresholdEvent.cs [new file with mode: 0644]
Content.Shared/Damage/Systems/SharedStaminaSystem.Modifier.cs
Content.Shared/Damage/Systems/SharedStaminaSystem.cs
Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs
Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
Resources/Prototypes/Entities/Mobs/NPCs/carp.yml
Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml
Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml
Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml
Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
Resources/Prototypes/Entities/Mobs/NPCs/space.yml
Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml
Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
Resources/Prototypes/Entities/Mobs/Species/base.yml
Resources/Prototypes/Entities/StatusEffects/body.yml
Resources/Prototypes/Reagents/narcotics.yml
Resources/Prototypes/status_effects.yml

index 9875d313491ea6658dc8168e41d0a7b3fefa96a3..07429cbab7e62a0bca5d040e5b4b53bf8698b3e5 100644 (file)
@@ -39,9 +39,15 @@ public sealed partial class StaminaComponent : Component
     public float StaminaDamage;
 
     /// <summary>
-    /// How much stamina damage is required to enter stam crit.
+    /// The base stamina the entity requires to enter stam crit. Should rarely if ever be modified outside of yaml.
     /// </summary>
-    [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
+    [DataField, AutoNetworkedField]
+    public float BaseCritThreshold = 100f;
+
+    /// <summary>
+    /// Modified crit threshold for when an entity should enter stamcrit.
+    /// </summary>
+    [ViewVariables, AutoNetworkedField]
     public float CritThreshold = 100f;
 
     /// <summary>
similarity index 90%
rename from Content.Shared/Damage/Components/StaminaModifierComponent.cs
rename to Content.Shared/Damage/Components/StaminaModifierStatusEffectComponent.cs
index e492ea04ffe96657a5c551220c588ac470aef8c0..4ca888ffbe5b363471bec4c3c6f9353f395f448b 100644 (file)
@@ -7,7 +7,7 @@ namespace Content.Shared.Damage.Components;
 /// Multiplies the entity's <see cref="StaminaComponent.StaminaDamage"/> by the <see cref="Modifier"/>.
 /// </summary>
 [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedStaminaSystem))]
-public sealed partial class StaminaModifierComponent : Component
+public sealed partial class StaminaModifierStatusEffectComponent : Component
 {
     /// <summary>
     /// What to multiply max stamina by.
diff --git a/Content.Shared/Damage/Events/RefreshStaminaCritThresholdEvent.cs b/Content.Shared/Damage/Events/RefreshStaminaCritThresholdEvent.cs
new file mode 100644 (file)
index 0000000..4ed8644
--- /dev/null
@@ -0,0 +1,18 @@
+using Content.Shared.Damage.Components;
+
+namespace Content.Shared.Damage.Events;
+
+/// <summary>
+/// Raised whenever the <see cref="StaminaComponent.CritThreshold"/> needs to be refreshed.
+/// </summary>
+[ByRefEvent]
+public record struct RefreshStaminaCritThresholdEvent
+{
+    public float ThresholdValue = 100f;
+    public float Modifier = 1f;
+
+    public RefreshStaminaCritThresholdEvent(float thresholdValue)
+    {
+        ThresholdValue = thresholdValue;
+    }
+}
index c723d8cb949fc10f7a8419ac72746df5822b0d01..8fcb4b8d1d48417ad79b25f250092d67f6a7c76c 100644 (file)
@@ -1,4 +1,6 @@
 using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Events;
+using Content.Shared.StatusEffectNew;
 
 namespace Content.Shared.Damage.Systems;
 
@@ -6,47 +8,36 @@ public partial class SharedStaminaSystem
 {
     private void InitializeModifier()
     {
-        SubscribeLocalEvent<StaminaModifierComponent, ComponentStartup>(OnModifierStartup);
-        SubscribeLocalEvent<StaminaModifierComponent, ComponentShutdown>(OnModifierShutdown);
+        SubscribeLocalEvent<StaminaModifierStatusEffectComponent, StatusEffectAppliedEvent>(OnEffectApplied);
+        SubscribeLocalEvent<StaminaModifierStatusEffectComponent, StatusEffectRemovedEvent>(OnEffectRemoved);
+        SubscribeLocalEvent<StaminaModifierStatusEffectComponent, StatusEffectRelayedEvent<RefreshStaminaCritThresholdEvent>>(OnRefreshCritThreshold);
     }
 
-    private void OnModifierStartup(EntityUid uid, StaminaModifierComponent comp, ComponentStartup args)
+    private void OnEffectApplied(Entity<StaminaModifierStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
     {
-        if (!TryComp<StaminaComponent>(uid, out var stamina))
-            return;
-
-        stamina.CritThreshold *= comp.Modifier;
+        RefreshStaminaCritThreshold(args.Target);
     }
 
-    private void OnModifierShutdown(EntityUid uid, StaminaModifierComponent comp, ComponentShutdown args)
+    private void OnEffectRemoved(Entity<StaminaModifierStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
     {
-        if (!TryComp<StaminaComponent>(uid, out var stamina))
-            return;
-
-        stamina.CritThreshold /= comp.Modifier;
+        RefreshStaminaCritThreshold(args.Target);
     }
 
-    /// <summary>
-    /// Change the stamina modifier for an entity.
-    /// If it has <see cref="StaminaComponent"/> it will also be updated.
-    /// </summary>
-    public void SetModifier(EntityUid uid, float modifier, StaminaComponent? stamina = null, StaminaModifierComponent? comp = null)
+    private void OnRefreshCritThreshold(Entity<StaminaModifierStatusEffectComponent> ent, ref StatusEffectRelayedEvent<RefreshStaminaCritThresholdEvent> args)
     {
-        if (!Resolve(uid, ref comp))
-            return;
-
-        var old = comp.Modifier;
+        var evArgs = args.Args;
+        evArgs.Modifier = Math.Max(ent.Comp.Modifier, evArgs.Modifier); // We only pick the highest value, to avoid stacking different status effects.
+        args.Args = evArgs;
+    }
 
-        if (old.Equals(modifier))
+    public void RefreshStaminaCritThreshold(Entity<StaminaComponent?> entity)
+    {
+        if (!Resolve(entity, ref entity.Comp))
             return;
 
-        comp.Modifier = modifier;
-        Dirty(uid, comp);
+        var ev = new RefreshStaminaCritThresholdEvent(entity.Comp.BaseCritThreshold);
+        RaiseLocalEvent(entity, ref ev);
 
-        if (Resolve(uid, ref stamina, false))
-        {
-            // scale to the new threshold, act as if it was removed then added
-            stamina.CritThreshold *= modifier / old;
-        }
+        entity.Comp.CritThreshold = ev.ThresholdValue * ev.Modifier;
     }
 }
index 045052d1facdfc7323417a8415a5852651df6aaa..ca030d5e5d109a260f550aaa35581f6a3d54224a 100644 (file)
@@ -99,6 +99,9 @@ public abstract partial class SharedStaminaSystem : EntitySystem
 
     private void OnStartup(Entity<StaminaComponent> entity, ref ComponentStartup args)
     {
+        // Set the base threshold here since ModifiedCritThreshold can't be modified via yaml.
+        entity.Comp.CritThreshold = entity.Comp.BaseCritThreshold;
+
         UpdateStaminaVisuals(entity);
     }
 
index 30c5d9f67e6ffbf0c9899ffd4372eed5bab1a059..cafe5075c9665d9b240749d0444e4481b58e3053 100644 (file)
@@ -27,6 +27,7 @@ public sealed partial class StatusEffectsSystem
 
         SubscribeLocalEvent<StatusEffectContainerComponent, StandUpAttemptEvent>(RefRelayStatusEffectEvent);
         SubscribeLocalEvent<StatusEffectContainerComponent, StunEndAttemptEvent>(RefRelayStatusEffectEvent);
+        SubscribeLocalEvent<StatusEffectContainerComponent, RefreshStaminaCritThresholdEvent>(RefRelayStatusEffectEvent);
 
         SubscribeLocalEvent<StatusEffectContainerComponent, BeforeForceSayEvent>(RelayStatusEffectEvent);
         SubscribeLocalEvent<StatusEffectContainerComponent, BeforeAlertSeverityCheckEvent>(RelayStatusEffectEvent);
index 05a72b3b337fec44bab29eb2394a92d6bc2e05e4..3685f891b617917d809957767464f6cbad234c1b 100644 (file)
       0: Alive
       10: Dead
   - type: Stamina
-    critThreshold: 10
+    baseCritThreshold: 10
     animationThreshold: 1
   - type: DamageStateVisuals
     states:
       types:
         Piercing: 0
   - type: Bloodstream
-    bloodReferenceSolution: 
+    bloodReferenceSolution:
       reagents:
       - ReagentId: Blood
         Quantity: 50
index c0ea417663dd1c5413fdcaa44409404912e2bcb6..1547e36339429ce416bab4b5466371d69e8c7c05 100644 (file)
@@ -44,7 +44,7 @@
       baseWalkSpeed: 2.5
       baseSprintSpeed: 3.5
     - type: Stamina
-      critThreshold: 100
+      baseCritThreshold: 100
     - type: DamageStateVisuals
       states:
         Alive:
         0: Alive
         82: Dead # Might seem random, but this brings up the hits to kill with a crusher mark to 3
     - type: Stamina
-      critThreshold: 150
+      baseCritThreshold: 150
     - type: DamageStateVisuals
       states:
         Alive:
index b430689361d41addb0e9996ad5fc989e9d6c4fc8..e9f0c4a8ef7807cb8417f92059ea05abb64c75ce 100644 (file)
@@ -28,7 +28,7 @@
       0: Alive
       120: Dead
   - type: Stamina
-    critThreshold: 120
+    baseCritThreshold: 120
   - type: Destructible
     thresholds:
     - trigger:
index 75f0aa83b8bf287eeb0c354135c9d1ee78fb7e4f..c32a9d3d0b38c7943daca6704c246124da636ba5 100644 (file)
@@ -41,7 +41,7 @@
       0: Alive
       75: Dead
   - type: Stamina
-    critThreshold: 50
+    baseCritThreshold: 50
     animationThreshold: 25
   - type: Butcherable
     spawned:
       0: Alive
       75: Dead
   - type: Stamina
-    critThreshold: 50
+    baseCritThreshold: 50
     animationThreshold: 25
   - type: Butcherable
     spawned:
index 13eeb2b372423fa332a07818912078f51d3216e1..d080f8c45f5e6e1f728463d3737cfc026454c074 100644 (file)
@@ -50,7 +50,6 @@
     allowed:
     - Corporeal
     - Electrocution
-    - StaminaModifier
   - type: Fixtures
     fixtures:
       fix1:
index 1de449a215b61e89d572bbc8e30faf7ff3e5e315..3e0edee084b3a938c05be8edc36ead576c5e3874 100644 (file)
       - !type:GibBehavior
         recursive: false
   - type: Stamina
-    critThreshold: 60
+    baseCritThreshold: 60
   - type: MeleeWeapon
     soundHit:
         path: /Audio/Weapons/bladeslice.ogg
index a538243192bbb0853492228675accc4353582c53..7c9f3ca95c56ba16f723728f8cd599fd771aa3a9 100644 (file)
@@ -82,7 +82,7 @@
     baseWalkSpeed : 3
     baseSprintSpeed : 4
   - type: Stamina
-    critThreshold: 120
+    baseCritThreshold: 120
   - type: Destructible
     thresholds:
     - trigger:
index d0ea13f26ed8299d99fdd1fd01dd21262a12be77..906675045b04e10936ddbd21a7d429ca3e64da09 100644 (file)
@@ -96,7 +96,6 @@
     - Electrocution
     - TemporaryBlindness
     - Pacified
-    - StaminaModifier
     - Flashed
     - RadiationProtection
     - Adrenaline
index d052728379c09e2d57e496ba0f4930b972365cc4..7a51d257ef4a2ab8e668b3bf27ee6fe0cb3807b4 100644 (file)
@@ -36,7 +36,7 @@
       0: Alive
       80: Dead
   - type: Stamina
-    critThreshold: 150
+    baseCritThreshold: 150
   - type: MovementAlwaysTouching
   - type: Bloodstream
     bloodReferenceSolution:
       Dead:
         Base: kangaroo-space-dead
   - type: Stamina
-    critThreshold: 180
+    baseCritThreshold: 180
   - type: Inventory
     speciesId: kangaroo
     templateId: spacekangaroo
       0: Alive
       45: Dead
   - type: Stamina
-    critThreshold: 150
+    baseCritThreshold: 150
   - type: DamageStateVisuals
     states:
       Alive:
         0: Alive
         45: Dead
     - type: Stamina
-      critThreshold: 150
+      baseCritThreshold: 150
     - type: DamageStateVisuals
       states:
         Alive:
index 780c4b0330b8ddd76e4cc5eafd8049b14ba531b2..653704cfbb55839b608522df07476bb2500c0e8b 100644 (file)
@@ -52,7 +52,7 @@
       - !type:GibBehavior
         recursive: false
   - type: Stamina
-    critThreshold: 15
+    baseCritThreshold: 15
     animationThreshold: 5
   - type: MovementAlwaysTouching
   - type: DamageStateVisuals
index 247d7636e59d78b0312c9ce1f1a84bc20cf74267..58e0088828b76b04b6bd9a4318f481f9b521ea28 100644 (file)
@@ -65,7 +65,7 @@
     speedModifierThresholds:
       25: 0.5
   - type: Stamina
-    critThreshold: 200
+    baseCritThreshold: 200
   - type: Bloodstream
     bloodReferenceSolution:
       reagents:
       0: Alive
       100: Dead
   - type: Stamina
-    critThreshold: 300
+    baseCritThreshold: 300
   - type: SlowOnDamage
     speedModifierThresholds:
       50: 0.7
   - type: ComplexInteraction
   - type: MobState
   - type: Stamina
-    critThreshold: 200
+    baseCritThreshold: 200
   - type: Bloodstream
     bloodReferenceSolution:
       reagents:
index f33cee8b209c1d83a001e2b36021fea772ef990d..a0ace57c47ec9e94bf59ec37b8ef45594264bdc2 100644 (file)
     - Muted
     - TemporaryBlindness
     - Pacified
-    - StaminaModifier
     - Flashed
     - RadiationProtection
     - Adrenaline
index 739c9c3b2243f1d08830f8e52804d99e627186da..7c7d5fc68c67166a1fb57f314161f3866f2b1801 100644 (file)
   parent: [ PainNumbnessTraitStatusEffect, MobStatusEffectDebuff ]
   id: StatusEffectPainNumbness
   name: pain numbness
+
+- type: entity
+  parent: MobStatusEffectBase
+  id: StaminaModifierStatusEffect
+  components:
+  - type: StatusEffect
+    whitelist:
+      components:
+      - Stamina
+  - type: StaminaModifierStatusEffect
+
+- type: entity
+  parent: StaminaModifierStatusEffect
+  name: 2x max stamina
+  id: StatusEffectDesoxyStamina
+
+- type: entity
+  parent: StaminaModifierStatusEffect
+  id: StatusEffectStimulantsStamina
+  name: 1.5x max stamina
+  components:
+  - type: StaminaModifierStatusEffect
+    modifier: 1.5
index aaaa62916c6aba81634ca1ebca78b6cec5942a64..7ad463bfcc429a86b12fdd9173b80644224161f9 100644 (file)
@@ -34,9 +34,8 @@
       - !type:MovementSpeedModifier
         walkSpeedModifier: 1.20
         sprintSpeedModifier: 1.20
-      - !type:GenericStatusEffect
-        key: StaminaModifier # You are on meth. You keep going.
-        component: StaminaModifier
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectDesoxyStamina # You are on meth. You keep going.
         time: 3
       - !type:GenericStatusEffect
         key: Adrenaline
       - !type:MovementSpeedModifier
         walkSpeedModifier: 1.25
         sprintSpeedModifier: 1.25
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectStimulantsStamina # You are on meth. You keep going.
+        time: 3
       - !type:ModifyStatusEffect
         effectProto: StatusEffectStunned
         time: 3.5
index 8ae32928a39e0a8ac539147716b85a6581daf32f..a48758716cad516e88fb27d18eb322750598bc4f 100644 (file)
@@ -50,9 +50,6 @@
 - type: statusEffect
   id: RatvarianLanguage #Praise him
 
-- type: statusEffect
-  id: StaminaModifier
-
 - type: statusEffect
   id: Flashed