diff --git a/Content.Server/Atmos/Miasma/MiasmaSystem.cs b/Content.Server/Atmos/Miasma/MiasmaSystem.cs index 14dc86f0d9..5d66045167 100644 --- a/Content.Server/Atmos/Miasma/MiasmaSystem.cs +++ b/Content.Server/Atmos/Miasma/MiasmaSystem.cs @@ -109,7 +109,7 @@ namespace Content.Server.Atmos.Miasma damage.DamageDict.Add("Blunt", 0.3); // Slowly accumulate enough to gib after like half an hour damage.DamageDict.Add("Cellular", 0.3); // Cloning rework might use this eventually - _damageableSystem.TryChangeDamage(perishable.Owner, damage, true, true); + _damageableSystem.TryChangeDamage(perishable.Owner, damage, true, true, origin: perishable.Owner); } if (!TryComp(perishable.Owner, out var physics)) diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs index 8b957e0735..5c6ead3d2f 100644 --- a/Content.Server/Bed/BedSystem.cs +++ b/Content.Server/Bed/BedSystem.cs @@ -78,7 +78,7 @@ namespace Content.Server.Bed if (HasComp(healedEntity)) damage *= bedComponent.SleepMultiplier; - _damageableSystem.TryChangeDamage(healedEntity, damage, true); + _damageableSystem.TryChangeDamage(healedEntity, damage, true, origin: bedComponent.Owner); } } } diff --git a/Content.Server/Bible/BibleSystem.cs b/Content.Server/Bible/BibleSystem.cs index 952c73389e..88dc339a79 100644 --- a/Content.Server/Bible/BibleSystem.cs +++ b/Content.Server/Bible/BibleSystem.cs @@ -107,7 +107,7 @@ namespace Content.Server.Bible _popupSystem.PopupEntity(Loc.GetString("bible-sizzle"), args.User, Filter.Entities(args.User)); SoundSystem.Play(component.SizzleSoundPath.GetSound(), Filter.Pvs(args.User), args.User); - _damageableSystem.TryChangeDamage(args.User, component.DamageOnUntrainedUse, true); + _damageableSystem.TryChangeDamage(args.User, component.DamageOnUntrainedUse, true, origin: uid); _delay.BeginDelay(uid, delay); return; @@ -125,13 +125,13 @@ namespace Content.Server.Bible _popupSystem.PopupEntity(selfFailMessage, args.User, Filter.Entities(args.User), PopupType.MediumCaution); SoundSystem.Play("/Audio/Effects/hit_kick.ogg", Filter.Pvs(args.Target.Value), args.User); - _damageableSystem.TryChangeDamage(args.Target.Value, component.DamageOnFail, true); + _damageableSystem.TryChangeDamage(args.Target.Value, component.DamageOnFail, true, origin: uid); _delay.BeginDelay(uid, delay); return; } } - var damage = _damageableSystem.TryChangeDamage(args.Target.Value, component.Damage, true); + var damage = _damageableSystem.TryChangeDamage(args.Target.Value, component.Damage, true, origin: uid); if (damage == null || damage.Total == 0) { diff --git a/Content.Server/Chat/SuicideSystem.cs b/Content.Server/Chat/SuicideSystem.cs index f7f35e2b87..4344b98efa 100644 --- a/Content.Server/Chat/SuicideSystem.cs +++ b/Content.Server/Chat/SuicideSystem.cs @@ -111,7 +111,7 @@ namespace Content.Server.Chat damagePrototype = _prototypeManager.Index(fallback.ToString()); } const int lethalAmountOfDamage = 200; // TODO: Would be nice to get this number from somewhere else - _damageableSystem.TryChangeDamage(target, new(damagePrototype, lethalAmountOfDamage), true); + _damageableSystem.TryChangeDamage(target, new(damagePrototype, lethalAmountOfDamage), true, origin: target); } } } diff --git a/Content.Server/Climbing/ClimbSystem.cs b/Content.Server/Climbing/ClimbSystem.cs index e1459adf96..d106a9d71f 100644 --- a/Content.Server/Climbing/ClimbSystem.cs +++ b/Content.Server/Climbing/ClimbSystem.cs @@ -148,7 +148,7 @@ public sealed class ClimbSystem : SharedClimbSystem _stunSystem.TryParalyze(user, TimeSpan.FromSeconds(component.BonkTime), true); if (component.BonkDamage is { } bonkDmg) - _damageableSystem.TryChangeDamage(user, bonkDmg, true); + _damageableSystem.TryChangeDamage(user, bonkDmg, true, origin: user); return true; } @@ -363,8 +363,8 @@ public sealed class ClimbSystem : SharedClimbSystem if (TryComp(args.Climber, out var physics) && physics.Mass <= component.MassLimit) return; - _damageableSystem.TryChangeDamage(args.Climber, component.ClimberDamage); - _damageableSystem.TryChangeDamage(uid, component.TableDamage); + _damageableSystem.TryChangeDamage(args.Climber, component.ClimberDamage, origin: args.Climber); + _damageableSystem.TryChangeDamage(uid, component.TableDamage, origin: args.Climber); _stunSystem.TryParalyze(args.Climber, TimeSpan.FromSeconds(component.StunTime), true); // Not shown to the user, since they already get a 'you climb on the glass table' popup diff --git a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs index 0f6ea3d4e7..db9335302f 100644 --- a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs +++ b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs @@ -30,7 +30,7 @@ namespace Content.Server.Damage.Systems && welder.Lit && !welder.TankSafe) { - var dmg = _damageableSystem.TryChangeDamage(args.Target, weldingDamage); + var dmg = _damageableSystem.TryChangeDamage(args.Target, weldingDamage, origin: args.User); if (dmg != null) _adminLogger.Add(LogType.Damaged, @@ -42,7 +42,7 @@ namespace Content.Server.Damage.Systems && EntityManager.TryGetComponent(args.Used, out var tool) && tool.Qualities.ContainsAny(component.Tools)) { - var dmg = _damageableSystem.TryChangeDamage(args.Target, damage); + var dmg = _damageableSystem.TryChangeDamage(args.Target, damage, origin: args.User); if (dmg != null) _adminLogger.Add(LogType.Damaged, diff --git a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs index 4584c08278..ae404779db 100644 --- a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs +++ b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs @@ -19,7 +19,7 @@ namespace Content.Server.Damage.Systems private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args) { - var dmg = _damageableSystem.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances); + var dmg = _damageableSystem.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances, origin: args.User); // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying. if (dmg != null && HasComp(args.Target)) diff --git a/Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs b/Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs index a32c68c4fd..5051751be9 100644 --- a/Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs +++ b/Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs @@ -35,7 +35,7 @@ public sealed class DamageUserOnTriggerSystem : EntitySystem var ev = new BeforeDamageUserOnTriggerEvent(damage, target); RaiseLocalEvent(source, ev); - return _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances) is not null; + return _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances, origin: source) is not null; } } diff --git a/Content.Server/Electrocution/Components/ElectrocutionComponent.cs b/Content.Server/Electrocution/Components/ElectrocutionComponent.cs index 7509f83b12..a93b55a525 100644 --- a/Content.Server/Electrocution/Components/ElectrocutionComponent.cs +++ b/Content.Server/Electrocution/Components/ElectrocutionComponent.cs @@ -10,6 +10,7 @@ [DataField("timeLeft")] public float TimeLeft { get; set; } [DataField("electrocuting")] public EntityUid Electrocuting { get; set; } [DataField("accumDamage")] public float AccumulatedDamage { get; set; } + [DataField("source")] public EntityUid Source { get; set; } } } diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index 7a53212830..7f1c9d5961 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -105,7 +105,7 @@ namespace Content.Server.Electrocution _prototypeManager.Index(DamageType), (int) finished.AccumulatedDamage); - var actual = _damageableSystem.TryChangeDamage(finished.Electrocuting, damage); + var actual = _damageableSystem.TryChangeDamage(finished.Electrocuting, damage, origin: finished.Source); if (actual != null) { _adminLogger.Add(LogType.Electrocution, @@ -315,6 +315,7 @@ namespace Content.Server.Electrocution electrocutionComponent.TimeLeft = 1f; electrocutionComponent.Electrocuting = uid; + electrocutionComponent.Source = sourceUid; RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true); @@ -369,7 +370,7 @@ namespace Content.Server.Electrocution if(shockDamage is {} dmg) { var actual = _damageableSystem.TryChangeDamage(uid, - new DamageSpecifier(_prototypeManager.Index(DamageType), dmg)); + new DamageSpecifier(_prototypeManager.Index(DamageType), dmg), origin: sourceUid); if (actual != null) { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 99f83587c1..078633ed52 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -363,6 +363,7 @@ public sealed partial class ExplosionSystem : EntitySystem ev.DamageCoefficient = Math.Max(0, ev.DamageCoefficient); + //todo need a way to track origin of explosion if (ev.DamageCoefficient == 1) { // no damage-dict multiplication required. diff --git a/Content.Server/Gatherable/GatherableSystem.cs b/Content.Server/Gatherable/GatherableSystem.cs index 396c8637f4..0c3ba4b09b 100644 --- a/Content.Server/Gatherable/GatherableSystem.cs +++ b/Content.Server/Gatherable/GatherableSystem.cs @@ -63,7 +63,7 @@ public sealed class GatherableSystem : EntitySystem return; // Complete the gathering process - _damageableSystem.TryChangeDamage(ev.Resource, tool.Damage); + _damageableSystem.TryChangeDamage(ev.Resource, tool.Damage, origin: ev.Player); SoundSystem.Play(tool.GatheringSound.GetSound(), Filter.Pvs(ev.Resource, entityManager: EntityManager), ev.Resource); tool.GatheringEntities.Remove(ev.Resource); diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs index 02ad50774d..5ae876ff80 100644 --- a/Content.Server/Guardian/GuardianSystem.cs +++ b/Content.Server/Guardian/GuardianSystem.cs @@ -243,7 +243,7 @@ namespace Content.Server.Guardian { if (args.DamageDelta == null) return; - _damageSystem.TryChangeDamage(component.Host, args.DamageDelta * component.DamageShare); + _damageSystem.TryChangeDamage(component.Host, args.DamageDelta * component.DamageShare, origin: args.Origin); _popupSystem.PopupEntity(Loc.GetString("guardian-entity-taking-damage"), component.Host, Filter.Entities(component.Host)); } diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index 8df4b550a7..8a76feec2d 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -117,7 +117,7 @@ namespace Content.Server.Light.EntitySystems var burnMsg = Loc.GetString("powered-light-component-burn-hand"); _popupSystem.PopupEntity(burnMsg, uid, Filter.Entities(userUid)); - var damage = _damageableSystem.TryChangeDamage(userUid, light.Damage); + var damage = _damageableSystem.TryChangeDamage(userUid, light.Damage, origin: userUid); if (damage != null) _adminLogger.Add(LogType.Damaged, diff --git a/Content.Server/Medical/HealingSystem.cs b/Content.Server/Medical/HealingSystem.cs index 46b39a460e..f996b786fa 100644 --- a/Content.Server/Medical/HealingSystem.cs +++ b/Content.Server/Medical/HealingSystem.cs @@ -55,7 +55,7 @@ public sealed class HealingSystem : EntitySystem _bloodstreamSystem.TryModifyBleedAmount(uid, args.Component.BloodlossModifier); } - var healed = _damageable.TryChangeDamage(uid, args.Component.Damage, true); + var healed = _damageable.TryChangeDamage(uid, args.Component.Damage, true, origin: args.User); // Reverify that we can heal the damage. if (healed == null) diff --git a/Content.Server/Projectiles/SharedProjectileSystem.cs b/Content.Server/Projectiles/SharedProjectileSystem.cs index 2f4f655b58..d36d3520fe 100644 --- a/Content.Server/Projectiles/SharedProjectileSystem.cs +++ b/Content.Server/Projectiles/SharedProjectileSystem.cs @@ -43,7 +43,7 @@ namespace Content.Server.Projectiles var otherEntity = args.OtherFixture.Body.Owner; var direction = args.OurFixture.Body.LinearVelocity.Normalized; - var modifiedDamage = _damageableSystem.TryChangeDamage(otherEntity, component.Damage, component.IgnoreResistances); + var modifiedDamage = _damageableSystem.TryChangeDamage(otherEntity, component.Damage, component.IgnoreResistances, origin: component.Shooter); component.DamagedEntity = true; if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter)) diff --git a/Content.Server/Repairable/RepairableSystem.cs b/Content.Server/Repairable/RepairableSystem.cs index 0c3fdf019f..948640f470 100644 --- a/Content.Server/Repairable/RepairableSystem.cs +++ b/Content.Server/Repairable/RepairableSystem.cs @@ -36,7 +36,7 @@ namespace Content.Server.Repairable if (component.Damage != null) { - var damageChanged = _damageableSystem.TryChangeDamage(uid, component.Damage, true, false); + var damageChanged = _damageableSystem.TryChangeDamage(uid, component.Damage, true, false, origin: args.User); _adminLogger.Add(LogType.Healed, $"{ToPrettyString(args.User):user} repaired {ToPrettyString(uid):target} by {damageChanged?.Total}"); } else diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index 0f2bc2fa25..65244663cb 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -202,7 +202,7 @@ public sealed partial class RevenantSystem return; DamageSpecifier dspec = new(); dspec.DamageDict.Add("Poison", damage.Value); - _damage.TryChangeDamage(args.Target, dspec, true); + _damage.TryChangeDamage(args.Target, dspec, true, origin: uid); } private void OnHarvestCancelled(EntityUid uid, RevenantComponent component, HarvestDoAfterCancelled args) @@ -252,7 +252,7 @@ public sealed partial class RevenantSystem //hardcoded damage specifiers til i die. var dspec = new DamageSpecifier(); dspec.DamageDict.Add("Structural", 15); - _damage.TryChangeDamage(ent, dspec); + _damage.TryChangeDamage(ent, dspec, origin: uid); } if (!_random.Prob(component.DefileEffectChance)) diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 0fffb94699..1a6daccd39 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -71,7 +71,7 @@ public sealed partial class GunSystem : SharedGunSystem if (_interaction.TryRollClumsy(user.Value, GunClumsyChance, clumsy)) { // Wound them - Damageable.TryChangeDamage(user, clumsy.ClumsyDamage); + Damageable.TryChangeDamage(user, clumsy.ClumsyDamage, origin: user); _stun.TryParalyze(user.Value, TimeSpan.FromSeconds(3f), true); // Apply salt to the wound ("Honk!") @@ -187,7 +187,7 @@ public sealed partial class GunSystem : SharedGunSystem var dmg = hitscan.Damage; if (dmg != null) - dmg = Damageable.TryChangeDamage(hitEntity, dmg); + dmg = Damageable.TryChangeDamage(hitEntity, dmg, origin: user); if (dmg != null) { diff --git a/Content.Shared/Blocking/BlockingUserSystem.cs b/Content.Shared/Blocking/BlockingUserSystem.cs index 8b1d3ff598..1ab0df51ed 100644 --- a/Content.Shared/Blocking/BlockingUserSystem.cs +++ b/Content.Shared/Blocking/BlockingUserSystem.cs @@ -58,7 +58,7 @@ public sealed class BlockingUserSystem : EntitySystem { if (args.DamageDelta != null && args.DamageIncreased) { - _damageable.TryChangeDamage(component.BlockingItem, args.DamageDelta); + _damageable.TryChangeDamage(component.BlockingItem, args.DamageDelta, origin: args.Origin); } } diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 4875ea9fa2..c12246e6a6 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -113,7 +113,7 @@ namespace Content.Shared.Damage /// The damage changed event is used by other systems, such as damage thresholds. /// public void DamageChanged(DamageableComponent component, DamageSpecifier? damageDelta = null, - bool interruptsDoAfters = true) + bool interruptsDoAfters = true, EntityUid? origin = null) { component.DamagePerGroup = component.Damage.GetDamagePerGroup(_prototypeManager); component.TotalDamage = component.Damage.Total; @@ -124,7 +124,7 @@ namespace Content.Shared.Damage var data = new DamageVisualizerGroupData(damageDelta.GetDamagePerGroup(_prototypeManager).Keys.ToList()); _appearance.SetData(component.Owner, DamageVisualizerKeys.DamageUpdateGroups, data, appearance); } - RaiseLocalEvent(component.Owner, new DamageChangedEvent(component, damageDelta, interruptsDoAfters)); + RaiseLocalEvent(component.Owner, new DamageChangedEvent(component, damageDelta, interruptsDoAfters, origin)); } /// @@ -140,7 +140,7 @@ namespace Content.Shared.Damage /// null if the user had no applicable components that can take damage. /// public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false, - bool interruptsDoAfters = true, DamageableComponent? damageable = null) + bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null) { if (!uid.HasValue || !Resolve(uid.Value, ref damageable, false)) { @@ -364,10 +364,16 @@ namespace Content.Shared.Damage /// public readonly bool InterruptsDoAfters = false; - public DamageChangedEvent(DamageableComponent damageable, DamageSpecifier? damageDelta, bool interruptsDoAfters) + /// + /// Contains the entity which caused the change in damage, if any was responsible. + /// + public readonly EntityUid? Origin; + + public DamageChangedEvent(DamageableComponent damageable, DamageSpecifier? damageDelta, bool interruptsDoAfters, EntityUid? origin) { Damageable = damageable; DamageDelta = damageDelta; + Origin = origin; if (DamageDelta == null) return; diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs index abb45c38f3..e8cd3c9bf9 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs @@ -406,7 +406,7 @@ public abstract class SharedDoorSystem : EntitySystem { door.CurrentlyCrushing.Add(entity); if (door.CrushDamage != null) - _damageableSystem.TryChangeDamage(entity, door.CrushDamage); + _damageableSystem.TryChangeDamage(entity, door.CrushDamage, origin: uid); _stunSystem.TryParalyze(entity, stunTime, true); } diff --git a/Content.Shared/MobState/EntitySystems/SharedMobStateSystem.cs b/Content.Shared/MobState/EntitySystems/SharedMobStateSystem.cs index 4b0ef72165..b185319226 100644 --- a/Content.Shared/MobState/EntitySystems/SharedMobStateSystem.cs +++ b/Content.Shared/MobState/EntitySystems/SharedMobStateSystem.cs @@ -178,7 +178,7 @@ namespace Content.Shared.MobState.EntitySystems public void UpdateState(EntityUid _, MobStateComponent component, DamageChangedEvent args) { - UpdateState(component, args.Damageable.TotalDamage); + UpdateState(component, args.Damageable.TotalDamage, args.Origin); } private void OnMoveAttempt(EntityUid uid, MobStateComponent component, UpdateCanMoveEvent args) @@ -275,20 +275,20 @@ namespace Content.Shared.MobState.EntitySystems /// /// Updates the mob state.. /// - public void UpdateState(MobStateComponent component, FixedPoint2 damage) + public void UpdateState(MobStateComponent component, FixedPoint2 damage, EntityUid? origin = null) { if (!TryGetState(component, damage, out var newState, out var threshold)) { return; } - SetMobState(component, component.CurrentState, (newState.Value, threshold)); + SetMobState(component, component.CurrentState, (newState.Value, threshold), origin); } /// /// Sets the mob state and marks the component as dirty. /// - private void SetMobState(MobStateComponent component, DamageState? old, (DamageState state, FixedPoint2 threshold)? current) + private void SetMobState(MobStateComponent component, DamageState? old, (DamageState state, FixedPoint2 threshold)? current, EntityUid? origin = null) { if (!current.HasValue) { @@ -313,7 +313,7 @@ namespace Content.Shared.MobState.EntitySystems EnterState(component, state); UpdateState(component, state, threshold); - var message = new MobStateChangedEvent(component, old, state); + var message = new MobStateChangedEvent(component, old, state, origin); RaiseLocalEvent(component.Owner, message, true); Dirty(component); } diff --git a/Content.Shared/MobState/MobStateChangedEvent.cs b/Content.Shared/MobState/MobStateChangedEvent.cs index aa482da8ba..783714cca3 100644 --- a/Content.Shared/MobState/MobStateChangedEvent.cs +++ b/Content.Shared/MobState/MobStateChangedEvent.cs @@ -7,11 +7,13 @@ namespace Content.Shared.MobState public MobStateChangedEvent( MobStateComponent component, DamageState? oldMobState, - DamageState currentMobState) + DamageState currentMobState, + EntityUid? origin) { Component = component; OldMobState = oldMobState; CurrentMobState = currentMobState; + Origin = origin; } public EntityUid Entity => Component.Owner; @@ -21,6 +23,8 @@ namespace Content.Shared.MobState public DamageState? OldMobState { get; } public DamageState CurrentMobState { get; } + + public EntityUid? Origin { get; } } public static class A