Make StaminaModifier into a status effect, apply to Hyperzine (#41902)

* Initial commit

* Probably better this way.

* Review fixes

* cleanup

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
SlamBamActionman
2025-12-18 20:41:08 +01:00
committed by GitHub
parent 89b25adf52
commit bb95787af7
21 changed files with 97 additions and 59 deletions

View 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>

View 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.

View File

@@ -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;
}
}

View 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))
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;
}
public void RefreshStaminaCritThreshold(Entity<StaminaComponent?> entity)
{
if (!Resolve(entity, ref entity.Comp))
return;
var old = comp.Modifier;
var ev = new RefreshStaminaCritThresholdEvent(entity.Comp.BaseCritThreshold);
RaiseLocalEvent(entity, ref ev);
if (old.Equals(modifier))
return;
comp.Modifier = modifier;
Dirty(uid, comp);
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;
}
}

View 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);
}

View 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);

View File

@@ -115,7 +115,7 @@
0: Alive
10: Dead
- type: Stamina
critThreshold: 10
baseCritThreshold: 10
animationThreshold: 1
- type: DamageStateVisuals
states:
@@ -1889,7 +1889,7 @@
types:
Piercing: 0
- type: Bloodstream
bloodReferenceSolution:
bloodReferenceSolution:
reagents:
- ReagentId: Blood
Quantity: 50

View File

@@ -44,7 +44,7 @@
baseWalkSpeed: 2.5
baseSprintSpeed: 3.5
- type: Stamina
critThreshold: 100
baseCritThreshold: 100
- type: DamageStateVisuals
states:
Alive:
@@ -233,7 +233,7 @@
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:

View File

@@ -28,7 +28,7 @@
0: Alive
120: Dead
- type: Stamina
critThreshold: 120
baseCritThreshold: 120
- type: Destructible
thresholds:
- trigger:

View File

@@ -41,7 +41,7 @@
0: Alive
75: Dead
- type: Stamina
critThreshold: 50
baseCritThreshold: 50
animationThreshold: 25
- type: Butcherable
spawned:
@@ -243,7 +243,7 @@
0: Alive
75: Dead
- type: Stamina
critThreshold: 50
baseCritThreshold: 50
animationThreshold: 25
- type: Butcherable
spawned:

View File

@@ -50,7 +50,6 @@
allowed:
- Corporeal
- Electrocution
- StaminaModifier
- type: Fixtures
fixtures:
fix1:

View File

@@ -241,7 +241,7 @@
- !type:GibBehavior
recursive: false
- type: Stamina
critThreshold: 60
baseCritThreshold: 60
- type: MeleeWeapon
soundHit:
path: /Audio/Weapons/bladeslice.ogg

View File

@@ -82,7 +82,7 @@
baseWalkSpeed : 3
baseSprintSpeed : 4
- type: Stamina
critThreshold: 120
baseCritThreshold: 120
- type: Destructible
thresholds:
- trigger:

View File

@@ -96,7 +96,6 @@
- Electrocution
- TemporaryBlindness
- Pacified
- StaminaModifier
- Flashed
- RadiationProtection
- Adrenaline

View File

@@ -36,7 +36,7 @@
0: Alive
80: Dead
- type: Stamina
critThreshold: 150
baseCritThreshold: 150
- type: MovementAlwaysTouching
- type: Bloodstream
bloodReferenceSolution:
@@ -157,7 +157,7 @@
Dead:
Base: kangaroo-space-dead
- type: Stamina
critThreshold: 180
baseCritThreshold: 180
- type: Inventory
speciesId: kangaroo
templateId: spacekangaroo
@@ -202,7 +202,7 @@
0: Alive
45: Dead
- type: Stamina
critThreshold: 150
baseCritThreshold: 150
- type: DamageStateVisuals
states:
Alive:
@@ -305,7 +305,7 @@
0: Alive
45: Dead
- type: Stamina
critThreshold: 150
baseCritThreshold: 150
- type: DamageStateVisuals
states:
Alive:

View File

@@ -52,7 +52,7 @@
- !type:GibBehavior
recursive: false
- type: Stamina
critThreshold: 15
baseCritThreshold: 15
animationThreshold: 5
- type: MovementAlwaysTouching
- type: DamageStateVisuals

View File

@@ -65,7 +65,7 @@
speedModifierThresholds:
25: 0.5
- type: Stamina
critThreshold: 200
baseCritThreshold: 200
- type: Bloodstream
bloodReferenceSolution:
reagents:
@@ -138,7 +138,7 @@
0: Alive
100: Dead
- type: Stamina
critThreshold: 300
baseCritThreshold: 300
- type: SlowOnDamage
speedModifierThresholds:
50: 0.7
@@ -492,7 +492,7 @@
- type: ComplexInteraction
- type: MobState
- type: Stamina
critThreshold: 200
baseCritThreshold: 200
- type: Bloodstream
bloodReferenceSolution:
reagents:

View File

@@ -127,7 +127,6 @@
- Muted
- TemporaryBlindness
- Pacified
- StaminaModifier
- Flashed
- RadiationProtection
- Adrenaline

View File

@@ -62,3 +62,26 @@
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

View 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
@@ -145,6 +144,9 @@
- !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

View File

@@ -50,9 +50,6 @@
- type: statusEffect
id: RatvarianLanguage #Praise him
- type: statusEffect
id: StaminaModifier
- type: statusEffect
id: Flashed