diff --git a/Content.Server/GameObjects/Components/Body/Behavior/LiverBehavior.cs b/Content.Server/GameObjects/Components/Body/Behavior/LiverBehavior.cs new file mode 100644 index 0000000000..a6a882e0a6 --- /dev/null +++ b/Content.Server/GameObjects/Components/Body/Behavior/LiverBehavior.cs @@ -0,0 +1,116 @@ +#nullable enable +using System.Linq; +using Content.Server.GameObjects.Components.Body.Circulatory; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Body.Networks; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +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. + /// + [ViewVariables] private float _alcoholLethality = 0.005f; + + /// + /// Modifier for alcohol damage. + /// + [ViewVariables] private float _alcoholExponent = 1.6f; + + /// + /// Toxin volume that can be purged without damage. + /// + [ViewVariables] private float _toxinTolerance = 3f; + + /// + /// Toxin damage modifier. + /// + [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); + } + } + } + + public override void ExposeData(ObjectSerializer serializer) + { + //Uses typical human values for defaults. + base.ExposeData(serializer); + serializer.DataField(ref _alcoholLethality, "alcoholLethality", 0.005f); + serializer.DataField(ref _alcoholExponent, "alcoholExponent", 1.6f); + serializer.DataField(ref _toxinTolerance, "toxinTolerance", 3f); + serializer.DataField(ref _toxinLethality, "toxinLethality", 0.01f); + } + } +} diff --git a/Content.Server/GameObjects/Components/Body/Behavior/StomachBehavior.cs b/Content.Server/GameObjects/Components/Body/Behavior/StomachBehavior.cs index 30107dbd03..b29983f7af 100644 --- a/Content.Server/GameObjects/Components/Body/Behavior/StomachBehavior.cs +++ b/Content.Server/GameObjects/Components/Body/Behavior/StomachBehavior.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections.Generic; using System.Linq; +using Content.Server.GameObjects.Components.Body.Circulatory; using Content.Server.GameObjects.Components.Chemistry; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Body.Networks; @@ -44,8 +45,8 @@ namespace Content.Server.GameObjects.Components.Body.Behavior _accumulatedFrameTime -= 1; - if (!Owner.TryGetComponent(out SharedSolutionContainerComponent? solution) || - !Body.Owner.TryGetComponent(out SharedBloodstreamComponent? bloodstream)) + if (!Body.Owner.TryGetComponent(out SolutionContainerComponent? solution) || + !Body.Owner.TryGetComponent(out BloodstreamComponent? bloodstream)) { return; } @@ -138,10 +139,10 @@ namespace Content.Server.GameObjects.Components.Body.Behavior public bool TryTransferSolution(Solution solution) { - if (!CanTransferSolution(solution)) + if (Body == null || !CanTransferSolution(solution)) return false; - if (!Owner.TryGetComponent(out SharedSolutionContainerComponent? solutionComponent)) + if (!Body.Owner.TryGetComponent(out SolutionContainerComponent? solutionComponent)) { return false; } diff --git a/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs b/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs index 959f55b810..b79cc1c7a5 100644 --- a/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs +++ b/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs @@ -9,14 +9,12 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Temperature; using Content.Shared.Alert; using Content.Shared.Atmos; -using Content.Shared.Chemistry; using Content.Shared.Damage; using Content.Shared.GameObjects.Components.Body; using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Mobs.State; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.Interfaces; -using Content.Shared.Interfaces.Chemistry; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; @@ -317,43 +315,7 @@ namespace Content.Server.GameObjects.Components.Metabolism } /// - /// Loops through each reagent in _internalSolution, - /// and calls for each of them. - /// - /// The time since the last metabolism tick in seconds. - private void ProcessNutrients(float frameTime) - { - if (!Owner.TryGetComponent(out BloodstreamComponent? bloodstream)) - { - return; - } - - if (bloodstream.Solution.CurrentVolume == 0) - { - 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; - } - - // Run metabolism code for each reagent - foreach (var metabolizable in prototype.Metabolism) - { - var reagentDelta = metabolizable.Metabolize(Owner, reagent.ReagentId, frameTime); - bloodstream.Solution.TryRemoveReagent(reagent.ReagentId, reagentDelta); - } - } - } - - /// - /// Processes gases in the bloodstream and triggers metabolism of the - /// reagents inside of it. + /// Processes gases in the bloodstream. /// /// /// The time since the last metabolism tick in seconds. @@ -374,7 +336,6 @@ namespace Content.Server.GameObjects.Components.Metabolism } ProcessGases(_accumulatedFrameTime); - ProcessNutrients(_accumulatedFrameTime); ProcessThermalRegulation(_accumulatedFrameTime); _accumulatedFrameTime -= 1; diff --git a/Content.Shared/Chemistry/ReagentPrototype.cs b/Content.Shared/Chemistry/ReagentPrototype.cs index ab09269656..33fb91b09e 100644 --- a/Content.Shared/Chemistry/ReagentPrototype.cs +++ b/Content.Shared/Chemistry/ReagentPrototype.cs @@ -29,6 +29,8 @@ namespace Content.Shared.Chemistry private List _tileReactions = default!; private List _plantMetabolism = default!; private float _customPlantMetabolism; + private bool _toxin; + private int _boozePower; public string ID => _id; public string Name => _name; @@ -36,6 +38,9 @@ namespace Content.Shared.Chemistry public string PhysicalDescription => _physicalDescription; public Color SubstanceColor => _substanceColor; + public bool Toxin => _toxin; + public int BoozePower => _boozePower; + //List of metabolism effects this reagent has, should really only be used server-side. public IReadOnlyList Metabolism => _metabolism; public IReadOnlyList TileReactions => _tileReactions; @@ -58,6 +63,8 @@ namespace Content.Shared.Chemistry serializer.DataField(ref _substanceColor, "color", Color.White); serializer.DataField(ref _spritePath, "spritePath", string.Empty); serializer.DataField(ref _customPlantMetabolism, "customPlantMetabolism", 1f); + serializer.DataField(ref _toxin, "toxin", false); + serializer.DataField(ref _boozePower, "boozePower", 0); if (_moduleManager.IsServerModule) { diff --git a/Resources/Prototypes/Body/Mechanisms/basic_human_organs.yml b/Resources/Prototypes/Body/Mechanisms/basic_human_organs.yml index 9139a10da5..1b70ce6415 100644 --- a/Resources/Prototypes/Body/Mechanisms/basic_human_organs.yml +++ b/Resources/Prototypes/Body/Mechanisms/basic_human_organs.yml @@ -108,7 +108,7 @@ id: LiverHuman parent: BaseHumanOrgan name: "human liver" - description: "Filters impurities out of a bloodstream and provides other important functionality to a human." + description: "Filters impurities out of a bloodstream and provides other important functionality to a human, such as reagent metabolization." components: - type: Sprite netsync: false @@ -118,6 +118,12 @@ durability: 15 size: 1 compatibility: Biological + behaviors: + - !type:LiverBehavior + alcoholLethality: 0.005 + alcoholExponent: 1.6 + toxinTolerance: 3 + toxinLethality: 0.01 - type: entity id: KidneysHuman