]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Layering for atmospheric pipes (#36124)
authorchromiumboy <50505512+chromiumboy@users.noreply.github.com>
Mon, 2 Jun 2025 05:01:43 +0000 (00:01 -0500)
committerGitHub <noreply@github.com>
Mon, 2 Jun 2025 05:01:43 +0000 (22:01 -0700)
Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
Co-authored-by: Kevin Zheng <kevinz5000@gmail.com>
134 files changed:
Content.Client/Atmos/AlignAtmosPipeLayers.cs [new file with mode: 0644]
Content.Client/Atmos/Consoles/AtmosMonitoringConsoleNavMapControl.cs
Content.Client/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs
Content.Client/Atmos/Consoles/AtmosMonitoringConsoleWindow.xaml.cs
Content.Client/Atmos/EntitySystems/AtmosPipeAppearanceSystem.cs
Content.Client/Atmos/EntitySystems/AtmosPipeLayersSystem.cs [new file with mode: 0644]
Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs
Content.Client/Construction/ConstructionPlacementHijack.cs
Content.Server/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs
Content.Server/Atmos/EntitySystems/AtmosPipeLayersSystem.cs [new file with mode: 0644]
Content.Server/Atmos/EntitySystems/PipeRestrictOverlapSystem.cs
Content.Server/Atmos/Piping/Components/GasPipeManifoldComponent.cs [new file with mode: 0644]
Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs
Content.Server/Atmos/Piping/EntitySystems/GasPipeManifoldSystem.cs [new file with mode: 0644]
Content.Server/NodeContainer/Nodes/PipeNode.cs
Content.Shared/Atmos/Components/AtmosPipeLayersComponent.cs [new file with mode: 0644]
Content.Shared/Atmos/Components/PipeAppearanceComponent.cs
Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleComponent.cs
Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleDeviceComponent.cs
Content.Shared/Atmos/Consoles/SharedAtmosMonitoringConsoleSystem.cs
Content.Shared/Atmos/EntitySystems/SharedAtmosPipeAppearanceSystem.cs [new file with mode: 0644]
Content.Shared/Atmos/EntitySystems/SharedAtmosPipeLayersSystem.cs [new file with mode: 0644]
Content.Shared/Construction/Prototypes/ConstructionPrototype.cs
Content.Shared/DrawDepth/DrawDepth.cs
Content.Shared/Prototypes/NavMapBlipPrototype.cs
Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
Content.Shared/Verbs/VerbCategory.cs
Resources/Locale/en-US/atmos/atmos-pipe-layers.ftl [new file with mode: 0644]
Resources/Locale/en-US/verbs/verb-system.ftl
Resources/Prototypes/Entities/Structures/Machines/Computers/nav_map_blips.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/alt_layers.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/gas_pipe_sensor.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml
Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml
Resources/Prototypes/Recipes/Construction/Graphs/utilities/atmos_pipes.yml
Resources/Prototypes/Recipes/Construction/utilities.yml
Resources/Textures/Interface/NavMap/attributions.yml
Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png [new file with mode: 0644]
Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png.yml [new file with mode: 0644]
Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png [new file with mode: 0644]
Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png.yml [new file with mode: 0644]
Resources/Textures/Interface/VerbIcons/ATTRIBUTION.txt
Resources/Textures/Interface/VerbIcons/screwdriver.png [new file with mode: 0644]
Resources/Textures/Interface/VerbIcons/screwdriver.png.yml [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json
Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/pipe.png
Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/pipe.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/pipe.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/base.png
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/lights.png
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/meta.json
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/base.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/blank.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/lights.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/base.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/blank.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/lights.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/meta.json
Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/pipe.png
Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt1.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt2.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeManifold.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/storageManifold.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/meta.json
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBinaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeUnaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageFourway.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageHalf.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png
Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBend.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBinaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBroken.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeConnector.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeFourway.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeHalf.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeStraight.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTJunction.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTrinaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeUnaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBend.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBinaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBroken.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeConnector.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeFourway.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeHalf.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeStraight.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTJunction.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTrinaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeUnaryConnectors.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpDigitalValve.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValve.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValveOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGate.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGateOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressure.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressureOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValve.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValveOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolume.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeBlocked.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpDigitalValve.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValve.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValveOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGate.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGateOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressure.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressureOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValve.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValveOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolume.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeBlocked.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeOn.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/meta.json
Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/pipe.png
Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/pipe.png [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/pipe.png [new file with mode: 0644]

diff --git a/Content.Client/Atmos/AlignAtmosPipeLayers.cs b/Content.Client/Atmos/AlignAtmosPipeLayers.cs
new file mode 100644 (file)
index 0000000..1bf3310
--- /dev/null
@@ -0,0 +1,203 @@
+using Content.Client.Construction;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
+using Content.Shared.Construction.Prototypes;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Client.Placement;
+using Robust.Client.Placement.Modes;
+using Robust.Client.Utility;
+using Robust.Shared.Enums;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+using System.Numerics;
+using static Robust.Client.Placement.PlacementManager;
+
+namespace Content.Client.Atmos;
+
+/// <summary>
+/// Allows users to place atmos pipes on different layers depending on how the mouse cursor is positioned within a grid tile.
+/// </summary>
+/// <remarks>
+/// This placement mode is not on the engine because it is content specific.
+/// </remarks>
+public sealed class AlignAtmosPipeLayers : SnapgridCenter
+{
+    [Dependency] private readonly IEntityManager _entityManager = default!;
+    [Dependency] private readonly IPrototypeManager _protoManager = default!;
+    [Dependency] private readonly IMapManager _mapManager = default!;
+    [Dependency] private readonly IEyeManager _eyeManager = default!;
+
+    private readonly SharedMapSystem _mapSystem;
+    private readonly SharedTransformSystem _transformSystem;
+    private readonly SharedAtmosPipeLayersSystem _pipeLayersSystem;
+    private readonly SpriteSystem _spriteSystem;
+
+    private const float SearchBoxSize = 2f;
+    private EntityCoordinates _unalignedMouseCoords = default;
+    private const float MouseDeadzoneRadius = 0.25f;
+
+    private Color _guideColor = new Color(0, 0, 0.5785f);
+    private const float GuideRadius = 0.1f;
+    private const float GuideOffset = 0.21875f;
+
+    public AlignAtmosPipeLayers(PlacementManager pMan) : base(pMan)
+    {
+        IoCManager.InjectDependencies(this);
+
+        _mapSystem = _entityManager.System<SharedMapSystem>();
+        _transformSystem = _entityManager.System<SharedTransformSystem>();
+        _pipeLayersSystem = _entityManager.System<SharedAtmosPipeLayersSystem>();
+        _spriteSystem = _entityManager.System<SpriteSystem>();
+    }
+
+    /// <inheritdoc/>
+    public override void Render(in OverlayDrawArgs args)
+    {
+        var gridUid = _entityManager.System<SharedTransformSystem>().GetGrid(MouseCoords);
+
+        if (gridUid == null || Grid == null)
+            return;
+
+        // Draw guide circles for each pipe layer if we are not in line/grid placing mode
+        if (pManager.PlacementType == PlacementTypes.None)
+        {
+            var gridRotation = _transformSystem.GetWorldRotation(gridUid.Value);
+            var worldPosition = _mapSystem.LocalToWorld(gridUid.Value, Grid, MouseCoords.Position);
+            var direction = (_eyeManager.CurrentEye.Rotation + gridRotation + Math.PI / 2).GetCardinalDir();
+            var multi = (direction == Direction.North || direction == Direction.South) ? -1f : 1f;
+
+            args.WorldHandle.DrawCircle(worldPosition, GuideRadius, _guideColor);
+            args.WorldHandle.DrawCircle(worldPosition + gridRotation.RotateVec(new Vector2(multi * GuideOffset, GuideOffset)), GuideRadius, _guideColor);
+            args.WorldHandle.DrawCircle(worldPosition - gridRotation.RotateVec(new Vector2(multi * GuideOffset, GuideOffset)), GuideRadius, _guideColor);
+        }
+
+        base.Render(args);
+    }
+
+    /// <inheritdoc/>
+    public override void AlignPlacementMode(ScreenCoordinates mouseScreen)
+    {
+        _unalignedMouseCoords = ScreenToCursorGrid(mouseScreen);
+        base.AlignPlacementMode(mouseScreen);
+
+        // Exit early if we are in line/grid placing mode
+        if (pManager.PlacementType != PlacementTypes.None)
+            return;
+
+        MouseCoords = _unalignedMouseCoords.AlignWithClosestGridTile(SearchBoxSize, _entityManager, _mapManager);
+
+        var gridId = _transformSystem.GetGrid(MouseCoords);
+
+        if (!_entityManager.TryGetComponent<MapGridComponent>(gridId, out var mapGrid))
+            return;
+
+        var gridRotation = _transformSystem.GetWorldRotation(gridId.Value);
+        CurrentTile = _mapSystem.GetTileRef(gridId.Value, mapGrid, MouseCoords);
+
+        float tileSize = mapGrid.TileSize;
+        GridDistancing = tileSize;
+
+        MouseCoords = new EntityCoordinates(MouseCoords.EntityId, new Vector2(CurrentTile.X + tileSize / 2 + pManager.PlacementOffset.X,
+            CurrentTile.Y + tileSize / 2 + pManager.PlacementOffset.Y));
+
+        // Calculate the position of the mouse cursor with respect to the center of the tile to determine which layer to use
+        var mouseCoordsDiff = _unalignedMouseCoords.Position - MouseCoords.Position;
+        var layer = AtmosPipeLayer.Primary;
+
+        if (mouseCoordsDiff.Length() > MouseDeadzoneRadius)
+        {
+            // Determine the direction of the mouse is relative to the center of the tile, adjusting for the player eye and grid rotation
+            var direction = (new Angle(mouseCoordsDiff) + _eyeManager.CurrentEye.Rotation + gridRotation + Math.PI / 2).GetCardinalDir();
+            layer = (direction == Direction.North || direction == Direction.East) ? AtmosPipeLayer.Secondary : AtmosPipeLayer.Tertiary;
+        }
+
+        // Update the construction menu placer
+        if (pManager.Hijack != null)
+            UpdateHijackedPlacer(layer, mouseScreen);
+
+        // Otherwise update the debug placer
+        else
+            UpdatePlacer(layer);
+    }
+
+    private void UpdateHijackedPlacer(AtmosPipeLayer layer, ScreenCoordinates mouseScreen)
+    {
+        // Try to get alternative prototypes from the construction prototype
+        var constructionSystem = (pManager.Hijack as ConstructionPlacementHijack)?.CurrentConstructionSystem;
+        var altPrototypes = (pManager.Hijack as ConstructionPlacementHijack)?.CurrentPrototype?.AlternativePrototypes;
+
+        if (constructionSystem == null || altPrototypes == null || (int)layer >= altPrototypes.Length)
+            return;
+
+        var newProtoId = altPrototypes[(int)layer];
+
+        if (!_protoManager.TryIndex(newProtoId, out var newProto))
+            return;
+
+        if (newProto.Type != ConstructionType.Structure)
+        {
+            pManager.Clear();
+            return;
+        }
+
+        if (newProto.ID == (pManager.Hijack as ConstructionPlacementHijack)?.CurrentPrototype?.ID)
+            return;
+
+        // Start placing
+        pManager.BeginPlacing(new PlacementInformation()
+        {
+            IsTile = false,
+            PlacementOption = newProto.PlacementMode,
+        }, new ConstructionPlacementHijack(constructionSystem, newProto));
+
+        if (pManager.CurrentMode is AlignAtmosPipeLayers { } newMode)
+            newMode.RefreshGrid(mouseScreen);
+
+        // Update construction guide
+        constructionSystem.GetGuide(newProto);
+    }
+
+    private void UpdatePlacer(AtmosPipeLayer layer)
+    {
+        // Try to get alternative prototypes from the entity atmos pipe layer component
+        if (pManager.CurrentPermission?.EntityType == null)
+            return;
+
+        if (!_protoManager.TryIndex<EntityPrototype>(pManager.CurrentPermission.EntityType, out var currentProto))
+            return;
+
+        if (!currentProto.TryGetComponent<AtmosPipeLayersComponent>(out var atmosPipeLayers, _entityManager.ComponentFactory))
+            return;
+
+        if (!_pipeLayersSystem.TryGetAlternativePrototype(atmosPipeLayers, layer, out var newProtoId))
+            return;
+
+        if (_protoManager.TryIndex<EntityPrototype>(newProtoId, out var newProto))
+        {
+            // Update the placed prototype
+            pManager.CurrentPermission.EntityType = newProtoId;
+
+            // Update the appearance of the ghost sprite
+            if (newProto.TryGetComponent<SpriteComponent>(out var sprite, _entityManager.ComponentFactory))
+            {
+                var textures = new List<IDirectionalTextureProvider>();
+
+                foreach (var spriteLayer in sprite.AllLayers)
+                {
+                    if (spriteLayer.ActualRsi?.Path != null && spriteLayer.RsiState.Name != null)
+                        textures.Add(_spriteSystem.RsiStateLike(new SpriteSpecifier.Rsi(spriteLayer.ActualRsi.Path, spriteLayer.RsiState.Name)));
+                }
+
+                pManager.CurrentTextures = textures;
+            }
+        }
+    }
+
+    private void RefreshGrid(ScreenCoordinates mouseScreen)
+    {
+        base.AlignPlacementMode(mouseScreen);
+    }
+}
index c23ebb643558741a8ad6330252252d7dcf90fa31..20902722ff1beec6f00e8acc4619d6789a0c5eb8 100644 (file)
@@ -17,6 +17,10 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
     public int? FocusNetId = null;
 
     private const int ChunkSize = 4;
+    private const float ScaleModifier = 4f;
+
+    private readonly float[] _layerFraction = { 0.5f, 0.75f, 0.25f };
+    private const float LineThickness = 0.05f;
 
     private readonly Color _basePipeNetColor = Color.LightGray;
     private readonly Color _unfocusedPipeNetColor = Color.DimGray;
@@ -95,23 +99,23 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
             foreach (var chunkedLine in atmosPipeNetwork)
             {
                 var leftTop = ScalePosition(new Vector2
-                    (Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - 0.1f,
-                    Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - 0.1f)
+                    (Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - LineThickness,
+                    Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - LineThickness)
                     - offset);
 
                 var rightTop = ScalePosition(new Vector2
-                    (Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + 0.1f,
-                    Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - 0.1f)
+                    (Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + LineThickness,
+                    Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - LineThickness)
                     - offset);
 
                 var leftBottom = ScalePosition(new Vector2
-                    (Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - 0.1f,
-                    Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + 0.1f)
+                    (Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - LineThickness,
+                    Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + LineThickness)
                     - offset);
 
                 var rightBottom = ScalePosition(new Vector2
-                    (Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + 0.1f,
-                    Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + 0.1f)
+                    (Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + LineThickness,
+                    Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + LineThickness)
                     - offset);
 
                 if (!pipeVertexUVs.TryGetValue(chunkedLine.Color, out var pipeVertexUV))
@@ -142,7 +146,7 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
         if (chunks == null || grid == null)
             return decodedOutput;
 
-        // Clear stale look up table values 
+        // Clear stale look up table values
         _horizLines.Clear();
         _horizLinesReversed.Clear();
         _vertLines.Clear();
@@ -158,7 +162,7 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
         {
             var list = new List<AtmosMonitoringConsoleLine>();
 
-            foreach (var ((netId, hexColor), atmosPipeData) in chunk.AtmosPipeData)
+            foreach (var ((netId, layer, hexColor), atmosPipeData) in chunk.AtmosPipeData)
             {
                 // Determine the correct coloration for the pipe
                 var color = Color.FromHex(hexColor) * _basePipeNetColor;
@@ -191,6 +195,9 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
                     _vertLinesReversed[color] = vertLinesReversed;
                 }
 
+                var layerFraction = _layerFraction[(int)layer];
+                var origin = new Vector2(grid.TileSize * layerFraction, -grid.TileSize * layerFraction);
+
                 // Loop over the chunk
                 for (var tileIdx = 0; tileIdx < ChunkSize * ChunkSize; tileIdx++)
                 {
@@ -208,21 +215,22 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
 
                     // Calculate the draw point offsets
                     var vertLineOrigin = (atmosPipeData & northMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
-                        new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 1f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
+                        new Vector2(grid.TileSize * layerFraction, -grid.TileSize * 1f) : origin;
 
                     var vertLineTerminus = (atmosPipeData & southMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
-                        new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
+                        new Vector2(grid.TileSize * layerFraction, -grid.TileSize * 0f) : origin;
 
                     var horizLineOrigin = (atmosPipeData & eastMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
-                        new Vector2(grid.TileSize * 1f, -grid.TileSize * 0.5f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
+                        new Vector2(grid.TileSize * 1f, -grid.TileSize * layerFraction) : origin;
 
                     var horizLineTerminus = (atmosPipeData & westMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
-                        new Vector2(grid.TileSize * 0f, -grid.TileSize * 0.5f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
+                        new Vector2(grid.TileSize * 0f, -grid.TileSize * layerFraction) : origin;
 
-                    // Since we can have pipe lines that have a length of a half tile, 
-                    // double the vectors and convert to vector2i so we can merge them
-                    AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + horizLineOrigin, 2), ConvertVector2ToVector2i(tile + horizLineTerminus, 2), horizLines, horizLinesReversed);
-                    AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + vertLineOrigin, 2), ConvertVector2ToVector2i(tile + vertLineTerminus, 2), vertLines, vertLinesReversed);
+                    // Scale up the vectors and convert to vector2i so we can merge them
+                    AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + horizLineOrigin, ScaleModifier),
+                        ConvertVector2ToVector2i(tile + horizLineTerminus, ScaleModifier), horizLines, horizLinesReversed);
+                    AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + vertLineOrigin, ScaleModifier),
+                        ConvertVector2ToVector2i(tile + vertLineTerminus, ScaleModifier), vertLines, vertLinesReversed);
                 }
             }
         }
@@ -235,7 +243,7 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
 
             foreach (var (origin, terminal) in horizLines)
                 decodedOutput.Add(new AtmosMonitoringConsoleLine
-                    (ConvertVector2iToVector2(origin, 0.5f), ConvertVector2iToVector2(terminal, 0.5f), sRGB));
+                    (ConvertVector2iToVector2(origin, 1f / ScaleModifier), ConvertVector2iToVector2(terminal, 1f / ScaleModifier), sRGB));
         }
 
         foreach (var (color, vertLines) in _vertLines)
