From 95cc36c41d1a01ce1568945e2734200c6add57a3 Mon Sep 17 00:00:00 2001 From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Sat, 17 May 2025 21:32:51 -0700 Subject: [PATCH] Atmos Air Grenades (#37531) --- .../ReleaseGasOnTriggerSystem.cs | 92 +++++++++++++++++ .../OnTrigger/ReleaseGasOnTriggerComponent.cs | 93 ++++++++++++++++++ .../SharedReleaseGasOnTriggerSystem.cs | 5 + .../Catalog/Fills/Lockers/engineer.yml | 2 + .../Objects/Weapons/Throwable/grenades.yml | 32 ++++++ .../Weapons/Grenades/airboom.rsi/active.png | Bin 0 -> 905 bytes .../Grenades/airboom.rsi/equipped-BELT.png | Bin 0 -> 229 bytes .../Weapons/Grenades/airboom.rsi/icon.png | Bin 0 -> 306 bytes .../Grenades/airboom.rsi/inhand-left.png | Bin 0 -> 363 bytes .../Grenades/airboom.rsi/inhand-right.png | Bin 0 -> 378 bytes .../Weapons/Grenades/airboom.rsi/meta.json | 44 +++++++++ .../Weapons/Grenades/airboom.rsi/primed.png | Bin 0 -> 299 bytes .../Weapons/Grenades/airboom.rsi/spent.png | Bin 0 -> 350 bytes 13 files changed, 268 insertions(+) create mode 100644 Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs create mode 100644 Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs create mode 100644 Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/active.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/equipped-BELT.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/primed.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/spent.png diff --git a/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs new file mode 100644 index 0000000000..09b6e1bf24 --- /dev/null +++ b/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs @@ -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; + +/// +/// 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. +/// +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(OnTrigger); + } + + /// + /// Shrimply sets the component to active when triggered, allowing it to release over time. + /// + private void OnTrigger(Entity 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(); + + 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(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(uid); + continue; + } + + if (comp.ExponentialRise) + UpdateExponentialRise(comp, comp.RemoveFraction); + } + } + + /// + /// Updates the RemoveFraction for exponential rise. + /// + /// See https://www.desmos.com/calculator/fx9gfrhoim + private static void UpdateExponentialRise(ReleaseGasOnTriggerComponent comp, float baseFraction) + { + comp.TimesReleased++; + comp.RemoveFraction = 1f - MathF.Pow(1f - baseFraction, comp.TimesReleased); + } + + private void UpdateAppearance(Entity 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 index 0000000000..5072b89dd2 --- /dev/null +++ b/Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs @@ -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; + +/// +/// Contains a GasMixture that will release its contents to the atmosphere when triggered. +/// +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentPause] +[Access(typeof(SharedReleaseGasOnTriggerSystem))] +public sealed partial class ReleaseGasOnTriggerComponent : Component +{ + /// + /// Represents visual states for whatever visuals that need to be applied + /// on state changes. + /// + [Serializable] [NetSerializable] + public enum ReleaseGasOnTriggerVisuals : byte + { + Key, + } + + /// + /// Whether this grenade is active and releasing gas. + /// Set to true when triggered, which starts gas release. + /// + [DataField] + public bool Active; + + /// + /// The gas mixture that will be released to the current tile atmosphere when triggered. + /// + [DataField] + public GasMixture Air; + + /// + /// If true, the gas will be released in an exponential manner. + /// + [DataField] + public bool ExponentialRise; + + /// + /// Time at which the next release will occur. + /// This is automatically set when the grenade activates. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] + public TimeSpan NextReleaseTime = TimeSpan.Zero; + + /// + /// The cap at which this grenade can fill the exposed atmosphere to. + /// The grenade automatically deletes itself when the pressure is reached. + /// + /// If set to 101.325, the grenade will only fill the exposed + /// atmosphere up to 101.325 kPa. + /// If zero, this limit won't be respected. + [DataField] + public float PressureLimit; + + /// + /// How often the grenade will release gas. + /// + [DataField] + public TimeSpan ReleaseInterval = TimeSpan.FromSeconds(1); + + /// + /// 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. + /// + /// If undefined on the prototype, the entire molar amount will be transferred. + [DataField] + public float RemoveFraction = 1; + + /// + /// Stores the total moles initially in the grenade upon activation. + /// Used to calculate the moles released over time. + /// + /// Set when the grenade is activated. + [DataField(readOnly: true)] + public float StartingTotalMoles; + + /// + /// Stores the number of times the grenade has been released, + /// for exponential rise calculations. + /// + [DataField] + public int TimesReleased; +} diff --git a/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs new file mode 100644 index 0000000000..5027b04517 --- /dev/null +++ b/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs @@ -0,0 +1,5 @@ +namespace Content.Shared.Explosion.EntitySystems; + +public abstract partial class SharedReleaseGasOnTriggerSystem : EntitySystem; + +// I have dreams of Atmos in shared. diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml b/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml index cac3eab043..b1c5b07aa6 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml @@ -115,6 +115,7 @@ - id: HolofanProjector - id: RCD - id: RCDAmmo + - id: AirGrenade - type: entity id: LockerAtmosphericsFilled @@ -131,6 +132,7 @@ - id: HolofanProjector - id: RCD - id: RCDAmmo + - id: AirGrenade - type: entity id: LockerEngineerFilledHardsuit diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index 66dc50c5c6..6cc8eb82c7 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -461,6 +461,38 @@ - 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 index 0000000000000000000000000000000000000000..69d3caf891783908da2c328b01d710a0ec861b0e GIT binary patch literal 905 zcmV;419tq0P)001Be1^@s6m49>f00001b5ch_0Itp) z=>Px&LrFwIRCt{2n!jt?KorNHN=>IOoirFN-D>EdKf=QmQ*ZqPveXdhn9*d&Rs!8T zWXjgf(E1=##y||pVuyxc0>X9#X>sb3y7BTlwAad#Ea`s8#qRrnmfXAdJ>5OMdv^{1 zK@bE%5ClOG1VIoPIF5tj*>ru*c}ycsKgr&tc9y>BF{tS0<$+G;YPG7f~i9c*csfR|8tYBb_N!e%lQthj&Z+gpK#g&XIYf%G=pvqeV0_YzE0G8K*d1@ft z`Y$bW%G6*g88{1*HK5cM%owx8V$^E2g;S90x>ixaC$`k^-C9&1;8%v$-F^jP;gIgW#kMgspb0WG9D|8nUo^YHh*tZd`ZsgroQ&#ce}&$ey6VsUC3*7imza% z-^^v2pKa7DLynrg2O0qa|NM`JEhv${5Op*xVJrKJTU=9W`?rT}6^(eyn8V7z@Z+4c X!C9N`9KNYrL8?7n{an^LB{Ts5Af{O| literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..c3c7f6fbe0184ce953033be50a3f9a955c06bb72 GIT binary patch literal 306 zcmV-20nPr2P)Px#>`6pHR9J=Wl|2f=KoEtWVz9FD0MmGvG?LmYn93uB^fq?6g7xZAwg|EaOZEa< zq>R;SbZurLh`1jF!YniM<|kPo5{X3qosra$h&umntrf=^OA`C!X_^K$E)%YUua<~9 z=iHM`g2?e*wNer64tVlBhcO1uIcTk=VdMgoQfQh+oOrN+EXzL90ruR8sOz`iqqP?8 z0n34iy2EyklWkF-FTr`G61E8T2##hIRR4fK3igi(0Lroi093o#{gEPC!lEbu0PD?F zoLDSix!B{Bw5X@y4rraQ1^m`m&=>J)8*(2+B9X6h0~(ZX1K?tGbN~PV07*qoM6N<$ Ef>t(zXaE2J literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..3ba282d6c19f4d42474464a73edada42d3621c9b GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zRXtrCLn`LH zy|vNzh=ItlkL*snSnpiev4icTa>OFf^i@0$-+fz<#1iJ^*;M#+~nb zc@8T~KfP4zu;p^wTZ^>MZdmvF)60jkarfV)&Qg;+zESJG#AH{OXO&@d^H27MUATT& zoc?jE8fN9M(wM0lZybH}^ySz-L$mknmG6stKHfhc@SnxYQEBNC z*}uMCo_+1bm(%}5YI>|GotnG$Zn$D{cXiD!W}v}S?HC_T%CFrcGtU%ckEg4j%Q~lo FCIFX9p3MLN literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..84e4dc7578c157f99609955043b39e265f121794 GIT binary patch literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zO*~y3Ln`LH zy=9o!Y#`F`@cODCy$7tJpC)L264d$15GF3))LUK9e6Lyc?J*%ucLz~tH8;HrC+AME znsPzJXTz6z?MFX<-kf(&m=S0)1A~2Jc5{%{9qaxXa>wl=vYQRl&c-a-a4pXEz(uAl zx!R$jo!{f81SM)+2$M`+C-yK=>p+3xuqmV&3pQZq_nMS%(?P9XCyUKiuoKp7W$8uB`W_ zf5Luiuj{4WPmET*wz~Pg@6*ShLZx$OPj%fEr5%+m+osrSdTn+|zn#tAdIp9D)>>wF Wg@TqF&30cv4)ApKb6Mw<&;$Uh!k|t7 literal 0 HcmV?d00001 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 index 0000000000..b2739f6b31 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Grenades/airboom.rsi/meta.json @@ -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 index 0000000000000000000000000000000000000000..7acc406dbac6e0f12826e3cff18aeb614ebc8002 GIT binary patch literal 299 zcmV+`0o4A9P)Px#lUB>c&r_g)e}Q55ChnMj31)b)MmoOqq7R0sfRn#RcE4S4UP4TwTF z41bR_4Ks-d0P;MCwHDrcFtc1pr{XyNfp#8(6Q7 xxFjv=`M3s{lVAhCbqj_j-p68oL`6})$^*@+V)jbF+pz!u002ovPDHLkV1kx%df)&6 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..c261eff5d19b3d5bf7b255694f44a7eaf671861e GIT binary patch literal 350 zcmV-k0iphhP)Px$7)eAyR9J=WmOX02Koo>0AtG%EDaC72rA(E=q*W7CyYLBAxyS*8DmOkru8>;J zA##8%j1hrF3&xoE2aHO&lC4D5&YGCOey||4%dRl0Wh8`w5nF(Lp+k_1Ijz!(Fi6nhMBAkTA@Wl3M`WS}<~;`#9b zn_Y#)_XhLj3VQTP8E^{WDWF3bhT)GE{CNoDI6g@TtzC;q-JXC3r4&^KD}jjAlkqKP zy2A8p+u48118Wo3E%+$j|F>T=G{vETR w!t}bE0i^