]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Update DamageableSystem to modern standards (#39417)
authorHannah Giovanna Dawson <karakkaraz@gmail.com>
Mon, 27 Oct 2025 19:53:04 +0000 (19:53 +0000)
committerGitHub <noreply@github.com>
Mon, 27 Oct 2025 19:53:04 +0000 (19:53 +0000)
* Update DamageableSystem to modern standards

* DamageContainerId -> DamageContainerID with lint flag

* Replace strings with protoids

* Make CVar subscription declarations all consistently whitespaced

* ChangeDamage -> TryChangeDamage, cope with C# jank

* Revert event signature changes

* Restore a comment

* Re-add two queries

* Init the queries

* Use appearanceQuery in DamageChanged

* Use damageableQuery in TryChangeDamage

* Use damageableQuery in SetDamageModifierSetId

* Final cleanup, fix sandboxing

* Rectify ExplosionSystem:::ProcessEntity's call to TryChangeDamage

* Re-organize DamageableSystem

* first big fuck you breaking change.

* THATS A LOT OF DAMAGE!!!

* Fix test fails

* test fixes 2

* push it

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
157 files changed:
Content.Benchmarks/DestructibleBenchmark.cs
Content.Client/Damage/DamageVisualsSystem.cs
Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs
Content.Client/Overlays/EntityHealthBarOverlay.cs
Content.Client/Overlays/ShowHealthIconsSystem.cs
Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs
Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs
Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs
Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs
Content.IntegrationTests/Tests/Damageable/DamageableTest.cs
Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs
Content.IntegrationTests/Tests/Destructible/DestructibleDamageTypeTest.cs
Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs
Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs
Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs
Content.IntegrationTests/Tests/Minds/MindTests.cs
Content.IntegrationTests/Tests/Mousetrap/MousetrapTest.cs
Content.IntegrationTests/Tests/Storage/EntityStorageTests.cs
Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs
Content.IntegrationTests/Tests/VendingMachineRestockTest.cs
Content.IntegrationTests/Tests/Weapons/WeaponTests.cs
Content.Server/Access/Systems/IdCardConsoleSystem.cs
Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs
Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs
Content.Server/Atmos/EntitySystems/FlammableSystem.cs
Content.Server/Atmos/Rotting/RottingSystem.cs
Content.Server/Bed/BedSystem.cs
Content.Server/Bible/BibleSystem.cs
Content.Server/Body/Systems/RespiratorSystem.cs
Content.Server/CardboardBox/CardboardBoxSystem.cs
Content.Server/Chat/SuicideSystem.cs
Content.Server/Chat/Systems/EmoteOnDamageSystem.cs
Content.Server/Cloning/CloningPodSystem.cs
Content.Server/Cluwne/CluwneSystem.cs
Content.Server/Construction/Conditions/MinHealth.cs
Content.Server/Damage/Commands/HurtCommand.cs
Content.Server/Damage/ForceSay/DamageForceSaySystem.cs
Content.Server/Damage/Systems/DamageOnHitSystem.cs
Content.Server/Damage/Systems/DamageOnLandSystem.cs
Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs
Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs
Content.Server/Damage/Systems/DamageRandomPopupSystem.cs
Content.Server/Damage/Systems/ExaminableDamageSystem.cs
Content.Server/Destructible/DestructibleSystem.BenchmarkHelpers.cs
Content.Server/Destructible/DestructibleSystem.cs
Content.Server/Disposal/Unit/DisposableSystem.cs
Content.Server/Dragon/DragonRiftSystem.cs
Content.Server/Electrocution/ElectrocutionSystem.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.cs
Content.Server/Ghost/GhostSystem.cs
Content.Server/Guardian/GuardianSystem.cs
Content.Server/ImmovableRod/ImmovableRodSystem.cs
Content.Server/KillTracking/KillTrackingSystem.cs
Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
Content.Server/Lightning/LightningTargetSystem.cs
Content.Server/Mech/Systems/MechSystem.cs
Content.Server/Medical/DefibrillatorSystem.cs
Content.Server/Medical/HealthAnalyzerSystem.cs
Content.Server/Mining/MeteorSystem.cs
Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs
Content.Server/NPC/Systems/NPCRetaliationSystem.cs
Content.Server/NPC/Systems/NPCUtilitySystem.cs
Content.Server/Ninja/Systems/StunProviderSystem.cs
Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
Content.Server/Polymorph/Systems/PolymorphSystem.cs
Content.Server/Projectiles/ProjectileSystem.cs
Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs
Content.Server/Revenant/EntitySystems/RevenantSystem.cs
Content.Server/Shuttles/Systems/ShuttleSystem.Impact.cs
Content.Server/Shuttles/Systems/ShuttleSystem.cs
Content.Server/Shuttles/Systems/ThrusterSystem.cs
Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs
Content.Server/Silicons/StationAi/StationAiSystem.cs
Content.Server/Speech/EntitySystems/DamagedSiliconAccentSystem.cs
Content.Server/Spreader/KudzuSystem.cs
Content.Server/Temperature/Systems/TemperatureSystem.cs
Content.Server/VendingMachines/VendingMachineSystem.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.AutoFire.cs
Content.Server/Zombies/ZombieSystem.Transform.cs
Content.Server/Zombies/ZombieSystem.cs
Content.Shared/Armor/SharedArmorSystem.cs
Content.Shared/Bed/Sleep/SleepingSystem.cs
Content.Shared/Blocking/BlockingSystem.User.cs
Content.Shared/Body/Systems/SharedBloodstreamSystem.cs
Content.Shared/Body/Systems/SharedBodySystem.Parts.cs
Content.Shared/Body/Systems/SharedBodySystem.cs
Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs
Content.Shared/Chat/SharedSuicideSystem.cs
Content.Shared/Climbing/Systems/ClimbSystem.cs
Content.Shared/Clothing/SharedCursedMaskSystem.cs
Content.Shared/Clumsy/ClumsySystem.cs
Content.Shared/Damage/Components/ClothingSlowOnDamageModifierComponent.cs
Content.Shared/Damage/Components/DamageableComponent.cs
Content.Shared/Damage/Components/IgnoreSlowOnDamageComponent.cs
Content.Shared/Damage/Components/RequireProjectileTargetComponent.cs
Content.Shared/Damage/DamageModifierSet.cs
Content.Shared/Damage/DamageSpecifier.cs
Content.Shared/Damage/Prototypes/DamageContainerPrototype.cs
Content.Shared/Damage/Prototypes/DamageGroupPrototype.cs
Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs
Content.Shared/Damage/Systems/DamageOnInteractSystem.cs
Content.Shared/Damage/Systems/DamageableSystem.API.cs [new file with mode: 0644]
Content.Shared/Damage/Systems/DamageableSystem.BenchmarkHelpers.cs
Content.Shared/Damage/Systems/DamageableSystem.Events.cs [new file with mode: 0644]
Content.Shared/Damage/Systems/DamageableSystem.cs
Content.Shared/Damage/Systems/PassiveDamageSystem.cs
Content.Shared/Damage/Systems/RequireProjectileTargetSystem.cs
Content.Shared/Damage/Systems/SharedGodmodeSystem.cs
Content.Shared/Damage/Systems/SlowOnDamageSystem.cs
Content.Shared/Destructible/Triggers/AndTrigger.cs
Content.Shared/Destructible/Triggers/DamageGroupTrigger.cs
Content.Shared/Destructible/Triggers/DamageTrigger.cs
Content.Shared/Destructible/Triggers/DamageTypeTrigger.cs
Content.Shared/Destructible/Triggers/IThresholdTrigger.cs
Content.Shared/Destructible/Triggers/OrTrigger.cs
Content.Shared/DoAfter/SharedDoAfterSystem.cs
Content.Shared/Doors/Systems/SharedDoorSystem.cs
Content.Shared/EntityConditions/Conditions/DamageGroupEntityConditionSystem.cs
Content.Shared/EntityConditions/Conditions/DamageTypeEntityConditionSystem.cs
Content.Shared/EntityConditions/Conditions/TotalDamageEntityConditionSystem.cs
Content.Shared/EntityEffects/Effects/EvenHealthChangeEntityEffectSystem.cs
Content.Shared/EntityEffects/Effects/HealthChangeEntityEffectSystem.cs
Content.Shared/Execution/SharedExecutionSystem.cs
Content.Shared/Fax/Systems/FaxecuteSystem.cs
Content.Shared/Flash/DamagedByFlashingSystem.cs
Content.Shared/HealthExaminable/HealthExaminableSystem.cs
Content.Shared/Implants/SharedImplanterSystem.cs
Content.Shared/Inventory/InventorySystem.Relay.cs
Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs
Content.Shared/Medical/Healing/HealingSystem.cs
Content.Shared/Medical/Stethoscope/StethoscopeSystem.cs
Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs
Content.Shared/Mobs/Components/MobStateComponent.cs
Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
Content.Shared/Mobs/Systems/MobStateSystem.cs
Content.Shared/Mobs/Systems/MobThresholdSystem.cs
Content.Shared/Nutrition/EntitySystems/HungerSystem.cs
Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs
Content.Shared/Repairable/RepairableSystem.cs
Content.Shared/Silicons/Borgs/SharedBorgSystem.Relay.cs
Content.Shared/Silicons/Bots/MedibotSystem.cs
Content.Shared/Storage/EntitySystems/SecretStashSystem.cs
Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs
Content.Shared/Trigger/Systems/DamageOnTriggerSystem.cs
Content.Shared/Turrets/SharedDeployableTurretSystem.cs
Content.Shared/Weapons/Hitscan/Systems/HitscanBasicDamageSystem.cs
Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs
Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.XAT.cs
Content.Shared/Xenoarchaeology/Artifact/XAE/XAEDamageInAreaSystem.cs
Content.Shared/Xenoarchaeology/Artifact/XAT/XATDamageThresholdReachedSystem.cs
Content.Shared/Xenoarchaeology/Equipment/SharedArtifactCrusherSystem.cs

index b91837e7ca3048216636b03f588c126c86a79ada..1b54bacca0492cdd04e8e77571560d316971c36d 100644 (file)
@@ -1,12 +1,13 @@
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Threading.Tasks;
 using BenchmarkDotNet.Attributes;
 using Content.IntegrationTests;
 using Content.IntegrationTests.Pair;
 using Content.Server.Destructible;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Maps;
 using Robust.Shared;
index 065bf628bc25fbdde35dad78ff3ea663c0aa38aa..ac3ff819aa9f0fdeb61202847613f8e8b5817566 100644 (file)
@@ -1,5 +1,6 @@
 using System.Linq;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Content.Shared.FixedPoint;
 using Robust.Client.GameObjects;
index 225619b0315bc7261521640ba4cd94182188c6b1..533a8b9f2cc072c26f23f44651b818624738c36c 100644 (file)
@@ -1,28 +1,22 @@
 using System.Linq;
 using System.Numerics;
-using Content.Client.Message;
 using Content.Shared.Atmos;
 using Content.Client.UserInterface.Controls;
-using Content.Shared.Alert;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Content.Shared.FixedPoint;
 using Content.Shared.Humanoid;
 using Content.Shared.Humanoid.Prototypes;
 using Content.Shared.IdentityManagement;
-using Content.Shared.Inventory;
 using Content.Shared.MedicalScanner;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
-using Content.Shared.Mobs.Systems;
-using Content.Shared.Nutrition.Components;
 using Robust.Client.AutoGenerated;
 using Robust.Client.UserInterface.XAML;
 using Robust.Client.GameObjects;
 using Robust.Client.Graphics;
 using Robust.Client.UserInterface.Controls;
 using Robust.Client.ResourceManagement;
-using Robust.Client.UserInterface;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
 
index cf9d879844d834404b02f33e95c40f46c1849928..55fc1e097435d85a0e8087577d45573aae6ae358 100644 (file)
@@ -1,7 +1,7 @@
 using System.Numerics;
 using Content.Client.StatusIcon;
 using Content.Client.UserInterface.Systems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
index 0a875e79c58249996c2ca3bf502d145a79b849a7..7fbc0cd944ab985c3e0f3b6edad14ed2d11afbc3 100644 (file)
@@ -1,5 +1,4 @@
 using Content.Shared.Atmos.Rotting;
-using Content.Shared.Damage;
 using Content.Shared.Inventory.Events;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Overlays;
@@ -7,6 +6,7 @@ using Content.Shared.StatusIcon;
 using Content.Shared.StatusIcon.Components;
 using Robust.Shared.Prototypes;
 using System.Linq;
+using Content.Shared.Damage.Components;
 
 namespace Content.Client.Overlays;
 
index 55d00fec18546f7470aff8f07bb199243ac54891..20db76554d66a433c7ffc5fb9be8908b867e67bd 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
index 53604b2c1e3b904299ecd101ca804439a0025231..87ff00691a68d3c073b69d7880a8c68fd303d184 100644 (file)
@@ -1,6 +1,8 @@
 using Content.Shared.Administration.Systems;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Mobs.Systems;
index c232ccf415e538dae422086d46082b819df0e27c..57e8bfd4496010c90f3fef5d4695fd9cfe7922ff 100644 (file)
@@ -1,6 +1,8 @@
 using System.Linq;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Execution;
 using Content.Shared.FixedPoint;
 using Content.Shared.Ghost;
@@ -280,7 +282,7 @@ public sealed class SuicideCommandTests
         await server.WaitAssertion(() =>
         {
             // Heal all damage first (possible low pressure damage taken)
-            damageableSystem.SetAllDamage(player, damageableComp, 0);
+            damageableSystem.ClearAllDamage((player, damageableComp));
             consoleHost.GetSessionShell(playerMan.Sessions.First()).ExecuteCommand("suicide");
             var lethalDamageThreshold = mobThresholdsComp.Thresholds.Keys.Last();
 
@@ -355,7 +357,7 @@ public sealed class SuicideCommandTests
         await server.WaitAssertion(() =>
         {
             // Heal all damage first (possible low pressure damage taken)
-            damageableSystem.SetAllDamage(player, damageableComp, 0);
+            damageableSystem.ClearAllDamage((player, damageableComp));
             consoleHost.GetSessionShell(playerMan.Sessions.First()).ExecuteCommand("suicide");
             var lethalDamageThreshold = mobThresholdsComp.Thresholds.Keys.Last();
 
index 192604edfd54ae1cc96fc869a73a7dd389ea185c..5a4d284c0fc41284eb71f55a8068c67c5e74a4f3 100644 (file)
@@ -1,6 +1,8 @@
 using Content.IntegrationTests.Tests.Interaction;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Prototypes;
 
@@ -21,7 +23,7 @@ public sealed class WindowRepair : InteractionTest
         var damageType = Server.ProtoMan.Index(BluntDamageType);
         var damage = new DamageSpecifier(damageType, FixedPoint2.New(10));
         Assert.That(comp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero));
-        await Server.WaitPost(() => sys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true));
+        await Server.WaitPost(() => sys.TryChangeDamage(SEntMan.GetEntity(Target).Value, damage, ignoreResistances: true));
         await RunTicks(5);
         Assert.That(comp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero));
 
index f610ab732e99853a8830e682025cf073878d1d5d..72e8901631fba38963946eb94afce77a458c5c06 100644 (file)
@@ -1,5 +1,7 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Robust.Shared.GameObjects;
 using Robust.Shared.Map;
@@ -232,10 +234,14 @@ namespace Content.IntegrationTests.Tests.Damageable
                     Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
                 });
 
-                // Test SetAll function
-                sDamageableSystem.SetAllDamage(sDamageableEntity, sDamageableComponent, 10);
+                // Test SetAll and ClearAll function
+                sDamageableSystem.SetAllDamage((sDamageableEntity, sDamageableComponent), 10);
                 Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(10 * sDamageableComponent.Damage.DamageDict.Count)));
-                sDamageableSystem.SetAllDamage(sDamageableEntity, sDamageableComponent, 0);
+                sDamageableSystem.SetAllDamage((sDamageableEntity, sDamageableComponent), 0);
+                Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
+                sDamageableSystem.SetAllDamage((sDamageableEntity, sDamageableComponent), 10);
+                Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(10 * sDamageableComponent.Damage.DamageDict.Count)));
+                sDamageableSystem.ClearAllDamage((sDamageableEntity, sDamageableComponent));
                 Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
 
                 // Test 'wasted' healing
index 3650fd69d700830b5e399c7070460c675fb2e297..99f68b3fa39b9db3eebfc48b2877ccdfd37e34a0 100644 (file)
@@ -1,5 +1,7 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Destructible.Thresholds.Triggers;
 using Content.Shared.FixedPoint;
 using Robust.Shared.GameObjects;
@@ -130,7 +132,7 @@ namespace Content.IntegrationTests.Tests.Destructible
                 sTestThresholdListenerSystem.ThresholdsReached.Clear();
 
                 // Heal both classes of damage to 0
-                sDamageableSystem.SetAllDamage(sDestructibleEntity, sDamageableComponent, 0);
+                sDamageableSystem.ClearAllDamage((sDestructibleEntity, sDamageableComponent));
 
                 // No new thresholds reached, healing should not trigger it
                 Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);
@@ -174,7 +176,7 @@ namespace Content.IntegrationTests.Tests.Destructible
                 threshold.TriggersOnce = true;
 
                 // Heal brute and burn back to 0
-                sDamageableSystem.SetAllDamage(sDestructibleEntity, sDamageableComponent, 0);
+                sDamageableSystem.ClearAllDamage((sDestructibleEntity, sDamageableComponent));
 
                 // No new thresholds reached from healing
                 Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);
index 4b1dc1ab3b0984656a527d0661506f1126c416e5..70baaea95a1beeef55152d0f49c7afe1afe23898 100644 (file)
@@ -1,5 +1,7 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Destructible.Thresholds.Triggers;
 using Robust.Shared.GameObjects;
 using Robust.Shared.Prototypes;
index b1342eeafefe8246791bd0219c9d769f175b85c0..df98294ee96044aeaeaec7c2146b8f11287f647f 100644 (file)
@@ -2,6 +2,7 @@ using System.Linq;
 using Content.Server.Destructible.Thresholds.Behaviors;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Destructible.Thresholds;
 using Robust.Shared.GameObjects;
 using Robust.Shared.Prototypes;
index fb3c40ec3c7248fc29b8d1d11e5cafd584170b16..1736d3d7e3412693e1e21a8be02850f7a0ac7f4a 100644 (file)
@@ -3,7 +3,9 @@ using Content.Server.Destructible;
 using Content.Server.Destructible.Thresholds;
 using Content.Server.Destructible.Thresholds.Behaviors;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Audio.Systems;
 using Content.Shared.Destructible;
@@ -124,7 +126,7 @@ namespace Content.IntegrationTests.Tests.Destructible
                 Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);
 
                 // Set damage to 0
-                sDamageableSystem.SetAllDamage(sDestructibleEntity, sDamageableComponent, 0);
+                sDamageableSystem.ClearAllDamage((sDestructibleEntity, sDamageableComponent));
 
                 // Damage for 100, up to 100
                 sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 10, true);
@@ -185,7 +187,7 @@ namespace Content.IntegrationTests.Tests.Destructible
                 sTestThresholdListenerSystem.ThresholdsReached.Clear();
 
                 // Heal all damage
-                sDamageableSystem.SetAllDamage(sDestructibleEntity, sDamageableComponent, 0);
+                sDamageableSystem.ClearAllDamage((sDestructibleEntity, sDamageableComponent));
 
                 // Damage up to 50
                 sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 5, true);
@@ -247,7 +249,7 @@ namespace Content.IntegrationTests.Tests.Destructible
                 sTestThresholdListenerSystem.ThresholdsReached.Clear();
 
                 // Heal the entity completely
-                sDamageableSystem.SetAllDamage(sDestructibleEntity, sDamageableComponent, 0);
+                sDamageableSystem.ClearAllDamage((sDestructibleEntity, sDamageableComponent));
 
                 // Check that the entity has 0 damage
                 Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));
index 4f92fd4e55d4c12732e2142034d725a4a8d312f4..246a770190289d3c09a939290586621a538c13cd 100644 (file)
@@ -10,7 +10,7 @@ using Content.Server.Roles;
 using Content.Server.RoundEnd;
 using Content.Server.Shuttles.Components;
 using Content.Shared.CCVar;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Content.Shared.GameTicking;
 using Content.Shared.Hands.Components;
index 1bda6fd4dba8c97e2f9b794e740def7ac6036324..35069339baf5916692b6d313e74d208ca117ace7 100644 (file)
@@ -4,7 +4,9 @@ using Content.Server.Ghost.Roles;
 using Content.Server.Ghost.Roles.Components;
 using Content.Server.Mind;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mind;
 using Content.Shared.Mind.Components;
@@ -147,7 +149,7 @@ public sealed partial class MindTests
             var damageable = entMan.GetComponent<DamageableComponent>(entity);
             var prototype = protoMan.Index(BluntDamageType);
 
-            damageableSystem.SetDamage(entity, damageable, new DamageSpecifier(prototype, FixedPoint2.New(401)));
+            damageableSystem.SetDamage((entity, damageable), new DamageSpecifier(prototype, FixedPoint2.New(401)));
             Assert.That(mindSystem.GetMind(entity, mindContainerComp), Is.EqualTo(mindId));
         });
 
