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:
mirrorcult
2021-07-31 04:50:32 -07:00
committed by GitHub
parent dc18997bf8
commit 8aa4f998de
36 changed files with 572 additions and 558 deletions

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View 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;
}
}
}
}
}

View 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);
}
}
}

View 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);
}
}
}