using System.Linq; using System.Text.RegularExpressions; using Content.Shared.Announcements.Prototypes; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Prototypes; namespace Content.Shared.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 = OopsConcat(char.ToLowerInvariant(announcementId[0]).ToString(), announcementId[1..]); // If the event has ended, add "Complete" to the end if (ended) id += "Complete"; return id; } private string OopsConcat(string a, string b) { // This exists to prevent Roslyn being clever and compiling something that fails sandbox checks. return a + b; } /// /// 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 for the funnies } /// /// 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 ? 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); } }