Give nukies the ability to declare war for a TC boost (#19291)

Co-authored-by: Kevin Zheng <kevinz5000@gmail.com>
This commit is contained in:
Morb
2023-08-30 10:56:20 +03:00
committed by GitHub
parent 5bb6a64dbd
commit c99e365ce7
23 changed files with 831 additions and 18 deletions

View File

@@ -1,9 +1,7 @@
using System.Globalization;
using System.Linq;
using Content.Server.Access.Systems;
using Content.Server.Administration.Logs;
using Content.Server.AlertLevel;
using Content.Server.Chat;
using Content.Server.Chat.Systems;
using Content.Server.Interaction;
using Content.Server.Popups;
@@ -16,11 +14,9 @@ using Content.Shared.CCVar;
using Content.Shared.Communications;
using Content.Shared.Database;
using Content.Shared.Emag.Components;
using Content.Shared.Examine;
using Content.Shared.Popups;
using Robust.Server.GameObjects;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
namespace Content.Server.Communications
{
@@ -262,6 +258,9 @@ namespace Content.Server.Communications
comp.AnnouncementCooldownRemaining = comp.DelayBetweenAnnouncements;
UpdateCommsConsoleInterface(uid, comp);
var ev = new CommunicationConsoleAnnouncementEvent(uid, comp, msg, message.Session.AttachedEntity);
RaiseLocalEvent(ref ev);
// allow admemes with vv
Loc.TryGetString(comp.AnnouncementDisplayName, out var title);
title ??= comp.AnnouncementDisplayName;
@@ -291,6 +290,15 @@ namespace Content.Server.Communications
_popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Session);
return;
}
var ev = new CommunicationConsoleCallShuttleAttemptEvent(uid, comp, mob);
RaiseLocalEvent(ref ev);
if (ev.Cancelled)
{
_popupSystem.PopupEntity(ev.Reason ?? Loc.GetString("comms-console-shuttle-unavailable"), uid, message.Session);
return;
}
_roundEndSystem.RequestRoundEnd(uid);
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(mob):player} has called the shuttle.");
}
@@ -309,4 +317,29 @@ namespace Content.Server.Communications
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(mob):player} has recalled the shuttle.");
}
}
/// <summary>
/// Raised on announcement
/// </summary>
[ByRefEvent]
public record struct CommunicationConsoleAnnouncementEvent(EntityUid Uid, CommunicationsConsoleComponent Component, string Text, EntityUid? Sender)
{
public EntityUid Uid = Uid;
public CommunicationsConsoleComponent Component = Component;
public EntityUid? Sender = Sender;
public string Text = Text;
}
/// <summary>
/// Raised on shuttle call attempt. Can be cancelled
/// </summary>
[ByRefEvent]
public record struct CommunicationConsoleCallShuttleAttemptEvent(EntityUid Uid, CommunicationsConsoleComponent Component, EntityUid? Sender)
{
public bool Cancelled = false;
public EntityUid Uid = Uid;
public CommunicationsConsoleComponent Component = Component;
public EntityUid? Sender = Sender;
public string? Reason;
}
}

View File

@@ -104,6 +104,7 @@ public sealed partial class GameTicker
_sawmill.Info($"Started game rule {ToPrettyString(ruleEntity)}");
ruleData.Active = true;
ruleData.ActivatedAt = _gameTiming.CurTime;
var ev = new GameRuleStartedEvent(ruleEntity, id);
RaiseLocalEvent(ruleEntity, ref ev, true);
return true;

View File

@@ -1,4 +1,6 @@
namespace Content.Server.GameTicking.Rules.Components;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.GameTicking.Rules.Components;
/// <summary>
/// Component attached to all gamerule entities.
@@ -14,6 +16,12 @@ public sealed partial class GameRuleComponent : Component
[DataField("active")]
public bool Active;
/// <summary>
/// Game time when game rule was activated
/// </summary>
[DataField("activatedAt", customTypeSerializer:typeof(TimeOffsetSerializer))]
public TimeSpan ActivatedAt;
/// <summary>
/// Whether or not the gamerule finished.
/// Used for tracking whether a non-active gamerule has been started before.

View File

@@ -0,0 +1,9 @@
namespace Content.Server.GameTicking.Rules.Components;
/// <summary>
/// Tags grid as nuke ops shuttle
/// </summary>
[RegisterComponent]
public sealed partial class NukeOpsShuttleComponent : Component
{
}

View File

