CatStation/Content.Shared/Damage/Systems/SlowOnDamageSystem.cs
Pok 17a7f22349
Adrenaline StatusEffects (#43750)
AdrenalineStatusEffects
2026-07-30 04:01:39 +00:00

116 lines
4.6 KiB
C#

using Content.Shared.Clothing;
using Content.Shared.Damage.Components;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
using Content.Shared.Movement.Systems;
using Content.Shared.StatusEffectNew;
namespace Content.Shared.Damage.Systems;
public sealed partial class SlowOnDamageSystem : EntitySystem
{
[Dependency] private MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
[Dependency] private DamageableSystem _damage = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SlowOnDamageComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<SlowOnDamageComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
SubscribeLocalEvent<ClothingSlowOnDamageModifierComponent, InventoryRelayedEvent<ModifySlowOnDamageSpeedEvent>>(OnModifySpeed);
SubscribeLocalEvent<ClothingSlowOnDamageModifierComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<ClothingSlowOnDamageModifierComponent, ClothingGotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<ClothingSlowOnDamageModifierComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<IgnoreSlowOnDamageComponent, StatusEffectAppliedEvent>(OnIgnoreApplied);
SubscribeLocalEvent<IgnoreSlowOnDamageComponent, StatusEffectRemovedEvent>(OnIgnoreRemoved);
SubscribeLocalEvent<IgnoreSlowOnDamageComponent, StatusEffectRelayedEvent<ModifySlowOnDamageSpeedEvent>>(OnIgnoreModifySpeed);
}
private void OnRefreshMovespeed(EntityUid uid, SlowOnDamageComponent component, RefreshMovementSpeedModifiersEvent args)
{
if (!TryComp<DamageableComponent>(uid, out var damage))
return;
var totalDamage = _damage.GetTotalDamage((uid, damage));
if (totalDamage == FixedPoint2.Zero)
return;
// Get closest threshold
FixedPoint2 closest = FixedPoint2.Zero;
var total = totalDamage;
foreach (var thres in component.SpeedModifierThresholds)
{
if (total >= thres.Key && thres.Key > closest)
closest = thres.Key;
}
if (closest != FixedPoint2.Zero)
{
var speed = component.SpeedModifierThresholds[closest];
var ev = new ModifySlowOnDamageSpeedEvent(speed);
RaiseLocalEvent(uid, ref ev);
args.ModifySpeed(ev.Speed, ev.Speed);
}
}
private void OnDamageChanged(EntityUid uid, SlowOnDamageComponent component, DamageChangedEvent args)
{
// We -could- only refresh if it crossed a threshold but that would kind of be a lot of duplicated
// code and this isn't a super hot path anyway since basically only humans have this
_movementSpeedModifierSystem.RefreshMovementSpeedModifiers(uid);
}
private void OnModifySpeed(Entity<ClothingSlowOnDamageModifierComponent> ent, ref InventoryRelayedEvent<ModifySlowOnDamageSpeedEvent> args)
{
var dif = 1 - args.Args.Speed;
if (dif <= 0)
return;
// reduces the slowness modifier by the given coefficient
args.Args.Speed += dif * ent.Comp.Modifier;
}
private void OnExamined(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ExaminedEvent args)
{
var msg = Loc.GetString("slow-on-damage-modifier-examine", ("mod", ent.Comp.Modifier * 100));
args.PushMarkup(msg);
}
private void OnGotEquipped(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ClothingGotEquippedEvent args)
{
_movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Wearer);
}
private void OnGotUnequipped(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ClothingGotUnequippedEvent args)
{
_movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Wearer);
}
private void OnIgnoreApplied(Entity<IgnoreSlowOnDamageComponent> ent, ref StatusEffectAppliedEvent args)
{
_movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Target);
}
private void OnIgnoreRemoved(Entity<IgnoreSlowOnDamageComponent> ent, ref StatusEffectRemovedEvent args)
{
_movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Target);
}
private void OnIgnoreModifySpeed(Entity<IgnoreSlowOnDamageComponent> ent, ref StatusEffectRelayedEvent<ModifySlowOnDamageSpeedEvent> args)
{
args.Args = args.Args with { Speed = 1f };
}
}
[ByRefEvent]
public record struct ModifySlowOnDamageSpeedEvent(float Speed) : IInventoryRelayEvent
{
public SlotFlags TargetSlots => SlotFlags.WITHOUT_POCKET;
}