From b2b547b8061fb33b07d7ff642c7fc7bbfe40c4c1 Mon Sep 17 00:00:00 2001 From: pathetic meowmeow Date: Fri, 6 Mar 2026 23:13:50 -0500 Subject: [PATCH] Initial decoupling pass on Damageable (#43103) * Initial decoupling pass on Damageable * ope * e * mroaw * ok sure on the medibot thing * no medibot bounds * okidooks * arcryox era * cryox moment --- .../Damage/DamageVisualsComponent.cs | 6 +- Content.Client/Damage/DamageVisualsSystem.cs | 17 ++-- .../UI/HealthAnalyzerControl.xaml.cs | 12 ++- .../Medical/Cryogenics/CryoPodWindow.xaml.cs | 5 +- .../Overlays/EntityHealthBarOverlay.cs | 10 ++- .../DamageOverlayUiController.cs | 10 ++- .../Tests/Commands/RejuvenateTest.cs | 2 +- .../Tests/Commands/SuicideCommandTests.cs | 8 +- .../Construction/Interaction/WindowRepair.cs | 7 +- .../Tests/Damageable/DamageableTest.cs | 55 ++++++------ .../DestructibleDamageGroupTest.cs | 2 +- .../DestructibleThresholdActivationTest.cs | 8 +- .../Tests/GameRules/NukeOpsTest.cs | 5 +- .../Tests/Medical/DefibrillatorTest.cs | 6 +- .../Tests/Mousetrap/MousetrapTest.cs | 21 +++-- .../Tests/Vending/VendingInteractionTest.cs | 6 +- .../Tests/Weapons/WeaponTests.cs | 11 ++- .../Systems/AdminVerbSystem.Smites.cs | 6 +- .../Atmos/EntitySystems/BarotraumaSystem.cs | 3 +- Content.Server/Cloning/CloningPodSystem.cs | 4 +- .../Construction/Conditions/MinHealth.cs | 87 ------------------- .../Damage/Systems/ExaminableDamageSystem.cs | 4 +- .../EntitySystems/ExplosionSystem.Airtight.cs | 4 +- Content.Server/Ghost/GhostSystem.cs | 3 +- Content.Server/Mech/Systems/MechSystem.cs | 2 +- Content.Server/Medical/CryoPodSystem.cs | 5 +- Content.Server/Mining/MeteorSystem.cs | 5 +- .../Specific/PickNearbyInjectableOperator.cs | 6 +- .../NPC/Systems/NPCUtilitySystem.cs | 7 +- .../Projectiles/ProjectileSystem.cs | 2 +- .../Silicons/Borgs/BorgSystem.Transponder.cs | 2 +- Content.Server/Silicons/Borgs/BorgSystem.cs | 2 + .../Silicons/StationAi/StationAiSystem.cs | 6 +- .../DamagedSiliconAccentSystem.cs | 4 +- Content.Server/Spreader/KudzuSystem.cs | 7 +- .../Blocking/BlockingSystem.User.cs | 4 +- .../Components/ChangelingDevourComponent.cs | 6 -- .../Systems/ChangelingDevourSystem.cs | 11 +-- Content.Shared/Chat/SharedSuicideSystem.cs | 4 +- .../Damage/Components/DamageableComponent.cs | 6 +- .../Damage/Components/GodmodeComponent.cs | 3 - .../Components/PassiveDamageComponent.cs | 6 -- Content.Shared/Damage/DamageSpecifier.cs | 6 +- Content.Shared/Damage/DamageVisualizerKeys.cs | 8 +- .../Damage/Systems/DamagePopupSystem.cs | 3 +- .../Damage/Systems/DamageableSystem.API.cs | 54 +++++++++++- .../Damage/Systems/PassiveDamageSystem.cs | 3 - .../Damage/Systems/SharedGodmodeSystem.cs | 13 --- .../Damage/Systems/SlowOnDamageSystem.cs | 7 +- .../Destructible/SharedDestructibleSystem.cs | 5 ++ .../Triggers/DamageGroupTrigger.cs | 2 +- .../Destructible/Triggers/DamageTrigger.cs | 2 +- .../Triggers/DamageTypeTrigger.cs | 2 +- .../DamageGroupEntityConditionSystem.cs | 38 -------- .../DamageTypeEntityConditionSystem.cs | 39 --------- .../TotalDamageEntityConditionSystem.cs | 33 ------- .../StoreDamageTakenOnMindSystem.cs | 7 +- .../HealthExaminableSystem.cs | 5 +- .../Medical/Cryogenics/CryoPodComponent.cs | 5 +- .../Medical/Healing/HealingSystem.cs | 4 +- .../Medical/SharedDefibrillatorSystem.cs | 3 +- .../Medical/Stethoscope/StethoscopeSystem.cs | 5 +- .../SuitSensors/SharedSuitSensorSystem.cs | 6 +- .../Mobs/Systems/MobThresholdSystem.cs | 7 +- Content.Shared/Repairable/RepairableSystem.cs | 10 ++- .../Silicons/Bots/MedibotComponent.cs | 23 ----- Content.Shared/Silicons/Bots/MedibotSystem.cs | 6 +- .../Locale/en-US/reagents/meta/medicine.ftl | 3 - Resources/Prototypes/Body/Species/slime.yml | 1 - Resources/Prototypes/Body/Species/vox.yml | 1 - Resources/Prototypes/Body/species_base.yml | 1 - .../Prototypes/Entities/Mobs/NPCs/animals.yml | 1 - .../Entities/Mobs/NPCs/living_light.yml | 1 - .../Entities/Mobs/NPCs/miscellaneous.yml | 1 - .../Prototypes/Entities/Mobs/NPCs/silicon.yml | 2 - .../Specific/Chemistry/chemistry-bottles.yml | 16 ---- .../Objects/Specific/Medical/morgue.yml | 2 +- .../Objects/Specific/Medical/randompill.yml | 1 - Resources/Prototypes/Reagents/medicine.yml | 53 +---------- Resources/Prototypes/Reagents/narcotics.yml | 8 +- .../Prototypes/Recipes/Reactions/medicine.yml | 14 --- .../Guidebook/Medical/Cryogenics.xml | 2 +- .../ServerInfo/Guidebook/Service/Botany.xml | 1 - 83 files changed, 281 insertions(+), 513 deletions(-) delete mode 100644 Content.Server/Construction/Conditions/MinHealth.cs delete mode 100644 Content.Shared/EntityConditions/Conditions/DamageGroupEntityConditionSystem.cs delete mode 100644 Content.Shared/EntityConditions/Conditions/DamageTypeEntityConditionSystem.cs delete mode 100644 Content.Shared/EntityConditions/Conditions/TotalDamageEntityConditionSystem.cs diff --git a/Content.Client/Damage/DamageVisualsComponent.cs b/Content.Client/Damage/DamageVisualsComponent.cs index 90171e78f9..26356496bb 100644 --- a/Content.Client/Damage/DamageVisualsComponent.cs +++ b/Content.Client/Damage/DamageVisualsComponent.cs @@ -1,4 +1,6 @@ +using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; namespace Content.Client.Damage; @@ -55,7 +57,7 @@ public sealed partial class DamageVisualsComponent : Component /// (for example, Brute), and has a value /// of a DamageVisualizerSprite (see below) /// - [DataField("damageOverlayGroups")] public Dictionary? DamageOverlayGroups; + [DataField("damageOverlayGroups")] public Dictionary, DamageVisualizerSprite>? DamageOverlayGroups; /// /// Sets if you want sprites to overlay the @@ -84,7 +86,7 @@ public sealed partial class DamageVisualsComponent : Component /// what kind of damage combination /// you would want, on which threshold. /// - [DataField("damageGroup")] public string? DamageGroup; + [DataField("damageGroup")] public ProtoId? DamageGroup; /// /// Set this if you want incoming damage to be diff --git a/Content.Client/Damage/DamageVisualsSystem.cs b/Content.Client/Damage/DamageVisualsSystem.cs index ac3ff819aa..a7eed4b06c 100644 --- a/Content.Client/Damage/DamageVisualsSystem.cs +++ b/Content.Client/Damage/DamageVisualsSystem.cs @@ -2,6 +2,7 @@ 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.FixedPoint; using Robust.Client.GameObjects; using Robust.Shared.Prototypes; @@ -28,6 +29,7 @@ namespace Content.Client.Damage; public sealed class DamageVisualsSystem : VisualizerSystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -174,7 +176,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem(uid, DamageVisualizerKeys.DamageUpdateGroups, out var data, component)) { - data = new DamageVisualizerGroupData(Comp(uid).DamagePerGroup.Keys.ToList()); + data = new DamageVisualizerGroupData(_damageable.GetDamagePerGroup(uid).Keys.ToList()); } UpdateDamageVisuals(data.GroupList, (uid, damageComponent, spriteComponent, damageVisComp)); @@ -486,11 +488,10 @@ public sealed class DamageVisualsSystem : VisualizerSystem private void UpdateDamageVisuals(Entity entity) { - var damageComponent = entity.Comp1; var spriteComponent = entity.Comp2; var damageVisComp = entity.Comp3; - if (!CheckThresholdBoundary(damageComponent.TotalDamage, damageVisComp.LastDamageThreshold, damageVisComp, out var threshold)) + if (!CheckThresholdBoundary(_damageable.GetTotalDamage(entity.AsNullable()), damageVisComp.LastDamageThreshold, damageVisComp, out var threshold)) return; damageVisComp.LastDamageThreshold = threshold; @@ -513,11 +514,11 @@ public sealed class DamageVisualsSystem : VisualizerSystem - private void UpdateDamageVisuals(List delta, Entity entity) + private void UpdateDamageVisuals(List> delta, Entity entity) { - var damageComponent = entity.Comp1; var spriteComponent = entity.Comp2; var damageVisComp = entity.Comp3; + var damage = _damageable.GetAllDamage((entity.Owner, entity.Comp1)); foreach (var damageGroup in delta) { @@ -525,7 +526,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem(damageGroup, out var damageGroupPrototype) - || !damageComponent.Damage.TryGetDamageInGroup(damageGroupPrototype, out var damageTotal)) + || !damage.TryGetDamageInGroup(damageGroupPrototype, out var damageTotal)) continue; if (!damageVisComp.LastThresholdPerGroup.TryGetValue(damageGroup, out var lastThreshold) @@ -590,7 +591,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem() { damageVisComp.DamageGroup }, entity); + UpdateDamageVisuals(new() { damageVisComp.DamageGroup.Value }, entity); } else if (damageVisComp.DamageOverlay != null) { diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerControl.xaml.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerControl.xaml.cs index 80b3e4b6a7..6a963b1a33 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerControl.xaml.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerControl.xaml.cs @@ -3,6 +3,7 @@ using System.Numerics; using Content.Shared.Atmos; using Content.Shared.Damage.Components; using Content.Shared.Damage.Prototypes; +using Content.Shared.Damage.Systems; using Content.Shared.FixedPoint; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Prototypes; @@ -30,6 +31,7 @@ public sealed partial class HealthAnalyzerControl : BoxContainer private readonly SpriteSystem _spriteSystem; private readonly IPrototypeManager _prototypes; private readonly IResourceCache _cache; + private readonly DamageableSystem _damageable; public HealthAnalyzerControl() { @@ -40,6 +42,7 @@ public sealed partial class HealthAnalyzerControl : BoxContainer _spriteSystem = _entityManager.System(); _prototypes = dependencies.Resolve(); _cache = dependencies.Resolve(); + _damageable = _entityManager.System(); } public void Populate(HealthAnalyzerUiState state) @@ -101,7 +104,7 @@ public sealed partial class HealthAnalyzerControl : BoxContainer // Total Damage - DamageLabel.Text = damageable.TotalDamage.ToString(); + DamageLabel.Text = _damageable.GetTotalDamage(target.Value).ToString(); // Alerts @@ -132,10 +135,11 @@ public sealed partial class HealthAnalyzerControl : BoxContainer // Damage Groups var damageSortedGroups = - damageable.DamagePerGroup.OrderByDescending(damage => damage.Value) + _damageable.GetDamagePerGroup(target.Value) + .OrderByDescending(damage => damage.Value) .ToDictionary(x => x.Key, x => x.Value); - var damagePerType = damageable.Damage.DamageDict; + var damagePerType = _damageable.GetAllDamage(target.Value).DamageDict; DrawDiagnosticGroups(damageSortedGroups, damagePerType); } @@ -152,7 +156,7 @@ public sealed partial class HealthAnalyzerControl : BoxContainer } private void DrawDiagnosticGroups( - Dictionary groups, + Dictionary, FixedPoint2> groups, IReadOnlyDictionary, FixedPoint2> damageDict) { GroupsContainer.RemoveAllChildren(); diff --git a/Content.Client/Medical/Cryogenics/CryoPodWindow.xaml.cs b/Content.Client/Medical/Cryogenics/CryoPodWindow.xaml.cs index f1d0e038f4..51ff5c1a00 100644 --- a/Content.Client/Medical/Cryogenics/CryoPodWindow.xaml.cs +++ b/Content.Client/Medical/Cryogenics/CryoPodWindow.xaml.cs @@ -4,6 +4,7 @@ using Content.Client.UserInterface.Controls; using Content.Shared.Atmos; using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.EntityConditions.Conditions; using Content.Shared.FixedPoint; using Content.Shared.Medical.Cryogenics; @@ -86,9 +87,7 @@ public sealed partial class CryoPodWindow : FancyWindow // Health analyzer var maybePatient = _entityManager.GetEntity(msg.Health.TargetEntity); var hasPatient = msg.Health.TargetEntity.HasValue; - var hasDamage = (hasPatient - && _entityManager.TryGetComponent(maybePatient, out DamageableComponent? damageable) - && damageable.TotalDamage > 0); + var hasDamage = hasPatient && msg.HasDamage; NoDamageText.Visible = (hasPatient && !hasDamage); HealthSection.Visible = hasPatient; diff --git a/Content.Client/Overlays/EntityHealthBarOverlay.cs b/Content.Client/Overlays/EntityHealthBarOverlay.cs index 55fc1e0974..e0bc50a33c 100644 --- a/Content.Client/Overlays/EntityHealthBarOverlay.cs +++ b/Content.Client/Overlays/EntityHealthBarOverlay.cs @@ -2,6 +2,7 @@ using System.Numerics; using Content.Client.StatusIcon; using Content.Client.UserInterface.Systems; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.FixedPoint; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; @@ -30,6 +31,7 @@ public sealed class EntityHealthBarOverlay : Overlay private readonly StatusIconSystem _statusIconSystem; private readonly SpriteSystem _spriteSystem; private readonly ProgressColorSystem _progressColor; + private readonly DamageableSystem _damageable; public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV; @@ -46,6 +48,7 @@ public sealed class EntityHealthBarOverlay : Overlay _statusIconSystem = _entManager.System(); _spriteSystem = _entManager.System(); _progressColor = _entManager.System(); + _damageable = _entManager.System(); } protected override void Draw(in OverlayDrawArgs args) @@ -129,16 +132,17 @@ public sealed class EntityHealthBarOverlay : Overlay /// private (float ratio, bool inCrit)? CalcProgress(EntityUid uid, MobStateComponent component, DamageableComponent dmg, MobThresholdsComponent thresholds) { + var totalDamage = _damageable.GetTotalDamage((uid, dmg)); if (_mobStateSystem.IsAlive(uid, component)) { - if (dmg.HealthBarThreshold != null && dmg.TotalDamage < dmg.HealthBarThreshold) + if (dmg.HealthBarThreshold != null && totalDamage < dmg.HealthBarThreshold) return null; if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var threshold, thresholds) && !_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Dead, out threshold, thresholds)) return (1, false); - var ratio = 1 - ((FixedPoint2)(dmg.TotalDamage / threshold)).Float(); + var ratio = 1 - ((FixedPoint2)(totalDamage / threshold)).Float(); return (ratio, false); } @@ -150,7 +154,7 @@ public sealed class EntityHealthBarOverlay : Overlay return (1, true); } - var ratio = 1 - ((dmg.TotalDamage - critThreshold) / (deadThreshold - critThreshold)).Value.Float(); + var ratio = 1 - ((totalDamage - critThreshold) / (deadThreshold - critThreshold)).Value.Float(); return (ratio, true); } diff --git a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs index f709df4b77..3c14e7c6b7 100644 --- a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs +++ b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs @@ -1,4 +1,5 @@ using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.FixedPoint; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; @@ -22,6 +23,7 @@ public sealed class DamageOverlayUiController : UIController [UISystemDependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; [UISystemDependency] private readonly StatusEffectsSystem _statusEffects = default!; + [UISystemDependency] private readonly DamageableSystem _damageable = default!; private Overlays.DamageOverlay _overlay = default!; public override void Initialize() @@ -90,6 +92,7 @@ public sealed class DamageOverlayUiController : UIController return; //this entity intentionally has no overlays } + var damagePerGroup = _damageable.GetDamagePerGroup((entity, damageable)); var critThreshold = foundThreshold.Value; _overlay.State = mobState.CurrentState; @@ -104,7 +107,8 @@ public sealed class DamageOverlayUiController : UIController { foreach (var painDamageType in damageable.PainDamageGroups) { - damageable.DamagePerGroup.TryGetValue(painDamageType, out var painDamage); + + damagePerGroup.TryGetValue(painDamageType, out var painDamage); painLevel += painDamage; } _overlay.PainLevel = FixedPoint2.Min(1f, painLevel / critThreshold).Float(); @@ -115,7 +119,7 @@ public sealed class DamageOverlayUiController : UIController } } - if (damageable.DamagePerGroup.TryGetValue("Airloss", out var oxyDamage)) + if (damagePerGroup.TryGetValue("Airloss", out var oxyDamage)) { _overlay.OxygenLevel = FixedPoint2.Min(1f, oxyDamage / critThreshold).Float(); } @@ -127,7 +131,7 @@ public sealed class DamageOverlayUiController : UIController case MobState.Critical: { if (!_mobThresholdSystem.TryGetDeadPercentage(entity, - FixedPoint2.Max(0.0, damageable.TotalDamage), out var critLevel)) + FixedPoint2.Max(0.0, _damageable.GetTotalDamage((entity, damageable))), out var critLevel)) return; _overlay.CritLevel = critLevel.Value.Float(); diff --git a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs index 87ff00691a..308f2797c4 100644 --- a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs @@ -89,7 +89,7 @@ namespace Content.IntegrationTests.Tests.Commands Assert.That(mobStateSystem.IsDead(human, mobState), Is.False); Assert.That(mobStateSystem.IsIncapacitated(human, mobState), Is.False); - Assert.That(damageable.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(damSystem.GetTotalDamage((human, damageable)), Is.EqualTo(FixedPoint2.Zero)); }); }); await pair.CleanReturnAsync(); diff --git a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs index 57e8bfd449..32f1f6128e 100644 --- a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs +++ b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs @@ -138,7 +138,6 @@ public sealed class SuicideCommandTests MindComponent mindComponent = default; MobStateComponent mobStateComp = default; MobThresholdsComponent mobThresholdsComp = default; - DamageableComponent damageableComp = default; await server.WaitPost(() => { if (mind != null) @@ -146,7 +145,6 @@ public sealed class SuicideCommandTests mobStateComp = entManager.GetComponent(player); mobThresholdsComp = entManager.GetComponent(player); - damageableComp = entManager.GetComponent(player); var slashProto = protoMan.Index(DamageType); damageableSystem.TryChangeDamage(player, new DamageSpecifier(slashProto, FixedPoint2.New(46.5))); @@ -165,7 +163,7 @@ public sealed class SuicideCommandTests Assert.That(mobStateSystem.IsDead(player, mobStateComp)); Assert.That(entManager.TryGetComponent(mindComponent.CurrentEntity, out var ghostComp) && !ghostComp.CanReturnToBody); - Assert.That(damageableComp.Damage.GetTotal(), Is.EqualTo(lethalDamageThreshold)); + Assert.That(damageableSystem.GetTotalDamage(player), Is.EqualTo(lethalDamageThreshold)); }); }); @@ -291,7 +289,7 @@ public sealed class SuicideCommandTests Assert.That(mobStateSystem.IsDead(player, mobStateComp)); Assert.That(entManager.TryGetComponent(mindComponent.CurrentEntity, out var ghostComp) && !ghostComp.CanReturnToBody); - Assert.That(damageableComp.Damage.DamageDict["Slash"], Is.EqualTo(lethalDamageThreshold)); + Assert.That(damageableSystem.GetAllDamage((player, damageableComp)).DamageDict["Slash"], Is.EqualTo(lethalDamageThreshold)); }); }); @@ -366,7 +364,7 @@ public sealed class SuicideCommandTests Assert.That(mobStateSystem.IsDead(player, mobStateComp)); Assert.That(entManager.TryGetComponent(mindComponent.CurrentEntity, out var ghostComp) && !ghostComp.CanReturnToBody); - Assert.That(damageableComp.Damage.DamageDict["Slash"], Is.EqualTo(lethalDamageThreshold / 2)); + Assert.That(damageableSystem.GetAllDamage((player, damageableComp)).DamageDict["Slash"], Is.EqualTo(lethalDamageThreshold / 2)); }); }); diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs b/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs index 5a4d284c0f..582a05e974 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs @@ -19,17 +19,16 @@ public sealed class WindowRepair : InteractionTest // Damage the entity. var sys = SEntMan.System(); - var comp = Comp(); var damageType = Server.ProtoMan.Index(BluntDamageType); var damage = new DamageSpecifier(damageType, FixedPoint2.New(10)); - Assert.That(comp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sys.GetTotalDamage(STarget.Value), Is.EqualTo(FixedPoint2.Zero)); await Server.WaitPost(() => sys.TryChangeDamage(SEntMan.GetEntity(Target).Value, damage, ignoreResistances: true)); await RunTicks(5); - Assert.That(comp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero)); + Assert.That(sys.GetTotalDamage(STarget.Value), Is.GreaterThan(FixedPoint2.Zero)); // Repair the entity await InteractUsing(Weld); - Assert.That(comp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sys.GetTotalDamage(STarget.Value), Is.EqualTo(FixedPoint2.Zero)); // Validate that we can still deconstruct the entity (i.e., that welding deconstruction is not blocked). await Interact( diff --git a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs index 11e7abd8a9..9777054625 100644 --- a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs +++ b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs @@ -147,6 +147,7 @@ namespace Content.IntegrationTests.Tests.Damageable await server.WaitAssertion(() => { var uid = sDamageableEntity; + var ent = new Entity(uid, sDamageableComponent); // Check that damage is evenly distributed over a group if its a nice multiple var types = group3.DamageTypes; @@ -157,11 +158,11 @@ namespace Content.IntegrationTests.Tests.Damageable Assert.Multiple(() => { - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal)); - Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(damageToDeal)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(damageToDeal)); + Assert.That(sDamageableSystem.GetDamagePerGroup(ent)[group3.ID], Is.EqualTo(damageToDeal)); foreach (var type in types) { - Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage)); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict.TryGetValue(type, out typeDamage)); Assert.That(typeDamage, Is.EqualTo(damageToDeal / types.Count)); } }); @@ -171,11 +172,11 @@ namespace Content.IntegrationTests.Tests.Damageable Assert.Multiple(() => { - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); - Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetDamagePerGroup(ent)[group3.ID], Is.EqualTo(FixedPoint2.Zero)); foreach (var type in types) { - Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage)); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict.TryGetValue(type, out typeDamage)); Assert.That(typeDamage, Is.EqualTo(FixedPoint2.Zero)); } }); @@ -190,11 +191,11 @@ namespace Content.IntegrationTests.Tests.Damageable Assert.Multiple(() => { - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(14))); - Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.New(14))); - Assert.That(sDamageableComponent.Damage.DamageDict[type3a.ID], Is.EqualTo(FixedPoint2.New(4.66f))); - Assert.That(sDamageableComponent.Damage.DamageDict[type3b.ID], Is.EqualTo(FixedPoint2.New(4.67f))); - Assert.That(sDamageableComponent.Damage.DamageDict[type3c.ID], Is.EqualTo(FixedPoint2.New(4.67f))); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.New(14))); + Assert.That(sDamageableSystem.GetDamagePerGroup(ent)[group3.ID], Is.EqualTo(FixedPoint2.New(14))); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict[type3a.ID], Is.EqualTo(FixedPoint2.New(4.66f))); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict[type3b.ID], Is.EqualTo(FixedPoint2.New(4.67f))); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict[type3c.ID], Is.EqualTo(FixedPoint2.New(4.67f))); }); // Heal @@ -202,36 +203,36 @@ namespace Content.IntegrationTests.Tests.Damageable Assert.Multiple(() => { - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); - Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetDamagePerGroup(ent)[group3.ID], Is.EqualTo(FixedPoint2.Zero)); foreach (var type in types) { - Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage)); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict.TryGetValue(type, out typeDamage)); Assert.That(typeDamage, Is.EqualTo(FixedPoint2.Zero)); } // Test that unsupported groups return false when setting/getting damage (and don't change damage) - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); }); damage = new DamageSpecifier(group1, FixedPoint2.New(10)) + new DamageSpecifier(type2b, FixedPoint2.New(10)); sDamageableSystem.ChangeDamage(uid, damage, true); Assert.Multiple(() => { - Assert.That(sDamageableComponent.DamagePerGroup.TryGetValue(group1.ID, out _), Is.False); - Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type1.ID, out typeDamage), Is.False); - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetDamagePerGroup(ent).TryGetValue(group1.ID, out _), Is.False); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict.TryGetValue(type1.ID, out typeDamage), Is.False); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); }); // Test SetAll and ClearAll function sDamageableSystem.SetAllDamage((sDamageableEntity, sDamageableComponent), 10); - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(10 * sDamageableComponent.Damage.DamageDict.Count))); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.New(10 * sDamageableSystem.GetAllDamage(uid).DamageDict.Count))); sDamageableSystem.SetAllDamage((sDamageableEntity, sDamageableComponent), 0); - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); sDamageableSystem.SetAllDamage((sDamageableEntity, sDamageableComponent), 10); - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(10 * sDamageableComponent.Damage.DamageDict.Count))); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.New(10 * sDamageableSystem.GetAllDamage(uid).DamageDict.Count))); sDamageableSystem.ClearAllDamage((sDamageableEntity, sDamageableComponent)); - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); // Test 'wasted' healing sDamageableSystem.ChangeDamage(uid, new DamageSpecifier(type3a, 5)); @@ -240,18 +241,18 @@ namespace Content.IntegrationTests.Tests.Damageable Assert.Multiple(() => { - Assert.That(sDamageableComponent.Damage.DamageDict[type3a.ID], Is.EqualTo(FixedPoint2.New(1.34))); - Assert.That(sDamageableComponent.Damage.DamageDict[type3b.ID], Is.EqualTo(FixedPoint2.New(3.33))); - Assert.That(sDamageableComponent.Damage.DamageDict[type3c.ID], Is.EqualTo(FixedPoint2.New(0))); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict[type3a.ID], Is.EqualTo(FixedPoint2.New(1.34))); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict[type3b.ID], Is.EqualTo(FixedPoint2.New(3.33))); + Assert.That(sDamageableSystem.GetAllDamage(uid).DamageDict[type3c.ID], Is.EqualTo(FixedPoint2.New(0))); }); // Test Over-Healing sDamageableSystem.ChangeDamage(uid, new DamageSpecifier(group3, FixedPoint2.New(-100))); - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); // Test that if no health change occurred, returns false sDamageableSystem.ChangeDamage(uid, new DamageSpecifier(group3, -100)); - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(ent), Is.EqualTo(FixedPoint2.Zero)); }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs index 99f68b3fa3..f5010eefdc 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs @@ -117,7 +117,7 @@ namespace Content.IntegrationTests.Tests.Destructible sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage * -10); Assert.Multiple(() => { - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(20))); + Assert.That(sDamageableSystem.GetTotalDamage(sDestructibleEntity), Is.EqualTo(FixedPoint2.New(20))); // No new thresholds reached, healing should not trigger it Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty); diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs index 1736d3d7e3..4460affedf 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs @@ -195,7 +195,7 @@ namespace Content.IntegrationTests.Tests.Destructible Assert.Multiple(() => { // Check that the total damage matches - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(50))); + Assert.That(sDamageableSystem.GetTotalDamage(sDestructibleEntity), Is.EqualTo(FixedPoint2.New(50))); // Both thresholds should have triggered Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Has.Exactly(2).Items); @@ -252,7 +252,7 @@ namespace Content.IntegrationTests.Tests.Destructible sDamageableSystem.ClearAllDamage((sDestructibleEntity, sDamageableComponent)); // Check that the entity has 0 damage - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(sDamageableSystem.GetTotalDamage(sDestructibleEntity), Is.EqualTo(FixedPoint2.Zero)); // Set both thresholds to only trigger once foreach (var destructibleThreshold in sDestructibleComponent.Thresholds) @@ -267,7 +267,7 @@ namespace Content.IntegrationTests.Tests.Destructible Assert.Multiple(() => { // Check that the total damage matches - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(50))); + Assert.That(sDamageableSystem.GetTotalDamage(sDestructibleEntity), Is.EqualTo(FixedPoint2.New(50))); // No thresholds should have triggered as they were already triggered before, and they are set to only trigger once Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty); @@ -283,7 +283,7 @@ namespace Content.IntegrationTests.Tests.Destructible Assert.Multiple(() => { // Check that the total damage matches - Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(50))); + Assert.That(sDamageableSystem.GetTotalDamage(sDestructibleEntity), Is.EqualTo(FixedPoint2.New(50))); // They shouldn't have been triggered by changing TriggersOnce Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty); diff --git a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs index ebb58a173c..53165adca0 100644 --- a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs @@ -11,6 +11,7 @@ using Content.Server.RoundEnd; using Content.Server.Shuttles.Components; using Content.Shared.CCVar; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.FixedPoint; using Content.Shared.GameTicking; using Content.Shared.Hands.Components; @@ -58,6 +59,7 @@ public sealed class NukeOpsTest var invSys = server.System(); var factionSys = server.System(); var roundEndSys = server.System(); + var damageSys = server.System(); server.CfgMan.SetCVar(CCVars.GridFill, true); @@ -231,12 +233,11 @@ public sealed class NukeOpsTest var totalSeconds = 30; var totalTicks = (int)Math.Ceiling(totalSeconds / server.Timing.TickPeriod.TotalSeconds); var increment = 5; - var damage = entMan.GetComponent(player); for (var tick = 0; tick < totalTicks; tick += increment) { await pair.RunTicksSync(increment); Assert.That(resp.SuffocationCycles, Is.LessThanOrEqualTo(resp.SuffocationCycleThreshold)); - Assert.That(damage.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); + Assert.That(damageSys.GetTotalDamage(player), Is.EqualTo(FixedPoint2.Zero)); } } diff --git a/Content.IntegrationTests/Tests/Medical/DefibrillatorTest.cs b/Content.IntegrationTests/Tests/Medical/DefibrillatorTest.cs index 9781bf5c80..18361a9d90 100644 --- a/Content.IntegrationTests/Tests/Medical/DefibrillatorTest.cs +++ b/Content.IntegrationTests/Tests/Medical/DefibrillatorTest.cs @@ -47,7 +47,7 @@ public sealed class DefibrillatorTest : InteractionTest Assert.Multiple(() => { Assert.That(targetMobState.CurrentState, Is.EqualTo(MobState.Alive), "Target mob was not alive when spawned."); - Assert.That(targetDamageable.TotalDamage, Is.EqualTo(FixedPoint2.Zero), "Target mob was damaged when spawned."); + Assert.That(damageableSystem.GetTotalDamage(STarget!.Value), Is.EqualTo(FixedPoint2.Zero), "Target mob was damaged when spawned."); }); // Get the damage needed to kill or crit the target. @@ -64,7 +64,7 @@ public sealed class DefibrillatorTest : InteractionTest Assert.Multiple(() => { Assert.That(targetMobState.CurrentState, Is.EqualTo(MobState.Dead), "Target mob did not die from deadly damage amount."); - Assert.That(targetDamageable.TotalDamage, Is.EqualTo(deathThreshold), "Target mob had the wrong total damage amount after being killed."); + Assert.That(damageableSystem.GetTotalDamage(STarget!.Value), Is.EqualTo(deathThreshold), "Target mob had the wrong total damage amount after being killed."); }); // Spawn a defib and activate it. @@ -82,7 +82,7 @@ public sealed class DefibrillatorTest : InteractionTest Assert.Multiple(() => { Assert.That(targetMobState.CurrentState, Is.EqualTo(MobState.Dead), "Target mob was revived despite being over the death damage threshold."); - Assert.That(targetDamageable.TotalDamage, Is.GreaterThan(deathThreshold), "Target mob did not take damage from being defibrillated."); + Assert.That(damageableSystem.GetTotalDamage(STarget!.Value), Is.GreaterThan(deathThreshold), "Target mob did not take damage from being defibrillated."); }); // Set the damage halfway between the crit and death thresholds so that the target can be revived. diff --git a/Content.IntegrationTests/Tests/Mousetrap/MousetrapTest.cs b/Content.IntegrationTests/Tests/Mousetrap/MousetrapTest.cs index 5f1b9172dd..52432e631b 100644 --- a/Content.IntegrationTests/Tests/Mousetrap/MousetrapTest.cs +++ b/Content.IntegrationTests/Tests/Mousetrap/MousetrapTest.cs @@ -1,6 +1,7 @@ using Content.IntegrationTests.Tests.Movement; using Content.Server.NPC.HTN; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.Item.ItemToggle; using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Mobs; @@ -44,9 +45,8 @@ public sealed class MousetrapMouseMoveOverTest : MovementTest // The mouse is spawned by the test before the atmosphere is added, so it has some barotrauma damage already // TODO: fix this since it can have an impact on integration tests - Assert.That(SEntMan.TryGetComponent(SPlayer, out var damageComp), - $"Player does not have a DamageableComponent."); - var startingDamage = damageComp.TotalDamage; + var damageSystem = Server.System(); + var startingDamage = damageSystem.GetTotalDamage(SPlayer); Assert.That(SEntMan.TryGetComponent(SPlayer, out var mouseMobStateComp), $"{MouseProtoId} does not have a MobStateComponent."); @@ -58,7 +58,7 @@ public sealed class MousetrapMouseMoveOverTest : MovementTest Assert.That(Delta(), Is.LessThan(0.5), "Mouse did not move over mousetrap."); // Walking over an inactive trap does not trigger it - Assert.That(damageComp.TotalDamage, Is.LessThanOrEqualTo(startingDamage), "Mouse took damage from inactive trap!"); + Assert.That(damageSystem.GetTotalDamage(SPlayer), Is.LessThanOrEqualTo(startingDamage), "Mouse took damage from inactive trap!"); Assert.That(itemToggleComp.Activated, Is.False, "Mousetrap was activated."); // Activate the trap @@ -72,7 +72,7 @@ public sealed class MousetrapMouseMoveOverTest : MovementTest Assert.That(Delta(), Is.LessThan(0.1), "Mouse moved past active mousetrap."); // Walking over an active trap triggers it - Assert.That(damageComp.TotalDamage, Is.GreaterThan(startingDamage), "Mouse did not take damage from active trap!"); + Assert.That(damageSystem.GetTotalDamage(SPlayer), Is.GreaterThan(startingDamage), "Mouse did not take damage from active trap!"); Assert.That(itemToggleComp.Activated, Is.False, "Mousetrap was not deactivated after triggering."); Assert.That(mouseMobStateComp.CurrentState, Is.EqualTo(MobState.Dead), "Mouse was not killed by trap."); } @@ -117,9 +117,8 @@ public sealed class MousetrapHumanMoveOverTest : MovementTest Assert.That(itemToggleSystem.TrySetActive(STarget.Value, true), "Could not activate the mouse trap."); }); - Assert.That(SEntMan.TryGetComponent(SPlayer, out var damageComp), - $"Player does not have a DamageableComponent."); - var startingDamage = damageComp.TotalDamage; + var damageSystem = Server.System(); + var startingDamage = damageSystem.GetTotalDamage(SPlayer); // Move player over the trap await Move(DirectionFlag.East, 0.5f); @@ -127,7 +126,7 @@ public sealed class MousetrapHumanMoveOverTest : MovementTest Assert.That(Delta(), Is.LessThan(0.5), "Player did not move over mousetrap."); // Walking over the trap without shoes activates it - Assert.That(damageComp.TotalDamage, Is.GreaterThan(startingDamage), "Player did not take damage."); + Assert.That(damageSystem.GetTotalDamage(SPlayer), Is.GreaterThan(startingDamage), "Player did not take damage."); Assert.That(itemToggleComp.Activated, Is.False, "Mousetrap was not deactivated after triggering."); // Reactivate the trap @@ -135,7 +134,7 @@ public sealed class MousetrapHumanMoveOverTest : MovementTest { Assert.That(itemToggleSystem.TrySetActive(STarget.Value, true), "Could not activate the mouse trap."); }); - var afterStepDamage = damageComp.TotalDamage; + var afterStepDamage = damageSystem.GetTotalDamage(SPlayer); // Give the player some shoes await PlaceInHands(ShoesProtoId); @@ -147,7 +146,7 @@ public sealed class MousetrapHumanMoveOverTest : MovementTest Assert.That(Delta(), Is.GreaterThan(0.5), "Player did not move back over mousetrap."); // Walking over the trap with shoes on does not activate it - Assert.That(damageComp.TotalDamage, Is.LessThanOrEqualTo(afterStepDamage), "Player took damage from trap!"); + Assert.That(damageSystem.GetTotalDamage(SPlayer), Is.LessThanOrEqualTo(afterStepDamage), "Player took damage from trap!"); Assert.That(itemToggleComp.Activated, "Mousetrap was deactivated despite the player being protected by shoes."); } } diff --git a/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs b/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs index af16f1278a..f7e5bc2a33 100644 --- a/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs +++ b/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs @@ -196,14 +196,14 @@ public sealed class VendingInteractionTest : InteractionTest private async Task BreakVendor() { var damageableSys = SEntMan.System(); - Assert.That(TryComp(out var damageableComp), $"{VendingMachineProtoId} does not have DamageableComponent."); - Assert.That(damageableComp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero), $"{VendingMachineProtoId} started with unexpected damage."); + Assert.That(HasComp(), $"{VendingMachineProtoId} does not have DamageableComponent."); + Assert.That(damageableSys.GetAllDamage(STarget!.Value).GetTotal(), Is.EqualTo(FixedPoint2.Zero), $"{VendingMachineProtoId} started with unexpected damage."); // 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).Value, damage, ignoreResistances: true)); await RunTicks(5); - Assert.That(damageableComp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero), $"{VendingMachineProtoId} did not take damage."); + Assert.That(damageableSys.GetAllDamage(STarget!.Value).GetTotal(), Is.GreaterThan(FixedPoint2.Zero), $"{VendingMachineProtoId} did not take damage."); } } diff --git a/Content.IntegrationTests/Tests/Weapons/WeaponTests.cs b/Content.IntegrationTests/Tests/Weapons/WeaponTests.cs index 135e75f8be..8ddbe0ed08 100644 --- a/Content.IntegrationTests/Tests/Weapons/WeaponTests.cs +++ b/Content.IntegrationTests/Tests/Weapons/WeaponTests.cs @@ -1,5 +1,7 @@ using Content.IntegrationTests.Tests.Interaction; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; +using Content.Shared.FixedPoint; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Systems; using Content.Shared.Wieldable.Components; @@ -17,6 +19,7 @@ public sealed class WeaponTests : InteractionTest public async Task GunRequiresWieldTest() { var gunSystem = SEntMan.System(); + var damageSystem = SEntMan.System(); await AddAtmosphere(); // prevent the Urist from suffocating @@ -44,8 +47,8 @@ public sealed class WeaponTests : InteractionTest Assert.That(updatedAmmo, Is.EqualTo(startAmmo), "Mosin discharged ammo when the weapon should not have fired!"); - Assert.That(damageComp.TotalDamage.Value, - Is.EqualTo(0), + Assert.That(damageSystem.GetTotalDamage(ToServer(urist)), + Is.EqualTo(FixedPoint2.Zero), "Urist took damage when the weapon should not have fired!"); await UseInHand(); @@ -56,8 +59,8 @@ public sealed class WeaponTests : InteractionTest updatedAmmo = gunSystem.GetAmmoCount(mosinEnt); Assert.That(updatedAmmo, Is.EqualTo(startAmmo - 1), "Mosin failed to discharge appropriate amount of ammo!"); - Assert.That(damageComp.TotalDamage.Value, - Is.GreaterThan(0), + Assert.That(damageSystem.GetTotalDamage(ToServer(urist)), + Is.GreaterThan(FixedPoint2.Zero), "Mosin was fired but urist sustained no damage!"); } } diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index dab886f810..540bd7d089 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -95,6 +95,7 @@ public sealed partial class AdminVerbSystem [Dependency] private readonly SuperBonkSystem _superBonkSystem = default!; [Dependency] private readonly SlipperySystem _slipperySystem = default!; [Dependency] private readonly GibbingSystem _gibbing = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; private readonly EntProtoId _actionViewLawsProtoId = "ActionViewLaws"; private readonly ProtoId _crewsimovLawset = "Crewsimov"; @@ -230,6 +231,7 @@ public sealed partial class AdminVerbSystem Icon = new SpriteSpecifier.Rsi(new("/Textures/Clothing/Hands/Gloves/Color/yellow.rsi"), "icon"), Act = () => { + var totalDamage = _damageable.GetTotalDamage((args.Target, damageable)); int damageToDeal; if (!_mobThresholdSystem.TryGetThresholdForState(args.Target, MobState.Critical, out var criticalThreshold)) { @@ -237,11 +239,11 @@ public sealed partial class AdminVerbSystem if (!_mobThresholdSystem.TryGetThresholdForState(args.Target, MobState.Dead, out var deadThreshold)) return;// whelp. - damageToDeal = deadThreshold.Value.Int() - (int)damageable.TotalDamage; + damageToDeal = deadThreshold.Value.Int() - (int)totalDamage; } else { - damageToDeal = criticalThreshold.Value.Int() - (int)damageable.TotalDamage; + damageToDeal = criticalThreshold.Value.Int() - (int)totalDamage; } if (damageToDeal <= 0) diff --git a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs index c23f58637d..6eb46b1946 100644 --- a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs +++ b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs @@ -211,9 +211,10 @@ namespace Content.Server.Atmos.EntitySystems while (enumerator.MoveNext(out var uid, out var barotrauma, out var damageable)) { var totalDamage = FixedPoint2.Zero; + var damageSpecifier = _damageableSystem.GetAllDamage((uid, damageable)); foreach (var (barotraumaDamageType, _) in barotrauma.Damage.DamageDict) { - if (!damageable.Damage.DamageDict.TryGetValue(barotraumaDamageType, out var damage)) + if (!damageSpecifier.DamageDict.TryGetValue(barotraumaDamageType, out var damage)) continue; totalDamage += damage; } diff --git a/Content.Server/Cloning/CloningPodSystem.cs b/Content.Server/Cloning/CloningPodSystem.cs index 67d6dc39a6..706a6fdc77 100644 --- a/Content.Server/Cloning/CloningPodSystem.cs +++ b/Content.Server/Cloning/CloningPodSystem.cs @@ -30,6 +30,7 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Content.Shared.Chemistry.Reagent; +using Content.Shared.Damage.Systems; namespace Content.Server.Cloning; @@ -55,6 +56,7 @@ public sealed class CloningPodSystem : EntitySystem [Dependency] private readonly SharedMindSystem _mindSystem = default!; [Dependency] private readonly CloningSystem _cloning = default!; [Dependency] private readonly EmagSystem _emag = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public readonly Dictionary ClonesWaitingForMind = new(); public readonly ProtoId SettingsId = "CloningPod"; @@ -180,7 +182,7 @@ public sealed class CloningPodSystem : EntitySystem // genetic damage checks if (TryComp(bodyToClone, out var damageable) && - damageable.Damage.DamageDict.TryGetValue("Cellular", out var cellularDmg)) + _damageable.GetAllDamage((bodyToClone, damageable)).DamageDict.TryGetValue("Cellular", out var cellularDmg)) { var chance = Math.Clamp((float)(cellularDmg / 100), 0, 1); chance *= failChanceModifier; diff --git a/Content.Server/Construction/Conditions/MinHealth.cs b/Content.Server/Construction/Conditions/MinHealth.cs deleted file mode 100644 index cef30db71f..0000000000 --- a/Content.Server/Construction/Conditions/MinHealth.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Content.Server.Destructible; -using Content.Shared.Construction; -using Content.Shared.Damage.Components; -using Content.Shared.Examine; -using Content.Shared.FixedPoint; - -namespace Content.Server.Construction.Conditions; - -/// -/// Requires that the structure has at least some amount of health -/// -[DataDefinition] -public sealed partial class MinHealth : IGraphCondition -{ - /// - /// If ByProportion is true, Threshold is a value less than or equal to 1, but more than 0, - /// which is compared to the percent of health remaining in the structure. - /// Else, Threshold is any positive value with at most 2 decimal points of percision, - /// which is compared to the current health of the structure. - /// - [DataField] - public FixedPoint2 Threshold = 1; - [DataField] - public bool ByProportion = false; - - [DataField] - public bool IncludeEquals = true; - - public bool Condition(EntityUid uid, IEntityManager entMan) - { - if (!entMan.TryGetComponent(uid, out DestructibleComponent? destructibleComp) || - !entMan.TryGetComponent(uid, out DamageableComponent? damageComp)) - { - return false; - } - - var destructionSys = entMan.System(); - var maxHealth = destructionSys.DestroyedAt(uid, destructibleComp); - var curHealth = maxHealth - damageComp.TotalDamage; - var proportionHealth = curHealth / maxHealth; - - if (IncludeEquals) - { - if (ByProportion) - { - return proportionHealth >= Threshold; - } - else - { - return curHealth >= Threshold; - } - } - else - { - if (ByProportion) - { - return proportionHealth > Threshold; - } - else - { - return curHealth > Threshold; - } - } - } - - public bool DoExamine(ExaminedEvent args) - { - var entMan = IoCManager.Resolve(); - var entity = args.Examined; - - if (Condition(entity, entMan)) - { - return false; - } - args.PushMarkup(Loc.GetString("construction-examine-condition-low-health")); - - return true; - } - - public IEnumerable GenerateGuideEntry() - { - yield return new ConstructionGuideEntry() - { - Localization = "construction-step-condition-low-health" - }; - } -} diff --git a/Content.Server/Damage/Systems/ExaminableDamageSystem.cs b/Content.Server/Damage/Systems/ExaminableDamageSystem.cs index a2a9f234f5..e2b686dd31 100644 --- a/Content.Server/Damage/Systems/ExaminableDamageSystem.cs +++ b/Content.Server/Damage/Systems/ExaminableDamageSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Damage.Components; using Content.Server.Destructible; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.Examine; using Content.Shared.Rounding; using Robust.Shared.Prototypes; @@ -11,6 +12,7 @@ public sealed class ExaminableDamageSystem : EntitySystem { [Dependency] private readonly DestructibleSystem _destructible = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -39,7 +41,7 @@ public sealed class ExaminableDamageSystem : EntitySystem if (!TryComp(ent, out var damageable)) return 0; - var damage = damageable.TotalDamage; + var damage = _damageable.GetTotalDamage((ent, damageable)); var damageThreshold = _destructible.DestroyedAt(ent); if (damageThreshold == 0) diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs index da2a571900..d70029ae97 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs @@ -245,7 +245,7 @@ public sealed partial class ExplosionSystem var damagePerIntensity = FixedPoint2.Zero; foreach (var (type, value) in explosionType.DamagePerIntensity.DamageDict) { - if (!damageable.Damage.DamageDict.ContainsKey(type)) + if (_damageableSystem.CanBeDamagedBy((uid, damageable), type)) continue; // TODO EXPLOSION SYSTEM @@ -260,7 +260,7 @@ public sealed partial class ExplosionSystem } var toleranceValue = damagePerIntensity > 0 - ? (float) ((totalDamageTarget - damageable.TotalDamage) / damagePerIntensity) + ? (float) ((totalDamageTarget - _damageableSystem.GetTotalDamage((uid, damageable))) / damagePerIntensity) : ToleranceValues.Invulnerable; explosionTolerance[index] = toleranceValue; diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index cccee48ba5..9d3d05c607 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -590,7 +590,8 @@ namespace Content.Server.Ghost && TryComp(playerEntity, out var thresholds)) { var playerDeadThreshold = _mobThresholdSystem.GetThresholdForState(playerEntity.Value, MobState.Dead, thresholds); - dealtDamage = playerDeadThreshold - damageable.TotalDamage; + dealtDamage = playerDeadThreshold - + _damageable.GetTotalDamage((playerEntity.Value, damageable)); } DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage); diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs index f4b7ee48a8..36fd072210 100644 --- a/Content.Server/Mech/Systems/MechSystem.cs +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -258,7 +258,7 @@ public sealed partial class MechSystem : SharedMechSystem private void OnDamageChanged(EntityUid uid, MechComponent component, DamageChangedEvent args) { - var integrity = component.MaxIntegrity - args.Damageable.TotalDamage; + var integrity = component.MaxIntegrity - _damageable.GetTotalDamage((uid, args.Damageable)); SetIntegrity(uid, integrity, component); if (args.DamageIncreased && diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs index e54f80bca9..239de94455 100644 --- a/Content.Server/Medical/CryoPodSystem.cs +++ b/Content.Server/Medical/CryoPodSystem.cs @@ -6,6 +6,7 @@ using Content.Server.NodeContainer.EntitySystems; using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.Nodes; using Content.Shared.Atmos; +using Content.Shared.Damage.Systems; using Content.Shared.Medical.Cryogenics; namespace Content.Server.Medical; @@ -16,6 +17,7 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem [Dependency] private readonly GasAnalyzerSystem _gasAnalyzerSystem = default!; [Dependency] private readonly HealthAnalyzerSystem _healthAnalyzerSystem = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() @@ -55,11 +57,12 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem var injecting = GetInjectingReagents(entity); var health = _healthAnalyzerSystem.GetHealthAnalyzerUiState(patient); health.ScanMode = true; + var hasDamage = patient is null ? false : _damageable.GetTotalDamage(patient.Value) > 0; UI.ServerSendUiMessage( entity.Owner, CryoPodUiKey.Key, - new CryoPodUserMessage(gasMix, health, beakerCapacity, beaker, injecting) + new CryoPodUserMessage(gasMix, health, beakerCapacity, beaker, injecting, hasDamage) ); } diff --git a/Content.Server/Mining/MeteorSystem.cs b/Content.Server/Mining/MeteorSystem.cs index 361844ba25..e5f190167d 100644 --- a/Content.Server/Mining/MeteorSystem.cs +++ b/Content.Server/Mining/MeteorSystem.cs @@ -46,12 +46,13 @@ public sealed class MeteorSystem : EntitySystem { threshold = FixedPoint2.MaxValue; } - var otherEntDamage = CompOrNull(args.OtherEntity)?.TotalDamage ?? FixedPoint2.Zero; + + var otherEntDamage = _damageable.GetTotalDamage(args.OtherEntity); // account for the damage that the other entity has already taken: don't overkill threshold -= otherEntDamage; // The max amount of damage our meteor can take before breaking. - var maxMeteorDamage = _destructible.DestroyedAt(uid) - CompOrNull(uid)?.TotalDamage ?? FixedPoint2.Zero; + var maxMeteorDamage = _destructible.DestroyedAt(uid) - _damageable.GetTotalDamage(uid); // Cap damage so we don't overkill the meteor var trueDamage = FixedPoint2.Min(maxMeteorDamage, threshold); diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs index 6f656b0e29..53164ad7ca 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs @@ -4,10 +4,12 @@ using Content.Shared.NPC.Components; using Content.Server.NPC.Pathfinding; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.Interaction; using Content.Shared.Mobs.Components; using Content.Shared.Silicons.Bots; using Content.Shared.Emag.Components; +using Content.Shared.FixedPoint; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific; @@ -16,6 +18,7 @@ public sealed partial class PickNearbyInjectableOperator : HTNOperator [Dependency] private readonly IEntityManager _entManager = default!; private MedibotSystem _medibot = default!; private PathfindingSystem _pathfinding = default!; + private DamageableSystem _damageable = default!; private EntityQuery _damageQuery = default!; private EntityQuery _injectQuery = default!; @@ -42,6 +45,7 @@ public sealed partial class PickNearbyInjectableOperator : HTNOperator base.Initialize(sysManager); _medibot = sysManager.GetEntitySystem(); _pathfinding = sysManager.GetEntitySystem(); + _damageable = sysManager.GetEntitySystem(); _damageQuery = _entManager.GetEntityQuery(); _injectQuery = _entManager.GetEntityQuery(); @@ -79,7 +83,7 @@ public sealed partial class PickNearbyInjectableOperator : HTNOperator // Only go towards a target if the bot can actually help them or if the medibot is emagged // note: this and the actual injecting don't check for specific damage types so for example, // radiation damage will trigger injection but the tricordrazine won't heal it. - if (!_emaggedQuery.HasComponent(entity) && !treatment.IsValid(damage.TotalDamage)) + if (!_emaggedQuery.HasComponent(entity) && _damageable.GetTotalDamage((entity, damage)) == FixedPoint2.Zero) continue; //Needed to make sure it doesn't sometimes stop right outside it's interaction range diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs index 9b791ae2f0..fe3dc26c91 100644 --- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs +++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs @@ -29,6 +29,7 @@ using Robust.Shared.Utility; using Content.Shared.Atmos.Components; using System.Linq; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.Temperature.Components; namespace Content.Server.NPC.Systems; @@ -54,6 +55,7 @@ public sealed class NPCUtilitySystem : EntitySystem [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; [Dependency] private readonly MobThresholdSystem _thresholdSystem = default!; [Dependency] private readonly TurretTargetSettingsSystem _turretTargetSettings = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; private EntityQuery _puddleQuery; private EntityQuery _xformQuery; @@ -304,9 +306,10 @@ public sealed class NPCUtilitySystem : EntitySystem { if (!TryComp(targetUid, out DamageableComponent? damage)) return 0f; - if (con.TargetState != MobState.Invalid && _thresholdSystem.TryGetPercentageForState(targetUid, con.TargetState, damage.TotalDamage, out var percentage)) + var totalDamage = _damageable.GetTotalDamage((targetUid, damage)); + if (con.TargetState != MobState.Invalid && _thresholdSystem.TryGetPercentageForState(targetUid, con.TargetState, totalDamage, out var percentage)) return Math.Clamp((float)(1 - percentage), 0f, 1f); - if (_thresholdSystem.TryGetIncapPercentage(targetUid, damage.TotalDamage, out var incapPercentage)) + if (_thresholdSystem.TryGetIncapPercentage(targetUid, totalDamage, out var incapPercentage)) return Math.Clamp((float)(1 - incapPercentage), 0f, 1f); return 0f; } diff --git a/Content.Server/Projectiles/ProjectileSystem.cs b/Content.Server/Projectiles/ProjectileSystem.cs index 01fe80e094..b5eef17b6a 100644 --- a/Content.Server/Projectiles/ProjectileSystem.cs +++ b/Content.Server/Projectiles/ProjectileSystem.cs @@ -53,7 +53,7 @@ public sealed class ProjectileSystem : SharedProjectileSystem var damageRequired = _destructibleSystem.DestroyedAt(target); if (TryComp(target, out var damageableComponent)) { - damageRequired -= damageableComponent.TotalDamage; + damageRequired -= _damageableSystem.GetTotalDamage((target, damageableComponent)); damageRequired = FixedPoint2.Max(damageRequired, FixedPoint2.Zero); } var deleted = Deleted(target); diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs index a6d3cf1dff..d181c7e228 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs @@ -179,7 +179,7 @@ public sealed partial class BorgSystem return 1; } - return 1 - ((FixedPoint2)(damageable.TotalDamage / threshold)).Float(); + return 1 - ((FixedPoint2)(_damageable.GetTotalDamage((uid, damageable)) / threshold)).Float(); } /// diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 925050f28e..063514060e 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Administration.Managers; using Content.Server.DeviceNetwork.Systems; using Content.Shared.Containers.ItemSlots; +using Content.Shared.Damage.Systems; using Content.Shared.Emag.Systems; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; @@ -31,6 +32,7 @@ public sealed partial class BorgSystem : SharedBorgSystem [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly PowerCellSystem _powerCell = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public static readonly ProtoId BorgJobId = "Borg"; diff --git a/Content.Server/Silicons/StationAi/StationAiSystem.cs b/Content.Server/Silicons/StationAi/StationAiSystem.cs index 36aa9acd6b..cc2f7a4e2f 100644 --- a/Content.Server/Silicons/StationAi/StationAiSystem.cs +++ b/Content.Server/Silicons/StationAi/StationAiSystem.cs @@ -120,7 +120,7 @@ public sealed class StationAiSystem : SharedStationAiSystem // Set the new AI brain to the 'rebooting' state if (TryComp(aiBrain, out var customization)) SetStationAiState((aiBrain, customization), StationAiState.Rebooting); - + } // Delete the new AI brain if it cannot be inserted into the core @@ -252,7 +252,7 @@ public sealed class StationAiSystem : SharedStationAiSystem accent.OverrideChargeLevel = _battery.GetChargeLevel((ent.Owner, battery)); if (TryComp(ent, out var damageable)) - accent.OverrideTotalDamage = damageable.TotalDamage; + accent.OverrideTotalDamage = _damageable.GetTotalDamage((ent, damageable)); if (TryComp(ent, out var destructible)) accent.DamageAtMaxCorruption = _destructible.DestroyedAt(ent, destructible); @@ -299,7 +299,7 @@ public sealed class StationAiSystem : SharedStationAiSystem if (!_proto.TryIndex(_damageAlert, out var proto)) return; - var damagePercent = damageable.TotalDamage / _destructible.DestroyedAt(ent, destructible); + var damagePercent = _damageable.GetTotalDamage((ent, damageable)) / _destructible.DestroyedAt(ent, destructible); var damageLevel = Math.Round(damagePercent.Float() * proto.MaxSeverity); _alerts.ShowAlert(held.Value, _damageAlert, (short)Math.Clamp(damageLevel, 0, proto.MaxSeverity)); diff --git a/Content.Server/Speech/EntitySystems/DamagedSiliconAccentSystem.cs b/Content.Server/Speech/EntitySystems/DamagedSiliconAccentSystem.cs index e9bbfdf528..e197f2a50b 100644 --- a/Content.Server/Speech/EntitySystems/DamagedSiliconAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/DamagedSiliconAccentSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Destructible; using Content.Shared.Speech.Components; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.FixedPoint; using Content.Shared.Power.EntitySystems; using Content.Shared.PowerCell; @@ -16,6 +17,7 @@ public sealed class DamagedSiliconAccentSystem : EntitySystem [Dependency] private readonly SharedBatterySystem _battery = default!; [Dependency] private readonly PowerCellSystem _powerCell = default!; [Dependency] private readonly DestructibleSystem _destructibleSystem = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -52,7 +54,7 @@ public sealed class DamagedSiliconAccentSystem : EntitySystem } else if (TryComp(uid, out var damageable)) { - damage = damageable.TotalDamage; + damage = _damageable.GetTotalDamage((uid, damageable)); } // Corrupt due to damage (drop, repeat, replace with symbols) args.Message = CorruptDamage(args.Message, damage, ent); diff --git a/Content.Server/Spreader/KudzuSystem.cs b/Content.Server/Spreader/KudzuSystem.cs index e8470ebd57..687ee9dd57 100644 --- a/Content.Server/Spreader/KudzuSystem.cs +++ b/Content.Server/Spreader/KudzuSystem.cs @@ -30,7 +30,7 @@ public sealed class KudzuSystem : EntitySystem { // Every time we take any damage, we reduce growth depending on all damage over the growth impact // So the kudzu gets slower growing the more it is hurt. - var growthDamage = (int) (args.Damageable.TotalDamage / component.GrowthHealth); + var growthDamage = (int) (_damageable.GetTotalDamage((uid, args.Damageable)) / component.GrowthHealth); if (growthDamage > 0) { if (!EnsureComp(uid, out _)) @@ -118,14 +118,15 @@ public sealed class KudzuSystem : EntitySystem if (damageableQuery.TryGetComponent(uid, out var damage)) { - if (damage.TotalDamage > 1.0) + var totalDamage = _damageable.GetTotalDamage((uid, damage)); + if (totalDamage > 1.0) { if (kudzu.DamageRecovery != null) { // This kudzu features healing, so Gradually heal _damageable.TryChangeDamage(uid, kudzu.DamageRecovery, true); } - if (damage.TotalDamage >= kudzu.GrowthBlock) + if (totalDamage >= kudzu.GrowthBlock) { // Don't grow when quite damaged if (_robustRandom.Prob(0.95f)) diff --git a/Content.Shared/Blocking/BlockingSystem.User.cs b/Content.Shared/Blocking/BlockingSystem.User.cs index db59a8d5f6..ac73d70ffb 100644 --- a/Content.Shared/Blocking/BlockingSystem.User.cs +++ b/Content.Shared/Blocking/BlockingSystem.User.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Shared.Damage; using Content.Shared.Damage.Components; using Content.Shared.Damage.Systems; @@ -53,11 +54,12 @@ public sealed partial class BlockingSystem return; var blockFraction = blocking.IsBlocking ? blocking.ActiveBlockFraction : blocking.PassiveBlockFraction; + var modifier = blocking.IsBlocking ? blocking.ActiveBlockDamageModifier : blocking.PassiveBlockDamageModifer; 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) + foreach (var key in modifier.Coefficients.Keys.Concat(modifier.FlatReduction.Keys)) { modify.Coefficients.TryAdd(key, 1 - blockFraction); } diff --git a/Content.Shared/Changeling/Components/ChangelingDevourComponent.cs b/Content.Shared/Changeling/Components/ChangelingDevourComponent.cs index 3b907eb494..f2c5c82ca9 100644 --- a/Content.Shared/Changeling/Components/ChangelingDevourComponent.cs +++ b/Content.Shared/Changeling/Components/ChangelingDevourComponent.cs @@ -81,12 +81,6 @@ public sealed partial class ChangelingDevourComponent : Component [DataField, AutoNetworkedField] public TimeSpan DevourConsumeTime = TimeSpan.FromSeconds(10); - /// - /// Damage cap that a target is allowed to be caused due to IdentityConsumption - /// - [DataField, AutoNetworkedField] - public float DevourConsumeDamageCap = 350f; - /// /// The Currently active devour sound in the world /// diff --git a/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs b/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs index 926f19632d..3406038e9c 100644 --- a/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs +++ b/Content.Shared/Changeling/Systems/ChangelingDevourSystem.cs @@ -84,16 +84,7 @@ public sealed class ChangelingDevourSystem : EntitySystem if (target == null) return; - if (!TryComp(target, out var damage)) - return; - - foreach (var damagePoints in comp.DamagePerTick.DamageDict) - { - - if (damage.Damage.DamageDict.TryGetValue(damagePoints.Key, out var val) && val > comp.DevourConsumeDamageCap) - return; - } - _damageable.ChangeDamage((target.Value, damage), comp.DamagePerTick, true, true, user); + _damageable.ChangeDamage(target.Value, comp.DamagePerTick, true, true, user); } /// diff --git a/Content.Shared/Chat/SharedSuicideSystem.cs b/Content.Shared/Chat/SharedSuicideSystem.cs index 0484e51ab2..ed6eca9859 100644 --- a/Content.Shared/Chat/SharedSuicideSystem.cs +++ b/Content.Shared/Chat/SharedSuicideSystem.cs @@ -29,7 +29,7 @@ public sealed class SharedSuicideSystem : EntitySystem // Mob thresholds are sorted from alive -> crit -> dead, // grabbing the last key will give us how much damage is needed to kill a target from zero // The exact lethal damage amount is adjusted based on their current damage taken - var lethalAmountOfDamage = mobThresholds.Thresholds.Keys.Last() - target.Comp.TotalDamage; + var lethalAmountOfDamage = mobThresholds.Thresholds.Keys.Last() - _damageableSystem.GetTotalDamage(target.AsNullable()); var totalDamage = appliedDamageSpecifier.GetTotal(); // Removing structural because it causes issues against entities that cannot take structural damage, @@ -56,7 +56,7 @@ public sealed class SharedSuicideSystem : EntitySystem // Mob thresholds are sorted from alive -> crit -> dead, // grabbing the last key will give us how much damage is needed to kill a target from zero // The exact lethal damage amount is adjusted based on their current damage taken - var lethalAmountOfDamage = mobThresholds.Thresholds.Keys.Last() - target.Comp.TotalDamage; + var lethalAmountOfDamage = mobThresholds.Thresholds.Keys.Last() - _damageableSystem.GetTotalDamage(target.AsNullable()); // We don't want structural damage for the same reasons listed above if (!_prototypeManager.TryIndex(damageType, out var damagePrototype) || damagePrototype.ID == "Structural") diff --git a/Content.Shared/Damage/Components/DamageableComponent.cs b/Content.Shared/Damage/Components/DamageableComponent.cs index 00fbcda561..a78cacf16a 100644 --- a/Content.Shared/Damage/Components/DamageableComponent.cs +++ b/Content.Shared/Damage/Components/DamageableComponent.cs @@ -47,6 +47,7 @@ public sealed partial class DamageableComponent : Component /// If this data-field is specified, this allows damageable components to be initialized with non-zero damage. /// [DataField] + [Access(typeof(DamageableSystem), Other = AccessPermissions.None)] public DamageSpecifier Damage = new(); /// @@ -56,12 +57,15 @@ public sealed partial class DamageableComponent : Component /// Groups which have no members that are supported by this component will not be present in this /// dictionary. /// - [ViewVariables] public Dictionary DamagePerGroup = new(); + [ViewVariables] + [Access(typeof(DamageableSystem), Other = AccessPermissions.None)] + public Dictionary, FixedPoint2> DamagePerGroup = new(); /// /// The sum of all damages in the DamageableComponent. /// [ViewVariables] + [Access(typeof(DamageableSystem), Other = AccessPermissions.None)] public FixedPoint2 TotalDamage; [DataField("radiationDamageTypes")] diff --git a/Content.Shared/Damage/Components/GodmodeComponent.cs b/Content.Shared/Damage/Components/GodmodeComponent.cs index 66f0daff39..f49fd9bb93 100644 --- a/Content.Shared/Damage/Components/GodmodeComponent.cs +++ b/Content.Shared/Damage/Components/GodmodeComponent.cs @@ -8,7 +8,4 @@ public sealed partial class GodmodeComponent : Component { [DataField("wasMovedByPressure")] public bool WasMovedByPressure; - - [DataField("oldDamage")] - public DamageSpecifier? OldDamage = null; } diff --git a/Content.Shared/Damage/Components/PassiveDamageComponent.cs b/Content.Shared/Damage/Components/PassiveDamageComponent.cs index 269960adac..679ce24662 100644 --- a/Content.Shared/Damage/Components/PassiveDamageComponent.cs +++ b/Content.Shared/Damage/Components/PassiveDamageComponent.cs @@ -29,12 +29,6 @@ public sealed partial class PassiveDamageComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public float Interval = 1f; - /// - /// The maximum HP the damage will be given to. If 0, disabled. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 DamageCap = 0; - [DataField("nextDamage", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] public TimeSpan NextDamage = TimeSpan.Zero; } diff --git a/Content.Shared/Damage/DamageSpecifier.cs b/Content.Shared/Damage/DamageSpecifier.cs index 4b08476982..b0dc63e2e3 100644 --- a/Content.Shared/Damage/DamageSpecifier.cs +++ b/Content.Shared/Damage/DamageSpecifier.cs @@ -320,15 +320,15 @@ namespace Content.Shared.Damage /// total of each group. If no members of a group are present in this , the /// group is not included in the resulting dictionary. /// - public Dictionary GetDamagePerGroup(IPrototypeManager protoManager) + public Dictionary, FixedPoint2> GetDamagePerGroup(IPrototypeManager protoManager) { - var dict = new Dictionary(); + var dict = new Dictionary, FixedPoint2>(); GetDamagePerGroup(protoManager, dict); return dict; } /// - public void GetDamagePerGroup(IPrototypeManager protoManager, Dictionary dict) + public void GetDamagePerGroup(IPrototypeManager protoManager, Dictionary, FixedPoint2> dict) { dict.Clear(); foreach (var group in protoManager.EnumeratePrototypes()) diff --git a/Content.Shared/Damage/DamageVisualizerKeys.cs b/Content.Shared/Damage/DamageVisualizerKeys.cs index ba70ab3b91..9719b96fe7 100644 --- a/Content.Shared/Damage/DamageVisualizerKeys.cs +++ b/Content.Shared/Damage/DamageVisualizerKeys.cs @@ -1,3 +1,5 @@ +using Content.Shared.Damage.Prototypes; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Damage @@ -14,16 +16,16 @@ namespace Content.Shared.Damage [Serializable, NetSerializable] public sealed class DamageVisualizerGroupData : ICloneable { - public List GroupList; + public List> GroupList; - public DamageVisualizerGroupData(List groupList) + public DamageVisualizerGroupData(List> groupList) { GroupList = groupList; } public object Clone() { - return new DamageVisualizerGroupData(new List(GroupList)); + return new DamageVisualizerGroupData(new List>(GroupList)); } } } diff --git a/Content.Shared/Damage/Systems/DamagePopupSystem.cs b/Content.Shared/Damage/Systems/DamagePopupSystem.cs index fa29b5a018..d6a8e0beba 100644 --- a/Content.Shared/Damage/Systems/DamagePopupSystem.cs +++ b/Content.Shared/Damage/Systems/DamagePopupSystem.cs @@ -7,6 +7,7 @@ namespace Content.Shared.Damage.Systems; public sealed class DamagePopupSystem : EntitySystem { [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -19,7 +20,7 @@ public sealed class DamagePopupSystem : EntitySystem { if (args.DamageDelta != null) { - var damageTotal = args.Damageable.TotalDamage; + var damageTotal = _damageable.GetTotalDamage((ent, args.Damageable)); var damageDelta = args.DamageDelta.GetTotal(); var msg = ent.Comp.Type switch diff --git a/Content.Shared/Damage/Systems/DamageableSystem.API.cs b/Content.Shared/Damage/Systems/DamageableSystem.API.cs index ff56c1affc..2975f22762 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.API.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.API.cs @@ -301,7 +301,7 @@ public sealed partial class DamageableSystem ProtoId? group = null) { // get the damage should be healed (either all or only from one group) - damage = group == null ? GetDamage(ent) : GetDamage(ent, group.Value); + damage = group == null ? GetPositiveDamage(ent) : GetPositiveDamage(ent, group.Value); // If trying to heal more than the total damage of damageEntity just heal everything return damage.GetTotal() > amount; @@ -313,7 +313,7 @@ public sealed partial class DamageableSystem /// entity with damage /// group of damage to get values from /// - public DamageSpecifier GetDamage(Entity ent, ProtoId group) + public DamageSpecifier GetPositiveDamage(Entity ent, ProtoId group) { // No damage if no group exists... if (!_prototypeManager.Resolve(group, out var groupProto)) @@ -338,7 +338,7 @@ public sealed partial class DamageableSystem /// /// entity with damage /// - public DamageSpecifier GetDamage(Entity ent) + public DamageSpecifier GetPositiveDamage(Entity ent) { var damage = new DamageSpecifier(); damage.DamageDict.EnsureCapacity(ent.Comp.Damage.DamageDict.Count); @@ -428,4 +428,52 @@ public sealed partial class DamageableSystem Dirty(ent); } + + /// + /// Gets the damages currently sustained by an entity. + /// + [Obsolete("Do not rely on the ability to determine a numerically quantifiable amount of damage")] + public DamageSpecifier GetAllDamage(Entity ent) + { + if (!_damageableQuery.Resolve(ent, ref ent.Comp)) + return new(); + + return ent.Comp.Damage.Clone(); + } + + /// + /// Gets the total amount of damage currently sustained by an entity. + /// + [Obsolete("Do not rely on the ability to determine a numerically quantifiable amount of damage")] + public FixedPoint2 GetTotalDamage(Entity ent) + { + if (!_damageableQuery.Resolve(ent, ref ent.Comp, false)) + return FixedPoint2.Zero; + + return ent.Comp.TotalDamage; + } + + /// + /// Gets the total amount of damage currently sustained by an entity, indexed by damage group. + /// + [Obsolete("Do not rely on the ability to determine a numerically quantifiable amount of damage")] + public IReadOnlyDictionary, FixedPoint2> GetDamagePerGroup(Entity ent) + { + if (!_damageableQuery.Resolve(ent, ref ent.Comp)) + return new Dictionary, FixedPoint2>(); + + return ent.Comp.DamagePerGroup; + } + + /// + /// Returns whether the entity can be damaged by the given type of damage + /// + [Obsolete("Do not rely on the ability to determine if an entity will be able to be damaged by something")] + public bool CanBeDamagedBy(Entity ent, ProtoId type) + { + if (!_damageableQuery.Resolve(ent, ref ent.Comp, false)) + return false; + + return SupportsType(ent.Comp.DamageContainerID, type); + } } diff --git a/Content.Shared/Damage/Systems/PassiveDamageSystem.cs b/Content.Shared/Damage/Systems/PassiveDamageSystem.cs index fddf7dc975..94fff7e97d 100644 --- a/Content.Shared/Damage/Systems/PassiveDamageSystem.cs +++ b/Content.Shared/Damage/Systems/PassiveDamageSystem.cs @@ -35,9 +35,6 @@ public sealed class PassiveDamageSystem : EntitySystem if (comp.NextDamage > curTime) continue; - if (comp.DamageCap != 0 && damage.TotalDamage >= comp.DamageCap) - continue; - // Set the next time they can take damage comp.NextDamage = curTime + TimeSpan.FromSeconds(1f); diff --git a/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs b/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs index 2a020732c2..39ff4f1070 100644 --- a/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs +++ b/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs @@ -15,7 +15,6 @@ namespace Content.Shared.Damage.Systems; public abstract class SharedGodmodeSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _protoMan = default!; - [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -69,13 +68,6 @@ public abstract class SharedGodmodeSystem : EntitySystem public virtual void EnableGodmode(EntityUid uid, GodmodeComponent? godmode = null) { - godmode ??= EnsureComp(uid); - - if (TryComp(uid, out var damageable)) - { - godmode.OldDamage = new DamageSpecifier(damageable.Damage); - } - // Rejuv to cover other stuff RaiseLocalEvent(uid, new RejuvenateEvent()); } @@ -85,11 +77,6 @@ public abstract class SharedGodmodeSystem : EntitySystem if (!Resolve(uid, ref godmode, false)) return; - if (godmode.OldDamage != null) - { - _damageable.SetDamage(uid, godmode.OldDamage); - } - RemComp(uid); } diff --git a/Content.Shared/Damage/Systems/SlowOnDamageSystem.cs b/Content.Shared/Damage/Systems/SlowOnDamageSystem.cs index fef7b6ae06..4c80aa89d0 100644 --- a/Content.Shared/Damage/Systems/SlowOnDamageSystem.cs +++ b/Content.Shared/Damage/Systems/SlowOnDamageSystem.cs @@ -10,6 +10,7 @@ namespace Content.Shared.Damage.Systems; public sealed class SlowOnDamageSystem : EntitySystem { [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!; + [Dependency] private readonly DamageableSystem _damage = default!; public override void Initialize() { @@ -33,12 +34,14 @@ public sealed class SlowOnDamageSystem : EntitySystem if (!TryComp(uid, out var damage)) return; - if (damage.TotalDamage == FixedPoint2.Zero) + var totalDamage = _damage.GetTotalDamage((uid, damage)); + + if (totalDamage == FixedPoint2.Zero) return; // Get closest threshold FixedPoint2 closest = FixedPoint2.Zero; - var total = damage.TotalDamage; + var total = totalDamage; foreach (var thres in component.SpeedModifierThresholds) { if (total >= thres.Key && thres.Key > closest) diff --git a/Content.Shared/Destructible/SharedDestructibleSystem.cs b/Content.Shared/Destructible/SharedDestructibleSystem.cs index 6b7148a4c9..4917ded326 100644 --- a/Content.Shared/Destructible/SharedDestructibleSystem.cs +++ b/Content.Shared/Destructible/SharedDestructibleSystem.cs @@ -1,7 +1,12 @@ +using Content.Shared.Damage.Systems; + namespace Content.Shared.Destructible; public abstract class SharedDestructibleSystem : EntitySystem { + // TODO: I don't really like this but this is out of scope to re-do destructible triggers while refactoring damageable + [Dependency] public readonly DamageableSystem Damageable = default!; + /// /// Force entity to be destroyed and deleted. /// diff --git a/Content.Shared/Destructible/Triggers/DamageGroupTrigger.cs b/Content.Shared/Destructible/Triggers/DamageGroupTrigger.cs index 11c78fbd1e..3acbf25375 100644 --- a/Content.Shared/Destructible/Triggers/DamageGroupTrigger.cs +++ b/Content.Shared/Destructible/Triggers/DamageGroupTrigger.cs @@ -28,6 +28,6 @@ public sealed partial class DamageGroupTrigger : IThresholdTrigger public bool Reached(Entity damageable, SharedDestructibleSystem system) { - return damageable.Comp.DamagePerGroup.GetValueOrDefault(DamageGroup) >= Damage; + return system.Damageable.GetDamagePerGroup(damageable.Owner).GetValueOrDefault(DamageGroup) >= Damage; } } diff --git a/Content.Shared/Destructible/Triggers/DamageTrigger.cs b/Content.Shared/Destructible/Triggers/DamageTrigger.cs index 7a2d612f75..481b55b30f 100644 --- a/Content.Shared/Destructible/Triggers/DamageTrigger.cs +++ b/Content.Shared/Destructible/Triggers/DamageTrigger.cs @@ -20,6 +20,6 @@ public sealed partial class DamageTrigger : IThresholdTrigger public bool Reached(Entity damageable, SharedDestructibleSystem system) { - return damageable.Comp.TotalDamage >= Damage; + return system.Damageable.GetTotalDamage(damageable.AsNullable()) >= Damage; } } diff --git a/Content.Shared/Destructible/Triggers/DamageTypeTrigger.cs b/Content.Shared/Destructible/Triggers/DamageTypeTrigger.cs index 60bd9baf67..5debc51864 100644 --- a/Content.Shared/Destructible/Triggers/DamageTypeTrigger.cs +++ b/Content.Shared/Destructible/Triggers/DamageTypeTrigger.cs @@ -28,7 +28,7 @@ public sealed partial class DamageTypeTrigger : IThresholdTrigger public bool Reached(Entity damageable, SharedDestructibleSystem system) { - return damageable.Comp.Damage.DamageDict.TryGetValue(DamageType, out var damageReceived) && + return system.Damageable.GetAllDamage(damageable.AsNullable()).DamageDict.TryGetValue(DamageType, out var damageReceived) && damageReceived >= Damage; } } diff --git a/Content.Shared/EntityConditions/Conditions/DamageGroupEntityConditionSystem.cs b/Content.Shared/EntityConditions/Conditions/DamageGroupEntityConditionSystem.cs deleted file mode 100644 index 0cfa4dedca..0000000000 --- a/Content.Shared/EntityConditions/Conditions/DamageGroupEntityConditionSystem.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Content.Shared.Damage.Components; -using Content.Shared.Damage.Prototypes; -using Content.Shared.FixedPoint; -using Robust.Shared.Prototypes; - -namespace Content.Shared.EntityConditions.Conditions; - -/// -/// Returns true if this entity can take damage and if its damage of a given damage group is within a specified minimum and maximum. -/// -/// -public sealed partial class DamageGroupEntityConditionSystem : EntityConditionSystem -{ - protected override void Condition(Entity entity, ref EntityConditionEvent args) - { - var value = entity.Comp.DamagePerGroup.GetValueOrDefault(args.Condition.DamageGroup); - args.Result = value >= args.Condition.Min && value <= args.Condition.Max; - } -} - -/// -public sealed partial class DamageGroupCondition : EntityConditionBase -{ - [DataField] - public FixedPoint2 Max = FixedPoint2.MaxValue; - - [DataField] - public FixedPoint2 Min = FixedPoint2.Zero; - - [DataField(required: true)] - public ProtoId DamageGroup; - - public override string EntityConditionGuidebookText(IPrototypeManager prototype) => - Loc.GetString("entity-condition-guidebook-group-damage", - ("max", Max == FixedPoint2.MaxValue ? int.MaxValue : Max.Float()), - ("min", Min.Float()), - ("type", prototype.Index(DamageGroup).LocalizedName)); -} diff --git a/Content.Shared/EntityConditions/Conditions/DamageTypeEntityConditionSystem.cs b/Content.Shared/EntityConditions/Conditions/DamageTypeEntityConditionSystem.cs deleted file mode 100644 index f2611a8200..0000000000 --- a/Content.Shared/EntityConditions/Conditions/DamageTypeEntityConditionSystem.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Content.Shared.Damage; -using Content.Shared.Damage.Components; -using Content.Shared.Damage.Prototypes; -using Content.Shared.FixedPoint; -using Robust.Shared.Prototypes; - -namespace Content.Shared.EntityConditions.Conditions; - -/// -/// Returns true if this entity can take damage and if its damage of a given damage type is within a specified minimum and maximum. -/// -/// -public sealed partial class DamageTypeEntityConditionSystem : EntityConditionSystem -{ - protected override void Condition(Entity entity, ref EntityConditionEvent args) - { - var value = entity.Comp.Damage.DamageDict.GetValueOrDefault(args.Condition.DamageType); - args.Result = value >= args.Condition.Min && value <= args.Condition.Max; - } -} - -/// -public sealed partial class DamageTypeCondition : EntityConditionBase -{ - [DataField] - public FixedPoint2 Max = FixedPoint2.MaxValue; - - [DataField] - public FixedPoint2 Min = FixedPoint2.Zero; - - [DataField(required: true)] - public ProtoId DamageType; - - public override string EntityConditionGuidebookText(IPrototypeManager prototype) => - Loc.GetString("entity-condition-guidebook-type-damage", - ("max", Max == FixedPoint2.MaxValue ? int.MaxValue : Max.Float()), - ("min", Min.Float()), - ("type", prototype.Index(DamageType).LocalizedName)); -} diff --git a/Content.Shared/EntityConditions/Conditions/TotalDamageEntityConditionSystem.cs b/Content.Shared/EntityConditions/Conditions/TotalDamageEntityConditionSystem.cs deleted file mode 100644 index 306398b4eb..0000000000 --- a/Content.Shared/EntityConditions/Conditions/TotalDamageEntityConditionSystem.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Content.Shared.Damage.Components; -using Content.Shared.FixedPoint; -using Robust.Shared.Prototypes; - -namespace Content.Shared.EntityConditions.Conditions; - -/// -/// Returns true if this entity can take damage and if its total damage is within a specified minimum and maximum. -/// -/// -public sealed partial class TotalDamageEntityConditionSystem : EntityConditionSystem -{ - protected override void Condition(Entity entity, ref EntityConditionEvent args) - { - var total = entity.Comp.TotalDamage; - args.Result = total >= args.Condition.Min && total <= args.Condition.Max; - } -} - -/// -public sealed partial class TotalDamageCondition : EntityConditionBase -{ - [DataField] - public FixedPoint2 Max = FixedPoint2.MaxValue; - - [DataField] - public FixedPoint2 Min = FixedPoint2.Zero; - - public override string EntityConditionGuidebookText(IPrototypeManager prototype) => - Loc.GetString("entity-condition-guidebook-total-damage", - ("max", Max == FixedPoint2.MaxValue ? int.MaxValue : Max.Float()), - ("min", Min.Float())); -} diff --git a/Content.Shared/GhostTypes/StoreDamageTakenOnMindSystem.cs b/Content.Shared/GhostTypes/StoreDamageTakenOnMindSystem.cs index 0e985b0b2d..94e3492f77 100644 --- a/Content.Shared/GhostTypes/StoreDamageTakenOnMindSystem.cs +++ b/Content.Shared/GhostTypes/StoreDamageTakenOnMindSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Damage.Components; using Content.Shared.Damage.Prototypes; +using Content.Shared.Damage.Systems; using Content.Shared.Destructible; using Content.Shared.Explosion; using Content.Shared.FixedPoint; @@ -13,6 +14,8 @@ namespace Content.Shared.GhostTypes; public sealed class StoreDamageTakenOnMindSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; + public override void Initialize() { SubscribeLocalEvent(SaveBodyOnGib); @@ -57,7 +60,7 @@ public sealed class StoreDamageTakenOnMindSystem : EntitySystem EnsureComp(mindContainer.Mind.Value, out var storedDamage); var protoDict = new Dictionary, FixedPoint2>(); - foreach (var stringDict in damageable.DamagePerGroup) // Translates the strings into ProtoId's before saving the Dictionary + foreach (var stringDict in _damageable.GetDamagePerGroup((ent, damageable))) // Translates the strings into ProtoId's before saving the Dictionary { if (!_proto.TryIndex(stringDict.Key, out DamageGroupPrototype? proto)) continue; @@ -65,7 +68,7 @@ public sealed class StoreDamageTakenOnMindSystem : EntitySystem } storedDamage.DamagePerGroup = protoDict; - storedDamage.Damage = damageable.Damage; + storedDamage.Damage = _damageable.GetAllDamage((ent, damageable)); Dirty(mindContainer.Mind.Value, storedDamage); } diff --git a/Content.Shared/HealthExaminable/HealthExaminableSystem.cs b/Content.Shared/HealthExaminable/HealthExaminableSystem.cs index ae938e0995..37dd9c350c 100644 --- a/Content.Shared/HealthExaminable/HealthExaminableSystem.cs +++ b/Content.Shared/HealthExaminable/HealthExaminableSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.IdentityManagement; @@ -10,6 +11,7 @@ namespace Content.Shared.HealthExaminable; public sealed class HealthExaminableSystem : EntitySystem { [Dependency] private readonly ExamineSystemShared _examineSystem = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -47,9 +49,10 @@ public sealed class HealthExaminableSystem : EntitySystem var msg = new FormattedMessage(); var first = true; + var damageSpecifier = _damageable.GetAllDamage((uid, damage)); foreach (var type in component.ExaminableTypes) { - if (!damage.Damage.DamageDict.TryGetValue(type, out var dmg)) + if (!damageSpecifier.DamageDict.TryGetValue(type, out var dmg)) continue; if (dmg == FixedPoint2.Zero) diff --git a/Content.Shared/Medical/Cryogenics/CryoPodComponent.cs b/Content.Shared/Medical/Cryogenics/CryoPodComponent.cs index d75d22f60d..386d0989d9 100644 --- a/Content.Shared/Medical/Cryogenics/CryoPodComponent.cs +++ b/Content.Shared/Medical/Cryogenics/CryoPodComponent.cs @@ -132,19 +132,22 @@ public sealed class CryoPodUserMessage : BoundUserInterfaceMessage public FixedPoint2? BeakerCapacity; public List? Beaker; public List? Injecting; + public bool HasDamage; public CryoPodUserMessage( GasAnalyzerComponent.GasMixEntry gasMix, HealthAnalyzerUiState health, FixedPoint2? beakerCapacity, List? beaker, - List? injecting) + List? injecting, + bool hasDamage) { GasMix = gasMix; Health = health; BeakerCapacity = beakerCapacity; Beaker = beaker; Injecting = injecting; + HasDamage = hasDamage; } } diff --git a/Content.Shared/Medical/Healing/HealingSystem.cs b/Content.Shared/Medical/Healing/HealingSystem.cs index 21bdd077d7..0e9c4bf991 100644 --- a/Content.Shared/Medical/Healing/HealingSystem.cs +++ b/Content.Shared/Medical/Healing/HealingSystem.cs @@ -126,7 +126,7 @@ public sealed class HealingSystem : EntitySystem private bool HasDamage(Entity healing, Entity target) { - var damageableDict = target.Comp.Damage.DamageDict; + var damageableDict = _damageable.GetAllDamage(target.AsNullable()).DamageDict; var healingDict = healing.Comp.Damage.DamageDict; foreach (var type in healingDict) { @@ -240,7 +240,7 @@ public sealed class HealingSystem : EntitySystem if (!_mobThresholdSystem.TryGetThresholdForState(ent, MobState.Critical, out var amount, ent.Comp2)) return 1; - var percentDamage = (float)(ent.Comp1.TotalDamage / amount); + var percentDamage = (float)(_damageable.GetTotalDamage(ent) / amount); //basically make it scale from 1 to the multiplier. var output = percentDamage * (mod - 1) + 1; diff --git a/Content.Shared/Medical/SharedDefibrillatorSystem.cs b/Content.Shared/Medical/SharedDefibrillatorSystem.cs index b774fbe38d..4f8a533017 100644 --- a/Content.Shared/Medical/SharedDefibrillatorSystem.cs +++ b/Content.Shared/Medical/SharedDefibrillatorSystem.cs @@ -209,9 +209,8 @@ public abstract class SharedDefibrillatorSystem : EntitySystem _damageable.TryChangeDamage(target, ent.Comp.ZapHeal, true, origin: user); if (TryComp(target, out var targetThresholds) && - TryComp(target, out var targetDamageable) && _mobThreshold.TryGetThresholdForState(target, MobState.Dead, out var threshold, targetThresholds) && - targetDamageable.TotalDamage < threshold) + _damageable.GetTotalDamage(target) < threshold) { _mobState.ChangeMobState(target, MobState.Critical, targetMobState, user); failedRevive = false; diff --git a/Content.Shared/Medical/Stethoscope/StethoscopeSystem.cs b/Content.Shared/Medical/Stethoscope/StethoscopeSystem.cs index 86a8249321..34db93f401 100644 --- a/Content.Shared/Medical/Stethoscope/StethoscopeSystem.cs +++ b/Content.Shared/Medical/Stethoscope/StethoscopeSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Actions; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; using Content.Shared.Inventory; @@ -18,6 +19,7 @@ public sealed class StethoscopeSystem : EntitySystem [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; // The damage type to "listen" for with the stethoscope. private const string DamageToListenFor = "Asphyxiation"; @@ -96,9 +98,8 @@ public sealed class StethoscopeSystem : EntitySystem // TODO: Add check for respirator component when it gets moved to shared. // If the mob is dead or cannot asphyxiation damage, the popup shows nothing. if (!TryComp(target, out var mobState) || - !TryComp(target, out var damageComp) || _mobState.IsDead(target, mobState) || - !damageComp.Damage.DamageDict.TryGetValue(DamageToListenFor, out var asphyxDmg)) + !_damageable.GetAllDamage(target).DamageDict.TryGetValue(DamageToListenFor, out var asphyxDmg)) { _popup.PopupPredicted(Loc.GetString("stethoscope-nothing"), target, user); stethoscope.Comp.LastMeasuredDamage = null; diff --git a/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs b/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs index 861fcd8daf..75dbc4a7c8 100644 --- a/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs +++ b/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Access.Systems; using Content.Shared.ActionBlocker; using Content.Shared.Clothing; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.DeviceNetwork; using Content.Shared.DoAfter; using Content.Shared.Emp; @@ -40,6 +41,7 @@ public abstract class SharedSuitSensorSystem : EntitySystem [Dependency] private readonly SharedIdCardSystem _idCardSystem = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; private EntityQuery _sensorQuery; public override void Initialize() @@ -375,9 +377,7 @@ public abstract class SharedSuitSensorSystem : EntitySystem isAlive = !_mobStateSystem.IsDead(sensor.User.Value, mobState); // get mob total damage - var totalDamage = 0; - if (TryComp(sensor.User.Value, out var damageable)) - totalDamage = damageable.TotalDamage.Int(); + var totalDamage = _damageable.GetTotalDamage(sensor.User.Value).Int(); // Get mob total damage crit threshold int? totalDamageThreshold = null; diff --git a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs index 3af7317954..c9534c1366 100644 --- a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs +++ b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs @@ -15,6 +15,7 @@ public sealed class MobThresholdSystem : EntitySystem { [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly AlertsSystem _alerts = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -270,7 +271,7 @@ public sealed class MobThresholdSystem : EntitySystem if (!TryGetThresholdForState(target2, MobState.Dead, out var ent2DeadThreshold, threshold2)) ent2DeadThreshold = 0; - damage = (oldDamage.Damage / ent1DeadThreshold.Value) * ent2DeadThreshold.Value; + damage = (_damageable.GetAllDamage((target1, oldDamage)) / ent1DeadThreshold.Value) * ent2DeadThreshold.Value; return true; } @@ -339,7 +340,7 @@ public sealed class MobThresholdSystem : EntitySystem { foreach (var (threshold, mobState) in thresholdsComponent.Thresholds.Reverse()) { - if (damageableComponent.TotalDamage < threshold) + if (_damageable.GetTotalDamage((target, damageableComponent)) < threshold) continue; TriggerThreshold(target, mobState, mobStateComponent, thresholdsComponent, origin); @@ -405,7 +406,7 @@ public sealed class MobThresholdSystem : EntitySystem } if (TryGetNextState(target, currentMobState, out var nextState, threshold) && - TryGetPercentageForState(target, nextState.Value, damageable.TotalDamage, out var percentage)) + TryGetPercentageForState(target, nextState.Value, _damageable.GetTotalDamage((target, damageable)), out var percentage)) { percentage = FixedPoint2.Clamp(percentage.Value, 0, 1); diff --git a/Content.Shared/Repairable/RepairableSystem.cs b/Content.Shared/Repairable/RepairableSystem.cs index 8fbdf90ee6..89fce2e005 100644 --- a/Content.Shared/Repairable/RepairableSystem.cs +++ b/Content.Shared/Repairable/RepairableSystem.cs @@ -28,7 +28,11 @@ public sealed partial class RepairableSystem : EntitySystem if (args.Cancelled) return; - if (!TryComp(ent.Owner, out DamageableComponent? damageable) || damageable.TotalDamage == 0) + if (!TryComp(ent.Owner, out DamageableComponent? damageable)) + return; + + var totalDamage = _damageableSystem.GetTotalDamage((ent.Owner, damageable)); + if (totalDamage == 0) return; if (ent.Comp.DamageValue != null) @@ -38,7 +42,7 @@ public sealed partial class RepairableSystem : EntitySystem else RepairAllDamage((ent, damageable), args.User); - args.Repeat = ent.Comp.AutoDoAfter && damageable.TotalDamage > 0; + args.Repeat = ent.Comp.AutoDoAfter && totalDamage > 0; args.Args.Event.Repeat = args.Repeat; args.Handled = true; @@ -95,7 +99,7 @@ public sealed partial class RepairableSystem : EntitySystem return; // Only try repair the target if it is damaged - if (!TryComp(ent.Owner, out var damageable) || damageable.TotalDamage == 0) + if (_damageableSystem.GetTotalDamage(ent.Owner) == 0) return; float delay = ent.Comp.DoAfterDelay; diff --git a/Content.Shared/Silicons/Bots/MedibotComponent.cs b/Content.Shared/Silicons/Bots/MedibotComponent.cs index 9bd45e9a6a..1ac5250d0f 100644 --- a/Content.Shared/Silicons/Bots/MedibotComponent.cs +++ b/Content.Shared/Silicons/Bots/MedibotComponent.cs @@ -44,27 +44,4 @@ public sealed partial class MedibotTreatment /// [DataField(required: true)] public FixedPoint2 Quantity; - - /// - /// Do nothing when the patient is at or below this total damage. - /// When null this will inject meds into completely healthy patients. - /// - [DataField] - public FixedPoint2? MinDamage; - - /// - /// Do nothing when the patient is at or above this total damage. - /// Useful for tricordrazine which does nothing above 50 damage. - /// - [DataField] - public FixedPoint2? MaxDamage; - - /// - /// Returns whether the treatment will probably work for an amount of damage. - /// Doesn't account for specific damage types only total amount. - /// - public bool IsValid(FixedPoint2 damage) - { - return (MaxDamage == null || damage < MaxDamage) && (MinDamage == null || damage > MinDamage); - } } diff --git a/Content.Shared/Silicons/Bots/MedibotSystem.cs b/Content.Shared/Silicons/Bots/MedibotSystem.cs index b960e19068..1505b60415 100644 --- a/Content.Shared/Silicons/Bots/MedibotSystem.cs +++ b/Content.Shared/Silicons/Bots/MedibotSystem.cs @@ -3,6 +3,7 @@ using Robust.Shared.Serialization; using System.Diagnostics.CodeAnalysis; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.DoAfter; using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; @@ -25,6 +26,7 @@ public sealed class MedibotSystem : EntitySystem [Dependency] private SharedSolutionContainerSystem _solutionContainer = default!; [Dependency] private SharedPopupSystem _popup = default!; [Dependency] private SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; public override void Initialize() { @@ -107,14 +109,14 @@ public sealed class MedibotSystem : EntitySystem return false; } - var total = damageable.TotalDamage; + var total = _damageable.GetTotalDamage((target, damageable)); if (total == 0 && !HasComp(medibot)) { _popup.PopupClient(Loc.GetString("medibot-target-healthy"), medibot, medibot); return false; } - if (!TryGetTreatment(medibot.Comp, mobState.CurrentState, out var treatment) || !treatment.IsValid(total) && !manual) return false; + if (!TryGetTreatment(medibot.Comp, mobState.CurrentState, out var treatment) || !manual) return false; return true; } diff --git a/Resources/Locale/en-US/reagents/meta/medicine.ftl b/Resources/Locale/en-US/reagents/meta/medicine.ftl index 8ff827f408..43ae5a806c 100644 --- a/Resources/Locale/en-US/reagents/meta/medicine.ftl +++ b/Resources/Locale/en-US/reagents/meta/medicine.ftl @@ -136,9 +136,6 @@ reagent-desc-opporozidone= A difficult to synthesize cryogenic drug used to rege reagent-name-arcryox = arcryox reagent-desc-arcryox = A sickeningly blue cryogenics chemical that is able to heal extreme wounds even on the dead. It has trouble stabilizing patients however. -reagent-name-necrosol = necrosol -reagent-desc-necrosol = A necrotic substance that seems to be able to heal frozen corpses. It can treat and rejuvenate plants when applied in small doses. - reagent-name-aloxadone = aloxadone reagent-desc-aloxadone = A cryogenics chemical. Used to treat severe burns and frostbite via regeneration of the affected tissue. Works regardless of the patient being alive or dead. diff --git a/Resources/Prototypes/Body/Species/slime.yml b/Resources/Prototypes/Body/Species/slime.yml index 1d8e946844..82c8b30ca6 100644 --- a/Resources/Prototypes/Body/Species/slime.yml +++ b/Resources/Prototypes/Body/Species/slime.yml @@ -116,7 +116,6 @@ - type: PassiveDamage # Around 8 damage a minute healed allowedStates: - Alive - damageCap: 65 damage: types: Heat: -0.14 diff --git a/Resources/Prototypes/Body/Species/vox.yml b/Resources/Prototypes/Body/Species/vox.yml index 92c98ea9cb..9fab05ea20 100644 --- a/Resources/Prototypes/Body/Species/vox.yml +++ b/Resources/Prototypes/Body/Species/vox.yml @@ -224,7 +224,6 @@ # This allows Vox to take their mask off temporarily to eat something without needing a trip to medbay afterwards. allowedStates: - Alive - damageCap: 20 damage: types: Heat: -0.07 diff --git a/Resources/Prototypes/Body/species_base.yml b/Resources/Prototypes/Body/species_base.yml index 74663cc814..454b376ad3 100644 --- a/Resources/Prototypes/Body/species_base.yml +++ b/Resources/Prototypes/Body/species_base.yml @@ -182,7 +182,6 @@ - type: PassiveDamage allowedStates: - Alive - damageCap: 20 damage: types: Heat: -0.07 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 00344c9383..cf8bb477f0 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -2588,7 +2588,6 @@ - type: PassiveDamage # Slight passive regen. Assuming one damage type, comes out to about 4 damage a minute from base.yml. allowedStates: - Alive - damageCap: 89 damage: types: Poison: -0.07 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml b/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml index 86b75ba7b2..74ab0102d5 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/living_light.yml @@ -67,7 +67,6 @@ - type: PassiveDamage allowedStates: - Alive - damageCap: 20 damage: types: Heat: -0.2 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml b/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml index 45ff0ea755..7ce6df4a9a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/miscellaneous.yml @@ -224,7 +224,6 @@ allowedStates: - Alive - Dead - damageCap: 50 damage: types: Blunt: 0.11 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index a4d5e4100f..8cf988c68e 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -321,8 +321,6 @@ Alive: reagent: Tricordrazine quantity: 30 - minDamage: 0 - maxDamage: 50 Critical: reagent: Inaprovaline quantity: 15 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chemistry-bottles.yml b/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chemistry-bottles.yml index 15aee05b1e..5fe9435f7a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chemistry-bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chemistry-bottles.yml @@ -619,21 +619,6 @@ - ReagentId: Mannitol Quantity: 30 -- type: entity - id: ChemistryBottleNecrosol - suffix: necrosol - parent: BaseChemistryBottleFilled - components: - - type: Label - currentLabel: reagent-name-necrosol - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Necrosol - Quantity: 30 - - type: entity id: ChemistryBottleOculine suffix: oculine @@ -1476,7 +1461,6 @@ - id: ChemistryBottleLeporazine - id: ChemistryBottleLipozine - id: ChemistryBottleMannitol - - id: ChemistryBottleNecrosol - id: ChemistryBottleOculine - id: ChemistryBottleOmnizine - id: ChemistryBottleOpporozidone diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml index 0dca01a6bc..9e1ca7236b 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml @@ -149,7 +149,7 @@ reagents: - ReagentId: Ash Quantity: 25 - - ReagentId: Necrosol + - ReagentId: Arcryox Quantity: 25 - type: GuideHelp guides: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml index 941abd1a43..aefcc5c8b4 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml @@ -11,7 +11,6 @@ weight: 5 reagents: - Ichor - - Necrosol - quantity: 5 weight: 4 reagents: diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index 782df52a51..0a3a565089 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -817,9 +817,6 @@ Bloodstream: effects: - !type:EvenHealthChange - conditions: - - !type:TotalDamageCondition - max: 50 damage: Brute: -1 Burn: -1 @@ -1160,8 +1157,6 @@ factor: 3 - !type:HealthChange conditions: - - !type:TotalDamageCondition - max: 50 damage: types: Blunt: -0.2 @@ -1312,53 +1307,9 @@ conditions: - !type:TemperatureCondition max: 213.0 - - !type:TotalDamageCondition - min: 199.9 damage: - Brute: -2 - Burn: -2 - - !type:EvenHealthChange - conditions: - - !type:TemperatureCondition - max: 213.0 - - !type:TotalDamageCondition - min: 500 - damage: - Brute: -4 - Burn: -4 - -- type: reagent - id: Necrosol - name: reagent-name-necrosol - group: Medicine - desc: reagent-desc-necrosol - physicalDesc: reagent-physical-desc-necrotic - flavor: medicine - color: "#86a5bd" - worksOnTheDead: true - plantMetabolism: - - !type:PlantAdjustToxins - amount: -5 - - !type:PlantAdjustHealth - amount: 5 - - !type:PlantCryoxadone {} - metabolisms: - Bloodstream: - effects: - - !type:EvenHealthChange - conditions: - - !type:TemperatureCondition - max: 213.0 - damage: - Brute: -2 - Burn: -2 - - !type:HealthChange - conditions: - - !type:TemperatureCondition - max: 213.0 - damage: - types: - Poison: -2 + Brute: -3 + Burn: -3 - type: reagent id : Aloxadone diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml index 396bcacf99..65674bb5a2 100644 --- a/Resources/Prototypes/Reagents/narcotics.yml +++ b/Resources/Prototypes/Reagents/narcotics.yml @@ -190,15 +190,15 @@ amount: -1.5 - !type:EvenHealthChange conditions: - - !type:TotalDamageCondition - min: 70 # only heals when you're more dead than alive + - !type:MobStateCondition + mobstate: Critical damage: # Doesn't heal poison because if you OD'd I'm not giving you a safety net Burn: -0.5 Brute: -0.5 - !type:HealthChange conditions: - - !type:TotalDamageCondition - min: 95 # Just to bring you back from the brink of death + - !type:MobStateCondition + mobstate: Critical damage: types: Asphyxiation: -2 diff --git a/Resources/Prototypes/Recipes/Reactions/medicine.yml b/Resources/Prototypes/Recipes/Reactions/medicine.yml index 335f1e0ed3..644452cff5 100644 --- a/Resources/Prototypes/Recipes/Reactions/medicine.yml +++ b/Resources/Prototypes/Recipes/Reactions/medicine.yml @@ -583,20 +583,6 @@ products: Arcryox: 3 -- type: reaction - id: Necrosol - impact: Medium - minTemp: 370 - reactants: - Blood: - amount: 3 - Omnizine: - amount: 1 - Cryoxadone: - amount: 2 - products: - Necrosol: 2 - - type: reaction id: Aloxadone impact: Medium diff --git a/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml b/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml index eb7af8b499..00b8003977 100644 --- a/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml +++ b/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml @@ -44,11 +44,11 @@ Once things have been set up, you're going to require a specific medication, Cry The standard pressure for a gas pump is 100.325 kpa. Cryoxadone works at under 170K, but it is standard practice to set the freezer to 100K for faster freezing. + - diff --git a/Resources/ServerInfo/Guidebook/Service/Botany.xml b/Resources/ServerInfo/Guidebook/Service/Botany.xml index 29982b0677..14096754bd 100644 --- a/Resources/ServerInfo/Guidebook/Service/Botany.xml +++ b/Resources/ServerInfo/Guidebook/Service/Botany.xml @@ -82,7 +82,6 @@ Some chemicals have special effects on plants. -