diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index 1be2fec643..356eb52843 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -1,6 +1,7 @@ using System.Threading; using Content.Server.Administration.Logs; using Content.Server.AlertLevel; +using Content.Shared.CCVar; using Content.Server.Chat; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; @@ -10,6 +11,7 @@ using Content.Server.Station.Systems; using Content.Shared.Database; using Content.Shared.GameTicking; using Robust.Shared.Audio; +using Robust.Shared.Configuration; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -24,6 +26,7 @@ namespace Content.Server.RoundEnd public sealed class RoundEndSystem : EntitySystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IPrototypeManager _protoManager = default!; @@ -47,10 +50,19 @@ namespace Content.Server.RoundEnd public TimeSpan? ExpectedShuttleLength => ExpectedCountdownEnd - LastCountdownStart; public TimeSpan? ShuttleTimeLeft => ExpectedCountdownEnd - _gameTiming.CurTime; + public TimeSpan AutoCallStartTime; + private bool AutoCalledBefore = false; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(_ => Reset()); + SetAutoCallTime(); + } + + private void SetAutoCallTime() + { + AutoCallStartTime = _gameTiming.CurTime; } private void Reset() @@ -69,6 +81,8 @@ namespace Content.Server.RoundEnd LastCountdownStart = null; ExpectedCountdownEnd = null; + SetAutoCallTime(); + AutoCalledBefore = false; RaiseLocalEvent(RoundEndSystemChangedEvent.Default); } @@ -77,7 +91,7 @@ namespace Content.Server.RoundEnd return _cooldownTokenSource == null; } - public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true) + public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, bool autoCall = false) { var duration = DefaultCountdownDuration; @@ -92,10 +106,10 @@ namespace Content.Server.RoundEnd } } - RequestRoundEnd(duration, requester, checkCooldown); + RequestRoundEnd(duration, requester, checkCooldown, autoCall); } - public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true) + public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, bool autoCall = false) { if (_gameTicker.RunLevel != GameRunLevel.InRound) return; @@ -128,13 +142,26 @@ namespace Content.Server.RoundEnd units = "eta-units-minutes"; } - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement", - ("time", time), - ("units", Loc.GetString(units))), - Loc.GetString("Station"), - false, - null, - Color.Gold); + if (autoCall) + { + _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-auto-called-announcement", + ("time", time), + ("units", Loc.GetString(units))), + Loc.GetString("Station"), + false, + null, + Color.Gold); + } + else + { + _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement", + ("time", time), + ("units", Loc.GetString(units))), + Loc.GetString("Station"), + false, + null, + Color.Gold); + } SoundSystem.Play("/Audio/Announcements/shuttlecalled.ogg", Filter.Broadcast()); @@ -206,6 +233,24 @@ namespace Content.Server.RoundEnd RaiseLocalEvent(RoundEndSystemChangedEvent.Default); }, _cooldownTokenSource.Token); } + + public override void Update(float frameTime) + { + // Check if we should auto-call. + int mins = AutoCalledBefore ? _cfg.GetCVar(CCVars.EmergencyShuttleAutoCallExtensionTime) + : _cfg.GetCVar(CCVars.EmergencyShuttleAutoCallTime); + if (mins != 0 && _gameTiming.CurTime - AutoCallStartTime > TimeSpan.FromMinutes(mins)) + { + if (!_shuttle.EmergencyShuttleArrived && ExpectedCountdownEnd is null) + { + RequestRoundEnd(null, false, true); + AutoCalledBefore = true; + } + + // Always reset auto-call in case of a recall. + SetAutoCallTime(); + } + } } public sealed class RoundEndSystemChangedEvent : EntityEventArgs diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 8668c58c42..0b897425b5 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -1028,6 +1028,19 @@ namespace Content.Shared.CCVar public static readonly CVarDef EmergencyRecallTurningPoint = CVarDef.Create("shuttle.recall_turning_point", 0.5f, CVar.SERVERONLY); + /// + /// Time in minutes after round start to auto-call the shuttle. Set to zero to disable. + /// + public static readonly CVarDef EmergencyShuttleAutoCallTime = + CVarDef.Create("shuttle.auto_call_time", 90, CVar.SERVERONLY); + + /// + /// Time in minutes after the round was extended (by recalling the shuttle) to call + /// the shuttle again. + /// + public static readonly CVarDef EmergencyShuttleAutoCallExtensionTime = + CVarDef.Create("shuttle.auto_call_extension_time", 45, CVar.SERVERONLY); + /// /// The map to load for CentCom for the emergency shuttle to dock to. /// diff --git a/Resources/Locale/en-US/round-end/round-end-system.ftl b/Resources/Locale/en-US/round-end/round-end-system.ftl index 9c349e1d86..7f4d5b0fff 100644 --- a/Resources/Locale/en-US/round-end/round-end-system.ftl +++ b/Resources/Locale/en-US/round-end/round-end-system.ftl @@ -1,6 +1,7 @@ ## RoundEndSystem round-end-system-shuttle-called-announcement = An emergency shuttle has been sent. ETA: {$time} {$units}. +round-end-system-shuttle-auto-called-announcement = An automatic crew shift change shuttle has been sent. ETA: {$time} {$units}. Recall the shuttle to extend the shift. round-end-system-shuttle-recalled-announcement = The emergency shuttle has been recalled. round-end-system-round-restart-eta-announcement = Restarting the round in {$minutes} minutes...