Hallway textscreens (#24189)
* hallway screen refactor pending comms console support * comms console broadcasts * screen and timer localization
This commit is contained in:
@@ -16,6 +16,8 @@ namespace Content.Client.Communications.UI
|
|||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool CanAnnounce { get; private set; }
|
public bool CanAnnounce { get; private set; }
|
||||||
|
[ViewVariables]
|
||||||
|
public bool CanBroadcast { get; private set; }
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool CanCall { get; private set; }
|
public bool CanCall { get; private set; }
|
||||||
@@ -71,6 +73,11 @@ namespace Content.Client.Communications.UI
|
|||||||
SendMessage(new CommunicationsConsoleAnnounceMessage(msg));
|
SendMessage(new CommunicationsConsoleAnnounceMessage(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void BroadcastButtonPressed(string message)
|
||||||
|
{
|
||||||
|
SendMessage(new CommunicationsConsoleBroadcastMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
public void CallShuttle()
|
public void CallShuttle()
|
||||||
{
|
{
|
||||||
SendMessage(new CommunicationsConsoleCallEmergencyShuttleMessage());
|
SendMessage(new CommunicationsConsoleCallEmergencyShuttleMessage());
|
||||||
@@ -89,6 +96,7 @@ namespace Content.Client.Communications.UI
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
CanAnnounce = commsState.CanAnnounce;
|
CanAnnounce = commsState.CanAnnounce;
|
||||||
|
CanBroadcast = commsState.CanBroadcast;
|
||||||
CanCall = commsState.CanCall;
|
CanCall = commsState.CanCall;
|
||||||
_expectedCountdownTime = commsState.ExpectedCountdownEnd;
|
_expectedCountdownTime = commsState.ExpectedCountdownEnd;
|
||||||
CountdownStarted = commsState.CountdownStarted;
|
CountdownStarted = commsState.CountdownStarted;
|
||||||
@@ -102,6 +110,7 @@ namespace Content.Client.Communications.UI
|
|||||||
_menu.AlertLevelButton.Disabled = !AlertLevelSelectable;
|
_menu.AlertLevelButton.Disabled = !AlertLevelSelectable;
|
||||||
_menu.EmergencyShuttleButton.Disabled = !CanCall;
|
_menu.EmergencyShuttleButton.Disabled = !CanCall;
|
||||||
_menu.AnnounceButton.Disabled = !CanAnnounce;
|
_menu.AnnounceButton.Disabled = !CanAnnounce;
|
||||||
|
_menu.BroadcastButton.Disabled = !CanBroadcast;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="5">
|
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="5">
|
||||||
<TextEdit Name="MessageInput" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 0 5" MinHeight="100" />
|
<TextEdit Name="MessageInput" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 0 5" MinHeight="100" />
|
||||||
<Button Name="AnnounceButton" Text="{Loc 'comms-console-menu-announcement-button'}" StyleClasses="OpenLeft" Access="Public" />
|
<Button Name="AnnounceButton" Text="{Loc 'comms-console-menu-announcement-button'}" StyleClasses="OpenLeft" Access="Public" />
|
||||||
|
<Button Name="BroadcastButton" Text="{Loc 'comms-console-menu-broadcast-button'}" StyleClasses="OpenLeft" Access="Public" />
|
||||||
|
|
||||||
<OptionButton Name="AlertLevelButton" StyleClasses="OpenRight" Access="Public" />
|
<OptionButton Name="AlertLevelButton" StyleClasses="OpenRight" Access="Public" />
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ namespace Content.Client.Communications.UI
|
|||||||
AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope));
|
AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope));
|
||||||
AnnounceButton.Disabled = !owner.CanAnnounce;
|
AnnounceButton.Disabled = !owner.CanAnnounce;
|
||||||
|
|
||||||
|
BroadcastButton.OnPressed += (_) => Owner.BroadcastButtonPressed(Rope.Collapse(MessageInput.TextRope));
|
||||||
|
BroadcastButton.Disabled = !owner.CanBroadcast;
|
||||||
|
|
||||||
AlertLevelButton.OnItemSelected += args =>
|
AlertLevelButton.OnItemSelected += args =>
|
||||||
{
|
{
|
||||||
var metadata = AlertLevelButton.GetItemMetadata(args.Id);
|
var metadata = AlertLevelButton.GetItemMetadata(args.Id);
|
||||||
|
|||||||
@@ -99,19 +99,43 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
|
|||||||
/// Called by <see cref="SharedAppearanceSystem.SetData"/> to handle text updates,
|
/// Called by <see cref="SharedAppearanceSystem.SetData"/> to handle text updates,
|
||||||
/// and spawn a <see cref="TextScreenTimerComponent"/> if necessary
|
/// and spawn a <see cref="TextScreenTimerComponent"/> if necessary
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The appearance updates are batched; order matters for both sender and receiver.
|
||||||
|
/// </remarks>
|
||||||
protected override void OnAppearanceChange(EntityUid uid, TextScreenVisualsComponent component, ref AppearanceChangeEvent args)
|
protected override void OnAppearanceChange(EntityUid uid, TextScreenVisualsComponent component, ref AppearanceChangeEvent args)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref args.Sprite))
|
if (!Resolve(uid, ref args.Sprite))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var appearance = args.Component;
|
if (args.AppearanceData.TryGetValue(TextScreenVisuals.Color, out var color) && color is Color)
|
||||||
|
component.Color = (Color) color;
|
||||||
|
|
||||||
if (AppearanceSystem.TryGetData(uid, TextScreenVisuals.TargetTime, out TimeSpan time, appearance))
|
// DefaultText: broadcast updates from comms consoles
|
||||||
|
// ScreenText: the text accompanying shuttle timers e.g. "ETA"
|
||||||
|
if (args.AppearanceData.TryGetValue(TextScreenVisuals.DefaultText, out var newDefault) && newDefault is string)
|
||||||
{
|
{
|
||||||
if (time > _gameTiming.CurTime)
|
string?[] defaultText = SegmentText((string) newDefault, component);
|
||||||
|
component.Text = defaultText;
|
||||||
|
component.TextToDraw = defaultText;
|
||||||
|
ResetText(uid, component);
|
||||||
|
BuildTextLayers(uid, component, args.Sprite);
|
||||||
|
DrawLayers(uid, component.LayerStatesToDraw);
|
||||||
|
}
|
||||||
|
if (args.AppearanceData.TryGetValue(TextScreenVisuals.ScreenText, out var text) && text is string)
|
||||||
|
{
|
||||||
|
component.TextToDraw = SegmentText((string) text, component);
|
||||||
|
ResetText(uid, component);
|
||||||
|
BuildTextLayers(uid, component, args.Sprite);
|
||||||
|
DrawLayers(uid, component.LayerStatesToDraw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.AppearanceData.TryGetValue(TextScreenVisuals.TargetTime, out var time) && time is TimeSpan)
|
||||||
|
{
|
||||||
|
var target = (TimeSpan) time;
|
||||||
|
if (target > _gameTiming.CurTime)
|
||||||
{
|
{
|
||||||
var timer = EnsureComp<TextScreenTimerComponent>(uid);
|
var timer = EnsureComp<TextScreenTimerComponent>(uid);
|
||||||
timer.Target = time;
|
timer.Target = target;
|
||||||
BuildTimerLayers(uid, timer, component);
|
BuildTimerLayers(uid, timer, component);
|
||||||
DrawLayers(uid, timer.LayerStatesToDraw);
|
DrawLayers(uid, timer.LayerStatesToDraw);
|
||||||
}
|
}
|
||||||
@@ -120,14 +144,6 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
|
|||||||
OnTimerFinish(uid, component);
|
OnTimerFinish(uid, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AppearanceSystem.TryGetData(uid, TextScreenVisuals.ScreenText, out string?[] text, appearance))
|
|
||||||
{
|
|
||||||
component.TextToDraw = text;
|
|
||||||
ResetText(uid, component);
|
|
||||||
BuildTextLayers(uid, component, args.Sprite);
|
|
||||||
DrawLayers(uid, component.LayerStatesToDraw);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -151,10 +167,28 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
|
|||||||
DrawLayers(uid, screen.LayerStatesToDraw);
|
DrawLayers(uid, screen.LayerStatesToDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts string to string?[] based on
|
||||||
|
/// <see cref="TextScreenVisualsComponent.RowLength"/> and <see cref="TextScreenVisualsComponent.Rows"/>.
|
||||||
|
/// </summary>
|
||||||
|
private string?[] SegmentText(string text, TextScreenVisualsComponent component)
|
||||||
|
{
|
||||||
|
int segment = component.RowLength;
|
||||||
|
var segmented = new string?[Math.Min(component.Rows, (text.Length - 1) / segment + 1)];
|
||||||
|
|
||||||
|
// populate segmented with a string sliding window using Substring.
|
||||||
|
// (Substring(5, 5) will return the 5 characters starting from 5th index)
|
||||||
|
// the Mins are for the very short string case, the very long string case, and to not OOB the end of the string.
|
||||||
|
for (int i = 0; i < Math.Min(text.Length, segment * component.Rows); i += segment)
|
||||||
|
segmented[i / segment] = text.Substring(i, Math.Min(text.Length - i, segment)).Trim();
|
||||||
|
|
||||||
|
return segmented;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears <see cref="TextScreenVisualsComponent.LayerStatesToDraw"/>, and instantiates new blank defaults.
|
/// Clears <see cref="TextScreenVisualsComponent.LayerStatesToDraw"/>, and instantiates new blank defaults.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ResetText(EntityUid uid, TextScreenVisualsComponent component, SpriteComponent? sprite = null)
|
private void ResetText(EntityUid uid, TextScreenVisualsComponent component, SpriteComponent? sprite = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref sprite))
|
if (!Resolve(uid, ref sprite))
|
||||||
return;
|
return;
|
||||||
@@ -167,11 +201,12 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
|
|||||||
for (var row = 0; row < component.Rows; row++)
|
for (var row = 0; row < component.Rows; row++)
|
||||||
for (var i = 0; i < component.RowLength; i++)
|
for (var i = 0; i < component.RowLength; i++)
|
||||||
{
|
{
|
||||||
sprite.LayerMapReserveBlank(TextMapKey + row + i);
|
var key = TextMapKey + row + i;
|
||||||
component.LayerStatesToDraw.Add(TextMapKey + row + i, null);
|
sprite.LayerMapReserveBlank(key);
|
||||||
sprite.LayerSetRSI(TextMapKey + row + i, new ResPath(TextPath));
|
component.LayerStatesToDraw.Add(key, null);
|
||||||
sprite.LayerSetColor(TextMapKey + row + i, component.Color);
|
sprite.LayerSetRSI(key, new ResPath(TextPath));
|
||||||
sprite.LayerSetState(TextMapKey + row + i, DefaultState);
|
sprite.LayerSetColor(key, component.Color);
|
||||||
|
sprite.LayerSetState(key, DefaultState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +217,7 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Remember to set <see cref="TextScreenVisualsComponent.TextToDraw"/> to a string?[] first.
|
/// Remember to set <see cref="TextScreenVisualsComponent.TextToDraw"/> to a string?[] first.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void BuildTextLayers(EntityUid uid, TextScreenVisualsComponent component, SpriteComponent? sprite = null)
|
private void BuildTextLayers(EntityUid uid, TextScreenVisualsComponent component, SpriteComponent? sprite = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref sprite))
|
if (!Resolve(uid, ref sprite))
|
||||||
return;
|
return;
|
||||||
@@ -211,7 +246,7 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Populates timer.LayerStatesToDraw & the sprite component's layer dict with calculated offsets.
|
/// Populates timer.LayerStatesToDraw & the sprite component's layer dict with calculated offsets.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BuildTimerLayers(EntityUid uid, TextScreenTimerComponent timer, TextScreenVisualsComponent screen)
|
private void BuildTimerLayers(EntityUid uid, TextScreenTimerComponent timer, TextScreenVisualsComponent screen)
|
||||||
{
|
{
|
||||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared.TextScreen;
|
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
|
|
||||||
namespace Content.Client.TextScreen;
|
namespace Content.Client.TextScreen;
|
||||||
@@ -37,7 +36,7 @@ public sealed partial class TextScreenVisualsComponent : Component
|
|||||||
/// Number of rows of text this screen can render.
|
/// Number of rows of text this screen can render.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("rows")]
|
[DataField("rows")]
|
||||||
public int Rows = 1;
|
public int Rows = 2;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spacing between each text row
|
/// Spacing between each text row
|
||||||
|
|||||||
@@ -12,10 +12,14 @@ namespace Content.Server.Communications
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remaining cooldown between making announcements.
|
/// Remaining cooldown between making announcements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
[DataField]
|
[DataField]
|
||||||
public float AnnouncementCooldownRemaining;
|
public float AnnouncementCooldownRemaining;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField]
|
||||||
|
public float BroadcastCooldownRemaining;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fluent ID for the announcement title
|
/// Fluent ID for the announcement title
|
||||||
/// If a Fluent ID isn't found, just uses the raw string
|
/// If a Fluent ID isn't found, just uses the raw string
|
||||||
@@ -27,28 +31,28 @@ namespace Content.Server.Communications
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Announcement color
|
/// Announcement color
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
[DataField]
|
[DataField]
|
||||||
public Color Color = Color.Gold;
|
public Color Color = Color.Gold;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time in seconds between announcement delays on a per-console basis
|
/// Time in seconds between announcement delays on a per-console basis
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
[DataField]
|
[DataField]
|
||||||
public int Delay = 90;
|
public int Delay = 90;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time in seconds of announcement cooldown when a new console is created on a per-console basis
|
/// Time in seconds of announcement cooldown when a new console is created on a per-console basis
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
[DataField]
|
[DataField]
|
||||||
public int InitialDelay = 30;
|
public int InitialDelay = 30;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Can call or recall the shuttle
|
/// Can call or recall the shuttle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool CanShuttle = true;
|
public bool CanShuttle = true;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,14 @@ using Content.Server.Access.Systems;
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.AlertLevel;
|
using Content.Server.AlertLevel;
|
||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
|
using Content.Server.DeviceNetwork;
|
||||||
|
using Content.Server.DeviceNetwork.Components;
|
||||||
|
using Content.Server.DeviceNetwork.Systems;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.RoundEnd;
|
using Content.Server.RoundEnd;
|
||||||
|
using Content.Server.Screens;
|
||||||
|
using Content.Server.Screens.Components;
|
||||||
using Content.Server.Shuttles.Systems;
|
using Content.Server.Shuttles.Systems;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
@@ -27,6 +32,7 @@ namespace Content.Server.Communications
|
|||||||
[Dependency] private readonly InteractionSystem _interaction = default!;
|
[Dependency] private readonly InteractionSystem _interaction = default!;
|
||||||
[Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!;
|
[Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!;
|
||||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||||
|
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
|
||||||
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
|
[Dependency] private readonly EmergencyShuttleSystem _emergency = default!;
|
||||||
[Dependency] private readonly IdCardSystem _idCardSystem = default!;
|
[Dependency] private readonly IdCardSystem _idCardSystem = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
@@ -49,6 +55,7 @@ namespace Content.Server.Communications
|
|||||||
// Messages from the BUI
|
// Messages from the BUI
|
||||||
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleSelectAlertLevelMessage>(OnSelectAlertLevelMessage);
|
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleSelectAlertLevelMessage>(OnSelectAlertLevelMessage);
|
||||||
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleAnnounceMessage>(OnAnnounceMessage);
|
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleAnnounceMessage>(OnAnnounceMessage);
|
||||||
|
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleBroadcastMessage>(OnBroadcastMessage);
|
||||||
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleCallEmergencyShuttleMessage>(OnCallShuttleMessage);
|
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleCallEmergencyShuttleMessage>(OnCallShuttleMessage);
|
||||||
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleRecallEmergencyShuttleMessage>(OnRecallShuttleMessage);
|
SubscribeLocalEvent<CommunicationsConsoleComponent, CommunicationsConsoleRecallEmergencyShuttleMessage>(OnRecallShuttleMessage);
|
||||||
|
|
||||||
@@ -162,6 +169,7 @@ namespace Content.Server.Communications
|
|||||||
|
|
||||||
_uiSystem.SetUiState(ui, new CommunicationsConsoleInterfaceState(
|
_uiSystem.SetUiState(ui, new CommunicationsConsoleInterfaceState(
|
||||||
CanAnnounce(comp),
|
CanAnnounce(comp),
|
||||||
|
CanBroadcast(comp),
|
||||||
CanCallOrRecall(comp),
|
CanCallOrRecall(comp),
|
||||||
levels,
|
levels,
|
||||||
currentLevel,
|
currentLevel,
|
||||||
@@ -175,6 +183,11 @@ namespace Content.Server.Communications
|
|||||||
return comp.AnnouncementCooldownRemaining <= 0f;
|
return comp.AnnouncementCooldownRemaining <= 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool CanBroadcast(CommunicationsConsoleComponent comp)
|
||||||
|
{
|
||||||
|
return comp.AnnouncementCooldownRemaining <= 0f;
|
||||||
|
}
|
||||||
|
|
||||||
private bool CanUse(EntityUid user, EntityUid console)
|
private bool CanUse(EntityUid user, EntityUid console)
|
||||||
{
|
{
|
||||||
// This shouldn't technically be possible because of BUI but don't trust client.
|
// This shouldn't technically be possible because of BUI but don't trust client.
|
||||||
@@ -278,6 +291,19 @@ namespace Content.Server.Communications
|
|||||||
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following station announcement: {msg}");
|
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following station announcement: {msg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnBroadcastMessage(EntityUid uid, CommunicationsConsoleComponent component, CommunicationsConsoleBroadcastMessage message)
|
||||||
|
{
|
||||||
|
if (!TryComp<DeviceNetworkComponent>(uid, out var net))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var payload = new NetworkPayload
|
||||||
|
{
|
||||||
|
[ScreenMasks.Text] = message.Message
|
||||||
|
};
|
||||||
|
|
||||||
|
_deviceNetworkSystem.QueuePacket(uid, null, payload, net.TransmitFrequency);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnCallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent comp, CommunicationsConsoleCallEmergencyShuttleMessage message)
|
private void OnCallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent comp, CommunicationsConsoleCallEmergencyShuttleMessage message)
|
||||||
{
|
{
|
||||||
if (!CanCallOrRecall(comp))
|
if (!CanCallOrRecall(comp))
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Content.Server.DeviceNetwork;
|
|||||||
using Content.Server.DeviceNetwork.Components;
|
using Content.Server.DeviceNetwork.Components;
|
||||||
using Content.Server.DeviceNetwork.Systems;
|
using Content.Server.DeviceNetwork.Systems;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.Screens.Components;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Server.Shuttles.Systems;
|
using Content.Server.Shuttles.Systems;
|
||||||
using Content.Server.Station.Components;
|
using Content.Server.Station.Components;
|
||||||
@@ -16,7 +17,6 @@ using Content.Shared.Database;
|
|||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -34,14 +34,11 @@ namespace Content.Server.RoundEnd
|
|||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||||
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
|
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
|
||||||
[Dependency] private readonly EmergencyShuttleSystem _shuttle = default!;
|
[Dependency] private readonly EmergencyShuttleSystem _shuttle = default!;
|
||||||
[Dependency] private readonly ShuttleTimerSystem _shuttleTimerSystem = default!;
|
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||||
|
|
||||||
@@ -112,13 +109,9 @@ namespace Content.Server.RoundEnd
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public EntityUid? GetCentcomm()
|
public EntityUid? GetCentcomm()
|
||||||
{
|
{
|
||||||
if (AllEntityQuery<StationCentcommComponent, TransformComponent>()
|
AllEntityQuery<StationCentcommComponent>().MoveNext(out var centcomm);
|
||||||
.MoveNext(out var centcomm, out var xform))
|
|
||||||
{
|
|
||||||
return xform.MapUid;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return centcomm == null ? null : centcomm.MapEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanCallOrRecall()
|
public bool CanCallOrRecall()
|
||||||
@@ -243,7 +236,7 @@ namespace Content.Server.RoundEnd
|
|||||||
ActivateCooldown();
|
ActivateCooldown();
|
||||||
RaiseLocalEvent(RoundEndSystemChangedEvent.Default);
|
RaiseLocalEvent(RoundEndSystemChangedEvent.Default);
|
||||||
|
|
||||||
// remove all active shuttle timers
|
// remove active clientside evac shuttle timers by zeroing the target time
|
||||||
var zero = TimeSpan.Zero;
|
var zero = TimeSpan.Zero;
|
||||||
var shuttle = _shuttle.GetShuttle();
|
var shuttle = _shuttle.GetShuttle();
|
||||||
if (shuttle != null && TryComp<DeviceNetworkComponent>(shuttle, out var net))
|
if (shuttle != null && TryComp<DeviceNetworkComponent>(shuttle, out var net))
|
||||||
@@ -256,7 +249,6 @@ namespace Content.Server.RoundEnd
|
|||||||
[ShuttleTimerMasks.ShuttleTime] = zero,
|
[ShuttleTimerMasks.ShuttleTime] = zero,
|
||||||
[ShuttleTimerMasks.SourceTime] = zero,
|
[ShuttleTimerMasks.SourceTime] = zero,
|
||||||
[ShuttleTimerMasks.DestTime] = zero,
|
[ShuttleTimerMasks.DestTime] = zero,
|
||||||
[ShuttleTimerMasks.Text] = new string?[] { string.Empty, string.Empty }
|
|
||||||
};
|
};
|
||||||
_deviceNetworkSystem.QueuePacket(shuttle.Value, null, payload, net.TransmitFrequency);
|
_deviceNetworkSystem.QueuePacket(shuttle.Value, null, payload, net.TransmitFrequency);
|
||||||
}
|
}
|
||||||
|
|||||||
35
Content.Server/Screens/Components/ScreenComponent.cs
Normal file
35
Content.Server/Screens/Components/ScreenComponent.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
namespace Content.Server.Screens.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class ScreenComponent : Component
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Player-facing hashable string consts for NetworkPayload
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ScreenMasks
|
||||||
|
{
|
||||||
|
public static readonly string Text = Loc.GetString("screen-text");
|
||||||
|
public static readonly string Color = Loc.GetString("screen-color");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Player-facing hashable string consts for NetworkPayload
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ShuttleTimerMasks
|
||||||
|
{
|
||||||
|
public static readonly string ShuttleTime = Loc.GetString("shuttle-timer-shuttle-time");
|
||||||
|
public static readonly string DestTime = Loc.GetString("shuttle-timer-dest-time");
|
||||||
|
public static readonly string SourceTime = Loc.GetString("shuttle-timer-source-time");
|
||||||
|
public static readonly string ShuttleMap = Loc.GetString("shuttle-timer-shuttle-map");
|
||||||
|
public static readonly string SourceMap = Loc.GetString("shuttle-timer-source-map");
|
||||||
|
public static readonly string DestMap = Loc.GetString("shuttle-timer-dest-map");
|
||||||
|
public static readonly string Docked = Loc.GetString("shuttle-timer-docked");
|
||||||
|
public static readonly string ETA = Loc.GetString("shuttle-timer-eta");
|
||||||
|
public static readonly string ETD = Loc.GetString("shuttle-timer-etd");
|
||||||
|
public static readonly string Bye = Loc.GetString("shuttle-timer-bye");
|
||||||
|
public static readonly string Kill = Loc.GetString("shuttle-timer-kill");
|
||||||
|
}
|
||||||
|
|
||||||
114
Content.Server/Screens/Systems/ScreenSystem.cs
Normal file
114
Content.Server/Screens/Systems/ScreenSystem.cs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
using Content.Shared.TextScreen;
|
||||||
|
using Content.Server.Screens.Components;
|
||||||
|
using Content.Server.DeviceNetwork.Components;
|
||||||
|
using Content.Server.DeviceNetwork.Systems;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Content.Server.Screens.Systems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the wallmounted screens on stations and shuttles displaying e.g. FTL duration, ETA
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ScreenSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ScreenComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calls either a normal screen text update or shuttle timer update based on the presence of
|
||||||
|
/// <see cref="ShuttleTimerMasks.ShuttleMap"/> in <see cref="args.Data"/>
|
||||||
|
/// </summary>
|
||||||
|
private void OnPacketReceived(EntityUid uid, ScreenComponent component, DeviceNetworkPacketEvent args)
|
||||||
|
{
|
||||||
|
if (args.Data.TryGetValue(ShuttleTimerMasks.ShuttleMap, out _))
|
||||||
|
ShuttleTimer(uid, component, args);
|
||||||
|
else
|
||||||
|
ScreenText(uid, component, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a text update to every screen on the same MapUid as the originating comms console.
|
||||||
|
/// </summary>
|
||||||
|
private void ScreenText(EntityUid uid, ScreenComponent component, DeviceNetworkPacketEvent args)
|
||||||
|
{
|
||||||
|
// don't allow text updates if there's an active timer
|
||||||
|
// (and just check here so the server doesn't have to track them)
|
||||||
|
if (_appearanceSystem.TryGetData(uid, TextScreenVisuals.TargetTime, out TimeSpan target)
|
||||||
|
&& target > _gameTiming.CurTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var screenMap = Transform(uid).MapUid;
|
||||||
|
var argsMap = Transform(args.Sender).MapUid;
|
||||||
|
|
||||||
|
if (screenMap != null
|
||||||
|
&& argsMap != null
|
||||||
|
&& screenMap == argsMap
|
||||||
|
&& args.Data.TryGetValue(ScreenMasks.Text, out string? text)
|
||||||
|
&& text != null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_appearanceSystem.SetData(uid, TextScreenVisuals.DefaultText, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if/how a timer packet affects this screen.
|
||||||
|
/// Currently there are 2 broadcast domains: Arrivals, and every other screen.
|
||||||
|
/// Domain is determined by the <see cref="DeviceNetworkComponent.TransmitFrequencyId"/> on each timer.
|
||||||
|
/// Each broadcast domain is divided into subnets. Screen MapUid determines subnet.
|
||||||
|
/// Subnets are the shuttle, source, and dest. Source/dest change each jump.
|
||||||
|
/// This is required to send different timers to the shuttle/terminal/station.
|
||||||
|
/// </summary>
|
||||||
|
private void ShuttleTimer(EntityUid uid, ScreenComponent component, DeviceNetworkPacketEvent args)
|
||||||
|
{
|
||||||
|
var timerXform = Transform(uid);
|
||||||
|
|
||||||
|
// no false positives.
|
||||||
|
if (timerXform.MapUid == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string key;
|
||||||
|
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);
|
||||||
|
string text = docked ? ShuttleTimerMasks.ETD : ShuttleTimerMasks.ETA;
|
||||||
|
|
||||||
|
switch (timerXform.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 || timerXform.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;
|
||||||
|
text = ShuttleTimerMasks.ETA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.Data.TryGetValue(key, out TimeSpan duration))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.Data.TryGetValue(ScreenMasks.Text, out string? label) && label != null)
|
||||||
|
text = label;
|
||||||
|
|
||||||
|
_appearanceSystem.SetData(uid, TextScreenVisuals.ScreenText, text);
|
||||||
|
_appearanceSystem.SetData(uid, TextScreenVisuals.TargetTime, _gameTiming.CurTime + duration);
|
||||||
|
|
||||||
|
if (args.Data.TryGetValue(ScreenMasks.Color, out Color color))
|
||||||
|
_appearanceSystem.SetData(uid, TextScreenVisuals.Color, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
namespace Content.Server.Shuttles.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class ShuttleTimerComponent : Component
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Awkward hashable string consts because NetworkPayload requires string keys
|
|
||||||
/// TODO: Refactor NetworkPayload to accept bytes from enums?
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ShuttleTimerMasks
|
|
||||||
{
|
|
||||||
public static readonly string ShuttleTime = "ShuttleTime";
|
|
||||||
public static readonly string DestTime = "DestTime";
|
|
||||||
public static readonly string SourceTime = "SourceTime";
|
|
||||||
public static readonly string ShuttleMap = "ShuttleMap";
|
|
||||||
public static readonly string SourceMap = "SourceMap";
|
|
||||||
public static readonly string DestMap = "DestMap";
|
|
||||||
public static readonly string Docked = "Docked";
|
|
||||||
public static readonly string Text = "Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ using Content.Server.DeviceNetwork;
|
|||||||
using Content.Server.DeviceNetwork.Components;
|
using Content.Server.DeviceNetwork.Components;
|
||||||
using Content.Server.DeviceNetwork.Systems;
|
using Content.Server.DeviceNetwork.Systems;
|
||||||
using Content.Server.Salvage;
|
using Content.Server.Salvage;
|
||||||
|
using Content.Server.Screens.Components;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Server.Shuttles.Events;
|
using Content.Server.Shuttles.Events;
|
||||||
using Content.Server.Spawners.Components;
|
using Content.Server.Spawners.Components;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.DeviceNetwork;
|
using Content.Server.DeviceNetwork;
|
||||||
using Content.Server.DeviceNetwork.Components;
|
using Content.Server.DeviceNetwork.Components;
|
||||||
|
using Content.Server.Screens.Components;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Server.Shuttles.Events;
|
using Content.Server.Shuttles.Events;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Content.Server.DeviceNetwork.Systems;
|
|||||||
using Content.Server.GameTicking.Events;
|
using Content.Server.GameTicking.Events;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.RoundEnd;
|
using Content.Server.RoundEnd;
|
||||||
|
using Content.Server.Screens.Components;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Server.Shuttles.Events;
|
using Content.Server.Shuttles.Events;
|
||||||
using Content.Server.Station.Components;
|
using Content.Server.Station.Components;
|
||||||
@@ -235,8 +236,18 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
|
|||||||
[ShuttleTimerMasks.ShuttleTime] = countdownTime,
|
[ShuttleTimerMasks.ShuttleTime] = countdownTime,
|
||||||
[ShuttleTimerMasks.SourceTime] = countdownTime,
|
[ShuttleTimerMasks.SourceTime] = countdownTime,
|
||||||
[ShuttleTimerMasks.DestTime] = countdownTime,
|
[ShuttleTimerMasks.DestTime] = countdownTime,
|
||||||
[ShuttleTimerMasks.Text] = new string?[] { "BYE!" }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// by popular request
|
||||||
|
// https://discord.com/channels/310555209753690112/770682801607278632/1189989482234126356
|
||||||
|
if (_random.Next(1000) == 0)
|
||||||
|
{
|
||||||
|
payload.Add(ScreenMasks.Text, ShuttleTimerMasks.Kill);
|
||||||
|
payload.Add(ScreenMasks.Color, Color.Red);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
payload.Add(ScreenMasks.Text, ShuttleTimerMasks.Bye);
|
||||||
|
|
||||||
_deviceNetworkSystem.QueuePacket(shuttle, null, payload, net.TransmitFrequency);
|
_deviceNetworkSystem.QueuePacket(shuttle, null, payload, net.TransmitFrequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
using Content.Shared.TextScreen;
|
|
||||||
using Content.Server.Shuttles.Components;
|
|
||||||
using Content.Server.DeviceNetwork.Systems;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Content.Server.Shuttles.Systems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Controls the wallmounted screens on stations and shuttles displaying e.g. FTL duration, ETA
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ShuttleTimerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<ShuttleTimerComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if/how a broadcast packet affects this timer.
|
|
||||||
/// All shuttle timer packets are broadcast in their network, and subnetting is implemented by filtering timer MapUid.
|
|
||||||
/// </summary>
|
|
||||||
private void OnPacketReceived(EntityUid uid, ShuttleTimerComponent component, DeviceNetworkPacketEvent args)
|
|
||||||
{
|
|
||||||
var timerXform = Transform(uid);
|
|
||||||
|
|
||||||
// no false positives.
|
|
||||||
if (timerXform.MapUid == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string key;
|
|
||||||
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);
|
|
||||||
string?[] text = new string?[] { docked ? Loc.GetString("shuttle-timer-etd") : Loc.GetString("shuttle-timer-eta")};
|
|
||||||
|
|
||||||
switch (timerXform.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 || timerXform.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;
|
|
||||||
text = new string?[] { Loc.GetString("shuttle-timer-eta") };
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!args.Data.TryGetValue(key, out TimeSpan duration))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (args.Data.TryGetValue(ShuttleTimerMasks.Text, out string?[]? label))
|
|
||||||
text = label;
|
|
||||||
|
|
||||||
_appearanceSystem.SetData(uid, TextScreenVisuals.TargetTime, _gameTiming.CurTime + duration);
|
|
||||||
_appearanceSystem.SetData(uid, TextScreenVisuals.ScreenText, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,6 +11,7 @@ namespace Content.Shared.Communications
|
|||||||
public sealed class CommunicationsConsoleInterfaceState : BoundUserInterfaceState
|
public sealed class CommunicationsConsoleInterfaceState : BoundUserInterfaceState
|
||||||
{
|
{
|
||||||
public readonly bool CanAnnounce;
|
public readonly bool CanAnnounce;
|
||||||
|
public readonly bool CanBroadcast;
|
||||||
public readonly bool CanCall;
|
public readonly bool CanCall;
|
||||||
public readonly TimeSpan? ExpectedCountdownEnd;
|
public readonly TimeSpan? ExpectedCountdownEnd;
|
||||||
public readonly bool CountdownStarted;
|
public readonly bool CountdownStarted;
|
||||||
@@ -18,9 +19,10 @@ namespace Content.Shared.Communications
|
|||||||
public string CurrentAlert;
|
public string CurrentAlert;
|
||||||
public float CurrentAlertDelay;
|
public float CurrentAlertDelay;
|
||||||
|
|
||||||
public CommunicationsConsoleInterfaceState(bool canAnnounce, bool canCall, List<string>? alertLevels, string currentAlert, float currentAlertDelay, TimeSpan? expectedCountdownEnd = null)
|
public CommunicationsConsoleInterfaceState(bool canAnnounce, bool canBroadcast, bool canCall, List<string>? alertLevels, string currentAlert, float currentAlertDelay, TimeSpan? expectedCountdownEnd = null)
|
||||||
{
|
{
|
||||||
CanAnnounce = canAnnounce;
|
CanAnnounce = canAnnounce;
|
||||||
|
CanBroadcast = canBroadcast;
|
||||||
CanCall = canCall;
|
CanCall = canCall;
|
||||||
ExpectedCountdownEnd = expectedCountdownEnd;
|
ExpectedCountdownEnd = expectedCountdownEnd;
|
||||||
CountdownStarted = expectedCountdownEnd != null;
|
CountdownStarted = expectedCountdownEnd != null;
|
||||||
@@ -52,6 +54,16 @@ namespace Content.Shared.Communications
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class CommunicationsConsoleBroadcastMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly string Message;
|
||||||
|
public CommunicationsConsoleBroadcastMessage(string message)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class CommunicationsConsoleCallEmergencyShuttleMessage : BoundUserInterfaceMessage
|
public sealed class CommunicationsConsoleCallEmergencyShuttleMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ namespace Content.Shared.TextScreen;
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public enum TextScreenVisuals : byte
|
public enum TextScreenVisuals : byte
|
||||||
{
|
{
|
||||||
|
// TODO: support for a small image, I think. Probably want to rename textscreen to just screen then.
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should this show any text? <br/>
|
/// What text to default to after timer completion?
|
||||||
/// Expects a <see cref="bool"/>.
|
/// Expects a <see cref="string"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
On,
|
DefaultText,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// What text to show? <br/>
|
/// What text to render? <br/>
|
||||||
/// Expects a <see cref="string?[]"/>.
|
/// Expects a <see cref="string"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ScreenText,
|
ScreenText,
|
||||||
|
|
||||||
@@ -21,5 +21,11 @@ public enum TextScreenVisuals : byte
|
|||||||
/// What is the target time? <br/>
|
/// What is the target time? <br/>
|
||||||
/// Expects a <see cref="TimeSpan"/>.
|
/// Expects a <see cref="TimeSpan"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TargetTime
|
TargetTime,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change text color on the entire screen
|
||||||
|
/// Expects a <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
Color
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
comms-console-menu-title = Communications Console
|
comms-console-menu-title = Communications Console
|
||||||
comms-console-menu-announcement-placeholder = Announcement text...
|
comms-console-menu-announcement-placeholder = Announcement text...
|
||||||
comms-console-menu-announcement-button = Announce
|
comms-console-menu-announcement-button = Announce
|
||||||
|
comms-console-menu-broadcast-button = Broadcast
|
||||||
comms-console-menu-call-shuttle = Call emergency shuttle
|
comms-console-menu-call-shuttle = Call emergency shuttle
|
||||||
comms-console-menu-recall-shuttle = Recall emergency shuttle
|
comms-console-menu-recall-shuttle = Recall emergency shuttle
|
||||||
|
|
||||||
|
|||||||
2
Resources/Locale/en-US/shuttles/screens.ftl
Normal file
2
Resources/Locale/en-US/shuttles/screens.ftl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
screens-text = text
|
||||||
|
screens-color = color
|
||||||
@@ -1,2 +1,11 @@
|
|||||||
shuttle-timer-eta = ETA
|
shuttle-timer-eta = ETA
|
||||||
shuttle-timer-etd = ETD
|
shuttle-timer-etd = ETD
|
||||||
|
shuttle-timer-shuttle-time = ShuttleTime
|
||||||
|
shuttle-timer-source-time = SourceTime
|
||||||
|
shuttle-timer-dest-time = DestTime
|
||||||
|
shuttle-timer-shuttle-map = ShuttleMap
|
||||||
|
shuttle-timer-source-map = SourceMap
|
||||||
|
shuttle-timer-dest-map = DestMap
|
||||||
|
shuttle-timer-docked = Docked
|
||||||
|
shuttle-timer-bye = BYE!
|
||||||
|
shuttle-timer-kill = KILL
|
||||||
|
|||||||
@@ -548,6 +548,8 @@
|
|||||||
access: [[ "Command" ]]
|
access: [[ "Command" ]]
|
||||||
- type: CommunicationsConsole
|
- type: CommunicationsConsole
|
||||||
title: comms-console-announcement-title-station
|
title: comms-console-announcement-title-station
|
||||||
|
- type: DeviceNetwork
|
||||||
|
transmitFrequencyId: ShuttleTimer
|
||||||
- type: ActivatableUI
|
- type: ActivatableUI
|
||||||
key: enum.CommunicationsConsoleUiKey.Key
|
key: enum.CommunicationsConsoleUiKey.Key
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
|
|||||||
@@ -2,12 +2,17 @@
|
|||||||
id: Screen
|
id: Screen
|
||||||
name: screen
|
name: screen
|
||||||
description: Displays text or time.
|
description: Displays text or time.
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
snap:
|
||||||
|
- Wallmount
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
anchored: true
|
anchored: true
|
||||||
- type: WallMount
|
- type: WallMount
|
||||||
arc: 360
|
arc: 360
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
|
- type: Clickable
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: Rotatable
|
- type: Rotatable
|
||||||
- type: TextScreenVisuals
|
- type: TextScreenVisuals
|
||||||
@@ -28,7 +33,7 @@
|
|||||||
enabled: false
|
enabled: false
|
||||||
usesApcPower: true
|
usesApcPower: true
|
||||||
- type: ExtensionCableReceiver
|
- type: ExtensionCableReceiver
|
||||||
- type: ShuttleTimer
|
- type: Screen
|
||||||
- type: DeviceNetwork
|
- type: DeviceNetwork
|
||||||
receiveFrequencyId: ShuttleTimer
|
receiveFrequencyId: ShuttleTimer
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
textOffset: 0,8
|
textOffset: 0,8
|
||||||
timerOffset: 0,8
|
timerOffset: 0,8
|
||||||
textLength: 5
|
textLength: 5
|
||||||
|
rows: 1
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
drawdepth: WallMountedItems
|
drawdepth: WallMountedItems
|
||||||
sprite: Structures/Wallmounts/signalscreen.rsi
|
sprite: Structures/Wallmounts/signalscreen.rsi
|
||||||
|
|||||||
Reference in New Issue
Block a user