diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasCondenserComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasCondenserComponent.cs
new file mode 100644
index 0000000000..1db0b524bb
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/Components/GasCondenserComponent.cs
@@ -0,0 +1,33 @@
+using Content.Server.Atmos.Piping.Unary.EntitySystems;
+
+namespace Content.Server.Atmos.Piping.Unary.Components;
+
+///
+/// Used for an entity that converts moles of gas into units of reagent.
+///
+[RegisterComponent]
+[Access(typeof(GasCondenserSystem))]
+public sealed partial class GasCondenserComponent : Component
+{
+ ///
+ /// The ID for the pipe node.
+ ///
+ [DataField]
+ public string Inlet = "pipe";
+
+ ///
+ /// The ID for the solution.
+ ///
+ [DataField]
+ public string SolutionId = "tank";
+
+ ///
+ /// For a condenser, how many U of reagents are given per each mole of gas.
+ ///
+ ///
+ /// Derived from a standard of 500u per canister:
+ /// 400u / 1871.71051 moles per canister
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float MolesToReagentMultiplier = 0.2137f;
+}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs
new file mode 100644
index 0000000000..1b790b5cf0
--- /dev/null
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs
@@ -0,0 +1,73 @@
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Atmos.Piping.Unary.Components;
+using Content.Server.NodeContainer;
+using Content.Server.NodeContainer.EntitySystems;
+using Content.Server.NodeContainer.Nodes;
+using Content.Server.Power.Components;
+using Content.Shared.Atmos;
+using JetBrains.Annotations;
+using Content.Server.Power.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
+
+namespace Content.Server.Atmos.Piping.Unary.EntitySystems;
+
+[UsedImplicitly]
+public sealed class GasCondenserSystem : EntitySystem
+{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+ [Dependency] private readonly PowerReceiverSystem _power = default!;
+ [Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
+ [Dependency] private readonly SolutionContainerSystem _solution = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnCondenserUpdated);
+ }
+
+ private void OnCondenserUpdated(EntityUid uid, GasCondenserComponent component, AtmosDeviceUpdateEvent args)
+ {
+ if (!(_power.IsPowered(uid) && TryComp(uid, out var receiver))
+ || !TryComp(uid, out var nodeContainer)
+ || !_nodeContainer.TryGetNode(nodeContainer, component.Inlet, out PipeNode? inlet)
+ || !_solution.TryGetSolution(uid, component.SolutionId, out var solution))
+ {
+ return;
+ }
+
+ if (solution.AvailableVolume == 0 || inlet.Air.TotalMoles == 0)
+ return;
+
+ var molesToConvert = NumberOfMolesToConvert(receiver, inlet.Air, args.dt);
+ var removed = inlet.Air.Remove(molesToConvert);
+ for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
+ {
+ var moles = removed.Moles[i];
+ if (moles <= 0)
+ continue;
+
+ if (_atmosphereSystem.GetGas(i).Reagent is not {} gasReagent)
+ continue;
+
+ var moleToReagentMultiplier = component.MolesToReagentMultiplier;
+ var amount = moles * moleToReagentMultiplier;
+
+ if (_solution.TryAddReagent(uid, solution, gasReagent, amount, out var remaining))
+ continue;
+
+ // if we have leftover reagent, then convert it back to moles and put it back in the mixture.
+ inlet.Air.AdjustMoles(i, remaining.Float() / moleToReagentMultiplier);
+ }
+ }
+
+ public float NumberOfMolesToConvert(ApcPowerReceiverComponent comp, GasMixture mix, float dt)
+ {
+ var hc = _atmosphereSystem.GetHeatCapacity(mix);
+ var alpha = 0.8f; // tuned to give us 1-ish u/second of reagent conversion
+ // ignores the energy needed to cool down the solution to the condensation point, but that probably adds too much difficulty and so let's not simulate that
+ var energy = comp.Load * dt;
+ return energy / (alpha * hc);
+ }
+}
diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs
index bb90351483..04ad17869f 100644
--- a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs
+++ b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs
@@ -374,6 +374,22 @@ public sealed partial class SolutionContainerSystem : EntitySystem
return acceptedQuantity == reagentQuantity.Quantity;
}
+ ///
+ /// Adds reagent of an Id to the container.
+ ///
+ ///
+ /// Container to which we are adding reagent
+ /// The Id of the reagent to add.
+ /// The amount of reagent to add.
+ /// If all the reagent could be added.
+ [PublicAPI]
+ public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string prototype, FixedPoint2 quantity,
+ float? temperature = null, ReagentData? data = null)
+ {
+ var reagent = new ReagentQuantity(prototype, quantity, data);
+ return TryAddReagent(targetUid, targetSolution, reagent, out _, temperature);
+ }
+
///
/// Adds reagent of an Id to the container.
///
diff --git a/Resources/Locale/en-US/wires/wire-names.ftl b/Resources/Locale/en-US/wires/wire-names.ftl
index aae87f9c53..4a94dc9ac6 100644
--- a/Resources/Locale/en-US/wires/wire-names.ftl
+++ b/Resources/Locale/en-US/wires/wire-names.ftl
@@ -3,6 +3,7 @@ wires-board-name-default = Wires
wires-board-name-booze = BoozeDispenser
wires-board-name-soda = SodaDispenser
wires-board-name-thermomachine = Thermomachine
+wires-board-name-condenser = Condenser
wires-board-name-pa = Mk2 Particle Accelerator
wires-board-name-highsec = HighSec Control
wires-board-name-vessel = Vessel
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
index af4f8cba78..7af85a09f0 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
@@ -338,6 +338,21 @@
deconstructionTarget: null
node: heater
+- type: entity
+ id: CondenserMachineCircuitBoard
+ parent: BaseMachineCircuitboard
+ name: condenser machine board
+ description: A machine printed circuit board for a condenser.
+ components:
+ - type: Sprite
+ state: engineering
+ - type: MachineBoard
+ prototype: BaseGasCondenser
+ requirements:
+ MatterBin: 1
+ materialRequirements:
+ Glass: 1
+
- type: entity
id: PortableScrubberMachineCircuitBoard
parent: BaseMachineCircuitboard
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 5972a6c976..730ecdf72d 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -306,6 +306,8 @@
producingSound: /Audio/Machines/circuitprinter.ogg
idleState: icon
runningState: building
+ staticRecipes:
+ - CondenserMachineCircuitBoard
dynamicRecipes:
- ThermomachineFreezerMachineCircuitBoard
- PortableScrubberMachineCircuitBoard
diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
index 0fdad5d967..05135da0ce 100644
--- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
+++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
@@ -351,3 +351,89 @@
enabled: true
- type: ApcPowerReceiver
powerDisabled: false
+
+- type: entity
+ parent: [ BaseMachinePowered, ConstructibleMachine ]
+ id: BaseGasCondenser
+ name: condenser
+ description: Condenses gases into liquids. Now we just need some plumbing.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Sprite
+ sprite: Structures/Piping/Atmospherics/condenser.rsi
+ snapCardinals: true
+ granularLayersRendering: true
+ layers:
+ - state: off
+ map: [ "enum.PowerDeviceVisualLayers.Powered" ]
+ - state: panel
+ map: ["enum.WiresVisualLayers.MaintenancePanel"]
+ - state: pipe
+ map: [ "enum.PipeVisualLayers.Pipe" ]
+ renderingStrategy: Default
+ - state: fill-1
+ map: ["enum.SolutionContainerLayers.Fill"]
+ visible: false
+ - state: trans
+ - type: GenericVisualizer
+ visuals:
+ enum.PowerDeviceVisuals.Powered:
+ enum.PowerDeviceVisualLayers.Powered:
+ True: { state: on }
+ False: { state: off }
+ - type: SolutionContainerVisuals
+ maxFillLevels: 7
+ fillBaseName: fill-
+ - type: Appearance
+ - type: PipeColorVisuals
+ - type: Rotatable
+ - type: GasCondenser
+ - type: AtmosPipeColor
+ - type: AtmosDevice
+ - type: ApcPowerReceiver
+ powerLoad: 10000
+ - type: Machine
+ board: CondenserMachineCircuitBoard
+ - type: WiresPanel
+ - type: Wires
+ boardName: wires-board-name-condenser
+ layoutId: Condenser
+ - type: WiresVisuals
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 200
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - trigger:
+ !type:DamageTrigger
+ damage: 100
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - !type:SpillBehavior
+ solution: tank
+ - !type:PlaySoundBehavior
+ sound:
+ path: /Audio/Effects/metalbreak.ogg
+ - type: NodeContainer
+ nodes:
+ pipe:
+ !type:PipeNode
+ nodeGroupID: Pipe
+ pipeDirection: South
+ - type: Transform
+ noRot: false
+ - type: SolutionContainerManager
+ solutions:
+ tank:
+ maxVol: 400
+ canMix: true
+ - type: DrainableSolution
+ solution: tank
+ - type: ExaminableSolution
+ solution: tank
+ - type: PowerSwitch
diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml
index 8477e6c9be..9ab48db864 100644
--- a/Resources/Prototypes/Recipes/Lathes/electronics.yml
+++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml
@@ -104,6 +104,14 @@
Glass: 900
Gold: 50
+- type: latheRecipe
+ id: CondenserMachineCircuitBoard
+ result: CondenserMachineCircuitBoard
+ completetime: 4
+ materials:
+ Steel: 100
+ Glass: 900
+
- type: latheRecipe
id: PortableScrubberMachineCircuitBoard
result: PortableScrubberMachineCircuitBoard
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-1.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-1.png
new file mode 100644
index 0000000000..a030b2d524
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-1.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-2.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-2.png
new file mode 100644
index 0000000000..9007c74cb3
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-2.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-3.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-3.png
new file mode 100644
index 0000000000..364bd10840
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-3.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-4.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-4.png
new file mode 100644
index 0000000000..efbfaf5c04
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-4.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-5.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-5.png
new file mode 100644
index 0000000000..f87544fa82
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-5.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-6.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-6.png
new file mode 100644
index 0000000000..1fabf81878
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-6.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-7.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-7.png
new file mode 100644
index 0000000000..55e26a4d5a
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/fill-7.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json
new file mode 100644
index 0000000000..591c223e5c
--- /dev/null
+++ b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json
@@ -0,0 +1,60 @@
+{
+ "version":1,
+ "size":
+ {
+ "x":32,
+ "y":32
+ },
+ "copyright":"Created by EmoGarbage404 (github) for Space Station 14.",
+ "license":"CC0-1.0",
+ "states":
+ [
+ {
+ "name":"off"
+ },
+ {
+ "name":"on",
+ "delays":
+ [
+ [
+ 0.05,
+ 0.05,
+ 0.05,
+ 0.05,
+ 0.05
+ ]
+ ]
+ },
+ {
+ "name":"panel"
+ },
+ {
+ "name":"trans"
+ },
+ {
+ "name":"pipe",
+ "directions":4
+ },
+ {
+ "name":"fill-1"
+ },
+ {
+ "name":"fill-2"
+ },
+ {
+ "name":"fill-3"
+ },
+ {
+ "name":"fill-4"
+ },
+ {
+ "name":"fill-5"
+ },
+ {
+ "name":"fill-6"
+ },
+ {
+ "name":"fill-7"
+ }
+ ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/off.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/off.png
new file mode 100644
index 0000000000..523adff6c3
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/off.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/on.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/on.png
new file mode 100644
index 0000000000..268750001a
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/on.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/panel.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/panel.png
new file mode 100644
index 0000000000..05c2f179fa
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/panel.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/pipe.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/pipe.png
new file mode 100644
index 0000000000..c9fbbec300
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/pipe.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/trans.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/trans.png
new file mode 100644
index 0000000000..06e34a2e36
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/trans.png differ