Metabolism refactor (#4395)
* metabolism -> respirator, add reageanteffect and reagenteffectcondition, start on metabolizercomp/system * move LiverBehavior metabolism logic to Metabolizer * minor tweaks and update all YAML * how about actually taking conditions into account * off by one * removals * reviews
This commit is contained in:
@@ -154,7 +154,8 @@ namespace Content.Client.Entry
|
||||
"GasPassiveGate",
|
||||
"GasValve",
|
||||
"GasThermoMachine",
|
||||
"Metabolism",
|
||||
"Respirator",
|
||||
"Metabolizer",
|
||||
"AiFactionTag",
|
||||
"PressureProtection",
|
||||
"AMEPart",
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Body.Behavior;
|
||||
using Content.Server.Body.Circulatory;
|
||||
using Content.Server.Metabolism;
|
||||
using Content.Server.Body.Respiratory;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
using NUnit.Framework;
|
||||
@@ -32,7 +32,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
template: HumanoidTemplate
|
||||
preset: HumanPreset
|
||||
centerSlot: torso
|
||||
- type: Metabolism
|
||||
- type: Respirator
|
||||
metabolismHeat: 5000
|
||||
radiatedHeat: 400
|
||||
implicitHeatRegulation: 5000
|
||||
@@ -148,7 +148,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
|
||||
MapId mapId;
|
||||
IMapGrid grid = null;
|
||||
MetabolismComponent metabolism = null;
|
||||
RespiratorComponent respirator = null;
|
||||
IEntity human = null;
|
||||
|
||||
var testMapName = "Maps/Test/Breathing/3by3-20oxy-80nit.yml";
|
||||
@@ -169,8 +169,8 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
|
||||
Assert.True(human.TryGetComponent(out SharedBodyComponent body));
|
||||
Assert.True(body.HasMechanismBehavior<LungBehavior>());
|
||||
Assert.True(human.TryGetComponent(out metabolism));
|
||||
Assert.False(metabolism.Suffocating);
|
||||
Assert.True(human.TryGetComponent(out respirator));
|
||||
Assert.False(respirator.Suffocating);
|
||||
});
|
||||
|
||||
var increment = 10;
|
||||
@@ -178,7 +178,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
for (var tick = 0; tick < 600; tick += increment)
|
||||
{
|
||||
await server.WaitRunTicks(increment);
|
||||
Assert.False(metabolism.Suffocating, $"Entity {human.Name} is suffocating on tick {tick}");
|
||||
Assert.False(respirator.Suffocating, $"Entity {human.Name} is suffocating on tick {tick}");
|
||||
}
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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;
|
||||
@@ -13,52 +12,8 @@ namespace Content.Server.Body.Behavior
|
||||
/// </summary>
|
||||
public class LiverBehavior : MechanismBehavior
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
private float _accumulatedFrameTime;
|
||||
|
||||
/// <summary>
|
||||
/// Delay time that determines how often to metabolise blood contents (in seconds).
|
||||
/// </summary>
|
||||
private float _updateIntervalSeconds = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the liver is functional.
|
||||
/// </summary>
|
||||
//[ViewVariables] private bool _liverFailing = false;
|
||||
|
||||
/// <summary>
|
||||
/// Modifier for alcohol damage.
|
||||
/// </summary>
|
||||
//[DataField("alcoholLethality")]
|
||||
//[ViewVariables] private float _alcoholLethality = 0.005f;
|
||||
|
||||
/// <summary>
|
||||
/// Modifier for alcohol damage.
|
||||
/// </summary>
|
||||
//[DataField("alcoholExponent")]
|
||||
//[ViewVariables] private float _alcoholExponent = 1.6f;
|
||||
|
||||
/// <summary>
|
||||
/// Toxin volume that can be purged without damage.
|
||||
/// </summary>
|
||||
//[DataField("toxinTolerance")]
|
||||
//[ViewVariables] private float _toxinTolerance = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// Toxin damage modifier.
|
||||
/// </summary>
|
||||
//[DataField("toxinLethality")]
|
||||
//[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)
|
||||
@@ -68,51 +23,13 @@ namespace Content.Server.Body.Behavior
|
||||
|
||||
_accumulatedFrameTime += frameTime;
|
||||
|
||||
// Update at most once every _updateIntervalSeconds
|
||||
if (_accumulatedFrameTime < _updateIntervalSeconds)
|
||||
// Update at most once per second
|
||||
if (_accumulatedFrameTime < 1)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
_accumulatedFrameTime -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ using System;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Respiratory;
|
||||
using Content.Server.Chemistry.Components;
|
||||
using Content.Server.Metabolism;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Networks;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
@@ -72,7 +72,7 @@ namespace Content.Server.Body.Circulatory
|
||||
{
|
||||
var atmosphereSystem = EntitySystem.Get<AtmosphereSystem>();
|
||||
|
||||
if (!Owner.TryGetComponent(out MetabolismComponent? metabolism))
|
||||
if (!Owner.TryGetComponent(out RespiratorComponent? metabolism))
|
||||
{
|
||||
atmosphereSystem.Merge(to, Air);
|
||||
Air.Clear();
|
||||
|
||||
57
Content.Server/Body/Metabolism/MetabolizerComponent.cs
Normal file
57
Content.Server/Body/Metabolism/MetabolizerComponent.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||
|
||||
namespace Content.Server.Body.Metabolism
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles metabolizing various reagents with given effects.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class MetabolizerComponent : Component
|
||||
{
|
||||
public override string Name => "Metabolizer";
|
||||
|
||||
public float AccumulatedFrametime = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How often to metabolize reagents, in seconds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DataField("updateFrequency")]
|
||||
public float UpdateFrequency = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this metabolizer should attempt to metabolize chemicals in its parent bodies' bloodstream,
|
||||
/// as opposed to a solution container on the metabolizing entity itself.
|
||||
/// </summary>
|
||||
[DataField("takeFromBloodstream")]
|
||||
public bool TakeFromBloodstream = true;
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary mapping reagent string IDs to a list of effects & associated metabolism rate.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DataField("metabolisms", required: true, customTypeSerializer:typeof(PrototypeIdDictionarySerializer<ReagentEffectsEntry, ReagentPrototype>))]
|
||||
public Dictionary<string, ReagentEffectsEntry> Metabolisms = default!;
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public class ReagentEffectsEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Amount of reagent to metabolize, per metabolism cycle.
|
||||
/// </summary>
|
||||
[DataField("metabolismRate")]
|
||||
public ReagentUnit MetabolismRate = ReagentUnit.New(1.0f);
|
||||
|
||||
/// <summary>
|
||||
/// A list of effects to apply when these reagents are metabolized.
|
||||
/// </summary>
|
||||
[DataField("effects", required: true)]
|
||||
public ReagentEffect[] Effects = default!;
|
||||
}
|
||||
}
|
||||
107
Content.Server/Body/Metabolism/MetabolizerSystem.cs
Normal file
107
Content.Server/Body/Metabolism/MetabolizerSystem.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Body.Circulatory;
|
||||
using Content.Server.Chemistry.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Mechanism;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Body.Metabolism
|
||||
{
|
||||
// TODO mirror in the future working on mechanisms move updating here to BodySystem so it can be ordered?
|
||||
public class MetabolizerSystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var metab in ComponentManager.EntityQuery<MetabolizerComponent>(false))
|
||||
{
|
||||
metab.AccumulatedFrametime += frameTime;
|
||||
|
||||
// Only update as frequently as it should
|
||||
if (metab.AccumulatedFrametime >= metab.UpdateFrequency)
|
||||
{
|
||||
metab.AccumulatedFrametime = 0.0f;
|
||||
TryMetabolize(metab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryMetabolize(MetabolizerComponent comp)
|
||||
{
|
||||
var owner = comp.Owner;
|
||||
var reagentList = new List<Solution.ReagentQuantity>();
|
||||
SolutionContainerComponent? solution = null;
|
||||
SharedBodyComponent? body = null;
|
||||
|
||||
// if this field is passed we should try and take from the bloodstream over anything else
|
||||
if (comp.TakeFromBloodstream && owner.TryGetComponent<SharedMechanismComponent>(out var mech))
|
||||
{
|
||||
body = mech.Body;
|
||||
if (body != null)
|
||||
{
|
||||
if (body.Owner.TryGetComponent<BloodstreamComponent>(out var bloodstream)
|
||||
&& bloodstream.Solution.CurrentVolume >= ReagentUnit.Zero)
|
||||
{
|
||||
solution = bloodstream.Solution;
|
||||
reagentList = bloodstream.Solution.ReagentList.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (owner.TryGetComponent<SolutionContainerComponent>(out var sol))
|
||||
{
|
||||
// if we have no mechanism/body but a solution container instead,
|
||||
// we'll just use that to metabolize from
|
||||
solution = sol;
|
||||
reagentList = sol.ReagentList.ToList();
|
||||
}
|
||||
if (solution == null || reagentList.Count == 0)
|
||||
{
|
||||
// We're all outta ideas on where to metabolize from
|
||||
return;
|
||||
}
|
||||
|
||||
// Run metabolism for each reagent, remove metabolized reagents
|
||||
foreach (var reagent in reagentList)
|
||||
{
|
||||
if (!comp.Metabolisms.ContainsKey(reagent.ReagentId))
|
||||
continue;
|
||||
|
||||
var metabolism = comp.Metabolisms[reagent.ReagentId];
|
||||
// Run metabolism code for each reagent
|
||||
foreach (var effect in metabolism.Effects)
|
||||
{
|
||||
var ent = body != null ? body.Owner : owner;
|
||||
var conditionsMet = true;
|
||||
if (effect.Conditions != null)
|
||||
{
|
||||
// yes this is 3 nested for loops, but all of these lists are
|
||||
// basically guaranteed to be small or empty
|
||||
foreach (var condition in effect.Conditions)
|
||||
{
|
||||
if (!condition.Condition(ent, reagent))
|
||||
{
|
||||
conditionsMet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!conditionsMet)
|
||||
return;
|
||||
|
||||
// If we're part of a body, pass that entity to Metabolize
|
||||
// Otherwise, just pass our owner entity, maybe we're a plant or something
|
||||
effect.Metabolize(ent, reagent);
|
||||
}
|
||||
|
||||
solution.TryRemoveReagent(reagent.ReagentId, metabolism.MetabolismRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Metabolism.Events;
|
||||
using Content.Shared.MobState;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -21,14 +20,14 @@ using Robust.Shared.Localization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Metabolism
|
||||
namespace Content.Server.Body.Respiratory
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class MetabolismComponent : Component
|
||||
public class RespiratorComponent : Component
|
||||
{
|
||||
[ComponentDependency] private readonly SharedBodyComponent? _body = default!;
|
||||
|
||||
public override string Name => "Metabolism";
|
||||
public override string Name => "Respirator";
|
||||
|
||||
private float _accumulatedFrameTime;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Metabolism
|
||||
namespace Content.Server.Body.Respiratory
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class MetabolismSystem : EntitySystem
|
||||
public class RespiratorSystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var metabolism in ComponentManager.EntityQuery<MetabolismComponent>(true))
|
||||
foreach (var respirator in ComponentManager.EntityQuery<RespiratorComponent>(false))
|
||||
{
|
||||
metabolism.Update(frameTime);
|
||||
respirator.Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Metabolizable;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Chemistry.Metabolism
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for drink reagents. Attempts to find a ThirstComponent on the target,
|
||||
/// and to update it's thirst values. Inherits metabolisation rate logic from DefaultMetabolizable.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public class DefaultDrink : DefaultMetabolizable
|
||||
{
|
||||
//How much thirst is satiated when 1u of the reagent is metabolized
|
||||
[DataField("hydrationFactor")]
|
||||
public float HydrationFactor { get; set; } = 30.0f;
|
||||
|
||||
//Remove reagent at set rate, satiate thirst if a ThirstComponent can be found
|
||||
public override ReagentUnit Metabolize(IEntity solutionEntity, string reagentId, float tickTime, ReagentUnit availableReagent)
|
||||
{
|
||||
// use DefaultMetabolism to determine how much reagent we should metabolize
|
||||
var amountMetabolized = base.Metabolize(solutionEntity, reagentId, tickTime, availableReagent);
|
||||
|
||||
// If metabolizing entity has a ThirstComponent, hydrate them.
|
||||
if (solutionEntity.TryGetComponent(out ThirstComponent? thirst))
|
||||
thirst.UpdateThirst(amountMetabolized.Float() * HydrationFactor);
|
||||
|
||||
//Return amount of reagent to be removed, remove reagent regardless of ThirstComponent presence
|
||||
return amountMetabolized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Metabolizable;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Chemistry.Metabolism
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for food reagents. Attempts to find a HungerComponent on the target,
|
||||
/// and to update it's hunger values. Inherits metabolisation rate logic from DefaultMetabolizable.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public class DefaultFood : DefaultMetabolizable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// How much hunger is satiated when 1u of the reagent is metabolized
|
||||
/// </summary>
|
||||
[DataField("nutritionFactor")] public float NutritionFactor { get; set; } = 30.0f;
|
||||
|
||||
|
||||
//Remove reagent at set rate, satiate hunger if a HungerComponent can be found
|
||||
public override ReagentUnit Metabolize(IEntity solutionEntity, string reagentId, float tickTime, ReagentUnit availableReagent)
|
||||
{
|
||||
// use DefaultMetabolism to determine how much reagent we should metabolize
|
||||
var amountMetabolized = base.Metabolize(solutionEntity, reagentId, tickTime, availableReagent);
|
||||
|
||||
// If metabolizing entity has a HungerComponent, feed them.
|
||||
if (solutionEntity.TryGetComponent(out HungerComponent? hunger))
|
||||
hunger.UpdateFood(amountMetabolized.Float() * NutritionFactor);
|
||||
|
||||
//Return amount of reagent to be removed. Reagent is removed regardless of HungerComponent presence
|
||||
return amountMetabolized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Metabolizable;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
|
||||
namespace Content.Server.Chemistry.Metabolism
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for medicine reagents. Attempts to find a DamageableComponent on the target,
|
||||
/// and to update its damage values. Inherits metabolisation rate logic from DefaultMetabolizable.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public class HealthChangeMetabolism : DefaultMetabolizable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// How much damage is changed when 1u of the reagent is metabolized.
|
||||
/// </summary>
|
||||
[DataField("healthChange")]
|
||||
public float HealthChange { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Class of damage changed, Brute, Burn, Toxin, Airloss.
|
||||
/// </summary>
|
||||
[DataField("damageClass")]
|
||||
public DamageClass DamageType { get; set; } = DamageClass.Brute;
|
||||
|
||||
private float _accumulatedHealth;
|
||||
|
||||
/// <summary>
|
||||
/// Remove reagent at set rate, changes damage if a DamageableComponent can be found.
|
||||
/// </summary>
|
||||
/// <param name="solutionEntity"></param>
|
||||
/// <param name="reagentId"></param>
|
||||
/// <param name="tickTime"></param>
|
||||
/// <param name="availableReagent">Reagent available to be metabolized.</param>
|
||||
/// <returns></returns>
|
||||
public override ReagentUnit Metabolize(IEntity solutionEntity, string reagentId, float tickTime, ReagentUnit availableReagent)
|
||||
{
|
||||
// use DefaultMetabolism to determine how much reagent we should metabolize
|
||||
var amountMetabolized = base.Metabolize(solutionEntity, reagentId, tickTime, availableReagent);
|
||||
|
||||
// how much does this much reagent heal for
|
||||
var healthChangeAmount = HealthChange * amountMetabolized.Float();
|
||||
|
||||
if (solutionEntity.TryGetComponent(out IDamageableComponent? health))
|
||||
{
|
||||
// Heal damage by healthChangeAmmount, rounding down to nearest integer
|
||||
health.ChangeDamage(DamageType, (int) healthChangeAmount, true);
|
||||
|
||||
// Store decimal remainder of healthChangeAmmount in _accumulatedHealth
|
||||
_accumulatedHealth += (healthChangeAmount - (int) healthChangeAmount);
|
||||
|
||||
if (_accumulatedHealth >= 1)
|
||||
{
|
||||
health.ChangeDamage(DamageType, 1, true);
|
||||
_accumulatedHealth -= 1;
|
||||
}
|
||||
|
||||
else if(_accumulatedHealth <= -1)
|
||||
{
|
||||
health.ChangeDamage(DamageType, -1, true);
|
||||
_accumulatedHealth += 1;
|
||||
}
|
||||
}
|
||||
return amountMetabolized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for implementing reagent effects that require a certain amount of reagent before it should be applied.
|
||||
/// For instance, overdoses.
|
||||
/// </summary>
|
||||
public class ReagentThreshold : ReagentEffectCondition
|
||||
{
|
||||
[DataField("min")]
|
||||
public ReagentUnit Min = ReagentUnit.Zero;
|
||||
|
||||
[DataField("max")]
|
||||
public ReagentUnit Max = ReagentUnit.MaxValue;
|
||||
|
||||
public override bool Condition(IEntity solutionEntity, Solution.ReagentQuantity reagent)
|
||||
{
|
||||
return reagent.Quantity >= Min && reagent.Quantity < Max;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Content.Server/Chemistry/ReagentEffects/HealthChange.cs
Normal file
56
Content.Server/Chemistry/ReagentEffects/HealthChange.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for medicine reagents. Attempts to find a DamageableComponent on the target,
|
||||
/// and to update its damage values.
|
||||
/// </summary>
|
||||
public class HealthChange : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How much damage is changed when 1u of the reagent is metabolized.
|
||||
/// </summary>
|
||||
[DataField("healthChange")]
|
||||
public float AmountToChange { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Class of damage changed, Brute, Burn, Toxin, Airloss.
|
||||
/// </summary>
|
||||
[DataField("damageClass")]
|
||||
public DamageClass DamageType { get; set; } = DamageClass.Brute;
|
||||
|
||||
private float _accumulatedHealth;
|
||||
|
||||
/// <summary>
|
||||
/// Changes damage if a DamageableComponent can be found.
|
||||
/// </summary>
|
||||
public override void Metabolize(IEntity solutionEntity, Solution.ReagentQuantity amount)
|
||||
{
|
||||
if (solutionEntity.TryGetComponent(out IDamageableComponent? health))
|
||||
{
|
||||
health.ChangeDamage(DamageType, (int)AmountToChange, true);
|
||||
float decHealthChange = (float) (AmountToChange - (int) AmountToChange);
|
||||
_accumulatedHealth += decHealthChange;
|
||||
|
||||
if (_accumulatedHealth >= 1)
|
||||
{
|
||||
health.ChangeDamage(DamageType, 1, true);
|
||||
_accumulatedHealth -= 1;
|
||||
}
|
||||
|
||||
else if(_accumulatedHealth <= -1)
|
||||
{
|
||||
health.ChangeDamage(DamageType, -1, true);
|
||||
_accumulatedHealth += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Content.Server/Chemistry/ReagentEffects/SatiateHunger.cs
Normal file
28
Content.Server/Chemistry/ReagentEffects/SatiateHunger.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to find a HungerComponent on the target,
|
||||
/// and to update it's hunger values.
|
||||
/// </summary>
|
||||
public class SatiateHunger : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How much hunger is satiated when 1u of the reagent is metabolized
|
||||
/// </summary>
|
||||
[DataField("nutritionFactor")] public float NutritionFactor { get; set; } = 3.0f;
|
||||
|
||||
//Remove reagent at set rate, satiate hunger if a HungerComponent can be found
|
||||
public override void Metabolize(IEntity solutionEntity, Solution.ReagentQuantity amount)
|
||||
{
|
||||
if (solutionEntity.TryGetComponent(out HungerComponent? hunger))
|
||||
hunger.UpdateFood(NutritionFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs
Normal file
28
Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for drink reagents. Attempts to find a ThirstComponent on the target,
|
||||
/// and to update it's thirst values.
|
||||
/// </summary>
|
||||
public class SatiateThirst : ReagentEffect
|
||||
{
|
||||
/// How much thirst is satiated each metabolism tick. Not currently tied to
|
||||
/// rate or anything.
|
||||
[DataField("hydrationFactor")]
|
||||
public float HydrationFactor { get; set; } = 3.0f;
|
||||
|
||||
/// Satiate thirst if a ThirstComponent can be found
|
||||
public override void Metabolize(IEntity solutionEntity, Solution.ReagentQuantity amount)
|
||||
{
|
||||
if (solutionEntity.TryGetComponent(out ThirstComponent? thirst))
|
||||
thirst.UpdateThirst(HydrationFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Content.Shared.Emoting;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Metabolism.Events;
|
||||
using Content.Shared.Body.Metabolism;
|
||||
using Content.Shared.Movement;
|
||||
using Content.Shared.Speech;
|
||||
using Content.Shared.Throwing;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Metabolism.Events
|
||||
namespace Content.Shared.Body.Metabolism
|
||||
{
|
||||
public class ShiverAttemptEvent : CancellableEntityEventArgs
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Metabolism.Events
|
||||
namespace Content.Shared.Body.Metabolism
|
||||
{
|
||||
public class SweatAttemptEvent : CancellableEntityEventArgs
|
||||
{
|
||||
@@ -1,36 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Chemistry.Metabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolization for reagents. Returns the amount of reagents metabolized without applying effects.
|
||||
/// Metabolizes reagents at a constant rate, limited by how much is available. Other classes are derived from
|
||||
/// this class, so that they do not need their own metabolization quantity calculation.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public class DefaultMetabolizable : IMetabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Rate of metabolism in units / second
|
||||
/// </summary>
|
||||
[DataField("rate")] public ReagentUnit MetabolismRate { get; set; } = ReagentUnit.New(1);
|
||||
|
||||
public virtual ReagentUnit Metabolize(IEntity solutionEntity, string reagentId, float tickTime, ReagentUnit availableReagent)
|
||||
{
|
||||
|
||||
// How much reagent should we metabolize
|
||||
// The default behaviour is to metabolize at a constant rate, independent of the quantity of reagents.
|
||||
var amountMetabolized = MetabolismRate * tickTime;
|
||||
|
||||
// is that much reagent actually available?
|
||||
if (availableReagent < amountMetabolized)
|
||||
{
|
||||
return availableReagent;
|
||||
}
|
||||
|
||||
return amountMetabolized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Chemistry.Metabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Metabolism behavior for a reagent.
|
||||
/// </summary>
|
||||
public interface IMetabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Metabolize the attached reagent. Return the amount of reagent to be removed from the solution.
|
||||
/// You shouldn't remove the reagent yourself to avoid invalidating the iterator of the metabolism
|
||||
/// organ that is processing it's reagents.
|
||||
/// </summary>
|
||||
/// <param name="solutionEntity">The entity containing the solution.</param>
|
||||
/// <param name="reagentId">The reagent id</param>
|
||||
/// <param name="tickTime">The time since the last metabolism tick in seconds.</param>
|
||||
/// <param name="availableReagent">Reagent available to be metabolized.</param>
|
||||
/// <returns>The amount of reagent to be removed. The metabolizing organ should handle removing the reagent.</returns>
|
||||
ReagentUnit Metabolize(IEntity solutionEntity, string reagentId, float tickTime, ReagentUnit availableReagent);
|
||||
}
|
||||
}
|
||||
23
Content.Shared/Chemistry/Reagent/ReagentEffect.cs
Normal file
23
Content.Shared/Chemistry/Reagent/ReagentEffect.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Chemistry.Reagent
|
||||
{
|
||||
/// <summary>
|
||||
/// Reagent effects describe behavior that occurs when a reagent is ingested and metabolized by some
|
||||
/// organ. They only trigger when their conditions (<see cref="ReagentEffectCondition"/>
|
||||
/// </summary>
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract class ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of conditions required for the effect to activate. Not required.
|
||||
/// </summary>
|
||||
[DataField("conditions")]
|
||||
public ReagentEffectCondition[]? Conditions;
|
||||
|
||||
public abstract void Metabolize(IEntity solutionEntity, Solution.Solution.ReagentQuantity amount);
|
||||
}
|
||||
}
|
||||
13
Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs
Normal file
13
Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Chemistry.Reagent
|
||||
{
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract class ReagentEffectCondition
|
||||
{
|
||||
public abstract bool Condition(IEntity solutionEntity, Solution.Solution.ReagentQuantity reagent);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Botany;
|
||||
using Content.Shared.Chemistry.Metabolizable;
|
||||
using Content.Shared.Chemistry.Reaction;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
@@ -16,9 +15,6 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
[DataDefinition]
|
||||
public class ReagentPrototype : IPrototype
|
||||
{
|
||||
[DataField("metabolism", serverOnly: true)]
|
||||
private readonly List<IMetabolizable> _metabolism = new() {new DefaultMetabolizable()};
|
||||
|
||||
[DataField("tileReactions", serverOnly: true)]
|
||||
private readonly List<ITileReaction> _tileReactions = new(0);
|
||||
|
||||
@@ -60,7 +56,6 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
public string SpriteReplacementPath { get; } = string.Empty;
|
||||
|
||||
//List of metabolism effects this reagent has, should really only be used server-side.
|
||||
public IReadOnlyList<IMetabolizable> Metabolism => _metabolism;
|
||||
public IReadOnlyList<ITileReaction> TileReactions => _tileReactions;
|
||||
public IReadOnlyList<IPlantMetabolizable> PlantMetabolism => _plantMetabolism;
|
||||
|
||||
|
||||
@@ -50,18 +50,30 @@
|
||||
compatibility: Biological
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanHeart
|
||||
id: OrganHumanTongue
|
||||
parent: BaseHumanOrgan
|
||||
name: heart
|
||||
description: "I feel bad for the heartless bastard who lost this."
|
||||
name: tongue
|
||||
description: "A fleshy muscle mostly used for lying."
|
||||
components:
|
||||
- type: Sprite
|
||||
state: heart-on
|
||||
state: tongue
|
||||
- type: Mechanism
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanAppendix
|
||||
parent: BaseHumanOrgan
|
||||
name: appendix
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: appendix
|
||||
- state: appendix-inflamed
|
||||
visible: false
|
||||
- type: Mechanism
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
behaviors:
|
||||
- !type:HeartBehavior {}
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanEars
|
||||
@@ -91,6 +103,92 @@
|
||||
behaviors:
|
||||
- !type:LungBehavior {}
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanHeart
|
||||
parent: BaseHumanOrgan
|
||||
name: heart
|
||||
description: "I feel bad for the heartless bastard who lost this."
|
||||
components:
|
||||
- type: Sprite
|
||||
state: heart-on
|
||||
- type: Mechanism
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
behaviors:
|
||||
- !type:HeartBehavior {}
|
||||
# The heart 'metabolizes' medicines and poisons that aren't filtered out by other organs.
|
||||
# This is done because these chemicals need to have some effect even if they aren't being filtered out of your body.
|
||||
# You're technically 'immune to poison' without a heart, but.. uhh, you'll have bigger problems on your hands.
|
||||
- type: Metabolizer
|
||||
metabolisms:
|
||||
Dylovene:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Toxin
|
||||
healthChange: -1
|
||||
Arithrazine:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Toxin
|
||||
healthChange: -1
|
||||
- !type:HealthChange
|
||||
damageClass: Brute
|
||||
healthChange: 0.5
|
||||
Bicaridine:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Brute
|
||||
healthChange: -2
|
||||
Dermaline:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Burn
|
||||
healthChange: -3
|
||||
Dexalin:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Airloss
|
||||
healthChange: -1
|
||||
DexalinPlus:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Airloss
|
||||
healthChange: -3
|
||||
Kelotane:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Burn
|
||||
healthChange: -1
|
||||
Synaptizine:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Toxin
|
||||
healthChange: 0.5
|
||||
HeartbreakerToxin:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Airloss
|
||||
healthChange: 4
|
||||
Lexorin:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damageClass: Airloss
|
||||
healthChange: 7
|
||||
Omnizine:
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
healthChange: -2
|
||||
damageClass: Burn
|
||||
- !type:HealthChange
|
||||
healthChange: -2
|
||||
damageClass: Toxin
|
||||
- !type:HealthChange
|
||||
healthChange: -2
|
||||
damageClass: Airloss
|
||||
- !type:HealthChange
|
||||
healthChange: -2
|
||||
damageClass: Brute
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanStomach
|
||||
parent: BaseHumanOrgan
|
||||
@@ -108,6 +206,93 @@
|
||||
digestionDelay: 20
|
||||
- type: SolutionContainer
|
||||
maxVol: 250
|
||||
# The stomach metabolizes stuff like foods and drinks.
|
||||
# TODO: Have it work off of the ent's solution container, and move this
|
||||
# to intestines instead.
|
||||
- type: Metabolizer # Release me from this hell called 1 reagent for every drink
|
||||
# TODO please make every drink their own base thing
|
||||
metabolisms:
|
||||
Flour:
|
||||
effects:
|
||||
- !type:SatiateHunger
|
||||
JuiceApple:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceBerry:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceBanana:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceCarrot:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceLime:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceLemon:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceGrape:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceOrange:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceTomato:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuiceBerryPoison:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
- !type:HealthChange
|
||||
damageClass: Toxin
|
||||
healthChange: 1
|
||||
JuiceWatermelon:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
JuicePineapple:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
Nutriment:
|
||||
effects:
|
||||
- !type:SatiateHunger
|
||||
Water:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
hydrationFactor: 2
|
||||
Coffee:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
Tea:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
Milk:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
SpoiledMilk:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
hydrationFactor: -2
|
||||
MilkSoy:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
hydrationFactor: 2 # soyboys stay winning
|
||||
MilkOat:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
hydrationFactor: 2 # oatboys stay winning
|
||||
Cola:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
hydrationFactor: 0.5 # sodaboys stay losing
|
||||
ThirteenLoko:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
hydrationFactor: 2
|
||||
- !type:HealthChange
|
||||
damageClass: Toxin
|
||||
healthChange: 1
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanLiver
|
||||
@@ -120,12 +305,17 @@
|
||||
- type: Mechanism
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
behaviors:
|
||||
- !type:LiverBehavior
|
||||
alcoholLethality: 0.005
|
||||
alcoholExponent: 1.6
|
||||
toxinTolerance: 3
|
||||
toxinLethality: 0.01
|
||||
- type: Metabolizer # The liver metabolizes certain chemicals only, like alcohol.
|
||||
metabolisms: # TODO add the rest of alcohol
|
||||
CreamyDelight:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
Lean:
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
LeanShine: # who added this?
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanKidneys
|
||||
@@ -141,28 +331,4 @@
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanTongue
|
||||
parent: BaseHumanOrgan
|
||||
name: tongue
|
||||
description: "A fleshy muscle mostly used for lying."
|
||||
components:
|
||||
- type: Sprite
|
||||
state: tongue
|
||||
- type: Mechanism
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
|
||||
- type: entity
|
||||
id: OrganHumanAppendix
|
||||
parent: BaseHumanOrgan
|
||||
name: appendix
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: appendix
|
||||
- state: appendix-inflamed
|
||||
visible: false
|
||||
- type: Mechanism
|
||||
size: 1
|
||||
compatibility: Biological
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
currentTemperature: 310.15
|
||||
specificHeat: 42
|
||||
tempDamageCoefficient: 0.1
|
||||
- type: Metabolism
|
||||
- type: Respirator
|
||||
metabolismHeat: 5000
|
||||
radiatedHeat: 400
|
||||
implicitHeatRegulation: 5000
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
0: !type:NormalMobState {}
|
||||
150: !type:CriticalMobState {}
|
||||
200: !type:DeadMobState {}
|
||||
- type: Metabolism
|
||||
- type: Respirator
|
||||
- type: UnarmedCombat
|
||||
range: 1.5
|
||||
arcwidth: 0
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
preset: HumanPreset
|
||||
- type: Damageable
|
||||
damageContainer: biologicalDamageContainer
|
||||
- type: Metabolism
|
||||
- type: Respirator
|
||||
metabolismHeat: 5000
|
||||
radiatedHeat: 400
|
||||
implicitHeatRegulation: 5000
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
- type: Body
|
||||
template: HumanoidTemplate
|
||||
preset: VoxPreset
|
||||
- type: Metabolism
|
||||
- type: Respirator
|
||||
needsGases:
|
||||
Nitrogen: 0.00060763888
|
||||
producesGases:
|
||||
|
||||
@@ -183,9 +183,6 @@
|
||||
desc: A combination of cream, wine and moonshine. Why would you do this?
|
||||
physicalDesc: foul
|
||||
color: "#a6969a"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Lean
|
||||
@@ -193,9 +190,6 @@
|
||||
desc: Turn up for days.
|
||||
physicalDesc: bubbly
|
||||
color: "#9400D3"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: LeanShine
|
||||
@@ -203,8 +197,3 @@
|
||||
desc: Lean mixed with moonshine. Turn up for months.
|
||||
physicalDesc: bubbly
|
||||
color: "#9d5fb8"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
desc: A drink made from brewed coffee beans. Contains a moderate amount of caffeine.
|
||||
physicalDesc: aromatic
|
||||
color: "#664300"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Tea
|
||||
@@ -14,9 +11,6 @@
|
||||
desc: A drink made by boiling leaves of the tea tree, Camellia sinensis.
|
||||
physicalDesc: aromatic
|
||||
color: "#8a5a3a"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Cream
|
||||
@@ -24,9 +18,6 @@
|
||||
desc: The fatty, still liquid part of milk. Why don't you mix this with sum scotch, eh?
|
||||
physicalDesc: creamy
|
||||
color: "#DFD7AF"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Milk
|
||||
@@ -34,9 +25,6 @@
|
||||
desc: An opaque white liquid produced by the mammary glands of mammals.
|
||||
physicalDesc: opaque
|
||||
color: "#DFDFDF"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
plantMetabolism:
|
||||
- !type:AdjustNutrition
|
||||
amount: 0.1
|
||||
@@ -49,9 +37,6 @@
|
||||
desc: This milk has gone rancid.
|
||||
physicalDesc: putrid
|
||||
color: "#faffba"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: MilkSoy
|
||||
@@ -59,9 +44,6 @@
|
||||
desc: Surprisingly tasty.
|
||||
physicalDesc: refreshing
|
||||
color: "#302000"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: MilkOat
|
||||
@@ -69,6 +51,3 @@
|
||||
desc: Surprisingly tasty.
|
||||
physicalDesc: refreshing
|
||||
color: "#302000"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
desc: It's a little piece of Eden.
|
||||
physicalDesc: crisp
|
||||
color: "#FDAD01"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuiceBerry
|
||||
@@ -14,9 +11,6 @@
|
||||
desc: A delicious blend of several different kinds of berries.
|
||||
physicalDesc: sweet
|
||||
color: "#660099"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuiceBanana
|
||||
@@ -24,9 +18,6 @@
|
||||
desc: The raw essence of a banana. HONK.
|
||||
physicalDesc: crisp
|
||||
color: "#FFE777"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
#TODO: port on_mob_life: restore eyesight
|
||||
#if(..())
|
||||
@@ -45,9 +36,6 @@
|
||||
desc: It's like a carrot, but less crunchy.
|
||||
physicalDesc: crisp
|
||||
color: "#FF8820"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuiceLime
|
||||
@@ -55,9 +43,6 @@
|
||||
desc: The sweet-sour juice of limes.
|
||||
physicalDesc: citric
|
||||
color: "#99bb43"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuiceLemon
|
||||
@@ -65,9 +50,6 @@
|
||||
desc: This juice is VERY sour.
|
||||
physicalDesc: citric
|
||||
color: "#fff690"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuiceGrape
|
||||
@@ -75,9 +57,6 @@
|
||||
desc: Freshly squeezed juice from red grapes. Quite sweet.
|
||||
physicalDesc: crisp
|
||||
color: "#512284"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
# /datum/reagent/drink/orangejuice/on_mob_life(var/mob/living/M)
|
||||
|
||||
@@ -93,9 +72,6 @@
|
||||
desc: Both delicious AND rich in Vitamin C. What more do you need?
|
||||
physicalDesc: citric
|
||||
color: "#E78108"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuiceTomato
|
||||
@@ -103,9 +79,6 @@
|
||||
desc: Tomatoes made into juice. What a waste of good tomatoes, huh?
|
||||
physicalDesc: saucey
|
||||
color: "#731008"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
# /datum/reagent/drink/poisonberryjuice/on_mob_life(var/mob/living/M)
|
||||
|
||||
@@ -120,9 +93,6 @@
|
||||
desc: A surprisingly tasty juice blended from various kinds of very deadly and toxic berries.
|
||||
physicalDesc: aromatic #maybe should be 'sickly'?
|
||||
color: "#6600CC"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuiceWatermelon
|
||||
@@ -130,9 +100,6 @@
|
||||
desc: The delicious juice of a watermelon.
|
||||
physicalDesc: sweet
|
||||
color: "#EF3520"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: JuicePineapple
|
||||
@@ -140,9 +107,6 @@
|
||||
desc: The delicious juice of a pineapple.
|
||||
physicalDesc: tropical
|
||||
color: yellow
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
|
||||
# - type: reagent
|
||||
# id: PotatoJuice
|
||||
@@ -150,6 +114,3 @@
|
||||
# desc: Juice of the potato. Bleh.
|
||||
# physicalDesc: starchy
|
||||
# color: "#302000"
|
||||
# metabolism:
|
||||
# - !type:DefaultDrink
|
||||
# rate: 1
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
desc: A sweet, carbonated soft drink. Caffeine free.
|
||||
physicalDesc: fizzy
|
||||
color: "#422912"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
plantMetabolism:
|
||||
- !type:AdjustNutrition
|
||||
amount: 0.1
|
||||
@@ -21,12 +18,6 @@
|
||||
desc: A highly processed liquid substance barely-passing intergalatic health standarts for a soft drink.
|
||||
physicalDesc: fizzy
|
||||
color: "#deb928"
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: 2
|
||||
damageClass: Toxin
|
||||
plantMetabolism:
|
||||
- !type:AdjustNutrition
|
||||
amount: 0.1
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
desc: The sweetness of a thousand sugars but none of the calories.
|
||||
# physicalDesc:
|
||||
color: aquamarine
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: BbqSauce
|
||||
@@ -14,9 +11,6 @@
|
||||
desc: Hand wipes not included.
|
||||
physicalDesc: Gloopy.
|
||||
color: darkred
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Cornoil
|
||||
@@ -24,9 +18,6 @@
|
||||
desc: Corn oil, A delicious oil used in cooking. Made from corn.
|
||||
# physicalDesc:
|
||||
color: yellow
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Frostoil
|
||||
@@ -34,9 +25,6 @@
|
||||
desc: Leaves the tongue numb in its passage.
|
||||
# physicalDesc:
|
||||
color: skyblue
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: HorseradishSauce
|
||||
@@ -44,9 +32,6 @@
|
||||
desc: Smelly horseradish sauce.
|
||||
physicalDesc: Overpowering.
|
||||
color: gray
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Hotsauce
|
||||
@@ -54,9 +39,6 @@
|
||||
desc: Burns so good.
|
||||
# physicalDesc:
|
||||
color: red
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Ketchup
|
||||
@@ -64,9 +46,6 @@
|
||||
desc: Made from pureed tomatoes and flavored with spices.
|
||||
# physicalDesc:
|
||||
color: red
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Soysauce
|
||||
@@ -74,6 +53,3 @@
|
||||
desc: A salty soy-based flavoring.
|
||||
# physicalDesc:
|
||||
color: saddlebrown
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
desc: Used for baking.
|
||||
physicalDesc: powdery
|
||||
color: white
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Oats
|
||||
@@ -14,18 +11,12 @@
|
||||
desc: Used for a variety of tasty purposes.
|
||||
physicalDesc: coarse
|
||||
color: tan
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Enzyme
|
||||
name: universal enzyme
|
||||
desc: Used in cooking various dishes.
|
||||
color: "#009900"
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Egg
|
||||
@@ -33,9 +24,6 @@
|
||||
desc: Used for baking.
|
||||
physicalDesc: mucus-like
|
||||
color: white
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Sugar
|
||||
@@ -43,9 +31,6 @@
|
||||
desc: Tasty spacey sugar!
|
||||
physicalDesc:
|
||||
color: white
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Salt
|
||||
@@ -53,9 +38,6 @@
|
||||
desc: Salt. From space oceans, presumably.
|
||||
physicalDesc: Coarse.
|
||||
color: white
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Blackpepper
|
||||
@@ -63,33 +45,21 @@
|
||||
desc: Often used to flavor food or make people sneeze.
|
||||
physicalDesc: Grainy.
|
||||
color: black
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Vinegar
|
||||
name: vinegar
|
||||
desc: Often used to flavor food.
|
||||
color: tan
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: Rice
|
||||
name: rice
|
||||
desc: Hard, small white grains.
|
||||
color: white
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
- type: reagent
|
||||
id: OilOlive
|
||||
name: olive oil
|
||||
desc: Viscous and fragrant.
|
||||
color: olive
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
|
||||
@@ -89,9 +89,6 @@
|
||||
desc: All the vitamins, minerals, and carbohydrates the body needs in pure form.
|
||||
physicalDesc: opaque
|
||||
color: "#664330"
|
||||
metabolism:
|
||||
- !type:DefaultFood
|
||||
rate: 1
|
||||
plantMetabolism:
|
||||
- !type:AdjustNutrition
|
||||
amount: 1
|
||||
@@ -218,9 +215,6 @@
|
||||
color: "#c0e0ff20"
|
||||
boilingPoint: 100.0
|
||||
meltingPoint: 0.0
|
||||
metabolism:
|
||||
- !type:DefaultDrink
|
||||
rate: 1
|
||||
tileReactions:
|
||||
- !type:ExtinguishTileReaction {}
|
||||
- !type:SpillIfPuddlePresentTileReaction {}
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
desc: A broad-spectrum anti-toxin, which treats toxin damage in the blood stream. Overdosing will cause vomiting, dizzyness and pain.
|
||||
physicalDesc: translucent
|
||||
color: "#3a1d8a"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -1
|
||||
damageClass: Toxin
|
||||
plantMetabolism:
|
||||
- !type:AdjustToxins
|
||||
amount: -10
|
||||
@@ -34,13 +30,6 @@
|
||||
desc: A slightly unstable medication used for the most extreme any serious case of radiation poisoning. Lowers radiation level at over twice the rate Hyronalin does and will heal toxin damage at the same time. Deals very minor brute damage to the patient over time, but the patient's body will typically out-regenerate it easily.
|
||||
physicalDesc: cloudy
|
||||
color: "#bd5902"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -1
|
||||
damageClass: Toxin #I think you need multiple of these components for different types of damage so I'll maybe change it to work better in the future
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: 0.5
|
||||
damageClass: Brute
|
||||
|
||||
- type: reagent
|
||||
id: Bicaridine
|
||||
@@ -48,10 +37,6 @@
|
||||
desc: An analgesic which is highly effective at treating brute damage. It is useful for stabilizing people who have been severely beaten, as well as treating less life-threatening injuries. In the case of bleeding (internal or external), bicaridine will slow down the bleeding heavily. If the dosage exceeds the overdose limit, it'll stop it outright.
|
||||
physicalDesc: opaque
|
||||
color: "#ffaa00"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -2
|
||||
damageClass: Brute
|
||||
|
||||
- type: reagent
|
||||
id: Cryoxadone
|
||||
@@ -90,10 +75,6 @@
|
||||
desc: An advanced chemical that is more effective at treating burn damage than Kelotane.
|
||||
physicalDesc: translucent
|
||||
color: "#215263"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -3
|
||||
damageClass: Burn
|
||||
|
||||
- type: reagent
|
||||
id: Dexalin
|
||||
@@ -101,10 +82,6 @@
|
||||
desc: Used for treating oxygen deprivation. In most cases where it is likely to be needed, the strength of Dexalin Plus will probably be more useful (Results in 1 unit instead of 2).
|
||||
physicalDesc: opaque
|
||||
color: "#0041a8"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -1
|
||||
damageClass: Airloss #this may be asphyxiation
|
||||
|
||||
- type: reagent
|
||||
id: DexalinPlus
|
||||
@@ -112,10 +89,6 @@
|
||||
desc: Used in treatment of extreme cases of oxygen deprivation. Even a single unit immediately counters all oxygen loss, which is hugely useful in many circumstances. Any dose beyond this will continue to counter oxygen loss until it is metabolized, essentially removing the need to breathe.
|
||||
physicalDesc: cloudy
|
||||
color: "#4da0bd"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -3
|
||||
damageClass: Airloss
|
||||
|
||||
- type: reagent
|
||||
id: Ethylredoxrazine
|
||||
@@ -165,10 +138,6 @@
|
||||
desc: Treats burn damage and prevents infection.
|
||||
physicalDesc: strong-smelling
|
||||
color: "#bf3d19"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -1
|
||||
damageClass: Burn
|
||||
|
||||
- type: reagent
|
||||
id: Leporazine
|
||||
@@ -225,11 +194,6 @@
|
||||
desc: Toxic, but treats hallucinations, drowsiness & halves the duration of paralysis, stuns and knockdowns. It is metabolized very slowly. One unit is enough to treat hallucinations; two units is deadly.
|
||||
physicalDesc: pungent
|
||||
color: "#d49a2f"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: 0.67
|
||||
damageClass: Toxin
|
||||
rate: 0.2
|
||||
|
||||
- type: reagent
|
||||
id: Tramadol
|
||||
@@ -289,10 +253,6 @@
|
||||
plantMetabolism:
|
||||
- !type:AdjustToxins
|
||||
amount: 10
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: 1
|
||||
damageClass: Airloss
|
||||
|
||||
- type: reagent
|
||||
id: Impedrezene
|
||||
@@ -307,10 +267,6 @@
|
||||
desc: Temporarily stops respiration and causes tissue damage. Large doses are fatal, and will cause people to pass out very quickly. Dexalin and Dexalin Plus will both remove it, however.
|
||||
physicalDesc: pungent
|
||||
color: "#6b0007"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: 7
|
||||
damageClass: Airloss
|
||||
|
||||
- type: reagent
|
||||
id: Lipozine
|
||||
@@ -363,17 +319,3 @@
|
||||
desc: A soothing milky liquid with an iridescent gleam. A well known conspiracy theory says that it's origins remain a mystery because knowing the secrets of its production would render most commercial pharmaceuticals obsolete.
|
||||
physicalDesc: soothing
|
||||
color: "#fcf7f9"
|
||||
metabolism:
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -2
|
||||
damageClass: Burn
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -2
|
||||
damageClass: Toxin
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -2
|
||||
damageClass: Airloss
|
||||
- !type:HealthChangeMetabolism
|
||||
healthChange: -2
|
||||
damageClass: Brute
|
||||
|
||||
|
||||
Reference in New Issue
Block a user