diff --git a/Content.Client/Audio/ContentAudioSystem.cs b/Content.Client/Audio/ContentAudioSystem.cs
index c81e0a44f1..8cfe08aa07 100644
--- a/Content.Client/Audio/ContentAudioSystem.cs
+++ b/Content.Client/Audio/ContentAudioSystem.cs
@@ -36,6 +36,7 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
public const float AmbientMusicMultiplier = 3f;
public const float LobbyMultiplier = 3f;
public const float InterfaceMultiplier = 2f;
+ public const float AnnouncerMultiplier = 3f; // Parkstation-RandomAnnouncers
public override void Initialize()
{
diff --git a/Content.Client/Options/UI/Tabs/AudioTab.xaml b/Content.Client/Options/UI/Tabs/AudioTab.xaml
index e54b0dc34e..7cd4e180b2 100644
--- a/Content.Client/Options/UI/Tabs/AudioTab.xaml
+++ b/Content.Client/Options/UI/Tabs/AudioTab.xaml
@@ -100,6 +100,20 @@
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Options/UI/Tabs/AudioTab.xaml.cs b/Content.Client/Options/UI/Tabs/AudioTab.xaml.cs
index 470ca7d799..e0700fd43a 100644
--- a/Content.Client/Options/UI/Tabs/AudioTab.xaml.cs
+++ b/Content.Client/Options/UI/Tabs/AudioTab.xaml.cs
@@ -1,5 +1,6 @@
using Content.Client.Audio;
using Content.Shared.CCVar;
+using Content.Shared.Parkstation.CCVar;
using Robust.Client.Audio;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
@@ -37,6 +38,7 @@ public AudioTab()
AmbienceSoundsSlider.OnValueChanged += OnAmbienceSoundsSliderChanged;
LobbyVolumeSlider.OnValueChanged += OnLobbyVolumeSliderChanged;
InterfaceVolumeSlider.OnValueChanged += OnInterfaceVolumeSliderChanged;
+ AnnouncerVolumeSlider.OnValueChanged += OnAnnouncerVolumeSliderChanged; // Parkstation-RandomAnnouncers
LobbyMusicCheckBox.OnToggled += OnLobbyMusicCheckToggled;
RestartSoundsCheckBox.OnToggled += OnRestartSoundsCheckToggled;
EventMusicCheckBox.OnToggled += OnEventMusicCheckToggled;
@@ -58,6 +60,7 @@ protected override void Dispose(bool disposing)
AmbienceVolumeSlider.OnValueChanged -= OnAmbienceVolumeSliderChanged;
LobbyVolumeSlider.OnValueChanged -= OnLobbyVolumeSliderChanged;
InterfaceVolumeSlider.OnValueChanged -= OnInterfaceVolumeSliderChanged;
+ AnnouncerVolumeSlider.OnValueChanged -= OnAnnouncerVolumeSliderChanged; // Parkstation-RandomAnnouncers
base.Dispose(disposing);
}
@@ -97,6 +100,12 @@ private void OnMidiVolumeSliderChanged(Range range)
UpdateChanges();
}
+ // Parkstation-RandomAnnouncers
+ private void OnAnnouncerVolumeSliderChanged(Range range)
+ {
+ UpdateChanges();
+ }
+
private void OnLobbyMusicCheckToggled(BaseButton.ButtonEventArgs args)
{
UpdateChanges();
@@ -125,6 +134,7 @@ private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
_cfg.SetCVar(CCVars.AmbientMusicVolume, AmbientMusicVolumeSlider.Value / 100f * ContentAudioSystem.AmbientMusicMultiplier);
_cfg.SetCVar(CCVars.LobbyMusicVolume, LobbyVolumeSlider.Value / 100f * ContentAudioSystem.LobbyMultiplier);
_cfg.SetCVar(CCVars.InterfaceVolume, InterfaceVolumeSlider.Value / 100f * ContentAudioSystem.InterfaceMultiplier);
+ _cfg.SetCVar(SimpleStationCCVars.AnnouncerVolume, AnnouncerVolumeSlider.Value / 100f * ContentAudioSystem.AnnouncerMultiplier); // Parkstation-RandomAnnouncers
_cfg.SetCVar(CCVars.MaxAmbientSources, (int)AmbienceSoundsSlider.Value);
@@ -149,6 +159,7 @@ private void Reset()
AmbientMusicVolumeSlider.Value = _cfg.GetCVar(CCVars.AmbientMusicVolume) * 100f / ContentAudioSystem.AmbientMusicMultiplier;
LobbyVolumeSlider.Value = _cfg.GetCVar(CCVars.LobbyMusicVolume) * 100f / ContentAudioSystem.LobbyMultiplier;
InterfaceVolumeSlider.Value = _cfg.GetCVar(CCVars.InterfaceVolume) * 100f / ContentAudioSystem.InterfaceMultiplier;
+ AnnouncerVolumeSlider.Value = _cfg.GetCVar(SimpleStationCCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier; // Parkstation-RandomAnnouncers
AmbienceSoundsSlider.Value = _cfg.GetCVar(CCVars.MaxAmbientSources);
@@ -174,6 +185,8 @@ private void UpdateChanges()
Math.Abs(LobbyVolumeSlider.Value - _cfg.GetCVar(CCVars.LobbyMusicVolume) * 100f / ContentAudioSystem.LobbyMultiplier) < 0.01f;
var isInterfaceVolumeSame =
Math.Abs(InterfaceVolumeSlider.Value - _cfg.GetCVar(CCVars.InterfaceVolume) * 100f / ContentAudioSystem.InterfaceMultiplier) < 0.01f;
+ var isAnnouncerVolumeSame = // Parkstation-RandomAnnouncers
+ Math.Abs(AnnouncerVolumeSlider.Value - _cfg.GetCVar(SimpleStationCCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier) < 0.01f;
var isAmbientSoundsSame = (int)AmbienceSoundsSlider.Value == _cfg.GetCVar(CCVars.MaxAmbientSources);
var isLobbySame = LobbyMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.LobbyMusicEnabled);
@@ -181,7 +194,7 @@ private void UpdateChanges()
var isEventSame = EventMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.EventMusicEnabled);
var isAdminSoundsSame = AdminSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.AdminSoundsEnabled);
var isEverythingSame = isMasterVolumeSame && isMidiVolumeSame && isAmbientVolumeSame && isAmbientMusicVolumeSame && isAmbientSoundsSame && isLobbySame && isRestartSoundsSame && isEventSame
- && isAdminSoundsSame && isLobbyVolumeSame && isInterfaceVolumeSame;
+ && isAdminSoundsSame && isLobbyVolumeSame && isInterfaceVolumeSame && isAnnouncerVolumeSame; // Parkstation-RandomAnnouncers
ApplyButton.Disabled = isEverythingSame;
ResetButton.Disabled = isEverythingSame;
MasterVolumeLabel.Text =
@@ -196,6 +209,8 @@ private void UpdateChanges()
Loc.GetString("ui-options-volume-percent", ("volume", LobbyVolumeSlider.Value / 100));
InterfaceVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", InterfaceVolumeSlider.Value / 100));
+ AnnouncerVolumeLabel.Text = // Parkstation-RandomAnnouncers
+ Loc.GetString("ui-options-volume-percent", ("volume", AnnouncerVolumeSlider.Value / 100));
AmbienceSoundsLabel.Text = ((int)AmbienceSoundsSlider.Value).ToString();
}
}
diff --git a/Content.Client/Parkstation/Announcements/Systems/AnnouncerSystem.cs b/Content.Client/Parkstation/Announcements/Systems/AnnouncerSystem.cs
new file mode 100644
index 0000000000..91dfbf53c2
--- /dev/null
+++ b/Content.Client/Parkstation/Announcements/Systems/AnnouncerSystem.cs
@@ -0,0 +1,69 @@
+using Content.Client.Audio;
+using Content.Shared.Parkstation.Announcements.Events;
+using Content.Shared.Parkstation.Announcements.Systems;
+using Content.Shared.Parkstation.CCVar;
+using Robust.Client.Audio;
+using Robust.Client.Player;
+using Robust.Client.ResourceManagement;
+using Robust.Shared.Audio.Sources;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Configuration;
+
+namespace Content.Client.Parkstation.Announcements.Systems;
+
+public sealed class AnnouncerSystem : SharedAnnouncerSystem
+{
+ [Dependency] private readonly IPlayerManager _player = default!;
+ [Dependency] private readonly IConfigurationManager _config = default!;
+ [Dependency] private readonly IResourceCache _cache = default!;
+ [Dependency] private readonly IAudioManager _audioManager = default!;
+
+ private IAudioSource? AnnouncerSource { get; set; }
+ private float AnnouncerVolume { get; set; }
+
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ AnnouncerVolume = _config.GetCVar(SimpleStationCCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier;
+
+ SubscribeNetworkEvent(OnAnnouncementReceived);
+ _config.OnValueChanged(SimpleStationCCVars.AnnouncerVolume, OnAnnouncerVolumeChanged);
+ }
+
+ public override void Shutdown()
+ {
+ base.Shutdown();
+
+ _config.UnsubValueChanged(SimpleStationCCVars.AnnouncerVolume, OnAnnouncerVolumeChanged);
+ }
+
+
+ private void OnAnnouncerVolumeChanged(float value)
+ {
+ AnnouncerVolume = value;
+
+ if (AnnouncerSource != null)
+ AnnouncerSource.Gain = AnnouncerVolume;
+ }
+
+ private void OnAnnouncementReceived(AnnouncementSendEvent ev)
+ {
+ if (!ev.Recipients.Contains(_player.LocalSession!.UserId)
+ || !_cache.TryGetResource(GetAnnouncementPath(ev.AnnouncementId, ev.AnnouncerId),
+ out var resource))
+ return;
+
+ var source = _audioManager.CreateAudioSource(resource);
+ if (source != null)
+ {
+ source.Gain = AnnouncerVolume * SharedAudioSystem.VolumeToGain(ev.AudioParams.Volume);
+ source.Global = true;
+ }
+
+ AnnouncerSource?.Dispose();
+ AnnouncerSource = source;
+ AnnouncerSource?.StartPlaying();
+ }
+}
diff --git a/Content.IntegrationTests/Tests/Parkstation/Announcers/AnnouncerFallbackTest.cs b/Content.IntegrationTests/Tests/Parkstation/Announcers/AnnouncerFallbackTest.cs
new file mode 100644
index 0000000000..6db350cfcf
--- /dev/null
+++ b/Content.IntegrationTests/Tests/Parkstation/Announcers/AnnouncerFallbackTest.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.Linq;
+using Content.Shared.Parkstation.Announcements.Prototypes;
+using Robust.Shared.Prototypes;
+
+namespace Content.IntegrationTests.Tests.Parkstation.Announcers;
+
+[TestFixture]
+[TestOf(typeof(AnnouncerPrototype))]
+public sealed class AnnouncerPrototypeTests
+{
+ [Test]
+ public async Task TestAnnouncerFallbacks()
+ {
+ // Checks if every announcer has a fallback announcement
+
+ await using var pair = await PoolManager.GetServerClient();
+ var server = pair.Server;
+
+ var prototype = server.ResolveDependency();
+
+ await server.WaitAssertion(() =>
+ {
+ var success = true;
+ var why = new List();
+
+ foreach (var announcer in prototype.EnumeratePrototypes())
+ {
+ if (announcer.Announcements.All(a => a.ID.ToLower() != "fallback"))
+ {
+ success = false;
+ why.Add(announcer.ID);
+ }
+ }
+
+ Assert.That(success, Is.True, $"The following announcers do not have a fallback announcement:\n {string.Join("\n ", why)}");
+ });
+
+ await pair.CleanReturnAsync();
+ }
+}
diff --git a/Content.IntegrationTests/Tests/Parkstation/Announcers/AnnouncerLocalizationTest.cs b/Content.IntegrationTests/Tests/Parkstation/Announcers/AnnouncerLocalizationTest.cs
new file mode 100644
index 0000000000..10c507e16b
--- /dev/null
+++ b/Content.IntegrationTests/Tests/Parkstation/Announcers/AnnouncerLocalizationTest.cs
@@ -0,0 +1,66 @@
+using System.Collections.Generic;
+using Content.Server.Parkstation.Announcements.Systems;
+using Content.Server.StationEvents;
+using Content.Shared.Parkstation.Announcements.Prototypes;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Localization;
+
+namespace Content.IntegrationTests.Tests.Parkstation.Announcers;
+
+[TestFixture]
+[TestOf(typeof(AnnouncerPrototype))]
+public sealed class AnnouncerLocalizationTest
+{
+ [Test]
+ public async Task TestEventLocalization()
+ {
+ // Checks if every station event wanting the announcerSystem to send messages has a localization string
+ // If an event doesn't have startAnnouncement or endAnnouncement set to true
+ // it will be expected for that system to handle the announcements if it wants them
+
+ await using var pair = await PoolManager.GetServerClient();
+ var server = pair.Server;
+
+ var locale = server.ResolveDependency();
+ var entSysMan = server.ResolveDependency();
+ var announcer = entSysMan.GetEntitySystem();
+ var events = entSysMan.GetEntitySystem();
+
+ await server.WaitAssertion(() =>
+ {
+ var succeeded = true;
+ var why = new List();
+
+ foreach (var ev in events.AllEvents())
+ {
+ if (ev.Value.StartAnnouncement)
+ {
+ var announcementId = announcer.GetAnnouncementId(ev.Key.ID);
+ var eventLocaleString = announcer.GetEventLocaleString(announcementId);
+
+ if (locale.GetString(eventLocaleString) == eventLocaleString)
+ {
+ succeeded = false;
+ why.Add($"\"{announcementId}\": \"{eventLocaleString}\"");
+ }
+ }
+
+ if (ev.Value.EndAnnouncement)
+ {
+ var announcementId = announcer.GetAnnouncementId(ev.Key.ID, true);
+ var eventLocaleString = announcer.GetEventLocaleString(announcementId);
+
+ if (locale.GetString(eventLocaleString) == eventLocaleString)
+ {
+ succeeded = false;
+ why.Add($"\"{announcementId}\": \"{eventLocaleString}\"");
+ }
+ }
+ }
+
+ Assert.That(succeeded, Is.True, $"The following announcements do not have a localization string:\n {string.Join("\n ", why)}");
+ });
+
+ await pair.CleanReturnAsync();
+ }
+}
diff --git a/Content.Server/Administration/UI/AdminAnnounceEui.cs b/Content.Server/Administration/UI/AdminAnnounceEui.cs
index b6a6ba9984..9a009be84f 100644
--- a/Content.Server/Administration/UI/AdminAnnounceEui.cs
+++ b/Content.Server/Administration/UI/AdminAnnounceEui.cs
@@ -3,8 +3,10 @@
using Content.Server.Chat.Managers;
using Content.Server.Chat.Systems;
using Content.Server.EUI;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Shared.Administration;
using Content.Shared.Eui;
+using Robust.Shared.Player;
namespace Content.Server.Administration.UI
{
@@ -12,6 +14,7 @@ public sealed class AdminAnnounceEui : BaseEui
{
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
private readonly ChatSystem _chatSystem;
public AdminAnnounceEui()
@@ -50,7 +53,10 @@ public override void HandleMessage(EuiMessageBase msg)
break;
// TODO: Per-station announcement support
case AdminAnnounceType.Station:
- _chatSystem.DispatchGlobalAnnouncement(doAnnounce.Announcement, doAnnounce.Announcer, colorOverride: Color.Gold);
+ // Parkstation-RandomAnnouncers-Start
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("Announce"), Filter.Broadcast(),
+ doAnnounce.Announcement, doAnnounce.Announcer, Color.Gold);
+ // Parkstation-RandomAnnouncers-End
break;
}
diff --git a/Content.Server/AlertLevel/AlertLevelSystem.cs b/Content.Server/AlertLevel/AlertLevelSystem.cs
index 04e274ceeb..e32893e2b1 100644
--- a/Content.Server/AlertLevel/AlertLevelSystem.cs
+++ b/Content.Server/AlertLevel/AlertLevelSystem.cs
@@ -1,7 +1,9 @@
using System.Linq;
using Content.Server.Chat.Systems;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Systems;
using Content.Shared.CCVar;
+using Content.Shared.Parkstation.Announcements.Systems;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
@@ -16,6 +18,7 @@ public sealed class AlertLevelSystem : EntitySystem
[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";
@@ -162,25 +165,13 @@ public void SetLevel(EntityUid station, string level, bool playSound, bool annou
// The full announcement to be spat out into chat.
var announcementFull = Loc.GetString("alert-level-announcement", ("name", name), ("announcement", announcement));
- var playDefault = false;
+ // Parkstation-RandomAnnouncers-Start
+ var alert = _announcer.GetAnnouncementId($"Alert{level}");
if (playSound)
- {
- if (detail.Sound != null)
- {
- var filter = _stationSystem.GetInOwningStation(station);
- _audio.PlayGlobal(detail.Sound.GetSound(), filter, true, detail.Sound.Params);
- }
- else
- {
- playDefault = true;
- }
- }
-
+ _announcer.SendAnnouncementAudio(alert, _stationSystem.GetInOwningStation(station));
if (announce)
- {
- _chatSystem.DispatchStationAnnouncement(station, announcementFull, playDefaultSound: playDefault,
- colorOverride: detail.Color, sender: stationName);
- }
+ _announcer.SendAnnouncementMessage(alert, announcementFull, colorOverride: detail.Color);
+ // Parkstation-RandomAnnouncers-End
RaiseLocalEvent(new AlertLevelChangedEvent(station, level));
}
diff --git a/Content.Server/Announcements/AnnounceCommand.cs b/Content.Server/Announcements/AnnounceCommand.cs
index cedde3fc14..7774024780 100644
--- a/Content.Server/Announcements/AnnounceCommand.cs
+++ b/Content.Server/Announcements/AnnounceCommand.cs
@@ -1,8 +1,11 @@
+using System.Linq;
using Content.Server.Administration;
-using Content.Server.Chat;
-using Content.Server.Chat.Systems;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Shared.Administration;
+using Content.Shared.Parkstation.Announcements.Prototypes;
using Robust.Shared.Console;
+using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
namespace Content.Server.Announcements
{
@@ -11,27 +14,79 @@ public sealed class AnnounceCommand : IConsoleCommand
{
public string Command => "announce";
public string Description => "Send an in-game announcement.";
- public string Help => $"{Command} or {Command} to send announcement as CentCom.";
+ // Parkstation-RandomAnnouncers-Start // This entire thing was rewritten
+ public string Help => $"{Command} ";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
- var chat = IoCManager.Resolve().GetEntitySystem();
+ var announcer = IoCManager.Resolve().GetEntitySystem();
+ var proto = IoCManager.Resolve();
- if (args.Length == 0)
+ switch (args.Length)
{
- shell.WriteError("Not enough arguments! Need at least 1.");
- return;
+ case 0:
+ shell.WriteError("Not enough arguments! Need at least 1.");
+ return;
+ case 1:
+ announcer.SendAnnouncement(announcer.GetAnnouncementId("CommandReport"), Filter.Broadcast(),
+ args[0], "Central Command", Color.Gold);
+ break;
+ case 2:
+ announcer.SendAnnouncement(announcer.GetAnnouncementId("CommandReport"), Filter.Broadcast(),
+ args[1], args[0], Color.Gold);
+ break;
+ case 3:
+ announcer.SendAnnouncement(announcer.GetAnnouncementId(args[2]), Filter.Broadcast(), args[1],
+ args[0], Color.Gold);
+ break;
+ case 4:
+ if (!proto.TryIndex(args[3], out AnnouncerPrototype? prototype))
+ {
+ shell.WriteError($"No announcer prototype with ID {args[3]} found!");
+ return;
+ }
+ announcer.SendAnnouncement(args[2], Filter.Broadcast(), args[1], args[0], Color.Gold, null,
+ prototype);
+ break;
}
- if (args.Length == 1)
- {
- chat.DispatchGlobalAnnouncement(args[0], colorOverride: Color.Gold);
- }
- else
+ shell.WriteLine("Sent!");
+ }
+
+ public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
+ {
+ switch (args.Length)
{
- var message = string.Join(' ', new ArraySegment(args, 1, args.Length-1));
- chat.DispatchGlobalAnnouncement(message, args[0], colorOverride: Color.Gold);
+ case 3:
+ {
+ var list = new List();
+
+ foreach (var prototype in IoCManager.Resolve()
+ .EnumeratePrototypes()
+ .SelectMany(p => p.Announcements.Select(a => a.ID)))
+ {
+ if (!list.Contains(prototype))
+ list.Add(prototype);
+ }
+
+ return CompletionResult.FromHintOptions(list, Loc.GetString("admin-announce-hint-sound"));
+ }
+ case 4:
+ {
+ var list = new List();
+
+ foreach (var prototype in IoCManager.Resolve()
+ .EnumeratePrototypes())
+ {
+ if (!list.Contains(prototype.ID))
+ list.Add(prototype.ID);
+ }
+
+ return CompletionResult.FromHintOptions(list, Loc.GetString("admin-announce-hint-voice"));
+ }
+ default:
+ return CompletionResult.Empty;
}
- shell.WriteLine("Sent!");
}
+ // Parkstation-RandomAnnouncers-End
}
}
diff --git a/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs b/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs
index 0f0365e56b..084f797581 100644
--- a/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs
+++ b/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs
@@ -1,10 +1,13 @@
using Content.Server.Chat;
+using Content.Server.Parkstation.Announcements.Systems;
+using Robust.Shared.Player;
namespace Content.Server.Chat.Systems;
public sealed class AnnounceOnSpawnSystem : EntitySystem
{
[Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
public override void Initialize()
{
@@ -17,6 +20,6 @@ private void OnInit(EntityUid uid, AnnounceOnSpawnComponent comp, MapInitEvent a
{
var message = Loc.GetString(comp.Message);
var sender = comp.Sender != null ? Loc.GetString(comp.Sender) : "Central Command";
- _chat.DispatchGlobalAnnouncement(message, sender, playSound: true, comp.Sound, comp.Color);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("SpawnAnnounceCaptain"), Filter.Broadcast(), message, sender, comp.Color); // Parkstation-RandomAnnouncers
}
}
diff --git a/Content.Server/Communications/CommsHackerSystem.cs b/Content.Server/Communications/CommsHackerSystem.cs
index 1248d21400..d38560dc66 100644
--- a/Content.Server/Communications/CommsHackerSystem.cs
+++ b/Content.Server/Communications/CommsHackerSystem.cs
@@ -1,11 +1,13 @@
using Content.Server.Chat.Systems;
using Content.Server.GameTicking;
using Content.Server.Ninja.Systems;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Shared.Communications;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
+using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
@@ -21,6 +23,7 @@ public sealed class CommsHackerSystem : SharedCommsHackerSystem
// TODO: remove when generic check event is used
[Dependency] private readonly NinjaGlovesSystem _gloves = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
public override void Initialize()
{
@@ -79,7 +82,7 @@ private void OnDoAfter(EntityUid uid, CommsHackerComponent comp, TerrorDoAfterEv
public void CallInThreat(NinjaHackingThreatPrototype ninjaHackingThreat)
{
_gameTicker.StartGameRule(ninjaHackingThreat.Rule, out _);
- _chat.DispatchGlobalAnnouncement(Loc.GetString(ninjaHackingThreat.Announcement), playSound: true, colorOverride: Color.Red);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("NinjaHacking"), Filter.Broadcast(), Loc.GetString(ninjaHackingThreat.Announcement), colorOverride: Color.Red); // Parkstation-RandomAnnouncers
}
}
diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs
index 4fa60563bd..91ec29e97f 100644
--- a/Content.Server/Communications/CommunicationsConsoleSystem.cs
+++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs
@@ -12,6 +12,8 @@
using Content.Server.Screens;
using Content.Server.Screens.Components;
using Content.Server.Shuttles.Systems;
+using Content.Server.Parkstation.Announcements.Systems;
+using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
@@ -23,6 +25,7 @@
using Content.Shared.Popups;
using Robust.Server.GameObjects;
using Robust.Shared.Configuration;
+using Robust.Shared.Player;
namespace Content.Server.Communications
{
@@ -41,6 +44,7 @@ public sealed class CommunicationsConsoleSystem : EntitySystem
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!; // Parkstation-RandomAnnouncers
private const float UIUpdateInterval = 5.0f;
@@ -278,14 +282,15 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com
msg += "\n" + Loc.GetString("comms-console-announcement-sent-by") + " " + author;
if (comp.Global)
{
- _chatSystem.DispatchGlobalAnnouncement(msg, title, announcementSound: comp.Sound, colorOverride: comp.Color);
+ _announcer.SendAnnouncement("announce", Filter.Broadcast(), msg, title, comp.Color); // Parkstation-RandomAnnouncers
if (message.Session.AttachedEntity != null)
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following global announcement: {msg}");
return;
}
- _chatSystem.DispatchStationAnnouncement(uid, msg, title, colorOverride: comp.Color);
+ if (TryComp(_stationSystem.GetOwningStation(uid), out var stationData)) // Parkstation-RandomAnnouncers
+ _announcer.SendAnnouncement("announce", _stationSystem.GetInStation(stationData), msg, title, comp.Color);
if (message.Session.AttachedEntity != null)
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following station announcement: {msg}");
diff --git a/Content.Server/Dragon/DragonRiftSystem.cs b/Content.Server/Dragon/DragonRiftSystem.cs
index f7d5cd783d..8c74a9cb53 100644
--- a/Content.Server/Dragon/DragonRiftSystem.cs
+++ b/Content.Server/Dragon/DragonRiftSystem.cs
@@ -11,6 +11,7 @@
using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager;
using System.Numerics;
+using Content.Server.Parkstation.Announcements.Systems;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
@@ -27,6 +28,7 @@ public sealed class DragonRiftSystem : EntitySystem
[Dependency] private readonly NavMapSystem _navMap = default!;
[Dependency] private readonly NPCSystem _npc = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
public override void Initialize()
{
@@ -70,8 +72,7 @@ public override void Update(float frameTime)
Dirty(comp);
var location = xform.LocalPosition;
- _chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red);
- _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("CarpRift"), Filter.Broadcast(), Loc.GetString("carp-rift-warning", ("location", location)), colorOverride: Color.Red); // Parkstation-RandomAnnouncers
_navMap.SetBeaconEnabled(uid, true);
}
diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs
index 0111816bb6..5de563313b 100644
--- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs
+++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs
@@ -5,9 +5,11 @@
using Content.Server.GameTicking.Events;
using Content.Server.Ghost;
using Content.Server.Maps;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Shared.Database;
using Content.Shared.GameTicking;
using Content.Shared.Mind;
+using Content.Shared.Parkstation.Announcements.Systems;
using Content.Shared.Players;
using Content.Shared.Preferences;
using JetBrains.Annotations;
@@ -27,6 +29,7 @@ public sealed partial class GameTicker
{
[Dependency] private readonly DiscordWebhook _discord = default!;
[Dependency] private readonly ITaskManager _taskManager = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
"ss14_round_number",
@@ -589,11 +592,10 @@ private void AnnounceRound()
var proto = _robustRandom.Pick(options);
- if (proto.Message != null)
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(proto.Message), playSound: true);
-
- if (proto.Sound != null)
- _audio.PlayGlobal(proto.Sound, Filter.Broadcast(), true);
+ // Parkstation-RandomAnnouncers-Start
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(proto.ID), Filter.Broadcast(),
+ Loc.GetString(proto.Message ?? "game-ticker-welcome-to-the-station"));
+ // Parkstation-RandomAnnouncers-End
}
private async void SendRoundStartedDiscordMessage()
diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs
index 5bce7f20e4..4dbd651e95 100644
--- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs
+++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs
@@ -23,6 +23,7 @@
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Shuttles.Systems;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Spawners.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
@@ -86,6 +87,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly WarDeclaratorSystem _warDeclarator = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
[ValidatePrototypeId]
@@ -211,7 +213,7 @@ public void DeclareWar(EntityUid opsUid, string msg, string title, SoundSpecifie
var nukieRule = comps.Value.Item1;
nukieRule.WarDeclaredTime = _gameTiming.CurTime;
- _chat.DispatchGlobalAnnouncement(msg, title, announcementSound: announcementSound, colorOverride: colorOverride);
+ _announcer.SendAnnouncement("war", Filter.Broadcast(), msg, title, colorOverride); // Parkstation-RandomAnnouncers
DistributeExtraTC(nukieRule);
_warDeclarator.RefreshAllUI(comps.Value.Item1, comps.Value.Item2);
}
diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs
index 886ff965c7..c7dc0f9d62 100644
--- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs
+++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs
@@ -8,6 +8,7 @@
using Content.Server.Preferences.Managers;
using Content.Server.Roles;
using Content.Server.RoundEnd;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.Zombies;
@@ -49,6 +50,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem
[Dependency] private readonly SharedRoleSystem _roles = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
public override void Initialize()
{
@@ -128,7 +130,7 @@ private void CheckRoundEnd()
comp.ShuttleCalled = true;
foreach (var station in _station.GetStations())
{
- _chat.DispatchStationAnnouncement(station, Loc.GetString("zombie-shuttle-call"), colorOverride: Color.Crimson);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleCalled"), _station.GetInOwningStation(station), Loc.GetString("zombie-shuttle-call"), colorOverride: Color.Crimson); // Parkstation-RandomAnnouncers
}
_roundEnd.RequestRoundEnd(null, false);
}
diff --git a/Content.Server/Nuke/NukeCodePaperSystem.cs b/Content.Server/Nuke/NukeCodePaperSystem.cs
index 8df25feebf..d332f8d118 100644
--- a/Content.Server/Nuke/NukeCodePaperSystem.cs
+++ b/Content.Server/Nuke/NukeCodePaperSystem.cs
@@ -2,9 +2,11 @@
using Content.Server.Chat.Systems;
using Content.Server.Fax;
using Content.Server.Paper;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Paper;
+using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@@ -17,6 +19,7 @@ public sealed class NukeCodePaperSystem : EntitySystem
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly PaperSystem _paper = default!;
[Dependency] private readonly FaxSystem _faxSystem = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
public override void Initialize()
{
@@ -79,7 +82,7 @@ public bool SendNukeCodes(EntityUid station)
if (wasSent)
{
var msg = Loc.GetString("nuke-component-announcement-send-codes");
- _chatSystem.DispatchStationAnnouncement(station, msg, colorOverride: Color.Red);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("NukeCodes"), Filter.Broadcast(), msg, colorOverride: Color.Red); // Parkstation-AnnouncerSystem
}
return wasSent;
diff --git a/Content.Server/Nuke/NukeSystem.cs b/Content.Server/Nuke/NukeSystem.cs
index 77689c4e2b..084c19de1e 100644
--- a/Content.Server/Nuke/NukeSystem.cs
+++ b/Content.Server/Nuke/NukeSystem.cs
@@ -4,6 +4,7 @@
using Content.Server.Explosion.EntitySystems;
using Content.Server.Pinpointer;
using Content.Server.Popups;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Systems;
using Content.Shared.Audio;
using Content.Shared.Containers.ItemSlots;
@@ -40,6 +41,7 @@ public sealed class NukeSystem : EntitySystem
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
///
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
@@ -455,7 +457,7 @@ public void ArmBomb(EntityUid uid, NukeComponent? component = null)
var announcement = Loc.GetString("nuke-component-announcement-armed",
("time", (int) component.RemainingTime), ("position", posText));
var sender = Loc.GetString("nuke-component-announcement-sender");
- _chatSystem.DispatchStationAnnouncement(stationUid ?? uid, announcement, sender, false, null, Color.Red);
+ _announcer.SendAnnouncementMessage(_announcer.GetAnnouncementId("NukeArm"), announcement, sender, Color.Red, stationUid ?? uid); // Parkstation-RandomAnnouncers
_sound.PlayGlobalOnStation(uid, _audio.GetSound(component.ArmSound));
@@ -493,7 +495,7 @@ public void DisarmBomb(EntityUid uid, NukeComponent? component = null)
// warn a crew
var announcement = Loc.GetString("nuke-component-announcement-unarmed");
var sender = Loc.GetString("nuke-component-announcement-sender");
- _chatSystem.DispatchStationAnnouncement(uid, announcement, sender, false);
+ _announcer.SendAnnouncementMessage(_announcer.GetAnnouncementId("NukeDisarm"), announcement, sender, station: stationUid ?? uid); // Parkstation-RandomAnnouncers
component.PlayedNukeSong = false;
_sound.PlayGlobalOnStation(uid, _audio.GetSound(component.DisarmSound));
@@ -604,4 +606,3 @@ public sealed class NukeDisarmSuccessEvent : EntityEventArgs
{
}
-
diff --git a/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.Announce.cs b/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.Announce.cs
new file mode 100644
index 0000000000..549ef679f8
--- /dev/null
+++ b/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.Announce.cs
@@ -0,0 +1,90 @@
+using System.Linq;
+using Content.Shared.Parkstation.Announcements.Events;
+using Content.Shared.Parkstation.Announcements.Prototypes;
+using Robust.Shared.Audio;
+using Robust.Shared.Player;
+
+namespace Content.Server.Parkstation.Announcements.Systems;
+
+public sealed partial class AnnouncerSystem
+{
+ ///
+ /// Gets an announcement message from the announcer
+ ///
+ /// ID of the announcement from the announcer to get information from
+ private string? GetAnnouncementMessage(string announcementId)
+ {
+ // Get the announcement data from the announcer
+ // Will be the fallback if the data for the announcementId is not found
+ var announcementType = Announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ??
+ Announcer.Announcements.First(a => a.ID == "fallback");
+
+ // Return the announcementType.MessageOverride if it exists, otherwise return null
+ return announcementType.MessageOverride != null ? Loc.GetString(announcementType.MessageOverride) : null;
+ }
+
+
+ ///
+ /// Sends an announcement audio
+ ///
+ /// ID of the announcement to get information from
+ /// Who hears the announcement audio
+ /// Uses this announcer instead of the current global one
+ public void SendAnnouncementAudio(string announcementId, Filter filter, AnnouncerPrototype? announcerOverride = null)
+ {
+ var ev = new AnnouncementSendEvent(
+ announcerOverride?.ID ?? Announcer.ID,
+ announcementId,
+ filter.Recipients.ToList().ConvertAll(p => p.UserId), // I hate this but IEnumerable isn't serializable, and then ICommonSession wasn't, so you get the User ID
+ GetAudioParams(announcementId, Announcer) ?? AudioParams.Default
+ );
+
+ RaiseNetworkEvent(ev);
+ }
+
+ ///
+ /// Sends an announcement message
+ ///
+ /// ID of the announcement to get information from
+ /// Text to send in the announcement
+ /// Who to show as the announcement announcer, defaults to the current announcer's name
+ /// What color the announcement should be
+ /// Station ID to send the announcement to
+ /// Uses this announcer instead of the current global one
+ public void SendAnnouncementMessage(string announcementId, string message, string? sender = null,
+ Color? colorOverride = null, EntityUid? station = null, AnnouncerPrototype? announcerOverride = null)
+ {
+ sender ??= Loc.GetString($"announcer-{announcerOverride?.ID ?? Announcer.ID}-name");
+
+ // If the announcement has a message override, use that instead of the message parameter
+ if (GetAnnouncementMessage(announcementId, announcerOverride?.ID ?? Announcer.ID) is { } announcementMessage)
+ message = announcementMessage;
+
+ // Don't send nothing
+ if (string.IsNullOrEmpty(message))
+ return;
+
+ // If there is a station, send the announcement to the station, otherwise send it to everyone
+ if (station == null)
+ _chat.DispatchGlobalAnnouncement(message, sender, false, colorOverride: colorOverride);
+ else
+ _chat.DispatchStationAnnouncement(station.Value, message, sender, false, colorOverride: colorOverride);
+ }
+
+ ///
+ /// Sends an announcement with a message and audio
+ ///
+ /// ID of the announcement to get information from
+ /// Who hears the announcement audio
+ /// Text to send in the announcement
+ /// Who to show as the announcement announcer, defaults to the current announcer's name
+ /// What color the announcement should be
+ /// Station ID to send the announcement to
+ /// Uses this announcer instead of the current global one
+ public void SendAnnouncement(string announcementId, Filter filter, string message, string? sender = null,
+ Color? colorOverride = null, EntityUid? station = null, AnnouncerPrototype? announcerOverride = null)
+ {
+ SendAnnouncementAudio(announcementId, filter, announcerOverride);
+ SendAnnouncementMessage(announcementId, message, sender, colorOverride, station, announcerOverride);
+ }
+}
diff --git a/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.Announcer.cs b/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.Announcer.cs
new file mode 100644
index 0000000000..3879fc5665
--- /dev/null
+++ b/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.Announcer.cs
@@ -0,0 +1,54 @@
+using System.Linq;
+using Content.Shared.GameTicking;
+using Content.Shared.Parkstation.Announcements.Prototypes;
+using Content.Shared.Parkstation.CCVar;
+using Robust.Shared.Random;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Parkstation.Announcements.Systems;
+
+public sealed partial class AnnouncerSystem
+{
+ private void OnRoundRestarting(RoundRestartCleanupEvent ev)
+ {
+ var announcer = _config.GetCVar(SimpleStationCCVars.Announcer);
+ if (string.IsNullOrEmpty(announcer))
+ SetAnnouncer(PickAnnouncer());
+ else
+ SetAnnouncer(announcer);
+ }
+
+
+ ///
+ /// Picks a random announcer
+ ///
+ /// Probably not very useful for any other system
+ public AnnouncerPrototype PickAnnouncer()
+ {
+ return _random.Pick(_proto.EnumeratePrototypes()
+ .Where(x => !_config.GetCVar(SimpleStationCCVars.AnnouncerBlacklist).Contains(x.ID))
+ .ToArray());
+ }
+
+
+ ///
+ /// Sets the announcer
+ ///
+ /// ID of the announcer to choose
+ public void SetAnnouncer(string announcerId)
+ {
+ if (!_proto.TryIndex(announcerId, out var announcer))
+ DebugTools.Assert("Set announcer does not exist, attempting to use previously set one.");
+ else
+ Announcer = announcer;
+ }
+
+ ///
+ /// Sets the announcer
+ ///
+ /// The announcer prototype to set the current announcer to
+ public void SetAnnouncer(AnnouncerPrototype announcer)
+ {
+ Announcer = announcer;
+ }
+}
diff --git a/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.cs b/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.cs
new file mode 100644
index 0000000000..17d838dced
--- /dev/null
+++ b/Content.Server/Parkstation/Announcements/Systems/AnnouncerSystem.cs
@@ -0,0 +1,36 @@
+using Content.Server.Chat.Systems;
+using Content.Shared.GameTicking;
+using Content.Shared.Parkstation.Announcements.Prototypes;
+using Content.Shared.Parkstation.Announcements.Systems;
+using Content.Shared.Parkstation.CCVar;
+using Robust.Shared.Configuration;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Server.Parkstation.Announcements.Systems;
+
+public sealed partial class AnnouncerSystem : SharedAnnouncerSystem
+{
+ [Dependency] private readonly IConfigurationManager _config = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
+
+ ///
+ /// The currently selected announcer
+ ///
+ [Access(typeof(AnnouncerSystem))]
+ public AnnouncerPrototype Announcer { get; set; } = default!;
+
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ PickAnnouncer();
+
+ _config.OnValueChanged(SimpleStationCCVars.Announcer, SetAnnouncer);
+
+ SubscribeLocalEvent(OnRoundRestarting);
+ }
+}
diff --git a/Content.Server/PowerSink/PowerSinkSystem.cs b/Content.Server/PowerSink/PowerSinkSystem.cs
index deb6693500..3293d3cd11 100644
--- a/Content.Server/PowerSink/PowerSinkSystem.cs
+++ b/Content.Server/PowerSink/PowerSinkSystem.cs
@@ -3,6 +3,7 @@
using Content.Shared.Examine;
using Robust.Shared.Utility;
using Content.Server.Chat.Systems;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Systems;
using Robust.Shared.Timing;
using Robust.Shared.Audio;
@@ -31,6 +32,7 @@ public sealed class PowerSinkSystem : EntitySystem
[Dependency] private readonly ExplosionSystem _explosionSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StationSystem _station = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
public override void Initialize()
{
@@ -133,12 +135,7 @@ private void NotifyStationOfImminentExplosion(EntityUid uid, PowerSinkComponent
if (station == null)
return;
- _chat.DispatchStationAnnouncement(
- station.Value,
- Loc.GetString("powersink-immiment-explosion-announcement"),
- playDefaultSound: true,
- colorOverride: Color.Yellow
- );
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("PowerSinkExplosion"), _station.GetInOwningStation(station.Value), Loc.GetString("powersink-immiment-explosion-announcement"), colorOverride: Color.Yellow, station: station.Value); // Parkstation-RandomAnnouncers
}
}
}
diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs
index 10d4bea8b5..3d63c214fa 100644
--- a/Content.Server/RoundEnd/RoundEndSystem.cs
+++ b/Content.Server/RoundEnd/RoundEndSystem.cs
@@ -12,6 +12,7 @@
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Components;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Systems;
using Content.Shared.Database;
using Content.Shared.GameTicking;
@@ -41,6 +42,7 @@ public sealed class RoundEndSystem : EntitySystem
[Dependency] private readonly EmergencyShuttleSystem _shuttle = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
public TimeSpan DefaultCooldownDuration { get; set; } = TimeSpan.FromSeconds(30);
@@ -175,15 +177,15 @@ public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null,
units = "eta-units-minutes";
}
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(text,
- ("time", time),
- ("units", Loc.GetString(units))),
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleCalled"), // Parkstation-RandomAnnouncers
+ Filter.Broadcast(),
+ Loc.GetString(text,
+ ("time", time),
+ ("units", Loc.GetString(units))
+ ),
name,
- false,
- null,
- Color.Gold);
-
- _audio.PlayGlobal("/Audio/Announcements/shuttlecalled.ogg", Filter.Broadcast(), true);
+ Color.Gold
+ );
LastCountdownStart = _gameTiming.CurTime;
ExpectedCountdownEnd = _gameTiming.CurTime + countdownTime;
@@ -226,10 +228,12 @@ public void CancelRoundEndCountdown(EntityUid? requester = null, bool checkCoold
_adminLogger.Add(LogType.ShuttleRecalled, LogImpact.High, $"Shuttle recalled");
}
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-recalled-announcement"),
- Loc.GetString("Station"), false, colorOverride: Color.Gold);
-
- _audio.PlayGlobal("/Audio/Announcements/shuttlerecalled.ogg", Filter.Broadcast(), true);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleRecalled"), // Parkstation-RandomAnnouncers
+ Filter.Broadcast(),
+ Loc.GetString("round-end-system-shuttle-recalled-announcement"),
+ Loc.GetString("Station"),
+ Color.Gold
+ );
LastCountdownStart = null;
ExpectedCountdownEnd = null;
@@ -308,9 +312,12 @@ public void DoRoundEndBehavior(RoundEndBehavior behavior,
// Check is shuttle called or not. We should only dispatch announcement if it's already called
if (IsRoundEndRequested())
{
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(textAnnounce),
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleCalled"), // Parkstation-RandomAnnouncers
+ Filter.Broadcast(),
+ Loc.GetString(textAnnounce),
Loc.GetString(sender),
- colorOverride: Color.Gold);
+ Color.Gold
+ );
}
else
{
diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs
index 37c70c4e48..0199b55b01 100644
--- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs
+++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs
@@ -217,7 +217,7 @@ private void UpdateEmergencyConsole(float frameTime)
if (!ShuttlesLeft && _consoleAccumulator <= 0f)
{
ShuttlesLeft = true;
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-left", ("transitTime", $"{TransitTime:0}")));
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleLeft"), Filter.Broadcast(), Loc.GetString("emergency-shuttle-left", ("transitTime", $"{TransitTime:0}"))); // Parkstation-RandomAnnouncers
Timer.Spawn((int) (TransitTime * 1000) + _bufferTime.Milliseconds, () => _roundEnd.EndRound(), _roundEndCancelToken?.Token ?? default);
}
@@ -253,7 +253,7 @@ private void OnEmergencyRepealAll(EntityUid uid, EmergencyShuttleConsoleComponen
return;
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL ALL by {args.Session:user}");
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-console-auth-revoked", ("remaining", component.AuthorizationsRequired)));
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleAuthRevoked"), Filter.Broadcast(), Loc.GetString("emergency-shuttle-console-auth-revoked", ("remaining", component.AuthorizationsRequired))); // Parkstation-RandomAnnouncers
component.AuthorizedEntities.Clear();
UpdateAllEmergencyConsoles();
}
@@ -276,7 +276,7 @@ private void OnEmergencyRepeal(EntityUid uid, EmergencyShuttleConsoleComponent c
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL by {args.Session:user}");
var remaining = component.AuthorizationsRequired - component.AuthorizedEntities.Count;
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-console-auth-revoked", ("remaining", remaining)));
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleAuthRevoked"), Filter.Broadcast(), Loc.GetString("emergency-shuttle-console-auth-revoked", ("remaining", remaining))); // Parkstation-RandomAnnouncers
CheckForLaunch(component);
UpdateAllEmergencyConsoles();
}
@@ -301,12 +301,11 @@ private void OnEmergencyAuthorize(EntityUid uid, EmergencyShuttleConsoleComponen
var remaining = component.AuthorizationsRequired - component.AuthorizedEntities.Count;
if (remaining > 0)
- _chatSystem.DispatchGlobalAnnouncement(
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleAuthAdded"), // Parkstation-RandomAnnouncers
+ Filter.Broadcast(),
Loc.GetString("emergency-shuttle-console-auth-left", ("remaining", remaining)),
- playSound: false, colorOverride: DangerColor);
+ colorOverride: DangerColor);
- if (!CheckForLaunch(component))
- _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), recordReplay: true);
UpdateAllEmergencyConsoles();
}
@@ -403,12 +402,7 @@ private void AnnounceLaunch()
if (_announced) return;
_announced = true;
- _chatSystem.DispatchGlobalAnnouncement(
- Loc.GetString("emergency-shuttle-launch-time", ("consoleAccumulator", $"{_consoleAccumulator:0}")),
- playSound: false,
- colorOverride: DangerColor);
-
- _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), recordReplay: true);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleAlmostLaunching"), Filter.Broadcast(), Loc.GetString("emergency-shuttle-launch-time", ("consoleAccumulator", $"{_consoleAccumulator:0}"))); // Parkstation-RandomAnnouncers
}
public bool DelayEmergencyRoundEnd()
diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs
index d984c72737..80e16ee89d 100644
--- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs
+++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs
@@ -14,6 +14,7 @@
using Content.Server.Screens.Components;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Access.Systems;
@@ -62,6 +63,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly TransformSystem _transformSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
private ISawmill _sawmill = default!;
@@ -270,9 +272,7 @@ public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleCo
if (targetGrid == null)
{
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} unable to dock with station {ToPrettyString(stationUid)}");
- _chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-good-luck"), playDefaultSound: false);
- // TODO: Need filter extensions or something don't blame me.
- _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleGoodLuck"), Filter.Broadcast(), Loc.GetString("emergency-shuttle-good-luck"), colorOverride: DangerColor);
return;
}
@@ -283,7 +283,7 @@ public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleCo
if (TryComp(targetGrid.Value, out var targetXform))
{
var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
- _chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir())), playDefaultSound: false);
+ _announcer.SendAnnouncementMessage(_announcer.GetAnnouncementId("ShuttleDock"), Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir()))); // Parkstation-RandomAnnouncers
}
// shuttle timers
@@ -304,20 +304,18 @@ public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleCo
}
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} docked with stations");
- // TODO: Need filter extensions or something don't blame me.
- _audio.PlayGlobal("/Audio/Announcements/shuttle_dock.ogg", Filter.Broadcast(), true);
+ _announcer.SendAnnouncementAudio(_announcer.GetAnnouncementId("ShuttleDock"), Filter.Broadcast()); // Parkstation-RandomAnnouncers
}
else
{
if (TryComp(targetGrid.Value, out var targetXform))
{
var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
- _chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir())), playDefaultSound: false);
+ _announcer.SendAnnouncementMessage(_announcer.GetAnnouncementId("ShuttleNearby"), Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir()))); // Parkstation-RandomAnnouncers
}
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} unable to find a valid docking port for {ToPrettyString(stationUid)}");
- // TODO: Need filter extensions or something don't blame me.
- _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
+ _announcer.SendAnnouncementAudio(_announcer.GetAnnouncementId("ShuttleNearby"), Filter.Broadcast()); // Parkstation-RandomAnnouncers
}
}
diff --git a/Content.Server/StationEvents/Components/StationEventComponent.cs b/Content.Server/StationEvents/Components/StationEventComponent.cs
index de0dc1c28a..52af957da8 100644
--- a/Content.Server/StationEvents/Components/StationEventComponent.cs
+++ b/Content.Server/StationEvents/Components/StationEventComponent.cs
@@ -19,16 +19,10 @@ public sealed partial class StationEventComponent : Component
public float Weight = WeightNormal;
[DataField("startAnnouncement")]
- public string? StartAnnouncement;
+ public bool StartAnnouncement; // Parkstation-RandomAnnouncers
[DataField("endAnnouncement")]
- public string? EndAnnouncement;
-
- [DataField("startAudio")]
- public SoundSpecifier? StartAudio;
-
- [DataField("endAudio")]
- public SoundSpecifier? EndAudio;
+ public bool EndAnnouncement; // Parkstation-RandomAnnouncers
///
/// In minutes, when is the first round time this event can start
diff --git a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs
index a59af52f6d..cd316503cc 100644
--- a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs
+++ b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs
@@ -1,13 +1,16 @@
using Content.Server.Anomaly;
using Content.Server.GameTicking.Rules.Components;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
+using Robust.Shared.Player;
namespace Content.Server.StationEvents.Events;
public sealed class AnomalySpawnRule : StationEventSystem
{
[Dependency] private readonly AnomalySystem _anomaly = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
protected override void Added(EntityUid uid, AnomalySpawnRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
@@ -15,7 +18,11 @@ protected override void Added(EntityUid uid, AnomalySpawnRuleComponent component
var str = Loc.GetString("anomaly-spawn-event-announcement",
("sighting", Loc.GetString($"anomaly-spawn-sighting-{RobustRandom.Next(1, 6)}")));
- ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5"));
+
+ // Parkstation-RandomAnnouncers-Start
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(args.RuleId), Filter.Broadcast(), str,
+ colorOverride: Color.FromHex("#18abf5"));
+ // Parkstation-RandomAnnouncers-End
}
protected override void Started(EntityUid uid, AnomalySpawnRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
diff --git a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs
index 306b735b84..c305421c77 100644
--- a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs
+++ b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs
@@ -1,18 +1,26 @@
using Content.Server.GameTicking.Rules.Components;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.StationEvents.Components;
+using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.Server.StationEvents.Events;
public sealed class BluespaceArtifactRule : StationEventSystem
{
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
+
protected override void Added(EntityUid uid, BluespaceArtifactRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
var str = Loc.GetString("bluespace-artifact-event-announcement",
("sighting", Loc.GetString(RobustRandom.Pick(component.PossibleSighting))));
- ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5"));
+
+ // Parkstation-RandomAnnouncers-Start
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(args.RuleId), Filter.Broadcast(), str,
+ colorOverride: Color.FromHex("#18abf5"));
+ // Parkstation-RandomAnnouncers-End
}
protected override void Started(EntityUid uid, BluespaceArtifactRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
diff --git a/Content.Server/StationEvents/Events/BreakerFlipRule.cs b/Content.Server/StationEvents/Events/BreakerFlipRule.cs
index 494779fe35..773eaf1807 100644
--- a/Content.Server/StationEvents/Events/BreakerFlipRule.cs
+++ b/Content.Server/StationEvents/Events/BreakerFlipRule.cs
@@ -1,9 +1,11 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using JetBrains.Annotations;
+using Robust.Shared.Player;
namespace Content.Server.StationEvents.Events;
@@ -11,13 +13,18 @@ namespace Content.Server.StationEvents.Events;
public sealed class BreakerFlipRule : StationEventSystem
{
[Dependency] private readonly ApcSystem _apcSystem = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
protected override void Added(EntityUid uid, BreakerFlipRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
var str = Loc.GetString("station-event-breaker-flip-announcement", ("data", Loc.GetString(Loc.GetString($"random-sentience-event-data-{RobustRandom.Next(1, 6)}"))));
- ChatSystem.DispatchGlobalAnnouncement(str, playSound: false, colorOverride: Color.Gold);
+
+ // Parkstation-RandomAnnouncers-Start
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(args.RuleId), Filter.Broadcast(), str,
+ colorOverride: Color.Gold);
+ // Parkstation-RandomAnnouncers-End
}
protected override void Started(EntityUid uid, BreakerFlipRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs
index 4d3ffa005d..2e23263fd3 100644
--- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs
+++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs
@@ -3,7 +3,9 @@
using Content.Server.Cargo.Systems;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.StationEvents.Components;
+using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Server.StationEvents.Events;
@@ -13,6 +15,7 @@ public sealed class CargoGiftsRule : StationEventSystem
[Dependency] private readonly CargoSystem _cargoSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly GameTicker _ticker = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
protected override void Added(EntityUid uid, CargoGiftsRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
@@ -20,7 +23,11 @@ protected override void Added(EntityUid uid, CargoGiftsRuleComponent component,
var str = Loc.GetString(component.Announce,
("sender", Loc.GetString(component.Sender)), ("description", Loc.GetString(component.Description)), ("dest", Loc.GetString(component.Dest)));
- ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5"));
+
+ // Parkstation-RandomAnnouncers-Start
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(args.RuleId), Filter.Broadcast(), str,
+ colorOverride: Color.FromHex("#18abf5"));
+ // Parkstation-RandomAnnouncers-End
}
///
diff --git a/Content.Server/StationEvents/Events/FalseAlarmRule.cs b/Content.Server/StationEvents/Events/FalseAlarmRule.cs
index 05e9435b40..2c48169454 100644
--- a/Content.Server/StationEvents/Events/FalseAlarmRule.cs
+++ b/Content.Server/StationEvents/Events/FalseAlarmRule.cs
@@ -1,6 +1,9 @@
using System.Linq;
+using System.Text.RegularExpressions;
using Content.Server.GameTicking.Rules.Components;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.StationEvents.Components;
+using Content.Shared.Parkstation.Announcements.Systems;
using JetBrains.Annotations;
using Robust.Shared.Player;
using Robust.Shared.Random;
@@ -11,18 +14,17 @@ namespace Content.Server.StationEvents.Events;
public sealed class FalseAlarmRule : StationEventSystem
{
[Dependency] private readonly EventManagerSystem _event = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
protected override void Started(EntityUid uid, FalseAlarmRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
- var allEv = _event.AllEvents().Select(p => p.Value).ToList();
+ var allEv = _event.AllEvents().Select(p => p.Key).ToList(); // Parkstation-RandomAnnouncers
var picked = RobustRandom.Pick(allEv);
- if (picked.StartAnnouncement != null)
- {
- ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(picked.StartAnnouncement), playSound: false, colorOverride: Color.Gold);
- }
- Audio.PlayGlobal(picked.StartAudio, Filter.Broadcast(), true);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(picked.ID), Filter.Broadcast(),
+ Loc.GetString(_announcer.GetEventLocaleString(_announcer.GetAnnouncementId(picked.ID))),
+ colorOverride: Color.Gold); // Parkstation-RandomAnnouncers
}
}
diff --git a/Content.Server/StationEvents/Events/PowerGridCheckRule.cs b/Content.Server/StationEvents/Events/PowerGridCheckRule.cs
index 5503438df8..7b162dd790 100644
--- a/Content.Server/StationEvents/Events/PowerGridCheckRule.cs
+++ b/Content.Server/StationEvents/Events/PowerGridCheckRule.cs
@@ -54,13 +54,15 @@ protected override void Ended(EntityUid uid, PowerGridCheckRuleComponent compone
}
}
- // Can't use the default EndAudio
- component.AnnounceCancelToken?.Cancel();
- component.AnnounceCancelToken = new CancellationTokenSource();
- Timer.Spawn(3000, () =>
- {
- Audio.PlayGlobal("/Audio/Announcements/power_on.ogg", Filter.Broadcast(), true, AudioParams.Default.WithVolume(-4f));
- }, component.AnnounceCancelToken.Token);
+ // Parkstation-RandomAnnouncers Start
+ // // Can't use the default EndAudio
+ // component.AnnounceCancelToken?.Cancel();
+ // component.AnnounceCancelToken = new CancellationTokenSource();
+ // Timer.Spawn(3000, () =>
+ // {
+ // Audio.PlayGlobal("/Audio/Announcements/power_on.ogg", Filter.Broadcast(), true, AudioParams.Default.WithVolume(-4f));
+ // }, component.AnnounceCancelToken.Token);
+ // Parkstation-RandomAnnouncers End
component.Unpowered.Clear();
}
diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs
index d90361fe96..68ff978f23 100644
--- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs
+++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs
@@ -1,12 +1,17 @@
using System.Linq;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Ghost.Roles.Components;
+using Content.Server.Parkstation.Announcements.Systems;
+using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
+using Robust.Shared.Player;
namespace Content.Server.StationEvents.Events;
public sealed class RandomSentienceRule : StationEventSystem
{
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
+
protected override void Started(EntityUid uid, RandomSentienceRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
HashSet stationsToNotify = new();
@@ -54,15 +59,13 @@ protected override void Started(EntityUid uid, RandomSentienceRuleComponent comp
}
foreach (var station in stationsToNotify)
{
- ChatSystem.DispatchStationAnnouncement(
- station,
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(args.RuleId),
+ StationSystem.GetInStation(EntityManager.GetComponent(station)),
Loc.GetString("station-event-random-sentience-announcement",
("kind1", kind1), ("kind2", kind2), ("kind3", kind3), ("amount", groupList.Count),
("data", Loc.GetString($"random-sentience-event-data-{RobustRandom.Next(1, 6)}")),
("strength", Loc.GetString($"random-sentience-event-strength-{RobustRandom.Next(1, 8)}"))),
- playDefaultSound: false,
- colorOverride: Color.Gold
- );
+ colorOverride: Color.Gold);
}
}
}
diff --git a/Content.Server/StationEvents/Events/StationEventSystem.cs b/Content.Server/StationEvents/Events/StationEventSystem.cs
index 221beccee7..5b990d9850 100644
--- a/Content.Server/StationEvents/Events/StationEventSystem.cs
+++ b/Content.Server/StationEvents/Events/StationEventSystem.cs
@@ -4,10 +4,12 @@
using Content.Server.Chat.Systems;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
+using Content.Server.Parkstation.Announcements.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.StationEvents.Components;
using Content.Shared.Database;
+using Content.Shared.Parkstation.Announcements.Systems;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Collections;
@@ -34,6 +36,7 @@ public abstract partial class StationEventSystem : GameRuleSystem where T
[Dependency] protected readonly SharedAudioSystem Audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] protected readonly StationSystem StationSystem = default!;
+ [Dependency] private readonly AnnouncerSystem _announcer = default!;
protected ISawmill Sawmill = default!;
@@ -54,12 +57,6 @@ protected override void Added(EntityUid uid, T component, GameRuleComponent game
AdminLogManager.Add(LogType.EventAnnounced, $"Event added / announced: {ToPrettyString(uid)}");
- if (stationEvent.StartAnnouncement != null)
- {
- ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.StartAnnouncement), playSound: false, colorOverride: Color.Gold);
- }
-
- Audio.PlayGlobal(stationEvent.StartAudio, Filter.Broadcast(), true);
stationEvent.StartTime = _timing.CurTime + stationEvent.StartDelay;
}
@@ -73,6 +70,15 @@ protected override void Started(EntityUid uid, T component, GameRuleComponent ga
AdminLogManager.Add(LogType.EventStarted, LogImpact.High, $"Event started: {ToPrettyString(uid)}");
+ // Parkstation-RandomAnnouncers-Start
+ if (stationEvent.StartAnnouncement)
+ {
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(args.RuleId), Filter.Broadcast(),
+ Loc.GetString(_announcer.GetEventLocaleString(_announcer.GetAnnouncementId(args.RuleId))),
+ colorOverride: Color.Gold);
+ }
+ // Parkstation-RandomAnnouncers-End
+
if (stationEvent.Duration != null)
{
var duration = stationEvent.MaxDuration == null
@@ -93,12 +99,14 @@ protected override void Ended(EntityUid uid, T component, GameRuleComponent game
AdminLogManager.Add(LogType.EventStopped, $"Event ended: {ToPrettyString(uid)}");
- if (stationEvent.EndAnnouncement != null)
+ // Parkstation-RandomAnnouncers-Start
+ if (stationEvent.EndAnnouncement)
{
- ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.EndAnnouncement), playSound: false, colorOverride: Color.Gold);
+ _announcer.SendAnnouncement(_announcer.GetAnnouncementId(args.RuleId, true), Filter.Broadcast(),
+ Loc.GetString(_announcer.GetEventLocaleString(_announcer.GetAnnouncementId(args.RuleId, true))),
+ colorOverride: Color.Gold);
}
-
- Audio.PlayGlobal(stationEvent.EndAudio, Filter.Broadcast(), true);
+ // Parkstation-RandomAnnouncers-End
}
///
diff --git a/Content.Shared/Parkstation/Announcements/Events/AnnouncementSendEvent.cs b/Content.Shared/Parkstation/Announcements/Events/AnnouncementSendEvent.cs
new file mode 100644
index 0000000000..a9d5124cc7
--- /dev/null
+++ b/Content.Shared/Parkstation/Announcements/Events/AnnouncementSendEvent.cs
@@ -0,0 +1,23 @@
+using Robust.Shared.Audio;
+using Robust.Shared.Network;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Parkstation.Announcements.Events;
+
+
+[Serializable, NetSerializable]
+public sealed class AnnouncementSendEvent : EntityEventArgs
+{
+ public string AnnouncerId { get; }
+ public string AnnouncementId { get; }
+ public List Recipients { get; }
+ public AudioParams AudioParams { get; }
+
+ public AnnouncementSendEvent(string announcerId, string announcementId, List recipients, AudioParams audioParams)
+ {
+ AnnouncerId = announcerId;
+ AnnouncementId = announcementId;
+ Recipients = recipients;
+ AudioParams = audioParams;
+ }
+}
diff --git a/Content.Shared/Parkstation/Announcements/Prototypes/AnnouncerPrototype.cs b/Content.Shared/Parkstation/Announcements/Prototypes/AnnouncerPrototype.cs
new file mode 100644
index 0000000000..1ccfbe2f81
--- /dev/null
+++ b/Content.Shared/Parkstation/Announcements/Prototypes/AnnouncerPrototype.cs
@@ -0,0 +1,71 @@
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Parkstation.Announcements.Prototypes;
+
+///
+/// Defines an announcer and their announcement file paths
+///
+[Prototype("announcer")]
+public sealed class AnnouncerPrototype : IPrototype
+{
+ [IdDataField]
+ public string ID { get; } = default!;
+
+ ///
+ /// A prefix to add to all announcement paths unless told not to by
+ ///
+ /// Paths always start in Resources/
+ [DataField("basePath")]
+ public string BasePath { get; } = default!;
+
+ ///
+ /// Audio parameters to apply to all announcement sounds unless overwritten by
+ ///
+ [DataField("baseAudioParams")]
+ public AudioParams? BaseAudioParams { get; }
+
+ [DataField("announcements")]
+ public AnnouncementData[] Announcements { get; } = default!;
+}
+
+///
+/// Defines a path to an announcement file and that announcement's ID
+///
+[DataDefinition]
+public sealed partial class AnnouncementData
+{
+ [DataField("id")]
+ public string ID = default!;
+
+ ///
+ /// If true, the will not be prepended to this announcement's path
+ ///
+ [DataField("ignoreBasePath")]
+ public bool IgnoreBasePath = false;
+
+ ///
+ /// Where to look for the announcement audio file
+ ///
+ [DataField("path")]
+ public string? Path;
+
+ ///
+ /// Use a soundCollection instead of a single sound
+ ///
+ [DataField("collection"), ValidatePrototypeId]
+ public string? Collection;
+
+ ///
+ /// Overrides the default announcement message for this announcement type
+ ///
+ [DataField("message")]
+ public string? MessageOverride;
+
+ ///
+ /// Audio parameters to apply to this announcement sound
+ /// Will override
+ ///
+ [DataField("audioParams")]
+ public AudioParams? AudioParams;
+}
diff --git a/Content.Shared/Parkstation/Announcements/Systems/SharedAnnouncerSystem.cs b/Content.Shared/Parkstation/Announcements/Systems/SharedAnnouncerSystem.cs
new file mode 100644
index 0000000000..d9877a5d6b
--- /dev/null
+++ b/Content.Shared/Parkstation/Announcements/Systems/SharedAnnouncerSystem.cs
@@ -0,0 +1,150 @@
+using System.Linq;
+using System.Text.RegularExpressions;
+using Content.Shared.Parkstation.Announcements.Prototypes;
+using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Parkstation.Announcements.Systems;
+
+public abstract class SharedAnnouncerSystem : EntitySystem
+{
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+
+
+ ///
+ /// Gets an announcement path from the announcer
+ ///
+ /// ID of the announcement from the announcer to get information for
+ /// ID of the announcer to use instead of the current one
+ public string GetAnnouncementPath(string announcementId, string announcerId)
+ {
+ if (!_proto.TryIndex(announcerId, out var announcer))
+ return "";
+
+ // Get the announcement data from the announcer
+ // Will be the fallback if the data for the announcementId is not found
+ var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ??
+ announcer.Announcements.First(a => a.ID.ToLower() == "fallback");
+
+ // If the greedy announcementType wants to do the job of announcer, ignore the base path and just return the path
+ if (announcementType.IgnoreBasePath)
+ return announcementType.Path!;
+ // If the announcementType has a collection, get the sound from the collection
+ if (announcementType.Collection != null)
+ return _audio.GetSound(new SoundCollectionSpecifier(announcementType.Collection));
+ // If nothing is overriding the base paths, return the base path + the announcement file path
+ return $"{announcer.BasePath}/{announcementType.Path}";
+ }
+
+ ///
+ /// Gets audio params from the announcer
+ ///
+ /// ID of the announcement from the announcer to get information for
+ /// Announcer prototype to get information from
+ public string GetAnnouncementPath(string announcementId, AnnouncerPrototype announcer)
+ {
+ // Get the announcement data from the announcer
+ // Will be the fallback if the data for the announcementId is not found
+ var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ??
+ announcer.Announcements.First(a => a.ID.ToLower() == "fallback");
+
+ // If the greedy announcementType wants to do the job of announcer, ignore the base path and just return the path
+ if (announcementType.IgnoreBasePath)
+ return announcementType.Path!;
+ // If the announcementType has a collection, get the sound from the collection
+ if (announcementType.Collection != null)
+ return _audio.GetSound(new SoundCollectionSpecifier(announcementType.Collection));
+ // If nothing is overriding the base paths, return the base path + the announcement file path
+ return $"{announcer.BasePath}/{announcementType.Path}";
+ }
+
+ ///
+ /// Converts a prototype ID to a consistently used format for announcements
+ ///
+ public string GetAnnouncementId(string announcementId, bool ended = false)
+ {
+ // Replace the first letter with lowercase
+ var id = char.ToLowerInvariant(announcementId[0]) + announcementId[1..];
+
+ // If the event has ended, add "Complete" to the end
+ if (ended)
+ id += "Complete";
+
+ return id;
+ }
+
+
+ ///
+ /// Gets audio params from the announcer
+ ///
+ /// ID of the announcement from the announcer to get information from
+ /// ID of the announcer to use instead of the current one
+ public AudioParams? GetAudioParams(string announcementId, string announcerId)
+ {
+ if (!_proto.TryIndex(announcerId, out var announcer))
+ return null;
+
+ // Get the announcement data from the announcer
+ // Will be the fallback if the data for the announcementId is not found
+ var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ??
+ announcer.Announcements.First(a => a.ID == "fallback");
+
+ // Return the announcer.BaseAudioParams if the announcementType doesn't have an override
+ return announcementType.AudioParams ?? announcer.BaseAudioParams ?? null; // For some reason the formatter doesn't warn me about "?? null" being redundant, so it stays
+ }
+
+ ///
+ /// Gets audio params from the announcer
+ ///
+ /// ID of the announcement from the announcer to get information from
+ /// Announcer prototype to get information from
+ public AudioParams? GetAudioParams(string announcementId, AnnouncerPrototype announcer)
+ {
+ // Get the announcement data from the announcer
+ // Will be the fallback if the data for the announcementId is not found
+ var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ??
+ announcer.Announcements.First(a => a.ID == "fallback");
+
+ // Return the announcer.BaseAudioParams if the announcementType doesn't have an override
+ return announcementType.AudioParams ?? announcer.BaseAudioParams;
+ }
+
+
+ ///
+ /// Gets an announcement message from the announcer
+ ///
+ /// ID of the announcement from the announcer to get information from
+ /// ID of the announcer to get information from
+ public string? GetAnnouncementMessage(string announcementId, string announcerId)
+ {
+ if (!_proto.TryIndex(announcerId, out var announcer))
+ return null;
+
+ // Get the announcement data from the announcer
+ // Will be the fallback if the data for the announcementId is not found
+ var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ??
+ announcer.Announcements.First(a => a.ID == "fallback");
+
+ // Return the announcementType.MessageOverride if it exists, otherwise return null
+ return announcementType.MessageOverride != null ? Loc.GetString(announcementType.MessageOverride) : null;
+ }
+
+ ///
+ /// Gets an announcement message from an event ID
+ ///
+ /// ID of the event to convert
+ /// Format for the locale string, replaces "{}" with the converted ID
+ /// The IDs use a hardcoded format, you can probably handle other formats yourself
+ /// Localized announcement
+ public string GetEventLocaleString(string eventId, string localeBase = "station-event-{}-announcement")
+ {
+ // Replace capital letters with lowercase plus a hyphen before it
+ var capsCapture = new Regex("([A-Z])");
+ var id = capsCapture.Replace(eventId, "-$1").ToLower();
+
+ // Replace {} with the converted ID
+ return localeBase.Replace("{}", id);
+ }
+}
diff --git a/Content.Shared/Parkstation/CCVar/PSCVars.cs b/Content.Shared/Parkstation/CCVar/PSCVars.cs
new file mode 100644
index 0000000000..f25de4e915
--- /dev/null
+++ b/Content.Shared/Parkstation/CCVar/PSCVars.cs
@@ -0,0 +1,25 @@
+using Robust.Shared.Configuration;
+
+namespace Content.Shared.Parkstation.CCVar;
+
+[CVarDefs]
+public sealed class SimpleStationCCVars
+{
+ ///
+ /// Optionally force set an announcer
+ ///
+ public static readonly CVarDef Announcer =
+ CVarDef.Create("announcer.announcer", "", CVar.SERVERONLY);
+
+ ///
+ /// Optionally blacklist announcers
+ ///
+ public static readonly CVarDef> AnnouncerBlacklist =
+ CVarDef.Create("announcer.blacklist", new List(), CVar.SERVERONLY);
+
+ ///
+ /// Changes how loud the announcers are for the client
+ ///
+ public static readonly CVarDef AnnouncerVolume =
+ CVarDef.Create("announcer.volume", 0.5f, CVar.ARCHIVE | CVar.CLIENTONLY);
+}
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce.ogg
new file mode 100644
index 0000000000..0ee0f36d56
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/1.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/1.ogg
new file mode 100644
index 0000000000..c4d182bc8c
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/1.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/10.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/10.ogg
new file mode 100644
index 0000000000..7380ccdeef
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/10.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/11.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/11.ogg
new file mode 100644
index 0000000000..ca548dcc20
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/11.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/12.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/12.ogg
new file mode 100644
index 0000000000..8d71419798
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/12.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/13.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/13.ogg
new file mode 100644
index 0000000000..128c7aa424
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/13.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/14.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/14.ogg
new file mode 100644
index 0000000000..81d54101be
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/14.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/2.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/2.ogg
new file mode 100644
index 0000000000..a2ef615d56
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/2.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/3.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/3.ogg
new file mode 100644
index 0000000000..51613ff036
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/3.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/4.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/4.ogg
new file mode 100644
index 0000000000..874536ca72
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/4.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/5.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/5.ogg
new file mode 100644
index 0000000000..0af0d28ce1
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/5.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/6.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/6.ogg
new file mode 100644
index 0000000000..a65006a8c0
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/6.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/7.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/7.ogg
new file mode 100644
index 0000000000..4a1d3f013a
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/7.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/8.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/8.ogg
new file mode 100644
index 0000000000..83ca80f493
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/8.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/9.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/9.ogg
new file mode 100644
index 0000000000..3c0c45b25d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/announce/9.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/1.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/1.ogg
new file mode 100644
index 0000000000..e3108b13d1
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/1.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/2.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/2.ogg
new file mode 100644
index 0000000000..cd67500426
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/2.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/3.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/3.ogg
new file mode 100644
index 0000000000..94241c5ba5
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/commandreport/3.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/1.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/1.ogg
new file mode 100644
index 0000000000..758f1967e0
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/1.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/2.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/2.ogg
new file mode 100644
index 0000000000..c2e72be510
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/2.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/3.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/3.ogg
new file mode 100644
index 0000000000..004f57371d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/3.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/4.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/4.ogg
new file mode 100644
index 0000000000..c4e1f7667c
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/4.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/5.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/5.ogg
new file mode 100644
index 0000000000..641b8208a4
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/5.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/6.ogg b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/6.ogg
new file mode 100644
index 0000000000..b0fc38237f
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/comms/welcome/6.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/events/aliens.ogg b/Resources/Audio/Parkstation/Announcements/Intern/events/aliens.ogg
new file mode 100644
index 0000000000..9dd3c07697
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/events/aliens.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/events/anomaly.ogg b/Resources/Audio/Parkstation/Announcements/Intern/events/anomaly.ogg
new file mode 100644
index 0000000000..9bed8eae3a
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/events/anomaly.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/events/ion_storm.ogg b/Resources/Audio/Parkstation/Announcements/Intern/events/ion_storm.ogg
new file mode 100644
index 0000000000..9e7b5c6b23
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/events/ion_storm.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/events/meteors.ogg b/Resources/Audio/Parkstation/Announcements/Intern/events/meteors.ogg
new file mode 100644
index 0000000000..c68c4bd8cc
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/events/meteors.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/events/power_grid_check-complete.ogg b/Resources/Audio/Parkstation/Announcements/Intern/events/power_grid_check-complete.ogg
new file mode 100644
index 0000000000..509cd398e6
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/events/power_grid_check-complete.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/events/power_grid_check.ogg b/Resources/Audio/Parkstation/Announcements/Intern/events/power_grid_check.ogg
new file mode 100644
index 0000000000..4b71053653
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/events/power_grid_check.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttlecalled.ogg b/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttlecalled.ogg
new file mode 100644
index 0000000000..c903367cdf
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttlecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttledock.ogg b/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttledock.ogg
new file mode 100644
index 0000000000..9f6ccd1a93
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttledock.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttlerecalled.ogg b/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttlerecalled.ogg
new file mode 100644
index 0000000000..e259a79f35
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/shuttle/shuttlerecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/unused/animes.ogg b/Resources/Audio/Parkstation/Announcements/Intern/unused/animes.ogg
new file mode 100644
index 0000000000..36102c3e60
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/unused/animes.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/unused/intercept.ogg b/Resources/Audio/Parkstation/Announcements/Intern/unused/intercept.ogg
new file mode 100644
index 0000000000..a87274abd9
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/unused/intercept.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/unused/newai.ogg b/Resources/Audio/Parkstation/Announcements/Intern/unused/newai.ogg
new file mode 100644
index 0000000000..c40b099020
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/unused/newai.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/unused/outbreak7.ogg b/Resources/Audio/Parkstation/Announcements/Intern/unused/outbreak7.ogg
new file mode 100644
index 0000000000..297a1bbe8d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/unused/outbreak7.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Intern/unused/radiation.ogg b/Resources/Audio/Parkstation/Announcements/Intern/unused/radiation.ogg
new file mode 100644
index 0000000000..08db53ebfd
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Intern/unused/radiation.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/comms/announce.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/comms/announce.ogg
new file mode 100644
index 0000000000..0ee0f36d56
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/comms/announce.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/comms/attention.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/comms/attention.ogg
new file mode 100644
index 0000000000..d4d5a27085
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/comms/attention.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/comms/command_report.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/comms/command_report.ogg
new file mode 100644
index 0000000000..4e5c2e1d1f
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/comms/command_report.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/comms/welcome.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/comms/welcome.ogg
new file mode 100644
index 0000000000..f9a698fd08
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/comms/welcome.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/events/aliens.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/events/aliens.ogg
new file mode 100644
index 0000000000..57fa70c3ca
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/events/aliens.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/events/anomaly.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/events/anomaly.ogg
new file mode 100644
index 0000000000..d710999e1e
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/events/anomaly.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/events/ion_storm.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/events/ion_storm.ogg
new file mode 100644
index 0000000000..15aeac9f7f
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/events/ion_storm.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/events/meteors.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/events/meteors.ogg
new file mode 100644
index 0000000000..91208cae12
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/events/meteors.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/events/power_grid_check-complete.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/events/power_grid_check-complete.ogg
new file mode 100644
index 0000000000..4b1605b1c7
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/events/power_grid_check-complete.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/events/power_grid_check.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/events/power_grid_check.ogg
new file mode 100644
index 0000000000..875df35002
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/events/power_grid_check.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/fallback.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/fallback.ogg
new file mode 100644
index 0000000000..d4d5a27085
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/fallback.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttlecalled.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttlecalled.ogg
new file mode 100644
index 0000000000..a775567abe
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttlecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttledock.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttledock.ogg
new file mode 100644
index 0000000000..933928db06
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttledock.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttlerecalled.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttlerecalled.ogg
new file mode 100644
index 0000000000..53b622576d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/shuttle/shuttlerecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/unused/animes.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/unused/animes.ogg
new file mode 100644
index 0000000000..7615a744a6
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/unused/animes.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/unused/intercept.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/unused/intercept.ogg
new file mode 100644
index 0000000000..c59d0455c1
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/unused/intercept.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/unused/newai.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/unused/newai.ogg
new file mode 100644
index 0000000000..c40b099020
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/unused/newai.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/unused/outbreak7.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/unused/outbreak7.ogg
new file mode 100644
index 0000000000..1fc542534d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/unused/outbreak7.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/MedBot/unused/radiation.ogg b/Resources/Audio/Parkstation/Announcements/MedBot/unused/radiation.ogg
new file mode 100644
index 0000000000..5c48830b5f
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/MedBot/unused/radiation.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/blue.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/blue.ogg
new file mode 100644
index 0000000000..f6458c00bb
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/blue.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/epsilon.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/epsilon.ogg
new file mode 100644
index 0000000000..82815eda27
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/epsilon.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/gamma.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/gamma.ogg
new file mode 100644
index 0000000000..0a402b6d33
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/gamma.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/green.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/green.ogg
new file mode 100644
index 0000000000..d9d0f036fd
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/green.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/red.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/red.ogg
new file mode 100644
index 0000000000..4a7f1e9472
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/red.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/rename.js b/Resources/Audio/Parkstation/Announcements/Michael/alerts/rename.js
new file mode 100644
index 0000000000..0c52f5fb32
--- /dev/null
+++ b/Resources/Audio/Parkstation/Announcements/Michael/alerts/rename.js
@@ -0,0 +1,191 @@
+// Set the method variable to one of these
+const methods = [
+ 'startsWith', // Replaces beginning with replace if matches searchfor OR cuts off the beginning if matches searchfor if replace is undefined
+ 'endsWith', // Replaces end with replace if matches searchfor OR cuts off the end if matches searchfor if replace is undefined
+ 'includes', // Replaces all instances of searchfor with replace OR removes all instances of searchfor if replace is undefined
+
+ 'numberedSuffix', // Adds a numbered suffix to the end of the file name
+ 'numberedPrefix', // Adds a numbered prefix to the beginning of the file name
+ 'numbered', // Replaces the file name with a number
+];
+
+// User set variables
+const dirname = './'; // Where to look for files ('./' is the current directory)
+const includedirs = false; // Whether or not to include directories in the search
+const searchfor = 'code_'; // What to search for
+const replace = undefined; // What to replace with (undefined will remove the searchfor from the file name entirely)
+const removeextraperiods = true; // Whether or not to remove extra periods in the file name (good for numbered methods)
+const method = 'startsWith'; // Which method to use (see above)
+const startingnumber = 0; // What number to start at (only used with numbered methods)
+const debuglog = true; // Provides some extra info about what's going on
+// End of user set variables
+
+
+// Check if method is valid
+if (typeof method !== 'string' || !methods.includes(method)) return console.log(`ERROR: Invalid method ${method}`);
+else console.log('INFO: Using method: ' + method);
+
+// Check if dirname is valid
+if (typeof dirname !== 'string') return console.log('ERROR: Invalid dirname');
+else console.log('INFO: Using directory: ' + dirname);
+
+// Warn of includedirs
+if (includedirs) console.log('WARNING: Including directories in search');
+else console.log('INFO: Not including directories in search');
+
+// Check if searchfor is valid
+if (typeof searchfor !== 'string' && !method.includes('numbered')) return console.log('ERROR: Invalid searchfor');
+if (typeof searchfor !== 'string' && method.includes('numbered')) console.log('WARNING: Searchfor is undefined, this will replace the file name with a number');
+else console.log(`INFO: Searching for: ${searchfor}`);
+
+// Warn if replace is undefined
+if (replace === undefined) console.log('WARNING: Replace is undefined, this will remove the searchfor from the file name entirely');
+else console.log(`INFO: Replacing with: ${replace}`);
+
+// Tell user if startingnumber is not 0
+if (startingnumber !== 0) console.log(`INFO: Starting number: ${startingnumber}`);
+
+// Check if debuglog is enabled
+if (debuglog) console.log('INFO: Debug log is enabled');
+else console.log('INFO: Debug log is disabled');
+
+
+console.log('\n');
+console.log('INFO: Starting search...');
+console.log('\n');
+
+
+const fs = require('fs');
+const files = fs.readdirSync(dirname);
+let number = 0 + startingnumber;
+
+
+// Debug log
+if (debuglog) {
+ console.log('DEBUG: Files:');
+ console.log(files);
+ console.log(`DEBUG: Files type: ${typeof files}`);
+ console.log('\n');
+}
+
+
+files.forEach((file) => {
+ // Split file name and extension
+ // If there is no extension, name[1] will be a blank string to avoid files getting fucked up
+ let name = file.includes('.') ? file.split('.') : [file, ''];
+ name.reverse();
+ if (name[0].length > 0) name[0] = '.' + name[0];
+ var extension = name[0];
+ name.reverse();
+ if (removeextraperiods) name = [name.join('').slice(0, -extension.length), extension];
+ else name = [name.join('.').slice(0, -extension.length), extension];
+
+
+ // Check if file is this script
+ if (process.argv[1].includes(name.join(''))) return;
+
+
+ // Debug log
+ if (debuglog) console.log(`DEBUG: File name: ${name[0]}`);
+
+
+ // Check if file is a directory
+ if (!includedirs) {
+ try {
+ if (fs.readdirSync(dirname + file).length) {
+ if (debuglog) console.log(`DEBUG: File is a directory, skipping: ${name[0]}`);
+ if (debuglog) console.log('\n');
+ return;
+ }
+ } catch (e) {
+ if (debuglog) console.log(`DEBUG: File is a file: ${name[0]}`);
+ }
+ } else {
+ try {
+ if (fs.readdirSync(dirname + file).length) {
+ if (debuglog) console.log(`DEBUG: File is a directory: ${name[0]}`);
+ }
+ } catch (e) {
+ if (debuglog) console.log(`DEBUG: File is a file: ${name[0]}`);
+ }
+ }
+
+
+ if (method === 'startsWith') {
+ if (!name[0].startsWith(searchfor)) {
+ if (debuglog) console.log(`DEBUG: File name does not start with '${searchfor}': ${name[0]}`);
+ if (debuglog) console.log('\n');
+ return;
+ }
+
+ if (replace) {
+ fs.renameSync(dirname + '/' + file, dirname + '/' + replace + name[0].slice(searchfor.length) + name[1]);
+ } else {
+ fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].slice(searchfor.length) + name[1]);
+ }
+ } else if (method === 'endsWith') {
+ if (!name[0].endsWith(searchfor)) {
+ if (debuglog) console.log(`DEBUG: File name does not end with '${searchfor}': ${name[0]}`);
+ if (debuglog) console.log('\n');
+ return;
+ }
+
+ if (replace) {
+ fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].slice(0, -searchfor.length) + replace + name[1]);
+ } else {
+ fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].slice(0, -searchfor.length) + name[1]);
+ }
+ } else if (method === 'includes') {
+ if (!name[0].includes(searchfor)) {
+ if (debuglog) console.log(`DEBUG: File name does not include '${searchfor}': ${name[0]}`);
+ if (debuglog) console.log('\n');
+ return;
+ }
+
+ const regex = new RegExp(searchfor, 'g');
+
+ if (replace) {
+ fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].replace(regex, replace) + name[1]);
+ } else {
+ fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].replace(regex, '') + name[1]);
+ }
+ } else if (method === 'numberedPrefix') {
+ if (!name[0].startsWith(searchfor)) {
+ if (debuglog) console.log(`DEBUG: File name does not start with '${searchfor}': ${name[0]}`);
+ if (debuglog) console.log('\n');
+ return;
+ }
+
+ fs.renameSync(dirname + '/' + file, dirname + '/' + number + name[0] + name[1]);
+
+ number++;
+ } else if (method === 'numberedSuffix') {
+ if (!name[0].endsWith(searchfor)) {
+ if (debuglog) console.log(`DEBUG: File name does not end with '${searchfor}': ${name[0]}`);
+ if (debuglog) console.log('\n');
+ return;
+ }
+
+ fs.renameSync(dirname + '/' + file, dirname + '/' + name[0] + number + name[1]);
+
+ number++;
+ } else if (method === 'numbered') {
+ if (typeof searchfor === 'string') {
+ if (!name[0].includes(searchfor)) {
+ if (debuglog) console.log(`DEBUG: File name does not include '${searchfor}': ${name[0]}`);
+ if (debuglog) console.log('\n');
+ return;
+ }
+
+ fs.renameSync(dirname + '/' + file, dirname + '/' + number + name[1]);
+ } else {
+ fs.renameSync(dirname + '/' + file, dirname + '/' + number + name[1]);
+ }
+
+ number++;
+ }
+
+ console.log('\n');
+});
+
+console.log('INFO: Search complete');
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/violet.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/violet.ogg
new file mode 100644
index 0000000000..7a611d819e
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/violet.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/white.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/white.ogg
new file mode 100644
index 0000000000..1bb3afd354
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/white.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/alerts/yellow.ogg b/Resources/Audio/Parkstation/Announcements/Michael/alerts/yellow.ogg
new file mode 100644
index 0000000000..3a72eca3bb
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/alerts/yellow.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/comms/attention.ogg b/Resources/Audio/Parkstation/Announcements/Michael/comms/attention.ogg
new file mode 100644
index 0000000000..e25fdf2af7
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/comms/attention.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/comms/welcome.ogg b/Resources/Audio/Parkstation/Announcements/Michael/comms/welcome.ogg
new file mode 100644
index 0000000000..32d9004109
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/comms/welcome.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/aliens.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/aliens.ogg
new file mode 100644
index 0000000000..1293b3ced5
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/aliens.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/bureaucratic_error.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/bureaucratic_error.ogg
new file mode 100644
index 0000000000..2bb2710acf
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/bureaucratic_error.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/gas_leak.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/gas_leak.ogg
new file mode 100644
index 0000000000..26912c859d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/gas_leak.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/kudzu_growth.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/kudzu_growth.ogg
new file mode 100644
index 0000000000..31eccef518
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/kudzu_growth.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/meteors.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/meteors.ogg
new file mode 100644
index 0000000000..62a2162571
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/meteors.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/noospheric_storm.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/noospheric_storm.ogg
new file mode 100644
index 0000000000..eedaaf5699
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/noospheric_storm.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/power_grid_check-complete.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/power_grid_check-complete.ogg
new file mode 100644
index 0000000000..de5fa1ff40
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/power_grid_check-complete.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/power_grid_check.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/power_grid_check.ogg
new file mode 100644
index 0000000000..07964d240e
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/power_grid_check.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/events/vent_clog.ogg b/Resources/Audio/Parkstation/Announcements/Michael/events/vent_clog.ogg
new file mode 100644
index 0000000000..16fbf88e03
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/events/vent_clog.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/fallback.ogg b/Resources/Audio/Parkstation/Announcements/Michael/fallback.ogg
new file mode 100644
index 0000000000..e25fdf2af7
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/fallback.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_called.ogg b/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_called.ogg
new file mode 100644
index 0000000000..261ecabf6e
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_called.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_dock.ogg b/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_dock.ogg
new file mode 100644
index 0000000000..a83b482f49
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_dock.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_recalled.ogg b/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_recalled.ogg
new file mode 100644
index 0000000000..b104ea561a
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/shuttle/shuttle_recalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/unused/outbreak7.ogg b/Resources/Audio/Parkstation/Announcements/Michael/unused/outbreak7.ogg
new file mode 100644
index 0000000000..fc584db60c
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/unused/outbreak7.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/Michael/unused/radiation.ogg b/Resources/Audio/Parkstation/Announcements/Michael/unused/radiation.ogg
new file mode 100644
index 0000000000..7b7ca0c2b9
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/Michael/unused/radiation.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_blue.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_blue.ogg
new file mode 100644
index 0000000000..48d9c6548b
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_blue.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_delta.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_delta.ogg
new file mode 100644
index 0000000000..7082671915
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_delta.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_epsilon.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_epsilon.ogg
new file mode 100644
index 0000000000..a8db858b1a
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_epsilon.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_gamma.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_gamma.ogg
new file mode 100644
index 0000000000..3351acc2e0
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_gamma.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_green.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_green.ogg
new file mode 100644
index 0000000000..3c0031833b
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_green.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_red.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_red.ogg
new file mode 100644
index 0000000000..209eb36ba1
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_red.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_violet.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_violet.ogg
new file mode 100644
index 0000000000..c1681c1edb
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_violet.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_white.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_white.ogg
new file mode 100644
index 0000000000..24c942dfcb
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_white.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_yellow.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_yellow.ogg
new file mode 100644
index 0000000000..9139446d2b
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/alerts/code_yellow.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/comms/announce.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/comms/announce.ogg
new file mode 100644
index 0000000000..0ee0f36d56
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/comms/announce.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/comms/attention.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/comms/attention.ogg
new file mode 100644
index 0000000000..310fad3ef6
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/comms/attention.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/comms/welcome.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/comms/welcome.ogg
new file mode 100644
index 0000000000..00c8991276
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/comms/welcome.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/bureaucraticerror.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/bureaucraticerror.ogg
new file mode 100644
index 0000000000..0cbafcf627
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/bureaucraticerror.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/gasleak.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/gasleak.ogg
new file mode 100644
index 0000000000..8efffd02c4
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/gasleak.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/kudzu.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/kudzu.ogg
new file mode 100644
index 0000000000..4ddd2f636b
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/kudzu.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/meteors.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/meteors.ogg
new file mode 100644
index 0000000000..cf52544174
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/meteors.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/noosphericstorm.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/noosphericstorm.ogg
new file mode 100644
index 0000000000..47b52f7cb4
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/noosphericstorm.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/power_grid_check-complete.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/power_grid_check-complete.ogg
new file mode 100644
index 0000000000..961b50a503
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/power_grid_check-complete.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/power_grid_check.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/power_grid_check.ogg
new file mode 100644
index 0000000000..7d7a43825f
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/power_grid_check.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/events/ventclog.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/events/ventclog.ogg
new file mode 100644
index 0000000000..90350f0e35
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/events/ventclog.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/fallback.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/fallback.ogg
new file mode 100644
index 0000000000..310fad3ef6
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/fallback.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttlecalled.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttlecalled.ogg
new file mode 100644
index 0000000000..482bf13319
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttlecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttledock.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttledock.ogg
new file mode 100644
index 0000000000..0615536555
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttledock.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttlerecalled.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttlerecalled.ogg
new file mode 100644
index 0000000000..5a198ca5fe
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/shuttle/shuttlerecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/unused/outbreak7.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/unused/outbreak7.ogg
new file mode 100644
index 0000000000..9106796012
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/unused/outbreak7.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/NEIL/unused/radiation.ogg b/Resources/Audio/Parkstation/Announcements/NEIL/unused/radiation.ogg
new file mode 100644
index 0000000000..3ea2928c1d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/NEIL/unused/radiation.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/comms/announce.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/announce.ogg
new file mode 100644
index 0000000000..0ee0f36d56
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/announce.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/comms/attention.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/attention.ogg
new file mode 100644
index 0000000000..912be4425e
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/attention.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/comms/command_report.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/command_report.ogg
new file mode 100644
index 0000000000..82e4ca425d
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/command_report.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/comms/welcome.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/welcome.ogg
new file mode 100644
index 0000000000..c7013dcbd5
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/comms/welcome.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/events/aliens.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/events/aliens.ogg
new file mode 100644
index 0000000000..f7d1746247
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/events/aliens.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/events/anomaly.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/events/anomaly.ogg
new file mode 100644
index 0000000000..7680726f15
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/events/anomaly.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/events/ion_storm.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/events/ion_storm.ogg
new file mode 100644
index 0000000000..9f39713de6
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/events/ion_storm.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/events/meteors.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/events/meteors.ogg
new file mode 100644
index 0000000000..8f1c3aeacb
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/events/meteors.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/events/power_grid_check-complete.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/events/power_grid_check-complete.ogg
new file mode 100644
index 0000000000..9d18797d6e
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/events/power_grid_check-complete.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/events/power_grid_check.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/events/power_grid_check.ogg
new file mode 100644
index 0000000000..1c6377c9d8
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/events/power_grid_check.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/fallback.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/fallback.ogg
new file mode 100644
index 0000000000..912be4425e
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/fallback.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttlecalled.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttlecalled.ogg
new file mode 100644
index 0000000000..716bf82465
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttlecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttledock.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttledock.ogg
new file mode 100644
index 0000000000..0f70bebc75
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttledock.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttlerecalled.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttlerecalled.ogg
new file mode 100644
index 0000000000..5f6db404b8
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/shuttle/shuttlerecalled.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/unused/newai.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/unused/newai.ogg
new file mode 100644
index 0000000000..35aba34564
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/unused/newai.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/unused/outbreak7.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/unused/outbreak7.ogg
new file mode 100644
index 0000000000..f21d4fca44
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/unused/outbreak7.ogg differ
diff --git a/Resources/Audio/Parkstation/Announcements/VoxFem/unused/radiation.ogg b/Resources/Audio/Parkstation/Announcements/VoxFem/unused/radiation.ogg
new file mode 100644
index 0000000000..ef395af310
Binary files /dev/null and b/Resources/Audio/Parkstation/Announcements/VoxFem/unused/radiation.ogg differ
diff --git a/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl b/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl
index eebfe1610f..eb59c8e0a6 100644
--- a/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl
+++ b/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl
@@ -1 +1 @@
-station-event-xeno-vent-start-announcement = Confirmed sightings of hostile alien wildlife on the station. Personnel are advised to arm themselves, barricade doors, and defend themselves if necessary. Security is advised to eradicate the threat as soon as possible.
+station-event-xeno-vents-announcement = Confirmed sightings of hostile alien wildlife on the station. Personnel are advised to arm themselves, barricade doors, and defend themselves if necessary. Security is advised to eradicate the threat as soon as possible.
diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
index 5392f1de6b..0eb3d3ce18 100644
--- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
+++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
@@ -30,6 +30,8 @@ ui-options-ambience-volume = Ambience volume:
ui-options-lobby-volume = Lobby & Round-end volume:
ui-options-interface-volume = Interface volume:
ui-options-ambience-max-sounds = Ambience simultaneous sounds:
+# Parkstation-RandomAnnouncers
+ui-options-announcer-volume = Announcer volume:
ui-options-lobby-music = Lobby & Round-end Music
ui-options-restart-sounds = Round Restart Sounds
ui-options-event-music = Event Music
diff --git a/Resources/Locale/en-US/game-ticking/game-ticker.ftl b/Resources/Locale/en-US/game-ticking/game-ticker.ftl
index 42be7de5f3..5a69669e9f 100644
--- a/Resources/Locale/en-US/game-ticking/game-ticker.ftl
+++ b/Resources/Locale/en-US/game-ticking/game-ticker.ftl
@@ -25,6 +25,8 @@ game-ticker-get-info-preround-text = Hi and welcome to [color=white]Space Statio
>[color=yellow]{$desc}[/color]
game-ticker-no-map-selected = [color=yellow]Map not yet selected![/color]
game-ticker-player-no-jobs-available-when-joining = When attempting to join to the game, no jobs were available.
+# Parkstation-RandomAnnouncers
+game-ticker-welcome-to-the-station = Welcome to the station crew, enjoy your stay!
# Displayed in chat to admins when a player joins
player-join-message = Player {$name} joined.
diff --git a/Resources/Locale/en-US/parkstation/Prototypes/Announcers/announcers.ftl b/Resources/Locale/en-US/parkstation/Prototypes/Announcers/announcers.ftl
new file mode 100644
index 0000000000..d18857a38e
--- /dev/null
+++ b/Resources/Locale/en-US/parkstation/Prototypes/Announcers/announcers.ftl
@@ -0,0 +1,5 @@
+announcer-Intern-name=Central Command
+announcer-MedBot-name=Automated
+announcer-Michael-name=Michael
+announcer-NEIL-name=N.E.I.L.
+announcer-VoxFem-name=Automated
diff --git a/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl b/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl
index 0e4b5f6e39..543bef949a 100644
--- a/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl
+++ b/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl
@@ -1,7 +1,7 @@
-anomaly-spawn-event-announcement = Our readings have detected a dangerous interspacial anomaly. Please inform the research team of { $sighting }.
+station-event-anomaly-spawn-announcement = Our readings have detected a dangerous interspacial anomaly. Please inform the research team of { $sighting }.
anomaly-spawn-sighting-1 = low pulsating sounds heard throughout the station
anomaly-spawn-sighting-2 = strange sources of light
anomaly-spawn-sighting-3 = inexplicable shapes
anomaly-spawn-sighting-4 = forms causing severe mental distress
-anomaly-spawn-sighting-5 = strange effects on the local environment
\ No newline at end of file
+anomaly-spawn-sighting-5 = strange effects on the local environment
diff --git a/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl b/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl
index a2307d77b5..6052911657 100644
--- a/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl
+++ b/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl
@@ -1,4 +1,4 @@
-bluespace-artifact-event-announcement = Our readings have detected an incoming object of alien origin. Please inform the research team of { $sighting }.
+station-event-bluespace-artifact-announcement = Our readings have detected an incoming object of alien origin. Please inform the research team of { $sighting }.
bluespace-artifact-sighting-1 = bright flashes of light
bluespace-artifact-sighting-2 = strange sounds coming from maintenance tunnels
@@ -6,4 +6,4 @@ bluespace-artifact-sighting-3 = otherworldly structures
bluespace-artifact-sighting-4 = incomprehensible alien objects
bluespace-artifact-sighting-5 = unfamiliar objects in strange places
bluespace-artifact-sighting-6 = unknown alien artifacts
-bluespace-artifact-sighting-7 = explosions of light accompanied by weird sounds
\ No newline at end of file
+bluespace-artifact-sighting-7 = explosions of light accompanied by weird sounds
diff --git a/Resources/Locale/en-US/station-events/events/gas-leak.ftl b/Resources/Locale/en-US/station-events/events/gas-leak.ftl
index 18429fa58d..230e886db4 100644
--- a/Resources/Locale/en-US/station-events/events/gas-leak.ftl
+++ b/Resources/Locale/en-US/station-events/events/gas-leak.ftl
@@ -1,2 +1,2 @@
-station-event-gas-leak-start-announcement = Attention crew, there is a gas leak on the station. We advise you to avoid the area and wear suit internals in the meantime.
-station-event-gas-leak-end-announcement = The source of the gas leak has been fixed. Please be cautious around areas with gas remaining.
+station-event-gas-leak-announcement = Attention crew, there is a gas leak on the station. We advise you to avoid the area and wear suit internals in the meantime.
+station-event-gas-leak-complete-announcement = The source of the gas leak has been fixed. Please be cautious around areas with gas remaining.
diff --git a/Resources/Locale/en-US/station-events/events/immovable-rod.ftl b/Resources/Locale/en-US/station-events/events/immovable-rod.ftl
index 06abcc85c3..ff39923ecd 100644
--- a/Resources/Locale/en-US/station-events/events/immovable-rod.ftl
+++ b/Resources/Locale/en-US/station-events/events/immovable-rod.ftl
@@ -1 +1 @@
-station-event-immovable-rod-start-announcement = High velocity unidentified object is on a collision course with the station. Impact imminent.
+station-event-immovable-rod-announcement = High velocity unidentified object is on a collision course with the station. Impact imminent.
diff --git a/Resources/Locale/en-US/station-events/events/ion-storm.ftl b/Resources/Locale/en-US/station-events/events/ion-storm.ftl
index 28192d9663..10e8f19006 100644
--- a/Resources/Locale/en-US/station-events/events/ion-storm.ftl
+++ b/Resources/Locale/en-US/station-events/events/ion-storm.ftl
@@ -1,4 +1,4 @@
-station-event-ion-storm-start-announcement = Ion storm detected near the station. Please check all AI-controlled equipment for errors.
+station-event-ion-storm-announcement = Ion storm detected near the station. Please check all AI-controlled equipment for errors.
ion-storm-law-scrambled-number = [font="Monospace"][scramble rate=250 length={$length} chars="@@###$$&%!01"/][/font]
diff --git a/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl b/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl
index e0725deaf1..9ba4adb4a2 100644
--- a/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl
+++ b/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl
@@ -1 +1 @@
-station-event-kudzu-growth-start-announcement = Attention crew, we have detected a Type 2 Biological Invader on-station, that poses potentially serious threat to crew productivity. We advise you to exterminate it.
+station-event-kudzu-growth-announcement = Attention crew, we have detected a Type 2 Biological Invader on-station, that poses potentially serious threat to crew productivity. We advise you to exterminate it.
diff --git a/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl b/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl
index 6a96c56048..9066fb5212 100644
--- a/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl
+++ b/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl
@@ -1,2 +1,2 @@
-station-event-meteor-swarm-start-announcement = Meteors are on a collision course with the station. Brace for impact.
-station-event-meteor-swarm-end-announcement = The meteor swarm has passed. Please return to your stations.
+station-event-meteor-swarm-announcement = Meteors are on a collision course with the station. Brace for impact.
+station-event-meteor-swarm-complete-announcement = The meteor swarm has passed. Please return to your stations.
diff --git a/Resources/Locale/en-US/station-events/events/power-grid-check.ftl b/Resources/Locale/en-US/station-events/events/power-grid-check.ftl
index b42dbd19db..90ede6b996 100644
--- a/Resources/Locale/en-US/station-events/events/power-grid-check.ftl
+++ b/Resources/Locale/en-US/station-events/events/power-grid-check.ftl
@@ -1,4 +1,4 @@
## PowerGridCheck
-station-event-power-grid-check-start-announcement = Abnormal activity detected in the station's powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.
-station-event-power-grid-check-end-announcement = Power has been restored to the station. We apologize for the inconvenience.
\ No newline at end of file
+station-event-power-grid-check-announcement = Abnormal activity detected in the station's powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.
+station-event-power-grid-check-complete-announcement = Power has been restored to the station. We apologize for the inconvenience.
diff --git a/Resources/Locale/en-US/station-events/events/radiation-storm.ftl b/Resources/Locale/en-US/station-events/events/radiation-storm.ftl
index c8f07c1b2f..a3c5f48e84 100644
--- a/Resources/Locale/en-US/station-events/events/radiation-storm.ftl
+++ b/Resources/Locale/en-US/station-events/events/radiation-storm.ftl
@@ -1,4 +1,4 @@
## RadiationStorm
-station-event-radiation-storm-start-announcement = High levels of radiation detected near the station. Evacuate any areas containing abnormal green energy fields.
-station-event-radiation-storm-end-announcement = The radiation threat has passed. Please return to your workplaces.
\ No newline at end of file
+station-event-radiation-storm-announcement = High levels of radiation detected near the station. Evacuate any areas containing abnormal green energy fields.
+station-event-radiation-storm-complete-announcement = The radiation threat has passed. Please return to your workplaces.
diff --git a/Resources/Locale/en-US/station-events/events/solar-flare.ftl b/Resources/Locale/en-US/station-events/events/solar-flare.ftl
index 5c88f82ded..617b65739a 100644
--- a/Resources/Locale/en-US/station-events/events/solar-flare.ftl
+++ b/Resources/Locale/en-US/station-events/events/solar-flare.ftl
@@ -1,2 +1,2 @@
-station-event-solar-flare-start-announcement = A solar flare has been detected near the station. Some communication channels may not function.
-station-event-solar-flare-end-announcement = The solar flare ended. Communication channels no longer affected.
+station-event-solar-flare-announcement = A solar flare has been detected near the station. Some communication channels may not function.
+station-event-solar-flare-complete-announcement = The solar flare ended. Communication channels no longer affected.
diff --git a/Resources/Locale/en-US/station-events/events/vent-clog.ftl b/Resources/Locale/en-US/station-events/events/vent-clog.ftl
index f87f9e241b..1d6ddd136b 100644
--- a/Resources/Locale/en-US/station-events/events/vent-clog.ftl
+++ b/Resources/Locale/en-US/station-events/events/vent-clog.ftl
@@ -1 +1 @@
-station-event-vent-clog-start-announcement = The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.
+station-event-vent-clog-announcement = The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.
diff --git a/Resources/Locale/en-US/station-events/events/vent-critters.ftl b/Resources/Locale/en-US/station-events/events/vent-critters.ftl
index 426f0c0ca1..330a40aafc 100644
--- a/Resources/Locale/en-US/station-events/events/vent-critters.ftl
+++ b/Resources/Locale/en-US/station-events/events/vent-critters.ftl
@@ -1 +1 @@
-station-event-vent-creatures-start-announcement = Attention. A large influx of unknown life forms have been detected residing within the station's ventilation systems. Please be rid of these creatures before it begins to affect productivity.
+station-event-vent-creatures-announcement = Attention. A large influx of unknown life forms have been detected residing within the station's ventilation systems. Please be rid of these creatures before it begins to affect productivity.
diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml
index a88e5296cb..00647e7ea1 100644
--- a/Resources/Prototypes/DeltaV/GameRules/events.yml
+++ b/Resources/Prototypes/DeltaV/GameRules/events.yml
@@ -4,9 +4,7 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-xeno-vent-start-announcement
- startAudio:
- path: /Audio/Announcements/aliens.ogg
+ startAnnouncement: true # Parkstation-RandomAnnouncers
earliestStart: 20
minimumPlayers: 15
weight: 1
diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml
index 2dcf3603cf..579922a74a 100644
--- a/Resources/Prototypes/GameRules/events.yml
+++ b/Resources/Prototypes/GameRules/events.yml
@@ -49,7 +49,7 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-bureaucratic-error-announcement
+ startAnnouncement: true # Parkstation-RandomAnnouncers
minimumPlayers: 25
weight: 5
duration: 1
@@ -61,7 +61,7 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-clerical-error-announcement
+ startAnnouncement: true # Parkstation-RandomAnnouncers
minimumPlayers: 15
weight: 5
duration: 1
@@ -124,6 +124,7 @@
noSpawn: true
components:
- type: StationEvent
+ # startAnnouncement: true # Parkstation-RandomAnnouncers # Inherited from the event it copies
weight: 15
duration: 1
- type: FalseAlarmRule
@@ -134,10 +135,8 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-gas-leak-start-announcement
- startAudio:
- path: /Audio/Announcements/gas_leak.ogg # DeltaV - custom announcer
- endAnnouncement: station-event-gas-leak-end-announcement
+ startAnnouncement: true # Parkstation-RandomAnnouncers
+ endAnnouncement: true # Parkstation-RandomAnnouncers
earliestStart: 10
minimumPlayers: 5
weight: 10
@@ -150,6 +149,7 @@
noSpawn: true
components:
- type: StationEvent
+ startAnnouncement: true # Parkstation-RandomAnnouncers
earliestStart: 15
minimumPlayers: 15
weight: 5
@@ -163,15 +163,11 @@
noSpawn: true
components:
- type: StationEvent
+ startAnnouncement: true # Parkstation-RandomAnnouncers
+ endAnnouncement: true # Parkstation-RandomAnnouncers
earliestStart: 30
weight: 7.5
minimumPlayers: 10 #Enough to hopefully have at least one engineering guy
- startAnnouncement: station-event-meteor-swarm-start-announcement
- endAnnouncement: station-event-meteor-swarm-end-announcement
- startAudio:
- path: /Audio/Announcements/meteors.ogg
- params:
- volume: -4
duration: null #ending is handled by MeteorSwarmRule
startDelay: 30
- type: MeteorSwarmRule
@@ -182,9 +178,7 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-vent-creatures-start-announcement
- startAudio:
- path: /Audio/Announcements/attention.ogg
+ startAnnouncement: true # Parkstation-RandomAnnouncers
startDelay: 10
earliestStart: 30
minimumPlayers: 35
@@ -208,9 +202,6 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-vent-creatures-start-announcement
- startAudio:
- path: /Audio/Announcements/attention.ogg
startDelay: 10
weight: 5
duration: 50
@@ -227,9 +218,9 @@
noSpawn: true
components:
- type: StationEvent
+ startAnnouncement: true # Parkstation-RandomAnnouncers
+ endAnnouncement: true # Parkstation-RandomAnnouncers
weight: 10
- startAnnouncement: station-event-power-grid-check-start-announcement
- endAnnouncement: station-event-power-grid-check-end-announcement
startAudio:
path: /Audio/Announcements/power_off.ogg
params:
@@ -245,6 +236,7 @@
# noSpawn: true
# components:
# - type: StationEvent
+# startAnnouncement: true # Parkstation-RandomAnnouncers
# weight: 10
# duration: 1
# startAudio:
@@ -257,11 +249,9 @@
noSpawn: true
components:
- type: StationEvent
+ startAnnouncement: true # Parkstation-RandomAnnouncers
+ endAnnouncement: true # Parkstation-RandomAnnouncers
weight: 10
- startAnnouncement: station-event-solar-flare-start-announcement
- endAnnouncement: station-event-solar-flare-end-announcement
- startAudio:
- path: /Audio/Announcements/attention.ogg
duration: 120
maxDuration: 240
- type: SolarFlareRule
@@ -299,9 +289,7 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-vent-clog-start-announcement
- startAudio:
- path: /Audio/Announcements/ventclog.ogg # DeltaV - custom announcer
+ startAnnouncement: true # Parkstation-RandomAnnouncers
earliestStart: 15
minimumPlayers: 15
weight: 5
@@ -315,9 +303,6 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-vent-creatures-start-announcement
- startAudio:
- path: /Audio/Announcements/attention.ogg
startDelay: 10
earliestStart: 15
minimumPlayers: 15
@@ -338,9 +323,6 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-vent-creatures-start-announcement
- startAudio:
- path: /Audio/Announcements/attention.ogg
startDelay: 10
earliestStart: 20
minimumPlayers: 15
@@ -361,9 +343,6 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-vent-creatures-start-announcement
- startAudio:
- path: /Audio/Announcements/attention.ogg
startDelay: 10
earliestStart: 20
minimumPlayers: 15
@@ -375,23 +354,21 @@
prob: 0.05
# - type: entity # DeltaV - Prevent normal spawning of MobClownSpider
-# id: SpiderClownSpawn
-# parent: BaseGameRule
-# noSpawn: true
-# components:
-# - type: StationEvent
-# startAnnouncement: station-event-vent-creatures-start-announcement
-# startAudio:
-# path: /Audio/Announcements/attention.ogg
-# startDelay: 10
-# earliestStart: 20
-# minimumPlayers: 15
-# weight: 1
-# duration: 60
-# - type: VentCrittersRule
-# entries:
-# - id: MobClownSpider
-# prob: 0.05
+# id: SpiderClownSpawn
+# parent: BaseGameRule
+# noSpawn: true
+# components:
+# - type: StationEvent
+# startAnnouncement: true # Parkstation-RandomAnnouncers
+# startDelay: 10
+# earliestStart: 20
+# minimumPlayers: 15
+# weight: 1
+# duration: 60
+# - type: VentCrittersRule
+# entries:
+# - id: MobClownSpider
+# prob: 0.05
- type: entity
id: ZombieOutbreak
@@ -399,6 +376,7 @@
noSpawn: true
components:
- type: StationEvent
+ startAnnouncement: true # Parkstation-RandomAnnouncers
earliestStart: 90 # DeltaV - was 50
minimumPlayers: 15
weight: 2.5 # DeltaV - was 5
@@ -439,20 +417,18 @@
sounds:
collection: Paracusia
-#- type: entity # DeltaV - Why does this exist??
-# id: ImmovableRodSpawn
-# parent: BaseGameRule
-# noSpawn: true
-# components:
+# - type: entity # DeltaV - Why does this exist??
+# id: ImmovableRodSpawn
+# parent: BaseGameRule
+# noSpawn: true
+# components:
# - type: StationEvent
-# startAnnouncement: station-event-immovable-rod-start-announcement
-# startAudio:
-# path: /Audio/Announcements/attention.ogg
-# weight: 5
-# duration: 1
-# earliestStart: 45
-# minimumPlayers: 20
-# - type: ImmovableRodRule
+# startAnnouncement: true # Parkstation-RandomAnnouncers
+# weight: 5
+# duration: 1
+# earliestStart: 45
+# minimumPlayers: 20
+# - type: ImmovableRodRule
- type: entity
noSpawn: true
@@ -460,6 +436,7 @@
id: IonStorm
components:
- type: StationEvent
+ startAnnouncement: true # Parkstation-RandomAnnouncers
weight: 10
earliestStart: 20
reoccurrenceDelay: 60
diff --git a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
index 61cf6eaf1f..0f3edc7bef 100644
--- a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
+++ b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml
@@ -5,7 +5,7 @@
noSpawn: true
components:
- type: StationEvent
- startAnnouncement: station-event-noospheric-storm-announcement
+ startAnnouncement: true
startAudio:
path: /Audio/Announcements/noosphericstorm.ogg
weight: 5
diff --git a/Resources/Prototypes/Parkstation/Announcers/intern.yml b/Resources/Prototypes/Parkstation/Announcers/intern.yml
new file mode 100644
index 0000000000..6f9b57fc3b
--- /dev/null
+++ b/Resources/Prototypes/Parkstation/Announcers/intern.yml
@@ -0,0 +1,136 @@
+- type: announcer
+ id: Intern
+ basePath: /Audio/Parkstation/Announcements/Intern
+ baseAudioParams:
+ volume: -7
+ announcements:
+ # Communications
+ - id: announce # Communications console
+ path: comms/announce.ogg
+ # - id: attention # Generic alert sound # Should be different from fallback but it's very similar
+ # path: comms/attention.ogg
+ - id: commandReport # Station goal, Central Command messages, etc
+ collection: InternCommandReportAnnouncements
+ # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular
+ # path: comms/spawn_announce.ogg
+ # - id: war # Nuclear Operative declaration of war
+ # path: comms/war.ogg
+ # - id: nukeCodes # The station has been send nuclear activation codes
+ # path: comms/nuke_codes.ogg # Or command_report.ogg if you want
+ # - id: nukeArm # The nuke is active and ticking
+ # path: comms/nuke_arm.ogg
+ # - id: nukeDisarm # The nuke has been disarmed
+ # path: comms/nuke_disarm.ogg
+ - id: welcome # The shift has started
+ collection: InternWelcomeAnnouncements
+
+ # Alert levels
+ # - id: alertGreen # Everything is fine
+ # path: alerts/green.ogg
+ # - id: alertBlue # Something is amiss
+ # path: alerts/blue.ogg
+ # - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical
+ # path: alerts/violet.ogg
+ # - id: alertWhite # Glimmer is too high, listen to Epistemics
+ # path: alerts/white.ogg
+ # - id: alertYellow # The station is being largely damaged, listen to Engineering
+ # path: alerts/yellow.ogg
+ # - id: alertRed # Generic many things are bad, listen to Security
+ # path: alerts/red.ogg
+ # - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command
+ # path: alerts/gamma.ogg
+ # - id: alertDelta # The station is being or about to be massively destroyed, run for your life
+ # path: alerts/delta.ogg
+ # - id: alertEpsilon # The station has been terminated, good luck survivors!
+ # path: alerts/epsilon.ogg
+
+ # Events
+ ## Wizard's Den
+ ### Mid-Round Antagonists
+ # - id: ninjaHacking # A Ninja is hacking something
+ # path: comms/ninja_hacking.ogg
+ # - id: powerSinkExplosion # A power sink is about to overcharge and explode
+ # path: comms/powersink_explosion.ogg
+ ### Events
+ - id: anomalySpawn # An anomaly has spawned in a random place
+ path: events/anomaly.ogg
+ # - id: bluespaceArtifact # An artifact has spawned in a random place
+ # path: events/bluespace_artifact.ogg
+ # - id: bluespaceLocker # Two random lockers now share inventories
+ # path: events/bluespace_locker.ogg
+ # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them
+ # path: events/breaker_flip.ogg
+ # - id: bureaucraticError # Random jobs have been added, removed, or made infinite
+ # path: events/bureaucratic_error.ogg
+ # - id: clericalError # Random crew are removed from the manifest
+ # path: events/clerical_error.ogg
+ # - id: carpRift # A dragon's carp rift is active
+ # path: events/carp_rift.ogg
+ # - id: revenantSpawn # A revenant has spawned (by a prober?)
+ # path: events/revenant_spawn.ogg
+ # - id: gasLeak # A random gas is coming out of a random vent
+ # path: events/gas_leak.ogg
+ # - id: gasLeakComplete # Gas has stopped coming out of a vent
+ # path: events/gas_leak-complete.ogg
+ # - id: kudzuGrowth # Kudzu is growing in a random place
+ # path: events/kudzu_growth.ogg
+ - id: meteorSwarm # Meteors are flying at the station, stay away from windows
+ path: events/meteors.ogg
+ # - id: meteorSwarmComplete # Meteors have stopped flying at the station
+ # path: events/meteors-complete.ogg
+ # - id: mouseMigration # Several mice have appeared in a random place
+ # path: events/mouse_migration.ogg
+ # - id: cockroachMigration # Several cockroaches have appeared in a random place
+ # path: events/cockroach_migration.ogg
+ - id: powerGridCheck # The station's power is offline for some moments
+ path: events/power_grid_check.ogg
+ - id: powerGridCheckComplete # The station's power is online again
+ path: events/power_grid_check-complete.ogg
+ # - id: randomSentience # A random few animals have become sentient
+ # path: events/random_sentience.ogg
+ # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics
+ # path: events/solar_flare.ogg
+ # - id: solarFlareComplete # The solar flare has passed
+ # path: events/solar_flare-complete.ogg
+ # - id: ventClog # A random reagent is coming out of a scrubber
+ # path: events/vent_clog.ogg
+ # - id: slimesSpawn # Some simple slimes are appearing in vents
+ # path: events/slimes_spawn.ogg
+ # - id: spiderSpawn # Some simple spiders are appearing in vents
+ # path: events/spider_spawn.ogg
+ # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it
+ # path: events/immovable_rod_spawn.ogg
+ - id: ionStorm # AI-controlled equipment are now weird, check their laws
+ path: events/ion_storm.ogg
+ ## Delta-V
+ - id: xenoVents # Xenomorphs are coming out of vents
+ path: events/aliens.ogg
+ ## NyanoTrasen
+ # - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic
+ # path: events/noospheric_storm.ogg
+ ## Parkstation
+ ### Nothing yet
+
+ # Shuttle
+ - id: shuttleCalled # The shuttle is on its way
+ path: shuttle/called.ogg
+ - id: shuttleRecalled # The shuttle is going back to Central Command
+ path: shuttle/recalled.ogg
+ - id: shuttleDock # The shuttle has arrived at the station
+ path: shuttle/dock.ogg
+ # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location
+ # path: shuttle/nearby.ogg
+ # - id: shuttleGodLuck # The shuttle could not find its way to the station, good luck crew
+ # path: shuttle/good_luck.ogg
+ # - id: shuttleAuthAdded # One of few have added their acceptance to early launching
+ # path: shuttle/auth_added.ogg
+ # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching
+ # path: shuttle/auth_revoked.ogg
+ # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds
+ # path: shuttle/almost_launching.ogg
+ # - id: shuttleLeft # The shuttle has left the station
+ # path: shuttle/left.ogg
+
+ # Fallback # REQUIRED
+ - id: fallback # Any announcement sent without a valid announcement on this announcer will use this
+ collection: InternAnnouncements
diff --git a/Resources/Prototypes/Parkstation/Announcers/medbot.yml b/Resources/Prototypes/Parkstation/Announcers/medbot.yml
new file mode 100644
index 0000000000..f71c7f6f87
--- /dev/null
+++ b/Resources/Prototypes/Parkstation/Announcers/medbot.yml
@@ -0,0 +1,134 @@
+- type: announcer
+ id: MedBot
+ basePath: /Audio/Parkstation/Announcements/MedBot
+ announcements:
+ # Communications
+ - id: announce # Communications console
+ path: comms/announce.ogg
+ - id: attention # Generic alert sound # Should be different from fallback but it's very similar
+ path: comms/attention.ogg
+ - id: commandReport # Station goal, Central Command messages, etc
+ path: comms/command_report.ogg
+ # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular
+ # path: comms/spawn_announce.ogg
+ # - id: war # Nuclear Operative declaration of war
+ # path: comms/war.ogg
+ # - id: nukeCodes # The station has been send nuclear activation codes
+ # path: comms/nuke_codes.ogg # Or command_report.ogg if you want
+ # - id: nukeArm # The nuke is active and ticking
+ # path: comms/nuke_arm.ogg
+ # - id: nukeDisarm # The nuke has been disarmed
+ # path: comms/nuke_disarm.ogg
+ - id: welcome # The shift has started
+ path: comms/welcome.ogg
+
+ # Alert levels
+ # - id: alertGreen # Everything is fine
+ # path: alerts/green.ogg
+ # - id: alertBlue # Something is amiss
+ # path: alerts/blue.ogg
+ # - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical
+ # path: alerts/violet.ogg
+ # - id: alertWhite # Glimmer is too high, listen to Epistemics
+ # path: alerts/white.ogg
+ # - id: alertYellow # The station is being largely damaged, listen to Engineering
+ # path: alerts/yellow.ogg
+ # - id: alertRed # Generic many things are bad, listen to Security
+ # path: alerts/red.ogg
+ # - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command
+ # path: alerts/gamma.ogg
+ # - id: alertDelta # The station is being or about to be massively destroyed, run for your life
+ # path: alerts/delta.ogg
+ # - id: alertEpsilon # The station has been terminated, good luck survivors!
+ # path: alerts/epsilon.ogg
+
+ # Events
+ ## Wizard's Den
+ ### Mid-Round Antagonists
+ # - id: ninjaHacking # A Ninja is hacking something
+ # path: comms/ninja_hacking.ogg
+ # - id: powerSinkExplosion # A power sink is about to overcharge and explode
+ # path: comms/powersink_explosion.ogg
+ ### Events
+ - id: anomalySpawn # An anomaly has spawned in a random place
+ path: events/anomaly.ogg
+ # - id: bluespaceArtifact # An artifact has spawned in a random place
+ # path: events/bluespace_artifact.ogg
+ # - id: bluespaceLocker # Two random lockers now share inventories
+ # path: events/bluespace_locker.ogg
+ # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them
+ # path: events/breaker_flip.ogg
+ # - id: bureaucraticError # Random jobs have been added, removed, or made infinite
+ # path: events/bureaucratic_error.ogg
+ # - id: clericalError # Random crew are removed from the manifest
+ # path: events/clerical_error.ogg
+ # - id: carpRift # A dragon's carp rift is active
+ # path: events/carp_rift.ogg
+ # - id: revenantSpawn # A revenant has spawned (by a prober?)
+ # path: events/revenant_spawn.ogg
+ # - id: gasLeak # A random gas is coming out of a random vent
+ # path: events/gas_leak.ogg
+ # - id: gasLeakComplete # Gas has stopped coming out of a vent
+ # path: events/gas_leak-complete.ogg
+ # - id: kudzuGrowth # Kudzu is growing in a random place
+ # path: events/kudzu_growth.ogg
+ - id: meteorSwarm # Meteors are flying at the station, stay away from windows
+ path: events/meteors.ogg
+ # - id: meteorSwarmComplete # Meteors have stopped flying at the station
+ # path: events/meteors-complete.ogg
+ # - id: mouseMigration # Several mice have appeared in a random place
+ # path: events/mouse_migration.ogg
+ # - id: cockroachMigration # Several cockroaches have appeared in a random place
+ # path: events/cockroach_migration.ogg
+ - id: powerGridCheck # The station's power is offline for some moments
+ path: events/power_grid_check.ogg
+ - id: powerGridCheckComplete # The station's power is online again
+ path: events/power_grid_check-complete.ogg
+ # - id: randomSentience # A random few animals have become sentient
+ # path: events/random_sentience.ogg
+ # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics
+ # path: events/solar_flare.ogg
+ # - id: solarFlareComplete # The solar flare has passed
+ # path: events/solar_flare-complete.ogg
+ # - id: ventClog # A random reagent is coming out of a scrubber
+ # path: events/vent_clog.ogg
+ # - id: slimesSpawn # Some simple slimes are appearing in vents
+ # path: events/slimes_spawn.ogg
+ # - id: spiderSpawn # Some simple spiders are appearing in vents
+ # path: events/spider_spawn.ogg
+ # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it
+ # path: events/immovable_rod_spawn.ogg
+ - id: ionStorm # AI-controlled equipment are now weird, check their laws
+ path: events/ion_storm.ogg
+ ## Delta-V
+ - id: xenoVents # Xenomorphs are coming out of vents
+ path: events/aliens.ogg
+ ## NyanoTrasen
+ # - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic
+ # path: events/noospheric_storm.ogg
+ ## Parkstation
+ ### Nothing yet
+
+ # Shuttle
+ - id: shuttleCalled # The shuttle is on its way
+ path: shuttle/called.ogg
+ - id: shuttleRecalled # The shuttle is going back to Central Command
+ path: shuttle/recalled.ogg
+ - id: shuttleDock # The shuttle has arrived at the station
+ path: shuttle/dock.ogg
+ # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location
+ # path: shuttle/nearby.ogg
+ # - id: shuttleGodLuck # The shuttle could not find its way to the station, good luck crew
+ # path: shuttle/good_luck.ogg
+ # - id: shuttleAuthAdded # One of few have added their acceptance to early launching
+ # path: shuttle/auth_added.ogg
+ # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching
+ # path: shuttle/auth_revoked.ogg
+ # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds
+ # path: shuttle/almost_launching.ogg
+ # - id: shuttleLeft # The shuttle has left the station
+ # path: shuttle/left.ogg
+
+ # Fallback # REQUIRED
+ - id: fallback # Any announcement sent without a valid announcement on this announcer will use this
+ path: fallback.ogg
diff --git a/Resources/Prototypes/Parkstation/Announcers/michael.yml b/Resources/Prototypes/Parkstation/Announcers/michael.yml
new file mode 100644
index 0000000000..a99c15ef15
--- /dev/null
+++ b/Resources/Prototypes/Parkstation/Announcers/michael.yml
@@ -0,0 +1,136 @@
+- type: announcer
+ id: Michael
+ basePath: /Audio/Parkstation/Announcements/Michael
+ announcements:
+ # Communications
+ # - id: announce # Communications console
+ # path: comms/announce.ogg
+ - id: attention # Generic alert sound # Should be different from fallback but it's very similar
+ path: comms/attention.ogg
+ # - id: commandReport # Station goal, Central Command messages, etc
+ # path: comms/command_report.ogg
+ # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular
+ # path: comms/spawn_announce.ogg
+ # - id: war # Nuclear Operative declaration of war
+ # path: comms/war.ogg
+ # - id: nukeCodes # The station has been send nuclear activation codes
+ # path: comms/nuke_codes.ogg # Or command_report.ogg if you want
+ # - id: nukeArm # The nuke is active and ticking
+ # path: comms/nuke_arm.ogg
+ # - id: nukeDisarm # The nuke has been disarmed
+ # path: comms/nuke_disarm.ogg
+ - id: welcome # The shift has started
+ path: comms/welcome.ogg
+
+ # Alert levels
+ - id: alertGreen # Everything is fine
+ path: alerts/green.ogg
+ - id: alertBlue # Something is amiss
+ path: alerts/blue.ogg
+ - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical
+ path: alerts/violet.ogg
+ - id: alertWhite # Glimmer is too high, listen to Epistemics
+ path: alerts/white.ogg
+ - id: alertYellow # The station is being largely damaged, listen to Engineering
+ path: alerts/yellow.ogg
+ - id: alertRed # Generic many things are bad, listen to Security
+ path: alerts/red.ogg
+ - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command
+ path: alerts/gamma.ogg
+ # - id: alertDelta # The station is being or about to be massively destroyed, run for your life
+ # path: alerts/delta.ogg
+ - id: alertEpsilon # The station has been terminated, good luck survivors!
+ path: alerts/epsilon.ogg
+ audioParams:
+ volume: -3
+
+ # Events
+ ## Wizard's Den
+ ### Mid-Round Antagonists
+ # - id: ninjaHacking # A Ninja is hacking something
+ # path: comms/ninja_hacking.ogg
+ # - id: powerSinkExplosion # A power sink is about to overcharge and explode
+ # path: comms/powersink_explosion.ogg
+ ### Events
+ # - id: anomalySpawn # An anomaly has spawned in a random place
+ # path: events/anomaly.ogg
+ # - id: bluespaceArtifact # An artifact has spawned in a random place
+ # path: events/bluespace_artifact.ogg
+ # - id: bluespaceLocker # Two random lockers now share inventories
+ # path: events/bluespace_locker.ogg
+ # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them
+ # path: events/breaker_flip.ogg
+ - id: bureaucraticError # Random jobs have been added, removed, or made infinite
+ path: events/bureaucratic_error.ogg
+ # - id: clericalError # Random crew are removed from the manifest
+ # path: events/clerical_error.ogg
+ # - id: carpRift # A dragon's carp rift is active
+ # path: events/carp_rift.ogg
+ # - id: revenantSpawn # A revenant has spawned (by a prober?)
+ # path: events/revenant_spawn.ogg
+ - id: gasLeak # A random gas is coming out of a random vent
+ path: events/gas_leak.ogg
+ # - id: gasLeakComplete # Gas has stopped coming out of a vent
+ # path: events/gas_leak-complete.ogg
+ - id: kudzuGrowth # Kudzu is growing in a random place
+ path: events/kudzu_growth.ogg
+ - id: meteorSwarm # Meteors are flying at the station, stay away from windows
+ path: events/meteors.ogg
+ # - id: meteorSwarmComplete # Meteors have stopped flying at the station
+ # path: events/meteors-complete.ogg
+ # - id: mouseMigration # Several mice have appeared in a random place
+ # path: events/mouse_migration.ogg
+ # - id: cockroachMigration # Several cockroaches have appeared in a random place
+ # path: events/cockroach_migration.ogg
+ - id: powerGridCheck # The station's power is offline for some moments
+ path: events/power_grid_check.ogg
+ - id: powerGridCheckComplete # The station's power is online again
+ path: events/power_grid_check-complete.ogg
+ # - id: randomSentience # A random few animals have become sentient
+ # path: events/random_sentience.ogg
+ # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics
+ # path: events/solar_flare.ogg
+ # - id: solarFlareComplete # The solar flare has passed
+ # path: events/solar_flare-complete.ogg
+ - id: ventClog # A random reagent is coming out of a scrubber
+ path: events/vent_clog.ogg
+ # - id: slimesSpawn # Some simple slimes are appearing in vents
+ # path: events/slimes_spawn.ogg
+ # - id: spiderSpawn # Some simple spiders are appearing in vents
+ # path: events/spider_spawn.ogg
+ # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it
+ # path: events/immovable_rod_spawn.ogg
+ # - id: ionStorm # AI-controlled equipment are now weird, check their laws
+ # path: events/ion_storm.ogg
+ ## Delta-V
+ - id: xenoVents # Xenomorphs are coming out of vents
+ path: events/aliens.ogg
+ ## NyanoTrasen
+ - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic
+ path: events/noospheric_storm.ogg
+ ## Parkstation
+ ### Nothing yet
+
+ # Shuttle
+ - id: shuttleCalled # The shuttle is on its way
+ path: shuttle/called.ogg
+ - id: shuttleRecalled # The shuttle is going back to Central Command
+ path: shuttle/recalled.ogg
+ - id: shuttleDock # The shuttle has arrived at the station
+ path: shuttle/dock.ogg
+ # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location
+ # path: shuttle/nearby.ogg
+ # - id: shuttleGodLuck # The shuttle could not find its way to the station, good luck crew
+ # path: shuttle/good_luck.ogg
+ # - id: shuttleAuthAdded # One of few have added their acceptance to early launching
+ # path: shuttle/auth_added.ogg
+ # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching
+ # path: shuttle/auth_revoked.ogg
+ # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds
+ # path: shuttle/almost_launching.ogg
+ # - id: shuttleLeft # The shuttle has left the station
+ # path: shuttle/left.ogg
+
+ # Fallback # REQUIRED
+ - id: fallback # Any announcement sent without a valid announcement on this announcer will use this
+ path: fallback.ogg
diff --git a/Resources/Prototypes/Parkstation/Announcers/neil.yml b/Resources/Prototypes/Parkstation/Announcers/neil.yml
new file mode 100644
index 0000000000..9afe7d0032
--- /dev/null
+++ b/Resources/Prototypes/Parkstation/Announcers/neil.yml
@@ -0,0 +1,136 @@
+- type: announcer
+ id: NEIL
+ basePath: /Audio/Parkstation/Announcements/NEIL
+ baseAudioParams:
+ volume: -3
+ announcements:
+ # Communications
+ - id: announce # Communications console
+ path: comms/announce.ogg
+ - id: attention # Generic alert sound # Should be different from fallback but it's very similar
+ path: comms/attention.ogg
+ # - id: commandReport # Station goal, Central Command messages, etc
+ # path: comms/command_report.ogg
+ # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular
+ # path: comms/spawn_announce.ogg
+ # - id: war # Nuclear Operative declaration of war
+ # path: comms/war.ogg
+ # - id: nukeCodes # The station has been send nuclear activation codes
+ # path: comms/nuke_codes.ogg # Or command_report.ogg if you want
+ # - id: nukeArm # The nuke is active and ticking
+ # path: comms/nuke_arm.ogg
+ # - id: nukeDisarm # The nuke has been disarmed
+ # path: comms/nuke_disarm.ogg
+ - id: welcome # The shift has started
+ path: comms/welcome.ogg
+
+ # Alert levels
+ - id: alertGreen # Everything is fine
+ path: alerts/green.ogg
+ - id: alertBlue # Something is amiss
+ path: alerts/blue.ogg
+ - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical
+ path: alerts/violet.ogg
+ - id: alertWhite # Glimmer is too high, listen to Epistemics
+ path: alerts/white.ogg
+ - id: alertYellow # The station is being largely damaged, listen to Engineering
+ path: alerts/yellow.ogg
+ - id: alertRed # Generic many things are bad, listen to Security
+ path: alerts/red.ogg
+ - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command
+ path: alerts/gamma.ogg
+ - id: alertDelta # The station is being or about to be massively destroyed, run for your life
+ path: alerts/delta.ogg
+ - id: alertEpsilon # The station has been terminated, good luck survivors!
+ path: alerts/epsilon.ogg
+
+ # Events
+ ## Wizard's Den
+ ### Mid-Round Antagonists
+ # - id: ninjaHacking # A Ninja is hacking something
+ # path: comms/ninja_hacking.ogg
+ # - id: powerSinkExplosion # A power sink is about to overcharge and explode
+ # path: comms/powersink_explosion.ogg
+ ### Events
+ - id: anomalySpawn # An anomaly has spawned in a random place
+ path: events/anomaly.ogg
+ # - id: bluespaceArtifact # An artifact has spawned in a random place
+ # path: events/bluespace_artifact.ogg
+ # - id: bluespaceLocker # Two random lockers now share inventories
+ # path: events/bluespace_locker.ogg
+ - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them
+ path: events/breaker_flip.ogg
+ - id: bureaucraticError # Random jobs have been added, removed, or made infinite
+ path: events/bureaucratic_error.ogg
+ # - id: clericalError # Random crew are removed from the manifest
+ # path: events/clerical_error.ogg
+ # - id: carpRift # A dragon's carp rift is active
+ # path: events/carp_rift.ogg
+ # - id: revenantSpawn # A revenant has spawned (by a prober?)
+ # path: events/revenant_spawn.ogg
+ - id: gasLeak # A random gas is coming out of a random vent
+ path: events/gas_leak.ogg
+ # - id: gasLeakComplete # Gas has stopped coming out of a vent
+ # path: events/gas_leak-complete.ogg
+ - id: kudzuGrowth # Kudzu is growing in a random place
+ path: events/kudzu_growth.ogg
+ - id: meteorSwarm # Meteors are flying at the station, stay away from windows
+ path: events/meteors.ogg
+ # - id: meteorSwarmComplete # Meteors have stopped flying at the station
+ # path: events/meteors-complete.ogg
+ # - id: mouseMigration # Several mice have appeared in a random place
+ # path: events/mouse_migration.ogg
+ # - id: cockroachMigration # Several cockroaches have appeared in a random place
+ # path: events/cockroach_migration.ogg
+ - id: powerGridCheck # The station's power is offline for some moments
+ path: events/power_grid_check.ogg
+ - id: powerGridCheckComplete # The station's power is online again
+ path: events/power_grid_check-complete.ogg
+ # - id: randomSentience # A random few animals have become sentient
+ # path: events/random_sentience.ogg
+ # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics
+ # path: events/solar_flare.ogg
+ # - id: solarFlareComplete # The solar flare has passed
+ # path: events/solar_flare-complete.ogg
+ - id: ventClog # A random reagent is coming out of a scrubber
+ path: events/vent_clog.ogg
+ # - id: slimesSpawn # Some simple slimes are appearing in vents
+ # path: events/slimes_spawn.ogg
+ # - id: spiderSpawn # Some simple spiders are appearing in vents
+ # path: events/spider_spawn.ogg
+ # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it
+ # path: events/immovable_rod_spawn.ogg
+ - id: ionStorm # AI-controlled equipment are now weird, check their laws
+ path: events/ion_storm.ogg
+ ## Delta-V
+ # - id: xenoVents # Xenomorphs are coming out of vents
+ # path: events/xeno_vents.ogg
+ ## NyanoTrasen
+ - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic
+ path: events/noospheric_storm.ogg
+ ## Parkstation
+ ### Nothing yet
+
+ # Shuttle
+ - id: shuttleCalled # The shuttle is on its way
+ path: shuttle/called.ogg
+ - id: shuttleRecalled # The shuttle is going back to Central Command
+ path: shuttle/recalled.ogg
+ - id: shuttleDock # The shuttle has arrived at the station
+ path: shuttle/dock.ogg
+ # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location
+ # path: shuttle/nearby.ogg
+ # - id: shuttleGodLuck # The shuttle could not find its way to the station, good luck crew
+ # path: shuttle/good_luck.ogg
+ # - id: shuttleAuthAdded # One of few have added their acceptance to early launching
+ # path: shuttle/auth_added.ogg
+ # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching
+ # path: shuttle/auth_revoked.ogg
+ # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds
+ # path: shuttle/almost_launching.ogg
+ # - id: shuttleLeft # The shuttle has left the station
+ # path: shuttle/left.ogg
+
+ # Fallback # REQUIRED
+ - id: fallback # Any announcement sent without a valid announcement on this announcer will use this
+ path: fallback.ogg
diff --git a/Resources/Prototypes/Parkstation/Announcers/template b/Resources/Prototypes/Parkstation/Announcers/template
new file mode 100644
index 0000000000..e67e63b46d
--- /dev/null
+++ b/Resources/Prototypes/Parkstation/Announcers/template
@@ -0,0 +1,160 @@
+# This should be getting auto detected as YML if you're using VSCode
+# If it's not, you can probably manually set the language mode to YML somehow
+# Or just change the filename to `template.yml` temporarily
+# The game will complain if I name it template.yaml in an attempt to not load it
+#
+# This file contains instructions for everything you can do with the announcer system
+# This also contains every "needed" announcement for any new announcers and descriptions for what they are
+#
+# Avoid renaming announcement audio files to keep consistency between announcers for workspace searching
+# Keep comments on specific announcements and follow this same formatting for every announcer
+# If you don't have an announcement audio, comment the announcemt type instead of deleting it
+
+- type: announcer
+ id: Announcer # Localized as "announcer--name" in chat
+ basePath: /Audio/Codebase/Announcements/Announcer # Where to start looking for audio files
+ baseAudioParams: # Default audio parameters for all announcements, all options explained in the template announcement
+ volume: -7 # If this announcer is really loud, lower it to match the others' volume #? Default is 3
+ announcements: # List of all announcements this announcer has audio for #! Comment out unused announcements, don't remove them
+ # Template, delete this in real announcer files
+ - id: template # Lowercase of the event ID, add "Complete" to the end for post-event announcements (endings)
+ ignoreBasePath: false # If true, it will ignore the basePath and use the path as is
+ path: template.ogg # Path to the file relative to basePath/, named with snake_case except for "-complete"
+ collection: AnnouncerTemplateAnnouncements # Collection of audios to randomly use for this, will ignore path if set #! Ignores basePath automatically
+ message: announcer-announcement-template # Localization key for the announcement message to use instead of the default one # NOTE this does not pass through previous loc args yet
+ audioParams: # Overrides baseAudioParams entirely for this specific announcement, numbers are all floats
+ volume: 3 # We don't want individual announcement volumes to vary too much, normalize them with this #? Default is 3
+ pitch: 1 #? Default is 1
+ playOffsetSeconds: 0 # How many seconds into the audio to start from #? Default is 0
+ variation: 0 # Probably wouldn't sound very good unless very low, 0.15 or less is normally used #? Default is 0
+
+ # Communications
+ - id: announce # Communications console
+ path: comms/announce.ogg
+ - id: attention # Generic alert sound # Should be different from fallback but it's very similar
+ path: comms/attention.ogg
+ - id: commandReport # Station goal, Central Command messages, etc
+ path: comms/command_report.ogg
+ - id: spawnAnnounce # Captain join # TODO That system is annoyingly not modular
+ path: comms/spawn_announce.ogg
+ - id: war # Nuclear Operative declaration of war
+ path: comms/war.ogg
+ - id: nukeCodes # The station has been send nuclear activation codes
+ path: comms/nuke_codes.ogg # Or command_report.ogg if you want
+ - id: nukeArm # The nuke is active and ticking
+ path: comms/nuke_arm.ogg
+ - id: nukeDisarm # The nuke has been disarmed
+ path: comms/nuke_disarm.ogg
+ - id: welcome # The shift has started
+ path: comms/welcome.ogg
+
+ # Alert levels
+ - id: alertGreen # Everything is fine
+ path: alerts/green.ogg
+ - id: alertBlue # Something is amiss
+ path: alerts/blue.ogg
+ - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical
+ path: alerts/violet.ogg
+ - id: alertWhite # Glimmer is too high, listen to Epistemics
+ path: alerts/white.ogg
+ - id: alertYellow # The station is being largely damaged, listen to Engineering
+ path: alerts/yellow.ogg
+ - id: alertRed # Generic many things are bad, listen to Security
+ path: alerts/red.ogg
+ - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command
+ path: alerts/gamma.ogg
+ - id: alertDelta # The station is being or about to be massively destroyed, run for your life
+ path: alerts/delta.ogg
+ - id: alertEpsilon # The station has been terminated, good luck survivors!
+ path: alerts/epsilon.ogg
+
+ # Events
+ ## Wizard's Den
+ ### Mid-Round Antagonists
+ - id: ninjaHacking # A Ninja is hacking something
+ path: comms/ninja_hacking.ogg
+ - id: powersinkExplosion # A power sink is about to overcharge and explode
+ path: comms/powersink_explosion.ogg
+ ### Events
+ - id: anomalySpawn # An anomaly has spawned in a random place
+ path: events/anomaly.ogg
+ - id: bluespaceArtifact # An artifact has spawned in a random place
+ path: events/bluespace_artifact.ogg
+ - id: bluespaceLocker # Two random lockers now share inventories
+ path: events/bluespace_locker.ogg
+ - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them
+ path: events/breaker_flip.ogg
+ - id: bureaucraticError # Random jobs have been added, removed, or made infinite
+ path: events/bureaucratic_error.ogg
+ - id: clericalError # Random crew are removed from the manifest
+ path: events/clerical_error.ogg
+ - id: carpRift # A dragon's carp rift is active
+ path: events/carp_rift.ogg
+ - id: revenantSpawn # A revenant has spawned (by a prober?)
+ path: events/revenant_spawn.ogg
+ - id: gasLeak # A random gas is coming out of a random vent
+ path: events/gas_leak.ogg
+ - id: gasLeakComplete # Gas has stopped coming out of a vent
+ path: events/gas_leak-complete.ogg
+ - id: kudzuGrowth # Kudzu is growing in a random place
+ path: events/kudzu_growth.ogg
+ - id: meteorSwarm # Meteors are flying at the station, stay away from windows
+ path: events/meteors.ogg
+ - id: meteorSwarmComplete # Meteors have stopped flying at the station
+ path: events/meteors-complete.ogg
+ - id: mouseMigration # Several mice have appeared in a random place
+ path: events/mouse_migration.ogg
+ - id: cockroachMigration # Several cockroaches have appeared in a random place
+ path: events/cockroach_migration.ogg
+ - id: powerGridCheck # The station's power is offline for some moments
+ path: events/power_grid_check.ogg
+ - id: powerGridCheckComplete # The station's power is online again
+ path: events/power_grid_check-complete.ogg
+ - id: randomSentience # A random few animals have become sentient
+ path: events/random_sentience.ogg
+ - id: solarFlare # A solar flare is nearby, may mess with comms and electronics
+ path: events/solar_flare.ogg
+ - id: solarFlareComplete # The solar flare has passed
+ path: events/solar_flare-complete.ogg
+ - id: ventClog # A random reagent is coming out of a scrubber
+ path: events/vent_clog.ogg
+ - id: slimesSpawn # Some simple slimes are appearing in vents
+ path: events/slimes_spawn.ogg
+ - id: spiderSpawn # Some simple spiders are appearing in vents
+ path: events/spider_spawn.ogg
+ - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it
+ path: events/immovable_rod_spawn.ogg
+ - id: ionStorm # AI-controlled equipment are now weird, check their laws
+ path: events/ion_storm.ogg
+ ## Delta-V
+ - id: xenoVents # Xenomorphs are coming out of vents
+ path: events/xeno_vents.ogg
+ ## NyanoTrasen
+ - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic
+ path: events/noospheric_storm.ogg
+ ## Parkstation
+ ### Nothing yet
+
+ # Shuttle
+ - id: shuttleCalled # The shuttle is on its way
+ path: shuttle/called.ogg
+ - id: shuttleRecalled # The shuttle is going back to Central Command
+ path: shuttle/recalled.ogg
+ - id: shuttleDock # The shuttle has arrived at the station
+ path: shuttle/dock.ogg
+ - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location
+ path: shuttle/nearby.ogg
+ - id: shuttleGodLuck # The shuttle could not find its way to the station, good luck crew
+ path: shuttle/good_luck.ogg
+ - id: shuttleAuthAdded # One of few have added their acceptance to early launching
+ path: shuttle/auth_added.ogg
+ - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching
+ path: shuttle/auth_revoked.ogg
+ - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds
+ path: shuttle/almost_launching.ogg
+ - id: shuttleLeft # The shuttle has left the station
+ path: shuttle/left.ogg
+
+ # Fallback # REQUIRED
+ - id: fallback # Any announcement sent without a valid announcement on this announcer will use this
+ path: fallback.ogg
diff --git a/Resources/Prototypes/Parkstation/Announcers/voxfem.yml b/Resources/Prototypes/Parkstation/Announcers/voxfem.yml
new file mode 100644
index 0000000000..fde63f50ec
--- /dev/null
+++ b/Resources/Prototypes/Parkstation/Announcers/voxfem.yml
@@ -0,0 +1,134 @@
+- type: announcer
+ id: VoxFem
+ basePath: /Audio/Parkstation/Announcements/VoxFem
+ announcements:
+ # Communications
+ - id: announce # Communications console
+ path: comms/announce.ogg
+ - id: attention # Generic alert sound # Should be different from fallback but it's very similar
+ path: comms/attention.ogg
+ - id: commandReport # Station goal, Central Command messages, etc
+ path: comms/command_report.ogg
+ # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular
+ # path: comms/spawn_announce.ogg
+ # - id: war # Nuclear Operative declaration of war
+ # path: comms/war.ogg
+ # - id: nukeCodes # The station has been send nuclear activation codes
+ # path: comms/nuke_codes.ogg # Or command_report.ogg if you want
+ # - id: nukeArm # The nuke is active and ticking
+ # path: comms/nuke_arm.ogg
+ # - id: nukeDisarm # The nuke has been disarmed
+ # path: comms/nuke_disarm.ogg
+ - id: welcome # The shift has started
+ path: comms/welcome.ogg
+
+ # Alert levels
+ # - id: alertGreen # Everything is fine
+ # path: alerts/green.ogg
+ # - id: alertBlue # Something is amiss
+ # path: alerts/blue.ogg
+ # - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical
+ # path: alerts/violet.ogg
+ # - id: alertWhite # Glimmer is too high, listen to Epistemics
+ # path: alerts/white.ogg
+ # - id: alertYellow # The station is being largely damaged, listen to Engineering
+ # path: alerts/yellow.ogg
+ # - id: alertRed # Generic many things are bad, listen to Security
+ # path: alerts/red.ogg
+ # - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command
+ # path: alerts/gamma.ogg
+ # - id: alertDelta # The station is being or about to be massively destroyed, run for your life
+ # path: alerts/delta.ogg
+ # - id: alertEpsilon # The station has been terminated, good luck survivors!
+ # path: alerts/epsilon.ogg
+
+ # Events
+ ## Wizard's Den
+ ### Mid-Round Antagonists
+ - id: ninjaHacking # A Ninja is hacking something
+ path: comms/ninja_hacking.ogg
+ - id: powerSinkExplosion # A power sink is about to overcharge and explode
+ path: comms/powersink_explosion.ogg
+ ### Events
+ # - id: anomalySpawn # An anomaly has spawned in a random place
+ # path: events/anomaly.ogg
+ # - id: bluespaceArtifact # An artifact has spawned in a random place
+ # path: events/bluespace_artifact.ogg
+ # - id: bluespaceLocker # Two random lockers now share inventories
+ # path: events/bluespace_locker.ogg
+ # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them
+ # path: events/breaker_flip.ogg
+ # - id: bureaucraticError # Random jobs have been added, removed, or made infinite
+ # path: events/bureaucratic_error.ogg
+ # - id: clericalError # Random crew are removed from the manifest
+ # path: events/clerical_error.ogg
+ # - id: carpRift # A dragon's carp rift is active
+ # path: events/carp_rift.ogg
+ # - id: revenantSpawn # A revenant has spawned (by a prober?)
+ # path: events/revenant_spawn.ogg
+ # - id: gasLeak # A random gas is coming out of a random vent
+ # path: events/gas_leak.ogg
+ # - id: gasLeakComplete # Gas has stopped coming out of a vent
+ # path: events/gas_leak-complete.ogg
+ # - id: kudzuGrowth # Kudzu is growing in a random place
+ # path: events/kudzu_growth.ogg
+ - id: meteorSwarm # Meteors are flying at the station, stay away from windows
+ path: events/meteors.ogg
+ # - id: meteorSwarmComplete # Meteors have stopped flying at the station
+ # path: events/meteors-complete.ogg
+ # - id: mouseMigration # Several mice have appeared in a random place
+ # path: events/mouse_migration.ogg
+ # - id: cockroachMigration # Several cockroaches have appeared in a random place
+ # path: events/cockroach_migration.ogg
+ - id: powerGridCheck # The station's power is offline for some moments
+ path: events/power_grid_check.ogg
+ - id: powerGridCheckComplete # The station's power is online again
+ path: events/power_grid_check-complete.ogg
+ # - id: randomSentience # A random few animals have become sentient
+ # path: events/random_sentience.ogg
+ # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics
+ # path: events/solar_flare.ogg
+ # - id: solarFlareComplete # The solar flare has passed
+ # path: events/solar_flare-complete.ogg
+ # - id: ventClog # A random reagent is coming out of a scrubber
+ # path: events/vent_clog.ogg
+ # - id: slimesSpawn # Some simple slimes are appearing in vents
+ # path: events/slimes_spawn.ogg
+ # - id: spiderSpawn # Some simple spiders are appearing in vents
+ # path: events/spider_spawn.ogg
+ # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it
+ # path: events/immovable_rod_spawn.ogg
+ - id: ionStorm # AI-controlled equipment are now weird, check their laws
+ path: events/ion_storm.ogg
+ ## Delta-V
+ - id: xenoVents # Xenomorphs are coming out of vents
+ path: events/aliens.ogg
+ ## NyanoTrasen
+ # - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic
+ # path: events/noospheric_storm.ogg
+ ## Parkstation
+ ### Nothing yet
+
+ # Shuttle
+ - id: shuttleCalled # The shuttle is on its way
+ path: shuttle/called.ogg
+ - id: shuttleRecalled # The shuttle is going back to Central Command
+ path: shuttle/recalled.ogg
+ - id: shuttleDock # The shuttle has arrived at the station
+ path: shuttle/dock.ogg
+ # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location
+ # path: shuttle/nearby.ogg
+ # - id: shuttleGodLuck # The shuttle could not find its way to the station, good luck crew
+ # path: shuttle/good_luck.ogg
+ # - id: shuttleAuthAdded # One of few have added their acceptance to early launching
+ # path: shuttle/auth_added.ogg
+ # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching
+ # path: shuttle/auth_revoked.ogg
+ # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds
+ # path: shuttle/almost_launching.ogg
+ # - id: shuttleLeft # The shuttle has left the station
+ # path: shuttle/left.ogg
+
+ # Fallback # REQUIRED
+ - id: fallback # Any announcement sent without a valid announcement on this announcer will use this
+ path: fallback.ogg
diff --git a/Resources/Prototypes/Parkstation/SoundCollections/Announcers/intern.yml b/Resources/Prototypes/Parkstation/SoundCollections/Announcers/intern.yml
new file mode 100644
index 0000000000..66b87d4ee6
--- /dev/null
+++ b/Resources/Prototypes/Parkstation/SoundCollections/Announcers/intern.yml
@@ -0,0 +1,34 @@
+- type: soundCollection
+ id: InternAnnouncements
+ files:
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/1.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/2.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/3.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/4.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/5.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/6.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/7.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/8.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/9.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/10.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/11.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/12.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/13.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/announce/14.ogg
+
+- type: soundCollection
+ id: InternCommandReportAnnouncements
+ files:
+ - /Audio/Parkstation/Announcements/Intern/comms/commandReport/1.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/commandReport/2.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/commandReport/3.ogg
+
+- type: soundCollection
+ id: InternWelcomeAnnouncements
+ files:
+ - /Audio/Parkstation/Announcements/Intern/comms/welcome/1.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/welcome/2.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/welcome/3.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/welcome/4.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/welcome/5.ogg
+ - /Audio/Parkstation/Announcements/Intern/comms/welcome/6.ogg