1
0

PortableScrubberSystem.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using Content.Server.Atmos.Piping.Unary.EntitySystems;
  2. using Content.Shared.Atmos.Piping.Unary.Components;
  3. using Content.Shared.Atmos.Visuals;
  4. using Content.Shared.Examine;
  5. using Content.Shared.Destructible;
  6. using Content.Server.Atmos.Piping.Components;
  7. using Content.Server.Atmos.EntitySystems;
  8. using Content.Server.Power.Components;
  9. using Content.Server.NodeContainer;
  10. using Robust.Server.GameObjects;
  11. using Content.Server.NodeContainer.Nodes;
  12. using Content.Server.NodeContainer.NodeGroups;
  13. using Content.Server.Audio;
  14. using Content.Server.Administration.Logs;
  15. using Content.Server.NodeContainer.EntitySystems;
  16. using Content.Shared.Atmos;
  17. using Content.Shared.Database;
  18. using Content.Shared.Power;
  19. namespace Content.Server.Atmos.Portable
  20. {
  21. public sealed class PortableScrubberSystem : EntitySystem
  22. {
  23. [Dependency] private readonly GasVentScrubberSystem _scrubberSystem = default!;
  24. [Dependency] private readonly GasCanisterSystem _canisterSystem = default!;
  25. [Dependency] private readonly GasPortableSystem _gasPortableSystem = default!;
  26. [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
  27. [Dependency] private readonly TransformSystem _transformSystem = default!;
  28. [Dependency] private readonly IAdminLogManager _adminLogger = default!;
  29. [Dependency] private readonly AmbientSoundSystem _ambientSound = default!;
  30. [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
  31. [Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
  32. public override void Initialize()
  33. {
  34. base.Initialize();
  35. SubscribeLocalEvent<PortableScrubberComponent, AtmosDeviceUpdateEvent>(OnDeviceUpdated);
  36. SubscribeLocalEvent<PortableScrubberComponent, AnchorStateChangedEvent>(OnAnchorChanged);
  37. SubscribeLocalEvent<PortableScrubberComponent, PowerChangedEvent>(OnPowerChanged);
  38. SubscribeLocalEvent<PortableScrubberComponent, ExaminedEvent>(OnExamined);
  39. SubscribeLocalEvent<PortableScrubberComponent, DestructionEventArgs>(OnDestroyed);
  40. SubscribeLocalEvent<PortableScrubberComponent, GasAnalyzerScanEvent>(OnScrubberAnalyzed);
  41. }
  42. private bool IsFull(PortableScrubberComponent component)
  43. {
  44. return component.Air.Pressure >= component.MaxPressure;
  45. }
  46. private void OnDeviceUpdated(EntityUid uid, PortableScrubberComponent component, ref AtmosDeviceUpdateEvent args)
  47. {
  48. var timeDelta = args.dt;
  49. if (!component.Enabled)
  50. return;
  51. // If we are on top of a connector port, empty into it.
  52. if (_nodeContainer.TryGetNode(uid, component.PortName, out PortablePipeNode? portableNode)
  53. && portableNode.ConnectionsEnabled)
  54. {
  55. _atmosphereSystem.React(component.Air, portableNode);
  56. if (portableNode.NodeGroup is PipeNet {NodeCount: > 1} net)
  57. _canisterSystem.MixContainerWithPipeNet(component.Air, net.Air);
  58. }
  59. if (IsFull(component))
  60. {
  61. UpdateAppearance(uid, true, false);
  62. return;
  63. }
  64. if (args.Grid is not {} grid)
  65. return;
  66. var position = _transformSystem.GetGridTilePositionOrDefault(uid);
  67. var environment = _atmosphereSystem.GetTileMixture(grid, args.Map, position, true);
  68. var running = Scrub(timeDelta, component, environment);
  69. UpdateAppearance(uid, false, running);
  70. // We scrub once to see if we can and set the animation
  71. if (!running)
  72. return;
  73. // widenet
  74. var enumerator = _atmosphereSystem.GetAdjacentTileMixtures(grid, position, false, true);
  75. while (enumerator.MoveNext(out var adjacent))
  76. {
  77. Scrub(timeDelta, component, adjacent);
  78. }
  79. }
  80. /// <summary>
  81. /// If there is a port under us, let us connect with adjacent atmos pipes.
  82. /// </summary>
  83. private void OnAnchorChanged(EntityUid uid, PortableScrubberComponent component, ref AnchorStateChangedEvent args)
  84. {
  85. if (!_nodeContainer.TryGetNode(uid, component.PortName, out PipeNode? portableNode))
  86. return;
  87. portableNode.ConnectionsEnabled = (args.Anchored && _gasPortableSystem.FindGasPortIn(Transform(uid).GridUid, Transform(uid).Coordinates, out _));
  88. _appearance.SetData(uid, PortableScrubberVisuals.IsDraining, portableNode.ConnectionsEnabled);
  89. }
  90. private void OnPowerChanged(EntityUid uid, PortableScrubberComponent component, ref PowerChangedEvent args)
  91. {
  92. UpdateAppearance(uid, IsFull(component), args.Powered);
  93. component.Enabled = args.Powered;
  94. }
  95. /// <summary>
  96. /// Examining tells you how full it is as a %.
  97. /// </summary>
  98. private void OnExamined(EntityUid uid, PortableScrubberComponent component, ExaminedEvent args)
  99. {
  100. if (args.IsInDetailsRange)
  101. {
  102. var percentage = Math.Round(((component.Air.Pressure) / component.MaxPressure) * 100);
  103. args.PushMarkup(Loc.GetString("portable-scrubber-fill-level", ("percent", percentage)));
  104. }
  105. }
  106. /// <summary>
  107. /// When this is destroyed, we dump out all the gas inside.
  108. /// </summary>
  109. private void OnDestroyed(EntityUid uid, PortableScrubberComponent component, DestructionEventArgs args)
  110. {
  111. var environment = _atmosphereSystem.GetContainingMixture(uid, false, true);
  112. if (environment != null)
  113. _atmosphereSystem.Merge(environment, component.Air);
  114. _adminLogger.Add(LogType.CanisterPurged, LogImpact.Medium, $"Portable scrubber {ToPrettyString(uid):canister} purged its contents of {component.Air} into the environment.");
  115. component.Air.Clear();
  116. }
  117. private bool Scrub(float timeDelta, PortableScrubberComponent scrubber, GasMixture? tile)
  118. {
  119. return _scrubberSystem.Scrub(timeDelta, scrubber.TransferRate * _atmosphereSystem.PumpSpeedup(), ScrubberPumpDirection.Scrubbing, scrubber.FilterGases, tile, scrubber.Air);
  120. }
  121. private void UpdateAppearance(EntityUid uid, bool isFull, bool isRunning)
  122. {
  123. _ambientSound.SetAmbience(uid, isRunning);
  124. _appearance.SetData(uid, PortableScrubberVisuals.IsFull, isFull);
  125. _appearance.SetData(uid, PortableScrubberVisuals.IsRunning, isRunning);
  126. }
  127. /// <summary>
  128. /// Returns the gas mixture for the gas analyzer
  129. /// </summary>
  130. private void OnScrubberAnalyzed(EntityUid uid, PortableScrubberComponent component, GasAnalyzerScanEvent args)
  131. {
  132. args.GasMixtures ??= new List<(string, GasMixture?)>();
  133. args.GasMixtures.Add((Name(uid), component.Air));
  134. }
  135. }
  136. }