@@ -1,15 +1,13 @@
using Content.Server.NPC.Components;
using Content.Server.StationEvents.Events;
using Content.Shared.Dataset;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Roles;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
using Robust.Shared.Utility;
namespace Content.Server.GameTicking.Rules.Components;
@@ -44,6 +42,48 @@ public sealed partial class NukeopsRuleComponent : Component
[DataField("spawnOutpost")]
public bool SpawnOutpost = true;
/// <summary>
/// Whether or not nukie left their outpost
/// </summary>
[DataField("leftOutpost")]
public bool LeftOutpost = false;
/// <summary>
/// Enables opportunity to get extra TC for war declaration
/// </summary>
[DataField("canEnableWarOps")]
public bool CanEnableWarOps = true;
/// <summary>
/// Indicates time when war has been declared, null if not declared
/// </summary>
[DataField("warDeclaredTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan? WarDeclaredTime;
/// <summary>
/// This amount of TC will be given to each nukie
/// </summary>
[DataField("warTCAmountPerNukie")]
public int WarTCAmountPerNukie = 40;
/// <summary>
/// Time allowed for declaration of war
/// </summary>
[DataField("warDeclarationDelay")]
public TimeSpan WarDeclarationDelay = TimeSpan.FromMinutes(6);
/// <summary>
/// Delay between war declaration and nuke ops arrival on station map. Gives crew time to prepare
/// </summary>
[DataField("warNukieArriveDelay")]
public TimeSpan? WarNukieArriveDelay = TimeSpan.FromMinutes(15);
/// <summary>
/// Minimal operatives count for war declaration
/// </summary>
[DataField("warDeclarationMinOps")]
public int WarDeclarationMinOps = 4;
[DataField("spawnPointProto", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string SpawnPointPrototype = "SpawnPointNukies";

View File

@@ -1,7 +1,10 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using Content.Server.Administration.Commands;
using Content.Server.Chat.Managers;
using Content.Server.Chat.Systems;
using Content.Server.Communications;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Ghost.Roles.Events;
@@ -11,30 +14,40 @@ using Content.Server.Mind.Components;
using Content.Server.NPC.Components;
using Content.Server.NPC.Systems;
using Content.Server.Nuke;
using Content.Server.NukeOps;
using Content.Server.Popups;
using Content.Server.Preferences.Managers;
using Content.Server.Roles;
using Content.Server.RoundEnd;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Shuttles.Systems;
using Content.Server.Spawners.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.Store.Components;
using Content.Server.Store.Systems;
using Content.Shared.Dataset;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Nuke;
using Content.Shared.NukeOps;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Content.Shared.Store;
using Content.Shared.Tag;
using Content.Shared.Zombies;
using Robust.Server.GameObjects;
using Robust.Server.Maps;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.GameTicking.Rules;
@@ -58,6 +71,18 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly RoleSystem _roles = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly StoreSystem _storeSystem = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly WarDeclaratorSystem _warDeclaratorSystem = default!;
[ValidatePrototypeId<CurrencyPrototype>]
private const string TelecrystalCurrencyPrototype = "Telecrystal";
[ValidatePrototypeId<TagPrototype>]
private const string NukeOpsUplinkTagPrototype = "NukeOpsUplink";
[ValidatePrototypeId<AntagPrototype>]
public const string NukeopsId = "Nukeops";
@@ -78,6 +103,119 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
SubscribeLocalEvent<NukeOperativeComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<NukeOperativeComponent, ComponentRemove>(OnComponentRemove);
SubscribeLocalEvent<NukeOperativeComponent, EntityZombifiedEvent>(OnOperativeZombified);
SubscribeLocalEvent<CommunicationConsoleCallShuttleAttemptEvent>(OnShuttleCallAttempt);
SubscribeLocalEvent<ShuttleConsoleFTLTravelStartEvent>(OnShuttleConsoleFTLStart);
SubscribeLocalEvent<ConsoleFTLAttemptEvent>(OnShuttleFTLAttempt);
}
/// <summary>
/// Returns true when the player with UID opUid is a nuclear operative. Prevents random
/// people from using the war declarator outside of the game mode.
/// </summary>
public bool TryGetRuleFromOperative(EntityUid opUid, [NotNullWhen(true)] out (NukeopsRuleComponent, GameRuleComponent)? comps)
{
comps = null;
var query = EntityQueryEnumerator<NukeopsRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEnt, out var nukeops, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEnt, gameRule))
continue;
var found = nukeops.OperativePlayers.Values.Any(v => v.AttachedEntity == opUid);
if (found)
{
comps = (nukeops, gameRule);
return true;
}
}
return false;
}
/// <summary>
/// Search rule components by grid uid
/// </summary>
public bool TryGetRuleFromGrid(EntityUid gridId, [NotNullWhen(true)] out (NukeopsRuleComponent, GameRuleComponent)? comps)
{
comps = null;
var query = EntityQueryEnumerator<NukeopsRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEnt, out var nukeops, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEnt, gameRule))
continue;
if (gridId == nukeops.NukieShuttle || gridId == nukeops.NukieOutpost)
{
comps = (nukeops, gameRule);
return true;
}
}
return false;
}
/// <summary>
/// Returns conditions for war declaration
/// </summary>
public WarConditionStatus GetWarCondition(NukeopsRuleComponent nukieRule, GameRuleComponent gameRule)
{
if (!nukieRule.CanEnableWarOps)
return WarConditionStatus.NO_WAR_UNKNOWN;
if (nukieRule.WarDeclaredTime != null && nukieRule.WarNukieArriveDelay != null)
{
// Nukies must wait some time after declaration of war to get on the station
var warTime = _gameTiming.CurTime.Subtract(nukieRule.WarDeclaredTime.Value);
if (warTime > nukieRule.WarNukieArriveDelay)
{
return WarConditionStatus.WAR_READY;
}
return WarConditionStatus.WAR_DELAY;
}
if (nukieRule.OperativePlayers.Count < nukieRule.WarDeclarationMinOps)
return WarConditionStatus.NO_WAR_SMALL_CREW;
if (nukieRule.LeftOutpost)
return WarConditionStatus.NO_WAR_SHUTTLE_DEPARTED;
var gameruleTime = _gameTiming.CurTime.Subtract(gameRule.ActivatedAt);
if (gameruleTime > nukieRule.WarDeclarationDelay)
return WarConditionStatus.NO_WAR_TIMEOUT;
return WarConditionStatus.YES_WAR;
}
public void DeclareWar(EntityUid opsUid, string msg, string title, SoundSpecifier? announcementSound = null, Color? colorOverride = null)
{
if (!TryGetRuleFromOperative(opsUid, out var comps))
return;
var nukieRule = comps.Value.Item1;
nukieRule.WarDeclaredTime = _gameTiming.CurTime;
_chatSystem.DispatchGlobalAnnouncement(msg, title, announcementSound: announcementSound, colorOverride: colorOverride);
DistributeExtraTC(nukieRule);
_warDeclaratorSystem.RefreshAllUI(comps.Value.Item1, comps.Value.Item2);
}
private void DistributeExtraTC(NukeopsRuleComponent nukieRule)
{
var enumerator = EntityQueryEnumerator<StoreComponent>();
while (enumerator.MoveNext(out var uid, out var component))
{
if (!_tag.HasTag(uid, NukeOpsUplinkTagPrototype))
continue;
if (!nukieRule.NukieOutpost.HasValue)
continue;
if (Transform(uid).MapID != Transform(nukieRule.NukieOutpost.Value).MapID) // Will receive bonus TC only on their start outpost
continue;
_storeSystem.TryAddCurrency(new () { { TelecrystalCurrencyPrototype, nukieRule.WarTCAmountPerNukie } }, uid, component);
var msg = Loc.GetString("store-currency-war-boost-given", ("target", uid));
_popupSystem.PopupEntity(msg, uid);
}
}
private void OnComponentInit(EntityUid uid, NukeOperativeComponent component, ComponentInit args)
@@ -597,7 +735,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
if (!_mindSystem.TryGetMind(uid, out var mindId, out var mind))
return;
foreach (var nukeops in EntityQuery<NukeopsRuleComponent>())
foreach (var (nukeops, gameRule) in EntityQuery<NukeopsRuleComponent, GameRuleComponent>())
{
if (nukeops.OperativeMindPendingData.TryGetValue(uid, out var role) || !nukeops.SpawnOutpost || !nukeops.EndsRound)
{
@@ -615,6 +753,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
var name = MetaData(uid).EntityName;
nukeops.OperativePlayers.Add(name, playerSession);
_warDeclaratorSystem.RefreshAllUI(nukeops, gameRule);
if (GameTicker.RunLevel != GameRunLevel.InRound)
return;
@@ -680,6 +819,8 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
_shuttle.TryFTLDock(shuttleId, shuttle, component.NukieOutpost.Value);
}
AddComp<NukeOpsShuttleComponent>(shuttleId);
component.NukiePlanet = mapId;
component.NukieShuttle = shuttleId;
return true;
@@ -856,6 +997,81 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
}
}
private void OnShuttleFTLAttempt(ref ConsoleFTLAttemptEvent ev)
{
var query = EntityQueryEnumerator<NukeopsRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleUid, out var nukeops, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleUid, gameRule))
continue;
if (nukeops.NukieOutpost == null ||
nukeops.WarDeclaredTime == null ||
nukeops.WarNukieArriveDelay == null ||
ev.Uid != nukeops.NukieShuttle)
continue;
var mapOutpost = Transform(nukeops.NukieOutpost.Value).MapID;
var mapShuttle = Transform(ev.Uid).MapID;
if (mapOutpost == mapShuttle)
{
var timeAfterDeclaration = _gameTiming.CurTime.Subtract(nukeops.WarDeclaredTime.Value);
var timeRemain = nukeops.WarNukieArriveDelay.Value.Subtract(timeAfterDeclaration);
if (timeRemain > TimeSpan.Zero)
{
ev.Cancelled = true;
ev.Reason = Loc.GetString("war-ops-infiltrator-unavailable", ("minutes", timeRemain.Minutes), ("seconds", timeRemain.Seconds));
}
}
}
}
private void OnShuttleConsoleFTLStart(ref ShuttleConsoleFTLTravelStartEvent ev)
{
var query = EntityQueryEnumerator<NukeopsRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleUid, out var nukeops, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleUid, gameRule))
continue;
var gridUid = Transform(ev.Uid).GridUid;
if (nukeops.NukieOutpost == null ||
gridUid == null ||
gridUid.Value != nukeops.NukieShuttle)
continue;
var mapOutpost = Transform(nukeops.NukieOutpost.Value).MapID;
var mapShuttle = Transform(ev.Uid).MapID;
if (mapOutpost == mapShuttle)
{
nukeops.LeftOutpost = true;
if (TryGetRuleFromGrid(gridUid.Value, out var comps))
_warDeclaratorSystem.RefreshAllUI(comps.Value.Item1, comps.Value.Item2);
}
}
}
private void OnShuttleCallAttempt(ref CommunicationConsoleCallShuttleAttemptEvent ev)
{
var query = EntityQueryEnumerator<NukeopsRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleUid, out var nukeops, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleUid, gameRule))
continue;
// Can't call while nukies are preparing to arrive
if (GetWarCondition(nukeops, gameRule) == WarConditionStatus.WAR_DELAY)
{
ev.Cancelled = true;
ev.Reason = Loc.GetString("war-ops-shuttle-call-unavailable");
return;
}
}
}
protected override void Started(EntityUid uid, NukeopsRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);

