2023-05-28 03:59:27 -05:00
using Content.Server.Administration.Logs ;
2022-12-25 12:35:51 +01:00
using Content.Server.Atmos ;
using Content.Server.Atmos.EntitySystems ;
using Content.Server.Atmos.Piping.Components ;
using Content.Server.Atmos.Piping.Unary.EntitySystems ;
using Content.Server.Body.Components ;
using Content.Server.Body.Systems ;
using Content.Server.Chemistry.Components.SolutionManager ;
using Content.Server.Chemistry.EntitySystems ;
using Content.Server.Climbing ;
using Content.Server.Medical.Components ;
using Content.Server.NodeContainer ;
2023-06-28 14:28:38 +03:00
using Content.Server.NodeContainer.EntitySystems ;
2022-12-25 12:35:51 +01:00
using Content.Server.NodeContainer.NodeGroups ;
using Content.Server.NodeContainer.Nodes ;
using Content.Server.Power.Components ;
using Content.Server.UserInterface ;
using Content.Shared.Chemistry ;
using Content.Shared.Chemistry.Components ;
using Content.Shared.Chemistry.Reagent ;
using Content.Shared.Containers.ItemSlots ;
2023-05-28 03:59:27 -05:00
using Content.Shared.Database ;
2023-02-24 19:01:25 -05:00
using Content.Shared.DoAfter ;
2022-12-25 12:35:51 +01:00
using Content.Shared.DragDrop ;
using Content.Shared.Emag.Systems ;
using Content.Shared.Examine ;
using Content.Shared.Interaction ;
using Content.Shared.Medical.Cryogenics ;
using Content.Shared.MedicalScanner ;
2023-02-24 19:01:25 -05:00
using Content.Shared.Tools ;
2022-12-25 12:35:51 +01:00
using Content.Shared.Verbs ;
using Robust.Server.GameObjects ;
using Robust.Shared.Timing ;
2023-07-18 17:13:26 -04:00
using Content.Server.Temperature.Components ;
2022-12-25 12:35:51 +01:00
namespace Content.Server.Medical ;
public sealed partial class CryoPodSystem : SharedCryoPodSystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default ! ;
[Dependency] private readonly GasCanisterSystem _gasCanisterSystem = default ! ;
[Dependency] private readonly ClimbSystem _climbSystem = default ! ;
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default ! ;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default ! ;
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default ! ;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default ! ;
2023-04-03 13:13:48 +12:00
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default ! ;
2022-12-25 12:35:51 +01:00
[Dependency] private readonly UserInterfaceSystem _uiSystem = default ! ;
2023-02-24 19:01:25 -05:00
[Dependency] private readonly SharedToolSystem _toolSystem = default ! ;
2022-12-25 12:35:51 +01:00
[Dependency] private readonly IGameTiming _gameTiming = default ! ;
[Dependency] private readonly MetaDataSystem _metaDataSystem = default ! ;
[Dependency] private readonly ReactiveSystem _reactiveSystem = default ! ;
2023-05-28 03:59:27 -05:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2023-06-28 14:28:38 +03:00
[Dependency] private readonly NodeContainerSystem _nodeContainer = default ! ;
2022-12-25 12:35:51 +01:00
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < CryoPodComponent , ComponentInit > ( OnComponentInit ) ;
SubscribeLocalEvent < CryoPodComponent , GetVerbsEvent < AlternativeVerb > > ( AddAlternativeVerbs ) ;
SubscribeLocalEvent < CryoPodComponent , GotEmaggedEvent > ( OnEmagged ) ;
2023-04-03 13:13:48 +12:00
SubscribeLocalEvent < CryoPodComponent , CryoPodDragFinished > ( OnDragFinished ) ;
2022-12-25 12:35:51 +01:00
SubscribeLocalEvent < CryoPodComponent , CryoPodPryFinished > ( OnCryoPodPryFinished ) ;
SubscribeLocalEvent < CryoPodComponent , AtmosDeviceUpdateEvent > ( OnCryoPodUpdateAtmosphere ) ;
2023-02-14 00:29:34 +11:00
SubscribeLocalEvent < CryoPodComponent , DragDropTargetEvent > ( HandleDragDropOn ) ;
2022-12-25 12:35:51 +01:00
SubscribeLocalEvent < CryoPodComponent , InteractUsingEvent > ( OnInteractUsing ) ;
SubscribeLocalEvent < CryoPodComponent , ExaminedEvent > ( OnExamined ) ;
SubscribeLocalEvent < CryoPodComponent , PowerChangedEvent > ( OnPowerChanged ) ;
SubscribeLocalEvent < CryoPodComponent , GasAnalyzerScanEvent > ( OnGasAnalyzed ) ;
SubscribeLocalEvent < CryoPodComponent , ActivatableUIOpenAttemptEvent > ( OnActivateUIAttempt ) ;
SubscribeLocalEvent < CryoPodComponent , AfterActivatableUIOpenEvent > ( OnActivateUI ) ;
}
public override void Update ( float frameTime )
{
base . Update ( frameTime ) ;
var curTime = _gameTiming . CurTime ;
var bloodStreamQuery = GetEntityQuery < BloodstreamComponent > ( ) ;
var metaDataQuery = GetEntityQuery < MetaDataComponent > ( ) ;
var itemSlotsQuery = GetEntityQuery < ItemSlotsComponent > ( ) ;
var fitsInDispenserQuery = GetEntityQuery < FitsInDispenserComponent > ( ) ;
var solutionContainerManagerQuery = GetEntityQuery < SolutionContainerManagerComponent > ( ) ;
foreach ( var ( _ , cryoPod ) in EntityQuery < ActiveCryoPodComponent , CryoPodComponent > ( ) )
{
metaDataQuery . TryGetComponent ( cryoPod . Owner , out var metaDataComponent ) ;
if ( curTime < cryoPod . NextInjectionTime + _metaDataSystem . GetPauseTime ( cryoPod . Owner , metaDataComponent ) )
continue ;
cryoPod . NextInjectionTime = curTime + TimeSpan . FromSeconds ( cryoPod . BeakerTransferTime ) ;
2022-12-30 15:34:59 +01:00
if ( ! itemSlotsQuery . TryGetComponent ( cryoPod . Owner , out var itemSlotsComponent ) )
2022-12-25 12:35:51 +01:00
{
continue ;
}
var container = _itemSlotsSystem . GetItemOrNull ( cryoPod . Owner , cryoPod . SolutionContainerName , itemSlotsComponent ) ;
var patient = cryoPod . BodyContainer . ContainedEntity ;
if ( container ! = null
& & container . Value . Valid
& & patient ! = null
2022-12-30 15:34:59 +01:00
& & fitsInDispenserQuery . TryGetComponent ( container , out var fitsInDispenserComponent )
& & solutionContainerManagerQuery . TryGetComponent ( container ,
out var solutionContainerManagerComponent )
2022-12-25 12:35:51 +01:00
& & _solutionContainerSystem . TryGetFitsInDispenser ( container . Value , out var containerSolution , dispenserFits : fitsInDispenserComponent , solutionManager : solutionContainerManagerComponent ) )
{
if ( ! bloodStreamQuery . TryGetComponent ( patient , out var bloodstream ) )
{
continue ;
}
var solutionToInject = _solutionContainerSystem . SplitSolution ( container . Value , containerSolution , cryoPod . BeakerTransferAmount ) ;
_bloodstreamSystem . TryAddToChemicals ( patient . Value , solutionToInject , bloodstream ) ;
_reactiveSystem . DoEntityReaction ( patient . Value , solutionToInject , ReactionMethod . Injection ) ;
}
}
}
2023-05-28 03:59:27 -05:00
public override EntityUid ? EjectBody ( EntityUid uid , CryoPodComponent ? cryoPodComponent )
2022-12-25 12:35:51 +01:00
{
if ( ! Resolve ( uid , ref cryoPodComponent ) )
2023-05-28 03:59:27 -05:00
return null ;
2022-12-25 12:35:51 +01:00
if ( cryoPodComponent . BodyContainer . ContainedEntity is not { Valid : true } contained )
2023-05-28 03:59:27 -05:00
return null ;
2022-12-25 12:35:51 +01:00
base . EjectBody ( uid , cryoPodComponent ) ;
_climbSystem . ForciblySetClimbing ( contained , uid ) ;
2023-05-28 03:59:27 -05:00
return contained ;
2022-12-25 12:35:51 +01:00
}
#region Interaction
2023-02-14 00:29:34 +11:00
private void HandleDragDropOn ( EntityUid uid , CryoPodComponent cryoPodComponent , ref DragDropTargetEvent args )
2022-12-25 12:35:51 +01:00
{
if ( cryoPodComponent . BodyContainer . ContainedEntity ! = null )
return ;
2023-04-03 13:13:48 +12:00
var doAfterArgs = new DoAfterArgs ( args . User , cryoPodComponent . EntryDelay , new CryoPodDragFinished ( ) , uid , target : args . Dragged , used : uid )
2022-12-25 12:35:51 +01:00
{
BreakOnDamage = true ,
BreakOnTargetMove = true ,
BreakOnUserMove = true ,
NeedHand = false ,
} ;
2023-04-03 13:13:48 +12:00
_doAfterSystem . TryStartDoAfter ( doAfterArgs ) ;
2022-12-25 12:35:51 +01:00
args . Handled = true ;
}
2023-04-03 13:13:48 +12:00
private void OnDragFinished ( EntityUid uid , CryoPodComponent component , CryoPodDragFinished args )
2023-02-24 19:01:25 -05:00
{
if ( args . Cancelled | | args . Handled | | args . Args . Target = = null )
return ;
2023-05-28 03:59:27 -05:00
if ( InsertBody ( uid , args . Args . Target . Value , component ) )
{
if ( ! TryComp ( uid , out CryoPodAirComponent ? cryoPodAir ) )
_adminLogger . Add ( LogType . Action , LogImpact . Medium ,
$"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(uid)}" ) ;
_adminLogger . Add ( LogType . Action , LogImpact . Medium ,
$"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(uid)} which contains gas: {cryoPodAir!.Air.ToPrettyString():gasMix}" ) ;
}
2023-02-24 19:01:25 -05:00
args . Handled = true ;
}
2022-12-25 12:35:51 +01:00
private void OnActivateUIAttempt ( EntityUid uid , CryoPodComponent cryoPodComponent , ActivatableUIOpenAttemptEvent args )
{
if ( args . Cancelled )
{
return ;
}
var containedEntity = cryoPodComponent . BodyContainer . ContainedEntity ;
if ( containedEntity = = null | | containedEntity = = args . User | | ! HasComp < ActiveCryoPodComponent > ( uid ) )
{
args . Cancel ( ) ;
}
}
private void OnActivateUI ( EntityUid uid , CryoPodComponent cryoPodComponent , AfterActivatableUIOpenEvent args )
{
2023-07-18 17:13:26 -04:00
TryComp < TemperatureComponent > ( cryoPodComponent . BodyContainer . ContainedEntity , out var temp ) ;
TryComp < BloodstreamComponent > ( cryoPodComponent . BodyContainer . ContainedEntity , out var bloodstream ) ;
2022-12-25 12:35:51 +01:00
_userInterfaceSystem . TrySendUiMessage (
uid ,
2023-04-11 17:11:02 -07:00
HealthAnalyzerUiKey . Key ,
2023-07-18 17:13:26 -04:00
new HealthAnalyzerScannedUserMessage ( cryoPodComponent . BodyContainer . ContainedEntity ,
temp ! = null ? temp . CurrentTemperature : 0 , bloodstream ! = null ? bloodstream . BloodSolution . FillFraction : 0 ) ) ;
2022-12-25 12:35:51 +01:00
}
private void OnInteractUsing ( EntityUid uid , CryoPodComponent cryoPodComponent , InteractUsingEvent args )
{
if ( args . Handled | | ! cryoPodComponent . Locked | | cryoPodComponent . BodyContainer . ContainedEntity = = null )
return ;
2023-04-03 13:13:48 +12:00
args . Handled = _toolSystem . UseTool ( args . Used , args . User , uid , cryoPodComponent . PryDelay , "Prying" , new CryoPodPryFinished ( ) ) ;
2022-12-25 12:35:51 +01:00
}
private void OnExamined ( EntityUid uid , CryoPodComponent component , ExaminedEvent args )
{
2023-02-24 19:01:25 -05:00
var container = _itemSlotsSystem . GetItemOrNull ( uid , component . SolutionContainerName ) ;
2022-12-25 12:35:51 +01:00
if ( args . IsInDetailsRange & & container ! = null & & _solutionContainerSystem . TryGetFitsInDispenser ( container . Value , out var containerSolution ) )
{
args . PushMarkup ( Loc . GetString ( "cryo-pod-examine" , ( "beaker" , Name ( container . Value ) ) ) ) ;
2023-01-12 16:41:40 +13:00
if ( containerSolution . Volume = = 0 )
2022-12-25 12:35:51 +01:00
{
args . PushMarkup ( Loc . GetString ( "cryo-pod-empty-beaker" ) ) ;
}
}
}
private void OnPowerChanged ( EntityUid uid , CryoPodComponent component , ref PowerChangedEvent args )
{
// Needed to avoid adding/removing components on a deleted entity
if ( Terminating ( uid ) )
{
return ;
}
if ( args . Powered )
{
EnsureComp < ActiveCryoPodComponent > ( uid ) ;
}
else
{
RemComp < ActiveCryoPodComponent > ( uid ) ;
2023-04-11 17:11:02 -07:00
_uiSystem . TryCloseAll ( uid , HealthAnalyzerUiKey . Key ) ;
2022-12-25 12:35:51 +01:00
}
UpdateAppearance ( uid , component ) ;
}
#endregion
#region Atmos handler
private void OnCryoPodUpdateAtmosphere ( EntityUid uid , CryoPodComponent cryoPod , AtmosDeviceUpdateEvent args )
{
if ( ! TryComp ( uid , out NodeContainerComponent ? nodeContainer ) )
return ;
2023-06-28 14:28:38 +03:00
if ( ! _nodeContainer . TryGetNode ( nodeContainer , cryoPod . PortName , out PortablePipeNode ? portNode ) )
2022-12-25 12:35:51 +01:00
return ;
2023-04-09 15:28:19 -07:00
if ( ! TryComp ( uid , out CryoPodAirComponent ? cryoPodAir ) )
return ;
_atmosphereSystem . React ( cryoPodAir . Air , portNode ) ;
2022-12-25 12:35:51 +01:00
if ( portNode . NodeGroup is PipeNet { NodeCount : > 1 } net )
{
2023-04-09 15:28:19 -07:00
_gasCanisterSystem . MixContainerWithPipeNet ( cryoPodAir . Air , net . Air ) ;
2022-12-25 12:35:51 +01:00
}
}
private void OnGasAnalyzed ( EntityUid uid , CryoPodComponent component , GasAnalyzerScanEvent args )
{
2023-04-09 15:28:19 -07:00
if ( ! TryComp ( uid , out CryoPodAirComponent ? cryoPodAir ) )
return ;
var gasMixDict = new Dictionary < string , GasMixture ? > { { Name ( uid ) , cryoPodAir . Air } } ;
2022-12-25 12:35:51 +01:00
// If it's connected to a port, include the port side
if ( TryComp ( uid , out NodeContainerComponent ? nodeContainer ) )
{
2023-06-28 14:28:38 +03:00
if ( _nodeContainer . TryGetNode ( nodeContainer , component . PortName , out PipeNode ? port ) )
2022-12-25 12:35:51 +01:00
gasMixDict . Add ( component . PortName , port . Air ) ;
}
args . GasMixtures = gasMixDict ;
}
#endregion
}