Add injectors + injected reagent metabolism via BloodstreamCompo… (#730)
* Add BloodstreamComponent and BloodstreamSystem New component for metabolizing reagents that other organs like the stomach pass their input reagents to. * Change StomachComponent to put ingested reagents in bloodstream after delay Now StomachComponent does not metabolize any reagents. Instead, it tracks how long each reagent has been inside it, and once they pass "digestionDelay" they'll be put inside the bloodstream, where the bloodstream will handle metabolism of the reagent. * Add reagent injectors Injects reagents straight into the bloodstream when used on mobs with bloodstreams. Also allows draw/inject from beakers. Does not support drawing blood/reagents from the bloodstream yet. * Address code review Make use of `Loc` static class instead of using `ILocalizationManager`. Localize InjectorToggleMode enum properly.
This commit is contained in:
@@ -1,40 +1,74 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.GameObjects.Components.Metabolism;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Nutrition;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Nutrition
|
||||
{
|
||||
/// <summary>
|
||||
/// Where reagents go when ingested. Tracks ingested reagents over time, and
|
||||
/// eventually transfers them to <see cref="BloodstreamComponent"/> once digested.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class StomachComponent : SharedStomachComponent
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
private SolutionComponent _stomachContents;
|
||||
/// <summary>
|
||||
/// Max volume of internal solution storage
|
||||
/// </summary>
|
||||
public int MaxVolume
|
||||
{
|
||||
get => _stomachContents.MaxVolume;
|
||||
set => _stomachContents.MaxVolume = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal solution storage
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private SolutionComponent _stomachContents;
|
||||
|
||||
/// <summary>
|
||||
/// Initial internal solution storage volume
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private int _initialMaxVolume;
|
||||
//Used to track changes to reagent amounts during metabolism
|
||||
private readonly Dictionary<string, int> _reagentDeltas = new Dictionary<string, int>();
|
||||
|
||||
/// <summary>
|
||||
/// Time in seconds between reagents being ingested and them being transferred to <see cref="BloodstreamComponent"/>
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private float _digestionDelay;
|
||||
|
||||
/// <summary>
|
||||
/// Used to track how long each reagent has been in the stomach
|
||||
/// </summary>
|
||||
private readonly List<ReagentDelta> _reagentDeltas = new List<ReagentDelta>();
|
||||
|
||||
/// <summary>
|
||||
/// Reference to bloodstream where digested reagents are transferred to
|
||||
/// </summary>
|
||||
private BloodstreamComponent _bloodstream;
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(ref _initialMaxVolume, "max_volume", 20);
|
||||
serializer.DataField(ref _initialMaxVolume, "maxVolume", 100);
|
||||
serializer.DataField(ref _digestionDelay, "digestionDelay", 20);
|
||||
}
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -43,6 +77,14 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
_stomachContents.InitializeFromPrototype();
|
||||
_stomachContents.MaxVolume = _initialMaxVolume;
|
||||
_stomachContents.Owner = Owner; //Manually set owner to avoid crash when VV'ing this
|
||||
|
||||
//Ensure bloodstream in present
|
||||
if (!Owner.TryGetComponent<BloodstreamComponent>(out _bloodstream))
|
||||
{
|
||||
Logger.Warning(_localizationManager.GetString(
|
||||
"StomachComponent entity does not have a BloodstreamComponent, which is required for it to function. Owner entity name: {0}",
|
||||
Owner.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryTransferSolution(Solution solution)
|
||||
@@ -52,47 +94,64 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Add solution to _stomachContents
|
||||
_stomachContents.TryAddSolution(solution, false, true);
|
||||
//Add each reagent to _reagentDeltas. Used to track how long each reagent has been in the stomach
|
||||
foreach (var reagent in solution.Contents)
|
||||
{
|
||||
_reagentDeltas.Add(new ReagentDelta(reagent.ReagentId, reagent.Quantity));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loops through each reagent in _stomachContents, and calls the IMetabolizable for each of them./>
|
||||
/// Updates digestion status of ingested reagents. Once reagents surpass _digestionDelay
|
||||
/// they are moved to the bloodstream, where they are then metabolized.
|
||||
/// </summary>
|
||||
/// <param name="tickTime">The time since the last metabolism tick in seconds.</param>
|
||||
public void Metabolize(float tickTime)
|
||||
/// <param name="tickTime">The time since the last update in seconds.</param>
|
||||
public void OnUpdate(float tickTime)
|
||||
{
|
||||
if (_stomachContents.CurrentVolume == 0)
|
||||
return;
|
||||
|
||||
//Run metabolism for each reagent, track quantity changes
|
||||
_reagentDeltas.Clear();
|
||||
foreach (var reagent in _stomachContents.ReagentList)
|
||||
if (_bloodstream == null)
|
||||
{
|
||||
if(!_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto))
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var metabolizable in proto.Metabolism)
|
||||
//Add reagents ready for transfer to bloodstream to transferSolution
|
||||
var transferSolution = new Solution();
|
||||
foreach (var delta in _reagentDeltas.ToList()) //Use ToList here to remove entries while iterating
|
||||
{
|
||||
//Increment lifetime of reagents
|
||||
delta.Increment(tickTime);
|
||||
if (delta.Lifetime > _digestionDelay)
|
||||
{
|
||||
_reagentDeltas[reagent.ReagentId] = metabolizable.Metabolize(Owner, reagent.ReagentId, tickTime);
|
||||
_stomachContents.TryRemoveReagent(delta.ReagentId, delta.Quantity);
|
||||
transferSolution.AddReagent(delta.ReagentId, delta.Quantity);
|
||||
_reagentDeltas.Remove(delta);
|
||||
}
|
||||
}
|
||||
|
||||
//Apply changes to quantity afterwards. Can't change the reagent quantities while the iterating the
|
||||
//list of reagents, because that would invalidate the iterator and throw an exception.
|
||||
foreach (var reagentDelta in _reagentDeltas)
|
||||
{
|
||||
_stomachContents.TryRemoveReagent(reagentDelta.Key, reagentDelta.Value);
|
||||
}
|
||||
//Transfer digested reagents to bloodstream
|
||||
_bloodstream.TryTransferSolution(transferSolution);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers metabolism of the reagents inside _stomachContents. Called by <see cref="StomachSystem"/>
|
||||
/// Used to track quantity changes when ingesting & digesting reagents
|
||||
/// </summary>
|
||||
/// <param name="tickTime">The time since the last metabolism tick in seconds.</param>
|
||||
public void OnUpdate(float tickTime)
|
||||
private class ReagentDelta
|
||||
{
|
||||
Metabolize(tickTime);
|
||||
public readonly string ReagentId;
|
||||
public readonly int Quantity;
|
||||
public float Lifetime { get; private set; }
|
||||
|
||||
public ReagentDelta(string reagentId, int quantity)
|
||||
{
|
||||
ReagentId = reagentId;
|
||||
Quantity = quantity;
|
||||
Lifetime = 0.0f;
|
||||
}
|
||||
|
||||
public void Increment(float delta) => Lifetime += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user