diff --git a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs
index 0310e91eeb..1a372bdba1 100644
--- a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs
+++ b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs
@@ -1,6 +1,7 @@
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Communications;
+using Content.Shared._DV.Communications; // DeltaV - Exfiltration shuttle
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
@@ -27,6 +28,7 @@ namespace Content.Client.Communications.UI
_menu.OnBroadcast += BroadcastButtonPressed;
_menu.OnAlertLevel += AlertLevelSelected;
_menu.OnEmergencyLevel += EmergencyShuttleButtonPressed;
+ _menu.OnExfiltrationLevel += ExfiltrationShuttleButtonPressed; // DeltaV - Exfiltration shuttle
}
public void AlertLevelSelected(string level)
@@ -46,6 +48,13 @@ namespace Content.Client.Communications.UI
CallShuttle();
}
+ // Begin DeltaV - Exfiltration Shuttle
+ public void ExfiltrationShuttleButtonPressed()
+ {
+ SendMessage(new CommunicationsConsoleExfiltrationShuttleMessage(!_menu!.CountdownStarted));
+ }
+ // End DeltaV - Exfiltration Shuttle
+
public void AnnounceButtonPressed(string message)
{
var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
@@ -85,6 +94,13 @@ namespace Content.Client.Communications.UI
_menu.CurrentLevel = commsState.CurrentAlert;
_menu.CountdownEnd = commsState.ExpectedCountdownEnd;
+
+ // Begin DeltaV - Exfiltration Shuttle
+ _menu.CanExfiltrate = commsState.CanCall;
+ _menu.ExfiltrationCountdownEnd = commsState.ExpectedExfiltrationCountdownEnd;
+ _menu.ExfiltrationShuttleButton.Disabled = !_menu.CanExfiltrate;
+ // End DeltaV - Exfiltration Shuttle
+
_menu.UpdateCountdown();
_menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel);
_menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable;
diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml
index b74df979cf..9132f3f502 100644
--- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml
+++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml
@@ -52,10 +52,19 @@
+
+
+
+
+
+
diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs
index 926b8c6567..977b81c0a1 100644
--- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs
+++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs
@@ -29,6 +29,12 @@ namespace Content.Client.Communications.UI
public event Action? OnAnnounce;
public event Action? OnBroadcast;
+ // Begin DeltaV - Exfiltration Shuttle
+ public bool CanExfiltrate;
+ public TimeSpan? ExfiltrationCountdownEnd;
+ public event Action? OnExfiltrationLevel;
+ // End DeltaV - Exfiltration Shuttle
+
public CommunicationsConsoleMenu()
{
IoCManager.InjectDependencies(this);
@@ -72,12 +78,18 @@ namespace Content.Client.Communications.UI
EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke();
EmergencyShuttleButton.Disabled = !CanCall;
+
+ // Begin DeltaV - Exfiltration Shuttle
+ ExfiltrationShuttleButton.OnPressed += _ => OnExfiltrationLevel?.Invoke();
+ ExfiltrationShuttleButton.Disabled = !CanExfiltrate;
+ // End DeltaV - Exfiltration Shuttle
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateCountdown();
+ UpdateExfiltrationCountdown(); // DeltaV - Exfiltration shuttle
}
// The current alert could make levels unselectable, so we need to ensure that the UI reacts properly.
@@ -117,6 +129,25 @@ namespace Content.Client.Communications.UI
}
}
+ // Begin DeltaV - Exfiltration Shuttle
+ public void UpdateExfiltrationCountdown()
+ {
+ if (ExfiltrationCountdownEnd is null)
+ {
+ ExfiltrationCountdownLabel.SetMessage(string.Empty);
+ ExfiltrationShuttleButton.Text = Loc.GetString("comms-console-menu-call-exfiltration");
+ return;
+ }
+
+ var exfiltrationDiff = MathHelper.Max((ExfiltrationCountdownEnd - _timing.CurTime) ?? TimeSpan.Zero, TimeSpan.Zero);
+ ExfiltrationShuttleButton.Text = Loc.GetString("comms-console-menu-recall-exfiltration");
+
+ var exfiltrationInfoText = Loc.GetString("comms-console-menu-exfiltration-time-remaining",
+ ("time", exfiltrationDiff.ToString(@"hh\:mm\:ss", CultureInfo.CurrentCulture)));
+ ExfiltrationCountdownLabel.SetMessage(exfiltrationInfoText);
+ }
+ // End DeltaV - Exfiltration Shuttle
+
public void UpdateCountdown()
{
if (!CountdownStarted)
diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs
index fc489c1823..565932d276 100644
--- a/Content.Server/Communications/CommunicationsConsoleSystem.cs
+++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs
@@ -1,3 +1,4 @@
+using Content.Server._DV.Station.Components; // DeltaV - Exfiltration shuttle
using Content.Server.Administration.Logs;
using Content.Server.AlertLevel;
using Content.Server.Chat.Systems;
@@ -22,7 +23,7 @@ using Robust.Shared.Configuration;
namespace Content.Server.Communications
{
- public sealed class CommunicationsConsoleSystem : EntitySystem
+ public sealed partial class CommunicationsConsoleSystem : EntitySystem // DeltaV - Partial Class
{
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
[Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!;
@@ -53,6 +54,8 @@ namespace Content.Server.Communications
SubscribeLocalEvent(OnCallShuttleMessage);
SubscribeLocalEvent(OnRecallShuttleMessage);
+ InitializeExfiltration(); // DeltaV - Exfiltration shuttle
+
// On console init, set cooldown
SubscribeLocalEvent(OnCommunicationsConsoleMapInit);
}
@@ -135,6 +138,7 @@ namespace Content.Server.Communications
List? levels = null;
string currentLevel = default!;
float currentDelay = 0;
+ TimeSpan? exfiltrationTime = null; // DeltaV - exfiltration shuttle
if (stationUid != null)
{
@@ -156,6 +160,12 @@ namespace Content.Server.Communications
currentLevel = alertComp.CurrentLevel;
currentDelay = _alertLevelSystem.GetAlertLevelDelay(stationUid.Value, alertComp);
}
+ // Begin DeltaV - exfiltration shuttle
+ if (TryComp(stationUid, out var exfiltration))
+ {
+ exfiltrationTime = exfiltration.ArrivalTime;
+ }
+ // End DeltaV - exfiltration shuttle
}
_uiSystem.SetUiState(uid, CommunicationsConsoleUiKey.Key, new CommunicationsConsoleInterfaceState(
@@ -164,7 +174,8 @@ namespace Content.Server.Communications
levels,
currentLevel,
currentDelay,
- _roundEndSystem.ExpectedCountdownEnd
+ _roundEndSystem.ExpectedCountdownEnd,
+ exfiltrationTime // DeltaV - exfiltration shuttle
));
}
diff --git a/Content.Server/_DV/Communications/CommunicationsConsoleSystem.cs b/Content.Server/_DV/Communications/CommunicationsConsoleSystem.cs
new file mode 100644
index 0000000000..7a9cc7ac75
--- /dev/null
+++ b/Content.Server/_DV/Communications/CommunicationsConsoleSystem.cs
@@ -0,0 +1,32 @@
+using Content.Server._DV.Station.Components;
+using Content.Server._DV.Station.Systems;
+using Content.Shared._DV.Communications;
+
+namespace Content.Server.Communications;
+
+public sealed partial class CommunicationsConsoleSystem : EntitySystem
+{
+ [Dependency] private readonly StationExfiltrationSystem _stationExfiltration = default!;
+
+ private void InitializeExfiltration()
+ {
+ SubscribeLocalEvent(OnExfiltrationMessage);
+ }
+
+ private void OnExfiltrationMessage(Entity ent, ref CommunicationsConsoleExfiltrationShuttleMessage args)
+ {
+ if (_stationSystem.GetOwningStation(ent) is not { } station)
+ return;
+
+ if (!CanUse(args.Actor, ent))
+ {
+ _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), ent, args.Actor);
+ return;
+ }
+
+ if (args.Call)
+ _stationExfiltration.Call(station);
+ else
+ _stationExfiltration.Recall(station);
+ }
+}
diff --git a/Content.Server/_DV/Station/Components/StationExfiltrationComponent.cs b/Content.Server/_DV/Station/Components/StationExfiltrationComponent.cs
new file mode 100644
index 0000000000..d181f7bd11
--- /dev/null
+++ b/Content.Server/_DV/Station/Components/StationExfiltrationComponent.cs
@@ -0,0 +1,116 @@
+using Content.Server._DV.Station.Systems;
+using Content.Shared.Tag;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+using Robust.Shared.Utility;
+
+namespace Content.Server._DV.Station.Components;
+
+[RegisterComponent, AutoGenerateComponentPause, Access(typeof(StationExfiltrationSystem))]
+public sealed partial class StationExfiltrationComponent : Component
+{
+ ///
+ /// Time at which the shuttle will dock to the station
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoPausedField]
+ public TimeSpan? ArrivalTime;
+
+ ///
+ /// Time at which the shuttle will announce that it's leaving the station
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoPausedField]
+ public TimeSpan? ImpendingDepartureAnnouncementTime;
+
+ ///
+ /// Time at which the shuttle leave the station
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoPausedField]
+ public TimeSpan? DepartureTime;
+
+ ///
+ /// How long it takes for the shuttle to arrive at the station
+ ///
+ [DataField]
+ public TimeSpan TravelTime = TimeSpan.FromMinutes(3);
+
+ ///
+ /// How long before leaving to warn
+ ///
+ [DataField]
+ public TimeSpan DepartureWarningTime = TimeSpan.FromSeconds(10);
+
+ ///
+ /// How long to wait at the station before leaving
+ ///
+ [DataField]
+ public TimeSpan LeaveTime = TimeSpan.FromMinutes(3);
+
+ ///
+ /// The dock tag the shuttle will prefer to dock to
+ ///
+ [DataField]
+ public ProtoId DockTo = "DockArrivals";
+
+ ///
+ /// The map to spawn for the shuttle
+ ///
+ [DataField]
+ public ResPath ShuttlePath = new("/Maps/_DV/Shuttles/exfiltration.yml");
+
+ ///
+ /// The spawned shuttle
+ ///
+ [DataField]
+ public EntityUid? SpawnedShuttle;
+
+ ///
+ /// Sender for exfiltration announcements
+ ///
+ [DataField]
+ public LocId Sender = "exfiltration-shuttle-sender";
+
+ ///
+ /// The announcement for when an exfiltration shuttle is called
+ ///
+ [DataField]
+ public LocId CalledAnnouncement = "exfiltration-shuttle-called";
+
+ ///
+ /// The announcement for when an exfiltration shuttle is recalled
+ ///
+ [DataField]
+ public LocId RecalledAnnouncement = "exfiltration-shuttle-recalled";
+
+ ///
+ /// The announcement for when the exfiltration shuttle docks in the vicinity of the station
+ ///
+ [DataField]
+ public LocId DockedNearbyStationAnnouncement = "exfiltration-shuttle-docked-nearby-station";
+
+ ///
+ /// The announcement for when the exfiltration shuttle docks at a station port
+ ///
+ [DataField]
+ public LocId DockedAtStationAnnouncement = "exfiltration-shuttle-docked-at-station";
+
+ ///
+ /// The announcement for when the exfiltration shuttle is about to leave
+ ///
+ [DataField]
+ public LocId AboutToLeaveAnnouncement = "exfiltration-shuttle-about-to-leave";
+
+ ///
+ /// The announcement for when the exfiltration shuttle leaves
+ ///
+ [DataField]
+ public LocId LeftAnnouncement = "exfiltration-shuttle-left";
+
+ ///
+ /// The announcement for when the exfiltration cannot be called due to technical issues
+ ///
+ [DataField]
+ public LocId FailedAnnouncement = "exfiltration-shuttle-failed";
+}
diff --git a/Content.Server/_DV/Station/Systems/StationExfiltrationSystem.cs b/Content.Server/_DV/Station/Systems/StationExfiltrationSystem.cs
new file mode 100644
index 0000000000..57bd520311
--- /dev/null
+++ b/Content.Server/_DV/Station/Systems/StationExfiltrationSystem.cs
@@ -0,0 +1,185 @@
+using System.Numerics;
+using Content.Server._DV.Station.Components;
+using Content.Server.Chat.Systems;
+using Content.Server.Communications;
+using Content.Server.DeviceNetwork.Systems;
+using Content.Server.Pinpointer;
+using Content.Server.Screens.Components;
+using Content.Server.Shuttles.Components;
+using Content.Server.Shuttles.Systems;
+using Content.Server.Station.Components;
+using Content.Server.Station.Systems;
+using Content.Shared.DeviceNetwork.Components;
+using Content.Shared.DeviceNetwork;
+using Content.Shared.Localizations;
+using Content.Shared.Shuttles.Components;
+using Content.Shared.Tiles;
+using Robust.Shared.Audio;
+using Robust.Shared.EntitySerialization.Systems;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Timing;
+using Robust.Shared.Utility;
+
+namespace Content.Server._DV.Station.Systems;
+
+public sealed class StationExfiltrationSystem : EntitySystem
+{
+ [Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!;
+ [Dependency] private readonly DockingSystem _docking = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly MapLoaderSystem _loader = default!;
+ [Dependency] private readonly ShuttleSystem _shuttle = default!;
+ [Dependency] private readonly StationSystem _station = default!;
+ [Dependency] private readonly NavMapSystem _navMap = default!;
+ [Dependency] private readonly CommunicationsConsoleSystem _communicationsConsole = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var comp))
+ {
+ if (_timing.CurTime >= comp.ArrivalTime && comp.SpawnedShuttle is not null)
+ {
+ DockShuttle((uid, comp));
+ }
+ if (_timing.CurTime >= comp.ImpendingDepartureAnnouncementTime)
+ {
+ _chat.DispatchGlobalAnnouncement(
+ Loc.GetString(comp.AboutToLeaveAnnouncement, ("time", comp.DepartureWarningTime.TotalSeconds), ("station", Name(uid))),
+ sender: Loc.GetString(comp.Sender),
+ colorOverride: Color.Red);
+ comp.ImpendingDepartureAnnouncementTime = null;
+ }
+ if (_timing.CurTime >= comp.DepartureTime)
+ {
+ _chat.DispatchGlobalAnnouncement(
+ Loc.GetString(comp.LeftAnnouncement, ("station", Name(uid))),
+ sender: Loc.GetString(comp.Sender),
+ colorOverride: Color.Gold);
+ comp.DepartureTime = null;
+ QueueDel(comp.SpawnedShuttle);
+ comp.SpawnedShuttle = null;
+ }
+ }
+ }
+
+ private bool PrepareShuttle(Entity ent)
+ {
+ if (ent.Comp.SpawnedShuttle is not null)
+ return true;
+
+ if (!TryComp(ent, out var centcomm) || !TryComp(centcomm.MapEntity, out var centcommMap))
+ return false;
+
+ if (!_loader.TryLoadGrid(centcommMap.MapId,
+ ent.Comp.ShuttlePath,
+ out var shuttle,
+ offset: new Vector2(-1000f, 0f)))
+ {
+ Log.Error($"Unable to spawn exfiltration shuttle {ent.Comp.ShuttlePath} for {ToPrettyString(ent)}");
+ return false;
+ }
+
+ ent.Comp.SpawnedShuttle = shuttle.Value;
+ EnsureComp(shuttle.Value);
+ EnsureComp(shuttle.Value);
+
+ return true;
+ }
+
+ private void DockShuttle(Entity ent)
+ {
+ if (ent.Comp.SpawnedShuttle is not { } shuttle)
+ return;
+
+ if (!TryComp(shuttle, out var shuttleComp))
+ return;
+
+ if (!TryComp(ent, out var stationData))
+ return;
+
+ if (_station.GetLargestGrid(stationData) is not { } grid)
+ return;
+
+ if (!TryComp(ent, out var centcomm))
+ return;
+
+ ent.Comp.ArrivalTime = null;
+
+ var ok = _shuttle.TryFTLDock(shuttle, shuttleComp, grid, out var config, ent.Comp.DockTo);
+
+ var angle = _docking.GetAngle(shuttle, Transform(shuttle), grid, Transform(grid));
+
+ var direction = ContentLocalizationManager.FormatDirection(angle.GetDir());
+ var location = FormattedMessage.RemoveMarkupPermissive(
+ _navMap.GetNearestBeaconString((shuttle, Transform(shuttle))));
+
+ var locKey = ok ? ent.Comp.DockedAtStationAnnouncement : ent.Comp.DockedNearbyStationAnnouncement;
+
+ _chat.DispatchStationAnnouncement(
+ ent,
+ Loc.GetString(
+ locKey,
+ ("time", $"{ent.Comp.LeaveTime.TotalSeconds}"),
+ ("direction", direction),
+ ("location", location),
+ ("station", Name(ent))),
+ sender: Loc.GetString(ent.Comp.Sender),
+ colorOverride: Color.Gold);
+
+ if (TryComp(shuttle, out var netComp))
+ {
+ var payload = new NetworkPayload
+ {
+ [ShuttleTimerMasks.ShuttleMap] = shuttle,
+ [ShuttleTimerMasks.SourceMap] = Transform(grid).MapUid,
+ [ShuttleTimerMasks.DestMap] = centcomm.MapEntity,
+ [ShuttleTimerMasks.ShuttleTime] = ent.Comp.LeaveTime,
+ [ShuttleTimerMasks.SourceTime] = ent.Comp.LeaveTime,
+ [ShuttleTimerMasks.DestTime] = ent.Comp.LeaveTime,
+ [ShuttleTimerMasks.Docked] = true,
+ };
+ _deviceNetwork.QueuePacket(shuttle, null, payload, netComp.TransmitFrequency);
+ }
+
+ ent.Comp.ImpendingDepartureAnnouncementTime = _timing.CurTime + ent.Comp.LeaveTime - ent.Comp.DepartureWarningTime;
+ ent.Comp.DepartureTime = _timing.CurTime + ent.Comp.LeaveTime;
+ }
+
+ public void Call(Entity ent)
+ {
+ if (!Resolve(ent.Owner, ref ent.Comp, false))
+ return;
+
+ if (!PrepareShuttle((ent.Owner, ent.Comp)))
+ {
+ _chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.FailedAnnouncement, ("station", Name(ent))), sender: Loc.GetString(ent.Comp.Sender), colorOverride: Color.Gold);
+ }
+ else
+ {
+ ent.Comp.ArrivalTime = _timing.CurTime + ent.Comp.TravelTime;
+ _chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.CalledAnnouncement, ("time", ent.Comp.TravelTime.TotalSeconds), ("station", Name(ent))), sender: Loc.GetString(ent.Comp.Sender), colorOverride: Color.Gold);
+ }
+
+ _communicationsConsole.UpdateCommsConsoleInterface();
+ }
+
+ public void Recall(Entity ent)
+ {
+ if (!Resolve(ent.Owner, ref ent.Comp, false))
+ return;
+
+ ent.Comp.ArrivalTime = null;
+ _chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.RecalledAnnouncement, ("station", Name(ent))), sender: Loc.GetString(ent.Comp.Sender), colorOverride: Color.Gold);
+
+ _communicationsConsole.UpdateCommsConsoleInterface();
+ }
+}
diff --git a/Content.Shared/Communications/SharedCommunicationsConsoleComponent.cs b/Content.Shared/Communications/SharedCommunicationsConsoleComponent.cs
index 604b067a84..7e16dde27f 100644
--- a/Content.Shared/Communications/SharedCommunicationsConsoleComponent.cs
+++ b/Content.Shared/Communications/SharedCommunicationsConsoleComponent.cs
@@ -18,8 +18,9 @@ namespace Content.Shared.Communications
public List? AlertLevels;
public string CurrentAlert;
public float CurrentAlertDelay;
+ public readonly TimeSpan? ExpectedExfiltrationCountdownEnd;
- public CommunicationsConsoleInterfaceState(bool canAnnounce, bool canCall, List? alertLevels, string currentAlert, float currentAlertDelay, TimeSpan? expectedCountdownEnd = null)
+ public CommunicationsConsoleInterfaceState(bool canAnnounce, bool canCall, List? alertLevels, string currentAlert, float currentAlertDelay, TimeSpan? expectedCountdownEnd, TimeSpan? expectedExfiltrationCountdownEnd) // DeltaV - Exfiltration Shuttle
{
CanAnnounce = canAnnounce;
CanCall = canCall;
@@ -28,6 +29,7 @@ namespace Content.Shared.Communications
AlertLevels = alertLevels;
CurrentAlert = currentAlert;
CurrentAlertDelay = currentAlertDelay;
+ ExpectedExfiltrationCountdownEnd = expectedExfiltrationCountdownEnd; // DeltaV - Exfiltration Shuttle
}
}
diff --git a/Content.Shared/_DV/Communications/CommunicationsConsoleExfiltrationShuttleMessage.cs b/Content.Shared/_DV/Communications/CommunicationsConsoleExfiltrationShuttleMessage.cs
new file mode 100644
index 0000000000..8d5dbd3b96
--- /dev/null
+++ b/Content.Shared/_DV/Communications/CommunicationsConsoleExfiltrationShuttleMessage.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared._DV.Communications;
+
+[Serializable, NetSerializable]
+public sealed class CommunicationsConsoleExfiltrationShuttleMessage(bool call) : BoundUserInterfaceMessage
+{
+ public readonly bool Call = call;
+}
diff --git a/Resources/Locale/en-US/_DV/communications/communications-console-component.ftl b/Resources/Locale/en-US/_DV/communications/communications-console-component.ftl
index a08029af6b..0c91d31173 100644
--- a/Resources/Locale/en-US/_DV/communications/communications-console-component.ftl
+++ b/Resources/Locale/en-US/_DV/communications/communications-console-component.ftl
@@ -1 +1,5 @@
comms-console-announcement-title-unauthorized = Unauthorized
+comms-console-menu-call-exfiltration = Call exfiltration shuttle
+comms-console-menu-exfiltration-shuttle-button-tooltip = Calls or recalls the exfiltration shuttle.
+comms-console-menu-exfiltration-time-remaining = ETA of exfiltration shuttle: {$time}
+comms-console-menu-recall-exfiltration = Recall exfiltration shuttle
diff --git a/Resources/Locale/en-US/_DV/shuttles/exfiltration.ftl b/Resources/Locale/en-US/_DV/shuttles/exfiltration.ftl
new file mode 100644
index 0000000000..6be448308f
--- /dev/null
+++ b/Resources/Locale/en-US/_DV/shuttles/exfiltration.ftl
@@ -0,0 +1,8 @@
+exfiltration-shuttle-sender = GALPOL
+exfiltration-shuttle-failed = Request received. An exfiltration shuttle could not be prepared to be sent to {$station}.
+exfiltration-shuttle-called = Request received. An exfiltration has been called for {$station}. Estimate {$time} seconds until arrival.
+exfiltration-shuttle-recalled = Request received. The exfiltration shuttle has been recalled for {$station}.
+exfiltration-shuttle-docked-nearby-station = The exfiltration shuttle is unable to dock with {$station}. It has warped in {$direction} of the station, {$location}. It will leave in {$time} seconds.
+exfiltration-shuttle-docked-at-station = The exfiltration shuttle docked {$direction} of {$station}, {$location}. It will depart in {$time} seconds.
+exfiltration-shuttle-about-to-leave = The exfiltration shuttle will depart from {$station} in {$time} seconds.
+exfiltration-shuttle-left = The exfiltration shuttle has left {$station}.
diff --git a/Resources/Maps/_DV/Shuttles/exfiltration.yml b/Resources/Maps/_DV/Shuttles/exfiltration.yml
index c2d6079483..3da0e2bb8b 100644
--- a/Resources/Maps/_DV/Shuttles/exfiltration.yml
+++ b/Resources/Maps/_DV/Shuttles/exfiltration.yml
@@ -1,11 +1,11 @@
meta:
format: 7
category: Grid
- engineVersion: 249.0.0
+ engineVersion: 255.1.0
forkId: ""
forkVersion: ""
- time: 04/12/2025 05:47:37
- entityCount: 295
+ time: 05/12/2025 20:04:45
+ entityCount: 299
maps: []
grids:
- 1
@@ -45,6 +45,11 @@ entities:
ind: -1,-1
tiles: AgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAAAAAAAAAAAAAAAA
version: 6
+ - type: DeviceNetwork
+ configurators: []
+ deviceLists: []
+ transmitFrequencyId: ShuttleTimer
+ deviceNetId: Wireless
- type: Broadphase
- type: Physics
bodyStatus: InAir
@@ -1391,6 +1396,28 @@ entities:
rot: 3.141592653589793 rad
pos: -1.5,13.5
parent: 1
+- proto: Screen
+ entities:
+ - uid: 296
+ components:
+ - type: Transform
+ pos: 0.5,11.5
+ parent: 1
+ - uid: 297
+ components:
+ - type: Transform
+ pos: 0.5,8.5
+ parent: 1
+ - uid: 298
+ components:
+ - type: Transform
+ pos: 0.5,5.5
+ parent: 1
+ - uid: 299
+ components:
+ - type: Transform
+ pos: 0.5,2.5
+ parent: 1
- proto: ShuttleWindow
entities:
- uid: 3
diff --git a/Resources/Prototypes/Entities/Stations/nanotrasen.yml b/Resources/Prototypes/Entities/Stations/nanotrasen.yml
index 184ec18825..6575475df5 100644
--- a/Resources/Prototypes/Entities/Stations/nanotrasen.yml
+++ b/Resources/Prototypes/Entities/Stations/nanotrasen.yml
@@ -25,10 +25,13 @@
- BaseStationSiliconLawCrewsimov
- BaseStationAllEventsEligible
- BaseStationNanotrasen
- - BaseStationMail # Nyano component, required for station mail to function
- - BaseStationAutomaticSpareId # DeltaV
- - BaseStationStockMarket # DeltaV
- - BaseStationLavaland # DeltaV
+ # Begin DeltaV - Station additions
+ - BaseStationMail
+ - BaseStationAutomaticSpareId
+ - BaseStationStockMarket
+ - BaseStationLavaland
+ - BaseStationExfiltration
+ # End DeltaV - Station additions
categories: [ HideSpawnMenu ]
components:
- type: Transform
diff --git a/Resources/Prototypes/_DV/Entities/Stations/base.yml b/Resources/Prototypes/_DV/Entities/Stations/base.yml
index c550255966..02515358d5 100644
--- a/Resources/Prototypes/_DV/Entities/Stations/base.yml
+++ b/Resources/Prototypes/_DV/Entities/Stations/base.yml
@@ -29,6 +29,12 @@
components:
- type: AutomaticSpareId
+- type: entity
+ id: BaseStationExfiltration
+ abstract: true
+ components:
+ - type: StationExfiltration
+
- type: entity
abstract: true
id: BaseStationLavaland