mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-20 06:58:55 +03:00
# Description Replaces every instance of station announcements with an announcer system meant to handle audio and messages for various announcers defined in prototypes instead of each server replacing the scattered files inconsistently with whatever singular thing they want to hear announce messages. # TODO - [x] Systems - [x] CVars - [x] Sounds - [x] Client volume slider - [x] Collections - [x] Prototypes - [x] Events - [x] Commands - [x] PR media - [x] Deglobalize - [x] Passthrough localization parameters to overrides - [x] Make every announcer follow the template - [x] Move sounds into subdirectories - [x] Make announcement IDs camelCased - [x] Test announcement localizations - [x] Weighted announcer lists --- <details><summary><h1>Media</h1></summary> <p> https://github.com/Simple-Station/Parkstation-Friendly-Chainsaw/assets/77995199/caf5805d-acb0-4140-b344-875a8f79e5ee </p> </details> --- # Changelog 🆑 - add: Added 4 new announcers that will randomly be selected every shift
171 lines
6.2 KiB
C#
171 lines
6.2 KiB
C#
using System.Linq;
|
|
using Content.Server.Chat.Systems;
|
|
using Content.Server.Station.Systems;
|
|
using Content.Shared.CCVar;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Audio.Systems;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.Prototypes;
|
|
using Content.Server.Announcements.Systems;
|
|
|
|
namespace Content.Server.AlertLevel;
|
|
|
|
public sealed class AlertLevelSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
|
[Dependency] private readonly StationSystem _stationSystem = default!;
|
|
[Dependency] private readonly AnnouncerSystem _announcer = default!;
|
|
|
|
// Until stations are a prototype, this is how it's going to have to be.
|
|
public const string DefaultAlertLevelSet = "stationAlerts";
|
|
|
|
public override void Initialize()
|
|
{
|
|
SubscribeLocalEvent<StationInitializedEvent>(OnStationInitialize);
|
|
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
|
|
}
|
|
|
|
public override void Update(float time)
|
|
{
|
|
var query = EntityQueryEnumerator<AlertLevelComponent>();
|
|
|
|
while (query.MoveNext(out var station, out var alert))
|
|
{
|
|
if (alert.CurrentDelay <= 0)
|
|
{
|
|
if (alert.ActiveDelay)
|
|
{
|
|
RaiseLocalEvent(new AlertLevelDelayFinishedEvent());
|
|
alert.ActiveDelay = false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
alert.CurrentDelay -= time;
|
|
}
|
|
}
|
|
|
|
private void OnStationInitialize(StationInitializedEvent args)
|
|
{
|
|
if (!TryComp<AlertLevelComponent>(args.Station, out var alertLevelComponent))
|
|
return;
|
|
|
|
if (!_prototypeManager.TryIndex(alertLevelComponent.AlertLevelPrototype, out AlertLevelPrototype? alerts))
|
|
{
|
|
return;
|
|
}
|
|
|
|
alertLevelComponent.AlertLevels = alerts;
|
|
|
|
var defaultLevel = alertLevelComponent.AlertLevels.DefaultLevel;
|
|
if (string.IsNullOrEmpty(defaultLevel))
|
|
{
|
|
defaultLevel = alertLevelComponent.AlertLevels.Levels.Keys.First();
|
|
}
|
|
|
|
SetLevel(args.Station, defaultLevel, false, false, true);
|
|
}
|
|
|
|
private void OnPrototypeReload(PrototypesReloadedEventArgs args)
|
|
{
|
|
if (!args.ByType.TryGetValue(typeof(AlertLevelPrototype), out var alertPrototypes)
|
|
|| !alertPrototypes.Modified.TryGetValue(DefaultAlertLevelSet, out var alertObject)
|
|
|| alertObject is not AlertLevelPrototype alerts)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var query = EntityQueryEnumerator<AlertLevelComponent>();
|
|
while (query.MoveNext(out var uid, out var comp))
|
|
{
|
|
comp.AlertLevels = alerts;
|
|
|
|
if (!comp.AlertLevels.Levels.ContainsKey(comp.CurrentLevel))
|
|
{
|
|
var defaultLevel = comp.AlertLevels.DefaultLevel;
|
|
if (string.IsNullOrEmpty(defaultLevel))
|
|
{
|
|
defaultLevel = comp.AlertLevels.Levels.Keys.First();
|
|
}
|
|
|
|
SetLevel(uid, defaultLevel, true, true, true);
|
|
}
|
|
}
|
|
|
|
RaiseLocalEvent(new AlertLevelPrototypeReloadedEvent());
|
|
}
|
|
|
|
public float GetAlertLevelDelay(EntityUid station, AlertLevelComponent? alert = null)
|
|
{
|
|
if (!Resolve(station, ref alert))
|
|
{
|
|
return float.NaN;
|
|
}
|
|
|
|
return alert.CurrentDelay;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the alert level based on the station's entity ID.
|
|
/// </summary>
|
|
/// <param name="station">Station entity UID.</param>
|
|
/// <param name="level">Level to change the station's alert level to.</param>
|
|
/// <param name="playSound">Play the alert level's sound.</param>
|
|
/// <param name="announce">Say the alert level's announcement.</param>
|
|
/// <param name="force">Force the alert change. This applies if the alert level is not selectable or not.</param>
|
|
/// <param name="locked">Will it be possible to change level by crew.</param>
|
|
public void SetLevel(EntityUid station, string level, bool playSound, bool announce, bool force = false,
|
|
bool locked = false, MetaDataComponent? dataComponent = null, AlertLevelComponent? component = null)
|
|
{
|
|
if (!Resolve(station, ref component, ref dataComponent)
|
|
|| component.AlertLevels == null
|
|
|| !component.AlertLevels.Levels.TryGetValue(level, out var detail)
|
|
|| component.CurrentLevel == level)
|
|
return;
|
|
|
|
if (!force)
|
|
{
|
|
if (!detail.Selectable
|
|
|| component.CurrentDelay > 0
|
|
|| component.IsLevelLocked)
|
|
return;
|
|
|
|
component.CurrentDelay = _cfg.GetCVar(CCVars.GameAlertLevelChangeDelay);
|
|
component.ActiveDelay = true;
|
|
}
|
|
|
|
component.CurrentLevel = level;
|
|
component.IsLevelLocked = locked;
|
|
|
|
var name = level.ToLower();
|
|
if (Loc.TryGetString($"alert-level-{level}", out var locName))
|
|
name = locName.ToLower();
|
|
|
|
// Announcement text. Is passed into announcementFull.
|
|
var announcement = detail.Announcement;
|
|
|
|
if (Loc.TryGetString(detail.Announcement, out var locAnnouncement))
|
|
announcement = locAnnouncement;
|
|
|
|
var alert = _announcer.GetAnnouncementId($"Alert{level}");
|
|
if (playSound)
|
|
_announcer.SendAnnouncementAudio(alert, _stationSystem.GetInOwningStation(station));
|
|
if (announce)
|
|
_announcer.SendAnnouncementMessage(alert, "alert-level-announcement", null, detail.Color, null, null,
|
|
("name", name), ("announcement", announcement));
|
|
|
|
RaiseLocalEvent(new AlertLevelChangedEvent(station, level));
|
|
}
|
|
}
|
|
|
|
public sealed class AlertLevelDelayFinishedEvent : EntityEventArgs;
|
|
public sealed class AlertLevelPrototypeReloadedEvent : EntityEventArgs;
|
|
public sealed class AlertLevelChangedEvent(EntityUid station, string alertLevel) : EntityEventArgs
|
|
{
|
|
public EntityUid Station { get; } = station;
|
|
public string AlertLevel { get; } = alertLevel;
|
|
}
|