using Content.Shared.Atmos.Components; using Content.Shared.CCVar; using Content.Shared.Destructible; using Content.Shared.Explosion.EntitySystems; using Content.Shared.Jittering; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Serialization; namespace Content.Shared.Atmos.EntitySystems; /// /// This handles gas volumes that have a maximum pressure, and the destructive results of them exceeding that pressure. /// You may call it the "MaxCapSystem" if you so desire. /// public abstract partial class GasMaxPressureSystem : EntitySystem where T : IGasMaxPressureHolder, IComponent { private float _maxExplosivePower; [Dependency] private IConfigurationManager _cfg = default!; [Dependency] protected SharedAppearanceSystem Appearance = default!; [Dependency] protected SharedAtmosphereSystem Atmos = default!; [Dependency] private SharedDestructibleSystem _destructible = default!; [Dependency] private SharedExplosionSystem _explosions = default!; [Dependency] protected SharedAudioSystem Audio = default!; /// public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnDeviceUpdated); Subs.CVar(_cfg, CCVars.AtmosTankFragment, value => _maxExplosivePower = value, true); } private void OnDeviceUpdated(Entity entity, ref AtmosDeviceUpdateEvent args) { // We don't update our atmos device if it's in the process of being deleted. if (CheckStatus(entity, args.dt)) DeviceUpdated(entity, ref args); } /// /// Handler for our atmos device being updated. /// /// Gas holding atmos device. /// protected abstract void DeviceUpdated(Entity entity, ref AtmosDeviceUpdateEvent args); /// /// Handler for when this atmos device is about to break due to exceeding its maximum pressure too many times /// /// Gas holding atmos device. protected virtual void BeforeDeviceFailure(Entity entity) { } /// /// Handler for when this atmos device loses integrity due to overpressure /// /// Gas holding atmos device. protected virtual void AfterDeviceFailure(Entity entity) { } /// /// Handler for when this atmos device loses integrity due to overpressure /// /// Gas holding atmos device. protected virtual void IntegrityLost(Entity entity) { } /// /// Handler for when this atmos device exceeds its safety parameters /// /// Gas holding atmos device. protected virtual void SafetyMeasures(Entity entity) { } /// /// Checks the status of an atmos device that has a specified max pressure, and handles overpressure issues. /// /// Gas holding atmos device. /// Time since the last status update. /// True if the device hasn't failed. False if the device has failed and been destroyed. protected bool CheckStatus(Entity entity, float dt) { var pressure = entity.Comp.Air.Pressure; // Better mixes mean bigger and faster explosions! if (pressure > entity.Comp.Overpressure * (entity.Comp.Integrity + 1)) { Atmos.MergeContainingMixture(entity.Owner, entity.Comp.Air, excite: true); Audio.PlayPvs(entity.Comp.RuptureSound, Transform(entity).Coordinates, AudioParams.Default.WithVariation(0.125f)); // Integrity failure, destroy ourselves! _destructible.DestroyEntity(entity); var totalIntensity = (float)Math.Sqrt(Atmos.GetOverPressure(entity.Comp.Air)); if (_maxExplosivePower > 0 && _maxExplosivePower < totalIntensity) totalIntensity = _maxExplosivePower; _explosions.TriggerExplosive(entity, totalIntensity: totalIntensity); Dirty(entity); return false; } // Device begins to fail. if (pressure > entity.Comp.Overpressure) { IntegrityLost(entity); entity.Comp.Integrity -= dt; Appearance.SetData(entity.Owner, GasIntegrity.Integrity, entity.Comp.Integrity); Appearance.SetData(entity.Owner, GasIntegrity.MaxIntegrity, entity.Comp.MaxIntegrity); } else if (entity.Comp.Integrity < entity.Comp.MaxIntegrity) { entity.Comp.Integrity = Math.Min(entity.Comp.Integrity + dt, entity.Comp.MaxIntegrity); Appearance.SetData(entity.Owner, GasIntegrity.Integrity, entity.Comp.Integrity); Appearance.SetData(entity.Owner, GasIntegrity.MaxIntegrity, entity.Comp.MaxIntegrity); } // Device tries to prevent failure. if (pressure > entity.Comp.SafetyPressure) SafetyMeasures(entity); return true; } } [Serializable, NetSerializable, Flags] public enum GasIntegrity { Integrity, MaxIntegrity }