From 77fa796a3b081549363fb781f2cad9d1f6d9bad4 Mon Sep 17 00:00:00 2001 From: py01 <60152240+collinlunn@users.noreply.github.com> Date: Mon, 12 Oct 2020 05:02:57 -0600 Subject: [PATCH] Rotatable Pumps (#2223) * Pump textures * PumpVisualizer enabled state * Pump rotation * Pump tests fix Co-authored-by: py01 --- .../Components/Atmos/PumpVisualizer.cs | 74 +++++------------- .../Atmos/Piping/Pumps/BasePumpComponent.cs | 60 +++++++++----- .../NodeContainer/Nodes/PipeNode.cs | 11 +-- .../Components/Atmos/SharedPipeComponent.cs | 14 ++++ .../Entities/Constructible/Ground/pumps.yml | 49 +++++------- .../Atmos/pressurepump.rsi/meta.json | 51 ------------ .../Atmos/pressurepump.rsi/pumpEast2West2.png | Bin 281 -> 0 bytes .../pumpEnabledEast2West2.png | Bin 386 -> 0 bytes .../pumpEnabledNorth2South2.png | Bin 896 -> 0 bytes .../pumpEnabledSouth2North2.png | Bin 823 -> 0 bytes .../pumpEnabledWest2East2.png | Bin 408 -> 0 bytes .../pressurepump.rsi/pumpNorth2South2.png | Bin 332 -> 0 bytes .../pressurepump.rsi/pumpSouth2North2.png | Bin 320 -> 0 bytes .../Atmos/pressurepump.rsi/pumpWest2East2.png | Bin 272 -> 0 bytes .../Constructible/Atmos/pump.rsi/meta.json | 1 + .../Atmos/pump.rsi/pumpDigitalValve2.png | Bin 0 -> 982 bytes .../Atmos/pump.rsi/pumpManualValve2.png | Bin 0 -> 1043 bytes .../Atmos/pump.rsi/pumpPassiveGate2.png | Bin 0 -> 1589 bytes .../Atmos/pump.rsi/pumpPassiveGate2On.png | Bin 0 -> 119 bytes .../Atmos/pump.rsi/pumpPressure2.png | Bin 0 -> 1303 bytes .../Atmos/pump.rsi/pumpPressure2On.png | Bin 0 -> 1932 bytes .../Atmos/pump.rsi/pumpVolume2.png | Bin 0 -> 1146 bytes .../Atmos/pump.rsi/pumpVolume2On.png | Bin 0 -> 1952 bytes 23 files changed, 95 insertions(+), 165 deletions(-) delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/meta.json delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpEast2West2.png delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpEnabledEast2West2.png delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpEnabledNorth2South2.png delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpEnabledSouth2North2.png delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpEnabledWest2East2.png delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpNorth2South2.png delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpSouth2North2.png delete mode 100644 Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpWest2East2.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/meta.json create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpDigitalValve2.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpManualValve2.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpPassiveGate2.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpPassiveGate2On.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpPressure2.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpPressure2On.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpVolume2.png create mode 100644 Resources/Textures/Constructible/Atmos/pump.rsi/pumpVolume2On.png diff --git a/Content.Client/GameObjects/Components/Atmos/PumpVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/PumpVisualizer.cs index 26e86403e5..04247bdae6 100644 --- a/Content.Client/GameObjects/Components/Atmos/PumpVisualizer.cs +++ b/Content.Client/GameObjects/Components/Atmos/PumpVisualizer.cs @@ -1,14 +1,8 @@ -using System; -using Content.Shared.GameObjects.Components.Atmos; +using Content.Shared.GameObjects.Components.Atmos; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.Graphics; using Robust.Client.Interfaces.GameObjects.Components; -using Robust.Client.Interfaces.ResourceManagement; -using Robust.Client.ResourceManagement; -using Robust.Shared.GameObjects.Components.Renderable; -using Robust.Shared.IoC; -using Robust.Shared.Log; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Utility; using YamlDotNet.RepresentationModel; @@ -17,68 +11,38 @@ namespace Content.Client.GameObjects.Components.Atmos [UsedImplicitly] public class PumpVisualizer : AppearanceVisualizer { - private RSI _pumpRSI; + private string _pumpEnabledState; public override void LoadData(YamlMappingNode node) { base.LoadData(node); + _pumpEnabledState = node.GetNode("pumpEnabledState").ToString(); + } - var rsiString = node.GetNode("pumpRSI").ToString(); - var rsiPath = SharedSpriteComponent.TextureRoot / rsiString; - try - { - var resourceCache = IoCManager.Resolve(); - var resource = resourceCache.GetResource(rsiPath); - _pumpRSI = resource.RSI; - } - catch (Exception e) - { - Logger.ErrorS("go.pumpvisualizer", "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath, e); - } + public override void InitializeEntity(IEntity entity) + { + base.InitializeEntity(entity); + + if (!entity.TryGetComponent(out ISpriteComponent sprite)) return; + + sprite.LayerMapReserveBlank(Layer.PumpEnabled); + var pumpEnabledLayer = sprite.LayerMapGet(Layer.PumpEnabled); + sprite.LayerSetState(pumpEnabledLayer, _pumpEnabledState); } public override void OnChangeData(AppearanceComponent component) { base.OnChangeData(component); - if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) - { - return; - } - if (!component.TryGetData(PumpVisuals.VisualState, out PumpVisualState pumpVisualState)) - { - return; - } - var pumpBaseState = "pump"; - pumpBaseState += pumpVisualState.InletDirection.ToString(); - pumpBaseState += ((int) pumpVisualState.InletConduitLayer).ToString(); - pumpBaseState += pumpVisualState.OutletDirection.ToString(); - pumpBaseState += ((int) pumpVisualState.OutletConduitLayer).ToString(); + if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) return; + if (!component.TryGetData(PumpVisuals.VisualState, out PumpVisualState pumpVisualState)) return; - sprite.LayerMapReserveBlank(Layer.PumpBase); - var basePumpLayer = sprite.LayerMapGet(Layer.PumpBase); - sprite.LayerSetRSI(basePumpLayer, _pumpRSI); - sprite.LayerSetState(basePumpLayer, pumpBaseState); - sprite.LayerSetVisible(basePumpLayer, true); - - - - var pumpEnabledAnimationState = "pumpEnabled"; - pumpEnabledAnimationState += pumpVisualState.InletDirection.ToString(); - pumpEnabledAnimationState += ((int) pumpVisualState.InletConduitLayer).ToString(); - pumpEnabledAnimationState += pumpVisualState.OutletDirection.ToString(); - pumpEnabledAnimationState += ((int) pumpVisualState.OutletConduitLayer).ToString(); - - sprite.LayerMapReserveBlank(Layer.PumpEnabled); - var pumpEnabledAnimationLayer = sprite.LayerMapGet(Layer.PumpEnabled); - sprite.LayerSetRSI(pumpEnabledAnimationLayer, _pumpRSI); - sprite.LayerSetState(pumpEnabledAnimationLayer, pumpEnabledAnimationState); - sprite.LayerSetVisible(pumpEnabledAnimationLayer, pumpVisualState.PumpEnabled); + var pumpEnabledLayer = sprite.LayerMapGet(Layer.PumpEnabled); + sprite.LayerSetVisible(pumpEnabledLayer, pumpVisualState.PumpEnabled); } - private enum Layer + public enum Layer { - PumpBase, PumpEnabled, } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs index 37e08ad5e0..d3521e9c8a 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs @@ -4,6 +4,8 @@ using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Shared.GameObjects.Components.Atmos; using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.Log; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -28,7 +30,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps UpdateAppearance(); } } - private bool _pumpEnabled = true; + private bool _pumpEnabled; /// /// Needs to be same as that of a on this entity. @@ -55,11 +57,50 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps base.ExposeData(serializer); serializer.DataField(ref _inletDirection, "inletDirection", PipeDirection.None); serializer.DataField(ref _outletDirection, "outletDirection", PipeDirection.None); + serializer.DataField(ref _pumpEnabled, "pumpEnabled", false); } public override void Initialize() { base.Initialize(); + UpdatePipes(); + Owner.EntityManager.EventBus.SubscribeEvent(EventSource.Local, this, RotateEvent); + Owner.TryGetComponent(out _appearance); + UpdateAppearance(); + } + + public override void Update() + { + if (!PumpEnabled) + return; + + PumpGas(_inletPipe.Air, _outletPipe.Air); + } + + protected abstract void PumpGas(GasMixture inletGas, GasMixture outletGas); + + private void RotateEvent(RotateEvent ev) + { + if (ev.Sender != Owner || ev.NewRotation == ev.OldRotation) + return; + + var diff = ev.NewRotation - ev.OldRotation; + _inletDirection = _inletDirection.RotatePipeDirection(diff); + _outletDirection = _outletDirection.RotatePipeDirection(diff); + UpdatePipes(); + } + + private void UpdateAppearance() + { + if (_inletPipe == null || _outletPipe == null) return; + _appearance?.SetData(PumpVisuals.VisualState, new PumpVisualState(_inletDirection, _outletDirection, _inletPipe.ConduitLayer, _outletPipe.ConduitLayer, PumpEnabled)); + } + + private void UpdatePipes() + { + _inletPipe = null; + _outletPipe = null; + if (!Owner.TryGetComponent(out var container)) { JoinedGridAtmos?.RemovePipeNetDevice(this); @@ -75,23 +116,6 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps Logger.Error($"{typeof(BasePumpComponent)} on entity {Owner.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } - Owner.TryGetComponent(out _appearance); - UpdateAppearance(); - } - - public override void Update() - { - if (!PumpEnabled) - return; - - PumpGas(_inletPipe.Air, _outletPipe.Air); - } - - protected abstract void PumpGas(GasMixture inletGas, GasMixture outletGas); - - private void UpdateAppearance() - { - _appearance?.SetData(PumpVisuals.VisualState, new PumpVisualState(_inletDirection, _outletDirection, _inletPipe.ConduitLayer, _outletPipe.ConduitLayer, PumpEnabled)); } } } diff --git a/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs b/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs index e2c3aa4f32..f1063a01da 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs @@ -96,16 +96,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes void IRotatableNode.RotateEvent(RotateEvent ev) { var diff = ev.NewRotation - ev.OldRotation; - var newPipeDir = PipeDirection.None; - for (var i = 0; i < PipeDirectionHelpers.PipeDirections; i++) - { - var pipeDirection = (PipeDirection) (1 << i); - if (!PipeDirection.HasFlag(pipeDirection)) continue; - var angle = pipeDirection.ToAngle(); - angle += diff; - newPipeDir |= angle.GetCardinalDir().ToPipeDirection(); - } - PipeDirection = newPipeDir; + PipeDirection = PipeDirection.RotatePipeDirection(diff); } protected override IEnumerable GetReachableNodes() diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedPipeComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedPipeComponent.cs index b8e3955d69..4d0b5ffce8 100644 --- a/Content.Shared/GameObjects/Components/Atmos/SharedPipeComponent.cs +++ b/Content.Shared/GameObjects/Components/Atmos/SharedPipeComponent.cs @@ -144,5 +144,19 @@ namespace Content.Shared.GameObjects.Components.Atmos _ => throw new ArgumentOutOfRangeException(nameof(pipeDirection)), }; } + + public static PipeDirection RotatePipeDirection(this PipeDirection pipeDirection, double diff) + { + var newPipeDir = PipeDirection.None; + for (var i = 0; i < PipeDirections; i++) + { + var currentPipeDirection = (PipeDirection) (1 << i); + if (!pipeDirection.HasFlag(currentPipeDirection)) continue; + var angle = currentPipeDirection.ToAngle(); + angle += diff; + newPipeDir |= angle.GetCardinalDir().ToPipeDirection(); + } + return newPipeDir; + } } } diff --git a/Resources/Prototypes/Entities/Constructible/Ground/pumps.yml b/Resources/Prototypes/Entities/Constructible/Ground/pumps.yml index 921f9d0263..047ad284fb 100644 --- a/Resources/Prototypes/Entities/Constructible/Ground/pumps.yml +++ b/Resources/Prototypes/Entities/Constructible/Ground/pumps.yml @@ -9,48 +9,35 @@ - type: Collidable - type: SnapGrid offset: Center - - type: Sprite - - type: Icon - sprite: Constructible/Atmos/pressurepump.rsi - state: pumpEnabledSouth2North2 - - type: Appearance - visuals: - - type: PipeVisualizer - pipeRSI: Constructible/Atmos/pipe.rsi - - type: PumpVisualizer - pumpRSI: Constructible/Atmos/pressurepump.rsi - type: Destructible thresholdvalue: 100 resistances: metallicResistances + - type: Sprite + sprite: Constructible/Atmos/pump.rsi + - type: Icon + sprite: Constructible/Atmos/pump.rsi - type: entity - abstract: true parent: PumpBase - id: NorthwardLongitudinalPump + id: DebugPressurePump + name: Debug Pressure Pump components: - type: NodeContainer nodes: - !type:PipeNode nodeGroupID: Pipe - pipeDirection: South + pipeDirection: West - !type:PipeNode nodeGroupID: Pipe - pipeDirection: North - -- type: entity - parent: NorthwardLongitudinalPump - id: NorthwardLongitudinalVolumePump - name: Northward Longitudinal Volume Pump - components: - - type: VolumePump - inletDirection: South - outletDirection: North - -- type: entity - parent: NorthwardLongitudinalPump - id: NorthwardLongitudinalPressurePump - name: Northward Longitudinal Pressure Pump - components: + pipeDirection: East - type: PressurePump - inletDirection: South - outletDirection: North + inletDirection: West + outletDirection: East + - type: Sprite + state: pumpPressure2 + - type: Icon + state: pumpPressure2 + - type: Appearance + visuals: + - type: PumpVisualizer + pumpEnabledState: pumpPressure2On diff --git a/Resources/Textures/Constructible/Atmos/pressurepump.rsi/meta.json b/Resources/Textures/Constructible/Atmos/pressurepump.rsi/meta.json deleted file mode 100644 index d8390a7ef9..0000000000 --- a/Resources/Textures/Constructible/Atmos/pressurepump.rsi/meta.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "version":1, - "size":{ - "x":32, - "y":32 - }, - "license":"CC-BY-SA-3.0", - "copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da", - "states":[ - { - "name":"pumpEast2West2", - "directions":1, - "delays":[ [ 1.0 ] ] - }, - { - "name":"pumpNorth2South2", - "directions":1, - "delays":[ [ 1.0 ] ] - }, - { - "name":"pumpSouth2North2", - "directions":1, - "delays":[ [ 1.0 ] ] - }, - { - "name":"pumpWest2East2", - "directions":1, - "delays":[ [ 1.0 ] ] - }, - { - "name":"pumpEnabledEast2West2", - "directions":1, - "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1 ] ] - }, - { - "name":"pumpEnabledNorth2South2", - "directions":1, - "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1 ] ] - }, - { - "name":"pumpEnabledSouth2North2", - "directions":1, - "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1 ] ] - }, - { - "name":"pumpEnabledWest2East2", - "directions":1, - "delays":[ [ 0.1, 0.1, 0.1, 0.1, 0.1 ] ] - } - ] -} \ No newline at end of file diff --git a/Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpEast2West2.png b/Resources/Textures/Constructible/Atmos/pressurepump.rsi/pumpEast2West2.png deleted file mode 100644 index dc07973864d14a63d8a72dec3ff506bad1385d12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 281 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Constructible/Atmos/pump.rsi/pumpPassiveGate2On.png b/Resources/Textures/Constructible/Atmos/pump.rsi/pumpPassiveGate2On.png new file mode 100644 index 0000000000000000000000000000000000000000..88023ac0836d107d9428101d724fa93521dd30b7 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=cAhSdAr*7p-aN?3V8FrbpkDf4 z_YKou&Zrl6St?mRd9VQ0*yw9#TQkS3Py@1oK)#@x(ct(iAj?Fy@hjKMC#pH~LE@gS KelF{r5}E+asUQph literal 0 HcmV?d00001 diff --git a/Resources/Textures/Constructible/Atmos/pump.rsi/pumpPressure2.png b/Resources/Textures/Constructible/Atmos/pump.rsi/pumpPressure2.png new file mode 100644 index 0000000000000000000000000000000000000000..7401c6bfd261806d81437362fa416d4e98c9dde1 GIT binary patch literal 1303 zcmV+y1?c*TP)zgUtSBGY2E6nyZZwXwm8sX~14slkarRzO-!56)~QL0W5eqiyN@Kxid) z-}~>(+cz_B7T}<}yPHNL5t_|r>CDUw^?JRO#||%c`gd6oQmt04Ty7aV{Bt#c%XM;@ zVHhwB!?Fk`{acCvr>It|P!t8SEL*n4Wr2mBBuS7Y$+C!Mkt7M9=5pwM_z)MKKE-zy zY*~r`7K*LLFbq&iL8 zGz|bSIy#D-ogHj%Z$sC0S|}9A-(PJH#bOcfz55Q{eCutfXU<}ERp++F9mBh+6s}*n zf`w?5+c^)as?uOEfY;jE;XUs~XXiNtg8}eHA@@w8cYM4q0$NF1TRV1BDdd-yO)b1| zH^6Qxh3l!5WdXeOj*lZ84r6O;3wwKe+;%KQz}VOrHa0ep&*!-X@Uojq;R_o&z)}QE zI~W1|*RCNH3So0|6Z`x7+;+Gdz%Bv2Y|YJKYiFt z1OfppFE1k&i=m^VgWDEY1F(WbCX?ZIY!$mIQd|vCsZ;>eS7us`q9~x0TCNCjjRJ%a ze6qfd?gtNW;n_2MZ%G25f4eGD+&O>{;%Ec_4(<#YhJkPVe*7AbW5t0<(7$45h*gE1 z*cf3wuPBOhRpDA8P9Zi&9r7;_2m}IwKp+qZ{`;J|qR~v{^;MO~Uxfy8nv(X>(Gl2d zG5!;EnPfSdhKN{csWJ}FNB7ut+FJd7YMI@QT zLNto^<8j=L$D!T21^vbiT)ll8E7Q~PfBqRpMl`Ih>WIZ+rj5}2JOG##q{d||^LzEh zZV!9^Pm&}g5($iqXz1)bhul|Ro4%NDriE#XB$Lo}9g~xjb+(z`THmtI=QICcRaTeF zg=)15LWsHc?(6HT`yLt^!d(D9pAR~K{{DWf0C=OP2eK^T@+ChKi3Bp43-q{LN=q9`br%jW;=JoY{RqDL1O7XkdWN3fpD z;d$v8KmGg*G)=?O(h@3_3SK`v1R=z{{$+F>9)ePebUF=LmZ51HbX`ZeTtPnnsLmJj z&9pRXoSmJ8qA2FQG~OQo5Rb=0YkQiNnQGs|Ef$MS=K#0cZMJl!QmJcoLWmh*EE?D` zJBLyVS(eS?VzJnC4sg5O=5JQPuB|2!Lc}N_5C{YUfj}S-2n7F2{seYLZkuYb3K{?a N002ovPDHLkV1k>GPr(2H literal 0 HcmV?d00001 diff --git a/Resources/Textures/Constructible/Atmos/pump.rsi/pumpPressure2On.png b/Resources/Textures/Constructible/Atmos/pump.rsi/pumpPressure2On.png new file mode 100644 index 0000000000000000000000000000000000000000..bd880ff51fab98f6fec75234fc6d6c4b158af8ad GIT binary patch literal 1932 zcmZ`)c{tnI8vZ3nP^rC9t+l-~MvL^SWlBX!2elO)Rmu-hw3b0zX^U8Eo7OUIZMVwU zN0HW&s3lQ~_M(WO_9dMNVrfNG(j+(ir+?h%-uHRFbKdiQ&+|R!JI{O0$++lbgOFC0 z1^@tIXNz$a&84D9kc5fG2U!0j004Kh!<@Tx=jp~A80>Z#=>JsW<>$`sZbQ!vM3Ky( z*Yff*etm#_ezU-mk!M`|`rn^5lMWI|oF(_Q#wSLy>zsf3DgL676`X*%D zM=^P6F1?!4d-3E+HInwM9EO{0>c3%qgR6M10!%-~Ar;|Ku?nBqiYl4jmuO(xoqOn1 ze=oh_{%#qM;w@m`B52XGAW?5HVLj*VQA-`FuBeL2{6h@GEJYjsgx!NU7hvI_*?6j= z3N4Re^onaw(%8vMk8A_nk1759+p0MgS&HIEm~Cn+-RY$QA9;6M)xcv)1+FxW#Fp;^#yLp*>>cr>~eaz`o%F}m;u$`jeO_zdV@F!CtNiZ-<#YJ#MMJsPDE^(Z8P^q z7RJkJ;*Y5FCAsbIe_GSHZ?ljgXmEbaj`>Z-8qGR4NtoD-Up;^_m&dH_tNhZGoCni9 zp<RvkJbehg7O94~!R==EgbbDuu$^Uibszc>_H76Kbuum6FEDU(@nRg3*g~Sa>fSGO z=%Z>@aDy1TL98uG3^VvuN#U#VQsI{la^?(JEGP@=x~fmo%{6`4ZivfyUlF-J0oopS zn&EgJ=bdN=tFC+g*+k#yj_*VbS@4Jmt1D0W$_qbgd(KxNvm_R29gjNPikDtcs9Y)< zeq8%IYQ;e*Kk#}9Aw^DJUJqR>wASVgPz*X@wA1z53{LblP@EG|Zm`>6>NqA{Tx@aL z*mzmMzw-6V*sw&qiERMInEU%Ph>_!o);Y6nnwzsVj_Kh|fralKoFOYt5$ee_84r*G z;|ab(zbJl4U2gxlap~LoDF^_>FoR91FHX1ctvs15rq zS<^LDOi0KH?cDTRvzeoH(}G2&L@%FM#I#3Ctp+obBgegFbzBn3S-ab+O>$MBOT2>U zh$RgPHA4B0RN3yMF4V08X7Z;eq*j+|396wln*mHuPe&}jkpi0XU|LwsqLX_Y1Tm4X zcDTCXLajG05=tga*8%7HWj7vv+fIaYl|`hce?7&9Qq8Ic&d!62quCyK@n)1*6s-3CVOug- zY-1^CwBqD@m!$tcxWC9;c-LHjkj!6Jb7f5iQp#jSrdizC*FCc|IH-19q53)Zye}o1 zr@ZxGgi3|_Wj)TitC9-w<1XDg4{ES(gY+S!mg4<4f`+NVE=H{-! z%+IEoeDkMHKc=i2aJ=njaT(u)Tvv2B_kH-{+N5L5|7W|?SD3v z=}B1C(+UFK_d(>_Ihja-6~(S|6y^(nq?)-zSkifFFvFEKqkfX6M`5+S1x?(!JKm zg?jTs;pTgOOr`p(v;V5Pe&2*dqW`_S{<6MP4Um%*2Y~kI4Jg2xYJvkJb90@G9thTC zv@jRxtDo<+%P)+)O2Mn;yZ!`p(P&D5Z&Z{55W!(x0lL_1b`sX;1vnGe0GYZxz0%~% h$#?v3CoppbkY&a)@omC>tLT>n?9Mx38mxSi{sS1((P{ty literal 0 HcmV?d00001 diff --git a/Resources/Textures/Constructible/Atmos/pump.rsi/pumpVolume2.png b/Resources/Textures/Constructible/Atmos/pump.rsi/pumpVolume2.png new file mode 100644 index 0000000000000000000000000000000000000000..9612cc03b3f4f911acbabe8a5205e519a3535242 GIT binary patch literal 1146 zcmV-=1cm#FP)y2OL01}8$c0;hMcgLqfjw2t)NMOU})2SPeY@B6;@ec!#i z``-Z)*tX4=mX^5Zd3Mp31fVg%6 z!!ST8MWIlLr2w!ji=Tas(!Xun+_Egb_{qoIvMi+&p`nigmSyo=E(ZWuUS7uD-X3;$ zcj3A&Z?#(F{L#_SZnyE#haceG_uhwf`3knTU1?j=2U6E{;krG?A|a!|vMip>W&i-G zYbkWQ4B2c3p4X5nfYMI9u&|&qT$-`5OYpn~R=@lTTU+-rHg-wc)`dJ16hu*g3!Q){ z&U2(!&1Nv4PUE-zeH<>aL{WgDJD}BS z5zlMjRp$iH4xZup^FQEu4UFnESdh!*;5ZJ-MtmlSyPU8PsYutgfzNVq!wtmQ(^5W9W9fa2zKVO%On2ij=e@CWu9lKraED zbL9d^9R&y>_L{_-X6D}^BEKPp8^dJQ0ioYLmvAhunAF@~?xY5a2cF21{c zTRDhf`B&T-5~^?a07K`D$`hE8Mr86@#;G81}f>32mBoYXM0ECe6+Iwnh3c&eK zWz_3+ymR9QC^c~FW*U`B1&-qY04_g%3_=KmKSIce)kg#vEf zOk;9#5~*vcfnpG`&d$z;^AdAnjD<=T=Nz0|2VkYUtoR zcA8DR>YU)mpMFL@pAW~qeRv2$NVp9Elu~rN-S8a%CJzt6IS>Dr&*xFA)!_SG?C<|R zPz+-1=H@0$(+uZwc7Bvn5Zku7$OiD2%+#;_A0HnNy#|brkB4n0DlN7})%)AOzXShn zOuOA4dJRY>li{{duti4)LC{mT2eO9$?omLa(P%UpjYgxk$Jm*PnB4=*d!>wx9nt|!p?qHbZcYAgpoYW3?o%SDk(X&n4$oeLFs0Wn%Ti;o0Hzw6|{f$}1 zU)#dl_04v)2tr~aetIbtv|A)g6kc97N2J}n%~tMgJV_0>_KU^a=FLMKcTM+s%illIKDc`_f`8ek)q6Y3iptTi*;1Zpx--8iQ-X`ic}rRFx&XoRcBLo`)O z5qNP|V@pf^92s+h%2rr*hrgwBH*I5G#xKn#pO&ABD*m`}j0g|8A+!F zJ4Q4apsNq}2!oyk_J}>Jr5|mlbV6)MT$os0)G7J>Lfk|PTksCPV&3U(w0fCEkKSA3 z%(5OMb|%nTNb9d!RCK@jSV12=lpMpku6i;2ZF*S(uHO9a;T`-jSR#_CJ7W(Is$=+% z@TE9~c(bt#LAa0GC*rdjkz(r*;{n^}>{@nA*F+u#En1)BEQ-%-I~kBZzkZ-3;o4ln z&1)!&>QM@sTJCYLk3ZIcgMiZ4Pb&IC5qX?sknT&>Xd#09=@yTiHVo3O6N-@THTLC4mtZQPukh}P;Q8je&q(WG zh>-1a^9eLa)GR5|^>5npYMvY~bxQtKyvQ_b79|KM#F5{9PAJ4}tuxvB6J1Dt3*{mG zKb2UPa@K7@75FJ*_jLV75w#hRzkuBryKPRp{s7IiJ`|ctLuZSi}f1KXo(?AgI}yI~zL9bqc}&w@QT4{>&MyJ=vN5nbyb zpklr{#J=5?gjpoc=(IOAnMJ0gbNg@)Dg(8|TSAk^^`}cn1rShkRd?zR%W>#SgRWSPlESGx;$wLL2T132ER z1f0jm{ey#JZ{^wV&jHkY8ndjrH6CE60Cf8UR25expQqRVGt1{SkJ-_L@DQ0;aDj2I zu)1NURmv}{2==>FZO)8E7%57b4aI>|(;;?{6*+|Xc@(31_YjJe!vl97ZWcgmm{D_2 zd!UL<-%9B*Lwc-r6U0*j4$kRU2LFt_wdH3#t>j$ISyb-n%c)3f!yj4~T$p~kp^`W3 znFn>i9y@}byH77@#X68_@rdBF8{6w{Nzz597!6k4+9#=Yg#YOsic+c^@v+Cu?_K%x Oa}wp@