index 422d58cdcf4b33af9b505dbefc23cda831e3a36e..5f1b9172ddd3340d316d2173282e6148cee0e36d 100644 (file)
@@ -1,7 +1,6 @@
 using Content.IntegrationTests.Tests.Movement;
 using Content.Server.NPC.HTN;
-using Content.Shared.Damage;
-using Content.Shared.FixedPoint;
+using Content.Shared.Damage.Components;
 using Content.Shared.Item.ItemToggle;
 using Content.Shared.Item.ItemToggle.Components;
 using Content.Shared.Mobs;
index 45ee69a9efab52c5829e283fd40d076cc4ed7ebc..f80cc089de41330d581235c29c72d9b0a62525ed 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Server.Storage.EntitySystems;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Robust.Shared.Containers;
 using Robust.Shared.GameObjects;
 
index 3645667737a03d35b2413693b354afd60fbe7e92..af16f1278a4a736926ecc8f7cee14df34f5a9c49 100644 (file)
@@ -2,7 +2,9 @@ using System.Linq;
 using Content.IntegrationTests.Tests.Interaction;
 using Content.Server.VendingMachines;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.VendingMachines;
 using Robust.Shared.Prototypes;
@@ -200,7 +202,7 @@ public sealed class VendingInteractionTest : InteractionTest
         // Damage the vending machine to the point that it breaks
         var damageType = ProtoMan.Index(TestDamageType);
         var damage = new DamageSpecifier(damageType, FixedPoint2.New(100));
-        await Server.WaitPost(() => damageableSys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true));
+        await Server.WaitPost(() => damageableSys.TryChangeDamage(SEntMan.GetEntity(Target).Value, damage, ignoreResistances: true));
         await RunTicks(5);
         Assert.That(damageableComp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero), $"{VendingMachineProtoId} did not take damage.");
     }
index f30eed0651e977c54de7ccc60b66dd6f5e7e114f..01770fe10798aa21fa9292cf695518eb4d706c43 100644 (file)
@@ -5,6 +5,7 @@ using Content.Server.Wires;
 using Content.Shared.Cargo.Prototypes;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Prototypes;
 using Content.Shared.Storage.Components;
 using Content.Shared.VendingMachines;
@@ -296,14 +297,12 @@ namespace Content.IntegrationTests.Tests
 
                 restock = entityManager.SpawnEntity("TestRestockExplode", coordinates);
                 var damageSpec = new DamageSpecifier(prototypeManager.Index(TestDamageType), 100);
-                var damageResult = damageableSystem.TryChangeDamage(restock, damageSpec);
+                var damageResult = damageableSystem.ChangeDamage(restock, damageSpec);
 
 #pragma warning disable NUnit2045
-                Assert.That(damageResult, Is.Not.Null,
-                    "Received null damageResult when attempting to damage restock box.");
+                Assert.That(!damageResult.Empty, "Received empty damageResult when attempting to damage restock box.");
 
-                Assert.That((int) damageResult!.GetTotal(), Is.GreaterThan(0),
-                    "Box damage result was not greater than 0.");
+                Assert.That((int) damageResult.GetTotal(), Is.GreaterThan(0), "Box damage result was not greater than 0.");
 #pragma warning restore NUnit2045
             });
             await server.WaitRunTicks(15);
index bf240ba9e2bca452f5f334bcb4ac53da852f13f0..135e75f8be9352cb2698ddef078e4d5f91a0e2a7 100644 (file)
@@ -1,5 +1,5 @@
 using Content.IntegrationTests.Tests.Interaction;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Weapons.Ranged.Components;
 using Content.Shared.Weapons.Ranged.Systems;
 using Content.Shared.Wieldable.Components;
index 7c772830ba5ddbede5bbaf28f3f80f7cc8a83386..9f21fd68d8c4bf786e7a87df42de53b5479349c3 100644 (file)
@@ -12,6 +12,7 @@ using Content.Shared.Chat;
 using Content.Shared.Construction;
 using Content.Shared.Containers.ItemSlots;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Roles;
 using Content.Shared.StationRecords;
index d03b799ff218fa45de7bd09c48a98051567e839a..617451f955dd29022d46f51af123496b7b7d7fb1 100644 (file)
@@ -1,6 +1,5 @@
 using Content.Server.Administration.Components;
 using Content.Server.Atmos.EntitySystems;
-using Content.Server.Body.Components;
 using Content.Server.Body.Systems;
 using Content.Server.Electrocution;
 using Content.Server.Explosion.EntitySystems;
@@ -24,7 +23,6 @@ using Content.Shared.Body.Part;
 using Content.Shared.Clothing.Components;
 using Content.Shared.Clumsy;
 using Content.Shared.Cluwne;
-using Content.Shared.Damage;
 using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Electrocution;
@@ -58,6 +56,7 @@ using Robust.Shared.Spawners;
 using Robust.Shared.Utility;
 using System.Numerics;
 using System.Threading;
+using Content.Shared.Damage.Components;
 using Timer = Robust.Shared.Timing.Timer;
 
 namespace Content.Server.Administration.Systems;
index 255e58dcbf5f724edbeba6af743313d7dbdb0d62..d6ab2a00874060cfee9714062d20a64e2c7e93f3 100644 (file)
@@ -251,7 +251,7 @@ public sealed partial class AtmosphereSystem
         var maxPressureCapped = Math.Min(maxPressure, ent.Comp.MaxEffectivePressure);
         var appliedDamage = ScaleDamage(ent, ent.Comp.BaseDamage, maxPressureCapped);
 
-        _damage.TryChangeDamage(ent, appliedDamage, ignoreResistances: true, interruptsDoAfters: false);
+        _damage.ChangeDamage(ent.Owner, appliedDamage, ignoreResistances: true, interruptsDoAfters: false);
         SetIsTakingDamageState(ent, true);
     }
 
index 00b7e169134c8308a3ecb630136b7d91cf9b0a40..8120caca4e05f2880b84208c318072968236fe8a 100644 (file)
@@ -14,7 +14,7 @@ using Robust.Shared.Map;
 using Robust.Shared.Physics.Systems;
 using Robust.Shared.Prototypes;
 using System.Linq;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Robust.Shared.Threading;
 
 namespace Content.Server.Atmos.EntitySystems;
index ec508790ba875eb27e63896af6859df50ceaedcc..c23f58637d7351ee23f0f28b85d2bfeb86cc1d79 100644 (file)
@@ -3,7 +3,8 @@ using Content.Server.Administration.Logs;
 using Content.Server.Atmos.Components;
 using Content.Shared.Alert;
 using Content.Shared.Atmos;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.FixedPoint;
 using Content.Shared.Inventory;
index 81bd4e5c6c880b318d4c5cde7ea20ccc2ec717af..071c63c5000595c3d63667fc19727405a41cfacb 100644 (file)
@@ -7,7 +7,7 @@ using Content.Shared.ActionBlocker;
 using Content.Shared.Alert;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.IgnitionSource;
 using Content.Shared.Interaction;
index 57c1504b168149bd74e996f2a1a5476f7123aeec..5feb95e3c495d63ed18c7ace60e0bd8bd6b57d41 100644 (file)
@@ -2,7 +2,7 @@ using Content.Server.Atmos.EntitySystems;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Rotting;
 using Content.Shared.Body.Events;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Temperature.Components;
 using Robust.Server.Containers;
 using Robust.Shared.Physics.Components;
index 8cfb28acb61b9f7bc2975a3163f399280c7c13c7..f6c2862a84a22beafb491c2c251849a23ace2f70 100644 (file)
@@ -2,7 +2,7 @@ using Content.Shared.Bed;
 using Content.Shared.Bed.Components;
 using Content.Shared.Bed.Sleep;
 using Content.Shared.Buckle.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Mobs.Systems;
 
 namespace Content.Server.Bed
index 2aabb5eb27070fa7e95556503ac4f5adeb47386d..eb11a465bd6325fba71e345ec4af43a3df45eab1 100644 (file)
@@ -4,7 +4,7 @@ using Content.Server.Popups;
 using Content.Shared.ActionBlocker;
 using Content.Shared.Actions;
 using Content.Shared.Bible;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Ghost.Roles.Components;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction;
@@ -14,7 +14,6 @@ using Content.Shared.Mobs.Systems;
 using Content.Shared.Popups;
 using Content.Shared.Timing;
 using Content.Shared.Verbs;
-using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Player;
 using Robust.Shared.Random;
@@ -133,9 +132,7 @@ namespace Content.Server.Bible
                 }
             }
 
-            var damage = _damageableSystem.TryChangeDamage(args.Target.Value, component.Damage, true, origin: uid);
-
-            if (damage == null || damage.Empty)
+            if (_damageableSystem.TryChangeDamage(args.Target.Value, component.Damage, true, origin: uid))
             {
                 var othersMessage = Loc.GetString(component.LocPrefix + "-heal-success-none-others", ("user", Identity.Entity(args.User, EntityManager)), ("target", Identity.Entity(args.Target.Value, EntityManager)), ("bible", uid));
                 _popupSystem.PopupEntity(othersMessage, args.User, Filter.PvsExcept(args.User), true, PopupType.Medium);
index ca3ee2c9e16946cfa6f737c6067dbbe1f0b64ac2..79457cb0368c93e9a30412b2e934cbdea8b64d11 100644 (file)
@@ -12,7 +12,7 @@ using Content.Shared.Chat;
 using Content.Shared.Chemistry.Components;
 using Content.Shared.Chemistry.EntitySystems;
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.EntityConditions;
 using Content.Shared.EntityConditions.Conditions.Body;
@@ -367,7 +367,7 @@ public sealed class RespiratorSystem : EntitySystem
         if (ent.Comp.SuffocationCycles == 2)
             _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} started suffocating");
 
-        _damageableSys.TryChangeDamage(ent, ent.Comp.Damage, interruptsDoAfters: false);
+        _damageableSys.ChangeDamage(ent.Owner, ent.Comp.Damage, interruptsDoAfters: false);
 
         if (ent.Comp.SuffocationCycles < ent.Comp.SuffocationCycleThreshold)
             return;
@@ -381,7 +381,7 @@ public sealed class RespiratorSystem : EntitySystem
         if (ent.Comp.SuffocationCycles >= 2)
             _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} stopped suffocating");
 
-        _damageableSys.TryChangeDamage(ent, ent.Comp.DamageRecovery);
+        _damageableSys.ChangeDamage(ent.Owner, ent.Comp.DamageRecovery);
 
         var ev = new StopSuffocatingEvent();
         RaiseLocalEvent(ent, ref ev);
index 836dc485d9225a9d26af383270eb6549268883cd..9fdd23e78044a17b20548112a999f7b38ec04fd9 100644 (file)
@@ -1,20 +1,16 @@
-using Content.Server.Storage.Components;
 using Content.Server.Storage.EntitySystems;
 using Content.Shared.Access.Components;
 using Content.Shared.CardboardBox;
 using Content.Shared.CardboardBox.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Interaction;
 using Content.Shared.Movement.Components;
 using Content.Shared.Movement.Systems;
 using Content.Shared.Stealth;
 using Content.Shared.Stealth.Components;
 using Content.Shared.Storage.Components;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Containers;
-using Robust.Shared.Player;
 using Robust.Shared.Timing;
 
 namespace Content.Server.CardboardBox;
@@ -109,10 +105,10 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
     //Relay damage to the mover
     private void OnDamage(EntityUid uid, CardboardBoxComponent component, DamageChangedEvent args)
     {
-        if (args.DamageDelta != null && args.DamageIncreased)
-        {
-            _damageable.TryChangeDamage(component.Mover, args.DamageDelta, origin: args.Origin);
-        }
+        if (args.DamageDelta == null || !args.DamageIncreased || component.Mover is not { } mover)
+            return;
+
+        _damageable.ChangeDamage(mover, args.DamageDelta, origin: args.Origin);
     }
 
     private void OnEntInserted(EntityUid uid, CardboardBoxComponent component, EntInsertedIntoContainerMessage args)
index dca2959f98ec68e7b9b0b73e545f9d392b4914e2..9f901b2ad8f72f18caf8ad4fca372bb46b8be990 100644 (file)
@@ -2,7 +2,7 @@ using Content.Server.Ghost;
 using Content.Server.Hands.Systems;
 using Content.Shared.Administration.Logs;
 using Content.Shared.Chat;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Database;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction.Events;
index 4afb885c4ce6c5614f06694f0bb7c7da0084bad5..2b2be1e8699a6a16cb4920c2638fade708416899 100644 (file)
@@ -1,3 +1,5 @@
+using Content.Shared.Damage.Systems;
+
 namespace Content.Server.Chat.Systems;
 
 using Content.Shared.Chat;
index f413a1863f01c61297175c926c28a7dbaa72ad16..2f113bee5795d26dfbe44527d7a669abe3d441a3 100644 (file)
@@ -12,7 +12,7 @@ using Content.Shared.CCVar;
 using Content.Shared.Chemistry.Components;
 using Content.Shared.Cloning;
 using Content.Shared.Chat;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.DeviceLinking.Events;
 using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
index ab13548e0448212367548509d4203e01c30aed8d..97d7005279c4286a4f0268fe23b620c4c6f8690b 100644 (file)
@@ -8,7 +8,7 @@ using Content.Shared.Chat;
 using Content.Shared.Chat.Prototypes;
 using Content.Shared.Clumsy;
 using Content.Shared.Cluwne;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Mobs;
 using Content.Shared.NameModifier.EntitySystems;
 using Content.Shared.Popups;
index 980f6a49ca44fe01ee55e95ed5c641938542a987..cef30db71fd038d59f234928e66c084bbb955477 100644 (file)
@@ -1,13 +1,8 @@
 using Content.Server.Destructible;
 using Content.Shared.Construction;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Examine;
 using Content.Shared.FixedPoint;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace Content.Server.Construction.Conditions;
 
index af9c1ee8fc3130eefe162c26034a59e848d5a24e..849f6e543e49e6cb47f478fcc1c2717465f7c977 100644 (file)
@@ -4,7 +4,7 @@ using Content.Server.Administration;
 using Content.Shared.Administration;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Prototypes;
-using Content.Shared.FixedPoint;
+using Content.Shared.Damage.Systems;
 using Robust.Shared.Console;
 using Robust.Shared.Prototypes;
 
index a46d42f3e3734cbaef275c26945f8dfaa683625d..5597c47fdb0bc75d99f9c4013a085d8e33c2e832 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Bed.Sleep;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Events;
 using Content.Shared.Damage.ForceSay;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Systems;
index f129a14f799cdc2b489174f6481aa7a4182c0cae..4b13106cc8cd1ab23d46f22deee13d701542c814 100644 (file)
@@ -1,8 +1,7 @@
 using Content.Server.Damage.Components;
-using Content.Shared.Damage;
-using Robust.Shared.Player;
 using Content.Shared.Weapons.Melee.Events;
 using System.Linq;
+using Content.Shared.Damage.Systems;
 
 namespace Content.Server.Damage.Systems;
 
