diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasDualPortVentPumpComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasDualPortVentPumpComponent.cs new file mode 100644 index 0000000000..eda13dc175 --- /dev/null +++ b/Content.Server/Atmos/Piping/Binary/Components/GasDualPortVentPumpComponent.cs @@ -0,0 +1,52 @@ +using System; +using Content.Server.Atmos.Piping.Unary.Components; +using Content.Shared.Atmos; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Atmos.Piping.Binary.Components +{ + [RegisterComponent] + public class GasDualPortVentPumpComponent : Component + { + public override string Name => "GasDualPortVentPump"; + + [ViewVariables(VVAccess.ReadWrite)] + public bool Enabled { get; set; } = true; + + [ViewVariables(VVAccess.ReadWrite)] + public bool Welded { get; set; } = false; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("inlet")] + public string InletName { get; set; } = "inlet"; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("outlet")] + public string OutletName { get; set; } = "outlet"; + + [ViewVariables(VVAccess.ReadWrite)] + public VentPumpDirection PumpDirection { get; set; } = VentPumpDirection.Releasing; + + [ViewVariables(VVAccess.ReadWrite)] + public DualPortVentPressureBound PressureChecks { get; set; } = DualPortVentPressureBound.ExternalBound; + + [ViewVariables(VVAccess.ReadWrite)] + public float ExternalPressureBound { get; set; } = Atmospherics.OneAtmosphere; + + [ViewVariables(VVAccess.ReadWrite)] + public float InputPressureMin { get; set; } = 0f; + + [ViewVariables(VVAccess.ReadWrite)] + public float OutputPressureMax { get; set; } = 0f; + } + + [Flags] + public enum DualPortVentPressureBound : sbyte + { + NoBound = 0, + ExternalBound = 1, + InputMinimum = 2, + } +} diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs new file mode 100644 index 0000000000..861b2b84bc --- /dev/null +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs @@ -0,0 +1,105 @@ +using System; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.Piping.Binary.Components; +using Content.Server.Atmos.Piping.Components; +using Content.Server.Atmos.Piping.Unary.Components; +using Content.Server.NodeContainer; +using Content.Server.NodeContainer.Nodes; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Visuals; +using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; + +namespace Content.Server.Atmos.Piping.Binary.EntitySystems +{ + [UsedImplicitly] + public class GasDualPortVentPumpSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGasDualPortVentPumpUpdated); + SubscribeLocalEvent(OnGasDualPortVentPumpDisabled); + } + + private void OnGasDualPortVentPumpUpdated(EntityUid uid, GasDualPortVentPumpComponent vent, AtmosDeviceUpdateEvent args) + { + var appearance = vent.Owner.GetComponentOrNull(); + + if (vent.Welded) + { + appearance?.SetData(VentPumpVisuals.State, VentPumpState.Welded); + return; + } + + appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off); + + if (!vent.Enabled) + return; + + if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) + return; + + if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet) + || !nodeContainer.TryGetNode(vent.OutletName, out PipeNode? outlet)) + return; + + var environment = args.Atmosphere.GetTile(vent.Owner.Transform.Coordinates)!; + + // We're in an air-blocked tile... Do nothing. + if (environment.Air == null) + return; + + if (vent.PumpDirection == VentPumpDirection.Releasing) + { + appearance?.SetData(VentPumpVisuals.State, VentPumpState.Out); + var pressureDelta = 10000f; + + if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0) + pressureDelta = MathF.Min(pressureDelta, (vent.ExternalPressureBound - environment.Air.Pressure)); + + if ((vent.PressureChecks & DualPortVentPressureBound.InputMinimum) != 0) + pressureDelta = MathF.Min(pressureDelta, (inlet.Air.Pressure - vent.InputPressureMin)); + + if (pressureDelta > 0 && inlet.Air.Temperature > 0) + { + var transferMoles = pressureDelta * environment.Air.Volume / inlet.Air.Temperature * Atmospherics.R; + var removed = inlet.Air.Remove(transferMoles); + environment.AssumeAir(removed); + } + } + else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Air.Pressure > 0f) + { + appearance?.SetData(VentPumpVisuals.State, VentPumpState.In); + var ourMultiplier = outlet.Air.Volume / environment.Air.Temperature * Atmospherics.R; + var molesDelta = 10000 * ourMultiplier; + + if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0) + molesDelta = + MathF.Min(molesDelta, + (environment.Air.Pressure - vent.OutputPressureMax) * environment.Air.Volume / (environment.Air.Temperature * Atmospherics.R)); + + if ((vent.PressureChecks &DualPortVentPressureBound.InputMinimum) != 0) + molesDelta = MathF.Min(molesDelta, (vent.InputPressureMin - outlet.Air.Pressure) * ourMultiplier); + + if (molesDelta > 0) + { + var removed = environment.Air.Remove(molesDelta); + + Get().Merge(outlet.Air, removed); + environment.Invalidate(); + } + } + } + + private void OnGasDualPortVentPumpDisabled(EntityUid uid, GasDualPortVentPumpComponent vent, AtmosDeviceDisabledEvent args) + { + if (ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance)) + { + appearance.SetData(VentPumpVisuals.State, VentPumpState.Off); + } + } + } +} diff --git a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/binary.yml b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/binary.yml index b3570a9c50..d9d2f6a82b 100644 --- a/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/binary.yml +++ b/Resources/Prototypes/Entities/Constructible/Piping/Atmospherics/binary.yml @@ -125,3 +125,27 @@ !type:PortPipeNode nodeGroupID: Pipe pipeDirection: South + +- type: entity + parent: GasUnaryBase + id: GasDualPortVentPump + name: dual-port air vent + description: Has a valve and a pump attached to it. There are two ports. + placement: + mode: SnapgridCenter + components: + - type: Sprite + netsync: false + sprite: Constructible/Atmos/vent.rsi + layers: + - sprite: Constructible/Atmos/pipe.rsi + state: pipeStraight + map: [ "enum.PipeColorVisualizer+Layers.Pipe" ] + - state: vent_off + map: ["enum.VentVisualLayers.Vent"] + - type: Appearance + visuals: + - type: PipeConnectorVisualizer + - type: PipeColorVisualizer + - type: VentPumpVisualizer + - type: GasVentPump