From 9ead38de5253e554b4445e199034aed23e3b527e Mon Sep 17 00:00:00 2001 From: SunChan07 Date: Wed, 13 May 2026 04:30:19 +0900 Subject: [PATCH 1/4] SomeAtmosTechV1 --- .../Consoles/AtmosAlarmEntryContainer.xaml.cs | 29 +- .../AtmosMonitoringEntryContainer.xaml.cs | 8 +- .../EntitySystems/AtmosDebugOverlaySystem.cs | 31 +- .../EntitySystems/AtmosphereSystem.CVars.cs | 17 + .../EntitySystems/AtmosphereSystem.Gases.cs | 58 ++++ .../Atmos/EntitySystems/AtmosphereSystem.cs | 3 +- .../EntitySystems/GasTileFireOverlaySystem.cs | 30 ++ .../EntitySystems/GasTileOverlaySystem.cs | 135 ++++---- .../GasTileVisibleGasOverlaySystem.cs | 31 ++ .../Atmos/Overlays/GasTileFireOverlay.cs | 167 ++++++++++ .../Atmos/Overlays/GasTileOverlay.cs | 302 ------------------ .../Overlays/GasTileVisibleGasOverlay.cs | 273 ++++++++++++++++ .../Atmos/UI/GasAnalyzerBoundUserInterface.cs | 62 ++-- .../Atmos/UI/GasAnalyzerWindow.xaml.cs | 33 +- .../EntitySystems/ChemistryGuideDataSystem.cs | 6 + .../Tests/Atmos/ConstantsTest.cs | 10 +- .../Atmos/AtmosDirectionExtensions.cs | 54 ++++ .../Components/IgniteOnAmmoHitComponent.cs | 14 + .../Consoles/AtmosAlertsComputerSystem.cs | 51 ++- .../EntitySystems/AtmosphereSystem.CVars.cs | 15 +- .../EntitySystems/AtmosphereSystem.Gases.cs | 233 ++++++++------ .../EntitySystems/AtmosphereSystem.Hotspot.cs | 21 +- .../AtmosphereSystem.Processing.cs | 12 +- .../EntitySystems/AtmosphereSystem.Utils.cs | 7 +- .../Atmos/EntitySystems/AtmosphereSystem.cs | 5 + .../Atmos/EntitySystems/BarotraumaSystem.cs | 4 - .../Atmos/EntitySystems/FlammableSystem.cs | 9 +- .../Atmos/EntitySystems/GasAnalyzerSystem.cs | 41 ++- .../EntitySystems/GasTileOverlaySystem.cs | 54 +++- .../Unary/Components/GasVentPumpComponent.cs | 5 + .../Components/GasVentScrubberComponent.cs | 2 +- .../Unary/EntitySystems/GasVentPumpSystem.cs | 18 ++ .../Portable/PortableScrubberComponent.cs | 14 +- .../Atmos/Reactions/FrezonCoolantReaction.cs | 7 +- .../Reactions/FrezonProductionReaction.cs | 7 +- .../Atmos/Reactions/GasReactionPrototype.cs | 14 - .../Atmos/Reactions/PlasmaFireReaction.cs | 5 + .../Atmos/Reactions/TritiumFireReaction.cs | 5 + Content.Server/Atmos/TileAtmosphere.cs | 29 +- .../Components/GridAtmosphereComponent.cs | 6 + .../EntitySystems/AtmosphereSystem.CCVars.cs | 57 ++++ .../AtmosphereSystem.Processing.cs | 10 + .../Atmos/EntitySystems/AtmosphereSystem.cs | 19 ++ .../Atmos/Reactions/BZProductionReaction.cs | 51 +++ .../HalonOxygenAbsorptionReaction.cs | 39 +++ .../Reactions/HealiumProductionReaction.cs | 40 +++ .../Atmos/Reactions/HydrogenFireReaction.cs | 59 ++++ .../HyperNobliumProductionReaction.cs | 41 +++ .../Reactions/NitriumDecompositionReaction.cs | 39 +++ .../Reactions/NitriumProductionReaction.cs | 41 +++ .../Reactions/PluoxiumProductionReaction.cs | 41 +++ .../ProtoNitrateBZaseConversionReaction.cs | 41 +++ .../ProtoNitrateHydrogenConversionReaction.cs | 38 +++ .../ProtoNitrateProductionReaction.cs | 40 +++ .../ProtoNitrateTritiumConversionReaction.cs | 40 +++ .../Reactions/ZaukerDecompositionReaction.cs | 39 +++ .../Reactions/ZaukerProductionReaction.cs | 40 +++ .../_Adventure/Atmos/TileAtmosphere.cs | 4 + .../Atmospherics/BZProductionReaction.cs | 52 --- .../HalonFireSuppressionReaction.cs | 45 --- .../Atmospherics/HealiumProductionReaction.cs | 54 ---- .../Atmospherics/HydrogenBurnReaction.cs | 63 ---- .../Atmospherics/HyperNobliumEffectSystem.cs | 35 -- .../HyperNobliumProductionReaction.cs | 66 ---- .../NitriumDecompositionReaction.cs | 41 --- .../Atmospherics/NitriumProductionReaction.cs | 73 ----- .../PluoxiumProductionReaction.cs | 60 ---- .../ProtoNitrateBZDecomposition.cs | 44 --- .../ProtoNitrateHydrogenConversion.cs | 41 --- .../ProtoNitrateProductionReaction.cs | 57 ---- .../ProtoNitrateTritiumReaction.cs | 43 --- .../ZaukerDecompositionReaction.cs | 39 --- .../Atmospherics/ZaukerProductionReaction.cs | 64 ---- Content.Shared/Atmos/Atmospherics.cs | 16 +- .../Atmos/Components/GasAnalyzerComponent.cs | 149 +++++---- .../AtmosAlertsComputerComponent.cs | 30 +- .../SharedAtmosAlertsComputerSystem.cs | 3 + .../SharedAtmosphereSystem.Gases.cs | 69 ++++ .../EntitySystems/SharedAtmosphereSystem.cs | 12 +- .../SharedGasTileOverlaySystem.cs | 289 ++++++++++++----- Content.Shared/Atmos/GasMixture.cs | 2 +- .../Atmos/GasMixtureStringRepresentation.cs | 13 +- .../Components/SharedVentScrubberComponent.cs | 32 +- .../Atmos/Prototypes/GasPrototype.cs | 210 +++++++----- Content.Shared/CCVar/CCVars.Atmos.cs | 11 +- Content.Shared/DrawDepth/DrawDepth.cs | 11 +- .../_Adventure/ADTCCVars/ADTCCVars.Atmos.cs | 24 ++ .../_Adventure/Atmos/Atmospherics.cs | 44 +++ .../AtmosAlertsComputerComponent.Sunrise.cs | 19 ++ ...SharedAtmosAlertsComputerSystem.Sunrise.cs | 41 +++ Resources/Prototypes/Atmospherics/gases.yml | 82 +++-- Resources/Prototypes/_Adventure/Gases/gas.yml | 135 -------- .../Prototypes/_Adventure/Gases/gases.yml | 152 +++++++++ .../Prototypes/_Adventure/Gases/reactions.yml | 22 +- .../Prototypes/_Adventure/Gases/reagents.yml | 2 +- .../Effects/atmospherics.rsi/bz.png | Bin 0 -> 3326 bytes .../Effects/atmospherics.rsi/meta.json | 4 +- .../Effects/atmospherics.rsi/nitryl.png | Bin 2152 -> 0 bytes 98 files changed, 2767 insertions(+), 1888 deletions(-) create mode 100644 Content.Client/Atmos/EntitySystems/AtmosphereSystem.CVars.cs create mode 100644 Content.Client/Atmos/EntitySystems/AtmosphereSystem.Gases.cs create mode 100644 Content.Client/Atmos/EntitySystems/GasTileFireOverlaySystem.cs create mode 100644 Content.Client/Atmos/EntitySystems/GasTileVisibleGasOverlaySystem.cs create mode 100644 Content.Client/Atmos/Overlays/GasTileFireOverlay.cs delete mode 100644 Content.Client/Atmos/Overlays/GasTileOverlay.cs create mode 100644 Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs create mode 100644 Content.Server/Atmos/AtmosDirectionExtensions.cs create mode 100644 Content.Server/Atmos/Components/IgniteOnAmmoHitComponent.cs create mode 100644 Content.Server/_Adventure/Atmos/Components/GridAtmosphereComponent.cs create mode 100644 Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.CCVars.cs create mode 100644 Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.Processing.cs create mode 100644 Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/BZProductionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/HalonOxygenAbsorptionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/HealiumProductionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/HydrogenFireReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/HyperNobliumProductionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/NitriumDecompositionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/NitriumProductionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/PluoxiumProductionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateBZaseConversionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateHydrogenConversionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateProductionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateTritiumConversionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/ZaukerDecompositionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/Reactions/ZaukerProductionReaction.cs create mode 100644 Content.Server/_Adventure/Atmos/TileAtmosphere.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/BZProductionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/HalonFireSuppressionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/HealiumProductionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/HydrogenBurnReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/HyperNobliumEffectSystem.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/HyperNobliumProductionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/NitriumDecompositionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/NitriumProductionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/PluoxiumProductionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/ProtoNitrateBZDecomposition.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/ProtoNitrateHydrogenConversion.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/ProtoNitrateProductionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/ProtoNitrateTritiumReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/ZaukerDecompositionReaction.cs delete mode 100644 Content.Server/_Adventure/Atmospherics/ZaukerProductionReaction.cs create mode 100644 Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.Gases.cs create mode 100644 Content.Shared/_Adventure/ADTCCVars/ADTCCVars.Atmos.cs create mode 100644 Content.Shared/_Adventure/Atmos/Atmospherics.cs create mode 100644 Content.Shared/_Adventure/Atmos/Consoles/Components/AtmosAlertsComputerComponent.Sunrise.cs create mode 100644 Content.Shared/_Adventure/Atmos/Consoles/SharedAtmosAlertsComputerSystem.Sunrise.cs delete mode 100644 Resources/Prototypes/_Adventure/Gases/gas.yml create mode 100644 Resources/Prototypes/_Adventure/Gases/gases.yml create mode 100644 Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png delete mode 100644 Resources/Textures/_Adventure/Effects/atmospherics.rsi/nitryl.png diff --git a/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs index f0e4b13356c..5432357368f 100644 --- a/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs +++ b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs @@ -31,6 +31,30 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer [AtmosAlarmType.Danger] = "atmos-alerts-window-danger-state", }; + private Dictionary _gasShorthands = new Dictionary() + { + [Gas.Ammonia] = "NH₃", + [Gas.CarbonDioxide] = "CO₂", + [Gas.Frezon] = "F", + [Gas.Nitrogen] = "N₂", + [Gas.NitrousOxide] = "N₂O", + [Gas.Oxygen] = "O₂", + [Gas.Plasma] = "P", + [Gas.Tritium] = "T", + [Gas.WaterVapor] = "H₂O", + [Gas.BZ] = "BZ", + [Gas.Healium] = "F₃BZ", + [Gas.Nitrium] = "N", + [Gas.Pluoxium] = "Pl₂", + [Gas.Hydrogen] = "H₂", + [Gas.HyperNoblium] = "HN₂", + [Gas.ProtoNitrate] = "PN₂", + [Gas.Zauker] = "Z₂", + [Gas.Halon] = "Ha₂", + [Gas.Helium] = "He₂", + [Gas.AntiNoblium] = "AN₂", + }; + public AtmosAlarmEntryContainer(NetEntity uid, EntityCoordinates? coordinates) { RobustXamlLoader.Load(this); @@ -149,11 +173,12 @@ public void UpdateEntry(AtmosAlertsComputerEntry entry, bool isFocus, AtmosAlert foreach ((var gas, (var mol, var percent, var alert)) in keyValuePairs) { FixedPoint2 gasPercent = percent * 100f; - var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation")); + + var gasShorthand = _gasShorthands.GetValueOrDefault(gas, "X"); var gasLabel = new Label() { - Text = Loc.GetString("atmos-alerts-window-other-gases-value", ("shorthand", gasAbbreviation), ("value", gasPercent)), + Text = Loc.GetString("atmos-alerts-window-other-gases-value", ("shorthand", gasShorthand), ("value", gasPercent)), FontOverride = normalFont, FontColorOverride = GetAlarmStateColor(alert), HorizontalAlignment = HAlignment.Center, diff --git a/Content.Client/Atmos/Consoles/AtmosMonitoringEntryContainer.xaml.cs b/Content.Client/Atmos/Consoles/AtmosMonitoringEntryContainer.xaml.cs index 0ce0c9c880a..5652c6a41ef 100644 --- a/Content.Client/Atmos/Consoles/AtmosMonitoringEntryContainer.xaml.cs +++ b/Content.Client/Atmos/Consoles/AtmosMonitoringEntryContainer.xaml.cs @@ -1,6 +1,7 @@ using Content.Client.Stylesheets; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.EntitySystems; using Content.Shared.FixedPoint; using Content.Shared.Temperature; using Robust.Client.AutoGenerated; @@ -19,12 +20,14 @@ public sealed partial class AtmosMonitoringEntryContainer : BoxContainer private readonly IEntityManager _entManager; private readonly IResourceCache _cache; + private readonly SharedAtmosphereSystem _atmosphereSystem; // Adventure edit public AtmosMonitoringEntryContainer(AtmosMonitoringConsoleEntry data) { RobustXamlLoader.Load(this); _entManager = IoCManager.Resolve(); _cache = IoCManager.Resolve(); + _atmosphereSystem = _entManager.System(); // Adventure edit Data = data; @@ -132,7 +135,10 @@ public void UpdateEntry(AtmosMonitoringConsoleEntry updatedData, bool isFocus) var gasPercent = (FixedPoint2)0f; gasPercent = percent * 100f; - var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation")); + var proto = ((int)gas >= 0 && (int)gas < Atmospherics.TotalNumberOfGases) ? _atmosphereSystem.GetGas((int)gas) : null; + var gasAbbreviation = proto?.Abbreviation is { } abbrev + ? Loc.GetString(abbrev.Id ?? "gas-unknown-abbreviation") + : Loc.GetString("gas-unknown-abbreviation"); var gasLabel = new Label() { diff --git a/Content.Client/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs index b63d274bdca..32e82922418 100644 --- a/Content.Client/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Client/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs @@ -10,7 +10,9 @@ namespace Content.Client.Atmos.EntitySystems [UsedImplicitly] internal sealed class AtmosDebugOverlaySystem : SharedAtmosDebugOverlaySystem { - public readonly Dictionary TileData = new(); + [Dependency] private readonly IOverlayManager _overlayManager = default!; + + public readonly Dictionary TileData = []; // Configuration set by debug commands and used by AtmosDebugOverlay { /// Value source for display @@ -25,6 +27,8 @@ internal sealed class AtmosDebugOverlaySystem : SharedAtmosDebugOverlaySystem public bool CfgCBM = false; // } + private AtmosDebugOverlay? _overlay; + public override void Initialize() { base.Initialize(); @@ -34,10 +38,6 @@ public override void Initialize() SubscribeNetworkEvent(HandleAtmosDebugOverlayDisableMessage); SubscribeLocalEvent(OnGridRemoved); - - var overlayManager = IoCManager.Resolve(); - if(!overlayManager.HasOverlay()) - overlayManager.AddOverlay(new AtmosDebugOverlay(this)); } private void OnGridRemoved(GridRemovalEvent ev) @@ -51,19 +51,25 @@ private void OnGridRemoved(GridRemovalEvent ev) private void HandleAtmosDebugOverlayMessage(AtmosDebugOverlayMessage message) { TileData[GetEntity(message.GridId)] = message; + + if (_overlay is not null) + return; + + _overlay = new AtmosDebugOverlay(this); + _overlayManager.AddOverlay(_overlay); } private void HandleAtmosDebugOverlayDisableMessage(AtmosDebugOverlayDisableMessage ev) { TileData.Clear(); + RemoveOverlay(); } public override void Shutdown() { base.Shutdown(); - var overlayManager = IoCManager.Resolve(); - if (overlayManager.HasOverlay()) - overlayManager.RemoveOverlay(); + + RemoveOverlay(); } public void Reset(RoundRestartCleanupEvent ev) @@ -75,6 +81,15 @@ public bool HasData(EntityUid gridId) { return TileData.ContainsKey(gridId); } + + private void RemoveOverlay() + { + if (_overlay is null) + return; + + _overlayManager.RemoveOverlay(_overlay); + _overlay = null; + } } internal enum AtmosDebugOverlayMode : byte diff --git a/Content.Client/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.CVars.cs new file mode 100644 index 00000000000..bf6fdaf0716 --- /dev/null +++ b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -0,0 +1,17 @@ +using Content.Shared.CCVar; +using Robust.Shared.Configuration; + +namespace Content.Client.Atmos.EntitySystems; + +public sealed partial class AtmosphereSystem +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + private void InitializeCVars() + { + _cfg.OnValueChanged( + CCVars.AtmosHeatScale, + v => HeatScale = MathF.Max(0.000001f, v), + invokeImmediately: true); + } +} diff --git a/Content.Client/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.Gases.cs new file mode 100644 index 00000000000..0da101d32c6 --- /dev/null +++ b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.Gases.cs @@ -0,0 +1,58 @@ +using System.Runtime.CompilerServices; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; + +namespace Content.Client.Atmos.EntitySystems; + +public sealed partial class AtmosphereSystem +{ + /* + Partial class for operations involving GasMixtures. + + Any method that is overridden here is usually because the server-sided implementation contains + code that would escape sandbox. As such these methods are overridden here with a safe + implementation. + */ + + /// + /// No-op on client as reactions aren't entirely in shared. + /// Don't call it. Smile. + public override ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder) + { + return ReactionResult.NoReaction; + } + + public override bool IsMixtureFuel(GasMixture mixture, float epsilon = Atmospherics.GasMinMoles) + { + var tmp = new float[Atmospherics.AdjustedNumberOfGases]; + NumericsHelpers.Multiply(mixture.Moles, GasFuelMask, tmp); + return NumericsHelpers.HorizontalAdd(tmp) > epsilon; + } + + public override bool IsMixtureOxidizer(GasMixture mixture, float epsilon = Atmospherics.GasMinMoles) + { + var tmp = new float[Atmospherics.AdjustedNumberOfGases]; + NumericsHelpers.Multiply(mixture.Moles, GasOxidizerMask, tmp); + return NumericsHelpers.HorizontalAdd(tmp) > epsilon; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override float GetHeatCapacityCalculation(float[] moles, bool space) + { + // Little hack to make space gas mixtures have heat capacity, therefore allowing them to cool down rooms. + if (space && MathHelper.CloseTo(NumericsHelpers.HorizontalAdd(moles), 0f)) + { + return Atmospherics.SpaceHeatCapacity; + } + + // explicit stackalloc call is banned on client tragically. + // the JIT does not stackalloc this during runtime, + // though this isnt the hottest code path so it should be fine + // the gc can eat a little as a treat + var tmp = new float[moles.Length]; + NumericsHelpers.Multiply(moles, GasSpecificHeats, tmp); + // Adjust heat capacity by speedup, because this is primarily what + // determines how quickly gases heat up/cool. + return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity); + } +} diff --git a/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs index 44759372f4e..7d1545d0014 100644 --- a/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Client/Atmos/EntitySystems/AtmosphereSystem.cs @@ -5,12 +5,13 @@ namespace Content.Client.Atmos.EntitySystems; -public sealed class AtmosphereSystem : SharedAtmosphereSystem +public sealed partial class AtmosphereSystem : SharedAtmosphereSystem // Adventure edit { public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapHandleState); + InitializeCVars(); // Adventure edit } private void OnMapHandleState(EntityUid uid, MapAtmosphereComponent component, ref ComponentHandleState args) diff --git a/Content.Client/Atmos/EntitySystems/GasTileFireOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/GasTileFireOverlaySystem.cs new file mode 100644 index 00000000000..06342903739 --- /dev/null +++ b/Content.Client/Atmos/EntitySystems/GasTileFireOverlaySystem.cs @@ -0,0 +1,30 @@ +using Content.Client.Atmos.Overlays; +using JetBrains.Annotations; +using Robust.Client.Graphics; + +namespace Content.Client.Atmos.EntitySystems; + +/// +/// System responsible for rendering atmos fire animations using . +/// +[UsedImplicitly] +public sealed class GasTileFireOverlaySystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlayMan = default!; + + private GasTileFireOverlay _fireOverlay = default!; + + public override void Initialize() + { + base.Initialize(); + + _fireOverlay = new GasTileFireOverlay(); + _overlayMan.AddOverlay(_fireOverlay); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlayMan.RemoveOverlay(); + } +} diff --git a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs index ad264369467..6ea77394959 100644 --- a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -1,106 +1,91 @@ -using Content.Client.Atmos.Overlays; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Atmos.EntitySystems; using JetBrains.Annotations; -using Robust.Client.GameObjects; -using Robust.Client.Graphics; -using Robust.Client.ResourceManagement; using Robust.Shared.GameStates; +using System.Linq; +using Robust.Shared.Timing; -namespace Content.Client.Atmos.EntitySystems +namespace Content.Client.Atmos.EntitySystems; + +[UsedImplicitly] +public sealed class GasTileOverlaySystem : SharedGasTileOverlaySystem { - [UsedImplicitly] - public sealed class GasTileOverlaySystem : SharedGasTileOverlaySystem + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() { - [Dependency] private readonly IResourceCache _resourceCache = default!; - [Dependency] private readonly IOverlayManager _overlayMan = default!; - [Dependency] private readonly SpriteSystem _spriteSys = default!; - [Dependency] private readonly SharedTransformSystem _xformSys = default!; + base.Initialize(); + SubscribeNetworkEvent(HandleGasOverlayUpdate); + SubscribeLocalEvent(OnHandleState); + } - private GasTileOverlay _overlay = default!; + private void OnHandleState(EntityUid gridUid, GasTileOverlayComponent comp, ref ComponentHandleState args) + { + Dictionary modifiedChunks; - public override void Initialize() + switch (args.Current) { - base.Initialize(); - SubscribeNetworkEvent(HandleGasOverlayUpdate); - SubscribeLocalEvent(OnHandleState); + // is this a delta or full state? + case GasTileOverlayDeltaState delta: + { + modifiedChunks = delta.ModifiedChunks; + foreach (var index in comp.Chunks.Keys) + { + if (!delta.AllChunks.Contains(index)) + comp.Chunks.Remove(index); + } + + break; + } + case GasTileOverlayState state: + { + modifiedChunks = state.Chunks; + foreach (var index in comp.Chunks.Keys.ToArray()) // Adventure edit + { + if (!state.Chunks.ContainsKey(index)) + comp.Chunks.Remove(index); + } - _overlay = new GasTileOverlay(this, EntityManager, _resourceCache, ProtoMan, _spriteSys, _xformSys); - _overlayMan.AddOverlay(_overlay); + break; + } + default: + return; } - public override void Shutdown() + foreach (var (index, data) in modifiedChunks) { - base.Shutdown(); - _overlayMan.RemoveOverlay(); + comp.Chunks[index] = data; + data.LastUpdate = _timing.CurTick; } + } - private void OnHandleState(EntityUid gridUid, GasTileOverlayComponent comp, ref ComponentHandleState args) + private void HandleGasOverlayUpdate(GasOverlayUpdateEvent ev) + { + foreach (var (nent, removedIndicies) in ev.RemovedChunks) { - Dictionary modifiedChunks; - - switch (args.Current) - { - // is this a delta or full state? - case GasTileOverlayDeltaState delta: - { - modifiedChunks = delta.ModifiedChunks; - foreach (var index in comp.Chunks.Keys) - { - if (!delta.AllChunks.Contains(index)) - comp.Chunks.Remove(index); - } - - break; - } - case GasTileOverlayState state: - { - modifiedChunks = state.Chunks; - foreach (var index in comp.Chunks.Keys) - { - if (!state.Chunks.ContainsKey(index)) - comp.Chunks.Remove(index); - } + var grid = GetEntity(nent); - break; - } - default: - return; - } + if (!TryComp(grid, out GasTileOverlayComponent? comp)) + continue; - foreach (var (index, data) in modifiedChunks) + foreach (var index in removedIndicies) { - comp.Chunks[index] = data; + comp.Chunks.Remove(index); } } - private void HandleGasOverlayUpdate(GasOverlayUpdateEvent ev) + foreach (var (nent, gridData) in ev.UpdatedChunks) { - foreach (var (nent, removedIndicies) in ev.RemovedChunks) - { - var grid = GetEntity(nent); + var grid = GetEntity(nent); - if (!TryComp(grid, out GasTileOverlayComponent? comp)) - continue; + if (!TryComp(grid, out GasTileOverlayComponent? comp)) + continue; - foreach (var index in removedIndicies) - { - comp.Chunks.Remove(index); - } - } - - foreach (var (nent, gridData) in ev.UpdatedChunks) + foreach (var chunkData in gridData) { - var grid = GetEntity(nent); - - if (!TryComp(grid, out GasTileOverlayComponent? comp)) - continue; - - foreach (var chunkData in gridData) - { - comp.Chunks[chunkData.Index] = chunkData; - } + comp.Chunks[chunkData.Index] = chunkData; + chunkData.LastUpdate = _timing.CurTick; } } } diff --git a/Content.Client/Atmos/EntitySystems/GasTileVisibleGasOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/GasTileVisibleGasOverlaySystem.cs new file mode 100644 index 00000000000..b1548776534 --- /dev/null +++ b/Content.Client/Atmos/EntitySystems/GasTileVisibleGasOverlaySystem.cs @@ -0,0 +1,31 @@ +using Content.Client.Atmos.Overlays; +using JetBrains.Annotations; +using Robust.Client.Graphics; + +namespace Content.Client.Atmos.EntitySystems; + +/// +/// System responsible for rendering visible atmos gasses (like plasma for example) using . +/// +[UsedImplicitly] +public sealed class GasTileVisibleGasOverlaySystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlayMan = default!; + + private GasTileVisibleGasOverlay _visibleGasOverlay = default!; + + public override void Initialize() + { + base.Initialize(); + + _visibleGasOverlay = new GasTileVisibleGasOverlay(); + _overlayMan.AddOverlay(_visibleGasOverlay); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlayMan.RemoveOverlay(); + } + +} diff --git a/Content.Client/Atmos/Overlays/GasTileFireOverlay.cs b/Content.Client/Atmos/Overlays/GasTileFireOverlay.cs new file mode 100644 index 00000000000..d0e26208058 --- /dev/null +++ b/Content.Client/Atmos/Overlays/GasTileFireOverlay.cs @@ -0,0 +1,167 @@ +using Content.Client.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Components; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.ResourceManagement; +using Robust.Shared.Enums; +using Robust.Shared.Graphics.RSI; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using System.Numerics; + +namespace Content.Client.Atmos.Overlays; + +/// +/// Overlay responsible for rendering atmos fire animation. +/// +public sealed class GasTileFireOverlay : Overlay +{ + [Dependency] private readonly IPrototypeManager _protoMan = default!; + [Dependency] private readonly IResourceCache _resourceCache = default!; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + + public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld; + private static readonly ProtoId UnshadedShader = "unshaded"; + + private readonly SharedTransformSystem _xformSys; + private readonly ShaderInstance _shader; + + private readonly float[] _timer; + private readonly float[][] _frameDelays; + private readonly int[] _frameCounter; + + // TODO combine textures into a single texture atlas. + private readonly Texture[][] _frames; + + private const int FireStates = 3; + private const string FireRsiPath = "/Textures/Effects/fire.rsi"; + + public const int GasOverlayZIndex = (int)Shared.DrawDepth.DrawDepth.Effects; // Under ghosts, above mostly everything else + + public GasTileFireOverlay() + { + IoCManager.InjectDependencies(this); + _xformSys = _entManager.System(); + _shader = _protoMan.Index(UnshadedShader).Instance(); + ZIndex = GasOverlayZIndex; + + _timer = new float[FireStates]; + _frameDelays = new float[FireStates][]; + _frameCounter = new int[FireStates]; + _frames = new Texture[FireStates][]; + + var fire = _resourceCache.GetResource(FireRsiPath).RSI; + + for (var i = 0; i < FireStates; i++) + { + if (!fire.TryGetState((i + 1).ToString(), out var state)) + throw new InvalidOperationException($"Fire RSI doesn't have state \"{i + 1}\"!"); + + _frames[i] = state.GetFrames(RsiDirection.South); + _frameDelays[i] = state.GetDelays(); + _frameCounter[i] = 0; + } + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + for (var i = 0; i < FireStates; i++) + { + var delays = _frameDelays[i]; + if (delays.Length == 0) + continue; + + var frameCount = _frameCounter[i]; + _timer[i] += args.DeltaSeconds; + var time = delays[frameCount]; + + if (_timer[i] < time) continue; + _timer[i] -= time; + _frameCounter[i] = (frameCount + 1) % _frames[i].Length; + } + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (args.MapId == MapId.Nullspace) + return; + + var drawHandle = args.WorldHandle; + var xformQuery = _entManager.GetEntityQuery(); + var overlayQuery = _entManager.GetEntityQuery(); + var gridState = (args.WorldBounds, + args.WorldHandle, + _frames, + _frameCounter, + _shader, + overlayQuery, + xformQuery, + _xformSys); + + if (args.Space != OverlaySpace.WorldSpaceEntities) + return; + + // TODO: WorldBounds callback. + _mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState, + static (EntityUid uid, MapGridComponent grid, + ref (Box2Rotated WorldBounds, + DrawingHandleWorld drawHandle, + Texture[][] frames, + int[] frameCounter, + ShaderInstance shader, + EntityQuery overlayQuery, + EntityQuery xformQuery, + SharedTransformSystem xformSys) state) => + { + if (!state.overlayQuery.TryGetComponent(uid, out var comp) || + !state.xformQuery.TryGetComponent(uid, out var gridXform)) + { + return true; + } + + var (_, _, worldMatrix, invMatrix) = state.xformSys.GetWorldPositionRotationMatrixWithInv(gridXform); + state.drawHandle.SetTransform(worldMatrix); + var floatBounds = invMatrix.TransformBox(state.WorldBounds).Enlarged(grid.TileSize); + var localBounds = new Box2i( + (int)MathF.Floor(floatBounds.Left), + (int)MathF.Floor(floatBounds.Bottom), + (int)MathF.Ceiling(floatBounds.Right), + (int)MathF.Ceiling(floatBounds.Top)); + + // Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are + // ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls + // by chunk, even though its currently slower. + + state.drawHandle.UseShader(state.shader); + foreach (var chunk in comp.Chunks.Values) + { + var enumerator = new GasChunkEnumerator(chunk); + + while (enumerator.MoveNext(out var gas)) + { + if (gas.FireState == 0 || gas.FireState > FireStates) + continue; + + var index = chunk.Origin + (enumerator.X, enumerator.Y); + if (!localBounds.Contains(index)) + continue; + + var fireState = gas.FireState - 1; + var texture = state.frames[fireState][state.frameCounter[fireState]]; + state.drawHandle.DrawTexture(texture, index); + } + } + + return true; + }); + + drawHandle.UseShader(null); + drawHandle.SetTransform(Matrix3x2.Identity); + } +} diff --git a/Content.Client/Atmos/Overlays/GasTileOverlay.cs b/Content.Client/Atmos/Overlays/GasTileOverlay.cs deleted file mode 100644 index eeb10b54d03..00000000000 --- a/Content.Client/Atmos/Overlays/GasTileOverlay.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System.Numerics; -using Content.Client.Atmos.Components; -using Content.Client.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Components; -using Content.Shared.Atmos.EntitySystems; -using Content.Shared.Atmos.Prototypes; -using Robust.Client.GameObjects; -using Robust.Client.Graphics; -using Robust.Client.ResourceManagement; -using Robust.Shared.Enums; -using Robust.Shared.Graphics.RSI; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Robust.Shared.Utility; - -namespace Content.Client.Atmos.Overlays -{ - public sealed class GasTileOverlay : Overlay - { - private static readonly ProtoId UnshadedShader = "unshaded"; - - private readonly IEntityManager _entManager; - private readonly IMapManager _mapManager; - private readonly SharedAtmosphereSystem _atmosphereSystem; - private readonly SharedMapSystem _mapSystem; - private readonly SharedTransformSystem _xformSys; - - public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld; - private readonly ShaderInstance _shader; - - // Gas overlays - private readonly float[] _timer; - private readonly float[][] _frameDelays; - private readonly int[] _frameCounter; - - // TODO combine textures into a single texture atlas. - private readonly Texture[][] _frames; - - // Fire overlays - private const int FireStates = 3; - private const string FireRsiPath = "/Textures/Effects/fire.rsi"; - - private readonly float[] _fireTimer = new float[FireStates]; - private readonly float[][] _fireFrameDelays = new float[FireStates][]; - private readonly int[] _fireFrameCounter = new int[FireStates]; - private readonly Texture[][] _fireFrames = new Texture[FireStates][]; - - private int _gasCount; - - public const int GasOverlayZIndex = (int) Shared.DrawDepth.DrawDepth.Effects; // Under ghosts, above mostly everything else - - public GasTileOverlay(GasTileOverlaySystem system, IEntityManager entManager, IResourceCache resourceCache, IPrototypeManager protoMan, SpriteSystem spriteSys, SharedTransformSystem xformSys) - { - _entManager = entManager; - _mapManager = IoCManager.Resolve(); - _atmosphereSystem = entManager.System(); - _mapSystem = entManager.System(); - _xformSys = xformSys; - _shader = protoMan.Index(UnshadedShader).Instance(); - ZIndex = GasOverlayZIndex; - - _gasCount = system.VisibleGasId.Length; - _timer = new float[_gasCount]; - _frameDelays = new float[_gasCount][]; - _frameCounter = new int[_gasCount]; - _frames = new Texture[_gasCount][]; - - for (var i = 0; i < _gasCount; i++) - { - var gasPrototype = _atmosphereSystem.GetGas(system.VisibleGasId[i]); - - SpriteSpecifier overlay; - - if (!string.IsNullOrEmpty(gasPrototype.GasOverlaySprite) && !string.IsNullOrEmpty(gasPrototype.GasOverlayState)) - overlay = new SpriteSpecifier.Rsi(new (gasPrototype.GasOverlaySprite), gasPrototype.GasOverlayState); - else if (!string.IsNullOrEmpty(gasPrototype.GasOverlayTexture)) - overlay = new SpriteSpecifier.Texture(new (gasPrototype.GasOverlayTexture)); - else - continue; - - switch (overlay) - { - case SpriteSpecifier.Rsi animated: - var rsi = resourceCache.GetResource(animated.RsiPath).RSI; - var stateId = animated.RsiState; - - if (!rsi.TryGetState(stateId, out var state)) - continue; - - _frames[i] = state.GetFrames(RsiDirection.South); - _frameDelays[i] = state.GetDelays(); - _frameCounter[i] = 0; - break; - case SpriteSpecifier.Texture texture: - _frames[i] = new[] { spriteSys.Frame0(texture) }; - _frameDelays[i] = Array.Empty(); - break; - } - } - - var fire = resourceCache.GetResource(FireRsiPath).RSI; - - for (var i = 0; i < FireStates; i++) - { - if (!fire.TryGetState((i + 1).ToString(), out var state)) - throw new ArgumentOutOfRangeException($"Fire RSI doesn't have state \"{i}\"!"); - - _fireFrames[i] = state.GetFrames(RsiDirection.South); - _fireFrameDelays[i] = state.GetDelays(); - _fireFrameCounter[i] = 0; - } - } - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); - - for (var i = 0; i < _gasCount; i++) - { - var delays = _frameDelays[i]; - if (delays.Length == 0) - continue; - - var frameCount = _frameCounter[i]; - _timer[i] += args.DeltaSeconds; - var time = delays[frameCount]; - - if (_timer[i] < time) - continue; - - _timer[i] -= time; - _frameCounter[i] = (frameCount + 1) % _frames[i].Length; - } - - for (var i = 0; i < FireStates; i++) - { - var delays = _fireFrameDelays[i]; - if (delays.Length == 0) - continue; - - var frameCount = _fireFrameCounter[i]; - _fireTimer[i] += args.DeltaSeconds; - var time = delays[frameCount]; - - if (_fireTimer[i] < time) continue; - _fireTimer[i] -= time; - _fireFrameCounter[i] = (frameCount + 1) % _fireFrames[i].Length; - } - } - - protected override void Draw(in OverlayDrawArgs args) - { - if (args.MapId == MapId.Nullspace) - return; - - var drawHandle = args.WorldHandle; - var xformQuery = _entManager.GetEntityQuery(); - var overlayQuery = _entManager.GetEntityQuery(); - var gridState = (args.WorldBounds, - args.WorldHandle, - _gasCount, - _frames, - _frameCounter, - _fireFrames, - _fireFrameCounter, - _shader, - overlayQuery, - xformQuery, - _xformSys); - - var mapUid = _mapSystem.GetMapOrInvalid(args.MapId); - - if (_entManager.TryGetComponent(mapUid, out var atmos)) - DrawMapOverlay(drawHandle, args, mapUid, atmos); - - if (args.Space != OverlaySpace.WorldSpaceEntities) - return; - - // TODO: WorldBounds callback. - _mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState, - static (EntityUid uid, MapGridComponent grid, - ref (Box2Rotated WorldBounds, - DrawingHandleWorld drawHandle, - int gasCount, - Texture[][] frames, - int[] frameCounter, - Texture[][] fireFrames, - int[] fireFrameCounter, - ShaderInstance shader, - EntityQuery overlayQuery, - EntityQuery xformQuery, - SharedTransformSystem xformSys) state) => - { - if (!state.overlayQuery.TryGetComponent(uid, out var comp) || - !state.xformQuery.TryGetComponent(uid, out var gridXform)) - { - return true; - } - - var (_, _, worldMatrix, invMatrix) = state.xformSys.GetWorldPositionRotationMatrixWithInv(gridXform); - state.drawHandle.SetTransform(worldMatrix); - var floatBounds = invMatrix.TransformBox(state.WorldBounds).Enlarged(grid.TileSize); - var localBounds = new Box2i( - (int) MathF.Floor(floatBounds.Left), - (int) MathF.Floor(floatBounds.Bottom), - (int) MathF.Ceiling(floatBounds.Right), - (int) MathF.Ceiling(floatBounds.Top)); - - // Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are - // ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls - // by chunk, even though its currently slower. - - state.drawHandle.UseShader(null); - foreach (var chunk in comp.Chunks.Values) - { - var enumerator = new GasChunkEnumerator(chunk); - - while (enumerator.MoveNext(out var gas)) - { - if (gas.Opacity == null!) - continue; - - var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y); - if (!localBounds.Contains(tilePosition)) - continue; - - for (var i = 0; i < state.gasCount; i++) - { - var opacity = gas.Opacity[i]; - if (opacity > 0) - state.drawHandle.DrawTexture(state.frames[i][state.frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); - } - } - } - - // And again for fire, with the unshaded shader - state.drawHandle.UseShader(state.shader); - foreach (var chunk in comp.Chunks.Values) - { - var enumerator = new GasChunkEnumerator(chunk); - - while (enumerator.MoveNext(out var gas)) - { - if (gas.FireState == 0) - continue; - - var index = chunk.Origin + (enumerator.X, enumerator.Y); - if (!localBounds.Contains(index)) - continue; - - var fireState = gas.FireState - 1; - var texture = state.fireFrames[fireState][state.fireFrameCounter[fireState]]; - state.drawHandle.DrawTexture(texture, index); - } - } - - return true; - }); - - drawHandle.UseShader(null); - drawHandle.SetTransform(Matrix3x2.Identity); - } - - private void DrawMapOverlay( - DrawingHandleWorld handle, - OverlayDrawArgs args, - EntityUid map, - MapAtmosphereComponent atmos) - { - var mapGrid = _entManager.HasComponent(map); - - // map-grid atmospheres get drawn above grids - if (mapGrid && args.Space != OverlaySpace.WorldSpaceEntities) - return; - - // Normal map atmospheres get drawn below grids - if (!mapGrid && args.Space != OverlaySpace.WorldSpaceBelowWorld) - return; - - var bottomLeft = args.WorldAABB.BottomLeft.Floored(); - var topRight = args.WorldAABB.TopRight.Ceiled(); - - for (var x = bottomLeft.X; x <= topRight.X; x++) - { - for (var y = bottomLeft.Y; y <= topRight.Y; y++) - { - var tilePosition = new Vector2(x, y); - - for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) - { - var opacity = atmos.OverlayData.Opacity[i]; - - if (opacity > 0) - handle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); - } - } - } - } - } -} diff --git a/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs b/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs new file mode 100644 index 00000000000..7e6847c10d2 --- /dev/null +++ b/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs @@ -0,0 +1,273 @@ +using Content.Client.Atmos.Components; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.EntitySystems; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.ResourceManagement; +using Robust.Shared.Enums; +using Robust.Shared.Graphics.RSI; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Robust.Shared.Utility; +using System.Numerics; +using DrawDepth = Content.Shared.DrawDepth.DrawDepth; + +namespace Content.Client.Atmos.Overlays; + +/// +/// Overlay responsible for rendering visible atmos gasses (like plasma for example) +/// +public sealed class GasTileVisibleGasOverlay : Overlay +{ + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IResourceCache _resourceCache = default!; + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + + /// Adventure edit: gas indices that should never be rendered (transparent gases) + private static readonly HashSet TransparentGases = new() + { + Gas.Oxygen, + Gas.Nitrogen, + Gas.CarbonDioxide, + Gas.NitrousOxide, + Gas.Hydrogen, + Gas.Helium, + Gas.Pluoxium + }; + + private readonly bool[] _isTransparent; + private readonly SharedAtmosphereSystem _atmosphereSystem; + private readonly SharedMapSystem _mapSystem; + private readonly SharedTransformSystem _xformSys; + private readonly SharedGasTileOverlaySystem _gasTileOverlaySystem; + private readonly SpriteSystem _spriteSystem; + + public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld; + + // Gas overlays + private readonly float[] _timer; + private readonly float[][] _frameDelays; + private readonly int[] _frameCounter; + + // TODO combine textures into a single texture atlas. + private readonly Texture[][] _frames; + + private readonly int _gasCount; + + public const int GasOverlayZIndex = (int)DrawDepth.Gasses; // Under ghosts and fire, above mostly everything else + + public GasTileVisibleGasOverlay() + { + IoCManager.InjectDependencies(this); + _atmosphereSystem = _entManager.System(); + _mapSystem = _entManager.System(); + _xformSys = _entManager.System(); + _gasTileOverlaySystem = _entManager.System(); + _spriteSystem = _entManager.System(); + + ZIndex = GasOverlayZIndex; + + _gasCount = _gasTileOverlaySystem.VisibleGasId.Length; + _timer = new float[_gasCount]; + _frameDelays = new float[_gasCount][]; + _frameCounter = new int[_gasCount]; + _frames = new Texture[_gasCount][]; + _isTransparent = new bool[_gasCount]; + for (var i = 0; i < _gasCount; i++) + { + _isTransparent[i] = TransparentGases.Contains((Gas)_gasTileOverlaySystem.VisibleGasId[i]); + } + + for (var i = 0; i < _gasCount; i++) + { + var gasPrototype = _atmosphereSystem.GetGas(_gasTileOverlaySystem.VisibleGasId[i]); + + switch (gasPrototype.GasOverlaySprite) + { + case SpriteSpecifier.Rsi animated: + var rsi = _resourceCache.GetResource(animated.RsiPath).RSI; + var stateId = animated.RsiState; + + if (!rsi.TryGetState(stateId, out var state)) + { + // Adventure Edit + Logger.Error($"Gas overlay state '{stateId}' was not found in '{gasPrototype.GasOverlaySprite}'. Gas: {gasPrototype.ID}"); + _frames[i] = new[] { Texture.White }; + _frameDelays[i] = Array.Empty(); + break; + } + + _frames[i] = state.GetFrames(RsiDirection.South); + _frameDelays[i] = state.GetDelays(); + _frameCounter[i] = 0; + break; + case SpriteSpecifier.Texture texture: + _frames[i] = new[] { _spriteSystem.Frame0(texture) }; + _frameDelays[i] = Array.Empty(); + break; + } + } + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + for (var i = 0; i < _gasCount; i++) + { + var delays = _frameDelays[i]; + if (delays.Length == 0) + continue; + + var frameCount = _frameCounter[i]; + _timer[i] += args.DeltaSeconds; + var time = delays[frameCount]; + + if (_timer[i] < time) + continue; + + _timer[i] -= time; + _frameCounter[i] = (frameCount + 1) % _frames[i].Length; + } + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (args.MapId == MapId.Nullspace) + return; + + var drawHandle = args.WorldHandle; + var xformQuery = _entManager.GetEntityQuery(); + var overlayQuery = _entManager.GetEntityQuery(); + var gridState = (args.WorldBounds, + args.WorldHandle, + _gasCount, + _frames, + _frameCounter, + overlayQuery, + xformQuery, + _xformSys, + _isTransparent); + + var mapUid = _mapSystem.GetMapOrInvalid(args.MapId); + + if (_entManager.TryGetComponent(mapUid, out var atmos)) + { + DrawMapOverlay(drawHandle, args, mapUid, atmos); + } + + if (args.Space != OverlaySpace.WorldSpaceEntities) + return; + + // TODO: WorldBounds callback. + _mapManager.FindGridsIntersecting(args.MapId, + args.WorldAABB, + ref gridState, + static (EntityUid uid, + MapGridComponent grid, + ref (Box2Rotated WorldBounds, + DrawingHandleWorld drawHandle, + int gasCount, + Texture[][] frames, + int[] frameCounter, + EntityQuery overlayQuery, + EntityQuery xformQuery, + SharedTransformSystem xformSys, + bool[] isTransparent) state) => + { + if (!state.overlayQuery.TryGetComponent(uid, out var comp) || + !state.xformQuery.TryGetComponent(uid, out var gridXform)) + { + return true; + } + + var (_, _, worldMatrix, invMatrix) = state.xformSys.GetWorldPositionRotationMatrixWithInv(gridXform); + state.drawHandle.SetTransform(worldMatrix); + var floatBounds = invMatrix.TransformBox(state.WorldBounds).Enlarged(grid.TileSize); + var localBounds = new Box2i( + (int)MathF.Floor(floatBounds.Left), + (int)MathF.Floor(floatBounds.Bottom), + (int)MathF.Ceiling(floatBounds.Right), + (int)MathF.Ceiling(floatBounds.Top)); + + // Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are + // ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls + // by chunk, even though its currently slower. + + foreach (var chunk in comp.Chunks.Values) + { + var enumerator = new GasChunkEnumerator(chunk); + + while (enumerator.MoveNext(out var gas)) + { + if (gas.Opacity == null!) + continue; + + var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y); + if (!localBounds.Contains(tilePosition)) + continue; + + for (var i = 0; i < state.gasCount; i++) + { + if (state.isTransparent[i]) + continue; + var opacity = gas.Opacity[i]; + if (opacity > 0) + { + state.drawHandle.DrawTexture(state.frames[i][state.frameCounter[i]], + tilePosition, + Color.White.WithAlpha(opacity / 255f * 0.6f)); + } + } + } + } + + return true; + }); + + drawHandle.SetTransform(Matrix3x2.Identity); + } + + private void DrawMapOverlay( + DrawingHandleWorld handle, + OverlayDrawArgs args, + EntityUid map, + MapAtmosphereComponent atmos) + { + var mapGrid = _entManager.HasComponent(map); + + // map-grid atmospheres get drawn above grids + if (mapGrid && args.Space != OverlaySpace.WorldSpaceEntities) + return; + + // Normal map atmospheres get drawn below grids + if (!mapGrid && args.Space != OverlaySpace.WorldSpaceBelowWorld) + return; + + var bottomLeft = args.WorldAABB.BottomLeft.Floored(); + var topRight = args.WorldAABB.TopRight.Ceiled(); + + for (var x = bottomLeft.X; x <= topRight.X; x++) + { + for (var y = bottomLeft.Y; y <= topRight.Y; y++) + { + var tilePosition = new Vector2(x, y); + + for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) + { + if (_isTransparent[i]) + continue; + + var opacity = atmos.OverlayData.Opacity[i]; + + if (opacity > 0) + handle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity / 255f * 0.6f)); + } + } + } + } +} diff --git a/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs b/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs index 3a5df3f9a88..c8f2091d133 100644 --- a/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs @@ -1,41 +1,33 @@ -using Robust.Client.GameObjects; using Robust.Client.UserInterface; -using static Content.Shared.Atmos.Components.GasAnalyzerComponent; +using Content.Shared.Atmos.Components; -namespace Content.Client.Atmos.UI +namespace Content.Client.Atmos.UI; + +public sealed class GasAnalyzerBoundUserInterface : BoundUserInterface { - public sealed class GasAnalyzerBoundUserInterface : BoundUserInterface + [ViewVariables] + private GasAnalyzerWindow? _window; + + public GasAnalyzerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() { - [ViewVariables] - private GasAnalyzerWindow? _window; - - public GasAnalyzerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) - { - } - - protected override void Open() - { - base.Open(); - - _window = this.CreateWindowCenteredLeft(); - _window.OnClose += Close; - } - - protected override void ReceiveMessage(BoundUserInterfaceMessage message) - { - if (_window == null) - return; - if (message is not GasAnalyzerUserMessage cast) - return; - _window.Populate(cast); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - _window?.Dispose(); - } + base.Open(); + + _window = this.CreateWindowCenteredLeft(); + _window.OnClose += Close; + } + + protected override void ReceiveMessage(BoundUserInterfaceMessage message) + { + if (_window == null) + return; + + if (message is not GasAnalyzerUserMessage cast) + return; + + _window.Populate(cast); } } diff --git a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs index 63b4e6b0c6f..94a9f237453 100644 --- a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs @@ -1,6 +1,8 @@ using System.Numerics; using Content.Client.UserInterface.Controls; using Content.Shared.Atmos; +using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.EntitySystems; using Content.Shared.Temperature; using Robust.Client.Graphics; using Robust.Client.UserInterface; @@ -8,7 +10,6 @@ using Robust.Client.UserInterface.CustomControls; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; -using static Content.Shared.Atmos.Components.GasAnalyzerComponent; using Direction = Robust.Shared.Maths.Direction; namespace Content.Client.Atmos.UI @@ -16,25 +17,17 @@ namespace Content.Client.Atmos.UI [GenerateTypedNameReferences] public sealed partial class GasAnalyzerWindow : DefaultWindow { + private readonly SharedAtmosphereSystem _atmosphere; private NetEntity _currentEntity = NetEntity.Invalid; public GasAnalyzerWindow() { RobustXamlLoader.Load(this); + _atmosphere = IoCManager.Resolve().System(); } public void Populate(GasAnalyzerUserMessage msg) { - if (msg.Error != null) - { - CTopBox.AddChild(new Label - { - Text = Loc.GetString("gas-analyzer-window-error-text", ("errorText", msg.Error)), - FontColorOverride = Color.Red - }); - return; - } - if (msg.NodeGasMixes.Length == 0) { CTopBox.AddChild(new Label @@ -329,31 +322,31 @@ private void GenerateGasDisplay(GasMixEntry gasMix, Control parent) for (var j = 0; j < gasMix.Gases.Length; j++) { - var gas = gasMix.Gases[j]; - var color = Color.FromHex($"#{gas.Color}", Color.White); + var gasEntry = gasMix.Gases[j]; + var gasProto = _atmosphere.GetGas(gasEntry.Gas); // Add to the table tableKey.AddChild(new Label { - Text = Loc.GetString(gas.Name) + Text = Loc.GetString(gasProto.Name) }); tableVal.AddChild(new Label { Text = Loc.GetString("gas-analyzer-window-molarity-text", - ("mol", $"{gas.Amount:0.00}")), + ("mol", $"{gasEntry.Amount:0.00}")), Align = Label.AlignMode.Right, }); tablePercent.AddChild(new Label { Text = Loc.GetString("gas-analyzer-window-percentage-text", - ("percentage", $"{(gas.Amount / totalGasAmount * 100):0.0}")), + ("percentage", $"{(gasEntry.Amount / totalGasAmount * 100):0.0}")), Align = Label.AlignMode.Right }); // Add to the gas bar //TODO: highlight the currently hover one - gasBar.AddEntry(gas.Amount, color, tooltip: Loc.GetString("gas-analyzer-window-molarity-percentage-text", - ("gasName", gas.Name), - ("amount", $"{gas.Amount:0.##}"), - ("percentage", $"{(gas.Amount / totalGasAmount * 100):0.#}"))); + gasBar.AddEntry(gasEntry.Amount, gasProto.Color, tooltip: Loc.GetString("gas-analyzer-window-molarity-percentage-text", + ("gasName", Loc.GetString(gasProto.Name)), + ("amount", $"{gasEntry.Amount:0.##}"), + ("percentage", $"{(gasEntry.Amount / totalGasAmount * 100):0.#}"))); } dataContainer.AddChild(gasBar); diff --git a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs index 3392545be8a..b8b5350ff31 100644 --- a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs +++ b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs @@ -77,6 +77,12 @@ private void OnPrototypesReloaded(PrototypesReloadedEventArgs? ev) if (gas.Reagent == null) continue; + if (!_reagentSources.ContainsKey(gas.Reagent)) + { + Logger.Warning($"Reagent '{gas.Reagent}' referenced by gas '{gas.ID}' not found in reagent prototypes, skipping..."); + continue; + } + var data = new ReagentGasSourceData( new () { DefaultCondenseCategory }, gas); diff --git a/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs b/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs index 6481e377c95..c95e168a010 100644 --- a/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs +++ b/Content.IntegrationTests/Tests/Atmos/ConstantsTest.cs @@ -27,16 +27,13 @@ await server.WaitPost(() => // number of gas prototypes Assert.That(gasProtos, Has.Count.EqualTo(Atmospherics.TotalNumberOfGases), - $"Number of GasPrototypes is not equal to TotalNumberOfGases."); + $"Number of GasPrototypes is not equal to TotalNumberOfGases."); // number of gas prototypes used in the atmos system Assert.That(atmosSystem.Gases.Count(), Is.EqualTo(Atmospherics.TotalNumberOfGases), - $"AtmosSystem.Gases is not equal to TotalNumberOfGases."); + $"AtmosSystem.Gases is not equal to TotalNumberOfGases."); // enum mapping gases to their Id Assert.That(Enum.GetValues(), Has.Length.EqualTo(Atmospherics.TotalNumberOfGases), - $"Gas enum size is not equal to TotalNumberOfGases."); - // localized abbreviations for UI purposes - Assert.That(Atmospherics.GasAbbreviations, Has.Count.EqualTo(Atmospherics.TotalNumberOfGases), - $"GasAbbreviations size is not equal to TotalNumberOfGases."); + $"Gas enum size is not equal to TotalNumberOfGases."); // the ID for each gas has to correspond to a value in the Gas enum (converted to a string) foreach (var gas in gasProtos) @@ -48,4 +45,3 @@ await server.WaitPost(() => await pair.CleanReturnAsync(); } } - diff --git a/Content.Server/Atmos/AtmosDirectionExtensions.cs b/Content.Server/Atmos/AtmosDirectionExtensions.cs new file mode 100644 index 00000000000..32470055c54 --- /dev/null +++ b/Content.Server/Atmos/AtmosDirectionExtensions.cs @@ -0,0 +1,54 @@ +using Content.Shared.Atmos; + +namespace Content.Server.Atmos; + +public static class AtmosDirectionExtensions +{ + public static Vector2i ToVec(this AtmosDirection direction) + { + return direction switch + { + AtmosDirection.North => new Vector2i(0, 1), + AtmosDirection.South => new Vector2i(0, -1), + AtmosDirection.East => new Vector2i(1, 0), + AtmosDirection.West => new Vector2i(-1, 0), + _ => Vector2i.Zero + }; + } + + public static AtmosDirection GetOpposite(this AtmosDirection direction) + { + return direction switch + { + AtmosDirection.North => AtmosDirection.South, + AtmosDirection.South => AtmosDirection.North, + AtmosDirection.East => AtmosDirection.West, + AtmosDirection.West => AtmosDirection.East, + _ => AtmosDirection.Invalid + }; + } + + public static int ToIndex(this AtmosDirection direction) + { + return direction switch + { + AtmosDirection.North => 0, + AtmosDirection.South => 1, + AtmosDirection.East => 2, + AtmosDirection.West => 3, + _ => -1 + }; + } + + public static int ToOppositeIndex(this int index) + { + return index switch + { + 0 => 1, + 1 => 0, + 2 => 3, + 3 => 2, + _ => -1 + }; + } +} diff --git a/Content.Server/Atmos/Components/IgniteOnAmmoHitComponent.cs b/Content.Server/Atmos/Components/IgniteOnAmmoHitComponent.cs new file mode 100644 index 00000000000..6eb3af60da1 --- /dev/null +++ b/Content.Server/Atmos/Components/IgniteOnAmmoHitComponent.cs @@ -0,0 +1,14 @@ +using Content.Server.Atmos.EntitySystems; + +namespace Content.Server.Atmos.Components; + +[RegisterComponent, Access(typeof(FlammableSystem))] +public sealed partial class IgniteOnAmmoHitComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("fireStacks")] + public float FireStacks; + + [ViewVariables(VVAccess.ReadWrite), DataField("fixtureId")] + public string FixtureId = "ignition"; + +} diff --git a/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs index 52f7f7f59ae..2370be29fd6 100644 --- a/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs +++ b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs @@ -2,7 +2,6 @@ using Content.Server.DeviceNetwork.Systems; using Content.Server.Pinpointer; using Content.Server.Power.Components; -using Content.Shared.PowerCell; // Adventure monitors using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Consoles; @@ -14,6 +13,16 @@ using Robust.Shared.Map.Components; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Content.Server.Power.EntitySystems; +using Content.Shared.Power.Components; +using Content.Shared.PowerCell; +using Content.Shared.UserInterface; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Player; +using Robust.Shared.Timing; +using Robust.Shared.Utility; +using Content.Shared.PowerCell.Components; // Adventure-edit namespace Content.Server.Atmos.Monitor.Systems; @@ -27,7 +36,9 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem [Dependency] private readonly TransformSystem _transformSystem = default!; [Dependency] private readonly NavMapSystem _navMapSystem = default!; [Dependency] private readonly DeviceListSystem _deviceListSystem = default!; - [Dependency] private readonly PowerCellSystem _cell = default!; // Adventure monitors + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly PowerCellSystem _cell = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; private const float UpdateTime = 1.0f; @@ -49,6 +60,7 @@ public override void Initialize() // Alarm events SubscribeLocalEvent(OnDeviceTerminatingEvent); SubscribeLocalEvent(OnDeviceAnchorChanged); + } #region Event handling @@ -191,12 +203,40 @@ public override void Update(float frameTime) if (TryComp(ent, out var entAppearance)) _appearance.SetData(ent, AtmosAlertsComputerVisuals.ComputerLayerScreen, (int) highestAlert, entAppearance); + // Adventure-start + if (HasComp(ent) && HasComp(ent)) + { + if (_cell.HasActivatableCharge(ent) || _cell.HasDrawCharge(ent)) + { + Beep(ent, entConsole, highestAlert); + } + } + if (HasComp(ent)) + { + if (this.IsPowered(ent, EntityManager)) + { + Beep(ent, entConsole, highestAlert); + } + } + + // Adventure-end + // If the console UI is open, send UI data to each subscribed session UpdateUIState(ent, airAlarmEntries, fireAlarmEntries, entConsole, entXform); } } } + private void Beep(EntityUid ent, AtmosAlertsComputerComponent entConsole, AtmosAlarmType highestAlert) + { + if (entConsole.NextBeep >= _gameTiming.CurTime || highestAlert != AtmosAlarmType.Danger || + entConsole.BeepSound == null || !entConsole.DoAtmosAlert) // Adventure-edit + return; + + _audio.PlayPvs(entConsole.BeepSound, ent); + entConsole.NextBeep = _gameTiming.CurTime + entConsole.Timer; + } + public void UpdateUIState (EntityUid uid, AtmosAlertsComputerEntry[] airAlarmStateData, @@ -207,11 +247,6 @@ public void UpdateUIState if (!_userInterfaceSystem.IsUiOpen(uid, AtmosAlertsComputerUiKey.Key)) return; - // Adventure monitors start - if (!_cell.TryUseActivatableCharge(uid)) - return; - // Adventure monitors end - var gridUid = xform.GridUid!.Value; if (!HasComp(gridUid)) @@ -225,7 +260,7 @@ public void UpdateUIState // Set the UI state _userInterfaceSystem.SetUiState(uid, AtmosAlertsComputerUiKey.Key, - new AtmosAlertsComputerBoundInterfaceState(airAlarmStateData, fireAlarmStateData, focusAlarmData)); + new AtmosAlertsComputerBoundInterfaceState(airAlarmStateData, fireAlarmStateData, focusAlarmData, component.DoAtmosAlert)); } private List GetAlarmStateData(EntityUid gridUid, AtmosAlertsComputerGroup group) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs index f24f0ae171f..8c186568664 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -1,3 +1,4 @@ +using System; using Content.Shared.CCVar; using Robust.Shared.Configuration; @@ -25,7 +26,6 @@ public sealed partial class AtmosphereSystem public float AtmosMaxProcessTime { get; private set; } public float AtmosTickRate { get; private set; } public float Speedup { get; private set; } - public float HeatScale { get; private set; } public bool DeltaPressureDamage { get; private set; } public int DeltaPressureParallelProcessPerIteration { get; private set; } public int DeltaPressureParallelBatchSize { get; private set; } @@ -55,7 +55,16 @@ private void InitializeCVars() Subs.CVar(_cfg, CCVars.AtmosMaxProcessTime, value => AtmosMaxProcessTime = value, true); Subs.CVar(_cfg, CCVars.AtmosTickRate, value => AtmosTickRate = value, true); Subs.CVar(_cfg, CCVars.AtmosSpeedup, value => Speedup = value, true); - Subs.CVar(_cfg, CCVars.AtmosHeatScale, value => { HeatScale = value; InitializeGases(); }, true); + Subs.CVar(_cfg, CCVars.AtmosHeatScale, value => + { + if (value <= 0f) + { + Log.Error($"AtmosHeatScale must be greater than 0, but got {value}. Keeping previous value."); + return; + } + HeatScale = value; + InitializeGases(); + }, true); Subs.CVar(_cfg, CCVars.ExcitedGroups, value => ExcitedGroups = value, true); Subs.CVar(_cfg, CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true); Subs.CVar(_cfg, CCVars.DeltaPressureDamage, value => DeltaPressureDamage = value, true); @@ -63,4 +72,4 @@ private void InitializeCVars() Subs.CVar(_cfg, CCVars.DeltaPressureParallelBatchSize, value => DeltaPressureParallelBatchSize = value, true); } } -} +} \ No newline at end of file diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs index b4d7c643ce3..b5a70d47405 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs @@ -13,53 +13,23 @@ public sealed partial class AtmosphereSystem { [Dependency] private readonly IPrototypeManager _protoMan = default!; - private GasReactionPrototype[] _gasReactions = Array.Empty(); - private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases]; + private GasReactionPrototype[] _gasReactions = []; /// /// List of gas reactions ordered by priority. /// public IEnumerable GasReactions => _gasReactions; - /// - /// Cached array of gas specific heats. - /// - public float[] GasSpecificHeats => _gasSpecificHeats; - - private void InitializeGases() + protected override void InitializeGases() { + base.InitializeGases(); + _gasReactions = _protoMan.EnumeratePrototypes().ToArray(); Array.Sort(_gasReactions, (a, b) => b.Priority.CompareTo(a.Priority)); - - Array.Resize(ref _gasSpecificHeats, MathHelper.NextMultipleOf(Atmospherics.TotalNumberOfGases, 4)); - - for (var i = 0; i < GasPrototypes.Length; i++) - { - _gasSpecificHeats[i] = GasPrototypes[i].SpecificHeat / HeatScale; - } - } - - /// - /// Calculates the heat capacity for a gas mixture. - /// - /// The mixture whose heat capacity should be calculated - /// Whether the internal heat capacity scaling should be applied. This should not be - /// used outside of atmospheric related heat transfer. - /// - public float GetHeatCapacity(GasMixture mixture, bool applyScaling) - { - var scale = GetHeatCapacityCalculation(mixture.Moles, mixture.Immutable); - - // By default GetHeatCapacityCalculation() has the heat-scale divisor pre-applied. - // So if we want the un-scaled heat capacity, we have to multiply by the scale. - return applyScaling ? scale : scale * HeatScale; } - private float GetHeatCapacity(GasMixture mixture) - => GetHeatCapacityCalculation(mixture.Moles, mixture.Immutable); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private float GetHeatCapacityCalculation(float[] moles, bool space) + protected override float GetHeatCapacityCalculation(float[] moles, bool space) { // Little hack to make space gas mixtures have heat capacity, therefore allowing them to cool down rooms. if (space && MathHelper.CloseTo(NumericsHelpers.HorizontalAdd(moles), 0f)) @@ -71,31 +41,29 @@ private float GetHeatCapacityCalculation(float[] moles, bool space) NumericsHelpers.Multiply(moles, GasSpecificHeats, tmp); // Adjust heat capacity by speedup, because this is primarily what // determines how quickly gases heat up/cool. - return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity); + return MathF.Max(NumericsHelpers.HorizontalAdd(tmp) / MathF.Max(HeatScale, 1e-6f), Atmospherics.MinimumHeatCapacity); // Adventure edit } - /// - /// Return speedup factor for pumped or flow-based devices that depend on MaxTransferRate. - /// - public float PumpSpeedup() + public override bool IsMixtureFuel(GasMixture mixture, float epsilon = Atmospherics.GasMinMoles) { - return Speedup; + var tmp = new float[Atmospherics.AdjustedNumberOfGases]; + NumericsHelpers.Multiply(mixture.Moles, GasFuelMask, tmp); + return NumericsHelpers.HorizontalAdd(tmp) > epsilon; } - /// - /// Calculates the thermal energy for a gas mixture. - /// - public float GetThermalEnergy(GasMixture mixture) + public override bool IsMixtureOxidizer(GasMixture mixture, float epsilon = Atmospherics.GasMinMoles) { - return mixture.Temperature * GetHeatCapacity(mixture); + var tmp = new float[Atmospherics.AdjustedNumberOfGases]; + NumericsHelpers.Multiply(mixture.Moles, GasOxidizerMask, tmp); + return NumericsHelpers.HorizontalAdd(tmp) > epsilon; } /// - /// Calculates the thermal energy for a gas mixture, using a cached heat capacity value. + /// Return speedup factor for pumped or flow-based devices that depend on MaxTransferRate. /// - public float GetThermalEnergy(GasMixture mixture, float cachedHeatCapacity) + public float PumpSpeedup() { - return mixture.Temperature * cachedHeatCapacity; + return Speedup; } /// @@ -108,28 +76,6 @@ public void AddHeat(GasMixture mixture, float dQ) mixture.Temperature += dT; } - /// - /// Merges the gas mixture into the gas mixture. - /// The gas mixture is not modified by this method. - /// - public void Merge(GasMixture receiver, GasMixture giver) - { - if (receiver.Immutable) return; - - if (MathF.Abs(receiver.Temperature - giver.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider) - { - var receiverHeatCapacity = GetHeatCapacity(receiver); - var giverHeatCapacity = GetHeatCapacity(giver); - var combinedHeatCapacity = receiverHeatCapacity + giverHeatCapacity; - if (combinedHeatCapacity > Atmospherics.MinimumHeatCapacity) - { - receiver.Temperature = (GetThermalEnergy(giver, giverHeatCapacity) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity; - } - } - - NumericsHelpers.Add(receiver.Moles, giver.Moles); - } - /// /// Divides a source gas mixture into several recipient mixtures, scaled by their relative volumes. Does not /// modify the source gas mixture. Used for pipe network splitting. Note that the total destination volume @@ -358,6 +304,89 @@ 3. Expand both sides. return (-quadraticB + MathF.Sqrt(quadraticB * quadraticB - 4 * quadraticA * quadraticC)) / (2 * quadraticA); } + /// + /// Determines the fraction of gas to be removed and transferred from a source + /// to a target to reach a target pressure + /// in the target . + /// + /// The source that gas will be removed from. + /// This should always be of higher pressure than the second . + /// The target that will increase in pressure + /// to the target pressure. + /// The target mixture's desired pressure to target. + /// A float representing the dimensionless fraction of gas to transfer from the source + /// to the target. This may return negative if you have your mixtures swapped. + /// Note that this method doesn't take into account the heat capacity of the + /// transferred volume causing a pressure rise in the target . + [PublicAPI] + public static float FractionToMaxPressure(GasMixture mix1, GasMixture mix2, float targetPressure) + { + var molesToTransfer = MolesToMaxPressure(mix1, mix2, targetPressure); + return molesToTransfer / mix1.TotalMoles; + } + + /// + /// Determines the number of moles to be removed and transferred from a source + /// to a target to reach a target pressure + /// in the target . + /// + /// The source that gas will be removed from. + /// This should always be of higher pressure than the second . + /// The target that will increase in pressure + /// to the target pressure. + /// The target mixture's desired pressure to target. + /// The difference in moles required to reach the target pressure. + /// Note that this method doesn't take into account the heat capacity of the + /// transferred volume causing a pressure rise in the target . + [PublicAPI] + public static float MolesToMaxPressure(GasMixture mix1, GasMixture mix2, float targetPressure) + { + /* + Calculate the moles required to reach the target pressure. + The formula is derived from the ideal gas law and the + general Richman's law, under the simplification that all the specific heat capacities are equal. + Derivation can also be seen at + https://github.com/space-wizards/space-station-14/pull/35211/files/a0ae787fe07a4e792570f55b49d9dd8038eb6e4d#r1961183456 + TODO ATMOS Make this properly obey the heat capacity change on the target mixture. + + Derivation is as follows. + Assume A is mix1, B is mix2, C is the combined mixture after transfer. + We can express the number of moles in C: + n_C = n_A + n_B + + We can then determine the temperature of C: + T_C = \frac{T_A n_A c_A + T_B n_B c_B}{n_A c_A + n_B c_B} + + Where c_A and c_B are the specific heats of mixtures A and B, respectively. + We can then express the pressure of C: + P_C = \frac{n_C R T_C}{V_C} + + Using the above equations, we can express P_C as follows: + P_C = \frac{(n_A + n_B) R (\frac{T_a n_A + T_B n_B}{n_A + n_B}}{V_C} + + Which can be reduced to: + P_C = \frac{R (T_A n_A + T_B n_B)}{V_C} + + Solving for n_A gives: + n_A = \frac{P_C V_C - R T_B n_B}{R T_A} + + Using the ideal gas law to substitute: + n_A = \frac{P_C V_C - P_B V_B}{R T_A} + + The output volume doesn't change: + V_B = V_C + + So: + n_A = \frac{(P_C - P_B) V_B}{R T_A} + */ + + var delta = targetPressure - mix2.Pressure; + var requiredMoles = (delta * mix2.Volume) / (mix1.Temperature * Atmospherics.R); + + // Return the fraction of moles to transfer. + return requiredMoles; + } + /// /// Determines the number of moles that need to be removed from a to reach a target pressure threshold. /// @@ -439,38 +468,9 @@ public GasCompareResult CompareExchange(GasMixture sample, GasMixture otherSampl return GasCompareResult.NoExchange; } - /// - /// Performs reactions for a given gas mixture on an optional holder. - /// - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder) + [PublicAPI] + public override ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder) { - // Adventure hyper-noblium effect start - var hnMoles = mixture.GetMoles(Gas.HyperNoblium); - if (hnMoles > 0 && mixture.TotalMoles > Atmospherics.GasMinMoles) - { - var hnFraction = hnMoles / mixture.TotalMoles; - if (hnFraction >= Atmospherics.HyperNobliumFullSuppressionThresholdPercentage) - { - var savedResults = mixture.ReactionResults.ToArray(); - Array.Clear(mixture.ReactionResults, 0, mixture.ReactionResults.Length); - foreach (var prototype in GasReactions) - { - if (prototype.ID == "HyperNobliumProduction") - { - prototype.React(mixture, holder, this, HeatScale); - break; - } - } - for (int i = 0; i < savedResults.Length; i++) - { - mixture.ReactionResults[i] = 0; - } - - return ReactionResult.StopReactions; - } - } - // Adventure hyper-noblium effect end - var reaction = ReactionResult.NoReaction; var temperature = mixture.Temperature; var energy = GetThermalEnergy(mixture); @@ -525,6 +525,35 @@ public static void AddMolsToMixture(GasMixture mixture, ReadOnlySpan mols NumericsHelpers.Max(mixture.Moles, 0f); } + // ---- Adventure shim API ---- // + + public float GetThermalEnergy(GasMixture mixture) + => mixture.Temperature * GetHeatCapacity(mixture); + + public float GetThermalEnergy(GasMixture mixture, float cachedHeatCapacity) + => mixture.Temperature * cachedHeatCapacity; + + public void Merge(GasMixture receiver, GasMixture giver) + { + if (receiver.Immutable) + return; + + if (MathF.Abs(receiver.Temperature - giver.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider) + { + var rHC = GetHeatCapacity(receiver); + var gHC = GetHeatCapacity(giver); + var combined = rHC + gHC; + if (combined > Atmospherics.MinimumHeatCapacity) + receiver.Temperature = (GetThermalEnergy(receiver, rHC) + GetThermalEnergy(giver, gHC)) / combined; + } + NumericsHelpers.Add(receiver.Moles, giver.Moles); + } + + public bool IsMixtureIgnitable(GasMixture mixture) + => IsMixtureFuel(mixture) && IsMixtureOxidizer(mixture); + +// ---- End Adventure shim API ---- // + public enum GasCompareResult { NoExchange = -2, diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs index f64212b2e77..67f19b3b0c3 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Content.Server.Atmos.Components; using Content.Server.Decals; using Content.Shared.Atmos; @@ -87,8 +88,7 @@ private void ProcessHotspot( if (tile.Hotspot.Temperature < Atmospherics.FireMinimumTemperatureToExist || tile.Hotspot.Volume <= 1f || tile.Air == null || - tile.Air.GetMoles(Gas.Oxygen) < 0.5f || - tile.Air.GetMoles(Gas.Plasma) < 0.5f && tile.Air.GetMoles(Gas.Tritium) < 0.5f && tile.Air.GetMoles(Gas.Hydrogen) < 0.5f) // Adventure gases + !IsMixtureIgnitable(tile.Air)) { tile.Hotspot = new Hotspot(); InvalidateVisuals(ent, tile); @@ -132,7 +132,7 @@ private void ProcessHotspot( cleanable: true); } - if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread) + if (tile.Air?.Temperature > Atmospherics.FireMinimumTemperatureToSpread) { var radiatedTemperature = tile.Air.Temperature * Atmospherics.FireSpreadRadiosityScale; foreach (var otherTile in tile.AdjacentTiles) @@ -201,20 +201,16 @@ private void HotspotExpose(GridAtmosphereComponent gridAtmosphere, if (tile.Air == null) return; - var oxygen = tile.Air.GetMoles(Gas.Oxygen); - - if (oxygen < 0.5f) + if (!IsMixtureOxidizer(tile.Air)) return; - var plasma = tile.Air.GetMoles(Gas.Plasma); - var tritium = tile.Air.GetMoles(Gas.Tritium); - var hydrogen = tile.Air.GetMoles(Gas.Hydrogen); // Adventure gases + var isFlammable = IsMixtureIgnitable(tile.Air); if (tile.Hotspot.Valid) { if (soh) { - if (plasma > 0.5f || tritium > 0.5f || hydrogen > 0.5f) // Adventure gases + if (isFlammable) { tile.Hotspot.Temperature = MathF.Max(tile.Hotspot.Temperature, exposedTemperature); tile.Hotspot.Volume = MathF.Max(tile.Hotspot.Volume, exposedVolume); @@ -224,13 +220,14 @@ private void HotspotExpose(GridAtmosphereComponent gridAtmosphere, return; } - if (exposedTemperature > Atmospherics.PlasmaMinimumBurnTemperature && (plasma > 0.5f || tritium > 0.5f || hydrogen > 0.5f)) // Adventure gases + if (exposedTemperature > Atmospherics.PlasmaMinimumBurnTemperature && isFlammable) { if (sparkSourceUid.HasValue) { _adminLog.Add(LogType.Flammable, LogImpact.High, - $"Heat/spark of {ToPrettyString(sparkSourceUid.Value)} caused atmos ignition of gas: {tile.Air.Temperature.ToString():temperature}K - {oxygen}mol Oxygen, {plasma}mol Plasma, {tritium}mol Tritium"); + $"Heat/spark of {ToPrettyString(sparkSourceUid.Value)} caused atmos ignition of gas: " + + $"{tile.Air.ToPrettyString()}"); } tile.Hotspot = new Hotspot diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index d562fe51117..69ac9c86eb6 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -68,7 +68,13 @@ private bool ProcessRevalidate(Entity= AtmosMaxProcessTime) return false; @@ -209,6 +214,9 @@ private void UpdateTileData( (tile.Air, tile.Space) = GetDefaultMapAtmosphere(mapAtmos); tile.MapAtmosphere = true; ent.Comp1.MapTiles.Add(tile); + // Adventure edit + UpdateAdjacentTiles(ent, tile, activate: true); + InvalidateVisuals(ent, tile); } DebugTools.AssertNotNull(tile.Air); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs index 9b53d0d16cb..4023315b364 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs @@ -25,7 +25,12 @@ public double GetPrice(GasMixture mixture) float maxComponent = 0; // moles of the dominant gas for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { - basePrice += mixture.Moles[i] * GetGas(i).PricePerMole; + // Adventure edit start - gas price CVar modifiers + var gas = GetGas(i); + var modifier = GetModifier(gas.ID); + basePrice += mixture.Moles[i] * gas.PricePerMole * modifier; + // Adventure edit end + totalMoles += mixture.Moles[i]; maxComponent = Math.Max(maxComponent, mixture.Moles[i]); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index df380912b6c..7ce35d2b700 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -16,6 +16,7 @@ using System.Linq; using Content.Shared.Damage.Systems; using Robust.Shared.Threading; +using System.Diagnostics; namespace Content.Server.Atmos.EntitySystems; @@ -73,6 +74,8 @@ public override void Initialize() SubscribeLocalEvent(OnPrototypesReloaded); CacheDecals(); + + InitADTAtmosCVars(); } public override void Shutdown() @@ -80,6 +83,8 @@ public override void Shutdown() base.Shutdown(); ShutdownCommands(); + + ShutdownADTAtmosCVars(); } private void OnTileChanged(ref TileChangedEvent ev) diff --git a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs index c23f58637d7..386f0e00070 100644 --- a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs +++ b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs @@ -245,8 +245,6 @@ public override void Update(float frameTime) barotrauma.TakingDamage = true; _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking low pressure damage"); } - - _alertsSystem.ShowAlert(uid, barotrauma.LowPressureAlert, 2); } else if (pressure >= Atmospherics.HazardHighPressure) { @@ -260,8 +258,6 @@ public override void Update(float frameTime) barotrauma.TakingDamage = true; _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking high pressure damage"); } - - _alertsSystem.ShowAlert(uid, barotrauma.HighPressureAlert, 2); } else { diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index bd05a2c9ec1..e3af9775e99 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -24,6 +24,7 @@ using Content.Shared.FixedPoint; using Content.Shared.Hands; using Content.Shared.Temperature.Components; +using Content.Shared.Weapons.Ranged.Events; using Robust.Server.Audio; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -433,14 +434,6 @@ public override void Update(float frameTime) flammable.FireStacks = MathF.Min(0, flammable.FireStacks + 1); } - if (!flammable.OnFire) - { - _alertsSystem.ClearAlert(uid, flammable.FireAlert); - continue; - } - - _alertsSystem.ShowAlert(uid, flammable.FireAlert); - if (flammable.FireStacks > 0) { var air = _atmosphereSystem.GetContainingMixture(uid); diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index 3cbe6575bf2..2a3ee3dc773 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -1,12 +1,10 @@ using System.Linq; using Content.Server.Atmos.Components; -using Content.Server.NodeContainer; using Content.Server.NodeContainer.Nodes; using Content.Server.Popups; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; using Content.Shared.NodeContainer; using JetBrains.Annotations; using Robust.Server.GameObjects; @@ -65,7 +63,7 @@ public override void Update(float frameTime) private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { var target = args.Target; - if (target != null && !_interactionSystem.InRangeUnobstructed((args.User, null), (target.Value, null))) + if (target != null && !_interactionSystem.InRangeUnobstructed(args.User, target.Value)) // Adventure edit { target = null; // if the target is out of reach, invalidate it } @@ -146,7 +144,7 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul // Listen! Even if you don't want the Gas Analyzer to work on moving targets, you should use // this code to determine if the object is still generally in range so that the check is consistent with the code // in OnAfterInteract() and also consistent with interaction code in general. - if (!_interactionSystem.InRangeUnobstructed((component.User, null), (component.Target.Value, null))) + if (component.User == null || !_interactionSystem.InRangeUnobstructed(component.User.Value, component.Target.Value)) { if (component.User is { } userId && component.Enabled) _popup.PopupEntity(Loc.GetString("gas-analyzer-object-out-of-range"), userId, userId); @@ -159,16 +157,8 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul // Fetch the environmental atmosphere around the scanner. This must be the first entry var tileMixture = _atmo.GetContainingMixture(uid, true); - if (tileMixture != null) - { - gasMixList.Add(new GasMixEntry(Loc.GetString("gas-analyzer-window-environment-tab-label"), tileMixture.Volume, tileMixture.Pressure, tileMixture.Temperature, - GenerateGasEntryArray(tileMixture))); - } - else - { - // No gases were found - gasMixList.Add(new GasMixEntry(Loc.GetString("gas-analyzer-window-environment-tab-label"), 0f, 0f, 0f)); - } + var tileMixtureName = Loc.GetString("gas-analyzer-window-environment-tab-label"); + gasMixList.Add(GenerateGasMixEntry(tileMixtureName, tileMixture)); var deviceFlipped = false; if (component.Target != null) @@ -192,7 +182,7 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul { if (mixes.Item2 != null) { - gasMixList.Add(new GasMixEntry(mixes.Item1, mixes.Item2.Volume, mixes.Item2.Pressure, mixes.Item2.Temperature, GenerateGasEntryArray(mixes.Item2))); + gasMixList.Add(GenerateGasMixEntry(mixes.Item1, mixes.Item2)); validTarget = true; } } @@ -215,7 +205,7 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul var pipeAir = pipeNode.Air.Clone(); pipeAir.Multiply(pipeNode.Volume / pipeNode.Air.Volume); pipeAir.Volume = pipeNode.Volume; - gasMixList.Add(new GasMixEntry(pair.Key, pipeAir.Volume, pipeAir.Pressure, pipeAir.Temperature, GenerateGasEntryArray(pipeAir))); + gasMixList.Add(GenerateGasMixEntry(pair.Key, pipeAir)); validTarget = true; } } @@ -242,6 +232,23 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul return true; } + /// + /// Generates a GasMixEntry for a given GasMixture + /// + public GasMixEntry GenerateGasMixEntry(string name, GasMixture? mixture) + { + if (mixture == null) + return new GasMixEntry(name, 0, 0, 0); + + return new GasMixEntry( + name, + mixture.Volume, + mixture.Pressure, + mixture.Temperature, + GenerateGasEntryArray(mixture) + ); + } + /// /// Generates a GasEntry array for a given GasMixture /// @@ -259,7 +266,7 @@ private GasEntry[] GenerateGasEntryArray(GasMixture? mixture) if (mixture != null) { var gasName = Loc.GetString(gas.Name); - gases.Add(new GasEntry(gasName, mixture[i], gas.Color)); + gases.Add(new GasEntry((Gas)i, mixture[i])); } } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index 4882e93d230..97f9036bb32 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -1,6 +1,3 @@ -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; using Content.Server.Atmos.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; @@ -15,24 +12,29 @@ using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.Enums; +using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Threading; using Robust.Shared.Timing; using Robust.Shared.Utility; +using System.Runtime.CompilerServices; // ReSharper disable once RedundantUsingDirective namespace Content.Server.Atmos.EntitySystems { + [UsedImplicitly] public sealed class GasTileOverlaySystem : SharedGasTileOverlaySystem { + [Robust.Shared.IoC.Dependency] private readonly IConfigurationManager _cfg = default!; + private int _thermalDirtyThreshold = 1; + [Robust.Shared.IoC.Dependency] private readonly IGameTiming _gameTiming = default!; [Robust.Shared.IoC.Dependency] private readonly IPlayerManager _playerManager = default!; [Robust.Shared.IoC.Dependency] private readonly IMapManager _mapManager = default!; - [Robust.Shared.IoC.Dependency] private readonly IConfigurationManager _confMan = default!; [Robust.Shared.IoC.Dependency] private readonly IParallelManager _parMan = default!; [Robust.Shared.IoC.Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Robust.Shared.IoC.Dependency] private readonly ChunkingSystem _chunkingSys = default!; @@ -85,9 +87,8 @@ public override void Initialize() }; _playerManager.PlayerStatusChanged += OnPlayerStatusChanged; - Subs.CVar(_confMan, CCVars.NetGasOverlayTickRate, UpdateTickRate, true); - Subs.CVar(_confMan, CCVars.GasOverlayThresholds, UpdateThresholds, true); - Subs.CVar(_confMan, CVars.NetPVS, OnPvsToggle, true); + + InitializeCVars(); SubscribeLocalEvent(Reset); SubscribeLocalEvent(OnStartup); @@ -175,7 +176,16 @@ private byte GetOpacity(float moles, float molesVisible, float molesVisibleMax) public GasOverlayData GetOverlayData(GasMixture? mixture) { - var data = new GasOverlayData(0, new byte[VisibleGasId.Length]); + ThermalByte byteTemp; + if (mixture == null) + { + byteTemp = new(); + byteTemp.SetVacuum(); + } + else + byteTemp = new(mixture.Temperature); + + var data = new GasOverlayData(0, new byte[VisibleGasId.Length], byteTemp); for (var i = 0; i < VisibleGasId.Length; i++) { @@ -215,15 +225,29 @@ private bool UpdateChunkTile(GridAtmosphereComponent gridAtmosphere, GasOverlayC } var changed = false; + + ThermalByte newByteTemp = new(); + + if (tile.Hotspot.Valid) + newByteTemp.SetTemperature(tile.Hotspot.Temperature); + else if (!tile.Space && tile.Air?.TotalMoles <= 5f) + newByteTemp.SetVacuum(); + else if (!tile.Space && tile.Air != null) + newByteTemp = new(tile.Air.Temperature); + if (oldData.Equals(default)) { changed = true; - oldData = new GasOverlayData(tile.Hotspot.State, new byte[VisibleGasId.Length]); + oldData = new GasOverlayData(tile.Hotspot.State, new byte[VisibleGasId.Length], newByteTemp); } - else if (oldData.FireState != tile.Hotspot.State) + else if ( + oldData.FireState != tile.Hotspot.State || + Math.Abs(newByteTemp.Value - oldData.ByteGasTemperature.Value) > _thermalDirtyThreshold || + (oldData.ByteGasTemperature.Value != newByteTemp.Value && + newByteTemp.Value > ThermalByte.TempResolution)) { changed = true; - oldData = new GasOverlayData(tile.Hotspot.State, oldData.Opacity); + oldData = new GasOverlayData(tile.Hotspot.State, oldData.Opacity, newByteTemp); } if (tile is {Air: not null, NoGridTile: false}) @@ -465,5 +489,13 @@ public void Execute(int index) } #endregion + + private void InitializeCVars() + { + Subs.CVar(ConfMan, CCVars.NetGasOverlayTickRate, UpdateTickRate, true); + Subs.CVar(ConfMan, CCVars.GasOverlayThresholds, UpdateThresholds, true); + Subs.CVar(ConfMan, CVars.NetPVS, OnPvsToggle, true); + Subs.CVar(_cfg, CCVars.GasOverlayThermalDirtyThreshold, v => _thermalDirtyThreshold = v, true); // Adventure-edit + } } } diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs index a9aa40611dc..af180c5386c 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs +++ b/Content.Server/Atmos/Piping/Unary/Components/GasVentPumpComponent.cs @@ -79,6 +79,11 @@ public sealed partial class GasVentPumpComponent : Component /// public float ManualLockoutDisableDoAfter = 2.0f; + // Sunrtise-Start + [DataField] + public float PressureLimit { get; set; } = 300; + // Sunrtise-End + [DataField] public float ExternalPressureBound { diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs index 4a9437bc1fc..f22f3057b9c 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs +++ b/Content.Server/Atmos/Piping/Unary/Components/GasVentScrubberComponent.cs @@ -23,7 +23,7 @@ public sealed partial class GasVentScrubberComponent : Component public string OutletName { get; set; } = "pipe"; [DataField] - public HashSet FilterGases = new(GasVentScrubberData.DefaultFilterGases); + public HashSet FilterGases = [..GasVentScrubberData._defaultFilterGases]; [DataField] public ScrubberPumpDirection PumpDirection { get; set; } = ScrubberPumpDirection.Scrubbing; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs index 1066e4e88d3..861ec87a0d6 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs @@ -92,6 +92,24 @@ private void OnGasVentPumpUpdated(EntityUid uid, GasVentPumpComponent vent, ref { return; } + + // Adventure-Start + if (pipe.Air.Pressure > vent.PressureLimit) + { + // Release all gas like a passive vent + var inletAir = pipe.Air.RemoveRatio(1f); + var envAir = environment.RemoveRatio(1f); + + var mergeAir = new GasMixture(inletAir.Volume + envAir.Volume); + _atmosphereSystem.Merge(mergeAir, inletAir); + _atmosphereSystem.Merge(mergeAir, envAir); + + _atmosphereSystem.Merge(pipe.Air, mergeAir.RemoveVolume(inletAir.Volume)); + _atmosphereSystem.Merge(environment, mergeAir); + return; + } + // Adventure-End + // If the lockout has expired, disable it. if (vent.IsPressureLockoutManuallyDisabled && _timing.CurTime >= vent.ManualLockoutReenabledAt) { diff --git a/Content.Server/Atmos/Portable/PortableScrubberComponent.cs b/Content.Server/Atmos/Portable/PortableScrubberComponent.cs index a295929aa2f..ea67667c46a 100644 --- a/Content.Server/Atmos/Portable/PortableScrubberComponent.cs +++ b/Content.Server/Atmos/Portable/PortableScrubberComponent.cs @@ -30,19 +30,17 @@ public sealed partial class PortableScrubberComponent : Component Gas.Ammonia, Gas.NitrousOxide, Gas.Frezon, - // Adventure gases begin Gas.BZ, - Gas.Halon, - Gas.Healium, - Gas.HyperNoblium, - Gas.Hydrogen, Gas.Pluoxium, + Gas.Hydrogen, Gas.Nitrium, + Gas.Healium, + Gas.HyperNoblium, + Gas.ProtoNitrate, + Gas.Zauker, + Gas.Halon, Gas.Helium, Gas.AntiNoblium, - Gas.ProtoNitrate, - Gas.Zauker - // Adventure gases end }; [ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs index 475c149cf37..e4757b04cfe 100644 --- a/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs +++ b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs @@ -1,4 +1,4 @@ -using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; @@ -13,6 +13,11 @@ public sealed partial class FrezonCoolantReaction : IGasReactionEffect { public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) { + ///Adventure start + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + ///Adventure end var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); var temperature = mixture.Temperature; diff --git a/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs b/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs index e3d3ece6b6a..08d688f21aa 100644 --- a/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs +++ b/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs @@ -1,4 +1,4 @@ -using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; @@ -14,6 +14,11 @@ public sealed partial class FrezonProductionReaction : IGasReactionEffect { public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) { + ///Adventure start + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + ///Adventure end var initialN2 = mixture.GetMoles(Gas.Nitrogen); var initialOxy = mixture.GetMoles(Gas.Oxygen); var initialTrit = mixture.GetMoles(Gas.Tritium); diff --git a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs index 85802dc9575..dc7ba85dcc3 100644 --- a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs +++ b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs @@ -36,15 +36,6 @@ public sealed partial class GasReactionPrototype : IPrototype [DataField("minimumEnergy")] public float MinimumEnergyRequirement { get; private set; } = 0f; - /// Adventure gases start - /// - /// Maximum pressure requirement for the reaction to occur. - /// Defaults to unlimited pressure. - /// - [DataField("maximumPressure")] - public float MaximumPressureRequirement { get; private set; } = float.MaxValue; - /// Adventure gases end - /// /// Lower numbers are checked/react later than higher numbers. /// If two reactions have the same priority, they may happen in either order. @@ -66,11 +57,6 @@ public sealed partial class GasReactionPrototype : IPrototype /// Scaling factor that should be applied to all heat input or outputs. public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) { - // Adventure gases begin - // Проверка максимального давления - if (mixture.Pressure > MaximumPressureRequirement) - return ReactionResult.NoReaction; - // Adventure gases end var result = ReactionResult.NoReaction; foreach (var effect in _effects) diff --git a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs index b214310da12..f273bad1cfc 100644 --- a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs +++ b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs @@ -11,6 +11,11 @@ public sealed partial class PlasmaFireReaction : IGasReactionEffect { public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) { + //Adventure start + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + //Adventure end var energyReleased = 0f; var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); var temperature = mixture.Temperature; diff --git a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs index 8b7d4e4872e..7eecde30cb4 100644 --- a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs +++ b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs @@ -11,6 +11,11 @@ public sealed partial class TritiumFireReaction : IGasReactionEffect { public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) { + //Adventure start + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + //Adventure end var energyReleased = 0f; var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); var temperature = mixture.Temperature; diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs index eba0df192a5..5d63a243d13 100644 --- a/Content.Server/Atmos/TileAtmosphere.cs +++ b/Content.Server/Atmos/TileAtmosphere.cs @@ -10,7 +10,7 @@ namespace Content.Server.Atmos; /// Use the public APIs in instead. /// [Access(typeof(AtmosphereSystem), typeof(GasTileOverlaySystem), typeof(AtmosDebugOverlaySystem))] -public sealed class TileAtmosphere : IGasMixtureHolder +public sealed partial class TileAtmosphere : IGasMixtureHolder // Adventure-edit { /// /// The last cycle this tile's air was archived into . @@ -245,4 +245,31 @@ public TileAtmosphere(TileAtmosphere other) public TileAtmosphere() { } + + // Adventure-Start + public void Reset() + { + Air = null; + AirArchived = null; + Array.Clear(AdjacentTiles, 0, AdjacentTiles.Length); + ExcitedGroup = null; + Hotspot = default; + GridIndex = EntityUid.Invalid; + GridIndices = default; + MapAtmosphere = false; + Space = false; + ArchivedCycle = 0; + LastShare = 0f; + MonstermosInfo = default; + CurrentCycle = 0; + Excited = false; + PressureDifference = 0f; + PressureDirection = AtmosDirection.Invalid; + PressureSpecificTarget = null; + MaxFireTemperatureSustained = 0f; + Temperature = 0f; + HeatCapacity = 0f; + AirtightData = default; + } + // Adventure-End } diff --git a/Content.Server/_Adventure/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/_Adventure/Atmos/Components/GridAtmosphereComponent.cs new file mode 100644 index 00000000000..ce93c7dc9dc --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Components/GridAtmosphereComponent.cs @@ -0,0 +1,6 @@ +namespace Content.Server.Atmos.Components +{ + public sealed partial class GridAtmosphereComponent + { + } +} diff --git a/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.CCVars.cs b/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.CCVars.cs new file mode 100644 index 00000000000..1e9de476236 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.CCVars.cs @@ -0,0 +1,57 @@ +using Content.Shared._Adventure.ADTCCVars; +using Robust.Shared.Configuration; + +namespace Content.Server.Atmos.EntitySystems; + +public enum GasIds +{ + Tritium, + NitrousOxide, + Frezon, + BZ, + Healium, + Nitrium +} + +public partial class AtmosphereSystem +{ + private float _defaultGasPriceModifier; + private float _gasPriceModifierTritium; + private float _gasPriceModifierNitrousOxide; + private float _gasPriceModifierFrezon; + + private IDisposable? _configSub; + + public void InitADTAtmosCVars() + { + if (_configSub is not null) + { + return; + } + + _configSub = _cfg.SubscribeMultiple() + .OnValueChanged(ADTCCVars.DefaultGasPriceModifier, (value) => _defaultGasPriceModifier = value, true) + .OnValueChanged(ADTCCVars.GasPriceModifierTritium, (value) => _gasPriceModifierTritium = value, true) + .OnValueChanged(ADTCCVars.GasPriceModifierNitrousOxide, (value) => _gasPriceModifierNitrousOxide = value, true) + .OnValueChanged(ADTCCVars.GasPriceModifierFrezon, (value) => _gasPriceModifierFrezon = value, true); + } + + public float GetModifier(string id) + { + if (!Enum.TryParse(id, out var gasId)) + return _defaultGasPriceModifier; + + return gasId switch + { + GasIds.Tritium => _gasPriceModifierTritium, + GasIds.NitrousOxide => _gasPriceModifierNitrousOxide, + GasIds.Frezon => _gasPriceModifierFrezon, + _ => _defaultGasPriceModifier, + }; + } + + private void ShutdownADTAtmosCVars() + { + _configSub?.Dispose(); + } +} diff --git a/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.Processing.cs new file mode 100644 index 00000000000..7ebfd63321f --- /dev/null +++ b/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -0,0 +1,10 @@ +using Content.Server.Atmos.Components; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Components; +using Robust.Shared.Map.Components; + +namespace Content.Server.Atmos.EntitySystems; + +public sealed partial class AtmosphereSystem +{ +} diff --git a/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.cs new file mode 100644 index 00000000000..b0586654046 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/EntitySystems/AtmosphereSystem.cs @@ -0,0 +1,19 @@ +using Content.Server.Atmos.Components; +using Content.Server.Electrocution; +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Shared.Mobs.Components; +using Content.Shared.Power.Components; +using Content.Shared.Power.EntitySystems; + +namespace Content.Server.Atmos.EntitySystems; + +public sealed partial class AtmosphereSystem +{ + [Dependency] private readonly ElectrocutionSystem _electrocution = default!; + [Dependency] private readonly BatterySystem _battery = default!; + + private EntityQuery _powerReceiverQuery; + private EntityQuery _mobQuery; + private EntityQuery _batteryQuery; +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/BZProductionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/BZProductionReaction.cs new file mode 100644 index 00000000000..3838e9f4d2b --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/BZProductionReaction.cs @@ -0,0 +1,51 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class BZProductionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialNitrousOxide = mixture.GetMoles(Gas.NitrousOxide); + var initialPlasma = mixture.GetMoles(Gas.Plasma); + + var environmentEfficiency = mixture.Volume / mixture.Pressure; + var ratioEfficiency = Math.Min(initialNitrousOxide / initialPlasma, 1); + + var BZFormed = Math.Min(0.01f * ratioEfficiency * environmentEfficiency, Math.Min(initialNitrousOxide * 0.4f, initialPlasma * 0.8f)); + + if (initialNitrousOxide - BZFormed * 0.4f < 0 || initialPlasma - (0.8f - BZFormed) < 0 || BZFormed <= 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + var amountDecomposed = 0.0f; + var nitrousOxideDecomposedFactor = Math.Max(4.0f * (initialPlasma / (initialNitrousOxide + initialPlasma) - 0.75f), 0); + if (nitrousOxideDecomposedFactor > 0) + { + amountDecomposed = 0.4f * BZFormed * nitrousOxideDecomposedFactor; + mixture.AdjustMoles(Gas.Oxygen, amountDecomposed); + mixture.AdjustMoles(Gas.Nitrogen, 0.5f * amountDecomposed); + } + + mixture.AdjustMoles(Gas.BZ, Math.Max(0f, BZFormed * (1.0f - nitrousOxideDecomposedFactor))); + mixture.AdjustMoles(Gas.NitrousOxide, -0.4f * BZFormed); + mixture.AdjustMoles(Gas.Plasma, -0.8f * BZFormed * (1.0f - nitrousOxideDecomposedFactor)); + + var energyReleased = BZFormed * (Atmospherics.BZFormationEnergy + nitrousOxideDecomposedFactor * (Atmospherics.NitrousOxideDecompositionEnergy - Atmospherics.BZFormationEnergy)); + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/HalonOxygenAbsorptionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/HalonOxygenAbsorptionReaction.cs new file mode 100644 index 00000000000..624cf1963b9 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/HalonOxygenAbsorptionReaction.cs @@ -0,0 +1,39 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class HalonOxygenAbsorptionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialHalon = mixture.GetMoles(Gas.Halon); + var initialOxygen = mixture.GetMoles(Gas.Oxygen); + + var temperature = mixture.Temperature; + + var heatEfficiency = Math.Min(temperature / (Atmospherics.FireMinimumTemperatureToExist * 10f), Math.Min(initialHalon, initialOxygen * 20f)); + if (heatEfficiency <= 0f || initialHalon - heatEfficiency < 0f || initialOxygen - heatEfficiency * 20f < 0f) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.Halon, -heatEfficiency); + mixture.AdjustMoles(Gas.Oxygen, -heatEfficiency * 20f); + mixture.AdjustMoles(Gas.CarbonDioxide, heatEfficiency * 5f); + + var energyUsed = heatEfficiency * Atmospherics.HalonCombustionEnergy; + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyUsed) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/HealiumProductionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/HealiumProductionReaction.cs new file mode 100644 index 00000000000..64be7a35333 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/HealiumProductionReaction.cs @@ -0,0 +1,40 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class HealiumProductionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialBZ = mixture.GetMoles(Gas.BZ); + var initialFrezon = mixture.GetMoles(Gas.Frezon); + + var temperature = mixture.Temperature; + var heatEfficiency = Math.Min(temperature * 0.3f, Math.Min(initialFrezon * 2.75f, initialBZ * 0.25f)); + + if (heatEfficiency <= 0 || initialFrezon - heatEfficiency * 2.75f < 0 || initialBZ - heatEfficiency * 0.25f < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.Frezon, -heatEfficiency * 2.75f); + mixture.AdjustMoles(Gas.BZ, -heatEfficiency * 0.25f); + mixture.AdjustMoles(Gas.Healium, heatEfficiency * 3); + + var energyReleased = heatEfficiency * Atmospherics.HealiumFormationEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/HydrogenFireReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/HydrogenFireReaction.cs new file mode 100644 index 00000000000..6e7c6532646 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/HydrogenFireReaction.cs @@ -0,0 +1,59 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions +{ + [UsedImplicitly] + [DataDefinition] + public sealed partial class HydrogenFireReaction : IGasReactionEffect + { + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var energyReleased = 0f; + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + var temperature = mixture.Temperature; + var location = holder as TileAtmosphere; + mixture.ReactionResults[(byte)GasReaction.Fire] = 0; + + var initialOxygen = mixture.GetMoles(Gas.Oxygen); + var initialHydrogen = mixture.GetMoles(Gas.Hydrogen); + + var burnedFuel = Math.Min(initialHydrogen / Atmospherics.FireH2BurnRateDelta, Math.Min(initialOxygen / (Atmospherics.FireH2BurnRateDelta * Atmospherics.H2OxygenFullBurn), Math.Min(initialHydrogen, initialOxygen * 0.5f))); + + if (burnedFuel > 0) + { + energyReleased += Atmospherics.FireH2EnergyReleased * burnedFuel; + + mixture.AdjustMoles(Gas.WaterVapor, burnedFuel); + mixture.AdjustMoles(Gas.Hydrogen, -burnedFuel); + mixture.AdjustMoles(Gas.Oxygen, -burnedFuel * 0.5f); + + mixture.ReactionResults[(byte)GasReaction.Fire] += burnedFuel; + } + + 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, temperature, mixture.Volume); + } + } + + return mixture.ReactionResults[(byte)GasReaction.Fire] != 0 ? ReactionResult.Reacting : ReactionResult.NoReaction; + } + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/HyperNobliumProductionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/HyperNobliumProductionReaction.cs new file mode 100644 index 00000000000..441bb8453bf --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/HyperNobliumProductionReaction.cs @@ -0,0 +1,41 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class HyperNobliumProductionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialNitrogen = mixture.GetMoles(Gas.Nitrogen); + var initialTritium = mixture.GetMoles(Gas.Tritium); + var initialBZ = mixture.GetMoles(Gas.BZ); + + var nobFormed = Math.Min((initialNitrogen + initialTritium) * 0.01f, Math.Min(initialTritium * 5f, initialNitrogen * 10f)); + if (nobFormed <= 0 || (initialTritium - 5f) * nobFormed < 0 || (initialNitrogen - 10f) * nobFormed < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + var reductionFactor = Math.Clamp(initialTritium / (initialTritium + initialBZ), 0.001f, 1f); + + mixture.AdjustMoles(Gas.Tritium, -5f * nobFormed * reductionFactor); + mixture.AdjustMoles(Gas.Nitrogen, -10f * nobFormed); + mixture.AdjustMoles(Gas.HyperNoblium, nobFormed); + + var energyReleased = nobFormed * (Atmospherics.NobliumFormationEnergy / Math.Max(initialBZ, 1)); + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/NitriumDecompositionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/NitriumDecompositionReaction.cs new file mode 100644 index 00000000000..540bb2671c0 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/NitriumDecompositionReaction.cs @@ -0,0 +1,39 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class NitriumDecompositionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialNitrium = mixture.GetMoles(Gas.Nitrium); + + var temperature = mixture.Temperature; + var heatEfficiency = Math.Min(temperature / Atmospherics.NitriumDecompositionTempDivisor, initialNitrium); + + if (heatEfficiency <= 0 || initialNitrium - heatEfficiency < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.Nitrium, -heatEfficiency); + mixture.AdjustMoles(Gas.Hydrogen, heatEfficiency); + mixture.AdjustMoles(Gas.Nitrogen, heatEfficiency); + + var energyReleased = heatEfficiency * Atmospherics.NitriumDecompositionEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/NitriumProductionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/NitriumProductionReaction.cs new file mode 100644 index 00000000000..96519be6660 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/NitriumProductionReaction.cs @@ -0,0 +1,41 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class NitriumProductionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialTritium = mixture.GetMoles(Gas.Tritium); + var initialNitrogen = mixture.GetMoles(Gas.Nitrogen); + var initialBZ = mixture.GetMoles(Gas.BZ); + + var temperature = mixture.Temperature; + var heatEfficiency = Math.Min(temperature / Atmospherics.NitriumFormationTempDivisor, Math.Min(initialTritium, Math.Min(initialNitrogen, initialBZ * 0.05f))); + + if (heatEfficiency <= 0 || initialTritium - heatEfficiency < 0 || initialNitrogen - heatEfficiency < 0 || initialBZ - heatEfficiency * 0.05f < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + mixture.AdjustMoles(Gas.Tritium, -heatEfficiency); + mixture.AdjustMoles(Gas.Nitrogen, -heatEfficiency); + mixture.AdjustMoles(Gas.BZ, -heatEfficiency * 0.05f); + mixture.AdjustMoles(Gas.Nitrium, heatEfficiency); + + var energyUsed = heatEfficiency * Atmospherics.NitriumFormationEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity - energyUsed) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/PluoxiumProductionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/PluoxiumProductionReaction.cs new file mode 100644 index 00000000000..4c02418a208 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/PluoxiumProductionReaction.cs @@ -0,0 +1,41 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class PluoxiumProductionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialCarbonDioxide = mixture.GetMoles(Gas.CarbonDioxide); + var initialOxygen = mixture.GetMoles(Gas.Oxygen); + var initialTritium = mixture.GetMoles(Gas.Tritium); + + var producedAmount = Math.Min(Atmospherics.PluoxiumMaxRate, Math.Min(initialCarbonDioxide, Math.Min(initialOxygen * 0.5f, initialTritium * 0.01f))); + + if (producedAmount <= 0 || initialCarbonDioxide - producedAmount < 0 || initialOxygen - producedAmount * 0.5f < 0 || initialTritium - producedAmount * 0.01f < 0) + return ReactionResult.NoReaction; + + mixture.AdjustMoles(Gas.CarbonDioxide, -producedAmount); + mixture.AdjustMoles(Gas.Oxygen, -producedAmount * 0.5f); + mixture.AdjustMoles(Gas.Tritium, -producedAmount * 0.01f); + mixture.AdjustMoles(Gas.Pluoxium, producedAmount); + mixture.AdjustMoles(Gas.Hydrogen, producedAmount * 0.01f); + + var energyReleased = producedAmount * Atmospherics.PluoxiumFormationEnergy; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateBZaseConversionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateBZaseConversionReaction.cs new file mode 100644 index 00000000000..8d89f1965f9 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateBZaseConversionReaction.cs @@ -0,0 +1,41 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class ProtoNitrateBZaseConversionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialProtoNitrate = mixture.GetMoles(Gas.ProtoNitrate); + var initialBZ = mixture.GetMoles(Gas.BZ); + + var temperature = mixture.Temperature; + var consumedAmount = Math.Min(temperature / 2240f * initialBZ * initialProtoNitrate / (initialBZ + initialProtoNitrate), Math.Min(initialBZ, initialProtoNitrate)); + + if (consumedAmount <= 0 || initialBZ - consumedAmount < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.BZ, -consumedAmount); + mixture.AdjustMoles(Gas.Nitrogen, consumedAmount * 0.4f); + mixture.AdjustMoles(Gas.Helium, consumedAmount * 1.6f); + mixture.AdjustMoles(Gas.Plasma, consumedAmount * 0.8f); + + var energyReleased = consumedAmount * Atmospherics.ProtoNitrateBZaseConversionEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateHydrogenConversionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateHydrogenConversionReaction.cs new file mode 100644 index 00000000000..bd01cd6ca14 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateHydrogenConversionReaction.cs @@ -0,0 +1,38 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class ProtoNitrateHydrogenConversionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialProtoNitrate = mixture.GetMoles(Gas.ProtoNitrate); + var initialHydrogen = mixture.GetMoles(Gas.Hydrogen); + + var producedAmount = Math.Min(Atmospherics.ProtoNitrateHydrogenConversionMaxRate, Math.Min(initialHydrogen, initialProtoNitrate)); + + if (producedAmount <= 0 || initialHydrogen-producedAmount < 0f) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.Hydrogen, -producedAmount); + mixture.AdjustMoles(Gas.ProtoNitrate, producedAmount * 0.5f); + + var energyUsed = producedAmount * Atmospherics.ProtoNitrateHydrogenConversionEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity - energyUsed) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateProductionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateProductionReaction.cs new file mode 100644 index 00000000000..43c9b49eca4 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateProductionReaction.cs @@ -0,0 +1,40 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class ProtoNitrateProductionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialPluoxium = mixture.GetMoles(Gas.Pluoxium); + var initialHydrogen = mixture.GetMoles(Gas.Hydrogen); + + var temperature = mixture.Temperature; + var heatEfficiency = Math.Min(temperature * 0.005f, Math.Min(initialPluoxium * 0.2f, initialHydrogen * 2.0f)); + + if (heatEfficiency <= 0 || initialPluoxium - heatEfficiency * 0.2f < 0 || initialHydrogen - heatEfficiency * 2f < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.Hydrogen, -heatEfficiency * 2f); + mixture.AdjustMoles(Gas.Pluoxium, -heatEfficiency * 0.2f); + mixture.AdjustMoles(Gas.ProtoNitrate, heatEfficiency * 0.2f); + + var energyReleased = heatEfficiency * Atmospherics.ProtoNitrateFormationEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateTritiumConversionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateTritiumConversionReaction.cs new file mode 100644 index 00000000000..3f873b8a1d2 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/ProtoNitrateTritiumConversionReaction.cs @@ -0,0 +1,40 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class ProtoNitrateTritiumConversionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialProtoNitrate = mixture.GetMoles(Gas.ProtoNitrate); + var initialTritium = mixture.GetMoles(Gas.Tritium); + + var temperature = mixture.Temperature; + var producedAmount = Math.Min(temperature / 34f * initialTritium * initialProtoNitrate/ (initialTritium + 10f * initialProtoNitrate), Math.Min(initialTritium, initialProtoNitrate * 0.01f)); + + if (initialTritium - producedAmount < 0 || initialProtoNitrate - producedAmount * 0.01f < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.ProtoNitrate, -producedAmount * 0.01f); + mixture.AdjustMoles(Gas.Tritium, -producedAmount); + mixture.AdjustMoles(Gas.Hydrogen, producedAmount); + + var energyReleased = producedAmount * Atmospherics.ProtoNitrateTritiumConversionEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/ZaukerDecompositionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/ZaukerDecompositionReaction.cs new file mode 100644 index 00000000000..5f93393419d --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/ZaukerDecompositionReaction.cs @@ -0,0 +1,39 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class ZaukerDecompositionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialZauker = mixture.GetMoles(Gas.Zauker); + var initialNitrogen = mixture.GetMoles(Gas.Nitrogen); + + var burnedFuel = Math.Min(Atmospherics.ZaukerDecompositionMaxRate, Math.Min(initialNitrogen, initialZauker)); + + if (burnedFuel <= 0 || initialZauker - burnedFuel < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.Zauker, -burnedFuel); + mixture.AdjustMoles(Gas.Oxygen, burnedFuel * 0.3f); + mixture.AdjustMoles(Gas.Nitrogen, burnedFuel * 0.7f); + + var energyReleased = burnedFuel * Atmospherics.ZaukerDecompositionEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/Reactions/ZaukerProductionReaction.cs b/Content.Server/_Adventure/Atmos/Reactions/ZaukerProductionReaction.cs new file mode 100644 index 00000000000..c1e101bcb15 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/Reactions/ZaukerProductionReaction.cs @@ -0,0 +1,40 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; + +namespace Content.Server.Atmos.Reactions; + +[UsedImplicitly] +public sealed partial class ZaukerProductionReaction : IGasReactionEffect +{ + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) + { + var initialHyperNoblium = mixture.GetMoles(Gas.HyperNoblium); + if (initialHyperNoblium >= 5.0f && mixture.Temperature > 20f) + return ReactionResult.NoReaction; + + var initialHypernoblium = mixture.GetMoles(Gas.HyperNoblium); + var initialNitrium = mixture.GetMoles(Gas.Nitrium); + + var temperature = mixture.Temperature; + var heatEfficiency = Math.Min(temperature * Atmospherics.ZaukerFormationTemperatureScale, Math.Min(initialHypernoblium * 0.01f, initialNitrium * 0.5f)); + + if (heatEfficiency <= 0 || initialHypernoblium - heatEfficiency * 0.01f < 0 || initialNitrium - heatEfficiency * 0.5f < 0) + return ReactionResult.NoReaction; + + var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + + mixture.AdjustMoles(Gas.HyperNoblium, -heatEfficiency * 0.01f); + mixture.AdjustMoles(Gas.Nitrium, -heatEfficiency * 0.5f); + mixture.AdjustMoles(Gas.Zauker, heatEfficiency * 0.5f); + + var energyUsed = heatEfficiency * Atmospherics.ZaukerFormationEnergy; + + var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); + if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) + mixture.Temperature = Math.Max((mixture.Temperature * oldHeatCapacity - energyUsed) / newHeatCapacity, Atmospherics.TCMB); + + return ReactionResult.Reacting; + } +} diff --git a/Content.Server/_Adventure/Atmos/TileAtmosphere.cs b/Content.Server/_Adventure/Atmos/TileAtmosphere.cs new file mode 100644 index 00000000000..bb26f89f379 --- /dev/null +++ b/Content.Server/_Adventure/Atmos/TileAtmosphere.cs @@ -0,0 +1,4 @@ +namespace Content.Server.Atmos; +public sealed partial class TileAtmosphere +{ +} diff --git a/Content.Server/_Adventure/Atmospherics/BZProductionReaction.cs b/Content.Server/_Adventure/Atmospherics/BZProductionReaction.cs deleted file mode 100644 index e111589f700..00000000000 --- a/Content.Server/_Adventure/Atmospherics/BZProductionReaction.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Синтез БЗ из плазмы и оксида азота. -/// Имеется лимит по давлению, если превышает 40КПа, реакция прекращается. -/// -[UsedImplicitly] -public sealed partial class BZProductionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Pressure > Atmospherics.BZSynthesisMaxPressure) - { - return ReactionResult.NoReaction; - } - var initialPlasma = mixture.GetMoles(Gas.Plasma); - var initialN20 = mixture.GetMoles(Gas.NitrousOxide); - - if (initialPlasma <= 0 || initialN20 <= 0) - return ReactionResult.NoReaction; - - var plasmaLimit = initialPlasma / Atmospherics.BZPlasmaRatio; - var n20Limit = initialN20 / Atmospherics.BZN20Ratio; - var limitingFactor = Math.Min(plasmaLimit, n20Limit); - - if (limitingFactor <= 0) - return ReactionResult.NoReaction; - - limitingFactor = Math.Min(limitingFactor, Atmospherics.BZSynthesisMaxRate); - - var plasmaBurned = limitingFactor * Atmospherics.BZPlasmaRatio; - var n20Burned = limitingFactor * Atmospherics.BZN20Ratio; - var bzProduced = (plasmaBurned + n20Burned) * Atmospherics.BZSynthesisEfficiency; - - mixture.AdjustMoles(Gas.Plasma, -plasmaBurned); - mixture.AdjustMoles(Gas.NitrousOxide, -n20Burned); - mixture.AdjustMoles(Gas.BZ, bzProduced); - - var energyToAdd = bzProduced * Atmospherics.BZFormationEnergy / heatScale; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature += energyToAdd / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/HalonFireSuppressionReaction.cs b/Content.Server/_Adventure/Atmospherics/HalonFireSuppressionReaction.cs deleted file mode 100644 index 35f628c46d7..00000000000 --- a/Content.Server/_Adventure/Atmospherics/HalonFireSuppressionReaction.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; -/// -/// Реакция поглощения кислорода и тепла галоном при нагревании. -/// -[UsedImplicitly] -public sealed partial class HalonFireSuppressionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature < Atmospherics.HalonActivationTemperature) - return ReactionResult.NoReaction; - - var initialHalon = mixture.GetMoles(Gas.Halon); - var initialOxygen = mixture.GetMoles(Gas.Oxygen); - - if (initialHalon <= 0 || initialOxygen <= 0) - return ReactionResult.NoReaction; - - var temperatureFactor = MathHelper.Clamp( - (mixture.Temperature - Atmospherics.HalonActivationTemperature) / - (Atmospherics.HalonMaxTemperature - Atmospherics.HalonActivationTemperature), - 0f, 1f); - - var absorptionRate = initialHalon * temperatureFactor * Atmospherics.HalonAbsorptionRate; - - var oxygenAbsorbed = Math.Min(absorptionRate, initialOxygen); - var heatAbsorbed = oxygenAbsorbed * Atmospherics.HalonHeatAbsorptionFactor; - - mixture.AdjustMoles(Gas.Halon, -oxygenAbsorbed * 0.1f); - mixture.AdjustMoles(Gas.Oxygen, -oxygenAbsorbed); - mixture.AdjustMoles(Gas.CarbonDioxide, oxygenAbsorbed * 0.8f); - - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature -= heatAbsorbed / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/HealiumProductionReaction.cs b/Content.Server/_Adventure/Atmospherics/HealiumProductionReaction.cs deleted file mode 100644 index 74777ae4c76..00000000000 --- a/Content.Server/_Adventure/Atmospherics/HealiumProductionReaction.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Реакция синтеза хилиума из фрезона и BZ -/// Соотношение: 1 Frezon + 1 BZ → 0.25 Healium -/// Ограничения: температура, максимальная скорость синтеза -/// -[UsedImplicitly] -public sealed partial class HealiumProductionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature < Atmospherics.HealiumMinTemperature || - mixture.Temperature > Atmospherics.HealiumMaxTemperature) - return ReactionResult.NoReaction; - - var initialFrezon = mixture.GetMoles(Gas.Frezon); - var initialBZ = mixture.GetMoles(Gas.BZ); - - var availableMix = (initialFrezon + initialBZ) / Atmospherics.HealiumConversionRatio; - var limitingFactor = Math.Min(availableMix, Math.Min(initialFrezon, initialBZ)); - - if (limitingFactor <= 0) - return ReactionResult.NoReaction; - - limitingFactor = Math.Min(limitingFactor, Atmospherics.HealiumProductionMaxRate); - - var frezonBurned = limitingFactor; - var bzBurned = limitingFactor; - var healiumProduced = limitingFactor * Atmospherics.HealiumProductionYield; - - mixture.AdjustMoles(Gas.Frezon, -frezonBurned); - mixture.AdjustMoles(Gas.BZ, -bzBurned); - mixture.AdjustMoles(Gas.Healium, healiumProduced); - - var temperatureFactor = MathHelper.Clamp( - (mixture.Temperature - Atmospherics.HealiumMinTemperature) / - (Atmospherics.HealiumMaxTemperature - Atmospherics.HealiumMinTemperature), - 0.5f, 2f); - - var energyReleased = healiumProduced * Atmospherics.HealiumProductionEnergy * temperatureFactor / heatScale; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature += energyReleased / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/HydrogenBurnReaction.cs b/Content.Server/_Adventure/Atmospherics/HydrogenBurnReaction.cs deleted file mode 100644 index 7135b2e5317..00000000000 --- a/Content.Server/_Adventure/Atmospherics/HydrogenBurnReaction.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions -/// -/// Реакция сгорания водорода в кислородной среде. -/// -{ - [UsedImplicitly] - [DataDefinition] - public sealed partial class HydrogenBurnReaction : 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[(byte)GasReaction.Fire] = 0f; - - var initialHydrogen = mixture.GetMoles(Gas.Hydrogen); - var initialOxygen = mixture.GetMoles(Gas.Oxygen); - - // Минимальное соотношение H2:O2 = 2:1 (по стехиометрии) - var burnRatio = Atmospherics.HydrogenBurnRate; - - var burnedFuel = Math.Min( - initialHydrogen * burnRatio, - initialOxygen * Atmospherics.HydrogenBurnOxyFactor // 1 моль O2 требуется на 2 моля H2 - ); - - if (burnedFuel <= 0f) - return ReactionResult.NoReaction; - - mixture.AdjustMoles(Gas.Hydrogen, -burnedFuel); - mixture.AdjustMoles(Gas.Oxygen, -burnedFuel * 0.5f); - - energyReleased += burnedFuel * Atmospherics.FireHydrogenEnergyReleased; - - mixture.ReactionResults[(byte)GasReaction.Fire] += burnedFuel; - - energyReleased /= heatScale; - - if (energyReleased > 0) - { - var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature = ((temperature * oldHeatCapacity + energyReleased) / newHeatCapacity); - } - - if (location != null && mixture.Temperature > Atmospherics.FireMinimumTemperatureToExist) - { - atmosphereSystem.HotspotExpose(location, mixture.Temperature, mixture.Volume); - } - - return ReactionResult.Reacting; - } - } -} diff --git a/Content.Server/_Adventure/Atmospherics/HyperNobliumEffectSystem.cs b/Content.Server/_Adventure/Atmospherics/HyperNobliumEffectSystem.cs deleted file mode 100644 index 41cd106fac3..00000000000 --- a/Content.Server/_Adventure/Atmospherics/HyperNobliumEffectSystem.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Server.Adventure.Atmos.Reactions; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Эффект газа гиперноблиум - полное подавление всех химических реакций при наличии ≥5 молей -/// -[UsedImplicitly] -public sealed partial class HypernobliumEffect : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - var hyperNobliumMoles = mixture.GetMoles(Gas.HyperNoblium); - var totalMoles = mixture.TotalMoles; - - if (totalMoles < Atmospherics.GasMinMoles) - return ReactionResult.NoReaction; - - var fraction = hyperNobliumMoles / totalMoles; - - if (fraction >= Atmospherics.HyperNobliumFullSuppressionThresholdPercentage) - { - Array.Clear(mixture.ReactionResults, 0, mixture.ReactionResults.Length); - return ReactionResult.StopReactions; - } - - return ReactionResult.NoReaction; - } -} - diff --git a/Content.Server/_Adventure/Atmospherics/HyperNobliumProductionReaction.cs b/Content.Server/_Adventure/Atmospherics/HyperNobliumProductionReaction.cs deleted file mode 100644 index 8e3b001cd9f..00000000000 --- a/Content.Server/_Adventure/Atmospherics/HyperNobliumProductionReaction.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; -/// -/// Реакция синтеза гипер-ноблиума из азота и трития -/// Соотношение: 10 азота + 5 трития → 1 гипер-ноблиума -/// -[UsedImplicitly] -public sealed partial class HyperNobliumProductionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature < Atmospherics.HyperNobliumProductionMinTemp || - mixture.Temperature > Atmospherics.HyperNobliumProductionMaxTemp) - return ReactionResult.NoReaction; - - var initialNitrogen = mixture.GetMoles(Gas.Nitrogen); - var initialTritium = mixture.GetMoles(Gas.Tritium); - var initialBZ = mixture.GetMoles(Gas.BZ); - - var totalGas = initialTritium + initialBZ; - var tritiumReductionFactor = totalGas > 0 - ? Math.Clamp(initialTritium / totalGas, 0.001f, 1f) - : 1f; - - var nobliumPossible = Math.Min( - (initialNitrogen + initialTritium) * 0.01f, - Math.Min( - initialTritium / (Atmospherics.HyperNobliumProductionTritiumRatio * tritiumReductionFactor), - initialNitrogen / Atmospherics.HyperNobliumProductionNitrogenRatio - ) - ); - - nobliumPossible = Math.Min(nobliumPossible, Atmospherics.HyperNobliumProductionMaxRate); - - if (nobliumPossible <= 0 || - initialTritium < Atmospherics.HyperNobliumProductionTritiumRatio * nobliumPossible * tritiumReductionFactor || - initialNitrogen < Atmospherics.HyperNobliumProductionNitrogenRatio * nobliumPossible) - { - return ReactionResult.NoReaction; - } - - mixture.AdjustMoles(Gas.Nitrogen, -Atmospherics.HyperNobliumProductionNitrogenRatio * nobliumPossible); - mixture.AdjustMoles(Gas.Tritium, -Atmospherics.HyperNobliumProductionTritiumRatio * nobliumPossible * tritiumReductionFactor); - mixture.AdjustMoles(Gas.HyperNoblium, nobliumPossible); - - var energyReleased = nobliumPossible * - (Atmospherics.HyperNobliumProductionEnergy / - Math.Max(initialBZ, 1f)) / heatScale; - - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - { - mixture.Temperature = Math.Max( - (mixture.Temperature * heatCapacity + energyReleased) / heatCapacity, - Atmospherics.TCMB - ); - } - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/NitriumDecompositionReaction.cs b/Content.Server/_Adventure/Atmospherics/NitriumDecompositionReaction.cs deleted file mode 100644 index 6ce173c5ae7..00000000000 --- a/Content.Server/_Adventure/Atmospherics/NitriumDecompositionReaction.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Разложение нитриума в кислородной среде. -/// -[UsedImplicitly] -public sealed partial class NitriumDecompositionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature > Atmospherics.NitriumDecompositionMaxTemp) - return ReactionResult.NoReaction; - - var initialNitrium = mixture.GetMoles(Gas.Nitrium); - if (initialNitrium <= 0) - return ReactionResult.NoReaction; - - var efficiency = Math.Min( - mixture.Temperature / Atmospherics.NitriumDecompositionTempDivisor, - initialNitrium - ); - - var decomposedAmount = efficiency * Atmospherics.NitriumDecompositionRate; - mixture.AdjustMoles(Gas.Nitrium, -decomposedAmount); - mixture.AdjustMoles(Gas.Nitrogen, decomposedAmount); - mixture.AdjustMoles(Gas.Hydrogen, decomposedAmount); - - var energyReleased = decomposedAmount * Atmospherics.NitriumDecompositionEnergy; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature += energyReleased / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/NitriumProductionReaction.cs b/Content.Server/_Adventure/Atmospherics/NitriumProductionReaction.cs deleted file mode 100644 index cea85990a9c..00000000000 --- a/Content.Server/_Adventure/Atmospherics/NitriumProductionReaction.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions -{ - [UsedImplicitly] - [DataDefinition] - public sealed partial class NitriumProductionReaction : IGasReactionEffect - { - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - var initialTritium = mixture.GetMoles(Gas.Tritium); - var initialNitrogen = mixture.GetMoles(Gas.Nitrogen); - var initialBZ = mixture.GetMoles(Gas.BZ); - - if (initialTritium < Atmospherics.NitriumMinTritium || - initialNitrogen < Atmospherics.NitriumMinNitrogen || - initialBZ < Atmospherics.NitriumMinBZ || - mixture.Temperature < Atmospherics.NitriumProductionMinTemp) - { - return ReactionResult.NoReaction; - } - - var productionEfficiency = Math.Min( - mixture.Temperature / Atmospherics.NitriumProductionTempDivisor, - Math.Min( - initialTritium / Atmospherics.NitriumTritiumRatio, - Math.Min( - initialNitrogen / Atmospherics.NitriumNitrogenRatio, - initialBZ / Atmospherics.NitriumBZRatio - ) - ) - ); - - productionEfficiency = Math.Min(productionEfficiency, Atmospherics.NitriumProductionMaxRate); - - if (productionEfficiency <= 0f || - initialTritium - productionEfficiency * Atmospherics.NitriumTritiumRatio < 0f || - initialNitrogen - productionEfficiency * Atmospherics.NitriumNitrogenRatio < 0f || - initialBZ - productionEfficiency * Atmospherics.NitriumBZRatio < 0f) - { - return ReactionResult.NoReaction; - } - - var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - var temperature = mixture.Temperature; - - mixture.AdjustMoles(Gas.Tritium, -productionEfficiency * Atmospherics.NitriumTritiumRatio); - mixture.AdjustMoles(Gas.Nitrogen, -productionEfficiency * Atmospherics.NitriumNitrogenRatio); - mixture.AdjustMoles(Gas.BZ, -productionEfficiency * Atmospherics.NitriumBZRatio); - mixture.AdjustMoles(Gas.Nitrium, productionEfficiency); - - var energyConsumed = productionEfficiency * Atmospherics.NitriumProductionEnergy / heatScale; - - if (energyConsumed > 0f) - { - var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) - { - mixture.Temperature = Math.Max( - (temperature * oldHeatCapacity - energyConsumed) / newHeatCapacity, - Atmospherics.TCMB - ); - } - } - - return ReactionResult.Reacting; - } - } -} diff --git a/Content.Server/_Adventure/Atmospherics/PluoxiumProductionReaction.cs b/Content.Server/_Adventure/Atmospherics/PluoxiumProductionReaction.cs deleted file mode 100644 index a8a2c80fdad..00000000000 --- a/Content.Server/_Adventure/Atmospherics/PluoxiumProductionReaction.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Реакция синтеза плюоксиума из диоксида, кислорода и трития. -/// Соотношение: 1 CO2 + 0.5 O2 + 0.01 трития → 1 плюоксиума + 0.01 H2 + Энергия -/// -[UsedImplicitly] -[DataDefinition] -public sealed partial class PluoxiumProductionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - var initialCO2 = mixture.GetMoles(Gas.CarbonDioxide); - var initialO2 = mixture.GetMoles(Gas.Oxygen); - var initialTritium = mixture.GetMoles(Gas.Tritium); - var producedAmount = Math.Min( - Atmospherics.PluoxiumFormationMaxRate, - Math.Min( - initialCO2, - Math.Min( - initialO2 / Atmospherics.PluoxiumOxygenRatio, - initialTritium / Atmospherics.PluoxiumTritiumRatio - ) - ) - ); - if (producedAmount <= 0 || - initialCO2 - producedAmount < 0 || - initialO2 - producedAmount * Atmospherics.PluoxiumOxygenRatio < 0 || - initialTritium - producedAmount * Atmospherics.PluoxiumTritiumRatio < 0) - { - return ReactionResult.NoReaction; - } - var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - var temperature = mixture.Temperature; - mixture.AdjustMoles(Gas.CarbonDioxide, -producedAmount); - mixture.AdjustMoles(Gas.Oxygen, -producedAmount * Atmospherics.PluoxiumOxygenRatio); - mixture.AdjustMoles(Gas.Tritium, -producedAmount * Atmospherics.PluoxiumTritiumRatio); - mixture.AdjustMoles(Gas.Pluoxium, producedAmount); - mixture.AdjustMoles(Gas.Hydrogen, producedAmount * Atmospherics.PluoxiumHydrogenByproductRatio); - var energyReleased = producedAmount * Atmospherics.PluoxiumFormationEnergy / heatScale; - if (energyReleased > 0) - { - var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (newHeatCapacity > Atmospherics.MinimumHeatCapacity) - { - mixture.Temperature = Math.Max( - (temperature * oldHeatCapacity + energyReleased) / newHeatCapacity, - Atmospherics.TCMB - ); - } - } - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/ProtoNitrateBZDecomposition.cs b/Content.Server/_Adventure/Atmospherics/ProtoNitrateBZDecomposition.cs deleted file mode 100644 index c3448dd865b..00000000000 --- a/Content.Server/_Adventure/Atmospherics/ProtoNitrateBZDecomposition.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Разложение БЗ с помощью прото-нитрата. -/// -[UsedImplicitly] -public sealed partial class ProtoNitrateBZDecomposition : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature < Atmospherics.PNBZaseMinTemp || - mixture.Temperature > Atmospherics.PNBZaseMaxTemp) - return ReactionResult.NoReaction; - - var initialBZ = mixture.GetMoles(Gas.BZ); - var initialPN = mixture.GetMoles(Gas.ProtoNitrate); - - if (initialBZ <= 0 || initialPN <= 0) - return ReactionResult.NoReaction; - - var reactionRate = Math.Min( - initialBZ, - initialPN * Atmospherics.PNBZaseConversionRate - ); - - mixture.AdjustMoles(Gas.BZ, -reactionRate); - mixture.AdjustMoles(Gas.Nitrogen, reactionRate * 0.4f); - mixture.AdjustMoles(Gas.Helium, reactionRate * 1.6f); - mixture.AdjustMoles(Gas.Plasma, reactionRate * 0.8f); - - var energyReleased = reactionRate * Atmospherics.PNBZaseEnergy; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature += energyReleased / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/ProtoNitrateHydrogenConversion.cs b/Content.Server/_Adventure/Atmospherics/ProtoNitrateHydrogenConversion.cs deleted file mode 100644 index e94ac4398cd..00000000000 --- a/Content.Server/_Adventure/Atmospherics/ProtoNitrateHydrogenConversion.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Конверсия водорода c участием прото-нитрата. -/// -[UsedImplicitly] -public sealed partial class ProtoNitrateHydrogenConversion : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - var initialHydrogen = mixture.GetMoles(Gas.Hydrogen); - var initialPN = mixture.GetMoles(Gas.ProtoNitrate); - - if (initialHydrogen < Atmospherics.PNHydrogenConversionThreshold || initialPN <= 0) - return ReactionResult.NoReaction; - - var conversionRate = Math.Min( - Math.Min(initialHydrogen, initialPN * Atmospherics.PNHydrogenConversionRate), - Atmospherics.PNHydrogenConversionMaxRate - ); - - mixture.AdjustMoles(Gas.Hydrogen, -conversionRate); - mixture.AdjustMoles(Gas.ProtoNitrate, conversionRate * 0.5f); - - var energyConsumed = conversionRate * Atmospherics.PNHydrogenConversionEnergy; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature = Math.Max( - mixture.Temperature - energyConsumed / heatCapacity, - Atmospherics.TCMB - ); - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/ProtoNitrateProductionReaction.cs b/Content.Server/_Adventure/Atmospherics/ProtoNitrateProductionReaction.cs deleted file mode 100644 index b205ce4906f..00000000000 --- a/Content.Server/_Adventure/Atmospherics/ProtoNitrateProductionReaction.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Производство прото-нитрата из плюоксиума и водорода. -/// Требует высоких температур (5000K-10000K) и имеет температурный коэффициент. -/// -[UsedImplicitly] -public sealed partial class ProtoNitrateProductionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature < Atmospherics.PNProductionMinTemperature || - mixture.Temperature > Atmospherics.PNProductionMaxTemperature) - { - return ReactionResult.NoReaction; - } - - var initialPluoxium = mixture.GetMoles(Gas.Pluoxium); - var initialHydrogen = mixture.GetMoles(Gas.Hydrogen); - - if (initialPluoxium <= 0 || initialHydrogen <= 0) - return ReactionResult.NoReaction; - - var temperatureFactor = mixture.Temperature * Atmospherics.PNProductionTemperatureScale; - - var pluoxiumLimit = initialPluoxium / Atmospherics.PNPluoxiumRatio; - var hydrogenLimit = initialHydrogen / Atmospherics.PNHydrogenRatio; - var limitingFactor = Math.Min(pluoxiumLimit, hydrogenLimit); - - if (limitingFactor <= 0) - return ReactionResult.NoReaction; - - var reactionRate = Math.Min(limitingFactor, temperatureFactor); - - var pluoxiumBurned = reactionRate * Atmospherics.PNPluoxiumRatio; - var hydrogenBurned = reactionRate * Atmospherics.PNHydrogenRatio; - - var protoNitrateProduced = (pluoxiumBurned + hydrogenBurned) * Atmospherics.PNProductionEfficiency; - - mixture.AdjustMoles(Gas.Pluoxium, -pluoxiumBurned); - mixture.AdjustMoles(Gas.Hydrogen, -hydrogenBurned); - mixture.AdjustMoles(Gas.ProtoNitrate, protoNitrateProduced); - - var energyToAdd = protoNitrateProduced * Atmospherics.PNProductionEnergy / heatScale; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature += energyToAdd / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/ProtoNitrateTritiumReaction.cs b/Content.Server/_Adventure/Atmospherics/ProtoNitrateTritiumReaction.cs deleted file mode 100644 index e54f5f1b705..00000000000 --- a/Content.Server/_Adventure/Atmospherics/ProtoNitrateTritiumReaction.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Детоксикация трития с помощью прото-нитрата. -/// -[UsedImplicitly] -public sealed partial class ProtoNitrateTritiumReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature < Atmospherics.PNTritiumMinTemp || - mixture.Temperature > Atmospherics.PNTritiumMaxTemp) - return ReactionResult.NoReaction; - - var initialTritium = mixture.GetMoles(Gas.Tritium); - var initialPN = mixture.GetMoles(Gas.ProtoNitrate); - - if (initialTritium <= 0 || initialPN <= 0) - return ReactionResult.NoReaction; - - var reactionRate = Math.Min( - initialTritium, - initialPN * Atmospherics.PNTritiumConversionRate - ); - - mixture.AdjustMoles(Gas.Tritium, -reactionRate); - mixture.AdjustMoles(Gas.Hydrogen, reactionRate); - mixture.AdjustMoles(Gas.ProtoNitrate, -reactionRate * 0.01f); - - var energyReleased = reactionRate * Atmospherics.PNTritiumConversionEnergy; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature += energyReleased / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/ZaukerDecompositionReaction.cs b/Content.Server/_Adventure/Atmospherics/ZaukerDecompositionReaction.cs deleted file mode 100644 index c42bbe4c7d7..00000000000 --- a/Content.Server/_Adventure/Atmospherics/ZaukerDecompositionReaction.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Разложение заукера в азотной среде. -/// -[UsedImplicitly] -public sealed partial class ZaukerDecompositionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - var initialZauker = mixture.GetMoles(Gas.Zauker); - var initialNitrogen = mixture.GetMoles(Gas.Nitrogen); - - if (initialZauker <= 0 || initialNitrogen <= 0) - return ReactionResult.NoReaction; - - var decomposedAmount = Math.Min( - Math.Min(initialZauker, initialNitrogen), - Atmospherics.ZaukerDecompositionMaxRate - ); - - mixture.AdjustMoles(Gas.Zauker, -decomposedAmount); - mixture.AdjustMoles(Gas.Nitrogen, decomposedAmount * 0.7f); - mixture.AdjustMoles(Gas.Oxygen, decomposedAmount * 0.3f); - - var energyReleased = decomposedAmount * Atmospherics.ZaukerDecompositionEnergy; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature += energyReleased / heatCapacity; - - return ReactionResult.Reacting; - } -} diff --git a/Content.Server/_Adventure/Atmospherics/ZaukerProductionReaction.cs b/Content.Server/_Adventure/Atmospherics/ZaukerProductionReaction.cs deleted file mode 100644 index ac7db988b86..00000000000 --- a/Content.Server/_Adventure/Atmospherics/ZaukerProductionReaction.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Content.Server.Atmos; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Reactions; -using JetBrains.Annotations; - -namespace Content.Server.Adventure.Atmos.Reactions; - -/// -/// Производство заукера из гипер-ноблиума и нитриума. -/// Требует экстремально высоких температур (50000K-75000K). -/// Максимальное производство ограничено 5 молями за тик. -/// -[UsedImplicitly] -public sealed partial class ZaukerProductionReaction : IGasReactionEffect -{ - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale) - { - if (mixture.Temperature < Atmospherics.ZaukerProductionMinTemperature || - mixture.Temperature > Atmospherics.ZaukerProductionMaxTemperature) - { - return ReactionResult.NoReaction; - } - - var initialHyperNob = mixture.GetMoles(Gas.HyperNoblium); - var initialNitrium = mixture.GetMoles(Gas.Nitrium); - - if (initialHyperNob <= 0 || initialNitrium <= 0) - return ReactionResult.NoReaction; - - var temperatureFactor = mixture.Temperature * Atmospherics.ZaukerProductionTemperatureScale; - - var hyperNobLimit = initialHyperNob / Atmospherics.ZaukerHyperNobRatio; - var nitriumLimit = initialNitrium / Atmospherics.ZaukerNitriumRatio; - var limitingFactor = Math.Min(hyperNobLimit, nitriumLimit); - - if (limitingFactor <= 0) - return ReactionResult.NoReaction; - - var reactionRate = Math.Min(limitingFactor, temperatureFactor); - - var hyperNobBurned = reactionRate * Atmospherics.ZaukerHyperNobRatio; - var nitriumBurned = reactionRate * Atmospherics.ZaukerNitriumRatio; - - var zaukerProduced = (hyperNobBurned + nitriumBurned) * Atmospherics.ZaukerProductionEfficiency; - - zaukerProduced = Math.Min(zaukerProduced, Atmospherics.ZaukerProductionMaxPerTick); - - var efficiencyRatio = zaukerProduced / ((hyperNobBurned + nitriumBurned) * Atmospherics.ZaukerProductionEfficiency); - hyperNobBurned *= efficiencyRatio; - nitriumBurned *= efficiencyRatio; - - mixture.AdjustMoles(Gas.HyperNoblium, -hyperNobBurned); - mixture.AdjustMoles(Gas.Nitrium, -nitriumBurned); - mixture.AdjustMoles(Gas.Zauker, zaukerProduced); - - var energyConsumed = zaukerProduced * Atmospherics.ZaukerProductionEnergy / heatScale; - var heatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true); - if (heatCapacity > Atmospherics.MinimumHeatCapacity) - mixture.Temperature = Math.Max(mixture.Temperature - energyConsumed / heatCapacity, Atmospherics.TCMB); - - return ReactionResult.Reacting; - } -} diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index cada28798ca..e22f9df1444 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Atmos /// /// Class to store atmos constants. /// - public static class Atmospherics + public static partial class Atmospherics { #region ATMOS /// @@ -333,7 +333,6 @@ public static class Atmospherics public const float PluoxiumOxygenRatio = 0.5f; public const float PluoxiumTritiumRatio = 0.01f; public const float PluoxiumHydrogenByproductRatio = 0.01f; - public const float PluoxiumFormationEnergy = 1000f; /// Nitrium Production Constants public const float NitriumProductionMinTemp = 1500f; @@ -384,18 +383,7 @@ public static class Atmospherics public const float PNBZaseMaxTemp = 280f; public const float PNBZaseConversionRate = 0.2f; public const float PNBZaseEnergy = 60000f; - /// Proto-Nitrate Reactions end - - /// Nitrium Decomposition - public const float NitriumDecompositionMaxTemp = 343f; - public const float NitriumDecompositionTempDivisor = 100f; - public const float NitriumDecompositionRate = 1.2f; - public const float NitriumDecompositionEnergy = 30000f; - - /// Zauker Decomposition - public const float ZaukerDecompositionMaxRate = 20f; - public const float ZaukerDecompositionEnergy = 460f; - /// Adventure gases end + #endregion /// diff --git a/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs b/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs index 115cb548929..2c07f9d509f 100644 --- a/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs +++ b/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs @@ -1,104 +1,103 @@ using Robust.Shared.GameStates; -using Robust.Shared.Map; using Robust.Shared.Serialization; namespace Content.Shared.Atmos.Components; +/// +/// Used for gas analyzers, an item that shows players the gas contents of an atmos +/// device they use it on or of the tile they are standing on. +/// [RegisterComponent, NetworkedComponent] public sealed partial class GasAnalyzerComponent : Component { - [ViewVariables] + /// + /// The target entity currently being analyzed. + /// public EntityUid? Target; - [ViewVariables] - public EntityUid User; + /// + /// The current user of the gas analyzer. + /// + public EntityUid? User; - [DataField("enabled"), ViewVariables(VVAccess.ReadWrite)] + /// + /// Is the analyzer currently active? + /// + [DataField] public bool Enabled; +} - [Serializable, NetSerializable] - public enum GasAnalyzerUiKey - { - Key, - } +/// +/// Atmospheric data is gathered in the system and sent to the user. +/// +[Serializable, NetSerializable] +public sealed class GasAnalyzerUserMessage(GasMixEntry[] nodeGasMixes, string deviceName, NetEntity deviceUid, bool deviceFlipped) : BoundUserInterfaceMessage +{ + public string DeviceName = deviceName; + public NetEntity DeviceUid = deviceUid; + public bool DeviceFlipped = deviceFlipped; + public GasMixEntry[] NodeGasMixes = nodeGasMixes; +} +/// +/// Contains information on a gas mix entry, turns into a tab in the UI. +/// +[Serializable, NetSerializable] +public readonly record struct GasMixEntry(string Name, float Volume, float Pressure, float Temperature, GasEntry[]? Gases = null) +{ /// - /// Atmospheric data is gathered in the system and sent to the user + /// Name of the tab in the UI. /// - [Serializable, NetSerializable] - public sealed class GasAnalyzerUserMessage : BoundUserInterfaceMessage - { - public string DeviceName; - public NetEntity DeviceUid; - public bool DeviceFlipped; - public string? Error; - public GasMixEntry[] NodeGasMixes; - public GasAnalyzerUserMessage(GasMixEntry[] nodeGasMixes, string deviceName, NetEntity deviceUid, bool deviceFlipped, string? error = null) - { - NodeGasMixes = nodeGasMixes; - DeviceName = deviceName; - DeviceUid = deviceUid; - DeviceFlipped = deviceFlipped; - Error = error; - } - } - + public readonly string Name = Name; /// - /// Contains information on a gas mix entry, turns into a tab in the UI + /// Volume of this gas mixture. /// - [Serializable, NetSerializable] - public struct GasMixEntry - { - /// - /// Name of the tab in the UI - /// - public readonly string Name; - public readonly float Volume; - public readonly float Pressure; - public readonly float Temperature; - public readonly GasEntry[]? Gases; - - public GasMixEntry(string name, float volume, float pressure, float temperature, GasEntry[]? gases = null) - { - Name = name; - Volume = volume; - Pressure = pressure; - Temperature = temperature; - Gases = gases; - } - } - + public readonly float Volume = Volume; /// - /// Individual gas entry data for populating the UI + /// Pressure of this gas mixture. /// - [Serializable, NetSerializable] - public struct GasEntry - { - public readonly string Name; - public readonly float Amount; - public readonly string Color; + public readonly float Pressure = Pressure; + /// + /// Temperature of this gas mixture. + /// + public readonly float Temperature = Temperature; + /// + /// The gases contained in this gas mixture. + /// The gases below a certain mol threshold are not included. + /// + public readonly GasEntry[]? Gases = Gases; +} - public GasEntry(string name, float amount, string color) - { - Name = name; - Amount = amount; - Color = color; - } +/// +/// Individual gas entry data for populating the UI. +/// +[Serializable, NetSerializable] +public readonly record struct GasEntry(Gas Gas, float Amount) +{ + /// + /// The gas this entry represents. + /// + public readonly Gas Gas = Gas; + /// + /// The gas amount in mol. + /// + public readonly float Amount = Amount; +} - public override string ToString() - { - // e.g. "Plasma: 2000 mol" - return Loc.GetString( - "gas-entry-info", - ("gasName", Name), - ("gasAmount", Amount)); - } - } +/// +/// Key for the GasAnalyzerBoundUserInterface. +/// +[Serializable, NetSerializable] +public enum GasAnalyzerUiKey +{ + Key, } +/// +/// Individual gas entry data for populating the UI +/// [Serializable, NetSerializable] public enum GasAnalyzerVisuals : byte { Enabled, } - diff --git a/Content.Shared/Atmos/Consoles/Components/AtmosAlertsComputerComponent.cs b/Content.Shared/Atmos/Consoles/Components/AtmosAlertsComputerComponent.cs index d64c8907afb..3c6e233604e 100644 --- a/Content.Shared/Atmos/Consoles/Components/AtmosAlertsComputerComponent.cs +++ b/Content.Shared/Atmos/Consoles/Components/AtmosAlertsComputerComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.Atmos.Consoles; using Content.Shared.Atmos.Monitor; +using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Serialization; @@ -27,6 +28,20 @@ public sealed partial class AtmosAlertsComputerComponent : Component /// [ViewVariables, AutoNetworkedField] public HashSet SilencedDevices = new(); + + // Adventure-start + [DataField] + public SoundSpecifier? BeepSound; + + [DataField] + public TimeSpan Timer = TimeSpan.FromSeconds(5); + + [DataField] + public TimeSpan NextBeep = TimeSpan.Zero; + + [DataField, AutoNetworkedField] + public bool DoAtmosAlert = false; + // Adventure-end } [Serializable, NetSerializable] @@ -77,7 +92,7 @@ public struct AtmosAlertsFocusDeviceData public (float, AtmosAlarmType) PressureData; /// - /// Moles, percentage, and related alert state, for all detected gases + /// Moles, percentage, and related alert state, for all detected gases /// public Dictionary GasData; @@ -98,7 +113,7 @@ public AtmosAlertsFocusDeviceData } [Serializable, NetSerializable] -public sealed class AtmosAlertsComputerBoundInterfaceState : BoundUserInterfaceState +public sealed partial class AtmosAlertsComputerBoundInterfaceState : BoundUserInterfaceState // Adventure - edit добавлено partial { /// /// A list of all air alarms @@ -115,6 +130,7 @@ public sealed class AtmosAlertsComputerBoundInterfaceState : BoundUserInterfaceS /// public AtmosAlertsFocusDeviceData? FocusData; + /// /// Sends data from the server to the client to populate the atmos monitoring console UI /// @@ -200,7 +216,7 @@ public sealed class AtmosAlertsComputerDeviceSilencedMessage : BoundUserInterfac public bool SilenceDevice = true; /// - /// Used to inform the server that the client has silenced alerts from the specified device to this atmos monitoring console + /// Used to inform the server that the client has silenced alerts from the specified device to this atmos monitoring console /// public AtmosAlertsComputerDeviceSilencedMessage(NetEntity atmosDevice, bool silenceDevice = true) { @@ -209,6 +225,14 @@ public AtmosAlertsComputerDeviceSilencedMessage(NetEntity atmosDevice, bool sile } } +// Adventure-start +[Serializable, NetSerializable] +public sealed class AtmosAlertsComputerAlertSoundToggleMessage(bool enabled) : BoundUserInterfaceMessage +{ + public bool Enabled = enabled; +} +// Adventure-end + /// /// List of all the different atmos device groups /// diff --git a/Content.Shared/Atmos/Consoles/SharedAtmosAlertsComputerSystem.cs b/Content.Shared/Atmos/Consoles/SharedAtmosAlertsComputerSystem.cs index 7e2b2b04670..ed863755497 100644 --- a/Content.Shared/Atmos/Consoles/SharedAtmosAlertsComputerSystem.cs +++ b/Content.Shared/Atmos/Consoles/SharedAtmosAlertsComputerSystem.cs @@ -9,6 +9,8 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnDeviceSilencedMessage); + + InitializeADT(); } private void OnDeviceSilencedMessage(EntityUid uid, AtmosAlertsComputerComponent component, AtmosAlertsComputerDeviceSilencedMessage args) @@ -21,4 +23,5 @@ private void OnDeviceSilencedMessage(EntityUid uid, AtmosAlertsComputerComponent Dirty(uid, component); } + } diff --git a/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.Gases.cs b/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.Gases.cs new file mode 100644 index 00000000000..04b733fad66 --- /dev/null +++ b/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.Gases.cs @@ -0,0 +1,69 @@ +using System; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; +using Robust.Shared.Maths; + +namespace Content.Shared.Atmos.EntitySystems; + +public abstract partial class SharedAtmosphereSystem +{ + protected float[] GasFuelMask = new float[Atmospherics.AdjustedNumberOfGases]; + protected float[] GasOxidizerMask = new float[Atmospherics.AdjustedNumberOfGases]; + protected float[] GasSpecificHeats = new float[Atmospherics.AdjustedNumberOfGases]; + + protected virtual void InitializeGases() + { + var simdLen = MathHelper.NextMultipleOf(Atmospherics.TotalNumberOfGases, 4); + Array.Resize(ref GasFuelMask, simdLen); + Array.Resize(ref GasOxidizerMask, simdLen); + Array.Resize(ref GasSpecificHeats, simdLen); + + for (var i = 0; i < GasPrototypes.Length; i++) + { + var proto = GasPrototypes[i]; + GasFuelMask[i] = proto.IsFuel ? 1f : 0f; + GasOxidizerMask[i] = proto.IsOxidizer ? 1f : 0f; + GasSpecificHeats[i] = proto.MolarHeatCapacity; + } + } + + public virtual bool IsMixtureFuel(GasMixture mixture, float epsilon = Atmospherics.GasMinMoles) + => throw new NotImplementedException(); + + public virtual bool IsMixtureOxidizer(GasMixture mixture, float epsilon = Atmospherics.GasMinMoles) + => throw new NotImplementedException(); + + protected virtual float GetHeatCapacityCalculation(float[] moles, bool space) + => throw new NotImplementedException(); + + public virtual ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder) + => ReactionResult.NoReaction; + + // ---- Test-visible aliases / shared heat-capacity API ---- // + + /// + /// Public read accessor for the SIMD-padded per-gas specific heats array. + /// + public float[] GasMolarHeatCapacities => GasSpecificHeats; + + /// + /// Speedup scale for heat-capacity calculations, populated from + /// CCVars.AtmosHeatScale in server/client CVars files. + /// + public float HeatScale { get; protected set; } = 1.0f; + + /// + /// Returns the heat capacity of a gas mixture. + /// + /// The gas mixture to evaluate. + /// + /// false (default) — returns the raw unscaled value.
+ /// true — divides by + /// (the atmospheric simulation speedup factor). + /// + public float GetHeatCapacity(GasMixture mixture, bool applyScaling = false) + { + var raw = GetHeatCapacityCalculation(mixture.Moles, mixture.Immutable); + return applyScaling && HeatScale > 0f ? raw / HeatScale : raw; + } +} diff --git a/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.cs b/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.cs index 67d6dec8af5..72c4ef7f2b7 100644 --- a/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.cs +++ b/Content.Shared/Atmos/EntitySystems/SharedAtmosphereSystem.cs @@ -1,6 +1,10 @@ +using System; +using System.Collections.Generic; +using Content.Shared.Atmos; using Content.Shared.Atmos.Prototypes; using Content.Shared.Body.Components; using Content.Shared.Body.Systems; +using Robust.Shared.Log; using Robust.Shared.Prototypes; namespace Content.Shared.Atmos.EntitySystems @@ -13,7 +17,6 @@ public abstract partial class SharedAtmosphereSystem : EntitySystem private EntityQuery _internalsQuery; public string?[] GasReagents = new string[Atmospherics.TotalNumberOfGases]; - protected readonly GasPrototype[] GasPrototypes = new GasPrototype[Atmospherics.TotalNumberOfGases]; public override void Initialize() @@ -26,13 +29,14 @@ public override void Initialize() foreach (var gas in Enum.GetValues()) { - var idx = (int)gas; - // Log an error if the corresponding prototype isn't found + var idx = (int) gas; + if (!_prototypeManager.TryIndex(gas.ToString(), out var gasPrototype)) { - Log.Error($"Failed to find corresponding {nameof(GasPrototype)} for gas ID {(int)gas} ({gas}) with expected ID \"{gas.ToString()}\". Is your prototype named correctly?"); + Log.Error($"Failed to find corresponding {nameof(GasPrototype)} for gas ID {(int) gas} ({gas}) with expected ID \"{gas}\". Is your prototype named correctly?"); continue; } + GasPrototypes[idx] = gasPrototype; GasReagents[idx] = gasPrototype.Reagent; } diff --git a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs index d831616355b..e3250d3a24c 100644 --- a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs +++ b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs @@ -1,114 +1,249 @@ using Content.Shared.Atmos.Components; -using Content.Shared.Atmos.Prototypes; +using Robust.Shared.Configuration; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -namespace Content.Shared.Atmos.EntitySystems +namespace Content.Shared.Atmos.EntitySystems; + +public abstract class SharedGasTileOverlaySystem : EntitySystem { - public abstract class SharedGasTileOverlaySystem : EntitySystem + public const byte ChunkSize = 8; + protected float AccumulatedFrameTime; + protected bool PvsEnabled; + + [Dependency] protected readonly IPrototypeManager ProtoMan = default!; + [Dependency] protected readonly IConfigurationManager ConfMan = default!; + [Dependency] private readonly SharedAtmosphereSystem _atmosphere = default!; + + /// + /// array of the ids of all visible gases. + /// + public int[] VisibleGasId = default!; + + public override void Initialize() { - public const byte ChunkSize = 8; - protected float AccumulatedFrameTime; - protected bool PvsEnabled; + base.Initialize(); + SubscribeLocalEvent(OnGetState); - [Dependency] protected readonly IPrototypeManager ProtoMan = default!; - [Dependency] private readonly SharedAtmosphereSystem _atmosphere = default!; + List visibleGases = new(); - /// - /// array of the ids of all visible gases. - /// - public int[] VisibleGasId = default!; + for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) + { + var gasPrototype = _atmosphere.GetGas(i); + if (gasPrototype.GasOverlaySprite != null) + visibleGases.Add(i); + } + VisibleGasId = visibleGases.ToArray(); + } - public override void Initialize() + private void OnGetState(EntityUid uid, GasTileOverlayComponent component, ref ComponentGetState args) + { + if (PvsEnabled && !args.ReplayState) + return; + + // Should this be a full component state or a delta-state? + if (args.FromTick <= component.CreationTick || args.FromTick <= component.ForceTick) { - base.Initialize(); - SubscribeLocalEvent(OnGetState); + args.State = new GasTileOverlayState(component.Chunks); + return; + } - List visibleGases = new(); + args.State = new GasTileOverlayState(component.Chunks); + } - for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) - { - var gasPrototype = _atmosphere.GetGas(i); - if (!string.IsNullOrEmpty(gasPrototype.GasOverlayTexture) || !string.IsNullOrEmpty(gasPrototype.GasOverlaySprite) && !string.IsNullOrEmpty(gasPrototype.GasOverlayState)) - visibleGases.Add(i); - } + public static Vector2i GetGasChunkIndices(Vector2i indices) + { + return new Vector2i((int)MathF.Floor((float)indices.X / ChunkSize), (int)MathF.Floor((float)indices.Y / ChunkSize)); + } + + [Serializable, NetSerializable] + public readonly struct GasOverlayData : IEquatable + { + [ViewVariables] public readonly byte FireState; + [ViewVariables] public readonly byte[] Opacity; + // TODO change fire color based on ByteTemp - VisibleGasId = visibleGases.ToArray(); + /// + /// Network-synced air temperature, compressed to a single byte per tile for bandwidth optimization. + /// Note: Values are approximate and may deviate even ~10°C from the precise server side only temperature. + /// + [ViewVariables] + public readonly ThermalByte ByteGasTemperature; + + + public GasOverlayData(byte fireState, byte[] opacity, ThermalByte byteTemp) + { + FireState = fireState; + Opacity = opacity; + ByteGasTemperature = byteTemp; } - private void OnGetState(EntityUid uid, GasTileOverlayComponent component, ref ComponentGetState args) + public bool Equals(GasOverlayData other) { - if (PvsEnabled && !args.ReplayState) - return; + if (FireState != other.FireState) + return false; - // Should this be a full component state or a delta-state? - if (args.FromTick <= component.CreationTick || args.FromTick <= component.ForceTick) - { - args.State = new GasTileOverlayState(component.Chunks); - return; - } + if (Opacity?.Length != other.Opacity?.Length) + return false; - var data = new Dictionary(); - foreach (var (index, chunk) in component.Chunks) + if (Opacity != null && other.Opacity != null) { - if (chunk.LastUpdate >= args.FromTick) - data[index] = chunk; + for (var i = 0; i < Opacity.Length; i++) + { + if (Opacity[i] != other.Opacity[i]) + return false; + } } - args.State = new GasTileOverlayDeltaState(data, new(component.Chunks.Keys)); - } + if (ByteGasTemperature != other.ByteGasTemperature) + return false; - public static Vector2i GetGasChunkIndices(Vector2i indices) - { - return new((int) MathF.Floor((float) indices.X / ChunkSize), (int) MathF.Floor((float) indices.Y / ChunkSize)); + return true; } + } - [Serializable, NetSerializable] - public readonly struct GasOverlayData : IEquatable - { - [ViewVariables] - public readonly byte FireState; + [Serializable, NetSerializable] + public sealed class GasOverlayUpdateEvent : EntityEventArgs + { + public Dictionary> UpdatedChunks = new(); + public Dictionary> RemovedChunks = new(); + } +} - [ViewVariables] - public readonly byte[] Opacity; +/// +/// Struct for networking gas temperatures to all clients using a single struct(byte) per tile. +/// +/// +/// +/// This struct compresses the gas temperature into a 1-byte value (0-255). +/// It clamps the temperature to a maximum of 1000K and divides it by 4, creating a range of 0-250. +/// This provides a resolution of 4 degrees Kelvin. +/// +/// +/// The remaining bytes are used as special flags: +/// +/// 255: Represents a Wall (block cannot hold atmosphere). +/// 254: Represents a Vacuum. +/// 251-253: Reserved for future use. +/// +/// +/// +/// Dirtying Logic: The value is only dirtied and networked if the difference between the +/// networked byte and the real atmosphere byte is greater than 1. This prevents network spam +/// from minor temperature fluctuations (e.g., heating from 1K to 8K will not trigger an update, +/// but hitting 9K moves the byte index enough to sync). +/// +/// +/// Currently, the conversion is linear. Future improvements might involve a quadratic scale +/// or pre-defined resolution points to offer higher precision at room temperatures +/// and lower precision at extreme temperatures (1000K). +/// +/// +[Serializable, NetSerializable] +public struct ThermalByte : IEquatable +{ + public const float TempMinimum = 0f; + public const float TempMaximum = 1000f; + public const int TempResolution = 250; - // TODO change fire color based on temps - // But also: dont dirty on a 0.01 kelvin change in temperatures. - // Either have a temp tolerance, or map temperature -> byte levels + public const byte ReservedFuture0 = 251; + public const byte ReservedFuture1 = 252; + public const byte ReservedFuture2 = 253; + public const byte StateVacuum = 254; + public const byte AtmosImpossible = 255; - public GasOverlayData(byte fireState, byte[] opacity) - { - FireState = fireState; - Opacity = opacity; - } + public const float TempDegreeResolution = (TempMaximum - TempMinimum) / TempResolution; + public const float TempToByteFactor = TempResolution / (TempMaximum - TempMinimum); - public bool Equals(GasOverlayData other) - { - if (FireState != other.FireState) - return false; + private byte _coreValue; - if (Opacity?.Length != other.Opacity?.Length) - return false; + public ThermalByte(float temperatureKelvin) + { + SetTemperature(temperatureKelvin); + } - if (Opacity != null && other.Opacity != null) - { - for (var i = 0; i < Opacity.Length; i++) - { - if (Opacity[i] != other.Opacity[i]) - return false; - } - } + public ThermalByte() + { + _coreValue = AtmosImpossible; + } - return true; - } - } + /// + /// Set temperature of air in this in Kelvin. + /// + public void SetTemperature(float temperatureKelvin) + { + var clampedTemp = Math.Clamp(temperatureKelvin, TempMinimum, TempMaximum); + _coreValue = (byte)((clampedTemp - TempMinimum) * TempResolution / (TempMaximum - TempMinimum)); + } + + public void SetAtmosIsImpossible() + { + _coreValue = AtmosImpossible; + } + + public void SetVacuum() + { + _coreValue = StateVacuum; + } - [Serializable, NetSerializable] - public sealed class GasOverlayUpdateEvent : EntityEventArgs + public bool IsAtmosImpossible => _coreValue == AtmosImpossible; // Cold space, solid walls + public bool IsVacuum => _coreValue == StateVacuum; + public byte Value => _coreValue; + + /// + /// Attempts to get the air temperature in Kelvin. + /// + /// The temperature in Kelvin, if the tile has a valid temperature. + /// + /// If true and the tile is a vacuum, will be set to + /// and the method will return . + /// + /// + /// if the tile contains a valid temperature (including vacuum if is set); + /// otherwise (e.g., walls). + /// + public readonly bool TryGetTemperature(out float temperature, bool onVacuumReturnTcmb = true) + { + switch (_coreValue) { - public Dictionary> UpdatedChunks = new(); - public Dictionary> RemovedChunks = new(); + case AtmosImpossible: + temperature = 0f; + return false; + case StateVacuum when onVacuumReturnTcmb: + temperature = Atmospherics.TCMB; + return true; + case StateVacuum: + temperature = 0f; + return false; + default: + temperature = (_coreValue * TempDegreeResolution) + TempMinimum; + return true; } } + + public bool Equals(ThermalByte other) + { + return _coreValue == other._coreValue; + } + + public static bool operator ==(ThermalByte left, ThermalByte right) + { + return left.Equals(right); + } + + public static bool operator !=(ThermalByte left, ThermalByte right) + { + return !left.Equals(right); + } + + public override bool Equals(object? obj) + { + return obj is ThermalByte other && Equals(other); + } + + public override int GetHashCode() + { + return _coreValue.GetHashCode(); + } } diff --git a/Content.Shared/Atmos/GasMixture.cs b/Content.Shared/Atmos/GasMixture.cs index 3da7827cdd8..a25f93b4cd4 100644 --- a/Content.Shared/Atmos/GasMixture.cs +++ b/Content.Shared/Atmos/GasMixture.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; diff --git a/Content.Shared/Atmos/GasMixtureStringRepresentation.cs b/Content.Shared/Atmos/GasMixtureStringRepresentation.cs index 942b2bdc672..33b9d9e181c 100644 --- a/Content.Shared/Atmos/GasMixtureStringRepresentation.cs +++ b/Content.Shared/Atmos/GasMixtureStringRepresentation.cs @@ -1,10 +1,19 @@ -namespace Content.Shared.Atmos; +using System.Text; + +namespace Content.Shared.Atmos; public readonly record struct GasMixtureStringRepresentation(float TotalMoles, float Temperature, float Pressure, Dictionary MolesPerGas) : IFormattable { public override string ToString() { - return $"{Temperature}K {Pressure} kPa"; + var stringBuilder = new StringBuilder(); + foreach (var (gas, moles) in MolesPerGas) + { + stringBuilder.Append($"{gas}: {moles}, "); + } + var result = stringBuilder.ToString(); + + return $"{Temperature} K, {Pressure} kPa, {result}Total Moles: {TotalMoles}"; } public string ToString(string? format, IFormatProvider? formatProvider) diff --git a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs index d77ff42ebcf..371b37f733b 100644 --- a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs +++ b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs @@ -9,14 +9,14 @@ public sealed class GasVentScrubberData : IAtmosDeviceData public bool Enabled { get; set; } public bool Dirty { get; set; } public bool IgnoreAlarms { get; set; } = false; - public HashSet FilterGases { get; set; } = new(DefaultFilterGases); + public HashSet FilterGases { get; set; } = new(_defaultFilterGases); public ScrubberPumpDirection PumpDirection { get; set; } = ScrubberPumpDirection.Scrubbing; public float VolumeRate { get; set; } = 200f; public bool WideNet { get; set; } = false; public bool AirAlarmPanicWireCut { get; set; } - public static HashSet DefaultFilterGases = new() - { + public static HashSet _defaultFilterGases = + [ Gas.CarbonDioxide, Gas.Plasma, Gas.Tritium, @@ -24,27 +24,25 @@ public sealed class GasVentScrubberData : IAtmosDeviceData Gas.Ammonia, Gas.NitrousOxide, Gas.Frezon, - // Adventure gases begin Gas.BZ, - Gas.Halon, - Gas.Healium, - Gas.HyperNoblium, - Gas.Hydrogen, Gas.Pluoxium, + Gas.Hydrogen, Gas.Nitrium, + Gas.Healium, + Gas.HyperNoblium, + Gas.ProtoNitrate, + Gas.Zauker, + Gas.Halon, Gas.Helium, Gas.AntiNoblium, - Gas.ProtoNitrate, - Gas.Zauker - // Adventure gases end - }; + ]; // Presets for 'dumb' air alarm modes public static GasVentScrubberData FilterModePreset = new GasVentScrubberData { Enabled = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), + FilterGases = new(GasVentScrubberData._defaultFilterGases), PumpDirection = ScrubberPumpDirection.Scrubbing, VolumeRate = 200f, WideNet = false @@ -53,7 +51,7 @@ public sealed class GasVentScrubberData : IAtmosDeviceData public static GasVentScrubberData WideFilterModePreset = new GasVentScrubberData { Enabled = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), + FilterGases = new(GasVentScrubberData._defaultFilterGases), PumpDirection = ScrubberPumpDirection.Scrubbing, VolumeRate = 200f, WideNet = true @@ -63,7 +61,7 @@ public sealed class GasVentScrubberData : IAtmosDeviceData { Enabled = false, Dirty = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), + FilterGases = new(GasVentScrubberData._defaultFilterGases), PumpDirection = ScrubberPumpDirection.Scrubbing, VolumeRate = 200f, WideNet = false @@ -73,7 +71,7 @@ public sealed class GasVentScrubberData : IAtmosDeviceData { Enabled = true, Dirty = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), + FilterGases = new(GasVentScrubberData._defaultFilterGases), PumpDirection = ScrubberPumpDirection.Siphoning, VolumeRate = 200f, WideNet = true @@ -84,7 +82,7 @@ public sealed class GasVentScrubberData : IAtmosDeviceData Enabled = true, IgnoreAlarms = true, Dirty = true, - FilterGases = new(GasVentScrubberData.DefaultFilterGases), + FilterGases = new(GasVentScrubberData._defaultFilterGases), PumpDirection = ScrubberPumpDirection.Siphoning, VolumeRate = 200f, WideNet = false diff --git a/Content.Shared/Atmos/Prototypes/GasPrototype.cs b/Content.Shared/Atmos/Prototypes/GasPrototype.cs index 6a2d4078207..524f8a59c45 100644 --- a/Content.Shared/Atmos/Prototypes/GasPrototype.cs +++ b/Content.Shared/Atmos/Prototypes/GasPrototype.cs @@ -1,87 +1,133 @@ -using Content.Shared.Chemistry.Reagent; +using Content.Shared.CCVar; +using Content.Shared.Chemistry.Reagent; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Atmos.Prototypes +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared.Atmos.Prototypes; + +/// +/// Prototype defining a gas for atmospherics. +/// +/// +/// The total number of gases is hardcoded in a bunch of places. +/// If you add any new ones, make sure to also adjust the constants in accordingly. +/// +[Prototype] +public sealed partial class GasPrototype : IPrototype, ISerializationHooks { - [Prototype] - public sealed partial class GasPrototype : IPrototype + // TODO: Add interfaces for gas behaviours e.g. breathing, burning + + /// + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// The name of the gas as shown to the player. + /// + [DataField(required: true)] + public LocId Name; + + /// + /// The abbreviation of the name. For example O₂ for Oxygen. + /// Used for UI purposes. + /// + [DataField] + public LocId? Abbreviation; + + /// + /// The molar heat capacity of this gas, in J/(K * mol). + /// Describes how much heat energy is needed to heat up this gas by one Kelvin. + /// Or in other words, the higher this number is the more energy this gas can store. + /// + /// + /// This will be divided by the cvar. + /// + [DataField] + public float MolarHeatCapacity; + + /// + /// Heat capacity ratio for gas. + /// TODO: Make gas pumps do proper adiabatic compression so that this is actually used. + /// + [DataField] + public float HeatCapacityRatio = 1.4f; + + /// + /// Molar mass of the gas. + /// TODO: This is not used anywhere, do we even need this? + /// + [DataField] + public float MolarMass = 1f; + + + /// + /// Minimum amount of moles for this gas to be visible. + /// + [DataField] + public float GasMolesVisible = 0.25f; + + /// + /// Visibility for this gas will be max after this value. + /// + [ViewVariables] + public float GasMolesVisibleMax => GasMolesVisible * GasVisibilityFactor; + + /// + /// Multiplier that decides when a gas will be at maximum visibility. + /// + [DataField] + public float GasVisibilityFactor = Atmospherics.FactorGasVisibleMax; + + /// + /// Sprite to show in the gas overlay if this gas is present on a tile. + /// If null the gas will be invisible. + /// + [DataField] + public SpriteSpecifier? GasOverlaySprite; + + /// + /// The reagent that this gas will turn into when inhaled or condensed. + /// + [DataField] + public ProtoId? Reagent; + + /// + /// The color of the gas used for UI purposes. + /// + [DataField] + public Color Color = Color.White; + + /// + /// The price per mole when this gas is sold at cargo. + /// The final price will also depend on the purity of the gas mixture. + /// + [DataField] + public float PricePerMole = 0; + + /// + /// Whether the gas is considered to be flammable. + /// This is used generically across Atmospherics to determine + /// if things like hotspots are allowed to ignite if an + /// oxidizer is present. + /// + [DataField] + public bool IsFuel; + + /// + /// Whether the gas is considered to be an oxidizer. + /// Same reasoning as but for oxidizers. + /// + [DataField] + public bool IsOxidizer; + + [DataField("gasOverlayTexture")] public string? GasOverlayTexture; + [DataField("gasOverlayState")] public string? GasOverlayState; + + void ISerializationHooks.AfterDeserialization() { - [DataField("name")] public string Name { get; set; } = ""; - - // TODO: Control gas amount necessary for overlay to appear - // TODO: Add interfaces for gas behaviours e.g. breathing, burning - - [ViewVariables] - [IdDataField] - public string ID { get; private set; } = default!; - - /// - /// Specific heat for gas. - /// - [DataField("specificHeat")] - public float SpecificHeat { get; private set; } - - /// - /// Heat capacity ratio for gas - /// - [DataField("heatCapacityRatio")] - public float HeatCapacityRatio { get; private set; } = 1.4f; - - /// - /// Molar mass of gas - /// - [DataField("molarMass")] - public float MolarMass { get; set; } = 1f; - - - /// - /// Minimum amount of moles for this gas to be visible. - /// - [DataField("gasMolesVisible")] - public float GasMolesVisible { get; private set; } = 0.25f; - - /// - /// Visibility for this gas will be max after this value. - /// - public float GasMolesVisibleMax => GasMolesVisible * GasVisibilityFactor; - - [DataField("gasVisbilityFactor")] - public float GasVisibilityFactor = Atmospherics.FactorGasVisibleMax; - - /// - /// If this reagent is in gas form, this is the path to the overlay that will be used to make the gas visible. - /// - [DataField("gasOverlayTexture")] - public string GasOverlayTexture { get; private set; } = string.Empty; - - /// - /// If this reagent is in gas form, this will be the path to the RSI sprite that will be used to make the gas visible. - /// - [DataField("gasOverlayState")] - public string GasOverlayState { get; set; } = string.Empty; - - /// - /// State for the gas RSI overlay. - /// - [DataField("gasOverlaySprite")] - public string GasOverlaySprite { get; set; } = string.Empty; - - /// - /// Path to the tile overlay used when this gas appears visible. - /// - [DataField("overlayPath")] - public string OverlayPath { get; private set; } = string.Empty; - - /// - /// The reagent that this gas will turn into when inhaled. - /// - [DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string? Reagent { get; private set; } = default!; - - [DataField("color")] public string Color { get; private set; } = string.Empty; - - [DataField("pricePerMole")] - public float PricePerMole { get; set; } = 0; + if (GasOverlayTexture != null && GasOverlayState != null) + GasOverlaySprite = new SpriteSpecifier.Rsi(new ResPath(GasOverlayTexture), GasOverlayState); } + } diff --git a/Content.Shared/CCVar/CCVars.Atmos.cs b/Content.Shared/CCVar/CCVars.Atmos.cs index 7ef40b7911b..2516d6a908d 100644 --- a/Content.Shared/CCVar/CCVars.Atmos.cs +++ b/Content.Shared/CCVar/CCVars.Atmos.cs @@ -8,7 +8,7 @@ public sealed partial class CCVars /// Whether gas differences will move entities. ///
public static readonly CVarDef SpaceWind = - CVarDef.Create("atmos.space_wind", false, CVar.SERVERONLY); + CVarDef.Create("atmos.space_wind", true, CVar.SERVERONLY); /// /// Divisor from maxForce (pressureDifference * 2.25f) to force applied on objects. @@ -57,7 +57,7 @@ public sealed partial class CCVars /// Also looks weird on slow spacing for unrelated reasons. If you do want to enable this, you should probably turn on instaspacing. /// public static readonly CVarDef MonstermosRipTiles = - CVarDef.Create("atmos.monstermos_rip_tiles", false, CVar.SERVERONLY); + CVarDef.Create("atmos.monstermos_rip_tiles", true, CVar.SERVERONLY); /// /// Whether explosive depressurization will cause the grid to gain an impulse. @@ -120,7 +120,7 @@ public sealed partial class CCVars /// Maximum time in milliseconds that atmos can take processing. /// public static readonly CVarDef AtmosMaxProcessTime = - CVarDef.Create("atmos.max_process_time", 3f, CVar.SERVERONLY); + CVarDef.Create("atmos.max_process_time", 5f, CVar.SERVERONLY); /// /// Atmos tickrate in TPS. Atmos processing will happen every 1/TPS seconds. @@ -142,7 +142,7 @@ public sealed partial class CCVars /// gases heat up and cool down 64x faster than real life. /// public static readonly CVarDef AtmosHeatScale = - CVarDef.Create("atmos.heat_scale", 8f, CVar.SERVERONLY); + CVarDef.Create("atmos.heat_scale", 1.0f, CVar.SERVER | CVar.REPLICATED); /// /// Maximum explosion radius for explosions caused by bursting a gas tank ("max caps"). @@ -177,4 +177,7 @@ public sealed partial class CCVars /// public static readonly CVarDef DeltaPressureParallelBatchSize = CVarDef.Create("atmos.delta_pressure_parallel_batch_size", 10, CVar.SERVERONLY); + + public static readonly CVarDef GasOverlayThermalDirtyThreshold = + CVarDef.Create("atmos.overlay_thermal_dirty_threshold", 1, CVar.SERVERONLY); } diff --git a/Content.Shared/DrawDepth/DrawDepth.cs b/Content.Shared/DrawDepth/DrawDepth.cs index 35fead5b3fd..288602353c8 100644 --- a/Content.Shared/DrawDepth/DrawDepth.cs +++ b/Content.Shared/DrawDepth/DrawDepth.cs @@ -112,17 +112,22 @@ public enum DrawDepth ///
Overdoors = DrawDepthTag.Default + 10, + /// + /// Visible atmos gas. + /// + Gasses = DrawDepthTag.Default + 11, + /// /// Explosions, fire, melee swings. Whatever. /// - Effects = DrawDepthTag.Default + 11, + Effects = DrawDepthTag.Default + 12, - Ghosts = DrawDepthTag.Default + 12, + Ghosts = DrawDepthTag.Default + 13, /// /// Use this selectively if it absolutely needs to be drawn above (almost) everything else. Examples include /// the pointing arrow, the drag & drop ghost-entity, and some debug tools. /// - Overlays = DrawDepthTag.Default + 13, + Overlays = DrawDepthTag.Default + 14, } } diff --git a/Content.Shared/_Adventure/ADTCCVars/ADTCCVars.Atmos.cs b/Content.Shared/_Adventure/ADTCCVars/ADTCCVars.Atmos.cs new file mode 100644 index 00000000000..d1a1372cbcd --- /dev/null +++ b/Content.Shared/_Adventure/ADTCCVars/ADTCCVars.Atmos.cs @@ -0,0 +1,24 @@ +using Robust.Shared.Configuration; + +namespace Content.Shared._Adventure.ADTCCVars; + +[CVarDefs] +public sealed class ADTCCVars +{ + /// + /// These variables control modifications of various gas prices. If gas has no specified + /// modifier here, it will use default price from prototype + /// + + public static readonly CVarDef DefaultGasPriceModifier = + CVarDef.Create("atmos.gas_price_modifier_default", 1f, CVar.SERVER); + + public static readonly CVarDef GasPriceModifierTritium = + CVarDef.Create("atmos.gas_price_modifier_tritium", 2.5f, CVar.SERVER); + + public static readonly CVarDef GasPriceModifierNitrousOxide = + CVarDef.Create("atmos.gas_price_modifier_nitrous_oxide", 0.1f, CVar.SERVER); + + public static readonly CVarDef GasPriceModifierFrezon = + CVarDef.Create("atmos.gas_price_modifier_frezon", 1f, CVar.SERVER); +} diff --git a/Content.Shared/_Adventure/Atmos/Atmospherics.cs b/Content.Shared/_Adventure/Atmos/Atmospherics.cs new file mode 100644 index 00000000000..4dd12843d79 --- /dev/null +++ b/Content.Shared/_Adventure/Atmos/Atmospherics.cs @@ -0,0 +1,44 @@ +namespace Content.Shared.Atmos; + +public static partial class Atmospherics +{ + /// + /// Defines energy released in N2O decomposition reaction. + /// + public const float NitrousOxideDecompositionEnergy = 200000f; + + /// + /// Defines energy released in Pluoxium formation. + /// + public const float PluoxiumFormationEnergy = 250f; + + /// + /// The maximum amount of pluoxium that can form per reaction tick. + /// + public const float PluoxiumMaxRate = 5f; + public const float FireH2EnergyReleased = 2800000f; + public const float H2OxygenFullBurn = 10f; + public const float FireH2BurnRateDelta = 2f; + public const float H2MinimumBurnTemperature = T0C + 100f; + public const float NitriumFormationTempDivisor = (T0C + 100f) * 8f; + public const float NitriumFormationEnergy = 100000f; + public const float NitriumDecompositionTempDivisor = (T0C + 100f) * 8f; + public const float NitriumDecompositionEnergy = 30000f; + public const float NitriumDecompositionMaxTemp = T0C + 70f; + public const float NobliumFormationEnergy = 20000000f; + public const float ReactionOpperssionThreshold = 5f; + public const float HalonFormationEnergy = 300f; + public const float HalonCombustionEnergy = 2500f; + public const float HealiumFormationEnergy = 9000f; + public const float ZaukerFormationEnergy = 5000f; + public const float ZaukerFormationTemperatureScale = 0.000005f; + public const float ZaukerDecompositionMaxRate = 20f; + public const float ZaukerDecompositionEnergy = 460f; + public const float ProtoNitrateTemperatureScale = 0.005f; + public const float ProtoNitrateFormationEnergy = 650f; + public const float ProtoNitrateHydrogenConversionThreshold = 150f; + public const float ProtoNitrateHydrogenConversionMaxRate = 5f; + public const float ProtoNitrateHydrogenConversionEnergy = 2500f; + public const float ProtoNitrateTritiumConversionEnergy = 10000f; + public const float ProtoNitrateBZaseConversionEnergy = 60000f; +} diff --git a/Content.Shared/_Adventure/Atmos/Consoles/Components/AtmosAlertsComputerComponent.Sunrise.cs b/Content.Shared/_Adventure/Atmos/Consoles/Components/AtmosAlertsComputerComponent.Sunrise.cs new file mode 100644 index 00000000000..ca140512491 --- /dev/null +++ b/Content.Shared/_Adventure/Atmos/Consoles/Components/AtmosAlertsComputerComponent.Sunrise.cs @@ -0,0 +1,19 @@ +namespace Content.Shared.Atmos.Components; + +public sealed partial class AtmosAlertsComputerBoundInterfaceState +{ + /// + /// Управление пищалкой + /// + public bool DoAtmosAlert; + + public AtmosAlertsComputerBoundInterfaceState( + AtmosAlertsComputerEntry[] airAlarms, + AtmosAlertsComputerEntry[] fireAlarms, + AtmosAlertsFocusDeviceData? focusData, + bool doAtmosAlert) + : this(airAlarms, fireAlarms, focusData) + { + DoAtmosAlert = doAtmosAlert; + } +} diff --git a/Content.Shared/_Adventure/Atmos/Consoles/SharedAtmosAlertsComputerSystem.Sunrise.cs b/Content.Shared/_Adventure/Atmos/Consoles/SharedAtmosAlertsComputerSystem.Sunrise.cs new file mode 100644 index 00000000000..3e3ef5bef4e --- /dev/null +++ b/Content.Shared/_Adventure/Atmos/Consoles/SharedAtmosAlertsComputerSystem.Sunrise.cs @@ -0,0 +1,41 @@ +using Content.Shared.Atmos.Components; +using Content.Shared.Verbs; + +namespace Content.Shared.Atmos.Consoles; + +public abstract partial class SharedAtmosAlertsComputerSystem +{ + private void InitializeADT() + { + SubscribeLocalEvent(OnAlertSoundToggleMessage); + SubscribeLocalEvent>(AddToggleVerb); + } + + private void OnAlertSoundToggleMessage(Entity ent, ref AtmosAlertsComputerAlertSoundToggleMessage args) + { + ent.Comp.DoAtmosAlert = args.Enabled; + Dirty(ent); + } + + private void AddToggleVerb(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var verb = new InteractionVerb + { + Text = Loc.GetString(ent.Comp.DoAtmosAlert + ? "item-toggle-deactivate-alert" + : "item-toggle-activate-alert"), + Act = () => ToggleAlert(ent), + }; + + args.Verbs.Add(verb); + } + + private void ToggleAlert(Entity ent) + { + ent.Comp.DoAtmosAlert = !ent.Comp.DoAtmosAlert; + Dirty(ent); + } +} diff --git a/Resources/Prototypes/Atmospherics/gases.yml b/Resources/Prototypes/Atmospherics/gases.yml index e12bd0225df..590f33aa816 100644 --- a/Resources/Prototypes/Atmospherics/gases.yml +++ b/Resources/Prototypes/Atmospherics/gases.yml @@ -1,102 +1,114 @@ - type: gas id: Oxygen - name: gases-oxygen - specificHeat: 20 + name: gas-oxygen + abbreviation: gas-oxygen-abbreviation + molarHeatCapacity: 20 heatCapacityRatio: 1.4 molarMass: 32 - color: 2887E8 + color: '#2887E8' reagent: Oxygen pricePerMole: 0 + isOxidizer: true - type: gas id: Nitrogen - name: gases-nitrogen - specificHeat: 30 + name: gas-nitrogen + abbreviation: gas-nitrogen-abbreviation + molarHeatCapacity: 30 heatCapacityRatio: 1.4 molarMass: 28 - color: DA1010 + color: '#DA1010' reagent: Nitrogen pricePerMole: 0 - type: gas id: CarbonDioxide - name: gases-co2 - specificHeat: 30 + name: gas-carbon-dioxide + abbreviation: gas-carbon-dioxide-abbreviation + molarHeatCapacity: 30 heatCapacityRatio: 1.3 molarMass: 44 - color: 4e4e4e + color: '#4e4e4e' reagent: CarbonDioxide pricePerMole: 0 - type: gas id: Plasma - name: gases-plasma - specificHeat: 200 + name: gas-plasma + abbreviation: gas-plasma-abbreviation + molarHeatCapacity: 200 heatCapacityRatio: 1.7 molarMass: 120 - gasOverlaySprite: /Textures/Effects/atmospherics.rsi + gasOverlayTexture: /Textures/Effects/atmospherics.rsi gasOverlayState: plasma - color: FF3300 + color: '#FF3300' reagent: Plasma pricePerMole: 0 + isFuel: true - type: gas id: Tritium - name: gases-tritium - specificHeat: 10 + name: gas-tritium + abbreviation: gas-tritium-abbreviation + molarHeatCapacity: 10 heatCapacityRatio: 1.3 molarMass: 6 - gasOverlaySprite: /Textures/Effects/atmospherics.rsi + gasOverlayTexture: /Textures/Effects/atmospherics.rsi gasOverlayState: tritium - color: 13FF4B + color: '#13FF4B' reagent: Tritium - pricePerMole: 0.1 # Adventure gases + pricePerMole: 2.5 + isFuel: true - type: gas id: WaterVapor - name: gases-water-vapor - specificHeat: 40 + name: gas-water-vapor + abbreviation: gas-water-vapor-abbreviation + molarHeatCapacity: 40 heatCapacityRatio: 1.33 molarMass: 18 - gasOverlaySprite: /Textures/Effects/atmospherics.rsi + gasOverlayTexture: /Textures/Effects/atmospherics.rsi gasOverlayState: water_vapor - color: bffffd + color: '#bffffd' reagent: Water pricePerMole: 0 - type: gas id: Ammonia - name: gases-ammonia - specificHeat: 20 + name: gas-ammonia + abbreviation: gas-ammonia-abbreviation + molarHeatCapacity: 20 heatCapacityRatio: 1.4 molarMass: 44 - gasOverlaySprite: /Textures/Effects/atmospherics.rsi + gasOverlayTexture: /Textures/Effects/atmospherics.rsi gasOverlayState: miasma gasMolesVisible: 2 - gasVisbilityFactor: 3.5 - color: 56941E + gasVisibilityFactor: 3.5 + color: '#56941E' reagent: Ammonia pricePerMole: 0.15 - type: gas id: NitrousOxide - name: gases-n2o - specificHeat: 40 + name: gas-nitrous-oxide + abbreviation: gas-nitrous-oxide-abbreviation + molarHeatCapacity: 40 heatCapacityRatio: 1.3 molarMass: 44 - color: 8F00FF + color: '#8F00FF' reagent: NitrousOxide pricePerMole: 0.1 - type: gas id: Frezon - name: gases-frezon - specificHeat: 600 # Strongest by far + name: gas-frezon + abbreviation: gas-frezon-abbreviation + molarHeatCapacity: 600 # Strongest by far heatCapacityRatio: 1.33 molarMass: 50 - gasOverlaySprite: /Textures/Effects/atmospherics.rsi + gasOverlayTexture: /Textures/Effects/atmospherics.rsi gasOverlayState: frezon gasMolesVisible: 0.6 - color: 3a758c + color: '#3a758c' reagent: Frezon - pricePerMole: 1 + pricePerMole: 1 \ No newline at end of file diff --git a/Resources/Prototypes/_Adventure/Gases/gas.yml b/Resources/Prototypes/_Adventure/Gases/gas.yml deleted file mode 100644 index fceec786273..00000000000 --- a/Resources/Prototypes/_Adventure/Gases/gas.yml +++ /dev/null @@ -1,135 +0,0 @@ -- type: gas - id: BZ - name: gases-bz - specificHeat: 20 - heatCapacityRatio: 1.33 - molarMass: 100 - color: c56091 - reagent: BZ - pricePerMole: 4 - -- type: gas - id: Halon - name: gases-halon - specificHeat: 175 - heatCapacityRatio: 1.33 - molarMass: 150 - gasOverlaySprite: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: halon - color: 99ccff - reagent: Halon - pricePerMole: 16 - -- type: gas - id: Healium - name: gases-healium - specificHeat: 10 - heatCapacityRatio: 1.33 - molarMass: 40 - gasOverlaySprite: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: healium - color: 512525 - reagent: Healium - pricePerMole: 24 - -- type: gas - id: HyperNoblium - name: gases-hyper-noblium - specificHeat: 2000 - heatCapacityRatio: 1.33 - molarMass: 150 - gasOverlaySprite: /Textures/Effects/atmospherics.rsi - gasOverlayState: frezon - gasMolesVisible: 0.1 - gasVisbilityFactor: 1000 - color: 0066ff - reagent: HyperNoblium - pricePerMole: 30 - -- type: gas - id: Hydrogen - name: gases-hydrogen - specificHeat: 15 - heatCapacityRatio: 1.5 - molarMass: 2 - color: e1e1e1 - reagent: Hydrogen - pricePerMole: 10 - -- type: gas - id: Pluoxium - name: gases-pluoxium - specificHeat: 80 - heatCapacityRatio: 1.5 - molarMass: 44 - gasOverlaySprite: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: halon - gasVisbilityFactor: 1000 - color: 25aef7 - reagent: Pluoxium - pricePerMole: 10 - -- type: gas - id: Nitrium - name: gases-nitrium - specificHeat: 10 - heatCapacityRatio: 1.3 - molarMass: 50 - gasOverlaySprite: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: nitrium - gasVisbilityFactor: 500 - color: b65d40 - reagent: Nitrium - pricePerMole: 24 - -- type: gas - id: Helium - name: gases-helium - specificHeat: 15 - heatCapacityRatio: 15 - molarMass: 4 - color: acac00 - reagent: Helium - pricePerMole: 14 - -- type: gas - id: AntiNoblium - name: gases-anti-noblium - specificHeat: 1 - heatCapacityRatio: 1 - molarMass: 200 - gasOverlaySprite: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: anti_noblium - gasMolesVisible: 0.1 - gasVisbilityFactor: 100 - color: 003000 - reagent: AntiNoblium - pricePerMole: 40 - -- type: gas - id: ProtoNitrate - name: gases-proto-nitrate - specificHeat: 30 - heatCapacityRatio: 1.33 - molarMass: 120 - gasOverlaySprite: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: proto_nitrate - gasMolesVisible: 0.1 - gasVisbilityFactor: 800 - color: 00cd0d - reagent: ProtoNitrate - pricePerMole: 10 - -- type: gas - id: Zauker - name: gases-zauker - specificHeat: 350 - heatCapacityRatio: 1.33 - molarMass: 110 - gasOverlaySprite: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: zauker - gasMolesVisible: 0.1 - gasVisbilityFactor: 100 - color: 000031 - reagent: Zauker - pricePerMole: 3000 diff --git a/Resources/Prototypes/_Adventure/Gases/gases.yml b/Resources/Prototypes/_Adventure/Gases/gases.yml new file mode 100644 index 00000000000..1107040a269 --- /dev/null +++ b/Resources/Prototypes/_Adventure/Gases/gases.yml @@ -0,0 +1,152 @@ +- type: gas + id: BZ + name: gas-bz + abbreviation: gas-bz-abbreviation + molarHeatCapacity: 20 + heatCapacityRatio: 1.3 + molarMass: 100 + color: '#9370db' + reagent: BZ + pricePerMole: 3 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: bz + +- type: gas + id: Healium + name: gas-healium + abbreviation: gas-healium-abbreviation + molarHeatCapacity: 10 + heatCapacityRatio: 1.3 + molarMass: 40 + gasMolesVisible: 0.1 + gasVisibilityFactor: 500 + color: '#8b0000' + reagent: Healium + pricePerMole: 12 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: healium + +- type: gas + id: Nitrium + name: gas-nitrium + abbreviation: gas-nitrium-abbreviation + molarHeatCapacity: 10 + heatCapacityRatio: 1.3 + molarMass: 60 + gasMolesVisible: 0.1 + gasVisibilityFactor: 500 + color: '#8B4513' + reagent: Nitrium + pricePerMole: 12 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: nitriumGas + +- type: gas + id: Pluoxium + name: gas-pluoxium + abbreviation: gas-pluoxium-abbreviation + molarHeatCapacity: 80 + heatCapacityRatio: 1.3 + molarMass: 40 + color: '#0054AA' + reagent: Pluoxium + pricePerMole: 5 + +- type: gas + id: Hydrogen + name: gas-hydrogen + abbreviation: gas-hydrogen-abbreviation + molarHeatCapacity: 15 + heatCapacityRatio: 1.4 + molarMass: 2 + color: '#FFFFFF' + reagent: Hydrogen + pricePerMole: 5 + isFuel: true + +- type: gas + id: HyperNoblium + name: gas-hyper-noblium + abbreviation: gas-hyper-noblium-abbreviation + molarHeatCapacity: 2000 + heatCapacityRatio: 1.3 + molarMass: 150 + gasMolesVisible: 0.1 + gasVisibilityFactor: 1000 + color: '#33cccc' + reagent: Hyper-Noblium + pricePerMole: 15 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: hyper_noblium + +- type: gas + id: ProtoNitrate + name: gas-proto-nitrate + abbreviation: gas-proto-nitrate-abbreviation + molarHeatCapacity: 30 + heatCapacityRatio: 1.3 + molarMass: 120 + gasMolesVisible: 0.1 + gasVisibilityFactor: 1000 + color: '#009933' + reagent: Proto-Nitrate + pricePerMole: 5 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: proto_nitrate + +- type: gas + id: Zauker + name: gas-zauker + abbreviation: gas-zauker-abbreviation + molarHeatCapacity: 350 + heatCapacityRatio: 1.3 + molarMass: 110 + gasMolesVisible: 0.1 + gasVisibilityFactor: 250 + color: '#1c1a1a' + reagent: Zauker + pricePerMole: 15 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: zauker + +- type: gas + id: Halon + name: gas-halon + abbreviation: gas-halon-abbreviation + molarHeatCapacity: 1.4 + heatCapacityRatio: 1.3 + molarMass: 150 + gasMolesVisible: 0.1 + gasVisibilityFactor: 500 + color: '#e3574d' + reagent: Halon + pricePerMole: 8 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: halon + +- type: gas + id: Helium + name: gas-helium + abbreviation: gas-helium-abbreviation + molarHeatCapacity: 15 + heatCapacityRatio: 20 + molarMass: 4 + color: '#005959' + reagent: Helium + pricePerMole: 7 + isFuel: true + +- type: gas + id: AntiNoblium + name: gas-anti-noblium + abbreviation: gas-anti-noblium-abbreviation + molarHeatCapacity: 1 + heatCapacityRatio: 1 + molarMass: 200 + gasMolesVisible: 0.1 + gasVisibilityFactor: 100 + color: '#525151' + reagent: Anti-Noblium + pricePerMole: 20 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: anti_noblium diff --git a/Resources/Prototypes/_Adventure/Gases/reactions.yml b/Resources/Prototypes/_Adventure/Gases/reactions.yml index 82c2e86ba45..f0689be8e6b 100644 --- a/Resources/Prototypes/_Adventure/Gases/reactions.yml +++ b/Resources/Prototypes/_Adventure/Gases/reactions.yml @@ -33,7 +33,7 @@ - 0 # bz - 0.01 # halon effects: - - !type:HalonFireSuppressionReaction {} + - !type:HalonOxygenAbsorptionReaction {} - type: gasReaction id: HealiumProduction @@ -91,7 +91,7 @@ - 0 # hyper-noblium - 0.02 # hydrogen effects: - - !type:HydrogenBurnReaction {} + - !type:HydrogenFireReaction {} - type: gasReaction id: PluoxiumProduction @@ -114,7 +114,7 @@ - 0 # hyper-noblium - 0 # hydrogen effects: - - !type:PluoxiumProductionReaction {} + - !type:PluoxiumProductionReaction {} - type: gasReaction id: NitriumProduction @@ -136,7 +136,7 @@ - 0 # hyper-noblium - 0 # hydrogen effects: - - !type:NitriumProductionReaction {} + - !type:NitriumProductionReaction {} - type: gasReaction id: NitriumDecomposition @@ -164,7 +164,7 @@ - 0 # protonitrate - 0 # zauker effects: - - !type:NitriumDecompositionReaction {} + - !type:NitriumDecompositionReaction {} - type: gasReaction id: PNProduction @@ -188,7 +188,7 @@ - 0.02 # hydrogen - 0.01 # pluoxium effects: - - !type:ProtoNitrateProductionReaction {} + - !type:ProtoNitrateProductionReaction {} - type: gasReaction id: PNHydrogenConversion @@ -214,7 +214,7 @@ - 0 # antinob - 0.01 # protonitrate effects: - - !type:ProtoNitrateHydrogenConversion {} + - !type:ProtoNitrateHydrogenConversionReaction {} - type: gasReaction id: PNTritiumDetox @@ -242,7 +242,7 @@ - 0 # antinob - 0.01 # protonitrate effects: - - !type:ProtoNitrateTritiumReaction {} + - !type:ProtoNitrateTritiumConversionReaction {} - type: gasReaction id: PNBZDecomposition @@ -270,7 +270,7 @@ - 0 # antinob - 0.01 # protonitrate effects: - - !type:ProtoNitrateBZDecomposition {} + - !type:ProtoNitrateBZaseConversionReaction {} - type: gasReaction id: ZaukerProduction @@ -295,7 +295,7 @@ - 0 # pluoxium - 0.01 # nitrium effects: - - !type:ZaukerProductionReaction {} + - !type:ZaukerProductionReaction {} - type: gasReaction id: ZaukerDecomposition @@ -322,4 +322,4 @@ - 0 # protonitrate - 0.01 # zauker effects: - - !type:ZaukerDecompositionReaction {} + - !type:ZaukerDecompositionReaction {} diff --git a/Resources/Prototypes/_Adventure/Gases/reagents.yml b/Resources/Prototypes/_Adventure/Gases/reagents.yml index 5552fc9436c..c7ce4968ce9 100644 --- a/Resources/Prototypes/_Adventure/Gases/reagents.yml +++ b/Resources/Prototypes/_Adventure/Gases/reagents.yml @@ -316,7 +316,7 @@ meltingPoint: -259.2 - type: reagent - id: ProtoNitrate + id: Proto-Nitrate name: reagent-name-proto-nitrate desc: reagent-desc-proto-nitrate physicalDesc: reagent-physical-desc-gaseous diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png new file mode 100644 index 0000000000000000000000000000000000000000..efc8a5c30903bf5a7349b33fdaa1bafb2d00b1ae GIT binary patch literal 3326 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 IM6N<$f?K#v8UO$Q literal 0 HcmV?d00001 diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json index 359e98841da..b8ba256e6c5 100644 --- a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json +++ b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json @@ -8,8 +8,8 @@ }, "states": [ { - "name": "nitryl", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + "name": "bz", + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, { "name": "nitrium", diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/nitryl.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/nitryl.png deleted file mode 100644 index 4fa5e1d231d42831c73fdcd1873d740736220b8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2152 zcmV-u2$%PXP)Nj35QJ5XgGo3MN8y~D9wYIOSG5G^=$-?MmDN?Mr$+)aSYU1psXzYt`_I2d9#3NI ztAL-!vx>(G{@&hI()z#`J3+x~U<+MwFbAF^upu|*AL8{WUc_<0S8n{w|NOfofb&`_ zgjD0d9Z&&~9>UtFPC>}ftXj|3hx#Ap^AXpau>c1_L=ZeWsMd9F{7M()fnAF?UKEHb z7k~&u=X^-o8Bjc|YNEn^~RQp?L<5pETRMGC zKh^v#npc*YXTIJ#%=bGiKo*DwN)NS4bHmz3()V0zi2&{-07&_Gb!IY~TtwSgAwZrf zd-$sB*g*i$dI9>-j3r=cR)Z0~3SJ+=EC~Seu-S#7hqS}xO_{bW;Em9GTiaKVNoC;G zMgKYdyAqZD8tt_}XneTYt6adUzJaS7LaOgLqEOfJmq7GYXVms1n%eZ>u-DMOzln@5HwtXae9pK-b}4sd4SvW{m5+^fJ@ehcTct zsy^sy4L`1*|f2omIy!q_oW$E4?noTjzGUbdWAtfSvt!2fQXuwi!d!w!!bMrO6&$h>ukW z`agluw#;Q$cf$;guTJ6@A=*)#xm~R2Vvd069Tahgh7bl>^UEIM?OkQ11*pN^%@m0LfSfXvGahWS{$-+kP8Y6ZY^b<_3 zgm!HM=`iycODzKVnz&sqLpsba!ZR};nHRMjD9re4hcxg?^Xt(^=dMDg_d*QR5drAZ zJj5(|f^n=ZV}2{G8j|f?1u@HdC~tlYRET9X&x^i2^NR+nE49|twg&o{XZsEUBNrhR znswDHX`=_i z2*Nxrn!%X!q8|)#2^;h71k}Z`83L;9QB9X(5Rq2&GHCVTXY**!RY?JAwq}4}Wq>NK z?+*O{(&0quAcDY}^E0A1qO0(+zQ_kdSW_3>5bv5uzY4*rQw>OSv3du`Lw1`4e7$e@T+AJni)h6w4ypX(?Q42@c7SG>W!cF{Q#ZF zq?MVps2bU8-7_*SZH88L6=8ikxN9+IAP??UBO}-$P}9sc8V{5_L+5SabNaXAu&%zL z>)`Lv(_(=T&@`~BX=Il)smgR`*AU@dx^|``C@bwR2}7fF$+TOM zs5d5x&O<^3Ot-cu#H`Qpz)o1{mMjIaTtd{Py3fU4 z234hSEG!FD1uexyQ%|Ov=iLTo-lxE30V!!yfIN_v+j<#B#3XC4S+BF01y zpLV$ndI>-C`v=ZuPcxgEY0TbjbOG%TuwL`#igR}83f6#VsstnuwccyhxS?lLR+hzH zz@c-+FN)0iTlV0xg(8m^OE=vMhs0nY;8t4EbDu1@HbD zxu32`Yce!eXxw=`v(EPVL?#QE7w7%|cujK?(b~9G3}O7FS8VA>0kep#>21y&1FR}~ zSbVMy!YpL(LpqRJlXV%SX==scpmSJ3^Q;IGgn7tj8dsOY-_9^n2gvwab}kcyWezi1 zb71*KvWj`0q#R)@P+1B_^IEH_$D%6;LoE=Ub_HovS1`ZlMuI>oV2j2Jhu&PwKf@T?*uHXuP+g0uz1nsMXumhJL{uup#FF>mecQB% z7kNKA*K#K!m_HsJ!7i64j0R>kt~1SK`XnHre=-K$z+H0eN<^AAZiAJ7HtvpKHEvZ5 zQHGtmf-{#wyI_?CWL%Fqb{7Gd?+wn-QbFs%ym*EQ_PP;?y%5&}1?f8oKr~{uHX+j$ zBw Date: Wed, 13 May 2026 04:42:02 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=D0=9D=D1=83=20=D0=BF=D1=80=D0=BE=D0=B1?= =?UTF-8?q?=D0=B5=D0=BB=20=D1=82=D0=B0=D0=BA=20=D0=BF=D1=80=D0=BE=D0=B1?= =?UTF-8?q?=D0=B5=D0=BB=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=86=D0=B5.=20?= =?UTF-8?q?=D0=9D=D0=B5=20=D0=B7=D0=BB=D0=B8=D1=81=D1=8C.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Resources/Prototypes/Atmospherics/gases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Atmospherics/gases.yml b/Resources/Prototypes/Atmospherics/gases.yml index 590f33aa816..a8ce3bd66ea 100644 --- a/Resources/Prototypes/Atmospherics/gases.yml +++ b/Resources/Prototypes/Atmospherics/gases.yml @@ -111,4 +111,4 @@ gasMolesVisible: 0.6 color: '#3a758c' reagent: Frezon - pricePerMole: 1 \ No newline at end of file + pricePerMole: 1 From eee23adb2d6cf70b40b25a4b8e536d4d84b51149 Mon Sep 17 00:00:00 2001 From: SunChan07 Date: Thu, 14 May 2026 04:16:50 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=D1=82=D0=B3=20=D0=B3=D0=B0=D0=B7=D1=8B=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B8=D0=BC=D0=B5=D1=8E?= =?UTF-8?q?=D1=82=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5=20=D1=83=D0=BD=D0=B8?= =?UTF-8?q?=D1=84=D0=B8=D1=86=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=81=20=D0=B1=D0=B0=D0=B7=D0=BE=D0=B2=D1=8B?= =?UTF-8?q?=D0=BC=D0=B8=20=D0=B3=D0=B0=D0=B7=D0=B0=D0=BC=D0=B8=20=D1=82?= =?UTF-8?q?=D0=B5=D0=BA=D1=81=D1=82=D1=83=D1=80=D1=83=20=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B9=D1=82=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Overlays/GasTileVisibleGasOverlay.cs | 1 - .../Prototypes/_Adventure/Gases/gases.yml | 4 ++- .../Effects/atmospherics.rsi/anti_noblium.png | Bin 749 -> 2263 bytes .../Effects/atmospherics.rsi/bz.png | Bin 3326 -> 10898 bytes .../Effects/atmospherics.rsi/halon.png | Bin 2659 -> 10248 bytes .../Effects/atmospherics.rsi/healium.png | Bin 2382 -> 8984 bytes .../atmospherics.rsi/hyper_noblium.png | Bin 0 -> 10365 bytes .../Effects/atmospherics.rsi/meta.json | 30 +++++++++++------- .../Effects/atmospherics.rsi/nitrium.png | Bin 2666 -> 10196 bytes .../Effects/atmospherics.rsi/pluoxium.png | Bin 0 -> 10625 bytes .../atmospherics.rsi/proto_nitrate.png | Bin 2423 -> 10663 bytes .../Effects/atmospherics.rsi/zauker.png | Bin 2337 -> 7270 bytes 12 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 Resources/Textures/_Adventure/Effects/atmospherics.rsi/hyper_noblium.png create mode 100644 Resources/Textures/_Adventure/Effects/atmospherics.rsi/pluoxium.png diff --git a/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs b/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs index 7e6847c10d2..4e02bc423c6 100644 --- a/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs +++ b/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs @@ -36,7 +36,6 @@ public sealed class GasTileVisibleGasOverlay : Overlay Gas.NitrousOxide, Gas.Hydrogen, Gas.Helium, - Gas.Pluoxium }; private readonly bool[] _isTransparent; diff --git a/Resources/Prototypes/_Adventure/Gases/gases.yml b/Resources/Prototypes/_Adventure/Gases/gases.yml index 1107040a269..4502b26df1c 100644 --- a/Resources/Prototypes/_Adventure/Gases/gases.yml +++ b/Resources/Prototypes/_Adventure/Gases/gases.yml @@ -39,7 +39,7 @@ reagent: Nitrium pricePerMole: 12 gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi - gasOverlayState: nitriumGas + gasOverlayState: nitrium - type: gas id: Pluoxium @@ -51,6 +51,8 @@ color: '#0054AA' reagent: Pluoxium pricePerMole: 5 + gasOverlayTexture: /Textures/_Adventure/Effects/atmospherics.rsi + gasOverlayState: pluoxium - type: gas id: Hydrogen diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/anti_noblium.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/anti_noblium.png index 2c9b61f82fc07be2b60c2f929004146010b97b47..876cfc1587e880cb5e68ebe6334abbf7f574831d 100644 GIT binary patch delta 2202 zcmV;L2xa%}1=kUfReuOS=YHvaHzeRJ|=_x;*;chfvGnVr4o&c3_%+;i@^_kW&~0I;4MBODGt(bUv* zIvfsfXliPDSj%&XJl(K_Hv|HKQ^2DY6&1&UHCmp)kpjZu@Dsp3dG#Hc_3ha_`ztCc zrhs?r>gpzdx3xThBLz62rl#f?@K`7mI<94lk-@>iO~C%XzP@HHGZOG?4OqQ;bvPD_ z9jU6S+J5ok#edtiJjdApyaim;f>b0^z(ybrysiaH%;R(7X3l9rDw4UNo=gpXG#YIK zw#lon)YjH^1KSdR^1fd8Q;Y$ny3q>B6mV5CK0aOqR3+X|PEHmA<8yn>W8A3%lDQxw z-M~+PBH$t5E6G-NA87#210!0H4x-U$TSG%bcQhK^+JDf{@I8a*pB9S&=o4lrz zQ@|w9lxUD=wgS(2{T*c1A5pU(pa7Ujys{8??FxSfL(h1lqO0B_ZHi;GbGxV6C{qUjZLzVK$Qw)apiuybILHVsu^$ zZBik#`gY*cGP?$JCj;+`qCO1#LkqK+RAyQ%KWZ~@5AaRhLGcGs!Uio!kitJU0^b1c z237%o1@>FqkGu+8pX}gEp7}-K+rU1H>%%p`U4KA{7C1rweyxBi38}VAsQE46R+04r zzgGP<(?F+0MYm|71^R&B0KWjbfWPPtNtgk`z-P2TF(C_gfd4PrKTV>H3ETZK;<+I+FLGhCtfWPU+g@{BVZH&sDCGkhfOc;-7T~yJ#0Q4;L~0Wf}P2X@OPb znO_FJ4zxP>4z8)It2+#QcjLy5FUy+P1snlx0`ArQ?UGUffx!PZc!}4AkXe7k#EhM| zFe5X-tVC>?ARn0S>+7qQJr5G)9RyxfeSdA^nG4DS+GX(uco^8NxOirxAT4?&wL1Y6u8%IXzWS>l9#h-q5K^Aa({b) z2Z8(Cepx5jRhGq^qft4cnAHNixKe;cX61}%S__=w^8UgV^2}cXKLVaN+4tCD&LUh` zSa@P;YU+n_%b#CZSonjfsi`}iUN$%($-V2MWR3;Q&dwGXG5{*$@pyrsgMT&RRTz34 z_&G2Hd`IH&cXX#E=Ht~GkSFIP=YJ)2#qIgeRfAU+u!KXrvVbKVVoL$#<>e=UudZLe z{uM1t7k=+d{l=C8cI?=30hk^f91H?wTAl^ms`7)gwvtz{JXxD}Tqd&}05C zuQ%e+43%Vs<+>63lfx7<1q6$Wi%$a0EiEkvfpxlr31gDE)+!khM&2737}x@|_xJbT zp=9acw8vI(9k2)30aR+CTTH{y^78Uy!^6WrE-Nd0WMpKdNzQSKETsM20^AHdFYX{y zv`S9VpR~XsdB7({vFCu37Jq66EMaB=3=a=)20BJYMjl8Uq7@exACK65gP+*l^F0ZV3QVT3`gcK0FR_NGQSKQHC+C?CY1uN5R1j`0Dlh4y=&*t(9mYx z$3PG8hWO6wwa_UxkD-qPpR#F*ZrsXd$p*BA=^EgGicl!jH99)Ff7h;EdpbHg?vnO( z5=D5H%4d@%`HkIL;4xbzQhL#BoeYISCq_p{pDisdy?<^7s!vIV4IsJ^~_5a8_D zvz3xkj#xpa1|Q%xpnqRCddzm2WWO~Ve1QD?{8?bSprBx$+jeRJ>!c3guoh%1hYlTj zs->mnTxVzJO*?n){F;_Kpal55gy3CTXccV%bIfA_wgOvZp-mTM;=fICvcXD~TIqm2 zviEU3_=p0o6eX9GlsulqA}WFVWpJKJQL$o)Xf)a;QO9Gwy??#N=;H&iGAA_#rpT;+ z-0tj8qU@(7*l@)h3s|*k)hKYm*e2W{1qyEg9l#~s!71^09AGv-e@^c0CEz6~^q5zr z?!^&6wxHL5Wl}w2WP`Yat_;*)C5lGgloF%`$>e3e)JD7^DeHZaNaSNyvnBKzU>y8P z@pEe>-_q~FM}NvqpON#WR^z`A$U@>y(&)7XB&d+Jb#8}vACd|#UC{< cu^|5i786(0g~Hhvq5uE@07*qoM6N<$f}ZIq`2YX_ delta 676 zcmV;V0$csp5$y$#Reu74Nkl7T zT+2+1@j>FIN10EOI`k?Eu*#P;n2Xq05%n7=8e@?8>$fbKDdF0000< KMNUMnLSTa5!#8*U diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png index efc8a5c30903bf5a7349b33fdaa1bafb2d00b1ae..97c9892f67c95e6024008f4b1fba8d0199ffa392 100644 GIT binary patch literal 10898 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 spR18@4q1 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 delta 3273 zcmV;)3^wzURsI=}ReubVNklO?Y&cGc!08GSJMkAFK_Wmx1W1Sw3y_d3z5(~#xuZ*GE&iz;2Z`SYK9RBgU!{PAe>%$)p&krBkVdKiSU&~&p+J7F(`?254wQZl>A9lQq z{SRXgUdINwcRu*>^TXf&{51|=c!N=BP@?@}o=ZD?>kYxjKYxDs{pUV^rtAC6wm0{O zjaRWJmC#3vkDD%lApyjLuz*4Ww)qzdX5#-gHj4gN+khIO&26G#ZfrN+V3??v5Hx7* z88uQEk%B^8XMZ9-=nMq|IECd^WD0c=`-&^MdBSn8CZ2`QfH>c^jlx1i;%y?n;-Z>i zDL%k4#YUT+gFH93J3qVUZ3v2awLQ~>PITh#0V(KLah$z+cbeH7x+KDu^S2bVF%N|N z=KjzbBEiOA+jwnn#*vhhX(=ePNF$i<#^zfYX%{fSPk-Y0TVwI%VT3R54+kjtAoPsF zfEpb$rUux6DT+q$+-^qm{hs`9+_n@H>4PcbSXei(AJWuBe9%Q$N;R4~b|K=o+7ZAI znX2s=Abgj;@E;R?CO)9}H*gl?(`JAWX;;cAU?Io;d-sPOxv(n`0^7CR_{+FKC!Awo zQX3%tzkgy+?{85c^Rn&MwkoHiT|poA%l&yiE!>8Vxudf*0}#8xSrnA*g*crN<9c3c z0Y(ahKoRbU8}#%O&Oxtk-fafcHf|WB^L3t%dE=hg{;6%vGh+|Xj&ll!KJ3Rm`9bVg zH6f4jc{gi7%Bw7#gy-;Z7diE3d%IpRdk#Pf(tm9a5Opi(H|$DkMoSst@&sAKF6t@4zwlabwjbx!;ho{cOr}yi1iqC5+@``B-7asy2 z!BTv%G62Q>D)!S{tcdj$%+-vixjXVcJa;g_taxL*Z4|FE5Uy$J>C%wFR8?^^`JSGh zCV$@#Y+bLo)f6;KFS-4(S-pyYaCo&aivp0-PCHNO0N|QF^uZ7<1xf$S)B#|q#R{)N z>xrWgkVWSCQR4535}`~>0)$+N4^({gZD}aP)O4icgDwiTyw|>)7U|oG_!L=D;j!Ty z+s!HkJ%}ScVy|)42&??ge%gO3cu)yedVjxtH(llYH}(qNB~f6Y!UH|Wc2^qUNG~RN ztv`Ej#CG&wMF2!(?(PJYLdfex`&VLvJf;-8fZh)gDI}j2ny})4xTeMc*$`a{qJXcC z^kR~inXPyy*pB{X{ttm6qNbNj782xigpCn{{y63{LKjKqbQDF?47s)I^nQBpzkh9; zElc0pci=S|LFc6*4$ovo0zu%B*uxl|M?WwsK#mN+HY`sEA{SG@fw&H_DR^ZJj%6gE zFOL1(z7L+38|HKn1zzhyOO*NgU!1aed+dQ8J9dwq=i7WR7=bZx{gQ7(H*+xzkRt=e zOYc1(tp2#OX9czVL8kg#1A;?P?tg(E19&*Z?hGmSM#`6QMZXyk5>LXL4`~Hngm)D} z6M?zAOZ;vw`;MIJZtv@8_w4(_$HTtBg&Fauc1W>S(4(uUfXH}tjeoSFhR8s0 z)&R_f^FR36yWwf-{%}CA!4OPWZj^ErB>9g#RD8|x>49kMrd_C9<~$ z5Qxg6O`|M}cv>mxc=Aiza!LRYQ1iKqW}q*wZM`D`c@BVi{PQA$bbl4Z)KH<`zUsGy zj=dZrAS(L|6%WULE}lnPMCeM%`nB=m9hLaNS2%J%=%;=42YQIg&58N5_<(cZT~X_A zY>5i-(FY9ul5XrbVE2WwxbB~KYy?b+{2FIVx*B2NIiPvvJHoUB;VbX2+FnGI4hDz_ ziL=dmpiB*wbz%fOXn)PFaMD#Y1Qeg`NF$Z_tMsCtt3X@|Od}{N{xzepc%JdSh!61c zjVm5{a0LyS#rOW%Noj!DdmBXyu^xBerc*d}OIUt6L)&M9zAM?=mG77sG%|#3f=wb> z-~Ds~$M>CjeNY;t)c{PAgv&60SA|r$3Xh_PcM(v0IYt1yRewEJb9|;nOc?Z71LAY= zxir9@)S?2mm5gXM2w!9a7@A|fKWc#gajtDSH=%o)}RvRcdjOdG-wN zZvvE&vM1js@gaCiK?c$a#N}2oYd;ImigYtD@i-W&8E@y4BKubbUGq8_+S2E+ZtO8lXRdvgmI0nT3XY9|)Y8BMj z6MrRwikl6`^W5HfI=nPKlkG6X@Q?q(n?0q3BT>*MtQkz(xM587j|orCJG~2fBxdh| zoLn>$r~ybr-0uNKZPE5*pM-TP2!Ii2I384K(T6Y(L^W;nqk{#_Qk70JQx5( zA=PxCPrP83{|Q9g%Ks`fjK%Y_ry&}k36?|Fywrs=p|D^5cA#u7TY;@yINvdX&wtP; zSP4sG4N-Fr9=!%w1idsP?s;>{h^SUURlcu)h7>lQ4daEPewHKtCW|%Y{ zB9}Sb?&ZSnWhF2L+^PYfjH)LW0e>RCdODBY0bC6Yo-0ub!)eepdhImIf;^7*j$?hk zz`1|kxlsc!{|{irlF~?L01-vo_dE+|A@)=u5$9rxfSx{5L}n2wGWz=XwAxZ-3yp)#*+^$6;W1uCK+Ksz z*v>xMm-}3VTY*fh3~>yMIDE#FdL3QW0E)C?)u$3%+dxi1Dn9>z)IvxlmH4Yd+B`jh z`S}@@p-;+k6=bMT$Kd0N)f0`Z#$Ji=zSS3sJQMW)n8V?J%&>GQK)I`x00000NkvXX Hu0mjf-nvRz diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/halon.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/halon.png index b134a5156dfa69f87d362dd8df6848ec113c9d34..bfe85181f7298544f73fcdc3a39e1184ad83a926 100644 GIT binary patch literal 10248 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%0Ap+0G94mBon*N}=Ait+9PL-mt(b`0WXnuh%QV^U_ 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 b{}23MC+CG!c`!Pe00000NkvXXu0mjfxsxvH literal 0 HcmV?d00001 diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json index b8ba256e6c5..9842fc9d8e4 100644 --- a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json +++ b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json @@ -1,39 +1,47 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/tgstation/tgstation at 04e43d8c1d5097fdb697addd4395fb849dd341bd", + "copyright": "https://github.com/SunChan07", "size": { "x": 32, "y": 32 }, "states": [ + { + "name": "healium", + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] + }, { "name": "bz", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, { "name": "nitrium", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, { - "name": "proto_nitrate", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + "name": "pluoxium", + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, { - "name": "zauker", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + "name": "halon", + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, { "name": "anti_noblium", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, { - "name": "healium", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + "name": "hyper_noblium", + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, { - "name": "halon", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + "name": "zauker", + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] + }, + { + "name": "proto_nitrate", + "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] } ] } diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/nitrium.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/nitrium.png index 28387ab2b705987fb231d9c488dfd6b6f58737c9..f00bcdff5159dd0ef6515bd9cf37798a502c4bae 100644 GIT binary patch literal 10196 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 delta 2643 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�xZND7%TNyP3omi^LwsRAzlyi$uoMlaY6I5Pa-vqyF=omx$XI4uz(Pq zfTdH!RREw3FZsdSuN;ICsd^-t+;RPsLYx3Lo>ZP$wXD}=YiikNf<1L(vT2Jm*)jf{ zu$AW{epC^M7Rgi1Ey?+;j#xLQ@zIBm(473+bXG@dIro-hN5?D)Sq;RLHsX(xFtY)H z3n^ORl=O?8mEdHp&%L8KfR75XP3Jai*dLn7#o?GQnpn_M2~!O;oY$#7y7g<1jq=0> z^SiD^Ex(pOWPqw=Vyo6YIX+Pp$HpCn*Jg1n4yOPB@7TNw@7TQbjvJZ|;Dv|~a;za% z>Nao9p0R)0cE=cXh&dQMD!W;sap5XA-^<28{|J#zkzTeR<`h!7HMKC2_%@aB>BDcWV@F}03Sh$UtY9D%L$;*z9@_m*E- zrldx?CxTt=6S6C`c$^7cco)TdR!725Sl0Tc-xmVUtAsBMyRbUWtjErQLvq(rha*Bl zH=?1~8GaL;^MqSBWTN>yQOxEra^7n-o3GP+z8A-~qLRfn5G~}MzR-C=3llJz!}jPa z0}v8-(F;`n-(XRSN+d0%HT!KghmmV@%Xj^VPVZjojKb6~mMq7GCaj6*IffUN6%?9> z;b-|#+}T?8^L)lPU?+1U|0h~L)raled{f^Vo;k36)NwzL?Iv3KOajs3>z}vo b#f1M2)|OM?IB6f+00000NkvXXu0mjfHqtSA literal 0 HcmV?d00001 diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/proto_nitrate.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/proto_nitrate.png index 7a43f2bff33eccab663d62a123a8282d22b67996..7f60944734ce56f90c299945822a92c7873c2ffe 100644 GIT binary patch literal 10663 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 delta 2311 zcmV+i3HbKrIH3|DiBL{Q4GJ0x0000DNk~Le0001h0001B2nGNE0M&YWNs%Eme+afo zL_t(|UhSM)QmaP{gh{f8yk-H}N%ntMksahIv_UQ*bRW$>2K-gI0RJ=UR*!t)a?Wor zFE9VR-gfcp{iDX;?;ky^{n6f4T_U6JX=zA(+F$Xd!F^a7pYR4C)4YZkNVZ9@MwM=` zlO71o3+Y%sGv`qCdfzJtU`NwLfA%1zJY@AOR((|Tp{1?gaULIZ_yBORRWsf2BMn~H z3T=W;@H@P8d~iZfl>y-F3g2sZ*I`Re9KM$QB|fYH09OT0R2tst?Zg0pjxML=;g8qb zf3LTHZ(n@`_x<_y=@!s1X;hoXK7Q-?gr?lrJ%ovzPy@YmX?egiz+Z2lf41pN9uFG( zyTNlRK1h%D;OkW%og6f}9$NYn0{}YVPm}eqOP{Fvp!N6~pRf3M z-~m`Z9w7tb*Yp4oJDS&OX6ng(T@R=AJA~(u9e_t@-f9M15$b7uFn$gz13;W?o`46s zzRS;PeK39wQv-0id5cLue;xe{6_4ZRFfjlYQ{hhs-|@BU@QJLaaUanDoDP3i@Q>sJ zwKIOUc<=_`5yH1T$QoU*Sue8w)%sw|d2|NgMDtZ5Pdl~24t-g339@6TYN$t?Bf10#*@(t{cnq{;B z$UGXR!bhD<5T2*57peK!y4@;pmSQ%igcidO$ zLDRROy0<+v0IP5Ve^-aksRlPmH-jn9T%Yjj-qugO1d!0F@QIW9kJfwS=XQPS8Q>=) zA9<$-f&8R={Dc9}o*Id%!{QpUW~5&_FaxQPu7v^U{2YLzHCUHLl$!S@BAHJr4xeiO_0DEeUCR9z3|e>i)m^0LVr=W;n8* zhNiL7PzJ3&?(1l+c-`G+#7&kd0^jd{Z}7=2@fFB(sVrU9j?s%jvRoj31Y>J)RMI_UZ%o0 z6273CJ+b6Tz6rd_gr=j_*gXWOe`VhmU42f)3+a9ME?|PlMAWFezb{{kVAY0Tj z)djk;X1BqLw@Bj=h9K%^*$W>4kSRDl02ZC*I^IYJd%5OS10Z!ZvR*R%f9SC@03ai@ zN;l|Le{WH!8DCuwR2%yvA0V?v2e7KiSs8$?4>z#?mIvv+r#sJ z2zh0D$Oh0orF|zm0GLkek@DmVlX(g74jvPH)l(Pg?5xc>@#vI3G!LUWL<67&lf^QK znpN|j57g4GuWD%fX-&0umZ*=Z9PWKs1KqTR1~i0XvkJ%IMxe?U+P2zVh8R0C@>rmd#CWOa$18Axbv_d3w}^E|nK z6sm2E0`SnxWw07p@sj0HGpN*X^YaD(oD82+@xj+l_G*$*6!_M$msdzh;K~`7O;CoFEnE@bn97Gh3)U?)Dy;Tn7e?;HJl=jE~ zSge?w8UT>>F>&~^MkRx+{z|SIs;>5vKnT+<0}59{B|3XNGWD{WmHt6CgXx|tsQpAg z3hsn3)uhy34S32|q(Qe;ru@3dmjLa+CyaCsv$JOcZ|JY`Kvcc(^>p3M@u~sn;2PhE z75b?hwo?6V;8mPDe2Z^+fB4{02jG$TwucX%1MtK7$^(Fx3G4NG1w7*U?OUV$ASmj$I@HV>fOXn+s}Jjbj-{>b{ZeGU3jkIC60Fm%XF>+nej>Uaq4@wiY64!@ zTSs6$UnhN8*D|$LFaYu&hFC<`BQ%p*gDV;txQ{6<*_%~Y%Yaz*U6QT+VO?baCg9?` zwXUSnmvvARdC1yU&HFk&08jc*pw&a{?z7+nkQ&72w}EHDAx#}VCsXsL{av2{_#=VX h5%i-`d`5YB`5)GES)dzKx|#q0002ovPDHLkV1mh!ZL|OY From fb68c6b25831edfca5fde95cca0d0fd88dfaec97 Mon Sep 17 00:00:00 2001 From: SunChan07 Date: Sat, 16 May 2026 05:21:13 +0900 Subject: [PATCH 4/4] RevertLastCommits --- .../Overlays/GasTileVisibleGasOverlay.cs | 2 ++ .../Effects/atmospherics.rsi/anti_noblium.png | Bin 2263 -> 749 bytes .../Effects/atmospherics.rsi/bz.png | Bin 10898 -> 0 bytes .../Effects/atmospherics.rsi/halon.png | Bin 10248 -> 2659 bytes .../Effects/atmospherics.rsi/healium.png | Bin 8984 -> 2382 bytes .../atmospherics.rsi/hyper_noblium.png | Bin 10365 -> 0 bytes .../Effects/atmospherics.rsi/meta.json | 14 +------------- .../Effects/atmospherics.rsi/nitrium.png | Bin 10196 -> 2666 bytes .../Effects/atmospherics.rsi/pluoxium.png | Bin 10625 -> 0 bytes .../atmospherics.rsi/proto_nitrate.png | Bin 10663 -> 2423 bytes .../Effects/atmospherics.rsi/zauker.png | Bin 7270 -> 2337 bytes 11 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png delete mode 100644 Resources/Textures/_Adventure/Effects/atmospherics.rsi/hyper_noblium.png delete mode 100644 Resources/Textures/_Adventure/Effects/atmospherics.rsi/pluoxium.png diff --git a/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs b/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs index 4e02bc423c6..a4462536639 100644 --- a/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs +++ b/Content.Client/Atmos/Overlays/GasTileVisibleGasOverlay.cs @@ -36,6 +36,8 @@ public sealed class GasTileVisibleGasOverlay : Overlay Gas.NitrousOxide, Gas.Hydrogen, Gas.Helium, + Gas.Pluoxium, + Gas.HyperNoblium, }; private readonly bool[] _isTransparent; diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/anti_noblium.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/anti_noblium.png index 876cfc1587e880cb5e68ebe6334abbf7f574831d..2c9b61f82fc07be2b60c2f929004146010b97b47 100644 GIT binary patch delta 676 zcmV;V0$csp5$y$#Reu74Nkl7T zT+2+1@j>FIN10EOI`k?Eu*#P;n2Xq05%n7=8e@?8>$fbKDdF0000< KMNUMnLSTa5!#8*U delta 2202 zcmV;L2xa%}1=kUfReuOS=YHvaHzeRJ|=_x;*;chfvGnVr4o&c3_%+;i@^_kW&~0I;4MBODGt(bUv* zIvfsfXliPDSj%&XJl(K_Hv|HKQ^2DY6&1&UHCmp)kpjZu@Dsp3dG#Hc_3ha_`ztCc zrhs?r>gpzdx3xThBLz62rl#f?@K`7mI<94lk-@>iO~C%XzP@HHGZOG?4OqQ;bvPD_ z9jU6S+J5ok#edtiJjdApyaim;f>b0^z(ybrysiaH%;R(7X3l9rDw4UNo=gpXG#YIK zw#lon)YjH^1KSdR^1fd8Q;Y$ny3q>B6mV5CK0aOqR3+X|PEHmA<8yn>W8A3%lDQxw z-M~+PBH$t5E6G-NA87#210!0H4x-U$TSG%bcQhK^+JDf{@I8a*pB9S&=o4lrz zQ@|w9lxUD=wgS(2{T*c1A5pU(pa7Ujys{8??FxSfL(h1lqO0B_ZHi;GbGxV6C{qUjZLzVK$Qw)apiuybILHVsu^$ zZBik#`gY*cGP?$JCj;+`qCO1#LkqK+RAyQ%KWZ~@5AaRhLGcGs!Uio!kitJU0^b1c z237%o1@>FqkGu+8pX}gEp7}-K+rU1H>%%p`U4KA{7C1rweyxBi38}VAsQE46R+04r zzgGP<(?F+0MYm|71^R&B0KWjbfWPPtNtgk`z-P2TF(C_gfd4PrKTV>H3ETZK;<+I+FLGhCtfWPU+g@{BVZH&sDCGkhfOc;-7T~yJ#0Q4;L~0Wf}P2X@OPb znO_FJ4zxP>4z8)It2+#QcjLy5FUy+P1snlx0`ArQ?UGUffx!PZc!}4AkXe7k#EhM| zFe5X-tVC>?ARn0S>+7qQJr5G)9RyxfeSdA^nG4DS+GX(uco^8NxOirxAT4?&wL1Y6u8%IXzWS>l9#h-q5K^Aa({b) z2Z8(Cepx5jRhGq^qft4cnAHNixKe;cX61}%S__=w^8UgV^2}cXKLVaN+4tCD&LUh` zSa@P;YU+n_%b#CZSonjfsi`}iUN$%($-V2MWR3;Q&dwGXG5{*$@pyrsgMT&RRTz34 z_&G2Hd`IH&cXX#E=Ht~GkSFIP=YJ)2#qIgeRfAU+u!KXrvVbKVVoL$#<>e=UudZLe z{uM1t7k=+d{l=C8cI?=30hk^f91H?wTAl^ms`7)gwvtz{JXxD}Tqd&}05C zuQ%e+43%Vs<+>63lfx7<1q6$Wi%$a0EiEkvfpxlr31gDE)+!khM&2737}x@|_xJbT zp=9acw8vI(9k2)30aR+CTTH{y^78Uy!^6WrE-Nd0WMpKdNzQSKETsM20^AHdFYX{y zv`S9VpR~XsdB7({vFCu37Jq66EMaB=3=a=)20BJYMjl8Uq7@exACK65gP+*l^F0ZV3QVT3`gcK0FR_NGQSKQHC+C?CY1uN5R1j`0Dlh4y=&*t(9mYx z$3PG8hWO6wwa_UxkD-qPpR#F*ZrsXd$p*BA=^EgGicl!jH99)Ff7h;EdpbHg?vnO( z5=D5H%4d@%`HkIL;4xbzQhL#BoeYISCq_p{pDisdy?<^7s!vIV4IsJ^~_5a8_D zvz3xkj#xpa1|Q%xpnqRCddzm2WWO~Ve1QD?{8?bSprBx$+jeRJ>!c3guoh%1hYlTj zs->mnTxVzJO*?n){F;_Kpal55gy3CTXccV%bIfA_wgOvZp-mTM;=fICvcXD~TIqm2 zviEU3_=p0o6eX9GlsulqA}WFVWpJKJQL$o)Xf)a;QO9Gwy??#N=;H&iGAA_#rpT;+ z-0tj8qU@(7*l@)h3s|*k)hKYm*e2W{1qyEg9l#~s!71^09AGv-e@^c0CEz6~^q5zr z?!^&6wxHL5Wl}w2WP`Yat_;*)C5lGgloF%`$>e3e)JD7^DeHZaNaSNyvnBKzU>y8P z@pEe>-_q~FM}NvqpON#WR^z`A$U@>y(&)7XB&d+Jb#8}vACd|#UC{< cu^|5i786(0g~Hhvq5uE@07*qoM6N<$f}ZIq`2YX_ diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/bz.png deleted file mode 100644 index 97c9892f67c95e6024008f4b1fba8d0199ffa392..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10898 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 spR18@4q1 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 diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/halon.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/halon.png index bfe85181f7298544f73fcdc3a39e1184ad83a926..b134a5156dfa69f87d362dd8df6848ec113c9d34 100644 GIT binary patch delta 2636 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%0Ap+0G94mBon*N}=Ait+9PL-mt(b`0WXnuh%QV^U_ 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 b{}23MC+CG!c`!Pe00000NkvXXu0mjfxsxvH diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json index 9842fc9d8e4..7585e455c63 100644 --- a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json +++ b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/SunChan07", + "copyright": "Taken from https://github.com/tgstation/tgstation at 04e43d8c1d5097fdb697addd4395fb849dd341bd", "size": { "x": 32, "y": 32 @@ -11,18 +11,10 @@ "name": "healium", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, - { - "name": "bz", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] - }, { "name": "nitrium", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, - { - "name": "pluoxium", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] - }, { "name": "halon", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] @@ -31,10 +23,6 @@ "name": "anti_noblium", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] }, - { - "name": "hyper_noblium", - "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] - }, { "name": "zauker", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1]] diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/nitrium.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/nitrium.png index f00bcdff5159dd0ef6515bd9cf37798a502c4bae..28387ab2b705987fb231d9c488dfd6b6f58737c9 100644 GIT binary patch delta 2643 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 diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/pluoxium.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/pluoxium.png deleted file mode 100644 index a1fe6fe4f3a050d23b0405868066fd1060a9800d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10625 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�xZND7%TNyP3omi^LwsRAzlyi$uoMlaY6I5Pa-vqyF=omx$XI4uz(Pq zfTdH!RREw3FZsdSuN;ICsd^-t+;RPsLYx3Lo>ZP$wXD}=YiikNf<1L(vT2Jm*)jf{ zu$AW{epC^M7Rgi1Ey?+;j#xLQ@zIBm(473+bXG@dIro-hN5?D)Sq;RLHsX(xFtY)H z3n^ORl=O?8mEdHp&%L8KfR75XP3Jai*dLn7#o?GQnpn_M2~!O;oY$#7y7g<1jq=0> z^SiD^Ex(pOWPqw=Vyo6YIX+Pp$HpCn*Jg1n4yOPB@7TNw@7TQbjvJZ|;Dv|~a;za% z>Nao9p0R)0cE=cXh&dQMD!W;sap5XA-^<28{|J#zkzTeR<`h!7HMKC2_%@aB>BDcWV@F}03Sh$UtY9D%L$;*z9@_m*E- zrldx?CxTt=6S6C`c$^7cco)TdR!725Sl0Tc-xmVUtAsBMyRbUWtjErQLvq(rha*Bl zH=?1~8GaL;^MqSBWTN>yQOxEra^7n-o3GP+z8A-~qLRfn5G~}MzR-C=3llJz!}jPa z0}v8-(F;`n-(XRSN+d0%HT!KghmmV@%Xj^VPVZjojKb6~mMq7GCaj6*IffUN6%?9> z;b-|#+}T?8^L)lPU?+1U|0h~L)raled{f^Vo;k36)NwzL?Iv3KOajs3>z}vo b#f1M2)|OM?IB6f+00000NkvXXu0mjfHqtSA diff --git a/Resources/Textures/_Adventure/Effects/atmospherics.rsi/proto_nitrate.png b/Resources/Textures/_Adventure/Effects/atmospherics.rsi/proto_nitrate.png index 7f60944734ce56f90c299945822a92c7873c2ffe..7a43f2bff33eccab663d62a123a8282d22b67996 100644 GIT binary patch delta 2398 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 literal 7270 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