Basic liver mechanism (#3424)
* Basic liver mechanism * makes the stupid thing work
This commit is contained in:
@@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Metabolizes reagents in <see cref="SharedBloodstreamComponent"/> after they are digested.
|
||||||
|
/// </summary>
|
||||||
|
public class LiverBehavior : MechanismBehavior
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
|
private float _accumulatedFrameTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the liver is functional.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] private bool _liverFailing = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Modifier for alcohol damage.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] private float _alcoholLethality = 0.005f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Modifier for alcohol damage.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] private float _alcoholExponent = 1.6f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toxin volume that can be purged without damage.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] private float _toxinTolerance = 3f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toxin damage modifier.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] private float _toxinLethality = 0.01f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loops through each reagent in _internalSolution,
|
||||||
|
/// and calls <see cref="IMetabolizable.Metabolize"/> for each of them.
|
||||||
|
/// Also handles toxins and alcohol.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frameTime">
|
||||||
|
/// The time since the last update in seconds.
|
||||||
|
/// </param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.GameObjects.Components.Body.Circulatory;
|
||||||
using Content.Server.GameObjects.Components.Chemistry;
|
using Content.Server.GameObjects.Components.Chemistry;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.GameObjects.Components.Body.Networks;
|
using Content.Shared.GameObjects.Components.Body.Networks;
|
||||||
@@ -44,8 +45,8 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
|||||||
|
|
||||||
_accumulatedFrameTime -= 1;
|
_accumulatedFrameTime -= 1;
|
||||||
|
|
||||||
if (!Owner.TryGetComponent(out SharedSolutionContainerComponent? solution) ||
|
if (!Body.Owner.TryGetComponent(out SolutionContainerComponent? solution) ||
|
||||||
!Body.Owner.TryGetComponent(out SharedBloodstreamComponent? bloodstream))
|
!Body.Owner.TryGetComponent(out BloodstreamComponent? bloodstream))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -138,10 +139,10 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
|||||||
|
|
||||||
public bool TryTransferSolution(Solution solution)
|
public bool TryTransferSolution(Solution solution)
|
||||||
{
|
{
|
||||||
if (!CanTransferSolution(solution))
|
if (Body == null || !CanTransferSolution(solution))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!Owner.TryGetComponent(out SharedSolutionContainerComponent? solutionComponent))
|
if (!Body.Owner.TryGetComponent(out SolutionContainerComponent? solutionComponent))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ using Content.Server.GameObjects.Components.Mobs;
|
|||||||
using Content.Server.GameObjects.Components.Temperature;
|
using Content.Server.GameObjects.Components.Temperature;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Chemistry;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.GameObjects.Components.Body;
|
using Content.Shared.GameObjects.Components.Body;
|
||||||
using Content.Shared.GameObjects.Components.Damage;
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
using Content.Shared.GameObjects.Components.Mobs.State;
|
using Content.Shared.GameObjects.Components.Mobs.State;
|
||||||
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
|
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
|
||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
using Content.Shared.Interfaces.Chemistry;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
@@ -317,43 +315,7 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loops through each reagent in _internalSolution,
|
/// Processes gases in the bloodstream.
|
||||||
/// and calls <see cref="IMetabolizable.Metabolize"/> for each of them.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="frameTime">The time since the last metabolism tick in seconds.</param>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Processes gases in the bloodstream and triggers metabolism of the
|
|
||||||
/// reagents inside of it.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="frameTime">
|
/// <param name="frameTime">
|
||||||
/// The time since the last metabolism tick in seconds.
|
/// The time since the last metabolism tick in seconds.
|
||||||
@@ -374,7 +336,6 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProcessGases(_accumulatedFrameTime);
|
ProcessGases(_accumulatedFrameTime);
|
||||||
ProcessNutrients(_accumulatedFrameTime);
|
|
||||||
ProcessThermalRegulation(_accumulatedFrameTime);
|
ProcessThermalRegulation(_accumulatedFrameTime);
|
||||||
|
|
||||||
_accumulatedFrameTime -= 1;
|
_accumulatedFrameTime -= 1;
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ namespace Content.Shared.Chemistry
|
|||||||
private List<ITileReaction> _tileReactions = default!;
|
private List<ITileReaction> _tileReactions = default!;
|
||||||
private List<IPlantMetabolizable> _plantMetabolism = default!;
|
private List<IPlantMetabolizable> _plantMetabolism = default!;
|
||||||
private float _customPlantMetabolism;
|
private float _customPlantMetabolism;
|
||||||
|
private bool _toxin;
|
||||||
|
private int _boozePower;
|
||||||
|
|
||||||
public string ID => _id;
|
public string ID => _id;
|
||||||
public string Name => _name;
|
public string Name => _name;
|
||||||
@@ -36,6 +38,9 @@ namespace Content.Shared.Chemistry
|
|||||||
public string PhysicalDescription => _physicalDescription;
|
public string PhysicalDescription => _physicalDescription;
|
||||||
public Color SubstanceColor => _substanceColor;
|
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.
|
//List of metabolism effects this reagent has, should really only be used server-side.
|
||||||
public IReadOnlyList<IMetabolizable> Metabolism => _metabolism;
|
public IReadOnlyList<IMetabolizable> Metabolism => _metabolism;
|
||||||
public IReadOnlyList<ITileReaction> TileReactions => _tileReactions;
|
public IReadOnlyList<ITileReaction> TileReactions => _tileReactions;
|
||||||
@@ -58,6 +63,8 @@ namespace Content.Shared.Chemistry
|
|||||||
serializer.DataField(ref _substanceColor, "color", Color.White);
|
serializer.DataField(ref _substanceColor, "color", Color.White);
|
||||||
serializer.DataField(ref _spritePath, "spritePath", string.Empty);
|
serializer.DataField(ref _spritePath, "spritePath", string.Empty);
|
||||||
serializer.DataField(ref _customPlantMetabolism, "customPlantMetabolism", 1f);
|
serializer.DataField(ref _customPlantMetabolism, "customPlantMetabolism", 1f);
|
||||||
|
serializer.DataField(ref _toxin, "toxin", false);
|
||||||
|
serializer.DataField(ref _boozePower, "boozePower", 0);
|
||||||
|
|
||||||
if (_moduleManager.IsServerModule)
|
if (_moduleManager.IsServerModule)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
id: LiverHuman
|
id: LiverHuman
|
||||||
parent: BaseHumanOrgan
|
parent: BaseHumanOrgan
|
||||||
name: "human liver"
|
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:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
netsync: false
|
netsync: false
|
||||||
@@ -118,6 +118,12 @@
|
|||||||
durability: 15
|
durability: 15
|
||||||
size: 1
|
size: 1
|
||||||
compatibility: Biological
|
compatibility: Biological
|
||||||
|
behaviors:
|
||||||
|
- !type:LiverBehavior
|
||||||
|
alcoholLethality: 0.005
|
||||||
|
alcoholExponent: 1.6
|
||||||
|
toxinTolerance: 3
|
||||||
|
toxinLethality: 0.01
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: KidneysHuman
|
id: KidneysHuman
|
||||||
|
|||||||
Reference in New Issue
Block a user