From 8937c3acf12ac0481aa0147c2f6d0be88d7df69a Mon Sep 17 00:00:00 2001 From: Kevin Zheng Date: Fri, 22 Dec 2023 17:10:33 -0800 Subject: [PATCH 1/4] Check for divide by near zero (#22876) --- Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs | 4 ++-- .../Atmos/EntitySystems/GenericGasReactionSystem.cs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs index 909ec5ec9cf..8506b4cd32c 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs @@ -123,7 +123,7 @@ public void Merge(GasMixture receiver, GasMixture giver) var receiverHeatCapacity = GetHeatCapacity(receiver); var giverHeatCapacity = GetHeatCapacity(giver); var combinedHeatCapacity = receiverHeatCapacity + giverHeatCapacity; - if (combinedHeatCapacity > 0f) + if (combinedHeatCapacity > Atmospherics.MinimumHeatCapacity) { receiver.Temperature = (GetThermalEnergy(giver, giverHeatCapacity) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity; } @@ -167,7 +167,7 @@ public void DivideInto(GasMixture source, List receivers) sourceHeatCapacity ??= GetHeatCapacity(source); var receiverHeatCapacity = GetHeatCapacity(receiver); var combinedHeatCapacity = receiverHeatCapacity + sourceHeatCapacity.Value * fraction; - if (combinedHeatCapacity > 0f) + if (combinedHeatCapacity > Atmospherics.MinimumHeatCapacity) receiver.Temperature = (GetThermalEnergy(source, sourceHeatCapacity.Value * fraction) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity; } } diff --git a/Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs b/Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs index a21f85ae954..15c4a33aaea 100644 --- a/Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs @@ -113,7 +113,10 @@ public ReactionResult ReactAll(IEnumerable reactions, GasM } float newHeatCapacity = _atmosphere.GetHeatCapacity(mix, true); - mix.Temperature = (initialE + reactionE)/newHeatCapacity; + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + { + mix.Temperature = (initialE + reactionE)/newHeatCapacity; + } if (reactionE > 0) { var location = holder as TileAtmosphere; From 40546b1f615dcf20cdc053129eb16a58461ff3ff Mon Sep 17 00:00:00 2001 From: Kevin Zheng Date: Sat, 23 Dec 2023 20:56:39 -0800 Subject: [PATCH 2/4] Clamp after AdjustMoles() (#22907) Clamping is needed because x - x can be negative with floating point numbers. If we don't clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(), which makes this function not very useful. --- Content.Server/Atmos/GasMixture.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index 1547c259e61..d49d1b78c1f 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -120,12 +120,9 @@ public void AdjustMoles(int gasId, float quantity) if (!float.IsFinite(quantity)) throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity)); - Moles[gasId] += quantity; - - var moles = Moles[gasId]; - - if (!float.IsFinite(moles) || float.IsNegative(moles)) - throw new Exception($"Invalid mole quantity \"{moles}\" in gas Id {gasId} after adjusting moles with \"{quantity}\"!"); + // Clamping is needed because x - x can be negative with floating point numbers. If we don't + // clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(). + Moles[gasId] = MathF.Max(Moles[gasId] + quantity, 0); } } From afe8f198e6e04dbf41aeb53efddc15198420b003 Mon Sep 17 00:00:00 2001 From: Kevin Zheng Date: Sun, 24 Dec 2023 07:05:42 -0800 Subject: [PATCH 3/4] Add maximum atmos temperature limit (#22882) * Add Tmax * Increase Tmax --- Content.Server/Atmos/GasMixture.cs | 4 +++- Content.Shared/Atmos/Atmospherics.cs | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index d49d1b78c1f..0a2ef235a71 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -4,6 +4,7 @@ using Content.Server.Atmos.Reactions; using Content.Shared.Atmos; using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Server.Atmos { @@ -58,8 +59,9 @@ public float Temperature get => _temperature; set { + DebugTools.Assert(!float.IsNaN(_temperature)); if (Immutable) return; - _temperature = MathF.Max(value, Atmospherics.TCMB); + _temperature = MathF.Min(MathF.Max(value, Atmospherics.TCMB), Atmospherics.Tmax); } } diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index 39b24de7466..b188fbb6086 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -45,6 +45,15 @@ static Atmospherics() /// public const float T20C = 293.15f; + /// + /// Do not allow any gas mixture temperatures to exceed this number. It is occasionally possible + /// to have very small heat capacity (e.g. room that was just unspaced) and for large amounts of + /// energy to be transferred to it, even for a brief moment. However, this messes up subsequent + /// calculations and so cap it here. The physical interpretation is that at this temperature, any + /// gas that you would have transforms into plasma. + /// + public const float Tmax = 200e3f; + /// /// Liters in a cell. /// From 8cf90d66f4ef0570e632caf66de4d6da1ef48bcb Mon Sep 17 00:00:00 2001 From: Kara Date: Sun, 24 Dec 2023 23:50:42 -0700 Subject: [PATCH 4/4] Revert "Add YAML gas reactions (#22803)" (#22939) This reverts commit 054321d2c2c17eb55a1640150131c61c29a3eb2b. Co-authored-by: Kevin Zheng --- .../EntitySystems/AtmosphereSystem.Gases.cs | 3 +- .../EntitySystems/GenericGasReactionSystem.cs | 133 ------------------ .../Atmos/Reactions/AmmoniaOxygenReaction.cs | 33 +++++ .../Atmos/Reactions/FrezonCoolantReaction.cs | 58 ++++++++ .../Atmos/Reactions/GasReactionPrototype.cs | 35 +---- .../Reactions/N2ODecompositionReaction.cs | 28 ++++ .../Atmos/Reactions/TritiumFireReaction.cs | 70 +++++++++ Content.Shared/Atmos/Atmospherics.cs | 34 +++++ .../Prototypes/Atmospherics/reactions.yml | 67 ++++++--- 9 files changed, 269 insertions(+), 192 deletions(-) delete mode 100644 Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs create mode 100644 Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs create mode 100644 Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs create mode 100644 Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs create mode 100644 Content.Server/Atmos/Reactions/TritiumFireReaction.cs diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs index 8506b4cd32c..f8ee4f41923 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs @@ -10,7 +10,6 @@ namespace Content.Server.Atmos.EntitySystems public sealed partial class AtmosphereSystem { [Dependency] private readonly IPrototypeManager _protoMan = default!; - [Dependency] private readonly GenericGasReactionSystem _reaction = default!; private GasReactionPrototype[] _gasReactions = Array.Empty(); private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases]; @@ -347,7 +346,7 @@ public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder) break; } - return _reaction.ReactAll(GasReactions, mixture, holder); + return reaction; } public enum GasCompareResult diff --git a/Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs b/Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs deleted file mode 100644 index 15c4a33aaea..00000000000 --- a/Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs +++ /dev/null @@ -1,133 +0,0 @@ -using Content.Server.Atmos.Reactions; -using Content.Shared.Atmos; -using JetBrains.Annotations; -using System.Collections; -using System.Linq; - -namespace Content.Server.Atmos.EntitySystems; - -public sealed class GenericGasReactionSystem : EntitySystem -{ - [Dependency] private readonly AtmosphereSystem _atmosphere = default!; - - /// - /// Return a reaction rate (in units reactants per second) for a given reaction. Based on the - /// Arrhenius equation (https://en.wikipedia.org/wiki/Arrhenius_equation). - /// - /// This means that most reactions scale exponentially above the MinimumTemperatureRequirement. - /// - private float ReactionRate(GasReactionPrototype reaction, GasMixture mix, float dE) - { - float temp = mix.Temperature; - - // Gas reactions have a MinimumEnergyRequirement which is in spirit activiation energy (Ea), - // but no reactions define it. So we have to calculate one to use. One way is to assume that - // Ea = 10*R*MinimumTemperatureRequirement such that Ea >> RT. - float TScaleFactor = 10; - float Ea = TScaleFactor*Atmospherics.R*reaction.MinimumTemperatureRequirement + dE; - - // To compute initial rate coefficient A, assume that at temp = min temp we return 1/10. - float RateScaleFactor = 10; // not necessarily the same as TScaleFactor! Don't get confused! - float A = MathF.Exp(TScaleFactor) / RateScaleFactor; - - return reaction.RateMultiplier*A*MathF.Exp(-Ea/(Atmospherics.R*temp)); - } - - /// - /// Run all of the reactions given on the given gas mixture located in the given container. - /// - public ReactionResult ReactAll(IEnumerable reactions, GasMixture mix, IGasMixtureHolder? holder) - { - // It is possible for reactions to change the specific heat capacity, so we need to save initial - // internal energy so that we can conserve energy at the end - float initialE = _atmosphere.GetThermalEnergy(mix); - float reactionE = 0; // heat added by reaction enthalpy - foreach (var reaction in reactions) - { - float rate = 1f; // rate of this reaction - int reactants = 0; - - // Reactions that have a maximum temperature really don't make physical sense since increasing - // kinetic energy always increases reaction rate. But begrudgingly implement this anyway. - if (mix.Temperature > reaction.MaximumTemperatureRequirement) - continue; - - // Add concentration-dependent reaction rate - // For 1A + 2B -> 3C, the concentration-dependence is [A]^1 * [B]^2 - float nTotal = mix.TotalMoles; - if (nTotal < Atmospherics.GasMinMoles) - continue; - - foreach (var (reactant, num) in reaction.Reactants) - { - rate *= MathF.Pow(mix.GetMoles(reactant)/nTotal, num); - reactants++; - } - - // No reactants; this is not a generic reaction. - if (reactants == 0) - continue; - - // Sum catalysts - float catalystEnergy = 0; - foreach (var (catalyst, dE) in reaction.Catalysts) - { - catalystEnergy += dE; - } - - // Now apply temperature-dependent reaction rate scaling - rate *= ReactionRate(reaction, mix, catalystEnergy); - - // Nothing to do - if (rate <= 0) - continue; - - // Pass to check the maximum rate, limited by the minimum available - // reactant to avoid going negative - float rateLim = rate; - foreach (var (reactant, num) in reaction.Reactants) - { - rateLim = MathF.Min(mix.GetMoles(reactant)/num, rateLim); - } - rate = rateLim; - - // Go through and remove all the reactants - foreach (var (reactant, num) in reaction.Reactants) - { - mix.AdjustMoles(reactant, -num*rate); - } - - // Go through and add products - foreach (var (product, num) in reaction.Products) - { - mix.AdjustMoles(product, num*rate); - } - - // Add heat from the reaction - if (reaction.Enthalpy != 0) - { - reactionE += reaction.Enthalpy/_atmosphere.HeatScale * rate; - if (reaction.Enthalpy > 0) - mix.ReactionResults[GasReaction.Fire] += rate; - } - } - - float newHeatCapacity = _atmosphere.GetHeatCapacity(mix, true); - if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) - { - mix.Temperature = (initialE + reactionE)/newHeatCapacity; - } - if (reactionE > 0) - { - var location = holder as TileAtmosphere; - if (location != null) - { - if (mix.Temperature > Atmospherics.FireMinimumTemperatureToExist) - { - _atmosphere.HotspotExpose(location.GridIndex, location.GridIndices, mix.Temperature, mix.Volume); - } - } - } - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs b/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs new file mode 100644 index 00000000000..197034ce545 --- /dev/null +++ b/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs @@ -0,0 +1,33 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class AmmoniaOxygenReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var nAmmonia = mixture.GetMoles(Gas.Ammonia); + var nOxygen = mixture.GetMoles(Gas.Oxygen); + var nTotal = mixture.TotalMoles; + + // Concentration-dependent reaction rate + var fAmmonia = nAmmonia/nTotal; + var fOxygen = nOxygen/nTotal; + var rate = MathF.Pow(fAmmonia, 2) * MathF.Pow(fOxygen, 2); + + var deltaMoles = nAmmonia / Atmospherics.AmmoniaOxygenReactionRate * 2 * rate; + + if (deltaMoles <= 0 || nAmmonia - deltaMoles < 0) + return ReactionResult.NoReaction; + + mixture.AdjustMoles(Gas.Ammonia, -deltaMoles); + mixture.AdjustMoles(Gas.Oxygen, -deltaMoles); + mixture.AdjustMoles(Gas.NitrousOxide, deltaMoles / 2); + mixture.AdjustMoles(Gas.WaterVapor, deltaMoles * 1.5f); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs new file mode 100644 index 00000000000..051ee8202db --- /dev/null +++ b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs @@ -0,0 +1,58 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +/// +/// Takes in nitrogen and frezon and cools down the surrounding area. +/// +[UsedImplicitly] +public sealed partial class FrezonCoolantReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + var temperature = mixture.Temperature; + + var energyModifier = 1f; + var scale = (temperature - Atmospherics.FrezonCoolLowerTemperature) / + (Atmospherics.FrezonCoolMidTemperature - Atmospherics.FrezonCoolLowerTemperature); + + if (scale > 1f) + { + // Scale energy but not frezon usage if we're in a very, very hot place + energyModifier = Math.Min(scale, Atmospherics.FrezonCoolMaximumEnergyModifier); + scale = 1f; + } + + if (scale <= 0) + return ReactionResult.NoReaction; + + var initialNit = mixture.GetMoles(Gas.Nitrogen); + var initialFrezon = mixture.GetMoles(Gas.Frezon); + + var burnRate = initialFrezon * scale / Atmospherics.FrezonCoolRateModifier; + + var energyReleased = 0f; + if (burnRate > Atmospherics.MinimumHeatCapacity) + { + var nitAmt = Math.Min(burnRate * Atmospherics.FrezonNitrogenCoolRatio, initialNit); + var frezonAmt = Math.Min(burnRate, initialFrezon); + mixture.AdjustMoles(Gas.Nitrogen, -nitAmt); + mixture.AdjustMoles(Gas.Frezon, -frezonAmt); + mixture.AdjustMoles(Gas.NitrousOxide, nitAmt + frezonAmt); + energyReleased = burnRate * Atmospherics.FrezonCoolEnergyReleased * energyModifier; + } + + energyReleased /= heatScale; // adjust energy to make sure speedup doesn't cause mega temperature rise + if (energyReleased >= 0f) + return ReactionResult.NoReaction; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = (temperature * oldHeatCapacity + energyReleased) / newHeatCapacity; + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs index b19e4c7a885..0ee29de3bf1 100644 --- a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs +++ b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs @@ -25,8 +25,7 @@ public sealed partial class GasReactionPrototype : IPrototype public string ID { get; private set; } = default!; /// - /// Minimum gas amount requirements. Reactions that meet these minimum mole requirements - /// have their reaction effects run. Generic gas reactions do not have minimum requirements. + /// Minimum gas amount requirements. /// [DataField("minimumRequirements")] public float[] MinimumRequirements { get; private set; } = new float[Atmospherics.TotalNumberOfGases]; @@ -43,13 +42,6 @@ public sealed partial class GasReactionPrototype : IPrototype [DataField("minimumTemperature")] public float MinimumTemperatureRequirement { get; private set; } = Atmospherics.TCMB; - /// - /// If this is a generic gas reaction, multiply the initial rate by this. The default is reasonable for - /// synthesis reactions. Consider raising this for fires. - /// - [DataField("rateMultiplier")] - public float RateMultiplier = 1f; - /// /// Minimum energy requirement. /// @@ -68,31 +60,6 @@ public sealed partial class GasReactionPrototype : IPrototype /// [DataField("effects")] private List _effects = new(); - /// - /// Energy released by the reaction. - /// - [DataField("enthalpy")] - public float Enthalpy; - - /// - /// Integer gas IDs and integer ratios required in the reaction. If this is defined, the - /// generic gas reaction will run. - /// - [DataField("reactants")] - public Dictionary Reactants = new(); - - /// - /// Integer gas IDs and integer ratios of reaction products. - /// - [DataField("products")] - public Dictionary Products = new(); - - /// - /// Integer gas IDs and how much they modify the activation energy (J/mol). - /// - [DataField("catalysts")] - public Dictionary Catalysts = new(); - /// /// Process all reaction effects. /// diff --git a/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs b/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs new file mode 100644 index 00000000000..7fce663dc31 --- /dev/null +++ b/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs @@ -0,0 +1,28 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +/// +/// Decomposes Nitrous Oxide into Nitrogen and Oxygen. +/// +[UsedImplicitly] +public sealed partial class N2ODecompositionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var cacheN2O = mixture.GetMoles(Gas.NitrousOxide); + + var burnedFuel = cacheN2O / Atmospherics.N2ODecompositionRate; + + if (burnedFuel <= 0 || cacheN2O - burnedFuel < 0) + return ReactionResult.NoReaction; + + mixture.AdjustMoles(Gas.NitrousOxide, -burnedFuel); + mixture.AdjustMoles(Gas.Nitrogen, burnedFuel); + mixture.AdjustMoles(Gas.Oxygen, burnedFuel / 2); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs new file mode 100644 index 00000000000..c52b431fd43 --- /dev/null +++ b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs @@ -0,0 +1,70 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions +{ + [UsedImplicitly] + [DataDefinition] + public sealed partial class TritiumFireReaction : IGasReactionEffect + { + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var energyReleased = 0f; + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + var temperature = mixture.Temperature; + var location = holder as TileAtmosphere; + mixture.ReactionResults[GasReaction.Fire] = 0f; + var burnedFuel = 0f; + var initialTrit = mixture.GetMoles(Gas.Tritium); + + if (mixture.GetMoles(Gas.Oxygen) < initialTrit || + Atmospherics.MinimumTritiumOxyburnEnergy > (temperature * oldHeatCapacity)) + { + burnedFuel = mixture.GetMoles(Gas.Oxygen) / Atmospherics.TritiumBurnOxyFactor; + if (burnedFuel > initialTrit) + burnedFuel = initialTrit; + + mixture.AdjustMoles(Gas.Tritium, -burnedFuel); + } + else + { + burnedFuel = initialTrit; + mixture.SetMoles(Gas.Tritium, mixture.GetMoles(Gas.Tritium ) * (1 - 1 / Atmospherics.TritiumBurnTritFactor)); + mixture.AdjustMoles(Gas.Oxygen, -mixture.GetMoles(Gas.Tritium)); + energyReleased += (Atmospherics.FireHydrogenEnergyReleased * burnedFuel * (Atmospherics.TritiumBurnTritFactor - 1)); + } + + if (burnedFuel > 0) + { + energyReleased += (Atmospherics.FireHydrogenEnergyReleased * burnedFuel); + + // TODO ATMOS Radiation pulse here! + + // Conservation of mass is important. + mixture.AdjustMoles(Gas.WaterVapor, burnedFuel); + + mixture.ReactionResults[GasReaction.Fire] += burnedFuel; + } + + energyReleased /= heatScale; // adjust energy to make sure speedup doesn't cause mega temperature rise + if (energyReleased > 0) + { + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = ((temperature * oldHeatCapacity + energyReleased) / newHeatCapacity); + } + + if (location != null) + { + temperature = mixture.Temperature; + if (temperature > Atmospherics.FireMinimumTemperatureToExist) + { + atmosphereSystem.HotspotExpose(location.GridIndex, location.GridIndices, temperature, mixture.Volume); + } + } + + return mixture.ReactionResults[GasReaction.Fire] != 0 ? ReactionResult.Reacting : ReactionResult.NoReaction; + } + } +} diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index b188fbb6086..6c4038fc415 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -204,6 +204,30 @@ static Atmospherics() public const float PlasmaOxygenFullburn = 10f; public const float PlasmaBurnRateDelta = 9f; + /// + /// This is calculated to help prevent singlecap bombs (Overpowered tritium/oxygen single tank bombs) + /// + public const float MinimumTritiumOxyburnEnergy = 143000f; + + public const float TritiumBurnOxyFactor = 100f; + public const float TritiumBurnTritFactor = 10f; + + public const float FrezonCoolLowerTemperature = 23.15f; + + /// + /// Frezon cools better at higher temperatures. + /// + public const float FrezonCoolMidTemperature = 373.15f; + + public const float FrezonCoolMaximumEnergyModifier = 10f; + + /// + /// Remove X mol of nitrogen for each mol of frezon. + /// + public const float FrezonNitrogenCoolRatio = 5; + public const float FrezonCoolEnergyReleased = -600e3f; + public const float FrezonCoolRateModifier = 20f; + public const float FrezonProductionMaxEfficiencyTemperature = 73.15f; /// @@ -221,6 +245,16 @@ static Atmospherics() /// public const float FrezonProductionConversionRate = 50f; + /// + /// The maximum portion of the N2O that can decompose each reaction tick. (50%) + /// + public const float N2ODecompositionRate = 2f; + + /// + /// Divisor for Ammonia Oxygen reaction so that it doesn't happen instantaneously. + /// + public const float AmmoniaOxygenReactionRate = 10f; + /// /// Determines at what pressure the ultra-high pressure red icon is displayed. /// diff --git a/Resources/Prototypes/Atmospherics/reactions.yml b/Resources/Prototypes/Atmospherics/reactions.yml index 03c563b125c..d226c81f6cc 100644 --- a/Resources/Prototypes/Atmospherics/reactions.yml +++ b/Resources/Prototypes/Atmospherics/reactions.yml @@ -14,23 +14,31 @@ id: TritiumFire priority: -1 minimumTemperature: 373.149 # Same as Atmospherics.FireMinimumTemperatureToExist - enthalpy: 284000 - reactants: - Tritium: 2 - Oxygen: 1 - products: - WaterVapor: 2 + minimumRequirements: # In this case, same as minimum mole count. + - 0.01 # oxygen + - 0 # nitrogen + - 0 # carbon dioxide + - 0 # plasma + - 0.01 # tritium + effects: + - !type:TritiumFireReaction {} - type: gasReaction id: FrezonCoolant priority: 1 minimumTemperature: 23.15 - enthalpy: -600000 - reactants: - Frezon: 1 - Nitrogen: 5 - products: - NitrousOxide: 6 + minimumRequirements: + - 0 # oxygen + - 0.01 # nitrogen + - 0 # carbon dioxide + - 0 # plasma + - 0 # tritium + - 0 # vapor + - 0 # ammonia + - 0 # n2o + - 0.01 # frezon + effects: + - !type:FrezonCoolantReaction {} - type: gasReaction id: FrezonProduction @@ -53,22 +61,35 @@ id: AmmoniaOxygenReaction priority: 2 minimumTemperature: 323.149 - reactants: - Ammonia: 2 - Oxygen: 2 - products: - NitrousOxide: 1 - WaterVapor: 3 + minimumRequirements: + - 0.01 # oxygen + - 0 # nitrogen + - 0 # carbon dioxide + - 0 # plasma + - 0 # tritium + - 0 # vapor + - 0.01 # ammonia + - 0 # n2o + - 0 # frezon + effects: + - !type:AmmoniaOxygenReaction {} - type: gasReaction id: N2ODecomposition priority: 0 minimumTemperature: 850 - reactants: - NitrousOxide: 2 - products: - Nitrogen: 2 - Oxygen: 1 + minimumRequirements: + - 0 # oxygen + - 0 # nitrogen + - 0 # carbon dioxide + - 0 # plasma + - 0 # tritium + - 0 # vapor + - 0 # ammonia + - 0.01 # n2o + - 0 # frezon + effects: + - !type:N2ODecompositionReaction {} #- type: gasReaction # id: WaterVaporPuddle