Make atmos Turing-complete (#10520)
* Add pneumatic valves Pneumatic valves permit bidirectional flow between the inlet and outlet if the pressure at the control port is high enough. * Add construction recipe
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
using Content.Shared.Atmos;
|
||||||
|
|
||||||
|
namespace Content.Server.Atmos.Piping.Trinary.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class PressureControlledValveComponent : Component
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("inlet")]
|
||||||
|
public string InletName { get; set; } = "inlet";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("control")]
|
||||||
|
public string ControlName { get; set; } = "control";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("outlet")]
|
||||||
|
public string OutletName { get; set; } = "outlet";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("enabled")]
|
||||||
|
public bool Enabled { get; set; } = false;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("gain")]
|
||||||
|
public float Gain { get; set; } = 10;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("threshold")]
|
||||||
|
public float Threshold { get; set; } = Atmospherics.OneAtmosphere;
|
||||||
|
|
||||||
|
[DataField("maxTransferRate")]
|
||||||
|
public float MaxTransferRate { get; set; } = Atmospherics.MaxTransferRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using Content.Server.Atmos.EntitySystems;
|
||||||
|
using Content.Server.Atmos.Piping.Components;
|
||||||
|
using Content.Server.Atmos.Piping.Trinary.Components;
|
||||||
|
using Content.Server.NodeContainer;
|
||||||
|
using Content.Server.NodeContainer.Nodes;
|
||||||
|
using Content.Shared.Atmos.Piping;
|
||||||
|
using Content.Shared.Audio;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class PressureControlledValveSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private IGameTiming _gameTiming = default!;
|
||||||
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<PressureControlledValveComponent, ComponentInit>(OnInit);
|
||||||
|
SubscribeLocalEvent<PressureControlledValveComponent, AtmosDeviceUpdateEvent>(OnUpdate);
|
||||||
|
SubscribeLocalEvent<PressureControlledValveComponent, AtmosDeviceDisabledEvent>(OnFilterLeaveAtmosphere);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInit(EntityUid uid, PressureControlledValveComponent comp, ComponentInit args)
|
||||||
|
{
|
||||||
|
UpdateAppearance(uid, comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUpdate(EntityUid uid, PressureControlledValveComponent comp, AtmosDeviceUpdateEvent args)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
||||||
|
|| !EntityManager.TryGetComponent(uid, out AtmosDeviceComponent? device)
|
||||||
|
|| !nodeContainer.TryGetNode(comp.InletName, out PipeNode? inletNode)
|
||||||
|
|| !nodeContainer.TryGetNode(comp.ControlName, out PipeNode? controlNode)
|
||||||
|
|| !nodeContainer.TryGetNode(comp.OutletName, out PipeNode? outletNode))
|
||||||
|
{
|
||||||
|
_ambientSoundSystem.SetAmbience(comp.Owner, false);
|
||||||
|
comp.Enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If output is higher than input, flip input/output to enable bidirectional flow.
|
||||||
|
if (outletNode.Air.Pressure > inletNode.Air.Pressure)
|
||||||
|
{
|
||||||
|
PipeNode temp = outletNode;
|
||||||
|
outletNode = inletNode;
|
||||||
|
inletNode = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
float control = (controlNode.Air.Pressure - outletNode.Air.Pressure) - comp.Threshold;
|
||||||
|
float transferRate;
|
||||||
|
if (control < 0)
|
||||||
|
{
|
||||||
|
comp.Enabled = false;
|
||||||
|
transferRate = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
comp.Enabled = true;
|
||||||
|
transferRate = Math.Min(control * comp.Gain, comp.MaxTransferRate);
|
||||||
|
}
|
||||||
|
UpdateAppearance(uid, comp);
|
||||||
|
|
||||||
|
// We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
|
||||||
|
var transferRatio = (float)(transferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;
|
||||||
|
if (transferRatio <= 0)
|
||||||
|
{
|
||||||
|
_ambientSoundSystem.SetAmbience(comp.Owner, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ambientSoundSystem.SetAmbience(comp.Owner, true);
|
||||||
|
var removed = inletNode.Air.RemoveRatio(transferRatio);
|
||||||
|
_atmosphereSystem.Merge(outletNode.Air, removed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFilterLeaveAtmosphere(EntityUid uid, PressureControlledValveComponent comp, AtmosDeviceDisabledEvent args)
|
||||||
|
{
|
||||||
|
comp.Enabled = false;
|
||||||
|
UpdateAppearance(uid, comp);
|
||||||
|
_ambientSoundSystem.SetAmbience(comp.Owner, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAppearance(EntityUid uid, PressureControlledValveComponent? comp = null, AppearanceComponent? appearance = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref comp, ref appearance, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
appearance.SetData(FilterVisuals.Enabled, comp.Enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -198,3 +198,58 @@
|
|||||||
!type:PipeNode
|
!type:PipeNode
|
||||||
nodeGroupID: Pipe
|
nodeGroupID: Pipe
|
||||||
pipeDirection: North
|
pipeDirection: North
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: GasPipeBase
|
||||||
|
id: PressureControlledValve
|
||||||
|
name: pneumatic valve
|
||||||
|
description: Valve controlled by pressure.
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: AtmosDevice
|
||||||
|
- type: SubFloorHide
|
||||||
|
blockInteractions: false
|
||||||
|
blockAmbience: false
|
||||||
|
- type: NodeContainer
|
||||||
|
nodes:
|
||||||
|
inlet:
|
||||||
|
!type:PipeNode
|
||||||
|
nodeGroupID: Pipe
|
||||||
|
pipeDirection: North
|
||||||
|
control:
|
||||||
|
!type:PipeNode
|
||||||
|
nodeGroupID: Pipe
|
||||||
|
pipeDirection: West
|
||||||
|
outlet:
|
||||||
|
!type:PipeNode
|
||||||
|
nodeGroupID: Pipe
|
||||||
|
pipeDirection: South
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
sprite: Structures/Piping/Atmospherics/pneumaticvalve.rsi
|
||||||
|
layers:
|
||||||
|
- sprite: Structures/Piping/Atmospherics/pipe.rsi
|
||||||
|
state: pipeTJunction
|
||||||
|
rotation: -90
|
||||||
|
map: [ "enum.PipeVisualLayers.Pipe" ]
|
||||||
|
- state: off
|
||||||
|
map: [ "enum.SubfloorLayers.FirstLayer", "enabled" ]
|
||||||
|
- type: Appearance
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.FilterVisuals.Enabled:
|
||||||
|
enabled:
|
||||||
|
True: { state: on }
|
||||||
|
False: { state: off }
|
||||||
|
- type: PipeColorVisuals
|
||||||
|
- type: PressureControlledValve
|
||||||
|
- type: AmbientSound
|
||||||
|
enabled: false
|
||||||
|
volume: -9
|
||||||
|
range: 5
|
||||||
|
sound:
|
||||||
|
path: /Audio/Ambience/Objects/gas_hiss.ogg
|
||||||
|
- type: Construction
|
||||||
|
graph: GasTrinary
|
||||||
|
node: pneumaticvalve
|
||||||
|
|||||||
@@ -16,6 +16,12 @@
|
|||||||
amount: 2
|
amount: 2
|
||||||
doAfter: 1
|
doAfter: 1
|
||||||
|
|
||||||
|
- to: pneumaticvalve
|
||||||
|
steps:
|
||||||
|
- material: Steel
|
||||||
|
amount: 2
|
||||||
|
doAfter: 1
|
||||||
|
|
||||||
- node: filter
|
- node: filter
|
||||||
entity: GasFilter
|
entity: GasFilter
|
||||||
edges:
|
edges:
|
||||||
@@ -47,3 +53,19 @@
|
|||||||
steps:
|
steps:
|
||||||
- tool: Welding
|
- tool: Welding
|
||||||
doAfter: 1
|
doAfter: 1
|
||||||
|
|
||||||
|
- node: pneumaticvalve
|
||||||
|
entity: PressureControlledValve
|
||||||
|
edges:
|
||||||
|
- to: start
|
||||||
|
conditions:
|
||||||
|
- !type:EntityAnchored
|
||||||
|
anchored: false
|
||||||
|
completed:
|
||||||
|
- !type:SpawnPrototype
|
||||||
|
prototype: SheetSteel1
|
||||||
|
amount: 2
|
||||||
|
- !type:DeleteEntity
|
||||||
|
steps:
|
||||||
|
- tool: Welding
|
||||||
|
doAfter: 1
|
||||||
|
|||||||
@@ -511,3 +511,17 @@
|
|||||||
conditions:
|
conditions:
|
||||||
- !type:TileNotBlocked {}
|
- !type:TileNotBlocked {}
|
||||||
|
|
||||||
|
- type: construction
|
||||||
|
id: PressureControlledValve
|
||||||
|
name: pneumatic valve
|
||||||
|
graph: GasTrinary
|
||||||
|
startNode: start
|
||||||
|
targetNode: pneumaticvalve
|
||||||
|
category: Utilities
|
||||||
|
placementMode: SnapgridCenter
|
||||||
|
canBuildInImpassable: false
|
||||||
|
icon:
|
||||||
|
sprite: Structures/Piping/Atmospherics/pneumaticvalve.rsi
|
||||||
|
state: off
|
||||||
|
conditions:
|
||||||
|
- !type:TileNotBlocked {}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-4.0",
|
||||||
|
"copyright": "Kevin Zheng 2022",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "off",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "on",
|
||||||
|
"directions": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Reference in New Issue
Block a user