index 3cf103e6eeec35b80f84a57fb8f7441b8c146279..8dede48deeb3329a82c20614cf234d41763f2077 100644 (file)
@@ -9,7 +9,7 @@ namespace Content.Server.Damage.Systems
     /// </summary>
     public sealed class DamageOnLandSystem : EntitySystem
     {
-        [Dependency] private readonly DamageableSystem _damageableSystem = default!;
+        [Dependency] private readonly Shared.Damage.Systems.DamageableSystem _damageableSystem = default!;
 
         public override void Initialize()
         {
index 8c0e0a13825c19d9312b6a0079beff062498adfe..88fe02510fc9b03dd3bc72129dc391f746f975bf 100644 (file)
@@ -11,7 +11,7 @@ namespace Content.Server.Damage.Systems
 {
     public sealed class DamageOnToolInteractSystem : EntitySystem
     {
-        [Dependency] private readonly DamageableSystem _damageableSystem = default!;
+        [Dependency] private readonly Shared.Damage.Systems.DamageableSystem _damageableSystem = default!;
         [Dependency] private readonly IAdminLogManager _adminLogger = default!;
         [Dependency] private readonly SharedToolSystem _toolSystem = default!;
 
@@ -35,22 +35,22 @@ namespace Content.Server.Damage.Systems
             && itemToggle.Activated
             && !welder.TankSafe)
             {
-                var dmg = _damageableSystem.TryChangeDamage(args.Target, weldingDamage, origin: args.User);
-
-                if (dmg != null)
+                if (_damageableSystem.TryChangeDamage(args.Target, weldingDamage, out var dmg, origin: args.User))
+                {
                     _adminLogger.Add(LogType.Damaged,
                         $"{ToPrettyString(args.User):user} used {ToPrettyString(args.Used):used} as a welder to deal {dmg.GetTotal():damage} damage to {ToPrettyString(args.Target):target}");
+                }
 
                 args.Handled = true;
             }
             else if (component.DefaultDamage is {} damage
                 && _toolSystem.HasQuality(args.Used, component.Tools))
             {
-                var dmg = _damageableSystem.TryChangeDamage(args.Target, damage, origin: args.User);
-
-                if (dmg != null)
+                if (_damageableSystem.TryChangeDamage(args.Target, damage, out var dmg, origin: args.User))
+                {
                     _adminLogger.Add(LogType.Damaged,
                         $"{ToPrettyString(args.User):user} used {ToPrettyString(args.Used):used} as a tool to deal {dmg.GetTotal():damage} damage to {ToPrettyString(args.Target):target}");
+                }
 
                 args.Handled = true;
             }
index 10930ca5c9e5c1f177838144be2debfeb1567bd6..02bc7334a6ccb64a256b670373fb050464289309 100644 (file)
@@ -17,7 +17,7 @@ public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem
 {
     [Dependency] private readonly IAdminLogManager _adminLogger = default!;
     [Dependency] private readonly GunSystem _guns = default!;
-    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly Shared.Damage.Systems.DamageableSystem _damageable = default!;
     [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!;
     [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
 
@@ -33,13 +33,13 @@ public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem
         if (TerminatingOrDeleted(args.Target))
             return;
 
-        var dmg = _damageable.TryChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
+        var dmg = _damageable.ChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
 
         // 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<MobStateComponent>(args.Target))
+        if (HasComp<MobStateComponent>(args.Target))
             _adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
 
-        if (dmg is { Empty: false })
+        if (!dmg.Empty)
         {
             _color.RaiseEffect(Color.Red, [args.Target], Filter.Pvs(args.Target, entityManager: EntityManager));
         }
index 8bdbf84147acb2f1a865c969793f92a7c3da7c09..25e7bc1644a420d71c448dc539b7a170eb2fb0ce 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Damage.Components;
 using Content.Server.Popups;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Robust.Shared.Player;
 using Robust.Shared.Random;
 
index b0dfae71b7fc69e2b0067e3f26dfadd1340ef431..a2a9f234f5fb705ebd0cc4310e9dc7ef5859ded6 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Server.Damage.Components;
 using Content.Server.Destructible;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Examine;
 using Content.Shared.Rounding;
 using Robust.Shared.Prototypes;
index ac5e3704fe87f1b4b886811c3a583d71f188dd2e..a00194c91106aa493a75f6eaeb5f587c56521ed8 100644 (file)
@@ -7,7 +7,7 @@ public sealed partial class DestructibleSystem
     /// <summary>
     /// Tests all triggers in a DestructibleComponent to see how expensive it is to query them.
     /// </summary>
-    public void TestAllTriggers(List<Entity<DamageableComponent, DestructibleComponent>> destructibles)
+    public void TestAllTriggers(List<Entity<Shared.Damage.Components.DamageableComponent, DestructibleComponent>> destructibles)
     {
         foreach (var (uid, damageable, destructible) in destructibles)
         {
@@ -22,7 +22,7 @@ public sealed partial class DestructibleSystem
     /// <summary>
     /// Tests all behaviours in a DestructibleComponent to see how expensive it is to query them.
     /// </summary>
-    public void TestAllBehaviors(List<Entity<DamageableComponent, DestructibleComponent>> destructibles)
+    public void TestAllBehaviors(List<Entity<Shared.Damage.Components.DamageableComponent, DestructibleComponent>> destructibles)
     {
        foreach (var (uid, damageable, destructible) in destructibles)
        {
index 847229278c3645dd713cdbcdb56c206d45b9c2bd..7ed736fffd66e919861b0d3471b6001f5923d2e7 100644 (file)
@@ -11,6 +11,7 @@ using Content.Server.Fluids.EntitySystems;
 using Content.Server.Stack;
 using Content.Shared.Chemistry.EntitySystems;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Destructible;
 using Content.Shared.Destructible.Thresholds.Triggers;
@@ -111,7 +112,7 @@ namespace Content.Server.Destructible
         /// <summary>
         /// Check if the given threshold should trigger.
         /// </summary>
-        public bool Triggered(DamageThreshold threshold, Entity<DamageableComponent> owner)
+        public bool Triggered(DamageThreshold threshold, Entity<Shared.Damage.Components.DamageableComponent> owner)
         {
             if (threshold.Trigger == null)
                 return false;
@@ -135,7 +136,7 @@ namespace Content.Server.Destructible
         /// <summary>
         /// Check if the conditions for the given threshold are currently true.
         /// </summary>
-        public bool Reached(DamageThreshold threshold, Entity<DamageableComponent> owner)
+        public bool Reached(DamageThreshold threshold, Entity<Shared.Damage.Components.DamageableComponent> owner)
         {
             if (threshold.Trigger == null)
                 return false;
index d307488110ebc3a8700cc02f2902ccb113fc9ed8..73365c4f62e4e47afb51778f533c5b2307ba2aac 100644 (file)
@@ -1,7 +1,7 @@
 using Content.Server.Atmos.EntitySystems;
 using Content.Server.Disposal.Tube;
 using Content.Shared.Body.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Disposal.Components;
 using Content.Shared.Item;
 using Content.Shared.Throwing;
index 9cab018fd79935eaaf4efe9eafdefa11147c16f1..842b27ec862cb6d7f9a74eeca943141ce43a0de2 100644 (file)
@@ -2,16 +2,14 @@ using Content.Server.Chat.Systems;
 using Content.Server.NPC;
 using Content.Server.NPC.Systems;
 using Content.Server.Pinpointer;
-using Content.Shared.Damage;
 using Content.Shared.Dragon;
 using Content.Shared.Examine;
 using Content.Shared.Sprite;
-using Robust.Shared.GameObjects;
 using Robust.Shared.Map;
 using Robust.Shared.Player;
 using Robust.Shared.Serialization.Manager;
 using System.Numerics;
-using Robust.Shared.Audio;
+using Content.Shared.Damage.Components;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.GameStates;
 using Robust.Shared.Utility;
index a162b29e19678bd5776c6b8f2003c91e9fc215bc..fe9fe445713ae4a81e1813cd68fad5ecd15f53f2 100644 (file)
@@ -1,14 +1,12 @@
 using Content.Server.Administration.Logs;
-using Content.Server.NodeContainer;
 using Content.Server.NodeContainer.EntitySystems;
-using Content.Server.NodeContainer.NodeGroups;
-using Content.Server.NodeContainer.Nodes;
 using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Server.Power.NodeGroups;
 using Content.Server.Weapons.Melee;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Electrocution;
 using Content.Shared.IdentityManagement;
@@ -27,7 +25,6 @@ using Content.Shared.Tag;
 using Content.Shared.Weapons.Melee.Events;
 using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
-using Robust.Shared.Map;
 using Robust.Shared.Physics.Events;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
@@ -402,19 +399,16 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
                 ? _stun.TryUpdateParalyzeDuration(uid, time * ParalyzeTimeMultiplier)
                 : _stun.TryAddParalyzeDuration(uid, time * ParalyzeTimeMultiplier);
         }
-            
+
 
         // TODO: Sparks here.
 
         if (shockDamage is { } dmg)
         {
-            var actual = _damageable.TryChangeDamage(uid,
-                new DamageSpecifier(_prototypeManager.Index(DamageType), dmg), origin: sourceUid);
-
-            if (actual != null)
+            if (_damageable.TryChangeDamage(uid, new DamageSpecifier(_prototypeManager.Index(DamageType), dmg), out var damage, origin: sourceUid))
             {
                 _adminLogger.Add(LogType.Electrocution,
-                    $"{ToPrettyString(uid):entity} received {actual.GetTotal():damage} powered electrocution damage{(sourceUid != null ? " from " + ToPrettyString(sourceUid.Value) : ""):source}");
+                    $"{ToPrettyString(uid):entity} received {damage:damage} powered electrocution damage{(sourceUid != null ? " from " + ToPrettyString(sourceUid.Value) : ""):source}");
             }
         }
 
index 3d55a7e8230659531c9cd1996df488f09c4b0a1b..303c4e8cab9859187354dabe482a13d76202fd1c 100644 (file)
@@ -1,9 +1,7 @@
 using Content.Server.Atmos.Components;
-using Content.Server.Destructible;
 using Content.Shared.Atmos;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Explosion;
-using Content.Shared.Explosion.EntitySystems;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Map.Components;
 
index 263fdabf98fc26d6436c6061aac4ff9dc6ce4097..c6528b0142f277ad8b3e20324a5466900bbf3fa4 100644 (file)
@@ -1,13 +1,10 @@
-using System.Linq;
 using System.Numerics;
-using Content.Server.Atmos.EntitySystems;
-using Content.Server.Explosion.Components;
 using Content.Shared.CCVar;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Database;
 using Content.Shared.Explosion;
 using Content.Shared.Explosion.Components;
-using Content.Shared.Explosion.EntitySystems;
 using Content.Shared.Maps;
 using Content.Shared.Physics;
 using Content.Shared.Projectiles;
@@ -17,7 +14,6 @@ using Robust.Shared.Map.Components;
 using Robust.Shared.Physics;
 using Robust.Shared.Physics.Components;
 using Robust.Shared.Physics.Dynamics;
-using Robust.Shared.Player;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
 using Robust.Shared.Utility;
@@ -439,28 +435,25 @@ public sealed partial class ExplosionSystem
         float? fireStacksOnIgnite,
         EntityUid? cause)
     {
-        if (originalDamage != null)
+        if (originalDamage is not null)
         {
             GetEntitiesToDamage(uid, originalDamage, id);
             foreach (var (entity, damage) in _toDamage)
             {
+                if (!_damageableQuery.TryComp(entity, out var damageable))
+                    continue;
+
+                // TODO EXPLOSIONS turn explosions into entities, and pass the the entity in as the damage origin.
+                _damageableSystem.TryChangeDamage((entity, damageable), damage, ignoreResistances: true, ignoreGlobalModifiers: true);
+
                 if (_actorQuery.HasComp(entity))
                 {
-                    // Log damage to player entities only, cause this will create a massive amount of log spam otherwise.
-                    if (cause != null)
-                    {
+                    // Log damage to player entities only; this will create a massive amount of log spam otherwise.
+                    if (cause is not null)
                         _adminLogger.Add(LogType.ExplosionHit, LogImpact.Medium, $"Explosion of {ToPrettyString(cause):actor} dealt {damage.GetTotal()} damage to {ToPrettyString(entity):subject}");
-                    }
                     else
-                    {
                         _adminLogger.Add(LogType.ExplosionHit, LogImpact.Medium, $"Explosion at {epicenter:epicenter} dealt {damage.GetTotal()} damage to {ToPrettyString(entity):subject}");
-                    }
-
                 }
-
-                // TODO EXPLOSIONS turn explosions into entities, and pass the the entity in as the damage origin.
-                _damageableSystem.TryChangeDamage(entity, damage, ignoreResistances: true, ignoreGlobalModifiers: true);
-
             }
         }
 
@@ -666,7 +659,7 @@ sealed class Explosion
     private readonly IEntityManager _entMan;
     private readonly ExplosionSystem _system;
     private readonly SharedMapSystem _mapSystem;
-    private readonly DamageableSystem _damageable;
+    private readonly Shared.Damage.Systems.DamageableSystem _damageable;
 
     public readonly EntityUid VisualEnt;
 
@@ -690,7 +683,7 @@ sealed class Explosion
         EntityUid visualEnt,
         EntityUid? cause,
         SharedMapSystem mapSystem,
-        DamageableSystem damageable)
+        Shared.Damage.Systems.DamageableSystem damageable)
     {
         VisualEnt = visualEnt;
         Cause = cause;
index 198db3eca135dabde73ad1005104d62e46f5ab57..70863d6f549de5b81ffd49df09128b0a19ae130b 100644 (file)
@@ -9,7 +9,8 @@ using Content.Server.NPC.Pathfinding;
 using Content.Shared.Atmos.Components;
 using Content.Shared.Camera;
 using Content.Shared.CCVar;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Explosion;
 using Content.Shared.Explosion.Components;
index 1a3c9031fe743ee9c6ea43c8ca754ec1bc0e232d..af1a433d1a30693b8466d4cc4695da5d2b84a7bc 100644 (file)
@@ -3,13 +3,14 @@ using System.Numerics;
 using Content.Server.Administration.Logs;
 using Content.Server.Chat.Managers;
 using Content.Server.GameTicking;
-using Content.Server.Ghost.Components;
 using Content.Server.Mind;
 using Content.Server.Roles.Jobs;
 using Content.Shared.Actions;
 using Content.Shared.CCVar;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Examine;
 using Content.Shared.Eye;
@@ -586,7 +587,7 @@ namespace Content.Server.Ghost
 
                     DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage);
 
-                    _damageable.TryChangeDamage(playerEntity, damage, true);
+                    _damageable.ChangeDamage(playerEntity.Value, damage, true);
                 }
             }
 
index ea1a6f4f4ff63bb874ddff2b29f312be292d88fc..5f2597afef33a4811d21d93d53948cfaf2fd52de 100644 (file)
@@ -1,7 +1,7 @@
 using Content.Server.Body.Systems;
 using Content.Server.Popups;
 using Content.Shared.Actions;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
 using Content.Shared.Examine;
 using Content.Shared.Guardian;
@@ -285,8 +285,8 @@ namespace Content.Server.Guardian
             if (args.DamageDelta == null || component.Host == null || component.DamageShare == 0)
                 return;
 
-            _damageSystem.TryChangeDamage(
-                component.Host,
+            _damageSystem.ChangeDamage(
+                component.Host.Value,
                 args.DamageDelta * component.DamageShare,
                 origin: args.Origin,
                 ignoreResistances: true,
index bcbcfda9af0019c08bea72a865c8b038f64087ff..646b5c97bbdb4d294c2215a12b96369544e0d156 100644 (file)
@@ -1,10 +1,9 @@
 using Content.Server.Body.Systems;
 using Content.Server.Destructible;
-using Content.Server.Examine;
 using Content.Server.Polymorph.Components;
 using Content.Server.Popups;
 using Content.Shared.Body.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Popups;
 using Robust.Shared.Audio.Systems;
index ba27ea5d9e5a0d1e415c5056d32096191984a3c7..d40e0e13dd959700474b9cdddfc8e6007e3d587e 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Server.NPC.HTN;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Systems;
index e23bea7bb42d5064c8f8fbad82e88d416413105c..1c6ed26d48817417b1bdd4ef585ff1ac5d1c9f42 100644 (file)
@@ -7,7 +7,6 @@ using Content.Server.Hands.Systems;
 using Content.Server.Kitchen.Components;
 using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
-using Content.Server.Temperature.Components;
 using Content.Server.Temperature.Systems;
 using Content.Shared.Body.Components;
 using Content.Shared.Body.Part;
@@ -40,9 +39,8 @@ using Robust.Shared.Timing;
 using Content.Shared.Stacks;
 using Content.Server.Construction.Components;
 using Content.Shared.Chat;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Temperature.Components;
-using Robust.Shared.Utility;
 
 namespace Content.Server.Kitchen.EntitySystems
 {
index 4a0ee23c5b70e50cd0f0967ca54f8821866e2970..eac23c3016394a9546d9427296939213d58df3fd 100644 (file)
@@ -2,6 +2,7 @@ using Content.Server.Explosion.EntitySystems;
 using Content.Server.Lightning;
 using Content.Server.Lightning.Components;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Robust.Server.GameObjects;
 
 namespace Content.Server.Tesla.EntitySystems;
@@ -26,7 +27,7 @@ public sealed class LightningTargetSystem : EntitySystem
     {
         DamageSpecifier damage = new();
         damage.DamageDict.Add("Structural", uid.Comp.DamageFromLightning);
-        _damageable.TryChangeDamage(uid, damage, true);
+        _damageable.ChangeDamage(uid.Owner, damage, true);
 
         if (uid.Comp.LightningExplode)
         {
index 917f4f5035ab2eceae60876e27778cf1e2206cbd..923c7018688c6bc34ee4356e7d4aa59439c331e0 100644 (file)
@@ -4,7 +4,7 @@ using Content.Server.Body.Systems;
 using Content.Server.Mech.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Shared.ActionBlocker;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
 using Content.Shared.FixedPoint;
 using Content.Shared.Interaction;
@@ -265,7 +265,7 @@ public sealed partial class MechSystem : SharedMechSystem
             component.PilotSlot.ContainedEntity != null)
         {
             var damage = args.DamageDelta * component.MechToPilotDamageMultiplier;
-            _damageable.TryChangeDamage(component.PilotSlot.ContainedEntity, damage);
+            _damageable.ChangeDamage(component.PilotSlot.ContainedEntity.Value, damage);
         }
     }
 
index 1578f11629827912f0a4e00106f7f8c7af2a697b..f0dfceb14e1e6542fca555bc08dc3d89e4dee8ae 100644 (file)
@@ -8,7 +8,8 @@ using Content.Server.Popups;
 using Content.Server.PowerCell;
 using Content.Shared.Traits.Assorted;
 using Content.Shared.Chat;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
 using Content.Shared.Interaction;
 using Content.Shared.Item.ItemToggle;
index 657ac3e636bc2340f18abe12f9f07b887d401ae1..f022dff5e352ccb76cd4fd9de47b9c3854e07f66 100644 (file)
@@ -2,7 +2,7 @@ using Content.Server.Medical.Components;
 using Content.Server.PowerCell;
 using Content.Shared.Body.Components;
 using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.DoAfter;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction;
index 3b0c6920b3b68a510af8e90b908bddfd6a1f5a58..361844ba2518ee51aaf03af0b2f54af8ce162fe7 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Administration.Logs;
 using Content.Server.Destructible;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs.Systems;
index f351d582c6eede65147c4f741b988c592c16febb..67a8198c385f2d570d68224ba45711fe1e3b5a7e 100644 (file)
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
 using Content.Shared.NPC.Components;
 using Content.Server.NPC.Pathfinding;
 using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Interaction;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Silicons.Bots;
index d6b2000f329513bd44854d09c71c26ec955e7b8f..a970d34bda627bdf2b87242fb73ed01dc3c7b767 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.NPC.Components;
 using Content.Shared.CombatMode;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Mobs.Components;
 using Content.Shared.NPC.Components;
 using Content.Shared.NPC.Systems;
index bc82e72692b9587e5dfbec8dbce171b28aa0baea..9605b6284746304f3e11003428b4e3282a357da5 100644 (file)
@@ -6,7 +6,6 @@ using Content.Server.NPC.Queries.Curves;
 using Content.Server.NPC.Queries.Queries;
 using Content.Server.Nutrition.Components;
 using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.Damage;
 using Content.Shared.Examine;
 using Content.Shared.Fluids.Components;
 using Content.Shared.Inventory;
@@ -29,6 +28,7 @@ using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
 using Content.Shared.Atmos.Components;
 using System.Linq;
+using Content.Shared.Damage.Components;
 using Content.Shared.Temperature.Components;
 
 namespace Content.Server.NPC.Systems;
index 8697692e5eb2afe1199546fa2453954d9d08e744..98df8a039a04b2948322dba71c62ee51fd206cf0 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Server.Ninja.Events;
 using Content.Server.Power.EntitySystems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Interaction;
 using Content.Shared.Ninja.Components;
 using Content.Shared.Ninja.Systems;
@@ -9,8 +9,6 @@ using Content.Shared.Stunnable;
 using Content.Shared.Timing;
 using Content.Shared.Whitelist;
 using Robust.Shared.Audio.Systems;
-using Robust.Shared.Timing;
-using Robust.Shared.Prototypes;
 
 namespace Content.Server.Ninja.Systems;
 
@@ -62,7 +60,7 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
 
         _audio.PlayPvs(comp.Sound, target);
 
-        _damageable.TryChangeDamage(target, comp.StunDamage, false, true, null, origin: uid);
+        _damageable.ChangeDamage(target, comp.StunDamage, origin: uid);
         _stun.TryAddParalyzeDuration(target, comp.StunTime);
 
         // short cooldown to prevent instant stunlocking
index 6905979a5faca699af4839c145fae9bb5d59d59b..871a15ee73c4ab370c140d8298ddcca617dd48a2 100644 (file)
@@ -4,7 +4,7 @@ using Content.Server.Nutrition.Components;
 using Content.Server.Popups;
 using Content.Shared.Body.Components;
 using Content.Shared.Atmos;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
 using Content.Shared.Emag.Systems;
 using Content.Shared.IdentityManagement;
index db7fb6a92f3c833b820669b7bd32b44f766c62ab..897ad720471fe68657c8c6f271e912a290fdc729 100644 (file)
@@ -4,7 +4,8 @@ using Content.Server.Inventory;
 using Content.Server.Polymorph.Components;
 using Content.Shared.Buckle;
 using Content.Shared.Coordinates;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Destructible;
 using Content.Shared.Hands.EntitySystems;
 using Content.Shared.IdentityManagement;
@@ -228,7 +229,7 @@ public sealed partial class PolymorphSystem : EntitySystem
             _mobThreshold.GetScaledDamage(uid, child, out var damage) &&
             damage != null)
         {
-            _damageable.SetDamage(child, damageParent, damage);
+            _damageable.SetDamage((child, damageParent), damage);
         }
 
         if (configuration.Inventory == PolymorphInventoryChange.Transfer)
@@ -323,7 +324,7 @@ public sealed partial class PolymorphSystem : EntitySystem
             _mobThreshold.GetScaledDamage(uid, parent, out var damage) &&
             damage != null)
         {
-            _damageable.SetDamage(parent, damageParent, damage);
+            _damageable.SetDamage((parent, damageParent), damage);
         }
 
         if (component.Configuration.Inventory == PolymorphInventoryChange.Transfer)
index 4c054a456129d5ce35a5a5845a90da482383cab9..28df1eb42dd62e3bfdcc95d88fafce68ba87d539 100644 (file)
@@ -3,7 +3,8 @@ using Content.Server.Destructible;
 using Content.Server.Effects;
 using Content.Server.Weapons.Ranged.Systems;
 using Content.Shared.Camera;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.FixedPoint;
 using Content.Shared.Projectiles;
@@ -54,64 +55,63 @@ public sealed class ProjectileSystem : SharedProjectileSystem
             damageRequired -= damageableComponent.TotalDamage;
             damageRequired = FixedPoint2.Max(damageRequired, FixedPoint2.Zero);
         }
-        var modifiedDamage = _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances, damageable: damageableComponent, origin: component.Shooter);
         var deleted = Deleted(target);
 
-        if (modifiedDamage is not null && Exists(component.Shooter))
+        if (_damageableSystem.TryChangeDamage((target, damageableComponent), ev.Damage, out var damage, component.IgnoreResistances, origin: component.Shooter) && Exists(component.Shooter))
         {
-            if (modifiedDamage.AnyPositive() && !deleted)
+            if (!deleted)
             {
                 _color.RaiseEffect(Color.Red, new List<EntityUid> { target }, Filter.Pvs(target, entityManager: EntityManager));
             }
 
             _adminLogger.Add(LogType.BulletHit,
                 LogImpact.Medium,
-                $"Projectile {ToPrettyString(uid):projectile} shot by {ToPrettyString(component.Shooter!.Value):user} hit {otherName:target} and dealt {modifiedDamage.GetTotal():damage} damage");
-        }
+                $"Projectile {ToPrettyString(uid):projectile} shot by {ToPrettyString(component.Shooter!.Value):user} hit {otherName:target} and dealt {damage:damage} damage");
 
-        // If penetration is to be considered, we need to do some checks to see if the projectile should stop.
-        if (modifiedDamage is not null && component.PenetrationThreshold != 0)
-        {
-            // If a damage type is required, stop the bullet if the hit entity doesn't have that type.
-            if (component.PenetrationDamageTypeRequirement != null)
+            // If penetration is to be considered, we need to do some checks to see if the projectile should stop.
+            if (component.PenetrationThreshold != 0)
             {
-                var stopPenetration = false;
-                foreach (var requiredDamageType in component.PenetrationDamageTypeRequirement)
+                // If a damage type is required, stop the bullet if the hit entity doesn't have that type.
+                if (component.PenetrationDamageTypeRequirement != null)
                 {
-                    if (!modifiedDamage.DamageDict.Keys.Contains(requiredDamageType))
+                    var stopPenetration = false;
+                    foreach (var requiredDamageType in component.PenetrationDamageTypeRequirement)
                     {
-                        stopPenetration = true;
-                        break;
+                        if (!damage.DamageDict.Keys.Contains(requiredDamageType))
+                        {
+                            stopPenetration = true;
+                            break;
+                        }
                     }
+                    if (stopPenetration)
+                        component.ProjectileSpent = true;
                 }
-                if (stopPenetration)
-                    component.ProjectileSpent = true;
-            }
-
-            // If the object won't be destroyed, it "tanks" the penetration hit.
-            if (modifiedDamage.GetTotal() < damageRequired)
-            {
-                component.ProjectileSpent = true;
-            }
 
-            if (!component.ProjectileSpent)
-            {
-                component.PenetrationAmount += damageRequired;
-                // The projectile has dealt enough damage to be spent.
-                if (component.PenetrationAmount >= component.PenetrationThreshold)
+                // If the object won't be destroyed, it "tanks" the penetration hit.
+                if (damage.GetTotal() < damageRequired)
                 {
                     component.ProjectileSpent = true;
                 }
+
+                if (!component.ProjectileSpent)
+                {
+                    component.PenetrationAmount += damageRequired;
+                    // The projectile has dealt enough damage to be spent.
+                    if (component.PenetrationAmount >= component.PenetrationThreshold)
+                    {
+                        component.ProjectileSpent = true;
+                    }
+                }
+            }
+            else
+            {
+                component.ProjectileSpent = true;
             }
-        }
-        else
-        {
-            component.ProjectileSpent = true;
         }
 
         if (!deleted)
         {
-            _guns.PlayImpactSound(target, modifiedDamage, component.SoundHit, component.ForceSound);
+            _guns.PlayImpactSound(target, damage, component.SoundHit, component.ForceSound);
 
             if (!args.OurBody.LinearVelocity.IsLengthZero())
                 _sharedCameraRecoil.KickCamera(target, args.OurBody.LinearVelocity.Normalized());
index 38c3480078eaa20ef7e2f7af7ffe715bf72acbbe..8089cba61b15f47f678be1a69a4f965f9096f810 100644 (file)
@@ -213,7 +213,7 @@ public sealed partial class RevenantSystem
             return;
         DamageSpecifier dspec = new();
         dspec.DamageDict.Add("Cold", damage.Value);
-        _damage.TryChangeDamage(args.Args.Target, dspec, true, origin: uid);
+        _damage.ChangeDamage(args.Args.Target.Value, dspec, true, origin: uid);
 
         args.Handled = true;
     }
index 6c8972be58d7919ef5b5b2bf1a3a33c52b78671e..34966d9c223711ea1cd4ca2d31a1094ac8a96f82 100644 (file)
@@ -3,7 +3,7 @@ using Content.Server.Actions;
 using Content.Server.GameTicking;
 using Content.Server.Store.Systems;
 using Content.Shared.Alert;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
 using Content.Shared.Examine;
 using Content.Shared.Eye;
index b5adeb04dbd5f473bcb45522cfe16faa8b8a9299..6126234451bc864216853a8f52cf75dce47250fa 100644 (file)
@@ -20,6 +20,7 @@ using Robust.Shared.Physics.Events;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 using System.Numerics;
+using Content.Shared.Damage.Components;
 
 namespace Content.Server.Shuttles.Systems;
 
@@ -372,7 +373,7 @@ public sealed partial class ShuttleSystem
                     damageSpec.DamageDict["Blunt"] = scaledDamage;
                     damageSpec.DamageDict["Structural"] = scaledDamage * _structuralDamage;
 
-                    _damageSys.TryChangeDamage(localEnt, damageSpec, damageable: damageable);
+                    _damageSys.ChangeDamage((localEnt, damageable), damageSpec);
                 }
                 // might've been destroyed
                 if (TerminatingOrDeleted(localEnt) || EntityManager.IsQueuedForDeletion(localEnt))
index e96ceffd16a06305cae7337f75c81ef199b31f47..86b97c40a61d2295da66815fd45467c4018d4b62 100644 (file)
@@ -8,7 +8,7 @@ using Content.Server.Shuttles.Events;
 using Content.Server.Station.Systems;
 using Content.Server.Stunnable;
 using Content.Shared.Buckle.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Light.Components;
 using Content.Shared.Movement.Events;
 using Content.Shared.Salvage;
index f7f0a8b25112fbfa59351bda65f986dbb6433c17..20040ab40a239457efc70410c6820e87f6e40e80 100644 (file)
@@ -1,16 +1,14 @@
 using System.Numerics;
 using Content.Server.Audio;
-using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Server.Shuttles.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Interaction;
 using Content.Shared.Maps;
 using Content.Shared.Physics;
 using Content.Shared.Shuttles.Components;
 using Content.Shared.Temperature;
-using Robust.Shared.Map;
 using Robust.Shared.Map.Components;
 using Robust.Shared.Physics.Collision.Shapes;
 using Robust.Shared.Physics.Components;
index 082e6776f081edff6b797bfd9d9b8e25aa7a186d..fd3b910753d40f3b7774363768e41ba80b9cbb74 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Shared.Containers.ItemSlots;
 using Content.Shared.DeviceNetwork;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Systems;
index 4ee2a07d72b6dc27dcab3ab843008fa6f0f46a24..a9198d5816f5ad7d34a7fdbb23191c45e2ecba66 100644 (file)
@@ -12,7 +12,8 @@ using Content.Server.Station.Systems;
 using Content.Shared.Alert;
 using Content.Shared.Chat.Prototypes;
 using Content.Shared.Containers.ItemSlots;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Destructible;
 using Content.Shared.DeviceNetwork.Components;
 using Content.Shared.DoAfter;
@@ -127,10 +128,7 @@ public sealed class StationAiSystem : SharedStationAiSystem
             _battery.SetCharge(ent, battery.MaxCharge);
         }
 
-        if (TryComp<DamageableComponent>(ent, out var damageable))
-        {
-            _damageable.SetAllDamage(ent, damageable, 0);
-        }
+        _damageable.ClearAllDamage(ent.Owner);
     }
 
     protected override void OnAiInsert(Entity<StationAiCoreComponent> ent, ref EntInsertedIntoContainerMessage args)
index d4a37a07cd61241e3b5c54ada52be91e5f464b32..a5e30346bd2a1a13b5b11b735e175ca98e6c10c8 100644 (file)
@@ -2,7 +2,7 @@
 using Content.Server.Destructible;
 using Content.Server.PowerCell;
 using Content.Shared.Speech.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Content.Shared.Speech;
 using Robust.Shared.Random;
index fbc809c15b7c93708f09c54c3b7602e954c52c9b..e8470ebd57caa3c9a7f161d5df37169c68928812 100644 (file)
@@ -1,4 +1,5 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Spreader;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
index f6a7536994defdab2cdef52b47d3a9d18d590d89..3bbde482c485ecc6fe4d8bd62e96ebf2504e00e4 100644 (file)
@@ -5,7 +5,8 @@ using Content.Server.Body.Components;
 using Content.Server.Temperature.Components;
 using Content.Shared.Alert;
 using Content.Shared.Atmos;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Inventory;
 using Content.Shared.Rejuvenate;
index 86a7b512b6c26f5840ebdd816483759e4a11270e..1fb695ae6199bd636f696d704a3401d84de6ebee 100644 (file)
@@ -5,6 +5,7 @@ using Content.Server.Power.Components;
 using Content.Server.Vocalization.Systems;
 using Content.Shared.Cargo;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Destructible;
 using Content.Shared.Emp;
 using Content.Shared.Power;
index 47b0d5f3c6fea6da5f5b2bac8a095fdc6684292b..995e29727bb7149ec987f8370f6147434a67f382 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Weapons.Ranged.Components;
 using Robust.Shared.Map;
 
index c44c2e7aa00bda4b7d3aed9b9472770ebbdf2f00..43a06f2614ed840fd8cae7ab1cd78d78fa887e24 100644 (file)
@@ -14,10 +14,9 @@ using Content.Server.NPC.Systems;
 using Content.Server.StationEvents.Components;
 using Content.Server.Speech.Components;
 using Content.Shared.Body.Components;
-using Content.Shared.Chat;
 using Content.Shared.CombatMode;
 using Content.Shared.CombatMode.Pacification;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Hands.Components;
 using Content.Shared.Hands.EntitySystems;
 using Content.Shared.Humanoid;
@@ -248,8 +247,7 @@ public sealed partial class ZombieSystem
             tempComp.ColdDamage.ClampMax(0);
 
         //Heals the zombie from all the damage it took while human
-        if (TryComp<DamageableComponent>(target, out var damageablecomp))
-            _damageable.SetAllDamage(target, damageablecomp, 0);
+        _damageable.ClearAllDamage(target);
         _mobState.ChangeMobState(target, MobState.Alive);
 
         _faction.ClearFactions(target, dirty: false);
index d4f86fa96cb4e7dcb76f36ff17892ba6ca0cbda9..72c52369303fc3291f5f1b51f0496aedfbe9c793 100644 (file)
@@ -1,4 +1,3 @@
-using System.Linq;
 using Content.Shared.NPC.Prototypes;
 using Content.Server.Actions;
 using Content.Server.Body.Systems;
@@ -11,7 +10,7 @@ using Content.Shared.Armor;
 using Content.Shared.Bed.Sleep;
 using Content.Shared.Cloning.Events;
 using Content.Shared.Chat;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Humanoid;
 using Content.Shared.Inventory;
 using Content.Shared.Mind;
@@ -118,7 +117,7 @@ namespace Content.Server.Zombies
             var curTime = _timing.CurTime;
 
             // Hurt the living infected
-            var query = EntityQueryEnumerator<PendingZombieComponent, DamageableComponent, MobStateComponent>();
+            var query = EntityQueryEnumerator<PendingZombieComponent, Shared.Damage.Components.DamageableComponent, MobStateComponent>();
             while (query.MoveNext(out var uid, out var comp, out var damage, out var mobState))
             {
                 // Process only once per second
@@ -138,11 +137,11 @@ namespace Content.Server.Zombies
                     ? comp.CritDamageMultiplier
                     : 1f;
 
-                _damageable.TryChangeDamage(uid, comp.Damage * multiplier, true, false, damage);
+                _damageable.ChangeDamage((uid, damage), comp.Damage * multiplier, true, false);
             }
 
             // Heal the zombified
-            var zombQuery = EntityQueryEnumerator<ZombieComponent, DamageableComponent, MobStateComponent>();
+            var zombQuery = EntityQueryEnumerator<ZombieComponent, Shared.Damage.Components.DamageableComponent, MobStateComponent>();
             while (zombQuery.MoveNext(out var uid, out var comp, out var damage, out var mobState))
             {
                 // Process only once per second
@@ -159,7 +158,7 @@ namespace Content.Server.Zombies
                     : 1f;
 
                 // Gradual healing for living zombies.
-                _damageable.TryChangeDamage(uid, comp.PassiveHealing * multiplier, true, false, damage);
+                _damageable.ChangeDamage((uid, damage), comp.PassiveHealing * multiplier, true, false);
             }
         }
 
