From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sat, 13 May 2023 03:10:32 +0000 (+1200) Subject: Make Reactions conserve thermal energy (#16190) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=0c4002bbd3f354fe678638cd7bf838483988d9bc;p=space-station-14.git Make Reactions conserve thermal energy (#16190) --- diff --git a/Content.Client/Chemistry/ChemicalReactionSystem.cs b/Content.Client/Chemistry/ChemicalReactionSystem.cs deleted file mode 100644 index 96aa6db29b..0000000000 --- a/Content.Client/Chemistry/ChemicalReactionSystem.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Shared.Chemistry.Reaction; - -namespace Content.Client.Chemistry -{ - public sealed class ChemicalReactionSystem : SharedChemicalReactionSystem - { - - } -} diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs index 1cf9eb3e93..34b49f0d09 100644 --- a/Content.Server/Body/Systems/MetabolizerSystem.cs +++ b/Content.Server/Body/Systems/MetabolizerSystem.cs @@ -181,7 +181,7 @@ namespace Content.Server.Body.Systems if (effect.ShouldLog) { _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact, - $"Metabolism effect {effect.GetType().Name:effect} of reagent {args.Reagent.LocalizedName:reagent} applied on entity {actualEntity:entity} at {Transform(actualEntity).Coordinates:coordinates}"); + $"Metabolism effect {effect.GetType().Name:effect} of reagent {proto.LocalizedName:reagent} applied on entity {actualEntity:entity} at {Transform(actualEntity).Coordinates:coordinates}"); } effect.Effect(args); diff --git a/Content.Server/Chemistry/EntitySystems/ChemicalReactionSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemicalReactionSystem.cs deleted file mode 100644 index e7df6c7ed6..0000000000 --- a/Content.Server/Chemistry/EntitySystems/ChemicalReactionSystem.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Reaction; -using Content.Shared.Chemistry.Reagent; -using Content.Shared.Database; -using Content.Shared.FixedPoint; -using Robust.Shared.Audio; -using Robust.Shared.Player; - -namespace Content.Server.Chemistry.EntitySystems -{ - public sealed class ChemicalReactionSystem : SharedChemicalReactionSystem - { - protected override void OnReaction(Solution solution, ReactionPrototype reaction, ReagentPrototype randomReagent, EntityUid owner, FixedPoint2 unitReactions) - { - base.OnReaction(solution, reaction, randomReagent, owner, unitReactions); - - var coordinates = Transform(owner).Coordinates; - - AdminLogger.Add(LogType.ChemicalReaction, reaction.Impact, - $"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(owner):metabolizer} at {coordinates}"); - - SoundSystem.Play(reaction.Sound.GetSound(), Filter.Pvs(owner, entityManager:EntityManager), owner); - } - } -} diff --git a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs index 782a1e7ec3..bdf6a87889 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs @@ -34,7 +34,7 @@ public sealed class SolutionChangedEvent : EntityEventArgs public sealed partial class SolutionContainerSystem : EntitySystem { [Dependency] - private readonly SharedChemicalReactionSystem _chemistrySystem = default!; + private readonly ChemicalReactionSystem _chemistrySystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; diff --git a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs index bf18fcd54f..c97b29a94c 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs @@ -23,13 +23,14 @@ namespace Content.Server.Chemistry.ReagentEffectConditions public override bool Condition(ReagentEffectArgs args) { - if (Reagent == null) - Reagent = args.Reagent.ID; + var reagent = Reagent ?? args.Reagent?.ID; + if (reagent == null) + return true; // No condition to apply. var quant = FixedPoint2.Zero; - if (args.Source != null && args.Source.ContainsReagent(Reagent)) + if (args.Source != null && args.Source.ContainsReagent(reagent)) { - quant = args.Source.GetReagentQuantity(args.Reagent.ID); + quant = args.Source.GetReagentQuantity(reagent); } return quant >= Min && quant <= Max; diff --git a/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs b/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs index c8027ec2c5..376398d7b7 100644 --- a/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs +++ b/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs @@ -14,7 +14,7 @@ namespace Content.Server.Chemistry.ReactionEffects public float CleanseRate = 3.0f; public override void Effect(ReagentEffectArgs args) { - if (args.Source == null) + if (args.Source == null || args.Reagent == null) return; var cleanseRate = CleanseRate; diff --git a/Content.Server/Chemistry/ReagentEffects/Electrocute.cs b/Content.Server/Chemistry/ReagentEffects/Electrocute.cs index d3a5383de7..08b2df966e 100644 --- a/Content.Server/Chemistry/ReagentEffects/Electrocute.cs +++ b/Content.Server/Chemistry/ReagentEffects/Electrocute.cs @@ -18,9 +18,10 @@ public sealed class Electrocute : ReagentEffect public override void Effect(ReagentEffectArgs args) { - EntitySystem.Get().TryDoElectrocution(args.SolutionEntity, null, + args.EntityManager.System().TryDoElectrocution(args.SolutionEntity, null, Math.Max((args.Quantity * ElectrocuteDamageScale).Int(), 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true); - args.Source?.RemoveReagent(args.Reagent.ID, args.Quantity); + if (args.Reagent != null) + args.Source?.RemoveReagent(args.Reagent.ID, args.Quantity); } } diff --git a/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs b/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs index 9d0db25a1e..54d3689135 100644 --- a/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs +++ b/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs @@ -17,10 +17,13 @@ namespace Content.Server.Chemistry.ReagentEffects public override void Effect(ReagentEffectArgs args) { - if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out FlammableComponent? flammable)) return; + if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out FlammableComponent? flammable)) + return; - EntitySystem.Get().AdjustFireStacks(args.SolutionEntity, args.Quantity.Float() * Multiplier, flammable); - args.Source?.RemoveReagent(args.Reagent.ID, args.Quantity); + args.EntityManager.System().AdjustFireStacks(args.SolutionEntity, args.Quantity.Float() * Multiplier, flammable); + + if (args.Reagent != null) + args.Source?.RemoveReagent(args.Reagent.ID, args.Quantity); } } } diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs index 8aaf9582ff..cc01b8f3b1 100644 --- a/Content.Shared/Chemistry/Components/Solution.cs +++ b/Content.Shared/Chemistry/Components/Solution.cs @@ -114,6 +114,10 @@ namespace Content.Shared.Chemistry.Components return _heatCapacity; } + public float GetThermalEnergy(IPrototypeManager? protoMan) + { + return GetHeatCapacity(protoMan) * Temperature; + } /// /// Constructs an empty solution (ex. an empty beaker). diff --git a/Content.Shared/Chemistry/Reaction/SharedChemicalReactionSystem.cs b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs similarity index 85% rename from Content.Shared/Chemistry/Reaction/SharedChemicalReactionSystem.cs rename to Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs index a2a4fec87a..da8560fc5b 100644 --- a/Content.Shared/Chemistry/Reaction/SharedChemicalReactionSystem.cs +++ b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs @@ -1,27 +1,23 @@ using System.Linq; -using Content.Shared.Administration; using Content.Shared.Administration.Logs; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.FixedPoint; -using Content.Shared.Interaction.Events; using Robust.Shared.Prototypes; -using Robust.Shared.Random; namespace Content.Shared.Chemistry.Reaction { - public abstract class SharedChemicalReactionSystem : EntitySystem + public sealed class ChemicalReactionSystem : EntitySystem { - /// /// The maximum number of reactions that may occur when a solution is changed. /// private const int MaxReactionIterations = 20; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; /// /// A cache of all existant chemical reactions indexed by one of their @@ -170,13 +166,12 @@ namespace Content.Shared.Chemistry.Reaction /// /// Perform a reaction on a solution. This assumes all reaction criteria are met. - /// Removes the reactants from the solution, then returns a solution with all products. + /// Removes the reactants from the solution, adds products, and returns a list of products. /// - private Solution PerformReaction(Solution solution, EntityUid owner, ReactionPrototype reaction, FixedPoint2 unitReactions) + private List PerformReaction(Solution solution, EntityUid owner, ReactionPrototype reaction, FixedPoint2 unitReactions) { - // We do this so that ReagentEffect can have something to work with, even if it's - // a little meaningless. - var randomReagent = _prototypeManager.Index(_random.Pick(reaction.Reactants).Key); + var energy = reaction.ConserveEnergy ? solution.GetThermalEnergy(_prototypeManager) : 0; + //Remove reactants foreach (var reactant in reaction.Reactants) { @@ -188,24 +183,35 @@ namespace Content.Shared.Chemistry.Reaction } //Create products - var products = new Solution(); + var products = new List(); foreach (var product in reaction.Products) { - products.AddReagent(product.Key, product.Value * unitReactions); + products.Add(product.Key); + solution.AddReagent(product.Key, product.Value * unitReactions); + } + + if (reaction.ConserveEnergy) + { + var newCap = solution.GetHeatCapacity(_prototypeManager); + if (newCap > 0) + solution.Temperature = energy / newCap; } - // Trigger reaction effects - OnReaction(solution, reaction, randomReagent, owner, unitReactions); + OnReaction(solution, reaction, null, owner, unitReactions); return products; } - protected virtual void OnReaction(Solution solution, ReactionPrototype reaction, ReagentPrototype randomReagent, EntityUid owner, FixedPoint2 unitReactions) + private void OnReaction(Solution solution, ReactionPrototype reaction, ReagentPrototype? reagent, EntityUid owner, FixedPoint2 unitReactions) { var args = new ReagentEffectArgs(owner, null, solution, - randomReagent, + reagent, unitReactions, EntityManager, null, 1f); + var coordinates = Transform(owner).Coordinates; + _adminLogger.Add(LogType.ChemicalReaction, reaction.Impact, + $"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(owner):metabolizer} at {coordinates}"); + foreach (var effect in reaction.Effects) { if (!effect.ShouldApply(args)) @@ -214,12 +220,14 @@ namespace Content.Shared.Chemistry.Reaction if (effect.ShouldLog) { var entity = args.SolutionEntity; - AdminLogger.Add(LogType.ReagentEffect, effect.LogImpact, + _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact, $"Reaction effect {effect.GetType().Name:effect} of reaction ${reaction.ID:reaction} applied on entity {ToPrettyString(entity):entity} at {Transform(entity).Coordinates:coordinates}"); } effect.Effect(args); } + + _audio.PlayPvs(reaction.Sound, owner); } /// @@ -230,7 +238,7 @@ namespace Content.Shared.Chemistry.Reaction private bool ProcessReactions(Solution solution, EntityUid owner, FixedPoint2 maxVolume, SortedSet reactions, ReactionMixerComponent? mixerComponent) { HashSet toRemove = new(); - Solution? products = null; + List? products = null; // attempt to perform any applicable reaction foreach (var reaction in reactions) @@ -249,30 +257,23 @@ namespace Content.Shared.Chemistry.Reaction if (products == null) return false; - // Remove any reactions that were not applicable. Avoids re-iterating over them in future. - foreach (var proto in toRemove) - { - reactions.Remove(proto); - } - - if (products.Volume <= 0) + if (products.Count == 0) return true; // remove excess product // TODO spill excess? - var excessVolume = solution.Volume + products.Volume - maxVolume; + var excessVolume = solution.Volume - maxVolume; if (excessVolume > 0) - products.RemoveSolution(excessVolume); + solution.RemoveSolution(excessVolume); // Add any reactions associated with the new products. This may re-add reactions that were already iterated // over previously. The new product may mean the reactions are applicable again and need to be processed. - foreach (var reactant in products.Contents) + foreach (var product in products) { - if (_reactions.TryGetValue(reactant.ReagentId, out var reactantReactions)) + if (_reactions.TryGetValue(product, out var reactantReactions)) reactions.UnionWith(reactantReactions); } - solution.AddSolution(products, _prototypeManager); return true; } diff --git a/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs b/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs index 413c56b1f1..ac561ccbdf 100644 --- a/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs +++ b/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs @@ -32,6 +32,12 @@ namespace Content.Shared.Chemistry.Reaction [DataField("minTemp")] public float MinimumTemperature = 0.0f; + /// + /// If true, this reaction will attempt to conserve thermal energy. + /// + [DataField("conserveEnergy")] + public bool ConserveEnergy = true; + /// /// The maximum temperature the reaction can occur at. /// diff --git a/Content.Shared/Chemistry/Reagent/ReagentEffect.cs b/Content.Shared/Chemistry/Reagent/ReagentEffect.cs index 5b22ae4a8a..9140c44f15 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentEffect.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentEffect.cs @@ -79,7 +79,7 @@ namespace Content.Shared.Chemistry.Reagent EntityUid SolutionEntity, EntityUid? OrganEntity, Solution? Source, - ReagentPrototype Reagent, + ReagentPrototype? Reagent, FixedPoint2 Quantity, IEntityManager EntityManager, ReactionMethod? Method, diff --git a/Resources/Prototypes/Recipes/Reactions/food.yml b/Resources/Prototypes/Recipes/Reactions/food.yml index 5e32ab08a9..2aaf62c88b 100644 --- a/Resources/Prototypes/Recipes/Reactions/food.yml +++ b/Resources/Prototypes/Recipes/Reactions/food.yml @@ -2,6 +2,7 @@ id: Curdling impact: Low quantized: true + conserveEnergy: false reactants: Milk: amount: 40 @@ -16,6 +17,7 @@ id: CreateDough impact: Low quantized: true + conserveEnergy: false reactants: Flour: amount: 15 @@ -29,6 +31,7 @@ id: CreateCornmealDough impact: Low quantized: true + conserveEnergy: false reactants: Cornmeal: amount: 15 @@ -44,6 +47,7 @@ id: CreateCakeBatter impact: Low quantized: true + conserveEnergy: false reactants: Flour: amount: 15 @@ -59,6 +63,7 @@ id: CreateButter impact: Low quantized: true + conserveEnergy: false reactants: Milk: amount: 30 @@ -73,6 +78,7 @@ id: CreatePieDough impact: Low quantized: true + conserveEnergy: false reactants: Flour: amount: 15 @@ -91,6 +97,7 @@ id: CreateVeganCakeBatter impact: Low quantized: true + conserveEnergy: false reactants: Flour: amount: 15 @@ -106,6 +113,7 @@ id: CreateTofu impact: Low quantized: true + conserveEnergy: false reactants: MilkSoy: amount: 30 @@ -221,6 +229,7 @@ id: CreateMeatball impact: Low quantized: true + conserveEnergy: false reactants: UncookedAnimalProteins: amount: 5