Remove LungBehavior and replace with LungComponent/System (#5630)

This commit is contained in:
mirrorcult
2021-11-30 18:25:02 -07:00
committed by GitHub
parent e3af2b5727
commit ccf01d7431
11 changed files with 311 additions and 242 deletions

View File

@@ -116,6 +116,7 @@ namespace Content.Client.Entry
"PowerSupplier",
"PowerConsumer",
"Battery",
"Lung",
"BatteryDischarger",
"Apc",
"PowerProvider",

View File

@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Atmos;
using Content.Server.Body.Behavior;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
using NUnit.Framework;
@@ -17,7 +16,7 @@ using Robust.Shared.Maths;
namespace Content.IntegrationTests.Tests.Body
{
[TestFixture]
[TestOf(typeof(LungBehavior))]
[TestOf(typeof(LungSystem))]
public class LungTest : ContentIntegrationTest
{
private const string Prototypes = @"
@@ -64,8 +63,12 @@ namespace Content.IntegrationTests.Tests.Body
var human = entityManager.SpawnEntity("HumanBodyAndBloodstreamDummy", new MapCoordinates(Vector2.Zero, mapId));
var bodySys = EntitySystem.Get<BodySystem>();
var lungSys = EntitySystem.Get<LungSystem>();
Assert.That(human.TryGetComponent(out SharedBodyComponent body));
Assert.That(body.TryGetMechanismBehaviors(out List<LungBehavior> lungs));
var lungs = bodySys.GetComponentsOnMechanisms<LungComponent>(human.Uid, body).ToArray();
Assert.That(lungs.Count, Is.EqualTo(1));
Assert.That(human.TryGetComponent(out BloodstreamComponent bloodstream));
@@ -78,8 +81,8 @@ namespace Content.IntegrationTests.Tests.Body
gas.AdjustMoles(Gas.Oxygen, originalOxygen);
gas.AdjustMoles(Gas.Nitrogen, originalNitrogen);
var lung = lungs[0];
lung.Inhale(1, gas);
var (lung, _) = lungs[0];
lungSys.TakeGasFrom(lung.OwnerUid, 1, gas, lung);
var lungOxygen = originalOxygen * breathedPercentage;
var lungNitrogen = originalNitrogen * breathedPercentage;
@@ -100,7 +103,7 @@ namespace Content.IntegrationTests.Tests.Body
Assert.Zero(lungOxygenBeforeExhale);
Assert.Zero(lungNitrogenBeforeExhale);
lung.Exhale(1, gas);
lungSys.PushGasTo(lung.OwnerUid, gas, lung);
var lungOxygenAfterExhale = lung.Air.GetMoles(Gas.Oxygen);
var exhaledOxygen = Math.Abs(lungOxygenBeforeExhale - lungOxygenAfterExhale);
@@ -168,8 +171,7 @@ namespace Content.IntegrationTests.Tests.Body
var coordinates = new EntityCoordinates(grid.GridEntityId, center);
human = entityManager.SpawnEntity("HumanBodyAndBloodstreamDummy", coordinates);
Assert.True(human.TryGetComponent(out SharedBodyComponent body));
Assert.True(body.HasMechanismBehavior<LungBehavior>());
Assert.True(human.HasComponent<SharedBodyComponent>());
Assert.True(human.TryGetComponent(out respirator));
Assert.False(respirator.Suffocating);
});

View File

@@ -1,205 +0,0 @@
using System;
using Content.Server.Atmos;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Popups;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
using Content.Shared.MobState;
using Content.Shared.MobState.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
namespace Content.Server.Body.Behavior
{
[DataDefinition]
public class LungBehavior : MechanismBehavior, ISerializationHooks
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
private float _accumulatedFrameTime;
[ViewVariables] private TimeSpan _lastGaspPopupTime;
[DataField("air")]
[ViewVariables]
public GasMixture Air { get; set; } = new()
{
Volume = 6,
Temperature = Atmospherics.NormalBodyTemperature
};
[DataField("gaspPopupCooldown")]
[ViewVariables]
public TimeSpan GaspPopupCooldown { get; private set; } = TimeSpan.FromSeconds(8);
[ViewVariables] public LungStatus Status { get; set; }
[DataField("cycleDelay")]
[ViewVariables]
public float CycleDelay { get; set; } = 2;
void ISerializationHooks.AfterDeserialization()
{
IoCManager.InjectDependencies(this);
}
protected override void OnAddedToBody(SharedBodyComponent body)
{
base.OnAddedToBody(body);
Inhale(CycleDelay);
}
public void Gasp()
{
if (_gameTiming.CurTime >= _lastGaspPopupTime + GaspPopupCooldown)
{
_lastGaspPopupTime = _gameTiming.CurTime;
Owner.PopupMessageEveryone(Loc.GetString("lung-behavior-gasp"));
}
Inhale(CycleDelay);
}
public void Transfer(GasMixture from, GasMixture to, float ratio)
{
EntitySystem.Get<AtmosphereSystem>().Merge(to, from.RemoveRatio(ratio));
}
public void ToBloodstream(GasMixture mixture)
{
if (Body == null)
{
return;
}
if (!Body.Owner.TryGetComponent(out BloodstreamComponent? bloodstream))
{
return;
}
var to = bloodstream.Air;
EntitySystem.Get<AtmosphereSystem>().Merge(to, mixture);
mixture.Clear();
}
public override void Update(float frameTime)
{
if (Body != null && Body.Owner.TryGetComponent(out MobStateComponent? mobState) && mobState.IsCritical())
{
return;
}
if (Status == LungStatus.None)
{
Status = LungStatus.Inhaling;
}
_accumulatedFrameTime += Status switch
{
LungStatus.Inhaling => frameTime,
LungStatus.Exhaling => -frameTime,
_ => throw new ArgumentOutOfRangeException()
};
var absoluteTime = Math.Abs(_accumulatedFrameTime);
var delay = CycleDelay;
if (absoluteTime < delay)
{
return;
}
switch (Status)
{
case LungStatus.Inhaling:
Inhale(absoluteTime);
Status = LungStatus.Exhaling;
break;
case LungStatus.Exhaling:
Exhale(absoluteTime);
Status = LungStatus.Inhaling;
break;
default:
throw new ArgumentOutOfRangeException();
}
_accumulatedFrameTime = absoluteTime - delay;
}
public void Inhale(float frameTime)
{
if (Body != null &&
Body.Owner.TryGetComponent(out InternalsComponent? internals) &&
internals.BreathToolEntity != null &&
internals.GasTankEntity != null &&
internals.BreathToolEntity.TryGetComponent(out BreathToolComponent? breathTool) &&
breathTool.IsFunctional &&
internals.GasTankEntity.TryGetComponent(out GasTankComponent? gasTank) &&
gasTank.Air != null)
{
Inhale(frameTime, gasTank.RemoveAirVolume(Atmospherics.BreathVolume));
return;
}
if (EntitySystem.Get<AtmosphereSystem>().GetTileMixture(Owner.Transform.Coordinates, true) is not {} tileAir)
{
return;
}
Inhale(frameTime, tileAir);
}
public void Inhale(float frameTime, GasMixture from)
{
var ratio = (Atmospherics.BreathVolume / from.Volume) * frameTime;
Transfer(from, Air, ratio);
ToBloodstream(Air);
}
public void Exhale(float frameTime)
{
if (EntitySystem.Get<AtmosphereSystem>().GetTileMixture(Owner.Transform.Coordinates, true) is not {} tileAir)
{
return;
}
Exhale(frameTime, tileAir);
}
public void Exhale(float frameTime, GasMixture to)
{
// TODO: Make the bloodstream separately pump toxins into the lungs, making the lungs' only job to empty.
if (Body == null)
{
return;
}
if (!Body.Owner.TryGetComponent(out BloodstreamComponent? bloodstream))
{
return;
}
EntitySystem.Get<BloodstreamSystem>().PumpToxins(Body.OwnerUid, Air, bloodstream);
var lungRemoved = Air.RemoveRatio(0.5f);
EntitySystem.Get<AtmosphereSystem>().Merge(to, lungRemoved);
}
}
public enum LungStatus
{
None = 0,
Inhaling,
Exhaling
}
}

