From 300a78a791d722cd1eca1d2efb98bfb52bb56103 Mon Sep 17 00:00:00 2001 From: Janet Blackquill Date: Mon, 29 Sep 2025 22:20:31 -0400 Subject: [PATCH] Fix floating damages --- .../Damage/Systems/DamageableSystem.cs | 2 +- Content.Shared/_Offbrand/Wounds/Damages.cs | 30 +++++++ .../_Offbrand/Wounds/TendingSystem.cs | 6 +- .../_Offbrand/Wounds/WoundableComponent.cs | 2 +- .../_Offbrand/Wounds/WoundableSystem.cs | 81 ++++++++++++++----- 5 files changed, 94 insertions(+), 27 deletions(-) diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index b533793276..ed495c749a 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -236,7 +236,7 @@ namespace Content.Shared.Damage damage = ApplyUniversalAllModifiers(damage); // Begin Offbrand - var beforeCommit = new Content.Shared._Offbrand.Wounds.BeforeDamageCommitEvent(damage); + var beforeCommit = new Content.Shared._Offbrand.Wounds.BeforeDamageCommitEvent(damage, forceRefresh); RaiseLocalEvent(uid.Value, ref beforeCommit); damage = beforeCommit.Damage; // End Offbrand diff --git a/Content.Shared/_Offbrand/Wounds/Damages.cs b/Content.Shared/_Offbrand/Wounds/Damages.cs index e8757ec1af..be468e5be5 100644 --- a/Content.Shared/_Offbrand/Wounds/Damages.cs +++ b/Content.Shared/_Offbrand/Wounds/Damages.cs @@ -4,6 +4,7 @@ using Content.Shared.Damage; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Shared._Offbrand.Wounds; @@ -60,6 +61,35 @@ public sealed partial class Damages : IEquatable, IRobustCloneable(args.Used, out var tending)) return; - _woundable.TendWound(ent, tending.Damage); - - if (tending.Damage is { } damage) - _damageable.TryChangeDamage(target, damage, true, origin: args.Args.User); + _woundable.TendWound(target, ent, tending.Damage); var hasMoreItems = true; if (TryComp(args.Used.Value, out var stackComp)) diff --git a/Content.Shared/_Offbrand/Wounds/WoundableComponent.cs b/Content.Shared/_Offbrand/Wounds/WoundableComponent.cs index 09056be591..88e1d941ce 100644 --- a/Content.Shared/_Offbrand/Wounds/WoundableComponent.cs +++ b/Content.Shared/_Offbrand/Wounds/WoundableComponent.cs @@ -15,7 +15,7 @@ public record struct WoundGetDamageEvent(DamageSpecifier Accumulator); /// Raised before damage is applied to a Damageable but after applying modifiers /// [ByRefEvent] -public record struct BeforeDamageCommitEvent(DamageSpecifier Damage); +public record struct BeforeDamageCommitEvent(DamageSpecifier Damage, bool ForceRefresh); /// /// Raised when the values for a damage overlay may have changed diff --git a/Content.Shared/_Offbrand/Wounds/WoundableSystem.cs b/Content.Shared/_Offbrand/Wounds/WoundableSystem.cs index b79e6aa914..bb46e89ac2 100644 --- a/Content.Shared/_Offbrand/Wounds/WoundableSystem.cs +++ b/Content.Shared/_Offbrand/Wounds/WoundableSystem.cs @@ -10,6 +10,7 @@ using Content.Shared.StatusEffectNew; using Robust.Shared.Network; using Robust.Shared.Prototypes; using Robust.Shared.Timing; +using Robust.Shared.Utility; namespace Content.Shared._Offbrand.Wounds; @@ -31,6 +32,7 @@ public sealed class WoundableSystem : EntitySystem SubscribeLocalEvent>(OnWoundGetDamage); SubscribeLocalEvent>(OnGetWoundsWithSpace); + SubscribeLocalEvent(OnWoundRemoved); SubscribeLocalEvent>(OnGetPain); SubscribeLocalEvent>(OnHealHealableWounds); @@ -117,6 +119,31 @@ public sealed class WoundableSystem : EntitySystem } } + private void ValidateWounds(EntityUid ent, DamageSpecifier? incoming) + { +#if DEBUG + var damageable = Comp(ent); + + var evt = new WoundGetDamageEvent(new()); + RaiseLocalEvent(ent, ref evt); + + foreach (var (type, currentValue) in damageable.Damage.DamageDict) + { + if (!evt.Accumulator.DamageDict.TryGetValue(type, out var expectedValue)) + continue; + + if (incoming is not null && incoming.DamageDict.TryGetValue(type, out var delta) && delta <= 0) + { + DebugTools.AssertEqual(currentValue + delta, expectedValue, "wounds and damageable after delta don't line up"); + } + else + { + DebugTools.AssertEqual(currentValue, expectedValue, "wounds and damageable don't line up"); + } + } +#endif + } + private void OnBeforeDamageCommit(Entity ent, ref BeforeDamageCommitEvent args) { if (_timing.ApplyingState) @@ -124,7 +151,7 @@ public sealed class WoundableSystem : EntitySystem var damageable = Comp(ent); - if (args.Damage.AnyNegative()) + if (args.Damage.AnyNegative() && !args.ForceRefresh) OnHealed(ent, DamageSpecifier.GetNegative(args.Damage)); var evt = new WoundGetDamageEvent(new()); @@ -155,6 +182,18 @@ public sealed class WoundableSystem : EntitySystem args.Damage.DamageDict[type] = deltaValue - delta; } + + if (!args.ForceRefresh) + ValidateWounds(ent, args.Damage); + } + + private void OnWoundRemoved(Entity ent, ref StatusEffectRemovedEvent args) + { + if (ent.Comp.Damage.Empty) + return; + + _damageable.TryChangeDamage(args.Target, -ent.Comp.Damage.ToSpecifier(), true, false, null, null, forceRefresh: true); + ValidateWounds(args.Target, null); } private void OnDamaged(Entity ent, DamageSpecifier overall) @@ -235,23 +274,7 @@ public sealed class WoundableSystem : EntitySystem var comp = Comp(ent); - foreach (var (type, value) in args.Args.Damage.DamageDict) - { - if (!comp.Damage.DamageDict.TryGetValue(type, out var existing)) - continue; - - var newValue = existing + value; - if (newValue <= 0) - { - args.Args.Damage.DamageDict[type] = newValue; - newValue = 0; - } - else - { - args.Args.Damage.DamageDict[type] = 0; - } - comp.Damage.DamageDict[type] = newValue; - } + args.Args = args.Args with { Damage = comp.Damage.Heal(args.Args.Damage).ToSpecifier() }; comp.Damage.TrimZeros(); args.Args.Damage.TrimZeros(); @@ -371,13 +394,31 @@ public sealed class WoundableSystem : EntitySystem Dirty(ent); } - public void TendWound(Entity ent, DamageSpecifier? specifier) + public void TendWound(Entity woundable, Entity ent, DamageSpecifier? specifier) { var wound = Comp(ent); ent.Comp.Tended = true; if (specifier is { } damage) - wound.Damage += damage; + { + var remainder = wound.Damage.Heal(damage); + wound.Damage.TrimZeros(); + Dirty(ent.Owner, wound); + + if (wound.Damage.Empty) + PredictedQueueDel(ent); + + var changeBy = damage - remainder.ToSpecifier(); + changeBy.TrimZeros(); + if (changeBy.AnyNegative()) + { + var actualDelta = _damageable.TryChangeDamage(woundable, changeBy, true, false, null, null, forceRefresh: true); + DebugTools.Assert(actualDelta is not null); + DebugTools.Assert(changeBy.Equals(actualDelta!), $"{changeBy} == {actualDelta!}"); + } + + ValidateWounds(woundable, null); + } Dirty(ent); }