Make crew monitors beep when someone dies / crits (#2930)

* Make the crew monitors beep when someone dies or crits

* Cleanup

* Fix a comment that was not updated earlier.

Signed-off-by: Quanteey <61941975+Quanteey@users.noreply.github.com>

* Switch frame time tracking to using timespans

* use timestamps of next alert instead of frame time tracking

* Fix outdated docs

---------

Signed-off-by: Quanteey <61941975+Quanteey@users.noreply.github.com>
This commit is contained in:
Quanteey 2025-02-11 09:40:36 +01:00 committed by GitHub
parent 5c67453014
commit ca4db5d946
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 86 additions and 1 deletions

View File

@ -1,8 +1,10 @@
using Content.Shared.Medical.SuitSensor;
using Robust.Shared.Audio; // DeltaV
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; // DeltaV
namespace Content.Server.Medical.CrewMonitoring;
[RegisterComponent]
[RegisterComponent, AutoGenerateComponentPause] // DeltaV - add AutoGenerateComponentPause
[Access(typeof(CrewMonitoringConsoleSystem))]
public sealed partial class CrewMonitoringConsoleComponent : Component
{
@ -16,4 +18,35 @@ public sealed partial class CrewMonitoringConsoleComponent : Component
/// </summary>
[DataField("sensorTimeout"), ViewVariables(VVAccess.ReadWrite)]
public float SensorTimeout = 10f;
// DeltaV - start of alert system code
/// <summary>
/// Should the component beep if someone goes critical or dies
/// </summary>
[DataField]
public bool AlertsEnabled = true;
/// <summary>
/// Track sensors that have triggered the crew member critical alert.
/// </summary>
public HashSet<string> AlertedSensors = [];
/// <summary>
/// Timestamp of the next possible alert (alert cooldown)
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
public TimeSpan NextAlert;
/// <summary>
/// Time between alerts
/// </summary>
[DataField]
public TimeSpan AlertCooldown = TimeSpan.FromSeconds(15);
/// <summary>
/// Alert sound that is played when a crew member goes into critical / dies.
/// </summary>
[DataField]
public SoundSpecifier AlertSound = new SoundPathSpecifier("/Audio/_DV/Medical/CrewMonitoring/crew_alert.ogg");
// DeltaV - end of alert system code
}

View File

@ -1,11 +1,15 @@
using System.Linq;
using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Systems;
using Content.Server.Power.EntitySystems; // DeltaV
using Content.Server.PowerCell;
using Content.Shared.Medical.CrewMonitoring;
using Content.Shared.Medical.SuitSensor;
using Content.Shared.Pinpointer;
using Robust.Server.GameObjects;
using Robust.Shared.Audio; // DeltaV
using Robust.Shared.Audio.Systems; // DeltaV
using Robust.Shared.Timing; // DeltaV
namespace Content.Server.Medical.CrewMonitoring;
@ -13,6 +17,8 @@ public sealed class CrewMonitoringConsoleSystem : EntitySystem
{
[Dependency] private readonly PowerCellSystem _cell = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!; // DeltaV
[Dependency] private readonly IGameTiming _timing = default!; // DeltaV
public override void Initialize()
{
@ -43,6 +49,48 @@ public sealed class CrewMonitoringConsoleSystem : EntitySystem
component.ConnectedSensors = sensorStatus;
UpdateUserInterface(uid, component);
// DeltaV - start of alert system code
if (!component.AlertsEnabled)
return;
// station power (for the machine version)
if (!this.IsPowered(uid, EntityManager))
return;
// cell power (for the handheld)
if (!_cell.HasActivatableCharge(uid))
return;
foreach (var (sensorId, status) in sensorStatus)
{
// DamagePercentage above 1f is considered critical. It is null when sensor vitals are off.
var isCritical = status.DamagePercentage is >= 1f;
// Skip crew members that we have already alerted about
if (component.AlertedSensors.Contains(sensorId))
{
if (status.IsAlive && !isCritical)
component.AlertedSensors.Remove(sensorId);
continue;
}
if (!status.IsAlive || isCritical)
{
if (_timing.CurTime >= component.NextAlert)
{
var audioParams = AudioParams.Default.WithVolume(-2f).WithMaxDistance(4f);
_audio.PlayPvs(component.AlertSound, uid, audioParams);
component.NextAlert = _timing.CurTime + component.AlertCooldown;
}
// We are doing this outside the cooldown check to avoid "alert queues"
// If two people die at the same time and remain dead for longer, we want to alert once for both people
// instead of alerting once for the first one, waiting the cooldown, and then alerting again for the second one.
component.AlertedSensors.Add(sensorId);
}
}
// DeltaV - end of alert system code
}
private void OnUIOpened(EntityUid uid, CrewMonitoringConsoleComponent component, BoundUIOpenedEvent args)

View File

@ -61,6 +61,8 @@
price: 750
- type: Tag # DeltaV - Let it be put in storage implants by removing HighRiskItem
tags: []
- type: CrewMonitoringConsole # DeltaV - disable crew crit / dead beeping alerts
alertsEnabled: false
- type: entity
id: SpyCrewMonitorEmpty
@ -85,6 +87,8 @@
sprite: Objects/Specific/Medical/syndihandheldcrewmonitor.rsi
- type: PowerCellDraw
useRate: 0 # DeltaV - Changed to zero with the removal of the microreactor in observations kit
- type: CrewMonitoringConsole # DeltaV - disable crew crit / dead beeping alerts
alertsEnabled: false
- type: entity
id: SyndiCrewMonitorEmpty