From 45012cbe1d9a691da868c2a1096ab6e7d3b1a7d5 Mon Sep 17 00:00:00 2001 From: chromiumboy <50505512+chromiumboy@users.noreply.github.com> Date: Mon, 2 Jun 2025 00:01:43 -0500 Subject: [PATCH] Layering for atmospheric pipes (#36124) Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Co-authored-by: Kevin Zheng --- Content.Client/Atmos/AlignAtmosPipeLayers.cs | 203 ++++++++++++++ .../AtmosMonitoringConsoleNavMapControl.cs | 48 ++-- .../Consoles/AtmosMonitoringConsoleSystem.cs | 4 +- .../AtmosMonitoringConsoleWindow.xaml.cs | 9 +- .../AtmosPipeAppearanceSystem.cs | 74 +++-- .../EntitySystems/AtmosPipeLayersSystem.cs | 56 ++++ .../Atmos/UI/GasAnalyzerWindow.xaml.cs | 1 + .../ConstructionPlacementHijack.cs | 5 +- .../Consoles/AtmosMonitoringConsoleSystem.cs | 36 ++- .../EntitySystems/AtmosPipeLayersSystem.cs | 77 +++++ .../PipeRestrictOverlapSystem.cs | 15 +- .../Components/GasPipeManifoldComponent.cs | 11 + .../AtmosPipeAppearanceSystem.cs | 43 ++- .../EntitySystems/GasPipeManifoldSystem.cs | 68 +++++ .../NodeContainer/Nodes/PipeNode.cs | 13 +- .../Components/AtmosPipeLayersComponent.cs | 122 ++++++++ .../Components/PipeAppearanceComponent.cs | 6 +- .../AtmosMonitoringConsoleComponent.cs | 34 ++- .../AtmosMonitoringConsoleDeviceComponent.cs | 12 +- .../SharedAtmosMonitoringConsoleSystem.cs | 18 +- .../SharedAtmosPipeAppearanceSystem.cs | 18 ++ .../SharedAtmosPipeLayersSystem.cs | 264 ++++++++++++++++++ .../Prototypes/ConstructionPrototype.cs | 6 + Content.Shared/DrawDepth/DrawDepth.cs | 8 +- .../Prototypes/NavMapBlipPrototype.cs | 13 + .../SubFloor/SharedSubFloorHideSystem.cs | 1 + Content.Shared/Verbs/VerbCategory.cs | 3 + .../Locale/en-US/atmos/atmos-pipe-layers.ftl | 10 + Resources/Locale/en-US/verbs/verb-system.ftl | 1 + .../Machines/Computers/nav_map_blips.yml | 33 ++- .../Piping/Atmospherics/alt_layers.yml | 133 +++++++++ .../Structures/Piping/Atmospherics/binary.yml | 26 +- .../Piping/Atmospherics/gas_pipe_sensor.yml | 7 +- .../Structures/Piping/Atmospherics/pipes.yml | 152 ++++++++-- .../Structures/Piping/Atmospherics/unary.yml | 25 +- .../Graphs/utilities/atmos_pipes.yml | 242 ++++++++++++++++ .../Recipes/Construction/utilities.yml | 177 +++++++++++- .../Interface/NavMap/attributions.yml | 10 + .../NavMap/beveled_rectangle_east_west.png | Bin 0 -> 390 bytes .../beveled_rectangle_east_west.png.yml | 2 + .../NavMap/beveled_rectangle_north_south.png | Bin 0 -> 394 bytes .../beveled_rectangle_north_south.png.yml | 2 + .../Interface/VerbIcons/ATTRIBUTION.txt | 3 + .../Interface/VerbIcons/screwdriver.png | Bin 0 -> 713 bytes .../Interface/VerbIcons/screwdriver.png.yml | 2 + .../Atmospherics/condenser.rsi/meta.json | 47 ++-- .../Atmospherics/condenser.rsi/pipe.png | Bin 344 -> 279 bytes .../Atmospherics/condenser_alt1.rsi/meta.json | 15 + .../Atmospherics/condenser_alt1.rsi/pipe.png | Bin 0 -> 571 bytes .../Atmospherics/condenser_alt2.rsi/meta.json | 15 + .../Atmospherics/condenser_alt2.rsi/pipe.png | Bin 0 -> 363 bytes .../Atmospherics/gas_pipe_sensor.rsi/base.png | Bin 248 -> 3428 bytes .../gas_pipe_sensor.rsi/lights.png | Bin 183 -> 2813 bytes .../gas_pipe_sensor.rsi/meta.json | 20 +- .../gas_pipe_sensor_alt1.rsi/base.png | Bin 0 -> 621 bytes .../gas_pipe_sensor_alt1.rsi/blank.png | Bin 0 -> 83 bytes .../gas_pipe_sensor_alt1.rsi/icon.png | Bin 0 -> 523 bytes .../gas_pipe_sensor_alt1.rsi/lights.png | Bin 0 -> 393 bytes .../gas_pipe_sensor_alt1.rsi/meta.json | 43 +++ .../gas_pipe_sensor_alt2.rsi/base.png | Bin 0 -> 621 bytes .../gas_pipe_sensor_alt2.rsi/blank.png | Bin 0 -> 83 bytes .../gas_pipe_sensor_alt2.rsi/icon.png | Bin 0 -> 523 bytes .../gas_pipe_sensor_alt2.rsi/lights.png | Bin 0 -> 398 bytes .../gas_pipe_sensor_alt2.rsi/meta.json | 43 +++ .../hellfirethermomachine.rsi/meta.json | 71 +++-- .../hellfirethermomachine.rsi/pipe.png | Bin 321 -> 307 bytes .../Atmospherics/manifold.rsi/meta.json | 30 ++ .../manifold.rsi/pipeConnector.png | Bin 0 -> 457 bytes .../manifold.rsi/pipeConnector_alt1.png | Bin 0 -> 458 bytes .../manifold.rsi/pipeConnector_alt2.png | Bin 0 -> 455 bytes .../manifold.rsi/pipeManifold.png | Bin 0 -> 8965 bytes .../manifold.rsi/storageManifold.png | Bin 0 -> 2339 bytes .../Piping/Atmospherics/pipe.rsi/meta.json | 181 ++++++------ .../pipe.rsi/pipeBinaryConnectors.png | Bin 0 -> 3619 bytes .../pipe.rsi/pipeUnaryConnectors.png | Bin 0 -> 2417 bytes .../Atmospherics/pipe.rsi/storageBend.png | Bin 449 -> 270 bytes .../Atmospherics/pipe.rsi/storageFourway.png | Bin 0 -> 2545 bytes .../Atmospherics/pipe.rsi/storageHalf.png | Bin 0 -> 1702 bytes .../Atmospherics/pipe.rsi/storageStraight.png | Bin 503 -> 305 bytes .../pipe.rsi/storageTJunction.png | Bin 509 -> 333 bytes .../Atmospherics/pipe_alt1.rsi/meta.json | 51 ++++ .../Atmospherics/pipe_alt1.rsi/pipeBend.png | Bin 0 -> 912 bytes .../pipe_alt1.rsi/pipeBinaryConnectors.png | Bin 0 -> 788 bytes .../Atmospherics/pipe_alt1.rsi/pipeBroken.png | Bin 0 -> 643 bytes .../pipe_alt1.rsi/pipeConnector.png | Bin 0 -> 206 bytes .../pipe_alt1.rsi/pipeFourway.png | Bin 0 -> 911 bytes .../Atmospherics/pipe_alt1.rsi/pipeHalf.png | Bin 0 -> 540 bytes .../pipe_alt1.rsi/pipeStraight.png | Bin 0 -> 721 bytes .../pipe_alt1.rsi/pipeTJunction.png | Bin 0 -> 1179 bytes .../pipe_alt1.rsi/pipeTrinaryConnectors.png | Bin 0 -> 972 bytes .../pipe_alt1.rsi/pipeUnaryConnectors.png | Bin 0 -> 690 bytes .../Atmospherics/pipe_alt2.rsi/meta.json | 51 ++++ .../Atmospherics/pipe_alt2.rsi/pipeBend.png | Bin 0 -> 890 bytes .../pipe_alt2.rsi/pipeBinaryConnectors.png | Bin 0 -> 774 bytes .../Atmospherics/pipe_alt2.rsi/pipeBroken.png | Bin 0 -> 643 bytes .../pipe_alt2.rsi/pipeConnector.png | Bin 0 -> 207 bytes .../pipe_alt2.rsi/pipeFourway.png | Bin 0 -> 877 bytes .../Atmospherics/pipe_alt2.rsi/pipeHalf.png | Bin 0 -> 545 bytes .../pipe_alt2.rsi/pipeStraight.png | Bin 0 -> 719 bytes .../pipe_alt2.rsi/pipeTJunction.png | Bin 0 -> 1190 bytes .../pipe_alt2.rsi/pipeTrinaryConnectors.png | Bin 0 -> 913 bytes .../pipe_alt2.rsi/pipeUnaryConnectors.png | Bin 0 -> 694 bytes .../Atmospherics/pump_alt1.rsi/meta.json | 157 +++++++++++ .../pump_alt1.rsi/pumpDigitalValve.png | Bin 0 -> 443 bytes .../pump_alt1.rsi/pumpManualValve.png | Bin 0 -> 533 bytes .../pump_alt1.rsi/pumpManualValveOn.png | Bin 0 -> 545 bytes .../pump_alt1.rsi/pumpPassiveGate.png | Bin 0 -> 943 bytes .../pump_alt1.rsi/pumpPassiveGateOn.png | Bin 0 -> 138 bytes .../pump_alt1.rsi/pumpPressure.png | Bin 0 -> 1350 bytes .../pump_alt1.rsi/pumpPressureOn.png | Bin 0 -> 1947 bytes .../pump_alt1.rsi/pumpSignalValve.png | Bin 0 -> 470 bytes .../pump_alt1.rsi/pumpSignalValveOn.png | Bin 0 -> 469 bytes .../Atmospherics/pump_alt1.rsi/pumpVolume.png | Bin 0 -> 697 bytes .../pump_alt1.rsi/pumpVolumeBlocked.png | Bin 0 -> 967 bytes .../pump_alt1.rsi/pumpVolumeOn.png | Bin 0 -> 1878 bytes .../Atmospherics/pump_alt2.rsi/meta.json | 157 +++++++++++ .../pump_alt2.rsi/pumpDigitalValve.png | Bin 0 -> 446 bytes .../pump_alt2.rsi/pumpManualValve.png | Bin 0 -> 557 bytes .../pump_alt2.rsi/pumpManualValveOn.png | Bin 0 -> 553 bytes .../pump_alt2.rsi/pumpPassiveGate.png | Bin 0 -> 944 bytes .../pump_alt2.rsi/pumpPassiveGateOn.png | Bin 0 -> 138 bytes .../pump_alt2.rsi/pumpPressure.png | Bin 0 -> 1347 bytes .../pump_alt2.rsi/pumpPressureOn.png | Bin 0 -> 1957 bytes .../pump_alt2.rsi/pumpSignalValve.png | Bin 0 -> 474 bytes .../pump_alt2.rsi/pumpSignalValveOn.png | Bin 0 -> 472 bytes .../Atmospherics/pump_alt2.rsi/pumpVolume.png | Bin 0 -> 699 bytes .../pump_alt2.rsi/pumpVolumeBlocked.png | Bin 0 -> 989 bytes .../pump_alt2.rsi/pumpVolumeOn.png | Bin 0 -> 1873 bytes .../Atmospherics/thermomachine.rsi/meta.json | 73 +++-- .../Atmospherics/thermomachine.rsi/pipe.png | Bin 321 -> 307 bytes .../thermomachine_alt1.rsi/meta.json | 15 + .../thermomachine_alt1.rsi/pipe.png | Bin 0 -> 311 bytes .../thermomachine_alt2.rsi/meta.json | 15 + .../thermomachine_alt2.rsi/pipe.png | Bin 0 -> 309 bytes 134 files changed, 2671 insertions(+), 306 deletions(-) create mode 100644 Content.Client/Atmos/AlignAtmosPipeLayers.cs create mode 100644 Content.Client/Atmos/EntitySystems/AtmosPipeLayersSystem.cs create mode 100644 Content.Server/Atmos/EntitySystems/AtmosPipeLayersSystem.cs create mode 100644 Content.Server/Atmos/Piping/Components/GasPipeManifoldComponent.cs create mode 100644 Content.Server/Atmos/Piping/EntitySystems/GasPipeManifoldSystem.cs create mode 100644 Content.Shared/Atmos/Components/AtmosPipeLayersComponent.cs create mode 100644 Content.Shared/Atmos/EntitySystems/SharedAtmosPipeAppearanceSystem.cs create mode 100644 Content.Shared/Atmos/EntitySystems/SharedAtmosPipeLayersSystem.cs create mode 100644 Resources/Locale/en-US/atmos/atmos-pipe-layers.ftl create mode 100644 Resources/Prototypes/Entities/Structures/Piping/Atmospherics/alt_layers.yml create mode 100644 Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png create mode 100644 Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png.yml create mode 100644 Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png create mode 100644 Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png.yml create mode 100644 Resources/Textures/Interface/VerbIcons/screwdriver.png create mode 100644 Resources/Textures/Interface/VerbIcons/screwdriver.png.yml create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/condenser_alt1.rsi/pipe.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/condenser_alt2.rsi/pipe.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/base.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/blank.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/icon.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/lights.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt1.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/base.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/blank.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/icon.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/lights.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt1.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeConnector_alt2.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/pipeManifold.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/storageManifold.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBinaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeUnaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageFourway.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageHalf.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBend.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBinaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeBroken.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeConnector.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeFourway.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeHalf.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeStraight.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTJunction.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeTrinaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt1.rsi/pipeUnaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBend.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBinaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeBroken.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeConnector.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeFourway.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeHalf.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeStraight.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTJunction.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeTrinaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/pipeUnaryConnectors.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpDigitalValve.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValve.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpManualValveOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGate.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPassiveGateOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressure.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpPressureOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValve.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpSignalValveOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolume.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeBlocked.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/pumpVolumeOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpDigitalValve.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValve.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpManualValveOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGate.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPassiveGateOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressure.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpPressureOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValve.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpSignalValveOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolume.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeBlocked.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/pump_alt2.rsi/pumpVolumeOn.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/pipe.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/meta.json create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/pipe.png diff --git a/Content.Client/Atmos/AlignAtmosPipeLayers.cs b/Content.Client/Atmos/AlignAtmosPipeLayers.cs new file mode 100644 index 0000000000..1bf3310a6c --- /dev/null +++ b/Content.Client/Atmos/AlignAtmosPipeLayers.cs @@ -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; + +/// +/// Allows users to place atmos pipes on different layers depending on how the mouse cursor is positioned within a grid tile. +/// +/// +/// This placement mode is not on the engine because it is content specific. +/// +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(); + _transformSystem = _entityManager.System(); + _pipeLayersSystem = _entityManager.System(); + _spriteSystem = _entityManager.System(); + } + + /// + public override void Render(in OverlayDrawArgs args) + { + var gridUid = _entityManager.System().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); + } + + /// + 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(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(pManager.CurrentPermission.EntityType, out var currentProto)) + return; + + if (!currentProto.TryGetComponent(out var atmosPipeLayers, _entityManager.ComponentFactory)) + return; + + if (!_pipeLayersSystem.TryGetAlternativePrototype(atmosPipeLayers, layer, out var newProtoId)) + return; + + if (_protoManager.TryIndex(newProtoId, out var newProto)) + { + // Update the placed prototype + pManager.CurrentPermission.EntityType = newProtoId; + + // Update the appearance of the ghost sprite + if (newProto.TryGetComponent(out var sprite, _entityManager.ComponentFactory)) + { + var textures = new List(); + + 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); + } +} diff --git a/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleNavMapControl.cs b/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleNavMapControl.cs index c23ebb6435..20902722ff 100644 --- a/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleNavMapControl.cs +++ b/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleNavMapControl.cs @@ -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(); - 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; diff --git a/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs b/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs index bfbb05d2ab..6a4967e4a4 100644 --- a/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs +++ b/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs @@ -15,7 +15,7 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS private void OnHandleState(EntityUid uid, AtmosMonitoringConsoleComponent component, ref ComponentHandleState args) { - Dictionary> modifiedChunks; + Dictionary> modifiedChunks; Dictionary 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(chunk); component.AtmosPipeChunks[origin] = newChunk; } diff --git a/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleWindow.xaml.cs b/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleWindow.xaml.cs index e25c3af9e9..1a084ea73b 100644 --- a/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleWindow.xaml.cs +++ b/Content.Client/Atmos/Consoles/AtmosMonitoringConsoleWindow.xaml.cs @@ -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 _navMapConsoleProtoId = "NavMapConsole"; private ProtoId _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(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; } diff --git a/Content.Client/Atmos/EntitySystems/AtmosPipeAppearanceSystem.cs b/Content.Client/Atmos/EntitySystems/AtmosPipeAppearanceSystem.cs index 2029cb9be5..1a12c3967b 100644 --- a/Content.Client/Atmos/EntitySystems/AtmosPipeAppearanceSystem.cs +++ b/Content.Client/Atmos/EntitySystems/AtmosPipeAppearanceSystem.cs @@ -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()) { - 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 entity) + private void HideAllPipeConnection(Entity entity, AtmosPipeLayersComponent? atmosPipeLayers, int numberOfPipeLayers) { var sprite = entity.Comp; foreach (var layerKey in Enum.GetValues()) { - if (!_sprite.LayerMapTryGet(entity.AsNullable(), layerKey, out var key, false)) - continue; + for (byte i = 0; i < numberOfPipeLayers; i++) + { + var layerName = layerKey.ToString() + i.ToString(); - var layer = sprite[key]; - layer.Visible = false; + if (!_sprite.LayerMapTryGet(entity.AsNullable(), layerName, out var key, false)) + continue; + + var layer = sprite[key]; + layer.Visible = false; + } } } @@ -61,33 +73,45 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem return; } - if (!_appearance.TryGetData(uid, PipeVisuals.VisualState, out var worldConnectedDirections, args.Component)) + var numberOfPipeLayers = GetNumberOfPipeLayers(uid, out var atmosPipeLayers); + + if (!_appearance.TryGetData(uid, PipeVisuals.VisualState, out var worldConnectedDirections, args.Component)) { - HideAllPipeConnection((uid, args.Sprite)); + HideAllPipeConnection((uid, args.Sprite), atmosPipeLayers, numberOfPipeLayers); return; } if (!_appearance.TryGetData(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()) + 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))); - var layer = args.Sprite[key]; - var dir = (PipeDirection)layerKey; - var visible = connectedDirections.HasDirection(dir); + // Transform the connected directions to local-coordinates + var connectedDirections = pipeLayerConnectedDirections.RotatePipeDirection(-Transform(uid).LocalRotation); - layer.Visible &= visible; + foreach (var layerKey in Enum.GetValues()) + { + var layerName = layerKey.ToString() + i.ToString(); - if (!visible) - continue; + if (!_sprite.LayerMapTryGet((uid, args.Sprite), layerName, out var key, false)) + continue; - layer.Color = color; + var layer = args.Sprite[key]; + var dir = (PipeDirection)layerKey; + var visible = connectedDirections.HasDirection(dir); + + layer.Visible &= visible; + + if (!visible) + continue; + + layer.Color = color; + } } } diff --git a/Content.Client/Atmos/EntitySystems/AtmosPipeLayersSystem.cs b/Content.Client/Atmos/EntitySystems/AtmosPipeLayersSystem.cs new file mode 100644 index 0000000000..f560e0b833 --- /dev/null +++ b/Content.Client/Atmos/EntitySystems/AtmosPipeLayersSystem.cs @@ -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; + +/// +/// The system responsible for updating the appearance of layered gas pipe +/// +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(OnAppearanceChange); + } + + private void OnAppearanceChange(Entity ent, ref AppearanceChangeEvent ev) + { + if (!TryComp(ent, out var sprite)) + return; + + if (_appearance.TryGetData(ent, AtmosPipeLayerVisuals.Sprite, out var spriteRsi) && + _resourceCache.TryGetResource(SpriteSpecifierSerializer.TextureRoot / spriteRsi, out RSIResource? resource)) + { + _sprite.SetBaseRsi((ent, sprite), resource.RSI); + } + + if (_appearance.TryGetData>(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); + } +} diff --git a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs index bb24da44e1..e280523e43 100644 --- a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs @@ -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); diff --git a/Content.Client/Construction/ConstructionPlacementHijack.cs b/Content.Client/Construction/ConstructionPlacementHijack.cs index e6a8e0f1f0..79112a8f8e 100644 --- a/Content.Client/Construction/ConstructionPlacementHijack.cs +++ b/Content.Client/Construction/ConstructionPlacementHijack.cs @@ -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) diff --git a/Content.Server/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs b/Content.Server/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs index 532ba04d29..a7debbdc80 100644 --- a/Content.Server/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs +++ b/Content.Server/Atmos/Consoles/AtmosMonitoringConsoleSystem.cs @@ -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(uid, out var atmosPipeColor) ? atmosPipeColor.Color : Color.White; + var layer = TryComp(uid, out var atmosPipeLayers) ? atmosPipeLayers.CurrentPipeLayer : AtmosPipeLayer.Primary; - if (!TryGettingFirstPipeNode(uid, out var _, out var netId)) - netId = -1; - - var color = Color.White; - - if (TryComp(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(ent, out var entNodeContainer)) continue; - UpdateAtmosPipeChunk(ent, entNodeContainer, entAtmosPipeColor, tileIdx, ref chunk); + var showAbsentConnections = TryComp(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 index 0000000000..0cb804bdbd --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/AtmosPipeLayersSystem.cs @@ -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; + +/// +/// The system responsible for checking and adjusting the connection layering of gas pipes +/// +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(OnInit); + } + + private void OnInit(Entity ent, ref ComponentInit args) + { + SetPipeLayer(ent, ent.Comp.CurrentPipeLayer); + } + + /// + public override void SetPipeLayer(Entity ent, AtmosPipeLayer layer, EntityUid? user = null, EntityUid? used = null) + { + if (ent.Comp.PipeLayersLocked) + return; + + base.SetPipeLayer(ent, layer); + + if (!TryComp(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(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); + } +} diff --git a/Content.Server/Atmos/EntitySystems/PipeRestrictOverlapSystem.cs b/Content.Server/Atmos/EntitySystems/PipeRestrictOverlapSystem.cs index f64aff47f4..351a754105 100644 --- a/Content.Server/Atmos/EntitySystems/PipeRestrictOverlapSystem.cs +++ b/Content.Server/Atmos/EntitySystems/PipeRestrictOverlapSystem.cs @@ -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 ent, Entity 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 GetAllDirections(Entity pipe) + IEnumerable<(PipeDirection, AtmosPipeLayer)> GetAllDirectionsAndLayers(Entity 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 index 0000000000..ded2ffcb07 --- /dev/null +++ b/Content.Server/Atmos/Piping/Components/GasPipeManifoldComponent.cs @@ -0,0 +1,11 @@ +namespace Content.Server.Atmos.Piping.Components; + +[RegisterComponent] +public sealed partial class GasPipeManifoldComponent : Component +{ + [DataField("inlets")] + public HashSet InletNames { get; set; } = new() { "south0", "south1", "south2" }; + + [DataField("outlets")] + public HashSet OutletNames { get; set; } = new() { "north0", "north1", "north2" }; +} diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs index 3e14fea2d8..17f9d4652f 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs @@ -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(xform.GridUid, out var grid)) return; + var numberOfPipeLayers = GetNumberOfPipeLayers(uid, out var atmosPipeLayers); + // get connected entities var anyPipeNodes = false; - HashSet 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) - { - // 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 connectedDirections = new PipeDirection[numberOfPipeLayers]; + Array.Fill(connectedDirections, PipeDirection.None); - netConnectedDirections |= (otherTile - tile) switch + var tile = _map.TileIndicesFor(xform.GridUid.Value, grid, xform.Coordinates); + + foreach (var (neighbour, pipeLayer) in connected) + { + var pipeIndex = (int)pipeLayer; + + if (pipeIndex >= numberOfPipeLayers) + continue; + + var otherTile = _map.TileIndicesFor(xform.GridUid.Value, grid, Transform(neighbour).Coordinates); + var pipeLayerDirections = connectedDirections[pipeIndex]; + + 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 index 0000000000..bb7678d28d --- /dev/null +++ b/Content.Server/Atmos/Piping/EntitySystems/GasPipeManifoldSystem.cs @@ -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(OnCompInit); + SubscribeLocalEvent(OnAnalyzed); + } + + private void OnCompInit(Entity ent, ref ComponentInit args) + { + if (!TryComp(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 ent, ref GasAnalyzerScanEvent args) + { + // All inlets and outlets have the same gas mixture + + args.GasMixtures = new List<(string, GasMixture?)>(); + + if (!TryComp(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; + } + } +} diff --git a/Content.Server/NodeContainer/Nodes/PipeNode.cs b/Content.Server/NodeContainer/Nodes/PipeNode.cs index d30d3b1777..3a76666a2c 100644 --- a/Content.Server/NodeContainer/Nodes/PipeNode.cs +++ b/Content.Server/NodeContainer/Nodes/PipeNode.cs @@ -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 { /// /// Connects with other s whose - /// correctly correspond. + /// and correctly correspond. /// [DataDefinition] [Virtual] @@ -24,6 +22,12 @@ namespace Content.Server.NodeContainer.Nodes [DataField("pipeDirection")] public PipeDirection OriginalPipeDirection; + /// + /// The *current* layer to which the pipe node is assigned. + /// + [DataField("pipeLayer")] + public AtmosPipeLayer CurrentPipeLayer = AtmosPipeLayer.Primary; + /// /// 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 index 0000000000..3081bb8d01 --- /dev/null +++ b/Content.Shared/Atmos/Components/AtmosPipeLayersComponent.cs @@ -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; + +/// +/// 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. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedAtmosPipeLayersSystem))] +public sealed partial class AtmosPipeLayersComponent : Component +{ + /// + /// The number of pipe layers this entity supports. + /// Must be equal to or less than the number of values + /// in . + /// + [DataField] + public byte NumberOfPipeLayers = 3; + + /// + /// Determines which layer the pipe is currently assigned. + /// Only pipes on the same layer can connect with each other. + /// + [DataField("pipeLayer"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly)] + public AtmosPipeLayer CurrentPipeLayer = AtmosPipeLayer.Primary; + + /// + /// 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 + /// instead. + /// + /// + /// If the dictionary is not empty there should be an entry for each atmos pipe layer. + /// + [DataField] + public Dictionary SpriteRsiPaths = new(); + + /// + /// 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 + /// instead. + /// + /// + /// If an dictionary is not empty there should be an entry for each pipe layer. + /// + [DataField] + public Dictionary> SpriteLayersRsiPaths = new(); + + /// + /// Entity prototypes that will be used to replace the current one when using + /// position dependent entity placement via AlignAtmosPipeLayers. + /// + /// + /// If the dictionary is not empty there should be an entry for each atmos pipe layer. + /// + [DataField] + public Dictionary AlternativePrototypes = new(); + + /// + /// The pipe layers of this entity cannot be changed when this value is true. + /// + [DataField] + public bool PipeLayersLocked; + + /// + /// Tool quality required to cause a pipe to change layers + /// + [DataField] + public ProtoId Tool = "Screwing"; + + /// + /// The base delay to use for changing layers. + /// + [DataField] + public float Delay = 1f; +} + +/// +/// Raised when a player attempts to cycle a pipe to its next layer +/// +[Serializable, NetSerializable] +public sealed partial class TrySetNextPipeLayerCompletedEvent : SimpleDoAfterEvent; + +/// +/// Raised when a player attempts to set a pipe a specified layer +/// +[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, +} diff --git a/Content.Shared/Atmos/Components/PipeAppearanceComponent.cs b/Content.Shared/Atmos/Components/PipeAppearanceComponent.cs index b5f979c482..f8599148ea 100644 --- a/Content.Shared/Atmos/Components/PipeAppearanceComponent.cs +++ b/Content.Shared/Atmos/Components/PipeAppearanceComponent.cs @@ -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")]; } diff --git a/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleComponent.cs b/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleComponent.cs index 2ac0d2a9af..d01fb4e8bc 100644 --- a/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleComponent.cs +++ b/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleComponent.cs @@ -64,10 +64,10 @@ public struct AtmosPipeChunk(Vector2i origin) /// /// 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 /// [ViewVariables] - public Dictionary<(int, string), ulong> AtmosPipeData = new(); + public Dictionary AtmosPipeData = new(); /// /// The last game tick that the chunk was updated @@ -90,7 +90,7 @@ public struct AtmosDeviceNavMapData public NetCoordinates NetCoordinates; /// - /// The associated pipe network ID + /// The associated pipe network ID /// public int NetId = -1; @@ -109,10 +109,21 @@ public struct AtmosDeviceNavMapData /// public Color PipeColor; + /// + /// The pipe layer the entity is on + /// + public AtmosPipeLayer PipeLayer; + /// /// Populate the atmos monitoring console nav map with a single entity /// - public AtmosDeviceNavMapData(NetEntity netEntity, NetCoordinates netCoordinates, int netId, ProtoId navMapBlip, Direction direction, Color pipeColor) + public AtmosDeviceNavMapData(NetEntity netEntity, + NetCoordinates netCoordinates, + int netId, + ProtoId 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; /// - /// The associated pipe network ID + /// The associated pipe network ID /// public int NetId = -1; @@ -184,7 +196,7 @@ public struct AtmosMonitoringConsoleEntry public float TotalMolData; /// - /// Mol and percentage for all detected gases + /// Mol and percentage for all detected gases /// public Dictionary GasData = new(); @@ -216,6 +228,16 @@ public struct AtmosMonitoringConsoleEntry } } +/// +/// 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. +/// +/// The associated network ID. +/// The associated pipe layer. +/// The color of the pipe. +[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. diff --git a/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleDeviceComponent.cs b/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleDeviceComponent.cs index 50c3abcfca..a7b83fde48 100644 --- a/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleDeviceComponent.cs +++ b/Content.Shared/Atmos/Consoles/Components/AtmosMonitoringConsoleDeviceComponent.cs @@ -5,7 +5,7 @@ using Robust.Shared.Prototypes; namespace Content.Shared.Atmos.Components; /// -/// Entities with this component appear on the +/// Entities with this component appear on the /// nav maps of atmos monitoring consoles /// [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) /// - [DataField, ViewVariables] + [DataField] public ProtoId? NavMapBlip = null; + + /// + /// 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. + /// + [DataField] + public bool ShowAbsentConnections = true; } diff --git a/Content.Shared/Atmos/Consoles/SharedAtmosMonitoringConsoleSystem.cs b/Content.Shared/Atmos/Consoles/SharedAtmosMonitoringConsoleSystem.cs index e6dd455be7..7fe94efd84 100644 --- a/Content.Shared/Atmos/Consoles/SharedAtmosMonitoringConsoleSystem.cs +++ b/Content.Shared/Atmos/Consoles/SharedAtmosMonitoringConsoleSystem.cs @@ -15,7 +15,7 @@ public abstract class SharedAtmosMonitoringConsoleSystem : EntitySystem private void OnGetState(EntityUid uid, AtmosMonitoringConsoleComponent component, ref ComponentGetState args) { - Dictionary> chunks; + Dictionary> 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> chunks, + Dictionary> chunks, Dictionary atmosDevices) : ComponentState { - public Dictionary> Chunks = chunks; + public Dictionary> Chunks = chunks; public Dictionary AtmosDevices = atmosDevices; } [Serializable, NetSerializable] protected sealed class AtmosMonitoringConsoleDeltaState( - Dictionary> modifiedChunks, + Dictionary> modifiedChunks, Dictionary atmosDevices, HashSet allChunks) : ComponentState, IComponentDeltaState { - public Dictionary> ModifiedChunks = modifiedChunks; + public Dictionary> ModifiedChunks = modifiedChunks; public Dictionary AtmosDevices = atmosDevices; public HashSet 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(data); } state.AtmosDevices.Clear(); @@ -93,7 +93,7 @@ public abstract class SharedAtmosMonitoringConsoleSystem : EntitySystem public AtmosMonitoringConsoleState CreateNewFullState(AtmosMonitoringConsoleState state) { - var chunks = new Dictionary>(state.Chunks.Count); + var chunks = new Dictionary>(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(ModifiedChunks[index]); else - chunks[index] = new Dictionary<(int, string), ulong>(state.Chunks[index]); + chunks[index] = new Dictionary(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 index 0000000000..c6944ec2de --- /dev/null +++ b/Content.Shared/Atmos/EntitySystems/SharedAtmosPipeAppearanceSystem.cs @@ -0,0 +1,18 @@ +using Content.Shared.Atmos.Components; + +namespace Content.Shared.Atmos.EntitySystems; + +public abstract partial class SharedAtmosPipeAppearanceSystem : EntitySystem +{ + /// + /// Returns the max number of pipe layers supported by a entity. + /// + /// The entity being checked. + /// The entity's , if available. + /// Returns + /// if the entity has the component, or 1 if it does not. + 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 index 0000000000..ff88601330 --- /dev/null +++ b/Content.Shared/Atmos/EntitySystems/SharedAtmosPipeLayersSystem.cs @@ -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; + +/// +/// The system responsible for checking and adjusting the connection layering of gas pipes +/// +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(OnExamined); + SubscribeLocalEvent>(OnGetVerb); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnUseInHandEvent); + SubscribeLocalEvent(OnSetNextPipeLayerCompleted); + SubscribeLocalEvent(OnSettingPipeLayerCompleted); + } + + private void OnExamined(Entity 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 ent, ref GetVerbsEvent 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(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 ent, ref InteractUsingEvent args) + { + if (ent.Comp.NumberOfPipeLayers <= 1 || ent.Comp.PipeLayersLocked) + return; + + if (TryComp(ent, out var subFloorHide) && subFloorHide.IsUnderCover) + { + _popup.PopupPredicted(Loc.GetString("atmos-pipe-layers-component-cannot-adjust-pipes"), ent, args.User); + return; + } + + if (TryComp(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 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 ent, ref TrySetNextPipeLayerCompletedEvent args) + { + if (args.Cancelled) + return; + + SetNextPipeLayer(ent, args.User, args.Used); + } + + private void OnSettingPipeLayerCompleted(Entity ent, ref TrySettingPipeLayerCompletedEvent args) + { + if (args.Cancelled) + return; + + SetPipeLayer(ent, args.PipeLayer, args.User, args.Used); + } + + /// + /// Increments an entity's pipe layer by 1, wrapping around to 0 if the max pipe layer is reached + /// + /// The pipe entity + /// The player entity who adjusting the pipe layer + /// The tool used to adjust the pipe layer + public void SetNextPipeLayer(Entity ent, EntityUid? user = null, EntityUid? used = null) + { + var newLayer = ((int)ent.Comp.CurrentPipeLayer + 1) % ent.Comp.NumberOfPipeLayers; + SetPipeLayer(ent, (AtmosPipeLayer)newLayer, user, used); + } + + /// + /// Sets an entity's pipe layer to a specified value + /// + /// The pipe entity + /// The new layer value + /// The player entity who adjusting the pipe layer + /// The tool used to adjust the pipe layer + public virtual void SetPipeLayer(Entity 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(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(); + + 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); + } + } + + /// + /// Try to find an entity prototype associated with a specified . + /// + /// The with the alternative prototypes data. + /// The atmos pipe layer associated with the entity prototype. + /// The returned entity prototype. + /// True if there was an entity prototype associated with the layer. + public bool TryGetAlternativePrototype(AtmosPipeLayersComponent component, AtmosPipeLayer layer, out EntProtoId proto) + { + return component.AlternativePrototypes.TryGetValue(layer, out proto); + } + + /// + /// Checks a player entity's hands to see if they are holding a tool with a specified quality + /// + /// The player entity + /// The tool quality being checked for + /// A tool with the specified tool quality + /// True if an appropriate tool was found + private bool TryGetHeldTool(EntityUid user, ProtoId toolQuality, [NotNullWhen(true)] out Entity? heldTool) + { + heldTool = null; + + foreach (var heldItem in _hands.EnumerateHeld(user)) + { + if (TryComp(heldItem, out var tool) && + _tool.HasQuality(heldItem, toolQuality, tool)) + { + heldTool = new Entity(heldItem, tool); + return true; + } + } + + return false; + } + + private string GetPipeLayerName(AtmosPipeLayer layer) + { + return Loc.GetString("atmos-pipe-layers-component-layer-" + layer.ToString().ToLower()); + } +} diff --git a/Content.Shared/Construction/Prototypes/ConstructionPrototype.cs b/Content.Shared/Construction/Prototypes/ConstructionPrototype.cs index 0e1a50d9a2..cd38b22b9c 100644 --- a/Content.Shared/Construction/Prototypes/ConstructionPrototype.cs +++ b/Content.Shared/Construction/Prototypes/ConstructionPrototype.cs @@ -85,6 +85,12 @@ public sealed partial class ConstructionPrototype : IPrototype [DataField] public ProtoId? Mirror { get; private set; } + /// + /// Possible constructions to replace this one with as determined by the placement mode + /// + [DataField] + public ProtoId[] AlternativePrototypes = []; + public IReadOnlyList Conditions => _conditions; } diff --git a/Content.Shared/DrawDepth/DrawDepth.cs b/Content.Shared/DrawDepth/DrawDepth.cs index dbec886971..35fead5b3f 100644 --- a/Content.Shared/DrawDepth/DrawDepth.cs +++ b/Content.Shared/DrawDepth/DrawDepth.cs @@ -9,13 +9,15 @@ namespace Content.Shared.DrawDepth /// /// This is for sub-floors, the floors you see after prying off a tile. /// - 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 diff --git a/Content.Shared/Prototypes/NavMapBlipPrototype.cs b/Content.Shared/Prototypes/NavMapBlipPrototype.cs index 2fcb6c5ccb..dff9f50054 100644 --- a/Content.Shared/Prototypes/NavMapBlipPrototype.cs +++ b/Content.Shared/Prototypes/NavMapBlipPrototype.cs @@ -39,4 +39,17 @@ public sealed partial class NavMapBlipPrototype : IPrototype /// [DataField] public float Scale { get; private set; } = 1f; + + /// + /// Describes how the blip should be positioned. + /// It's up to the individual system to enforce this + /// + [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) } diff --git a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs index 812003aae8..c7edf01499 100644 --- a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs +++ b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs @@ -225,6 +225,7 @@ namespace Content.Shared.SubFloor ScannerRevealed, } + [Serializable, NetSerializable] public enum SubfloorLayers : byte { FirstLayer diff --git a/Content.Shared/Verbs/VerbCategory.cs b/Content.Shared/Verbs/VerbCategory.cs index 9b9197249a..418921d38e 100644 --- a/Content.Shared/Verbs/VerbCategory.cs +++ b/Content.Shared/Verbs/VerbCategory.cs @@ -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 index 0000000000..27491efb5e --- /dev/null +++ b/Resources/Locale/en-US/atmos/atmos-pipe-layers.ftl @@ -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 diff --git a/Resources/Locale/en-US/verbs/verb-system.ftl b/Resources/Locale/en-US/verbs/verb-system.ftl index 64104f796e..d52b43c9a7 100644 --- a/Resources/Locale/en-US/verbs/verb-system.ftl +++ b/Resources/Locale/en-US/verbs/verb-system.ftl @@ -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 diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/nav_map_blips.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/nav_map_blips.yml index bc51557186..93530976f7 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/nav_map_blips.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/nav_map_blips.yml @@ -13,21 +13,22 @@ 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 @@ -45,12 +47,23 @@ 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" \ No newline at end of file + - "/Textures/Interface/NavMap/beveled_hexagon.png" + +- type: navMapBlip + id: GasPipeManifold + scale: 0.9 + color: LightGray + texturePaths: + - "/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 index 0000000000..1f4ab085f1 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/alt_layers.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml index 33a8414961..88940f4882 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml @@ -22,6 +22,11 @@ !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 @@ -325,10 +330,12 @@ 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 @@ -363,10 +370,12 @@ 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: @@ -423,18 +432,24 @@ 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 @@ -494,6 +509,9 @@ map: [ "enum.PipeVisualLayers.Pipe" ] - state: heStraight map: [ "enum.SubfloorLayers.FirstLayer" ] + - type: AtmosPipeLayers + spriteRsiPaths: {} + numberOfPipeLayers: 1 - type: SubFloorHide visibleLayers: - enum.SubfloorLayers.FirstLayer diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/gas_pipe_sensor.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/gas_pipe_sensor.yml index 57574f7f7d..c70b33639e 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/gas_pipe_sensor.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/gas_pipe_sensor.yml @@ -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. @@ -18,6 +18,11 @@ - 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: diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml index 4d100d434e..6d9d596760 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml @@ -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 @@ -66,12 +66,26 @@ - 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: @@ -81,11 +95,21 @@ 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 @@ -95,6 +119,8 @@ parent: GasPipeBase id: GasPipeStraight suffix: Straight + placement: + mode: AlignAtmosPipeLayers components: - type: NodeContainer nodes: @@ -104,13 +130,17 @@ 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 @@ -132,6 +162,8 @@ parent: GasPipeBase id: GasPipeBend suffix: Bend + placement: + mode: AlignAtmosPipeLayers components: - type: NodeContainer nodes: @@ -143,11 +175,15 @@ 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 @@ -175,6 +211,8 @@ - type: entity parent: GasPipeBase id: GasPipeTJunction + placement: + mode: AlignAtmosPipeLayers suffix: TJunction components: - type: NodeContainer @@ -187,14 +225,15 @@ 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 @@ -216,6 +255,8 @@ parent: GasPipeBase id: GasPipeFourway suffix: Fourway + placement: + mode: AlignAtmosPipeLayers components: - type: Transform noRot: true @@ -229,15 +270,19 @@ 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 @@ -264,9 +309,13 @@ 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: @@ -279,3 +328,74 @@ 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 diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml index abb0ead4a0..612e144e53 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml @@ -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" ] @@ -134,7 +134,7 @@ 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" ] @@ -180,7 +180,7 @@ 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 @@ -189,6 +189,7 @@ shader: unshaded map: [ "enum.LightLayers.Unshaded" ] color: "#990000" + - type: Appearance - type: GenericVisualizer visuals: # toggle color of the unshaded light: @@ -196,7 +197,6 @@ enum.LightLayers.Unshaded: True: { color: "#5eff5e" } False: { color: "#990000" } - - type: Appearance - type: PipeColorVisuals - type: GasOutletInjector - type: Construction @@ -228,6 +228,12 @@ - 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: @@ -405,6 +411,7 @@ map: ["enum.SolutionContainerLayers.Fill"] visible: false - state: trans + - type: Appearance - type: GenericVisualizer visuals: enum.PowerDeviceVisuals.Powered: @@ -414,11 +421,16 @@ - 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 @@ -470,3 +482,4 @@ - type: GuideHelp guides: - GasCondensing + diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/atmos_pipes.yml b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/atmos_pipes.yml index 771c63ebd5..14d487fdb5 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/atmos_pipes.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/atmos_pipes.yml @@ -10,30 +10,96 @@ 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: @@ -50,6 +116,38 @@ - 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: @@ -66,6 +164,38 @@ - 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: @@ -82,6 +212,38 @@ - 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: @@ -98,6 +260,38 @@ - 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: @@ -114,6 +308,38 @@ - 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: @@ -129,3 +355,19 @@ 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 diff --git a/Resources/Prototypes/Recipes/Construction/utilities.yml b/Resources/Prototypes/Recipes/Construction/utilities.yml index 575ca3ae4e..67389f85af 100644 --- a/Resources/Prototypes/Recipes/Construction/utilities.yml +++ b/Resources/Prototypes/Recipes/Construction/utilities.yml @@ -281,8 +281,40 @@ 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 @@ -290,8 +322,40 @@ 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 @@ -299,8 +363,40 @@ 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 @@ -308,8 +404,40 @@ 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 @@ -317,6 +445,47 @@ 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 diff --git a/Resources/Textures/Interface/NavMap/attributions.yml b/Resources/Textures/Interface/NavMap/attributions.yml index f624c0f448..344b871ae9 100644 --- a/Resources/Textures/Interface/NavMap/attributions.yml +++ b/Resources/Textures/Interface/NavMap/attributions.yml @@ -43,6 +43,16 @@ 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 index 0000000000000000000000000000000000000000..9a972cb93916c97675631d62786311e2f5a26419 GIT binary patch literal 390 zcmV;10eSw3P) zJ#GRq5Jo?*(oydX=yHh^+#vUf5E8jUirfU{2GpsbL!w!P)>?)gd&izsi;SRxurz*> z3(J<~dB%T0CX>k|sA{RI->SOO|7WGDU#eQBF-;mAz%PLE!RxF5yc%OF04S1y&jEr1 zKv~!ItnZ`(Z$p)unJ3o-#zO>e+ZIjJjIRkioERgR8P-}nMIeL#W=7LAcv=R!u7h*# zIRdJR7$ZUm!wabDNg!oVfe->>j8N5K1ymIx0_PmMt~<-ZOEPbr-UYp>F$Tt%yEdMP zfSEx=I2;b}-mk9-{PY6M3=ugA+LSVDme2hk;ckg{EA_yTs zL{6>WM7L(3ZChAtvD@vc?RGo8cntwyxm=b+G%Jc?;+z{35r_!h`?I5SV=30h<8e_{ k)pS0eSNZdk$z*!|0Eps55@ZNrQvd(}07*qoM6N<$g3phpssI20 literal 0 HcmV?d00001 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 index 0000000000..dabd6601f7 --- /dev/null +++ b/Resources/Textures/Interface/NavMap/beveled_rectangle_east_west.png.yml @@ -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 index 0000000000000000000000000000000000000000..a2a870381dccbc3d9b7ff62767d42a74c84ea199 GIT binary patch literal 394 zcmV;50d@X~P)B&s^d_h`;0UloVnGmK1!H^SndzpfsWRaZjOk+dk$6@N+qd^Cfp_Z~4us4B87yBfoY2-aGhPA41=2N+`(e+Fzeo7d53^g={M zj1kO?7~}V9PC!HuV}x@K#u)7P`*OS8PTT5dDc^RvTo%^aw>-}$A%wBD7S>u2(bd=` oBJ0cLvM9@PI-AYP;bGgBPo2J%j%aUrnE(I)07*qoM6N<$f;a-N`~Uy| literal 0 HcmV?d00001 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 index 0000000000..dabd6601f7 --- /dev/null +++ b/Resources/Textures/Interface/NavMap/beveled_rectangle_north_south.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Interface/VerbIcons/ATTRIBUTION.txt b/Resources/Textures/Interface/VerbIcons/ATTRIBUTION.txt index bb584a7c20..ee497a1c04 100644 --- a/Resources/Textures/Interface/VerbIcons/ATTRIBUTION.txt +++ b/Resources/Textures/Interface/VerbIcons/ATTRIBUTION.txt @@ -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 index 0000000000000000000000000000000000000000..e230262fe0ee1c1cd45a612f88bb9ff7b51ffecf GIT binary patch literal 713 zcmV;)0yh1LP)3^oBF7;?f&`HuQ6$J=5e30Q0zwcA2^J~D%EC%S?2M&9g(AT!h=dekAOsN$ ziy&fS?1I9fDMZ95f>@{+2!}uCV>1cEvbnv@T`)T{Z*?~_2m3xZ^X>P|?nqH#%cL~| zn3B|S67{PLOza0>WBy50gqKAS(CFgy=bfm)*dD$wDZ`EFpzF*G= zW)1`g0oVcjwnkn7+d_me>KF+R0#F8CgbraR@FqfNAB6Fu#)DQNxatZD0&ptQGLHLjXpaz`q5<<$FZ=^dw?}pwJ%z_~4iKIT;^i5LU zDF0W|OG&RKy^}O)j9Do1OlVb0z(CQLL#w*?KYXnD)?|$NC~3c>gOaXE`qbjJJS=*E z>;%Tw`0rovX>)ZnSo0P@2QU|;c?ZJrJm!I;%Sn|l05$<%n>0TJ{B$!*Um(opFu$xR zp8(v?X}$_{`vhPlSo2PWc*Q}iMr*rgf+;ctNi&kRN?MR~MA9EgyCvrQ1n3o zSOkJOhd7DZka?fyCl6SX0g)Ff%hJYiw0WLQRjsNjd%CZWIQQxRAp|+k({BJXlMsTx z0M~WhcYw%b002ovPDHLkV1l}b BZ_)q& delta 317 zcmbQvbc1PvNGZx^prw85kIaJY5_^D(1Ysso2-zAi#RT{2djF9Y~3kA%d;vZ4{Xb2 z_@@70B4bP^qX)l2FN|<-fq)Y8<<(Lf?mzEKzrOoU{R5L9g>$Y%B}a;VsePZzaZcNC zt!dYyhHJl0RpuR^s~`vh7lk|jw);;yQn%0l@{^}_4@HuDOpo1ozyFW*{z+#y>rBq! zcd#&P*p{n$n^}M_L4xh%w@<593B{l6u4^P)bEnM};1ham0^U^bf}%Q7gXP^na)wT4p4?z7o!kftf7(z^gbUFyb5NVp?DQ|&1gvDZEgb;8X$6ozbtA#j@(P%XI zge4-PXKjVQ(<~LYecvzrWbSFjMOi0591d^hlu|Z?yl2Qq-}i4?X{8j-=kv{+@B8oS zzR`+*8G`38fUY*2tSD$8jKp!0~uQ5CkyBK#1Rml#j+3JHD;^ ziB{YzYdMBth}~|7IF4<*ETx2$5?PiZ%QD+OXITa*rL8S)d!C2u^=jvfb-90O#l14` z$;07*{eF+tY6aJIp|!SGG+(y)S6%rP2mXBNWe>6tLb0y6D(-E?OA9~<0i_hy>-Asn z!)~|hESF3DlfUaYj;Yt{??QY?qtS>TXb=$*5fKp)5fS}gzW|1?`)fusCBgsz002ov JPDHLkV1hxbv= zZ;pCNT)5}l(c1oj>yXTmL&+75mW{o|4VF#Unx?i+O0iCyT_|n-_(xqRN8<_aPvS~U z@~_Hvzg(p8N6nDH2 zvpZk>V_&~T-}X91mL*dHybf;Cx$$kM{?t2r84G0=zppNdWoMZ2T+)eyLvh18?OWSy zzY11JH(Zkn^76Udk|^<^YVW>Re}o}c0?EItHM;nIi@#Xk6ZdL*YUd`MUcIL5qE9NG zJ@1_sGn)7ozh#(r{`uDKgjvhhy-YWVV%e93t5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/base.png b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor.rsi/base.png index 4a9a8f6f2069490a67965a5fdf60019008341678..5858ec39fb0cba0cb4b2d63324ed002de4328c6c 100644 GIT binary patch literal 3428 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 Hu0mjfpduiR literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..7bee0a002b75fb20e9b790068b7950121cdf779e GIT binary patch literal 83 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzDNh&2kch)?4>B?Wc})uc*XMaS cfSB*u1QZw;r+*K>4&*R+y85}Sb4q9e0KdKysQ>@~ literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..4ac9e76480361a744196e09cbc3edcfaa05f737d GIT binary patch literal 523 zcmV+m0`&cfP)4QFfKyZoFJf(g^&|8Oe4&~^=#%085CT*bCFYwkP}FRIzbjfqyss? zpdlL<4S}TSs#$0PPK2?mwfilrdG-JGzrWvm;1E(u8%2=?h@!|!DJ_n%=bG5-^#E+U z-6l`?u8Bej`u#q6!vZQgw}nfl`X&pTC|7{h2V0V`LDZ zlqzNz$spiibPd46Kj-%^YJB=M{2Kjur9hr=BJh?1o4CKbd$$3d2t3Z`TLT^*9li1f zkO|zW4}@X3t@AXFnZ_|nDZ(&xD#3^Lfvm50Qs5~`yhf|V_tR5;4~LvxT+li=a01WO ziZ^4ql!c^TucNi5*=&}x4`{6sLSU^ehrmYm)oNAVMg+V$jte2M0nTecX9B+Ovs^Bz z)oSH>z!2ZKR*f5CV>W;7aki^U=rfxil~y+@Q(CfWc1 N002ovPDHLkV1lGg_D%o* literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..45d84c3d5c109a07398c91e6f4b74fc764e88797 GIT binary patch literal 393 zcmV;40e1e0P)&MX)JkG-pscn004km9g*oCmB3|Nf+(pE8IvmS;%D#X`mYW}EM-31W zk1dPM5&M?)&MY_m?c%(=rVTLVJ#v=S{(5m44zCgiSNCNcUL_3bLXUB{256|qI9vnN zAPxrr008<8gM81|M$ci8@A(?IItuPFz~FYSHb9R72Dj657&JtHvAlnm^&Z||>vy{c zIBxi?dVs!+{@mlF+dTlk_md%7x067AZ;qJa4B53)W(yrtj+*h8yWT}^f!l_v8+2r(oxJ2N}3%nvXO!!QhEgC|5Ww-2-72~oTQ z#k~aK$>m4O{hr#7*>DO#sx`GAv+-=YcrWFB3#|ZnLKJV?EtFCSe80MW&N4_TaXcJG zcd9P|mpork+A>yvQVLSa>T{|!0^f&Hiqf``8xl}Z2EiDB!1s;&Jn(%azs`(FeetU> ztlq~+fH44d!@%@Sub%n3?J@zL5M))*8Gyb;Cvi-^7n}4YU>!wB;+P}|#sHkNtW|;l zsuCP~@xXLdXFLZ;DXV>+YK>IuR%0BKbCzKhhSjTn9r(LNhSI8lOP()|heH7XN#naI zN+0-1K-XO$iDOb*qc6sVYX`BH%?6*R6G<{Uo8X-EEsXk<>hvryH}$^oaNOJDxDyY( zc!psZhG7_nVHk#C7=~dOhGCq!I$XRqgqUJlJSM%)dqNbid5-0N-x4g8v-+t<=1sr4 zzO(gZa0Lu8?!qlHJ{v!-j>qeNHnoJUi>8V!)w&W@*kU~%Z!R8yvvF6tBr-128S4O0 z8Xp3cM!-oRQ5P@HP1&4XRb?a!k*S50T}o9K1*>%cD2=;f>N#a2w#BMrQ{RGIp}aL) zJ3FP6{T5%=Q3RmfgjZpRuiXwGLiGCeuaB|7{U6mCW@Nqrdl4Nv{xl`l00000NkvXX Hu0mjftN07& literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..7bee0a002b75fb20e9b790068b7950121cdf779e GIT binary patch literal 83 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzDNh&2kch)?4>B?Wc})uc*XMaS cfSB*u1QZw;r+*K>4&*R+y85}Sb4q9e0KdKysQ>@~ literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..4ac9e76480361a744196e09cbc3edcfaa05f737d GIT binary patch literal 523 zcmV+m0`&cfP)4QFfKyZoFJf(g^&|8Oe4&~^=#%085CT*bCFYwkP}FRIzbjfqyss? zpdlL<4S}TSs#$0PPK2?mwfilrdG-JGzrWvm;1E(u8%2=?h@!|!DJ_n%=bG5-^#E+U z-6l`?u8Bej`u#q6!vZQgw}nfl`X&pTC|7{h2V0V`LDZ zlqzNz$spiibPd46Kj-%^YJB=M{2Kjur9hr=BJh?1o4CKbd$$3d2t3Z`TLT^*9li1f zkO|zW4}@X3t@AXFnZ_|nDZ(&xD#3^Lfvm50Qs5~`yhf|V_tR5;4~LvxT+li=a01WO ziZ^4ql!c^TucNi5*=&}x4`{6sLSU^ehrmYm)oNAVMg+V$jte2M0nTecX9B+Ovs^Bz z)oSH>z!2ZKR*f5CV>W;7aki^U=rfxil~y+@Q(CfWc1 N002ovPDHLkV1lGg_D%o* literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..826c90d5a00bd76260ab8d5ab6329c32640ea936 GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3HERU8}DLQtTz3zOL*qnWgzf#lA|#-C5qPxc?{ z_e>!hKMjY-&>v>^>%)GEte>(!=l_dYPIEWm<`rnt=b&F);x0d-Y*{) z=HJvdsIIY^F57VPvGe^+;R)YEyz@i(1EycwUp*&eH~WG+y6qWP=dlFk^+-JWzVl>Whs6J?ZO`^Mp3QzJ p;LBhWz}=p~lrVFag$whhT4v>AwHx;_9TNiC?dj_0vd$@?2>@mHr6d3V literal 0 HcmV?d00001 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 index 0000000000..bfe74c313c --- /dev/null +++ b/Resources/Textures/Structures/Piping/Atmospherics/gas_pipe_sensor_alt2.rsi/meta.json @@ -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/hellfirethermomachine.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/meta.json index 979d804fb4..f216c2f60d 100644 --- a/Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/meta.json +++ b/Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/meta.json @@ -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 } ] } diff --git a/Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/pipe.png b/Resources/Textures/Structures/Piping/Atmospherics/hellfirethermomachine.rsi/pipe.png index 620ba905bea43a0cb2a7ae8d2c2647e6ff9ec5f9..e0209a7bc8967f8f7d89ebbe4d292f5f2aa70b0b 100644 GIT binary patch delta 281 zcmX@ew3%sway`Q@PZ!6Kid%1QD)zM)h#dQPyu`_=`8A_~#RUnL0;%}*aVEQ=0@YuCd-PFian{{{n{?NiyuOY2_$>-}1*-_NOVdeeGKCO;;Lwud(v&wM`fR$D13bn55$B0up9CcL{r c+8c!Jr*{Y$N?y=CvKPenboFyt=akR{0NILs<^TWy delta 295 zcmV+?0oeYt0>J{1BYy!1Nklu>>1#1+se zEN9>VSOfwp8q9lD&~&=#|ED%9W+q=S?A*jbVHoaZSxTPgGLEBkT_^KA-_F$fdG&Db z;QPLKo+oh}OPZz<1i|TAP6lu=#>l#^mufg2z`pNdjJZ_9$$tR0Z4;5l7jQKI00000 z00000zR0P4n#f~6cbw1es+qN2QpHc~67zT~D tpQk7a^(Q&i0U)ZX(rga^007{N-2n!mFe765T3G-9002ovPDHLkV1kS9hco~H 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 index 0000000000..315063828b --- /dev/null +++ b/Resources/Textures/Structures/Piping/Atmospherics/manifold.rsi/meta.json @@ -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 index 0000000000000000000000000000000000000000..25e7906af1498ef2786ce3620d8695b816b4a427 GIT binary patch literal 457 zcmV;)0XF`LP)b;z6b9hmc1@6Tf=rx&3o&sGCMK@JjKq16xByF}=*fN^kR#fvRTZGE>;IdgM6%2u z?8wgs3e3MC>i#vsOcS35-qVD0_gFE)TjDKY@(+_m%8 z);R=HO7Pwz#)#Q$R$l? zHfb?5pU)v8Xxp~p_h_1? z?ji6WObQ^Sgb+f#b3pzSUM`orHztam1ikkNA&eDTA|fIpA|fitQx^2k*e5uhPEYCU z%QG5Xuh*YGbI!pzH`WtxuK~O{{Fv{@7_r%GP)q>JT$DVWPP*Uk9~LG5 z+vv&Aa=CR@7)lc4t=A%wm{OGHHUo?fzBc|{TAa=E0h zOSjwYub(;R;GFA|rC~cKQF#NEug4g%+wCx!0Ib(*)O8J2Mb~xx%L-LhA*F;EBaAWq z5q56pWJ*N(O_jCw>9hW~3Bd7q>?=bLI@BMh{(5g7DDK^)WhqOnFE@p(OetM zf8*g3zvt(W$k(pd>ol?}A|fIpA|fIpBBFQp3HyAkS3;gmegFUf07*qoM6N<$g1LUs A{{R30 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..f64fc34cd34d71b3c0ab57e20ad2e173a93f7c6e GIT binary patch literal 455 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 TEYSDAR{&6yQS literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..a9d3b0da05e39ebb8c7fef988ff7403aefcdb164 GIT binary patch literal 2339 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 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..a4e22862776ef82361b70969b4681d66883892bd GIT binary patch literal 2417 zcmV-%36A!OP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U;0dax5nd{bv>$g}5#2L>#JTsz z_D52cY0q>w41-rux` zXGca8;ZE0U)qDIvJHJejdqSFT+k>oIPP+x&9S?!zD`!019GY4p}Kt#BcFc$iImO?*5x8W01G`GvSwf+()(x&&PMhdp^Ch zT^x5iy){LM^&U{)+30Rh{ITthgtZk{Jokp^x=f2W{iY03n+;d*Qz}p&0 z?s*+BieJgHP^TTJ0gnaLfCuHLF6pe>&w490th^IO<^*BM(R_b}j~YL7Jq4M$>!uXj z(^k+cyH7(6N6vpS3V1 z$-V`^L|B`lOd=o^PRqVF=14kYGv})r z)B+%wDhZ(JGyqm94F8eR;6sCnOJL^8!i_tRO0`t3wMuo48bVTprHV+CE~8N^jazNf zTI+4}+zAxMy>4Zsg&%)pi5;As95EnRG-bB*#O?*TAL16c z{3G1*-ys(qy6-?PICM91f5q(s)b=KVG24ceiZ6mkgIqB2)@L|X76@d<= zEt*c&)rTlp&!fI|>)qzC$+CweTRf?1*vo*T!kXGyN$MH?lwpOem26Y@w7P6>UAs>- zPU=e)gR!t>zz@z#S`58fkHBh!1tG7^knLu&NwA`r^f^VK%_8*ZmcH0CE#uF#$o=ru z`%eY2Z7NmPh9Wk$%xw+cx~5Gr?9RFvbmkx}SEzgJBDZZ}ktn=3U{}E(x?!0TVFZB} z%xYEzF>M4>VrJ!Gf#QIxptUXU7Nn8lox9h$kbaP(50*c>hhH7|b3xhkqpdaB-M2>6 z;oxTjbr=wLKQl%~HL4q1_92)Ruu0!ywlDg2_v}zMuiPj z2xm!fH9!$oQCR@Sy$nP%hbkftIG~m);HX*PU+^hIv;h=Ri!>n`ew_d|Uw-Z7aoZqG zS;@;VvI=^WhTD>zwWAGI&=&tup?sWF|3>apF^(__>$HAC_Wi(JHT5nxEZ z_pg9rp2$YuFYP{j!7M)#lmv;(l)?20P)x<%BJv>+oxb%6f}2i8(UAnMN^G>aNw5X} zxyg?d$&`;jA!{oP0v>>qRbEaE-ATI&@TN4~c-T1RBE!OC16Bcds8xmQp5%Z`F^t+k z-dF{$*|&RF7uNtPbY5kDg0sJk{Qnp9FB0UTLns(PBPhnqT0DWsib$<^9tdo_H!nAk zeROIsa32x`;l^3w@Y8^c+m=xfi~)o;v3?<~`>{1wce1ucR5 zbfVO4fdekDaw>-Z~>_ zK@UhKsOTUhz-p!0ET{)ze2W!pPD$#SL zP1l)m0AEnvjg4NTw7=-w;e!s5lNzI&Ws`G%DGoim5^oy;3Cit=1RfsqJ{Ul`SjvDL zz~>in68l+hByf3KAY+_5z}X{KL#28lu^kEWI&AKOqm8sF;9#UF!yyc%`or7ZjgoHN zyyEt(5kSZ|i)18+=ot_}Fi|O-OyY?G65(S7{H}!h-?NklUFl(uybW8GH&lJ6bCfdyNr?xrKpbv+-`S+?(AA=hqr0=7SlS zGY1?LMUhR@)E*88(loVE6xqKW%fnIg`J6n@?RY%yG>)?Y_`c6-wdy>MvjH5BM*xx} z;p5|@Ujb;XUw_{7Fvj%n3D8rrUDhdprXcBZ5S;?>yw~MjN>WY+V2t5*yW#sj#+WvUUIhS9*R|7kzta?$PNx8r zW!b4N?`!~7Rk7Rc`ui3rih}ietuB{~d>RWOgb+dqA%ttby_gq8kqv^NtrRPz&{|`R zX`7ke)epYv_&l9XKT>!ceD{FM$~s!Z3FaZH2Uq@{eG{U2q2DQ`_&ZqQ*(2(Ucl?ftyxRX=d=5# jFhU3+gb+dqA^sDeEK{rQeE4Sm00000NkvXXu0mjfEkJ<^ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png index 39ffe213efb7142a4979c79f1dd7fcfc0a12c6ad..003a49eaeceb5caf4bc5e68a13ab2d6039eb652f 100644 GIT binary patch delta 208 zcmX@e+{dKT8Q|y6%O%Cdz`(%k>ERLtq!mDzgBeJ=Ea^H1q`U)sLR|Bh0w=n8)MrQR zxC9hpED7=pW^j0RBMrzY^mK6yu{iy7vb9iy0uL)^3q#Y7>%Z?`+34U_=#hAG+s#US zO(mCLhK4B70uM{q2|oSQ6v^%Env z?-D3{KCNU608+aK#x)Hwkgws+u9ZUW(aU>S5(RpzREvu6{1-oD!M< D!B9zW delta 388 zcmeBUI>_wS8Q|y6%O%Cdz`(%k>ERLtq#Zz*gBeK9-QM^HNHG=%xjQkeJ16rJ$YDu$ z^mSxl*x1kgCy^D%_XzL_ah<5+QQy6~zXr&cC<*cl{*N6noE6r41ysXX;1OBOz@VoH z!i?{^<4bK09l_gfWhpDf`O z58KJF+*B{5v2@j``lMw=UHTVo=9$zx zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bva_cw@{O2j=2n0xQIS#m0%?;-G)1V~BPW)c% zRHU*ffm^d10BJY>`**p2a4}19QF2K&C66oCSXuE>{BhO&Bp>&4Uwl^K`@!yR6%12A z8II4aXM2TRJ~~`;PEsA6Pb)~ClfNmxn>gGM@nc18K7U!xMe-VDt$D0Y zV*;b;^eFExb~gKKfc6-6w}d<6CwR~MuDFX=-y!+%-8bBwDlxcTjv@_GS~PdrsRLr< z$+Grkp*|3WCr&b(2l-b)WM4JO6>JLP6Oy7c5YHJBDaNAHEf~ z&H?QNfAFC?ZKR5}Q=f6jDr*Qp(AaoaT^YmYj0V zCD*Jalvt#sl1nMIXyqD^1Er>#YpJ!WvQtc?7)#M!VQJh#i%nW;xs_I%cDPTEU3%)d zmtMOL9$_F&j5P8nqYj!PzVF0m^N;ZDFzASB$h=t z?LL%yNjE3uCEfTt<(x_P8_GFI_f@wistw!c`c~|SLgUm2L?7yBQO8AXQ`6VVmQo|d zv-qGGKV)5b0!wnppgIvegHr2L(SY>TVed=#Zii>MGV64Hwo-R3{BK18T*YTky88j| zYo+sVcK9eqRZKSw#Y*aQj@de}!UCkdOrxp|NZ%7Wgcn!ren8O|$}%_a=D}HOx>A7$ zkuEW`@Gd}_0LoT=3(e^-K)Maolyv4(PjjeIzz_^WjJIMr$`Hq0nuC8;!2M9NZwDGn zG2fh<6ok-H<`xaKuq^xh7#|GbMMV-t3TcK@l{q>IEvlX2OL2z>Z@*=Y(Nj84fq)I`_`3s}H&Focm;Pe{ThJ_eJ z9wj+2V+La&9;;7c8Q)fM>h0dnJ+tB2+OaI&+Tb{hRBN(eheWmn4{|x;+j+$OFeh$Y zmUh_U2z0q6X?u%m`6lE1y>vg{LM=n;UT04#yokFTa!we|ulMLBnAMA+r5* zMc$joqP{m13+cVDy}XJ1%D#3R=>ANw_qPPEg{Jwoy={U2ekgFiv4eab=;2hbW2x*T z%aK?NkR=T}G(W-Reh1I9fu7F+#scaI>8rOB>*@9Fmb@aSAfbDh*zGt;aXzo8hKUu9-k=BZ&go>h2uh+?D zvkV3Uy4^0T)ha#)06soGqA_q_B;lgLTsw}#;X6f9n9XK9JUpOj8l_T+(P+fm+Z%wd zC<@Ev@{h$1*9(4LEEbE%vW#upp|KPS1w79S=N+KcYVrL1Orz02(=>9q900jo4o%Z& zwOZ8cb(+m4wOZ|@c1$J{fUuTr+lZEBq3b$^VF;#a`hmPA5{cjD{QCMDfKsUhz+$oB z?(UA8n;QVK*=+bdlgZ%wKD*rxNs`#__ms`-RE_Q2!g zBh_k^*Vk93(<#g4lAs41$03zU;ks_Pl_w-y_^$*1gbqaV0>^Q9dV1pJ<>lna{dEAM zD1M6-pLHVou80I+zuzNC63JxpNG&f0KoA5rn+=jA#djnNn23deKvn@JlgU??y9@x= zbumpdzA5PU`xu5H*tUHZfT)*K;g_o+%d!v~1D0iRE(1RRDHITj@pXp<00000NkvXX Hu0mjf>pixo literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..5eba5e5e300b0393bcfc907fa89dfbefd23a0e68 GIT binary patch literal 1702 zcmV;X23h%uP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U-|ulIti8{I65&5s*Lvjw8OR_6B?WZ5$_)nU^=o z>`d*iXUYakShTw(oY4H|??r#%kWht^=3><>;7B!9aSTeh9QC+zNXPX!;e1~1%9=NW-?Y*7K>5*~Q$ zpA!!#=efEZ@w8oB`=0I%DTAeIwgQc+bm+qn2aT8HSmTHV%5|9pDN~di7CzRk$9kO$RvwJ0!U)EA(osTg0JnAKiuUHQWXm7L36L;c8;2~CnZaX$Kn~;*lQby6sxkmlQj8{)rN~|z z&tyL4ii*iLV{d{G8ZBmMQ=>zyloa`sQ$Y^7Mop?}nzfKtb&Hlv%`DsAa>|>nRWU?uC2Jz(q${Jvg-1iYNx8dv@fW}r)qL2 zwdduVYOqqy*ATq76Wy9YF-Z)?^Hu-}EnBltI3?N2ZO!oEKvAdwq;73!@Ky{Grpcm< zZ`!>n_mXa;$%1+J?60uzhU>`tS5!q2Y&h9D#tsfFes9zD=cq zL<5;Px%uAA{CGBe-qW)Quk@pOC)*uJniJZ2E5+y79F+z{xLLFH`GTJGBlU3xY9I+o zZnjxNMu8?U);43^Z36;2hp?aFqMyNYALv;PJShSCA&MRa`b`ZyDS;nV?X?MCS`N0QqL=b2qSv zCf*>P*|ZJL`@|wE$tv+V@wiDBB!1+&;_(~jqRRr$6wOR(o>(N7iXE(UFe{lF@icKn z)pW`ivL36Pw>WE+8f)E?zc7^7SJGUk6-FFONFWIb3Th~$0vl11wn)H%FF`)a!aXvcbxBI$7!Ab!Drw~Z~Lna zVD^*rdRvPe0R!8>#dTX#_JGSBVCcz^P1%)#w1h$dct4|W$^nD7K;N1-x7ImMAAk(a zYWW5@I0VLul)dir?%vM1{oB);-w$hAa-*P z!;qbGIfRgxWyyWt=U?BdBqG*Y0Dv(Dj|d#c@pTp#AR_TNMFPw$77+Q97h1azVA5Cv%J7{U0B!kxh>eX4c>c-F_sr-+m^bn wBWo?DX(D3`J+g*cLM@?|P)j(^Go&Sa0g_r>tf17=b^rhX07*qoM6N<$f=HPld;kCd literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png index 715aeb58249c6800597e1df477b52ba8b12fcbc1..2805fe662673cafe5a294e4a2a7601673702207c 100644 GIT binary patch delta 225 zcmey)ypc(#Gr-TCmrII^fq{Y7)59eQNGpIa2Q!d#S<-b3NW}*Dgt!9fiEdH#wKL|v z0x}s(g8YIR9G=}s19F-?T^vI!POrUulCMF5hb5rP^-e%x{Qv*vUo(=7iUZE+`$jK2 zW-~t``DlZBXDCmMSA+j%nZ`rY`I@w@@Ukq@WmJ45SCt`)+C|1mf(zy`Bv8!zFPn+n(0=*ZzbDLS%o;MxrwN^3M zv4hDsAfZ69K<>H2=lR}BZx8y3Dp~I_i<_}m zUE@LwXM!ZJ9!q*Z>#X8~ts4$Jh%va#^q;l)v`oxLQIqFQvv)f;9^AQLIeVmtL`+;_ z6H~LdbP0l+XkKBbc$s diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png index af8376a1527ae14ee15c6f51e52e61a7aec7c51c..92b5d5a0068cc856137311019510a0f663a6d099 100644 GIT binary patch delta 259 zcmey%e3nV4Gr-TCmrII^fq{Y7)59eQNGpIa2Q!d#S<-b3NQDRZgt!9fiEbhF;kA|f zflS7dAirP+hi5m^fSe_sE{-7w{5aQ zv)U#<`_{PXmv{$&_#Z0=JT|j;}JLGz2&s+W!h@a{!1($G?s8TU)d$# zExc>ehbh;?n>^QsUtc2PB3_eVs^Ys&VaKV9`u}E`FEnKRd2X>qJJ7)lp00i_>zopr E0B!?iDgXcg delta 436 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 d1u(|gm)&&~)y?K!Hu!0C%LUhbw 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 DO({@| literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..06b945f1c561d56a16e07da8d37143a1b5f9b74a GIT binary patch literal 1179 zcmV;M1Z4Y(P)B?CtHn;Vb2GS;}NGw#b^YEMuA`mSrJH60$5K%QBKA(d~8#27}nPjU@e!DoK(! zK0YRyOahQfr2x3Oxk1x3#{r2%!a1HwrO4;=l*?sF)ayaMuItXVN9E7W%>fXP$6xT5 zmX-jRpPzr1uVgYAdv$e{^Ye4AudkglqN*yot~-MX27~Cjj;gB8KQQ>Y)9C-p0GgXPPY4p0>3#X7=Q4p0;Y!!Ul#?r|(hP$WQK zP66Qn+qV5#1!iVu&~=^J*;#*10kK2#Z4wk=|NQ*yPX{=g3`z2*1H_I0gakMi2gtI_ z)6)~v)6@RW0hVR?cPSi;#Q><+>wkR&=1B+Wx=ucy_iq)rxVWHPE=%IMzi+q0ldx~0 z4{+0;pEQ4LPlQJ8&rh1~xxRqw?(k<1K=cI?i3Htlm;L?yFYODwrw{lOUm8ae8fg zN`D^sRDHsrK426Zn*&De&x?BfQGI~WCk*NXCh7p84`{dB!0`UOsM{aa2MB#atyUux z3ZZElkB^U&a{xfQ-4+@hN~IEpVNj`59MOa@apUms`hY^A0Kn<#DUnFTi9Fw}1Kd_2 z&*=lA(I~lGj=8xxs?{o`Qi)cp_5Vun%k~0>VN6sX;Fj+>eSllOC-nht_@34WjKcS% zKEMs%bNT?ce9!3v-10rA4{*!(oIb!U-*fr^w|vj(1KjdGs}C5J?>T*dTfXP?0dD!8 t(+9Zadr}|ZhVMyzfE&Ii^#N}9{{b#rC70RXd1L?p002ovPDHLkV1jZzLy7gzTqSJqPAbsB$taJ&(;g+bMIZ=d*Aoo2gn$@u5;5gIRKcZ$#q@l$Pw%EQxTKs zbUFaQHBEyItiw;!u6Fo$tyaVK_BJ*)HZT|r@bvVAhldBDyPcMwrXfE&JNq)`c^*_% zMZI3nmcDvZx+Ja#i!8joVod4Yv$8q3!o-pIH;!ouQhGAefn_)B>Eq!j= zHsh!B3Z+lIu+R?d=V(udkR+r=XPL$lo8eg-Eeq#2*WV2SS*C>dY1e&i%ER<$2_jqvf`&{ zC$VIh9~~Xx`uZB0rU|`S%7R}JF|qM@49l{J>$+0H^g8@h#IDTea{z#4S%t5@C`yRj z^Z`Z4NW;H#)dv*8cxn28A{bu?eSmBfLLZRSUlYXlrHHE!SjC@8ACS~v!|iDR!u1LN z;}@M{-78Vr4NW|Ps`>Pst<_Mo|er|qwd+x&(9N2AWnN)Hos7PK%Dlp zY<{8ofZN;K*r};3exdq+B<*S0{1qxxs8FFoj8G+0ACM(Vp%0L{0J8M~QWrqBK0w+6 u$kqoG;tPn%NF;((DuuVVH`MEO%w{tThr@6RpePEj)oPwK$8jKvBI5D*!|#!T8oXf` zh{a;iG|gRSjDhp>PqADs;W$pXuYjg$Sg+R@jYj|6w=4_W?Usc)3GVlMY&ILr=W|Gs zgyZq(?%fMM@B%Q#;5ZHzi^W615(GgI1VIo4K@bE%{5OiC@N&7#2ZI4`Hk)^6@2||a zOoVh@M2&z3i|{1@mdhnHO@peco{{uruUf65 z+wJnzYQ;h&z;?T3mSu4O7>~z)?H39KXqpDww!@nPu0^=b2cyvls;Y)R34U` zCzHvzUOwRL>+ARXztTkcYLU74c`VEFtWT%YUu&X#6X2eoM-T*_NF;DNor2#Cc@&oZ zXdI13KRkB{To43^qUc)}`J)0PlS!UVr=jb*XIk_Kx~?OcO!7cqfl8(Fv~?Bm&KVnx zMsNklX0uOQS8wNxf&K$}y`Ja!GwbTTIb$FTp+q9VpS7;umdxY;B?y8b2!bF8f*`)1 YcN0$;arVL*2LJ#707*qoM6N<$f)~g`ZU6uP literal 0 HcmV?d00001 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 index 0000000000..31825d6fe5 --- /dev/null +++ b/Resources/Textures/Structures/Piping/Atmospherics/pipe_alt2.rsi/meta.json @@ -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 index 0000000000000000000000000000000000000000..fc371f495c3c9bddcce9974c9cc334a6b4f20199 GIT binary patch literal 890 zcmV-=1BLvFP)Eh}KDReHPTenQ&pP^9d;L@UL&bfm( zxv8}(+(rZEyi-Zjo}4G|zw^8gG}MA1&`FYLfFwzD5Cpo8bvznu-EJ2^@9*!|wuaMW z0Hl)9FxfZc!AG=lM#^U0ht~-vpuEZWG5bd7iVgvr}Hr^PKs7 zzVy7V>wa1_T-PN{QvfED2?E|&*MfU<9H%Tl0C#tHOs7*WFE6>jzyC21f*{aw9CLDV zLKuciJ%QG`{9L_OfTFc#cXt=9H7_qO<&nD8YL)y#uh*mB?+Y(U65Z`~xxT(GIXK_< z0XRK9B@9ER)9H`D_3?Nt27`eHxVpMpdsdKAmI-sQSbX?hVYAr`fKI1VGS1#;G%7b< zb)hJV7!HRV9v=Q$+*d&;vv!3ac+VDjo`+Hjr4-xS+hkc*hJz5IJX#Nj!+*b77u$~G z=!1iU+9|2;fbc72uTg4MYaS;)3mlutkD2u zSw^qdGcyDLZfI00<0ahPi z^#N8NU?u=oAAr>dtn>uN0bsN~pgQZTPJ}nU&Q~|Q=i)Zel&quJtN(p;bVL+IwR?c~ z)#lI6&elHUCg$_Niaw#Zuib9f?`fZHK8|Dd_V&v8d{LMGcRqi7d|b}wVO5_{NMqnl zpHOER{4xZ>Fy!IkVQHjX?bZKxJ`Zo~???KC!UlsuZBycJ(c(`}Pdq+8lBVg#=kvgd zK0yev1ZJHh@-G1>-1qkOwh>~fA1i}JY}XlojRwH#1FSy4>I1Akzyy83A6wQ67luxR Q3;+NC07*qoM6N<$f|E<7vj6}9 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..3573b28923b5075c9ccddcf6e841646d46f9f978 GIT binary patch literal 774 zcmV+h1Nr=kP))g;0x;Yy6}Bp0D$lNqF%2HC`6T?A8Ty4+W;VH zwHkDw!hbXXaU5eX7+^l1BS{jJN+t3B{=Rcgnx;%v=T!LlIVV-CRdl;uWLXB&GGWWG z7=}`dBeMNx6-M6P-jE~-q9_9A93LMan>N`+5!wEu0cf>aFijIt6d{TtB{!?uZyak} ztyXw^eAG7Gs_-8Tz-%@{5Cm+wTxtn`Za+Z~1VIo4K@h}0%ijBSF$sCiJNS35rP|Mn zUnnLaA08gQ9o^!!PAzNI;pf}(LrKVM@H}tx`P8yjUH-k4*r_DsB}^t00GBOmRqa2R z5z3R0VHjT3fiMh_B+11$qtd@O0vKb+vJB79&sQfQ(==t5E^Afo-;4mx|Hh(RF8|mx zlZy?*fN7d2Zg|k`=lN98Y&MnD`&`!rfIW#WKfk@bMXgqY>$=kGefiE0%d!9fdA3)l z-^kO>p69`~ZE5wsIF4c4HayS6-Q69Q%O!#!V7mRx_kGcBw-Lwj&cEkRR$=lvKBv`c zVYOOeHk$$X+#RON&kpU!lTm`YWZ$1|KS2-#LHsBD0cEH<=!OABw*UYD07*qoM6N<$ Ef+D15VgLXD literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..8a54fed66d7259ae7d9fd9675e27d01c02152388 GIT binary patch literal 643 zcmV-}0(||6P)EX>4Tx04R}tkv&MmKpe$iTSciA2U{rOkfA!+MMWHI6^c+H)C#RSm|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx6k5c1aNLh~_a1le0DrT}RI?`msG4PD zQb{3~UlsaZ5ySu@h$12}Q=b#XG(5-GJ$!t6^ClDu?Zdk+{#50?g z&Uv3W%*v8Nd`>)J&;^Mfxh}i>#<}FMpJ#@RY-XM~Oe~bTSngt0HdNwi;+Udpl<&{E ztZ?4qtXAu+eNX0S*p< z@e*aPd%U~9ySIPOwEO!3bhUD)-E{o~00006VoOIv0HOe-0HKTo5la97010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=L!oI94iU}+q?h(0DwtEK~z}7?bNXez#tHX;jEz| z;#f8oP9j(d?xRk3K?_M8LSFO!1^n=iyDr8UV=vNL3mgzaI0)z5zaV3b#2ELZtu=uG zdhY@Sj4?0(rPSVm1*o-R0P6?loRV|K0!k?uKuT$k00OYqo+X3;o_7Fph}H<8r`UUs d1u(|gm)&&z@qLn>~)y}6tBu!0C{fY3&^ z<_gL0YYs5P9bQ}^qu+Ef55)#i^Z2eN$a<^NhDhw|Gh81ZvGAB zhB=>4e+}~5;mUB?g!ePcE|v}JR!bRp@iH_>TQe+Tva-=qlMn`J_jL7hS?83{1OVS3 BPm2Hm literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..f879717da3883591740c433a4881537e6dcbcefa GIT binary patch literal 877 zcmV-z1CsoSP)~In_}N$pOF#oYz`{O*FJO~2Y4j=5i+y|pS+Gha3Q_FR_ytL0 zXJgRaowrS;;787!bLO0rKTNS|wW^{hQUFmDscN;V&}h2&Zr)+N zUI$PsD=U~V9sEMxq33zDS}jbO4t}l!?(XgY*xufzSS)IHfDZmt2RM%N`GrD(EX%b2 zcwPLd4v%!al)|LVn_u|O zO_(%eH9$&9k|Y2|UIAVFnbV*Ug3)MXY#N+5e`3sA>#W! zjYflVxlFIuUZmX=UT@&5k)HPS9DEFh(1cXyX| zyGmq?9Z!E|Mh4S2zkGW{$Qd__hzQeZYU-2Nd$&%DufkPESucJUrAs2k7GG z4nsi@0MPIEr#3J1G#&hzE3tOFZEP2ygP-ew>+5UcI2PlMO}FXbn_K$-C1&*jvodSbc!i2N*D`55VdJtUkba5w!XMs}HdH0ILtM`T(px!0H3Q{x4wv7XYgd0ILtM z`T(mBu=)V253qfJ?F0U$KEUb&@(!&&!0H43eSN?W?Kw`r)

R00000NkvXXu0mjf Dz}lb< literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..227a31c2b0968655a0b2b4a59c2d7a33a28886fd GIT binary patch literal 545 zcmV++0^a?JP)^YYVoZogJ-}iM@mFaX7el`91K_$YgAAZv zg?;O4tTljoJ^rm)1E>p<-x@?~0G3sKq^putZv)U;lVur>%dxI>?q9_WCF}SYV z9G33N#{)PV4sWkzSq4-)PIX5ZRNY~x)2ZnZ@;vYN&H-TcDhjIh=sgut@(sr-`xq?BN-MU0VU{8Ra7 zYk>D2N-35hK;>TyKx@r*6rk`+5u7VR&N(QhShhZue{l#5!@zPBpz==!pp=5O7S6eG zccg^MzgS^XO5o(%e*K#*!3kRph%v%@4*)Dj0V@CE)u2)e*Xxz-YVh0sU!7%e6hSKg zYyd@3uogiIzn+sn9uL+(PvM^}g1G>33;`medJXSAHk%F05TNqw zx$|&qEn5+!@=pekce~r|#u5OPUrvRW#9X(-sQi-wXsvO%T(DZLSOTE(FV=tslPDhRCT~+#LR*u508qIlJBNtv^3cPUOe3EZ-(6LI}8CuWzpzV`itb zj4?Q!P5^*>x0lnefaj{Lyf!B{C&w6}l!De8T5Bk!Fbo5nb4V$Tb9ebMPh*D=kW#{C zvq4G;x7%%Od0(woW8=f&a6s2}Kl*cf9ED%CZJU~=fwgvAqhqawwHDs{@y9sl#yR`U z>+{c^p3lz$z~yoQ@SO4S-lOk(0MFH7uYTv;_#NN&tIzd##u&sH-x?G0Yp;m|_-i#s zQ51+VBE~p&c;wwNZ_TCI-k)}1O1~fof*|}y`~d<4`Xm^&Nv;3@002ovPDHLkV1nvN BO@{yg literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..6ff306dc022bce716bff0490ae9155bcc81872fe GIT binary patch literal 1190 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 literal 0 HcmV?d00001 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 index 0000000000..ef75896795 --- /dev/null +++ b/Resources/Textures/Structures/Piping/Atmospherics/pump_alt1.rsi/meta.json @@ -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 index 0000000000000000000000000000000000000000..ec8e261f2bb233f564fc8181bd16404f366f46a1 GIT binary patch literal 443 zcmV;s0Yv_ZP)o1JtA}jRE5wQ-Pi11wnz?IF(1AlB(Gzsw z2HB80GJz@)MJSx1Y#nldbRw!$n#$&PQ04bYC@2wm##ko)4G<9#5fKIHM)GEnQtfZo zKAT1~ODbQiQIS&Z^K6DgUH`ZiYmJxr+-oPe=HE&-;!xMP&mQq{JmO(8>0YNs_5DKE z%Dhog0rv0D#08?8~zCITCF1MMnStR8@8M2mr6^wRGIY`Qjarrs>%u z06a~n(s38(4>|(&W$FFjz&2lW4v4kx-jB1aJH}e$ZME|LMr la{v($5fKp)5fM>fz5q6+4Fg}Lg|`3z002ovPDHLkV1j`nzlQ(- literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..2bae097010d6cbe6fdde6d58b4fee8350026b20a GIT binary patch literal 533 zcmV+w0_y#VP)00GHKL_t(|ob8%1Zo)7WhX2x@083ryz|h$Y1f&i~9eRWwpf_OX&J8+n zgRYf01X4E$tz^H~p@B<}$bLI@#*5OR{7NnJ=O zmHc+ja=8@qN%=1%C-K-E%g0ryqm>K9o7 zSG5{Gq6h#m@qM(7v3Dy$EP}wcb>bKRFwz=fwTidtR6-^07YV>>`2k;hZnW0d^gKJUqV57Ne&+zJ zF1q@GSp)$tt5w^-{;d>&tN-Mm0|+665JCtcWN(yG$qYzlK(fzE$Y1tXTn3L_1`8nJ zcM8CN;N%04DI>INzpb|)BI)7c&zuso#fM&R^B5%;KZN|bw!l0LF$ORM@G=-|q@&9~ z(w{3SI`Ms+e}8TpgArh>FJ&O<&%6S*iw|k-MI!Cb9Duaq!*+X-Nc(ebfuD*GWgzL# z6@apfA4U2z-7^ned^og!VckwVDs5@Q00000NkvXXu0mjf4#(ui literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..f889124d18c1b1e820b8ab87782a09fab780691b GIT binary patch literal 545 zcmV++0^a?JP)M;1e*o^9Bw) zfwKt@LE=CHt%+rDAx#rx>?^bmN-a$>_V(NY;s2)FmYlErlzW?d073{Mr^}giL8VlZ zJ&vMC+#%_2n7D~)6k!@gCQ6I@jRXJyb5n(d{l)?~7EV5ZbE!i4$*1VN$q7-{FBSj* zJPromgW+)d7{JqLB&ibfSN;nqrIKvQ%P_4g@mt#TQ&7b(5DLOt zb6xa&KRv$leRKib7ku_sDIG;^{?Y;Dn-BdsPCGGqx@C*+!CyLnqUOWQwh>wu-WH3p zsivT6+qq150n0re-F^Uk+y9o@Gg?JZ72V^u|xH1rB%mTf5?79 j2qA*Kz*y3+&l-9m6Xr5FyM0 z{eC}DA1wv|0Q&o3^jUKz7>_ah*{4MPv>70DLB<$PrM*EGbb2k!zj~YK6Vzsa&;?7S z5(-4R#6)7xuH$+4b)rvDOBMjG2cay}pzFHW*x11F@iBbgk8P{X07=tOnsCl@j4`px zIleZV001^&A*Rg$NmgNLLqy^m=O{{b4v%xON~BzfX^8=@>!Mz-V`pba$M8yO1LfuI zcoE3evJApRB*w3-WQQBEZO0KG2S$+JKX@8a0cP8AL}LmHGO2Rc+wpq=5s3?6cs(lR z4F-e3U@#bN!mW!G@=9wOkHM7_R-N-lEiF$uk1TtoZIGKRYs0xt`maLd1S1OzfLN8v z&N7TK<@>aZARl}tfiVV^4)UBLD?)N%Vb5{!E(lNrat+SKucal_YBh9vtzps8vaI1r zP>7CV$kITzif~SqN(FD4O{ET7QlHq0(8xLefW^f{0KojqWppm9=ytofy1E*<13v?NMQuIw+Fr5P2~MGG3FfkJkk zE{-7;bKc%K$jM;9!R(-3`d{}AQ|-@ysCQ~7lm$FkfNE@XwX?06V^*jE*$jV64B5D}NQhkO`9bO@AICc(}j zEnBCRhz&XfL$3XBz&NBhga#etw%3~CgTM~*7fX^uWLm72LJm2!HZ~+NRf!KiH7FLy z4oIulgPE;mh`bBC+Lq1_gg$th_h#nJn>TM(fyZ=qcH+{dOBf#?$Ej1Nu)e;It*tGu z)p({q~Y3*Vl_TS`Hy{EP}SS zqv-4FMI$ftJP!bX6Uk(q2Q-tGmP1&}WKfu$vu$aFF9Wca$>2sNukw{>9 zc^OZhJZUKFn+FUI4&u?HM<^5ueyC{3S|)?998Q359xxi92XtS(ig-MZ$B!RleSN*5 ztS|U}Iy$YZV9LW*hc26D*ZVl*=vR)y_7aZ#>6~7k?p_TST+cV8MxG5??=j zh%4!IGu7_m_Auf#ZVzLgp9K^}fngZ*<4<{9zka=`GY z2?}{R8jya8L?Zc5;W$xobI0e``QHy4$jN!VSS;Fieh0C$vyEJC5eFSZ-BK(Txv#Gm zEiH!}$(yF>$Od(2XvqGu|FIUakET*7oIZUTcZY{@C7s6I;bD9@Hir9SV=!*thI#WQ zF5kI>`O#6tzWf6H{RS2mOdc5-A<;&BYKj3sq{sXBXrcFVCc^+A9&S(+1*ueu`}+;F zwH-x%{2N=B&@F5cwp~f5VVWkcUAtD-w$Qs*w;GK`?H|MuG877-R;z)C?8M^a$&+>O z=gytOeE`vD6efV~?rzKjc&n=ms;c0^`502E6lb$pA|f1q@Bl=FGiT0#ne7KC6h(n$ zSqOzfAR-*OcMr^rXfz6DMk0~m3+H2KZ*NEBSOob!x`b|F%YGZro;{0Ntp;Yc`(#;` zou*rs1$BCQ8o+M;z86i?P^nbx--VobpPHHi0L;wH006StEC66BpU116ZT$SpuP_XQ zW@l$ntyb~o<|c^9{{QP}-`oTGpM?xFLseD#bGcl0 z9RtGQupI-$@qBNpOhj@QkVqsFi9{liNF)-8L?V$$B>yk|23NRsNqnvH-v9sr07*qo IM6N<$f>(xRmjD0& literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..117ff9c8fb72055eff67667f4c5db9c6070ade6d GIT binary patch literal 1947 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 G&;$UpMAv)( literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..a2549e268c2762d26d4b83f5c7dff277495cd3a8 GIT binary patch literal 469 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>?NMQuIw+Fr5SaF-j{KkFfcH7 zdb&7c? zU75{y>E~9xAM4NdYi<3`(r+rCGx?nPEs?cZb|#KS_bbAG1bkko3DnN|BhQY7QGmhY zU3Kq0#z{bd6<{U%%NYB>n)3fvgF_1(Vy9~uznU|5Rz3Nu1dJyJPgg&ebxsLQ038X< AS^xk5 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..55708b37dd156ab289d241098d619a42bec299d7 GIT binary patch literal 697 zcmV;q0!ICbP)V8rIOTj9nMx&9`p+n_zoAA6oUcP#b zPUi@@+-B(bTe%JZ)GxrTEr2R2K-K}WMg_<^K-Ll~fa|(R9XeLAFN7A0ISiwYr?nbB zkH?ryCUH-pMD+s1`VA05Xr9-{(!e%jlU03tU>e;UUalg*}ut*v|LbdDl3*tWguO-4~JK&4Uv5Z-cfT^ILvcCfK= z7YF+_oSY7%<2W!)Q_JV`N*km?p>XZ*EkUchSS+GkDl26OvZ_!nK)2gnO%UeIV1UcT z9B<#fhY&(DO%nj%`@T{EeBZxT03n2SaypP#S4)h?Uz9QgSyin4Jz(vh0)!Ak2qA?NMQuIw+Fr5UxYdSF} zox(BwEVtL?OFLN$H#i5M5fIRtAuZ&1`u5WF$!^8s#qan2{8)3qk)ty1y>#);-RkTD zf)|$-|n`pS4C}V z&G-d-7e>69EBk^WW?JgOO*#w>yB!ZL(T?X(y!^71!NF+ak*{C#mt20m;q9ln&H>*H zOOlhFuLl1P>U7)s#7(I`;dbht>i>*C|L7@Abhnj1|Cqt`&prlAhO-t(XbSIw5UrI} zS@A)=ZP#k{GuaDdZ=L0_{Q5_wsfYTrM7KuizUWwZuKZ^$Bik?e2Nr#aw^L)b&9YcK z_tBp};yJrzZtaw~`%~|-NuY+vgwszC_55|`P~4m!=e<9j<+vu$rT_nPR`Z&3Ulg)Y z`FZQ@`}f&*8FqcnbkVqJSvz;`)Q=T1y>5p$iyHL({2NdtlOVyy<9z@ATI=~8Ah1GQ z)m{7Vm&fXJC#B8ls;jY2HxHfjKYXga(E4-V&MluFwp#LstHjiwUjLXwBI4qXojcd} z{PDK!_myUw?)KVvUtCP3p?bgSs#D=+42mubdY>#^s>-leyMAd9r~k8O2Bu#H>R&(H z6riCn`J}|fjFJVyC3$u0&t8<7v}LN&t>J7vYr$Oa{xu)~w%i|}Wm)p)anST22o!vX*cYQv5&9osx=i0}wO53ySjE$R9lsFIUUi`l7 z<@>|_`@-GpC;Zt^%DW(LeR&SU@xq?w!(DrJ?Q+}tOSqxj{r=la_uJ>!tmppM{G`42 lH^bQSsoMZlWXMmo~Zk|4VW_-JYD@<);T3K0RZ>V%3%Ni literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..6a5efbff379f9d39b8e8001a77acb2c23ae1467c GIT binary patch literal 1878 zcmaKscT`h(7RMjWP!_^YcEyI#sEbkr6#BC zQA&``Kq895N>@aPA`CK0C^2yeHA_iAoEK8|IlFsy|Czbx{MtFcbMF0qZpk_0M%32a zrU?LmwzCt#6FK?F>Q>)`?E2}^qX2-?cP58f8?u7wH&9% zXpEe+qI1UWZc;J@X?E}R8%G%jC1X@y%ib#!8Zw&2hU{T z?|-*DMn6OU`ssM`(ozq%gXEc2UOSY!xbfk^BzKPz;`cw6#>x9djgB3|xNUy>s_qC~$3 zXn_+4yP2WYB4*b_rd(c;+f~fdSm{sHxESS|wr?zbt(oR@F5y1}?yP?$7(@(~~AM~l02;q1pi&bqMg9PXa zH6(W<;xfTNBmUpFaMAp1)mRhrrBEXRMA=$BRQ!H8xNq8Peg0$5+9Ng= z1n<x}LM+U5f4RB97E8YV>143a&1*4#93p zG>MQ41UsLy>d9A}Jtb=S0&3w9PbvNtT6rWz)8&?yHFIPB#!|k>Rn+i0=@IU!O<62h zk_0ji3FGcv8~;`+0}am8`&Lh*wDB+n1YH)ZRKDZ=d#nx zJ^+5cUL)w)hnp`D*HmVV8QN!>#q+2E4~SGT{L?iQ`qI=(ZF)XcItS-8Y>^dtFpdYh zbrm=A;Rk;@uFA}f1)3SppvCM9UvyGWGDU)CUD_JiJ5>N9d;5(FdrN-nK}*; z><{Xm7dxc(tV<;0e(3W}C{>)*a}#@r=7&W2w(Wo3ZJxXhl0Od!8yj-8g=44jxtQjO#Tc*8 zQ|pYIdK67cvF!YQd|o@%RA*l^suG(kZJ!|?LkEyZBTYQT7HgDr@*RhxW&Q1wt|zqVm1{Is%OxItvLZ|w^Gqg;0`!xz&%2R#=(fzdhQ@4wW^`+ z_sRv_jnU0%WQ8^@8GNI>8B+Gs%Nt)`9s7*g=H6ZI>s3SrFMxq@7=CGxmC`JELT6x^ z;|2&t#KjtWH-n(6kT&JSM>ZNQJ3&obCFaJM;oyVj?SMq2S%US(Sq58f(>_{s`qNb# zW$ zmsXJWV^-p2VI`Twt96#G<7D<~`wPji<8*ZAMqI**PQUpoK6`Ve|B!8x?A+Hd6nf(3 zXcjM}z_AlM=^e6 zLtg1f+x@Y{rCSDvhHdR1BH40vgN^MG{%p3*9f)_C%K=rytA*|$-=YEH<7A8iX`!Jo2&Sm-Gh_!5p74;HcDsf#v&ah zOpk*JW% zo&hK=U(w$D>2M(r@;|q8jN0s9A+{{M->@v0>&Y@&mm;&sz4TzVTL{C#;)65IFn5o) zdH*D9RM?v^hd1P{9#8t~Y)`EXT`CVXeWPu1;%nGn$gklM?!h!cZTU3QJEj2vb_|94 zjaY!%UeI2+>yL>6z+H>?6Uj+O4#Nd-W@*|bmD|yG8NT+5PDoWo-zAw(@AvOqo&8ZF zf1y#r^w}4cuok7L+texLv-Tn|US8!iorPk0eUGl7I-?NMQuIw+Fr5WXwRPN`$WME({ z@^oSD7JGfQGYQ(x`Mmp%#?r* z!-JO2n@c}1-qBnpaPrtX73Z&Z9DH6+o@+RnyHuRL8+Riik zEpMuDyt@8W==r8SKZ`V2?uBWuZhm0(KkjOUp0|zK`5(JtKA6lmU;o;5>tAQJ9cSt< z)E3-X!^jXh%`|uOOA!VE&(7d^*Ui$KR@Xe`VQ5&SF~yys;{Mxzvu>XZ-B-r&$RbRR z@j>cFgEGeC=lru6m)mTwGcTCBK8D#zan|?EDw%x?1%BMfTl>Fa`p;i&FV4^%* zzRACP2V{~DUkcf`&2E9V%_O1up{*WXuT7oJK3DhOxe*y z-0U`MneXq!{qL(+Ir=>RF2}H7Z_8QM$v>OL4sK&o6Zd(>FV(P3$PCD+wr8$d&lszk kvu)zopr0GTAf%>V!Z literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..c83d71fb709d90df977095148d9473ed30adae3b GIT binary patch literal 557 zcmV+|0@D47P)S%j)UuNH}_hg`du;Q zPtAakV==AUhv-N#kw%g*ulJ?zfuBDfyO5ww@R#tqOI#>+{D&-6@RG& z0ErT|@i=`9%_Ve-{8CF`69iZSm;rd5PE$oqI#B5^Jp+J!3ETPi?}6uG0f-tt9jNq| zo&nhsw!CmmKwb%3HeM&H{ZdQdrxG?DsPs!EKz9jUo&HkKOw%Q7rv0gb^lW?g v0qlCVz5C0+{;OZf=P;o6li0MMkQ3qy`^Y7;xxTOz00000NkvXXu0mjfX({d% literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..2adedbc95f47b406b7e241715d8119f861fd6310 GIT binary patch literal 553 zcmV+^0@nSBP)gJ6NM(lp^G6T){$3$4%RCms1WYX==YnB_ z@;D5`!m%i0IZ9Zl2u!6 z+s0k92_XMps{5{}(_bk7*KyGGJaPQ!dFTLm${G7$npG6a{G|iPmaz4rNYwLX>6E>= z27l=Q@=DmImW9AD@HwBCyS#z<&w}Hp=l}gPSYPN^9_1?SVPA$QMv&V~j49 z4HuNODg70Ku!~fYF~;uZBSeJ2wbHt989BujG0`zxj75q`aau7}c1Jm^S;xBh!Lsb^ zpZABi@9oY!2m}IwkC;l)2@x@`w4NLviJ-MEyndk&5z_->kM+Qah$*^fq3Dc_?}6Ei zH}4Q;c!S4Mc$sD>wqi-zXf)8cj@>0H2VGWLeOGqY02yJojIV}?b7Xb0Z5X>t0EcG zVLlp-s8*}qt?>|vn-u9}*G^-+H zRbVt4d6ngK0D%1c-Q8o)m0&u@=+A!eDQ>m{vJg~Cab^7*l)>QkjFo3!dwm6GIv@+d zMx(*1h&M&@s4Z{v`S44xub{IEz`v7FnPo6Z5_WcWxVX5W-|u^oG1CFQ%TOL#>xxp! zywaMVkB6^wSP>#(e$kq`HDA%w+Pn~%`-hk_2P8?t(a{n6`}^~hIg|F- zc>8y}4wZJ9NmxY8^j4Pa>_==bj?MRDC)nc)Psf^o*^6V-S>OqoTps#&{C|Onn71(5 zJ}Tn_fj}S-2m}IwKp+qZ1OkCTAQ14wy%!qo`TED$O#Q*#;&}@cS6b&bPt4mPAF?=- z={l?9Jy*fp>y+CcU@uP}#xdWdDRroHv^IZi zY|w7E8Qh*tT34bdn)DN9_*hck7|Sjq)2Y>J@zwEhp$#vsdz}3Nce=&Ltgo*Fu=4ad zgLelEheK{|Ztm;>>h=0POwDI)Z4Dq-=HT4{D^H&T?;Yi`!N%!;%{1lDakqHJ>FFr| z*Kb}^dvZV&MO3TRJ9~ih^YeR{nosu3Jejp82VB2-4Zz9CiPHv~!W_`nnwQr34wzO! z4k)6G9N@}7MK;(vIjex(7r5%E0!5Tj1zZ)V$OikmM_0FP9{V>)AP@*VIR60QrN@r6 S48Au20000?NMQuIw+Fr5P3FZHp{gfkJkk zE{-7;bKc(C$je~B!EB)S^uPWKW?8|IRke<79+5(fKsEj+PTe}kAijzd$OeHA+UErs do<+zqRLLB(=X$x3I}>CpgQu&X%Q~loCIG(1BkKSF literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..cb5286e46c2f0b5e07fbfaa2bd95dd56748e6c70 GIT binary patch literal 1347 zcmV-J1-$x+P)TgL1ii;G+9Mwtme42!&pM<#JLC@M0yM##fRjpsoju2Iv9pmoFn8kK@s!M_655m7?J} z0Dc(Y#nR*?mL?|w1mppJ7~q8;OR#PXkR61)@M8(qjRCTQkQaVz!!-wBdwUD5pMHYQ zSPXyUa#&kilVX4uer&_Lo(bmjd0Je&k5}7Uc)s==FJAnG#l`#Z>oiz!GLgX7_wM0R zD&?o_Yy7$xsfAw`V>Pb@G);qLS@h#iSzNht#n+h!fN(fWU0q!?KR-_+BO`S5=uv-D zVj>}t$z*)*yugo)RLub>l}Z4rGc$f;7zUVGYDTE$E(mD+kV8g)Mqg~(7SgmSqI zB68Eyr%s)!dOmyhEbah^Mx(F+w70k87J#=}TcPV3&Yz1RnM`sflOZC);k$Q1L^yNi z44B!y4PVnVIF5r*C1hD3t3Z_)hJj+S=zcERiRY=QDFDFi>?{BvlgR)89%Qq4 zwY`O(fB6-bWzpQ+97?4U-dtY?5xKvwMbr8^m>JX4)6jJtmSvG`+gvP`kjwp9r6sh5 zEjw+Tn3#ZJ7;ay7_74E4xw*M&rbQ*D@~p80k`}R5j{EQfbxC~V8XEur002ovPDHLk FV1kYObe8}C literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..114ed9a62796252ebdbfc41056895784309b6036 GIT binary patch literal 1957 zcmah~eKgaH8y_o*QE|GW^n#0D3Lz9Vew)06mYZCe=IUj-laZL%_9YS$S8lHIp1h>4 zHRRoByZAC>Ff*PJ5@&Wy0@Q)rU1TE?OzVT1}A@4d4j#s?q?E;=O^4F zLRQpRi$q7%)LYlW_Mun4v=Q6Fp3$av2T!wv4&Un4245YxlYxrcloJ1TQq&b2Q$6zT z=)1Y96h{m>Vc#KLU0KA&vk`?(j<<)ZdU_3i4zLKY@oTROyYF0~F~4`5z7rf9TbB~2 zd9zDiW=o2JLr?fv2PI-)p(y z@fMAZje~=OwvLWx3v6!6U21SMag}q3k9Hdz%`WFe;YlZpUuxH2Bg3lAPeatcTLf#F z!WOj#*6Vl8d@~wncKI?ws@+YWBvpeffd*&5wH1=lgBf6F9zrox3;>(S>^`um~{dn~u-l1$DQi&u;#F z^w8^+BD1Mnxg$(MO^N0k-&?$bQtW%3GV9fgbK;PetW#QEcO!is3T|W7gSxu+EYT!4 z)OQ0@HraSdCGqjPHa|d#&&J~(6Q>WM6b3uk9iF^CZ&QU6HKtfJFqQ2(hObuArY`Q; zjh`kc<)s#3EBdLUT$AgrqjTf1mxy@esqPLBqGx3V)PffMA&nf)}9Xsm!vb7C(@ zbD@4OWMF=nc*~U&DCn57)S^6}w7J8$>S_b4MJ+*wvhK8b)HG5kX!p;Kh|Vi*rliX^ zKI$Y1t`yacLg|e3;O|>I`-Qr?O-&1HA9iWC6%$iOp95C{fr@nnugtZP!#?=I_N`J- z*OAGR0KkM{G?hvXGLOwG(st_m)Ik37JJ5I0x?uj5*D@&{xOFMGN7l^S&P}>-jy0P<4%FrugF zHt?I&3AQS|FOkJk%?=_SAk-?2wt=>(6ZmYY%W+YUYIeY@ERntsJGDw>U4GW&?Y5 zin;3Wk?GR=r(6H(TpFBh7y|D>`sgKCiRO&@8kLxP%#r8x!wGhf|74FjJ)8 zIXE~(i$5IUY49gb8P3;)Xbj32_TziJfKN%hSPfCuQM9P5_j37Xw1MnN2Hnsy5ipRw zP?1`zbDrHDmqabF&|yH2ehQT9N9P-2>@ihrw@Hc;P#1>Z5-Kf0lmCnGp#rC(wju(0 zm7aN5et(R|F+Mo3zqz?NO0Wm}eXF~9Y)lAalQ1X>7~pD0MMieVr5EIEyxF<8Uca)w zUe{te0Ef#}ZO;bvrk0k;MdR<%{t{~M<^9^*d!qPdyIoEI!!0z_xL)6C8FhRGC4S@V zqo}B&rpV=qSc^{tUR=1<)FzEo=NqIa$fkETs~>EhWt;9m{FUZIv5-J)#lf;<9UUD) z4!9!GEN^QwOs=jrhf%j90zyIt;&IddiZ>$S+6L_8x3OypGEs1H6(QsKwZkP0f8Pa( zRnRJ*)7=d1z%cBsKvbeBI9!Pek{K(f4rp~mcQue#7zRad9Q%~azby;U{!wm_pb&kx*3 zdZHg9q|ICBvT2Zz^=2;?NMQuIw+Fr5UwMimW8~7#JA) zJY5_^D(1YswJ`6HgACh;{L?Dx0^T!}u9|dY8%1}&wSL3t*5-I#;TuaeV~Ffam9Er9 zO(LcjOUjZK@gKNi#c|#2?Yq8|zjdp22JHJ3=rs8^vkM5!Em;`#hI^yF^+WCRQ=h*` zG5-JL>@TM`@6(OnOnUO8|K-&3a}jg^*Sv$X30sR zoM+nH3_vkfhL*&LHFtT~7#cQCxp8dcMWLLh)5RDVGG~b$?|UqA{QPUvyw)GtWxCQo zr-we2pUiXpGtcD8vJ%7ced|^Cbglh!$@)N{jDpl7VYmSM?mz}Bq@(gpp3Pcd zyuYyc`Mq7&=H7qN^54QK+)`y}kolpsS?~TFV`aFioMZOlOnxXsfZd_A?sb2{SpW2F zsFZua*df;*_MTzx&$V1Dq!Kqfrq?}YdgXS*=knb9Kc6!wE%N)#_JM=BGq5U96c||y Mp00i_>zopr05eC`GXMYp literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..181c6f2ace7d78bc39fb1fbb6737433dce055fee GIT binary patch literal 472 zcmV;}0Vn>6P)0AWFrz!>A2Rs{eQ3q{Okzo2PVxNdjlMTor&)@rp?jwdXW*@o+O@%G(& zv|1;~WVWS@v)1bXK>i6>`vS;D1xPzU+Nc0&2S{6N0UXCkB1dYLE`)+$3QeoxWu=1e z!y!haQIfglWS@YA-vHnD71!!Q=?Y<2I*>aKHh?Zm}&ojxomTbpty)kI-tJ#AYx}bKc<^N4Nl`QVBqG z$YexvQ>ipOua39x-eY}z1F2NnNDkKlF-#wTEPyZ;Ko|=kj0F(J0tkyOK&@6w zVjQ80?Y3yXX`u_TPUjSkvxMixBEC19I668?a$Ms10n-Oy&sTu&`WO_8Bb^^`T^H4A6_rXQ$=JVa+t%gRue9k;1V=I7wr&0IPts$!9EeEph~$gg z-rg3S0O@?X<03C=UuI@>E|){Q-8R-0Fv|H!h+GF)mIcd_d*0IdL_|bHL_{V;u5yy- zj~{oDD`ED>6Opj7|3bvD$ZJ5*AI~C~6Iy_){qg0p%OV)kvj9PV{DV{)g?s^%lT&b< zB^JSe(7vElDh;I+Jg*KwW`o8!i0zD%+8{A5*c&R01rWvp2x9?+u>is%_X&@Ze%2r+ zx~NU%#};4|Hb`9EIUlFfIUV|jYLoeq1#n%r>sA4h78e(>wzd}gcdM&!P%gXIZY}U_ zeqI9@_=_b|`8^BZ`@W@=(f}@R6%hP>kiieb!omW8=#A60S`80pXE8BxAAfGLp{vy@ zN~MyO$z*QT<{0EhEli8;cHjA-uK>x(?qzdx6F~fyp%0A)&N`>~_~|oz-?vJo5&)pp zYTc>;L4MpRx!?Sen&dD8oP&pY0GZ7HFA4zM-FHDmL_|bHL_|bHL_|bHL_|bHL^Nc5 zb#O^{he_v~aN|J+o40TJ|Fo1+L+{U&%s1s)cXY2lcH6dfx$I(catiC~8?g^ssZ_e! z+WR4$pR{WQ$Y!%$H)#rP*fBjljY7TvAihUG=%pXTP4eS<^ly`&v}*-uwOU;h;QPL{ zv)j<;=ND);e*lQ@(GPm*2XT}9xE}r6|Pl%0kX3p6^_RRO3_j2CnkN16^&+~ond$>EP z9@9Psfk0GUoE<#n>%4sQ995Ff$aK;e1fs0v;$V9oqz3zQqJ4RO-kAM|M zPM(;5Z9Kg5AG~8_&_PIjYV;PS$9(bB_0}2a144pk_A3VBGqL&(w#OogWDSjEQhOp{ zz`vNt`I7I`eN;s5J%#+@6J|$Y;{Ln{S$a?}DI&s%QascgIkSvAXuto6(95bxcD0_v!b_G#r+uk3tL~>T?&EC z1tE}LufB)Bbf~ZTnTe+si=7?4=k)B4|i5^mghYH9wQg6SsenU^FUdHPnYCe=St7DL|H*3jw>aViZK=)^P4p|yV$*G!%>!Zem(=5XjBw|TgWqAfc{ZS2t*4l%G9Nk?Wa`~{wYqp=N)utpK)2N)I)t%bWrNWoR9N)Dz}s4=oE#Pfg-5n}#+uq8AMHF<)0 zt)&DqD#Wh>*l}%Pi_J@q>Fu)oPe+W5Z?>h^j-kq))7Q~b!zck3S|^?GoF!C%TZ_c} zmBhfVv31?nmcMyd*M3Yc$wXp;FH*g5bf0Fwk;zFvp0PU)ECN{pZ1O+haCiWf6)SWa z7+7j*;;k2F=AblNWlYPVL0#%$qWvT!cVXehGM_&+tM$3+>S(Kq;ZkDK&U{!Msa80M z2j+&2CnSoBOo{qO$v%S{`d9N^W^=Vqx2(b*35Ak3E(Z@fh3lg~->d9ZeuecuY|KAX zFmHQLF-V9}pb!9^O+;6gns8!=M_G@S`PSdnx`x*Vd8}u1n~I$=f&#rYp_4I{Cdio; zy1yz#AKjXnXw*I{bshG)-IdVphx%wmWbH)@D$0dM>Lh2+a&T$*yx_I5#sk7ruEXOX zV`>vQJ~frB4mN*&)nIhTC%*NkkbUL-T}kXQY&P(XSk9XsZX@ouc*pnh5clI@atr>s zdSQgOIJ+BYJOIYnZ(YjzN9cEpi+xFcvy%OEl7e`VO27v{jN>NKeCVA?|85Uq3AP6^ z$YQk-wObQ|t>#(3eL*D2V>DOcGzdR*ncPOrW*?_IVk&*dTgfLCf8lRl>GBAAN*@T_ zmcuYak|L#5n`fs2li2m=OkeIT;}S>>6B=5v?4}tFOR0ye#)A~T#2QM+rA%Iby*%%k zUS1Ac+nX}2sfmydou~3L92+x1HZ-gDExBDBX^=^4@o)wY@{{ec8lMT~Fwmlnrj)M$~$EaURQ*Ea!QX*si{ zGt8Q}bl?rw7{#q6Ur;JppFYK$X(zV=O=~_z%>l)gWg~-e<76&? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/meta.json index 4cbb72e1ac..3ba53e431c 100644 --- a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/meta.json +++ b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/meta.json @@ -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 +} diff --git a/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/pipe.png b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine.rsi/pipe.png index 620ba905bea43a0cb2a7ae8d2c2647e6ff9ec5f9..e0209a7bc8967f8f7d89ebbe4d292f5f2aa70b0b 100644 GIT binary patch delta 281 zcmX@ew3%sway`Q@PZ!6Kid%1QD)zM)h#dQPyu`_=`8A_~#RUnL0;%}*aVEQ=0@YuCd-PFian{{{n{?NiyuOY2_$>-}1*-_NOVdeeGKCO;;Lwud(v&wM`fR$D13bn55$B0up9CcL{r c+8c!Jr*{Y$N?y=CvKPenboFyt=akR{0NILs<^TWy delta 295 zcmV+?0oeYt0>J{1BYy!1Nklu>>1#1+se zEN9>VSOfwp8q9lD&~&=#|ED%9W+q=S?A*jbVHoaZSxTPgGLEBkT_^KA-_F$fdG&Db z;QPLKo+oh}OPZz<1i|TAP6lu=#>l#^mufg2z`pNdjJZ_9$$tR0Z4;5l7jQKI00000 z00000zR0P4n#f~6cbw1es+qN2QpHc~67zT~D tpQk7a^(Q&i0U)ZX(rga^007{N-2n!mFe765T3G-9002ovPDHLkV1kS9hco~H 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 index 0000000000..f8a645528c --- /dev/null +++ b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt1.rsi/meta.json @@ -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 index 0000000000000000000000000000000000000000..cb6fc36c97503fbcd194e1f7d3288b7198b093e4 GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=|2$nBLn>~)y{XvOVjyztp;1{N12SPHoM4oO;YggY$WFsG3@L6Botm+9=8vBu1r|K}?`WSym-d-+-ABZ=f5 z-P1vzY^G<S?R4GJ7bzSnj>j<{qp)qp4dnzi@=M@`k++x|vA&tbS0 z73g(WzoGViecFL~CZH?8;DOto@|r6W$^Fm6Yc188EoM!Q%8tAq+LpMZgd_hYPv+XC z>#|R7dh^Nq!9hI+h6gG?3|@O1TaS?83{1OR3K Be)9kT literal 0 HcmV?d00001 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 index 0000000000..f8a645528c --- /dev/null +++ b/Resources/Textures/Structures/Piping/Atmospherics/thermomachine_alt2.rsi/meta.json @@ -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 index 0000000000000000000000000000000000000000..4a52081bc897845bcf2b0c60eea5278b194c8770 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=e>`0rLn>~)y{XvOVjyztqxoe{ zPTqCw2Oc;i3mnkg!7Tp3C5Ey0P!StngR8;|t*|$0i`%wH{(Z&U9!#bT4`;~u5*{KGaNFQqQIfzDRgp^&mxUoOZv7m&Y2Rl>HY82*VXb3 zTf?RVedm5)(RW|CAQk8e2)J|NcHC^kWAh$s|0;@OFECTzdTmqg?4HLzrYi1v%agfw zX{OZ4&wsMlADA2t)p201#m{Gbk8k{&8$Ipl$+$SZu5G!$^Vhw$+Ud)XIjgFebq>pg z?|=6)&sf%ZJ=|r9j`#Dqn#-kEyq*=zz@Yb+A=uVXQZ6B*2V|P3tDnm{r-UW|pzMOz literal 0 HcmV?d00001