Power Sink Upgraded (#15683)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -1,8 +1,44 @@
|
|||||||
namespace Content.Server.PowerSink
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
|
namespace Content.Server.PowerSink
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Absorbs power up to its capacity when anchored then explodes.
|
/// Absorbs power up to its capacity when anchored then explodes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[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)
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,41 @@
|
|||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Robust.Shared.Utility;
|
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
|
namespace Content.Server.PowerSink
|
||||||
{
|
{
|
||||||
public sealed class PowerSinkSystem : EntitySystem
|
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 ExplosionSystem _explosionSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly StationSystem _station = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<PowerSinkComponent, ExaminedEvent>(OnExamine);
|
SubscribeLocalEvent<PowerSinkComponent, ExaminedEvent>(OnExamine);
|
||||||
|
SubscribeLocalEvent<PowerSinkComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExamine(EntityUid uid, PowerSinkComponent component, ExaminedEvent args)
|
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)
|
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.
|
// 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;
|
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);
|
_explosionSystem.QueueExplosion(entity, "PowerSink", 2000f, 4f, 20f, canCreateVacuum: true);
|
||||||
EntityManager.RemoveComponent(comp.Owner, comp);
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Resources/Audio/Effects/PowerSink/charge_fire.ogg
Normal file
BIN
Resources/Audio/Effects/PowerSink/charge_fire.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Effects/PowerSink/electric.ogg
Normal file
BIN
Resources/Audio/Effects/PowerSink/electric.ogg
Normal file
Binary file not shown.
10
Resources/Audio/Effects/PowerSink/licenses.txt
Normal file
10
Resources/Audio/Effects/PowerSink/licenses.txt
Normal file
@@ -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/"
|
||||||
|
|
||||||
@@ -1 +1,2 @@
|
|||||||
powersink-examine-drain-amount = The power sink is draining [color={$markupDrainColor}]{$amount} kW[/color].
|
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.
|
||||||
|
|||||||
@@ -85,3 +85,19 @@
|
|||||||
lightColor: Orange
|
lightColor: Orange
|
||||||
texturePath: /Textures/Effects/fire.rsi
|
texturePath: /Textures/Effects/fire.rsi
|
||||||
fireStates: 3
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user