From: Skye <22365940+Skyedra@users.noreply.github.com> Date: Wed, 17 May 2023 13:55:42 +0000 (-0700) Subject: Power Sink Upgraded (#15683) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=67d6d1528bfe05364216b0a1a21f89ebfb4e2133;p=space-station-14.git Power Sink Upgraded (#15683) Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: metalgearsloth --- diff --git a/Content.Server/PowerSink/PowerSinkComponent.cs b/Content.Server/PowerSink/PowerSinkComponent.cs index 4654205a38..1b55739c8c 100644 --- a/Content.Server/PowerSink/PowerSinkComponent.cs +++ b/Content.Server/PowerSink/PowerSinkComponent.cs @@ -1,8 +1,44 @@ -namespace Content.Server.PowerSink +using Robust.Shared.Audio; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Server.PowerSink { /// /// Absorbs power up to its capacity when anchored then explodes. /// [RegisterComponent] - public sealed class PowerSinkComponent : Component {} + public sealed class PowerSinkComponent : Component + { + /// + /// When the power sink is nearing its explosion, warn the crew so they can look for it + /// (if they're not already). + /// + [DataField("sentImminentExplosionWarning")] + [ViewVariables(VVAccess.ReadWrite)] + public bool SentImminentExplosionWarningMessage = false; + + /// + /// If explosion has been triggered, time at which to explode. + /// + [DataField("explosionTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + public System.TimeSpan? ExplosionTime = null; + + /// + /// The highest sound warning threshold that has been hit (plays sfx occasionally as explosion nears) + /// + [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) + }; + } } diff --git a/Content.Server/PowerSink/PowerSinkSystem.cs b/Content.Server/PowerSink/PowerSinkSystem.cs index d67cda1d47..e5a118b07e 100644 --- a/Content.Server/PowerSink/PowerSinkSystem.cs +++ b/Content.Server/PowerSink/PowerSinkSystem.cs @@ -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 { + /// + /// Percentage of battery full to trigger the announcement warning at. + /// + private const float WarningMessageThreshold = 0.70f; + + private readonly float[] _warningSoundThresholds = new[] { .80f, .90f, .95f, .98f }; + + /// + /// Length of time to delay explosion from battery full state -- this is used to play + /// a brief SFX winding up the explosion. + /// + /// + 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(OnExamine); + SubscribeLocalEvent(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(); // Realistically it's gonna be like <5 per station. - foreach (var (comp, networkLoad, battery, xform) in EntityManager.EntityQuery()) + 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 index 0000000000..c16b08bd9c 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 index 0000000000..f6360d6f8e 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 index 0000000000..52898e4710 --- /dev/null +++ b/Resources/Audio/Effects/PowerSink/licenses.txt @@ -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/" + diff --git a/Resources/Locale/en-US/powersink/powersink.ftl b/Resources/Locale/en-US/powersink/powersink.ftl index 2d5b73be19..92e87dd90f 100644 --- a/Resources/Locale/en-US/powersink/powersink.ftl +++ b/Resources/Locale/en-US/powersink/powersink.ftl @@ -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. diff --git a/Resources/Prototypes/explosion.yml b/Resources/Prototypes/explosion.yml index 7a196ae31e..de55aaa3f4 100644 --- a/Resources/Prototypes/explosion.yml +++ b/Resources/Prototypes/explosion.yml @@ -85,3 +85,19 @@ 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