epic Respiration Rework (#6022)
This commit is contained in:
@@ -1,33 +1,28 @@
|
||||
using System;
|
||||
using Content.Server.Atmos;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Inventory.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;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
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!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
|
||||
public static string LungSolutionName = "Lung";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<LungComponent, AddedToBodyEvent>(OnAddedToBody);
|
||||
SubscribeLocalEvent<LungComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<BreathToolComponent, GotEquippedEvent>(OnGotEquipped);
|
||||
SubscribeLocalEvent<BreathToolComponent, GotUnequippedEvent>(OnGotUnequipped);
|
||||
}
|
||||
@@ -50,175 +45,30 @@ public class LungSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddedToBody(EntityUid uid, LungComponent component, AddedToBodyEvent args)
|
||||
private void OnComponentInit(EntityUid uid, LungComponent component, ComponentInit args)
|
||||
{
|
||||
Inhale(uid, component.CycleDelay);
|
||||
component.LungSolution = _solutionContainerSystem.EnsureSolution(uid, LungSolutionName);
|
||||
component.LungSolution.MaxVolume = 100.0f;
|
||||
component.LungSolution.CanReact = false; // No dexalin lungs
|
||||
}
|
||||
|
||||
public void Gasp(EntityUid uid,
|
||||
LungComponent? lung=null,
|
||||
MechanismComponent? mech=null)
|
||||
public void GasToReagent(EntityUid uid, LungComponent lung)
|
||||
{
|
||||
if (!Resolve(uid, ref lung, ref mech))
|
||||
return;
|
||||
|
||||
if (_gameTiming.CurTime >= lung.LastGaspPopupTime + lung.GaspPopupCooldown)
|
||||
foreach (var gas in lung.ValidGases)
|
||||
{
|
||||
lung.LastGaspPopupTime = _gameTiming.CurTime;
|
||||
_popupSystem.PopupEntity(Loc.GetString("lung-behavior-gasp"), uid, Filter.Pvs(uid));
|
||||
var i = (int) gas;
|
||||
var moles = lung.Air.Moles[i];
|
||||
if (moles <= 0)
|
||||
continue;
|
||||
var reagent = _atmosphereSystem.GasReagents[i];
|
||||
if (reagent == null) continue;
|
||||
|
||||
var amount = moles * Atmospherics.BreathMolesToReagentMultiplier;
|
||||
_solutionContainerSystem.TryAddReagent(uid, lung.LungSolution, reagent, amount, out _);
|
||||
|
||||
// We don't remove the gas from the lung mix,
|
||||
// that's the responsibility of whatever gas is being metabolized.
|
||||
// Most things will just want to exhale again.
|
||||
}
|
||||
|
||||
if (mech.Body != null && TryComp((mech.Body).Owner, out MobStateComponent? mobState) && !mobState.IsAlive())
|
||||
return;
|
||||
|
||||
Inhale(uid, lung.CycleDelay);
|
||||
}
|
||||
|
||||
public void UpdateLung(EntityUid uid,
|
||||
LungComponent? lung=null,
|
||||
MechanismComponent? mech=null)
|
||||
{
|
||||
if (!Resolve(uid, ref lung, ref mech))
|
||||
return;
|
||||
|
||||
if (mech.Body != null && EntityManager.TryGetComponent((mech.Body).Owner, out MobStateComponent? mobState) && mobState.IsCritical())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lung.Status == LungStatus.None)
|
||||
{
|
||||
lung.Status = LungStatus.Inhaling;
|
||||
}
|
||||
|
||||
lung.AccumulatedFrametime += lung.Status switch
|
||||
{
|
||||
LungStatus.Inhaling => 1,
|
||||
LungStatus.Exhaling => -1,
|
||||
_ => 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,
|
||||
MechanismComponent? 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).Owner, out InternalsComponent? internals) &&
|
||||
internals.BreathToolEntity != null &&
|
||||
internals.GasTankEntity != null &&
|
||||
EntityManager.TryGetComponent(internals.BreathToolEntity, out BreathToolComponent? breathTool) &&
|
||||
breathTool.IsFunctional &&
|
||||
EntityManager.TryGetComponent(internals.GasTankEntity, 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,
|
||||
MechanismComponent? 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).Owner, 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,
|
||||
MechanismComponent? 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,
|
||||
MechanismComponent? 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).Owner, out BloodstreamComponent? bloodstream))
|
||||
return;
|
||||
|
||||
_bloodstreamSystem.PumpToxins((mech.Body).Owner, lung.Air, bloodstream);
|
||||
|
||||
var lungRemoved = lung.Air.RemoveRatio(0.5f);
|
||||
_atmosSys.Merge(to, lungRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user