index 972289460fe95e4907130302130d5520e74d152c..6a3db3184dfc701cfd0b408828e1108c8b6dbf75 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Shared.Clothing.Components;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Inventory;
 using Content.Shared.Silicons.Borgs;
index 27e11bc8784f59b9fc889f683208af087994aab2..661c8399a1c8323804cb48cf3e0e3572b4d4117f 100644 (file)
@@ -4,6 +4,7 @@ using Content.Shared.Buckle.Components;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Events;
 using Content.Shared.Damage.ForceSay;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Emoting;
 using Content.Shared.Examine;
 using Content.Shared.Eye.Blinding.Systems;
index 2cd1db7f1fe13d6fc298d7a85664abfcacba1504..db59a8d5f6c85aea1fb10a69d379282d7d48a9d9 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Shared.Damage;
-using Content.Shared.Damage.Prototypes;
-using Robust.Shared.Audio;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Containers;
 
@@ -42,31 +42,31 @@ public sealed partial class BlockingSystem
 
     private void OnUserDamageModified(EntityUid uid, BlockingUserComponent component, DamageModifyEvent args)
     {
-        if (TryComp<BlockingComponent>(component.BlockingItem, out var blocking))
-        {
-            if (args.Damage.GetTotal() <= 0)
-                return;
+        if (component.BlockingItem is not { } item || !TryComp<BlockingComponent>(item, out var blocking))
+            return;
+
+        if (args.Damage.GetTotal() <= 0)
+            return;
 
-            // A shield should only block damage it can itself absorb. To determine that we need the Damageable component on it.
-            if (!TryComp<DamageableComponent>(component.BlockingItem, out var dmgComp))
-                return;
+        // A shield should only block damage it can itself absorb. To determine that we need the Damageable component on it.
+        if (!TryComp<DamageableComponent>(item, out var dmgComp))
+            return;
 
-            var blockFraction = blocking.IsBlocking ? blocking.ActiveBlockFraction : blocking.PassiveBlockFraction;
-            blockFraction = Math.Clamp(blockFraction, 0, 1);
-            _damageable.TryChangeDamage(component.BlockingItem, blockFraction * args.OriginalDamage);
+        var blockFraction = blocking.IsBlocking ? blocking.ActiveBlockFraction : blocking.PassiveBlockFraction;
+        blockFraction = Math.Clamp(blockFraction, 0, 1);
+        _damageable.TryChangeDamage((item, dmgComp), blockFraction * args.OriginalDamage);
 
-            var modify = new DamageModifierSet();
-            foreach (var key in dmgComp.Damage.DamageDict.Keys)
-            {
-                modify.Coefficients.TryAdd(key, 1 - blockFraction);
-            }
+        var modify = new DamageModifierSet();
+        foreach (var key in dmgComp.Damage.DamageDict.Keys)
+        {
+            modify.Coefficients.TryAdd(key, 1 - blockFraction);
+        }
 
-            args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modify);
+        args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modify);
 
-            if (blocking.IsBlocking && !args.Damage.Equals(args.OriginalDamage))
-            {
-                _audio.PlayPvs(blocking.BlockSound, uid);
-            }
+        if (blocking.IsBlocking && !args.Damage.Equals(args.OriginalDamage))
+        {
+            _audio.PlayPvs(blocking.BlockSound, uid);
         }
     }
 
index 693eede7d8388a76840e2c2b1f13342f809a1cb5..688e3ccb9266c5220b67357d2401d259502317a7 100644 (file)
@@ -6,8 +6,8 @@ using Content.Shared.Chemistry.EntitySystems;
 using Content.Shared.Chemistry.Reaction;
 using Content.Shared.Chemistry.Reagent;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.EntityEffects.Effects.Solution;
-using Content.Shared.EntityEffects.Effects.Transform;
 using Content.Shared.FixedPoint;
 using Content.Shared.Fluids;
 using Content.Shared.Forensics.Components;
@@ -99,8 +99,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem
                 // bloodloss damage is based on the base value, and modified by how low your blood level is.
                 var amt = bloodstream.BloodlossDamage / (0.1f + bloodPercentage);
 
-                _damageableSystem.TryChangeDamage(uid, amt,
-                    ignoreResistances: false, interruptsDoAfters: false);
+                _damageableSystem.TryChangeDamage(uid, amt, ignoreResistances: false, interruptsDoAfters: false);
 
                 // Apply dizziness as a symptom of bloodloss.
                 // The effect is applied in a way that it will never be cleared without being healthy.
index 78d270ddc9416ea621e23bf2ea53efa10f916cab..0b2efdce59f74d204c25fdefd1b3cad5eb6fd9b8 100644 (file)
@@ -181,7 +181,7 @@ public partial class SharedBodySystem
         {
             // TODO BODY SYSTEM KILL : remove this when wounding and required parts are implemented properly
             var damage = new DamageSpecifier(Prototypes.Index(BloodlossDamageType), 300);
-            Damageable.TryChangeDamage(bodyEnt, damage);
+            Damageable.ChangeDamage(bodyEnt.Owner, damage);
         }
     }
 
index a45966fcc375129bc59f4e28f74493308313a24e..f359ebc6324b6d1112527a7c661749e0446338e5 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Movement.Systems;
 using Content.Shared.Standing;
 using Robust.Shared.Containers;
index 500ee06b22d1d04d1be28a4cf5296a5d367211b6..a30387a807eacf0745a8bcbb9562fb302b140da0 100644 (file)
@@ -4,7 +4,8 @@ using Content.Shared.Armor;
 using Content.Shared.Atmos.Rotting;
 using Content.Shared.Body.Components;
 using Content.Shared.Changeling.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.DoAfter;
 using Content.Shared.Humanoid;
@@ -92,7 +93,7 @@ public sealed class ChangelingDevourSystem : EntitySystem
             if (damage.Damage.DamageDict.TryGetValue(damagePoints.Key, out var val) && val > comp.DevourConsumeDamageCap)
                 return;
         }
-        _damageable.TryChangeDamage(target, comp.DamagePerTick, true, true, damage, user);
+        _damageable.ChangeDamage((target.Value, damage), comp.DamagePerTick, true, true, user);
     }
 
     /// <summary>
index 4b9eaf24b7c4d2e579218be32c4b0b484c4d4887..0484e51ab26c8db84d73a5bbd94f361a329942d8 100644 (file)
@@ -1,8 +1,10 @@
+using System.Linq;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Mobs.Components;
 using Robust.Shared.Prototypes;
-using System.Linq;
 
 namespace Content.Shared.Chat;
 
@@ -40,7 +42,7 @@ public sealed class SharedSuicideSystem : EntitySystem
             appliedDamageSpecifier.DamageDict[key] = Math.Ceiling((double) (value * lethalAmountOfDamage / totalDamage));
         }
 
-        _damageableSystem.TryChangeDamage(target, appliedDamageSpecifier, true, origin: target);
+        _damageableSystem.ChangeDamage(target.AsNullable(), appliedDamageSpecifier, true, origin: target);
     }
 
     /// <summary>
@@ -64,6 +66,6 @@ public sealed class SharedSuicideSystem : EntitySystem
         }
 
         var damage = new DamageSpecifier(damagePrototype, lethalAmountOfDamage);
-        _damageableSystem.TryChangeDamage(target, damage, true, origin: target);
+        _damageableSystem.ChangeDamage(target.AsNullable(), damage, true, origin: target);
     }
 }
index 45055ebbccac172d6a4b71ff185ebf85e2a05837..9cc0a55ce1ccdcc56d271c7ae7b2fa28867be4ce 100644 (file)
@@ -2,7 +2,7 @@ using Content.Shared.ActionBlocker;
 using Content.Shared.Buckle.Components;
 using Content.Shared.Climbing.Components;
 using Content.Shared.Climbing.Events;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
 using Content.Shared.DragDrop;
 using Content.Shared.Hands.Components;
index 8ba83be151ce1c81749ed470367d26006622c0ba..359e8ef769b41c716790904bd465d8e044c6c412 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Shared.Clothing.Components;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Inventory;
 using Content.Shared.Movement.Systems;
index d7b4019eb8bbc45417c9a956a4e9c0c5d74e75a6..35866b155afd7a160125ef4d01d92c0c29b364a9 100644 (file)
@@ -2,7 +2,7 @@ using Content.Shared.CCVar;
 using Content.Shared.Chemistry.Hypospray.Events;
 using Content.Shared.Climbing.Components;
 using Content.Shared.Climbing.Events;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Medical;
 using Content.Shared.Popups;
@@ -95,7 +95,7 @@ public sealed class ClumsySystem : EntitySystem
         args.Cancelled = true; // fail to catch
 
         if (ent.Comp.CatchingFailDamage != null)
-            _damageable.TryChangeDamage(ent, ent.Comp.CatchingFailDamage, origin: args.Item);
+            _damageable.ChangeDamage(ent.Owner, ent.Comp.CatchingFailDamage, origin: args.Item);
 
         // Collisions don't work properly with PopupPredicted or PlayPredicted.
         // So we make this server only.
@@ -127,7 +127,7 @@ public sealed class ClumsySystem : EntitySystem
             return;
 
         if (ent.Comp.GunShootFailDamage != null)
-            _damageable.TryChangeDamage(ent, ent.Comp.GunShootFailDamage, origin: ent);
+            _damageable.ChangeDamage(ent.Owner, ent.Comp.GunShootFailDamage, origin: ent);
 
         _stun.TryUpdateParalyzeDuration(ent, ent.Comp.GunShootFailStunTime);
 
@@ -199,7 +199,7 @@ public sealed class ClumsySystem : EntitySystem
         {
             stunTime = bonkComp.BonkTime;
             if (bonkComp.BonkDamage != null)
-                _damageable.TryChangeDamage(target, bonkComp.BonkDamage, true);
+                _damageable.ChangeDamage(target.Owner, bonkComp.BonkDamage, true);
         }
 
         _stun.TryUpdateParalyzeDuration(target, stunTime);
index 3d4bdd597c304b44351da1235d518cf35c732622..faf8a1bb579fffb6f4e19ebd09a48558b65e1790 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Damage.Systems;
 using Robust.Shared.GameStates;
 
 namespace Content.Shared.Damage.Components;
index 1d290181ec5451df4d1c96c11a3bd0afecebbcef..cef27d4d2f11337231c1eccd3bee84eb57e0a34a 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs;
 using Content.Shared.StatusIcon;
