1
0

AlertLevelSystem.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. using System.Linq;
  2. using Content.Server.Chat.Systems;
  3. using Content.Server.Station.Systems;
  4. using Content.Shared.CCVar;
  5. using Robust.Shared.Audio;
  6. using Robust.Shared.Audio.Systems;
  7. using Robust.Shared.Configuration;
  8. using Robust.Shared.Prototypes;
  9. namespace Content.Server.AlertLevel;
  10. public sealed class AlertLevelSystem : EntitySystem
  11. {
  12. [Dependency] private readonly IConfigurationManager _cfg = default!;
  13. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  14. [Dependency] private readonly ChatSystem _chatSystem = default!;
  15. [Dependency] private readonly SharedAudioSystem _audio = default!;
  16. [Dependency] private readonly StationSystem _stationSystem = default!;
  17. // Until stations are a prototype, this is how it's going to have to be.
  18. public const string DefaultAlertLevelSet = "stationAlerts";
  19. public override void Initialize()
  20. {
  21. SubscribeLocalEvent<StationInitializedEvent>(OnStationInitialize);
  22. SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
  23. }
  24. public override void Update(float time)
  25. {
  26. var query = EntityQueryEnumerator<AlertLevelComponent>();
  27. while (query.MoveNext(out var station, out var alert))
  28. {
  29. if (alert.CurrentDelay <= 0)
  30. {
  31. if (alert.ActiveDelay)
  32. {
  33. RaiseLocalEvent(new AlertLevelDelayFinishedEvent());
  34. alert.ActiveDelay = false;
  35. }
  36. continue;
  37. }
  38. alert.CurrentDelay -= time;
  39. }
  40. }
  41. private void OnStationInitialize(StationInitializedEvent args)
  42. {
  43. if (!TryComp<AlertLevelComponent>(args.Station, out var alertLevelComponent))
  44. return;
  45. if (!_prototypeManager.TryIndex(alertLevelComponent.AlertLevelPrototype, out AlertLevelPrototype? alerts))
  46. {
  47. return;
  48. }
  49. alertLevelComponent.AlertLevels = alerts;
  50. var defaultLevel = alertLevelComponent.AlertLevels.DefaultLevel;
  51. if (string.IsNullOrEmpty(defaultLevel))
  52. {
  53. defaultLevel = alertLevelComponent.AlertLevels.Levels.Keys.First();
  54. }
  55. SetLevel(args.Station, defaultLevel, false, false, true);
  56. }
  57. private void OnPrototypeReload(PrototypesReloadedEventArgs args)
  58. {
  59. if (!args.ByType.TryGetValue(typeof(AlertLevelPrototype), out var alertPrototypes)
  60. || !alertPrototypes.Modified.TryGetValue(DefaultAlertLevelSet, out var alertObject)
  61. || alertObject is not AlertLevelPrototype alerts)
  62. {
  63. return;
  64. }
  65. var query = EntityQueryEnumerator<AlertLevelComponent>();
  66. while (query.MoveNext(out var uid, out var comp))
  67. {
  68. comp.AlertLevels = alerts;
  69. if (!comp.AlertLevels.Levels.ContainsKey(comp.CurrentLevel))
  70. {
  71. var defaultLevel = comp.AlertLevels.DefaultLevel;
  72. if (string.IsNullOrEmpty(defaultLevel))
  73. {
  74. defaultLevel = comp.AlertLevels.Levels.Keys.First();
  75. }
  76. SetLevel(uid, defaultLevel, true, true, true);
  77. }
  78. }
  79. RaiseLocalEvent(new AlertLevelPrototypeReloadedEvent());
  80. }
  81. public string GetLevel(EntityUid station, AlertLevelComponent? alert = null)
  82. {
  83. if (!Resolve(station, ref alert))
  84. {
  85. return string.Empty;
  86. }
  87. return alert.CurrentLevel;
  88. }
  89. public float GetAlertLevelDelay(EntityUid station, AlertLevelComponent? alert = null)
  90. {
  91. if (!Resolve(station, ref alert))
  92. {
  93. return float.NaN;
  94. }
  95. return alert.CurrentDelay;
  96. }
  97. /// <summary>
  98. /// Set the alert level based on the station's entity ID.
  99. /// </summary>
  100. /// <param name="station">Station entity UID.</param>
  101. /// <param name="level">Level to change the station's alert level to.</param>
  102. /// <param name="playSound">Play the alert level's sound.</param>
  103. /// <param name="announce">Say the alert level's announcement.</param>
  104. /// <param name="force">Force the alert change. This applies if the alert level is not selectable or not.</param>
  105. /// <param name="locked">Will it be possible to change level by crew.</param>
  106. public void SetLevel(EntityUid station, string level, bool playSound, bool announce, bool force = false,
  107. bool locked = false, MetaDataComponent? dataComponent = null, AlertLevelComponent? component = null)
  108. {
  109. if (!Resolve(station, ref component, ref dataComponent)
  110. || component.AlertLevels == null
  111. || !component.AlertLevels.Levels.TryGetValue(level, out var detail)
  112. || component.CurrentLevel == level)
  113. {
  114. return;
  115. }
  116. if (!force)
  117. {
  118. if (!detail.Selectable
  119. || component.CurrentDelay > 0
  120. || component.IsLevelLocked)
  121. {
  122. return;
  123. }
  124. component.CurrentDelay = _cfg.GetCVar(CCVars.GameAlertLevelChangeDelay);
  125. component.ActiveDelay = true;
  126. }
  127. component.CurrentLevel = level;
  128. component.IsLevelLocked = locked;
  129. var stationName = dataComponent.EntityName;
  130. var name = level.ToLower();
  131. if (Loc.TryGetString($"alert-level-{level}", out var locName))
  132. {
  133. name = locName.ToLower();
  134. }
  135. // Announcement text. Is passed into announcementFull.
  136. var announcement = detail.Announcement;
  137. if (Loc.TryGetString(detail.Announcement, out var locAnnouncement))
  138. {
  139. announcement = locAnnouncement;
  140. }
  141. // The full announcement to be spat out into chat.
  142. var announcementFull = Loc.GetString("alert-level-announcement", ("name", name), ("announcement", announcement));
  143. var playDefault = false;
  144. if (playSound)
  145. {
  146. if (detail.Sound != null)
  147. {
  148. var filter = _stationSystem.GetInOwningStation(station);
  149. _audio.PlayGlobal(detail.Sound, filter, true, detail.Sound.Params);
  150. }
  151. else
  152. {
  153. playDefault = true;
  154. }
  155. }
  156. if (announce)
  157. {
  158. _chatSystem.DispatchStationAnnouncement(station, announcementFull, playDefaultSound: playDefault,
  159. colorOverride: detail.Color, sender: stationName);
  160. }
  161. RaiseLocalEvent(new AlertLevelChangedEvent(station, level));
  162. }
  163. }
  164. public sealed class AlertLevelDelayFinishedEvent : EntityEventArgs
  165. {}
  166. public sealed class AlertLevelPrototypeReloadedEvent : EntityEventArgs
  167. {}
  168. public sealed class AlertLevelChangedEvent : EntityEventArgs
  169. {
  170. public EntityUid Station { get; }
  171. public string AlertLevel { get; }
  172. public AlertLevelChangedEvent(EntityUid station, string alertLevel)
  173. {
  174. Station = station;
  175. AlertLevel = alertLevel;
  176. }
  177. }