Hallway textscreens (#24189)

* hallway screen refactor pending comms console support

* comms console broadcasts

* screen and timer localization
This commit is contained in:
avery
2024-01-27 05:51:24 -08:00
committed by GitHub
parent a923beb21b
commit 7e16ee0b55
23 changed files with 318 additions and 142 deletions

View File

@@ -16,6 +16,8 @@ namespace Content.Client.Communications.UI
[ViewVariables]
public bool CanAnnounce { get; private set; }
[ViewVariables]
public bool CanBroadcast { get; private set; }
[ViewVariables]
public bool CanCall { get; private set; }
@@ -71,6 +73,11 @@ namespace Content.Client.Communications.UI
SendMessage(new CommunicationsConsoleAnnounceMessage(msg));
}
public void BroadcastButtonPressed(string message)
{
SendMessage(new CommunicationsConsoleBroadcastMessage(message));
}
public void CallShuttle()
{
SendMessage(new CommunicationsConsoleCallEmergencyShuttleMessage());
@@ -89,6 +96,7 @@ namespace Content.Client.Communications.UI
return;
CanAnnounce = commsState.CanAnnounce;
CanBroadcast = commsState.CanBroadcast;
CanCall = commsState.CanCall;
_expectedCountdownTime = commsState.ExpectedCountdownEnd;
CountdownStarted = commsState.CountdownStarted;
@@ -102,6 +110,7 @@ namespace Content.Client.Communications.UI
_menu.AlertLevelButton.Disabled = !AlertLevelSelectable;
_menu.EmergencyShuttleButton.Disabled = !CanCall;
_menu.AnnounceButton.Disabled = !CanAnnounce;
_menu.BroadcastButton.Disabled = !CanBroadcast;
}
}

View File

@@ -5,6 +5,7 @@
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="5">
<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="BroadcastButton" Text="{Loc 'comms-console-menu-broadcast-button'}" StyleClasses="OpenLeft" Access="Public" />
<OptionButton Name="AlertLevelButton" StyleClasses="OpenRight" Access="Public" />

View File

@@ -26,6 +26,9 @@ namespace Content.Client.Communications.UI
AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope));
AnnounceButton.Disabled = !owner.CanAnnounce;
BroadcastButton.OnPressed += (_) => Owner.BroadcastButtonPressed(Rope.Collapse(MessageInput.TextRope));
BroadcastButton.Disabled = !owner.CanBroadcast;
AlertLevelButton.OnItemSelected += args =>
{
var metadata = AlertLevelButton.GetItemMetadata(args.Id);

View File

@@ -99,19 +99,43 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
/// Called by <see cref="SharedAppearanceSystem.SetData"/> to handle text updates,
/// and spawn a <see cref="TextScreenTimerComponent"/> if necessary
/// </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)
{
if (!Resolve(uid, ref args.Sprite))
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);
timer.Target = time;
timer.Target = target;
BuildTimerLayers(uid, timer, component);
DrawLayers(uid, timer.LayerStatesToDraw);
}
@@ -120,14 +144,6 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
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>
@@ -151,10 +167,28 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
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>
/// Clears <see cref="TextScreenVisualsComponent.LayerStatesToDraw"/>, and instantiates new blank defaults.
/// </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))
return;
@@ -167,11 +201,12 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
for (var row = 0; row < component.Rows; row++)
for (var i = 0; i < component.RowLength; i++)
{
sprite.LayerMapReserveBlank(TextMapKey + row + i);
component.LayerStatesToDraw.Add(TextMapKey + row + i, null);
sprite.LayerSetRSI(TextMapKey + row + i, new ResPath(TextPath));
sprite.LayerSetColor(TextMapKey + row + i, component.Color);
sprite.LayerSetState(TextMapKey + row + i, DefaultState);
var key = TextMapKey + row + i;
sprite.LayerMapReserveBlank(key);
component.LayerStatesToDraw.Add(key, null);
sprite.LayerSetRSI(key, new ResPath(TextPath));
sprite.LayerSetColor(key, component.Color);
sprite.LayerSetState(key, DefaultState);
}
}
@@ -182,7 +217,7 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
/// <remarks>
/// Remember to set <see cref="TextScreenVisualsComponent.TextToDraw"/> to a string?[] first.
/// </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))
return;
@@ -211,7 +246,7 @@ public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsCompone
/// <summary>
/// Populates timer.LayerStatesToDraw & the sprite component's layer dict with calculated offsets.
/// </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))
return;

View File

@@ -1,5 +1,4 @@
using System.Numerics;
using Content.Shared.TextScreen;
using Robust.Client.Graphics;
namespace Content.Client.TextScreen;
@@ -37,7 +36,7 @@ public sealed partial class TextScreenVisualsComponent : Component
/// Number of rows of text this screen can render.
/// </summary>
[DataField("rows")]
public int Rows = 1;
public int Rows = 2;
/// <summary>
/// Spacing between each text row