Delta-v/Content.Server/_DV/Station/Systems/AutomaticSpareIdSystem.cs

209 lines
8.0 KiB
C#

using System.Linq;
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;
public sealed class AutomaticSpareIdSystem : EntitySystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private bool _autoUnlock;
private TimeSpan _alertDelay;
private TimeSpan _unlockDelay;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AutomaticSpareIdComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<AutomaticSpareIdComponent, PlayerJobAddedEvent>(OnPlayerJobAdded);
SubscribeLocalEvent<AutomaticSpareIdComponent, PlayerJobsRemovedEvent>(OnPlayerJobsRemoved);
SubscribeLocalEvent<WarDeclaredEvent>(OnWarDeclared);
Subs.CVar(_cfg, DCCVars.SpareIdAutoUnlock, a => _autoUnlock = a, true);
Subs.CVar(_cfg, DCCVars.SpareIdAlertDelay, a => _alertDelay = a, true);
Subs.CVar(_cfg, DCCVars.SpareIdUnlockDelay, a => _unlockDelay = a, true);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<AutomaticSpareIdComponent>();
while (query.MoveNext(out var station, out var spareId))
{
if (spareId.Timeout is { } timeout && _timing.CurTime > timeout)
{
Timeout((station, spareId));
}
}
}
private void Timeout(Entity<AutomaticSpareIdComponent> ent)
{
if (ent.Comp.State is AutomaticSpareIdState.RoundStart)
{
if (HasCaptain(ent))
RoundStartCaptain(ent);
else
RoundStartNoCaptain(ent);
}
else if (ent.Comp.State is AutomaticSpareIdState.AwaitingUnlock)
{
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}");
}
}
private void RoundStartNoCaptain(Entity<AutomaticSpareIdComponent> ent)
{
if (_autoUnlock)
MoveToAwaitingUnlock(ent);
else
MoveToAlerted(ent);
}
private static void RoundStartCaptain(Entity<AutomaticSpareIdComponent> ent)
{
ent.Comp.State = AutomaticSpareIdState.CaptainPresent;
ent.Comp.Timeout = null;
}
private void OnMapInit(Entity<AutomaticSpareIdComponent> ent, ref MapInitEvent args)
{
ent.Comp.Timeout = _timing.CurTime + _alertDelay;
}
private void OnPlayerJobAdded(Entity<AutomaticSpareIdComponent> ent, ref PlayerJobAddedEvent args)
{
if (args.JobPrototypeId == ent.Comp.CaptainJob)
MoveToCaptainPresent(ent);
}
private void OnPlayerJobsRemoved(Entity<AutomaticSpareIdComponent> ent, ref PlayerJobsRemovedEvent args)
{
if (!args.PlayerJobs.Contains(ent.Comp.CaptainJob) || HasCaptain(ent))
return;
MoveToAlerted(ent);
}
private void OnWarDeclared(ref WarDeclaredEvent args)
{
if (args.Status == WarConditionStatus.YesWar)
{
foreach (var spareId in EntityQuery<AutomaticSpareIdComponent>())
{
spareId.Timeout = _timing.CurTime + spareId.WarOpsUnlockDelay;
spareId.State = AutomaticSpareIdState.WarOps;
}
}
}
private bool HasCaptain(Entity<AutomaticSpareIdComponent> ent)
{
if (!TryComp<StationJobsComponent>(ent, out var stationJobs))
return false;
return stationJobs.PlayerJobs.Any(playerJobs => playerJobs.Value.Contains(ent.Comp.CaptainJob));
}
private void MoveToAwaitingUnlock(Entity<AutomaticSpareIdComponent> ent)
{
DebugTools.Assert(ent.Comp.State is AutomaticSpareIdState.RoundStart, $"Spare ID state has unexpected state {ent.Comp.State} on awaiting to unlock");
ent.Comp.State = AutomaticSpareIdState.AwaitingUnlock;
ent.Comp.Timeout = _timing.CurTime + _unlockDelay;
_chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.AwaitingUnlockMessage, ("minutes", _unlockDelay.TotalMinutes)), colorOverride: Color.Gold);
}
/// <summary>
/// Unlocks all spare ID cabinets, giving access to a certain access prototype and displays a message to the station.
/// </summary>
/// <param name="ent">The station entity that has the <see cref="AutomaticSpareIdComponent"/>.</param>
/// <param name="newSpareIdAccess">The access to give to the spare ID cabinet. If not specified or null, will default to ent.Comp.GrantAccessToCommand</param>
/// <param name="unlockMessageLocId">The message to display to the station upon unlocking the spare ID. If not specified or null, will default to ent.Comp.UnlockedMessage</param>
private void MoveToUnlocked(Entity<AutomaticSpareIdComponent> ent, ProtoId<AccessLevelPrototype>? newSpareIdAccess = null, LocId? unlockMessageLocId = null)
{
DebugTools.Assert(ent.Comp.State is AutomaticSpareIdState.AwaitingUnlock, $"Spare ID state has unexpected state {ent.Comp.State} on unlocking");
ent.Comp.State = AutomaticSpareIdState.Unlocked;
ent.Comp.Timeout = null;
var query = EntityQueryEnumerator<SpareIDSafeComponent, AccessReaderComponent>();
while (query.MoveNext(out var uid, out _, out var accessReader))
{
var accesses = accessReader.AccessLists;
if (accesses.Count <= 0)
continue;
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());
}
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<AutomaticSpareIdComponent> ent)
{
if (!(ent.Comp.State is AutomaticSpareIdState.Alerted or AutomaticSpareIdState.AwaitingUnlock or AutomaticSpareIdState.Unlocked))
{
return;
}
ent.Comp.State = AutomaticSpareIdState.CaptainPresent;
ent.Comp.Timeout = null;
_chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.CaptainPresentAfterAlertsMessage), colorOverride: Color.Gold);
}
private void MoveToAlerted(Entity<AutomaticSpareIdComponent> ent)
{
DebugTools.Assert(ent.Comp.State is AutomaticSpareIdState.RoundStart or AutomaticSpareIdState.CaptainPresent, $"Spare ID state has unexpected state {ent.Comp.State} on moving to alerted");
ent.Comp.State = AutomaticSpareIdState.Alerted;
ent.Comp.Timeout = null;
_chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.AlertedMessage), colorOverride: Color.Gold);
}
}