View File

@@ -0,0 +1,48 @@
using Robust.Shared.Audio;
namespace Content.Server.NukeOps;
/// <summary>
/// Used with NukeOps game rule to send war declaration announcement
/// </summary>
[RegisterComponent]
public sealed partial class WarDeclaratorComponent : Component
{
/// <summary>
/// Custom war declaration message. If empty, use default.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("message")]
public string Message;
/// <summary>
/// Permission to customize message text
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("allowEditingMessage")]
public bool AllowEditingMessage = true;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxMessageLength")]
public int MaxMessageLength = 512;
/// <summary>
/// War declarement text color
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("color")]
public Color DeclarementColor = Color.Red;
/// <summary>
/// War declarement sound file path
/// </summary>
[DataField("sound")]
public SoundSpecifier DeclarementSound = new SoundPathSpecifier("/Audio/Announcements/war.ogg");
/// <summary>
/// Fluent ID for the declarement title
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("title")]
public string DeclarementTitle = "comms-console-announcement-title-nukie";
}

View File

@@ -0,0 +1,127 @@
using Content.Server.Administration.Logs;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Popups;
using Content.Server.UserInterface;
using Content.Shared.Database;
using Content.Shared.NukeOps;
using Robust.Server.GameObjects;
namespace Content.Server.NukeOps;
/// <summary>
/// This handles nukeops special war mode declaration device and directly using nukeops game rule
/// </summary>
public sealed class WarDeclaratorSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly NukeopsRuleSystem _nukeopsRuleSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<WarDeclaratorComponent, WarDeclaratorActivateMessage>(OnActivated);
SubscribeLocalEvent<WarDeclaratorComponent, ActivatableUIOpenAttemptEvent>(OnAttemptOpenUI);
}
private void OnAttemptOpenUI(EntityUid uid, WarDeclaratorComponent component, ActivatableUIOpenAttemptEvent args)
{
if (!_nukeopsRuleSystem.TryGetRuleFromOperative(args.User, out var comps))
{
var msg = Loc.GetString("war-declarator-not-nukeops");
_popupSystem.PopupEntity(msg, uid);
args.Cancel();
return;
}
UpdateUI(uid, comps.Value.Item1, comps.Value.Item2);
}
private void OnActivated(EntityUid uid, WarDeclaratorComponent component, WarDeclaratorActivateMessage args)
{
if (!args.Session.AttachedEntity.HasValue ||
!_nukeopsRuleSystem.TryGetRuleFromOperative(args.Session.AttachedEntity.Value, out var comps))
return;
var condition = _nukeopsRuleSystem.GetWarCondition(comps.Value.Item1, comps.Value.Item2);
if (condition != WarConditionStatus.YES_WAR)
{
UpdateUI(uid, comps.Value.Item1, comps.Value.Item2);
return;
}
var text = (args.Message.Length <= component.MaxMessageLength ? args.Message.Trim() : $"{args.Message.Trim().Substring(0, 256)}...").ToCharArray();
// No more than 2 newlines, other replaced to spaces
var newlines = 0;
for (var i = 0; i < text.Length; i++)
{
if (text[i] != '\n')
continue;
if (newlines >= 2)
text[i] = ' ';
newlines++;
}
string message = new string(text);
if (component.AllowEditingMessage && message != string.Empty)
{
component.Message = message;
}
else
{
message = Loc.GetString("war-declarator-default-message");
}
var title = Loc.GetString(component.DeclarementTitle);
_nukeopsRuleSystem.DeclareWar(args.Session.AttachedEntity.Value, message, title, component.DeclarementSound, component.DeclarementColor);
if (args.Session.AttachedEntity != null)
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(args.Session.AttachedEntity.Value):player} has declared war with this text: {message}");
}
public void RefreshAllUI(NukeopsRuleComponent nukeops, GameRuleComponent gameRule)
{
var enumerator = EntityQueryEnumerator<WarDeclaratorComponent>();
while (enumerator.MoveNext(out var uid, out _))
{
UpdateUI(uid, nukeops, gameRule);
}
}
private void UpdateUI(EntityUid declaratorUid, NukeopsRuleComponent nukeops, GameRuleComponent gameRule)
{
var condition = _nukeopsRuleSystem.GetWarCondition(nukeops, gameRule);
TimeSpan startTime;
TimeSpan delayTime;
switch(condition)
{
case WarConditionStatus.YES_WAR:
startTime = gameRule.ActivatedAt;
delayTime = nukeops.WarDeclarationDelay;
break;
case WarConditionStatus.WAR_DELAY:
startTime = nukeops.WarDeclaredTime!.Value;
delayTime = nukeops.WarNukieArriveDelay!.Value;
break;
default:
startTime = TimeSpan.Zero;
delayTime = TimeSpan.Zero;
break;
}
_userInterfaceSystem.TrySetUiState(
declaratorUid,
WarDeclaratorUiKey.Key,
new WarDeclaratorBoundUserInterfaceState(
condition,
nukeops.WarDeclarationMinOps,
delayTime,
startTime));
}
}

View File

@@ -0,0 +1,10 @@
namespace Content.Server.Shuttles.Events;
/// <summary>
/// Raised when shuttle console approved FTL
/// </summary>
[ByRefEvent]
public record struct ShuttleConsoleFTLTravelStartEvent(EntityUid Uid)
{
public EntityUid Uid = Uid;
}

View File

@@ -122,6 +122,9 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
var tagEv = new FTLTagEvent();
RaiseLocalEvent(xform.GridUid.Value, ref tagEv);
var ev = new ShuttleConsoleFTLTravelStartEvent(uid);
RaiseLocalEvent(ref ev);
_shuttle.FTLTravel(xform.GridUid.Value, shuttle, args.Destination, dock: dock, priorityTag: tagEv.Tag);
}
@@ -211,7 +214,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
{
RemovePilot(user, pilotComponent);
// This feels backwards; is this intended to be a toggle?
// This feels backwards; is this intended to be a toggle?
if (console == uid)
return false;
}