View File

@@ -0,0 +1,44 @@
using System;
using Content.Server.Atmos;
using Content.Server.Body.Systems;
using Content.Shared.Atmos;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Body.Components;
[RegisterComponent, Friend(typeof(LungSystem))]
public class LungComponent : Component
{
public override string Name => "Lung";
public float AccumulatedFrametime;
[ViewVariables]
public TimeSpan LastGaspPopupTime;
[DataField("air")]
public GasMixture Air { get; set; } = new()
{
Volume = 6,
Temperature = Atmospherics.NormalBodyTemperature
};
[DataField("gaspPopupCooldown")]
public TimeSpan GaspPopupCooldown { get; private set; } = TimeSpan.FromSeconds(8);
[ViewVariables]
public LungStatus Status { get; set; }
[DataField("cycleDelay")]
public float CycleDelay { get; set; } = 2;
}
public enum LungStatus
{
None = 0,
Inhaling,
Exhaling
}

View File

@@ -40,8 +40,15 @@ namespace Content.Server.Body.Systems
}
}
public IEnumerable<T> GetComponentsOnMechanisms<T>(EntityUid uid,
SharedBodyComponent? body) where T : Component
/// <summary>
/// Returns a list of ValueTuples of <see cref="T"/> and SharedMechanismComponent on each mechanism
/// in the given body.
/// </summary>
/// <param name="uid">The entity to check for the component on.</param>
/// <param name="body">The body to check for mechanisms on.</param>
/// <typeparam name="T">The component to check for.</typeparam>
public IEnumerable<(T Comp, SharedMechanismComponent Mech)> GetComponentsOnMechanisms<T>(EntityUid uid,
SharedBodyComponent? body=null) where T : Component
{
if (!Resolve(uid, ref body))
yield break;
@@ -50,13 +57,22 @@ namespace Content.Server.Body.Systems
foreach (var mechanism in part.Mechanisms)
{
if (EntityManager.TryGetComponent<T>(mechanism.OwnerUid, out var comp))
yield return comp;
yield return (comp, mechanism);
}
}
/// <summary>
/// Tries to get a list of ValueTuples of <see cref="T"/> and SharedMechanismComponent on each mechanism
/// in the given body.
/// </summary>
/// <param name="uid">The entity to check for the component on.</param>
/// <param name="comps">The list of components.</param>
/// <param name="body">The body to check for mechanisms on.</param>
/// <typeparam name="T">The component to check for.</typeparam>
/// <returns>Whether any were found.</returns>
public bool TryGetComponentsOnMechanisms<T>(EntityUid uid,
[NotNullWhen(true)] out IEnumerable<T>? comps,
SharedBodyComponent? body) where T: Component
[NotNullWhen(true)] out IEnumerable<(T Comp, SharedMechanismComponent Mech)>? comps,
SharedBodyComponent? body=null) where T: Component
{
if (!Resolve(uid, ref body))
{

View 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);
}
}