@@ -6,105 +7,100 @@ using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
-namespace Content.Shared.Damage
+namespace Content.Shared.Damage.Components;
+
+/// <summary>
+///     Component that allows entities to take damage.
+/// </summary>
+/// <remarks>
+///     The supported damage types are specified using a <see cref="DamageContainerPrototype"/>s. DamageContainers
+///     may also have resistances to certain damage types, defined via a <see cref="DamageModifierSetPrototype"/>.
+/// </remarks>
+[RegisterComponent]
+[NetworkedComponent]
+[Access(typeof(DamageableSystem), Other = AccessPermissions.ReadExecute)]
+public sealed partial class DamageableComponent : Component
 {
     /// <summary>
-    ///     Component that allows entities to take damage.
+    ///     This <see cref="DamageContainerPrototype"/> specifies what damage types are supported by this component.
+    ///     If null, all damage types will be supported.
+    /// </summary>
+    [DataField("damageContainer")]
+    // ReSharper disable once InconsistentNaming - This is wrong but fixing it is potentially annoying for downstreams.
+    public ProtoId<DamageContainerPrototype>? DamageContainerID;
+
+    /// <summary>
+    ///     This <see cref="DamageModifierSetPrototype"/> will be applied to any damage that is dealt to this container,
+    ///     unless the damage explicitly ignores resistances.
     /// </summary>
     /// <remarks>
-    ///     The supported damage types are specified using a <see cref="DamageContainerPrototype"/>s. DamageContainers
-    ///     may also have resistances to certain damage types, defined via a <see cref="DamageModifierSetPrototype"/>.
+    ///     Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here
+    ///     to reduce duplication.
     /// </remarks>
-    [RegisterComponent]
-    [NetworkedComponent]
-    [Access(typeof(DamageableSystem), Other = AccessPermissions.ReadExecute)]
-    public sealed partial class DamageableComponent : Component
-    {
-        /// <summary>
-        ///     This <see cref="DamageContainerPrototype"/> specifies what damage types are supported by this component.
-        ///     If null, all damage types will be supported.
-        /// </summary>
-        [DataField("damageContainer")]
-        public ProtoId<DamageContainerPrototype>? DamageContainerID;
-
-        /// <summary>
-        ///     This <see cref="DamageModifierSetPrototype"/> will be applied to any damage that is dealt to this container,
-        ///     unless the damage explicitly ignores resistances.
-        /// </summary>
-        /// <remarks>
-        ///     Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here
-        ///     to reduce duplication.
-        /// </remarks>
-        [DataField("damageModifierSet")]
-        public ProtoId<DamageModifierSetPrototype>? DamageModifierSetId;
+    [DataField("damageModifierSet")]
+    public ProtoId<DamageModifierSetPrototype>? DamageModifierSetId;
 
-        /// <summary>
-        ///     All the damage information is stored in this <see cref="DamageSpecifier"/>.
-        /// </summary>
-        /// <remarks>
-        ///     If this data-field is specified, this allows damageable components to be initialized with non-zero damage.
-        /// </remarks>
-        [DataField(readOnly: true)] // TODO FULL GAME SAVE
-        public DamageSpecifier Damage = new();
-
-        /// <summary>
-        ///     Damage, indexed by <see cref="DamageGroupPrototype"/> ID keys.
-        /// </summary>
-        /// <remarks>
-        ///     Groups which have no members that are supported by this component will not be present in this
-        ///     dictionary.
-        /// </remarks>
-        [ViewVariables] public Dictionary<string, FixedPoint2> DamagePerGroup = new();
+    /// <summary>
+    ///     All the damage information is stored in this <see cref="DamageSpecifier"/>.
+    /// </summary>
+    /// <remarks>
+    ///     If this data-field is specified, this allows damageable components to be initialized with non-zero damage.
+    /// </remarks>
+    [DataField(readOnly: true)] //TODO FULL GAME SAVE
+    public DamageSpecifier Damage = new();
 
-        /// <summary>
-        ///     The sum of all damages in the DamageableComponent.
-        /// </summary>
-        [ViewVariables]
-        public FixedPoint2 TotalDamage;
+    /// <summary>
+    ///     Damage, indexed by <see cref="DamageGroupPrototype"/> ID keys.
+    /// </summary>
+    /// <remarks>
+    ///     Groups which have no members that are supported by this component will not be present in this
+    ///     dictionary.
+    /// </remarks>
+    [ViewVariables] public Dictionary<string, FixedPoint2> DamagePerGroup = new();
 
-        [DataField("radiationDamageTypes")]
-        public List<ProtoId<DamageTypePrototype>> RadiationDamageTypeIDs = new() { "Radiation" };
+    /// <summary>
+    ///     The sum of all damages in the DamageableComponent.
+    /// </summary>
+    [ViewVariables]
+    public FixedPoint2 TotalDamage;
 
-        /// <summary>
-        ///     Group types that affect the pain overlay.
-        /// </summary>
-        ///     TODO: Add support for adding damage types specifically rather than whole damage groups
-        [DataField]
-        public List<ProtoId<DamageGroupPrototype>> PainDamageGroups = new() { "Brute", "Burn" };
+    [DataField("radiationDamageTypes")]
+    // ReSharper disable once UseCollectionExpression - Cannot refactor this as it's a potential sandbox violation.
+    public List<ProtoId<DamageTypePrototype>> RadiationDamageTypeIDs = new() { "Radiation" };
 
-        [DataField]
-        public Dictionary<MobState, ProtoId<HealthIconPrototype>> HealthIcons = new()
-        {
-            { MobState.Alive, "HealthIconFine" },
-            { MobState.Critical, "HealthIconCritical" },
-            { MobState.Dead, "HealthIconDead" },
-        };
+    /// <summary>
+    ///     Group types that affect the pain overlay.
+    /// </summary>
+    ///     TODO: Add support for adding damage types specifically rather than whole damage groups
+    [DataField]
+    // ReSharper disable once UseCollectionExpression - Cannot refactor this as it's a potential sandbox volation.
+    public List<ProtoId<DamageGroupPrototype>> PainDamageGroups = new() { "Brute", "Burn" };
 
-        [DataField]
-        public ProtoId<HealthIconPrototype> RottingIcon = "HealthIconRotting";
+    [DataField]
+    public Dictionary<MobState, ProtoId<HealthIconPrototype>> HealthIcons = new()
+    {
+        { MobState.Alive, "HealthIconFine" },
+        { MobState.Critical, "HealthIconCritical" },
+        { MobState.Dead, "HealthIconDead" },
+    };
 
-        [DataField]
-        public FixedPoint2? HealthBarThreshold;
-    }
+    [DataField]
+    public ProtoId<HealthIconPrototype> RottingIcon = "HealthIconRotting";
 
-    [Serializable, NetSerializable]
-    public sealed class DamageableComponentState : ComponentState
-    {
-        public readonly Dictionary<string, FixedPoint2> DamageDict;
-        public readonly string? DamageContainerId;
-        public readonly string? ModifierSetId;
-        public readonly FixedPoint2? HealthBarThreshold;
+    [DataField]
+    public FixedPoint2? HealthBarThreshold;
+}
 
-        public DamageableComponentState(
-            Dictionary<string, FixedPoint2> damageDict,
-            string? damageContainerId,
-            string? modifierSetId,
-            FixedPoint2? healthBarThreshold)
-        {
-            DamageDict = damageDict;
-            DamageContainerId = damageContainerId;
-            ModifierSetId = modifierSetId;
-            HealthBarThreshold = healthBarThreshold;
-        }
-    }
+[Serializable, NetSerializable]
+public sealed class DamageableComponentState(
+    Dictionary<string, FixedPoint2> damageDict,
+    ProtoId<DamageContainerPrototype>? damageContainerId,
+    ProtoId<DamageModifierSetPrototype>? modifierSetId,
+    FixedPoint2? healthBarThreshold)
+    : ComponentState
+{
+    public readonly Dictionary<string, FixedPoint2> DamageDict = damageDict;
+    public readonly ProtoId<DamageContainerPrototype>? DamageContainerId = damageContainerId;
+    public readonly ProtoId<DamageModifierSetPrototype>? ModifierSetId = modifierSetId;
+    public readonly FixedPoint2? HealthBarThreshold = healthBarThreshold;
 }
index e933eb1a7905edb4e2ec36b00843e0f142a2b30f..101a494bc937c26afdff37a88ba9a44647a26e32 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Damage.Systems;
 using Robust.Shared.GameStates;
 
 namespace Content.Shared.Damage.Components;
index 5bd8292daae7942e704f829bb2e2a37a8a68a280..3c94dcbc38e11a0d4c64ab318947517194cb475e 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Damage.Systems;
 using Robust.Shared.GameStates;
 
 namespace Content.Shared.Damage.Components;
index eaa6e93da4c1f61a591c9abf2c336f886cffe837..d8b00ad1f2e6d750d4d51a6fa936854fae8c2cb0 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Robust.Shared.Serialization;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
index 7bf921baa2965ed062d5b20e1f23da11a0210af7..6c11f88b1e8cc10c1bedd3859137d03acf029dbb 100644 (file)
@@ -1,5 +1,6 @@
 using System.Linq;
 using System.Text.Json.Serialization;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Content.Shared.FixedPoint;
 using JetBrains.Annotations;
index 00322f0884a696c864e08fcadc521121bef3f0b9..1643a5469dbf4580130d7502ee85c853457bdfe0 100644 (file)
@@ -1,5 +1,5 @@
+using Content.Shared.Damage.Components;
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization;
 
 namespace Content.Shared.Damage.Prototypes
 {
index a33064f934e5d391e5f53c28e63ba3bbdbd0bf6f..facdcce0e8768647e4350d1aa5a3a7c571026210 100644 (file)
@@ -1,5 +1,5 @@
+using Content.Shared.Damage.Components;
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization;
 
 namespace Content.Shared.Damage.Prototypes
 {
index 29de43fba4a8f9c79c5e602348f3125c36988f1d..d628f40b764e6a3959cbc01ef8b20481e6a23394 100644 (file)
@@ -73,9 +73,9 @@ public sealed class DamageOnAttackedSystem : EntitySystem
             }
         }
 
-        totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, entity.Comp.IgnoreResistances, origin: entity);
+        totalDamage = _damageableSystem.ChangeDamage(args.User, totalDamage, entity.Comp.IgnoreResistances, origin: entity);
 
-        if (totalDamage != null && totalDamage.AnyPositive())
+        if (totalDamage.AnyPositive())
         {
             _adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} injured themselves by attacking {ToPrettyString(entity):target} and received {totalDamage.GetTotal():damage} damage");
             _audioSystem.PlayPredicted(entity.Comp.InteractSound, entity, args.User);
index bd3b6979f70056de8c973be0608a95baa5f6434a..401c94f33ecf6f7ccf29a30e6e99ff9175d0b76d 100644 (file)
@@ -65,7 +65,7 @@ public sealed class DamageOnInteractSystem : EntitySystem
             // or checking the entity for  the comp itself if the inventory didn't work
             if (protectiveEntity.Comp == null && TryComp<DamageOnInteractProtectionComponent>(args.User, out var protectiveComp))
                 protectiveEntity = (args.User, protectiveComp);
-            
+
 
             // if protectiveComp isn't null after all that, it means the user has protection,
             // so let's calculate how much they resist
@@ -75,9 +75,9 @@ public sealed class DamageOnInteractSystem : EntitySystem
             }
         }
 
-        totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, origin: args.Target);
+        totalDamage = _damageableSystem.ChangeDamage(args.User, totalDamage, origin: args.Target);
 
-        if (totalDamage != null && totalDamage.AnyPositive())
+        if (totalDamage.AnyPositive())
         {
             // Record this interaction and determine when a user is allowed to interact with this entity again
             entity.Comp.LastInteraction = _gameTiming.CurTime;
diff --git a/Content.Shared/Damage/Systems/DamageableSystem.API.cs b/Content.Shared/Damage/Systems/DamageableSystem.API.cs
new file mode 100644 (file)
index 0000000..c2a1374
--- /dev/null
@@ -0,0 +1,235 @@
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Prototypes;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Damage.Systems;
+
+public sealed partial class DamageableSystem
+{
+    /// <summary>
+    ///     Directly sets the damage specifier of a damageable component.
+    /// </summary>
+    /// <remarks>
+    ///     Useful for some unfriendly folk. Also ensures that cached values are updated and that a damage changed
+    ///     event is raised.
+    /// </remarks>
+    public void SetDamage(Entity<DamageableComponent?> ent, DamageSpecifier damage)
+    {
+        if (!_damageableQuery.Resolve(ent, ref ent.Comp, false))
+            return;
+
+        ent.Comp.Damage = damage;
+
+        OnEntityDamageChanged((ent, ent.Comp));
+    }
+
+    /// <summary>
+    ///     Applies damage specified via a <see cref="DamageSpecifier"/>.
+    /// </summary>
+    /// <remarks>
+    ///     <see cref="DamageSpecifier"/> is effectively just a dictionary of damage types and damage values. This
+    ///     function just applies the container's resistances (unless otherwise specified) and then changes the
+    ///     stored damage data. Division of group damage into types is managed by <see cref="DamageSpecifier"/>.
+    /// </remarks>
+    /// <returns>
+    ///     If the attempt was successful or not.
+    /// </returns>
+    public bool TryChangeDamage(
+        Entity<DamageableComponent?> ent,
+        DamageSpecifier damage,
+        bool ignoreResistances = false,
+        bool interruptsDoAfters = true,
+        EntityUid? origin = null,
+        bool ignoreGlobalModifiers = false
+    )
+    {
+        //! Empty just checks if the DamageSpecifier is _literally_ empty, as in, is internal dictionary of damage types is empty.
+        // If you deal 0.0 of some damage type, Empty will be false!
+        return !TryChangeDamage(ent, damage, out _, ignoreResistances, interruptsDoAfters, origin, ignoreGlobalModifiers);
+    }
+
+    /// <summary>
+    ///     Applies damage specified via a <see cref="DamageSpecifier"/>.
+    /// </summary>
+    /// <remarks>
+    ///     <see cref="DamageSpecifier"/> is effectively just a dictionary of damage types and damage values. This
+    ///     function just applies the container's resistances (unless otherwise specified) and then changes the
+    ///     stored damage data. Division of group damage into types is managed by <see cref="DamageSpecifier"/>.
+    /// </remarks>
+    /// <returns>
+    ///     If the attempt was successful or not.
+    /// </returns>
+    public bool TryChangeDamage(
+        Entity<DamageableComponent?> ent,
+        DamageSpecifier damage,
+        out DamageSpecifier newDamage,
+        bool ignoreResistances = false,
+        bool interruptsDoAfters = true,
+        EntityUid? origin = null,
+        bool ignoreGlobalModifiers = false
+    )
+    {
+        //! Empty just checks if the DamageSpecifier is _literally_ empty, as in, is internal dictionary of damage types is empty.
+        // If you deal 0.0 of some damage type, Empty will be false!
+        newDamage = ChangeDamage(ent, damage, ignoreResistances, interruptsDoAfters, origin, ignoreGlobalModifiers);
+        return !damage.Empty;
+    }
+
+    /// <summary>
+    ///     Applies damage specified via a <see cref="DamageSpecifier"/>.
+    /// </summary>
+    /// <remarks>
+    ///     <see cref="DamageSpecifier"/> is effectively just a dictionary of damage types and damage values. This
+    ///     function just applies the container's resistances (unless otherwise specified) and then changes the
+    ///     stored damage data. Division of group damage into types is managed by <see cref="DamageSpecifier"/>.
+    /// </remarks>
+    /// <returns>
+    ///     The actual amount of damage taken, as a DamageSpecifier.
+    /// </returns>
+    public DamageSpecifier ChangeDamage(
+        Entity<DamageableComponent?> ent,
+        DamageSpecifier damage,
+        bool ignoreResistances = false,
+        bool interruptsDoAfters = true,
+        EntityUid? origin = null,
+        bool ignoreGlobalModifiers = false
+    )
+    {
+        var damageDone = new DamageSpecifier();
+
+        if (!_damageableQuery.Resolve(ent, ref ent.Comp, false))
+            return damageDone;
+
+        if (damage.Empty)
+            return damageDone;
+
+        var before = new BeforeDamageChangedEvent(damage, origin);
+        RaiseLocalEvent(ent, ref before);
+
+        if (before.Cancelled)
+            return damageDone;
+
+        // Apply resistances
+        if (!ignoreResistances)
+        {
+            if (
+                ent.Comp.DamageModifierSetId != null &&
+                _prototypeManager.Resolve(ent.Comp.DamageModifierSetId, out var modifierSet)
+            )
+                damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet);
+
+            // TODO DAMAGE
+            // byref struct event.
+            var ev = new DamageModifyEvent(damage, origin);
+            RaiseLocalEvent(ent, ev);
+            damage = ev.Damage;
+
+            if (damage.Empty)
+                return damageDone;
+        }
+
+        if (!ignoreGlobalModifiers)
+            damage = ApplyUniversalAllModifiers(damage);
+
+
+        damageDone.DamageDict.EnsureCapacity(damage.DamageDict.Count);
+
+        var dict = ent.Comp.Damage.DamageDict;
+        foreach (var (type, value) in damage.DamageDict)
+        {
+            // CollectionsMarshal my beloved.
+            if (!dict.TryGetValue(type, out var oldValue))
+                continue;
+
+            var newValue = FixedPoint2.Max(FixedPoint2.Zero, oldValue + value);
+            if (newValue == oldValue)
+                continue;
+
+            dict[type] = newValue;
+            damageDone.DamageDict[type] = newValue - oldValue;
+        }
+
+        if (!damageDone.Empty)
+            OnEntityDamageChanged((ent, ent.Comp), damageDone, interruptsDoAfters, origin);
+
+        return damageDone;
+    }
+
+    /// <summary>
+    /// Applies the two universal "All" modifiers, if set.
+    /// Individual damage source modifiers are set in their respective code.
+    /// </summary>
+    /// <param name="damage">The damage to be changed.</param>
+    public DamageSpecifier ApplyUniversalAllModifiers(DamageSpecifier damage)
+    {
+        // Checks for changes first since they're unlikely in normal play.
+        if (
+            MathHelper.CloseToPercent(UniversalAllDamageModifier, 1f) &&
+            MathHelper.CloseToPercent(UniversalAllHealModifier, 1f)
+        )
+            return damage;
+
+        foreach (var (key, value) in damage.DamageDict)
+        {
+            if (value == 0)
+                continue;
+
+            if (value > 0)
+            {
+                damage.DamageDict[key] *= UniversalAllDamageModifier;
+
+                continue;
+            }
+
+            if (value < 0)
+                damage.DamageDict[key] *= UniversalAllHealModifier;
+        }
+
+        return damage;
+    }
+
+    public void ClearAllDamage(Entity<DamageableComponent?> ent)
+    {
+        SetAllDamage(ent, FixedPoint2.Zero);
+    }
+
+    /// <summary>
+    ///     Sets all damage types supported by a <see cref="Components.DamageableComponent"/> to the specified value.
+    /// </summary>
+    /// <remarks>
+    ///     Does nothing If the given damage value is negative.
+    /// </remarks>
+    public void SetAllDamage(Entity<DamageableComponent?> ent, FixedPoint2 newValue)
+    {
+        if (!_damageableQuery.Resolve(ent, ref ent.Comp, false))
+            return;
+
+        if (newValue < 0)
+            return;
+
+        foreach (var type in ent.Comp.Damage.DamageDict.Keys)
+        {
+            ent.Comp.Damage.DamageDict[type] = newValue;
+        }
+
+        // Setting damage does not count as 'dealing' damage, even if it is set to a larger value, so we pass an
+        // empty damage delta.
+        OnEntityDamageChanged((ent, ent.Comp), new DamageSpecifier());
+    }
+
+    /// <summary>
+    /// Set's the damage modifier set prototype for this entity.
+    /// </summary>
+    /// <param name="ent">The entity we're setting the modifier set of.</param>
+    /// <param name="damageModifierSetId">The prototype we're setting.</param>
+    public void SetDamageModifierSetId(Entity<DamageableComponent?> ent, ProtoId<DamageModifierSetPrototype>? damageModifierSetId)
+    {
+        if (!_damageableQuery.Resolve(ent, ref ent.Comp, false))
+            return;
+
+        ent.Comp.DamageModifierSetId = damageModifierSetId;
+
+        Dirty(ent);
+    }
+}
index d248d717b80c9712039efe33efaca0ab69137a10..5ca7fe1992bb2e12477965dc4cc0a8af4098304d 100644 (file)
@@ -1,4 +1,6 @@
-namespace Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+
+namespace Content.Shared.Damage.Systems;
 
 public sealed partial class DamageableSystem
 {
@@ -9,7 +11,7 @@ public sealed partial class DamageableSystem
     {
         foreach (var (uid, damageable) in damageables)
         {
-            TryChangeDamage(uid, damage, damageable: damageable);
+            TryChangeDamage((uid, damageable), damage);
         }
     }
 }
