SalvageSystem.Runner.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using System.Numerics;
  2. using Content.Server.Salvage.Expeditions;
  3. using Content.Server.Shuttles.Components;
  4. using Content.Server.Shuttles.Events;
  5. using Content.Server.Station.Components;
  6. using Content.Shared.Chat;
  7. using Content.Shared.Humanoid;
  8. using Content.Shared.Mobs.Components;
  9. using Content.Shared.Mobs.Systems;
  10. using Content.Shared.Salvage.Expeditions;
  11. using Content.Shared.Shuttles.Components;
  12. using Content.Shared.Localizations;
  13. using Robust.Shared.Map.Components;
  14. using Robust.Shared.Player;
  15. namespace Content.Server.Salvage;
  16. public sealed partial class SalvageSystem
  17. {
  18. /*
  19. * Handles actively running a salvage expedition.
  20. */
  21. [Dependency] private readonly MobStateSystem _mobState = default!;
  22. private void InitializeRunner()
  23. {
  24. SubscribeLocalEvent<FTLRequestEvent>(OnFTLRequest);
  25. SubscribeLocalEvent<FTLStartedEvent>(OnFTLStarted);
  26. SubscribeLocalEvent<FTLCompletedEvent>(OnFTLCompleted);
  27. SubscribeLocalEvent<ConsoleFTLAttemptEvent>(OnConsoleFTLAttempt);
  28. }
  29. private void OnConsoleFTLAttempt(ref ConsoleFTLAttemptEvent ev)
  30. {
  31. if (!TryComp(ev.Uid, out TransformComponent? xform) ||
  32. !TryComp<SalvageExpeditionComponent>(xform.MapUid, out var salvage))
  33. {
  34. return;
  35. }
  36. // TODO: This is terrible but need bluespace harnesses or something.
  37. var query = EntityQueryEnumerator<HumanoidAppearanceComponent, MobStateComponent, TransformComponent>();
  38. while (query.MoveNext(out var uid, out _, out var mobState, out var mobXform))
  39. {
  40. if (mobXform.MapUid != xform.MapUid)
  41. continue;
  42. // Don't count unidentified humans (loot) or anyone you murdered so you can still maroon them once dead.
  43. if (_mobState.IsDead(uid, mobState))
  44. continue;
  45. // Okay they're on salvage, so are they on the shuttle.
  46. if (mobXform.GridUid != ev.Uid)
  47. {
  48. ev.Cancelled = true;
  49. ev.Reason = Loc.GetString("salvage-expedition-not-all-present");
  50. return;
  51. }
  52. }
  53. }
  54. /// <summary>
  55. /// Announces status updates to salvage crewmembers on the state of the expedition.
  56. /// </summary>
  57. private void Announce(EntityUid mapUid, string text)
  58. {
  59. var mapId = Comp<MapComponent>(mapUid).MapId;
  60. // I love TComms and chat!!!
  61. _chat.ChatMessageToManyFiltered(
  62. Filter.BroadcastMap(mapId),
  63. ChatChannel.Radio,
  64. text,
  65. text,
  66. _mapManager.GetMapEntityId(mapId),
  67. false,
  68. true,
  69. null);
  70. }
  71. private void OnFTLRequest(ref FTLRequestEvent ev)
  72. {
  73. if (!HasComp<SalvageExpeditionComponent>(ev.MapUid) ||
  74. !TryComp<FTLDestinationComponent>(ev.MapUid, out var dest))
  75. {
  76. return;
  77. }
  78. // Only one shuttle can occupy an expedition.
  79. dest.Enabled = false;
  80. _shuttleConsoles.RefreshShuttleConsoles();
  81. }
  82. private void OnFTLCompleted(ref FTLCompletedEvent args)
  83. {
  84. if (!TryComp<SalvageExpeditionComponent>(args.MapUid, out var component))
  85. return;
  86. // Someone FTLd there so start announcement
  87. if (component.Stage != ExpeditionStage.Added)
  88. return;
  89. Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", (component.EndTime - _timing.CurTime).Minutes)));
  90. var directionLocalization = ContentLocalizationManager.FormatDirection(component.DungeonLocation.GetDir()).ToLower();
  91. if (component.DungeonLocation != Vector2.Zero)
  92. Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-dungeon", ("direction", directionLocalization)));
  93. component.Stage = ExpeditionStage.Running;
  94. Dirty(args.MapUid, component);
  95. }
  96. private void OnFTLStarted(ref FTLStartedEvent ev)
  97. {
  98. if (!TryComp<SalvageExpeditionComponent>(ev.FromMapUid, out var expedition) ||
  99. !TryComp<SalvageExpeditionDataComponent>(expedition.Station, out var station))
  100. {
  101. return;
  102. }
  103. // Check if any shuttles remain.
  104. var query = EntityQueryEnumerator<ShuttleComponent, TransformComponent>();
  105. while (query.MoveNext(out _, out var xform))
  106. {
  107. if (xform.MapUid == ev.FromMapUid)
  108. return;
  109. }
  110. // Last shuttle has left so finish the mission.
  111. QueueDel(ev.FromMapUid.Value);
  112. }
  113. // Runs the expedition
  114. private void UpdateRunner()
  115. {
  116. // Generic missions
  117. var query = EntityQueryEnumerator<SalvageExpeditionComponent>();
  118. // Run the basic mission timers (e.g. announcements, auto-FTL, completion, etc)
  119. while (query.MoveNext(out var uid, out var comp))
  120. {
  121. var remaining = comp.EndTime - _timing.CurTime;
  122. var audioLength = _audio.GetAudioLength(comp.SelectedSong);
  123. if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(45))
  124. {
  125. comp.Stage = ExpeditionStage.FinalCountdown;
  126. Dirty(uid, comp);
  127. Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-seconds", ("duration", TimeSpan.FromSeconds(45).Seconds)));
  128. }
  129. else if (comp.Stream == null && remaining < audioLength)
  130. {
  131. var audio = _audio.PlayPvs(comp.Sound, uid);
  132. comp.Stream = audio?.Entity;
  133. _audio.SetMapAudio(audio);
  134. comp.Stage = ExpeditionStage.MusicCountdown;
  135. Dirty(uid, comp);
  136. Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", audioLength.Minutes)));
  137. }
  138. else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(4))
  139. {
  140. comp.Stage = ExpeditionStage.Countdown;
  141. Dirty(uid, comp);
  142. Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(5).Minutes)));
  143. }
  144. // Auto-FTL out any shuttles
  145. else if (remaining < TimeSpan.FromSeconds(_shuttle.DefaultStartupTime) + TimeSpan.FromSeconds(0.5))
  146. {
  147. var ftlTime = (float) remaining.TotalSeconds;
  148. if (remaining < TimeSpan.FromSeconds(_shuttle.DefaultStartupTime))
  149. {
  150. ftlTime = MathF.Max(0, (float) remaining.TotalSeconds - 0.5f);
  151. }
  152. ftlTime = MathF.Min(ftlTime, _shuttle.DefaultStartupTime);
  153. var shuttleQuery = AllEntityQuery<ShuttleComponent, TransformComponent>();
  154. if (TryComp<StationDataComponent>(comp.Station, out var data))
  155. {
  156. foreach (var member in data.Grids)
  157. {
  158. while (shuttleQuery.MoveNext(out var shuttleUid, out var shuttle, out var shuttleXform))
  159. {
  160. if (shuttleXform.MapUid != uid || HasComp<FTLComponent>(shuttleUid))
  161. continue;
  162. _shuttle.FTLToDock(shuttleUid, shuttle, member, ftlTime);
  163. }
  164. break;
  165. }
  166. }
  167. }
  168. if (remaining < TimeSpan.Zero)
  169. {
  170. QueueDel(uid);
  171. }
  172. }
  173. }
  174. }