diff --git a/Content.Server/NodeContainer/NodeGroups/PipeNet.cs b/Content.Server/NodeContainer/NodeGroups/PipeNet.cs index e905a6e78e87bb..989209beb039ee 100644 --- a/Content.Server/NodeContainer/NodeGroups/PipeNet.cs +++ b/Content.Server/NodeContainer/NodeGroups/PipeNet.cs @@ -3,6 +3,8 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.NodeContainer.Nodes; using Content.Shared.Atmos; +using Content.Shared.Damage; +using Robust.Shared.Random; using Robust.Shared.Utility; namespace Content.Server.NodeContainer.NodeGroups @@ -21,6 +23,9 @@ public sealed class PipeNet : BaseNodeGroup, IPipeNet [ViewVariables] public GasMixture Air { get; set; } = new() {Temperature = Atmospherics.T20C}; [ViewVariables] private AtmosphereSystem? _atmosphereSystem; + [ViewVariables] private DamageableSystem? _damage; + [ViewVariables] private IEntityManager? _entMan; + [ViewVariables] private IRobustRandom? _random; public EntityUid? Grid { get; private set; } @@ -38,11 +43,53 @@ public override void Initialize(Node sourceNode, IEntityManager entMan) _atmosphereSystem = entMan.EntitySysManager.GetEntitySystem(); _atmosphereSystem.AddPipeNet(Grid.Value, this); + _damage = entMan.EntitySysManager.GetEntitySystem(); + _entMan = entMan; + _random = IoCManager.Resolve(); + } + + /// + /// Calculate pressure damage for pipe. There is no damage if the pressure is below MaxPressure, + /// and damage scales exponentially beyond that. + /// + private int PressureDamage(PipeNode pipe) + { + const float tau = 10; // number of atmos ticks to break pipe at nominal overpressure + var diff = pipe.Air.Pressure - pipe.MaxPressure; + const float alpha = 100/tau; + return diff > 0 ? (int)(alpha*float.Exp(diff / pipe.MaxPressure)) : 0; } public void Update() { _atmosphereSystem?.React(Air, this); + + // Check each pipe node for overpressure and apply damage if needed + foreach (var node in Nodes) + { + if (node is PipeNode pipe && pipe.MaxPressure > 0) + { + // Prefer damaging pipes that are already damaged. This means that only one pipe + // fails instead of the whole pipenet bursting at the same time. + const float baseChance = 0.5f; + float p = baseChance; + if (_entMan != null && _entMan.TryGetComponent(pipe.Owner, out var damage)) + { + p += (float)damage.TotalDamage * (1 - baseChance); + } + + if (_random != null && _random.Prob(1-p)) + continue; + + int dam = PressureDamage(pipe); + if (dam > 0) + { + var dspec = new DamageSpecifier(); + dspec.DamageDict.Add("Structural", dam); + _damage?.TryChangeDamage(pipe.Owner, dspec); + } + } + } } public override void LoadNodes(List groupNodes) diff --git a/Content.Server/NodeContainer/Nodes/PipeNode.cs b/Content.Server/NodeContainer/Nodes/PipeNode.cs index 14afa2f1083eca..500bed08ae45cc 100644 --- a/Content.Server/NodeContainer/Nodes/PipeNode.cs +++ b/Content.Server/NodeContainer/Nodes/PipeNode.cs @@ -102,6 +102,12 @@ public GasMixture Air private const float DefaultVolume = 200f; + /// + /// Pressure beyond which this pipe node starts taking damage. Set to zero for no pressure damage. + /// + [DataField] + public float MaxPressure = 0; + public override void Initialize(EntityUid owner, IEntityManager entMan) { base.Initialize(owner, entMan); diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml index 132da2f1a841f2..dec739357a4c05 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml @@ -83,6 +83,7 @@ !type:PipeNode nodeGroupID: Pipe pipeDirection: Longitudinal + maxPressure: 6750 - type: Sprite layers: - state: pipeStraight @@ -102,6 +103,7 @@ !type:PipeNode nodeGroupID: Pipe pipeDirection: SWBend + maxPressure: 6750 - type: Sprite layers: - state: pipeBend @@ -121,6 +123,7 @@ !type:PipeNode nodeGroupID: Pipe pipeDirection: TSouth + maxPressure: 6750 - type: Sprite layers: - state: pipeTJunction @@ -142,6 +145,7 @@ !type:PipeNode nodeGroupID: Pipe pipeDirection: Fourway + maxPressure: 6750 - type: Sprite layers: - state: pipeFourway