]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Atmos Air Grenades (#37531)
authorArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
Sun, 18 May 2025 04:32:51 +0000 (21:32 -0700)
committerGitHub <noreply@github.com>
Sun, 18 May 2025 04:32:51 +0000 (21:32 -0700)
13 files changed:
Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs [new file with mode: 0644]
Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs [new file with mode: 0644]
Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs [new file with mode: 0644]
Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml
Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/active.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/equipped-BELT.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-left.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-right.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/primed.png [new file with mode: 0644]
Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/spent.png [new file with mode: 0644]

diff --git a/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs
new file mode 100644 (file)
index 0000000..09b6e1b
--- /dev/null
@@ -0,0 +1,92 @@
+using Content.Server.Atmos.EntitySystems;
+using Content.Shared.Explosion.Components.OnTrigger;
+using Content.Shared.Explosion.EntitySystems;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Explosion.EntitySystems;
+
+/// <summary>
+/// Releases a gas mixture to the atmosphere when triggered.
+/// Can also release gas over a set timespan to prevent trolling people
+/// with the instant-wall-of-pressure-inator.
+/// </summary>
+public sealed partial class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem
+{
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<ReleaseGasOnTriggerComponent, TriggerEvent>(OnTrigger);
+    }
+
+    /// <summary>
+    /// Shrimply sets the component to active when triggered, allowing it to release over time.
+    /// </summary>
+    private void OnTrigger(Entity<ReleaseGasOnTriggerComponent> ent, ref TriggerEvent args)
+    {
+        ent.Comp.Active = true;
+        ent.Comp.NextReleaseTime = _timing.CurTime;
+        ent.Comp.StartingTotalMoles = ent.Comp.Air.TotalMoles;
+        UpdateAppearance(ent.Owner, true);
+    }
+
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+
+        var curTime = _timing.CurTime;
+        var query = EntityQueryEnumerator<ReleaseGasOnTriggerComponent>();
+
+        while (query.MoveNext(out var uid, out var comp))
+        {
+            if (!comp.Active || comp.NextReleaseTime > curTime)
+                continue;
+
+            var giverGasMix = comp.Air.Remove(comp.StartingTotalMoles * comp.RemoveFraction);
+            var environment = _atmosphereSystem.GetContainingMixture(uid, false, true);
+
+            if (environment == null)
+            {
+                UpdateAppearance(uid, false);
+                RemCompDeferred<ReleaseGasOnTriggerComponent>(uid);
+                continue;
+            }
+
+            _atmosphereSystem.Merge(environment, giverGasMix);
+            comp.NextReleaseTime += comp.ReleaseInterval;
+
+            if (comp.PressureLimit != 0 && environment.Pressure >= comp.PressureLimit ||
+                comp.Air.TotalMoles <= 0)
+            {
+                UpdateAppearance(uid, false);
+                RemCompDeferred<ReleaseGasOnTriggerComponent>(uid);
+                continue;
+            }
+
+            if (comp.ExponentialRise)
+                UpdateExponentialRise(comp, comp.RemoveFraction);
+        }
+    }
+
+    /// <summary>
+    /// Updates the RemoveFraction for exponential rise.
+    /// </summary>
+    /// <remarks>See https://www.desmos.com/calculator/fx9gfrhoim</remarks>
+    private static void UpdateExponentialRise(ReleaseGasOnTriggerComponent comp, float baseFraction)
+    {
+        comp.TimesReleased++;
+        comp.RemoveFraction = 1f - MathF.Pow(1f - baseFraction, comp.TimesReleased);
+    }
+
+    private void UpdateAppearance(Entity<AppearanceComponent?> entity, bool state)
+    {
+        if (!Resolve(entity, ref entity.Comp, false))
+            return;
+
+        _appearance.SetData(entity, ReleaseGasOnTriggerComponent.ReleaseGasOnTriggerVisuals.Key, state);
+    }
+}
diff --git a/Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs b/Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs
new file mode 100644 (file)
index 0000000..5072b89
--- /dev/null
@@ -0,0 +1,93 @@
+using Content.Shared.Atmos;
+using Content.Shared.Explosion.EntitySystems;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Explosion.Components.OnTrigger;
+
+/// <summary>
+/// Contains a GasMixture that will release its contents to the atmosphere when triggered.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentPause]
+[Access(typeof(SharedReleaseGasOnTriggerSystem))]
+public sealed partial class ReleaseGasOnTriggerComponent : Component
+{
+    /// <summary>
+    /// Represents visual states for whatever visuals that need to be applied
+    /// on state changes.
+    /// </summary>
+    [Serializable] [NetSerializable]
+    public enum ReleaseGasOnTriggerVisuals : byte
+    {
+        Key,
+    }
+
+    /// <summary>
+    /// Whether this grenade is active and releasing gas.
+    /// Set to true when triggered, which starts gas release.
+    /// </summary>
+    [DataField]
+    public bool Active;
+
+    /// <summary>
+    /// The gas mixture that will be released to the current tile atmosphere when triggered.
+    /// </summary>
+    [DataField]
+    public GasMixture Air;
+
+    /// <summary>
+    /// If true, the gas will be released in an exponential manner.
+    /// </summary>
+    [DataField]
+    public bool ExponentialRise;
+
+    /// <summary>
+    /// Time at which the next release will occur.
+    /// This is automatically set when the grenade activates.
+    /// </summary>
+    [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+    [AutoPausedField]
+    public TimeSpan NextReleaseTime = TimeSpan.Zero;
+
+    /// <summary>
+    /// The cap at which this grenade can fill the exposed atmosphere to.
+    /// The grenade automatically deletes itself when the pressure is reached.
+    /// </summary>
+    /// <example>If set to 101.325, the grenade will only fill the exposed
+    /// atmosphere up to 101.325 kPa.</example>
+    /// <remarks>If zero, this limit won't be respected.</remarks>
+    [DataField]
+    public float PressureLimit;
+
+    /// <summary>
+    /// How often the grenade will release gas.
+    /// </summary>
+    [DataField]
+    public TimeSpan ReleaseInterval = TimeSpan.FromSeconds(1);
+
+    /// <summary>
+    /// A float from 0 to 1, representing a partial portion of the moles
+    /// of the gas mixture that will be
+    /// released to the current tile atmosphere when triggered.
+    /// </summary>
+    /// <remarks>If undefined on the prototype, the entire molar amount will be transferred.</remarks>
+    [DataField]
+    public float RemoveFraction = 1;
+
+    /// <summary>
+    /// Stores the total moles initially in the grenade upon activation.
+    /// Used to calculate the moles released over time.
+    /// </summary>
+    /// <remarks>Set when the grenade is activated.</remarks>
+    [DataField(readOnly: true)]
+    public float StartingTotalMoles;
+
+    /// <summary>
+    /// Stores the number of times the grenade has been released,
+    /// for exponential rise calculations.
+    /// </summary>
+    [DataField]
+    public int TimesReleased;
+}
diff --git a/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs
new file mode 100644 (file)
index 0000000..5027b04
--- /dev/null
@@ -0,0 +1,5 @@
+namespace Content.Shared.Explosion.EntitySystems;
+
+public abstract partial class SharedReleaseGasOnTriggerSystem : EntitySystem;
+
+// I have dreams of Atmos in shared.
index cac3eab0430d6139ee4707c2a644c221be9df7f0..b1c5b07aa6f3ca68b6689144a412d13ed69f7405 100644 (file)
       - id: HolofanProjector
       - id: RCD
       - id: RCDAmmo
+      - id: AirGrenade
 
 - type: entity
   id: LockerAtmosphericsFilled
       - id: HolofanProjector
       - id: RCD
       - id: RCDAmmo
+      - id: AirGrenade
 
 - type: entity
   id: LockerEngineerFilledHardsuit
index 66dc50c5c663fadb27163a651d430b142921bc64..6cc8eb82c7c959539286c2b16d2e655d402a34f5 100644 (file)
   - type: StaticPrice
     price: 350
 
+- type: entity
+  parent: [ BaseEngineeringContraband, GrenadeBase ] # Prevent inheriting DeleteOnTrigger from SmokeGrenade
+  id: AirGrenade
+  name: air grenade
+  description: A special solid state chemical grenade used for quickly releasing standard air into a spaced area. Fills up to 30 tiles!
+  components:
+  - type: Sprite
+    sprite: Objects/Weapons/Grenades/airboom.rsi
+  - type: SoundOnTrigger
+    sound: /Audio/Items/smoke_grenade_smoke.ogg
+  - type: TimerTriggerVisuals
+    primingSound:
+      path: /Audio/Items/smoke_grenade_prime.ogg
+  - type: OnUseTimerTrigger
+    delay: 3
+  - type: ReleaseGasOnTrigger
+    removeFraction: 0.25
+    air:
+      volume: 1000
+      moles: # Target is 3117.84 mols total for filling 30 tiles (goal is 101.325 kPa @ 20C)
+      - 654.7464 # oxygen
+      - 2463.0936 # nitrogen
+      temperature: 293.15
+  - type: StaticPrice
+    price: 350
+  - type: GenericVisualizer
+    visuals:
+      enum.ReleaseGasOnTriggerVisuals.Key:
+        enabled:
+          True: { state: active }
+          False: { state: spent }
+
 # Non-explosive "dummy" grenades to use as a distraction.
 
 - type: entity
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/active.png b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/active.png
new file mode 100644 (file)
index 0000000..69d3caf
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/active.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/equipped-BELT.png b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/equipped-BELT.png
new file mode 100644 (file)
index 0000000..c0ec51c
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/equipped-BELT.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/icon.png b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/icon.png
new file mode 100644 (file)
index 0000000..c3c7f6f
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-left.png
new file mode 100644 (file)
index 0000000..3ba282d
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-left.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-right.png
new file mode 100644 (file)
index 0000000..84e4dc7
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-right.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/meta.json b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/meta.json
new file mode 100644 (file)
index 0000000..b2739f6
--- /dev/null
@@ -0,0 +1,44 @@
+{
+    "version": 1,
+    "license": "CC0-1.0",
+    "copyright": "Created by EmoGarbage404 (github) for Space Station 14",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "icon"
+        },
+        {
+            "name": "primed"
+        },
+        {
+            "name": "active",
+            "delays": [
+                [
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1,
+                    0.1
+                ]
+            ]
+        },
+        {
+            "name": "spent"
+        },
+        {
+            "name": "equipped-BELT",
+            "directions": 4
+        },
+        {
+            "name": "inhand-left",
+            "directions": 4
+        },
+        {
+            "name": "inhand-right",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/primed.png b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/primed.png
new file mode 100644 (file)
index 0000000..7acc406
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/primed.png differ
diff --git a/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/spent.png b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/spent.png
new file mode 100644 (file)
index 0000000..c261eff
Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/spent.png differ