2022-07-15 08:46:30 -04:00
using Content.Server.Atmos.Piping.Unary.EntitySystems ;
using Content.Shared.Atmos.Piping.Unary.Components ;
using Content.Shared.Atmos.Visuals ;
using Content.Shared.Examine ;
using Content.Shared.Destructible ;
using Content.Server.Atmos.Piping.Components ;
using Content.Server.Atmos.EntitySystems ;
using Content.Server.Power.Components ;
using Content.Server.NodeContainer ;
using Robust.Server.GameObjects ;
using Content.Server.NodeContainer.Nodes ;
using Content.Server.NodeContainer.NodeGroups ;
using Content.Server.Audio ;
using Content.Server.Administration.Logs ;
2023-06-28 14:28:38 +03:00
using Content.Server.NodeContainer.EntitySystems ;
2024-04-30 14:31:05 -07:00
using Content.Shared.Atmos ;
2022-07-15 08:46:30 -04:00
using Content.Shared.Database ;
2024-08-25 22:18:42 +10:00
using Content.Shared.Power ;
2022-07-15 08:46:30 -04:00
namespace Content.Server.Atmos.Portable
{
public sealed class PortableScrubberSystem : EntitySystem
{
[Dependency] private readonly GasVentScrubberSystem _scrubberSystem = default ! ;
[Dependency] private readonly GasCanisterSystem _canisterSystem = default ! ;
[Dependency] private readonly GasPortableSystem _gasPortableSystem = default ! ;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default ! ;
[Dependency] private readonly TransformSystem _transformSystem = default ! ;
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
[Dependency] private readonly AmbientSoundSystem _ambientSound = default ! ;
2022-10-22 18:49:30 -04:00
[Dependency] private readonly SharedAppearanceSystem _appearance = default ! ;
2023-06-28 14:28:38 +03:00
[Dependency] private readonly NodeContainerSystem _nodeContainer = default ! ;
2022-07-15 08:46:30 -04:00
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < PortableScrubberComponent , AtmosDeviceUpdateEvent > ( OnDeviceUpdated ) ;
SubscribeLocalEvent < PortableScrubberComponent , AnchorStateChangedEvent > ( OnAnchorChanged ) ;
SubscribeLocalEvent < PortableScrubberComponent , PowerChangedEvent > ( OnPowerChanged ) ;
SubscribeLocalEvent < PortableScrubberComponent , ExaminedEvent > ( OnExamined ) ;
SubscribeLocalEvent < PortableScrubberComponent , DestructionEventArgs > ( OnDestroyed ) ;
2022-09-08 14:22:14 +00:00
SubscribeLocalEvent < PortableScrubberComponent , GasAnalyzerScanEvent > ( OnScrubberAnalyzed ) ;
2022-10-22 18:49:30 -04:00
}
private bool IsFull ( PortableScrubberComponent component )
{
return component . Air . Pressure > = component . MaxPressure ;
2022-07-15 08:46:30 -04:00
}
2023-12-21 18:48:18 -07:00
private void OnDeviceUpdated ( EntityUid uid , PortableScrubberComponent component , ref AtmosDeviceUpdateEvent args )
2022-07-15 08:46:30 -04:00
{
2023-08-12 23:42:12 -07:00
var timeDelta = args . dt ;
2022-07-15 08:46:30 -04:00
if ( ! component . Enabled )
return ;
2022-10-22 18:49:30 -04:00
// If we are on top of a connector port, empty into it.
2024-03-30 17:17:53 +13:00
if ( _nodeContainer . TryGetNode ( uid , component . PortName , out PortablePipeNode ? portableNode )
2022-07-15 08:46:30 -04:00
& & portableNode . ConnectionsEnabled )
{
_atmosphereSystem . React ( component . Air , portableNode ) ;
if ( portableNode . NodeGroup is PipeNet { NodeCount : > 1 } net )
_canisterSystem . MixContainerWithPipeNet ( component . Air , net . Air ) ;
}
2022-10-22 18:49:30 -04:00
if ( IsFull ( component ) )
2022-07-15 08:46:30 -04:00
{
UpdateAppearance ( uid , true , false ) ;
return ;
}
2024-03-30 17:17:53 +13:00
if ( args . Grid is not { } grid )
2022-07-15 08:46:30 -04:00
return ;
2024-03-30 17:17:53 +13:00
var position = _transformSystem . GetGridTilePositionOrDefault ( uid ) ;
var environment = _atmosphereSystem . GetTileMixture ( grid , args . Map , position , true ) ;
2022-07-15 08:46:30 -04:00
var running = Scrub ( timeDelta , component , environment ) ;
UpdateAppearance ( uid , false , running ) ;
2022-10-22 18:49:30 -04:00
// We scrub once to see if we can and set the animation
2022-07-15 08:46:30 -04:00
if ( ! running )
return ;
2024-03-30 17:17:53 +13:00
2022-10-22 18:49:30 -04:00
// widenet
2024-03-30 17:17:53 +13:00
var enumerator = _atmosphereSystem . GetAdjacentTileMixtures ( grid , position , false , true ) ;
2024-03-28 15:22:19 +13:00
while ( enumerator . MoveNext ( out var adjacent ) )
2022-07-15 08:46:30 -04:00
{
2022-10-22 18:49:30 -04:00
Scrub ( timeDelta , component , adjacent ) ;
2022-07-15 08:46:30 -04:00
}
}
/// <summary>
/// If there is a port under us, let us connect with adjacent atmos pipes.
/// </summary>
private void OnAnchorChanged ( EntityUid uid , PortableScrubberComponent component , ref AnchorStateChangedEvent args )
{
2024-03-30 17:17:53 +13:00
if ( ! _nodeContainer . TryGetNode ( uid , component . PortName , out PipeNode ? portableNode ) )
2022-07-15 08:46:30 -04:00
return ;
portableNode . ConnectionsEnabled = ( args . Anchored & & _gasPortableSystem . FindGasPortIn ( Transform ( uid ) . GridUid , Transform ( uid ) . Coordinates , out _ ) ) ;
2022-10-22 18:49:30 -04:00
_appearance . SetData ( uid , PortableScrubberVisuals . IsDraining , portableNode . ConnectionsEnabled ) ;
2022-07-15 08:46:30 -04:00
}
2022-10-22 18:49:30 -04:00
2022-10-15 15:08:15 +11:00
private void OnPowerChanged ( EntityUid uid , PortableScrubberComponent component , ref PowerChangedEvent args )
2022-07-15 08:46:30 -04:00
{
2022-10-22 18:49:30 -04:00
UpdateAppearance ( uid , IsFull ( component ) , args . Powered ) ;
2022-07-15 08:46:30 -04:00
component . Enabled = args . Powered ;
}
/// <summary>
/// Examining tells you how full it is as a %.
/// </summary>
private void OnExamined ( EntityUid uid , PortableScrubberComponent component , ExaminedEvent args )
{
if ( args . IsInDetailsRange )
{
var percentage = Math . Round ( ( ( component . Air . Pressure ) / component . MaxPressure ) * 100 ) ;
args . PushMarkup ( Loc . GetString ( "portable-scrubber-fill-level" , ( "percent" , percentage ) ) ) ;
}
}
/// <summary>
/// When this is destroyed, we dump out all the gas inside.
/// </summary>
private void OnDestroyed ( EntityUid uid , PortableScrubberComponent component , DestructionEventArgs args )
{
var environment = _atmosphereSystem . GetContainingMixture ( uid , false , true ) ;
if ( environment ! = null )
_atmosphereSystem . Merge ( environment , component . Air ) ;
2022-10-22 18:49:30 -04:00
_adminLogger . Add ( LogType . CanisterPurged , LogImpact . Medium , $"Portable scrubber {ToPrettyString(uid):canister} purged its contents of {component.Air} into the environment." ) ;
2022-07-15 08:46:30 -04:00
component . Air . Clear ( ) ;
}
private bool Scrub ( float timeDelta , PortableScrubberComponent scrubber , GasMixture ? tile )
{
2023-12-11 15:59:47 -08:00
return _scrubberSystem . Scrub ( timeDelta , scrubber . TransferRate * _atmosphereSystem . PumpSpeedup ( ) , ScrubberPumpDirection . Scrubbing , scrubber . FilterGases , tile , scrubber . Air ) ;
2022-07-15 08:46:30 -04:00
}
private void UpdateAppearance ( EntityUid uid , bool isFull , bool isRunning )
{
_ambientSound . SetAmbience ( uid , isRunning ) ;
2022-10-22 18:49:30 -04:00
_appearance . SetData ( uid , PortableScrubberVisuals . IsFull , isFull ) ;
_appearance . SetData ( uid , PortableScrubberVisuals . IsRunning , isRunning ) ;
2022-07-15 08:46:30 -04:00
}
2022-09-08 14:22:14 +00:00
/// <summary>
/// Returns the gas mixture for the gas analyzer
/// </summary>
private void OnScrubberAnalyzed ( EntityUid uid , PortableScrubberComponent component , GasAnalyzerScanEvent args )
{
2024-04-17 19:42:24 +02:00
args . GasMixtures ? ? = new List < ( string , GasMixture ? ) > ( ) ;
args . GasMixtures . Add ( ( Name ( uid ) , component . Air ) ) ;
2022-09-08 14:22:14 +00:00
}
2022-07-15 08:46:30 -04:00
}
}