View File

@@ -4,7 +4,6 @@ using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Alert;
using Content.Server.Atmos;
using Content.Server.Body.Behavior;
using Content.Server.Body.Components;
using Content.Shared.Alert;
using Content.Shared.Atmos;
@@ -23,6 +22,8 @@ namespace Content.Server.Body.Systems
{
[Dependency] private readonly DamageableSystem _damageableSys = default!;
[Dependency] private readonly AdminLogSystem _logSys = default!;
[Dependency] private readonly BodySystem _bodySystem = default!;
[Dependency] private readonly LungSystem _lungSystem = default!;
public override void Update(float frameTime)
{
@@ -136,10 +137,16 @@ namespace Content.Server.Body.Systems
if (!Resolve(uid, ref bloodstream, ref body, false))
return;
var lungs = body.GetMechanismBehaviors<LungBehavior>().ToArray();
var lungs = _bodySystem.GetComponentsOnMechanisms<LungComponent>(uid, body).ToArray();
var needs = NeedsAndDeficit(respirator, frameTime);
var used = 0f;
foreach (var (lung, mech) in lungs)
{
_lungSystem.UpdateLung(lung.OwnerUid, frameTime, lung, mech);
}
foreach (var (gas, amountNeeded) in needs)
{
var bloodstreamAmount = bloodstream.Air.GetMoles(gas);
@@ -150,9 +157,9 @@ namespace Content.Server.Body.Systems
if (!EntityManager.GetComponent<MobStateComponent>(uid).IsCritical())
{
// Panic inhale
foreach (var lung in lungs)
foreach (var (lung, mech) in lungs)
{
lung.Gasp();
_lungSystem.Gasp(lung.OwnerUid, lung, mech);
}
}

View File

@@ -27,6 +27,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Nutrition.EntitySystems
{
@@ -263,8 +264,8 @@ namespace Content.Server.Nutrition.EntitySystems
var transferAmount = FixedPoint2.Min(drink.TransferAmount, drinkSolution.DrainAvailable);
var drain = _solutionContainerSystem.Drain(uid, drinkSolution, transferAmount);
var firstStomach = stomachs.FirstOrDefault(
stomach => _stomachSystem.CanTransferSolution(stomach.OwnerUid, drain));
var firstStomach = stomachs.FirstOrNull(
stomach => _stomachSystem.CanTransferSolution(stomach.Comp.OwnerUid, drain));
// All stomach are full or can't handle whatever solution we have.
if (firstStomach == null)
@@ -289,7 +290,7 @@ namespace Content.Server.Nutrition.EntitySystems
Filter.Pvs(userUid));
drain.DoEntityReaction(userUid, ReactionMethod.Ingestion);
_stomachSystem.TryTransferSolution(firstStomach.OwnerUid, drain, firstStomach);
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.OwnerUid, drain, firstStomach.Value.Comp);
return true;
}
@@ -371,8 +372,8 @@ namespace Content.Server.Nutrition.EntitySystems
return;
}
var firstStomach = stomachs.FirstOrDefault(
stomach => _stomachSystem.CanTransferSolution(stomach.OwnerUid, drained));
var firstStomach = stomachs.FirstOrNull(
stomach => _stomachSystem.CanTransferSolution(stomach.Comp.OwnerUid, drained));
// All stomach are full or can't handle whatever solution we have.
if (firstStomach == null)
@@ -399,7 +400,7 @@ namespace Content.Server.Nutrition.EntitySystems
SoundSystem.Play(Filter.Pvs(uid), args.Drink.UseSound.GetSound(), uid, AudioParams.Default.WithVolume(-2f));
drained.DoEntityReaction(uid, ReactionMethod.Ingestion);
_stomachSystem.TryTransferSolution(firstStomach.OwnerUid, drained, firstStomach);
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.OwnerUid, drained, firstStomach.Value.Comp);
}
private void OnForceDrinkCancelled(ForceDrinkCancelledEvent args)

