diff --git a/Content.Server/_DV/Station/Components/AutomaticSpareIdComponent.cs b/Content.Server/_DV/Station/Components/AutomaticSpareIdComponent.cs index edd88ce9da..05519fe1ef 100644 --- a/Content.Server/_DV/Station/Components/AutomaticSpareIdComponent.cs +++ b/Content.Server/_DV/Station/Components/AutomaticSpareIdComponent.cs @@ -13,6 +13,7 @@ public enum AutomaticSpareIdState AwaitingUnlock, Unlocked, CaptainPresent, + WarOps } [RegisterComponent, Access(typeof(AutomaticSpareIdSystem)), AutoGenerateComponentPause] @@ -38,9 +39,17 @@ public sealed partial class AutomaticSpareIdComponent : Component /// /// The access that the spare ID safe will be extended to have if it is automatically unlocked + /// if there is no captain /// [DataField] - public ProtoId GrantAccessTo = "Command"; + public ProtoId GrantAccessToCommand = "Command"; + + /// + /// The access that the spare ID safe will be extended to have if it is automatically unlocked + /// if there is a captain + /// + [DataField] + public ProtoId GrantAccessToCaptain = "Captain"; /// /// Message for when a Captain joins after the system has alerted about their absence @@ -65,4 +74,19 @@ public sealed partial class AutomaticSpareIdComponent : Component /// [DataField] public LocId UnlockedMessage = "no-captain-aa-unlocked-announcement"; + + /// + /// The amount of time in which that the spare ID will unlock after nuclear operatives declare war. + /// + public TimeSpan WarOpsUnlockDelay = TimeSpan.FromSeconds(15); + + /// + /// Message that will be displayed to the station when there is no captain and war ops is declared. + /// + public LocId WarOpsUnlockedMessageACO = "spare-id-warops-no-captain"; + + /// + /// Message that will be displayed to the station when there is a captain and war ops is declared. + /// + public LocId WarOpsUnlockedMessageCaptain = "spare-id-warops-captain"; } diff --git a/Content.Server/_DV/Station/Systems/AutomaticSpareIdSystem.cs b/Content.Server/_DV/Station/Systems/AutomaticSpareIdSystem.cs index 5ccbb24f5c..53e89eca2c 100644 --- a/Content.Server/_DV/Station/Systems/AutomaticSpareIdSystem.cs +++ b/Content.Server/_DV/Station/Systems/AutomaticSpareIdSystem.cs @@ -3,13 +3,16 @@ using Content.Server._DV.Cabinet; using Content.Server._DV.Station.Components; using Content.Server._DV.Station.Events; using Content.Server.Chat.Systems; +using Content.Server.NukeOps; using Content.Server.Station.Components; using Content.Shared._DV.CCVars; using Content.Shared.Access.Components; using Content.Shared.Access; +using Content.Shared.NukeOps; using Robust.Shared.Configuration; using Robust.Shared.Timing; using Robust.Shared.Utility; +using Robust.Shared.Prototypes; namespace Content.Server._DV.Station.Systems; @@ -30,6 +33,7 @@ public sealed class AutomaticSpareIdSystem : EntitySystem SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnPlayerJobAdded); SubscribeLocalEvent(OnPlayerJobsRemoved); + SubscribeLocalEvent(OnWarDeclared); Subs.CVar(_cfg, DCCVars.SpareIdAutoUnlock, a => _autoUnlock = a, true); Subs.CVar(_cfg, DCCVars.SpareIdAlertDelay, a => _alertDelay = a, true); @@ -63,6 +67,19 @@ public sealed class AutomaticSpareIdSystem : EntitySystem { MoveToUnlocked(ent); } + else if (ent.Comp.State is AutomaticSpareIdState.WarOps) + { + // Default to these, then check if there is a captain + var message = ent.Comp.WarOpsUnlockedMessageACO; + var accessGranted = ent.Comp.GrantAccessToCommand; + if (HasCaptain(ent)) + { + message = ent.Comp.WarOpsUnlockedMessageCaptain; + accessGranted = ent.Comp.GrantAccessToCaptain; + } + ent.Comp.State = AutomaticSpareIdState.AwaitingUnlock; + MoveToUnlocked(ent, accessGranted, message); + } else { DebugTools.Assert($"Spare ID state timed out with unexpected state {ent.Comp.State}"); @@ -102,6 +119,18 @@ public sealed class AutomaticSpareIdSystem : EntitySystem MoveToAlerted(ent); } + private void OnWarDeclared(ref WarDeclaredEvent args) + { + if (args.Status == WarConditionStatus.YesWar) + { + foreach (var spareId in EntityQuery()) + { + spareId.Timeout = _timing.CurTime + spareId.WarOpsUnlockDelay; + spareId.State = AutomaticSpareIdState.WarOps; + } + } + } + private bool HasCaptain(Entity ent) { if (!TryComp(ent, out var stationJobs)) @@ -120,7 +149,13 @@ public sealed class AutomaticSpareIdSystem : EntitySystem _chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.AwaitingUnlockMessage, ("minutes", _unlockDelay.TotalMinutes)), colorOverride: Color.Gold); } - private void MoveToUnlocked(Entity ent) + /// + /// Unlocks all spare ID cabinets, giving access to a certain access prototype and displays a message to the station. + /// + /// The station entity that has the . + /// The access to give to the spare ID cabinet. If not specified or null, will default to ent.Comp.GrantAccessToCommand + /// The message to display to the station upon unlocking the spare ID. If not specified or null, will default to ent.Comp.UnlockedMessage + private void MoveToUnlocked(Entity ent, ProtoId? newSpareIdAccess = null, LocId? unlockMessageLocId = null) { DebugTools.Assert(ent.Comp.State is AutomaticSpareIdState.AwaitingUnlock, $"Spare ID state has unexpected state {ent.Comp.State} on unlocking"); @@ -134,12 +169,18 @@ public sealed class AutomaticSpareIdSystem : EntitySystem if (accesses.Count <= 0) continue; - accesses.Add([ent.Comp.GrantAccessTo]); + if (!newSpareIdAccess.HasValue) + newSpareIdAccess = ent.Comp.GrantAccessToCommand; // Default to command if no access is specified + + accesses.Add([newSpareIdAccess.Value]); Dirty(uid, accessReader); RaiseLocalEvent(uid, new AccessReaderConfigurationChangedEvent()); } - _chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.UnlockedMessage), colorOverride: Color.Red); + if (!unlockMessageLocId.HasValue) + unlockMessageLocId = ent.Comp.UnlockedMessage; // Default message if nothing is specified + + _chat.DispatchStationAnnouncement(ent, Loc.GetString(unlockMessageLocId), colorOverride: Color.Red); } private void MoveToCaptainPresent(Entity ent) diff --git a/Resources/Locale/en-US/_DV/job/captain-state.ftl b/Resources/Locale/en-US/_DV/job/captain-state.ftl index 1fb0b144c7..fda851f812 100644 --- a/Resources/Locale/en-US/_DV/job/captain-state.ftl +++ b/Resources/Locale/en-US/_DV/job/captain-state.ftl @@ -4,3 +4,6 @@ captain-arrived-revoke-aco-announcement = The Acting Commanding Officer's positi no-captain-request-aco-vote-with-aa-announcement = Station records indicate that no captain is currently present. Command personnel are requested to nominate an Acting Commanding Officer and report the results to Central Command in accordance with Standard Operating Procedure. Emergency AA will be unlocked in {$minutes} minutes to ensure continued operational efficiency. no-captain-request-aco-vote-announcement = Station records indicate that no captain is currently present. Command personnel are requested to nominate an Acting Commanding Officer and report the results to Central Command in accordance with Standard Operating Procedure. no-captain-aa-unlocked-announcement = Command access authority has been granted to the Spare ID cabinet for use by the Acting Commanding Officer. Unauthorized possession of Emergency AA is punishable under Grand Felony Offense [307]: Grand Larceny. + +spare-id-warops-no-captain = Due to the current circumstances, command has been granted to the Spare ID cabinet for use by the Acting Commanding Officer. Ensure the spare ID remains secure. Unauthorized possession of Emergency AA is punishable under Grand Felony Offense [307]: Grand Larceny. +spare-id-warops-captain = Due to the current circumstances, access has been granted to the Spare ID cabinet for use by the Captain. Ensure the spare ID remains secure. Unauthorized possession of Emergency AA is punishable under Grand Felony Offense [307]: Grand Larceny.