diff --git a/Content.Shared/Damage/Systems/DamageableSystem.Events.cs b/Content.Shared/Damage/Systems/DamageableSystem.Events.cs
new file mode 100644 (file)
index 0000000..3e985ba
--- /dev/null
@@ -0,0 +1,290 @@
+using Content.Shared.CCVar;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Prototypes;
+using Content.Shared.FixedPoint;
+using Content.Shared.Inventory;
+using Content.Shared.Radiation.Events;
+using Content.Shared.Rejuvenate;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Damage.Systems;
+
+public sealed partial class DamageableSystem
+{
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<DamageableComponent, ComponentInit>(DamageableInit);
+        SubscribeLocalEvent<DamageableComponent, ComponentHandleState>(DamageableHandleState);
+        SubscribeLocalEvent<DamageableComponent, ComponentGetState>(DamageableGetState);
+        SubscribeLocalEvent<DamageableComponent, OnIrradiatedEvent>(OnIrradiated);
+        SubscribeLocalEvent<DamageableComponent, RejuvenateEvent>(OnRejuvenate);
+
+        _appearanceQuery = GetEntityQuery<AppearanceComponent>();
+        _damageableQuery = GetEntityQuery<DamageableComponent>();
+
+        // Damage modifier CVars are updated and stored here to be queried in other systems.
+        // Note that certain modifiers requires reloading the guidebook.
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestAllDamageModifier,
+            value =>
+            {
+                UniversalAllDamageModifier = value;
+                _chemistryGuideData.ReloadAllReagentPrototypes();
+                _explosion.ReloadMap();
+            },
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestAllHealModifier,
+            value =>
+            {
+                UniversalAllHealModifier = value;
+                _chemistryGuideData.ReloadAllReagentPrototypes();
+            },
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestProjectileDamageModifier,
+            value => UniversalProjectileDamageModifier = value,
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestMeleeDamageModifier,
+            value => UniversalMeleeDamageModifier = value,
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestProjectileDamageModifier,
+            value => UniversalProjectileDamageModifier = value,
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestHitscanDamageModifier,
+            value => UniversalHitscanDamageModifier = value,
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestReagentDamageModifier,
+            value =>
+            {
+                UniversalReagentDamageModifier = value;
+                _chemistryGuideData.ReloadAllReagentPrototypes();
+            },
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestReagentHealModifier,
+            value =>
+            {
+                UniversalReagentHealModifier = value;
+                _chemistryGuideData.ReloadAllReagentPrototypes();
+            },
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestExplosionDamageModifier,
+            value =>
+            {
+                UniversalExplosionDamageModifier = value;
+                _explosion.ReloadMap();
+            },
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestThrownDamageModifier,
+            value => UniversalThrownDamageModifier = value,
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestTopicalsHealModifier,
+            value => UniversalTopicalsHealModifier = value,
+            true
+        );
+        Subs.CVar(
+            _config,
+            CCVars.PlaytestMobDamageModifier,
+            value => UniversalMobDamageModifier = value,
+            true
+        );
+    }
+
+    /// <summary>
+    ///     Initialize a damageable component
+    /// </summary>
+    private void DamageableInit(Entity<DamageableComponent> ent, ref ComponentInit _)
+    {
+        if (
+            ent.Comp.DamageContainerID is null ||
+            !_prototypeManager.Resolve(ent.Comp.DamageContainerID, out var damageContainerPrototype)
+        )
+        {
+            // No DamageContainerPrototype was given. So we will allow the container to support all damage types
+            foreach (var type in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
+            {
+                ent.Comp.Damage.DamageDict.TryAdd(type.ID, FixedPoint2.Zero);
+            }
+        }
+        else
+        {
+            // Initialize damage dictionary, using the types and groups from the damage
+            // container prototype
+            foreach (var type in damageContainerPrototype.SupportedTypes)
+            {
+                ent.Comp.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
+            }
+
+            foreach (var groupId in damageContainerPrototype.SupportedGroups)
+            {
+                var group = _prototypeManager.Index(groupId);
+                foreach (var type in group.DamageTypes)
+                {
+                    ent.Comp.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
+                }
+            }
+        }
+
+        ent.Comp.Damage.GetDamagePerGroup(_prototypeManager, ent.Comp.DamagePerGroup);
+        ent.Comp.TotalDamage = ent.Comp.Damage.GetTotal();
+    }
+
+    private void OnIrradiated(Entity<DamageableComponent> ent, ref OnIrradiatedEvent args)
+    {
+        var damageValue = FixedPoint2.New(args.TotalRads);
+
+        // Radiation should really just be a damage group instead of a list of types.
+        DamageSpecifier damage = new();
+        foreach (var typeId in ent.Comp.RadiationDamageTypeIDs)
+        {
+            damage.DamageDict.Add(typeId, damageValue);
+        }
+
+        ChangeDamage(ent.Owner, damage, interruptsDoAfters: false, origin: args.Origin);
+    }
+
+    private void OnRejuvenate(Entity<DamageableComponent> ent, ref RejuvenateEvent args)
+    {
+        // Do this so that the state changes when we set the damage
+        _mobThreshold.SetAllowRevives(ent, true);
+        ClearAllDamage(ent.AsNullable());
+        _mobThreshold.SetAllowRevives(ent, false);
+    }
+
+    private void DamageableHandleState(Entity<DamageableComponent> ent, ref ComponentHandleState args)
+    {
+        if (args.Current is not DamageableComponentState state)
+            return;
+
+        ent.Comp.DamageContainerID = state.DamageContainerId;
+        ent.Comp.DamageModifierSetId = state.ModifierSetId;
+        ent.Comp.HealthBarThreshold = state.HealthBarThreshold;
+
+        // Has the damage actually changed?
+        DamageSpecifier newDamage = new() { DamageDict = new Dictionary<string, FixedPoint2>(state.DamageDict) };
+        var delta = newDamage - ent.Comp.Damage;
+        delta.TrimZeros();
+
+        if (delta.Empty)
+            return;
+
+        ent.Comp.Damage = newDamage;
+
+        OnEntityDamageChanged(ent, delta);
+    }
+}
+
+/// <summary>
+///     Raised before damage is done, so stuff can cancel it if necessary.
+/// </summary>
+[ByRefEvent]
+public record struct BeforeDamageChangedEvent(DamageSpecifier Damage, EntityUid? Origin = null, bool Cancelled = false);
+
+/// <summary>
+///     Raised on an entity when damage is about to be dealt,
+///     in case anything else needs to modify it other than the base
+///     damageable component.
+///
+///     For example, armor.
+/// </summary>
+public sealed class DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null)
+    : EntityEventArgs, IInventoryRelayEvent
+{
+    // Whenever locational damage is a thing, this should just check only that bit of armour.
+    public SlotFlags TargetSlots => ~SlotFlags.POCKET;
+
+    public readonly DamageSpecifier OriginalDamage = damage;
+    public DamageSpecifier Damage = damage;
+}
+
+public sealed class DamageChangedEvent : EntityEventArgs
+{
+    /// <summary>
+    ///     This is the component whose damage was changed.
+    /// </summary>
+    /// <remarks>
+    ///     Given that nearly every component that cares about a change in the damage, needs to know the
+    ///     current damage values, directly passing this information prevents a lot of duplicate
+    ///     Owner.TryGetComponent() calls.
+    /// </remarks>
+    public readonly DamageableComponent Damageable;
+
+    /// <summary>
+    ///     The amount by which the damage has changed. If the damage was set directly to some number, this will be
+    ///     null.
+    /// </summary>
+    public readonly DamageSpecifier? DamageDelta;
+
+    /// <summary>
+    ///     Was any of the damage change dealing damage, or was it all healing?
+    /// </summary>
+    public readonly bool DamageIncreased;
+
+    /// <summary>
+    ///     Does this event interrupt DoAfters?
+    ///     Note: As provided in the constructor, this *does not* account for DamageIncreased.
+    ///     As written into the event, this *does* account for DamageIncreased.
+    /// </summary>
+    public readonly bool InterruptsDoAfters;
+
+    /// <summary>
+    ///     Contains the entity which caused the change in damage, if any was responsible.
+    /// </summary>
+    public readonly EntityUid? Origin;
+
+    public DamageChangedEvent(
+        DamageableComponent damageable,
+        DamageSpecifier? damageDelta,
+        bool interruptsDoAfters,
+        EntityUid? origin
+    )
+    {
+        Damageable = damageable;
+        DamageDelta = damageDelta;
+        Origin = origin;
+
+        if (DamageDelta is null)
+            return;
+
+        foreach (var damageChange in DamageDelta.DamageDict.Values)
+        {
+            if (damageChange <= 0)
+                continue;
+
+            DamageIncreased = true;
+
+            break;
+        }
+
+        InterruptsDoAfters = interruptsDoAfters && DamageIncreased;
+    }
+}
index f1e259001cffb54c023273ea00f7b285b6874de6..2b4c5ad36090c0cbedae0b062e199aac5cb2b9ff 100644 (file)
 using System.Linq;
-using Content.Shared.CCVar;
 using Content.Shared.Chemistry;
-using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Components;
 using Content.Shared.Explosion.EntitySystems;
-using Content.Shared.FixedPoint;
-using Content.Shared.Inventory;
-using Content.Shared.Mobs.Components;
 using Content.Shared.Mobs.Systems;
-using Content.Shared.Radiation.Events;
-using Content.Shared.Rejuvenate;
 using Robust.Shared.Configuration;
 using Robust.Shared.GameStates;
 using Robust.Shared.Network;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
 