@@ -245,7 +253,7 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
 
             foreach (var (origin, terminal) in vertLines)
                 decodedOutput.Add(new AtmosMonitoringConsoleLine
-                    (ConvertVector2iToVector2(origin, 0.5f), ConvertVector2iToVector2(terminal, 0.5f), sRGB));
+                    (ConvertVector2iToVector2(origin, 1f / ScaleModifier), ConvertVector2iToVector2(terminal, 1f / ScaleModifier), sRGB));
         }
 
         return decodedOutput;
index bfbb05d2ab150e26868485339563a92a9fd42d80..6a4967e4a41253c180e7dd79fb1422ae716e89c1 100644 (file)
@@ -15,7 +15,7 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
 
     private void OnHandleState(EntityUid uid, AtmosMonitoringConsoleComponent component, ref ComponentHandleState args)
     {
-        Dictionary<Vector2i, Dictionary<(int, string), ulong>> modifiedChunks;
+        Dictionary<Vector2i, Dictionary<AtmosMonitoringConsoleSubnet, ulong>> modifiedChunks;
         Dictionary<NetEntity, AtmosDeviceNavMapData> atmosDevices;
 
         switch (args.Current)
@@ -54,7 +54,7 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
         foreach (var (origin, chunk) in modifiedChunks)
         {
             var newChunk = new AtmosPipeChunk(origin);
-            newChunk.AtmosPipeData = new Dictionary<(int, string), ulong>(chunk);
+            newChunk.AtmosPipeData = new Dictionary<AtmosMonitoringConsoleSubnet, ulong>(chunk);
 
             component.AtmosPipeChunks[origin] = newChunk;
         }
index e25c3af9e9076bd0dba2545988f7d17493f7ec5d..1a084ea73bf93ada0c7635394783b21ad080eb85 100644 (file)
@@ -13,6 +13,7 @@ using Robust.Shared.Timing;
 using Robust.Shared.Utility;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
+using System.Numerics;
 
 namespace Content.Client.Atmos.Consoles;
 
@@ -33,6 +34,8 @@ public sealed partial class AtmosMonitoringConsoleWindow : FancyWindow
     private ProtoId<NavMapBlipPrototype> _navMapConsoleProtoId = "NavMapConsole";
     private ProtoId<NavMapBlipPrototype> _gasPipeSensorProtoId = "GasPipeSensor";
 
+    private readonly Vector2[] _pipeLayerOffsets = { new Vector2(0f, 0f), new Vector2(0.25f, 0.25f), new Vector2(-0.25f, -0.25f) };
+
     public AtmosMonitoringConsoleWindow(AtmosMonitoringConsoleBoundUserInterface userInterface, EntityUid? owner)
     {
         RobustXamlLoader.Load(this);
@@ -53,7 +56,7 @@ public sealed partial class AtmosMonitoringConsoleWindow : FancyWindow
             consoleCoords = xform.Coordinates;
             NavMap.MapUid = xform.GridUid;
 
-            // Assign station name      
+            // Assign station name
             if (_entManager.TryGetComponent<MetaDataComponent>(xform.GridUid, out var stationMetaData))
                 stationName = stationMetaData.EntityName;
 
@@ -238,6 +241,10 @@ public sealed partial class AtmosMonitoringConsoleWindow : FancyWindow
 
         var blinks = proto.Blinks || _focusEntity == metaData.NetEntity;
         var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
+
+        if (proto.Placement == NavMapBlipPlacement.Offset && metaData.PipeLayer > 0)
+            coords = coords.Offset(_pipeLayerOffsets[(int)metaData.PipeLayer]);
+
         var blip = new NavMapBlip(coords, _spriteSystem.Frame0(new SpriteSpecifier.Texture(texture)), color, blinks, proto.Selectable, proto.Scale);
         NavMap.TrackedEntities[metaData.NetEntity] = blip;
     }
index 2029cb9be5d32708ea53c905d4f7cf27da3c50af..1a12c3967b5b6df57ef97444adac8d3e58512924 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Client.SubFloor;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
 using Content.Shared.Atmos.Piping;
 using JetBrains.Annotations;
 using Robust.Client.GameObjects;
@@ -8,7 +9,7 @@ using Robust.Client.GameObjects;
 namespace Content.Client.Atmos.EntitySystems;
 
 [UsedImplicitly]
-public sealed class AtmosPipeAppearanceSystem : EntitySystem
+public sealed partial class AtmosPipeAppearanceSystem : SharedAtmosPipeAppearanceSystem
 {
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SpriteSystem _sprite = default!;
@@ -26,26 +27,37 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
         if (!TryComp(uid, out SpriteComponent? sprite))
             return;
 
+        var numberOfPipeLayers = GetNumberOfPipeLayers(uid, out _);
+
         foreach (var layerKey in Enum.GetValues<PipeConnectionLayer>())
         {
-            var layer = _sprite.LayerMapReserve((uid, sprite), layerKey);
-            _sprite.LayerSetRsi((uid, sprite), layer, component.Sprite.RsiPath);
-            _sprite.LayerSetRsiState((uid, sprite), layer, component.Sprite.RsiState);
-            _sprite.LayerSetDirOffset((uid, sprite), layer, ToOffset(layerKey));
+            for (byte i = 0; i < numberOfPipeLayers; i++)
+            {
+                var layerName = layerKey.ToString() + i.ToString();
+                var layer = _sprite.LayerMapReserve((uid, sprite), layerName);
+                _sprite.LayerSetRsi((uid, sprite), layer, component.Sprite[i].RsiPath);
+                _sprite.LayerSetRsiState((uid, sprite), layer, component.Sprite[i].RsiState);
+                _sprite.LayerSetDirOffset((uid, sprite), layer, ToOffset(layerKey));
+            }
         }
     }
 
-    private void HideAllPipeConnection(Entity<SpriteComponent> entity)
+    private void HideAllPipeConnection(Entity<SpriteComponent> entity, AtmosPipeLayersComponent? atmosPipeLayers, int numberOfPipeLayers)
     {
         var sprite = entity.Comp;
 
         foreach (var layerKey in Enum.GetValues<PipeConnectionLayer>())
         {
-            if (!_sprite.LayerMapTryGet(entity.AsNullable(), layerKey, out var key, false))
-                continue;
+            for (byte i = 0; i < numberOfPipeLayers; i++)
+            {
+                var layerName = layerKey.ToString() + i.ToString();
+
+                if (!_sprite.LayerMapTryGet(entity.AsNullable(), layerName, out var key, false))
+                    continue;
 
-            var layer = sprite[key];
-            layer.Visible = false;
+                var layer = sprite[key];
+                layer.Visible = false;
+            }
         }
     }
 
@@ -61,33 +73,45 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
             return;
         }
 
-        if (!_appearance.TryGetData<PipeDirection>(uid, PipeVisuals.VisualState, out var worldConnectedDirections, args.Component))
+        var numberOfPipeLayers = GetNumberOfPipeLayers(uid, out var atmosPipeLayers);
+
+        if (!_appearance.TryGetData<int>(uid, PipeVisuals.VisualState, out var worldConnectedDirections, args.Component))
         {
-            HideAllPipeConnection((uid, args.Sprite));
+            HideAllPipeConnection((uid, args.Sprite), atmosPipeLayers, numberOfPipeLayers);
             return;
         }
 
         if (!_appearance.TryGetData<Color>(uid, PipeColorVisuals.Color, out var color, args.Component))
             color = Color.White;
 
-        // transform connected directions to local-coordinates
-        var connectedDirections = worldConnectedDirections.RotatePipeDirection(-Transform(uid).LocalRotation);
-
-        foreach (var layerKey in Enum.GetValues<PipeConnectionLayer>())
+        for (byte i = 0; i < numberOfPipeLayers; i++)
         {
-            if (!_sprite.LayerMapTryGet((uid, args.Sprite), layerKey, out var key, false))
-                continue;
+            // Extract the cardinal pipe orientations for the current pipe layer
+            // '15' is the four bit mask that is used to extract the pipe orientations of interest from 'worldConnectedDirections'
+            // Fun fact: a collection of four bits is called a 'nibble'! They aren't natively supported :(
+            var pipeLayerConnectedDirections = (PipeDirection)(15 & (worldConnectedDirections >> (PipeDirectionHelpers.PipeDirections * i)));
+
+            // Transform the connected directions to local-coordinates
+            var connectedDirections = pipeLayerConnectedDirections.RotatePipeDirection(-Transform(uid).LocalRotation);
+
+            foreach (var layerKey in Enum.GetValues<PipeConnectionLayer>())
+            {
+                var layerName = layerKey.ToString() + i.ToString();
+
+                if (!_sprite.LayerMapTryGet((uid, args.Sprite), layerName, out var key, false))
+                    continue;
 
-            var layer = args.Sprite[key];
-            var dir = (PipeDirection)layerKey;
-            var visible = connectedDirections.HasDirection(dir);
+                var layer = args.Sprite[key];
+                var dir = (PipeDirection)layerKey;
+                var visible = connectedDirections.HasDirection(dir);
 
-            layer.Visible &= visible;
+                layer.Visible &= visible;
 
-            if (!visible)
-                continue;
+                if (!visible)
+                    continue;
 
-            layer.Color = color;
+                layer.Color = color;
+            }
         }
     }
 
diff --git a/Content.Client/Atmos/EntitySystems/AtmosPipeLayersSystem.cs b/Content.Client/Atmos/EntitySystems/AtmosPipeLayersSystem.cs
new file mode 100644 (file)
index 0000000..f560e0b
--- /dev/null
@@ -0,0 +1,56 @@
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
+using Robust.Client.GameObjects;
+using Robust.Client.ResourceManagement;
+using Robust.Shared.Reflection;
+using Robust.Shared.Serialization.TypeSerializers.Implementations;
+using Robust.Shared.Utility;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Content.Client.Atmos.EntitySystems;
+
+/// <summary>
+/// The system responsible for updating the appearance of layered gas pipe
+/// </summary>
+public sealed partial class AtmosPipeLayersSystem : SharedAtmosPipeLayersSystem
+{
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly IReflectionManager _reflection = default!;
+    [Dependency] private readonly IResourceCache _resourceCache = default!;
+    [Dependency] private readonly SpriteSystem _sprite = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<AtmosPipeLayersComponent, AppearanceChangeEvent>(OnAppearanceChange);
+    }
+
+    private void OnAppearanceChange(Entity<AtmosPipeLayersComponent> ent, ref AppearanceChangeEvent ev)
+    {
+        if (!TryComp<SpriteComponent>(ent, out var sprite))
+            return;
+
+        if (_appearance.TryGetData<string>(ent, AtmosPipeLayerVisuals.Sprite, out var spriteRsi) &&
+            _resourceCache.TryGetResource(SpriteSpecifierSerializer.TextureRoot / spriteRsi, out RSIResource? resource))
+        {
+            _sprite.SetBaseRsi((ent, sprite), resource.RSI);
+        }
+
+        if (_appearance.TryGetData<Dictionary<string, string>>(ent, AtmosPipeLayerVisuals.SpriteLayers, out var pipeState))
+        {
+            foreach (var (layerKey, rsiPath) in pipeState)
+            {
+                if (TryParseKey(layerKey, out var @enum))
+                    _sprite.LayerSetRsi((ent, sprite), @enum, new ResPath(rsiPath));
+                else
+                    _sprite.LayerSetRsi((ent, sprite), layerKey, new ResPath(rsiPath));
+            }
+        }
+    }
+
+    private bool TryParseKey(string keyString, [NotNullWhen(true)] out Enum? @enum)
+    {
+        return _reflection.TryParseEnumReference(keyString, out @enum);
+    }
+}
index bb24da44e132abc5908cfe11ac389931c170dc9a..e280523e43e63a5b6235629c678a71f51eac6482 100644 (file)
@@ -136,6 +136,7 @@ namespace Content.Client.Atmos.UI
                 else
                 {
                     // oh shit of fuck its more than 4 this ui isn't gonna look pretty anymore
+                    CDeviceMixes.RemoveAllChildren();
                     for (var i = 1; i < msg.NodeGasMixes.Length; i++)
                     {
                         GenerateGasDisplay(msg.NodeGasMixes[i], CDeviceMixes);
index e6a8e0f1f005a6302dc47f449c9cffd1b9447f60..79112a8f8ecfcddfed89ba0009cd873fbf1eb0fa 100644 (file)
@@ -1,4 +1,4 @@
-using System.Linq;
+using System.Linq;
 using Content.Shared.Construction.Prototypes;
 using Robust.Client.GameObjects;
 using Robust.Client.Placement;
@@ -13,6 +13,9 @@ namespace Content.Client.Construction
         private readonly ConstructionSystem _constructionSystem;
         private readonly ConstructionPrototype? _prototype;
 
+        public ConstructionSystem? CurrentConstructionSystem { get { return _constructionSystem; } }
+        public ConstructionPrototype? CurrentPrototype { get { return _prototype; } }
+
         public override bool CanRotate { get; }
 
         public ConstructionPlacementHijack(ConstructionSystem constructionSystem, ConstructionPrototype? prototype)
index 532ba04d29592fedab79485f3a23f086ceef9182..a7debbdc80dd51fb38f6b5ffb6e33288705e62cb 100644 (file)
@@ -282,16 +282,11 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
             return false;
 
         var direction = xform.LocalRotation.GetCardinalDir();
+        var netId = TryGettingFirstPipeNode(uid, out var _, out var firstNetId) ? firstNetId : -1;
+        var color = TryComp<AtmosPipeColorComponent>(uid, out var atmosPipeColor) ? atmosPipeColor.Color : Color.White;
+        var layer = TryComp<AtmosPipeLayersComponent>(uid, out var atmosPipeLayers) ? atmosPipeLayers.CurrentPipeLayer : AtmosPipeLayer.Primary;
 
-        if (!TryGettingFirstPipeNode(uid, out var _, out var netId))
-            netId = -1;
-
-        var color = Color.White;
-
-        if (TryComp<AtmosPipeColorComponent>(uid, out var atmosPipeColor))
-            color = atmosPipeColor.Color;
-
-        device = new AtmosDeviceNavMapData(GetNetEntity(uid), GetNetCoordinates(xform.Coordinates), netId.Value, component.NavMapBlip.Value, direction, color);
+        device = new AtmosDeviceNavMapData(GetNetEntity(uid), GetNetCoordinates(xform.Coordinates), netId.Value, component.NavMapBlip.Value, direction, color, layer);
 
         return true;
     }
@@ -371,7 +366,9 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
             if (!TryComp<NodeContainerComponent>(ent, out var entNodeContainer))
                 continue;
 
-            UpdateAtmosPipeChunk(ent, entNodeContainer, entAtmosPipeColor, tileIdx, ref chunk);
+            var showAbsentConnections = TryComp<AtmosMonitoringConsoleDeviceComponent>(ent, out var device) ? device.ShowAbsentConnections : true;
+
+            UpdateAtmosPipeChunk(ent, entNodeContainer, entAtmosPipeColor, tileIdx, ref chunk, showAbsentConnections);
         }
 
         // Add or update the chunk on the associated grid
@@ -393,7 +390,13 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
         }
     }
 
-    private void UpdateAtmosPipeChunk(EntityUid uid, NodeContainerComponent nodeContainer, AtmosPipeColorComponent pipeColor, int tileIdx, ref AtmosPipeChunk chunk)
+    private void UpdateAtmosPipeChunk
+        (EntityUid uid,
+        NodeContainerComponent nodeContainer,
+        AtmosPipeColorComponent pipeColor,
+        int tileIdx,
+        ref AtmosPipeChunk chunk,
+        bool showAbsentConnections = true)
     {
         // Entities that are actively being deleted are not to be drawn
         if (MetaData(uid).EntityLifeStage >= EntityLifeStage.Terminating)
@@ -401,16 +404,19 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
 
         foreach ((var id, var node) in nodeContainer.Nodes)
         {
-            if (node is not PipeNode)
+            if (node is not PipeNode { } pipeNode)
+                continue;
+
+            if (!showAbsentConnections && !pipeNode.ReachableNodes.Any(x => x.Owner != uid))
                 continue;
 
-            var pipeNode = (PipeNode)node;
             var netId = GetPipeNodeNetId(pipeNode);
+            var subnet = new AtmosMonitoringConsoleSubnet(netId, pipeNode.CurrentPipeLayer, pipeColor.Color.ToHex());
             var pipeDirection = pipeNode.CurrentPipeDirection;
 
-            chunk.AtmosPipeData.TryGetValue((netId, pipeColor.Color.ToHex()), out var atmosPipeData);
+            chunk.AtmosPipeData.TryGetValue(subnet, out var atmosPipeData);
             atmosPipeData |= (ulong)pipeDirection << tileIdx * SharedNavMapSystem.Directions;
-            chunk.AtmosPipeData[(netId, pipeColor.Color.ToHex())] = atmosPipeData;
+            chunk.AtmosPipeData[subnet] = atmosPipeData;
         }
     }
 
