using System.Linq; using Content.Server.Body.Circulatory; using Content.Shared.Body.Networks; using Content.Shared.Chemistry.Metabolizable; using Content.Shared.Chemistry.Reagent; using Robust.Shared.IoC; using Robust.Shared.Prototypes; namespace Content.Server.Body.Behavior { /// /// Metabolizes reagents in after they are digested. /// public class LiverBehavior : MechanismBehavior { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private float _accumulatedFrameTime; /// /// Delay time that determines how often to metabolise blood contents (in seconds). /// private float _updateIntervalSeconds = 1.0f; /// /// Whether the liver is functional. /// //[ViewVariables] private bool _liverFailing = false; /// /// Modifier for alcohol damage. /// //[DataField("alcoholLethality")] //[ViewVariables] private float _alcoholLethality = 0.005f; /// /// Modifier for alcohol damage. /// //[DataField("alcoholExponent")] //[ViewVariables] private float _alcoholExponent = 1.6f; /// /// Toxin volume that can be purged without damage. /// //[DataField("toxinTolerance")] //[ViewVariables] private float _toxinTolerance = 3f; /// /// Toxin damage modifier. /// //[DataField("toxinLethality")] //[ViewVariables] private float _toxinLethality = 0.01f; /// /// Loops through each reagent in _internalSolution, /// and calls for each of them. /// Also handles toxins and alcohol. /// /// /// The time since the last update in seconds. /// public override void Update(float frameTime) { if (Body == null) { return; } _accumulatedFrameTime += frameTime; // Update at most once every _updateIntervalSeconds if (_accumulatedFrameTime < _updateIntervalSeconds) { return; } _accumulatedFrameTime -= _updateIntervalSeconds; if (!Body.Owner.TryGetComponent(out BloodstreamComponent? bloodstream)) { return; } if (bloodstream.Solution.CurrentVolume <= ReagentUnit.Zero) { return; } // Run metabolism for each reagent, remove metabolized reagents // Using ToList here lets us edit reagents while iterating foreach (var reagent in bloodstream.Solution.ReagentList.ToList()) { if (!_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? prototype)) { continue; } // How much reagent is available to metabolise? // This needs to be passed to other functions that have metabolism rate information, such that they don't "overmetabolise" a reagent. var availableReagent = bloodstream.Solution.Solution.GetReagentQuantity(reagent.ReagentId); //TODO BODY Check if it's a Toxin. If volume < _toxinTolerance, just remove it. If greater, add damage = volume * _toxinLethality //TODO BODY Check if it has BoozePower > 0. Affect drunkenness, apply damage. Proposed formula (SS13-derived): damage = sqrt(volume) * BoozePower^_alcoholExponent * _alcoholLethality / 10 //TODO BODY Liver failure. //TODO Make sure reagent prototypes actually have the toxin and boozepower vars set. // Run metabolism code for each reagent foreach (var metabolizable in prototype.Metabolism) { var reagentDelta = metabolizable.Metabolize(Body.Owner, reagent.ReagentId, _updateIntervalSeconds, availableReagent); bloodstream.Solution.TryRemoveReagent(reagent.ReagentId, reagentDelta); availableReagent -= reagentDelta; } } } } }