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
2026-04-04 16:57:19 +02:00
committed by BarryNorfolk
co-authored by Princess Cheeseballs
parent 713159fa1a
commit d514f400a4
21 changed files with 96 additions and 58 deletions
@@ -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;
}
}