diff --git a/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupMessage.xaml.cs b/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupMessage.xaml.cs
index 7bb425f618..c8d7e915a1 100644
--- a/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupMessage.xaml.cs
+++ b/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupMessage.xaml.cs
@@ -1,4 +1,4 @@
-using Content.Shared.Administration.Notes;
+using Content.Shared.Administration.Notes;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
@@ -13,7 +13,7 @@ public AdminMessagePopupMessage(AdminMessageEuiState.Message message)
{
RobustXamlLoader.Load(this);
- Admin.SetMessage(FormattedMessage.FromMarkup(Loc.GetString(
+ Admin.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString(
"admin-notes-message-admin",
("admin", message.AdminName),
("date", message.AddedOn.ToLocalTime()))));
diff --git a/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupWindow.xaml.cs b/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupWindow.xaml.cs
index bf2ca9bec4..148cbf4e18 100644
--- a/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupWindow.xaml.cs
+++ b/Content.Client/Administration/UI/AdminRemarks/AdminMessagePopupWindow.xaml.cs
@@ -49,7 +49,7 @@ public void SetState(AdminMessageEuiState state)
MessageContainer.AddChild(new AdminMessagePopupMessage(message));
}
- Description.SetMessage(FormattedMessage.FromMarkup(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
+ Description.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
}
private void OnDismissButtonPressed(BaseButton.ButtonEventArgs obj)
diff --git a/Content.Client/Administration/UI/Bwoink/BwoinkPanel.xaml.cs b/Content.Client/Administration/UI/Bwoink/BwoinkPanel.xaml.cs
index 7a032d0bbd..833514e4aa 100644
--- a/Content.Client/Administration/UI/Bwoink/BwoinkPanel.xaml.cs
+++ b/Content.Client/Administration/UI/Bwoink/BwoinkPanel.xaml.cs
@@ -59,7 +59,7 @@ public void ReceiveLine(SharedBwoinkSystem.BwoinkTextMessage message)
Unread++;
var formatted = new FormattedMessage(1);
- formatted.AddMarkup($"[color=gray]{message.SentAt.ToShortTimeString()}[/color] {message.Text}");
+ formatted.AddMarkupOrThrow($"[color=gray]{message.SentAt.ToShortTimeString()}[/color] {message.Text}");
TextOutput.AddMessage(formatted);
LastMessage = message.SentAt;
}
diff --git a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs
index 5d1985485c..f088ac1976 100644
--- a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs
+++ b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs
@@ -1,7 +1,5 @@
using Content.Shared.Anomaly;
-using Content.Shared.Gravity;
using JetBrains.Annotations;
-using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Anomaly.Ui;
diff --git a/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml
new file mode 100644
index 0000000000..6bdfb3989f
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs
new file mode 100644
index 0000000000..79bb66560e
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlarmEntryContainer.xaml.cs
@@ -0,0 +1,215 @@
+using Content.Client.Stylesheets;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Monitor;
+using Content.Shared.FixedPoint;
+using Content.Shared.Temperature;
+using Robust.Client.AutoGenerated;
+using Robust.Client.Graphics;
+using Robust.Client.ResourceManagement;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Map;
+using System.Linq;
+
+namespace Content.Client.Atmos.Consoles;
+
+[GenerateTypedNameReferences]
+public sealed partial class AtmosAlarmEntryContainer : BoxContainer
+{
+ public NetEntity NetEntity;
+ public EntityCoordinates? Coordinates;
+
+ private readonly IEntityManager _entManager;
+ private readonly IResourceCache _cache;
+
+ private Dictionary _alarmStrings = new Dictionary()
+ {
+ [AtmosAlarmType.Invalid] = "atmos-alerts-window-invalid-state",
+ [AtmosAlarmType.Normal] = "atmos-alerts-window-normal-state",
+ [AtmosAlarmType.Warning] = "atmos-alerts-window-warning-state",
+ [AtmosAlarmType.Danger] = "atmos-alerts-window-danger-state",
+ };
+
+ private Dictionary _gasShorthands = new Dictionary()
+ {
+ [Gas.Ammonia] = "NH₃",
+ [Gas.CarbonDioxide] = "CO₂",
+ [Gas.Frezon] = "F",
+ [Gas.Nitrogen] = "N₂",
+ [Gas.NitrousOxide] = "N₂O",
+ [Gas.Oxygen] = "O₂",
+ [Gas.Plasma] = "P",
+ [Gas.Tritium] = "T",
+ [Gas.WaterVapor] = "H₂O",
+ };
+
+ public AtmosAlarmEntryContainer(NetEntity uid, EntityCoordinates? coordinates)
+ {
+ RobustXamlLoader.Load(this);
+
+ _entManager = IoCManager.Resolve();
+ _cache = IoCManager.Resolve();
+
+ NetEntity = uid;
+ Coordinates = coordinates;
+
+ // Load fonts
+ var headerFont = new VectorFont(_cache.GetResource("/Fonts/NotoSans/NotoSans-Bold.ttf"), 11);
+ var normalFont = new VectorFont(_cache.GetResource("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
+ var smallFont = new VectorFont(_cache.GetResource("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
+
+ // Set fonts
+ TemperatureHeaderLabel.FontOverride = headerFont;
+ PressureHeaderLabel.FontOverride = headerFont;
+ OxygenationHeaderLabel.FontOverride = headerFont;
+ GasesHeaderLabel.FontOverride = headerFont;
+
+ TemperatureLabel.FontOverride = normalFont;
+ PressureLabel.FontOverride = normalFont;
+ OxygenationLabel.FontOverride = normalFont;
+
+ NoDataLabel.FontOverride = headerFont;
+
+ SilenceCheckBox.Label.FontOverride = smallFont;
+ SilenceCheckBox.Label.FontColorOverride = Color.DarkGray;
+ }
+
+ public void UpdateEntry(AtmosAlertsComputerEntry entry, bool isFocus, AtmosAlertsFocusDeviceData? focusData = null)
+ {
+ NetEntity = entry.NetEntity;
+ Coordinates = _entManager.GetCoordinates(entry.Coordinates);
+
+ // Load fonts
+ var normalFont = new VectorFont(_cache.GetResource("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
+
+ // Update alarm state
+ if (!_alarmStrings.TryGetValue(entry.AlarmState, out var alarmString))
+ alarmString = "atmos-alerts-window-invalid-state";
+
+ AlarmStateLabel.Text = Loc.GetString(alarmString);
+ AlarmStateLabel.FontColorOverride = GetAlarmStateColor(entry.AlarmState);
+
+ // Update alarm name
+ AlarmNameLabel.Text = Loc.GetString("atmos-alerts-window-alarm-label", ("name", entry.EntityName), ("address", entry.Address));
+
+ // Focus updates
+ FocusContainer.Visible = isFocus;
+
+ if (isFocus)
+ SetAsFocus();
+ else
+ RemoveAsFocus();
+
+ if (isFocus && entry.Group == AtmosAlertsComputerGroup.AirAlarm)
+ {
+ MainDataContainer.Visible = (entry.AlarmState != AtmosAlarmType.Invalid);
+ NoDataLabel.Visible = (entry.AlarmState == AtmosAlarmType.Invalid);
+
+ if (focusData != null)
+ {
+ // Update temperature
+ var tempK = (FixedPoint2)focusData.Value.TemperatureData.Item1;
+ var tempC = (FixedPoint2)TemperatureHelpers.KelvinToCelsius(tempK.Float());
+
+ TemperatureLabel.Text = Loc.GetString("atmos-alerts-window-temperature-value", ("valueInC", tempC), ("valueInK", tempK));
+ TemperatureLabel.FontColorOverride = GetAlarmStateColor(focusData.Value.TemperatureData.Item2);
+
+ // Update pressure
+ PressureLabel.Text = Loc.GetString("atmos-alerts-window-pressure-value", ("value", (FixedPoint2)focusData.Value.PressureData.Item1));
+ PressureLabel.FontColorOverride = GetAlarmStateColor(focusData.Value.PressureData.Item2);
+
+ // Update oxygenation
+ var oxygenPercent = (FixedPoint2)0f;
+ var oxygenAlert = AtmosAlarmType.Invalid;
+
+ if (focusData.Value.GasData.TryGetValue(Gas.Oxygen, out var oxygenData))
+ {
+ oxygenPercent = oxygenData.Item2 * 100f;
+ oxygenAlert = oxygenData.Item3;
+ }
+
+ OxygenationLabel.Text = Loc.GetString("atmos-alerts-window-oxygenation-value", ("value", oxygenPercent));
+ OxygenationLabel.FontColorOverride = GetAlarmStateColor(oxygenAlert);
+
+ // Update other present gases
+ GasGridContainer.RemoveAllChildren();
+
+ var gasData = focusData.Value.GasData.Where(g => g.Key != Gas.Oxygen);
+
+ if (gasData.Count() == 0)
+ {
+ // No other gases
+ var gasLabel = new Label()
+ {
+ Text = Loc.GetString("atmos-alerts-window-other-gases-value-nil"),
+ FontOverride = normalFont,
+ FontColorOverride = StyleNano.DisabledFore,
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ HorizontalExpand = true,
+ Margin = new Thickness(0, 2, 0, 0),
+ SetHeight = 24f,
+ };
+
+ GasGridContainer.AddChild(gasLabel);
+ }
+
+ else
+ {
+ // Add an entry for each gas
+ foreach ((var gas, (var mol, var percent, var alert)) in gasData)
+ {
+ var gasPercent = (FixedPoint2)0f;
+ gasPercent = percent * 100f;
+
+ if (!_gasShorthands.TryGetValue(gas, out var gasShorthand))
+ gasShorthand = "X";
+
+ var gasLabel = new Label()
+ {
+ Text = Loc.GetString("atmos-alerts-window-other-gases-value", ("shorthand", gasShorthand), ("value", gasPercent)),
+ FontOverride = normalFont,
+ FontColorOverride = GetAlarmStateColor(alert),
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ HorizontalExpand = true,
+ Margin = new Thickness(0, 2, 0, 0),
+ SetHeight = 24f,
+ };
+
+ GasGridContainer.AddChild(gasLabel);
+ }
+ }
+ }
+ }
+ }
+
+ public void SetAsFocus()
+ {
+ FocusButton.AddStyleClass(StyleNano.StyleClassButtonColorGreen);
+ ArrowTexture.TexturePath = "/Textures/Interface/Nano/inverted_triangle.svg.png";
+ }
+
+ public void RemoveAsFocus()
+ {
+ FocusButton.RemoveStyleClass(StyleNano.StyleClassButtonColorGreen);
+ ArrowTexture.TexturePath = "/Textures/Interface/Nano/triangle_right.png";
+ FocusContainer.Visible = false;
+ }
+
+ private Color GetAlarmStateColor(AtmosAlarmType alarmType)
+ {
+ switch (alarmType)
+ {
+ case AtmosAlarmType.Normal:
+ return StyleNano.GoodGreenFore;
+ case AtmosAlarmType.Warning:
+ return StyleNano.ConcerningOrangeFore;
+ case AtmosAlarmType.Danger:
+ return StyleNano.DangerousRedFore;
+ }
+
+ return StyleNano.DisabledFore;
+ }
+}
diff --git a/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs b/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs
new file mode 100644
index 0000000000..08cae979b9
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Atmos.Components;
+
+namespace Content.Client.Atmos.Consoles;
+
+public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
+{
+ [ViewVariables]
+ private AtmosAlertsComputerWindow? _menu;
+
+ public AtmosAlertsComputerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }
+
+ protected override void Open()
+ {
+ _menu = new AtmosAlertsComputerWindow(this, Owner);
+ _menu.OpenCentered();
+ _menu.OnClose += Close;
+
+ EntMan.TryGetComponent(Owner, out var xform);
+ }
+
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+
+ var castState = (AtmosAlertsComputerBoundInterfaceState) state;
+
+ if (castState == null)
+ return;
+
+ EntMan.TryGetComponent(Owner, out var xform);
+ _menu?.UpdateUI(xform?.Coordinates, castState.AirAlarms, castState.FireAlarms, castState.FocusData);
+ }
+
+ public void SendFocusChangeMessage(NetEntity? netEntity)
+ {
+ SendMessage(new AtmosAlertsComputerFocusChangeMessage(netEntity));
+ }
+
+ public void SendDeviceSilencedMessage(NetEntity netEntity, bool silenceDevice)
+ {
+ SendMessage(new AtmosAlertsComputerDeviceSilencedMessage(netEntity, silenceDevice));
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing)
+ return;
+
+ _menu?.Dispose();
+ }
+}
diff --git a/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml
new file mode 100644
index 0000000000..8824a776ee
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml.cs b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml.cs
new file mode 100644
index 0000000000..f0b7ffbe11
--- /dev/null
+++ b/Content.Client/Atmos/Consoles/AtmosAlertsComputerWindow.xaml.cs
@@ -0,0 +1,548 @@
+using Content.Client.Message;
+using Content.Client.Pinpointer.UI;
+using Content.Client.Stylesheets;
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Atmos.Components;
+using Content.Shared.Atmos.Monitor;
+using Content.Shared.Pinpointer;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Map;
+using Robust.Shared.Timing;
+using Robust.Shared.Utility;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+namespace Content.Client.Atmos.Consoles;
+
+[GenerateTypedNameReferences]
+public sealed partial class AtmosAlertsComputerWindow : FancyWindow
+{
+ private readonly IEntityManager _entManager;
+ private readonly SpriteSystem _spriteSystem;
+
+ private EntityUid? _owner;
+ private NetEntity? _trackedEntity;
+
+ private AtmosAlertsComputerEntry[]? _airAlarms = null;
+ private AtmosAlertsComputerEntry[]? _fireAlarms = null;
+ private IEnumerable? _allAlarms = null;
+
+ private IEnumerable? _activeAlarms = null;
+ private Dictionary _deviceSilencingProgress = new();
+
+ public event Action? SendFocusChangeMessageAction;
+ public event Action? SendDeviceSilencedMessageAction;
+
+ private bool _autoScrollActive = false;
+ private bool _autoScrollAwaitsUpdate = false;
+
+ private const float SilencingDuration = 2.5f;
+
+ public AtmosAlertsComputerWindow(AtmosAlertsComputerBoundUserInterface userInterface, EntityUid? owner)
+ {
+ RobustXamlLoader.Load(this);
+ _entManager = IoCManager.Resolve();
+ _spriteSystem = _entManager.System();
+
+ // Pass the owner to nav map
+ _owner = owner;
+ NavMap.Owner = _owner;
+
+ // Set nav map colors
+ NavMap.WallColor = new Color(64, 64, 64);
+ NavMap.TileColor = Color.DimGray * NavMap.WallColor;
+
+ // Set nav map grid uid
+ var stationName = Loc.GetString("atmos-alerts-window-unknown-location");
+
+ if (_entManager.TryGetComponent(owner, out var xform))
+ {
+ NavMap.MapUid = xform.GridUid;
+
+ // Assign station name
+ if (_entManager.TryGetComponent(xform.GridUid, out var stationMetaData))
+ stationName = stationMetaData.EntityName;
+
+ var msg = new FormattedMessage();
+ msg.TryAddMarkup(Loc.GetString("atmos-alerts-window-station-name", ("stationName", stationName)), out _);
+
+ StationName.SetMessage(msg);
+ }
+
+ else
+ {
+ StationName.SetMessage(stationName);
+ NavMap.Visible = false;
+ }
+
+ // Set trackable entity selected action
+ NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap;
+
+ // Update nav map
+ NavMap.ForceNavMapUpdate();
+
+ // Set tab container headers
+ MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-no-alerts"));
+ MasterTabContainer.SetTabTitle(1, Loc.GetString("atmos-alerts-window-tab-air-alarms"));
+ MasterTabContainer.SetTabTitle(2, Loc.GetString("atmos-alerts-window-tab-fire-alarms"));
+
+ // Set UI toggles
+ ShowInactiveAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowInactiveAlarms, AtmosAlarmType.Invalid);
+ ShowNormalAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowNormalAlarms, AtmosAlarmType.Normal);
+ ShowWarningAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowWarningAlarms, AtmosAlarmType.Warning);
+ ShowDangerAlarms.OnToggled += _ => OnShowAlarmsToggled(ShowDangerAlarms, AtmosAlarmType.Danger);
+
+ // Set atmos monitoring message action
+ SendFocusChangeMessageAction += userInterface.SendFocusChangeMessage;
+ SendDeviceSilencedMessageAction += userInterface.SendDeviceSilencedMessage;
+ }
+
+ #region Toggle handling
+
+ private void OnShowAlarmsToggled(CheckBox toggle, AtmosAlarmType toggledAlarmState)
+ {
+ if (_owner == null)
+ return;
+
+ if (!_entManager.TryGetComponent(_owner.Value, out var console))
+ return;
+
+ foreach (var device in console.AtmosDevices)
+ {
+ var alarmState = GetAlarmState(device.NetEntity);
+
+ if (toggledAlarmState != alarmState)
+ continue;
+
+ if (toggle.Pressed)
+ AddTrackedEntityToNavMap(device, alarmState);
+
+ else
+ NavMap.TrackedEntities.Remove(device.NetEntity);
+ }
+ }
+
+ private void OnSilenceAlertsToggled(NetEntity netEntity, bool toggleState)
+ {
+ if (!_entManager.TryGetComponent(_owner, out var console))
+ return;
+
+ if (toggleState)
+ _deviceSilencingProgress[netEntity] = SilencingDuration;
+
+ else
+ _deviceSilencingProgress.Remove(netEntity);
+
+ foreach (AtmosAlarmEntryContainer entryContainer in AlertsTable.Children)
+ {
+ if (entryContainer.NetEntity == netEntity)
+ entryContainer.SilenceAlarmProgressBar.Visible = toggleState;
+ }
+
+ SendDeviceSilencedMessageAction?.Invoke(netEntity, toggleState);
+ }
+
+ #endregion
+
+ public void UpdateUI(EntityCoordinates? consoleCoords, AtmosAlertsComputerEntry[] airAlarms, AtmosAlertsComputerEntry[] fireAlarms, AtmosAlertsFocusDeviceData? focusData)
+ {
+ if (_owner == null)
+ return;
+
+ if (!_entManager.TryGetComponent(_owner.Value, out var console))
+ return;
+
+ if (_trackedEntity != focusData?.NetEntity)
+ {
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+ focusData = null;
+ }
+
+ // Retain alarm data for use inbetween updates
+ _airAlarms = airAlarms;
+ _fireAlarms = fireAlarms;
+ _allAlarms = airAlarms.Concat(fireAlarms);
+
+ var silenced = console.SilencedDevices;
+
+ _activeAlarms = _allAlarms.Where(x => x.AlarmState > AtmosAlarmType.Normal &&
+ (!silenced.Contains(x.NetEntity) || _deviceSilencingProgress.ContainsKey(x.NetEntity)));
+
+ // Reset nav map data
+ NavMap.TrackedCoordinates.Clear();
+ NavMap.TrackedEntities.Clear();
+
+ // Add tracked entities to the nav map
+ foreach (var device in console.AtmosDevices)
+ {
+ if (!NavMap.Visible)
+ continue;
+
+ var alarmState = GetAlarmState(device.NetEntity);
+
+ if (_trackedEntity != device.NetEntity)
+ {
+ // Skip air alarms if the appropriate overlay is off
+ if (!ShowInactiveAlarms.Pressed && alarmState == AtmosAlarmType.Invalid)
+ continue;
+
+ if (!ShowNormalAlarms.Pressed && alarmState == AtmosAlarmType.Normal)
+ continue;
+
+ if (!ShowWarningAlarms.Pressed && alarmState == AtmosAlarmType.Warning)
+ continue;
+
+ if (!ShowDangerAlarms.Pressed && alarmState == AtmosAlarmType.Danger)
+ continue;
+ }
+
+ AddTrackedEntityToNavMap(device, alarmState);
+ }
+
+ // Show the monitor location
+ var consoleUid = _entManager.GetNetEntity(_owner);
+
+ if (consoleCoords != null && consoleUid != null)
+ {
+ var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
+ var blip = new NavMapBlip(consoleCoords.Value, texture, Color.Cyan, true, false);
+ NavMap.TrackedEntities[consoleUid.Value] = blip;
+ }
+
+ // Update the nav map
+ NavMap.ForceNavMapUpdate();
+
+ // Clear excess children from the tables
+ var activeAlarmCount = _activeAlarms.Count();
+
+ while (AlertsTable.ChildCount > activeAlarmCount)
+ AlertsTable.RemoveChild(AlertsTable.GetChild(AlertsTable.ChildCount - 1));
+
+ while (AirAlarmsTable.ChildCount > airAlarms.Length)
+ AirAlarmsTable.RemoveChild(AirAlarmsTable.GetChild(AirAlarmsTable.ChildCount - 1));
+
+ while (FireAlarmsTable.ChildCount > fireAlarms.Length)
+ FireAlarmsTable.RemoveChild(FireAlarmsTable.GetChild(FireAlarmsTable.ChildCount - 1));
+
+ // Update all entries in each table
+ for (int index = 0; index < _activeAlarms.Count(); index++)
+ {
+ var entry = _activeAlarms.ElementAt(index);
+ UpdateUIEntry(entry, index, AlertsTable, console, focusData);
+ }
+
+ for (int index = 0; index < airAlarms.Count(); index++)
+ {
+ var entry = airAlarms.ElementAt(index);
+ UpdateUIEntry(entry, index, AirAlarmsTable, console, focusData);
+ }
+
+ for (int index = 0; index < fireAlarms.Count(); index++)
+ {
+ var entry = fireAlarms.ElementAt(index);
+ UpdateUIEntry(entry, index, FireAlarmsTable, console, focusData);
+ }
+
+ // If no alerts are active, display a message
+ if (MasterTabContainer.CurrentTab == 0 && activeAlarmCount == 0)
+ {
+ var label = new RichTextLabel()
+ {
+ HorizontalExpand = true,
+ VerticalExpand = true,
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ };
+
+ label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", StyleNano.GoodGreenFore.ToHexNoAlpha())));
+
+ AlertsTable.AddChild(label);
+ }
+
+ // Update the alerts tab with the number of active alerts
+ if (activeAlarmCount == 0)
+ MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-no-alerts"));
+
+ else
+ MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-alerts", ("value", activeAlarmCount)));
+
+ // Auto-scroll re-enable
+ if (_autoScrollAwaitsUpdate)
+ {
+ _autoScrollActive = true;
+ _autoScrollAwaitsUpdate = false;
+ }
+ }
+
+ private void AddTrackedEntityToNavMap(AtmosAlertsDeviceNavMapData metaData, AtmosAlarmType alarmState)
+ {
+ var data = GetBlipTexture(alarmState);
+
+ if (data == null)
+ return;
+
+ var texture = data.Value.Item1;
+ var color = data.Value.Item2;
+ var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
+
+ if (_trackedEntity != null && _trackedEntity != metaData.NetEntity)
+ color *= Color.DimGray;
+
+ var selectable = true;
+ var blip = new NavMapBlip(coords, _spriteSystem.Frame0(texture), color, _trackedEntity == metaData.NetEntity, selectable);
+
+ NavMap.TrackedEntities[metaData.NetEntity] = blip;
+ }
+
+ private void UpdateUIEntry(AtmosAlertsComputerEntry entry, int index, Control table, AtmosAlertsComputerComponent console, AtmosAlertsFocusDeviceData? focusData = null)
+ {
+ // Make new UI entry if required
+ if (index >= table.ChildCount)
+ {
+ var newEntryContainer = new AtmosAlarmEntryContainer(entry.NetEntity, _entManager.GetCoordinates(entry.Coordinates));
+
+ // On click
+ newEntryContainer.FocusButton.OnButtonUp += args =>
+ {
+ if (_trackedEntity == newEntryContainer.NetEntity)
+ {
+ _trackedEntity = null;
+ }
+
+ else
+ {
+ _trackedEntity = newEntryContainer.NetEntity;
+
+ if (newEntryContainer.Coordinates != null)
+ NavMap.CenterToCoordinates(newEntryContainer.Coordinates.Value);
+ }
+
+ // Send message to console that the focus has changed
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+
+ // Update affected UI elements across all tables
+ UpdateConsoleTable(console, AlertsTable, _trackedEntity);
+ UpdateConsoleTable(console, AirAlarmsTable, _trackedEntity);
+ UpdateConsoleTable(console, FireAlarmsTable, _trackedEntity);
+ };
+
+ // On toggling the silence check box
+ newEntryContainer.SilenceCheckBox.OnToggled += _ => OnSilenceAlertsToggled(newEntryContainer.NetEntity, newEntryContainer.SilenceCheckBox.Pressed);
+
+ // Add the entry to the current table
+ table.AddChild(newEntryContainer);
+ }
+
+ // Update values and UI elements
+ var tableChild = table.GetChild(index);
+
+ if (tableChild is not AtmosAlarmEntryContainer)
+ {
+ table.RemoveChild(tableChild);
+ UpdateUIEntry(entry, index, table, console, focusData);
+
+ return;
+ }
+
+ var entryContainer = (AtmosAlarmEntryContainer)tableChild;
+
+ entryContainer.UpdateEntry(entry, entry.NetEntity == _trackedEntity, focusData);
+
+ if (_trackedEntity != entry.NetEntity)
+ {
+ var silenced = console.SilencedDevices;
+ entryContainer.SilenceCheckBox.Pressed = (silenced.Contains(entry.NetEntity) || _deviceSilencingProgress.ContainsKey(entry.NetEntity));
+ }
+
+ entryContainer.SilenceAlarmProgressBar.Visible = (table == AlertsTable && _deviceSilencingProgress.ContainsKey(entry.NetEntity));
+ }
+
+ private void UpdateConsoleTable(AtmosAlertsComputerComponent console, Control table, NetEntity? currTrackedEntity)
+ {
+ foreach (var tableChild in table.Children)
+ {
+ if (tableChild is not AtmosAlarmEntryContainer)
+ continue;
+
+ var entryContainer = (AtmosAlarmEntryContainer)tableChild;
+
+ if (entryContainer.NetEntity != currTrackedEntity)
+ entryContainer.RemoveAsFocus();
+
+ else if (entryContainer.NetEntity == currTrackedEntity)
+ entryContainer.SetAsFocus();
+ }
+ }
+
+ private void SetTrackedEntityFromNavMap(NetEntity? netEntity)
+ {
+ if (netEntity == null)
+ return;
+
+ if (!_entManager.TryGetComponent(_owner, out var console))
+ return;
+
+ _trackedEntity = netEntity;
+
+ if (netEntity != null)
+ {
+ // Tab switching
+ if (MasterTabContainer.CurrentTab != 0 || _activeAlarms?.Any(x => x.NetEntity == netEntity) == false)
+ {
+ var device = console.AtmosDevices.FirstOrNull(x => x.NetEntity == netEntity);
+
+ switch (device?.Group)
+ {
+ case AtmosAlertsComputerGroup.AirAlarm:
+ MasterTabContainer.CurrentTab = 1; break;
+ case AtmosAlertsComputerGroup.FireAlarm:
+ MasterTabContainer.CurrentTab = 2; break;
+ }
+ }
+
+ // Get the scroll position of the selected entity on the selected button the UI
+ ActivateAutoScrollToFocus();
+ }
+
+ // Send message to console that the focus has changed
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+ }
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ AutoScrollToFocus();
+
+ // Device silencing update
+ foreach ((var device, var remainingTime) in _deviceSilencingProgress)
+ {
+ var t = remainingTime - args.DeltaSeconds;
+
+ if (t <= 0)
+ {
+ _deviceSilencingProgress.Remove(device);
+
+ if (device == _trackedEntity)
+ _trackedEntity = null;
+ }
+
+ else
+ _deviceSilencingProgress[device] = t;
+ }
+ }
+
+ private void ActivateAutoScrollToFocus()
+ {
+ _autoScrollActive = false;
+ _autoScrollAwaitsUpdate = true;
+ }
+
+ private void AutoScrollToFocus()
+ {
+ if (!_autoScrollActive)
+ return;
+
+ var scroll = MasterTabContainer.Children.ElementAt(MasterTabContainer.CurrentTab) as ScrollContainer;
+ if (scroll == null)
+ return;
+
+ if (!TryGetVerticalScrollbar(scroll, out var vScrollbar))
+ return;
+
+ if (!TryGetNextScrollPosition(out float? nextScrollPosition))
+ return;
+
+ vScrollbar.ValueTarget = nextScrollPosition.Value;
+
+ if (MathHelper.CloseToPercent(vScrollbar.Value, vScrollbar.ValueTarget))
+ _autoScrollActive = false;
+ }
+
+ private bool TryGetVerticalScrollbar(ScrollContainer scroll, [NotNullWhen(true)] out VScrollBar? vScrollBar)
+ {
+ vScrollBar = null;
+
+ foreach (var child in scroll.Children)
+ {
+ if (child is not VScrollBar)
+ continue;
+
+ var castChild = child as VScrollBar;
+
+ if (castChild != null)
+ {
+ vScrollBar = castChild;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private bool TryGetNextScrollPosition([NotNullWhen(true)] out float? nextScrollPosition)
+ {
+ nextScrollPosition = null;
+
+ var scroll = MasterTabContainer.Children.ElementAt(MasterTabContainer.CurrentTab) as ScrollContainer;
+ if (scroll == null)
+ return false;
+
+ var container = scroll.Children.ElementAt(0) as BoxContainer;
+ if (container == null || container.Children.Count() == 0)
+ return false;
+
+ // Exit if the heights of the children haven't been initialized yet
+ if (!container.Children.Any(x => x.Height > 0))
+ return false;
+
+ nextScrollPosition = 0;
+
+ foreach (var control in container.Children)
+ {
+ if (control == null || control is not AtmosAlarmEntryContainer)
+ continue;
+
+ if (((AtmosAlarmEntryContainer)control).NetEntity == _trackedEntity)
+ return true;
+
+ nextScrollPosition += control.Height;
+ }
+
+ // Failed to find control
+ nextScrollPosition = null;
+
+ return false;
+ }
+
+ private AtmosAlarmType GetAlarmState(NetEntity netEntity)
+ {
+ var alarmState = _allAlarms?.FirstOrNull(x => x.NetEntity == netEntity)?.AlarmState;
+
+ if (alarmState == null)
+ return AtmosAlarmType.Invalid;
+
+ return alarmState.Value;
+ }
+
+ private (SpriteSpecifier.Texture, Color)? GetBlipTexture(AtmosAlarmType alarmState)
+ {
+ (SpriteSpecifier.Texture, Color)? output = null;
+
+ switch (alarmState)
+ {
+ case AtmosAlarmType.Invalid:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), StyleNano.DisabledFore); break;
+ case AtmosAlarmType.Normal:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), Color.LimeGreen); break;
+ case AtmosAlarmType.Warning:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), new Color(255, 182, 72)); break;
+ case AtmosAlarmType.Danger:
+ output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), new Color(255, 67, 67)); break;
+ }
+
+ return output;
+ }
+}
diff --git a/Content.Client/Changelog/ChangelogTab.xaml.cs b/Content.Client/Changelog/ChangelogTab.xaml.cs
index 8fbeaab5f4..ca86f8a6b2 100644
--- a/Content.Client/Changelog/ChangelogTab.xaml.cs
+++ b/Content.Client/Changelog/ChangelogTab.xaml.cs
@@ -131,13 +131,13 @@ public void PopulateChangelog(ChangelogManager.Changelog changelog)
Margin = new Thickness(6, 0, 0, 0),
};
authorLabel.SetMessage(
- FormattedMessage.FromMarkup(Loc.GetString("changelog-author-changed", ("author", author))));
+ FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", author))));
ChangelogBody.AddChild(authorLabel);
foreach (var change in groupedEntry.SelectMany(c => c.Changes))
{
var text = new RichTextLabel();
- text.SetMessage(FormattedMessage.FromMarkup(change.Message));
+ text.SetMessage(FormattedMessage.FromMarkupOrThrow(change.Message));
ChangelogBody.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
diff --git a/Content.Client/Chat/UI/SpeechBubble.cs b/Content.Client/Chat/UI/SpeechBubble.cs
index adb61d10e6..32e9f4ae9b 100644
--- a/Content.Client/Chat/UI/SpeechBubble.cs
+++ b/Content.Client/Chat/UI/SpeechBubble.cs
@@ -180,7 +180,7 @@ protected FormattedMessage FormatSpeech(string message, Color? fontColor = null)
var msg = new FormattedMessage();
if (fontColor != null)
msg.PushColor(fontColor.Value);
- msg.AddMarkup(message);
+ msg.AddMarkupOrThrow(message);
return msg;
}
diff --git a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs
index a3cedb5f2f..7c7d824ee9 100644
--- a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs
+++ b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs
@@ -1,5 +1,5 @@
using System.Linq;
-using Content.Client.Chemistry.Containers.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Atmos.Prototypes;
using Content.Shared.Body.Part;
using Content.Shared.Chemistry;
@@ -16,7 +16,7 @@ namespace Content.Client.Chemistry.EntitySystems;
///
public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
{
- [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
[ValidatePrototypeId]
private const string DefaultMixingCategory = "DummyMix";
diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs
index 96bbcc54f2..27d77eda49 100644
--- a/Content.Client/Clothing/ClientClothingSystem.cs
+++ b/Content.Client/Clothing/ClientClothingSystem.cs
@@ -50,7 +50,6 @@ public sealed class ClientClothingSystem : ClothingSystem
};
[Dependency] private readonly IResourceCache _cache = default!;
- [Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
diff --git a/Content.Client/Commands/ActionsCommands.cs b/Content.Client/Commands/ActionsCommands.cs
index 593b8e8256..c155c7a9de 100644
--- a/Content.Client/Commands/ActionsCommands.cs
+++ b/Content.Client/Commands/ActionsCommands.cs
@@ -1,6 +1,4 @@
using Content.Client.Actions;
-using Content.Client.Actions;
-using Content.Client.Mapping;
using Content.Shared.Administration;
using Robust.Shared.Console;
diff --git a/Content.Client/Commands/MappingClientSideSetupCommand.cs b/Content.Client/Commands/MappingClientSideSetupCommand.cs
index 3255e85e18..d17f1fccaf 100644
--- a/Content.Client/Commands/MappingClientSideSetupCommand.cs
+++ b/Content.Client/Commands/MappingClientSideSetupCommand.cs
@@ -13,7 +13,6 @@ internal sealed class MappingClientSideSetupCommand : LocalizedCommands
{
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly ILightManager _lightManager = default!;
- [Dependency] private readonly IStateManager _stateManager = default!;
public override string Command => "mappingclientsidesetup";
diff --git a/Content.Client/Computer/ComputerBoundUserInterface.cs b/Content.Client/Computer/ComputerBoundUserInterface.cs
index 11c26b252e..9f34eeda20 100644
--- a/Content.Client/Computer/ComputerBoundUserInterface.cs
+++ b/Content.Client/Computer/ComputerBoundUserInterface.cs
@@ -11,8 +11,6 @@ namespace Content.Client.Computer
[Virtual]
public class ComputerBoundUserInterface : ComputerBoundUserInterfaceBase where TWindow : BaseWindow, IComputerWindow, new() where TState : BoundUserInterfaceState
{
- [Dependency] private readonly IDynamicTypeFactory _dynamicTypeFactory = default!;
-
[ViewVariables]
private TWindow? _window;
diff --git a/Content.Client/Credits/CreditsWindow.xaml.cs b/Content.Client/Credits/CreditsWindow.xaml.cs
index 60ac579845..ba24020953 100644
--- a/Content.Client/Credits/CreditsWindow.xaml.cs
+++ b/Content.Client/Credits/CreditsWindow.xaml.cs
@@ -145,7 +145,7 @@ void AddSection(string title, string path, bool markup = false)
var text = _resourceManager.ContentFileReadAllText($"/Credits/{path}");
if (markup)
{
- label.SetMessage(FormattedMessage.FromMarkup(text.Trim()));
+ label.SetMessage(FormattedMessage.FromMarkupOrThrow(text.Trim()));
}
else
{
diff --git a/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs b/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs
index 21aa54c962..7cae290fe1 100644
--- a/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs
+++ b/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs
@@ -227,7 +227,7 @@ private void PopulateRecordContainer(GeneralStationRecord stationRecord, Crimina
StatusOptionButton.SelectId((int) criminalRecord.Status);
if (criminalRecord.Reason is {} reason)
{
- var message = FormattedMessage.FromMarkup(Loc.GetString("criminal-records-console-wanted-reason"));
+ var message = FormattedMessage.FromMarkupOrThrow(Loc.GetString("criminal-records-console-wanted-reason"));
message.AddText($": {reason}");
WantedReason.SetMessage(message);
WantedReason.Visible = true;
diff --git a/Content.Client/Gravity/GravitySystem.cs b/Content.Client/Gravity/GravitySystem.cs
index 3e87f76ba2..dd51436a1f 100644
--- a/Content.Client/Gravity/GravitySystem.cs
+++ b/Content.Client/Gravity/GravitySystem.cs
@@ -1,4 +1,5 @@
using Content.Shared.Gravity;
+using Content.Shared.Power;
using Robust.Client.GameObjects;
namespace Content.Client.Gravity;
@@ -21,7 +22,7 @@ private void OnAppearanceChange(EntityUid uid, SharedGravityGeneratorComponent c
if (args.Sprite == null)
return;
- if (_appearanceSystem.TryGetData(uid, GravityGeneratorVisuals.State, out var state, args.Component))
+ if (_appearanceSystem.TryGetData(uid, PowerChargeVisuals.State, out var state, args.Component))
{
if (comp.SpriteMap.TryGetValue(state, out var spriteState))
{
@@ -30,7 +31,7 @@ private void OnAppearanceChange(EntityUid uid, SharedGravityGeneratorComponent c
}
}
- if (_appearanceSystem.TryGetData(uid, GravityGeneratorVisuals.Charge, out var charge, args.Component))
+ if (_appearanceSystem.TryGetData(uid, PowerChargeVisuals.Charge, out var charge, args.Component))
{
var layer = args.Sprite.LayerMapGet(GravityGeneratorVisualLayers.Core);
switch (charge)
diff --git a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs b/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs
deleted file mode 100644
index 32b40747d5..0000000000
--- a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using Content.Shared.Gravity;
-using JetBrains.Annotations;
-using Robust.Client.UserInterface;
-
-namespace Content.Client.Gravity.UI
-{
- [UsedImplicitly]
- public sealed class GravityGeneratorBoundUserInterface : BoundUserInterface
- {
- [ViewVariables]
- private GravityGeneratorWindow? _window;
-
- public GravityGeneratorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
- {
- }
-
- protected override void Open()
- {
- base.Open();
-
- _window = this.CreateWindow();
- _window.SetEntity(Owner);
- }
-
- protected override void UpdateState(BoundUserInterfaceState state)
- {
- base.UpdateState(state);
-
- var castState = (SharedGravityGeneratorComponent.GeneratorState) state;
- _window?.UpdateState(castState);
- }
-
- public void SetPowerSwitch(bool on)
- {
- SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on));
- }
- }
-}
diff --git a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs b/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs
deleted file mode 100644
index 6f04133b59..0000000000
--- a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using Content.Shared.Gravity;
-using Robust.Client.AutoGenerated;
-using Robust.Client.GameObjects;
-using Robust.Client.UserInterface.Controls;
-using Robust.Client.UserInterface.XAML;
-using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
-
-namespace Content.Client.Gravity.UI
-{
- [GenerateTypedNameReferences]
- public sealed partial class GravityGeneratorWindow : FancyWindow
- {
- private readonly ButtonGroup _buttonGroup = new();
-
- public event Action? OnPowerSwitch;
-
- public GravityGeneratorWindow()
- {
- RobustXamlLoader.Load(this);
- IoCManager.InjectDependencies(this);
-
- OnButton.Group = _buttonGroup;
- OffButton.Group = _buttonGroup;
-
- OnButton.OnPressed += _ => OnPowerSwitch?.Invoke(true);
- OffButton.OnPressed += _ => OnPowerSwitch?.Invoke(false);
- }
-
- public void SetEntity(EntityUid uid)
- {
- EntityView.SetEntity(uid);
- }
-
- public void UpdateState(SharedGravityGeneratorComponent.GeneratorState state)
- {
- if (state.On)
- OnButton.Pressed = true;
- else
- OffButton.Pressed = true;
-
- PowerLabel.Text = Loc.GetString(
- "gravity-generator-window-power-label",
- ("draw", state.PowerDraw),
- ("max", state.PowerDrawMax));
-
- PowerLabel.SetOnlyStyleClass(MathHelper.CloseTo(state.PowerDraw, state.PowerDrawMax) ? "Good" : "Caution");
-
- ChargeBar.Value = state.Charge;
- ChargeText.Text = (state.Charge / 255f).ToString("P0");
- StatusLabel.Text = Loc.GetString(state.PowerStatus switch
- {
- GravityGeneratorPowerStatus.Off => "gravity-generator-window-status-off",
- GravityGeneratorPowerStatus.Discharging => "gravity-generator-window-status-discharging",
- GravityGeneratorPowerStatus.Charging => "gravity-generator-window-status-charging",
- GravityGeneratorPowerStatus.FullyCharged => "gravity-generator-window-status-fully-charged",
- _ => throw new ArgumentOutOfRangeException()
- });
-
- StatusLabel.SetOnlyStyleClass(state.PowerStatus switch
- {
- GravityGeneratorPowerStatus.Off => "Danger",
- GravityGeneratorPowerStatus.Discharging => "Caution",
- GravityGeneratorPowerStatus.Charging => "Caution",
- GravityGeneratorPowerStatus.FullyCharged => "Good",
- _ => throw new ArgumentOutOfRangeException()
- });
-
- EtaLabel.Text = state.EtaSeconds >= 0
- ? Loc.GetString("gravity-generator-window-eta-value", ("left", TimeSpan.FromSeconds(state.EtaSeconds)))
- : Loc.GetString("gravity-generator-window-eta-none");
-
- EtaLabel.SetOnlyStyleClass(state.EtaSeconds >= 0 ? "Caution" : "Disabled");
- }
- }
-}
diff --git a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs
index 87931bf845..f8d1c7e972 100644
--- a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs
+++ b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs
@@ -140,7 +140,7 @@ private void GenerateControl(ReagentPrototype reagent)
var i = 0;
foreach (var effectString in effect.EffectDescriptions)
{
- descMsg.AddMarkup(effectString);
+ descMsg.AddMarkupOrThrow(effectString);
i++;
if (i < descriptionsCount)
descMsg.PushNewline();
@@ -174,7 +174,7 @@ private void GenerateControl(ReagentPrototype reagent)
var i = 0;
foreach (var effectString in guideEntryRegistryPlant.PlantMetabolisms)
{
- descMsg.AddMarkup(effectString);
+ descMsg.AddMarkupOrThrow(effectString);
i++;
if (i < descriptionsCount)
descMsg.PushNewline();
@@ -195,7 +195,7 @@ private void GenerateControl(ReagentPrototype reagent)
FormattedMessage description = new();
description.AddText(reagent.LocalizedDescription);
description.PushNewline();
- description.AddMarkup(Loc.GetString("guidebook-reagent-physical-description",
+ description.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-physical-description",
("description", reagent.LocalizedPhysicalDescription)));
ReagentDescription.SetMessage(description);
}
diff --git a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs
index 168f352d1a..135dc5522a 100644
--- a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs
+++ b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs
@@ -155,7 +155,7 @@ private void SetReagents(Dictionary reagents, ref RichTextL
var i = 0;
foreach (var (product, amount) in reagents.OrderByDescending(p => p.Value))
{
- msg.AddMarkup(Loc.GetString("guidebook-reagent-recipes-reagent-display",
+ msg.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-recipes-reagent-display",
("reagent", protoMan.Index(product).LocalizedName), ("ratio", amount)));
i++;
if (i < reagentCount)
diff --git a/Content.Client/Info/InfoSection.xaml.cs b/Content.Client/Info/InfoSection.xaml.cs
index ab9d352d32..9e10a4d7b4 100644
--- a/Content.Client/Info/InfoSection.xaml.cs
+++ b/Content.Client/Info/InfoSection.xaml.cs
@@ -1,4 +1,4 @@
-using Robust.Client.AutoGenerated;
+using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
@@ -18,7 +18,7 @@ public void SetText(string title, string text, bool markup = false)
{
TitleLabel.Text = title;
if (markup)
- Content.SetMessage(FormattedMessage.FromMarkup(text.Trim()));
+ Content.SetMessage(FormattedMessage.FromMarkupOrThrow(text.Trim()));
else
Content.SetMessage(text);
}
diff --git a/Content.Client/Info/ServerInfo.cs b/Content.Client/Info/ServerInfo.cs
index 23be750626..901fc91337 100644
--- a/Content.Client/Info/ServerInfo.cs
+++ b/Content.Client/Info/ServerInfo.cs
@@ -24,7 +24,7 @@ public ServerInfo()
}
public void SetInfoBlob(string markup)
{
- _richTextLabel.SetMessage(FormattedMessage.FromMarkup(markup));
+ _richTextLabel.SetMessage(FormattedMessage.FromMarkupOrThrow(markup));
}
}
}
diff --git a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs
index 6b65612341..b9b58f2322 100644
--- a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs
+++ b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs
@@ -26,6 +26,11 @@ protected override void Open()
_window = this.CreateWindow();
+ if (_entManager.TryGetComponent(Owner, out HandLabelerComponent? labeler))
+ {
+ _window.SetMaxLabelLength(labeler!.MaxLabelChars);
+ }
+
_window.OnLabelChanged += OnLabelChanged;
Reload();
}
diff --git a/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs b/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs
index 6482cdc1cc..7a0627b3e2 100644
--- a/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs
+++ b/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs
@@ -21,7 +21,7 @@ public HandLabelerWindow()
{
RobustXamlLoader.Load(this);
- LabelLineEdit.OnTextEntered += e =>
+ LabelLineEdit.OnTextChanged += e =>
{
_label = e.Text;
OnLabelChanged?.Invoke(_label);
@@ -33,6 +33,10 @@ public HandLabelerWindow()
_focused = false;
LabelLineEdit.Text = _label;
};
+
+ // Give the editor keybard focus, since that's the only
+ // thing the user will want to be doing with this UI
+ LabelLineEdit.GrabKeyboardFocus();
}
public void SetCurrentLabel(string label)
@@ -44,5 +48,10 @@ public void SetCurrentLabel(string label)
if (!_focused)
LabelLineEdit.Text = label;
}
+
+ public void SetMaxLabelLength(int maxLength)
+ {
+ LabelLineEdit.IsValid = s => s.Length <= maxLength;
+ }
}
}
diff --git a/Content.Client/Light/Components/LightBehaviourComponent.cs b/Content.Client/Light/Components/LightBehaviourComponent.cs
index 9df793ee93..246863ba60 100644
--- a/Content.Client/Light/Components/LightBehaviourComponent.cs
+++ b/Content.Client/Light/Components/LightBehaviourComponent.cs
@@ -359,9 +359,6 @@ void ISerializationHooks.AfterDeserialization()
[RegisterComponent]
public sealed partial class LightBehaviourComponent : SharedLightBehaviourComponent, ISerializationHooks
{
- [Dependency] private readonly IEntityManager _entMan = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
-
public const string KeyPrefix = nameof(LightBehaviourComponent);
public sealed class AnimationContainer
diff --git a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs
index 11abe8c245..0607c76831 100644
--- a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs
+++ b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs
@@ -7,8 +7,6 @@ namespace Content.Client.MachineLinking.UI;
public sealed class SignalTimerBoundUserInterface : BoundUserInterface
{
- [Dependency] private readonly IGameTiming _gameTiming = default!;
-
[ViewVariables]
private SignalTimerWindow? _window;
diff --git a/Content.Client/Message/RichTextLabelExt.cs b/Content.Client/Message/RichTextLabelExt.cs
index 7ff6390764..ee3c00fa1b 100644
--- a/Content.Client/Message/RichTextLabelExt.cs
+++ b/Content.Client/Message/RichTextLabelExt.cs
@@ -15,7 +15,7 @@ public static class RichTextLabelExt
///
public static RichTextLabel SetMarkup(this RichTextLabel label, string markup)
{
- label.SetMessage(FormattedMessage.FromMarkup(markup));
+ label.SetMessage(FormattedMessage.FromMarkupOrThrow(markup));
return label;
}
diff --git a/Content.Client/Physics/JointVisualsOverlay.cs b/Content.Client/Physics/JointVisualsOverlay.cs
index e0b3499a97..9cc2831d21 100644
--- a/Content.Client/Physics/JointVisualsOverlay.cs
+++ b/Content.Client/Physics/JointVisualsOverlay.cs
@@ -1,9 +1,8 @@
+using System.Numerics;
using Content.Shared.Physics;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
-using Robust.Shared.Physics;
-using Robust.Shared.Physics.Dynamics.Joints;
namespace Content.Client.Physics;
@@ -16,8 +15,6 @@ public sealed class JointVisualsOverlay : Overlay
private IEntityManager _entManager;
- private HashSet _drawn = new();
-
public JointVisualsOverlay(IEntityManager entManager)
{
_entManager = entManager;
@@ -25,7 +22,6 @@ public JointVisualsOverlay(IEntityManager entManager)
protected override void Draw(in OverlayDrawArgs args)
{
- _drawn.Clear();
var worldHandle = args.WorldHandle;
var spriteSystem = _entManager.System();
@@ -33,12 +29,14 @@ protected override void Draw(in OverlayDrawArgs args)
var joints = _entManager.EntityQueryEnumerator();
var xformQuery = _entManager.GetEntityQuery();
+ args.DrawingHandle.SetTransform(Matrix3x2.Identity);
+
while (joints.MoveNext(out var visuals, out var xform))
{
if (xform.MapID != args.MapId)
continue;
- var other = visuals.Target;
+ var other = _entManager.GetEntity(visuals.Target);
if (!xformQuery.TryGetComponent(other, out var otherXform))
continue;
diff --git a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs
index 736c80e17c..42a79aec95 100644
--- a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs
+++ b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs
@@ -1,4 +1,4 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
using Content.Client.Lobby;
using Content.Shared.CCVar;
using Content.Shared.Players;
@@ -143,7 +143,7 @@ public bool CheckRoleRequirements(HashSet? requirements, Humanoi
reasons.Add(jobReason.ToMarkup());
}
- reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkup(string.Join('\n', reasons));
+ reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkupOrThrow(string.Join('\n', reasons));
return reason == null;
}
diff --git a/Content.Client/Power/PowerCharge/PowerChargeBoundUserInterface.cs b/Content.Client/Power/PowerCharge/PowerChargeBoundUserInterface.cs
new file mode 100644
index 0000000000..7a36b8ddf5
--- /dev/null
+++ b/Content.Client/Power/PowerCharge/PowerChargeBoundUserInterface.cs
@@ -0,0 +1,38 @@
+using Content.Shared.Power;
+using Robust.Client.UserInterface;
+
+namespace Content.Client.Power.PowerCharge;
+
+public sealed class PowerChargeBoundUserInterface : BoundUserInterface
+{
+ [ViewVariables]
+ private PowerChargeWindow? _window;
+
+ public PowerChargeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ }
+
+ public void SetPowerSwitch(bool on)
+ {
+ SendMessage(new SwitchChargingMachineMessage(on));
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+ if (!EntMan.TryGetComponent(Owner, out PowerChargeComponent? component))
+ return;
+
+ _window = this.CreateWindow();
+ _window.UpdateWindow(this, Loc.GetString(component.WindowTitle));
+ }
+
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+ if (state is not PowerChargeState chargeState)
+ return;
+
+ _window?.UpdateState(chargeState);
+ }
+}
diff --git a/Content.Client/Power/PowerCharge/PowerChargeComponent.cs b/Content.Client/Power/PowerCharge/PowerChargeComponent.cs
new file mode 100644
index 0000000000..ab5baa4e2f
--- /dev/null
+++ b/Content.Client/Power/PowerCharge/PowerChargeComponent.cs
@@ -0,0 +1,10 @@
+using Content.Shared.Power;
+
+namespace Content.Client.Power.PowerCharge;
+
+///
+[RegisterComponent]
+public sealed partial class PowerChargeComponent : SharedPowerChargeComponent
+{
+
+}
diff --git a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml b/Content.Client/Power/PowerCharge/PowerChargeWindow.xaml
similarity index 60%
rename from Content.Client/Gravity/UI/GravityGeneratorWindow.xaml
rename to Content.Client/Power/PowerCharge/PowerChargeWindow.xaml
index 853f437a2b..4e61255326 100644
--- a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml
+++ b/Content.Client/Power/PowerCharge/PowerChargeWindow.xaml
@@ -1,27 +1,26 @@
-
+
-
-
+
+
-
-
+
+
-
+
-
+
@@ -31,5 +30,4 @@
-
diff --git a/Content.Client/Power/PowerCharge/PowerChargeWindow.xaml.cs b/Content.Client/Power/PowerCharge/PowerChargeWindow.xaml.cs
new file mode 100644
index 0000000000..6739e24c20
--- /dev/null
+++ b/Content.Client/Power/PowerCharge/PowerChargeWindow.xaml.cs
@@ -0,0 +1,72 @@
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Power;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Power.PowerCharge;
+
+[GenerateTypedNameReferences]
+public sealed partial class PowerChargeWindow : FancyWindow
+{
+ private readonly ButtonGroup _buttonGroup = new();
+
+ public PowerChargeWindow()
+ {
+ RobustXamlLoader.Load(this);
+
+ OnButton.Group = _buttonGroup;
+ OffButton.Group = _buttonGroup;
+ }
+
+ public void UpdateWindow(PowerChargeBoundUserInterface bui, string title)
+ {
+ Title = title;
+
+ OnButton.OnPressed += _ => bui.SetPowerSwitch(true);
+ OffButton.OnPressed += _ => bui.SetPowerSwitch(false);
+
+ EntityView.SetEntity(bui.Owner);
+ }
+
+ public void UpdateState(PowerChargeState state)
+ {
+ if (state.On)
+ OnButton.Pressed = true;
+ else
+ OffButton.Pressed = true;
+
+ PowerLabel.Text = Loc.GetString(
+ "power-charge-window-power-label",
+ ("draw", state.PowerDraw),
+ ("max", state.PowerDrawMax));
+
+ PowerLabel.SetOnlyStyleClass(MathHelper.CloseTo(state.PowerDraw, state.PowerDrawMax) ? "Good" : "Caution");
+
+ ChargeBar.Value = state.Charge;
+ ChargeText.Text = (state.Charge / 255f).ToString("P0");
+ StatusLabel.Text = Loc.GetString(state.PowerStatus switch
+ {
+ PowerChargePowerStatus.Off => "power-charge-window-status-off",
+ PowerChargePowerStatus.Discharging => "power-charge-window-status-discharging",
+ PowerChargePowerStatus.Charging => "power-charge-window-status-charging",
+ PowerChargePowerStatus.FullyCharged => "power-charge-window-status-fully-charged",
+ _ => throw new ArgumentOutOfRangeException()
+ });
+
+ StatusLabel.SetOnlyStyleClass(state.PowerStatus switch
+ {
+ PowerChargePowerStatus.Off => "Danger",
+ PowerChargePowerStatus.Discharging => "Caution",
+ PowerChargePowerStatus.Charging => "Caution",
+ PowerChargePowerStatus.FullyCharged => "Good",
+ _ => throw new ArgumentOutOfRangeException()
+ });
+
+ EtaLabel.Text = state.EtaSeconds >= 0
+ ? Loc.GetString("power-charge-window-eta-value", ("left", TimeSpan.FromSeconds(state.EtaSeconds)))
+ : Loc.GetString("power-charge-window-eta-none");
+
+ EtaLabel.SetOnlyStyleClass(state.EtaSeconds >= 0 ? "Caution" : "Disabled");
+ }
+}
diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs
index d995299207..3f7ccfb903 100644
--- a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs
+++ b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs
@@ -309,7 +309,7 @@ private void UpdateWarningLabel(PowerMonitoringFlags flags)
BorderThickness = new Thickness(2),
};
- msg.AddMarkup(Loc.GetString("power-monitoring-window-rogue-power-consumer"));
+ msg.AddMarkupOrThrow(Loc.GetString("power-monitoring-window-rogue-power-consumer"));
SystemWarningPanel.Visible = true;
}
@@ -322,7 +322,7 @@ private void UpdateWarningLabel(PowerMonitoringFlags flags)
BorderThickness = new Thickness(2),
};
- msg.AddMarkup(Loc.GetString("power-monitoring-window-power-net-abnormalities"));
+ msg.AddMarkupOrThrow(Loc.GetString("power-monitoring-window-power-net-abnormalities"));
SystemWarningPanel.Visible = true;
}
diff --git a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs
index 87d7e62c39..06e5674d9c 100644
--- a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs
+++ b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs
@@ -128,12 +128,12 @@ private void PopulateData()
};
var text = new FormattedMessage();
- text.PushMarkup(Loc.GetString("robotics-console-model", ("name", model)));
- text.AddMarkup(Loc.GetString("robotics-console-designation"));
+ text.AddMarkupOrThrow($"{Loc.GetString("robotics-console-model", ("name", model))}\n");
+ text.AddMarkupOrThrow(Loc.GetString("robotics-console-designation"));
text.AddText($" {data.Name}\n"); // prevent players trolling by naming borg [color=red]satan[/color]
- text.PushMarkup(Loc.GetString("robotics-console-battery", ("charge", (int) (data.Charge * 100f)), ("color", batteryColor)));
- text.PushMarkup(Loc.GetString("robotics-console-brain", ("brain", data.HasBrain)));
- text.AddMarkup(Loc.GetString("robotics-console-modules", ("count", data.ModuleCount)));
+ text.AddMarkupOrThrow($"{Loc.GetString("robotics-console-battery", ("charge", (int)(data.Charge * 100f)), ("color", batteryColor))}\n");
+ text.AddMarkupOrThrow($"{Loc.GetString("robotics-console-brain", ("brain", data.HasBrain))}\n");
+ text.AddMarkupOrThrow(Loc.GetString("robotics-console-modules", ("count", data.ModuleCount)));
BorgInfo.SetMessage(text);
// how the turntables
diff --git a/Content.Client/RoundEnd/RoundEndSummaryWindow.cs b/Content.Client/RoundEnd/RoundEndSummaryWindow.cs
index 9c9f83a427..7108e4cca8 100644
--- a/Content.Client/RoundEnd/RoundEndSummaryWindow.cs
+++ b/Content.Client/RoundEnd/RoundEndSummaryWindow.cs
@@ -61,9 +61,9 @@ private BoxContainer MakeRoundEndSummaryTab(string gamemode, string roundEnd, Ti
//Gamemode Name
var gamemodeLabel = new RichTextLabel();
var gamemodeMessage = new FormattedMessage();
- gamemodeMessage.AddMarkup(Loc.GetString("round-end-summary-window-round-id-label", ("roundId", roundId)));
+ gamemodeMessage.AddMarkupOrThrow(Loc.GetString("round-end-summary-window-round-id-label", ("roundId", roundId)));
gamemodeMessage.AddText(" ");
- gamemodeMessage.AddMarkup(Loc.GetString("round-end-summary-window-gamemode-name-label", ("gamemode", gamemode)));
+ gamemodeMessage.AddMarkupOrThrow(Loc.GetString("round-end-summary-window-gamemode-name-label", ("gamemode", gamemode)));
gamemodeLabel.SetMessage(gamemodeMessage);
roundEndSummaryContainer.AddChild(gamemodeLabel);
diff --git a/Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs b/Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs
index 24a802a60f..b152f5ead8 100644
--- a/Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs
+++ b/Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs
@@ -15,7 +15,6 @@ public sealed partial class StationAiMenu : RadialMenu
{
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
- [Dependency] private readonly IEyeManager _eyeManager = default!;
public event Action? OnAiRadial;
diff --git a/Content.Client/Store/Ui/StoreBoundUserInterface.cs b/Content.Client/Store/Ui/StoreBoundUserInterface.cs
index 7ed67f7b5d..8c48258de0 100644
--- a/Content.Client/Store/Ui/StoreBoundUserInterface.cs
+++ b/Content.Client/Store/Ui/StoreBoundUserInterface.cs
@@ -19,7 +19,7 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
private string _search = string.Empty;
[ViewVariables]
- private HashSet _listings = new();
+ private HashSet _listings = new();
public StoreBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
@@ -33,7 +33,7 @@ protected override void Open()
_menu.OnListingButtonPressed += (_, listing) =>
{
- SendMessage(new StoreBuyListingMessage(listing));
+ SendMessage(new StoreBuyListingMessage(listing.ID));
};
_menu.OnCategoryButtonPressed += (_, category) =>
@@ -68,6 +68,7 @@ protected override void UpdateState(BoundUserInterfaceState state)
_listings = msg.Listings;
_menu?.UpdateBalance(msg.Balance);
+
UpdateListingsWithSearchFilter();
_menu?.SetFooterVisibility(msg.ShowFooter);
_menu?.UpdateRefund(msg.AllowRefund);
@@ -80,7 +81,7 @@ private void UpdateListingsWithSearchFilter()
if (_menu == null)
return;
- var filteredListings = new HashSet(_listings);
+ var filteredListings = new HashSet(_listings);
if (!string.IsNullOrEmpty(_search))
{
filteredListings.RemoveWhere(listingData => !ListingLocalisationHelpers.GetLocalisedNameOrEntityName(listingData, _prototypeManager).Trim().ToLowerInvariant().Contains(_search) &&
diff --git a/Content.Client/Store/Ui/StoreListingControl.xaml b/Content.Client/Store/Ui/StoreListingControl.xaml
index 12b4d7b5b3..3142f1cb06 100644
--- a/Content.Client/Store/Ui/StoreListingControl.xaml
+++ b/Content.Client/Store/Ui/StoreListingControl.xaml
@@ -2,6 +2,8 @@
+