Fix floating damages

This commit is contained in:
Janet Blackquill
2025-09-29 22:20:31 -04:00
parent 5818dbdc7a
commit 300a78a791
5 changed files with 94 additions and 27 deletions

View File

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

View File

@@ -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<Damages>, IRobustCloneable<Dama
return specifier;
}
public Damages Heal(DamageSpecifier incoming)
{
var remainder = new Damages(incoming);
foreach (var (type, value) in remainder.DamageDict)
{
DebugTools.Assert(value <= 0);
if (!DamageDict.TryGetValue(type, out var existing))
continue;
var newValue = existing + value;
if (newValue <= 0)
{
remainder.DamageDict[type] = newValue;
newValue = 0;
}
else
{
remainder.DamageDict[type] = 0;
}
DamageDict[type] = newValue;
}
remainder.TrimZeros();
return remainder;
}
public static Damages operator +(Damages damages, DamageSpecifier specifier)
{
var newDamages = damages.Clone();

View File

@@ -14,7 +14,6 @@ namespace Content.Shared._Offbrand.Wounds;
public sealed class TendingSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
@@ -137,10 +136,7 @@ public sealed class TendingSystem : EntitySystem
if (!TryComp<TendingComponent>(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<StackComponent>(args.Used.Value, out var stackComp))

View File

@@ -15,7 +15,7 @@ public record struct WoundGetDamageEvent(DamageSpecifier Accumulator);
/// Raised before damage is applied to a Damageable but after applying modifiers
/// </summary>
[ByRefEvent]
public record struct BeforeDamageCommitEvent(DamageSpecifier Damage);
public record struct BeforeDamageCommitEvent(DamageSpecifier Damage, bool ForceRefresh);
/// <summary>
/// Raised when the values for a damage overlay may have changed

View File

@@ -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<WoundComponent, StatusEffectRelayedEvent<WoundGetDamageEvent>>(OnWoundGetDamage);
SubscribeLocalEvent<WoundComponent, StatusEffectRelayedEvent<GetWoundsWithSpaceEvent>>(OnGetWoundsWithSpace);
SubscribeLocalEvent<WoundComponent, StatusEffectRemovedEvent>(OnWoundRemoved);
SubscribeLocalEvent<PainfulWoundComponent, StatusEffectRelayedEvent<GetPainEvent>>(OnGetPain);
SubscribeLocalEvent<HealableWoundComponent, StatusEffectRelayedEvent<HealWoundsEvent>>(OnHealHealableWounds);
@@ -117,6 +119,31 @@ public sealed class WoundableSystem : EntitySystem
}
}
private void ValidateWounds(EntityUid ent, DamageSpecifier? incoming)
{
#if DEBUG
var damageable = Comp<DamageableComponent>(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<WoundableComponent> ent, ref BeforeDamageCommitEvent args)
{
if (_timing.ApplyingState)
@@ -124,7 +151,7 @@ public sealed class WoundableSystem : EntitySystem
var damageable = Comp<DamageableComponent>(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<WoundComponent> 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<WoundableComponent> ent, DamageSpecifier overall)
@@ -235,23 +274,7 @@ public sealed class WoundableSystem : EntitySystem
var comp = Comp<WoundComponent>(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<TendableWoundComponent> ent, DamageSpecifier? specifier)
public void TendWound(Entity<WoundableComponent?> woundable, Entity<TendableWoundComponent> ent, DamageSpecifier? specifier)
{
var wound = Comp<WoundComponent>(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);
}