-namespace Content.Shared.Damage
-{
-    public sealed partial class DamageableSystem : EntitySystem
-    {
-        [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
-        [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
-        [Dependency] private readonly INetManager _netMan = default!;
-        [Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
-        [Dependency] private readonly IConfigurationManager _config = default!;
-        [Dependency] private readonly SharedChemistryGuideDataSystem _chemistryGuideData = default!;
-        [Dependency] private readonly SharedExplosionSystem _explosion = default!;
-
-        private EntityQuery<AppearanceComponent> _appearanceQuery;
-        private EntityQuery<DamageableComponent> _damageableQuery;
-
-        public float UniversalAllDamageModifier { get; private set; } = 1f;
-        public float UniversalAllHealModifier { get; private set; } = 1f;
-        public float UniversalMeleeDamageModifier { get; private set; } = 1f;
-        public float UniversalProjectileDamageModifier { get; private set; } = 1f;
-        public float UniversalHitscanDamageModifier { get; private set; } = 1f;
-        public float UniversalReagentDamageModifier { get; private set; } = 1f;
-        public float UniversalReagentHealModifier { get; private set; } = 1f;
-        public float UniversalExplosionDamageModifier { get; private set; } = 1f;
-        public float UniversalThrownDamageModifier { get; private set; } = 1f;
-        public float UniversalTopicalsHealModifier { get; private set; } = 1f;
-        public float UniversalMobDamageModifier { get; private set; } = 1f;
-
-        public override void Initialize()
-        {
-            SubscribeLocalEvent<DamageableComponent, ComponentInit>(DamageableInit);
-            SubscribeLocalEvent<DamageableComponent, ComponentHandleState>(DamageableHandleState);
-            SubscribeLocalEvent<DamageableComponent, ComponentGetState>(DamageableGetState);
-            SubscribeLocalEvent<DamageableComponent, OnIrradiatedEvent>(OnIrradiated);
-            SubscribeLocalEvent<DamageableComponent, RejuvenateEvent>(OnRejuvenate);
-
-            _appearanceQuery = GetEntityQuery<AppearanceComponent>();
-            _damageableQuery = GetEntityQuery<DamageableComponent>();
-
-            // Damage modifier CVars are updated and stored here to be queried in other systems.
-            // Note that certain modifiers requires reloading the guidebook.
-            Subs.CVar(_config, CCVars.PlaytestAllDamageModifier, value =>
-            {
-                UniversalAllDamageModifier = value;
-                _chemistryGuideData.ReloadAllReagentPrototypes();
-                _explosion.ReloadMap();
-            }, true);
-            Subs.CVar(_config, CCVars.PlaytestAllHealModifier, value =>
-            {
-                UniversalAllHealModifier = value;
-                _chemistryGuideData.ReloadAllReagentPrototypes();
-            }, true);
-            Subs.CVar(_config, CCVars.PlaytestProjectileDamageModifier, value => UniversalProjectileDamageModifier = value, true);
-            Subs.CVar(_config, CCVars.PlaytestMeleeDamageModifier, value => UniversalMeleeDamageModifier = value, true);
-            Subs.CVar(_config, CCVars.PlaytestProjectileDamageModifier, value => UniversalProjectileDamageModifier = value, true);
-            Subs.CVar(_config, CCVars.PlaytestHitscanDamageModifier, value => UniversalHitscanDamageModifier = value, true);
-            Subs.CVar(_config, CCVars.PlaytestReagentDamageModifier, value =>
-            {
-                UniversalReagentDamageModifier = value;
-                _chemistryGuideData.ReloadAllReagentPrototypes();
-            }, true);
-            Subs.CVar(_config, CCVars.PlaytestReagentHealModifier, value =>
-            {
-                 UniversalReagentHealModifier = value;
-                 _chemistryGuideData.ReloadAllReagentPrototypes();
-            }, true);
-            Subs.CVar(_config, CCVars.PlaytestExplosionDamageModifier, value =>
-            {
-                UniversalExplosionDamageModifier = value;
-                _explosion.ReloadMap();
-            }, true);
-            Subs.CVar(_config, CCVars.PlaytestThrownDamageModifier, value => UniversalThrownDamageModifier = value, true);
-            Subs.CVar(_config, CCVars.PlaytestTopicalsHealModifier, value => UniversalTopicalsHealModifier = value, true);
-            Subs.CVar(_config, CCVars.PlaytestMobDamageModifier, value => UniversalMobDamageModifier = value, true);
-        }
-
-        /// <summary>
-        ///     Initialize a damageable component
-        /// </summary>
-        private void DamageableInit(EntityUid uid, DamageableComponent component, ComponentInit _)
-        {
-            if (component.DamageContainerID != null &&
-                _prototypeManager.Resolve<DamageContainerPrototype>(component.DamageContainerID,
-                out var damageContainerPrototype))
-            {
-                // Initialize damage dictionary, using the types and groups from the damage
-                // container prototype
-                foreach (var type in damageContainerPrototype.SupportedTypes)
-                {
-                    component.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
-                }
-
-                foreach (var groupId in damageContainerPrototype.SupportedGroups)
-                {
-                    var group = _prototypeManager.Index<DamageGroupPrototype>(groupId);
-                    foreach (var type in group.DamageTypes)
-                    {
-                        component.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
-                    }
-                }
-            }
-            else
-            {
-                // No DamageContainerPrototype was given. So we will allow the container to support all damage types
-                foreach (var type in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
-                {
-                    component.Damage.DamageDict.TryAdd(type.ID, FixedPoint2.Zero);
-                }
-            }
-
-            component.Damage.GetDamagePerGroup(_prototypeManager, component.DamagePerGroup);
-            component.TotalDamage = component.Damage.GetTotal();
-        }
-
-        /// <summary>
-        ///     Directly sets the damage specifier of a damageable component.
-        /// </summary>
-        /// <remarks>
-        ///     Useful for some unfriendly folk. Also ensures that cached values are updated and that a damage changed
-        ///     event is raised.
-        /// </remarks>
-        public void SetDamage(EntityUid uid, DamageableComponent damageable, DamageSpecifier damage)
-        {
-            damageable.Damage = damage;
-            DamageChanged(uid, damageable);
-        }
-
-        /// <summary>
-        ///     If the damage in a DamageableComponent was changed, this function should be called.
-        /// </summary>
-        /// <remarks>
-        ///     This updates cached damage information, flags the component as dirty, and raises a damage changed event.
-        ///     The damage changed event is used by other systems, such as damage thresholds.
-        /// </remarks>
-        public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSpecifier? damageDelta = null,
-            bool interruptsDoAfters = true, EntityUid? origin = null)
-        {
-            component.Damage.GetDamagePerGroup(_prototypeManager, component.DamagePerGroup);
-            component.TotalDamage = component.Damage.GetTotal();
-            Dirty(uid, component);
-
-            if (_appearanceQuery.TryGetComponent(uid, out var appearance) && damageDelta != null)
-            {
-                var data = new DamageVisualizerGroupData(component.DamagePerGroup.Keys.ToList());
-                _appearance.SetData(uid, DamageVisualizerKeys.DamageUpdateGroups, data, appearance);
-            }
-
-            // TODO DAMAGE
-            // byref struct event.
-            RaiseLocalEvent(uid, new DamageChangedEvent(component, damageDelta, interruptsDoAfters, origin));
-        }
-
-        /// <summary>
-        ///     Applies damage specified via a <see cref="DamageSpecifier"/>.
-        /// </summary>
-        /// <remarks>
-        ///     <see cref="DamageSpecifier"/> is effectively just a dictionary of damage types and damage values. This
-        ///     function just applies the container's resistances (unless otherwise specified) and then changes the
-        ///     stored damage data. Division of group damage into types is managed by <see cref="DamageSpecifier"/>.
-        /// </remarks>
-        /// <returns>
-        ///     Returns a <see cref="DamageSpecifier"/> with information about the actual damage changes. This will be
-        ///     null if the user had no applicable components that can take damage.
-        /// </returns>
-        /// <param name="ignoreResistances">If true, this will ignore the entity's damage modifier (<see cref="DamageableComponent.DamageModifierSetId"/> and skip raising a <see cref="DamageModifyEvent"/>.</param>
-        /// <param name="interruptsDoAfters">Whether the damage should cancel any damage sensitive do-afters</param>
-        /// <param name="origin">The entity that is causing this damage</param>
-        /// <param name="ignoreGlobalModifiers">If true, this will skip over applying the universal damage modifiers (see <see cref="ApplyUniversalAllModifiers"/>).</param>
-        /// <returns></returns>
-        public DamageSpecifier? TryChangeDamage(
-            EntityUid? uid,
-            DamageSpecifier damage,
-            bool ignoreResistances = false,
-            bool interruptsDoAfters = true,
-            DamageableComponent? damageable = null,
-            EntityUid? origin = null,
-            bool ignoreGlobalModifiers = false)
-        {
-            if (!uid.HasValue || !_damageableQuery.Resolve(uid.Value, ref damageable, false))
-            {
-                // TODO BODY SYSTEM pass damage onto body system
-                // BOBBY WHEN?
-                return null;
-            }
-
-            if (damage.Empty)
-            {
-                return damage;
-            }
-
-            var before = new BeforeDamageChangedEvent(damage, origin);
-            RaiseLocalEvent(uid.Value, ref before);
-
-            if (before.Cancelled)
-                return null;
-
-            // Apply resistances
-            if (!ignoreResistances)
-            {
-                if (damageable.DamageModifierSetId != null &&
-                    _prototypeManager.Resolve(damageable.DamageModifierSetId, out var modifierSet))
-                {
-                    damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet);
-                }
-
-                // TODO DAMAGE
-                // byref struct event.
-                var ev = new DamageModifyEvent(damage, origin);
-                RaiseLocalEvent(uid.Value, ev);
-                damage = ev.Damage;
-
-                if (damage.Empty)
-                {
-                    return damage;
-                }
-            }
-
-            if (!ignoreGlobalModifiers)
-                damage = ApplyUniversalAllModifiers(damage);
-
-            var delta = new DamageSpecifier();
-            delta.DamageDict.EnsureCapacity(damage.DamageDict.Count);
-
-            var dict = damageable.Damage.DamageDict;
-            foreach (var (type, value) in damage.DamageDict)
-            {
-                // CollectionsMarshal my beloved.
-                if (!dict.TryGetValue(type, out var oldValue))
-                    continue;
-
-                var newValue = FixedPoint2.Max(FixedPoint2.Zero, oldValue + value);
-                if (newValue == oldValue)
-                    continue;
-
-                dict[type] = newValue;
-                delta.DamageDict[type] = newValue - oldValue;
-            }
-
-            if (delta.DamageDict.Count > 0)
-                DamageChanged(uid.Value, damageable, delta, interruptsDoAfters, origin);
-
-            return delta;
-        }
-
-        /// <summary>
-        /// Applies the two univeral "All" modifiers, if set.
-        /// Individual damage source modifiers are set in their respective code.
-        /// </summary>
-        /// <param name="damage">The damage to be changed.</param>
-        public DamageSpecifier ApplyUniversalAllModifiers(DamageSpecifier damage)
-        {
-            // Checks for changes first since they're unlikely in normal play.
-            if (UniversalAllDamageModifier == 1f && UniversalAllHealModifier == 1f)
-                return damage;
-
-            foreach (var (key, value) in damage.DamageDict)
-            {
-                if (value == 0)
-                    continue;
-
-                if (value > 0)
-                {
-                    damage.DamageDict[key] *= UniversalAllDamageModifier;
-                    continue;
-                }
-
-                if (value < 0)
-                {
-                    damage.DamageDict[key] *= UniversalAllHealModifier;
-                }
-            }
+namespace Content.Shared.Damage.Systems;
 
-            return damage;
-        }
-
-        /// <summary>
-        ///     Sets all damage types supported by a <see cref="DamageableComponent"/> to the specified value.
-        /// </summary>
-        /// <remakrs>
-        ///     Does nothing If the given damage value is negative.
-        /// </remakrs>
-        public void SetAllDamage(EntityUid uid, DamageableComponent component, FixedPoint2 newValue)
-        {
-            if (newValue < 0)
-            {
-                // invalid value
-                return;
-            }
-
-            foreach (var type in component.Damage.DamageDict.Keys)
-            {
-                component.Damage.DamageDict[type] = newValue;
-            }
-
-            // Setting damage does not count as 'dealing' damage, even if it is set to a larger value, so we pass an
-            // empty damage delta.
-            DamageChanged(uid, component, new DamageSpecifier());
-        }
-
-        public void SetDamageModifierSetId(EntityUid uid, string? damageModifierSetId, DamageableComponent? comp = null)
-        {
-            if (!_damageableQuery.Resolve(uid, ref comp))
-                return;
-
-            comp.DamageModifierSetId = damageModifierSetId;
-            Dirty(uid, comp);
-        }
-
-        private void DamageableGetState(EntityUid uid, DamageableComponent component, ref ComponentGetState args)
-        {
-            if (_netMan.IsServer)
-            {
-                args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageContainerID, component.DamageModifierSetId, component.HealthBarThreshold);
-            }
-            else
-            {
-                // avoid mispredicting damage on newly spawned entities.
-                args.State = new DamageableComponentState(component.Damage.DamageDict.ShallowClone(), component.DamageContainerID, component.DamageModifierSetId, component.HealthBarThreshold);
-            }
-        }
-
-        private void OnIrradiated(EntityUid uid, DamageableComponent component, OnIrradiatedEvent args)
-        {
-            var damageValue = FixedPoint2.New(args.TotalRads);
-
-            // Radiation should really just be a damage group instead of a list of types.
-            DamageSpecifier damage = new();
-            foreach (var typeId in component.RadiationDamageTypeIDs)
-            {
-                damage.DamageDict.Add(typeId, damageValue);
-            }
-
-            TryChangeDamage(uid, damage, interruptsDoAfters: false, origin: args.Origin);
-        }
-
-        private void OnRejuvenate(EntityUid uid, DamageableComponent component, RejuvenateEvent args)
-        {
-            TryComp<MobThresholdsComponent>(uid, out var thresholds);
-            _mobThreshold.SetAllowRevives(uid, true, thresholds); // do this so that the state changes when we set the damage
-            SetAllDamage(uid, component, 0);
-            _mobThreshold.SetAllowRevives(uid, false, thresholds);
-        }
-
-        private void DamageableHandleState(EntityUid uid, DamageableComponent component, ref ComponentHandleState args)
-        {
-            if (args.Current is not DamageableComponentState state)
-            {
-                return;
-            }
-
-            component.DamageContainerID = state.DamageContainerId;
-            component.DamageModifierSetId = state.ModifierSetId;
-            component.HealthBarThreshold = state.HealthBarThreshold;
-
-            // Has the damage actually changed?
-            DamageSpecifier newDamage = new() { DamageDict = new(state.DamageDict) };
-            var delta = newDamage - component.Damage;
-            delta.TrimZeros();
-
-            if (!delta.Empty)
-            {
-                component.Damage = newDamage;
-                DamageChanged(uid, component, delta);
-            }
-        }
-    }
-
-    /// <summary>
-    ///     Raised before damage is done, so stuff can cancel it if necessary.
-    /// </summary>
-    [ByRefEvent]
-    public record struct BeforeDamageChangedEvent(DamageSpecifier Damage, EntityUid? Origin = null, bool Cancelled = false);
+public sealed partial class DamageableSystem : EntitySystem
+{
+    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly INetManager _netMan = default!;
+    [Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
+    [Dependency] private readonly IConfigurationManager _config = default!;
+    [Dependency] private readonly SharedChemistryGuideDataSystem _chemistryGuideData = default!;
+    [Dependency] private readonly SharedExplosionSystem _explosion = default!;
+
+    private EntityQuery<AppearanceComponent> _appearanceQuery;
+    private EntityQuery<DamageableComponent> _damageableQuery;
+
+    public float UniversalAllDamageModifier { get; private set; } = 1f;
+    public float UniversalAllHealModifier { get; private set; } = 1f;
+    public float UniversalMeleeDamageModifier { get; private set; } = 1f;
+    public float UniversalProjectileDamageModifier { get; private set; } = 1f;
+    public float UniversalHitscanDamageModifier { get; private set; } = 1f;
+    public float UniversalReagentDamageModifier { get; private set; } = 1f;
+    public float UniversalReagentHealModifier { get; private set; } = 1f;
+    public float UniversalExplosionDamageModifier { get; private set; } = 1f;
+    public float UniversalThrownDamageModifier { get; private set; } = 1f;
+    public float UniversalTopicalsHealModifier { get; private set; } = 1f;
+    public float UniversalMobDamageModifier { get; private set; } = 1f;
 
     /// <summary>
-    ///     Raised on an entity when damage is about to be dealt,
-    ///     in case anything else needs to modify it other than the base
-    ///     damageable component.
-    ///
-    ///     For example, armor.
+    ///     If the damage in a DamageableComponent was changed this function should be called.
     /// </summary>
-    public sealed class DamageModifyEvent : EntityEventArgs, IInventoryRelayEvent
+    /// <remarks>
+    ///     This updates cached damage information, flags the component as dirty, and raises a damage changed event.
+    ///     The damage changed event is used by other systems, such as damage thresholds.
+    /// </remarks>
+    private void OnEntityDamageChanged(
+        Entity<DamageableComponent> ent,
+        DamageSpecifier? damageDelta = null,
+        bool interruptsDoAfters = true,
+        EntityUid? origin = null
+    )
     {
-        // Whenever locational damage is a thing, this should just check only that bit of armour.
-        public SlotFlags TargetSlots { get; } = ~SlotFlags.POCKET;
+        ent.Comp.Damage.GetDamagePerGroup(_prototypeManager, ent.Comp.DamagePerGroup);
+        ent.Comp.TotalDamage = ent.Comp.Damage.GetTotal();
+        Dirty(ent);
 
-        public readonly DamageSpecifier OriginalDamage;
-        public DamageSpecifier Damage;
-        public EntityUid? Origin;
-
-        public DamageModifyEvent(DamageSpecifier damage, EntityUid? origin = null)
+        if (damageDelta != null && _appearanceQuery.TryGetComponent(ent, out var appearance))
         {
-            OriginalDamage = damage;
-            Damage = damage;
-            Origin = origin;
+            _appearance.SetData(
+                ent,
+                DamageVisualizerKeys.DamageUpdateGroups,
+                new DamageVisualizerGroupData(ent.Comp.DamagePerGroup.Keys.ToList()),
+                appearance
+            );
         }
+
+        // TODO DAMAGE
+        // byref struct event.
+        RaiseLocalEvent(ent, new DamageChangedEvent(ent.Comp, damageDelta, interruptsDoAfters, origin));
     }
 
-    public sealed class DamageChangedEvent : EntityEventArgs
+    private void DamageableGetState(Entity<DamageableComponent> ent, ref ComponentGetState args)
     {
-        /// <summary>
-        ///     This is the component whose damage was changed.
-        /// </summary>
-        /// <remarks>
-        ///     Given that nearly every component that cares about a change in the damage, needs to know the
-        ///     current damage values, directly passing this information prevents a lot of duplicate
-        ///     Owner.TryGetComponent() calls.
-        /// </remarks>
-        public readonly DamageableComponent Damageable;
-
-        /// <summary>
-        ///     The amount by which the damage has changed. If the damage was set directly to some number, this will be
-        ///     null.
-        /// </summary>
-        public readonly DamageSpecifier? DamageDelta;
-
-        /// <summary>
-        ///     Was any of the damage change dealing damage, or was it all healing?
-        /// </summary>
-        public readonly bool DamageIncreased;
-
-        /// <summary>
-        ///     Does this event interrupt DoAfters?
-        ///     Note: As provided in the constructor, this *does not* account for DamageIncreased.
-        ///     As written into the event, this *does* account for DamageIncreased.
-        /// </summary>
-        public readonly bool InterruptsDoAfters;
-
-        /// <summary>
-        ///     Contains the entity which caused the change in damage, if any was responsible.
-        /// </summary>
-        public readonly EntityUid? Origin;
-
-        public DamageChangedEvent(DamageableComponent damageable, DamageSpecifier? damageDelta, bool interruptsDoAfters, EntityUid? origin)
+        if (_netMan.IsServer)
         {
-            Damageable = damageable;
-            DamageDelta = damageDelta;
-            Origin = origin;
-
-            if (DamageDelta == null)
-                return;
-
-            foreach (var damageChange in DamageDelta.DamageDict.Values)
-            {
-                if (damageChange > 0)
-                {
-                    DamageIncreased = true;
-                    break;
-                }
-            }
-            InterruptsDoAfters = interruptsDoAfters && DamageIncreased;
+            args.State = new DamageableComponentState(
+                ent.Comp.Damage.DamageDict,
+                ent.Comp.DamageContainerID,
+                ent.Comp.DamageModifierSetId,
+                ent.Comp.HealthBarThreshold
+            );
+            // TODO BODY SYSTEM pass damage onto body system
+            // BOBBY WHEN? 😭
+            // BOBBY SOON 🫡
+
+            return;
         }
+
+        // avoid mispredicting damage on newly spawned entities.
+        args.State = new DamageableComponentState(
+            ent.Comp.Damage.DamageDict.ShallowClone(),
+            ent.Comp.DamageContainerID,
+            ent.Comp.DamageModifierSetId,
+            ent.Comp.HealthBarThreshold
+        );
     }
 }
index e750863e243ff6aacb214856b57a18da17ed3d70..fddf7dc9757f2d8cbabca8ae5aeb4faf4f9c8f26 100644 (file)
@@ -1,10 +1,8 @@
 using Content.Shared.Damage.Components;
-using Content.Shared.Mobs.Systems;
 using Content.Shared.Mobs.Components;
-using Content.Shared.FixedPoint;
 using Robust.Shared.Timing;
 
-namespace Content.Shared.Damage;
+namespace Content.Shared.Damage.Systems;
 
 public sealed class PassiveDamageSystem : EntitySystem
 {
@@ -47,7 +45,7 @@ public sealed class PassiveDamageSystem : EntitySystem
             foreach (var allowedState in comp.AllowedStates)
             {
                 if(allowedState == mobState.CurrentState)
-                    _damageable.TryChangeDamage(uid, comp.Damage, true, false, damage);
+                    _damageable.ChangeDamage((uid, damage), comp.Damage, true, false);
             }
         }
     }
index 66b1de65e8eeb178770cd2798980363d6d76df29..63b690a67c01ca0d89d0c0acbd4eb9a3f02746f7 100644 (file)
@@ -1,10 +1,11 @@
+using Content.Shared.Damage.Components;
 using Content.Shared.Projectiles;
-using Content.Shared.Weapons.Ranged.Components;
 using Content.Shared.Standing;
-using Robust.Shared.Physics.Events;
+using Content.Shared.Weapons.Ranged.Components;
 using Robust.Shared.Containers;
+using Robust.Shared.Physics.Events;
 
-namespace Content.Shared.Damage.Components;
+namespace Content.Shared.Damage.Systems;
 
 public sealed class RequireProjectileTargetSystem : EntitySystem
 {
index 4bf762c479a5406c4b6235b448ebd0876aeae98a..2a020732c27020f9e0b042196cd1db549b79b3e5 100644 (file)
@@ -85,9 +85,9 @@ public abstract class SharedGodmodeSystem : EntitySystem
         if (!Resolve(uid, ref godmode, false))
             return;
 
-        if (TryComp<DamageableComponent>(uid, out var damageable) && godmode.OldDamage != null)
+        if (godmode.OldDamage != null)
         {
-            _damageable.SetDamage(uid, damageable, godmode.OldDamage);
+            _damageable.SetDamage(uid, godmode.OldDamage);
         }
 
         RemComp<GodmodeComponent>(uid);
index e339727200df193dad10f302843ca331d0686b9c..fef7b6ae06a05e5acde03f22f026c0e4350a2980 100644 (file)
@@ -5,109 +5,108 @@ using Content.Shared.FixedPoint;
 using Content.Shared.Inventory;
 using Content.Shared.Movement.Systems;
 
-namespace Content.Shared.Damage
+namespace Content.Shared.Damage.Systems;
+
+public sealed class SlowOnDamageSystem : EntitySystem
 {
-    public sealed class SlowOnDamageSystem : EntitySystem
+    [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
+
+    public override void Initialize()
     {
-        [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
+        base.Initialize();
 
-        public override void Initialize()
-        {
-            base.Initialize();
+        SubscribeLocalEvent<SlowOnDamageComponent, DamageChangedEvent>(OnDamageChanged);
+        SubscribeLocalEvent<SlowOnDamageComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
 
-            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<ClothingSlowOnDamageModifierComponent, InventoryRelayedEvent<ModifySlowOnDamageSpeedEvent>>(OnModifySpeed);
-            SubscribeLocalEvent<ClothingSlowOnDamageModifierComponent, ExaminedEvent>(OnExamined);
-            SubscribeLocalEvent<ClothingSlowOnDamageModifierComponent, ClothingGotEquippedEvent>(OnGotEquipped);
-            SubscribeLocalEvent<ClothingSlowOnDamageModifierComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
+        SubscribeLocalEvent<IgnoreSlowOnDamageComponent, ComponentStartup>(OnIgnoreStartup);
+        SubscribeLocalEvent<IgnoreSlowOnDamageComponent, ComponentShutdown>(OnIgnoreShutdown);
+        SubscribeLocalEvent<IgnoreSlowOnDamageComponent, ModifySlowOnDamageSpeedEvent>(OnIgnoreModifySpeed);
+    }
 
-            SubscribeLocalEvent<IgnoreSlowOnDamageComponent, ComponentStartup>(OnIgnoreStartup);
-            SubscribeLocalEvent<IgnoreSlowOnDamageComponent, ComponentShutdown>(OnIgnoreShutdown);
-            SubscribeLocalEvent<IgnoreSlowOnDamageComponent, ModifySlowOnDamageSpeedEvent>(OnIgnoreModifySpeed);
-        }
+    private void OnRefreshMovespeed(EntityUid uid, SlowOnDamageComponent component, RefreshMovementSpeedModifiersEvent args)
+    {
+        if (!TryComp<DamageableComponent>(uid, out var damage))
+            return;
+
+        if (damage.TotalDamage == FixedPoint2.Zero)
+            return;
 
-        private void OnRefreshMovespeed(EntityUid uid, SlowOnDamageComponent component, RefreshMovementSpeedModifiersEvent args)
+        // Get closest threshold
+        FixedPoint2 closest = FixedPoint2.Zero;
+        var total = damage.TotalDamage;
+        foreach (var thres in component.SpeedModifierThresholds)
         {
-            if (!TryComp<DamageableComponent>(uid, out var damage))
-                return;
-
-            if (damage.TotalDamage == FixedPoint2.Zero)
-                return;
-
-            // Get closest threshold
-            FixedPoint2 closest = FixedPoint2.Zero;
-            var total = damage.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);
-            }
+            if (total >= thres.Key && thres.Key > closest)
+                closest = thres.Key;
         }
 
-        private void OnDamageChanged(EntityUid uid, SlowOnDamageComponent component, DamageChangedEvent args)
+        if (closest != FixedPoint2.Zero)
         {
-            // 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
+            var speed = component.SpeedModifierThresholds[closest];
 
-            _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(uid);
+            var ev = new ModifySlowOnDamageSpeedEvent(speed);
+            RaiseLocalEvent(uid, ref ev);
+            args.ModifySpeed(ev.Speed, ev.Speed);
         }
+    }
 
-        private void OnModifySpeed(Entity<ClothingSlowOnDamageModifierComponent> ent, ref InventoryRelayedEvent<ModifySlowOnDamageSpeedEvent> args)
-        {
-            var dif = 1 - args.Args.Speed;
-            if (dif <= 0)
-                return;
+    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
 
-            // reduces the slowness modifier by the given coefficient
-            args.Args.Speed += dif * ent.Comp.Modifier;
-        }
+        _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(uid);
+    }
 
-        private void OnExamined(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ExaminedEvent args)
-        {
-            var msg = Loc.GetString("slow-on-damage-modifier-examine", ("mod", (1 - ent.Comp.Modifier) * 100));
-            args.PushMarkup(msg);
-        }
+    private void OnModifySpeed(Entity<ClothingSlowOnDamageModifierComponent> ent, ref InventoryRelayedEvent<ModifySlowOnDamageSpeedEvent> args)
+    {
+        var dif = 1 - args.Args.Speed;
+        if (dif <= 0)
+            return;
 
-        private void OnGotEquipped(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ClothingGotEquippedEvent args)
-        {
-            _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Wearer);
-        }
+        // reduces the slowness modifier by the given coefficient
+        args.Args.Speed += dif * ent.Comp.Modifier;
+    }
 
-        private void OnGotUnequipped(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ClothingGotUnequippedEvent args)
-        {
-            _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Wearer);
-        }
+    private void OnExamined(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ExaminedEvent args)
+    {
+        var msg = Loc.GetString("slow-on-damage-modifier-examine", ("mod", (1 - ent.Comp.Modifier) * 100));
+        args.PushMarkup(msg);
+    }
 
-        private void OnIgnoreStartup(Entity<IgnoreSlowOnDamageComponent> ent, ref ComponentStartup args)
-        {
-            _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(ent);
-        }
+    private void OnGotEquipped(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ClothingGotEquippedEvent args)
+    {
+        _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Wearer);
+    }
 
-        private void OnIgnoreShutdown(Entity<IgnoreSlowOnDamageComponent> ent, ref ComponentShutdown args)
-        {
-            _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(ent);
-        }
+    private void OnGotUnequipped(Entity<ClothingSlowOnDamageModifierComponent> ent, ref ClothingGotUnequippedEvent args)
+    {
+        _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.Wearer);
+    }
 
-        private void OnIgnoreModifySpeed(Entity<IgnoreSlowOnDamageComponent> ent, ref ModifySlowOnDamageSpeedEvent args)
-        {
-            args.Speed = 1f;
-        }
+    private void OnIgnoreStartup(Entity<IgnoreSlowOnDamageComponent> ent, ref ComponentStartup args)
+    {
+        _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(ent);
     }
 
-    [ByRefEvent]
-    public record struct ModifySlowOnDamageSpeedEvent(float Speed) : IInventoryRelayEvent
+    private void OnIgnoreShutdown(Entity<IgnoreSlowOnDamageComponent> ent, ref ComponentShutdown args)
     {
-        public SlotFlags TargetSlots => SlotFlags.WITHOUT_POCKET;
+        _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(ent);
     }
+
+    private void OnIgnoreModifySpeed(Entity<IgnoreSlowOnDamageComponent> ent, ref ModifySlowOnDamageSpeedEvent args)
+    {
+        args.Speed = 1f;
+    }
+}
+
+[ByRefEvent]
+public record struct ModifySlowOnDamageSpeedEvent(float Speed) : IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots => SlotFlags.WITHOUT_POCKET;
 }
index ebedeee479d219527a2932599b042e2ba50f0323..938f125b01c2df5aea322a80471799a052b33144 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Destructible.Thresholds.Triggers;
index 902198e33dd673525cea3530cd3badd2ee437d3e..c1add2e891f7ed245d5b48405f7e0510943ea09a 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Content.Shared.Damage.Prototypes;
 using Robust.Shared.Prototypes;
index 9ec2060e5f107b7728e8a7a22472bf2a051484b1..7a2d612f757941a040469a59456cff122cae9f10 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Serialization;
 
index 8f50b627911de3cbbc32e3706a188219cdf6691a..60bd9baf67d279a45e4220a51a8780ef12faea66 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Prototypes;
index 98c96a5bd58071934ca5b56dba62dd93d803963b..d97394c4065378e721223204118d4657599e6e58 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 
 namespace Content.Shared.Destructible.Thresholds.Triggers;
 
index 3e379cac7f5b9aa752f8419f27231dcc0c2537f4..cdf72bed7feb70df9f8302b97e1e0f4ac6d1da00 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Destructible.Thresholds.Triggers;
index c1a3d6ecee4800d298ef969dbdf055f69f8b0942..d80f65755ef167a1ffb603d174dd2ab426c73010 100644 (file)
@@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Threading.Tasks;
 using Content.Shared.ActionBlocker;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Hands.Components;
 using Content.Shared.Tag;
 using Robust.Shared.GameStates;
index 50132e42ddfaa02f730a5700fbf27fb86fc97ccc..c031dcc7bd832a7ce13ca8f8db547988239f8bb8 100644 (file)
@@ -2,7 +2,7 @@ using System.Linq;
 using Content.Shared.Access.Components;
 using Content.Shared.Access.Systems;
 using Content.Shared.Administration.Logs;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Doors.Components;
 using Content.Shared.Emag.Systems;
index dd877140d61c78050d52df7f77f89b5c8e917e89..3691039189e22f6dcc4028e81a7446074fee0790 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Prototypes;
index 30490c72e8ca2535ec56d2b06f95473f5929011d..f2611a8200fb36cc4a5c0af59688b219a8a91355 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Prototypes;
index 16f4a946f3cf8e3dd5438563e7c01023329b93e4..306398b4ebbc392fa104556fc41065399bea6030 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Prototypes;
 
index 33b2041b373aa0b0ee2f21805cd723e390665d1e..b26b801264092c2558d0c71c80e82ff19cbe6629 100644 (file)
@@ -1,5 +1,7 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Localizations;
 using Robust.Shared.Prototypes;
