]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Power Sink Upgraded (#15683)
authorSkye <22365940+Skyedra@users.noreply.github.com>
Wed, 17 May 2023 13:55:42 +0000 (06:55 -0700)
committerGitHub <noreply@github.com>
Wed, 17 May 2023 13:55:42 +0000 (23:55 +1000)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Content.Server/PowerSink/PowerSinkComponent.cs
Content.Server/PowerSink/PowerSinkSystem.cs
Resources/Audio/Effects/PowerSink/charge_fire.ogg [new file with mode: 0644]
Resources/Audio/Effects/PowerSink/electric.ogg [new file with mode: 0644]
Resources/Audio/Effects/PowerSink/licenses.txt [new file with mode: 0644]
Resources/Locale/en-US/powersink/powersink.ftl
Resources/Prototypes/explosion.yml

index 4654205a381525d1418fe20f2520c9e95d255260..1b55739c8c5f7efb3e7c256ce145314a6da95a19 100644 (file)
@@ -1,8 +1,44 @@
-namespace Content.Server.PowerSink
+using Robust.Shared.Audio;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Server.PowerSink
 {
     /// <summary>
     /// Absorbs power up to its capacity when anchored then explodes.
     /// </summary>
     [RegisterComponent]
-    public sealed class PowerSinkComponent : Component {}
+    public sealed class PowerSinkComponent : Component
+    {
+        /// <summary>
+        /// When the power sink is nearing its explosion, warn the crew so they can look for it
+        /// (if they're not already).
+        /// </summary>
+        [DataField("sentImminentExplosionWarning")]
+        [ViewVariables(VVAccess.ReadWrite)]
+        public bool SentImminentExplosionWarningMessage = false;
+
+        /// <summary>
+        /// If explosion has been triggered, time at which to explode.
+        /// </summary>
+        [DataField("explosionTime", customTypeSerializer:typeof(TimeOffsetSerializer))]
+        public System.TimeSpan? ExplosionTime = null;
+
+        /// <summary>
+        /// The highest sound warning threshold that has been hit (plays sfx occasionally as explosion nears)
+        /// </summary>
+        [DataField("highestWarningSoundThreshold")]
+        [ViewVariables(VVAccess.ReadWrite)]
+        public float HighestWarningSoundThreshold = 0f;
+
+        [DataField("chargeFireSound")]
+        public SoundSpecifier ChargeFireSound = new SoundPathSpecifier("/Audio/Effects/PowerSink/charge_fire.ogg");
+
+        [DataField("electricSound")] public SoundSpecifier ElectricSound =
+            new SoundPathSpecifier("/Audio/Effects/PowerSink/electric.ogg")
+            {
+                Params = AudioParams.Default
+                    .WithVolume(15f) // audible even behind walls
+                    .WithRolloffFactor(10)
+            };
+    }
 }
index d67cda1d47fcf3b852f479f57e8968efeace543d..e5a118b07e4efa2ffc60d8bd5ba98d88839a5e60 100644 (file)
@@ -2,18 +2,41 @@
 using Content.Server.Power.Components;
 using Content.Shared.Examine;
 using Robust.Shared.Utility;
+using Content.Server.Chat.Systems;
+using Content.Server.Station.Systems;
+using Robust.Shared.Timing;
+using Robust.Shared.Audio;
 
 namespace Content.Server.PowerSink
 {
     public sealed class PowerSinkSystem : EntitySystem
     {
+        /// <summary>
+        /// Percentage of battery full to trigger the announcement warning at.
+        /// </summary>
+        private const float WarningMessageThreshold = 0.70f;
+
+        private readonly float[] _warningSoundThresholds = new[] { .80f, .90f, .95f, .98f };
+
+        /// <summary>
+        /// Length of time to delay explosion from battery full state -- this is used to play
+        /// a brief SFX winding up the explosion.
+        /// </summary>
+        /// <returns></returns>
+        private readonly TimeSpan _explosionDelayTime = TimeSpan.FromSeconds(1.465);
+
+        [Dependency] private readonly IGameTiming _gameTiming = default!;
+        [Dependency] private readonly ChatSystem _chat = default!;
         [Dependency] private readonly ExplosionSystem _explosionSystem = default!;
+        [Dependency] private readonly SharedAudioSystem _audio = default!;
+        [Dependency] private readonly StationSystem _station = default!;
 
         public override void Initialize()
         {
             base.Initialize();
 
             SubscribeLocalEvent<PowerSinkComponent, ExaminedEvent>(OnExamine);
+            SubscribeLocalEvent<PowerSinkComponent, EntityUnpausedEvent>(OnUnpaused);
         }
 
         private void OnExamine(EntityUid uid, PowerSinkComponent component, ExaminedEvent args)
@@ -30,26 +53,91 @@ namespace Content.Server.PowerSink
             );
         }
 
+        private void OnUnpaused(EntityUid uid, PowerSinkComponent component, ref EntityUnpausedEvent args)
+        {
+            if (component.ExplosionTime == null)
+                return;
+
+            component.ExplosionTime = component.ExplosionTime + args.PausedTime;
+        }
+
         public override void Update(float frameTime)
         {
-            var toRemove = new RemQueue<(PowerSinkComponent Sink, BatteryComponent Battery)>();
+            var toRemove = new RemQueue<(EntityUid Entity, PowerSinkComponent Sink)>();
+            var query = EntityQueryEnumerator<PowerSinkComponent, PowerConsumerComponent, BatteryComponent, TransformComponent>();
 
             // Realistically it's gonna be like <5 per station.
-            foreach (var (comp, networkLoad, battery, xform) in EntityManager.EntityQuery<PowerSinkComponent, PowerConsumerComponent, BatteryComponent, TransformComponent>())
+            while (query.MoveNext(out var entity, out var component, out var networkLoad, out var battery, out var transform))
             {
-                if (!xform.Anchored) continue;
+                if (!transform.Anchored)
+                    continue;
 
                 battery.CurrentCharge += networkLoad.NetworkLoad.ReceivingPower / 1000;
-                if (battery.CurrentCharge < battery.MaxCharge) continue;
 
-                toRemove.Add((comp, battery));
+                var currentBatteryThreshold = battery.CurrentCharge / battery.MaxCharge;
+
+                // Check for warning message threshold
+                if (!component.SentImminentExplosionWarningMessage &&
+                    currentBatteryThreshold >= WarningMessageThreshold)
+                {
+                    NotifyStationOfImminentExplosion(entity, component);
+                }
+
+                // Check for warning sound threshold
+                foreach (var testThreshold in _warningSoundThresholds)
+                {
+                    if (currentBatteryThreshold >= testThreshold &&
+                        testThreshold > component.HighestWarningSoundThreshold)
+                    {
+                        component.HighestWarningSoundThreshold = currentBatteryThreshold; // Don't re-play in future until next threshold hit
+                        _audio.PlayPvs(component.ElectricSound, entity); // Play SFX
+                        break;
+                    }
+                }
+
+                // Check for explosion
+                if (battery.CurrentCharge < battery.MaxCharge)
+                    continue;
+
+                if (component.ExplosionTime == null)
+                {
+                    // Set explosion sequence to start soon
+                    component.ExplosionTime = _gameTiming.CurTime.Add(_explosionDelayTime);
+
+                    // Wind-up SFX
+                    _audio.PlayPvs(component.ChargeFireSound, entity); // Play SFX
+                }
+                else if (_gameTiming.CurTime >= component.ExplosionTime)
+                {
+                    // Explode!
+                    toRemove.Add((entity, component));
+                }
             }
 
-            foreach (var (comp, battery) in toRemove)
+            foreach (var (entity, component) in toRemove)
             {
-                _explosionSystem.QueueExplosion(comp.Owner, "Default", 5 * (battery.MaxCharge / 2500000), 0.5f, 10, canCreateVacuum: false);
-                EntityManager.RemoveComponent(comp.Owner, comp);
+                _explosionSystem.QueueExplosion(entity, "PowerSink", 2000f, 4f, 20f, canCreateVacuum: true);
+                EntityManager.RemoveComponent(entity, component);
             }
         }
+
+        private void NotifyStationOfImminentExplosion(EntityUid uid, PowerSinkComponent powerSinkComponent)
+        {
+            if (powerSinkComponent.SentImminentExplosionWarningMessage)
+                return;
+
+            powerSinkComponent.SentImminentExplosionWarningMessage = true;
+            var station = _station.GetOwningStation(uid);
+
+            if (station == null)
+                return;
+
+            _chat.DispatchStationAnnouncement(
+                station.Value,
+                Loc.GetString("powersink-immiment-explosion-announcement"),
+                playDefaultSound: true,
+                colorOverride: Color.Yellow
+            );
+        }
     }
 }