diff --git a/Content.Server/Atmos/EntitySystems/AtmosPipeLayersSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosPipeLayersSystem.cs
new file mode 100644 (file)
index 0000000..0cb804b
--- /dev/null
@@ -0,0 +1,77 @@
+using Content.Server.Atmos.Components;
+using Content.Server.NodeContainer.EntitySystems;
+using Content.Server.NodeContainer.NodeGroups;
+using Content.Server.NodeContainer.Nodes;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
+using Content.Shared.Construction.Components;
+using Content.Shared.NodeContainer;
+using Content.Shared.Popups;
+
+namespace Content.Server.Atmos.EntitySystems;
+
+/// <summary>
+/// The system responsible for checking and adjusting the connection layering of gas pipes
+/// </summary>
+public sealed partial class AtmosPipeLayersSystem : SharedAtmosPipeLayersSystem
+{
+    [Dependency] private readonly NodeGroupSystem _nodeGroup = default!;
+    [Dependency] private readonly PipeRestrictOverlapSystem _pipeRestrictOverlap = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly SharedTransformSystem _xform = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<AtmosPipeLayersComponent, ComponentInit>(OnInit);
+    }
+
+    private void OnInit(Entity<AtmosPipeLayersComponent> ent, ref ComponentInit args)
+    {
+        SetPipeLayer(ent, ent.Comp.CurrentPipeLayer);
+    }
+
+    /// <inheritdoc/>
+    public override void SetPipeLayer(Entity<AtmosPipeLayersComponent> ent, AtmosPipeLayer layer, EntityUid? user = null, EntityUid? used = null)
+    {
+        if (ent.Comp.PipeLayersLocked)
+            return;
+
+        base.SetPipeLayer(ent, layer);
+
+        if (!TryComp<NodeContainerComponent>(ent, out var nodeContainer))
+            return;
+
+        // Update the layer values of all pipe nodes associated with the entity
+        foreach (var (id, node) in nodeContainer.Nodes)
+        {
+            if (node is not PipeNode { } pipeNode)
+                continue;
+
+            if (pipeNode.CurrentPipeLayer == ent.Comp.CurrentPipeLayer)
+                continue;
+
+            pipeNode.CurrentPipeLayer = ent.Comp.CurrentPipeLayer;
+
+            if (pipeNode.NodeGroup != null)
+                _nodeGroup.QueueRemakeGroup((BaseNodeGroup)pipeNode.NodeGroup);
+        }
+
+        // If a user wasn't responsible for unanchoring the pipe, leave it be
+        if (user == null || used == null)
+            return;
+
+        // Unanchor the pipe if its new layer overlaps with another pipe
+        var xform = Transform(ent);
+
+        if (!HasComp<PipeRestrictOverlapComponent>(ent) || !_pipeRestrictOverlap.CheckOverlap((ent, nodeContainer, xform)))
+            return;
+
+        RaiseLocalEvent(ent, new BeforeUnanchoredEvent(user.Value, used.Value));
+        _xform.Unanchor(ent, xform);
+        RaiseLocalEvent(ent, new UserUnanchoredEvent(user.Value, used.Value));
+
+        _popup.PopupEntity(Loc.GetString("pipe-restrict-overlap-popup-blocked", ("pipe", ent)), ent, user.Value);
+    }
+}
index f64aff47f4e896c997bebab7220e5cb8564781f0..351a754105eea95922b89f64511ec69e81c081ab 100644 (file)
@@ -4,6 +4,7 @@ using Content.Server.NodeContainer;
 using Content.Server.NodeContainer.Nodes;
 using Content.Server.Popups;
 using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
 using Content.Shared.Construction.Components;
 using Content.Shared.NodeContainer;
 using JetBrains.Annotations;
@@ -97,27 +98,27 @@ public sealed class PipeRestrictOverlapSystem : EntitySystem
 
     public bool PipeNodesOverlap(Entity<NodeContainerComponent, TransformComponent> ent, Entity<NodeContainerComponent, TransformComponent> other)
     {
-        var entDirs = GetAllDirections(ent).ToList();
-        var otherDirs = GetAllDirections(other).ToList();
+        var entDirsAndLayers = GetAllDirectionsAndLayers(ent).ToList();
+        var otherDirsAndLayers = GetAllDirectionsAndLayers(other).ToList();
 
-        foreach (var dir in entDirs)
+        foreach (var (dir, layer) in entDirsAndLayers)
         {
-            foreach (var otherDir in otherDirs)
+            foreach (var (otherDir, otherLayer) in otherDirsAndLayers)
             {
-                if ((dir & otherDir) != 0)
+                if ((dir & otherDir) != 0 && layer == otherLayer)
                     return true;
             }
         }
 
         return false;
 
-        IEnumerable<PipeDirection> GetAllDirections(Entity<NodeContainerComponent, TransformComponent> pipe)
+        IEnumerable<(PipeDirection, AtmosPipeLayer)> GetAllDirectionsAndLayers(Entity<NodeContainerComponent, TransformComponent> pipe)
         {
             foreach (var node in pipe.Comp1.Nodes.Values)
             {
                 // we need to rotate the pipe manually like this because the rotation doesn't update for pipes that are unanchored.
                 if (node is PipeNode pipeNode)
-                    yield return pipeNode.OriginalPipeDirection.RotatePipeDirection(pipe.Comp2.LocalRotation);
+                    yield return (pipeNode.OriginalPipeDirection.RotatePipeDirection(pipe.Comp2.LocalRotation), pipeNode.CurrentPipeLayer);
             }
         }
     }
diff --git a/Content.Server/Atmos/Piping/Components/GasPipeManifoldComponent.cs b/Content.Server/Atmos/Piping/Components/GasPipeManifoldComponent.cs
new file mode 100644 (file)
index 0000000..ded2ffc
--- /dev/null
@@ -0,0 +1,11 @@
+namespace Content.Server.Atmos.Piping.Components;
+
+[RegisterComponent]
+public sealed partial class GasPipeManifoldComponent : Component
+{
+    [DataField("inlets")]
+    public HashSet<string> InletNames { get; set; } = new() { "south0", "south1", "south2" };
+
+    [DataField("outlets")]
+    public HashSet<string> OutletNames { get; set; } = new() { "north0", "north1", "north2" };
+}
index 3e14fea2d84b0f68e7741a7256d62ac38df76422..17f9d4652f35128135baa7e48f891882eda0c7bf 100644 (file)
@@ -1,14 +1,14 @@
-using Content.Server.NodeContainer;
 using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.Nodes;
 using Content.Shared.Atmos;
 using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.EntitySystems;
 using Content.Shared.NodeContainer;
 using Robust.Shared.Map.Components;
 
 namespace Content.Server.Atmos.Piping.EntitySystems;
 
-public sealed class AtmosPipeAppearanceSystem : EntitySystem
+public sealed partial class AtmosPipeAppearanceSystem : SharedAtmosPipeAppearanceSystem
 {
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SharedMapSystem _map = default!;
@@ -34,9 +34,12 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
         if (!TryComp<MapGridComponent>(xform.GridUid, out var grid))
             return;
 
+        var numberOfPipeLayers = GetNumberOfPipeLayers(uid, out var atmosPipeLayers);
+
         // get connected entities
         var anyPipeNodes = false;
-        HashSet<EntityUid> connected = new();
+        HashSet<(EntityUid, AtmosPipeLayer)> connected = new();
+
         foreach (var node in container.Nodes.Values)
         {
             if (node is not PipeNode)
@@ -46,8 +49,8 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
 
             foreach (var connectedNode in node.ReachableNodes)
             {
-                if (connectedNode is PipeNode)
-                    connected.Add(connectedNode.Owner);
+                if (connectedNode is PipeNode { } pipeNode)
+                    connected.Add((connectedNode.Owner, pipeNode.CurrentPipeLayer));
             }
         }
 
@@ -55,14 +58,22 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
             return;
 
         // find the cardinal directions of any connected entities
-        var netConnectedDirections = PipeDirection.None;
-        var tile = _map.TileIndicesFor((xform.GridUid.Value, grid), xform.Coordinates);
-        foreach (var neighbour in connected)
+        var connectedDirections = new PipeDirection[numberOfPipeLayers];
+        Array.Fill(connectedDirections, PipeDirection.None);
+
+        var tile = _map.TileIndicesFor(xform.GridUid.Value, grid, xform.Coordinates);
+
+        foreach (var (neighbour, pipeLayer) in connected)
         {
-            // TODO z-levels, pipes across grids - we shouldn't assume that the neighboring tile's transform is on the same grid
-            var otherTile = _map.TileIndicesFor((xform.GridUid.Value, grid), Transform(neighbour).Coordinates);
+            var pipeIndex = (int)pipeLayer;
+
+            if (pipeIndex >= numberOfPipeLayers)
+                continue;
+
+            var otherTile = _map.TileIndicesFor(xform.GridUid.Value, grid, Transform(neighbour).Coordinates);
+            var pipeLayerDirections = connectedDirections[pipeIndex];
 
-            netConnectedDirections |= (otherTile - tile) switch
+            pipeLayerDirections |= (otherTile - tile) switch
             {
                 (0, 1) => PipeDirection.North,
                 (0, -1) => PipeDirection.South,
@@ -70,8 +81,16 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
                 (-1, 0) => PipeDirection.West,
                 _ => PipeDirection.None
             };
+
+            connectedDirections[pipeIndex] = pipeLayerDirections;
         }
 
+        // Convert the pipe direction array into a single int for serialization
+        var netConnectedDirections = 0;
+
+        for (var i = numberOfPipeLayers - 1; i >= 0; i--)
+            netConnectedDirections += (int)connectedDirections[i] << (PipeDirectionHelpers.PipeDirections * i);
+
         _appearance.SetData(uid, PipeVisuals.VisualState, netConnectedDirections, appearance);
     }
 }
diff --git a/Content.Server/Atmos/Piping/EntitySystems/GasPipeManifoldSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/GasPipeManifoldSystem.cs
new file mode 100644 (file)
index 0000000..bb7678d
--- /dev/null
@@ -0,0 +1,68 @@
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.NodeContainer.EntitySystems;
+using Content.Server.NodeContainer.Nodes;
+using Content.Shared.Atmos;
+using Content.Shared.NodeContainer;
+using System.Linq;
+
+namespace Content.Server.Atmos.Piping.EntitySystems;
+
+public sealed partial class GasPipeManifoldSystem : EntitySystem
+{
+    [Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<GasPipeManifoldComponent, ComponentInit>(OnCompInit);
+        SubscribeLocalEvent<GasPipeManifoldComponent, GasAnalyzerScanEvent>(OnAnalyzed);
+    }
+
+    private void OnCompInit(Entity<GasPipeManifoldComponent> ent, ref ComponentInit args)
+    {
+        if (!TryComp<NodeContainerComponent>(ent, out var nodeContainer))
+            return;
+
+        foreach (var inletName in ent.Comp.InletNames)
+        {
+            if (!_nodeContainer.TryGetNode(nodeContainer, inletName, out PipeNode? inlet))
+                continue;
+
+            foreach (var outletName in ent.Comp.OutletNames)
+            {
+                if (!_nodeContainer.TryGetNode(nodeContainer, outletName, out PipeNode? outlet))
+                    continue;
+
+                inlet.AddAlwaysReachable(outlet);
+                outlet.AddAlwaysReachable(inlet);
+            }
+        }
+    }
+
+    private void OnAnalyzed(Entity<GasPipeManifoldComponent> ent, ref GasAnalyzerScanEvent args)
+    {
+        // All inlets and outlets have the same gas mixture
+
+        args.GasMixtures = new List<(string, GasMixture?)>();
+
+        if (!TryComp<NodeContainerComponent>(ent, out var nodeContainer))
+            return;
+
+        var pipeNames = ent.Comp.InletNames.Union(ent.Comp.OutletNames);
+
+        foreach (var pipeName in pipeNames)
+        {
+            if (!_nodeContainer.TryGetNode(nodeContainer, pipeName, out PipeNode? pipe))
+                continue;
+
+            var pipeLocal = pipe.Air.Clone();
+            pipeLocal.Multiply(pipe.Volume / pipe.Air.Volume);
+            pipeLocal.Volume = pipe.Volume;
+
+            args.GasMixtures.Add((Name(ent), pipeLocal));
+            break;
+        }
+    }
+}
index d30d3b1777beca09d91bf81e72b538e0ac488c5e..3a76666a2c084524abf780b98a708e9ca3c808d2 100644 (file)
@@ -1,10 +1,8 @@
-using Content.Server.Atmos;
 using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NodeContainer.NodeGroups;
 using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
 using Content.Shared.NodeContainer;
-using Content.Shared.NodeContainer.NodeGroups;
-using Robust.Shared.Map;
 using Robust.Shared.Map.Components;
 using Robust.Shared.Utility;
 
