Remove LungBehavior and replace with LungComponent/System (#5630)
This commit is contained in:
200
Content.Server/Body/Systems/LungSystem.cs
Normal file
200
Content.Server/Body/Systems/LungSystem.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Body.Systems;
|
||||
|
||||
public class LungSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosSys = default!;
|
||||
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<LungComponent, AddedToBodyEvent>(OnAddedToBody);
|
||||
}
|
||||
|
||||
private void OnAddedToBody(EntityUid uid, LungComponent component, AddedToBodyEvent args)
|
||||
{
|
||||
Inhale(uid, component.CycleDelay);
|
||||
}
|
||||
|
||||
public void Gasp(EntityUid uid,
|
||||
LungComponent? lung=null,
|
||||
SharedMechanismComponent? mech=null)
|
||||
{
|
||||
if (!Resolve(uid, ref lung))
|
||||
return;
|
||||
|
||||
if (_gameTiming.CurTime >= lung.LastGaspPopupTime + lung.GaspPopupCooldown)
|
||||
{
|
||||
lung.LastGaspPopupTime = _gameTiming.CurTime;
|
||||
_popupSystem.PopupEntity(Loc.GetString("lung-behavior-gasp"), uid, Filter.Pvs(uid));
|
||||
}
|
||||
|
||||
Inhale(uid, lung.CycleDelay);
|
||||
}
|
||||
|
||||
public void UpdateLung(EntityUid uid, float frameTime,
|
||||
LungComponent? lung=null,
|
||||
SharedMechanismComponent? mech=null)
|
||||
{
|
||||
if (!Resolve(uid, ref lung, ref mech))
|
||||
return;
|
||||
|
||||
if (mech.Body != null && EntityManager.TryGetComponent(mech.Body.OwnerUid, out MobStateComponent? mobState) && mobState.IsCritical())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lung.Status == LungStatus.None)
|
||||
{
|
||||
lung.Status = LungStatus.Inhaling;
|
||||
}
|
||||
|
||||
lung.AccumulatedFrametime += lung.Status switch
|
||||
{
|
||||
LungStatus.Inhaling => frameTime,
|
||||
LungStatus.Exhaling => -frameTime,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
var absoluteTime = Math.Abs(lung.AccumulatedFrametime);
|
||||
var delay = lung.CycleDelay;
|
||||
|
||||
if (absoluteTime < delay)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (lung.Status)
|
||||
{
|
||||
case LungStatus.Inhaling:
|
||||
Inhale(uid, absoluteTime);
|
||||
lung.Status = LungStatus.Exhaling;
|
||||
break;
|
||||
case LungStatus.Exhaling:
|
||||
Exhale(uid, absoluteTime);
|
||||
lung.Status = LungStatus.Inhaling;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
lung.AccumulatedFrametime = absoluteTime - delay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find an air mixture to inhale from, then inhales from it.
|
||||
/// </summary>
|
||||
public void Inhale(EntityUid uid, float frameTime,
|
||||
LungComponent? lung=null,
|
||||
SharedMechanismComponent? mech=null)
|
||||
{
|
||||
if (!Resolve(uid, ref lung, ref mech))
|
||||
return;
|
||||
|
||||
// TODO Jesus Christ make this event based.
|
||||
if (mech.Body != null &&
|
||||
EntityManager.TryGetComponent(mech.Body.OwnerUid, out InternalsComponent? internals) &&
|
||||
internals.BreathToolEntity != null &&
|
||||
internals.GasTankEntity != null &&
|
||||
internals.BreathToolEntity.TryGetComponent(out BreathToolComponent? breathTool) &&
|
||||
breathTool.IsFunctional &&
|
||||
internals.GasTankEntity.TryGetComponent(out GasTankComponent? gasTank))
|
||||
{
|
||||
TakeGasFrom(uid, frameTime, gasTank.RemoveAirVolume(Atmospherics.BreathVolume), lung);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_atmosSys.GetTileMixture(EntityManager.GetComponent<TransformComponent>(uid).Coordinates, true) is not { } tileAir)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TakeGasFrom(uid, frameTime, tileAir, lung);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inhales directly from a given mixture.
|
||||
/// </summary>
|
||||
public void TakeGasFrom(EntityUid uid, float frameTime, GasMixture from,
|
||||
LungComponent? lung=null,
|
||||
SharedMechanismComponent? mech=null)
|
||||
{
|
||||
if (!Resolve(uid, ref lung, ref mech))
|
||||
return;
|
||||
|
||||
var ratio = (Atmospherics.BreathVolume / from.Volume) * frameTime;
|
||||
|
||||
_atmosSys.Merge(lung.Air, from.RemoveRatio(ratio));
|
||||
|
||||
// Push to bloodstream
|
||||
if (mech.Body == null)
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(mech.Body.OwnerUid, out BloodstreamComponent? bloodstream))
|
||||
return;
|
||||
|
||||
var to = bloodstream.Air;
|
||||
|
||||
_atmosSys.Merge(to, lung.Air);
|
||||
lung.Air.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a gas mixture to exhale to, then pushes gas to it.
|
||||
/// </summary>
|
||||
public void Exhale(EntityUid uid, float frameTime,
|
||||
LungComponent? lung=null,
|
||||
SharedMechanismComponent? mech=null)
|
||||
{
|
||||
if (!Resolve(uid, ref lung, ref mech))
|
||||
return;
|
||||
|
||||
if (_atmosSys.GetTileMixture(EntityManager.GetComponent<TransformComponent>(uid).Coordinates, true) is not { } tileAir)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PushGasTo(uid, tileAir, lung, mech);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes gas from the lungs to a gas mixture.
|
||||
/// </summary>
|
||||
public void PushGasTo(EntityUid uid, GasMixture to,
|
||||
LungComponent? lung=null,
|
||||
SharedMechanismComponent? mech=null)
|
||||
{
|
||||
if (!Resolve(uid, ref lung, ref mech))
|
||||
return;
|
||||
|
||||
// TODO: Make the bloodstream separately pump toxins into the lungs, making the lungs' only job to empty.
|
||||
if (mech.Body == null)
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(mech.Body.OwnerUid, out BloodstreamComponent? bloodstream))
|
||||
return;
|
||||
|
||||
_bloodstreamSystem.PumpToxins(mech.Body.OwnerUid, lung.Air, bloodstream);
|
||||
|
||||
var lungRemoved = lung.Air.RemoveRatio(0.5f);
|
||||
_atmosSys.Merge(to, lungRemoved);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user