Communications console & screens overhaul (#5954)

* i'm going insane from screens

* some wiring

* screemes

* holy shit adhd lock-in

* incomplete

* its FUCKING DONE

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* zeta

* mrrrp

* test fix

* fix arrivals

* fix misnetwork

* Fix iteration outline. Fixed all headers showing if all options where hidden. Added access requirement to keycard auth mechnism. Added countdown. Fixed ninja and fugitive. Fixed AI and aghost.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Vanessa <vanessalouwagie@gmail.com>
This commit is contained in:
pathetic meowmeow
2026-08-27 13:37:40 -05:00
committed by GitHub
co-authored by pre-commit-ci[bot] Vanessa
parent bd1e4224cd
commit a635429d3e
81 changed files with 2454 additions and 199 deletions
@@ -28,7 +28,6 @@ namespace Content.Client.Communications.UI
_menu.OnBroadcast += BroadcastButtonPressed; _menu.OnBroadcast += BroadcastButtonPressed;
_menu.OnAlertLevel += AlertLevelSelected; _menu.OnAlertLevel += AlertLevelSelected;
_menu.OnEmergencyLevel += EmergencyShuttleButtonPressed; _menu.OnEmergencyLevel += EmergencyShuttleButtonPressed;
_menu.OnExfiltrationLevel += ExfiltrationShuttleButtonPressed; // DeltaV - Exfiltration shuttle
} }
public void AlertLevelSelected(string level) public void AlertLevelSelected(string level)
@@ -48,13 +47,6 @@ namespace Content.Client.Communications.UI
CallShuttle(); CallShuttle();
} }
// Begin DeltaV - Exfiltration Shuttle
public void ExfiltrationShuttleButtonPressed()
{
SendMessage(new CommunicationsConsoleExfiltrationShuttleMessage(!_menu!.CountdownStarted));
}
// End DeltaV - Exfiltration Shuttle
public void AnnounceButtonPressed(string message) public void AnnounceButtonPressed(string message)
{ {
var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
@@ -94,13 +86,6 @@ namespace Content.Client.Communications.UI
_menu.CurrentLevel = commsState.CurrentAlert; _menu.CurrentLevel = commsState.CurrentAlert;
_menu.CountdownEnd = commsState.ExpectedCountdownEnd; _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.UpdateCountdown();
_menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel); _menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel);
_menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable; _menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable;
@@ -52,19 +52,10 @@
<RichTextLabel Name="CountdownLabel"/> <RichTextLabel Name="CountdownLabel"/>
<!-- DeltaV - Exfiltration Shuttle -->
<RichTextLabel Name="ExfiltrationCountdownLabel"/>
<Button Name="EmergencyShuttleButton" <Button Name="EmergencyShuttleButton"
Access="Public" Access="Public"
Text="Placeholder Text" Text="Placeholder Text"
ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/> ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/>
<!-- DeltaV - Exfiltration Shuttle -->
<Button Name="ExfiltrationShuttleButton"
Access="Public"
Text="Placeholder Text"
ToolTip="{Loc 'comms-console-menu-exfiltration-shuttle-button-tooltip'}"/>
</BoxContainer> </BoxContainer>
</BoxContainer> </BoxContainer>
</BoxContainer> </BoxContainer>
@@ -29,12 +29,6 @@ namespace Content.Client.Communications.UI
public event Action<string>? OnAnnounce; public event Action<string>? OnAnnounce;
public event Action<string>? OnBroadcast; public event Action<string>? OnBroadcast;
// Begin DeltaV - Exfiltration Shuttle
public bool CanExfiltrate;
public TimeSpan? ExfiltrationCountdownEnd;
public event Action? OnExfiltrationLevel;
// End DeltaV - Exfiltration Shuttle
public CommunicationsConsoleMenu() public CommunicationsConsoleMenu()
{ {
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
@@ -78,18 +72,12 @@ namespace Content.Client.Communications.UI
EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke(); EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke();
EmergencyShuttleButton.Disabled = !CanCall; EmergencyShuttleButton.Disabled = !CanCall;
// Begin DeltaV - Exfiltration Shuttle
ExfiltrationShuttleButton.OnPressed += _ => OnExfiltrationLevel?.Invoke();
ExfiltrationShuttleButton.Disabled = !CanExfiltrate;
// End DeltaV - Exfiltration Shuttle
} }
protected override void FrameUpdate(FrameEventArgs args) protected override void FrameUpdate(FrameEventArgs args)
{ {
base.FrameUpdate(args); base.FrameUpdate(args);
UpdateCountdown(); UpdateCountdown();
UpdateExfiltrationCountdown(); // DeltaV - Exfiltration shuttle
} }
// The current alert could make levels unselectable, so we need to ensure that the UI reacts properly. // The current alert could make levels unselectable, so we need to ensure that the UI reacts properly.
@@ -129,25 +117,6 @@ 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() public void UpdateCountdown()
{ {
if (!CountdownStarted) if (!CountdownStarted)
@@ -70,6 +70,11 @@ public sealed class ConfirmButton : Button
[ViewVariables] [ViewVariables]
public bool IsConfirming = false; public bool IsConfirming = false;
// Begin DeltaV
[ViewVariables]
public bool ForceDisabled = false;
// End DeltaV
public ConfirmButton() public ConfirmButton()
{ {
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
@@ -87,7 +92,7 @@ public sealed class ConfirmButton : Button
} }
if (Disabled && _gameTiming.CurTime > _nextCooldown) if (Disabled && _gameTiming.CurTime > _nextCooldown)
Disabled = false; Disabled = ForceDisabled; // DeltaV
} }
protected override void DrawModeChanged() protected override void DrawModeChanged()
@@ -0,0 +1,30 @@
using Content.Shared._DV.Communications;
using Robust.Client.UserInterface;
namespace Content.Client._DV.Communications;
public sealed class DVCommunicationsConsoleBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IEntityManager _entity = default!;
private DVCommunicationsConsoleMenu? _menu;
public DVCommunicationsConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_menu = this.CreateWindow<DVCommunicationsConsoleMenu>();
_menu.OnMessage += SendMessage;
if (_entity.TryGetComponent<DVCommunicationsConsoleComponent>(Owner, out var comp))
Update((Owner, comp));
}
public void Update(Entity<DVCommunicationsConsoleComponent> ent)
{
_menu?.Update(ent, PlayerManager.LocalEntity!.Value);
}
}
@@ -0,0 +1,117 @@
<controls:FancyWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'comms-console-menu-title'}"
MinSize="400 300">
<BoxContainer Name="HomeScreen" Orientation="Vertical" Margin="8">
<Label Text="{Loc 'comms-console-menu-station-title'}" Name="StationHeaderLabel" StyleClasses="LabelKeyText" />
<Button Name="AnnouncementTab" Text="{Loc 'comms-console-menu-tab.Announcement'}" />
<Button Name="ScreenTab" Text="{Loc 'comms-console-menu-tab.Screen'}" />
<Button Name="AlertLevelTab" Text="{Loc 'comms-console-menu-tab.AlertLevel'}" />
<Label Text="{Loc 'comms-console-menu-transit-title'}" Name="TransitHeaderLabel" StyleClasses="LabelKeyText" Margin="0 8 0 0" />
<Button Name="ShuttlesTab" Text="{Loc 'comms-console-menu-tab.Shuttles'}" />
<Label Text="{Loc 'comms-console-menu-emergency-title'}" Name="EmergencyHeaderLabel" StyleClasses="LabelKeyText" Margin="0 8 0 0" />
<Button Name="KeycardAuthenticationDeviceTab" Text="{Loc 'comms-console-menu-tab.KeycardAuthenticationDevice'}" />
</BoxContainer>
<BoxContainer Orientation="Vertical">
<Button Name="HomeButton" Text="{Loc 'comms-console-menu-home'}" Visible="False" />
<BoxContainer Name="AnnouncementScreen" Visible="False" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" SeparationOverride="8" Margin="8">
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer SeparationOverride="8" Margin="8" HorizontalExpand="True" Orientation="Vertical">
<Label Text="{Loc 'comms-console-menu-announcement-text'}" StyleClasses="LabelKeyText" />
<TextEdit Name="AnnounceInput"
VerticalExpand="True"
HorizontalExpand="True"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
MinHeight="100" />
</BoxContainer>
</PanelContainer>
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True">
<Button Name="AnnounceButton" Margin="8" Text="{Loc 'comms-console-menu-send-announcement'}" />
</PanelContainer>
</BoxContainer>
<BoxContainer Name="ScreenScreen" Visible="False" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" SeparationOverride="8" Margin="8">
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True">
<BoxContainer SeparationOverride="8" Margin="8" HorizontalExpand="True" Orientation="Vertical">
<Label Text="{Loc 'comms-console-menu-screen-configuration'}" StyleClasses="LabelKeyText" />
<BoxContainer>
<Label Text="{Loc 'comms-console-menu-screen-contents'}" HorizontalExpand="True" />
<OptionButton Name="ScreenContentsButton" />
</BoxContainer>
<BoxContainer>
<Label Text="{Loc 'comms-console-menu-alert-level-border'}" HorizontalExpand="True" />
<Button Name="ScreenAlertBorder" Text="{Loc 'comms-console-menu-enable-border'}" ToggleMode="True" />
</BoxContainer>
</BoxContainer>
</PanelContainer>
<PanelContainer StyleClasses="PanelDark">
<BoxContainer Margin="8" Orientation="Vertical" SeparationOverride="4">
<Label Text="{Loc 'comms-console-menu-screen-text'}" StyleClasses="LabelKeyText" />
<GridContainer Columns="2" HorizontalExpand="True">
<Label Text="{Loc 'comms-console-menu-line-1'}" />
<LineEdit Name="ScreenLine1" HorizontalExpand="True" StyleClasses="comms-console-display" />
<Label Text="{Loc 'comms-console-menu-line-2'}" />
<LineEdit Name="ScreenLine2" HorizontalExpand="True" StyleClasses="comms-console-display" />
</GridContainer>
<Button Name="ScreenUpdateTextButton" Text="{Loc 'comms-console-menu-update-screen-text'}" HorizontalAlignment="Right" />
</BoxContainer>
</PanelContainer>
</BoxContainer>
<BoxContainer Name="ShuttlesScreen" Visible="False" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" SeparationOverride="8" Margin="8">
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True">
<BoxContainer Margin="8" HorizontalExpand="True" Orientation="Vertical">
<Label Text="{Loc 'comms-console-menu-emergency-shuttle'}" StyleClasses="LabelKeyText" />
<RichTextLabel Name="EmergencyStatus" Text="{Loc 'comms-console-menu-shuttle-not-coming'}" />
<Button Name="ShuttleEmergencyButton" Text="{Loc 'comms-console-menu-call-emergency.True'}" HorizontalAlignment="Right" Margin="0 8 0 0" />
</BoxContainer>
</PanelContainer>
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True">
<BoxContainer Margin="8" HorizontalExpand="True" Orientation="Vertical">
<Label Text="{Loc 'comms-console-menu-exfiltration-shuttle'}" StyleClasses="LabelKeyText" />
<RichTextLabel Name="ExfiltrationStatus" Text="{Loc 'comms-console-menu-shuttle-not-coming'}" />
<Button Name="ShuttleExfiltrationButton" Text="{Loc 'comms-console-menu-call-exfiltration.True'}" HorizontalAlignment="Right" Margin="0 8 0 0" />
</BoxContainer>
</PanelContainer>
</BoxContainer>
<BoxContainer Name="AlertLevelScreen" Visible="False" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" SeparationOverride="8" Margin="8">
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True" MaxWidth="400">
<BoxContainer Margin="8" HorizontalExpand="True" Orientation="Vertical">
<Label Text="{Loc 'comms-console-menu-alert-level'}" StyleClasses="LabelKeyText" />
<RichTextLabel Name="AlertLevel" HorizontalExpand="True" />
<Button Name="AlertLevelsDropdown" Text="{Loc 'comms-console-menu-change-alert-level'}" HorizontalAlignment="Right" Margin="0 8 0 0" />
</BoxContainer>
</PanelContainer>
</BoxContainer>
<BoxContainer Name="KeycardAuthenticationDeviceScreen" Visible="False" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" SeparationOverride="8" Margin="8">
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True" MaxWidth="400">
<BoxContainer Margin="8" HorizontalExpand="True" Orientation="Vertical">
<Label Text="{Loc 'comms-console-menu-declare-mayday.title'}" StyleClasses="LabelKeyText" />
<RichTextLabel Text="{Loc 'comms-console-menu-declare-mayday.desc'}" />
<controls:ConfirmButton Name="CallZeta" Text="{Loc 'comms-console-menu-declare-mayday.button'}" HorizontalAlignment="Stretch" Margin="0 8 0 0" />
</BoxContainer>
</PanelContainer>
<PanelContainer StyleClasses="PanelDark" HorizontalExpand="True" MaxWidth="400">
<BoxContainer Margin="8" HorizontalExpand="True" Orientation="Vertical">
<Label Text="{Loc 'comms-console-menu-request-codes.title'}" StyleClasses="LabelKeyText" />
<RichTextLabel Text="{Loc 'comms-console-menu-request-codes.desc'}" />
<controls:ConfirmButton Name="RequestCodes" Text="{Loc 'comms-console-menu-request-codes.button'}" HorizontalAlignment="Stretch" Margin="0 8 0 0" />
</BoxContainer>
</PanelContainer>
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>
@@ -0,0 +1,320 @@
using System.Globalization;
using System.Numerics;
using Content.Client.UserInterface.Controls;
using Content.Shared._DV.Communications;
using Content.Shared._DV.KeycardAuthenticationDevice;
using Content.Shared._DV.Screens;
using Content.Shared.Humanoid;
using Content.Shared.Station;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client._DV.Communications;
[GenerateTypedNameReferences]
public sealed partial class DVCommunicationsConsoleMenu : FancyWindow
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IEntityManager _entity = default!;
private readonly SharedStationSystem _station;
private readonly BoxContainer[] _screens;
private readonly ButtonGroup _group;
public event Action<BoundUserInterfaceMessage>? OnMessage;
private Entity<DVCommunicationsConsoleComponent>? _console;
private Entity<DVStationKeycardAuthenticationDeviceComponent>? _stationKeycardAuthenticationDevice;
private EntityUid? _user;
private readonly Popup _alertLevelsPopup;
private readonly BoxContainer _alertLevels = new()
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
};
private string _lastConfiguredLine1 = string.Empty;
private string _lastConfiguredLine2 = string.Empty;
public DVCommunicationsConsoleMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_station = _entity.System<SharedStationSystem>();
_group = new();
_screens = new[]
{
HomeScreen, AnnouncementScreen, ScreenScreen, ShuttlesScreen, AlertLevelScreen,
KeycardAuthenticationDeviceScreen,
};
HomeButton.OnPressed += _ => SetScreen(HomeScreen);
AnnouncementTab.OnPressed += _ => SetScreen(AnnouncementScreen);
ScreenTab.OnPressed += _ => SetScreen(ScreenScreen);
ShuttlesTab.OnPressed += _ => SetScreen(ShuttlesScreen);
AlertLevelTab.OnPressed += _ => SetScreen(AlertLevelScreen);
KeycardAuthenticationDeviceTab.OnPressed += _ => SetScreen(KeycardAuthenticationDeviceScreen);
foreach (var value in Enum.GetValues<DVScreenContent>())
{
ScreenContentsButton.AddItem(Loc.GetString($"comms-console-menu-screen-content.{value}"), (int)value);
}
AnnounceButton.OnPressed += OnAnnouncePressed;
ScreenUpdateTextButton.OnPressed += OnUpdateScreenText;
ScreenContentsButton.OnItemSelected += OnScreenContentsSelected;
ScreenAlertBorder.OnToggled += OnScreenAlertBorderToggled;
ShuttleEmergencyButton.OnPressed += OnEmergencyPressed;
ShuttleExfiltrationButton.OnPressed += OnExfiltrationPressed;
AlertLevelsDropdown.OnPressed += OnAlertLevelsDropdownPressed;
CallZeta.OnPressed += OnCallZetaPressed;
RequestCodes.OnPressed += OnRequestCodesPressed;
_alertLevelsPopup = new()
{
Children = { _alertLevels },
};
_alertLevelsPopup.OnPopupHide += () => _alertLevelsPopup.Orphan();
AnnounceInput.Placeholder = new Rope.Leaf(Loc.GetString("comms-console-menu-announcement-placeholder"));
}
private void OnAlertLevelsDropdownPressed(BaseButton.ButtonEventArgs args)
{
var globalPos = AlertLevelsDropdown.GlobalPosition;
globalPos.Y += AlertLevelsDropdown.Size.Y + 1; // Place it below us, with a safety margin.
_alertLevels.Measure(Window?.Size ?? Vector2Helpers.Infinity);
var (minX, minY) = _alertLevels.DesiredSize;
var box = UIBox2.FromDimensions(globalPos, new Vector2(Math.Max(minX, AlertLevelsDropdown.Width), minY));
_alertLevelsPopup.Orphan();
Root?.ModalRoot.AddChild(_alertLevelsPopup);
_alertLevelsPopup.Open(box);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (_console is not { } console)
return;
AnnounceButton.Disabled = _timing.CurTime <= console.Comp.CanAnnounceAt;
AlertLevelsDropdown.Disabled = console.Comp.CanSetAlertAt is null || _timing.CurTime <= console.Comp.CanSetAlertAt;
if (AlertLevelsDropdown.Disabled)
_alertLevelsPopup.Close();
if (console.Comp.ExpectedEvacuationArrival is { } evacArrival)
{
var diff = MathHelper.Max(evacArrival - _timing.CurTime, TimeSpan.Zero);
var infoText = Loc.GetString($"comms-console-menu-shuttle-eta",
("time", diff.ToString(@"hh\:mm\:ss", CultureInfo.CurrentCulture)));
EmergencyStatus.Text = infoText;
}
else
{
EmergencyStatus.Text = Loc.GetString("comms-console-menu-shuttle-not-coming");
}
if (console.Comp.ExpectedExfiltrationArrival is { } exfiltrationArrival)
{
var diff = MathHelper.Max(exfiltrationArrival - _timing.CurTime, TimeSpan.Zero);
var infoText = Loc.GetString($"comms-console-menu-shuttle-eta",
("time", diff.ToString(@"hh\:mm\:ss", CultureInfo.CurrentCulture)));
ExfiltrationStatus.Text = infoText;
}
else
{
ExfiltrationStatus.Text = Loc.GetString("comms-console-menu-shuttle-not-coming");
}
UpdateKeycardAuthenticationDevice();
}
private void SetScreen(Control screen)
{
foreach (var other in _screens)
{
other.Visible = false;
}
screen.Visible = true;
HomeButton.Visible = screen != HomeScreen;
}
public void Update(Entity<DVCommunicationsConsoleComponent> console, EntityUid user)
{
_console = console;
_user = user;
if (_station.GetOwningStation(console) is { } station &&
_entity.TryGetComponent<DVStationKeycardAuthenticationDeviceComponent>(station,
out var keycardAuthenticationDevice))
{
_stationKeycardAuthenticationDevice = (station, keycardAuthenticationDevice);
}
// If they only have the ability to announce, there's no point in having a home button
if (console.Comp.CanAnnounce && !(console.Comp.CanAlertLevel || console.Comp.CanCallShuttles || console.Comp.CanConfigureScreens || console.Comp.CanKeycardAuthenticationDevice))
{
SetScreen(AnnouncementScreen);
HomeButton.Visible = false;
}
// Station
StationHeaderLabel.Visible = console.Comp.CanAnnounce || console.Comp.CanConfigureScreens || console.Comp.CanAlertLevel;
AnnouncementTab.Visible = console.Comp.CanAnnounce;
ScreenTab.Visible = console.Comp.CanConfigureScreens;
AlertLevelTab.Visible = console.Comp.CanAlertLevel;
// Shuttles
TransitHeaderLabel.Visible = console.Comp.CanCallShuttles; // Should be only hidden if all buttons under are also hidden.
ShuttlesTab.Visible = console.Comp.CanCallShuttles;
// Emergency
EmergencyHeaderLabel.Visible = console.Comp.CanKeycardAuthenticationDevice; // Should be only hidden if all buttons under are also hidden.
KeycardAuthenticationDeviceTab.Visible = console.Comp.CanKeycardAuthenticationDevice;
ShuttleEmergencyButton.Disabled = !console.Comp.ShuttlesCallable;
ShuttleExfiltrationButton.Disabled = !console.Comp.ShuttlesCallable;
ShuttleEmergencyButton.Text =
Loc.GetString($"comms-console-menu-call-emergency.{console.Comp.ExpectedEvacuationArrival is null}");
ShuttleExfiltrationButton.Text =
Loc.GetString($"comms-console-menu-call-exfiltration.{console.Comp.ExpectedExfiltrationArrival is null}");
_alertLevels.RemoveAllChildren();
foreach (var level in console.Comp.AlertLevels)
{
if (level.Id == console.Comp.CurrentAlertLevel)
{
AlertLevel.Text = Loc.GetString("comms-console-menu-current-alert-level",
("name", Loc.GetString(level.AlertLevel)),
("color", level.Color),
("description", Loc.GetString(level.Description)));
}
if (!level.CanSet)
continue;
var btn = new Button
{
Text = Loc.GetString(level.AlertLevel),
ToggleMode = true,
Group = _group,
Pressed = level.Id == console.Comp.CurrentAlertLevel,
};
_alertLevels.AddChild(btn);
btn.OnPressed += _ =>
{
_alertLevelsPopup.Close();
OnMessage?.Invoke(new DVCommunicationsConsoleAlertLevelMessage(level.Id));
};
}
if (console.Comp.LastConfiguredLine1 != _lastConfiguredLine1)
ScreenLine1.Text = console.Comp.LastConfiguredLine1;
if (console.Comp.LastConfiguredLine2 != _lastConfiguredLine2)
ScreenLine2.Text = console.Comp.LastConfiguredLine2;
ScreenContentsButton.SelectId((int)console.Comp.LastConfiguredContent);
ScreenAlertBorder.Pressed = console.Comp.LastConfiguredShowBorders;
_lastConfiguredLine1 = console.Comp.LastConfiguredLine1;
_lastConfiguredLine2 = console.Comp.LastConfiguredLine2;
UpdateKeycardAuthenticationDevice();
}
private void UpdateKeycardAuthenticationDevice()
{
if (_user is not { } user || _stationKeycardAuthenticationDevice is not { } station)
return;
var canCall = !_entity.HasComponent<DVStationKeycardAuthenticationDeviceAlreadySwipedComponent>(user)
&& _entity.HasComponent<HumanoidProfileComponent>(user) // Can't be AI or a borg
&& station.Comp.AccessibleAfter <= _timing.CurTime;
CallZeta.ForceDisabled = !(canCall && station.Comp.SwipingFor is null or DVStationKeycardAction.Mayday);
CallZeta.Disabled = CallZeta.ForceDisabled;
RequestCodes.ForceDisabled = !(canCall && station.Comp.SwipingFor is null or DVStationKeycardAction.Scuttling);
RequestCodes.Disabled = RequestCodes.ForceDisabled;
if (CallZeta.IsConfirming || RequestCodes.IsConfirming)
return;
// Kinda messy but it works
if (station.Comp.SwipesStartedAt is { } firstSwipeTime)
{
var countdown = firstSwipeTime + station.Comp.SwipeWindow;
var timeRemaining = countdown.Subtract(_timing.CurTime);
if (timeRemaining > TimeSpan.Zero && station.Comp.SwipingFor is DVStationKeycardAction.Mayday)
CallZeta.Text = $"{timeRemaining:ss\\.fff}";
if (timeRemaining > TimeSpan.Zero && station.Comp.SwipingFor is DVStationKeycardAction.Scuttling)
RequestCodes.Text = $"{timeRemaining:ss\\.fff}";
}
else
{
CallZeta.Text = Loc.GetString("comms-console-menu-declare-mayday.button");
RequestCodes.Text = Loc.GetString("comms-console-menu-request-codes.button");
}
}
private void OnAnnouncePressed(BaseButton.ButtonEventArgs args)
{
OnMessage?.Invoke(new DVCommunicationsConsoleAnnouncementMessage(Rope.Collapse(AnnounceInput.TextRope)));
}
private void UpdateScreens()
{
OnMessage?.Invoke(new DVCommunicationsConsoleScreenConfigurationMessage(
(DVScreenContent) ScreenContentsButton.SelectedId,
ScreenAlertBorder.Pressed,
ScreenLine1.Text,
ScreenLine2.Text));
}
private void OnUpdateScreenText(BaseButton.ButtonEventArgs buttonEventArgs)
{
UpdateScreens();
}
private void OnScreenContentsSelected(OptionButton.ItemSelectedEventArgs itemSelectedEventArgs)
{
ScreenContentsButton.SelectId(itemSelectedEventArgs.Id);
UpdateScreens();
}
private void OnScreenAlertBorderToggled(BaseButton.ButtonToggledEventArgs buttonToggledEventArgs)
{
UpdateScreens();
}
private void OnExfiltrationPressed(BaseButton.ButtonEventArgs args)
{
OnMessage?.Invoke(new DVCommunicationsConsoleExfiltrationShuttleMessage(_console?.Comp.ExpectedExfiltrationArrival is null));
}
private void OnEmergencyPressed(BaseButton.ButtonEventArgs args)
{
OnMessage?.Invoke(new DVCommunicationsConsoleEvacuationShuttleMessage(_console?.Comp.ExpectedEvacuationArrival is null));
}
private void OnCallZetaPressed(BaseButton.ButtonEventArgs obj)
{
OnMessage?.Invoke(new DVCommunicationsConsoleKeycardAuthenticationDeviceMessage(DVStationKeycardAction.Mayday));
}
private void OnRequestCodesPressed(BaseButton.ButtonEventArgs obj)
{
OnMessage?.Invoke(new DVCommunicationsConsoleKeycardAuthenticationDeviceMessage(DVStationKeycardAction.Scuttling));
}
}
@@ -0,0 +1,26 @@
using Content.Shared._DV.Communications;
using Robust.Client.GameObjects;
namespace Content.Client._DV.Communications;
public sealed class DVCommunicationsConsoleSystem : SharedDVCommunicationsConsoleSystem
{
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DVCommunicationsConsoleComponent, AfterAutoHandleStateEvent>(OnHandleState);
}
private void OnHandleState(Entity<DVCommunicationsConsoleComponent> ent, ref AfterAutoHandleStateEvent args)
{
if (!_userInterface.TryGetOpenUi<DVCommunicationsConsoleBoundUserInterface>(ent.Owner,
DVCommunicationsConsoleUi.Key,
out var bui))
return;
bui.Update(ent);
}
}
@@ -0,0 +1,5 @@
using Content.Shared._DV.KeycardAuthenticationDevice;
namespace Content.Client._DV.KeycardAuthenticationDevice;
public sealed class DVStationKeycardAuthenticationDeviceSystem : SharedDVStationKeycardAuthenticationDeviceSystem;
@@ -0,0 +1,103 @@
using System.Globalization;
using Content.Client.GameTicking.Managers;
using Content.Client.Interactable.Components;
using Content.Client.TextScreen;
using Content.Shared._DV.Screens;
using Robust.Shared.Timing;
namespace Content.Client._DV.Screens;
public sealed class DVScreenSystem : DVSharedScreenSystem
{
[Dependency] private readonly DVTextVisualsSystem _textVisuals = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ClientGameTicker _ticker = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DVScreenComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<DVScreenComponent, AfterAutoHandleStateEvent>(OnScreenState);
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
var query = EntityQueryEnumerator<DVScreenComponent>();
while (query.MoveNext(out var uid, out var screen))
{
switch (screen.Content)
{
case DVScreenContent.Text:
break;
case DVScreenContent.CurrentTime:
CurrentTime((uid, screen));
break;
case DVScreenContent.EstimatedTimeOfArrival:
EstimatedTimeOfArrival((uid, screen));
break;
case DVScreenContent.AlertLevel:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
private void OnInit(Entity<DVScreenComponent> ent, ref ComponentInit args)
{
// Remove interaction outline because it outlines the offscreen text and looks bad
RemComp<InteractionOutlineComponent>(ent);
}
private void OnScreenState(Entity<DVScreenComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateVisuals(ent);
switch (ent.Comp.Content)
{
case DVScreenContent.Text:
Text(ent);
break;
case DVScreenContent.CurrentTime:
CurrentTime(ent);
break;
case DVScreenContent.EstimatedTimeOfArrival:
EstimatedTimeOfArrival(ent);
break;
case DVScreenContent.AlertLevel:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private void Text(Entity<DVScreenComponent> ent)
{
_textVisuals.SetText(ent.Owner, ent.Comp.Line1, ent.Comp.Line2);
}
private void CurrentTime(Entity<DVScreenComponent> ent)
{
var time = (_timing.CurTime - _ticker.RoundStartTimeSpan).Duration();
_textVisuals.SetText(ent.Owner, Loc.GetString("status-display-time"), time.ToString("hh\\:mm"));
}
private void EstimatedTimeOfArrival(Entity<DVScreenComponent> ent)
{
if (ent.Comp.TargetTime <= _timing.CurTime)
{
_textVisuals.SetText(ent.Owner, string.Empty, string.Empty);
return;
}
var time = (_timing.CurTime - ent.Comp.TargetTime).Duration();
var formatted = time.ToString("mm\\:ss");
Log.Debug($"{_timing.CurTime} - {ent.Comp.TargetTime} = {time}");
var title = ent.Comp.ScreenIsAtDestination ? Loc.GetString("status-display-etd") : Loc.GetString("status-display-eta");
_textVisuals.SetText(ent.Owner, title, formatted);
}
}
@@ -0,0 +1,140 @@
using System.Linq;
using System.Numerics;
using System.Threading;
using JetBrains.Annotations;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
namespace Content.Client._DV.Screens;
[UsedImplicitly]
public sealed class DVTextRenderingOverlay : Overlay
{
[Dependency] private readonly IClyde _clyde = default!;
private readonly SpriteSystem _sprite;
private readonly AnimationPlayerSystem _animationPlayer;
public override OverlaySpace Space => OverlaySpace.ScreenSpaceBelowWorld;
private readonly Queue<(Entity<DVTextVisualsComponent> Entity, Font Font, CancellationToken Cancellation)> _queue = new();
public const string MarqueeKey = "dv-text-screen-marquee";
public DVTextRenderingOverlay(SpriteSystem sprite, AnimationPlayerSystem animationPlayer)
{
IoCManager.InjectDependencies(this);
_sprite = sprite;
_animationPlayer = animationPlayer;
ZIndex = -100; // this needs to render before almost everything
}
public CancellationTokenSource QueueRender(
Entity<DVTextVisualsComponent> ent,
Font font)
{
var source = new CancellationTokenSource();
_queue.Enqueue((ent, font, source.Token));
return source;
}
protected override void Draw(in OverlayDrawArgs args)
{
var screenHandle = args.ScreenHandle;
while (_queue.TryDequeue(out var queued))
{
if (queued.Cancellation.IsCancellationRequested)
continue;
var font = queued.Font;
foreach (var row in queued.Entity.Comp.Rows)
{
if (row.Text == string.Empty)
{
_sprite.LayerSetTexture(queued.Entity.Owner, row.Layer, null);
continue;
}
var dimensions = screenHandle.GetDimensions(queued.Font, row.Text, 1f);
var dimensionsInt = new Vector2i((int)MathF.Round(dimensions.X), (int)MathF.Round(dimensions.Y));
if (row.Texture is null || row.Texture.Size != dimensionsInt)
{
row.Texture = _clyde.CreateRenderTarget(dimensionsInt,
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8),
name: $"dv-text-visuals-{queued.Entity.Owner.Id}");
_sprite.LayerSetTexture(queued.Entity.Owner, row.Layer, row.Texture.Texture);
_sprite.LayerSetOffset(queued.Entity.Owner, row.Layer, row.Offset);
}
args.DrawingHandle.RenderInRenderTarget(row.Texture,
() =>
{
screenHandle.DrawString(font, Vector2.Zero, row.Text);
},
Color.Transparent);
}
_animationPlayer.Stop(queued.Entity.Owner, MarqueeKey);
if (CreateMarqueeAnimation(queued.Entity) is { } animation)
{
queued.Entity.Comp.Animation = animation;
_animationPlayer.Play(queued.Entity.Owner, animation, MarqueeKey);
}
}
}
private Animation? CreateMarqueeAnimation(Entity<DVTextVisualsComponent> ent)
{
var largestRowWidth = ent.Comp.Rows.Aggregate(0, (i, row) => Math.Max(i, row.Texture?.Size.X ?? 0));
var animationTime = ent.Comp.MarqueeRate * largestRowWidth;
var marqueeWidth = new Vector2((float)ent.Comp.MarqueeWidth / EyeManager.PixelsPerMeter, 0);
var animation = new Animation
{
Length = animationTime,
};
foreach (var row in ent.Comp.Rows)
{
if (row.Texture is null)
continue;
var rowHalfWidth = new Vector2(row.Texture.Size.X / 2f / EyeManager.PixelsPerMeter, 0f);
if (row.Texture.Size.X <= ent.Comp.MarqueeWidth)
continue;
animation.AnimationTracks.Add(new AnimationTrackLayerOffset()
{
Layer = row.Layer,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(row.Offset + rowHalfWidth + marqueeWidth, 0f),
new AnimationTrackProperty.KeyFrame(row.Offset - rowHalfWidth - marqueeWidth, (float)animationTime.TotalSeconds),
},
});
}
return animation.AnimationTracks.Count > 0 ? animation : null;
}
public sealed class AnimationTrackLayerOffset : AnimationTrackProperty
{
public required Enum Layer;
private readonly SpriteSystem _sprite = IoCManager.Resolve<IEntityManager>().System<SpriteSystem>();
protected override void ApplyProperty(object context, object value)
{
if (value is not Vector2 vector)
throw new InvalidOperationException("Value must be a .");
_sprite.LayerSetOffset((EntityUid) context, Layer, vector);
}
}
}
@@ -0,0 +1,43 @@
using System.Numerics;
using System.Threading;
using Content.Shared._DV.Screens;
using Robust.Client.Animations;
using Robust.Client.Graphics;
namespace Content.Client._DV.Screens;
[RegisterComponent]
[Access(typeof(DVTextVisualsSystem), typeof(DVTextRenderingOverlay))]
public sealed partial class DVTextVisualsComponent : Component
{
[DataField(required: true)]
public List<DVTextVisualsRow> Rows;
[DataField]
public TimeSpan MarqueeRate = TimeSpan.FromSeconds(0.045f);
[DataField]
public int MarqueeWidth = 24;
[DataField]
public int MarqueePadding = 8;
public Animation? Animation;
public CancellationTokenSource? Token;
}
[DataDefinition]
public sealed partial class DVTextVisualsRow
{
public IRenderTexture? Texture;
[DataField]
public string Text;
[DataField]
public Vector2 Offset;
[DataField(required: true)]
public Enum Layer = DVTextScreenVisualLayers.Line1;
}
@@ -0,0 +1,73 @@
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
namespace Content.Client._DV.Screens;
public sealed class DVTextVisualsSystem : EntitySystem
{
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly IResourceCache _resource = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
private DVTextRenderingOverlay _textRendering = default!;
private Font _font = default!;
public override void Initialize()
{
base.Initialize();
_textRendering = new(_sprite, _animationPlayer);
_overlay.AddOverlay(_textRendering);
_font = new VectorFont(_resource.GetResource<FontResource>("/Fonts/_DV/TinyUnicode.ttf"), 12);
SubscribeLocalEvent<DVTextVisualsComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<DVTextVisualsComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<DVTextVisualsComponent, AnimationCompletedEvent>(OnAnimationComplete);
}
public override void Shutdown()
{
_overlay.RemoveOverlay(_textRendering);
}
private void OnComponentInit(Entity<DVTextVisualsComponent> ent, ref ComponentInit args)
{
ent.Comp.Token = _textRendering.QueueRender(ent, _font);
}
private void OnComponentShutdown(Entity<DVTextVisualsComponent> ent, ref ComponentShutdown args)
{
foreach (var row in ent.Comp.Rows)
{
row.Texture?.Dispose();
}
ent.Comp.Token?.Cancel();
}
private void OnAnimationComplete(Entity<DVTextVisualsComponent> ent, ref AnimationCompletedEvent args)
{
if (args.Key != DVTextRenderingOverlay.MarqueeKey || !args.Finished || ent.Comp.Animation is not { } animation)
return;
_animationPlayer.Play(ent.Owner, animation, DVTextRenderingOverlay.MarqueeKey);
}
public void SetText(Entity<DVTextVisualsComponent?> ent, params string[] rows)
{
if (!Resolve(ent, ref ent.Comp))
return;
var count = Math.Min(rows.Length, ent.Comp.Rows.Count);
for (var i = 0; i < count; i++)
{
ent.Comp.Rows[i].Text = rows[i];
}
ent.Comp.Token?.Cancel();
ent.Comp.Token = _textRendering.QueueRender((ent, ent.Comp), _font);
}
}
@@ -0,0 +1,23 @@
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using static Content.Client.Stylesheets.StylesheetHelpers;
namespace Content.Client._DV.Stylesheets.Sheetlets;
[CommonSheetlet]
public sealed class DVLineEditSheetlet : Sheetlet<PalettedStylesheet>
{
public override StyleRule[] GetRules(PalettedStylesheet sheet, object config)
{
var tinyUnicode = ResCache.GetFont("/Fonts/_DV/TinyUnicode.ttf", size: 24);
return
[
E<LineEdit>()
.Class("comms-console-display")
.Font(tinyUnicode),
];
}
}
@@ -1,6 +1,7 @@
using Content.Server.Chat.Systems; using Content.Server.Chat.Systems;
using Content.Server.GameTicking; using Content.Server.GameTicking;
using Content.Server.Ninja.Systems; using Content.Server.Ninja.Systems;
using Content.Shared._DV.Communications; // DeltaV Comms Console
using Content.Shared.Communications; using Content.Shared.Communications;
using Content.Shared.DoAfter; using Content.Shared.DoAfter;
using Content.Shared.Interaction; using Content.Shared.Interaction;
@@ -35,7 +36,7 @@ public sealed class CommsHackerSystem : SharedCommsHackerSystem
/// </summary> /// </summary>
private void OnBeforeInteractHand(EntityUid uid, CommsHackerComponent comp, BeforeInteractHandEvent args) private void OnBeforeInteractHand(EntityUid uid, CommsHackerComponent comp, BeforeInteractHandEvent args)
{ {
if (args.Handled || !HasComp<CommunicationsConsoleComponent>(args.Target)) if (args.Handled || !HasComp<DVCommunicationsConsoleComponent>(args.Target)) // DeltaV - Comms Console
return; return;
// TODO: generic check event // TODO: generic check event
@@ -23,7 +23,7 @@ using Robust.Shared.Configuration;
namespace Content.Server.Communications namespace Content.Server.Communications
{ {
public sealed partial class CommunicationsConsoleSystem : EntitySystem // DeltaV - Partial Class public sealed class CommunicationsConsoleSystem : EntitySystem
{ {
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!; [Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
[Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!; [Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!;
@@ -53,8 +53,6 @@ namespace Content.Server.Communications
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleCallEmergencyShuttleMessage>(OnCallShuttleMessage); SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleCallEmergencyShuttleMessage>(OnCallShuttleMessage);
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleRecallEmergencyShuttleMessage>(OnRecallShuttleMessage); SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleRecallEmergencyShuttleMessage>(OnRecallShuttleMessage);
InitializeExfiltration(); // DeltaV - Exfiltration shuttle
// On console init, set cooldown // On console init, set cooldown
SubscribeLocalEvent<CommunicationsConsoleComponent, MapInitEvent>(OnCommunicationsConsoleMapInit); SubscribeLocalEvent<CommunicationsConsoleComponent, MapInitEvent>(OnCommunicationsConsoleMapInit);
} }
@@ -138,7 +136,6 @@ namespace Content.Server.Communications
List<string>? levels = null; List<string>? levels = null;
string currentLevel = default!; string currentLevel = default!;
float currentDelay = 0; float currentDelay = 0;
TimeSpan? exfiltrationTime = null; // DeltaV - exfiltration shuttle
if (stationUid != null) if (stationUid != null)
{ {
@@ -160,12 +157,6 @@ namespace Content.Server.Communications
currentLevel = alertComp.CurrentLevel; currentLevel = alertComp.CurrentLevel;
currentDelay = _alertLevelSystem.GetAlertLevelDelay(stationUid.Value, alertComp); currentDelay = _alertLevelSystem.GetAlertLevelDelay(stationUid.Value, alertComp);
} }
// Begin DeltaV - exfiltration shuttle
if (TryComp<StationExfiltrationComponent>(stationUid, out var exfiltration))
{
exfiltrationTime = exfiltration.ArrivalTime;
}
// End DeltaV - exfiltration shuttle
} }
_uiSystem.SetUiState(uid, CommunicationsConsoleUiKey.Key, new CommunicationsConsoleInterfaceState( _uiSystem.SetUiState(uid, CommunicationsConsoleUiKey.Key, new CommunicationsConsoleInterfaceState(
@@ -174,8 +165,7 @@ namespace Content.Server.Communications
levels, levels,
currentLevel, currentLevel,
currentDelay, currentDelay,
_roundEndSystem.ExpectedCountdownEnd, _roundEndSystem.ExpectedCountdownEnd
exfiltrationTime // DeltaV - exfiltration shuttle
)); ));
} }
@@ -30,6 +30,17 @@ public sealed partial class EmergencyLightComponent : SharedEmergencyLightCompon
[DataField("chargingEfficiency")] [DataField("chargingEfficiency")]
public float ChargingEfficiency = 0.85f; public float ChargingEfficiency = 0.85f;
// Begin DeltaV Additions
[DataField]
public float MaydayRadius = 10f;
[DataField]
public float MaydayFalloff = 0f;
[DataField]
public float MaydayEnergy = 0.7f;
// End DeltaV Additions
public Dictionary<EmergencyLightState, string> BatteryStateText = new() public Dictionary<EmergencyLightState, string> BatteryStateText = new()
{ {
{ EmergencyLightState.Full, "emergency-light-component-light-state-full" }, { EmergencyLightState.Full, "emergency-light-component-light-state-full" },
@@ -1,32 +0,0 @@
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<CommunicationsConsoleComponent, CommunicationsConsoleExfiltrationShuttleMessage>(OnExfiltrationMessage);
}
private void OnExfiltrationMessage(Entity<CommunicationsConsoleComponent> 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);
}
}
@@ -0,0 +1,184 @@
using Content.Server._DV.Station.Components;
using Content.Server._DV.Station.Systems;
using Content.Server.AlertLevel;
using Content.Server.Communications;
using Content.Server.RoundEnd;
using Content.Server.Shuttles.Systems;
using Content.Shared._DV.Communications;
using Content.Shared.CCVar;
using Content.Shared.Database;
using Content.Shared.Station;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
namespace Content.Server._DV.Communications;
public sealed class DVCommunicationsConsoleSystem : SharedDVCommunicationsConsoleSystem
{
[Dependency] private readonly SharedStationSystem _station = default!;
[Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly RoundEndSystem _roundEnd = default!;
[Dependency] private readonly IConfigurationManager _configuration = default!;
[Dependency] private readonly AlertLevelSystem _alertLevel = default!;
[Dependency] private readonly StationExfiltrationSystem _stationExfiltration = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RoundEndSystemChangedEvent>(OnRoundEndChanged);
SubscribeLocalEvent<StationExfiltrationChangedEvent>(OnExfiltrationChanged);
SubscribeLocalEvent<AlertLevelChangedEvent>(OnAlertLevelChanged);
}
private void OnAlertLevelChanged(AlertLevelChangedEvent ev)
{
var query = EntityQueryEnumerator<DVCommunicationsConsoleComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (_station.GetOwningStation(uid) != ev.Station)
continue;
var alertLevel = Comp<AlertLevelComponent>(ev.Station);
comp.CanSetAlertAt = Timing.CurTime + TimeSpan.FromSeconds(alertLevel.CurrentDelay);
comp.CurrentAlertLevel = ev.AlertLevel;
if (alertLevel.IsLevelLocked)
comp.CanSetAlertAt = null;
Dirty(uid, comp);
}
}
private void OnExfiltrationChanged(ref StationExfiltrationChangedEvent ev)
{
var query = EntityQueryEnumerator<DVCommunicationsConsoleComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (_station.GetOwningStation(uid) != ev.Station)
continue;
comp.ExpectedExfiltrationArrival = ev.Station.Comp.ArrivalTime;
Dirty(uid, comp);
}
}
private void OnRoundEndChanged(RoundEndSystemChangedEvent ev)
{
var query = EntityQueryEnumerator<DVCommunicationsConsoleComponent>();
while (query.MoveNext(out var uid, out var comp))
{
comp.ExpectedEvacuationArrival = _roundEnd.ExpectedCountdownEnd;
comp.ExpectedEvacuationDuration = _roundEnd.ExpectedShuttleLength;
comp.ShuttlesCallable = ShuttlesCallable();
Dirty(uid, comp);
}
}
protected override void OnMapInit(Entity<DVCommunicationsConsoleComponent> ent, ref MapInitEvent args)
{
base.OnMapInit(ent, ref args);
if (_station.GetOwningStation(ent) is not { } station)
return;
if (!TryComp<AlertLevelComponent>(station, out var alertLevel))
return;
ent.Comp.CurrentAlertLevel = alertLevel.CurrentLevel;
var proto = _prototype.Index<AlertLevelPrototype>(alertLevel.AlertLevelPrototype);
foreach (var (name, detail) in proto.Levels)
{
ent.Comp.AlertLevels.Add(new($"alert-level-{name}", $"alert-level-{name}-announcement", name, !detail.DisableSelection, detail.Color));
}
ent.Comp.CanSetAlertAt = Timing.CurTime + TimeSpan.FromSeconds(alertLevel.CurrentDelay);
if (alertLevel.IsLevelLocked)
ent.Comp.CanSetAlertAt = null;
ent.Comp.ShuttlesCallable = ShuttlesCallable();
ent.Comp.ExpectedEvacuationArrival = _roundEnd.ExpectedCountdownEnd;
ent.Comp.ExpectedEvacuationDuration = _roundEnd.ExpectedShuttleLength;
if (TryComp<StationExfiltrationComponent>(station, out var exfiltration))
ent.Comp.ExpectedExfiltrationArrival = exfiltration.ArrivalTime;
Dirty(ent);
}
private bool ShuttlesCallable()
{
// Defer to what the round end system thinks we should be able to do.
if (_emergencyShuttle.EmergencyShuttleArrived || !_roundEnd.CanCallOrRecall())
return false;
// Calling shuttle checks
if (_roundEnd.ExpectedCountdownEnd is null)
return true;
// Recalling shuttle checks
var recallThreshold = _configuration.GetCVar(CCVars.EmergencyRecallTurningPoint);
// shouldn't really be happening if we got here
if (_roundEnd.ShuttleTimeLeft is not { } left
|| _roundEnd.ExpectedShuttleLength is not { } expected)
return false;
return !(left.TotalSeconds / expected.TotalSeconds < recallThreshold);
}
protected override void OnAlertLevel(Entity<DVCommunicationsConsoleComponent> ent, ref DVCommunicationsConsoleAlertLevelMessage args)
{
base.OnAlertLevel(ent, ref args);
if (!AccessReader.IsAllowed(ent, args.Actor))
return;
if (_station.GetOwningStation(ent) is not { } station)
return;
_alertLevel.SetLevel(station, args.AlertLevel, true, true);
AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):player} has set the alert level to {args.AlertLevel:level} on {ToPrettyString(station):station} using {ToPrettyString(ent):console}");
}
protected override void OnEvacuationShuttle(Entity<DVCommunicationsConsoleComponent> ent, ref DVCommunicationsConsoleEvacuationShuttleMessage args)
{
base.OnEvacuationShuttle(ent, ref args);
if (!AccessReader.IsAllowed(ent, args.Actor))
return;
if (args.Call)
{
var ev = new CommunicationConsoleCallShuttleAttemptEvent(ent, default!, args.Actor);
RaiseLocalEvent(ref ev);
_roundEnd.RequestRoundEnd(args.Actor);
AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):player} has called the evacuation shuttle using {ToPrettyString(ent):console}");
}
else
{
_roundEnd.CancelRoundEndCountdown(args.Actor);
AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):player} has recalled the evacuation shuttle using {ToPrettyString(ent):console}");
}
}
protected override void OnExfiltrationShuttle(Entity<DVCommunicationsConsoleComponent> ent, ref DVCommunicationsConsoleExfiltrationShuttleMessage args)
{
base.OnExfiltrationShuttle(ent, ref args);
if (!AccessReader.IsAllowed(ent, args.Actor))
return;
if (_station.GetOwningStation(ent) is not { } station)
return;
if (args.Call)
{
_stationExfiltration.Call(station);
AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):player} has called the exfiltration shuttle using {ToPrettyString(ent):console}");
}
else
{
_stationExfiltration.Recall(station);
AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):player} has recalled the exfiltration shuttle using {ToPrettyString(ent):console}");
}
}
}
@@ -0,0 +1,88 @@
using Content.Server.AlertLevel;
using Content.Server.Audio.Jukebox;
using Content.Server.Instruments;
using Content.Server.Light.Components;
using Content.Server.Light.EntitySystems;
using Content.Server.Nuke;
using Content.Server.RoundEnd;
using Content.Shared._DV.KeycardAuthenticationDevice;
using Content.Shared.Audio.Jukebox;
using Content.Shared.Light.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.Server._DV.KeycardAuthenticationDevice;
public sealed class DVStationKeycardAuthenticationDeviceSystem : SharedDVStationKeycardAuthenticationDeviceSystem
{
[Dependency] private readonly NukeCodePaperSystem _nukeCodePaper = default!;
[Dependency] private readonly AlertLevelSystem _alertLevel = default!;
[Dependency] private readonly RoundEndSystem _roundEnd = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly PoweredLightSystem _poweredLight = default!;
[Dependency] private readonly PointLightSystem _pointLight = default!;
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
[Dependency] private readonly JukeboxSystem _jukebox = default!;
protected override void Mayday(Entity<DVStationKeycardAuthenticationDeviceComponent> station)
{
base.Mayday(station);
_alertLevel.SetLevel(station, "zeta", true, true, true, true);
var alertLevel = Comp<AlertLevelComponent>(station);
var level = _prototype.Index<AlertLevelPrototype>(alertLevel.AlertLevelPrototype).Levels[alertLevel.CurrentLevel];
_roundEnd.RequestRoundEnd(level.ShuttleTime, null, null, false, cantRecall: true);
var bulbQuery = GetEntityQuery<LightBulbComponent>();
var tubeQuery = EntityQueryEnumerator<PoweredLightComponent>();
while (tubeQuery.MoveNext(out var uid, out var light))
{
if (Station.GetOwningStation(uid) != station.Owner)
continue;
if (_poweredLight.GetBulb(uid, light) is not { } bulb || !bulbQuery.TryComp(bulb, out var bulbComp))
continue;
bulbComp.LightEnergy /= 2;
bulbComp.PowerUse /= 2;
_poweredLight.SetState(uid, light.On, light);
}
var emergencyQuery = EntityQueryEnumerator<EmergencyLightComponent, PointLightComponent>();
while (emergencyQuery.MoveNext(out var uid, out var emergency, out var light))
{
if (Station.GetOwningStation(uid) != station.Owner)
continue;
_pointLight.SetEnergy(uid, emergency.MaydayEnergy, light);
_pointLight.SetRadius(uid, emergency.MaydayRadius, light);
_pointLight.SetFalloff(uid, emergency.MaydayFalloff, light);
}
var instrumentQuery = EntityQueryEnumerator<InstrumentComponent>();
while (instrumentQuery.MoveNext(out var uid, out _))
{
if (Station.GetOwningStation(uid) != station.Owner)
continue;
_userInterface.CloseUis(uid);
}
var jukeboxQuery = EntityQueryEnumerator<JukeboxComponent>();
while (jukeboxQuery.MoveNext(out var uid, out var jukebox))
{
if (Station.GetOwningStation(uid) != station.Owner)
continue;
_jukebox.Stop((uid, jukebox));
}
}
protected override void Scuttling(Entity<DVStationKeycardAuthenticationDeviceComponent> station)
{
base.Scuttling(station);
_nukeCodePaper.SendNukeCodes(station);
}
}
@@ -0,0 +1,111 @@
using Content.Server.AlertLevel;
using Content.Server.Screens.Components;
using Content.Shared._DV.Communications;
using Content.Shared._DV.Screens;
using Content.Shared.DeviceNetwork.Events;
using Content.Shared.Station;
using Robust.Shared.Timing;
namespace Content.Server._DV.Screens;
public sealed class DVScreenSystem : DVSharedScreenSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedStationSystem _station = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DVScreenComponent, DeviceNetworkPacketEvent>(OnPacket);
SubscribeLocalEvent<AlertLevelChangedEvent>(OnAlertLevelChanged);
}
private void OnPacket(Entity<DVScreenComponent> ent, ref DeviceNetworkPacketEvent args)
{
if (args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out _))
OnShuttlePacket(ent, ref args);
if (args.Data.TryGetValue(DVScreenPackets.Text, out (string, string)? text))
OnTextPacket(ent, text.Value, ref args);
if (args.Data.TryGetValue(DVScreenPackets.ShowBorders, out bool? showBorders))
OnBordersPacket(ent, showBorders.Value, ref args);
if (args.Data.TryGetValue(DVScreenPackets.Content, out DVScreenContent? content))
OnContentPacket(ent, content.Value, ref args);
}
private void OnShuttlePacket(Entity<DVScreenComponent> ent, ref DeviceNetworkPacketEvent args)
{
var xform = Transform(ent);
args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out EntityUid? shuttleMap);
args.Data.TryGetValue(ShuttleTimerMasks.SourceMap, out EntityUid? source);
args.Data.TryGetValue(ShuttleTimerMasks.DestMap, out EntityUid? dest);
args.Data.TryGetValue(ShuttleTimerMasks.Docked, out bool docked);
var screenIsAtDestination = docked;
string key;
switch (xform.MapUid)
{
// sometimes the timer transforms on FTL shuttles have a hyperspace mapuid, so matching by grid works as a fallback.
case var local when local == shuttleMap || xform.GridUid == shuttleMap:
key = ShuttleTimerMasks.ShuttleTime;
break;
case var origin when origin == source:
key = ShuttleTimerMasks.SourceTime;
break;
case var remote when remote == dest:
key = ShuttleTimerMasks.DestTime;
screenIsAtDestination = false;
break;
default:
return;
}
if (!args.Data.TryGetValue(key, out TimeSpan duration))
return;
ent.Comp.ScreenIsAtDestination = screenIsAtDestination;
ent.Comp.TargetTime = _timing.CurTime + duration;
Dirty(ent);
UpdateVisuals(ent);
}
private void OnTextPacket(Entity<DVScreenComponent> ent, (string, string) text, ref DeviceNetworkPacketEvent args)
{
ent.Comp.Line1 = text.Item1;
ent.Comp.Line2 = text.Item2;
Dirty(ent);
UpdateVisuals(ent);
}
private void OnBordersPacket(Entity<DVScreenComponent> ent, bool showBorders, ref DeviceNetworkPacketEvent args)
{
ent.Comp.ShowAlertBorder = showBorders;
Dirty(ent);
UpdateVisuals(ent);
}
private void OnContentPacket(Entity<DVScreenComponent> ent, DVScreenContent content, ref DeviceNetworkPacketEvent args)
{
ent.Comp.Content = content;
Dirty(ent);
UpdateVisuals(ent);
}
private void OnAlertLevelChanged(AlertLevelChangedEvent ev)
{
var query = EntityQueryEnumerator<DVScreenComponent>();
while (query.MoveNext(out var uid, out var screen))
{
if (_station.GetOwningStation(uid) != ev.Station)
continue;
screen.AlertLevel = ev.AlertLevel;
Dirty(uid, screen);
UpdateVisuals((uid, screen));
}
}
}
@@ -32,7 +32,6 @@ public sealed class StationExfiltrationSystem : EntitySystem
[Dependency] private readonly ShuttleSystem _shuttle = default!; [Dependency] private readonly ShuttleSystem _shuttle = default!;
[Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly NavMapSystem _navMap = default!; [Dependency] private readonly NavMapSystem _navMap = default!;
[Dependency] private readonly CommunicationsConsoleSystem _communicationsConsole = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -169,7 +168,8 @@ public sealed class StationExfiltrationSystem : EntitySystem
_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); _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(); var evt = new StationExfiltrationChangedEvent((ent, ent.Comp), true);
RaiseLocalEvent(ref evt);
} }
public void Recall(Entity<StationExfiltrationComponent?> ent) public void Recall(Entity<StationExfiltrationComponent?> ent)
@@ -180,6 +180,10 @@ public sealed class StationExfiltrationSystem : EntitySystem
ent.Comp.ArrivalTime = null; ent.Comp.ArrivalTime = null;
_chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.RecalledAnnouncement, ("station", Name(ent))), sender: Loc.GetString(ent.Comp.Sender), colorOverride: Color.Gold); _chat.DispatchStationAnnouncement(ent, Loc.GetString(ent.Comp.RecalledAnnouncement, ("station", Name(ent))), sender: Loc.GetString(ent.Comp.Sender), colorOverride: Color.Gold);
_communicationsConsole.UpdateCommsConsoleInterface(); var evt = new StationExfiltrationChangedEvent((ent, ent.Comp), false);
RaiseLocalEvent(ref evt);
} }
} }
[ByRefEvent]
public readonly record struct StationExfiltrationChangedEvent(Entity<StationExfiltrationComponent> Station, bool Exfiltrating);
@@ -1,7 +1,7 @@
using Content.Server._DV.StationEvents.Components; using Content.Server._DV.StationEvents.Components;
using Content.Server.Antag; using Content.Server.Antag;
using Content.Server.Communications;
using Content.Server.StationEvents.Events; using Content.Server.StationEvents.Events;
using Content.Shared._DV.Communications;
using Content.Shared.Forensics.Components; using Content.Shared.Forensics.Components;
using Content.Shared.GameTicking.Components; using Content.Shared.GameTicking.Components;
using Content.Shared.Ghost; using Content.Shared.Ghost;
@@ -43,7 +43,7 @@ public sealed class FugitiveRule : StationEventSystem<FugitiveRuleComponent>
ChatSystem.DispatchGlobalAnnouncement(announcement, sender: sender, colorOverride: comp.Color); ChatSystem.DispatchGlobalAnnouncement(announcement, sender: sender, colorOverride: comp.Color);
// send the report to every comms console on the station // send the report to every comms console on the station
var query = EntityQueryEnumerator<TransformComponent, CommunicationsConsoleComponent>(); var query = EntityQueryEnumerator<TransformComponent, DVCommunicationsConsoleComponent>();
var consoles = new List<TransformComponent>(); var consoles = new List<TransformComponent>();
while (query.MoveNext(out var console, out var xform, out _)) while (query.MoveNext(out var console, out var xform, out _))
{ {
@@ -18,9 +18,8 @@ namespace Content.Shared.Communications
public List<string>? AlertLevels; public List<string>? AlertLevels;
public string CurrentAlert; public string CurrentAlert;
public float CurrentAlertDelay; public float CurrentAlertDelay;
public readonly TimeSpan? ExpectedExfiltrationCountdownEnd;
public CommunicationsConsoleInterfaceState(bool canAnnounce, bool canCall, List<string>? alertLevels, string currentAlert, float currentAlertDelay, TimeSpan? expectedCountdownEnd, TimeSpan? expectedExfiltrationCountdownEnd) // DeltaV - Exfiltration Shuttle public CommunicationsConsoleInterfaceState(bool canAnnounce, bool canCall, List<string>? alertLevels, string currentAlert, float currentAlertDelay, TimeSpan? expectedCountdownEnd)
{ {
CanAnnounce = canAnnounce; CanAnnounce = canAnnounce;
CanCall = canCall; CanCall = canCall;
@@ -29,7 +28,6 @@ namespace Content.Shared.Communications
AlertLevels = alertLevels; AlertLevels = alertLevels;
CurrentAlert = currentAlert; CurrentAlert = currentAlert;
CurrentAlertDelay = currentAlertDelay; CurrentAlertDelay = currentAlertDelay;
ExpectedExfiltrationCountdownEnd = expectedExfiltrationCountdownEnd; // DeltaV - Exfiltration Shuttle
} }
} }
@@ -1,9 +0,0 @@
using Robust.Shared.Serialization;
namespace Content.Shared._DV.Communications;
[Serializable, NetSerializable]
public sealed class CommunicationsConsoleExfiltrationShuttleMessage(bool call) : BoundUserInterfaceMessage
{
public readonly bool Call = call;
}
@@ -0,0 +1,136 @@
using Content.Shared._DV.KeycardAuthenticationDevice;
using Content.Shared._DV.Screens;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared._DV.Communications;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
[Access(typeof(SharedDVCommunicationsConsoleSystem))]
public sealed partial class DVCommunicationsConsoleComponent : Component
{
[DataField]
public LocId AnnouncementTitle = "comms-console-announcement-title-station";
[DataField]
public Color AnnouncementColor = Color.Gold;
[DataField]
public SoundSpecifier AnnouncementSound = new SoundPathSpecifier("/Audio/Announcements/announce.ogg");
[DataField, AutoNetworkedField]
public bool GlobalAnnouncements;
[DataField, AutoNetworkedField]
public bool CanAnnounce = true;
[DataField, AutoNetworkedField]
public bool CanAlertLevel = true;
[DataField, AutoNetworkedField]
public bool CanCallShuttles = true;
[DataField, AutoNetworkedField]
public bool CanConfigureScreens = true;
[DataField, AutoNetworkedField]
public bool CanKeycardAuthenticationDevice = true;
[DataField, AutoNetworkedField]
public TimeSpan CanAnnounceAt = TimeSpan.Zero;
[DataField]
public TimeSpan AnnouncementInterval = TimeSpan.FromSeconds(90f);
[DataField]
public TimeSpan InitialAnnouncementDelay = TimeSpan.FromSeconds(30f);
[DataField, AutoNetworkedField]
public string CurrentAlertLevel = string.Empty;
[DataField, AutoNetworkedField]
public List<DVCommunicationsConsoleAlertLevel> AlertLevels = new();
[DataField, AutoNetworkedField]
public TimeSpan? CanSetAlertAt = TimeSpan.Zero;
[DataField, AutoNetworkedField]
public bool ShuttlesCallable = true;
[DataField, AutoNetworkedField]
public TimeSpan? ExpectedEvacuationArrival;
[DataField, AutoNetworkedField]
public TimeSpan? ExpectedEvacuationDuration;
[DataField, AutoNetworkedField]
public TimeSpan? ExpectedExfiltrationArrival;
[DataField, AutoNetworkedField]
public DVScreenContent LastConfiguredContent = DVScreenContent.Text;
[DataField, AutoNetworkedField]
public bool LastConfiguredShowBorders;
[DataField, AutoNetworkedField]
public string LastConfiguredLine1 = string.Empty;
[DataField, AutoNetworkedField]
public string LastConfiguredLine2 = string.Empty;
}
[Serializable, NetSerializable]
public readonly record struct DVCommunicationsConsoleAlertLevel(LocId AlertLevel, LocId Description, string Id, bool CanSet, Color Color);
[Serializable, NetSerializable]
public sealed class DVCommunicationsConsoleEvacuationShuttleMessage(bool call) : BoundUserInterfaceMessage
{
public readonly bool Call = call;
}
[Serializable, NetSerializable]
public sealed class DVCommunicationsConsoleExfiltrationShuttleMessage(bool call) : BoundUserInterfaceMessage
{
public readonly bool Call = call;
}
[Serializable, NetSerializable]
public sealed class DVCommunicationsConsoleKeycardAuthenticationDeviceMessage(DVStationKeycardAction action) : BoundUserInterfaceMessage
{
public readonly DVStationKeycardAction Action = action;
}
[Serializable, NetSerializable]
public sealed class DVCommunicationsConsoleAnnouncementMessage(string announcement) : BoundUserInterfaceMessage
{
public readonly string Announcement = announcement;
}
[Serializable, NetSerializable]
public sealed class DVCommunicationsConsoleAlertLevelMessage(string alertLevel) : BoundUserInterfaceMessage
{
public readonly string AlertLevel = alertLevel;
}
[Serializable, NetSerializable]
public sealed class DVCommunicationsConsoleScreenConfigurationMessage(DVScreenContent content, bool showBorder, string line1, string line2) : BoundUserInterfaceMessage
{
public readonly DVScreenContent Content = content;
public readonly bool ShowBorder = showBorder;
public readonly string Line1 = line1;
public readonly string Line2 = line2;
}
[Serializable, NetSerializable]
public enum DVCommunicationsConsoleUi : byte
{
Key,
}
public static class DVScreenPackets
{
public const string Content = "dv-screen-content";
public const string ShowBorders = "dv-screen-borders";
public const string Text = "dv-screen-text";
}
@@ -0,0 +1,148 @@
using Content.Shared._DV.KeycardAuthenticationDevice;
using Content.Shared._DV.Screens;
using Content.Shared.Access.Systems;
using Content.Shared.Administration.Logs;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.DeviceNetwork;
using Content.Shared.DeviceNetwork.Events;
using Content.Shared.DeviceNetwork.Systems;
using Content.Shared.IdentityManagement;
using Robust.Shared.Timing;
namespace Content.Shared._DV.Communications;
public abstract class SharedDVCommunicationsConsoleSystem : EntitySystem
{
[Dependency] private readonly SharedDeviceNetworkSystem _deviceNetwork = default!;
[Dependency] protected readonly IGameTiming Timing = default!;
[Dependency] private readonly SharedChatSystem _chat = default!;
[Dependency] protected readonly AccessReaderSystem AccessReader = default!;
[Dependency] protected readonly ISharedAdminLogManager AdminLog = default!;
[Dependency] private readonly SharedDVStationKeycardAuthenticationDeviceSystem _stationKeycardAuthenticationDevice = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DVCommunicationsConsoleComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<DVCommunicationsConsoleComponent, DeviceNetworkPacketEvent>(OnPacketReceive);
Subs.BuiEvents<DVCommunicationsConsoleComponent>(DVCommunicationsConsoleUi.Key,
subs =>
{
subs.Event<DVCommunicationsConsoleEvacuationShuttleMessage>(OnEvacuationShuttle);
subs.Event<DVCommunicationsConsoleExfiltrationShuttleMessage>(OnExfiltrationShuttle);
subs.Event<DVCommunicationsConsoleScreenConfigurationMessage>(OnConfiguration);
subs.Event<DVCommunicationsConsoleAnnouncementMessage>(OnAnnouncement);
subs.Event<DVCommunicationsConsoleAlertLevelMessage>(OnAlertLevel);
subs.Event<DVCommunicationsConsoleKeycardAuthenticationDeviceMessage>(OnKeycardAuthenticationDevice);
});
}
private void OnPacketReceive(Entity<DVCommunicationsConsoleComponent> ent, ref DeviceNetworkPacketEvent args)
{
if (args.Data.TryGetValue(DVScreenPackets.Text, out (string, string)? text))
{
ent.Comp.LastConfiguredLine1 = text.Value.Item1;
ent.Comp.LastConfiguredLine2 = text.Value.Item2;
Dirty(ent);
}
if (args.Data.TryGetValue(DVScreenPackets.ShowBorders, out bool? showBorders))
{
ent.Comp.LastConfiguredShowBorders = showBorders.Value;
Dirty(ent);
}
if (args.Data.TryGetValue(DVScreenPackets.Content, out DVScreenContent? content))
{
ent.Comp.LastConfiguredContent = content.Value;
Dirty(ent);
}
}
protected virtual void OnMapInit(Entity<DVCommunicationsConsoleComponent> ent, ref MapInitEvent args)
{
ent.Comp.CanAnnounceAt = Timing.CurTime + ent.Comp.InitialAnnouncementDelay;
Dirty(ent);
}
private void OnAnnouncement(Entity<DVCommunicationsConsoleComponent> ent, ref DVCommunicationsConsoleAnnouncementMessage args)
{
if (!ent.Comp.CanAnnounce)
return;
if (Timing.CurTime <= ent.Comp.CanAnnounceAt)
return;
if (!AccessReader.IsAllowed(args.Actor, ent))
return;
var identity = new TryGetIdentityShortInfoEvent(ent, args.Actor);
RaiseLocalEvent(identity);
Loc.TryGetString(ent.Comp.AnnouncementTitle, out var title);
title ??= ent.Comp.AnnouncementTitle;
var msg = args.Announcement;
msg += "\n" + Loc.GetString("comms-console-announcement-sent-by") + " " + identity.Title;
if (ent.Comp.GlobalAnnouncements)
{
_chat.DispatchGlobalAnnouncement(msg, title, announcementSound: ent.Comp.AnnouncementSound, colorOverride: ent.Comp.AnnouncementColor);
AdminLog.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(args.Actor):player} sent the following global announcement using {ToPrettyString(ent):console}: {msg:message}");
}
else
{
_chat.DispatchStationAnnouncement(ent, msg, title, announcementSound: ent.Comp.AnnouncementSound, colorOverride: ent.Comp.AnnouncementColor);
AdminLog.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(args.Actor):player} sent the following station announcement using {ToPrettyString(ent):console}: {msg:message}");
}
ent.Comp.CanAnnounceAt = Timing.CurTime + ent.Comp.AnnouncementInterval;
Dirty(ent);
}
private void OnConfiguration(Entity<DVCommunicationsConsoleComponent> ent, ref DVCommunicationsConsoleScreenConfigurationMessage args)
{
if (!ent.Comp.CanConfigureScreens)
return;
if (!AccessReader.IsAllowed(args.Actor, ent))
return;
ent.Comp.LastConfiguredLine1 = args.Line1;
ent.Comp.LastConfiguredLine2 = args.Line2;
ent.Comp.LastConfiguredShowBorders = args.ShowBorder;
ent.Comp.LastConfiguredContent = args.Content;
Dirty(ent);
var payload = new NetworkPayload
{
[DVScreenPackets.Content] = args.Content,
[DVScreenPackets.ShowBorders] = args.ShowBorder,
[DVScreenPackets.Text] = (args.Line1, args.Line2),
};
AdminLog.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(args.Actor):player} configured the following text using {ToPrettyString(ent):console}: {args.Line1:line1} {args.Line2:line2}");
_deviceNetwork.QueuePacket(ent, null, payload);
}
protected virtual void OnExfiltrationShuttle(Entity<DVCommunicationsConsoleComponent> ent,
ref DVCommunicationsConsoleExfiltrationShuttleMessage args)
{
}
protected virtual void OnEvacuationShuttle(Entity<DVCommunicationsConsoleComponent> ent,
ref DVCommunicationsConsoleEvacuationShuttleMessage args)
{
}
protected virtual void OnAlertLevel(Entity<DVCommunicationsConsoleComponent> ent,
ref DVCommunicationsConsoleAlertLevelMessage args)
{
}
private void OnKeycardAuthenticationDevice(Entity<DVCommunicationsConsoleComponent> ent,
ref DVCommunicationsConsoleKeycardAuthenticationDeviceMessage args)
{
_stationKeycardAuthenticationDevice.TrySwipe(args.Actor, ent, args.Action);
}
}
@@ -0,0 +1,7 @@
using Robust.Shared.GameStates;
namespace Content.Shared._DV.KeycardAuthenticationDevice;
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedDVStationKeycardAuthenticationDeviceSystem))]
public sealed partial class DVStationKeycardAuthenticationDeviceAlreadySwipedComponent : Component;
@@ -0,0 +1,50 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared._DV.KeycardAuthenticationDevice;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
[Access(typeof(SharedDVStationKeycardAuthenticationDeviceSystem))]
public sealed partial class DVStationKeycardAuthenticationDeviceComponent : Component
{
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField]
public TimeSpan AccessibleAfter = TimeSpan.Zero;
[DataField]
public TimeSpan FailureDelay = TimeSpan.FromMinutes(2);
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField]
public TimeSpan? SwipesStartedAt = null;
[DataField]
public TimeSpan SwipeWindow = TimeSpan.FromSeconds(20);
[DataField(required: true)]
public Dictionary<DVStationKeycardAction, int> ActionThresholds;
[DataField, AutoNetworkedField]
public int Swipes;
[DataField, AutoNetworkedField]
public DVStationKeycardAction? SwipingFor;
[DataField]
public LocId FailureAnnouncementSender = "keycard-authentication-device-sender";
[DataField]
public LocId FailureAnnouncement = "keycard-authentication-device-warning";
[DataField]
public Color FailureAnnouncementColor = Color.FromHex("#e93a9a");
[DataField]
public TimeSpan FailureElectrocutionDuration = TimeSpan.FromSeconds(5);
}
[Serializable, NetSerializable]
public enum DVStationKeycardAction
{
Mayday,
Scuttling,
}
@@ -0,0 +1,124 @@
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Chat;
using Content.Shared.Electrocution;
using Content.Shared.Station;
using Robust.Shared.Audio;
using Robust.Shared.Timing;
namespace Content.Shared._DV.KeycardAuthenticationDevice;
public abstract class SharedDVStationKeycardAuthenticationDeviceSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] protected readonly SharedStationSystem Station = default!;
[Dependency] private readonly SharedElectrocutionSystem _electrocution = default!;
[Dependency] private readonly SharedChatSystem _chat = default!;
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<DVStationKeycardAuthenticationDeviceComponent>();
while (query.MoveNext(out var uid, out var keycard))
{
if (keycard.SwipesStartedAt is not { } startedAt || _timing.CurTime <= startedAt + keycard.SwipeWindow)
continue;
StopSwipes((uid, keycard), true);
}
}
private void StopSwipes(Entity<DVStationKeycardAuthenticationDeviceComponent> station, bool failed)
{
station.Comp.SwipesStartedAt = null;
station.Comp.Swipes = 0;
station.Comp.SwipingFor = null;
if (failed)
{
station.Comp.AccessibleAfter = _timing.CurTime + station.Comp.FailureDelay;
_chat.DispatchStationAnnouncement(station,
Loc.GetString(station.Comp.FailureAnnouncement),
Loc.GetString(station.Comp.FailureAnnouncementSender),
announcementSound: new SoundPathSpecifier("/Audio/_DV/Announcements/attention.ogg"),
colorOverride: station.Comp.FailureAnnouncementColor);
}
Dirty(station);
var query = EntityQueryEnumerator<DVStationKeycardAuthenticationDeviceAlreadySwipedComponent>();
while (query.MoveNext(out var uid, out _))
{
if (failed)
{
_electrocution.TryDoElectrocution(uid,
null,
10,
station.Comp.FailureElectrocutionDuration,
true,
ignoreInsulation: true);
}
RemCompDeferred<DVStationKeycardAuthenticationDeviceAlreadySwipedComponent>(uid);
}
}
private void Swipe(Entity<DVStationKeycardAuthenticationDeviceComponent> station, EntityUid user, DVStationKeycardAction action)
{
if (!station.Comp.ActionThresholds.TryGetValue(action, out var threshold))
return;
station.Comp.SwipesStartedAt ??= _timing.CurTime;
station.Comp.SwipingFor = action;
station.Comp.Swipes++;
AddComp<DVStationKeycardAuthenticationDeviceAlreadySwipedComponent>(user);
Dirty(station);
if (station.Comp.Swipes >= threshold)
{
StopSwipes(station, false);
DoAction(station, action);
}
}
private void DoAction(Entity<DVStationKeycardAuthenticationDeviceComponent> station, DVStationKeycardAction action)
{
switch (action)
{
case DVStationKeycardAction.Mayday:
Mayday(station);
break;
case DVStationKeycardAction.Scuttling:
Scuttling(station);
break;
}
}
protected virtual void Mayday(Entity<DVStationKeycardAuthenticationDeviceComponent> station)
{
}
protected virtual void Scuttling(Entity<DVStationKeycardAuthenticationDeviceComponent> station)
{
}
public void TrySwipe(EntityUid user, EntityUid console, DVStationKeycardAction action)
{
if (HasComp<DVStationKeycardAuthenticationDeviceAlreadySwipedComponent>(console))
return;
if (Station.GetOwningStation(user) is not { } station || !TryComp<DVStationKeycardAuthenticationDeviceComponent>(station, out var keycard))
return;
if (TryComp<AccessReaderComponent>(console, out var accessReader) && !_accessReader.IsAllowed(user, console, accessReader))
return;
if (keycard.SwipingFor is { } swipingFor && swipingFor != action)
return;
if (_timing.CurTime <= keycard.AccessibleAfter)
return;
Swipe((station, keycard), user, action);
}
}
@@ -0,0 +1,55 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared._DV.Screens;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause]
[Access(typeof(DVSharedScreenSystem))]
public sealed partial class DVScreenComponent : Component
{
[DataField, AutoNetworkedField]
public string? AlertLevel; // I don't like this but uhhh the prototype isn't client-accessible
[DataField, AutoNetworkedField]
public bool ShowAlertBorder;
[DataField, AutoNetworkedField]
public DVScreenContent Content = DVScreenContent.Text;
#region Text Screens
[DataField, AutoNetworkedField]
public string Line1 = string.Empty;
[DataField, AutoNetworkedField]
public string Line2 = string.Empty;
#endregion
#region ETA Screens
[DataField, AutoNetworkedField]
public bool ScreenIsAtDestination;
[DataField, AutoNetworkedField, AutoPausedField]
public TimeSpan TargetTime = TimeSpan.Zero;
#endregion
}
[Serializable, NetSerializable]
public enum DVScreenVisuals : byte
{
AlertLevel,
ShowAlertBorder,
Content,
}
[Serializable, NetSerializable]
public enum DVScreenContent : byte
{
Text,
CurrentTime,
EstimatedTimeOfArrival,
AlertLevel,
}
@@ -0,0 +1,13 @@
namespace Content.Shared._DV.Screens;
public abstract class DVSharedScreenSystem : EntitySystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
protected void UpdateVisuals(Entity<DVScreenComponent> ent)
{
_appearance.SetData(ent.Owner, DVScreenVisuals.AlertLevel, ent.Comp.AlertLevel ?? string.Empty);
_appearance.SetData(ent.Owner, DVScreenVisuals.ShowAlertBorder, ent.Comp.ShowAlertBorder);
_appearance.SetData(ent.Owner, DVScreenVisuals.Content, ent.Comp.Content);
}
}
@@ -0,0 +1,10 @@
using Robust.Shared.Serialization;
namespace Content.Shared._DV.Screens;
[Serializable, NetSerializable]
public enum DVTextScreenVisualLayers : byte
{
Line1,
Line2,
}
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,60 @@
comms-console-announcement-title-unauthorized = Unauthorized 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-shuttle-button-tooltip = Calls or recalls the exfiltration shuttle.
comms-console-menu-exfiltration-time-remaining = ETA of exfiltration shuttle: {$time} comms-console-menu-exfiltration-time-remaining = ETA of exfiltration shuttle: {$time}
comms-console-menu-recall-exfiltration = Recall exfiltration shuttle comms-console-menu-recall-exfiltration = Recall exfiltration shuttle
comms-console-menu-screen-content =
.Text = Text
.CurrentTime = Current Time
.EstimatedTimeOfArrival = ETA / ETD
.AlertLevel = Alert Level
comms-console-menu-tab =
.Announcement = Make an announcement
.Screen = Configure status displays
.Shuttles = Manage shuttles
.AlertLevel = Set the alert level
.KeycardAuthenticationDevice = Keycard Authentication Device
comms-console-menu-line-1 = Line 1:
comms-console-menu-line-2 = Line 2:
comms-console-menu-alert-level-border = Alert level border:
comms-console-menu-alert-level = Alert level
comms-console-menu-screen-contents = Screen contents:
comms-console-menu-send-announcement = Send announcement
comms-console-menu-update-screen-text = Update text
comms-console-menu-enable-border = Enable alert level border
comms-console-menu-home = Home
comms-console-menu-emergency-shuttle = Emergency shuttle
comms-console-menu-exfiltration-shuttle = Exfiltration shuttle
comms-console-menu-shuttle-not-coming = This shuttle is not currently requested.
comms-console-menu-shuttle-eta = This shuttle will arrive in {$time}.
comms-console-menu-screen-text = Screen text
comms-console-menu-screen-configuration = Screen options
comms-console-menu-current-alert-level = The current alert level is [color={$color}]{$name}[/color]. {$description}
comms-console-menu-change-alert-level = Change alert level
comms-console-menu-station-title = Station
comms-console-menu-transit-title = Transit
comms-console-menu-emergency-title = Emergency
comms-console-menu-declare-mayday =
.title = Declare mayday
.desc = Declare the station unfit for life and send out a distress signal to all nearby vessels. Requires two simultaneous authorizations.
.button = Declare Code Zeta
comms-console-menu-request-codes =
.title = Scuttle the station
.desc = Order the destruction of the station to prevent capture, containment breach, or further threats to the sector. Requires three simultaneous authorizations.
.button = Request nuclear authorization codes
comms-console-menu-call-emergency =
.True = Call emergency shuttle
.False = Recall emergency shuttle
comms-console-menu-call-exfiltration =
.True = Call exfiltration shuttle
.False = Recall exfiltration shuttle
comms-console-menu-announcement-text = Announcement text
@@ -0,0 +1,2 @@
keycard-authentication-device-sender = Keycard Authentication Device
keycard-authentication-device-warning = Unsuccessful authorization attempt of the keycard authentication device detected. Administering deterrence measures and initiating keycard authentication device lockdown.
@@ -0,0 +1,3 @@
status-display-eta = -ETA-
status-display-etd = -ETD-
status-display-time = TIME
@@ -1,3 +0,0 @@
alert-level-orange = Orange
alert-level-orange-announcement = There is a critical station-wide structural or atmospheric threat and recovery is unlikely. Engineering staff are advised to minimize hazards and secure the Evacuation Dock. Crewmembers are advised to stay away from hazardous areas, and prepare for Evacuation. MAYDAY signals have been activated
alert-level-orange-instructions = Avoid hazards and prepare for Evacuation.
@@ -45,3 +45,7 @@ alert-level-octarine = Octarine
alert-level-octarine-announcement = A cataclysmic noospheric event threatens to envelop realspace. Station crew are to contain the event if possible, or else evacuate. alert-level-octarine-announcement = A cataclysmic noospheric event threatens to envelop realspace. Station crew are to contain the event if possible, or else evacuate.
alert-level-octarine-instructions = Crewmembers are advised to listen to heads of staff for more information. alert-level-octarine-instructions = Crewmembers are advised to listen to heads of staff for more information.
## DeltaV - Zeta
alert-level-zeta = Zeta
alert-level-zeta-announcement = The station is unrecoverable, and all important assets and crewmembers are to be evacuated. A distress signal has been sent to all nearby vessels. Security and Engineering staff are advised to minimize hazards and secure the Evacuation Dock. Crewmembers are advised to disembark the station by any means necessary. Godspeed.
alert-level-zeta-instructions = Avoid hazards and prepare for Evacuation.
-2
View File
@@ -28978,8 +28978,6 @@ entities:
- type: Transform - type: Transform
pos: 12.5,39.5 pos: 12.5,39.5
parent: 8 parent: 8
- type: CommunicationsConsole
announcementCooldownRemaining: -0.0166666
- proto: ComputerCrewMonitoring - proto: ComputerCrewMonitoring
entities: entities:
- uid: 678 - uid: 678
+5 -1
View File
@@ -252,5 +252,9 @@ BoxPerformer: BoxPerformerDV
SpawnPointMedicalBorg: SpawnPointBorg SpawnPointMedicalBorg: SpawnPointBorg
SpawnPointSecurityBorg: SpawnPointBorg SpawnPointSecurityBorg: SpawnPointBorg
# 2026-06-02
Screen: StatusDisplay
ArrivalsShuttleTimer: StatusDisplayShuttle
# 2026-08-10 # 2026-08-10
BookSecretDocuments: BookMedicalDocuments BookSecretDocuments: BookMedicalDocuments
@@ -43,17 +43,6 @@
emergencyLightColor: Red emergencyLightColor: Red
forceEnableEmergencyLights: true forceEnableEmergencyLights: true
shuttleTime: 600 #No reduction in time as we don't have swiping for red alert like in /tg/. Shuttle times are intended to create friction, so having a way to brainlessly bypass that would be dumb. shuttleTime: 600 #No reduction in time as we don't have swiping for red alert like in /tg/. Shuttle times are intended to create friction, so having a way to brainlessly bypass that would be dumb.
# Begin Starlight Additions
orange:
announcement: alert-level-orange-announcement
selectable: true
sound:
path: /Audio/_Starlight/misc/orange.ogg
color: "#ff8119"
emergencyLightColor: "#ff8119"
forceEnableEmergencyLights: true
shuttleTime: 480
# End Starlight Additions
gamma: gamma:
announcement: alert-level-gamma-announcement announcement: alert-level-gamma-announcement
selectable: false selectable: false
@@ -90,3 +79,13 @@
emergencyLightColor: CadetBlue emergencyLightColor: CadetBlue
forceEnableEmergencyLights: true forceEnableEmergencyLights: true
shuttleTime: 600 shuttleTime: 600
zeta: # DeltaV - zeta
announcement: alert-level-zeta-announcement
selectable: false
disableSelection: true
sound:
path: /Audio/_DV/Announcements/Alerts/code_zeta.ogg
color: "#fe8401"
emergencyLightColor: "#fe8401"
forceEnableEmergencyLights: true
shuttleTime: 480
@@ -57,8 +57,12 @@
interfaces: interfaces:
enum.SolarControlConsoleUiKey.Key: enum.SolarControlConsoleUiKey.Key:
type: SolarControlConsoleBoundUserInterface type: SolarControlConsoleBoundUserInterface
enum.CommunicationsConsoleUiKey.Key: # BEGIN DeltaV - our own thing
type: CommunicationsConsoleBoundUserInterface #enum.CommunicationsConsoleUiKey.Key:
# type: CommunicationsConsoleBoundUserInterface
enum.DVCommunicationsConsoleUi.Key:
type: DVCommunicationsConsoleBoundUserInterface
# END DeltaV
enum.RadarConsoleUiKey.Key: enum.RadarConsoleUiKey.Key:
type: RadarConsoleBoundUserInterface type: RadarConsoleBoundUserInterface
enum.CargoConsoleUiKey.Orders: enum.CargoConsoleUiKey.Orders:
@@ -76,7 +80,8 @@
uis: uis:
enum.SolarControlConsoleUiKey.Key: enum.SolarControlConsoleUiKey.Key:
toggleAction: ActionAGhostShowSolar toggleAction: ActionAGhostShowSolar
enum.CommunicationsConsoleUiKey.Key: #enum.CommunicationsConsoleUiKey.Key: # DeltaV - comms console
enum.DVCommunicationsConsoleUi.Key: # DeltaV - comms console
toggleAction: ActionAGhostShowCommunications toggleAction: ActionAGhostShowCommunications
enum.RadarConsoleUiKey.Key: enum.RadarConsoleUiKey.Key:
toggleAction: ActionAGhostShowRadar toggleAction: ActionAGhostShowRadar
@@ -91,12 +96,22 @@
toggleAction: ActionAGhostShowCharacterRecords toggleAction: ActionAGhostShowCharacterRecords
# End CD - Character Records # End CD - Character Records
- type: SolarControlConsole # look ma i AM the computer! - type: SolarControlConsole # look ma i AM the computer!
- type: CommunicationsConsole # Begin DeltaV - our own thing
title: comms-console-announcement-title-centcom #- type: CommunicationsConsole
color: "#1d8bad" # title: comms-console-announcement-title-centcom
delay: 10 # color: "#1d8bad"
initialDelay: 0 # delay: 10
global: true # initialDelay: 0
# global: true
- type: DVCommunicationsConsole
announcementTitle: comms-console-announcement-title-centcom
announcementColor: "#1d8bad"
canAlertLevel: true
canCallShuttles: true
canConfigureScreens: false
canKeycardAuthenticationDevice: false
globalAnnouncements: true
# End DeltaV
- type: RadarConsole - type: RadarConsole
followEntity: true followEntity: true
- type: CargoOrderConsole - type: CargoOrderConsole
@@ -112,7 +127,7 @@
- type: DeviceNetwork - type: DeviceNetwork
deviceNetId: Wireless deviceNetId: Wireless
receiveFrequencyId: NTNet # DeltaV - NTNet receiveFrequencyId: NTNet # DeltaV - NTNet
transmitFrequencyId: ShuttleTimer transmitFrequencyId: NTNet # DeltaV - DVComms Console
- type: WirelessNetworkConnection - type: WirelessNetworkConnection
range: 10000 # DeltaV range: 10000 # DeltaV
#- type: StationLimitedNetwork # DeltaV - Off-station coordinates #- type: StationLimitedNetwork # DeltaV - Off-station coordinates
@@ -164,7 +179,7 @@
keywords: [ "AI", "console", "interface" ] keywords: [ "AI", "console", "interface" ]
priority: -4 priority: -4
- type: InstantAction - type: InstantAction
event: !type:ToggleIntrinsicUIEvent { key: enum.CommunicationsConsoleUiKey.Key } event: !type:ToggleIntrinsicUIEvent { key: enum.DVCommunicationsConsoleUi.Key } # DeltaV - was enum.CommunicationsConsoleUiKey.Key
- type: entity - type: entity
parent: BaseAGhostAction parent: BaseAGhostAction
@@ -58,8 +58,12 @@
type: GeneralStationRecordConsoleBoundUserInterface type: GeneralStationRecordConsoleBoundUserInterface
enum.SiliconLawsUiKey.Key: enum.SiliconLawsUiKey.Key:
type: SiliconLawBoundUserInterface type: SiliconLawBoundUserInterface
enum.CommunicationsConsoleUiKey.Key: # BEGIN DeltaV - comms console rework
type: CommunicationsConsoleBoundUserInterface #enum.CommunicationsConsoleUiKey.Key:
# type: CommunicationsConsoleBoundUserInterface
enum.DVCommunicationsConsoleUi.Key:
type: DVCommunicationsConsoleBoundUserInterface
# END DeltaV
enum.StoreUiKey.Key: # DeltaV - AI shop system enum.StoreUiKey.Key: # DeltaV - AI shop system
type: StoreBoundUserInterface type: StoreBoundUserInterface
# Begin DeltaV - AI PDAs # Begin DeltaV - AI PDAs
@@ -80,7 +84,8 @@
toggleAction: ActionAGhostShowCrewMonitoring toggleAction: ActionAGhostShowCrewMonitoring
enum.GeneralStationRecordConsoleKey.Key: enum.GeneralStationRecordConsoleKey.Key:
toggleAction: ActionAGhostShowStationRecords toggleAction: ActionAGhostShowStationRecords
enum.CommunicationsConsoleUiKey.Key: #enum.CommunicationsConsoleUiKey.Key: # DeltaV - comms console
enum.DVCommunicationsConsoleUi.Key: # DeltaV - comms console
toggleAction: ActionAGhostShowCommunications toggleAction: ActionAGhostShowCommunications
# Begin DeltaV - AI fax # Begin DeltaV - AI fax
enum.FaxUiKey.Key: enum.FaxUiKey.Key:
@@ -94,10 +99,20 @@
transmitFrequencyId: NTNet # DeltaV transmitFrequencyId: NTNet # DeltaV
- type: RadarConsole - type: RadarConsole
followEntity: false followEntity: false
- type: CommunicationsConsole # BEGIN DeltaV - our own thing
canShuttle: false #- type: CommunicationsConsole
title: comms-console-announcement-title-station-ai # canShuttle: false
color: "#5ed7aa" # title: comms-console-announcement-title-station-ai
# color: "#5ed7aa"
- type: DVCommunicationsConsole
announcementTitle: comms-console-announcement-title-station-ai
announcementColor: "#5ed7aa"
canAlertLevel: true
canCallShuttles: false
canConfigureScreens: true
canKeycardAuthenticationDevice: false
globalAnnouncements: true
# END DeltaV
- type: ShowJobIcons - type: ShowJobIcons
#- type: ShowCrewIcons # DeltaV - Disable crew icons #- type: ShowCrewIcons # DeltaV - Disable crew icons
- type: DamagedSiliconAccent - type: DamagedSiliconAccent
@@ -32,6 +32,7 @@
- BaseStationStockMarket - BaseStationStockMarket
- BaseStationLavaland - BaseStationLavaland
- BaseStationExfiltration - BaseStationExfiltration
- BaseStationKeycardAuthenticationDevice
# End DeltaV - Station additions # End DeltaV - Station additions
categories: [ HideSpawnMenu ] categories: [ HideSpawnMenu ]
components: components:
@@ -695,17 +695,23 @@
state: generic_panel_open state: generic_panel_open
- type: AccessReader - type: AccessReader
access: [[ "Command" ]] access: [[ "Command" ]]
- type: CommunicationsConsole # Begin DeltaV - DV Comms Console
title: comms-console-announcement-title-station # - type: CommunicationsConsole
# title: comms-console-announcement-title-station
- type: ActivatableUIRequiresAccess
- type: DVCommunicationsConsole # DeltaV - new functionality
announcementTitle: comms-console-announcement-title-station
# End DeltaV
- type: DeviceNetwork - type: DeviceNetwork
deviceNetId: Wireless deviceNetId: Wireless
transmitFrequencyId: ShuttleTimer transmitFrequencyId: NTNet # DeltaV - DVComms console
receiveFrequencyId: NTNet # DeltaV - DVComms console
- type: ActivatableUI - type: ActivatableUI
key: enum.CommunicationsConsoleUiKey.Key key: enum.DVCommunicationsConsoleUi.Key # DeltaV - new UI
- type: UserInterface - type: UserInterface
interfaces: interfaces:
enum.CommunicationsConsoleUiKey.Key: enum.DVCommunicationsConsoleUi.Key: # DeltaV - new UI
type: CommunicationsConsoleBoundUserInterface type: DVCommunicationsConsoleBoundUserInterface
enum.WiresUiKey.Key: enum.WiresUiKey.Key:
type: WiresBoundUserInterface type: WiresBoundUserInterface
- type: Computer - type: Computer
@@ -741,13 +747,25 @@
state: generic_panel_open state: generic_panel_open
- type: AccessReader - type: AccessReader
access: [[ "NuclearOperative" ]] access: [[ "NuclearOperative" ]]
- type: CommunicationsConsole # Begin DeltaV Changes
title: comms-console-announcement-title-unauthorized # DeltaV # - type: CommunicationsConsole
color: "#ff0000" # title: comms-console-announcement-title-unauthorized # DeltaV
canShuttle: false # color: "#ff0000"
global: true #announce to everyone they're about to fuck shit up # canShuttle: false
sound: /Audio/Announcements/intercept.ogg # DeltaV # global: true #announce to everyone they're about to fuck shit up
announceSentBy: false # The title already says who they are. # sound: /Audio/Announcements/intercept.ogg # DeltaV
# announceSentBy: false # The title already says who they are.
- type: DVCommunicationsConsole
announcementTitle: comms-console-announcement-title-unauthorized
announcementColor: "#ff0000"
announcementSound:
path: /Audio/Announcements/intercept.ogg
canAlertLevel: false
canCallShuttles: false
canConfigureScreens: false
canKeycardAuthenticationDevice: false
globalAnnouncements: true
# End DeltaV Changes
- type: Computer - type: Computer
board: SyndicateCommsComputerCircuitboard board: SyndicateCommsComputerCircuitboard
- type: PointLight - type: PointLight
@@ -775,13 +793,23 @@
state: generic_panel_open state: generic_panel_open
- type: AccessReader - type: AccessReader
access: [[ "Wizard" ]] access: [[ "Wizard" ]]
- type: CommunicationsConsole # Begin DeltaV Changes
title: comms-console-announcement-title-wizard # - type: CommunicationsConsole
color: "#ff00ff" # title: comms-console-announcement-title-wizard
canShuttle: false # color: "#ff00ff"
global: true #announce to everyone they're about to fuck shit up # canShuttle: false
announceSentBy: false # global: true #announce to everyone they're about to fuck shit up
sound: /Audio/Announcements/announce.ogg # DeltaV - changed from war.oog to announce.ogg # announceSentBy: false
# sound: /Audio/Announcements/announce.ogg # DeltaV - changed from war.oog to announce.ogg
- type: DVCommunicationsConsole
announcementTitle: comms-console-announcement-title-wizard
announcementColor: "#ff00ff"
canAlertLevel: false
canCallShuttles: false
canConfigureScreens: false
canKeycardAuthenticationDevice: false
globalAnnouncements: true
# End DeltaV Changes
- type: Computer - type: Computer
board: WizardCommsComputerCircuitboard board: WizardCommsComputerCircuitboard
- type: PointLight - type: PointLight
@@ -809,11 +837,21 @@
state: generic_panel_open state: generic_panel_open
- type: AccessReader - type: AccessReader
access: [[ "CentralCommand" ]] access: [[ "CentralCommand" ]]
- type: CommunicationsConsole # Begin DeltaV Changes
title: comms-console-announcement-title-centcom # - type: CommunicationsConsole
color: "#1d8bad" # title: comms-console-announcement-title-centcom
canShuttle: false # color: "#1d8bad"
global: true # canShuttle: false
# global: true
- type: DVCommunicationsConsole
announcementTitle: comms-console-announcement-title-centcom
announcementColor: "#1d8bad"
canAlertLevel: false
canCallShuttles: false
canConfigureScreens: false
canKeycardAuthenticationDevice: false
globalAnnouncements: true
# End DeltaV Changes
- type: Computer - type: Computer
board: CentcommCommsComputerCircuitboard board: CentcommCommsComputerCircuitboard
- type: PointLight - type: PointLight
@@ -1,4 +1,5 @@
- type: entity - type: entity
categories: [ HideSpawnMenu ] # DeltaV - use the other one
parent: BaseWallmountMachine parent: BaseWallmountMachine
id: Screen id: Screen
name: screen name: screen
@@ -32,9 +33,10 @@
- type: Screen - type: Screen
- type: DeviceNetwork - type: DeviceNetwork
deviceNetId: Wireless deviceNetId: Wireless
receiveFrequencyId: ShuttleTimer receiveFrequencyId: NTNet # DeltaV - comms console
- type: entity - type: entity
categories: [ HideSpawnMenu ] # DeltaV - use the other one
id: ArrivalsShuttleTimer id: ArrivalsShuttleTimer
parent: Screen parent: Screen
name: arrivals screen name: arrivals screen
@@ -42,3 +42,12 @@
- type: StationPlanetSpawner - type: StationPlanetSpawner
planet: Lavaland planet: Lavaland
gridPath: /Maps/_DV/Nonstations/lavaland_mining_base.yml gridPath: /Maps/_DV/Nonstations/lavaland_mining_base.yml
- type: entity
abstract: true
id: BaseStationKeycardAuthenticationDevice
components:
- type: DVStationKeycardAuthenticationDevice
actionThresholds:
Mayday: 2
Scuttling: 3
@@ -0,0 +1,105 @@
- type: entity
parent: BaseWallmountMachine
id: StatusDisplay
name: status display
description: Displays the current status of the station.
components:
- type: Rotatable
- type: DVTextVisuals
rows:
- text: ""
layer: enum.DVTextScreenVisualLayers.Line1
offset: 0.03125,0.15625 # 1/32, 5/32
- text: ""
layer: enum.DVTextScreenVisualLayers.Line2
offset: 0.03125,-0.0625 # 1/32, 0/32
- type: DVScreen
- type: Sprite
drawdepth: WallMountedItems
sprite: _DV/Structures/Wallmounts/screen.rsi
noRot: true
layers:
- state: frame
- shader: StencilClear
state: mask
- shader: StencilMask
state: mask
- map: ["enum.DVTextScreenVisualLayers.Line1"]
shader: StencilDraw
color: "#22ccff"
visible: false
- map: ["enum.DVTextScreenVisualLayers.Line2"]
shader: StencilDraw
color: "#22ccff"
visible: false
- map: ["alert_status"]
visible: false
state: status_display_green
- map: ["alert_border"]
visible: false
state: alert_border_green
- type: Appearance
- type: ApcPowerReceiver
- type: ExtensionCableReceiver
- type: GenericVisualizer
visuals:
enum.DVScreenVisuals.ShowAlertBorder:
alert_border:
True: { visible: true }
False: { visible: false }
enum.DVScreenVisuals.AlertLevel:
alert_border:
green: { state: alert_border_green }
blue: { state: alert_border_blue }
red: { state: alert_border_red }
white: { state: alert_border_white }
yellow: { state: alert_border_yellow }
violet: { state: alert_border_violet }
delta: { state: alert_border_delta }
epsilon: { state: alert_border_epsilon }
gamma: { state: alert_border_gamma }
octarine: { state: alert_border_octarine }
zeta: { state: alert_border_zeta }
alert_status:
green: { state: status_display_green }
blue: { state: status_display_blue }
red: { state: status_display_red }
white: { state: status_display_white }
yellow: { state: status_display_yellow }
violet: { state: status_display_violet }
delta: { state: status_display_delta }
epsilon: { state: status_display_epsilon }
gamma: { state: status_display_gamma }
octarine: { state: status_display_octarine }
zeta: { state: status_display_zeta }
enum.DVScreenVisuals.Content:
enum.DVTextScreenVisualLayers.Line1:
Text: { visible: true }
CurrentTime: { visible: true }
EstimatedTimeOfArrival: { visible: true }
AlertLevel: { visible: false }
enum.DVTextScreenVisualLayers.Line2:
Text: { visible: true }
CurrentTime: { visible: true }
EstimatedTimeOfArrival: { visible: true }
AlertLevel: { visible: false }
alert_status:
Text: { visible: false }
CurrentTime: { visible: false }
EstimatedTimeOfArrival: { visible: false }
AlertLevel: { visible: true }
- type: DeviceNetwork
deviceNetId: Wireless
receiveFrequencyId: NTNet
- type: entity
parent: StatusDisplay
id: StatusDisplayShuttle
name: arrivals status display
description: Displays the current status of the arrivals shuttle.
components:
- type: DeviceNetwork
deviceNetId: Private
receiveFrequencyId: ArrivalsShuttleTimer
- type: DVScreen
content: EstimatedTimeOfArrival
+5
View File
@@ -30,3 +30,8 @@
id: MonumentPulse id: MonumentPulse
kind: source kind: source
path: "/Textures/_DV/Shaders/monument_pulse.swsl" path: "/Textures/_DV/Shaders/monument_pulse.swsl"
- type: shader
id: Masked
kind: source
path: "/Textures/_DV/Shaders/mask.swsl"
@@ -67,15 +67,15 @@ On Delta-V, there are some restrictions on when certain alert levels can be used
- [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew. Prepare for detonation of probers. - [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew. Prepare for detonation of probers.
- [color=#a4885c]ROE[/color]: Engage with minimal force required; ROE on mindwiping is lifted and may be performed by the Psionic Mantis, Chaplain or Mystagogue at their discretion. - [color=#a4885c]ROE[/color]: Engage with minimal force required; ROE on mindwiping is lifted and may be performed by the Psionic Mantis, Chaplain or Mystagogue at their discretion.
## Code Gamma ## Code Zeta
[color=#db7093]Emergency alert status. Central Command has called the Gamma Alert; the station is on its last legs, almost everyone is dead, or there is another existential crisis affecting the station.[/color] [color=#db7093]Emergency alert status. The station has called the Zeta Alert; the station unfit for life and is now sending out a distress signal to all nearby vessels.[/color]
- [color=#a4885c]COC[/color]: CO, Security Personnel, Department Heads, Supervisory Roles - [color=#a4885c]COC[/color]: Commanding Officer (CO), Department Heads, Supervisory Roles
- [color=#a4885c]Armory Policy[/color]: Issuing of lethal weapons heavily recommended. Body armour and helmets mandatory for Security personnel. EVA protection heavily advised for all personnel. - [color=#a4885c]Armory Policy[/color]: Issuing of lethal weapons only advised if station threat is still present. EVA protection heavily advised for all personnel.
- [color=#a4885c]Discipline[/color]: Report to supervisor for general orders. Martial law is in effect. - [color=#a4885c]Discipline[/color]: Report to supervisor for orders. Non-engineering personnel advised to evacuate dangerous areas or combat zones and head to the nearest escape pod.
- [color=#a4885c]Secure Areas[/color]: All HSAs recommended to be bolted and under guard. Secure areas unbolted. - [color=#a4885c]Secure Areas[/color]: All secure areas and HSAs should remain unbolted.
- [color=#a4885c]Medical[/color]: Full suit sensors mandatory for observation and safety. EVA suits and functioning internals heavily advised for emergency responders. - [color=#a4885c]Medical[/color]: Full suit sensors heavily advised. EVA suits and functioning internals recommended for emergency responders.
- [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew. - [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew. Ensure evacuation as soon as possible.
- [color=#a4885c]ROE[/color]: Martial law is in effect. - [color=#a4885c]ROE[/color]: Engage with adequate force to safely subdue suspects, dependent on threat and compliance. Lethal force is permitted to effect arrests against evasive targets.
## Code Delta ## Code Delta
[color=#8b0000]Emergency alert status. The nuclear destruction mechanism has been engaged and station destruction is imminent. All crew aboard the station must attempt to reverse the self-destruct mechanism, if engaged in error. Should reversal prove impossible, evacuate as applicable.[/color] [color=#8b0000]Emergency alert status. The nuclear destruction mechanism has been engaged and station destruction is imminent. All crew aboard the station must attempt to reverse the self-destruct mechanism, if engaged in error. Should reversal prove impossible, evacuate as applicable.[/color]
@@ -97,6 +97,16 @@ On Delta-V, there are some restrictions on when certain alert levels can be used
- [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew. - [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew.
- [color=#a4885c]ROE[/color]: Engage with adequate force to neutralise threats. Lethal force authorised at the discretion of Security personnel, in self-defence, or to effect arrests. ROE on mindwiping is lifted and may be performed by the Psionic Mantis or Mystagogue at their discretion. - [color=#a4885c]ROE[/color]: Engage with adequate force to neutralise threats. Lethal force authorised at the discretion of Security personnel, in self-defence, or to effect arrests. ROE on mindwiping is lifted and may be performed by the Psionic Mantis or Mystagogue at their discretion.
## Code Gamma
[color=#db7093]Emergency alert status. Central Command has called the Gamma Alert; the station is on its last legs, almost everyone is dead, or there is another existential crisis affecting the station.[/color]
- [color=#a4885c]COC[/color]: CO, Security Personnel, Department Heads, Supervisory Roles
- [color=#a4885c]Armory Policy[/color]: Issuing of lethal weapons heavily recommended. Body armour and helmets mandatory for Security personnel. EVA protection heavily advised for all personnel.
- [color=#a4885c]Discipline[/color]: Report to supervisor for general orders. Martial law is in effect.
- [color=#a4885c]Secure Areas[/color]: All HSAs recommended to be bolted and under guard. Secure areas unbolted.
- [color=#a4885c]Medical[/color]: Full suit sensors mandatory for observation and safety. EVA suits and functioning internals heavily advised for emergency responders.
- [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew.
- [color=#a4885c]ROE[/color]: Martial law is in effect.
## Code Epsilon ## Code Epsilon
[color=#b000ff]Emergency alert status. Central Command has ordered the Epsilon security level on the station. Only orders from Central Command Officials are to be obeyed by the Station's Crew. Martial Law is in effect.[/color] [color=#b000ff]Emergency alert status. Central Command has ordered the Epsilon security level on the station. Only orders from Central Command Officials are to be obeyed by the Station's Crew. Martial Law is in effect.[/color]
- [color=#a4885c]COC[/color]: Central Command - [color=#a4885c]COC[/color]: Central Command
@@ -106,14 +116,4 @@ On Delta-V, there are some restrictions on when certain alert levels can be used
- [color=#a4885c]Medical[/color]: Full suit sensors mandatory for observation and safety. Await orders from Central Command Personnel. - [color=#a4885c]Medical[/color]: Full suit sensors mandatory for observation and safety. Await orders from Central Command Personnel.
- [color=#a4885c]Engineering[/color]: Await orders from Central Command Personnel. - [color=#a4885c]Engineering[/color]: Await orders from Central Command Personnel.
- [color=#a4885c]ROE[/color]: Martial Law is in effect. Do not engage with Central Command Personnel. Await orders from Central Command Personnel. - [color=#a4885c]ROE[/color]: Martial Law is in effect. Do not engage with Central Command Personnel. Await orders from Central Command Personnel.
## Code Orange
[color=#ff8119]There is a critical station-wide structural or atmospheric threat and recovery is unlikely. Engineering staff are advised to minimize hazards and secure the Evacuation Dock. Crewmembers are advised to stay away from hazardous areas, and prepare for Evacuation. [/color]
- [color=#a4885c]COC[/color]: CO, Chief Engineer, Engineering Personnel, Department Heads, Supervisory Roles
- [color=#a4885c]Armory Policy[/color]: Issuing of lethal weapons disadvised. EVA protection heavily advised for all personnel.
- [color=#a4885c]Discipline[/color]: Report to supervisor for orders. Non-engineering personnel advised to evacuate affected areas. Security should seek to aid engineering staff where possible.
- [color=#a4885c]Secure Areas[/color]: Secure areas unbolted. HSAs and areas with an expectation of privacy, such as bedrooms, dorms, or medical treatment facilities, may be bolted as needed.
- [color=#a4885c]Medical[/color]: Full suit sensors heavily advised. EVA suits and functioning internals recommended for emergency responders.
- [color=#a4885c]Engineering[/color]: EVA suits heavily advised for engineers. Distribute emergency internals to crew. Ensure evacuation as soon as possible.
- [color=#a4885c]ROE[/color]: Engage with minimal force; prioritize de-escalation whenever possible.
</Document> </Document>
+15
View File
@@ -0,0 +1,15 @@
uniform sampler2D uMask;
uniform highp vec4 uMaskUV;
varying highp vec2 vMaskUV;
void vertex()
{
vMaskUV = (tCoord2 - uMaskUV.xy) / (uMaskUV.zw - uMaskUV.xy);
// vMaskUV = mix(uMaskUV.xy, uMaskUV.zw, tCoord2);
}
void fragment()
{
COLOR.rgba = zTexture(UV) * texture2D(uMask, vMaskUV);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

@@ -0,0 +1,269 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from Baystation12 at https://github.com/Baystation12/Baystation12/blob/926c09fe7fe69d647e530d03dce356737af82a3a/icons/misc/security_state.dmi and https://github.com/Baystation12/Baystation12/blob/926c09fe7fe69d647e530d03dce356737af82a3a/icons/obj/machines/status_display.dmi. white, octarine, zeta, yellow, gamma, epsilon made by sowelipililimute based on prior sprites",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "status_display_green",
"delays": [
[
1.6,
1.6
]
]
},
{
"name": "status_display_blue",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "status_display_red",
"delays": [
[
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2
]
]
},
{
"name": "status_display_delta",
"delays": [
[
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2
]
]
},
{
"name": "alert_border_green",
"delays": [
[
1.6,
1.6
]
]
},
{
"name": "alert_border_blue",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "alert_border_delta",
"delays": [
[
0.2,
0.2,
0.2,
0.2
]
]
},
{
"name": "alert_border_red",
"delays": [
[
0.2,
0.2
]
]
},
{
"name": "alert_border_violet",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "frame"
},
{
"name": "frame_broken"
},
{
"name": "mask"
},
{
"name": "radiation",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "status_display_violet",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "status_display_white",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "alert_border_white",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "status_display_octarine",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "alert_border_octarine",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "status_display_zeta",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "alert_border_zeta",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "status_display_yellow",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "alert_border_yellow",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "status_display_gamma",
"delays": [
[
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2
]
]
},
{
"name": "alert_border_gamma",
"delays": [
[
0.2,
0.2,
0.2,
0.2
]
]
},
{
"name": "status_display_epsilon",
"delays": [
[
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2
]
]
},
{
"name": "alert_border_epsilon",
"delays": [
[
0.2,
0.2,
0.2,
0.2
]
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B