mirror of
https://github.com/corvax-team/ss14-wl.git
synced 2026-06-09 10:06:46 +02:00
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
This commit is contained in:
committed by
GitHub
parent
c2681cdb17
commit
b2b547b806
@@ -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)
|
||||
/// </summary>
|
||||
[DataField("damageOverlayGroups")] public Dictionary<string, DamageVisualizerSprite>? DamageOverlayGroups;
|
||||
[DataField("damageOverlayGroups")] public Dictionary<ProtoId<DamageGroupPrototype>, DamageVisualizerSprite>? DamageOverlayGroups;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[DataField("damageGroup")] public string? DamageGroup;
|
||||
[DataField("damageGroup")] public ProtoId<DamageGroupPrototype>? DamageGroup;
|
||||
|
||||
/// <summary>
|
||||
/// Set this if you want incoming damage to be
|
||||
|
||||
@@ -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<DamageVisualsComponent>
|
||||
{
|
||||
[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<DamageVisualsComponen
|
||||
// See if that group is in our entity's damage container.
|
||||
else if (!damageVisComp.Overlay && damageVisComp.DamageGroup != null)
|
||||
{
|
||||
if (!damageContainer.SupportedGroups.Contains(damageVisComp.DamageGroup))
|
||||
if (!damageContainer.SupportedGroups.Contains(damageVisComp.DamageGroup.Value))
|
||||
{
|
||||
Log.Error($"Damage keys were invalid for entity {entity}.");
|
||||
damageVisComp.Valid = false;
|
||||
@@ -384,7 +386,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
|
||||
if (!AppearanceSystem.TryGetData<DamageVisualizerGroupData>(uid, DamageVisualizerKeys.DamageUpdateGroups,
|
||||
out var data, component))
|
||||
{
|
||||
data = new DamageVisualizerGroupData(Comp<DamageableComponent>(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<DamageVisualsComponen
|
||||
/// </summary>
|
||||
private void UpdateDamageVisuals(Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> 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<DamageVisualsComponen
|
||||
/// according to the list of damage groups
|
||||
/// passed into it.
|
||||
/// </summary>
|
||||
private void UpdateDamageVisuals(List<string> delta, Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
|
||||
private void UpdateDamageVisuals(List<ProtoId<DamageGroupPrototype>> delta, Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> 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<DamageVisualsComponen
|
||||
continue;
|
||||
|
||||
if (!_prototypeManager.TryIndex<DamageGroupPrototype>(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<DamageVisualsComponen
|
||||
}
|
||||
else if (damageVisComp.DamageGroup != null)
|
||||
{
|
||||
UpdateDamageVisuals(new List<string>() { damageVisComp.DamageGroup }, entity);
|
||||
UpdateDamageVisuals(new() { damageVisComp.DamageGroup.Value }, entity);
|
||||
}
|
||||
else if (damageVisComp.DamageOverlay != null)
|
||||
{
|
||||
|
||||
@@ -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<SpriteSystem>();
|
||||
_prototypes = dependencies.Resolve<IPrototypeManager>();
|
||||
_cache = dependencies.Resolve<IResourceCache>();
|
||||
_damageable = _entityManager.System<DamageableSystem>();
|
||||
}
|
||||
|
||||
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<string, FixedPoint2> groups,
|
||||
Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2> groups,
|
||||
IReadOnlyDictionary<ProtoId<DamageTypePrototype>, FixedPoint2> damageDict)
|
||||
{
|
||||
GroupsContainer.RemoveAllChildren();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<StatusIconSystem>();
|
||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
||||
_progressColor = _entManager.System<ProgressColorSystem>();
|
||||
_damageable = _entManager.System<DamageableSystem>();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
@@ -129,16 +132,17 @@ public sealed class EntityHealthBarOverlay : Overlay
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<MobStateComponent>(player);
|
||||
mobThresholdsComp = entManager.GetComponent<MobThresholdsComponent>(player);
|
||||
damageableComp = entManager.GetComponent<DamageableComponent>(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<GhostComponent>(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<GhostComponent>(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<GhostComponent>(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));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -19,17 +19,16 @@ public sealed class WindowRepair : InteractionTest
|
||||
|
||||
// Damage the entity.
|
||||
var sys = SEntMan.System<DamageableSystem>();
|
||||
var comp = Comp<DamageableComponent>();
|
||||
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(
|
||||
|
||||
@@ -147,6 +147,7 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var uid = sDamageableEntity;
|
||||
var ent = new Entity<DamageableComponent>(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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<InventorySystem>();
|
||||
var factionSys = server.System<NpcFactionSystem>();
|
||||
var roundEndSys = server.System<RoundEndSystem>();
|
||||
var damageSys = server.System<DamageableSystem>();
|
||||
|
||||
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<DamageableComponent>(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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<DamageableComponent>(SPlayer, out var damageComp),
|
||||
$"Player does not have a DamageableComponent.");
|
||||
var startingDamage = damageComp.TotalDamage;
|
||||
var damageSystem = Server.System<DamageableSystem>();
|
||||
var startingDamage = damageSystem.GetTotalDamage(SPlayer);
|
||||
|
||||
Assert.That(SEntMan.TryGetComponent<MobStateComponent>(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<DamageableComponent>(SPlayer, out var damageComp),
|
||||
$"Player does not have a DamageableComponent.");
|
||||
var startingDamage = damageComp.TotalDamage;
|
||||
var damageSystem = Server.System<DamageableSystem>();
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,14 +196,14 @@ public sealed class VendingInteractionTest : InteractionTest
|
||||
private async Task BreakVendor()
|
||||
{
|
||||
var damageableSys = SEntMan.System<DamageableSystem>();
|
||||
Assert.That(TryComp<DamageableComponent>(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<DamageableComponent>(), $"{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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SharedGunSystem>();
|
||||
var damageSystem = SEntMan.System<DamageableSystem>();
|
||||
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SiliconLawsetPrototype> _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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<MindComponent, EntityUid> ClonesWaitingForMind = new();
|
||||
public readonly ProtoId<CloningSettingsPrototype> SettingsId = "CloningPod";
|
||||
@@ -180,7 +182,7 @@ public sealed class CloningPodSystem : EntitySystem
|
||||
|
||||
// genetic damage checks
|
||||
if (TryComp<DamageableComponent>(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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the structure has at least some amount of health
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed partial class MinHealth : IGraphCondition
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[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<DestructibleSystem>();
|
||||
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<IEntityManager>();
|
||||
var entity = args.Examined;
|
||||
|
||||
if (Condition(entity, entMan))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
args.PushMarkup(Loc.GetString("construction-examine-condition-low-health"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<ConstructionGuideEntry> GenerateGuideEntry()
|
||||
{
|
||||
yield return new ConstructionGuideEntry()
|
||||
{
|
||||
Localization = "construction-step-condition-low-health"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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<DamageableComponent>(ent, out var damageable))
|
||||
return 0;
|
||||
|
||||
var damage = damageable.TotalDamage;
|
||||
var damage = _damageable.GetTotalDamage((ent, damageable));
|
||||
var damageThreshold = _destructible.DestroyedAt(ent);
|
||||
|
||||
if (damageThreshold == 0)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -590,7 +590,8 @@ namespace Content.Server.Ghost
|
||||
&& TryComp<MobThresholdsComponent>(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);
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,12 +46,13 @@ public sealed class MeteorSystem : EntitySystem
|
||||
{
|
||||
threshold = FixedPoint2.MaxValue;
|
||||
}
|
||||
var otherEntDamage = CompOrNull<DamageableComponent>(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<DamageableComponent>(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);
|
||||
|
||||
+5
-1
@@ -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<DamageableComponent> _damageQuery = default!;
|
||||
private EntityQuery<InjectableSolutionComponent> _injectQuery = default!;
|
||||
@@ -42,6 +45,7 @@ public sealed partial class PickNearbyInjectableOperator : HTNOperator
|
||||
base.Initialize(sysManager);
|
||||
_medibot = sysManager.GetEntitySystem<MedibotSystem>();
|
||||
_pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
|
||||
_damageable = sysManager.GetEntitySystem<DamageableSystem>();
|
||||
|
||||
_damageQuery = _entManager.GetEntityQuery<DamageableComponent>();
|
||||
_injectQuery = _entManager.GetEntityQuery<InjectableSolutionComponent>();
|
||||
@@ -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
|
||||
|
||||
@@ -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<PuddleComponent> _puddleQuery;
|
||||
private EntityQuery<TransformComponent> _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;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public sealed class ProjectileSystem : SharedProjectileSystem
|
||||
var damageRequired = _destructibleSystem.DestroyedAt(target);
|
||||
if (TryComp<DamageableComponent>(target, out var damageableComponent))
|
||||
{
|
||||
damageRequired -= damageableComponent.TotalDamage;
|
||||
damageRequired -= _damageableSystem.GetTotalDamage((target, damageableComponent));
|
||||
damageRequired = FixedPoint2.Max(damageRequired, FixedPoint2.Zero);
|
||||
}
|
||||
var deleted = Deleted(target);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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<JobPrototype> BorgJobId = "Borg";
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ public sealed class StationAiSystem : SharedStationAiSystem
|
||||
// Set the new AI brain to the 'rebooting' state
|
||||
if (TryComp<StationAiCustomizationComponent>(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<DamageableComponent>(ent, out var damageable))
|
||||
accent.OverrideTotalDamage = damageable.TotalDamage;
|
||||
accent.OverrideTotalDamage = _damageable.GetTotalDamage((ent, damageable));
|
||||
|
||||
if (TryComp<DestructibleComponent>(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));
|
||||
|
||||
@@ -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<DamageableComponent>(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);
|
||||
|
||||
@@ -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<GrowingKudzuComponent>(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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -81,12 +81,6 @@ public sealed partial class ChangelingDevourComponent : Component
|
||||
[DataField, AutoNetworkedField]
|
||||
public TimeSpan DevourConsumeTime = TimeSpan.FromSeconds(10);
|
||||
|
||||
/// <summary>
|
||||
/// Damage cap that a target is allowed to be caused due to IdentityConsumption
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float DevourConsumeDamageCap = 350f;
|
||||
|
||||
/// <summary>
|
||||
/// The Currently active devour sound in the world
|
||||
/// </summary>
|
||||
|
||||
@@ -84,16 +84,7 @@ public sealed class ChangelingDevourSystem : EntitySystem
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (!TryComp<DamageableComponent>(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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
[Access(typeof(DamageableSystem), Other = AccessPermissions.None)]
|
||||
public DamageSpecifier Damage = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -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.
|
||||
/// </remarks>
|
||||
[ViewVariables] public Dictionary<string, FixedPoint2> DamagePerGroup = new();
|
||||
[ViewVariables]
|
||||
[Access(typeof(DamageableSystem), Other = AccessPermissions.None)]
|
||||
public Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2> DamagePerGroup = new();
|
||||
|
||||
/// <summary>
|
||||
/// The sum of all damages in the DamageableComponent.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[Access(typeof(DamageableSystem), Other = AccessPermissions.None)]
|
||||
public FixedPoint2 TotalDamage;
|
||||
|
||||
[DataField("radiationDamageTypes")]
|
||||
|
||||
@@ -8,7 +8,4 @@ public sealed partial class GodmodeComponent : Component
|
||||
{
|
||||
[DataField("wasMovedByPressure")]
|
||||
public bool WasMovedByPressure;
|
||||
|
||||
[DataField("oldDamage")]
|
||||
public DamageSpecifier? OldDamage = null;
|
||||
}
|
||||
|
||||
@@ -29,12 +29,6 @@ public sealed partial class PassiveDamageComponent : Component
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public float Interval = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum HP the damage will be given to. If 0, disabled.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public FixedPoint2 DamageCap = 0;
|
||||
|
||||
[DataField("nextDamage", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan NextDamage = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
@@ -320,15 +320,15 @@ namespace Content.Shared.Damage
|
||||
/// total of each group. If no members of a group are present in this <see cref="DamageSpecifier"/>, the
|
||||
/// group is not included in the resulting dictionary.
|
||||
/// </remarks>
|
||||
public Dictionary<string, FixedPoint2> GetDamagePerGroup(IPrototypeManager protoManager)
|
||||
public Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2> GetDamagePerGroup(IPrototypeManager protoManager)
|
||||
{
|
||||
var dict = new Dictionary<string, FixedPoint2>();
|
||||
var dict = new Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2>();
|
||||
GetDamagePerGroup(protoManager, dict);
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GetDamagePerGroup(Robust.Shared.Prototypes.IPrototypeManager)"/>
|
||||
public void GetDamagePerGroup(IPrototypeManager protoManager, Dictionary<string, FixedPoint2> dict)
|
||||
public void GetDamagePerGroup(IPrototypeManager protoManager, Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2> dict)
|
||||
{
|
||||
dict.Clear();
|
||||
foreach (var group in protoManager.EnumeratePrototypes<DamageGroupPrototype>())
|
||||
|
||||
@@ -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<string> GroupList;
|
||||
public List<ProtoId<DamageGroupPrototype>> GroupList;
|
||||
|
||||
public DamageVisualizerGroupData(List<string> groupList)
|
||||
public DamageVisualizerGroupData(List<ProtoId<DamageGroupPrototype>> groupList)
|
||||
{
|
||||
GroupList = groupList;
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new DamageVisualizerGroupData(new List<string>(GroupList));
|
||||
return new DamageVisualizerGroupData(new List<ProtoId<DamageGroupPrototype>>(GroupList));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -301,7 +301,7 @@ public sealed partial class DamageableSystem
|
||||
ProtoId<DamageGroupPrototype>? 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
|
||||
/// <param name="ent">entity with damage</param>
|
||||
/// <param name="group">group of damage to get values from</param>
|
||||
/// <returns></returns>
|
||||
public DamageSpecifier GetDamage(Entity<DamageableComponent> ent, ProtoId<DamageGroupPrototype> group)
|
||||
public DamageSpecifier GetPositiveDamage(Entity<DamageableComponent> ent, ProtoId<DamageGroupPrototype> group)
|
||||
{
|
||||
// No damage if no group exists...
|
||||
if (!_prototypeManager.Resolve(group, out var groupProto))
|
||||
@@ -338,7 +338,7 @@ public sealed partial class DamageableSystem
|
||||
/// </summary>
|
||||
/// <param name="ent">entity with damage</param>
|
||||
/// <returns></returns>
|
||||
public DamageSpecifier GetDamage(Entity<DamageableComponent> ent)
|
||||
public DamageSpecifier GetPositiveDamage(Entity<DamageableComponent> ent)
|
||||
{
|
||||
var damage = new DamageSpecifier();
|
||||
damage.DamageDict.EnsureCapacity(ent.Comp.Damage.DamageDict.Count);
|
||||
@@ -428,4 +428,52 @@ public sealed partial class DamageableSystem
|
||||
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the damages currently sustained by an entity.
|
||||
/// </summary>
|
||||
[Obsolete("Do not rely on the ability to determine a numerically quantifiable amount of damage")]
|
||||
public DamageSpecifier GetAllDamage(Entity<DamageableComponent?> ent)
|
||||
{
|
||||
if (!_damageableQuery.Resolve(ent, ref ent.Comp))
|
||||
return new();
|
||||
|
||||
return ent.Comp.Damage.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total amount of damage currently sustained by an entity.
|
||||
/// </summary>
|
||||
[Obsolete("Do not rely on the ability to determine a numerically quantifiable amount of damage")]
|
||||
public FixedPoint2 GetTotalDamage(Entity<DamageableComponent?> ent)
|
||||
{
|
||||
if (!_damageableQuery.Resolve(ent, ref ent.Comp, false))
|
||||
return FixedPoint2.Zero;
|
||||
|
||||
return ent.Comp.TotalDamage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total amount of damage currently sustained by an entity, indexed by damage group.
|
||||
/// </summary>
|
||||
[Obsolete("Do not rely on the ability to determine a numerically quantifiable amount of damage")]
|
||||
public IReadOnlyDictionary<ProtoId<DamageGroupPrototype>, FixedPoint2> GetDamagePerGroup(Entity<DamageableComponent?> ent)
|
||||
{
|
||||
if (!_damageableQuery.Resolve(ent, ref ent.Comp))
|
||||
return new Dictionary<ProtoId<DamageGroupPrototype>, FixedPoint2>();
|
||||
|
||||
return ent.Comp.DamagePerGroup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the entity can be damaged by the given type of damage
|
||||
/// </summary>
|
||||
[Obsolete("Do not rely on the ability to determine if an entity will be able to be damaged by something")]
|
||||
public bool CanBeDamagedBy(Entity<DamageableComponent?> ent, ProtoId<DamageTypePrototype> type)
|
||||
{
|
||||
if (!_damageableQuery.Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
return SupportsType(ent.Comp.DamageContainerID, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<GodmodeComponent>(uid);
|
||||
|
||||
if (TryComp<DamageableComponent>(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<GodmodeComponent>(uid);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<DamageableComponent>(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)
|
||||
|
||||
@@ -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!;
|
||||
|
||||
/// <summary>
|
||||
/// Force entity to be destroyed and deleted.
|
||||
/// </summary>
|
||||
|
||||
@@ -28,6 +28,6 @@ public sealed partial class DamageGroupTrigger : IThresholdTrigger
|
||||
|
||||
public bool Reached(Entity<DamageableComponent> damageable, SharedDestructibleSystem system)
|
||||
{
|
||||
return damageable.Comp.DamagePerGroup.GetValueOrDefault(DamageGroup) >= Damage;
|
||||
return system.Damageable.GetDamagePerGroup(damageable.Owner).GetValueOrDefault(DamageGroup) >= Damage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@ public sealed partial class DamageTrigger : IThresholdTrigger
|
||||
|
||||
public bool Reached(Entity<DamageableComponent> damageable, SharedDestructibleSystem system)
|
||||
{
|
||||
return damageable.Comp.TotalDamage >= Damage;
|
||||
return system.Damageable.GetTotalDamage(damageable.AsNullable()) >= Damage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public sealed partial class DamageTypeTrigger : IThresholdTrigger
|
||||
|
||||
public bool Reached(Entity<DamageableComponent> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this entity can take damage and if its damage of a given damage group is within a specified minimum and maximum.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
|
||||
public sealed partial class DamageGroupEntityConditionSystem : EntityConditionSystem<DamageableComponent, DamageGroupCondition>
|
||||
{
|
||||
protected override void Condition(Entity<DamageableComponent> entity, ref EntityConditionEvent<DamageGroupCondition> args)
|
||||
{
|
||||
var value = entity.Comp.DamagePerGroup.GetValueOrDefault(args.Condition.DamageGroup);
|
||||
args.Result = value >= args.Condition.Min && value <= args.Condition.Max;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="EntityCondition"/>
|
||||
public sealed partial class DamageGroupCondition : EntityConditionBase<DamageGroupCondition>
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 Min = FixedPoint2.Zero;
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<DamageGroupPrototype> 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));
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this entity can take damage and if its damage of a given damage type is within a specified minimum and maximum.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
|
||||
public sealed partial class DamageTypeEntityConditionSystem : EntityConditionSystem<DamageableComponent, DamageTypeCondition>
|
||||
{
|
||||
protected override void Condition(Entity<DamageableComponent> entity, ref EntityConditionEvent<DamageTypeCondition> args)
|
||||
{
|
||||
var value = entity.Comp.Damage.DamageDict.GetValueOrDefault(args.Condition.DamageType);
|
||||
args.Result = value >= args.Condition.Min && value <= args.Condition.Max;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="EntityCondition"/>
|
||||
public sealed partial class DamageTypeCondition : EntityConditionBase<DamageTypeCondition>
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 Min = FixedPoint2.Zero;
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<DamageTypePrototype> 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));
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.EntityConditions.Conditions;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this entity can take damage and if its total damage is within a specified minimum and maximum.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EntityConditionSystem{T, TCondition}"/>
|
||||
public sealed partial class TotalDamageEntityConditionSystem : EntityConditionSystem<DamageableComponent, TotalDamageCondition>
|
||||
{
|
||||
protected override void Condition(Entity<DamageableComponent> entity, ref EntityConditionEvent<TotalDamageCondition> args)
|
||||
{
|
||||
var total = entity.Comp.TotalDamage;
|
||||
args.Result = total >= args.Condition.Min && total <= args.Condition.Max;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="EntityCondition"/>
|
||||
public sealed partial class TotalDamageCondition : EntityConditionBase<TotalDamageCondition>
|
||||
{
|
||||
[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()));
|
||||
}
|
||||
@@ -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<StoreDamageTakenOnMindComponent, DestructionEventArgs>(SaveBodyOnGib);
|
||||
@@ -57,7 +60,7 @@ public sealed class StoreDamageTakenOnMindSystem : EntitySystem
|
||||
EnsureComp<LastBodyDamageComponent>(mindContainer.Mind.Value, out var storedDamage);
|
||||
|
||||
var protoDict = new Dictionary<ProtoId<DamageGroupPrototype>, 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -132,19 +132,22 @@ public sealed class CryoPodUserMessage : BoundUserInterfaceMessage
|
||||
public FixedPoint2? BeakerCapacity;
|
||||
public List<ReagentQuantity>? Beaker;
|
||||
public List<ReagentQuantity>? Injecting;
|
||||
public bool HasDamage;
|
||||
|
||||
public CryoPodUserMessage(
|
||||
GasAnalyzerComponent.GasMixEntry gasMix,
|
||||
HealthAnalyzerUiState health,
|
||||
FixedPoint2? beakerCapacity,
|
||||
List<ReagentQuantity>? beaker,
|
||||
List<ReagentQuantity>? injecting)
|
||||
List<ReagentQuantity>? injecting,
|
||||
bool hasDamage)
|
||||
{
|
||||
GasMix = gasMix;
|
||||
Health = health;
|
||||
BeakerCapacity = beakerCapacity;
|
||||
Beaker = beaker;
|
||||
Injecting = injecting;
|
||||
HasDamage = hasDamage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ public sealed class HealingSystem : EntitySystem
|
||||
|
||||
private bool HasDamage(Entity<HealingComponent> healing, Entity<DamageableComponent> 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;
|
||||
|
||||
@@ -209,9 +209,8 @@ public abstract class SharedDefibrillatorSystem : EntitySystem
|
||||
_damageable.TryChangeDamage(target, ent.Comp.ZapHeal, true, origin: user);
|
||||
|
||||
if (TryComp<MobThresholdsComponent>(target, out var targetThresholds) &&
|
||||
TryComp<DamageableComponent>(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;
|
||||
|
||||
@@ -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<MobStateComponent>(target, out var mobState) ||
|
||||
!TryComp<DamageableComponent>(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;
|
||||
|
||||
@@ -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<SuitSensorComponent> _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<DamageableComponent>(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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<DamageableComponent>(ent.Owner, out var damageable) || damageable.TotalDamage == 0)
|
||||
if (_damageableSystem.GetTotalDamage(ent.Owner) == 0)
|
||||
return;
|
||||
|
||||
float delay = ent.Comp.DoAfterDelay;
|
||||
|
||||
@@ -44,27 +44,4 @@ public sealed partial class MedibotTreatment
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public FixedPoint2 Quantity;
|
||||
|
||||
/// <summary>
|
||||
/// Do nothing when the patient is at or below this total damage.
|
||||
/// When null this will inject meds into completely healthy patients.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2? MinDamage;
|
||||
|
||||
/// <summary>
|
||||
/// Do nothing when the patient is at or above this total damage.
|
||||
/// Useful for tricordrazine which does nothing above 50 damage.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2? MaxDamage;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the treatment will probably work for an amount of damage.
|
||||
/// Doesn't account for specific damage types only total amount.
|
||||
/// </summary>
|
||||
public bool IsValid(FixedPoint2 damage)
|
||||
{
|
||||
return (MaxDamage == null || damage < MaxDamage) && (MinDamage == null || damage > MinDamage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<EmaggedComponent>(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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -116,7 +116,6 @@
|
||||
- type: PassiveDamage # Around 8 damage a minute healed
|
||||
allowedStates:
|
||||
- Alive
|
||||
damageCap: 65
|
||||
damage:
|
||||
types:
|
||||
Heat: -0.14
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -182,7 +182,6 @@
|
||||
- type: PassiveDamage
|
||||
allowedStates:
|
||||
- Alive
|
||||
damageCap: 20
|
||||
damage:
|
||||
types:
|
||||
Heat: -0.07
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
- type: PassiveDamage
|
||||
allowedStates:
|
||||
- Alive
|
||||
damageCap: 20
|
||||
damage:
|
||||
types:
|
||||
Heat: -0.2
|
||||
|
||||
@@ -224,7 +224,6 @@
|
||||
allowedStates:
|
||||
- Alive
|
||||
- Dead
|
||||
damageCap: 50
|
||||
damage:
|
||||
types:
|
||||
Blunt: 0.11
|
||||
|
||||
@@ -321,8 +321,6 @@
|
||||
Alive:
|
||||
reagent: Tricordrazine
|
||||
quantity: 30
|
||||
minDamage: 0
|
||||
maxDamage: 50
|
||||
Critical:
|
||||
reagent: Inaprovaline
|
||||
quantity: 15
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
reagents:
|
||||
- ReagentId: Ash
|
||||
Quantity: 25
|
||||
- ReagentId: Necrosol
|
||||
- ReagentId: Arcryox
|
||||
Quantity: 25
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
weight: 5
|
||||
reagents:
|
||||
- Ichor
|
||||
- Necrosol
|
||||
- quantity: 5
|
||||
weight: 4
|
||||
reagents:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
<GuideReagentEmbed Reagent="Aloxadone"/>
|
||||
<GuideReagentEmbed Reagent="Arcryox"/>
|
||||
<GuideReagentEmbed Reagent="Cryoxadone"/>
|
||||
<GuideReagentEmbed Reagent="Doxarubixadone"/>
|
||||
<GuideReagentEmbed Reagent="Dexalin"/>
|
||||
<GuideReagentEmbed Reagent="Leporazine"/>
|
||||
<GuideReagentEmbed Reagent="Necrosol"/>
|
||||
<GuideReagentEmbed Reagent="Opporozidone"/>
|
||||
|
||||
</Document>
|
||||
|
||||
@@ -82,7 +82,6 @@ Some chemicals have special effects on plants.
|
||||
|
||||
<GuideReagentEmbed Reagent="Dylovene"/>
|
||||
<GuideReagentEmbed Reagent="Cryoxadone"/>
|
||||
<GuideReagentEmbed Reagent="Necrosol"/>
|
||||
<GuideReagentEmbed Reagent="Phalanximine"/>
|
||||
<GuideReagentGroupEmbed Group="Botanical"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user