diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleBoundUserInterface.cs b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleBoundUserInterface.cs
new file mode 100644
index 0000000000..80c0fc0276
--- /dev/null
+++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleBoundUserInterface.cs
@@ -0,0 +1,40 @@
+using Content.Shared._EE.Supermatter.Components;
+
+namespace Content.Client._EE.Supermatter.Consoles;
+
+public sealed class SupermatterConsoleBoundUserInterface : BoundUserInterface
+{
+ [ViewVariables]
+ private SupermatterConsoleWindow? _menu;
+
+ public SupermatterConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }
+
+ protected override void Open()
+ {
+ _menu = new SupermatterConsoleWindow(this, Owner);
+ _menu.OpenCentered();
+ _menu.OnClose += Close;
+ }
+
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+
+ var castState = (SupermatterConsoleBoundInterfaceState)state;
+ _menu?.UpdateUI(castState.Supermatters, castState.FocusData);
+ }
+
+ public void SendFocusChangeMessage(NetEntity? netEntity)
+ {
+ SendMessage(new SupermatterConsoleFocusChangeMessage(netEntity));
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing)
+ return;
+
+ _menu?.Dispose();
+ }
+}
diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleWindow.xaml b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleWindow.xaml
new file mode 100644
index 0000000000..3d2c638c16
--- /dev/null
+++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleWindow.xaml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleWindow.xaml.cs b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleWindow.xaml.cs
new file mode 100644
index 0000000000..1d68dbb53c
--- /dev/null
+++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleWindow.xaml.cs
@@ -0,0 +1,258 @@
+using Content.Client.Message;
+using Content.Client.Stylesheets;
+using Content.Client.UserInterface.Controls;
+using Content.Shared._EE.Supermatter.Components;
+using Content.Shared._EE.Supermatter.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.Timing;
+using Robust.Shared.Utility;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+namespace Content.Client._EE.Supermatter.Consoles;
+
+[GenerateTypedNameReferences]
+public sealed partial class SupermatterConsoleWindow : FancyWindow
+{
+ private readonly IEntityManager _entManager;
+ private readonly SpriteSystem _spriteSystem;
+ private readonly SharedNavMapSystem _navMapSystem;
+
+ private EntityUid? _owner;
+ private NetEntity? _trackedEntity;
+
+ private SupermatterConsoleEntry[]? _supermatters = null;
+ private IEnumerable? _activeAlerts = null;
+
+ public event Action? SendFocusChangeMessageAction;
+
+ private bool _autoScrollActive = false;
+ private bool _autoScrollAwaitsUpdate = false;
+
+ // Colors
+ private Color _wallColor = new Color(64, 64, 64);
+ private Color _tileColor = new Color(28, 28, 28);
+ private Color _monitorBlipColor = Color.Cyan;
+ private Color _untrackedEntColor = Color.DimGray;
+ private Color _regionBaseColor = new Color(154, 154, 154);
+ private Color _inactiveColor = StyleNano.DisabledFore;
+ private Color _statusTextColor = StyleNano.GoodGreenFore;
+ private Color _goodColor = Color.LimeGreen;
+ private Color _warningColor = new Color(255, 182, 72);
+ private Color _dangerColor = new Color(255, 67, 67);
+
+ public SupermatterConsoleWindow(SupermatterConsoleBoundUserInterface userInterface, EntityUid? owner)
+ {
+ RobustXamlLoader.Load(this);
+ _entManager = IoCManager.Resolve();
+ _spriteSystem = _entManager.System();
+ _navMapSystem = _entManager.System();
+
+ // Pass the owner to nav map
+ _owner = owner;
+
+ // Set supermatter monitoring message action
+ SendFocusChangeMessageAction += userInterface.SendFocusChangeMessage;
+ }
+
+ public void UpdateUI(SupermatterConsoleEntry[] supermatters, SupermatterFocusData? focusData)
+ {
+ if (_owner == null)
+ return;
+
+ if (!_entManager.TryGetComponent(_owner.Value, out var console))
+ return;
+
+ if (_trackedEntity != focusData?.NetEntity)
+ {
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+ focusData = null;
+ }
+
+ // Retain supermatter data for use inbetween updates
+ _supermatters = supermatters;
+
+ // Clear excess children from the tables
+ var supermattersCount = _supermatters.Count();
+
+ while (SupermattersTable.ChildCount > supermattersCount)
+ SupermattersTable.RemoveChild(SupermattersTable.GetChild(SupermattersTable.ChildCount - 1));
+
+ // Update all entries in each table
+ for (int index = 0; index < _supermatters.Count(); index++)
+ {
+ var entry = _supermatters.ElementAt(index);
+ UpdateUIEntry(entry, index, SupermattersTable, console, focusData);
+ }
+
+ // If no alerts are active, display a message
+ if (supermattersCount == 0)
+ {
+ var label = new RichTextLabel()
+ {
+ HorizontalExpand = true,
+ VerticalExpand = true,
+ HorizontalAlignment = HAlignment.Center,
+ VerticalAlignment = VAlignment.Center,
+ };
+
+ label.SetMarkup(Loc.GetString("supermatter-console-window-no-supermatters"));
+
+ SupermattersTable.AddChild(label);
+ }
+
+ // Auto-scroll re-enable
+ if (_autoScrollAwaitsUpdate)
+ {
+ _autoScrollActive = true;
+ _autoScrollAwaitsUpdate = false;
+ }
+ }
+
+ private void UpdateUIEntry(SupermatterConsoleEntry entry, int index, Control table, SupermatterConsoleComponent console, SupermatterFocusData? focusData = null)
+ {
+ // Make new UI entry if required
+ if (index >= table.ChildCount)
+ {
+ var newEntryContainer = new SupermatterEntryContainer(entry.NetEntity);
+
+ // On click
+ newEntryContainer.FocusButton.OnButtonUp += args =>
+ {
+ if (_trackedEntity == newEntryContainer.NetEntity)
+ {
+ _trackedEntity = null;
+ }
+
+ else
+ {
+ _trackedEntity = newEntryContainer.NetEntity;
+ }
+
+ // Send message to console that the focus has changed
+ SendFocusChangeMessageAction?.Invoke(_trackedEntity);
+ };
+
+ // Add the entry to the current table
+ table.AddChild(newEntryContainer);
+ }
+
+ // Update values and UI elements
+ var tableChild = table.GetChild(index);
+
+ if (tableChild is not SupermatterEntryContainer)
+ {
+ table.RemoveChild(tableChild);
+ UpdateUIEntry(entry, index, table, console, focusData);
+
+ return;
+ }
+
+ var entryContainer = (SupermatterEntryContainer)tableChild;
+
+ entryContainer.UpdateEntry(entry, entry.NetEntity == _trackedEntity, focusData);
+ }
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ AutoScrollToFocus();
+ }
+
+ private void ActivateAutoScrollToFocus()
+ {
+ _autoScrollActive = false;
+ _autoScrollAwaitsUpdate = true;
+ }
+
+ private void AutoScrollToFocus()
+ {
+ if (!_autoScrollActive)
+ return;
+
+ var scroll = SupermattersTable.Parent 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 = SupermattersTable.Parent 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 SupermatterEntryContainer)
+ continue;
+
+ if (((SupermatterEntryContainer)control).NetEntity == _trackedEntity)
+ return true;
+
+ nextScrollPosition += control.Height;
+ }
+
+ // Failed to find control
+ nextScrollPosition = null;
+
+ return false;
+ }
+
+ private SupermatterStatusType GetStatus(NetEntity netEntity)
+ {
+ var status = _supermatters?.FirstOrNull(x => x.NetEntity == netEntity)?.EntityStatus;
+
+ if (status == null)
+ return SupermatterStatusType.Error;
+
+ return status.Value;
+ }
+}
diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterEntryContainer.xaml b/Content.Client/_EE/Supermatter/Consoles/SupermatterEntryContainer.xaml
new file mode 100644
index 0000000000..6cabb4ab33
--- /dev/null
+++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterEntryContainer.xaml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterEntryContainer.xaml.cs b/Content.Client/_EE/Supermatter/Consoles/SupermatterEntryContainer.xaml.cs
new file mode 100644
index 0000000000..68f8ddf7b7
--- /dev/null
+++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterEntryContainer.xaml.cs
@@ -0,0 +1,285 @@
+using Content.Client.Atmos.EntitySystems;
+using Content.Client.Stylesheets;
+using Content.Shared._EE.Supermatter.Components;
+using Content.Shared._EE.Supermatter.Monitor;
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.Prototypes;
+using Robust.Client.AutoGenerated;
+using Robust.Client.Graphics;
+using Robust.Client.ResourceManagement;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using System.Linq;
+
+namespace Content.Client._EE.Supermatter.Consoles;
+
+[GenerateTypedNameReferences]
+public sealed partial class SupermatterEntryContainer : BoxContainer
+{
+ public NetEntity NetEntity;
+
+ private readonly IEntityManager _entManager;
+ private readonly IResourceCache _cache;
+
+ private Dictionary _statusStrings = new()
+ {
+ [SupermatterStatusType.Inactive] = "supermatter-console-window-inactive-status",
+ [SupermatterStatusType.Normal] = "supermatter-console-window-normal-status",
+ [SupermatterStatusType.Caution] = "supermatter-console-window-caution-status",
+ [SupermatterStatusType.Warning] = "supermatter-console-window-warning-status",
+ [SupermatterStatusType.Danger] = "supermatter-console-window-danger-status",
+ [SupermatterStatusType.Emergency] = "supermatter-console-window-emergency-status",
+ [SupermatterStatusType.Delaminating] = "supermatter-console-window-delaminating-status"
+ };
+
+ public SupermatterEntryContainer(NetEntity uid)
+ {
+ RobustXamlLoader.Load(this);
+
+ _entManager = IoCManager.Resolve();
+ _cache = IoCManager.Resolve();
+
+ NetEntity = uid;
+
+ // 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 monoFont = new VectorFont(_cache.GetResource("/EngineFonts/NotoSans/NotoSansMono-Regular.ttf"), 10);
+
+ // Set fonts
+ SupermatterNameLabel.FontOverride = headerFont;
+
+ SupermatterStatusLabel.FontOverride = normalFont;
+
+ IntegrityLabel.FontOverride = normalFont;
+ PowerLabel.FontOverride = normalFont;
+ RadiationLabel.FontOverride = normalFont;
+ MolesLabel.FontOverride = normalFont;
+ TemperatureLabel.FontOverride = normalFont;
+ TemperatureLimitLabel.FontOverride = normalFont;
+ WasteLabel.FontOverride = normalFont;
+ AbsorptionLabel.FontOverride = normalFont;
+
+ IntegrityBarLabel.FontOverride = monoFont;
+ PowerBarLabel.FontOverride = monoFont;
+ RadiationBarLabel.FontOverride = monoFont;
+ MolesBarLabel.FontOverride = monoFont;
+ TemperatureBarLabel.FontOverride = monoFont;
+ TemperatureLimitBarLabel.FontOverride = monoFont;
+ WasteBarLabel.FontOverride = monoFont;
+ AbsorptionBarLabel.FontOverride = monoFont;
+ }
+
+ public void UpdateEntry(SupermatterConsoleEntry entry, bool isFocus, SupermatterFocusData? focusData = null)
+ {
+ NetEntity = entry.NetEntity;
+
+ // Load fonts
+ var normalFont = new VectorFont(_cache.GetResource("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
+
+ // Update supermatter name
+ SupermatterNameLabel.Text = Loc.GetString("supermatter-console-window-label-sm", ("name", entry.EntityName));
+
+ // Update supermatter status
+ SupermatterStatusLabel.Text = Loc.GetString(GetStatusLabel(entry.EntityStatus));
+ SupermatterStatusLabel.FontColorOverride = GetStatusColor(entry.EntityStatus);
+
+ // Focus updates
+ FocusContainer.Visible = isFocus;
+
+ if (isFocus)
+ {
+ if (focusData != null)
+ {
+ var red = StyleNano.DangerousRedFore;
+ var orange = StyleNano.ConcerningOrangeFore;
+ var green = StyleNano.GoodGreenFore;
+ var turqoise = Color.FromHex("#009893");
+
+ // TODO: please don't define this dictionary every update you animal
+ var engineDictionary = new Dictionary()
+ {
+ { "integrity", (IntegrityBarLabel, IntegrityBar, IntegrityBarBorder, focusData.Value.Integrity, 0.9f, 0.1f, red, orange, green) },
+ { "power", (PowerBarLabel, PowerBar, PowerBarBorder, focusData.Value.Power, 0.9f, 0.1f, green, orange, red ) },
+ { "radiation", (RadiationBarLabel, RadiationBar, RadiationBarBorder, focusData.Value.Radiation, 0.1f, 0.9f, green, orange, red ) },
+ { "moles", (MolesBarLabel, MolesBar, MolesBarBorder, focusData.Value.AbsorbedMoles, 0.5f, 0.5f, green, orange, red ) },
+ { "temperature", (TemperatureBarLabel, TemperatureBar, TemperatureBarBorder, focusData.Value.Temperature, 0.5f, 0.5f, turqoise, green, red ) },
+ { "waste", (WasteBarLabel, WasteBar, WasteBarBorder, focusData.Value.WasteMultiplier, 0.5f, 0.5f, green, orange, red ) }
+ };
+
+ // Special cases
+ var powerBar = engineDictionary["power"];
+ var powerPrefix = powerBar.value switch { >= 1000 => "G", >= 1 => "M", _ => "" };
+ var powerMultiplier = powerBar.value switch { >= 1000 => 0.001, >= 1 => 1, _ => 1000 };
+ powerBar.label.Text = Loc.GetString("supermatter-console-window-label-power-bar", ("power", (powerBar.value * powerMultiplier).ToString("0.000")), ("prefix", powerPrefix));
+
+ var temperatureLimit = focusData.Value.TemperatureLimit;
+ TemperatureBar.MaxValue = temperatureLimit;
+ TemperatureLimitBarLabel.Text = Loc.GetString("supermatter-console-window-label-temperature-bar", ("temperature", temperatureLimit.ToString("0.00")));
+
+ var absorptionRatio = focusData.Value.AbsorptionRatio;
+ AbsorptionBarLabel.Text = Loc.GetString("supermatter-console-window-label-absorption-bar", ("absorption", absorptionRatio.ToString("0")));
+
+ // Update engine bars
+ foreach (var bar in engineDictionary)
+ {
+ var current = bar.Value;
+ UpdateEngineBar(current.bar, current.border, current.value, current.leftSize, current.rightSize, current.leftColor, current.middleColor, current.rightColor);
+
+ if (bar.Key == "power")
+ continue;
+
+ current.label.Text = Loc.GetString("supermatter-console-window-label-" + bar.Key + "-bar", (bar.Key, current.value.ToString("0.00")));
+ }
+
+ // Update gas bars
+ var atmosphereSystem = _entManager.System();
+ var gases = atmosphereSystem.Gases.OrderByDescending(gas => GetStoredGas(gas, focusData));
+ var index = 0;
+
+ foreach (var gas in gases)
+ {
+ var name = gas.Name;
+ var color = Color.FromHex("#" + gas.Color);
+ var value = GetStoredGas(gas, focusData) / focusData.Value.AbsorbedMoles * 100;
+
+ UpdateGasBar(index, GasTable, name, color, value);
+ index++;
+ }
+ }
+ }
+ }
+
+ private string GetStatusLabel(SupermatterStatusType status)
+ {
+ switch (status)
+ {
+ case SupermatterStatusType.Inactive:
+ return "supermatter-console-window-inactive-status";
+
+ case SupermatterStatusType.Normal:
+ return "supermatter-console-window-normal-status";
+
+ case SupermatterStatusType.Caution:
+ return "supermatter-console-window-caution-status";
+
+ case SupermatterStatusType.Warning:
+ return "supermatter-console-window-warning-status";
+
+ case SupermatterStatusType.Danger:
+ return "supermatter-console-window-danger-status";
+
+ case SupermatterStatusType.Emergency:
+ return "supermatter-console-window-emergency-status";
+
+ case SupermatterStatusType.Delaminating:
+ return "supermatter-console-window-delaminating-status";
+ }
+
+ return "supermatter-console-window-error-status";
+ }
+
+ private Color GetStatusColor(SupermatterStatusType status)
+ {
+ switch (status)
+ {
+ case SupermatterStatusType.Inactive:
+ return Color.DarkGray;
+
+ case SupermatterStatusType.Normal:
+ return StyleNano.GoodGreenFore;
+
+ case SupermatterStatusType.Caution:
+ case SupermatterStatusType.Warning:
+ return StyleNano.ConcerningOrangeFore;
+
+ case SupermatterStatusType.Danger:
+ case SupermatterStatusType.Emergency:
+ case SupermatterStatusType.Delaminating:
+ return StyleNano.DangerousRedFore;
+ }
+
+ return StyleNano.DisabledFore;
+ }
+
+ private float GetStoredGas(GasPrototype gas, SupermatterFocusData? focusData)
+ {
+ var id = int.Parse(gas.ID);
+
+ if (focusData == null)
+ return 0;
+
+ return focusData.Value.GasStorage[(Gas)id];
+ }
+
+ private void UpdateEngineBar(ProgressBar bar, PanelContainer border, float value, float leftSize, float rightSize, Color leftColor, Color middleColor, Color rightColor)
+ {
+ var clamped = Math.Clamp(value, bar.MinValue, bar.MaxValue);
+
+ var normalized = clamped / bar.MaxValue;
+ var leftHsv = Color.ToHsv(leftColor);
+ var middleHsv = Color.ToHsv(middleColor);
+ var rightHsv = Color.ToHsv(rightColor);
+
+ // Ensure leftSize and rightSize add up to 1.0 or the transition won't be smooth
+ var minColor = new Vector4(0, 0, 0, 0);
+ var maxColor = new Vector4(1, 1, 1, 1);
+ Color finalColor;
+
+ if (normalized <= leftSize)
+ {
+ normalized /= leftSize; // Adjust range to 0.0 to 1.0
+ var calcColor = Vector4.Lerp(leftHsv, middleHsv, normalized);
+ var clampedColor = Vector4.Clamp(calcColor, minColor, maxColor);
+ finalColor = Color.FromHsv(clampedColor);
+ }
+
+ else
+ {
+ normalized = (normalized - leftSize) / rightSize; // Adjust range to 0.0 to 1.0
+ var calcColor = Vector4.Lerp(middleHsv, rightHsv, normalized);
+ var clampedColor = Vector4.Clamp(calcColor, minColor, maxColor);
+ finalColor = Color.FromHsv(clampedColor);
+ }
+
+ // Check if null first to avoid repeatedly creating this.
+ bar.ForegroundStyleBoxOverride ??= new StyleBoxFlat();
+ border.PanelOverride ??= new StyleBoxFlat();
+
+ var barOverride = (StyleBoxFlat)bar.ForegroundStyleBoxOverride;
+ barOverride.BackgroundColor = finalColor;
+
+ var panelOverride = (StyleBoxFlat)border.PanelOverride;
+ panelOverride.BackgroundColor = finalColor;
+
+ bar.Value = clamped;
+ }
+
+ private void UpdateGasBar(int index, Control table, string name, Color color, float value)
+ {
+ // Make new UI entry if required
+ if (index >= table.ChildCount)
+ {
+ var newEntryContainer = new SupermatterGasBarContainer();
+
+ // Add the entry to the current table
+ table.AddChild(newEntryContainer);
+ }
+
+ // Update values and UI elements
+ var tableChild = table.GetChild(index);
+
+ if (tableChild is not SupermatterGasBarContainer)
+ {
+ table.RemoveChild(tableChild);
+ UpdateGasBar(index, table, name, color, value);
+
+ return;
+ }
+
+ var entryContainer = (SupermatterGasBarContainer)tableChild;
+
+ entryContainer.UpdateEntry(name, color, value);
+ }
+}
diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterGasBarContainer.xaml b/Content.Client/_EE/Supermatter/Consoles/SupermatterGasBarContainer.xaml
new file mode 100644
index 0000000000..6382d38934
--- /dev/null
+++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterGasBarContainer.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterGasBarContainer.xaml.cs b/Content.Client/_EE/Supermatter/Consoles/SupermatterGasBarContainer.xaml.cs
new file mode 100644
index 0000000000..77b83dd652
--- /dev/null
+++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterGasBarContainer.xaml.cs
@@ -0,0 +1,47 @@
+using Robust.Client.AutoGenerated;
+using Robust.Client.Graphics;
+using Robust.Client.ResourceManagement;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client._EE.Supermatter.Consoles;
+
+[GenerateTypedNameReferences]
+public sealed partial class SupermatterGasBarContainer : BoxContainer
+{
+ private readonly IEntityManager _entManager;
+ private readonly IResourceCache _cache;
+
+ public SupermatterGasBarContainer()
+ {
+ RobustXamlLoader.Load(this);
+
+ _entManager = IoCManager.Resolve();
+ _cache = IoCManager.Resolve();
+
+ // Load fonts
+ var normalFont = new VectorFont(_cache.GetResource("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
+ var monoFont = new VectorFont(_cache.GetResource("/EngineFonts/NotoSans/NotoSansMono-Regular.ttf"), 10);
+
+ // Set fonts
+ GasLabel.FontOverride = normalFont;
+ GasBarLabel.FontOverride = monoFont;
+ }
+
+ public void UpdateEntry(string name, Color color, float value)
+ {
+ GasBar.Value = value;
+ GasLabel.Text = Loc.GetString(name) + ":";
+ GasBarLabel.Text = Loc.GetString("supermatter-console-window-label-gas-bar", ("gas", value.ToString("0.00")));
+
+ // Check if null first to avoid repeatedly creating this.
+ GasBar.ForegroundStyleBoxOverride ??= new StyleBoxFlat();
+ GasBarBorder.PanelOverride ??= new StyleBoxFlat();
+
+ var barOverride = (StyleBoxFlat)GasBar.ForegroundStyleBoxOverride;
+ barOverride.BackgroundColor = color;
+
+ var borderOverride = (StyleBoxFlat)GasBarBorder.PanelOverride;
+ borderOverride.BackgroundColor = color;
+ }
+}
diff --git a/Content.Server/Beam/BeamSystem.cs b/Content.Server/Beam/BeamSystem.cs
index ad67f983c2..9c1ebfa213 100644
--- a/Content.Server/Beam/BeamSystem.cs
+++ b/Content.Server/Beam/BeamSystem.cs
@@ -1,10 +1,9 @@
-using System.Numerics;
+using System.Numerics;
using Content.Server.Beam.Components;
using Content.Shared.Beam;
using Content.Shared.Beam.Components;
using Content.Shared.Physics;
using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Physics;
@@ -83,6 +82,11 @@ public sealed class BeamSystem : SharedBeamSystem
if (!TryComp(ent, out var physics) || !TryComp(ent, out var beam))
return;
+ // imp - start non-randomized lightning sprites
+ if (!beam.AllowSpriteOverwrite)
+ bodyState = null;
+ // imp - end non-randomized lightning sprites
+
FixturesComponent? manager = null;
_fixture.TryCreateFixture(
ent,
@@ -146,21 +150,8 @@ public sealed class BeamSystem : SharedBeamSystem
if (Deleted(user) || Deleted(target))
return;
- var userMapPos = _transform.GetMapCoordinates(user);
- var targetMapPos = _transform.GetMapCoordinates(target);
-
- //The distance between the target and the user.
- var calculatedDistance = targetMapPos.Position - userMapPos.Position;
- var userAngle = calculatedDistance.ToWorldAngle();
-
- if (userMapPos.MapId != targetMapPos.MapId)
- return;
-
- //Where the start of the beam will spawn
- var beamStartPos = userMapPos.Offset(calculatedDistance.Normalized());
-
- //Don't divide by zero
- if (calculatedDistance.Length() == 0)
+ // imp - Beam creation was changed to a coordinate-to-coordinate method to allow for more flexibility.
+ if (!TryCreateBeam(_transform.GetMapCoordinates(user), _transform.GetMapCoordinates(target), bodyPrototype, bodyState, shader, controller))
return;
if (controller != null && TryComp(controller, out var controllerBeamComp))
@@ -169,11 +160,95 @@ public sealed class BeamSystem : SharedBeamSystem
controllerBeamComp.HitTargets.Add(target);
}
- var distanceCorrection = calculatedDistance - calculatedDistance.Normalized();
-
- CreateBeam(bodyPrototype, userAngle, calculatedDistance, beamStartPos, distanceCorrection, controller, bodyState, shader);
-
var ev = new CreateBeamSuccessEvent(user, target);
RaiseLocalEvent(user, ev);
}
+
+ ///
+ /// Called where you want an entity to create a beam from one set of coordinates to another.
+ /// Tries to create the beam and does calculations like the distance, angle, and offset.
+ ///
+ ///
+ /// Ported from imp
+ ///
+ /// The coordinates that the beam is being fired from
+ /// The coordinates that are being targeted
+ /// The prototype spawned when this beam is created
+ /// Optional sprite state for the if a default one is not given
+ /// Optional shader for the if a default one is not given
+ ///
+ public bool TryCreateBeam(MapCoordinates coordinates, MapCoordinates targetCoordinates, string bodyPrototype, string? bodyState = null, string shader = "unshaded", EntityUid? controller = null)
+ {
+ //The distance between the target and the user.
+ var calculatedDistance = targetCoordinates.Position - coordinates.Position;
+ var userAngle = calculatedDistance.ToWorldAngle();
+
+ if (coordinates.MapId != targetCoordinates.MapId)
+ return false;
+
+ //Where the start of the beam will spawn
+ var beamStartPos = coordinates.Offset(calculatedDistance.Normalized());
+
+ //Don't divide by zero
+ if (calculatedDistance.Length() == 0)
+ return false;
+
+ var distanceCorrection = calculatedDistance - calculatedDistance.Normalized();
+
+ CreateBeam(bodyPrototype, userAngle, calculatedDistance, beamStartPos, distanceCorrection, controller, bodyState, shader);
+ return true;
+ }
+
+ ///
+ /// Called where you want an entity to create a beam from a set of coordinates to an entity.
+ /// Tries to create the beam and does calculations like the distance, angle, and offset.
+ ///
+ ///
+ /// Ported from imp
+ ///
+ /// The coordinates that the beam is being fired from
+ /// The entity that's being targeted by the user
+ /// The prototype spawned when this beam is created
+ /// Optional sprite state for the if a default one is not given
+ /// Optional shader for the if a default one is not given
+ ///
+ public void TryCreateBeam(MapCoordinates coordinates, EntityUid target, string bodyPrototype, string? bodyState = null, string shader = "unshaded", EntityUid? controller = null)
+ {
+ if (Deleted(target))
+ return;
+
+ if (TryCreateBeam(coordinates, _transform.GetMapCoordinates(target), bodyPrototype, bodyState, shader, controller))
+ {
+ if (controller != null && TryComp(controller, out var controllerBeamComp))
+ controllerBeamComp.HitTargets.Add(target);
+ }
+ }
+
+ ///
+ /// Called where you want an entity to create a beam from an entity to a set of coordinates.
+ /// Tries to create the beam and does calculations like the distance, angle, and offset.
+ ///
+ ///
+ /// Ported from imp
+ ///
+ /// The entity that's firing off the beam
+ /// The coordinates that are being targeted
+ /// The prototype spawned when this beam is created
+ /// Optional sprite state for the if a default one is not given
+ /// Optional shader for the if a default one is not given
+ ///
+ public void TryCreateBeam(EntityUid user, MapCoordinates targetCoordinates, string bodyPrototype, string? bodyState = null, string shader = "unshaded", EntityUid? controller = null)
+ {
+ if (Deleted(user))
+ return;
+
+ if (TryCreateBeam(_transform.GetMapCoordinates(user), targetCoordinates, bodyPrototype, bodyState, shader, controller))
+ {
+ if (controller != null && TryComp(controller, out var controllerBeamComp))
+ controllerBeamComp.HitTargets.Add(user);
+
+ var ev = new CreateBeamSuccessEvent(user, targetCoordinates);
+ RaiseLocalEvent(user, ev);
+ }
+ }
}
diff --git a/Content.Server/Lightning/LightningSystem.cs b/Content.Server/Lightning/LightningSystem.cs
index 5a7b85d26e..18c47dbf70 100644
--- a/Content.Server/Lightning/LightningSystem.cs
+++ b/Content.Server/Lightning/LightningSystem.cs
@@ -4,6 +4,7 @@ using Content.Server.Beam.Components;
using Content.Server.Lightning.Components;
using Content.Shared.Lightning;
using Robust.Server.GameObjects;
+using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Lightning;
@@ -21,7 +22,7 @@ public sealed class LightningSystem : SharedLightningSystem
[Dependency] private readonly BeamSystem _beam = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
- [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly TransformSystem _transform = default!;
public override void Initialize()
{
@@ -59,6 +60,134 @@ public sealed class LightningSystem : SharedLightningSystem
}
}
+ ///
+ /// Fires lightning from user to coordinates
+ ///
+ ///
+ /// Ported from imp
+ ///
+ /// Where the lightning fires from
+ /// Where the lightning fires to
+ /// The prototype for the lightning to be created
+ /// if the lightnings being fired should trigger lightning events.
+ public void ShootLightning(EntityUid user, MapCoordinates targetCoordinates, string lightningPrototype = "Lightning", bool triggerLightningEvents = true)
+ {
+ var spriteState = LightningRandomizer();
+ _beam.TryCreateBeam(user, targetCoordinates, lightningPrototype, spriteState);
+ }
+
+ ///
+ /// Fires lightning from coordinates to target
+ ///
+ ///
+ /// Ported from imp
+ ///
+ /// Where the lightning fires from
+ /// Where the lightning fires to
+ /// The prototype for the lightning to be created
+ /// if the lightnings being fired should trigger lightning events.
+ public void ShootLightning(MapCoordinates coordinates, EntityUid target, string lightningPrototype = "Lightning", bool triggerLightningEvents = true)
+ {
+ var spriteState = LightningRandomizer();
+ _beam.TryCreateBeam(coordinates, target, lightningPrototype, spriteState);
+
+ if (triggerLightningEvents) // we don't want certain prototypes to trigger lightning level events
+ {
+ var ev = new HitByLightningEvent(null, target);
+ RaiseLocalEvent(target, ref ev);
+ }
+ }
+
+ ///
+ /// Fires lightning from coordinates to other coordinates
+ ///
+ ///
+ /// Ported from imp
+ ///
+ /// Where the lightning fires from
+ /// Where the lightning fires to
+ /// The prototype for the lightning to be created
+ /// if the lightnings being fired should trigger lightning events.
+ public void ShootLightning(MapCoordinates coordinates, MapCoordinates targetCoordinates, string lightningPrototype = "Lightning", bool triggerLightningEvents = true)
+ {
+ var spriteState = LightningRandomizer();
+ _beam.TryCreateBeam(coordinates, targetCoordinates, lightningPrototype, spriteState);
+ }
+
+
+ ///
+ /// Looks for objects with a LightningTarget component in the radius, prioritizes them, and hits the highest priority targets with lightning.
+ ///
+ ///
+ /// Ported from imp.
+ ///
+ /// Where the lightning fires from
+ /// Targets selection radius
+ /// Number of lightning bolts
+ /// The prototype for the lightning to be created
+ /// how many times to recursively fire lightning bolts from the target points of the first shot.
+ /// if the lightnings being fired should trigger lightning events.
+ /// Chance for lightning to strike random coordinates instead of an entity.
+ public void ShootRandomLightnings(MapCoordinates coordinates, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true, float hitCoordsChance = 0f, EntityUid? user = null)
+ {
+ //TODO: add support to different priority target tablem for different lightning types
+ //TODO: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
+ //TODO: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
+ // several hashsets every time
+
+ var targets = _lookup.GetEntitiesInRange(coordinates, range).ToList();
+ _random.Shuffle(targets);
+ targets.Sort((x, y) => y.Comp.Priority.CompareTo(x.Comp.Priority));
+
+ int shootedCount = 0;
+ int count = -1;
+ int mobLightningResistance = 2; // imp - If the target has a lightning resistance less than or equal to this, the lightning can hit random coordinates instead.
+ while (shootedCount < boltCount)
+ {
+ count++;
+
+ // imp - random coordinate lightning start
+ var outOfRange = count >= targets.Count;
+ var targetLightningResistance = outOfRange ? 0 : targets[count].Comp.LightningResistance;
+
+ if (hitCoordsChance > 0 && targetLightningResistance <= mobLightningResistance && _random.Prob(hitCoordsChance))
+ {
+ var targetCoordinate = coordinates.Offset(_random.NextVector2(range, range));
+
+ if (user != null)
+ ShootLightning(user.Value, targetCoordinate, lightningPrototype, triggerLightningEvents);
+ else
+ ShootLightning(coordinates, targetCoordinate, lightningPrototype, triggerLightningEvents);
+
+ if (arcDepth > 0)
+ {
+ ShootRandomLightnings(targetCoordinate, range, 1, lightningPrototype, arcDepth - 1, triggerLightningEvents, hitCoordsChance, user);
+ }
+
+ shootedCount++;
+ continue;
+ }
+
+ if (outOfRange) { break; }
+ // imp - random coordinate lightning end
+
+ var curTarget = targets[count];
+ if (!_random.Prob(curTarget.Comp.HitProbability)) //Chance to ignore target
+ continue;
+
+ // imp - use correct shoot lightning method based on whether this is coordinates-based or entity-based
+ if (user != null)
+ ShootLightning(user.Value, targets[count].Owner, lightningPrototype, triggerLightningEvents);
+ else
+ ShootLightning(coordinates, targets[count].Owner, lightningPrototype, triggerLightningEvents);
+
+ if (arcDepth - targetLightningResistance > 0)
+ {
+ ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targetLightningResistance, triggerLightningEvents, hitCoordsChance);
+ }
+ shootedCount++;
+ }
+ }
///
/// Looks for objects with a LightningTarget component in the radius, prioritizes them, and hits the highest priority targets with lightning.
@@ -69,45 +198,18 @@ public sealed class LightningSystem : SharedLightningSystem
/// The prototype for the lightning to be created
/// how many times to recursively fire lightning bolts from the target points of the first shot.
/// if the lightnings being fired should trigger lightning events.
- public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
+ /// Chance for lightning to strike random coordinates instead of an entity.
+ public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true, float hitCoordsChance = 0f)
{
- //To Do: add support to different priority target tablem for different lightning types
- //To Do: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
- //To Do: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
- // several hashsets every time
- var mapCoords = _transform.GetMapCoordinates(user);
- var targets = _lookup.GetEntitiesInRange(mapCoords, range).ToList();
- _random.Shuffle(targets);
- targets.Sort((x, y) => y.Comp.Priority.CompareTo(x.Comp.Priority));
-
- int shotCount = 0;
- int count = -1;
-
- while (shotCount < boltCount)
- {
- count++;
-
- if (count >= targets.Count) { break; }
- var curTarget = targets[count];
-
- // Chance to ignore target
- if (!_random.Prob(curTarget.Comp.HitProbability))
- continue;
-
- ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents);
-
- if (arcDepth - targets[count].Comp.LightningResistance > 0)
- ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].Comp.LightningResistance, triggerLightningEvents);
-
- shotCount++;
- }
+ // imp - Redirect to the other function for compatibility
+ ShootRandomLightnings(_transform.GetMapCoordinates(user), range, boltCount, lightningPrototype, arcDepth, triggerLightningEvents, hitCoordsChance, user);
}
}
///
/// Raised directed on the target when an entity becomes the target of a lightning strike (not when touched)
///
-/// The entity that created the lightning
+/// The entity that created the lightning. May be null if the lightning came from coordinates rather than an entity.
/// The entity that was struck by lightning.
[ByRefEvent]
-public readonly record struct HitByLightningEvent(EntityUid Source, EntityUid Target);
+public readonly record struct HitByLightningEvent(EntityUid? Source, EntityUid Target); // imp - Lightning might come from coordinates instead of an entity, so Source can be null
diff --git a/Content.Server/_EE/Supermatter/Consoles/SupermatterConsoleSystem.cs b/Content.Server/_EE/Supermatter/Consoles/SupermatterConsoleSystem.cs
new file mode 100644
index 0000000000..1ad0cc9f7e
--- /dev/null
+++ b/Content.Server/_EE/Supermatter/Consoles/SupermatterConsoleSystem.cs
@@ -0,0 +1,217 @@
+using Content.Server.Pinpointer;
+using Content.Shared._EE.Supermatter.Components;
+using Content.Shared._EE.Supermatter.Consoles;
+using Content.Shared._EE.Supermatter.Monitor;
+using Content.Shared.Atmos;
+using Content.Shared.Pinpointer;
+using Content.Shared.Radiation.Components;
+using Robust.Server.GameObjects;
+using Robust.Shared.Map.Components;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+namespace Content.Server._EE.Supermatter.Console.Systems;
+
+public sealed class SupermatterConsoleSystem : SharedSupermatterConsoleSystem
+{
+ [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+ [Dependency] private readonly NavMapSystem _navMapSystem = default!;
+
+ private const float UpdateTime = 1.0f;
+
+ // Note: this data does not need to be saved
+ private float _updateTimer = 1.0f;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ // Console events
+ SubscribeLocalEvent(OnConsoleInit);
+ SubscribeLocalEvent(OnConsoleParentChanged);
+ SubscribeLocalEvent(OnFocusChangedMessage);
+
+ // Grid events
+ SubscribeLocalEvent(OnGridSplit);
+ }
+
+ #region Event handling
+
+ private void OnConsoleInit(EntityUid uid, SupermatterConsoleComponent component, ComponentInit args)
+ {
+ InitalizeConsole(uid, component);
+ }
+
+ private void OnConsoleParentChanged(EntityUid uid, SupermatterConsoleComponent component, EntParentChangedMessage args)
+ {
+ InitalizeConsole(uid, component);
+ }
+
+ private void OnFocusChangedMessage(EntityUid uid, SupermatterConsoleComponent component, SupermatterConsoleFocusChangeMessage args)
+ {
+ component.FocusSupermatter = args.FocusSupermatter;
+ }
+
+ private void OnGridSplit(ref GridSplitEvent args)
+ {
+ // Collect grids
+ var allGrids = args.NewGrids.ToList();
+
+ if (!allGrids.Contains(args.Grid))
+ allGrids.Add(args.Grid);
+
+ // Update supermatter monitoring consoles that stand upon an updated grid
+ var query = AllEntityQuery();
+ while (query.MoveNext(out var ent, out var entConsole, out var entXform))
+ {
+ if (entXform.GridUid == null)
+ continue;
+
+ if (!allGrids.Contains(entXform.GridUid.Value))
+ continue;
+
+ InitalizeConsole(ent, entConsole);
+ }
+ }
+
+ #endregion
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ // Keep a list of UI entries for each gridUid, in case multiple consoles stand on the same grid
+ var supermatterEntriesForEachGrid = new Dictionary();
+
+ var query = AllEntityQuery();
+ while (query.MoveNext(out var ent, out var entConsole, out var entXform))
+ {
+ if (entXform?.GridUid == null)
+ continue;
+
+ // Make a list of alarm state data for all the supermatters on the grid
+ if (!supermatterEntriesForEachGrid.TryGetValue(entXform.GridUid.Value, out var supermatterEntries))
+ {
+ supermatterEntries = GetSupermatterStateData(entXform.GridUid.Value).ToArray();
+ supermatterEntriesForEachGrid[entXform.GridUid.Value] = supermatterEntries;
+ }
+
+ // Determine the highest level of status for the console
+ var highestStatus = SupermatterStatusType.Inactive;
+
+ foreach (var entry in supermatterEntries)
+ {
+ var status = entry.EntityStatus;
+
+ if (status > highestStatus)
+ highestStatus = status;
+ }
+
+ // Update the appearance of the console based on the highest recorded level of alert
+ if (TryComp(ent, out var entAppearance))
+ _appearance.SetData(ent, SupermatterConsoleVisuals.ComputerLayerScreen, (int)highestStatus, entAppearance);
+
+ // If the console UI is open, send UI data to each subscribed session
+ UpdateUIState(ent, supermatterEntries, entConsole, entXform);
+ }
+ }
+
+ public void UpdateUIState
+ (EntityUid uid,
+ SupermatterConsoleEntry[] supermatterStateData,
+ SupermatterConsoleComponent component,
+ TransformComponent xform)
+ {
+ if (!_userInterfaceSystem.IsUiOpen(uid, SupermatterConsoleUiKey.Key))
+ return;
+
+ var gridUid = xform.GridUid!.Value;
+
+ // Gathering remaining data to be send to the client
+ var focusSupermatterData = GetFocusSupermatterData(uid, GetEntity(component.FocusSupermatter), gridUid);
+
+ // Set the UI state
+ _userInterfaceSystem.SetUiState(uid, SupermatterConsoleUiKey.Key,
+ new SupermatterConsoleBoundInterfaceState(supermatterStateData, focusSupermatterData));
+ }
+
+ private List GetSupermatterStateData(EntityUid gridUid)
+ {
+ var supermatterStateData = new List();
+
+ var querySupermatters = AllEntityQuery();
+ while (querySupermatters.MoveNext(out var ent, out var entSupermatter, out var entXform))
+ {
+ if (entXform.GridUid != gridUid)
+ continue;
+
+ if (!entXform.Anchored)
+ continue;
+
+ // Create entry
+ var netEnt = GetNetEntity(ent);
+
+ var entry = new SupermatterConsoleEntry
+ (netEnt,
+ MetaData(ent).EntityName,
+ entSupermatter.Status);
+
+ supermatterStateData.Add(entry);
+ }
+
+ return supermatterStateData;
+ }
+
+ private SupermatterFocusData? GetFocusSupermatterData(EntityUid uid, EntityUid? focusSupermatter, EntityUid gridUid)
+ {
+ if (focusSupermatter == null)
+ return null;
+
+ var focusSupermatterXform = Transform(focusSupermatter.Value);
+
+ if (!focusSupermatterXform.Anchored ||
+ focusSupermatterXform.GridUid != gridUid ||
+ !TryComp(focusSupermatter.Value, out var focusComp))
+ return null;
+
+ if (!TryComp(focusSupermatter.Value, out var sm))
+ return null;
+
+ if (!TryComp(focusSupermatter.Value, out var radiationComp))
+ return null;
+
+ var gases = sm.GasStorage;
+ var tempThreshold = Atmospherics.T0C + sm.HeatPenaltyThreshold;
+
+ return new SupermatterFocusData(
+ GetNetEntity(focusSupermatter.Value),
+ GetIntegrity(sm),
+ sm.Power,
+ radiationComp.Intensity,
+ gases.Sum(gas => gases[gas.Key]),
+ sm.Temperature,
+ tempThreshold * sm.DynamicHeatResistance,
+ sm.WasteMultiplier,
+ sm.GasEfficiency * 100,
+ sm.GasStorage);
+ }
+
+ public float GetIntegrity(SupermatterComponent sm)
+ {
+ var integrity = sm.Damage / sm.DamageDelaminationPoint;
+ integrity = (float)Math.Round(100 - integrity * 100, 2);
+ integrity = integrity < 0 ? 0 : integrity;
+ return integrity;
+ }
+
+ private void InitalizeConsole(EntityUid uid, SupermatterConsoleComponent component)
+ {
+ var xform = Transform(uid);
+
+ if (xform.GridUid == null)
+ return;
+
+ Dirty(uid, component);
+ }
+}
diff --git a/Content.Server/Supermatter/Systems/SupermatterSystem.Processing.cs b/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.Processing.cs
similarity index 59%
rename from Content.Server/Supermatter/Systems/SupermatterSystem.Processing.cs
rename to Content.Server/_EE/Supermatter/Systems/SupermatterSystem.Processing.cs
index 36ae2646b8..6e1e0b63a5 100644
--- a/Content.Server/Supermatter/Systems/SupermatterSystem.Processing.cs
+++ b/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.Processing.cs
@@ -1,13 +1,25 @@
-using Content.Shared.Atmos;
-using Content.Shared.Radiation.Components;
-using Content.Shared.Supermatter.Components;
-using System.Text;
-using Content.Shared.Chat;
using System.Linq;
+using System.Text;
+using Content.Server.Chat.Systems;
+using Content.Server.Explosion.EntitySystems;
+using Content.Server.Sound.Components;
+using Content.Shared._EE.CCVars;
+using Content.Shared._EE.Supermatter.Components;
+using Content.Shared._EE.Supermatter.Monitor;
+using Content.Shared.Atmos;
using Content.Shared.Audio;
using Content.Shared.CCVar;
+using Content.Shared.Chat;
+using Content.Shared.Popups;
+using Content.Shared.Radiation.Components;
+using Content.Shared.Speech;
+using Robust.Shared.Audio;
+using Robust.Shared.Configuration;
+using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
-namespace Content.Server.Supermatter.Systems;
+namespace Content.Server._EE.Supermatter.Systems;
public sealed partial class SupermatterSystem
{
@@ -97,11 +109,16 @@ public sealed partial class SupermatterSystem
// Irradiate stuff
if (TryComp(uid, out var rad))
+ {
rad.Intensity =
- sm.Power
+ _config.GetCVar(ECCVars.SupermatterRadsBase) +
+ (sm.Power
* Math.Max(0, 1f + transmissionBonus / 10f)
* 0.003f
- * _config.GetCVar(CCVars.SupermatterRadsModifier);
+ * _config.GetCVar(ECCVars.SupermatterRadsModifier));
+
+ rad.Slope = Math.Clamp(rad.Intensity / 15, 0.2f, 1f);
+ }
// Power * 0.55 * 0.8~1
// This has to be differentiated with respect to time, since its going to be interacting with systems
@@ -126,6 +143,14 @@ public sealed partial class SupermatterSystem
// After this point power is lowered
// This wraps around to the begining of the function
sm.Power = Math.Max(sm.Power - Math.Min(powerReduction * powerlossInhibitor, sm.Power * 0.83f * powerlossInhibitor), 0f);
+
+ // Save values to the supermatter
+ sm.GasStorage = sm.GasStorage.ToDictionary(
+ gas => gas.Key,
+ gas => absorbedGas.GetMoles(gas.Key)
+ );
+ sm.Temperature = absorbedGas.Temperature;
+ sm.WasteMultiplier = heatModifier;
}
///
@@ -133,10 +158,35 @@ public sealed partial class SupermatterSystem
///
private void SupermatterZap(EntityUid uid, SupermatterComponent sm)
{
- // Divide power by its' threshold to get a value from 0-1, then multiply by the amount of possible lightnings
- var zapPower = sm.Power / sm.PowerPenaltyThreshold * sm.LightningPrototypes.Length;
- var zapPowerNorm = (int) Math.Clamp(zapPower, 0, sm.LightningPrototypes.Length - 1);
- _lightning.ShootRandomLightnings(uid, 3.5f, sm.Power > sm.PowerPenaltyThreshold ? 3 : 1, sm.LightningPrototypes[zapPowerNorm]);
+ var zapPower = 0;
+ var zapCount = 0;
+ var zapRange = Math.Clamp(sm.Power / 1000, 2, 7);
+
+ // fuck this
+ if (_random.Prob(0.05f))
+ {
+ zapCount += 1;
+ }
+
+ if (sm.Power >= sm.PowerPenaltyThreshold)
+ {
+ zapCount += 2;
+ }
+
+ if (sm.Power >= sm.SeverePowerPenaltyThreshold)
+ {
+ zapPower = 1;
+ zapCount++;
+ }
+
+ if (sm.Power >= sm.CriticalPowerPenaltyThreshold)
+ {
+ zapPower = 2;
+ zapCount++;
+ }
+
+ if (zapCount >= 1)
+ _lightning.ShootRandomLightnings(uid, zapRange, zapCount, sm.LightningPrototypes[zapPower], hitCoordsChance: sm.ZapHitCoordinatesChance);
}
///
@@ -184,20 +234,16 @@ public sealed partial class SupermatterSystem
totalDamage += powerDamage;
// Mol count only starts affecting damage when it is above 1800
- var moleDamage = Math.Max(moles - sm.MolePenaltyThreshold, 0) / 80 * sm.DamageIncreaseMultiplier;
+ var moleDamage = Math.Max(moles - sm.MolePenaltyThreshold, 0f) / 80 * sm.DamageIncreaseMultiplier;
totalDamage += moleDamage;
// Healing damage
if (moles < sm.MolePenaltyThreshold)
{
- // There's a very small float so that it doesn't divide by 0
- var healHeatDamage = Math.Min(absorbedGas.Temperature - tempThreshold, 0.001f) / 150;
+ var healHeatDamage = Math.Min(absorbedGas.Temperature - tempThreshold, 0f) / 150;
totalDamage += healHeatDamage;
}
- // Return the manipulated gas back to the mix
- _atmosphere.Merge(mix, absorbedGas);
-
// Check for space tiles next to SM
//TODO: Change moles out for checking if adjacent tiles exist
var enumerator = _atmosphere.GetAdjacentTileMixtures(xform.GridUid.Value, indices, false, false);
@@ -217,12 +263,12 @@ public sealed partial class SupermatterSystem
_ => 0f
};
- totalDamage += Math.Clamp(sm.Power * factor * sm.DamageIncreaseMultiplier, 0, sm.MaxSpaceExposureDamage);
+ totalDamage += Math.Clamp(sm.Power * factor * sm.DamageIncreaseMultiplier, 0f, sm.MaxSpaceExposureDamage);
break;
}
- var damage = Math.Min(sm.DamageArchived + sm.DamageHardcap * sm.DamageDelaminationPoint, totalDamage);
+ var damage = Math.Min(sm.DamageArchived + sm.DamageHardcap * sm.DamageDelaminationPoint, sm.Damage + totalDamage);
// Prevent it from going negative
sm.Damage = Math.Clamp(damage, 0, float.PositiveInfinity);
@@ -233,19 +279,16 @@ public sealed partial class SupermatterSystem
///
private void AnnounceCoreDamage(EntityUid uid, SupermatterComponent sm)
{
+ // If undamaged, no need to announce anything
+ if (sm.Damage == 0)
+ return;
+
var message = string.Empty;
var global = false;
var integrity = GetIntegrity(sm).ToString("0.00");
- // Special cases
- if (sm.Damage < sm.DamageDelaminationPoint && sm.Delamming)
- {
- message = Loc.GetString("supermatter-delam-cancel", ("integrity", integrity));
- sm.DelamAnnounced = false;
- global = true;
- }
-
+ // Instantly announce delamination
if (sm.Delamming && !sm.DelamAnnounced)
{
var sb = new StringBuilder();
@@ -259,18 +302,73 @@ public sealed partial class SupermatterSystem
default: loc = "supermatter-delam-explosion"; break;
}
- var station = _station.GetOwningStation(uid);
- if (station != null)
- _alert.SetLevel((EntityUid) station, sm.AlertCodeDeltaId, true, true, true, false);
-
sb.AppendLine(Loc.GetString(loc));
- sb.AppendLine(Loc.GetString("supermatter-seconds-before-delam", ("seconds", sm.DelamTimer)));
+ sb.Append(Loc.GetString("supermatter-seconds-before-delam", ("seconds", sm.DelamTimer)));
message = sb.ToString();
global = true;
sm.DelamAnnounced = true;
+ sm.YellTimer = TimeSpan.FromSeconds(sm.DelamTimer / 2);
- SendSupermatterAnnouncement(uid, message, global);
+ SendSupermatterAnnouncement(uid, sm, message, global);
+ return;
+ }
+
+ // Only announce every YellTimer seconds
+ if (_timing.CurTime < sm.YellLast + sm.YellTimer)
+ return;
+
+ // Recovered after the delamination point
+ if (sm.Damage < sm.DamageDelaminationPoint && sm.DelamAnnounced)
+ {
+ message = Loc.GetString("supermatter-delam-cancel", ("integrity", integrity));
+ sm.DelamAnnounced = false;
+ sm.YellTimer = TimeSpan.FromSeconds(_config.GetCVar(ECCVars.SupermatterYellTimer));
+ global = true;
+
+ SendSupermatterAnnouncement(uid, sm, message, global);
+ return;
+ }
+
+ // Oh god oh fuck
+ if (sm.Delamming && sm.DelamAnnounced)
+ {
+ var seconds = Math.Ceiling(sm.DelamEndTime.TotalSeconds - _timing.CurTime.TotalSeconds);
+
+ if (seconds <= 0)
+ return;
+
+ var loc = seconds switch
+ {
+ > 5 => "supermatter-seconds-before-delam-countdown",
+ <= 5 => "supermatter-seconds-before-delam-imminent",
+ _ => String.Empty
+ };
+
+ sm.YellTimer = seconds switch
+ {
+ > 30 => TimeSpan.FromSeconds(10),
+ > 5 => TimeSpan.FromSeconds(5),
+ <= 5 => TimeSpan.FromSeconds(1),
+ _ => TimeSpan.FromSeconds(_config.GetCVar(ECCVars.SupermatterYellTimer))
+ };
+
+ message = Loc.GetString(loc, ("seconds", seconds));
+ global = true;
+
+ SendSupermatterAnnouncement(uid, sm, message, global);
+ return;
+ }
+
+ // We're safe
+ if (sm.Damage < sm.DamageArchived && sm.Status >= SupermatterStatusType.Warning)
+ {
+ message = Loc.GetString("supermatter-healing", ("integrity", integrity));
+
+ if (sm.Status >= SupermatterStatusType.Emergency)
+ global = true;
+
+ SendSupermatterAnnouncement(uid, sm, message, global);
return;
}
@@ -292,21 +390,27 @@ public sealed partial class SupermatterSystem
}
}
- SendSupermatterAnnouncement(uid, message, global);
+ SendSupermatterAnnouncement(uid, sm, message, global);
}
- /// If true, sends a station announcement
+ /// If true, sends the message to the common radio
/// Localisation string for a custom announcer name
- public void SendSupermatterAnnouncement(EntityUid uid, string message, bool global = false, string? customSender = null)
+ public void SendSupermatterAnnouncement(EntityUid uid, SupermatterComponent sm, string message, bool global = false)
{
- if (global)
- {
- var sender = Loc.GetString(customSender != null ? customSender : "supermatter-announcer");
- _chat.DispatchStationAnnouncement(uid, message, sender, colorOverride: Color.Yellow);
+ if (message == String.Empty)
return;
- }
+ var channel = sm.Channel;
+
+ if (global)
+ channel = sm.ChannelGlobal;
+
+ // Ensure status, otherwise the wrong speech sound may be used
+ HandleStatus(uid, sm);
+
+ sm.YellLast = _timing.CurTime;
_chat.TrySendInGameICMessage(uid, message, InGameICChatType.Speak, hideChat: false, checkRadioPrefix: true);
+ _radio.SendRadioMessage(uid, message, channel, uid);
}
///
@@ -325,8 +429,8 @@ public sealed partial class SupermatterSystem
///
public DelamType ChooseDelamType(EntityUid uid, SupermatterComponent sm)
{
- if (_config.GetCVar(CCVars.SupermatterDoForceDelam))
- return _config.GetCVar(CCVars.SupermatterForcedDelamType);
+ if (_config.GetCVar(ECCVars.SupermatterDoForceDelam))
+ return _config.GetCVar(ECCVars.SupermatterForcedDelamType);
var mix = _atmosphere.GetContainingMixture(uid, true, true);
@@ -335,13 +439,13 @@ public sealed partial class SupermatterSystem
var absorbedGas = mix.Remove(sm.GasEfficiency * mix.TotalMoles);
var moles = absorbedGas.TotalMoles;
- if (_config.GetCVar(CCVars.SupermatterDoSingulooseDelam)
- && moles >= sm.MolePenaltyThreshold * _config.GetCVar(CCVars.SupermatterSingulooseMolesModifier))
+ if (_config.GetCVar(ECCVars.SupermatterDoSingulooseDelam)
+ && moles >= sm.MolePenaltyThreshold * _config.GetCVar(ECCVars.SupermatterSingulooseMolesModifier))
return DelamType.Singulo;
}
- if (_config.GetCVar(CCVars.SupermatterDoTeslooseDelam)
- && sm.Power >= sm.PowerPenaltyThreshold * _config.GetCVar(CCVars.SupermatterTesloosePowerModifier))
+ if (_config.GetCVar(ECCVars.SupermatterDoTeslooseDelam)
+ && sm.Power >= sm.PowerPenaltyThreshold * _config.GetCVar(ECCVars.SupermatterTesloosePowerModifier))
return DelamType.Tesla;
//TODO: Add resonance cascade when there's crazy conditions or a destabilizing crystal
@@ -361,6 +465,7 @@ public sealed partial class SupermatterSystem
if (!sm.Delamming)
{
sm.Delamming = true;
+ sm.DelamEndTime = _timing.CurTime + TimeSpan.FromSeconds(sm.DelamTimer);
AnnounceCoreDamage(uid, sm);
}
@@ -370,11 +475,23 @@ public sealed partial class SupermatterSystem
AnnounceCoreDamage(uid, sm);
}
- sm.DelamTimerAccumulator++;
-
- if (sm.DelamTimerAccumulator < sm.DelamTimer)
+ if (_timing.CurTime < sm.DelamEndTime)
return;
+ var smTransform = Transform(uid);
+
+ foreach (var pSession in Filter.GetAllPlayers())
+ {
+ var pEntity = pSession.AttachedEntity;
+
+ if (pEntity != null
+ && TryComp(pEntity, out var pTransform)
+ && pTransform.MapID == smTransform.MapID)
+ _popup.PopupEntity(Loc.GetString("supermatter-delam-player"), pEntity.Value, pEntity.Value, PopupType.MediumCaution);
+ }
+
+ _audio.PlayGlobal(sm.DistortSound, Filter.BroadcastMap(Transform(uid).MapID), true);
+
switch (sm.PreferredDelamType)
{
case DelamType.Cascade:
@@ -395,6 +512,55 @@ public sealed partial class SupermatterSystem
}
}
+ ///
+ /// Sets the supermatter's status and speech sound based on thresholds
+ ///
+ private void HandleStatus(EntityUid uid, SupermatterComponent sm)
+ {
+ var currentStatus = GetStatus(uid, sm);
+
+ if (sm.Status != currentStatus)
+ {
+ sm.Status = currentStatus;
+
+ if (!TryComp(uid, out var speech))
+ return;
+
+ sm.StatusCurrentSound = currentStatus switch
+ {
+ SupermatterStatusType.Warning => sm.StatusWarningSound,
+ SupermatterStatusType.Danger => sm.StatusDangerSound,
+ SupermatterStatusType.Emergency => sm.StatusEmergencySound,
+ SupermatterStatusType.Delaminating => sm.StatusDelamSound,
+ _ => null
+ };
+
+ ProtoId? speechSound = sm.StatusCurrentSound;
+
+ if (currentStatus == SupermatterStatusType.Warning)
+ speech.AudioParams = AudioParams.Default.AddVolume(7.5f);
+ else
+ speech.AudioParams = AudioParams.Default.AddVolume(10f);
+
+ if (currentStatus == SupermatterStatusType.Delaminating)
+ speech.SoundCooldownTime = 6.8f; // approximate length of bloblarm.ogg
+ else
+ speech.SoundCooldownTime = 0.0f;
+
+ speech.SpeechSounds = speechSound;
+ }
+
+ // Supermatter is healing, don't play any speech sounds
+ if (sm.Damage < sm.DamageArchived)
+ {
+ if (!TryComp(uid, out var speech))
+ return;
+
+ sm.StatusCurrentSound = null;
+ speech.SpeechSounds = null;
+ }
+ }
+
///
/// Swaps out ambience sounds when the SM is delamming or not.
///
@@ -405,13 +571,48 @@ public sealed partial class SupermatterSystem
if (ambient == null)
return;
- if (sm.Delamming && sm.CurrentSoundLoop != sm.DelamSound)
- sm.CurrentSoundLoop = sm.DelamSound;
+ var volume = (float) Math.Round(Math.Clamp((sm.Power / 50) - 5, -5, 5));
- else if (!sm.Delamming && sm.CurrentSoundLoop != sm.CalmSound)
- sm.CurrentSoundLoop = sm.CalmSound;
+ _ambient.SetVolume(uid, volume);
+
+ if (sm.Status >= SupermatterStatusType.Danger && sm.CurrentSoundLoop != sm.DelamLoopSound)
+ sm.CurrentSoundLoop = sm.DelamLoopSound;
+
+ else if (sm.Status < SupermatterStatusType.Danger && sm.CurrentSoundLoop != sm.CalmLoopSound)
+ sm.CurrentSoundLoop = sm.CalmLoopSound;
if (ambient.Sound != sm.CurrentSoundLoop)
_ambient.SetSound(uid, sm.CurrentSoundLoop, ambient);
}
+
+ ///
+ /// Plays normal/delam sounds at a rate determined by power and damage
+ ///
+ private void HandleAccent(EntityUid uid, SupermatterComponent sm)
+ {
+ var emit = Comp(uid);
+
+ if (emit == null)
+ return;
+
+ if (sm.AccentLastTime >= _timing.CurTime || !_random.Prob(0.05f))
+ return;
+
+ var aggression = Math.Min((sm.Damage / 800) * (sm.Power / 2500), 1) * 100;
+ var nextSound = Math.Max(Math.Round((100 - aggression) * 5), sm.AccentMinCooldown);
+
+ if (sm.AccentLastTime + TimeSpan.FromSeconds(nextSound) > _timing.CurTime)
+ return;
+
+ if (sm.Status >= SupermatterStatusType.Danger && emit.Sound != sm.DelamAccent)
+ emit.Sound = sm.DelamAccent;
+
+ else if (sm.Status < SupermatterStatusType.Danger && emit.Sound != sm.CalmAccent)
+ emit.Sound = sm.CalmAccent;
+
+ sm.AccentLastTime = _timing.CurTime;
+
+ var ev = new TriggerEvent(uid);
+ RaiseLocalEvent(uid, ev);
+ }
}
diff --git a/Content.Server/Supermatter/Systems/SupermatterSystem.cs b/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.cs
similarity index 66%
rename from Content.Server/Supermatter/Systems/SupermatterSystem.cs
rename to Content.Server/_EE/Supermatter/Systems/SupermatterSystem.cs
index 7521b42c48..5e9ec4c48a 100644
--- a/Content.Server/Supermatter/Systems/SupermatterSystem.cs
+++ b/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.cs
@@ -1,33 +1,46 @@
+using Content.Server.AlertLevel;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos.Piping.Components;
+using Content.Server.Chat.Systems;
+using Content.Server.Decals;
+using Content.Server.DoAfter;
+using Content.Server.Explosion.EntitySystems;
+using Content.Server.Kitchen.Components;
+using Content.Server.Lightning;
+using Content.Server.Lightning.Components;
+using Content.Server.Popups;
+using Content.Server.Radio.EntitySystems;
+using Content.Server.Speech;
+using Content.Server.Station.Systems;
+using Content.Shared._EE.CCVars;
+using Content.Shared._EE.Supermatter.Components;
+using Content.Shared._EE.Supermatter.Monitor;
+using Content.Shared.Atmos;
+using Content.Shared.Audio;
+using Content.Shared.Body.Components;
+using Content.Shared.CCVar;
+using Content.Shared.DoAfter;
+using Content.Shared.Examine;
+using Content.Shared.Interaction;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Popups;
+using Content.Shared.Projectiles;
+using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Events;
-using Robust.Server.GameObjects;
-using Content.Shared.Atmos;
-using Content.Shared.Interaction;
-using Content.Shared.Projectiles;
-using Content.Shared.Mobs.Components;
-using Content.Server.Atmos.EntitySystems;
-using Content.Server.Chat.Systems;
-using Content.Server.Explosion.EntitySystems;
-using Content.Shared.Supermatter.Components;
-using Content.Server.Lightning;
-using Content.Server.AlertLevel;
-using Content.Server.Station.Systems;
-using Content.Server.Kitchen.Components;
-using Content.Shared.DoAfter;
-using Content.Shared.Examine;
-using Content.Server.DoAfter;
-using Content.Server.Popups;
-using Content.Shared.Audio;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
-namespace Content.Server.Supermatter.Systems;
+namespace Content.Server._EE.Supermatter.Systems;
public sealed partial class SupermatterSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly RadioSystem _radio = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly ExplosionSystem _explosion = default!;
[Dependency] private readonly TransformSystem _xform = default!;
@@ -36,10 +49,13 @@ public sealed partial class SupermatterSystem : EntitySystem
[Dependency] private readonly LightningSystem _lightning = default!;
[Dependency] private readonly AlertLevelSystem _alert = default!;
[Dependency] private readonly StationSystem _station = default!;
+ [Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
@@ -47,6 +63,7 @@ public sealed partial class SupermatterSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnSupermatterUpdated);
SubscribeLocalEvent(OnCollideEvent);
SubscribeLocalEvent(OnHandInteract);
@@ -55,56 +72,22 @@ public sealed partial class SupermatterSystem : EntitySystem
SubscribeLocalEvent(OnGetSliver);
}
-
public override void Update(float frameTime)
{
base.Update(frameTime);
foreach (var sm in EntityManager.EntityQuery())
{
- if (!sm.Activated)
- return;
-
var uid = sm.Owner;
- sm.UpdateAccumulator += frameTime;
-
- if (sm.UpdateAccumulator >= sm.UpdateTimer)
- {
- sm.UpdateAccumulator -= sm.UpdateTimer;
- Cycle(uid, sm, frameTime);
- }
- }
- }
-
-
- public void Cycle(EntityUid uid, SupermatterComponent sm, float frameTime)
- {
- sm.ZapAccumulator++;
- sm.YellAccumulator++;
-
- ProcessAtmos(uid, sm, frameTime);
- HandleDamage(uid, sm);
-
- if (sm.Damage >= sm.DamageDelaminationPoint || sm.Delamming)
- HandleDelamination(uid, sm);
-
- HandleSoundLoop(uid, sm);
-
- if (sm.ZapAccumulator >= sm.ZapTimer)
- {
- sm.ZapAccumulator -= sm.ZapTimer;
- SupermatterZap(uid, sm);
- }
-
- if (sm.YellAccumulator >= sm.YellTimer)
- {
- sm.YellAccumulator -= sm.YellTimer;
AnnounceCoreDamage(uid, sm);
}
}
private void OnMapInit(EntityUid uid, SupermatterComponent sm, MapInitEvent args)
{
+ // Set the yell timer
+ sm.YellTimer = TimeSpan.FromSeconds(_config.GetCVar(ECCVars.SupermatterYellTimer));
+
// Set the Sound
_ambient.SetAmbience(uid, true);
@@ -113,6 +96,21 @@ public sealed partial class SupermatterSystem : EntitySystem
mix?.AdjustMoles(Gas.Oxygen, Atmospherics.OxygenMolesStandard);
mix?.AdjustMoles(Gas.Nitrogen, Atmospherics.NitrogenMolesStandard);
}
+ public void OnSupermatterUpdated(EntityUid uid, SupermatterComponent sm, AtmosDeviceUpdateEvent args)
+ {
+ ProcessAtmos(uid, sm, args.dt);
+ HandleDamage(uid, sm);
+
+ if (sm.Damage >= sm.DamageDelaminationPoint || sm.Delamming)
+ HandleDelamination(uid, sm);
+
+ HandleStatus(uid, sm);
+ HandleSoundLoop(uid, sm);
+ HandleAccent(uid, sm);
+
+ if (sm.Damage >= sm.DamagePenaltyPoint)
+ SupermatterZap(uid, sm);
+ }
private void OnCollideEvent(EntityUid uid, SupermatterComponent sm, ref StartCollideEvent args)
{
@@ -127,12 +125,26 @@ public sealed partial class SupermatterSystem : EntitySystem
if (!HasComp(target))
{
- EntityManager.SpawnEntity(sm.CollisionResultPrototype, Transform(target).Coordinates);
- _audio.PlayPvs(sm.DustSound, uid);
+ var popup = "supermatter-collide";
+
+ if (HasComp(target))
+ {
+ popup = "supermatter-collide-mob";
+ EntityManager.SpawnEntity(sm.CollisionResultPrototype, Transform(target).Coordinates);
+ }
+
+ var targetProto = MetaData(target).EntityPrototype;
+ if (targetProto != null && targetProto.ID != sm.CollisionResultPrototype)
+ {
+ _popup.PopupEntity(Loc.GetString(popup, ("sm", uid), ("target", target)), uid, PopupType.LargeCaution);
+ _audio.PlayPvs(sm.DustSound, uid);
+ }
+
sm.Power += args.OtherBody.Mass;
}
EntityManager.QueueDeleteEntity(target);
+ AddComp(target); // prevent spam or excess power production
if (TryComp(target, out var food))
sm.Power += food.Energy;
@@ -157,6 +169,7 @@ public sealed partial class SupermatterSystem : EntitySystem
sm.MatterPower += 200;
EntityManager.SpawnEntity(sm.CollisionResultPrototype, Transform(target).Coordinates);
+ _popup.PopupEntity(Loc.GetString("supermatter-collide-mob", ("sm", uid), ("target", target)), uid, PopupType.LargeCaution);
_audio.PlayPvs(sm.DustSound, uid);
EntityManager.QueueDeleteEntity(target);
}
@@ -176,7 +189,6 @@ public sealed partial class SupermatterSystem : EntitySystem
{
BreakOnDamage = true,
BreakOnHandChange = false,
- BreakOnMove = true,
BreakOnWeightlessMove = false,
NeedHand = true,
RequireCanInteract = true,
@@ -195,7 +207,7 @@ public sealed partial class SupermatterSystem : EntitySystem
sm.Damage += sm.DamageDelaminationPoint / 10;
var integrity = GetIntegrity(sm).ToString("0.00");
- SendSupermatterAnnouncement(uid, Loc.GetString("supermatter-announcement-cc-tamper", ("integrity", integrity)), true, "Central Command");
+ SendSupermatterAnnouncement(uid, sm, Loc.GetString("supermatter-announcement-cc-tamper", ("integrity", integrity)));
Spawn(sm.SliverPrototype, _transform.GetMapCoordinates(args.User));
_popup.PopupClient(Loc.GetString("supermatter-tamper-end"), uid, args.User);
@@ -208,4 +220,32 @@ public sealed partial class SupermatterSystem : EntitySystem
if (args.IsInDetailsRange)
args.PushMarkup(Loc.GetString("supermatter-examine-integrity", ("integrity", GetIntegrity(sm).ToString("0.00"))));
}
+
+ private SupermatterStatusType GetStatus(EntityUid uid, SupermatterComponent sm)
+ {
+ var mix = _atmosphere.GetContainingMixture(uid, true, true);
+
+ if (mix is not { })
+ return SupermatterStatusType.Error;
+
+ if (sm.Delamming || sm.Damage >= sm.DamageDelaminationPoint)
+ return SupermatterStatusType.Delaminating;
+
+ if (sm.Damage >= sm.DamagePenaltyPoint)
+ return SupermatterStatusType.Emergency;
+
+ if (sm.Damage >= sm.DamageDelamAlertPoint)
+ return SupermatterStatusType.Danger;
+
+ if (sm.Damage >= sm.DamageWarningThreshold)
+ return SupermatterStatusType.Warning;
+
+ if (mix.Temperature > Atmospherics.T0C + (sm.HeatPenaltyThreshold * 0.8))
+ return SupermatterStatusType.Caution;
+
+ if (sm.Power > 5)
+ return SupermatterStatusType.Normal;
+
+ return SupermatterStatusType.Inactive;
+ }
}
diff --git a/Content.Shared/Beam/Components/SharedBeamComponent.cs b/Content.Shared/Beam/Components/SharedBeamComponent.cs
index 9c5c5dd344..65598f88b6 100644
--- a/Content.Shared/Beam/Components/SharedBeamComponent.cs
+++ b/Content.Shared/Beam/Components/SharedBeamComponent.cs
@@ -1,4 +1,5 @@
-using Robust.Shared.Audio;
+using Robust.Shared.Audio;
+using Robust.Shared.Map;
using Robust.Shared.Serialization;
namespace Content.Shared.Beam.Components;
@@ -44,6 +45,16 @@ public abstract partial class SharedBeamComponent : Component
[ViewVariables(VVAccess.ReadWrite)]
[DataField("sound")]
public SoundSpecifier? Sound;
+
+ ///
+ /// Allow the sprite to be randomized.
+ ///
+ ///
+ /// Ported from imp
+ ///
+ [ViewVariables]
+ [DataField("allowSpriteOverwrite")]
+ public bool AllowSpriteOverwrite = true;
}
///
@@ -68,13 +79,29 @@ public sealed class BeamControllerCreatedEvent : EntityEventArgs
public sealed class CreateBeamSuccessEvent : EntityEventArgs
{
public readonly EntityUid User;
- public readonly EntityUid Target;
+
+ ///
+ /// The entity the beam targeted.
+ /// Imp - This may be null if the beam targeted a map coordinate.
+ ///
+ public readonly EntityUid? Target;
+
+ ///
+ /// The coordinates the beam targeted. This may be null if the beam targeted an entity.
+ ///
+ public readonly MapCoordinates? Coordinates;
public CreateBeamSuccessEvent(EntityUid user, EntityUid target)
{
User = user;
Target = target;
}
+
+ public CreateBeamSuccessEvent(EntityUid user, MapCoordinates coordinates)
+ {
+ User = user;
+ Coordinates = coordinates;
+ }
}
///
diff --git a/Content.Shared/CCVar/CCVars.Supermatter.cs b/Content.Shared/_EE/CCVars/ECCVars.Supermatter.cs
similarity index 80%
rename from Content.Shared/CCVar/CCVars.Supermatter.cs
rename to Content.Shared/_EE/CCVars/ECCVars.Supermatter.cs
index 8aea6524ae..69e90d0216 100644
--- a/Content.Shared/CCVar/CCVars.Supermatter.cs
+++ b/Content.Shared/_EE/CCVars/ECCVars.Supermatter.cs
@@ -1,9 +1,11 @@
-using Content.Shared.Supermatter.Components;
+using Content.Shared._EE.Supermatter.Components;
using Robust.Shared.Configuration;
-namespace Content.Shared.CCVar;
+namespace Content.Shared._EE.CCVars;
-public sealed partial class CCVars
+[CVarDefs]
+// ReSharper disable once InconsistentNaming
+public sealed partial class ECCVars
{
///
/// With completely default supermatter values, Singuloose delamination will occur if engineers inject at least 900 moles of coolant per tile
@@ -44,9 +46,21 @@ public sealed partial class CCVars
public static readonly CVarDef SupermatterForcedDelamType =
CVarDef.Create("supermatter.forced_delam_type", DelamType.Singulo, CVar.SERVER);
+ ///
+ /// Base amount of radiation that the supermatter emits.
+ ///
+ public static readonly CVarDef SupermatterRadsBase =
+ CVarDef.Create("supermatter.rads_base", 3f, CVar.SERVER);
+
///
/// Directly multiplies the amount of rads put out by the supermatter. Be VERY conservative with this.
///
public static readonly CVarDef SupermatterRadsModifier =
CVarDef.Create("supermatter.rads_modifier", 1f, CVar.SERVER);
+
+ ///
+ /// How often the supermatter should announce its status.
+ ///
+ public static readonly CVarDef SupermatterYellTimer =
+ CVarDef.Create("supermatter.yell_timer", 60f, CVar.SERVER);
}
diff --git a/Content.Shared/Supermatter/Components/SupermatterComponent.cs b/Content.Shared/_EE/Supermatter/Components/SupermatterComponent.cs
similarity index 71%
rename from Content.Shared/Supermatter/Components/SupermatterComponent.cs
rename to Content.Shared/_EE/Supermatter/Components/SupermatterComponent.cs
index ad7604f5ba..e40fe87ba5 100644
--- a/Content.Shared/Supermatter/Components/SupermatterComponent.cs
+++ b/Content.Shared/_EE/Supermatter/Components/SupermatterComponent.cs
@@ -1,11 +1,14 @@
-using Robust.Shared.GameStates;
-using Robust.Shared.Audio;
+using Content.Shared._EE.Supermatter.Monitor;
using Content.Shared.Atmos;
-using Content.Shared.Whitelist;
using Content.Shared.DoAfter;
+using Content.Shared.Radio;
+using Content.Shared.Speech;
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
-namespace Content.Shared.Supermatter.Components;
+namespace Content.Shared._EE.Supermatter.Components;
[RegisterComponent, NetworkedComponent]
public sealed partial class SupermatterComponent : Component
@@ -16,7 +19,13 @@ public sealed partial class SupermatterComponent : Component
/// The SM will only cycle if activated.
///
[DataField]
- public bool Activated = false;
+ public bool Activated = true;
+
+ ///
+ /// The current status of the singularity, used for alert sounds and the monitoring console
+ ///
+ [DataField]
+ public SupermatterStatusType Status = SupermatterStatusType.Inactive;
[DataField]
public string SliverPrototype = "SupermatterSliver";
@@ -26,14 +35,13 @@ public sealed partial class SupermatterComponent : Component
/// If removed - delamination timer is divided by 2.
///
[DataField]
- public bool SliverRemoved = false;
+ public bool SliverRemoved;
public string[] LightningPrototypes =
{
- "Lightning",
- "ChargedLightning",
- "SuperchargedLightning",
- "HyperchargedLightning"
+ "SupermatterLightning",
+ "SupermatterLightningCharged",
+ "SupermatterLightningSupercharged"
};
[DataField]
@@ -51,17 +59,45 @@ public sealed partial class SupermatterComponent : Component
[DataField]
public string CollisionResultPrototype = "Ash";
- [DataField]
- public SoundSpecifier DustSound = new SoundPathSpecifier("/Audio/Effects/Grenades/Supermatter/supermatter_start.ogg");
+ #endregion
+
+ #region Sounds
[DataField]
- public SoundSpecifier CalmSound = new SoundPathSpecifier("/Audio/Supermatter/calm.ogg");
+ public SoundSpecifier DustSound = new SoundPathSpecifier("/Audio/_EE/Supermatter/supermatter.ogg");
[DataField]
- public SoundSpecifier DelamSound = new SoundPathSpecifier("/Audio/Supermatter/delamming.ogg");
+ public SoundSpecifier DistortSound = new SoundPathSpecifier("/Audio/_EE/Supermatter/distort.ogg");
[DataField]
- public SoundSpecifier CurrentSoundLoop = new SoundPathSpecifier("/Audio/Supermatter/calm.ogg");
+ public SoundSpecifier CalmLoopSound = new SoundPathSpecifier("/Audio/_EE/Supermatter/calm.ogg");
+
+ [DataField]
+ public SoundSpecifier DelamLoopSound = new SoundPathSpecifier("/Audio/_EE/Supermatter/delamming.ogg");
+
+ [DataField]
+ public SoundSpecifier CurrentSoundLoop = new SoundPathSpecifier("/Audio/_EE/Supermatter/calm.ogg");
+
+ [DataField]
+ public SoundSpecifier CalmAccent = new SoundCollectionSpecifier("SupermatterAccentNormal");
+
+ [DataField]
+ public SoundSpecifier DelamAccent = new SoundCollectionSpecifier("SupermatterAccentDelam");
+
+ [DataField]
+ public string StatusWarningSound = "SupermatterWarning";
+
+ [DataField]
+ public string StatusDangerSound = "SupermatterDanger";
+
+ [DataField]
+ public string StatusEmergencySound = "SupermatterEmergency";
+
+ [DataField]
+ public string StatusDelamSound = "SupermatterDelaminating";
+
+ [DataField]
+ public string? StatusCurrentSound;
#endregion
@@ -70,6 +106,12 @@ public sealed partial class SupermatterComponent : Component
[DataField]
public float Power;
+ [DataField]
+ public float Temperature;
+
+ [DataField]
+ public float WasteMultiplier;
+
[DataField]
public float MatterPower;
@@ -134,6 +176,12 @@ public sealed partial class SupermatterComponent : Component
[DataField]
public float OxygenReleaseEfficiencyModifier = 0.0031f;
+ ///
+ /// The chance for supermatter lightning to strike random coordinates instead of an entity
+ ///
+ [DataField]
+ public float ZapHitCoordinatesChance = 0.75f;
+
#endregion
#region Timing
@@ -142,43 +190,40 @@ public sealed partial class SupermatterComponent : Component
/// We yell if over 50 damage every YellTimer Seconds
///
[DataField]
- public float YellTimer = 60f;
+ public TimeSpan YellTimer = TimeSpan.Zero;
///
- /// Set to YellTimer at first so it doesnt yell a minute after being hit
+ /// Last time the supermatter's damage was announced
///
[DataField]
- public float YellAccumulator = 60f;
+ public TimeSpan YellLast = TimeSpan.Zero;
///
- /// Timer for delam
+ /// Time when the delamination will occuer
///
[DataField]
- public float DelamTimerAccumulator;
+ public TimeSpan DelamEndTime;
///
- /// Time until delam
+ /// How long it takes in seconds for the supermatter to delaminate after reaching zero integrity
///
[DataField]
- public float DelamTimer = 120f;
+ public float DelamTimer = 30f;
///
- /// The message timer
+ /// Last time a supermatter accent sound was triggered
///
[DataField]
- public float SpeakAccumulator = 60f;
+ public TimeSpan AccentLastTime = TimeSpan.Zero;
+
+ ///
+ /// Minimum time in seconds between supermatter accent sounds
+ ///
+ [DataField]
+ public float AccentMinCooldown = 2f;
[DataField]
- public float UpdateAccumulator = 0f;
-
- [DataField]
- public float UpdateTimer = 1f;
-
- [DataField]
- public float ZapAccumulator = 0f;
-
- [DataField]
- public float ZapTimer = 10f;
+ public TimeSpan ZapLast = TimeSpan.Zero;
#endregion
@@ -213,7 +258,7 @@ public sealed partial class SupermatterComponent : Component
/// Above this value we can get lord singulo and independent mol damage, below it we can heal damage
///
[DataField]
- public float MolePenaltyThreshold = 900f;
+ public float MolePenaltyThreshold = 1800f;
///
/// More moles of gases are harder to heat than fewer, so let's scale heat damage around them
@@ -226,7 +271,19 @@ public sealed partial class SupermatterComponent : Component
/// and delamming into a tesla. Low chance of pyro anomalies, +2 bolts of electricity
///
[DataField]
- public float PowerPenaltyThreshold = 4000f;
+ public float PowerPenaltyThreshold = 5000f;
+
+ ///
+ /// +1 bolt of electricity, TODO: anomaly spawning
+ ///
+ [DataField]
+ public float SeverePowerPenaltyThreshold = 7000f;
+
+ ///
+ /// +1 bolt of electricity
+ ///
+ [DataField]
+ public float CriticalPowerPenaltyThreshold = 9000f;
///
/// Maximum safe operational temperature in degrees Celsius.
@@ -243,14 +300,14 @@ public sealed partial class SupermatterComponent : Component
/// The amount of damage taken
///
[DataField]
- public float Damage = 0f;
+ public float Damage;
///
/// The damage from before this cycle.
/// Used to limit the damage we can take each cycle, and for safe alert.
///
[DataField]
- public float DamageArchived = 0f;
+ public float DamageArchived;
///
/// Is multiplied by ExplosionPoint to cap evironmental damage per cycle
@@ -282,14 +339,26 @@ public sealed partial class SupermatterComponent : Component
[DataField]
public float DamageEmergencyThreshold = 500;
+ ///
+ /// The point at which the SM begins shooting lightning.
+ ///
+ [DataField]
+ public int DamagePenaltyPoint = 550;
+
///
/// The point at which the SM begins delaminating.
///
[DataField]
public int DamageDelaminationPoint = 900;
+ ///
+ /// The point at which the SM begins showing warning signs.
+ ///
[DataField]
- public bool Delamming = false;
+ public int DamageDelamAlertPoint = 300;
+
+ [DataField]
+ public bool Delamming;
[DataField]
public DelamType PreferredDelamType = DelamType.Explosion;
@@ -299,13 +368,13 @@ public sealed partial class SupermatterComponent : Component
#region Announcements
[DataField]
- public string AlertCodeYellowId = "yellow";
+ public bool DelamAnnounced;
[DataField]
- public string AlertCodeDeltaId = "delta";
+ public ProtoId Channel = "Engineering";
[DataField]
- public bool DelamAnnounced = false;
+ public ProtoId ChannelGlobal = "Common";
#endregion
diff --git a/Content.Shared/Supermatter/Components/SupermatterFoodComponent.cs b/Content.Shared/_EE/Supermatter/Components/SupermatterFoodComponent.cs
similarity index 73%
rename from Content.Shared/Supermatter/Components/SupermatterFoodComponent.cs
rename to Content.Shared/_EE/Supermatter/Components/SupermatterFoodComponent.cs
index 9d235a4b4d..2d7ebca607 100644
--- a/Content.Shared/Supermatter/Components/SupermatterFoodComponent.cs
+++ b/Content.Shared/_EE/Supermatter/Components/SupermatterFoodComponent.cs
@@ -1,4 +1,4 @@
-namespace Content.Shared.Supermatter.Components;
+namespace Content.Shared._EE.Supermatter.Components;
[RegisterComponent]
public sealed partial class SupermatterFoodComponent : Component
diff --git a/Content.Shared/Supermatter/Components/SupermatterImmuneComponent.cs b/Content.Shared/_EE/Supermatter/Components/SupermatterImmuneComponent.cs
similarity index 73%
rename from Content.Shared/Supermatter/Components/SupermatterImmuneComponent.cs
rename to Content.Shared/_EE/Supermatter/Components/SupermatterImmuneComponent.cs
index b517115eca..ca6f2701b5 100644
--- a/Content.Shared/Supermatter/Components/SupermatterImmuneComponent.cs
+++ b/Content.Shared/_EE/Supermatter/Components/SupermatterImmuneComponent.cs
@@ -1,6 +1,6 @@
using Robust.Shared.GameStates;
-namespace Content.Shared.Supermatter.Components;
+namespace Content.Shared._EE.Supermatter.Components;
[RegisterComponent, NetworkedComponent]
public sealed partial class SupermatterImmuneComponent : Component
diff --git a/Content.Shared/_EE/Supermatter/Consoles/SharedSupermatterConsoleSystem.cs b/Content.Shared/_EE/Supermatter/Consoles/SharedSupermatterConsoleSystem.cs
new file mode 100644
index 0000000000..088996c3f4
--- /dev/null
+++ b/Content.Shared/_EE/Supermatter/Consoles/SharedSupermatterConsoleSystem.cs
@@ -0,0 +1,3 @@
+namespace Content.Shared._EE.Supermatter.Consoles;
+public abstract partial class SharedSupermatterConsoleSystem : EntitySystem
+{ }
diff --git a/Content.Shared/_EE/Supermatter/Consoles/SupermatterConsoleComponent.cs b/Content.Shared/_EE/Supermatter/Consoles/SupermatterConsoleComponent.cs
new file mode 100644
index 0000000000..d5925b33c6
--- /dev/null
+++ b/Content.Shared/_EE/Supermatter/Consoles/SupermatterConsoleComponent.cs
@@ -0,0 +1,208 @@
+using Content.Shared._EE.Supermatter.Consoles;
+using Content.Shared._EE.Supermatter.Monitor;
+using Content.Shared.Atmos;
+using Robust.Shared.GameStates;
+using Robust.Shared.Map;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared._EE.Supermatter.Components;
+
+[RegisterComponent, NetworkedComponent]
+[Access(typeof(SharedSupermatterConsoleSystem))]
+public sealed partial class SupermatterConsoleComponent : Component
+{
+ ///
+ /// The current entity of interest (selected via the console UI)
+ ///
+ [ViewVariables]
+ public NetEntity? FocusSupermatter;
+}
+
+[Serializable, NetSerializable]
+public struct SupermatterNavMapData
+{
+ ///
+ /// The entity in question
+ ///
+ public NetEntity NetEntity;
+
+ ///
+ /// Location of the entity
+ ///
+ public NetCoordinates NetCoordinates;
+
+ ///
+ /// Populate the supermatter console nav map with a single entity
+ ///
+ public SupermatterNavMapData(NetEntity netEntity, NetCoordinates netCoordinates)
+ {
+ NetEntity = netEntity;
+ NetCoordinates = netCoordinates;
+ }
+}
+
+[Serializable, NetSerializable]
+public struct SupermatterFocusData
+{
+ ///
+ /// Focus entity
+ ///
+ public NetEntity NetEntity;
+
+ ///
+ /// The supermatter's integrity, from 0 to 100
+ ///
+ public float Integrity;
+
+ ///
+ /// The supermatter's power
+ ///
+ public float Power;
+
+ ///
+ /// The supermatter's emitted radiation
+ ///
+ public float Radiation;
+
+ ///
+ /// The supermatter's total absorbed moles
+ ///
+ public float AbsorbedMoles;
+
+ ///
+ /// The supermatter's temperature
+ ///
+ public float Temperature;
+
+ ///
+ /// The supermatter's temperature limit
+ ///
+ public float TemperatureLimit;
+
+ ///
+ /// The supermatter's waste multiplier
+ ///
+ public float WasteMultiplier;
+
+ ///
+ /// The supermatter's absorption ratio
+ ///
+ public float AbsorptionRatio;
+
+ ///
+ /// The supermatter's gas storage
+ ///
+ [DataField]
+ public Dictionary GasStorage;
+
+ ///
+ /// Populates the supermatter console focus entry with supermatter data
+ ///
+ public SupermatterFocusData
+ (NetEntity netEntity,
+ float integrity,
+ float power,
+ float radiation,
+ float absorbedMoles,
+ float temperature,
+ float temperatureLimit,
+ float wasteMultiplier,
+ float absorptionRatio,
+ Dictionary gasStorage)
+ {
+ NetEntity = netEntity;
+ Integrity = integrity;
+ Power = power;
+ Radiation = radiation;
+ AbsorbedMoles = absorbedMoles;
+ Temperature = temperature;
+ TemperatureLimit = temperatureLimit;
+ WasteMultiplier = wasteMultiplier;
+ AbsorptionRatio = absorptionRatio;
+ GasStorage = gasStorage;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class SupermatterConsoleBoundInterfaceState : BoundUserInterfaceState
+{
+ ///
+ /// A list of all supermatters
+ ///
+ public SupermatterConsoleEntry[] Supermatters;
+
+ ///
+ /// Data for the UI focus (if applicable)
+ ///
+ public SupermatterFocusData? FocusData;
+
+ ///
+ /// Sends data from the server to the client to populate the atmos monitoring console UI
+ ///
+ public SupermatterConsoleBoundInterfaceState(SupermatterConsoleEntry[] supermatters, SupermatterFocusData? focusData)
+ {
+ Supermatters = supermatters;
+ FocusData = focusData;
+ }
+}
+
+[Serializable, NetSerializable]
+public struct SupermatterConsoleEntry
+{
+ ///
+ /// The entity in question
+ ///
+ public NetEntity NetEntity;
+
+ ///
+ /// Name of the entity
+ ///
+ public string EntityName;
+
+ ///
+ /// Current alert level
+ ///
+ public SupermatterStatusType EntityStatus;
+
+ ///
+ /// Used to populate the supermatter console UI with data from a single supermatter
+ ///
+ public SupermatterConsoleEntry
+ (NetEntity entity,
+ string entityName,
+ SupermatterStatusType status)
+ {
+ NetEntity = entity;
+ EntityName = entityName;
+ EntityStatus = status;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class SupermatterConsoleFocusChangeMessage : BoundUserInterfaceMessage
+{
+ public NetEntity? FocusSupermatter;
+
+ ///
+ /// Used to inform the server that the specified focus for the atmos monitoring console has been changed by the client
+ ///
+ public SupermatterConsoleFocusChangeMessage(NetEntity? focusSupermatter)
+ {
+ FocusSupermatter = focusSupermatter;
+ }
+}
+
+[NetSerializable, Serializable]
+public enum SupermatterConsoleVisuals
+{
+ ComputerLayerScreen,
+}
+
+///
+/// UI key associated with the supermatter monitoring console
+///
+[Serializable, NetSerializable]
+public enum SupermatterConsoleUiKey
+{
+ Key
+}
diff --git a/Content.Shared/_EE/Supermatter/Monitor/SupermatterStatusType.cs b/Content.Shared/_EE/Supermatter/Monitor/SupermatterStatusType.cs
new file mode 100644
index 0000000000..c43bafea86
--- /dev/null
+++ b/Content.Shared/_EE/Supermatter/Monitor/SupermatterStatusType.cs
@@ -0,0 +1,16 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared._EE.Supermatter.Monitor;
+
+[Serializable, NetSerializable]
+public enum SupermatterStatusType : sbyte
+{
+ Error = -1,
+ Inactive = 0,
+ Normal = 1,
+ Caution = 2,
+ Warning = 3,
+ Danger = 4,
+ Emergency = 5,
+ Delaminating = 6
+}
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/1.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/1.ogg
new file mode 100644
index 0000000000..78bbddad71
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/1.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/10.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/10.ogg
new file mode 100644
index 0000000000..754694f4e6
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/10.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/11.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/11.ogg
new file mode 100644
index 0000000000..f023e527b7
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/11.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/12.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/12.ogg
new file mode 100644
index 0000000000..f04493bb57
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/12.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/13.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/13.ogg
new file mode 100644
index 0000000000..dadbb8cc0d
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/13.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/14.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/14.ogg
new file mode 100644
index 0000000000..27c0f71f94
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/14.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/15.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/15.ogg
new file mode 100644
index 0000000000..e615f22a4a
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/15.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/16.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/16.ogg
new file mode 100644
index 0000000000..1792305868
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/16.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/17.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/17.ogg
new file mode 100644
index 0000000000..f414715b31
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/17.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/18.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/18.ogg
new file mode 100644
index 0000000000..7a5581a2d2
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/18.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/19.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/19.ogg
new file mode 100644
index 0000000000..7b75a2bfea
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/19.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/2.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/2.ogg
new file mode 100644
index 0000000000..9eb1365536
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/2.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/20.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/20.ogg
new file mode 100644
index 0000000000..47875c953e
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/20.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/21.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/21.ogg
new file mode 100644
index 0000000000..a1a22c00a8
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/21.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/22.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/22.ogg
new file mode 100644
index 0000000000..37c155b81d
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/22.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/23.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/23.ogg
new file mode 100644
index 0000000000..bfd667b5ef
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/23.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/24.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/24.ogg
new file mode 100644
index 0000000000..fc11c0bbbe
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/24.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/25.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/25.ogg
new file mode 100644
index 0000000000..f10f38cec2
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/25.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/26.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/26.ogg
new file mode 100644
index 0000000000..6df5c1858f
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/26.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/27.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/27.ogg
new file mode 100644
index 0000000000..3081d86c23
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/27.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/28.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/28.ogg
new file mode 100644
index 0000000000..c3a972460f
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/28.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/29.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/29.ogg
new file mode 100644
index 0000000000..a9ed3f23f7
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/29.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/3.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/3.ogg
new file mode 100644
index 0000000000..8f33395656
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/3.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/30.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/30.ogg
new file mode 100644
index 0000000000..ee8b23adfa
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/30.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/31.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/31.ogg
new file mode 100644
index 0000000000..21839f4c04
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/31.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/32.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/32.ogg
new file mode 100644
index 0000000000..204e2477ca
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/32.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/33.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/33.ogg
new file mode 100644
index 0000000000..2016586382
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/33.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/4.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/4.ogg
new file mode 100644
index 0000000000..ad4faa058b
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/4.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/5.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/5.ogg
new file mode 100644
index 0000000000..29ded5af22
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/5.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/6.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/6.ogg
new file mode 100644
index 0000000000..73ecf956e7
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/6.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/7.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/7.ogg
new file mode 100644
index 0000000000..4aa20b9b7a
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/7.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/8.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/8.ogg
new file mode 100644
index 0000000000..f779bcaca2
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/8.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/9.ogg b/Resources/Audio/_EE/Supermatter/accent/delam/9.ogg
new file mode 100644
index 0000000000..0946bb646d
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/delam/9.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/delam/attributions.yml b/Resources/Audio/_EE/Supermatter/accent/delam/attributions.yml
new file mode 100644
index 0000000000..530ce714c6
--- /dev/null
+++ b/Resources/Audio/_EE/Supermatter/accent/delam/attributions.yml
@@ -0,0 +1,37 @@
+- files:
+ - 1.ogg
+ - 2.ogg
+ - 3.ogg
+ - 4.ogg
+ - 5.ogg
+ - 6.ogg
+ - 7.ogg
+ - 8.ogg
+ - 9.ogg
+ - 10.ogg
+ - 11.ogg
+ - 12.ogg
+ - 13.ogg
+ - 14.ogg
+ - 15.ogg
+ - 16.ogg
+ - 17.ogg
+ - 18.ogg
+ - 19.ogg
+ - 20.ogg
+ - 21.ogg
+ - 22.ogg
+ - 23.ogg
+ - 24.ogg
+ - 25.ogg
+ - 26.ogg
+ - 27.ogg
+ - 28.ogg
+ - 29.ogg
+ - 30.ogg
+ - 31.ogg
+ - 32.ogg
+ - 33.ogg
+ copyright: "Created by actioninja for tgstation13"
+ license: "CC-BY-SA-3.0"
+ source: "https://github.com/tgstation/tgstation/pull/45462"
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/1.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/1.ogg
new file mode 100644
index 0000000000..9c43ffc0a0
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/1.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/10.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/10.ogg
new file mode 100644
index 0000000000..16b46c1f8a
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/10.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/11.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/11.ogg
new file mode 100644
index 0000000000..8a0ae2047f
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/11.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/12.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/12.ogg
new file mode 100644
index 0000000000..eaf34be0a7
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/12.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/13.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/13.ogg
new file mode 100644
index 0000000000..aeb8331a83
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/13.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/14.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/14.ogg
new file mode 100644
index 0000000000..ff4e89f389
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/14.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/15.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/15.ogg
new file mode 100644
index 0000000000..0223a370b7
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/15.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/16.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/16.ogg
new file mode 100644
index 0000000000..1d63c92f4a
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/16.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/17.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/17.ogg
new file mode 100644
index 0000000000..18005458d6
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/17.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/18.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/18.ogg
new file mode 100644
index 0000000000..16a67cea8c
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/18.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/19.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/19.ogg
new file mode 100644
index 0000000000..c1aa8f9298
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/19.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/2.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/2.ogg
new file mode 100644
index 0000000000..f12185c556
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/2.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/20.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/20.ogg
new file mode 100644
index 0000000000..82ea3011b6
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/20.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/21.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/21.ogg
new file mode 100644
index 0000000000..1f2bd4ff92
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/21.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/22.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/22.ogg
new file mode 100644
index 0000000000..2322de2669
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/22.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/23.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/23.ogg
new file mode 100644
index 0000000000..c88747f39a
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/23.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/24.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/24.ogg
new file mode 100644
index 0000000000..98717fc488
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/24.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/25.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/25.ogg
new file mode 100644
index 0000000000..d40654fc33
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/25.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/26.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/26.ogg
new file mode 100644
index 0000000000..d3fffcb79e
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/26.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/27.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/27.ogg
new file mode 100644
index 0000000000..5dd6e174de
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/27.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/28.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/28.ogg
new file mode 100644
index 0000000000..0daa79e059
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/28.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/29.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/29.ogg
new file mode 100644
index 0000000000..b80c4984be
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/29.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/3.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/3.ogg
new file mode 100644
index 0000000000..ca0acb41cd
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/3.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/30.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/30.ogg
new file mode 100644
index 0000000000..9251c034da
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/30.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/31.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/31.ogg
new file mode 100644
index 0000000000..6dfa40b851
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/31.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/32.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/32.ogg
new file mode 100644
index 0000000000..79fb549697
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/32.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/33.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/33.ogg
new file mode 100644
index 0000000000..f640750679
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/33.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/4.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/4.ogg
new file mode 100644
index 0000000000..c8ebf4ddf4
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/4.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/5.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/5.ogg
new file mode 100644
index 0000000000..e4f7d8b22f
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/5.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/6.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/6.ogg
new file mode 100644
index 0000000000..f0453e8ab8
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/6.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/7.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/7.ogg
new file mode 100644
index 0000000000..878adba8fc
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/7.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/8.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/8.ogg
new file mode 100644
index 0000000000..6fedc91aff
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/8.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/accent/normal/9.ogg b/Resources/Audio/_EE/Supermatter/accent/normal/9.ogg
new file mode 100644
index 0000000000..83cdfa7320
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/accent/normal/9.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/calm.ogg b/Resources/Audio/_EE/Supermatter/calm.ogg
new file mode 100644
index 0000000000..dc3102e578
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/calm.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/delamming.ogg b/Resources/Audio/_EE/Supermatter/delamming.ogg
new file mode 100644
index 0000000000..a48878ec42
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/delamming.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/distort.ogg b/Resources/Audio/_EE/Supermatter/distort.ogg
new file mode 100644
index 0000000000..332ff801dd
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/distort.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/lightning.ogg b/Resources/Audio/_EE/Supermatter/lightning.ogg
new file mode 100644
index 0000000000..3621eba423
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/lightning.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/status/bloblarm.ogg b/Resources/Audio/_EE/Supermatter/status/bloblarm.ogg
new file mode 100644
index 0000000000..10050c720f
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/status/bloblarm.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/status/engine_alert1.ogg b/Resources/Audio/_EE/Supermatter/status/engine_alert1.ogg
new file mode 100644
index 0000000000..bb27649bee
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/status/engine_alert1.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/status/engine_alert2.ogg b/Resources/Audio/_EE/Supermatter/status/engine_alert2.ogg
new file mode 100644
index 0000000000..f5b0c924dc
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/status/engine_alert2.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/status/terminal_alert.ogg b/Resources/Audio/_EE/Supermatter/status/terminal_alert.ogg
new file mode 100644
index 0000000000..85255010e4
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/status/terminal_alert.ogg differ
diff --git a/Resources/Audio/_EE/Supermatter/supermatter.ogg b/Resources/Audio/_EE/Supermatter/supermatter.ogg
new file mode 100644
index 0000000000..0e9abf3ad8
Binary files /dev/null and b/Resources/Audio/_EE/Supermatter/supermatter.ogg differ
diff --git a/Resources/Locale/en-US/_EE/supermatter/supermatter-console.ftl b/Resources/Locale/en-US/_EE/supermatter/supermatter-console.ftl
new file mode 100644
index 0000000000..fbf1d4fbfe
--- /dev/null
+++ b/Resources/Locale/en-US/_EE/supermatter/supermatter-console.ftl
@@ -0,0 +1,44 @@
+supermatter-console-window-title = Supermatter Monitoring Console
+supermatter-console-window-station-name = [color=white][font size=14]{$stationName}[/font][/color]
+supermatter-console-window-unknown-location = Unknown location
+supermatter-console-window-no-supermatters = [font size=16][color=white]No supermatter detected[/font]
+
+supermatter-console-window-label-sm = {CAPITALIZE($name)}
+
+supermatter-console-window-label-alert-types = Supermatter status:
+supermatter-console-window-error-status = Error
+supermatter-console-window-inactive-status = Inactive
+supermatter-console-window-normal-status = Normal
+supermatter-console-window-caution-status = Caution
+supermatter-console-window-warning-status = Warning
+supermatter-console-window-danger-status = Danger
+supermatter-console-window-emergency-status = Emergency
+supermatter-console-window-delaminating-status = Delaminating
+
+supermatter-console-window-label-integrity = Integrity:
+supermatter-console-window-label-integrity-bar = {$integrity}%
+
+supermatter-console-window-label-power = Internal Energy:
+supermatter-console-window-label-power-bar = {$power} {$prefix}eV
+
+supermatter-console-window-label-radiation = Radiation Emission:
+supermatter-console-window-label-radiation-bar = {$radiation} rads
+
+supermatter-console-window-label-moles = Absorbed Moles:
+supermatter-console-window-label-moles-bar = {$moles} Moles
+
+supermatter-console-window-label-temperature = Temperature:
+supermatter-console-window-label-temperature-limit = Temperature Limit:
+supermatter-console-window-label-temperature-bar = {$temperature} K
+
+supermatter-console-window-label-waste = Waste Multiplier:
+supermatter-console-window-label-waste-bar = {$waste} x
+
+supermatter-console-window-label-absorption = Absorption Ratio:
+supermatter-console-window-label-absorption-bar = {$absorption}%
+
+supermatter-console-window-label-gas = Unknown gas
+supermatter-console-window-label-gas-bar = {$gas}%
+
+supermatter-console-window-flavor-left = ⚠ Do not approach the crystal
+supermatter-console-window-flavor-right = v1.1
diff --git a/Resources/Locale/en-US/supermatter/supermatter.ftl b/Resources/Locale/en-US/_EE/supermatter/supermatter.ftl
similarity index 70%
rename from Resources/Locale/en-US/supermatter/supermatter.ftl
rename to Resources/Locale/en-US/_EE/supermatter/supermatter.ftl
index 2f36560a26..d5719a7e6c 100644
--- a/Resources/Locale/en-US/supermatter/supermatter.ftl
+++ b/Resources/Locale/en-US/_EE/supermatter/supermatter.ftl
@@ -1,6 +1,7 @@
-supermatter-announcer = Automatic Supermatter Engine
supermatter-examine-integrity =
- Its' integrity is [color=yellow]{$integrity}%[/color].
+ Its integrity is [color=yellow]{$integrity}%[/color].
+supermatter-healing =
+ Crystalline hyperstructure returning to safe operating parameters. Integrity: {$integrity}%.
supermatter-warning =
Warning! Crystal hyperstructure integrity faltering! Integrity: {$integrity}%.
supermatter-emergency =
@@ -14,9 +15,16 @@ supermatter-delam-tesla =
supermatter-delam-cascade =
CRYSTAL DELAMINATION IMMINENT! Harmonic frequency limits exceeded, casualty destabilization field could not be engaged!
supermatter-delam-cancel =
- Crystalline hyperstructure returning to safe operating parameters. Failsafe has been Disengaged. Integrity: {$integrity}%.
+ Crystalline hyperstructure returning to safe operating parameters. Failsafe has been disengaged. Integrity: {$integrity}%.
+supermatter-delam-player =
+ You feel reality distort for a moment...
supermatter-seconds-before-delam =
Estimated time before delamination: {$seconds} seconds.
+supermatter-seconds-before-delam-countdown =
+ {$seconds} seconds remain before causality stabilization.
+supermatter-seconds-before-delam-imminent =
+ {$seconds}...
+
supermatter-tamper-begin =
You begin carefully cutting a piece off the supermatter crystal...
supermatter-tamper-end =
@@ -24,3 +32,8 @@ supermatter-tamper-end =
supermatter-announcement-cc-tamper =
Our automatic casualty system has detected that the supermatter crystal structural integrity was compromised by an external force.
Engineering department, report to the supermatter engine immediately.
+
+supermatter-collide =
+ {CAPITALIZE(THE($target))} slams into the {$sm}!
+supermatter-collide-mob =
+ {CAPITALIZE(THE($target))}'s body flashes into dust!
diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl
index d8356dfa2d..6040391bca 100644
--- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl
+++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl
@@ -170,3 +170,6 @@ chat-speech-verb-electricity-2 = buzzes
chat-speech-verb-electricity-3 = screeches
chat-speech-verb-marish = Mars
+
+chat-speech-verb-name-supermatter = Supermatter
+chat-speech-verb-supermatter = states
diff --git a/Resources/Prototypes/Entities/Objects/Misc/supermatter_sliver.yml b/Resources/Prototypes/Entities/Objects/Misc/supermatter_sliver.yml
deleted file mode 100644
index d62935523d..0000000000
--- a/Resources/Prototypes/Entities/Objects/Misc/supermatter_sliver.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-- type: entity
- parent: BaseItem
- id: SupermatterSliver
- name: supermatter sliver
- description: A shard from the station's Supermatter crystal. Highly radioactive.
- components:
- - type: PointLight
- enabled: true
- radius: 3
- energy: 2
- color: "#fff633"
- - type: RadiationSource
- intensity: .75
- - type: Icon
- sprite: Supermatter/supermatter_sliver.rsi
- state: icon
- - type: Sprite
- sprite: Supermatter/supermatter_sliver.rsi
- state: icon
- - type: StealTarget
- stealGroup: SupermatterSliver
- - type: Tag
- tags:
- - HighRiskItem
- - type: SupermatterImmune
diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Supermatter/supermatter.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Supermatter/supermatter.yml
deleted file mode 100644
index 6fc3429600..0000000000
--- a/Resources/Prototypes/Entities/Structures/Power/Generation/Supermatter/supermatter.yml
+++ /dev/null
@@ -1,66 +0,0 @@
-- type: entity
- id: Supermatter
- name: supermatter crystal
- description: A strangely translucent and iridescent crystal.
- placement:
- mode: SnapgridCenter
- components:
- - type: Supermatter
- - type: RadiationSource
- - type: AmbientSound
- range: 5
- volume: 0
- sound:
- path: /Audio/Supermatter/calm.ogg
- - type: Physics
- - type: Speech
- speechSounds: Pai
- - type: Fixtures
- fixtures:
- fix1:
- shape:
- !type:PhysShapeAabb
- bounds: "-0.25,-0.25,0.25,0.25"
- mask:
- - Impassable
- - MidImpassable
- - HighImpassable
- - LowImpassable
- - InteractImpassable
- - Opaque
- layer:
- - MidImpassable
- - HighImpassable
- - BulletImpassable
- - InteractImpassable
- - type: Transform
- anchored: true
- noRot: true
- - type: CollisionWake
- enabled: false
- - type: Clickable
- - type: InteractionOutline
- - type: Sprite
- drawdepth: WallMountedItems
- sprite: Supermatter/supermatter.rsi
- state: supermatter
- - type: Icon
- sprite: Supermatter/supermatter.rsi
- state: supermatter
- - type: PointLight
- enabled: true
- radius: 10
- energy: 5
- color: "#ffe000"
- - type: Explosive
- explosionType: Supermatter
- maxIntensity: 25000
- intensitySlope: 5
- totalIntensity: 25000
- - type: GuideHelp
- guides: [ Supermatter, Power ]
- - type: WarpPoint
- follow: true
- location: supermatter
- - type: SinguloFood
- energy: 10000
\ No newline at end of file
diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml
index 9ba05f14c3..f014194411 100644
--- a/Resources/Prototypes/Objectives/stealTargetGroups.yml
+++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml
@@ -1,12 +1,5 @@
# Traitor single items
-- type: stealTargetGroup
- id: SupermatterSliver
- name: supermatter sliver
- sprite:
- sprite: Supermatter/supermatter_sliver.rsi
- state: icon
-
- type: stealTargetGroup
id: Hypospray
name: hypospray
diff --git a/Resources/Prototypes/_EE/Entities/Effects/lightning.yml b/Resources/Prototypes/_EE/Entities/Effects/lightning.yml
new file mode 100644
index 0000000000..dc706641d9
--- /dev/null
+++ b/Resources/Prototypes/_EE/Entities/Effects/lightning.yml
@@ -0,0 +1,82 @@
+- type: entity
+ parent: BaseLightning
+ id: SupermatterLightning
+ name: supermatter arc
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Sprite
+ sprite: /Textures/Effects/lightning.rsi
+ drawdepth: Effects
+ layers:
+ - state: "yellow_lightning"
+ shader: unshaded
+ - type: Electrified
+ requirePower: false
+ shockDamage: 40
+ - type: PointLight
+ enabled: true
+ color: "#FFFFEC"
+ radius: 3.5
+ softness: 1
+ autoRot: true
+ castShadows: false
+ - type: Lightning
+ canArc: true
+ lightningPrototype: SupermatterLightning
+ - type: Beam
+ sound: /Audio/_EE/Supermatter/lightning.ogg
+ allowSpriteOverwrite: false
+ - type: TimedDespawn
+ lifetime: 1
+
+- type: entity
+ parent: SupermatterLightning
+ id: SupermatterLightningCharged
+ name: charged supermatter arc
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Sprite
+ sprite: /Textures/Effects/lightning.rsi
+ drawdepth: Effects
+ layers:
+ - state: "blue_lightning"
+ shader: unshaded
+ - type: Electrified
+ requirePower: false
+ shockDamage: 60
+ - type: PointLight
+ enabled: true
+ color: "#ECF2FF"
+ radius: 3.5
+ softness: 1
+ autoRot: true
+ castShadows: false
+ - type: Lightning
+ canArc: true
+ lightningPrototype: SupermatterLightningCharged
+
+- type: entity
+ parent: SupermatterLightningCharged
+ id: SupermatterLightningSupercharged
+ name: supercharged supermatter arc
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Sprite
+ sprite: /Textures/Effects/lightning.rsi
+ drawdepth: Effects
+ layers:
+ - state: "red_lightning"
+ shader: unshaded
+ - type: Electrified
+ requirePower: false
+ shockDamage: 80
+ - type: PointLight
+ enabled: true
+ color: "#FFECED"
+ radius: 3.5
+ softness: 1
+ autoRot: true
+ castShadows: false
+ - type: Lightning
+ canArc: true
+ lightningPrototype: SupermatterLightningSupercharged
diff --git a/Resources/Prototypes/_EE/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/_EE/Entities/Objects/Devices/Circuitboards/computer.yml
new file mode 100644
index 0000000000..dcc0204745
--- /dev/null
+++ b/Resources/Prototypes/_EE/Entities/Objects/Devices/Circuitboards/computer.yml
@@ -0,0 +1,10 @@
+- type: entity
+ parent: BaseComputerCircuitboard
+ id: SupermatterComputerCircuitboard
+ name: supermatter monitoring console board
+ description: A computer printed circuit board for a supermatter monitoring console.
+ components:
+ - type: Sprite
+ state: cpu_engineering
+ - type: ComputerBoard
+ prototype: ComputerSupermatter
diff --git a/Resources/Prototypes/_EE/Entities/Objects/Misc/supermatter_sliver.yml b/Resources/Prototypes/_EE/Entities/Objects/Misc/supermatter_sliver.yml
new file mode 100644
index 0000000000..699e8075e1
--- /dev/null
+++ b/Resources/Prototypes/_EE/Entities/Objects/Misc/supermatter_sliver.yml
@@ -0,0 +1,25 @@
+- type: entity
+ parent: BaseItem
+ id: SupermatterSliver
+ name: supermatter sliver
+ description: A shard from the station's Supermatter crystal. Highly radioactive.
+ components:
+ - type: PointLight
+ enabled: true
+ radius: 3
+ energy: 2
+ color: "#fff633"
+ - type: RadiationSource
+ intensity: .75
+ - type: Icon
+ sprite: _EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi
+ state: icon
+ - type: Sprite
+ sprite: _EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi
+ state: icon
+ - type: StealTarget
+ stealGroup: SupermatterSliver
+ - type: Tag
+ tags:
+ - HighRiskItem
+ - type: SupermatterImmune
diff --git a/Resources/Prototypes/_EE/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/_EE/Entities/Structures/Machines/Computers/computers.yml
new file mode 100644
index 0000000000..d0e152389e
--- /dev/null
+++ b/Resources/Prototypes/_EE/Entities/Structures/Machines/Computers/computers.yml
@@ -0,0 +1,57 @@
+- type: entity
+ parent: BaseComputerAiAccess
+ id: ComputerSupermatter
+ name: supermatter monitoring console
+ description: Used to monitor the status of supermatter crystals.
+ components:
+ - type: Computer
+ board: SupermatterComputerCircuitboard
+ - type: Sprite
+ sprite: _EE/Structures/Machines/computers.rsi
+ layers:
+ - map: ["computerLayerBody"]
+ state: computer
+ - map: ["computerLayerKeyboard"]
+ state: generic_keyboard
+ - map: ["computerLayerScreen"]
+ state: supermatter-0
+ - map: ["computerLayerKeys"]
+ state: supermatter_keys
+ - map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
+ state: generic_panel_open
+ - type: PointLight
+ radius: 1.5
+ energy: 1.6
+ color: "#0f704b"
+ - type: GenericVisualizer
+ visuals:
+ enum.ComputerVisuals.Powered:
+ computerLayerScreen:
+ True: { visible: true, shader: unshaded }
+ False: { visible: false }
+ computerLayerKeys:
+ True: { visible: true, shader: unshaded }
+ False: { visible: true, shader: shaded }
+ enum.SupermatterConsoleVisuals.ComputerLayerScreen:
+ computerLayerScreen:
+ 0: { state: supermatter-0 }
+ 1: { state: supermatter-1 }
+ 2: { state: supermatter-2 }
+ 3: { state: supermatter-3 }
+ 4: { state: supermatter-4 }
+ 5: { state: supermatter-5 }
+ 6: { state: supermatter-6 }
+ enum.WiresVisuals.MaintenancePanelState:
+ enum.WiresVisualLayers.MaintenancePanel:
+ True: { visible: false }
+ False: { visible: true }
+ - type: SupermatterConsole
+ - type: ActivatableUI
+ singleUser: true
+ key: enum.SupermatterConsoleUiKey.Key
+ - type: UserInterface
+ interfaces:
+ enum.SupermatterConsoleUiKey.Key:
+ type: SupermatterConsoleBoundUserInterface
+ enum.WiresUiKey.Key:
+ type: WiresBoundUserInterface
diff --git a/Resources/Prototypes/_EE/Entities/Structures/Power/Generation/Supermatter/supermatter.yml b/Resources/Prototypes/_EE/Entities/Structures/Power/Generation/Supermatter/supermatter.yml
new file mode 100644
index 0000000000..e5610b652d
--- /dev/null
+++ b/Resources/Prototypes/_EE/Entities/Structures/Power/Generation/Supermatter/supermatter.yml
@@ -0,0 +1,79 @@
+- type: entity
+ id: Supermatter
+ name: supermatter crystal
+ description: A strangely translucent and iridescent crystal.
+ placement:
+ mode: SnapgridCenter
+ components:
+ - type: Supermatter
+ - type: AtmosDevice
+ - type: RadiationSource
+ - type: AmbientSound
+ range: 20
+ volume: -5
+ sound:
+ path: /Audio/_EE/Supermatter/calm.ogg
+ - type: EmitSoundOnTrigger
+ sound:
+ collection: SupermatterAccentNormal
+ - type: Physics
+ - type: Speech
+ speechSounds: null
+ speechVerb: Supermatter
+ suffixSpeechVerbs:
+ chat-speech-verb-suffix-exclamation-strong: Supermatter
+ chat-speech-verb-suffix-exclamation: Supermatter
+ chat-speech-verb-suffix-question: Supermatter
+ chat-speech-verb-suffix-stutter: Supermatter
+ chat-speech-verb-suffix-mumble: Supermatter
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.25,-0.25,0.25,0.4"
+ mask:
+ - Impassable
+ - MidImpassable
+ - HighImpassable
+ - LowImpassable
+ - InteractImpassable
+ - Opaque
+ layer:
+ - MidImpassable
+ - HighImpassable
+ - BulletImpassable
+ - InteractImpassable
+ - type: Transform
+ anchored: true
+ noRot: true
+ - type: CollisionWake
+ enabled: false
+ - type: Clickable
+ - type: InteractionOutline
+ - type: Sprite
+ sprite: _EE/Structures/Power/Generation/Supermatter/supermatter.rsi
+ state: supermatter
+ drawdepth: Mobs
+ snapCardinals: true
+ offset: -0.015,0.295
+ - type: Icon
+ sprite: _EE/Structures/Power/Generation/Supermatter/supermatter.rsi
+ state: supermatter
+ - type: PointLight
+ enabled: true
+ radius: 10
+ energy: 5
+ color: "#ffe000"
+ - type: Explosive
+ explosionType: Supermatter
+ totalIntensity: 120000
+ intensitySlope: 5
+ maxIntensity: 100
+ - type: GuideHelp
+ guides: [ Supermatter, Power ]
+ - type: WarpPoint
+ follow: true
+ location: supermatter
+ - type: SinguloFood
+ energy: 10000
diff --git a/Resources/Prototypes/_EE/Objectives/stealTargetGroups.yml b/Resources/Prototypes/_EE/Objectives/stealTargetGroups.yml
new file mode 100644
index 0000000000..f10fcee964
--- /dev/null
+++ b/Resources/Prototypes/_EE/Objectives/stealTargetGroups.yml
@@ -0,0 +1,6 @@
+- type: stealTargetGroup
+ id: SupermatterSliver
+ name: steal-target-supermatter-sliver
+ sprite:
+ sprite: _EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi
+ state: icon
diff --git a/Resources/Prototypes/_EE/Objectives/traitor.yml b/Resources/Prototypes/_EE/Objectives/traitor.yml
new file mode 100644
index 0000000000..1e37e996c3
--- /dev/null
+++ b/Resources/Prototypes/_EE/Objectives/traitor.yml
@@ -0,0 +1,11 @@
+# imp - disabled supermatter steal objectives
+#- type: entity
+# parent: BaseTraitorStealObjective
+# id: StealSupermatterSliverObjective
+# components:
+# - type: Objective
+# difficulty: 3.5
+# - type: StealCondition
+# stealGroup: SupermatterSliver
+# objectiveNoOwnerText: objective-condition-steal-smsliver-title
+# descriptionText: objective-condition-steal-smsliver-description
diff --git a/Resources/Prototypes/_EE/SoundCollections/supermatter.yml b/Resources/Prototypes/_EE/SoundCollections/supermatter.yml
new file mode 100644
index 0000000000..1653dbf18c
--- /dev/null
+++ b/Resources/Prototypes/_EE/SoundCollections/supermatter.yml
@@ -0,0 +1,73 @@
+- type: soundCollection
+ id: SupermatterAccentNormal
+ files:
+ - /Audio/_EE/Supermatter/accent/normal/1.ogg
+ - /Audio/_EE/Supermatter/accent/normal/2.ogg
+ - /Audio/_EE/Supermatter/accent/normal/3.ogg
+ - /Audio/_EE/Supermatter/accent/normal/4.ogg
+ - /Audio/_EE/Supermatter/accent/normal/5.ogg
+ - /Audio/_EE/Supermatter/accent/normal/6.ogg
+ - /Audio/_EE/Supermatter/accent/normal/7.ogg
+ - /Audio/_EE/Supermatter/accent/normal/8.ogg
+ - /Audio/_EE/Supermatter/accent/normal/9.ogg
+ - /Audio/_EE/Supermatter/accent/normal/10.ogg
+ - /Audio/_EE/Supermatter/accent/normal/11.ogg
+ - /Audio/_EE/Supermatter/accent/normal/12.ogg
+ - /Audio/_EE/Supermatter/accent/normal/13.ogg
+ - /Audio/_EE/Supermatter/accent/normal/14.ogg
+ - /Audio/_EE/Supermatter/accent/normal/15.ogg
+ - /Audio/_EE/Supermatter/accent/normal/16.ogg
+ - /Audio/_EE/Supermatter/accent/normal/17.ogg
+ - /Audio/_EE/Supermatter/accent/normal/18.ogg
+ - /Audio/_EE/Supermatter/accent/normal/19.ogg
+ - /Audio/_EE/Supermatter/accent/normal/20.ogg
+ - /Audio/_EE/Supermatter/accent/normal/21.ogg
+ - /Audio/_EE/Supermatter/accent/normal/22.ogg
+ - /Audio/_EE/Supermatter/accent/normal/23.ogg
+ - /Audio/_EE/Supermatter/accent/normal/24.ogg
+ - /Audio/_EE/Supermatter/accent/normal/25.ogg
+ - /Audio/_EE/Supermatter/accent/normal/26.ogg
+ - /Audio/_EE/Supermatter/accent/normal/27.ogg
+ - /Audio/_EE/Supermatter/accent/normal/28.ogg
+ - /Audio/_EE/Supermatter/accent/normal/29.ogg
+ - /Audio/_EE/Supermatter/accent/normal/30.ogg
+ - /Audio/_EE/Supermatter/accent/normal/31.ogg
+ - /Audio/_EE/Supermatter/accent/normal/32.ogg
+ - /Audio/_EE/Supermatter/accent/normal/33.ogg
+
+- type: soundCollection
+ id: SupermatterAccentDelam
+ files:
+ - /Audio/_EE/Supermatter/accent/delam/1.ogg
+ - /Audio/_EE/Supermatter/accent/delam/2.ogg
+ - /Audio/_EE/Supermatter/accent/delam/3.ogg
+ - /Audio/_EE/Supermatter/accent/delam/4.ogg
+ - /Audio/_EE/Supermatter/accent/delam/5.ogg
+ - /Audio/_EE/Supermatter/accent/delam/6.ogg
+ - /Audio/_EE/Supermatter/accent/delam/7.ogg
+ - /Audio/_EE/Supermatter/accent/delam/8.ogg
+ - /Audio/_EE/Supermatter/accent/delam/9.ogg
+ - /Audio/_EE/Supermatter/accent/delam/10.ogg
+ - /Audio/_EE/Supermatter/accent/delam/11.ogg
+ - /Audio/_EE/Supermatter/accent/delam/12.ogg
+ - /Audio/_EE/Supermatter/accent/delam/13.ogg
+ - /Audio/_EE/Supermatter/accent/delam/14.ogg
+ - /Audio/_EE/Supermatter/accent/delam/15.ogg
+ - /Audio/_EE/Supermatter/accent/delam/16.ogg
+ - /Audio/_EE/Supermatter/accent/delam/17.ogg
+ - /Audio/_EE/Supermatter/accent/delam/18.ogg
+ - /Audio/_EE/Supermatter/accent/delam/19.ogg
+ - /Audio/_EE/Supermatter/accent/delam/20.ogg
+ - /Audio/_EE/Supermatter/accent/delam/21.ogg
+ - /Audio/_EE/Supermatter/accent/delam/22.ogg
+ - /Audio/_EE/Supermatter/accent/delam/23.ogg
+ - /Audio/_EE/Supermatter/accent/delam/24.ogg
+ - /Audio/_EE/Supermatter/accent/delam/25.ogg
+ - /Audio/_EE/Supermatter/accent/delam/26.ogg
+ - /Audio/_EE/Supermatter/accent/delam/27.ogg
+ - /Audio/_EE/Supermatter/accent/delam/28.ogg
+ - /Audio/_EE/Supermatter/accent/delam/29.ogg
+ - /Audio/_EE/Supermatter/accent/delam/30.ogg
+ - /Audio/_EE/Supermatter/accent/delam/31.ogg
+ - /Audio/_EE/Supermatter/accent/delam/32.ogg
+ - /Audio/_EE/Supermatter/accent/delam/33.ogg
diff --git a/Resources/Prototypes/_EE/Voice/speech_sounds.yml b/Resources/Prototypes/_EE/Voice/speech_sounds.yml
new file mode 100644
index 0000000000..cbd12f3687
--- /dev/null
+++ b/Resources/Prototypes/_EE/Voice/speech_sounds.yml
@@ -0,0 +1,39 @@
+- type: speechSounds
+ id: SupermatterWarning
+ variation: 0
+ saySound:
+ path: /Audio/_EE/Supermatter/status/terminal_alert.ogg
+ askSound:
+ path: /Audio/_EE/Supermatter/status/terminal_alert.ogg
+ exclaimSound:
+ path: /Audio/_EE/Supermatter/status/terminal_alert.ogg
+
+- type: speechSounds
+ id: SupermatterDanger
+ variation: 0
+ saySound:
+ path: /Audio/_EE/Supermatter/status/engine_alert2.ogg
+ askSound:
+ path: /Audio/_EE/Supermatter/status/engine_alert2.ogg
+ exclaimSound:
+ path: /Audio/_EE/Supermatter/status/engine_alert2.ogg
+
+- type: speechSounds
+ id: SupermatterEmergency
+ variation: 0
+ saySound:
+ path: /Audio/_EE/Supermatter/status/engine_alert1.ogg
+ askSound:
+ path: /Audio/_EE/Supermatter/status/engine_alert1.ogg
+ exclaimSound:
+ path: /Audio/_EE/Supermatter/status/engine_alert1.ogg
+
+- type: speechSounds
+ id: SupermatterDelaminating
+ variation: 0
+ saySound:
+ path: /Audio/_EE/Supermatter/status/bloblarm.ogg
+ askSound:
+ path: /Audio/_EE/Supermatter/status/bloblarm.ogg
+ exclaimSound:
+ path: /Audio/_EE/Supermatter/status/bloblarm.ogg
diff --git a/Resources/Prototypes/_EE/Voice/speech_verbs.yml b/Resources/Prototypes/_EE/Voice/speech_verbs.yml
new file mode 100644
index 0000000000..72373bd99f
--- /dev/null
+++ b/Resources/Prototypes/_EE/Voice/speech_verbs.yml
@@ -0,0 +1,5 @@
+- type: speechVerb
+ id: Supermatter
+ name: chat-speech-verb-name-supermatter
+ speechVerbStrings:
+ - chat-speech-verb-supermatter
diff --git a/Resources/Prototypes/_EE/explosion.yml b/Resources/Prototypes/_EE/explosion.yml
new file mode 100644
index 0000000000..2601eb1092
--- /dev/null
+++ b/Resources/Prototypes/_EE/explosion.yml
@@ -0,0 +1,15 @@
+- type: explosion
+ id: Supermatter
+ damagePerIntensity:
+ types:
+ Radiation: 5
+ Heat: 4
+ Blunt: 3
+ Piercing: 3
+ tileBreakChance: [0, 0.5, 1]
+ tileBreakIntensity: [0, 10, 30]
+ tileBreakRerollReduction: 20
+ lightColor: Yellow
+ fireColor: Green
+ texturePath: /Textures/Effects/fire_greyscale.rsi
+ fireStates: 3
diff --git a/Resources/Prototypes/explosion.yml b/Resources/Prototypes/explosion.yml
index 492b752591..4f72067376 100644
--- a/Resources/Prototypes/explosion.yml
+++ b/Resources/Prototypes/explosion.yml
@@ -118,22 +118,6 @@
texturePath: /Textures/Effects/fire.rsi
fireStates: 6
-- type: explosion
- id: Supermatter
- damagePerIntensity:
- types:
- Radiation: 5
- Heat: 4
- Blunt: 3
- Piercing: 3
- tileBreakChance: [0, 0.5, 1]
- tileBreakIntensity: [0, 10, 30]
- tileBreakRerollReduction: 20
- lightColor: Yellow
- fireColor: Green
- texturePath: /Textures/Effects/fire_greyscale.rsi
- fireStates: 3
-
- type: explosion
id: FireBomb
damagePerIntensity:
diff --git a/Resources/Textures/Supermatter/supermatter.rsi/supermatter.png b/Resources/Textures/Supermatter/supermatter.rsi/supermatter.png
deleted file mode 100644
index 0c5747a315..0000000000
Binary files a/Resources/Textures/Supermatter/supermatter.rsi/supermatter.png and /dev/null differ
diff --git a/Resources/Textures/_EE/Interface/Supermatter/supermatter.png b/Resources/Textures/_EE/Interface/Supermatter/supermatter.png
new file mode 100644
index 0000000000..e6abc87717
Binary files /dev/null and b/Resources/Textures/_EE/Interface/Supermatter/supermatter.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/computer.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/computer.png
new file mode 100644
index 0000000000..c608b2bb4d
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/computer.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/generic_keyboard.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/generic_keyboard.png
new file mode 100644
index 0000000000..24428eb4e3
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/generic_keyboard.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/generic_panel_open.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/generic_panel_open.png
new file mode 100644
index 0000000000..ac7f9f6641
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/generic_panel_open.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/meta.json b/Resources/Textures/_EE/Structures/Machines/computers.rsi/meta.json
new file mode 100644
index 0000000000..651e5dbcea
--- /dev/null
+++ b/Resources/Textures/_EE/Structures/Machines/computers.rsi/meta.json
@@ -0,0 +1,73 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Generic sprites taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bd6873fd4dd6a61d7e46f1d75cd4d90f64c40894. generic_panel_open made by Errant, commit https://github.com/space-wizards/space-station-14/pull/32273. Supermatter computer sprites by AftrLite(Github).",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "computer",
+ "directions": 4
+ },
+ {
+ "name": "generic_keyboard",
+ "directions": 4
+ },
+ {
+ "name": "generic_panel_open",
+ "directions": 4
+ },
+ {
+ "name": "supermatter_keys",
+ "directions": 4
+ },
+ {
+ "name": "supermatter-0",
+ "directions": 4
+ },
+ {
+ "name": "supermatter-1",
+ "directions": 4
+ },
+ {
+ "name": "supermatter-2",
+ "directions": 4
+ },
+ {
+ "name": "supermatter-3",
+ "directions": 4
+ },
+ {
+ "name": "supermatter-4",
+ "directions": 4
+ },
+ {
+ "name": "supermatter-5",
+ "directions": 4
+ },
+ {
+ "name": "supermatter-6",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1
+ ]
+ ]
+ }
+ ]
+}
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-0.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-0.png
new file mode 100644
index 0000000000..d8301a4023
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-0.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-1.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-1.png
new file mode 100644
index 0000000000..b74452db52
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-1.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-2.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-2.png
new file mode 100644
index 0000000000..8096e8fc4a
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-2.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-3.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-3.png
new file mode 100644
index 0000000000..fac6045054
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-3.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-4.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-4.png
new file mode 100644
index 0000000000..4da4dc822c
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-4.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-5.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-5.png
new file mode 100644
index 0000000000..21a0631e77
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-5.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-6.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-6.png
new file mode 100644
index 0000000000..15d55084a8
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter-6.png differ
diff --git a/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter_keys.png b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter_keys.png
new file mode 100644
index 0000000000..3fec5a800b
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Machines/computers.rsi/supermatter_keys.png differ
diff --git a/Resources/Textures/Supermatter/supermatter.rsi/meta.json b/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter.rsi/meta.json
similarity index 64%
rename from Resources/Textures/Supermatter/supermatter.rsi/meta.json
rename to Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter.rsi/meta.json
index 6bca0558a8..e174bdfe04 100644
--- a/Resources/Textures/Supermatter/supermatter.rsi/meta.json
+++ b/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter.rsi/meta.json
@@ -1,7 +1,7 @@
{
"version": 1,
- "copyright": "Taken and edited from https://tgstation13.org/wiki/images/a/a4/Supermatter-bg.gif",
"license": "CC-BY-SA-3.0",
+ "copyright": "Taken and edited from https://tgstation13.org/wiki/images/a/a4/Supermatter-bg.gif",
"size": {
"x": 32,
"y": 48
@@ -9,7 +9,13 @@
"states": [
{
"name": "supermatter",
- "delays": [ [ 0.08, 0.08, 0.08 ] ]
+ "delays": [
+ [
+ 0.08,
+ 0.08,
+ 0.08
+ ]
+ ]
}
]
-}
\ No newline at end of file
+}
diff --git a/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter.rsi/supermatter.png b/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter.rsi/supermatter.png
new file mode 100644
index 0000000000..9239d348c2
Binary files /dev/null and b/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter.rsi/supermatter.png differ
diff --git a/Resources/Textures/Supermatter/supermatter_sliver.rsi/icon.png b/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi/icon.png
similarity index 100%
rename from Resources/Textures/Supermatter/supermatter_sliver.rsi/icon.png
rename to Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi/icon.png
diff --git a/Resources/Textures/Supermatter/supermatter_sliver.rsi/meta.json b/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi/meta.json
similarity index 99%
rename from Resources/Textures/Supermatter/supermatter_sliver.rsi/meta.json
rename to Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi/meta.json
index f157223291..68f10cb838 100644
--- a/Resources/Textures/Supermatter/supermatter_sliver.rsi/meta.json
+++ b/Resources/Textures/_EE/Structures/Power/Generation/Supermatter/supermatter_sliver.rsi/meta.json
@@ -1,7 +1,7 @@
{
"version": 1,
- "copyright": "Taken and edited from https://github.com/tgstation/tgstation/blob/master/icons/obj/antags/syndicate_tools.dmi",
"license": "CC-BY-SA-3.0",
+ "copyright": "Taken and edited from https://github.com/tgstation/tgstation/blob/master/icons/obj/antags/syndicate_tools.dmi",
"size": {
"x": 32,
"y": 32
@@ -11,4 +11,4 @@
"name": "icon"
}
]
-}
\ No newline at end of file
+}