@@ -12,7 +10,7 @@ namespace Content.Server.NodeContainer.Nodes
 {
     /// <summary>
     ///     Connects with other <see cref="PipeNode"/>s whose <see cref="PipeDirection"/>
-    ///     correctly correspond.
+    ///     and <see cref="CurrentPipeLayer"/> correctly correspond.
     /// </summary>
     [DataDefinition]
     [Virtual]
@@ -24,6 +22,12 @@ namespace Content.Server.NodeContainer.Nodes
         [DataField("pipeDirection")]
         public PipeDirection OriginalPipeDirection;
 
+        /// <summary>
+        ///     The *current* layer to which the pipe node is assigned.
+        /// </summary>
+        [DataField("pipeLayer")]
+        public AtmosPipeLayer CurrentPipeLayer = AtmosPipeLayer.Primary;
+
         /// <summary>
         ///     The *current* pipe directions (accounting for rotation)
         ///     Used to check if this pipe can connect to another pipe in a given direction.
@@ -204,6 +208,7 @@ namespace Content.Server.NodeContainer.Nodes
             foreach (var pipe in PipesInDirection(pos, pipeDir, grid, nodeQuery))
             {
                 if (pipe.NodeGroupID == NodeGroupID
+                    && pipe.CurrentPipeLayer == CurrentPipeLayer
                     && pipe.CurrentPipeDirection.HasDirection(pipeDir.GetOpposite()))
                 {
                     yield return pipe;
diff --git a/Content.Shared/Atmos/Components/AtmosPipeLayersComponent.cs b/Content.Shared/Atmos/Components/AtmosPipeLayersComponent.cs
new file mode 100644 (file)
index 0000000..3081bb8
--- /dev/null
@@ -0,0 +1,122 @@
+using Content.Shared.Atmos.EntitySystems;
+using Content.Shared.DoAfter;
+using Content.Shared.Tools;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Atmos.Components;
+
+/// <summary>
+/// Contains layer data for atmos pipes. Layers allow multiple atmos pipes with the
+/// same orientation to be anchored to the same tile without their contents mixing.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+[Access(typeof(SharedAtmosPipeLayersSystem))]
+public sealed partial class AtmosPipeLayersComponent : Component
+{
+    /// <summary>
+    /// The number of pipe layers this entity supports.
+    /// Must be equal to or less than the number of values
+    /// in <see cref="AtmosPipeLayer"/>.
+    /// </summary>
+    [DataField]
+    public byte NumberOfPipeLayers = 3;
+
+    /// <summary>
+    /// Determines which layer the pipe is currently assigned.
+    /// Only pipes on the same layer can connect with each other.
+    /// </summary>
+    [DataField("pipeLayer"), AutoNetworkedField]
+    [ViewVariables(VVAccess.ReadOnly)]
+    public AtmosPipeLayer CurrentPipeLayer = AtmosPipeLayer.Primary;
+
+    /// <summary>
+    /// The RSI paths that the entity will use to update its sprite when its pipe layer changes;
+    /// if empty, the entity sprite will not update when it pipe layer changes.
+    /// If you want to set specific sprite layers to update when the pipe layer changes, use
+    /// <see cref="SpriteLayersRsiPaths"/> instead.
+    /// </summary>
+    /// <remarks>
+    /// If the dictionary is not empty there should be an entry for each atmos pipe layer.
+    /// </remarks>
+    [DataField]
+    public Dictionary<AtmosPipeLayer, string> SpriteRsiPaths = new();
+
+    /// <summary>
+    /// Used to update specific sprite layers when the entity's pipe layer changes.
+    /// The dictionary key is the name of the sprite layer to be updated, and its value is
+    /// a second dictionary which contains the RSI paths indexed by pipe layer.
+    /// If you want to change the default RSI path used by the entity, use
+    /// <see cref="SpriteRsiPaths"/> instead.
+    /// </summary>
+    /// <remarks>
+    /// If an dictionary is not empty there should be an entry for each pipe layer.
+    /// </remarks>
+    [DataField]
+    public Dictionary<string, Dictionary<AtmosPipeLayer, string>> SpriteLayersRsiPaths = new();
+
+    /// <summary>
+    /// Entity prototypes that will be used to replace the current one when using
+    /// position dependent entity placement via AlignAtmosPipeLayers.
+    /// </summary>
+    /// <remarks>
+    /// If the dictionary is not empty there should be an entry for each atmos pipe layer.
+    /// </remarks>
+    [DataField]
+    public Dictionary<AtmosPipeLayer, EntProtoId> AlternativePrototypes = new();
+
+    /// <summary>
+    /// The pipe layers of this entity cannot be changed when this value is true.
+    /// </summary>
+    [DataField]
+    public bool PipeLayersLocked;
+
+    /// <summary>
+    /// Tool quality required to cause a pipe to change layers
+    /// </summary>
+    [DataField]
+    public ProtoId<ToolQualityPrototype> Tool = "Screwing";
+
+    /// <summary>
+    /// The base delay to use for changing layers.
+    /// </summary>
+    [DataField]
+    public float Delay = 1f;
+}
+
+/// <summary>
+/// Raised when a player attempts to cycle a pipe to its next layer
+/// </summary>
+[Serializable, NetSerializable]
+public sealed partial class TrySetNextPipeLayerCompletedEvent : SimpleDoAfterEvent;
+
+/// <summary>
+/// Raised when a player attempts to set a pipe a specified layer
+/// </summary>
+[Serializable, NetSerializable]
+public sealed partial class TrySettingPipeLayerCompletedEvent : SimpleDoAfterEvent
+{
+    public AtmosPipeLayer PipeLayer;
+
+    public TrySettingPipeLayerCompletedEvent(AtmosPipeLayer pipeLayer)
+    {
+        PipeLayer = pipeLayer;
+    }
+}
+
+[Serializable, NetSerializable]
+public enum AtmosPipeLayerVisuals
+{
+    Sprite,
+    SpriteLayers,
+    DrawDepth,
+}
+
+[Serializable, NetSerializable]
+public enum AtmosPipeLayer
+{
+    Primary,
+    Secondary,
+    Tertiary,
+}
index b5f979c482115349e73a4d96196fd02511bfa5c0..f8599148ea1cdff61f8b9ad5e84577290e48991e 100644 (file)
@@ -5,6 +5,8 @@ namespace Content.Shared.Atmos.Components;
 [RegisterComponent]
 public sealed partial class PipeAppearanceComponent : Component
 {
-    [DataField("sprite")]
-    public SpriteSpecifier.Rsi Sprite = new(new("Structures/Piping/Atmospherics/pipe.rsi"), "pipeConnector");
+    [DataField]
+    public SpriteSpecifier.Rsi[] Sprite = [new(new("Structures/Piping/Atmospherics/pipe.rsi"), "pipeConnector"),
+        new(new("Structures/Piping/Atmospherics/pipe_alt1.rsi"), "pipeConnector"),
+        new(new("Structures/Piping/Atmospherics/pipe_alt2.rsi"), "pipeConnector")];
 }
index 2ac0d2a9af14b2ee4e5a740ae12f3ff74b54a372..d01fb4e8bc4b592973e256996dee95663608c252 100644 (file)
@@ -64,10 +64,10 @@ public struct AtmosPipeChunk(Vector2i origin)
 
     /// <summary>
     /// Bitmask look up for atmos pipes, 1 for occupied and 0 for empty.
-    /// Indexed by the color hexcode of the pipe
+    /// Indexed by the net ID, layer and color hexcode of the pipe
     /// </summary>
     [ViewVariables]
-    public Dictionary<(int, string), ulong> AtmosPipeData = new();
+    public Dictionary<AtmosMonitoringConsoleSubnet, ulong> AtmosPipeData = new();
 
     /// <summary>
     /// The last game tick that the chunk was updated
@@ -90,7 +90,7 @@ public struct AtmosDeviceNavMapData
     public NetCoordinates NetCoordinates;
 
     /// <summary>
-    /// The associated pipe network ID 
+    /// The associated pipe network ID
     /// </summary>
     public int NetId = -1;
 
@@ -109,10 +109,21 @@ public struct AtmosDeviceNavMapData
     /// </summary>
     public Color PipeColor;
 
+    /// <summary>
+    /// The pipe layer the entity is on
+    /// </summary>
+    public AtmosPipeLayer PipeLayer;
+
     /// <summary>
     /// Populate the atmos monitoring console nav map with a single entity
     /// </summary>
-    public AtmosDeviceNavMapData(NetEntity netEntity, NetCoordinates netCoordinates, int netId, ProtoId<NavMapBlipPrototype> navMapBlip, Direction direction, Color pipeColor)
+    public AtmosDeviceNavMapData(NetEntity netEntity,
+        NetCoordinates netCoordinates,
+        int netId,
+        ProtoId<NavMapBlipPrototype> navMapBlip,
+        Direction direction,
+        Color pipeColor,
+        AtmosPipeLayer pipeLayer)
     {
         NetEntity = netEntity;
         NetCoordinates = netCoordinates;
@@ -120,6 +131,7 @@ public struct AtmosDeviceNavMapData
         NavMapBlip = navMapBlip;
         Direction = direction;
         PipeColor = pipeColor;
+        PipeLayer = pipeLayer;
     }
 }
 
@@ -154,7 +166,7 @@ public struct AtmosMonitoringConsoleEntry
     public NetCoordinates Coordinates;
 
     /// <summary>
-    /// The associated pipe network ID 
+    /// The associated pipe network ID
     /// </summary>
     public int NetId = -1;
 
@@ -184,7 +196,7 @@ public struct AtmosMonitoringConsoleEntry
     public float TotalMolData;
 
     /// <summary>
-    /// Mol and percentage for all detected gases 
+    /// Mol and percentage for all detected gases
     /// </summary>
     public Dictionary<Gas, float> GasData = new();
 
@@ -216,6 +228,16 @@ public struct AtmosMonitoringConsoleEntry
     }
 }
 
+/// <summary>
+/// Used to group atmos pipe chunks into subnets based on their properties and
+/// improve the efficiency of rendering these chunks on the atmos monitoring console.
+/// </summary>
+/// <param name="NetId">The associated network ID.</param>
+/// <param name="PipeLayer">The associated pipe layer.</param>
+/// <param name="HexCode">The color of the pipe.</param>
+[Serializable, NetSerializable]
+public record AtmosMonitoringConsoleSubnet(int NetId, AtmosPipeLayer PipeLayer, string HexCode);
+
 public enum AtmosPipeChunkDataFacing : byte
 {
     // Values represent bit shift offsets when retrieving data in the tile array.
index 50c3abcfcaa0629af8fa068872ae24e39af373e7..a7b83fde480fd9ed6f17e7a6eaafe7b80281fdaf 100644 (file)
@@ -5,7 +5,7 @@ using Robust.Shared.Prototypes;
 namespace Content.Shared.Atmos.Components;
 
 /// <summary>
-/// Entities with this component appear on the 
+/// Entities with this component appear on the
 /// nav maps of atmos monitoring consoles
 /// </summary>
 [RegisterComponent, NetworkedComponent]
@@ -16,6 +16,14 @@ public sealed partial class AtmosMonitoringConsoleDeviceComponent : Component
     /// entity on the atmos monitoring console nav map.
     /// If null, no blip is drawn (i.e., null for pipes)
     /// </summary>
-    [DataField, ViewVariables]
+    [DataField]
     public ProtoId<NavMapBlipPrototype>? NavMapBlip = null;
+
+    /// <summary>
+    /// Sets whether attached atmos pipes will always be rendered
+    /// on the atmos monitoring console nav map, even if these
+    /// pipes are not connected to any pipes in a neighboring tile.
+    /// </summary>
+    [DataField]
+    public bool ShowAbsentConnections = true;
 }