@@ -43,11 +45,10 @@ public sealed partial class EvenHealthChangeEntityEffectSystem : EntityEffectSys
         damageSpec *= args.Scale;
 
         _damageable.TryChangeDamage(
-            entity,
+            entity.AsNullable(),
             damageSpec,
             args.Effect.IgnoreResistances,
-            interruptsDoAfters: false,
-            damageable: entity.Comp);
+            interruptsDoAfters: false);
     }
 }
 
index 89948cd2e4e0b3b2fb937b1fb0184469e9b241cc..595bf15aa5bb908087d2118f4db2e21d6120b677 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Prototypes;
 using Content.Shared.FixedPoint;
 using Content.Shared.Localizations;
@@ -13,7 +14,7 @@ namespace Content.Shared.EntityEffects.Effects;
 /// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
 public sealed partial class HealthChangeEntityEffectSystem : EntityEffectSystem<DamageableComponent, HealthChange>
 {
-    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly Damage.Systems.DamageableSystem _damageable = default!;
 
     protected override void Effect(Entity<DamageableComponent> entity, ref EntityEffectEvent<HealthChange> args)
     {
@@ -22,7 +23,7 @@ public sealed partial class HealthChangeEntityEffectSystem : EntityEffectSystem<
         damageSpec *= args.Scale;
 
         _damageable.TryChangeDamage(
-                entity,
+                entity.AsNullable(),
                 damageSpec,
                 args.Effect.IgnoreResistances,
                 interruptsDoAfters: false);
@@ -49,10 +50,10 @@ public sealed partial class HealthChange : EntityEffectBase<HealthChange>
 
             var damageSpec = new DamageSpecifier(Damage);
 
-            var universalReagentDamageModifier = entSys.GetEntitySystem<DamageableSystem>().UniversalReagentDamageModifier;
-            var universalReagentHealModifier = entSys.GetEntitySystem<DamageableSystem>().UniversalReagentHealModifier;
+            var universalReagentDamageModifier = entSys.GetEntitySystem<Damage.Systems.DamageableSystem>().UniversalReagentDamageModifier;
+            var universalReagentHealModifier = entSys.GetEntitySystem<Damage.Systems.DamageableSystem>().UniversalReagentHealModifier;
 
-            damageSpec = entSys.GetEntitySystem<DamageableSystem>().ApplyUniversalAllModifiers(damageSpec);
+            damageSpec = entSys.GetEntitySystem<Damage.Systems.DamageableSystem>().ApplyUniversalAllModifiers(damageSpec);
 
             foreach (var (kind, amount) in damageSpec.DamageDict)
             {
index b6d52cf352b1091506417ff51e36d0964a8ed6e8..926e6e08c2854bc69365ea2d67a76cdd89099434 100644 (file)
@@ -1,7 +1,7 @@
 using Content.Shared.ActionBlocker;
 using Content.Shared.Chat;
 using Content.Shared.CombatMode;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Database;
 using Content.Shared.DoAfter;
 using Content.Shared.IdentityManagement;
@@ -12,7 +12,6 @@ using Content.Shared.Verbs;
 using Content.Shared.Weapons.Melee;
 using Content.Shared.Weapons.Melee.Events;
 using Content.Shared.Interaction.Events;
-using Content.Shared.Mind;
 using Robust.Shared.Player;
 using Robust.Shared.Audio.Systems;
 
index 7768c7a3d2e95969a458729defada6815fde98e6..3018b70c05e332a8a11ce039428955b1b4d93c74 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Popups;
 using Content.Shared.Fax.Components;
 
@@ -26,7 +26,7 @@ public sealed class FaxecuteSystem : EntitySystem
             return;
 
         var damageSpec = faxecute.Damage;
-        _damageable.TryChangeDamage(sendEntity, damageSpec);
+        _damageable.ChangeDamage(sendEntity.Value, damageSpec);
         _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-error", ("target", uid)), uid, PopupType.LargeCaution);
         return;
 
index 103dfb663cc37116b48899c02d85004bc6edffe8..9dbd01b89e8680eb237ffc8b11b665c8eac22f07 100644 (file)
@@ -1,5 +1,5 @@
 using Content.Shared.Flash.Components;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 
 namespace Content.Shared.Flash;
 
@@ -18,7 +18,7 @@ public sealed class DamagedByFlashingSystem : EntitySystem
     // Best wait for Ed's status effect system rewrite.
     private void OnFlashAttempt(Entity<DamagedByFlashingComponent> ent, ref FlashAttemptEvent args)
     {
-        _damageable.TryChangeDamage(ent, ent.Comp.FlashDamage);
+        _damageable.ChangeDamage(ent.Owner, ent.Comp.FlashDamage);
 
         // TODO: It would be more logical if different flashes had different power,
         // and the damage would be inflicted depending on the strength of the flash.
index 0645c51a473cd55ed43fb77054612cdcdbaee964..ae938e09953f295997da287a8b6bf6d990abcb7b 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Examine;
 using Content.Shared.FixedPoint;
 using Content.Shared.IdentityManagement;
index 6ff6d42d3baa50c7fff957a3894a1f09f504d38a..6431b3d42e106672e6dd92783d25655eadee09f0 100644 (file)
@@ -1,7 +1,7 @@
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Content.Shared.Containers.ItemSlots;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
 using Content.Shared.Examine;
 using Content.Shared.Forensics;
index 392234297cb90b132d6e58acce7eee0676b0b298..11b7f6113070f815d94d8e3436ed21feaef98986 100644 (file)
@@ -7,6 +7,7 @@ using Content.Shared.Climbing.Events;
 using Content.Shared.Contraband;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Events;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Electrocution;
 using Content.Shared.Explosion;
 using Content.Shared.Eye.Blinding.Systems;
index 530dcb437bd1cdae234f778f0895b07bd3005fbb..7e7dbd744e3d0b9014491566e662e99b40518329 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Shared.Administration.Logs;
 using Content.Shared.Body.Systems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Destructible;
 using Content.Shared.DoAfter;
@@ -330,7 +330,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem
         {
             EnsureComp<KitchenSpikeVictimComponent>(args.Target.Value);
 
-            _damageableSystem.TryChangeDamage(args.Target, ent.Comp.ButcherDamage, true);
+            _damageableSystem.ChangeDamage(args.Target.Value, ent.Comp.ButcherDamage, true);
 
             // Log severity for damaging other entities is normally medium.
             _logger.Add(LogType.Action,
@@ -428,7 +428,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem
             kitchenSpike.NextDamage += kitchenSpike.DamageInterval;
             Dirty(uid, kitchenSpike);
 
-            _damageableSystem.TryChangeDamage(contained, kitchenSpike.TimeDamage, true);
+            _damageableSystem.ChangeDamage(contained.Value, kitchenSpike.TimeDamage, true);
         }
     }
 
index 2ac2c50871f670de449981b4a3e34fc4a459b083..bd9f0003ba815e47355af7a9b8ad00613c419666 100644 (file)
@@ -2,7 +2,8 @@ using Content.Shared.Administration.Logs;
 using Content.Shared.Body.Components;
 using Content.Shared.Body.Systems;
 using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.DoAfter;
 using Content.Shared.FixedPoint;
@@ -76,12 +77,10 @@ public sealed class HealingSystem : EntitySystem
         if (healing.ModifyBloodLevel != 0 && bloodstream != null)
             _bloodstreamSystem.TryModifyBloodLevel((target.Owner, bloodstream), healing.ModifyBloodLevel);
 
-        var healed = _damageable.TryChangeDamage(target.Owner, healing.Damage * _damageable.UniversalTopicalsHealModifier, true, origin: args.Args.User);
-
-        if (healed == null && healing.BloodlossModifier != 0)
+        if (!_damageable.TryChangeDamage(target.Owner, healing.Damage * _damageable.UniversalTopicalsHealModifier, out var healed, true, origin: args.Args.User) && healing.BloodlossModifier != 0)
             return;
 
-        var total = healed?.GetTotal() ?? FixedPoint2.Zero;
+        var total = healed.GetTotal();
 
         // Re-verify that we can heal the damage.
         var dontRepeat = false;
index 01d61aa06e8e34ec5cdb46b153925bbcdeeb3695..86a8249321b25fc0660821cb8639f59d0599279d 100644 (file)
@@ -1,5 +1,5 @@
 using Content.Shared.Actions;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.DoAfter;
 using Content.Shared.FixedPoint;
 using Content.Shared.Inventory;
index 6930b029b797d32bb9e25587ae4d1c531cc17d23..861fcd8dafe66b28f5b68461e7a8120e42b1613d 100644 (file)
@@ -2,7 +2,7 @@ using System.Numerics;
 using Content.Shared.Access.Systems;
 using Content.Shared.ActionBlocker;
 using Content.Shared.Clothing;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.DeviceNetwork;
 using Content.Shared.DoAfter;
 using Content.Shared.Emp;
index 7cff0779cbe71fda18d52586fb25b898be03f418..80a0674c96cb0a6dcdab433d420359d820801bbf 100644 (file)
@@ -1,7 +1,6 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Mobs.Systems;
 using Robust.Shared.GameStates;
-using Robust.Shared.Serialization;
 
 namespace Content.Shared.Mobs.Components
 {
index 7b5ee52b272db34cf0a5483f8aa31e398f0cac7b..ded30499ee88d473dc10815dcbaef8d1cb751829 100644 (file)
@@ -3,6 +3,7 @@ using Content.Shared.Buckle.Components;
 using Content.Shared.CombatMode.Pacification;
 using Content.Shared.Damage;
 using Content.Shared.Damage.ForceSay;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Emoting;
 using Content.Shared.Hands;
 using Content.Shared.Interaction;
index d3cfda32bb519e065c43db73acf6a46088517db7..0497f3cce0b2a261552745f68bb3e9b63cb81b8d 100644 (file)
@@ -1,9 +1,8 @@
 using Content.Shared.ActionBlocker;
 using Content.Shared.Administration.Logs;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Standing;
-using Robust.Shared.Physics.Systems;
 using Robust.Shared.Timing;
 
 namespace Content.Shared.Mobs.Systems;
index a059c18dd8f40358bd3483b221d8348678e37ff3..3af7317954ef7298406d3b829744f182a9669a65 100644 (file)
@@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Content.Shared.Alert;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Mobs.Events;
index 559a6a1019a3b8445e44049c83cd263b1f6ff71e..226f2c4c4000b3bf0558495b22d4327810648e6a 100644 (file)
@@ -1,16 +1,14 @@
 using System.Diagnostics.CodeAnalysis;
 using Content.Shared.Alert;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Mobs.Systems;
 using Content.Shared.Movement.Systems;
 using Content.Shared.Nutrition.Components;
 using Content.Shared.Rejuvenate;
 using Content.Shared.StatusIcon;
-using Robust.Shared.Network;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
-using Robust.Shared.Utility;
 
 namespace Content.Shared.Nutrition.EntitySystems;
 
index 69b9bf8f8d43c4738238893dc4d93ded4abf1af8..3fd9ed07bd7e7beafbf24f5d32421470b955f4aa 100644 (file)
@@ -1,6 +1,5 @@
 using Content.Shared.Actions;
 using Content.Shared.Coordinates;
-using Content.Shared.Damage;
 using Content.Shared.Hands;
 using Content.Shared.Interaction;
 using Content.Shared.Item;
@@ -14,6 +13,7 @@ using Robust.Shared.Network;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.Manager;
 using System.Diagnostics.CodeAnalysis;
+using Content.Shared.Damage.Systems;
 
 namespace Content.Shared.Polymorph.Systems;
 
index 7a0f01b9b66c364abfbc98affc702084520032ba..7526faeb51fb59f8cc885298d81f9c5d78d8b9c5 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Shared.Administration.Logs;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.DoAfter;
 using Content.Shared.Interaction;
@@ -32,14 +33,14 @@ public sealed partial class RepairableSystem : EntitySystem
 
         if (ent.Comp.Damage != null)
         {
-            var damageChanged = _damageableSystem.TryChangeDamage(ent.Owner, ent.Comp.Damage, true, false, origin: args.User);
-            _adminLogger.Add(LogType.Healed, $"{ToPrettyString(args.User):user} repaired {ToPrettyString(ent.Owner):target} by {damageChanged?.GetTotal()}");
+            var damageChanged = _damageableSystem.ChangeDamage(ent.Owner, ent.Comp.Damage, true, false, origin: args.User);
+            _adminLogger.Add(LogType.Healed, $"{ToPrettyString(args.User):user} repaired {ToPrettyString(ent.Owner):target} by {damageChanged.GetTotal()}");
         }
 
         else
         {
             // Repair all damage
-            _damageableSystem.SetAllDamage(ent.Owner, damageable, 0);
+            _damageableSystem.SetAllDamage((ent.Owner, damageable), 0);
             _adminLogger.Add(LogType.Healed, $"{ToPrettyString(args.User):user} repaired {ToPrettyString(ent.Owner):target} back to full health");
         }
 
index 87df866c98da7995970a8f6ccdbea952f391ddb7..7a1ca31eb52921ac2d13ba37f4040df9889b7b3e 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Silicons.Borgs.Components;
 
 namespace Content.Shared.Silicons.Borgs;
index 407e586eb1c8957c8cb0a90fb08dfad28c0122db..68ee5ff405007994c50a40ff65d1655b0b034944 100644 (file)
@@ -1,5 +1,8 @@
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Serialization;
+using System.Diagnostics.CodeAnalysis;
 using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.DoAfter;
 using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
@@ -8,9 +11,6 @@ using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
 using Content.Shared.NPC.Components;
 using Content.Shared.Popups;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Serialization;
-using System.Diagnostics.CodeAnalysis;
 
 namespace Content.Shared.Silicons.Bots;
 
index 7e83b50fba15ca876405b7d961293cecfaf8f02a..273359e4d3609d406ae315edc0d52ae78e42da8c 100644 (file)
@@ -1,5 +1,5 @@
 using Content.Shared.Construction.EntitySystems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Destructible;
 using Content.Shared.Hands.Components;
 using Content.Shared.Hands.EntitySystems;
index ae8f97062399205eb7e03d5a7bf12d98e054aeef..fc2b01c649aec2647d7026a8029c58d96066400e 100644 (file)
@@ -3,6 +3,7 @@ using Content.Shared.Buckle.Components;
 using Content.Shared.CCVar;
 using Content.Shared.Damage;
 using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.DoAfter;
 using Content.Shared.Gravity;
index cdcb1044f7197fe10eec95489b7f5bf4f085d509..d021eed80d618047929fbd2f1f40164534ca5588 100644 (file)
@@ -5,7 +5,7 @@ namespace Content.Shared.Trigger.Systems;
 
 public sealed class DamageOnTriggerSystem : XOnTriggerSystem<DamageOnTriggerComponent>
 {
-    [Dependency] private readonly DamageableSystem _damageableSystem = default!;
+    [Dependency] private readonly Damage.Systems.DamageableSystem _damageableSystem = default!;
 
     protected override void OnTrigger(Entity<DamageOnTriggerComponent> ent, EntityUid target, ref TriggerEvent args)
     {
@@ -13,7 +13,7 @@ public sealed class DamageOnTriggerSystem : XOnTriggerSystem<DamageOnTriggerComp
         var ev = new BeforeDamageOnTriggerEvent(damage, target);
         RaiseLocalEvent(ent.Owner, ref ev);
 
-        args.Handled |= _damageableSystem.TryChangeDamage(target, ev.Damage, ent.Comp.IgnoreResistances, origin: ent.Owner) is not null;
+        args.Handled |= _damageableSystem.TryChangeDamage(target, ev.Damage, ent.Comp.IgnoreResistances, origin: ent.Owner);
     }
 }
 
index 8209a49efd0a1408e4629919f3b738ed11fa86b6..f252297c91324dfbb3f56bfe13e9669b32b2e8c2 100644 (file)
@@ -1,6 +1,6 @@
-using Content.Shared.Access.Components;
 using Content.Shared.Access.Systems;
-using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Interaction;
 using Content.Shared.Popups;
@@ -137,7 +137,7 @@ public abstract partial class SharedDeployableTurretSystem : EntitySystem
         if (TryComp<DamageableComponent>(ent, out var damageable))
         {
             var damageSetID = enabled ? ent.Comp.DeployedDamageModifierSetId : ent.Comp.RetractedDamageModifierSetId;
-            _damageable.SetDamageModifierSetId(ent, damageSetID, damageable);
+            _damageable.SetDamageModifierSetId((ent, damageable), damageSetID);
         }
 
         // Change the turret's fixtures
index 130687469a3285e03e3924f542d9d48e26d26655..e5298a2937e2d9d3a38c8fc373cfcc5cce2d4e62 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Weapons.Hitscan.Components;
 using Content.Shared.Weapons.Hitscan.Events;
 
@@ -22,9 +22,7 @@ public sealed class HitscanBasicDamageSystem : EntitySystem
 
         var dmg = ent.Comp.Damage * _damage.UniversalHitscanDamageModifier;
 
-        var damageDealt = _damage.TryChangeDamage(args.Data.HitEntity, dmg, origin: args.Data.Gun);
-
-        if (damageDealt == null)
+        if(!_damage.TryChangeDamage(args.Data.HitEntity.Value, dmg, out var damageDealt, origin: args.Data.Gun))
             return;
 
         var damageEvent = new HitscanDamageDealtEvent
index eab638a9fc2ac6c54c17ec19a3e2b6d6019b1cf5..b236824815f97388e83c98eb99af1ffcfe552063 100644 (file)
@@ -1,8 +1,8 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Projectiles;
 using Content.Shared.Weapons.Melee.Events;
 using Content.Shared.Whitelist;
-using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Network;
 using Robust.Shared.Physics.Events;
index 9bc0b845aee72bfcca4f287b16505228024024b7..a010dbec17fa1406b5b3285cdcc3d70219fef520 100644 (file)
@@ -7,6 +7,7 @@ using Content.Shared.Administration.Components;
 using Content.Shared.Administration.Logs;
 using Content.Shared.CombatMode;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Events;
 using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
@@ -541,9 +542,8 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
         RaiseLocalEvent(target.Value, attackedEvent);
 
         var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
-        var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, origin:user, ignoreResistances:resistanceBypass);
 
-        if (damageResult is {Empty: false})
+        if (!Damageable.TryChangeDamage(target.Value, modifiedDamage, out var damageResult, origin:user, ignoreResistances:resistanceBypass))
         {
             // If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor
             if (damageResult.DamageDict.TryGetValue("Blunt", out var bluntDamage))
@@ -568,7 +568,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
 
         _meleeSound.PlayHitSound(target.Value, user, GetHighestDamageSound(modifiedDamage, _protoManager), hitEvent.HitSoundOverride, component);
 
-        if (damageResult?.GetTotal() > FixedPoint2.Zero)
+        if (damageResult.GetTotal() > FixedPoint2.Zero)
         {
             DoDamageEffect(targets, user, targetXform);
         }
@@ -697,9 +697,9 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
             RaiseLocalEvent(entity, attackedEvent);
             var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
 
-            var damageResult = Damageable.TryChangeDamage(entity, modifiedDamage, origin: user, ignoreResistances: resistanceBypass);
+            var damageResult = Damageable.ChangeDamage(entity, modifiedDamage, origin: user, ignoreResistances: resistanceBypass);
 
-            if (damageResult != null && damageResult.GetTotal() > FixedPoint2.Zero)
+            if (damageResult.GetTotal() > FixedPoint2.Zero)
             {
                 // If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor
                 if (damageResult.DamageDict.TryGetValue("Blunt", out var bluntDamage))
index 1b7bf4bae84668e92fdf9767dc02df177c797b22..ed8849a41ac1a9f6634b029a6cff705ffb24415e 100644 (file)
@@ -7,6 +7,7 @@ using Content.Shared.Audio;
 using Content.Shared.CombatMode;
 using Content.Shared.Containers.ItemSlots;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Hands;
 using Content.Shared.Hands.EntitySystems;
index 1ef85db27fd87bcf9dab8fc751154b7b3c561e85..4d9e2e6df4c42f2962112218f3101b17d5fd8921 100644 (file)
@@ -1,6 +1,7 @@
 using System.Linq;
 using Content.Shared.Chemistry;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Interaction;
 using Content.Shared.Movement.Pulling.Events;
index 405fa338ffb8f4879d261f71cf815d87b8b09652..a0d9d0936831fe5d9abb3a0332e15aabb8798ea6 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Whitelist;
 using Content.Shared.Xenoarchaeology.Artifact.XAE.Components;
 using Robust.Shared.Random;
index eab832ce6dc4c9c5ff989274aabcc6c426593b9d..e392b9182345f4f020627c53de2fd02d1f2723f0 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Xenoarchaeology.Artifact.Components;
 using Content.Shared.Xenoarchaeology.Artifact.XAT.Components;
 using Robust.Shared.Prototypes;
index a8c4b9ff06487c6fb12a3f4e607ac7928866730a..2807fd9250a5a1f2683a443206df8e87c0dadbc1 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
 using Content.Shared.Emag.Systems;
 using Content.Shared.Examine;
 using Content.Shared.Popups;