View File

@@ -24,6 +24,7 @@ using Robust.Shared.Localization;
using Robust.Shared.Player;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.Utility;
namespace Content.Server.Nutrition.EntitySystems
{
@@ -144,7 +145,8 @@ namespace Content.Server.Nutrition.EntitySystems
var transferAmount = component.TransferAmount != null ? FixedPoint2.Min((FixedPoint2) component.TransferAmount, solution.CurrentVolume) : solution.CurrentVolume;
var split = _solutionContainerSystem.SplitSolution(uid, solution, transferAmount);
var firstStomach = stomachs.FirstOrDefault(stomach => _stomachSystem.CanTransferSolution(stomach.OwnerUid, split));
var firstStomach = stomachs.FirstOrNull(
stomach => _stomachSystem.CanTransferSolution(stomach.Comp.OwnerUid, split));
if (firstStomach == null)
{
@@ -155,7 +157,7 @@ namespace Content.Server.Nutrition.EntitySystems
// TODO: Account for partial transfer.
split.DoEntityReaction(userUid, ReactionMethod.Ingestion);
_stomachSystem.TryTransferSolution(firstStomach.OwnerUid, split, firstStomach);
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.OwnerUid, split, firstStomach.Value.Comp);
SoundSystem.Play(Filter.Pvs(userUid), component.UseSound.GetSound(), userUid, AudioParams.Default.WithVolume(-1f));
_popupSystem.PopupEntity(Loc.GetString(component.EatMessage, ("food", component.Owner)), userUid, Filter.Entities(userUid));
@@ -292,7 +294,8 @@ namespace Content.Server.Nutrition.EntitySystems
: args.FoodSolution.CurrentVolume;
var split = _solutionContainerSystem.SplitSolution(args.Food.OwnerUid, args.FoodSolution, transferAmount);
var firstStomach = stomachs.FirstOrDefault(stomach => _stomachSystem.CanTransferSolution(stomach.OwnerUid, split));
var firstStomach = stomachs.FirstOrNull(
stomach => _stomachSystem.CanTransferSolution(stomach.Comp.OwnerUid, split));
if (firstStomach == null)
{
@@ -302,7 +305,7 @@ namespace Content.Server.Nutrition.EntitySystems
}
split.DoEntityReaction(uid, ReactionMethod.Ingestion);
_stomachSystem.TryTransferSolution(firstStomach.OwnerUid, split, firstStomach);
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.OwnerUid, split, firstStomach.Value.Comp);
EntityManager.TryGetComponent(uid, out MetaDataComponent? targetMeta);
var targetName = targetMeta?.EntityName ?? string.Empty;
@@ -350,7 +353,9 @@ namespace Content.Server.Nutrition.EntitySystems
if (food.UsesRemaining <= 0)
DeleteAndSpawnTrash(food);
var firstStomach = stomachs.FirstOrDefault(stomach => _stomachSystem.CanTransferSolution(stomach.OwnerUid, foodSolution));
var firstStomach = stomachs.FirstOrNull(
stomach => _stomachSystem.CanTransferSolution(stomach.Comp.OwnerUid, foodSolution));
if (firstStomach == null)
return;
@@ -365,7 +370,7 @@ namespace Content.Server.Nutrition.EntitySystems
_popupSystem.PopupEntity(Loc.GetString(food.EatMessage), target, Filter.Entities(target));
foodSolution.DoEntityReaction(uid, ReactionMethod.Ingestion);
_stomachSystem.TryTransferSolution(firstStomach.OwnerUid, foodSolution, firstStomach);
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.OwnerUid, foodSolution, firstStomach.Value.Comp);
SoundSystem.Play(Filter.Pvs(target), food.UseSound.GetSound(), target, AudioParams.Default.WithVolume(-1f));
if (string.IsNullOrEmpty(food.TrashPrototype))

View File

@@ -99,8 +99,7 @@
- type: Mechanism
size: 1
compatibility: Biological
behaviors:
- !type:LungBehavior {}
- type: Lung
- type: entity
id: OrganHumanHeart

View File

@@ -83,8 +83,7 @@
- type: Mechanism
size: 1
compatibility: Biological
behaviors:
- !type:LungBehavior {}
- type: Lung
- type: entity
id: OrganAnimalStomach