diff --git a/Resources/Audio/Effects/PowerSink/charge_fire.ogg b/Resources/Audio/Effects/PowerSink/charge_fire.ogg
new file mode 100644 (file)
index 0000000..c16b08b
Binary files /dev/null and b/Resources/Audio/Effects/PowerSink/charge_fire.ogg differ
diff --git a/Resources/Audio/Effects/PowerSink/electric.ogg b/Resources/Audio/Effects/PowerSink/electric.ogg
new file mode 100644 (file)
index 0000000..f6360d6
Binary files /dev/null and b/Resources/Audio/Effects/PowerSink/electric.ogg differ
diff --git a/Resources/Audio/Effects/PowerSink/licenses.txt b/Resources/Audio/Effects/PowerSink/licenses.txt
new file mode 100644 (file)
index 0000000..52898e4
--- /dev/null
@@ -0,0 +1,10 @@
+- files: ["electric.ogg"]
+  license: "CC0 1.0"
+  copyright: "The-Sacha-Rush"
+  source: "https://freesound.org/people/The-Sacha-Rush/sounds/657802/"
+
+- files: ["charge_fire.ogg"]
+  license: "CC BY 3.0"
+  copyright: "Teh_Bucket, dylanperitz, satanicupsman, CaptainGusterd, arightwizard, BigKahuna360, michael_grinnell, weaveofkev, MichelleGrobler, Alex_John73, sandyrb, breo2012"
+  source: "https://freesound.org/people/Teh_Bucket/sounds/518739/"
+
index 2d5b73be19d90eab62f6840e973f7bd25027801b..92e87dd90fdfe0cb04cc020223c21247e4ef72c7 100644 (file)
@@ -1 +1,2 @@
 powersink-examine-drain-amount = The power sink is draining [color={$markupDrainColor}]{$amount} kW[/color].
+powersink-immiment-explosion-announcement = System scans have detected a rogue power consuming device is becoming unstable.  Staff are advised to locate and disconnect this device immediately before the station is damaged.
index 7a196ae31e5b38d8d195aabbad6c13a99659ba8f..de55aaa3f43d1b1fd966eecaf389f1fcffb0d194 100644 (file)
   lightColor: Orange
   texturePath: /Textures/Effects/fire.rsi
   fireStates: 3
+
+- type: explosion
+  id: PowerSink
+  damagePerIntensity:
+    types:
+      Heat: 12
+      Blunt: 12
+      Piercing: 12
+      Structural: 40
+  tileBreakChance: [ 0, 0.5, 1 ]
+  tileBreakIntensity: [ 1, 5, 10 ]
+  tileBreakRerollReduction: 3
+  intensityPerState: 20
+  lightColor: Orange
+  texturePath: /Textures/Effects/fire.rsi
+  fireStates: 6