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