#nullable enable using System.Linq; using Content.Server.GameObjects.Components.Body.Circulatory; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Body.Networks; using Content.Shared.Interfaces.Chemistry; using Robust.Shared.IoC; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Body.Behavior { /// /// Metabolizes reagents in after they are digested. /// public class LiverBehavior : MechanismBehavior { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private float _accumulatedFrameTime; /// /// 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 per second if (_accumulatedFrameTime < 1) { return; } _accumulatedFrameTime -= 1; 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; } //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, frameTime); bloodstream.Solution.TryRemoveReagent(reagent.ReagentId, reagentDelta); } } } } }