index e6dd455be7dc9cebd78390338ec56d7417bfa918..7fe94efd8483cc107f010ee98edaaaacbdcf4aa4 100644 (file)
@@ -15,7 +15,7 @@ public abstract class SharedAtmosMonitoringConsoleSystem : EntitySystem
 
     private void OnGetState(EntityUid uid, AtmosMonitoringConsoleComponent component, ref ComponentGetState args)
     {
-        Dictionary<Vector2i, Dictionary<(int, string), ulong>> chunks;
+        Dictionary<Vector2i, Dictionary<AtmosMonitoringConsoleSubnet, ulong>> chunks;
 
         // Should this be a full component state or a delta-state?
         if (args.FromTick <= component.CreationTick || component.ForceFullUpdate)
@@ -52,22 +52,22 @@ public abstract class SharedAtmosMonitoringConsoleSystem : EntitySystem
 
     [Serializable, NetSerializable]
     protected sealed class AtmosMonitoringConsoleState(
-        Dictionary<Vector2i, Dictionary<(int, string), ulong>> chunks,
+        Dictionary<Vector2i, Dictionary<AtmosMonitoringConsoleSubnet, ulong>> chunks,
         Dictionary<NetEntity, AtmosDeviceNavMapData> atmosDevices)
         : ComponentState
     {
-        public Dictionary<Vector2i, Dictionary<(int, string), ulong>> Chunks = chunks;
+        public Dictionary<Vector2i, Dictionary<AtmosMonitoringConsoleSubnet, ulong>> Chunks = chunks;
         public Dictionary<NetEntity, AtmosDeviceNavMapData> AtmosDevices = atmosDevices;
     }
 
     [Serializable, NetSerializable]
     protected sealed class AtmosMonitoringConsoleDeltaState(
-        Dictionary<Vector2i, Dictionary<(int, string), ulong>> modifiedChunks,
+        Dictionary<Vector2i, Dictionary<AtmosMonitoringConsoleSubnet, ulong>> modifiedChunks,
         Dictionary<NetEntity, AtmosDeviceNavMapData> atmosDevices,
         HashSet<Vector2i> allChunks)
         : ComponentState, IComponentDeltaState<AtmosMonitoringConsoleState>
     {
-        public Dictionary<Vector2i, Dictionary<(int, string), ulong>> ModifiedChunks = modifiedChunks;
+        public Dictionary<Vector2i, Dictionary<AtmosMonitoringConsoleSubnet, ulong>> ModifiedChunks = modifiedChunks;
         public Dictionary<NetEntity, AtmosDeviceNavMapData> AtmosDevices = atmosDevices;
         public HashSet<Vector2i> AllChunks = allChunks;
 
@@ -81,7 +81,7 @@ public abstract class SharedAtmosMonitoringConsoleSystem : EntitySystem
 
             foreach (var (index, data) in ModifiedChunks)
             {
-                state.Chunks[index] = new Dictionary<(int, string), ulong>(data);
+                state.Chunks[index] = new Dictionary<AtmosMonitoringConsoleSubnet, ulong>(data);
             }
 
             state.AtmosDevices.Clear();
@@ -93,7 +93,7 @@ public abstract class SharedAtmosMonitoringConsoleSystem : EntitySystem
 
         public AtmosMonitoringConsoleState CreateNewFullState(AtmosMonitoringConsoleState state)
         {
-            var chunks = new Dictionary<Vector2i, Dictionary<(int, string), ulong>>(state.Chunks.Count);
+            var chunks = new Dictionary<Vector2i, Dictionary<AtmosMonitoringConsoleSubnet, ulong>>(state.Chunks.Count);
 
             foreach (var (index, data) in state.Chunks)
             {
@@ -101,10 +101,10 @@ public abstract class SharedAtmosMonitoringConsoleSystem : EntitySystem
                     continue;
 
                 if (ModifiedChunks.ContainsKey(index))
-                    chunks[index] = new Dictionary<(int, string), ulong>(ModifiedChunks[index]);
+                    chunks[index] = new Dictionary<AtmosMonitoringConsoleSubnet, ulong>(ModifiedChunks[index]);
 
                 else
-                    chunks[index] = new Dictionary<(int, string), ulong>(state.Chunks[index]);
+                    chunks[index] = new Dictionary<AtmosMonitoringConsoleSubnet, ulong>(state.Chunks[index]);
             }
 
             return new AtmosMonitoringConsoleState(chunks, new(AtmosDevices));
diff --git a/Content.Shared/Atmos/EntitySystems/SharedAtmosPipeAppearanceSystem.cs b/Content.Shared/Atmos/EntitySystems/SharedAtmosPipeAppearanceSystem.cs
new file mode 100644 (file)
index 0000000..c6944ec
--- /dev/null
@@ -0,0 +1,18 @@
+using Content.Shared.Atmos.Components;
+
+namespace Content.Shared.Atmos.EntitySystems;
+
+public abstract partial class SharedAtmosPipeAppearanceSystem : EntitySystem
+{
+    /// <summary>
+    /// Returns the max number of pipe layers supported by a entity.
+    /// </summary>
+    /// <param name="uid">The entity being checked.</param>
+    /// <param name="atmosPipeLayers">The entity's <see cref="AtmosPipeLayersComponent"/>, if available.</param>
+    /// <returns>Returns <see cref="AtmosPipeLayersComponent.NumberOfPipeLayers"/>
+    /// if the entity has the component, or 1 if it does not.</returns>
+    protected int GetNumberOfPipeLayers(EntityUid uid, out AtmosPipeLayersComponent? atmosPipeLayers)
+    {
+        return TryComp(uid, out atmosPipeLayers) ? atmosPipeLayers.NumberOfPipeLayers : 1;
+    }
+}
diff --git a/Content.Shared/Atmos/EntitySystems/SharedAtmosPipeLayersSystem.cs b/Content.Shared/Atmos/EntitySystems/SharedAtmosPipeLayersSystem.cs
new file mode 100644 (file)
index 0000000..ff88601
--- /dev/null
@@ -0,0 +1,264 @@
+using Content.Shared.Atmos.Components;
+using Content.Shared.Database;
+using Content.Shared.Examine;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Popups;
+using Content.Shared.SubFloor;
+using Content.Shared.Tools;
+using Content.Shared.Tools.Components;
+using Content.Shared.Tools.Systems;
+using Content.Shared.Verbs;
+using Robust.Shared.Prototypes;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Content.Shared.Atmos.EntitySystems;
+
+/// <summary>
+/// The system responsible for checking and adjusting the connection layering of gas pipes
+/// </summary>
+public abstract partial class SharedAtmosPipeLayersSystem : EntitySystem
+{
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly IPrototypeManager _protoManager = default!;
+    [Dependency] private readonly SharedToolSystem _tool = default!;
+    [Dependency] private readonly SharedHandsSystem _hands = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<AtmosPipeLayersComponent, ExaminedEvent>(OnExamined);
+        SubscribeLocalEvent<AtmosPipeLayersComponent, GetVerbsEvent<Verb>>(OnGetVerb);
+        SubscribeLocalEvent<AtmosPipeLayersComponent, InteractUsingEvent>(OnInteractUsing);
+        SubscribeLocalEvent<AtmosPipeLayersComponent, UseInHandEvent>(OnUseInHandEvent);
+        SubscribeLocalEvent<AtmosPipeLayersComponent, TrySetNextPipeLayerCompletedEvent>(OnSetNextPipeLayerCompleted);
+        SubscribeLocalEvent<AtmosPipeLayersComponent, TrySettingPipeLayerCompletedEvent>(OnSettingPipeLayerCompleted);
+    }
+
+    private void OnExamined(Entity<AtmosPipeLayersComponent> ent, ref ExaminedEvent args)
+    {
+        var layerName = GetPipeLayerName(ent.Comp.CurrentPipeLayer);
+        args.PushMarkup(Loc.GetString("atmos-pipe-layers-component-current-layer", ("layerName", layerName)));
+    }
+
+    private void OnGetVerb(Entity<AtmosPipeLayersComponent> ent, ref GetVerbsEvent<Verb> args)
+    {
+        if (!args.CanAccess || !args.CanInteract || !args.CanComplexInteract)
+            return;
+
+        if (ent.Comp.NumberOfPipeLayers <= 1 || ent.Comp.PipeLayersLocked)
+            return;
+
+        if (!_protoManager.TryIndex(ent.Comp.Tool, out var toolProto))
+            return;
+
+        var user = args.User;
+
+        if (TryComp<SubFloorHideComponent>(ent, out var subFloorHide) && subFloorHide.IsUnderCover)
+        {
+            var v = new Verb
+            {
+                Priority = 1,
+                Category = VerbCategory.Adjust,
+                Text = Loc.GetString("atmos-pipe-layers-component-pipes-are-covered"),
+                Disabled = true,
+                Impact = LogImpact.Low,
+                DoContactInteraction = true,
+            };
+
+            args.Verbs.Add(v);
+        }
+
+        else if (!TryGetHeldTool(user, ent.Comp.Tool, out var tool))
+        {
+            var v = new Verb
+            {
+                Priority = 1,
+                Category = VerbCategory.Adjust,
+                Text = Loc.GetString("atmos-pipe-layers-component-tool-missing", ("toolName", Loc.GetString(toolProto.ToolName).ToLower())),
+                Disabled = true,
+                Impact = LogImpact.Low,
+                DoContactInteraction = true,
+            };
+
+            args.Verbs.Add(v);
+        }
+
+        else
+        {
+            for (var i = 0; i < ent.Comp.NumberOfPipeLayers; i++)
+            {
+                var index = i;
+                var layerName = GetPipeLayerName((AtmosPipeLayer)index);
+                var label = Loc.GetString("atmos-pipe-layers-component-select-layer", ("layerName", layerName));
+
+                var v = new Verb
+                {
+                    Priority = 1,
+                    Category = VerbCategory.Adjust,
+                    Text = label,
+                    Disabled = index == (int)ent.Comp.CurrentPipeLayer,
+                    Impact = LogImpact.Low,
+                    DoContactInteraction = true,
+                    Act = () =>
+                    {
+                        _tool.UseTool(tool.Value, user, ent, ent.Comp.Delay, tool.Value.Comp.Qualities, new TrySettingPipeLayerCompletedEvent((AtmosPipeLayer)index));
+                    }
+                };
+
+                args.Verbs.Add(v);
+            }
+        }
+    }
+
+    private void OnInteractUsing(Entity<AtmosPipeLayersComponent> ent, ref InteractUsingEvent args)
+    {
+        if (ent.Comp.NumberOfPipeLayers <= 1 || ent.Comp.PipeLayersLocked)
+            return;
+
+        if (TryComp<SubFloorHideComponent>(ent, out var subFloorHide) && subFloorHide.IsUnderCover)
+        {
+            _popup.PopupPredicted(Loc.GetString("atmos-pipe-layers-component-cannot-adjust-pipes"), ent, args.User);
+            return;
+        }
+
+        if (TryComp<ToolComponent>(args.Used, out var tool) && _tool.HasQuality(args.Used, ent.Comp.Tool, tool))
+            _tool.UseTool(args.Used, args.User, ent, ent.Comp.Delay, tool.Qualities, new TrySetNextPipeLayerCompletedEvent());
+    }
+
+    private void OnUseInHandEvent(Entity<AtmosPipeLayersComponent> ent, ref UseInHandEvent args)
+    {
+        if (ent.Comp.NumberOfPipeLayers <= 1 || ent.Comp.PipeLayersLocked)
+            return;
+
+        if (!TryGetHeldTool(args.User, ent.Comp.Tool, out var tool))
+        {
+            if (_protoManager.TryIndex(ent.Comp.Tool, out var toolProto))
+            {
+                var toolName = Loc.GetString(toolProto.ToolName).ToLower();
+                var message = Loc.GetString("atmos-pipe-layers-component-tool-missing", ("toolName", toolName));
+
+                _popup.PopupPredicted(message, ent, args.User);
+            }
+
+            return;
+        }
+
+        _tool.UseTool(tool.Value, args.User, ent, ent.Comp.Delay, tool.Value.Comp.Qualities, new TrySetNextPipeLayerCompletedEvent());
+    }
+
+    private void OnSetNextPipeLayerCompleted(Entity<AtmosPipeLayersComponent> ent, ref TrySetNextPipeLayerCompletedEvent args)
+    {
+        if (args.Cancelled)
+            return;
+
+        SetNextPipeLayer(ent, args.User, args.Used);
+    }
+
+    private void OnSettingPipeLayerCompleted(Entity<AtmosPipeLayersComponent> ent, ref TrySettingPipeLayerCompletedEvent args)
+    {
+        if (args.Cancelled)
+            return;
+
+        SetPipeLayer(ent, args.PipeLayer, args.User, args.Used);
+    }
+
+    /// <summary>
+    /// Increments an entity's pipe layer by 1, wrapping around to 0 if the max pipe layer is reached
+    /// </summary>
+    /// <param name="ent">The pipe entity</param>
+    /// <param name="user">The player entity who adjusting the pipe layer</param>
+    /// <param name="used">The tool used to adjust the pipe layer</param>
+    public void SetNextPipeLayer(Entity<AtmosPipeLayersComponent> ent, EntityUid? user = null, EntityUid? used = null)
+    {
+        var newLayer = ((int)ent.Comp.CurrentPipeLayer + 1) % ent.Comp.NumberOfPipeLayers;
+        SetPipeLayer(ent, (AtmosPipeLayer)newLayer, user, used);
+    }
+
+    /// <summary>
+    /// Sets an entity's pipe layer to a specified value
+    /// </summary>
+    /// <param name="ent">The pipe entity</param>
+    /// <param name="layer">The new layer value</param>
+    /// <param name="user">The player entity who adjusting the pipe layer</param>
+    /// <param name="used">The tool used to adjust the pipe layer</param>
+    public virtual void SetPipeLayer(Entity<AtmosPipeLayersComponent> ent, AtmosPipeLayer layer, EntityUid? user = null, EntityUid? used = null)
+    {
+        if (ent.Comp.PipeLayersLocked)
+            return;
+
+        ent.Comp.CurrentPipeLayer = (AtmosPipeLayer)Math.Clamp((int)layer, 0, ent.Comp.NumberOfPipeLayers - 1);
+        Dirty(ent);
+
+        if (TryComp<AppearanceComponent>(ent, out var appearance))
+        {
+            if (ent.Comp.SpriteRsiPaths.TryGetValue(ent.Comp.CurrentPipeLayer, out var path))
+                _appearance.SetData(ent, AtmosPipeLayerVisuals.Sprite, path, appearance);
+
+            if (ent.Comp.SpriteLayersRsiPaths.Count > 0)
+            {
+                var data = new Dictionary<string, string>();
+
+                foreach (var (layerKey, rsiPaths) in ent.Comp.SpriteLayersRsiPaths)
+                {
+                    if (rsiPaths.TryGetValue(ent.Comp.CurrentPipeLayer, out path))
+                        data.TryAdd(layerKey, path);
+                }
+
+                _appearance.SetData(ent, AtmosPipeLayerVisuals.SpriteLayers, data, appearance);
+            }
+        }
+
+        if (user != null)
+        {
+            var layerName = GetPipeLayerName(ent.Comp.CurrentPipeLayer);
+            var message = Loc.GetString("atmos-pipe-layers-component-change-layer", ("layerName", layerName));
+
+            _popup.PopupPredicted(message, ent, user);
+        }
+    }
+
+    /// <summary>
+    /// Try to find an entity prototype associated with a specified <see cref="AtmosPipeLayer"/>.
+    /// </summary>
+    /// <param name="component">The <see cref="AtmosPipeLayersComponent"/> with the alternative prototypes data.</param>
+    /// <param name="layer">The atmos pipe layer associated with the entity prototype.</param>
+    /// <param name="proto">The returned entity prototype.</param>
+    /// <returns>True if there was an entity prototype associated with the layer.</returns>
+    public bool TryGetAlternativePrototype(AtmosPipeLayersComponent component, AtmosPipeLayer layer, out EntProtoId proto)
+    {
+        return component.AlternativePrototypes.TryGetValue(layer, out proto);
+    }
+
+    /// <summary>
+    /// Checks a player entity's hands to see if they are holding a tool with a specified quality
+    /// </summary>
+    /// <param name="user">The player entity</param>
+    /// <param name="toolQuality">The tool quality being checked for</param>
+    /// <param name="heldTool">A tool with the specified tool quality</param>
+    /// <returns>True if an appropriate tool was found</returns>
+    private bool TryGetHeldTool(EntityUid user, ProtoId<ToolQualityPrototype> toolQuality, [NotNullWhen(true)] out Entity<ToolComponent>? heldTool)
+    {
+        heldTool = null;
+
+        foreach (var heldItem in _hands.EnumerateHeld(user))
+        {
+            if (TryComp<ToolComponent>(heldItem, out var tool) &&
+                _tool.HasQuality(heldItem, toolQuality, tool))
+            {
+                heldTool = new Entity<ToolComponent>(heldItem, tool);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private string GetPipeLayerName(AtmosPipeLayer layer)
+    {
+        return Loc.GetString("atmos-pipe-layers-component-layer-" + layer.ToString().ToLower());
+    }
+}
index 0e1a50d9a2a6d940e8882e855f139533b98d20ed..cd38b22b9ca420b439df018c66c73e96dbca3c12 100644 (file)
@@ -85,6 +85,12 @@ public sealed partial class ConstructionPrototype : IPrototype
     [DataField]
     public ProtoId<ConstructionPrototype>? Mirror { get; private set; }
 
+    /// <summary>
+    ///     Possible constructions to replace this one with as determined by the placement mode
+    /// </summary>
+    [DataField]
+    public ProtoId<ConstructionPrototype>[] AlternativePrototypes = [];
+
     public IReadOnlyList<IConstructionCondition> Conditions => _conditions;
 }
 
index dbec886971ee693e016467dd3331ffaf9f467f13..35fead5b3fd5b2863a5b1a6821c3b492e720a212 100644 (file)
@@ -9,13 +9,15 @@ namespace Content.Shared.DrawDepth
         /// <summary>
         ///     This is for sub-floors, the floors you see after prying off a tile.
         /// </summary>
-        LowFloors = DrawDepthTag.Default - 18,
+        LowFloors = DrawDepthTag.Default - 20,
 
         // various entity types that require different
         // draw depths, as to avoid hiding
         #region SubfloorEntities
-        ThickPipe = DrawDepthTag.Default - 17,
-        ThickWire = DrawDepthTag.Default - 16,
+        ThickPipe = DrawDepthTag.Default - 19,
+        ThickWire = DrawDepthTag.Default - 18,
+        ThinPipeAlt2 = DrawDepthTag.Default - 17,
+        ThinPipeAlt1 = DrawDepthTag.Default - 16,
         ThinPipe = DrawDepthTag.Default - 15,
         ThinWire = DrawDepthTag.Default - 14,
         #endregion
index 2fcb6c5ccb4976733c485893e7f51e20f9e07740..dff9f500549b1f7e99acecb4b0d253723f142943 100644 (file)
@@ -39,4 +39,17 @@ public sealed partial class NavMapBlipPrototype : IPrototype
     /// </summary>
     [DataField]
     public float Scale { get; private set; } = 1f;
+
+    /// <summary>
+    /// Describes how the blip should be positioned.
+    /// It's up to the individual system to enforce this
+    /// </summary>
+    [DataField]
+    public NavMapBlipPlacement Placement { get; private set; } = NavMapBlipPlacement.Centered;
+}
+
+public enum NavMapBlipPlacement
+{
+    Centered,   // The blip appears in the center of the tile
+    Offset      // The blip is offset from the center of the tile (determined by the system using the blips)
 }
index 812003aae8f4e6e8b11a3ec9400315f3d10cc179..c7edf014990e1ad7a3ad194643dfcd2964b7010a 100644 (file)
@@ -225,6 +225,7 @@ namespace Content.Shared.SubFloor
         ScannerRevealed,
     }
 
+    [Serializable, NetSerializable]
     public enum SubfloorLayers : byte
     {
         FirstLayer
index 9b9197249a93ea258029a19302e47e4cd2fd3ff9..418921d38e43e70fe88f7bb0215279c192f277e5 100644 (file)
@@ -85,5 +85,8 @@ namespace Content.Shared.Verbs
         public static readonly VerbCategory SelectType = new("verb-categories-select-type", null);
 
         public static readonly VerbCategory PowerLevel = new("verb-categories-power-level", null);
+
+        public static readonly VerbCategory Adjust =
+            new("verb-categories-adjust", "/Textures/Interface/VerbIcons/screwdriver.png");
     }
 }
diff --git a/Resources/Locale/en-US/atmos/atmos-pipe-layers.ftl b/Resources/Locale/en-US/atmos/atmos-pipe-layers.ftl
new file mode 100644 (file)
index 0000000..27491ef
--- /dev/null
@@ -0,0 +1,10 @@
+atmos-pipe-layers-component-layer-primary = primary 
+atmos-pipe-layers-component-layer-secondary = secondary
+atmos-pipe-layers-component-layer-tertiary = tertiary
+
+atmos-pipe-layers-component-change-layer = Adjusted to its {$layerName} configuration.
+atmos-pipe-layers-component-current-layer = It is in its {$layerName} configuration.
+atmos-pipe-layers-component-select-layer = {CAPITALIZE($layerName)} configuration
+atmos-pipe-layers-component-tool-missing = Requires {INDEFINITE($toolName)} {$toolName}
+atmos-pipe-layers-component-pipes-are-covered = The pipes are covered
+atmos-pipe-layers-component-cannot-adjust-pipes = You need to uncover the pipes before they can be adjusted.
\ No newline at end of file
index 64104f796e8609b22cd0ce9a9b6e19f3269aa32e..d52b43c9a7d7734f2e7f35d37c12ab22d4e245b1 100644 (file)
@@ -28,6 +28,7 @@ verb-categories-lever = Lever
 verb-categories-select-type = Select Type
 verb-categories-fax = Set Destination
 verb-categories-power-level = Power Level
+verb-categories-adjust = Adjust
 
 verb-common-toggle-light = Toggle light
 verb-common-close = Close
index bc5155718604f9497aa99b0437c6025fb4769296..93530976f7b4fbd346066f09aab3a639ea0f9cb7 100644 (file)
   color: "#ffcd00"
   texturePaths:
   - "/Textures/Interface/NavMap/beveled_star.png"
-  
+  placement: Offset
+
 - type: navMapBlip
   id: GasVentOpening
-  scale: 0.6667
+  scale: 0.75
   color: LightGray
   texturePaths:
   - "/Textures/Interface/NavMap/beveled_square.png"
-  
+
 - type: navMapBlip
   id: GasVentScrubber
-  scale: 0.6667
+  scale: 0.75
   color: LightGray
   texturePaths:
   - "/Textures/Interface/NavMap/beveled_circle.png"
-  
+
 - type: navMapBlip
   id: GasFlowRegulator
   scale: 0.75
@@ -37,7 +38,8 @@
   - "/Textures/Interface/NavMap/beveled_arrow_east.png"
   - "/Textures/Interface/NavMap/beveled_arrow_north.png"
   - "/Textures/Interface/NavMap/beveled_arrow_west.png"
-  
+  placement: Offset
+
 - type: navMapBlip
   id: GasValve
   scale: 0.6667
   texturePaths:
   - "/Textures/Interface/NavMap/beveled_diamond_north_south.png"
   - "/Textures/Interface/NavMap/beveled_diamond_east_west.png"
-  - "/Textures/Interface/NavMap/beveled_diamond_north_south.png"   
+  - "/Textures/Interface/NavMap/beveled_diamond_north_south.png"
   - "/Textures/Interface/NavMap/beveled_diamond_east_west.png"
-  
+  placement: Offset
+
 - type: navMapBlip
   id: Thermoregulator
-  scale: 0.6667
+  scale: 0.75
+  color: LightGray
+  texturePaths:
+  - "/Textures/Interface/NavMap/beveled_hexagon.png"
+
+- type: navMapBlip
+  id: GasPipeManifold
+  scale: 0.9
   color: LightGray
   texturePaths:
-  - "/Textures/Interface/NavMap/beveled_hexagon.png"
\ No newline at end of file
+  - "/Textures/Interface/NavMap/beveled_rectangle_east_west.png"
+  - "/Textures/Interface/NavMap/beveled_rectangle_north_south.png"
+  - "/Textures/Interface/NavMap/beveled_rectangle_east_west.png"
+  - "/Textures/Interface/NavMap/beveled_rectangle_north_south.png"
diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/alt_layers.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/alt_layers.yml
new file mode 100644 (file)
index 0000000..1f4ab08
--- /dev/null
@@ -0,0 +1,133 @@
+## This file contains duplicated pipe prototypes with
+## different layer offsets to faciliate mapping
+
+# Layer 1
+- type: entity
+  abstract: true
+  id: GasPipeLayerAlt1
+  components:
+  - type: AtmosPipeLayers
+    pipeLayer: 1
+
+# Layer 2
+- type: entity
+  abstract: true
+  id: GasPipeLayerAlt2
+  components:
+  - type: AtmosPipeLayers
+    pipeLayer: 2
+
+# GasPipeStraight
+- type: entity
+  parent: [GasPipeLayerAlt1, GasPipeStraight]
+  id: GasPipeStraightAlt1
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt1
+    sprite: Structures/Piping/Atmospherics/pipe_alt1.rsi
+  - type: Construction
+    node: straightAlt1
+
+- type: entity
+  parent: [GasPipeLayerAlt2, GasPipeStraight]
+  id: GasPipeStraightAlt2
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt2
+    sprite: Structures/Piping/Atmospherics/pipe_alt2.rsi
+  - type: Construction
+    node: straightAlt2
+
+# GasPipeHalf
+- type: entity
+  parent: [GasPipeLayerAlt1, GasPipeHalf]
+  id: GasPipeHalfAlt1
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt1
+    sprite: Structures/Piping/Atmospherics/pipe_alt1.rsi
+  - type: Construction
+    node: halfAlt1
+
+- type: entity
+  parent: [GasPipeLayerAlt2, GasPipeHalf]
+  id: GasPipeHalfAlt2
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt2
+    sprite: Structures/Piping/Atmospherics/pipe_alt2.rsi
+  - type: Construction
+    node: halfAlt2
+
+# GasPipeBend
+- type: entity
+  parent: [GasPipeLayerAlt1, GasPipeBend]
+  id: GasPipeBendAlt1
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt1
+    sprite: Structures/Piping/Atmospherics/pipe_alt1.rsi
+  - type: Construction
+    node: bendAlt1
+
+- type: entity
+  parent: [GasPipeLayerAlt2, GasPipeBend]
+  id: GasPipeBendAlt2
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt2
+    sprite: Structures/Piping/Atmospherics/pipe_alt2.rsi
+  - type: Construction
+    node: bendAlt2
+
+# GasPipeTJunction
+- type: entity
+  parent: [GasPipeLayerAlt1, GasPipeTJunction]
+  id: GasPipeTJunctionAlt1
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt1
+    sprite: Structures/Piping/Atmospherics/pipe_alt1.rsi
+  - type: Construction
+    node: tjunctionAlt1
+
+- type: entity
+  parent: [GasPipeLayerAlt2, GasPipeTJunction]
+  id: GasPipeTJunctionAlt2
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt2
+    sprite: Structures/Piping/Atmospherics/pipe_alt2.rsi
+  - type: Construction
+    node: tjunctionAlt2
+
+# GasPipeFourway
+- type: entity
+  parent: [GasPipeLayerAlt1, GasPipeFourway]
+  id: GasPipeFourwayAlt1
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt1
+    sprite: Structures/Piping/Atmospherics/pipe_alt1.rsi
+  - type: Construction
+    node: fourwayAlt1
+
+- type: entity
+  parent: [GasPipeLayerAlt2, GasPipeFourway]
+  id: GasPipeFourwayAlt2
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: Sprite
+    drawdepth: ThinPipeAlt2
+    sprite: Structures/Piping/Atmospherics/pipe_alt2.rsi
+  - type: Construction
+    node: fourwayAlt2
index 33a8414961da655d04bf1e7fd91f568953160a6a..88940f48824c789930479e1de7d67ca349380895 100644 (file)
         !type:PipeNode
         nodeGroupID: Pipe
         pipeDirection: South
+  - type: AtmosPipeLayers
+    spriteRsiPaths:
+      Primary: Structures/Piping/Atmospherics/pump.rsi
+      Secondary: Structures/Piping/Atmospherics/pump_alt1.rsi
+      Tertiary: Structures/Piping/Atmospherics/pump_alt2.rsi
 
 - type: entity
   parent: GasBinaryBase
       sprite: Structures/Piping/Atmospherics/gascanisterport.rsi
       layers:
         - sprite: Structures/Piping/Atmospherics/pipe.rsi
-          state: pipeHalf
+          state: pipeUnaryConnectors
           map: [ "enum.PipeVisualLayers.Pipe" ]
         - state: gasCanisterPort
           map: [ "enum.SubfloorLayers.FirstLayer" ]
+    - type: AtmosPipeLayers
+      spriteRsiPaths: {}
     - type: Appearance
     - type: PipeColorVisuals
     - type: GasPort
       sprite: Structures/Piping/Atmospherics/vent.rsi
       layers:
         - sprite: Structures/Piping/Atmospherics/pipe.rsi
-          state: pipeStraight
+          state: pipeBinaryConnectors
           map: [ "enum.PipeVisualLayers.Pipe" ]
         - state: vent_off
           map: [ "enabled", "enum.SubfloorLayers.FirstLayer" ]
+    - type: AtmosPipeLayers
+      spriteRsiPaths: {}
     - type: GenericVisualizer
       visuals:
         enum.VentPumpVisuals.State:
     sprite: Structures/Machines/gasrecycler.rsi
     layers:
     - sprite: Structures/Piping/Atmospherics/pipe.rsi
-      state: pipeStraight
+      state: pipeBinaryConnectors
       map: [ "enum.PipeVisualLayers.Pipe" ]
     - state: running
     - state: unlit
       shader: unshaded
+  - type: AtmosPipeLayers
+    spriteLayersRsiPaths:
+      enum.PipeVisualLayers.Pipe:
+        Primary: Structures/Piping/Atmospherics/pipe.rsi
+        Secondary: Structures/Piping/Atmospherics/pipe_alt1.rsi
+        Tertiary: Structures/Piping/Atmospherics/pipe_alt2.rsi
+  - type: Appearance
   - type: GenericVisualizer
     visuals:
       enum.PumpVisuals.Enabled:
         enabled:
           True: { state: running }
           False: { state: unlit }
-  - type: Appearance
   - type: PipeColorVisuals
   - type: Rotatable
   - type: GasRecycler
       map: [ "enum.PipeVisualLayers.Pipe" ]
     - state: heStraight
       map: [ "enum.SubfloorLayers.FirstLayer" ]
+  - type: AtmosPipeLayers
+    spriteRsiPaths: {}
+    numberOfPipeLayers: 1
   - type: SubFloorHide
     visibleLayers:
     - enum.SubfloorLayers.FirstLayer
index 57574f7f7de92c096155571d8ec328b6e9d5c7bd..c70b33639e54925c92eee9ae162acc27a8cce00a 100644 (file)
@@ -1,5 +1,5 @@
 - type: entity
-  parent: [AirSensorBase, GasPipeBase]
+  parent: [AirSensorBase, GasBinaryBase]
   id: GasPipeSensor
   name: gas pipe sensor
   description: Reports on the status of the gas in the attached pipe network.
     - map: [ "enum.PowerDeviceVisualLayers.Powered" ]
       state: lights
       shader: unshaded
+  - type: AtmosPipeLayers
+    spriteRsiPaths:
+      Primary: Structures/Piping/Atmospherics/gas_pipe_sensor.rsi
+      Secondary: Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi
+      Tertiary: Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi
   - type: Appearance
   - type: GenericVisualizer
     visuals:
index 4d100d434efc13420eab7377b53c4dd5241b590f..6d9d596760ad8f4e3e1e3686eacdb918257d1afd 100644 (file)
@@ -1,7 +1,7 @@
 - type: entity
   abstract: true
-  id: GasPipeBase
   parent: BaseItem
+  id: GasPipeSansLayers
   name: gas pipe
   description: Holds gas.
   placement:
@@ -18,7 +18,6 @@
     damageModifierSet: Metallic
   - type: SubFloorHide
   - type: CollideOnAnchor
-  - type: PipeAppearance
   - type: Anchorable
   - type: Rotatable
   - type: Destructible
@@ -51,6 +50,7 @@
     drawdepth: ThinPipe
     visible: false
   - type: Appearance
+  - type: PipeAppearance
   - type: PipeColorVisuals
   - type: NodeContainer
   - type: PipeRestrictOverlap
   - type: StaticPrice
     price: 30
 
+- type: entity
+  abstract: true
+  parent: GasPipeSansLayers
+  id: GasPipeBase
+  components:
+  - type: AtmosPipeLayers
+    spriteLayersRsiPaths:
+      enum.PipeVisualLayers.Pipe:
+        Primary: Structures/Piping/Atmospherics/pipe.rsi
+        Secondary: Structures/Piping/Atmospherics/pipe_alt1.rsi
+        Tertiary: Structures/Piping/Atmospherics/pipe_alt2.rsi
+
 #Note: The PipeDirection of the PipeNode should be the south-facing version, because the entity starts at an angle of 0 (south)
 
 - type: entity
   parent: GasPipeBase
   id: GasPipeHalf
   suffix: Half
+  placement:
+    mode: AlignAtmosPipeLayers
   components:
   - type: NodeContainer
     nodes:
         pipeDirection: South
   - type: Sprite
     layers:
-      - state: pipeHalf
-        map: [ "enum.PipeVisualLayers.Pipe" ]
+    - state: pipeHalf
+      map: [ "enum.PipeVisualLayers.Pipe" ]
+  - type: AtmosPipeLayers
+    alternativePrototypes:
+      Primary: GasPipeHalf
+      Secondary: GasPipeHalfAlt1
+      Tertiary: GasPipeHalfAlt2
   - type: Construction
     graph: GasPipe
     node: half
+  - type: Item
+    size: Small
+    storedSprite:
+      sprite: Structures/Piping/Atmospherics/pipe.rsi
+      state: storageHalf
   - type: GuideHelp
     guides:
     - Pipes
   parent: GasPipeBase
   id: GasPipeStraight
   suffix: Straight
+  placement:
+    mode: AlignAtmosPipeLayers
   components:
   - type: NodeContainer
     nodes:
         pipeDirection: Longitudinal
   - type: Sprite
     layers:
-      - state: pipeStraight
-        map: [ "enum.PipeVisualLayers.Pipe" ]
+    - state: pipeStraight
+      map: [ "enum.PipeVisualLayers.Pipe" ]
+  - type: AtmosPipeLayers
+    alternativePrototypes:
+      Primary: GasPipeStraight
+      Secondary: GasPipeStraightAlt1
+      Tertiary: GasPipeStraightAlt2
   - type: Construction
     graph: GasPipe
     node: straight
   - type: Item
-    size: Normal
     storedSprite:
       sprite: Structures/Piping/Atmospherics/pipe.rsi
       state: storageStraight
   parent: GasPipeBase
   id: GasPipeBend
   suffix: Bend
+  placement:
+    mode: AlignAtmosPipeLayers
   components:
   - type: NodeContainer
     nodes:
     layers:
       - state: pipeBend
         map: [ "enum.PipeVisualLayers.Pipe" ]
+  - type: AtmosPipeLayers
+    alternativePrototypes:
+      Primary: GasPipeBend
+      Secondary: GasPipeBendAlt1
+      Tertiary: GasPipeBendAlt2
   - type: Construction
     graph: GasPipe
     node: bend
   - type: Item
-    size: Small
     shape:
     - 0,0,1,0
     - 1,1,1,1
 - type: entity
   parent: GasPipeBase
   id: GasPipeTJunction
+  placement:
+    mode: AlignAtmosPipeLayers
   suffix: TJunction
   components:
   - type: NodeContainer
     layers:
       - state: pipeTJunction
         map: [ "enum.PipeVisualLayers.Pipe" ]
+  - type: AtmosPipeLayers
+    alternativePrototypes:
+      Primary: GasPipeTJunction
+      Secondary: GasPipeTJunctionAlt1
+      Tertiary: GasPipeTJunctionAlt2
   - type: Construction
     graph: GasPipe
     node: tjunction
   - type: Item
-    size: Normal
-    shape:
-    - 0,0,2,0
-    - 1,1,1,1
     heldPrefix: TJunction
     storedSprite:
       sprite: Structures/Piping/Atmospherics/pipe.rsi
   parent: GasPipeBase
   id: GasPipeFourway
   suffix: Fourway
+  placement:
+    mode: AlignAtmosPipeLayers
   components:
   - type: Transform
     noRot: true
     layers:
       - state: pipeFourway
         map: [ "enum.PipeVisualLayers.Pipe" ]
+  - type: AtmosPipeLayers
+    alternativePrototypes:
+      Primary: GasPipeFourway
+      Secondary: GasPipeFourwayAlt1
+      Tertiary: GasPipeFourwayAlt2
   - type: Construction
     graph: GasPipe
     node: fourway
   - type: Item
-    size: Normal
-    shape:
-    - 1,0,1,2
-    - 0,1,2,1
     heldPrefix: Fourway
+    storedSprite:
+      sprite: Structures/Piping/Atmospherics/pipe.rsi
+      state: storageFourway
   - type: MeleeWeapon
     wideAnimationRotation: 90
     attackRate: 0.75
     layers:
       - state: pipeBroken
         map: [ "enum.PipeVisualLayers.Pipe" ]
+  - type: AtmosPipeLayers
+    numberOfPipeLayers: 1
   - type: Construction
     graph: GasPipe
     node: broken
+  - type: Item
+    size: Small
   - type: Destructible
     thresholds: # override parent to avoid recursive destruction
     - trigger:
     guides:
     - Pipes
     - PipeNetworks
+
+- type: entity
+  parent: GasPipeSansLayers
+  id: GasPipeManifold
+  name: gas pipe manifold
+  description: Allows gas pipes of different configurations to be connected together.
+  placement:
+    mode: SnapgridCenter
+  components:
+  - type: Sprite
+    sprite: Structures/Piping/Atmospherics/manifold.rsi
+    layers:
+    - state: pipeManifold
+      map: [ "enum.PipeVisualLayers.Pipe" ]
+  - type: AtmosPipeLayers
+    pipeLayersLocked: true
+  - type: PipeAppearance
+    sprite:
+    - { sprite: Structures/Piping/Atmospherics/manifold.rsi, state: pipeConnector }
+    - { sprite: Structures/Piping/Atmospherics/manifold.rsi, state: pipeConnector_alt1 }
+    - { sprite: Structures/Piping/Atmospherics/manifold.rsi, state: pipeConnector_alt2 }
+  - type: Construction
+    graph: GasPipe
+    node: manifold
+  - type: Item
+    size: Small
+    shape:
+    - 0,0,1,0
+    storedSprite:
+      sprite: Structures/Piping/Atmospherics/manifold.rsi
+      state: storageManifold
+  - type: NodeContainer
+    nodes:
+      south0:
+        !type:PipeNode
+        nodeGroupID: Pipe
+        pipeDirection: South
+        pipeLayer: 0
+      south1:
+        !type:PipeNode
+        nodeGroupID: Pipe
+        pipeDirection: South
+        pipeLayer: 1
+      south2:
+        !type:PipeNode
+        nodeGroupID: Pipe
+        pipeDirection: South
+        pipeLayer: 2
+      north0:
+        !type:PipeNode
+        nodeGroupID: Pipe
+        pipeDirection: North
+        pipeLayer: 0
+      north1:
+        !type:PipeNode
+        nodeGroupID: Pipe
+        pipeDirection: North
+        pipeLayer: 1
+      north2:
+        !type:PipeNode
+        nodeGroupID: Pipe
+        pipeDirection: North
+        pipeLayer: 2
+  - type: GasPipeManifold
+  - type: AtmosMonitoringConsoleDevice
+    navMapBlip: GasPipeManifold
+    showAbsentConnections: false
+  - type: AtmosDevice
+  - type: Tag
+    tags:
+    - Unstackable
index abb0ead4a08cbc91846c880903b51ed58e8591bb..612e144e536888bcddc778400feb8e67238871a4 100644 (file)
@@ -44,7 +44,7 @@
       sprite: Structures/Piping/Atmospherics/vent.rsi
       layers:
         - sprite: Structures/Piping/Atmospherics/pipe.rsi
-          state: pipeHalf
+          state: pipeUnaryConnectors
           map: [ "enum.PipeVisualLayers.Pipe" ]
         - state: vent_off
           map: [ "enabled", "enum.SubfloorLayers.FirstLayer" ]
@@ -94,7 +94,7 @@
       sprite: Structures/Piping/Atmospherics/vent.rsi
       layers:
         - sprite: Structures/Piping/Atmospherics/pipe.rsi
-          state: pipeHalf
+          state: pipeUnaryConnectors
           map: [ "enum.PipeVisualLayers.Pipe" ]
         - state: vent_passive
           map: [ "enum.SubfloorLayers.FirstLayer" ]
       sprite: Structures/Piping/Atmospherics/scrubber.rsi
       layers:
         - sprite: Structures/Piping/Atmospherics/pipe.rsi
-          state: pipeHalf
+          state: pipeUnaryConnectors
           map: [ "enum.PipeVisualLayers.Pipe" ]
         - state: scrub_off
           map: [ "enabled", "enum.SubfloorLayers.FirstLayer" ]
       drawdepth: FloorObjects
       sprite: Structures/Piping/Atmospherics/outletinjector.rsi
       layers:
-        - state: pipeHalf
+        - state: pipeUnaryConnectors
           sprite: Structures/Piping/Atmospherics/pipe.rsi
           map: [ "enum.PipeVisualLayers.Pipe" ]
         - state: injector
           shader: unshaded
           map: [ "enum.LightLayers.Unshaded" ]
           color: "#990000"
+    - type: Appearance
     - type: GenericVisualizer
       visuals:
        # toggle color of the unshaded light:
          enum.LightLayers.Unshaded:
            True: { color: "#5eff5e" }
            False: { color: "#990000" }
-    - type: Appearance
     - type: PipeColorVisuals
     - type: GasOutletInjector
     - type: Construction
     - type: Rotatable
     - type: GasThermoMachine
     - type: AtmosPipeColor
+    - type: AtmosPipeLayers
+      spriteLayersRsiPaths:
+        enum.PipeVisualLayers.Pipe:
+          Primary: Structures/Piping/Atmospherics/thermomachine.rsi
+          Secondary: Structures/Piping/Atmospherics/thermomachine_alt1.rsi
+          Tertiary: Structures/Piping/Atmospherics/thermomachine_alt2.rsi
     - type: AtmosDevice
     - type: UserInterface
       interfaces:
       map: ["enum.SolutionContainerLayers.Fill"]
       visible: false
     - state: trans
+  - type: Appearance
   - type: GenericVisualizer
     visuals:
       enum.PowerDeviceVisuals.Powered:
   - type: SolutionContainerVisuals
     maxFillLevels: 7
     fillBaseName: fill-
-  - type: Appearance
   - type: PipeColorVisuals
   - type: Rotatable
   - type: GasCondenser
   - type: AtmosPipeColor
+  - type: AtmosPipeLayers
+    spriteLayersRsiPaths:
+      enum.PipeVisualLayers.Pipe:
+        Primary: Structures/Piping/Atmospherics/condenser.rsi
+        Secondary: Structures/Piping/Atmospherics/condenser_alt1.rsi
+        Tertiary: Structures/Piping/Atmospherics/condenser_alt2.rsi
   - type: AtmosDevice
   - type: PipeRestrictOverlap
   - type: ApcPowerReceiver
   - type: GuideHelp
     guides:
     - GasCondensing
+
index 771c63ebd5c4a6464fdeb125f9b935e3801e0a90..14d487fdb50b24298689b086a8b7aaa736535ee4 100644 (file)
         amount: 1
         doAfter: 1
 
+    - to: halfAlt1
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
+    - to: halfAlt2
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
     - to: straight
       steps:
       - material: Steel
         amount: 1
         doAfter: 1
 
+    - to: straightAlt1
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
+    - to: straightAlt2
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
     - to: bend
       steps:
       - material: Steel
         amount: 1
         doAfter: 1
 
+    - to: bendAlt1
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
+    - to: bendAlt2
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
     - to: tjunction
       steps:
       - material: Steel
         amount: 1
         doAfter: 1
 
+    - to: tjunctionAlt1
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
+    - to: tjunctionAlt2
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
     - to: fourway
       steps:
       - material: Steel
         amount: 1
         doAfter: 1
 
+    - to: fourwayAlt1
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
+    - to: fourwayAlt2
+      steps:
+      - material: Steel
+        amount: 1
+        doAfter: 1
+
+    - to: manifold
+      steps:
+      - material: Steel
+        amount: 2
+        doAfter: 1
+
   - node: half
     entity: GasPipeHalf
     edges:
       - tool: Welding
         doAfter: 1
 
+  - node: halfAlt1
+    entity: GasPipeHalfAlt1
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
+  - node: halfAlt2
+    entity: GasPipeHalfAlt2
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
   - node: straight
     entity: GasPipeStraight
     edges:
       - tool: Welding
         doAfter: 1
 
+  - node: straightAlt1
+    entity: GasPipeStraightAlt1
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
+  - node: straightAlt2
+    entity: GasPipeStraightAlt2
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
   - node: bend
     entity: GasPipeBend
     edges:
       - tool: Welding
         doAfter: 1
 
+  - node: bendAlt1
+    entity: GasPipeBendAlt1
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
+  - node: bendAlt2
+    entity: GasPipeBendAlt2
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
   - node: tjunction
     entity: GasPipeTJunction
     edges:
       - tool: Welding
         doAfter: 1
 
+  - node: tjunctionAlt1
+    entity: GasPipeTJunctionAlt1
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
+  - node: tjunctionAlt2
+    entity: GasPipeTJunctionAlt2
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
   - node: fourway
     entity: GasPipeFourway
     edges:
       - tool: Welding
         doAfter: 1
 
+  - node: fourwayAlt1
+    entity: GasPipeFourwayAlt1
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
+  - node: fourwayAlt2
+    entity: GasPipeFourwayAlt2
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 1
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
+
   - node: broken
     entity: GasPipeBroken
     edges:
       steps:
       - tool: Welding
         doAfter: 1
+
+  - node: manifold
+    entity: GasPipeManifold
+    edges:
+    - to: start
+      conditions:
+      - !type:EntityAnchored
+        anchored: false
+      completed:
+      - !type:SpawnPrototype
+        prototype: SheetSteel1
+        amount: 2
+      - !type:DeleteEntity
+      steps:
+      - tool: Welding
+        doAfter: 1
index 575ca3ae4e5d343d2f690d6e211ce3664c6ef43c..67389f85afb7b88420c06d7a5bb309836f12b8f8 100644 (file)
   startNode: start
   targetNode: half
   category: construction-category-utilities
-  placementMode: SnapgridCenter
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeHalf
+  - GasPipeHalfAlt1
+  - GasPipeHalfAlt2
+
+- type: construction
+  id: GasPipeHalfAlt1
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: halfAlt1
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeHalf
+  - GasPipeHalfAlt1
+  - GasPipeHalfAlt2
+
+- type: construction
+  id: GasPipeHalfAlt2
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: halfAlt2
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
   canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeHalf
+  - GasPipeHalfAlt1
+  - GasPipeHalfAlt2
 
 - type: construction
   id: GasPipeStraight
   startNode: start
   targetNode: straight
   category: construction-category-utilities
-  placementMode: SnapgridCenter
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeStraight
+  - GasPipeStraightAlt1
+  - GasPipeStraightAlt2
+
+- type: construction
+  id: GasPipeStraightAlt1
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: straightAlt1
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeStraight
+  - GasPipeStraightAlt1
+  - GasPipeStraightAlt2
+
+- type: construction
+  id: GasPipeStraightAlt2
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: straightAlt2
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
   canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeStraight
+  - GasPipeStraightAlt1
+  - GasPipeStraightAlt2
 
 - type: construction
   id: GasPipeBend
   startNode: start
   targetNode: bend
   category: construction-category-utilities
-  placementMode: SnapgridCenter
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeBend
+  - GasPipeBendAlt1
+  - GasPipeBendAlt2
+
+- type: construction
+  id: GasPipeBendAlt1
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: bendAlt1
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeBend
+  - GasPipeBendAlt1
+  - GasPipeBendAlt2
+
+- type: construction
+  id: GasPipeBendAlt2
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: bendAlt2
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
   canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeBend
+  - GasPipeBendAlt1
+  - GasPipeBendAlt2
 
 - type: construction
   id: GasPipeTJunction
   startNode: start
   targetNode: tjunction
   category: construction-category-utilities
-  placementMode: SnapgridCenter
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeTJunction
+  - GasPipeTJunctionAlt1
+  - GasPipeTJunctionAlt2
+
+- type: construction
+  id: GasPipeTJunctionAlt1
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: tjunctionAlt1
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeTJunction
+  - GasPipeTJunctionAlt1
+  - GasPipeTJunctionAlt2
+
+- type: construction
+  id: GasPipeTJunctionAlt2
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: tjunctionAlt2
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
   canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeTJunction
+  - GasPipeTJunctionAlt1
+  - GasPipeTJunctionAlt2
 
 - type: construction
   id: GasPipeFourway
   startNode: start
   targetNode: fourway
   category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeFourway
+  - GasPipeFourwayAlt1
+  - GasPipeFourwayAlt2
+
+- type: construction
+  id: GasPipeFourwayAlt1
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: fourwayAlt1
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeFourway
+  - GasPipeFourwayAlt1
+  - GasPipeFourwayAlt2
+
+- type: construction
+  id: GasPipeFourwayAlt2
+  hide: true
+  graph: GasPipe
+  startNode: start
+  targetNode: fourwayAlt2
+  category: construction-category-utilities
+  placementMode: AlignAtmosPipeLayers
+  canBuildInImpassable: true
+  alternativePrototypes:
+  - GasPipeFourway
+  - GasPipeFourwayAlt1
+  - GasPipeFourwayAlt2
+
+- type: construction
+  id: GasPipeManifold
+  graph: GasPipe
+  startNode: start
+  targetNode: manifold
+  category: construction-category-utilities
   placementMode: SnapgridCenter
   canBuildInImpassable: true
 
index f624c0f4483d1dbab29bd3de0816ee29ffc4f691..344b871ae940d19c41e2243e5b578036717b9797 100644 (file)
   copyright: "Created by chromiumboy"
   source: "https://github.com/chromiumboy"
 
+- files: ["beveled_rectangle_east_west.png"]
+  license: "CC-BY-SA-3.0"
+  copyright: "Created by chromiumboy"
+  source: "https://github.com/chromiumboy"
+
+- files: ["beveled_rectangle_north_south.png"]
+  license: "CC-BY-SA-3.0"
+  copyright: "Created by chromiumboy"
+  source: "https://github.com/chromiumboy"
+
 - files: ["beveled_square.png"]
   license: "CC-BY-SA-3.0"
   copyright: "Created by chromiumboy"
diff --git a/Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png b/Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png
new file mode 100644 (file)
index 0000000..9a972cb
Binary files /dev/null and b/Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png differ
diff --git a/Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png.yml b/Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png.yml
new file mode 100644 (file)
index 0000000..dabd660
--- /dev/null
@@ -0,0 +1,2 @@
+sample:
+  filter: true
diff --git a/Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png b/Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png
new file mode 100644 (file)
index 0000000..a2a8703
Binary files /dev/null and b/Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png differ
diff --git a/Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png.yml b/Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png.yml
new file mode 100644 (file)
index 0000000..dabd660
--- /dev/null
@@ -0,0 +1,2 @@
+sample:
+  filter: true
index bb584a7c20dbf31883684d954719f962b43dd4f7..ee497a1c049840b30224950590c6319f34f2bb74 100644 (file)
@@ -10,3 +10,6 @@ https://game-icons.net/1x1/delapouite/padlock-open.html
 
 bubbles.svg by Lorc under CC BY 3.0
 https://game-icons.net/1x1/lorc/bubbles.html
+
+screwdriver.png by Lorc (edited by chromiumboy) under CC BY 3.0
+https://game-icons.net/1x1/lorc/screwdriver.html
diff --git a/Resources/Textures/Interface/VerbIcons/screwdriver.png b/Resources/Textures/Interface/VerbIcons/screwdriver.png
new file mode 100644 (file)
index 0000000..e230262
Binary files /dev/null and b/Resources/Textures/Interface/VerbIcons/screwdriver.png differ
diff --git a/Resources/Textures/Interface/VerbIcons/screwdriver.png.yml b/Resources/Textures/Interface/VerbIcons/screwdriver.png.yml
new file mode 100644 (file)
index 0000000..5c43e23
--- /dev/null
@@ -0,0 +1,2 @@
+sample:
+  filter: true
index 05a1e617a51b36a5fb5e2edb6e2ece225c8084ea..0ad29bf3a892d9b686acc40b02f16926fe657c32 100644 (file)
@@ -1,21 +1,18 @@
 {
-    "version":1,
-    "size":
-    {
-        "x":32,
-        "y":32
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
     },
-    "copyright":"Created by EmoGarbage404 (github) for Space Station 14.",
-    "license":"CC0-1.0",
-    "states":
-    [
+    "copyright": "Created by EmoGarbage404 (github) for Space Station 14, edited by chromiumboy.",
+    "license": "CC0-1.0",
+    "states": [
         {
-            "name":"off"
+            "name": "off"
         },
         {
-            "name":"on",
-            "delays":
-            [
+            "name": "on",
+            "delays": [
                 [
                     0.05,
                     0.05,
             ]
         },
         {
-            "name":"panel"
+            "name": "panel"
         },
         {
-            "name":"trans"
+            "name": "trans"
         },
         {
-            "name":"pipe",
-            "directions":4
+            "name": "pipe",
+            "directions": 4
         },
         {
-            "name":"display"
+            "name": "display"
         },
         {
-            "name":"fill-1"
+            "name": "fill-1"
         },
         {
-            "name":"fill-2"
+            "name": "fill-2"
         },
         {
-            "name":"fill-3"
+            "name": "fill-3"
         },
         {
-            "name":"fill-4"
+            "name": "fill-4"
         },
         {
-            "name":"fill-5"
+            "name": "fill-5"
         },
         {
-            "name":"fill-6"
+            "name": "fill-6"
         },
         {
-            "name":"fill-7"
+            "name": "fill-7"
         }
     ]
 }
index c9fbbec3004bf2932dd24463424d1a42e2f601fe..694a3a15b6d4f66d644546b8856a3d92e8437f00 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/pipe.png and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/pipe.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/meta.json
new file mode 100644 (file)
index 0000000..3176fce
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "copyright": "Created by EmoGarbage404 (github) for Space Station 14, edited by chromiumboy.",
+    "license": "CC0-1.0",
+    "states": [
+        {
+            "name": "pipe",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/pipe.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/pipe.png
new file mode 100644 (file)
index 0000000..e5ae199
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/pipe.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/meta.json
new file mode 100644 (file)
index 0000000..3176fce
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "copyright": "Created by EmoGarbage404 (github) for Space Station 14, edited by chromiumboy.",
+    "license": "CC0-1.0",
+    "states": [
+        {
+            "name": "pipe",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/pipe.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/pipe.png
new file mode 100644 (file)
index 0000000..4ac647a
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/pipe.png differ
index 4a9a8f6f2069490a67965a5fdf60019008341678..5858ec39fb0cba0cb4b2d63324ed002de4328c6c 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/base.png and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/base.png differ
index 6108d2b99492134bbeeb0d5f7bfc64256627e5a9..f294bc3fce5325d2218ad90b02b09fe218ca0ac4 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/lights.png and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/lights.png differ
index 878c7817a2b387513a1adca0ff585f3f956d0025..bfe74c313cca567b384b70bf1551ae0cd24923e1 100644 (file)
         {
             "name": "icon"
         },
-       {
-            "name": "base"
+        {
+            "name": "base",
+            "directions": 4
         },
-       {
+        {
             "name": "blank"
         },
         {
             "name": "lights",
+            "directions": 4,
             "delays": [
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ],
                 [
                     1.0,
                     0.25
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/base.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/base.png
new file mode 100644 (file)
index 0000000..0afdd9f
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/base.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/blank.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/blank.png
new file mode 100644 (file)
index 0000000..7bee0a0
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/blank.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/icon.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/icon.png
new file mode 100644 (file)
index 0000000..4ac9e76
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/icon.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/lights.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/lights.png
new file mode 100644 (file)
index 0000000..45d84c3
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/lights.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/meta.json
new file mode 100644 (file)
index 0000000..bfe74c3
--- /dev/null
@@ -0,0 +1,43 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Created by chromiumboy (github) for SS14, based on the digital valve from /tg/, taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da.",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "icon"
+        },
+        {
+            "name": "base",
+            "directions": 4
+        },
+        {
+            "name": "blank"
+        },
+        {
+            "name": "lights",
+            "directions": 4,
+            "delays": [
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ]
+            ]
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/base.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/base.png
new file mode 100644 (file)
index 0000000..131d75e
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/base.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/blank.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/blank.png
new file mode 100644 (file)
index 0000000..7bee0a0
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/blank.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/icon.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/icon.png
new file mode 100644 (file)
index 0000000..4ac9e76
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/icon.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/lights.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/lights.png
new file mode 100644 (file)
index 0000000..826c90d
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/lights.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/meta.json
new file mode 100644 (file)
index 0000000..bfe74c3
--- /dev/null
@@ -0,0 +1,43 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Created by chromiumboy (github) for SS14, based on the digital valve from /tg/, taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da.",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "icon"
+        },
+        {
+            "name": "base",
+            "directions": 4
+        },
+        {
+            "name": "blank"
+        },
+        {
+            "name": "lights",
+            "directions": 4,
+            "delays": [
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ],
+                [
+                    1.0,
+                    0.25
+                ]
+            ]
+        }
+    ]
+}
index 979d804fb4a1d35df612bdb205f27f6631f7825c..f216c2f60d5e33829e26f92106f18fd370b8bb1a 100644 (file)
@@ -1,38 +1,67 @@
 {
-    "version":1,
-    "size":{"x":32,"y":32},
-    "copyright":"Base sprites taken from tgstation, split to display on two layers (machinebody/panel) by Menshin, and recolored and edited by EmoGarbage404 (github)",
-    "license":"CC-BY-SA-3.0",
-    "states":[
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "copyright": "Base sprites taken from tgstation, split to display on two layers (machinebody/panel) by Menshin, and recolored and edited by EmoGarbage404 (github) and chromiumboy (github)",
+    "license": "CC-BY-SA-3.0",
+    "states": [
         {
-            "name":"freezerOff",
-            "directions":1
+            "name": "freezerOff",
+            "directions": 1
         },
         {
-            "name":"freezerPanelOpen",
-            "directions":1
+            "name": "freezerPanelOpen",
+            "directions": 1
         },
         {
-            "name":"freezerOn",
-            "directions":1,
-            "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] ]
+            "name": "freezerOn",
+            "directions": 1,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
         },
         {
-            "name":"heaterOff",
-            "directions":1
+            "name": "heaterOff",
+            "directions": 1
         },
         {
-            "name":"heaterPanelOpen",
-            "directions":1
+            "name": "heaterPanelOpen",
+            "directions": 1
         },
         {
-            "name":"heaterOn",
-            "directions":1,
-            "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] ]
+            "name": "heaterOn",
+            "directions": 1,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
         },
         {
-            "name":"pipe",
-            "directions":4
+            "name": "pipe",
+            "directions": 4
         }
     ]
 }
index 620ba905bea43a0cb2a7ae8d2c2647e6ff9ec5f9..e0209a7bc8967f8f7d89ebbe4d292f5f2aa70b0b 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/pipe.png and b/Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/pipe.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/meta.json
new file mode 100644 (file)
index 0000000..3150638
--- /dev/null
@@ -0,0 +1,30 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "copyright": "Base sprites taken from tgstation at https://github.com/tgstation/tgstation/commit/662c08272acd7be79531550919f56f846726eabb and edited by chromiumboy (github)",
+    "license": "CC-BY-SA-3.0",
+    "states": [
+        {
+            "name": "pipeManifold",
+            "directions": 4
+        },
+        {
+            "name": "storageManifold"
+        },
+        {
+            "name": "pipeConnector",
+            "directions": 4
+        },
+        {
+            "name": "pipeConnector_alt1",
+            "directions": 4
+        },
+        {
+            "name": "pipeConnector_alt2",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector.png b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector.png
new file mode 100644 (file)
index 0000000..25e7906
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt1.png b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt1.png
new file mode 100644 (file)
index 0000000..3f4debb
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt1.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt2.png b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt2.png
new file mode 100644 (file)
index 0000000..f64fc34
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt2.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeManifold.png b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeManifold.png
new file mode 100644 (file)
index 0000000..f81fbdc
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeManifold.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/storageManifold.png b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/storageManifold.png
new file mode 100644 (file)
index 0000000..a9d3b0d
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/storageManifold.png differ
index aecb62aee527c77b9bc4b3510d6b4f11f4690b65..82106dbfe6142719aa10eb723fccf9501858e4dd 100644 (file)
@@ -1,87 +1,98 @@
 {
-   "version":1,
-   "size":{
-      "x":32,
-      "y":32
-   },
-   "license":"CC-BY-SA-3.0",
-   "copyright":"Inhand sprites by alzore_(discord) for SS14. pipeTrinaryConnectors made by Menshin for SS14 based on pipeTJunction, the rest is taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da.",
-   "states":[
-      {
-         "name": "inhand-left",
-         "directions":4
-      },
-      {
-         "name":"inhand-right",
-         "directions":4
-      },
-      {
-         "name": "Bend-inhand-left",
-         "directions":4
-      },
-      {
-         "name":"Bend-inhand-right",
-         "directions":4
-      },
-      {
-         "name": "TJunction-inhand-left",
-         "directions":4
-      },
-      {
-         "name":"TJunction-inhand-right",
-         "directions":4
-      },
-      {
-         "name": "Fourway-inhand-left",
-         "directions":4
-      },
-      {
-         "name":"Fourway-inhand-right",
-         "directions":4
-      },
-      {
-         "name":"pipeBroken",
-         "directions":1
-      },
-      {
-         "name":"pipeTJunction",
-         "directions":4
-      },
-      {
-         "name":"pipeHalf",
-         "directions":4
-      },
-      {
-         "name":"pipeBend",
-         "directions":4
-      },
-      {
-         "name": "pipeFourway",
-         "directions":4
-      },
-      {
-         "name":"pipeStraight",
-         "directions":4
-      },
-      {
-         "name":"pipeConnector",
-         "directions":4
-      },
-         {
-         "name":"pipeTrinaryConnectors",
-         "directions":4
-      },
-      {
-         "name":"storageStraight",
-         "directions":4
-      },
-      {
-         "name":"storageBend",
-         "directions":4
-      },
-      {
-         "name":"storageTJunction",
-         "directions":4
-      }
-   ]
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Inhand sprites by alzore_(discord) for SS14. pipeTrinaryConnectors made by Menshin for SS14 based on pipeTJunction, the rest is taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da, edited by chromiumboy.",
+    "states": [
+        {
+            "name": "inhand-left",
+            "directions": 4
+        },
+        {
+            "name": "inhand-right",
+            "directions": 4
+        },
+        {
+            "name": "Bend-inhand-left",
+            "directions": 4
+        },
+        {
+            "name": "Bend-inhand-right",
+            "directions": 4
+        },
+        {
+            "name": "TJunction-inhand-left",
+            "directions": 4
+        },
+        {
+            "name": "TJunction-inhand-right",
+            "directions": 4
+        },
+        {
+            "name": "Fourway-inhand-left",
+            "directions": 4
+        },
+        {
+            "name": "Fourway-inhand-right",
+            "directions": 4
+        },
+        {
+            "name": "pipeBroken",
+            "directions": 1
+        },
+        {
+            "name": "pipeTJunction",
+            "directions": 4
+        },
+        {
+            "name": "pipeHalf",
+            "directions": 4
+        },
+        {
+            "name": "pipeBend",
+            "directions": 4
+        },
+        {
+            "name": "pipeFourway",
+            "directions": 4
+        },
+        {
+            "name": "pipeStraight",
+            "directions": 4
+        },
+        {
+            "name": "pipeConnector",
+            "directions": 4
+        },
+        {
+            "name": "pipeUnaryConnectors",
+            "directions": 4
+        },
+        {
+            "name": "pipeBinaryConnectors",
+            "directions": 4
+        },
+        {
+            "name": "pipeTrinaryConnectors",
+            "directions": 4
+        },
+        {
+            "name": "storageStraight"
+        },
+        {
+            "name": "storageHalf"
+        },
+        {
+            "name": "storageBend"
+        },
+        {
+            "name": "storageTJunction"
+        },
+        {
+            "name": "storageFourway"
+        }
+    ]
 }
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBinaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBinaryConnectors.png
new file mode 100644 (file)
index 0000000..a2fb4b7
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBinaryConnectors.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeUnaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeUnaryConnectors.png
new file mode 100644 (file)
index 0000000..a4e2286
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeUnaryConnectors.png differ
index 39ffe213efb7142a4979c79f1dd7fcfc0a12c6ad..003a49eaeceb5caf4bc5e68a13ab2d6039eb652f 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageFourway.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageFourway.png
new file mode 100644 (file)
index 0000000..911c0da
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageFourway.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageHalf.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageHalf.png
new file mode 100644 (file)
index 0000000..5eba5e5
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageHalf.png differ
index 715aeb58249c6800597e1df477b52ba8b12fcbc1..2805fe662673cafe5a294e4a2a7601673702207c 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png differ
index af8376a1527ae14ee15c6f51e52e61a7aec7c51c..92b5d5a0068cc856137311019510a0f663a6d099 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/meta.json
new file mode 100644 (file)
index 0000000..31825d6
--- /dev/null
@@ -0,0 +1,51 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Inhand sprites by alzore_(discord) for SS14. pipeTrinaryConnectors made by Menshin for SS14 based on pipeTJunction, the rest is taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da, edited by chromiumboy.",
+    "states": [
+        {
+            "name": "pipeBroken",
+            "directions": 1
+        },
+        {
+            "name": "pipeTJunction",
+            "directions": 4
+        },
+        {
+            "name": "pipeHalf",
+            "directions": 4
+        },
+        {
+            "name": "pipeBend",
+            "directions": 4
+        },
+        {
+            "name": "pipeFourway",
+            "directions": 4
+        },
+        {
+            "name": "pipeStraight",
+            "directions": 4
+        },
+        {
+            "name": "pipeConnector",
+            "directions": 4
+        },
+        {
+            "name": "pipeUnaryConnectors",
+            "directions": 4
+        },
+        {
+            "name": "pipeBinaryConnectors",
+            "directions": 4
+        },
+        {
+            "name": "pipeTrinaryConnectors",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBend.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBend.png
new file mode 100644 (file)
index 0000000..42fddaa
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBend.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBinaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBinaryConnectors.png
new file mode 100644 (file)
index 0000000..e2eccac
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBinaryConnectors.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBroken.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBroken.png
new file mode 100644 (file)
index 0000000..8a54fed
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBroken.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeConnector.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeConnector.png
new file mode 100644 (file)
index 0000000..a464bcf
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeConnector.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeFourway.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeFourway.png
new file mode 100644 (file)
index 0000000..e9508bb
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeFourway.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeHalf.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeHalf.png
new file mode 100644 (file)
index 0000000..c022162
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeHalf.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeStraight.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeStraight.png
new file mode 100644 (file)
index 0000000..d0b0105
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeStraight.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTJunction.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTJunction.png
new file mode 100644 (file)
index 0000000..06b945f
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTJunction.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTrinaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTrinaryConnectors.png
new file mode 100644 (file)
index 0000000..f2dd866
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTrinaryConnectors.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeUnaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeUnaryConnectors.png
new file mode 100644 (file)
index 0000000..a1a79e3
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeUnaryConnectors.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/meta.json
new file mode 100644 (file)
index 0000000..31825d6
--- /dev/null
@@ -0,0 +1,51 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Inhand sprites by alzore_(discord) for SS14. pipeTrinaryConnectors made by Menshin for SS14 based on pipeTJunction, the rest is taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da, edited by chromiumboy.",
+    "states": [
+        {
+            "name": "pipeBroken",
+            "directions": 1
+        },
+        {
+            "name": "pipeTJunction",
+            "directions": 4
+        },
+        {
+            "name": "pipeHalf",
+            "directions": 4
+        },
+        {
+            "name": "pipeBend",
+            "directions": 4
+        },
+        {
+            "name": "pipeFourway",
+            "directions": 4
+        },
+        {
+            "name": "pipeStraight",
+            "directions": 4
+        },
+        {
+            "name": "pipeConnector",
+            "directions": 4
+        },
+        {
+            "name": "pipeUnaryConnectors",
+            "directions": 4
+        },
+        {
+            "name": "pipeBinaryConnectors",
+            "directions": 4
+        },
+        {
+            "name": "pipeTrinaryConnectors",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBend.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBend.png
new file mode 100644 (file)
index 0000000..fc371f4
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBend.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBinaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBinaryConnectors.png
new file mode 100644 (file)
index 0000000..3573b28
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBinaryConnectors.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBroken.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBroken.png
new file mode 100644 (file)
index 0000000..8a54fed
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBroken.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeConnector.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeConnector.png
new file mode 100644 (file)
index 0000000..5310c11
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeConnector.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeFourway.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeFourway.png
new file mode 100644 (file)
index 0000000..f879717
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeFourway.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeHalf.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeHalf.png
new file mode 100644 (file)
index 0000000..227a31c
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeHalf.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeStraight.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeStraight.png
new file mode 100644 (file)
index 0000000..5fb9c34
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeStraight.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTJunction.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTJunction.png
new file mode 100644 (file)
index 0000000..6ff306d
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTJunction.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTrinaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTrinaryConnectors.png
new file mode 100644 (file)
index 0000000..4049d71
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTrinaryConnectors.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeUnaryConnectors.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeUnaryConnectors.png
new file mode 100644 (file)
index 0000000..8eb130b
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeUnaryConnectors.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/meta.json
new file mode 100644 (file)
index 0000000..ef75896
--- /dev/null
@@ -0,0 +1,157 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da. Signal valve is a digital valve modified by deltanedas. Manual valve modified by Deerstop at https://github.com/space-wizards/space-station-14/pull/34378. Modified by chromiumboy.",
+    "states": [
+        {
+            "name": "pumpDigitalValve",
+            "directions": 4
+        },
+        {
+            "name": "pumpManualValve",
+            "directions": 4
+        },
+        {
+            "name": "pumpManualValveOn",
+            "directions": 4
+        },
+        {
+            "name": "pumpSignalValve",
+            "directions": 4
+        },
+        {
+            "name": "pumpSignalValveOn",
+            "directions": 4
+        },
+        {
+            "name": "pumpPassiveGate",
+            "directions": 4
+        },
+        {
+            "name": "pumpPassiveGateOn",
+            "directions": 4
+        },
+        {
+            "name": "pumpPressure",
+            "directions": 4
+        },
+        {
+            "name": "pumpPressureOn",
+            "directions": 4,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
+        },
+        {
+            "name": "pumpVolume",
+            "directions": 4
+        },
+        {
+            "name": "pumpVolumeOn",
+            "directions": 4,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
+        },
+        {
+            "name": "pumpVolumeBlocked",
+            "directions": 4,
+            "delays": [
+                [
+                    1.0,
+                    1.0
+                ],
+                [
+                    1.0,
+                    1.0
+                ],
+                [
+                    1.0,
+                    1.0
+                ],
+                [
+                    1.0,
+                    1.0
+                ]
+            ]
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpDigitalValve.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpDigitalValve.png
new file mode 100644 (file)
index 0000000..ec8e261
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpDigitalValve.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValve.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValve.png
new file mode 100644 (file)
index 0000000..2bae097
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValve.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValveOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValveOn.png
new file mode 100644 (file)
index 0000000..f889124
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValveOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGate.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGate.png
new file mode 100644 (file)
index 0000000..0d20549
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGate.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGateOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGateOn.png
new file mode 100644 (file)
index 0000000..e899d0e
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGateOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressure.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressure.png
new file mode 100644 (file)
index 0000000..3a634fc
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressure.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressureOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressureOn.png
new file mode 100644 (file)
index 0000000..117ff9c
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressureOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValve.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValve.png
new file mode 100644 (file)
index 0000000..53656aa
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValve.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValveOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValveOn.png
new file mode 100644 (file)
index 0000000..a2549e2
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValveOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolume.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolume.png
new file mode 100644 (file)
index 0000000..55708b3
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolume.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeBlocked.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeBlocked.png
new file mode 100644 (file)
index 0000000..bf41bf2
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeBlocked.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeOn.png
new file mode 100644 (file)
index 0000000..6a5efbf
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/meta.json
new file mode 100644 (file)
index 0000000..ef75896
--- /dev/null
@@ -0,0 +1,157 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da. Signal valve is a digital valve modified by deltanedas. Manual valve modified by Deerstop at https://github.com/space-wizards/space-station-14/pull/34378. Modified by chromiumboy.",
+    "states": [
+        {
+            "name": "pumpDigitalValve",
+            "directions": 4
+        },
+        {
+            "name": "pumpManualValve",
+            "directions": 4
+        },
+        {
+            "name": "pumpManualValveOn",
+            "directions": 4
+        },
+        {
+            "name": "pumpSignalValve",
+            "directions": 4
+        },
+        {
+            "name": "pumpSignalValveOn",
+            "directions": 4
+        },
+        {
+            "name": "pumpPassiveGate",
+            "directions": 4
+        },
+        {
+            "name": "pumpPassiveGateOn",
+            "directions": 4
+        },
+        {
+            "name": "pumpPressure",
+            "directions": 4
+        },
+        {
+            "name": "pumpPressureOn",
+            "directions": 4,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
+        },
+        {
+            "name": "pumpVolume",
+            "directions": 4
+        },
+        {
+            "name": "pumpVolumeOn",
+            "directions": 4,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ],
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
+        },
+        {
+            "name": "pumpVolumeBlocked",
+            "directions": 4,
+            "delays": [
+                [
+                    1.0,
+                    1.0
+                ],
+                [
+                    1.0,
+                    1.0
+                ],
+                [
+                    1.0,
+                    1.0
+                ],
+                [
+                    1.0,
+                    1.0
+                ]
+            ]
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpDigitalValve.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpDigitalValve.png
new file mode 100644 (file)
index 0000000..4b43b43
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpDigitalValve.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValve.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValve.png
new file mode 100644 (file)
index 0000000..c83d71f
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValve.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValveOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValveOn.png
new file mode 100644 (file)
index 0000000..2adedbc
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValveOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGate.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGate.png
new file mode 100644 (file)
index 0000000..668c626
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGate.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGateOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGateOn.png
new file mode 100644 (file)
index 0000000..38ff927
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGateOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressure.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressure.png
new file mode 100644 (file)
index 0000000..cb5286e
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressure.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressureOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressureOn.png
new file mode 100644 (file)
index 0000000..114ed9a
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressureOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValve.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValve.png
new file mode 100644 (file)
index 0000000..ba0a3ed
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValve.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValveOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValveOn.png
new file mode 100644 (file)
index 0000000..181c6f2
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValveOn.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolume.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolume.png
new file mode 100644 (file)
index 0000000..0e9f52f
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolume.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeBlocked.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeBlocked.png
new file mode 100644 (file)
index 0000000..0d267ff
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeBlocked.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeOn.png b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeOn.png
new file mode 100644 (file)
index 0000000..85e33e7
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeOn.png differ
index 4cbb72e1ac97a31f4775cde18d899ce6d941219a..3ba53e431c376e99ef267fff9fe4dd2a63c34fcb 100644 (file)
@@ -1,38 +1,67 @@
 {
-    "version":1,
-    "size":{"x":32,"y":32},
-    "copyright":"Base sprites taken from tgstation, splitted to display on two layers (machinebody/panel) by Menshin, for SS14",
-    "license":"CC-BY-SA-3.0",
-    "states":[
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "copyright": "Base sprites taken from tgstation, splitted to display on two layers (machinebody/panel) by Menshin, for SS14, edited by chromiumboy",
+    "license": "CC-BY-SA-3.0",
+    "states": [
         {
-            "name":"freezerOff",
-            "directions":1
+            "name": "freezerOff",
+            "directions": 1
         },
         {
-            "name":"freezerPanelOpen",
-            "directions":1
+            "name": "freezerPanelOpen",
+            "directions": 1
         },
         {
-            "name":"freezerOn",
-            "directions":1,
-            "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] ]
+            "name": "freezerOn",
+            "directions": 1,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
         },
         {
-            "name":"heaterOff",
-            "directions":1
+            "name": "heaterOff",
+            "directions": 1
         },
         {
-            "name":"heaterPanelOpen",
-            "directions":1
+            "name": "heaterPanelOpen",
+            "directions": 1
         },
         {
-            "name":"heaterOn",
-            "directions":1,
-            "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] ]
+            "name": "heaterOn",
+            "directions": 1,
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
         },
         {
-            "name":"pipe",
-            "directions":4
+            "name": "pipe",
+            "directions": 4
         }
     ]
-}
\ No newline at end of file
+}
index 620ba905bea43a0cb2a7ae8d2c2647e6ff9ec5f9..e0209a7bc8967f8f7d89ebbe4d292f5f2aa70b0b 100644 (file)
Binary files a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/pipe.png and b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/pipe.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/meta.json
new file mode 100644 (file)
index 0000000..f8a6455
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "copyright": "Base sprites taken from tgstation, splitted to display on two layers (machinebody/panel) by Menshin, for SS14, edited by chromiumboy",
+    "license": "CC-BY-SA-3.0",
+    "states": [
+        {
+            "name": "pipe",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/pipe.png b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/pipe.png
new file mode 100644 (file)
index 0000000..cb6fc36
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/pipe.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/meta.json
new file mode 100644 (file)
index 0000000..f8a6455
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "version": 1,
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "copyright": "Base sprites taken from tgstation, splitted to display on two layers (machinebody/panel) by Menshin, for SS14, edited by chromiumboy",
+    "license": "CC-BY-SA-3.0",
+    "states": [
+        {
+            "name": "pipe",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/pipe.png b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/pipe.png
new file mode 100644 (file)
index 0000000..4a52081
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/pipe.png differ