]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Remove AlertType and AlertCategory (#27933)
authorNemanja <98561806+EmoGarbage404@users.noreply.github.com>
Fri, 24 May 2024 02:43:04 +0000 (22:43 -0400)
committerGitHub <noreply@github.com>
Fri, 24 May 2024 02:43:04 +0000 (22:43 -0400)
69 files changed:
Content.Client/Alerts/ClientAlertsSystem.cs
Content.Client/Revenant/RevenantSystem.cs
Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs
Content.Client/UserInterface/Systems/Alerts/Widgets/AlertsUI.xaml.cs
Content.IntegrationTests/Tests/GameObjects/Components/Mobs/AlertsComponentTests.cs
Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs
Content.Server/Abilities/Mime/MimePowersComponent.cs
Content.Server/Abilities/Mime/MimePowersSystem.cs
Content.Server/Alert/Commands/ClearAlert.cs
Content.Server/Alert/Commands/ShowAlert.cs
Content.Server/Atmos/Components/BarotraumaComponent.cs
Content.Server/Atmos/Components/FlammableComponent.cs
Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs
Content.Server/Atmos/EntitySystems/FlammableSystem.cs
Content.Server/Body/Components/BloodstreamComponent.cs
Content.Server/Body/Components/InternalsComponent.cs
Content.Server/Body/Components/LungComponent.cs
Content.Server/Body/Systems/BloodstreamSystem.cs
Content.Server/Body/Systems/InternalsSystem.cs
Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs
Content.Server/Clothing/MagbootsSystem.cs
Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs
Content.Server/Ninja/Systems/SpaceNinjaSystem.cs
Content.Server/Revenant/EntitySystems/RevenantSystem.cs
Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs
Content.Server/Silicons/Borgs/BorgSystem.cs
Content.Server/Temperature/Components/TemperatureComponent.cs
Content.Server/Temperature/Systems/TemperatureSystem.cs
Content.Shared/Alert/AlertCategory.cs [deleted file]
Content.Shared/Alert/AlertCategoryPrototype.cs [new file with mode: 0644]
Content.Shared/Alert/AlertKey.cs
Content.Shared/Alert/AlertOrderPrototype.cs
Content.Shared/Alert/AlertPrototype.cs
Content.Shared/Alert/AlertState.cs
Content.Shared/Alert/AlertType.cs [deleted file]
Content.Shared/Alert/AlertsSystem.cs
Content.Shared/Alert/ClickAlertEvent.cs
Content.Shared/Buckle/Components/StrapComponent.cs
Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs
Content.Shared/Clothing/MagbootsComponent.cs
Content.Shared/CombatMode/Pacification/PacificationSystem.cs
Content.Shared/CombatMode/Pacification/PacifiedComponent.cs
Content.Shared/Cuffs/Components/CuffableComponent.cs
Content.Shared/Cuffs/SharedCuffableSystem.cs
Content.Shared/Damage/Components/StaminaComponent.cs
Content.Shared/Damage/Systems/StaminaSystem.cs
Content.Shared/Ensnaring/Components/EnsnareableComponent.cs
Content.Shared/Gravity/SharedGravitySystem.cs
Content.Shared/Mobs/Components/MobThresholdsComponent.cs
Content.Shared/Mobs/Systems/MobThresholdSystem.cs
Content.Shared/Movement/Pulling/Components/PullableComponent.cs
Content.Shared/Movement/Pulling/Components/PullerComponent.cs
Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
Content.Shared/Ninja/Components/SpaceNinjaComponent.cs
Content.Shared/Nutrition/Components/HungerComponent.cs
Content.Shared/Nutrition/Components/ThirstComponent.cs
Content.Shared/Nutrition/EntitySystems/HungerSystem.cs
Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs
Content.Shared/Revenant/Components/RevenantComponent.cs
Content.Shared/Shuttles/Components/PilotComponent.cs
Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs
Content.Shared/StatusEffect/StatusEffectPrototype.cs
Content.Shared/StatusEffect/StatusEffectsSystem.cs
Content.Shared/Weapons/Reflect/ReflectSystem.cs
Content.Tests/Shared/Alert/AlertManagerTests.cs
Content.Tests/Shared/Alert/AlertOrderPrototypeTests.cs
Content.Tests/Shared/Alert/AlertPrototypeTests.cs
Content.Tests/Shared/Alert/ServerAlertsComponentTests.cs
Resources/Prototypes/Alerts/categories.yml [new file with mode: 0644]

index 223bf7876ac07b07eff7243f3f63e91eeda1745b..359c8957f9d772e025eef2eba3d67de531390749 100644 (file)
@@ -91,7 +91,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
         ClearAlerts?.Invoke(this, EventArgs.Empty);
     }
 
-    public void AlertClicked(AlertType alertType)
+    public void AlertClicked(ProtoId<AlertPrototype> alertType)
     {
         RaiseNetworkEvent(new ClickAlertEvent(alertType));
     }
index 49d29d8a5f4cd0d32ee40ba43d49281209485d8e..e050fe35aa2cf408f883f5755754301b7ea291ce 100644 (file)
@@ -1,5 +1,4 @@
 using Content.Client.Alerts;
-using Content.Shared.Alert;
 using Content.Shared.Revenant;
 using Content.Shared.Revenant.Components;
 using Robust.Client.GameObjects;
@@ -42,7 +41,7 @@ public sealed class RevenantSystem : EntitySystem
 
     private void OnUpdateAlert(Entity<RevenantComponent> ent, ref UpdateAlertSpriteEvent args)
     {
-        if (args.Alert.AlertType != AlertType.Essence)
+        if (args.Alert.ID != ent.Comp.EssenceAlert)
             return;
 
         var sprite = args.SpriteViewEnt.Comp;
index 3b85972a9b24e4f1805c988ce621f6dca3d528d2..5c1951203892735c07522d1cceb25ab89615247b 100644 (file)
@@ -7,6 +7,7 @@ using Robust.Client.GameObjects;
 using Robust.Client.Player;
 using Robust.Client.UserInterface;
 using Robust.Client.UserInterface.Controllers;
+using Robust.Shared.Prototypes;
 
 namespace Content.Client.UserInterface.Systems.Alerts;
 
@@ -43,7 +44,7 @@ public sealed class AlertsUIController : UIController, IOnStateEntered<GameplayS
         SyncAlerts();
     }
 
-    private void OnAlertPressed(object? sender, AlertType e)
+    private void OnAlertPressed(object? sender, ProtoId<AlertPrototype> e)
     {
         _alertsSystem?.AlertClicked(e);
     }
index a1a494c47b3301d8b8b195d0cf0186e0ca95fc70..d6a79a81c461b2d67f37e616cd677e10c4c2c21e 100644 (file)
@@ -4,6 +4,7 @@ using Robust.Client.AutoGenerated;
 using Robust.Client.UserInterface.Controls;
 using Robust.Client.UserInterface.XAML;
 using Robust.Shared.Input;
+using Robust.Shared.Prototypes;
 
 namespace Content.Client.UserInterface.Systems.Alerts.Widgets;
 
@@ -21,8 +22,10 @@ public sealed partial class AlertsUI : UIWidget
         RobustXamlLoader.Load(this);
     }
 
-    public void SyncControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype,
-        IReadOnlyDictionary<AlertKey, AlertState> alertStates)
+    public void SyncControls(AlertsSystem alertsSystem,
+        AlertOrderPrototype? alertOrderPrototype,
+        IReadOnlyDictionary<AlertKey,
+        AlertState> alertStates)
     {
         // remove any controls with keys no longer present
         if (SyncRemoveControls(alertStates))
@@ -46,7 +49,7 @@ public sealed partial class AlertsUI : UIWidget
         _alertControls.Clear();
     }
 
-    public event EventHandler<AlertType>? AlertPressed;
+    public event EventHandler<ProtoId<AlertPrototype>>? AlertPressed;
 
     private bool SyncRemoveControls(IReadOnlyDictionary<AlertKey, AlertState> alertStates)
     {
@@ -88,7 +91,7 @@ public sealed partial class AlertsUI : UIWidget
             }
 
             if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) &&
-                existingAlertControl.Alert.AlertType == newAlert.AlertType)
+                existingAlertControl.Alert.ID == newAlert.ID)
             {
                 // key is the same, simply update the existing control severity / cooldown
                 existingAlertControl.SetSeverity(alertState.Severity);
@@ -155,6 +158,6 @@ public sealed partial class AlertsUI : UIWidget
         if (args.Event.Function != EngineKeyFunctions.UIClick)
             return;
 
-        AlertPressed?.Invoke(this, control.Alert.AlertType);
+        AlertPressed?.Invoke(this, control.Alert.ID);
     }
 }
index 1da77ac55892605f0176c60a9ec1a46329265510..ef4e6326cda519dacb71a1585bb6be29564ebbd7 100644 (file)
@@ -5,7 +5,6 @@ using Content.Shared.Alert;
 using Robust.Client.UserInterface;
 using Robust.Server.Player;
 using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
 
 namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
 {
@@ -45,8 +44,8 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
                 Assert.That(alerts, Is.Not.Null);
                 var alertCount = alerts.Count;
 
-                alertsSystem.ShowAlert(playerUid, AlertType.Debug1);
-                alertsSystem.ShowAlert(playerUid, AlertType.Debug2);
+                alertsSystem.ShowAlert(playerUid, "Debug1");
+                alertsSystem.ShowAlert(playerUid, "Debug2");
 
                 Assert.That(alerts, Has.Count.EqualTo(alertCount + 2));
             });
@@ -87,14 +86,14 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
                 // we should be seeing 3 alerts - our health, and the 2 debug alerts, in a specific order.
                 Assert.That(clientAlertsUI.AlertContainer.ChildCount, Is.GreaterThanOrEqualTo(3));
                 var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c);
-                var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray();
-                var expectedIDs = new[] { AlertType.HumanHealth, AlertType.Debug1, AlertType.Debug2 };
+                var alertIDs = alertControls.Select(ac => ac.Alert.ID).ToArray();
+                var expectedIDs = new[] { "HumanHealth", "Debug1", "Debug2" };
                 Assert.That(alertIDs, Is.SupersetOf(expectedIDs));
             });
 
             await server.WaitAssertion(() =>
             {
-                alertsSystem.ClearAlert(playerUid, AlertType.Debug1);
+                alertsSystem.ClearAlert(playerUid, "Debug1");
             });
 
             await pair.RunTicksSync(5);
@@ -104,8 +103,8 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
                 // we should be seeing 2 alerts now because one was cleared
                 Assert.That(clientAlertsUI.AlertContainer.ChildCount, Is.GreaterThanOrEqualTo(2));
                 var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c);
-                var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray();
-                var expectedIDs = new[] { AlertType.HumanHealth, AlertType.Debug2 };
+                var alertIDs = alertControls.Select(ac => ac.Alert.ID).ToArray();
+                var expectedIDs = new[] { "HumanHealth", "Debug2" };
                 Assert.That(alertIDs, Is.SupersetOf(expectedIDs));
             });
 
index 0ad198d6ef2e3e3c02edd329cefd710bc91d5472..74641126aee89b088ca03d6ad2381eb55230070c 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Server.Gravity;
 using Content.Shared.Alert;
+using Content.Shared.Gravity;
 using Robust.Shared.GameObjects;
 
 namespace Content.IntegrationTests.Tests.Gravity
@@ -38,6 +39,7 @@ namespace Content.IntegrationTests.Tests.Gravity
 
             var entityManager = server.ResolveDependency<IEntityManager>();
             var alertsSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AlertsSystem>();
+            var weightlessAlert = SharedGravitySystem.WeightlessAlert;
 
             EntityUid human = default;
 
@@ -56,7 +58,7 @@ namespace Content.IntegrationTests.Tests.Gravity
             await server.WaitAssertion(() =>
             {
                 // No gravity without a gravity generator
-                Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless));
+                Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert));
 
                 generatorUid = entityManager.SpawnEntity("WeightlessGravityGeneratorDummy", entityManager.GetComponent<TransformComponent>(human).Coordinates);
             });
@@ -66,7 +68,7 @@ namespace Content.IntegrationTests.Tests.Gravity
 
             await server.WaitAssertion(() =>
             {
-                Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless), Is.False);
+                Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert), Is.False);
 
                 // This should kill gravity
                 entityManager.DeleteEntity(generatorUid);
@@ -76,7 +78,7 @@ namespace Content.IntegrationTests.Tests.Gravity
 
             await server.WaitAssertion(() =>
             {
-                Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless));
+                Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert));
             });
 
             await pair.RunTicksSync(10);
index fd4fc2c2af9c64195ea2c8c70bdebed4747548db..d56644ed1914c4c08348df09e6d75c6c9b8f1a0a 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Alert;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -47,5 +48,12 @@ namespace Content.Server.Abilities.Mime
         /// </summary>
         [DataField("vowCooldown")]
         public TimeSpan VowCooldown = TimeSpan.FromMinutes(5);
+
+        [DataField]
+        public ProtoId<AlertPrototype> VowAlert = "VowOfSilence";
+
+        [DataField]
+        public ProtoId<AlertPrototype> VowBrokenAlert = "VowBroken";
+
     }
 }
index 629fe993448ef8258313ddb735941982519bc949..f3bf6e703f52efa7b74086140b1a71e35f766c0d 100644 (file)
@@ -1,5 +1,4 @@
 using Content.Server.Popups;
-using Content.Server.Speech.Muting;
 using Content.Shared.Actions;
 using Content.Shared.Actions.Events;
 using Content.Shared.Alert;
@@ -54,7 +53,7 @@ namespace Content.Server.Abilities.Mime
         private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args)
         {
             EnsureComp<MutedComponent>(uid);
-            _alertsSystem.ShowAlert(uid, AlertType.VowOfSilence);
+            _alertsSystem.ShowAlert(uid, component.VowAlert);
             _actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid);
         }
 
@@ -115,8 +114,8 @@ namespace Content.Server.Abilities.Mime
             mimePowers.VowBroken = true;
             mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown;
             RemComp<MutedComponent>(uid);
-            _alertsSystem.ClearAlert(uid, AlertType.VowOfSilence);
-            _alertsSystem.ShowAlert(uid, AlertType.VowBroken);
+            _alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
+            _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
             _actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity);
         }
 
@@ -138,8 +137,8 @@ namespace Content.Server.Abilities.Mime
             mimePowers.ReadyToRepent = false;
             mimePowers.VowBroken = false;
             AddComp<MutedComponent>(uid);
-            _alertsSystem.ClearAlert(uid, AlertType.VowBroken);
-            _alertsSystem.ShowAlert(uid, AlertType.VowOfSilence);
+            _alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
+            _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
             _actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);
         }
     }
index 73a6ca52c70f4d250aadbf04409917af220fe944..2e317de75472e791c89e6ee9daf41a65871dba27 100644 (file)
@@ -40,13 +40,13 @@ namespace Content.Server.Alert.Commands
 
             var alertType = args[0];
             var alertsSystem = _e.System<AlertsSystem>();
-            if (!alertsSystem.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
+            if (!alertsSystem.TryGet(alertType, out var alert))
             {
                 shell.WriteLine("unrecognized alertType " + alertType);
                 return;
             }
 
-            alertsSystem.ClearAlert(attachedEntity, alert.AlertType);
+            alertsSystem.ClearAlert(attachedEntity, alert.ID);
         }
     }
 }
index f37ab23f2fa3cb6a74513961fb59e1c7aaec886d..cae24ff3360419efcb5faf60b37cd9d222a33177 100644 (file)
@@ -41,7 +41,7 @@ namespace Content.Server.Alert.Commands
             var alertType = args[0];
             var severity = args[1];
             var alertsSystem = _e.System<AlertsSystem>();
-            if (!alertsSystem.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
+            if (!alertsSystem.TryGet(alertType, out var alert))
             {
                 shell.WriteLine("unrecognized alertType " + alertType);
                 return;
@@ -53,7 +53,7 @@ namespace Content.Server.Alert.Commands
             }
 
             short? severity1 = sevint == -1 ? null : sevint;
-            alertsSystem.ShowAlert(attachedEntity, alert.AlertType, severity1, null);
+            alertsSystem.ShowAlert(attachedEntity, alert.ID, severity1, null);
         }
     }
 }
index 4e29699872e706e7d296ad5ed8b42d56476c051c..d261c5ab0308d1f46e4fab72e21c6fbbf1c5657c 100644 (file)
@@ -1,5 +1,7 @@
+using Content.Shared.Alert;
 using Content.Shared.Damage;
 using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Atmos.Components
 {
@@ -46,5 +48,13 @@ namespace Content.Server.Atmos.Components
         [ViewVariables(VVAccess.ReadWrite)]
         public bool HasImmunity = false;
 
+        [DataField]
+        public ProtoId<AlertPrototype> HighPressureAlert = "HighPressure";
+
+        [DataField]
+        public ProtoId<AlertPrototype> LowPressureAlert = "LowPressure";
+
+        [DataField]
+        public ProtoId<AlertCategoryPrototype> PressureAlertCategory = "Pressure";
     }
 }
index e00f5efbdc5cf65381d2c6c05b83d4cb16357d08..9ae99a15136e13cec2b2b07dc45a1bab8ce6e9fb 100644 (file)
@@ -1,5 +1,7 @@
+using Content.Shared.Alert;
 using Content.Shared.Damage;
 using Robust.Shared.Physics.Collision.Shapes;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Atmos.Components
 {
@@ -77,5 +79,8 @@ namespace Content.Server.Atmos.Components
         /// </summary>
         [DataField, ViewVariables(VVAccess.ReadWrite)]
         public float FirestackFade = -0.1f;
+
+        [DataField]
+        public ProtoId<AlertPrototype> FireAlert = "Fire";
     }
 }
index 98a5ffa70a861bc144ec695af19d0e05f94d6a4e..ec508790ba875eb27e63896af6859df50ceaedcc 100644 (file)
@@ -245,7 +245,7 @@ namespace Content.Server.Atmos.EntitySystems
                         _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking low pressure damage");
                     }
 
-                    _alertsSystem.ShowAlert(uid, AlertType.LowPressure, 2);
+                    _alertsSystem.ShowAlert(uid, barotrauma.LowPressureAlert, 2);
                 }
                 else if (pressure >= Atmospherics.HazardHighPressure)
                 {
@@ -260,7 +260,7 @@ namespace Content.Server.Atmos.EntitySystems
                         _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking high pressure damage");
                     }
 
-                    _alertsSystem.ShowAlert(uid, AlertType.HighPressure, 2);
+                    _alertsSystem.ShowAlert(uid, barotrauma.HighPressureAlert, 2);
                 }
                 else
                 {
@@ -275,13 +275,13 @@ namespace Content.Server.Atmos.EntitySystems
                     switch (pressure)
                     {
                         case <= Atmospherics.WarningLowPressure:
-                            _alertsSystem.ShowAlert(uid, AlertType.LowPressure, 1);
+                            _alertsSystem.ShowAlert(uid, barotrauma.LowPressureAlert, 1);
                             break;
                         case >= Atmospherics.WarningHighPressure:
-                            _alertsSystem.ShowAlert(uid, AlertType.HighPressure, 1);
+                            _alertsSystem.ShowAlert(uid, barotrauma.HighPressureAlert, 1);
                             break;
                         default:
-                            _alertsSystem.ClearAlertCategory(uid, AlertCategory.Pressure);
+                            _alertsSystem.ClearAlertCategory(uid, barotrauma.PressureAlertCategory);
                             break;
                     }
                 }
index 4a8cbbdc884d7b289dc9c63e7e835c7db79e2f5f..e8721920dd8c917e989c2ebeb4bc7430e4200ff2 100644 (file)
@@ -415,11 +415,11 @@ namespace Content.Server.Atmos.EntitySystems
 
                 if (!flammable.OnFire)
                 {
-                    _alertsSystem.ClearAlert(uid, AlertType.Fire);
+                    _alertsSystem.ClearAlert(uid, flammable.FireAlert);
                     continue;
                 }
 
-                _alertsSystem.ShowAlert(uid, AlertType.Fire);
+                _alertsSystem.ShowAlert(uid, flammable.FireAlert);
 
                 if (flammable.FireStacks > 0)
                 {
index 1d8aa9ffd3d49e3eceaeef3967345c3ef9e41237..a6d2afab2191a02e3d03974138d27f134fbfc254 100644 (file)
@@ -1,5 +1,6 @@
 using Content.Server.Body.Systems;
 using Content.Server.Chemistry.EntitySystems;
+using Content.Shared.Alert;
 using Content.Shared.Chemistry.Components;
 using Content.Shared.Chemistry.Reagent;
 using Content.Shared.Damage;
@@ -171,5 +172,8 @@ namespace Content.Server.Body.Components
         /// </summary>
         [ViewVariables(VVAccess.ReadWrite)]
         public TimeSpan StatusTime;
+
+        [DataField]
+        public ProtoId<AlertPrototype> BleedingAlert = "Bleed";
     }
 }
index 18caab8dcf041a8c2587469b0b14842ddff6f669..098f1789218f327dd411f55e368383e8cd697631 100644 (file)
@@ -1,3 +1,6 @@
+using Content.Shared.Alert;
+using Robust.Shared.Prototypes;
+
 namespace Content.Server.Body.Components
 {
     /// <summary>
@@ -18,5 +21,8 @@ namespace Content.Server.Body.Components
         [ViewVariables(VVAccess.ReadWrite)]
         [DataField]
         public TimeSpan Delay = TimeSpan.FromSeconds(3);
+
+        [DataField]
+        public ProtoId<AlertPrototype> InternalsAlert = "Internals";
     }
 }
index 46600b3020738532fa2ec1cedcd75e37c1889ed1..72af4d9e63a991727ab6a7908e7f0ecdf29dcbbc 100644 (file)
@@ -1,8 +1,8 @@
-using Content.Server.Atmos;
 using Content.Server.Body.Systems;
 using Content.Shared.Alert;
 using Content.Shared.Atmos;
 using Content.Shared.Chemistry.Components;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Body.Components;
 
@@ -33,5 +33,5 @@ public sealed partial class LungComponent : Component
     /// The type of gas this lung needs. Used only for the breathing alerts, not actual metabolism.
     /// </summary>
     [DataField]
-    public AlertType Alert = AlertType.LowOxygen;
+    public ProtoId<AlertPrototype> Alert = "LowOxygen";
 }
index ddeb154e790a90a34b979ba7ec711d8c2398818c..f961307fc6a079911d80be664e27c89875e336a2 100644 (file)
@@ -392,11 +392,11 @@ public sealed class BloodstreamSystem : EntitySystem
         component.BleedAmount = Math.Clamp(component.BleedAmount, 0, component.MaxBleedAmount);
 
         if (component.BleedAmount == 0)
-            _alertsSystem.ClearAlert(uid, AlertType.Bleed);
+            _alertsSystem.ClearAlert(uid, component.BleedingAlert);
         else
         {
             var severity = (short) Math.Clamp(Math.Round(component.BleedAmount, MidpointRounding.ToZero), 0, 10);
-            _alertsSystem.ShowAlert(uid, AlertType.Bleed, severity);
+            _alertsSystem.ShowAlert(uid, component.BleedingAlert, severity);
         }
 
         return true;
index 8afd1c767f66008bdbbdce63e364751ace5e0f4e..c1e1de2baad82749628a3a68d987ac73a578737d 100644 (file)
@@ -144,12 +144,12 @@ public sealed class InternalsSystem : EntitySystem
 
     private void OnInternalsStartup(Entity<InternalsComponent> ent, ref ComponentStartup args)
     {
-        _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
+        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
     }
 
     private void OnInternalsShutdown(Entity<InternalsComponent> ent, ref ComponentShutdown args)
     {
-        _alerts.ClearAlert(ent, AlertType.Internals);
+        _alerts.ClearAlert(ent, ent.Comp.InternalsAlert);
     }
 
     private void OnInhaleLocation(Entity<InternalsComponent> ent, ref InhaleLocationEvent args)
@@ -159,7 +159,7 @@ public sealed class InternalsSystem : EntitySystem
             var gasTank = Comp<GasTankComponent>(ent.Comp.GasTankEntity!.Value);
             args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume);
             // TODO: Should listen to gas tank updates instead I guess?
-            _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
+            _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
         }
     }
     public void DisconnectBreathTool(Entity<InternalsComponent> ent)
@@ -173,7 +173,7 @@ public sealed class InternalsSystem : EntitySystem
             DisconnectTank(ent);
         }
 
-        _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
+        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
     }
 
     public void ConnectBreathTool(Entity<InternalsComponent> ent, EntityUid toolEntity)
@@ -184,7 +184,7 @@ public sealed class InternalsSystem : EntitySystem
         }
 
         ent.Comp.BreathToolEntity = toolEntity;
-        _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
+        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
     }
 
     public void DisconnectTank(InternalsComponent? component)
@@ -196,7 +196,7 @@ public sealed class InternalsSystem : EntitySystem
             _gasTank.DisconnectFromInternals((component.GasTankEntity.Value, tank));
 
         component.GasTankEntity = null;
-        _alerts.ShowAlert(component.Owner, AlertType.Internals, GetSeverity(component));
+        _alerts.ShowAlert(component.Owner, component.InternalsAlert, GetSeverity(component));
     }
 
     public bool TryConnectTank(Entity<InternalsComponent> ent, EntityUid tankEntity)
@@ -208,7 +208,7 @@ public sealed class InternalsSystem : EntitySystem
             _gasTank.DisconnectFromInternals((ent.Comp.GasTankEntity.Value, tank));
 
         ent.Comp.GasTankEntity = tankEntity;
-        _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
+        _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
         return true;
     }
 
index 8d475570ad015dd94d460c87d3fe85336062cad5..40858176bd15bd5c7b5d7b35e795da01e82fe02f 100644 (file)
@@ -10,8 +10,8 @@ public sealed partial class AdjustAlert : ReagentEffect
     /// <summary>
     /// The specific Alert that will be adjusted
     /// </summary>
-    [DataField("alertType", required: true)]
-    public AlertType Type;
+    [DataField(required: true)]
+    public ProtoId<AlertPrototype> AlertType;
 
     /// <summary>
     /// If true, the alert is removed after Time seconds. If Time was not specified the alert is removed immediately.
@@ -42,7 +42,7 @@ public sealed partial class AdjustAlert : ReagentEffect
 
         if (Clear && Time <= 0)
         {
-                alertSys.ClearAlert(args.SolutionEntity, Type);
+                alertSys.ClearAlert(args.SolutionEntity, AlertType);
         }
         else
         {
@@ -52,7 +52,7 @@ public sealed partial class AdjustAlert : ReagentEffect
             if ((ShowCooldown || Clear) && Time > 0)
                 cooldown = (timing.CurTime, timing.CurTime + TimeSpan.FromSeconds(Time));
 
-            alertSys.ShowAlert(args.SolutionEntity, Type, cooldown: cooldown, autoRemove: Clear, showCooldown: ShowCooldown);
+            alertSys.ShowAlert(args.SolutionEntity, AlertType, cooldown: cooldown, autoRemove: Clear, showCooldown: ShowCooldown);
         }
 
     }
index f12558389e3ba494b34f27bc19e75cdea565b566..3838ad168d1baedc6da3215015313f4210253c15 100644 (file)
@@ -29,11 +29,11 @@ public sealed class MagbootsSystem : SharedMagbootsSystem
 
         if (state)
         {
-            _alerts.ShowAlert(parent, AlertType.Magboots);
+            _alerts.ShowAlert(parent, component.MagbootsAlert);
         }
         else
         {
-            _alerts.ClearAlert(parent, AlertType.Magboots);
+            _alerts.ClearAlert(parent, component.MagbootsAlert);
         }
     }
 
index 105a8f9720de9f0264c7503e0f2369024e23d55f..51d3242ce4f2f111c70a2cce23008dba5a9619fb 100644 (file)
@@ -163,8 +163,8 @@ public sealed partial class EnsnareableSystem
     public void UpdateAlert(EntityUid target, EnsnareableComponent component)
     {
         if (!component.IsEnsnared)
-            _alerts.ClearAlert(target, AlertType.Ensnared);
+            _alerts.ClearAlert(target, component.EnsnaredAlert);
         else
-            _alerts.ShowAlert(target, AlertType.Ensnared);
+            _alerts.ShowAlert(target, component.EnsnaredAlert);
     }
 }
index 1dfaf4f3393b91bf620ad4dd7b7aa9480652231d..0c1e88653fa4a421998c8793186375e12bfddd34 100644 (file)
@@ -102,20 +102,23 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
     /// </summary>
     public void SetSuitPowerAlert(EntityUid uid, SpaceNinjaComponent? comp = null)
     {
-        if (!Resolve(uid, ref comp, false) || comp.Deleted || comp.Suit == null)
+        if (!Resolve(uid, ref comp, false))
+            return;
+
+        if (comp.Deleted || comp.Suit == null)
         {
-            _alerts.ClearAlert(uid, AlertType.SuitPower);
+            _alerts.ClearAlert(uid, comp.SuitPowerAlert);
             return;
         }
 
         if (GetNinjaBattery(uid, out _, out var battery))
         {
             var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, battery.CurrentCharge), battery.MaxCharge, 8);
-            _alerts.ShowAlert(uid, AlertType.SuitPower, (short) severity);
+            _alerts.ShowAlert(uid, comp.SuitPowerAlert, (short) severity);
         }
         else
         {
-            _alerts.ClearAlert(uid, AlertType.SuitPower);
+            _alerts.ClearAlert(uid, comp.SuitPowerAlert);
         }
     }
 
index 86be70c41feabd8f853bd3d91557515190bc4a20..c390432f3a1b248bfb860ef51f288dcb17f903ef 100644 (file)
@@ -141,7 +141,7 @@ public sealed partial class RevenantSystem : EntitySystem
         if (TryComp<StoreComponent>(uid, out var store))
             _store.UpdateUserInterface(uid, uid, store);
 
-        _alerts.ShowAlert(uid, AlertType.Essence);
+        _alerts.ShowAlert(uid, component.EssenceAlert);
 
         if (component.Essence <= 0)
         {
index 2b5769881d2701132fed0bd31670c8a92f8268c2..7a19fd13b2e9dbc16ebd1f21035d57edfd7907f8 100644 (file)
@@ -317,7 +317,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
 
         component.SubscribedPilots.Add(entity);
 
-        _alertsSystem.ShowAlert(entity, AlertType.PilotingShuttle);
+        _alertsSystem.ShowAlert(entity, pilotComponent.PilotingAlert);
 
         pilotComponent.Console = uid;
         ActionBlockerSystem.UpdateCanMove(entity);
@@ -339,7 +339,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
         if (!helm.SubscribedPilots.Remove(pilotUid))
             return;
 
-        _alertsSystem.ClearAlert(pilotUid, AlertType.PilotingShuttle);
+        _alertsSystem.ClearAlert(pilotUid, pilotComponent.PilotingAlert);
 
         _popup.PopupEntity(Loc.GetString("shuttle-pilot-end"), pilotUid, pilotUid);
 
index ceab044d4c1c5aace3b1d7b8938dae9feeff6b3f..97adfd00eb4cd4c3d6c20cebdd4116166e541273 100644 (file)
@@ -84,7 +84,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
 
     private void OnMapInit(EntityUid uid, BorgChassisComponent component, MapInitEvent args)
     {
-        UpdateBatteryAlert(uid);
+        UpdateBatteryAlert((uid, component));
         _movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
     }
 
@@ -183,7 +183,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
 
     private void OnPowerCellChanged(EntityUid uid, BorgChassisComponent component, PowerCellChangedEvent args)
     {
-        UpdateBatteryAlert(uid);
+        UpdateBatteryAlert((uid, component));
 
         if (!TryComp<PowerCellDrawComponent>(uid, out var draw))
             return;
@@ -256,12 +256,12 @@ public sealed partial class BorgSystem : SharedBorgSystem
         args.Cancel();
     }
 
-    private void UpdateBatteryAlert(EntityUid uid, PowerCellSlotComponent? slotComponent = null)
+    private void UpdateBatteryAlert(Entity<BorgChassisComponent> ent, PowerCellSlotComponent? slotComponent = null)
     {
-        if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery, slotComponent))
+        if (!_powerCell.TryGetBatteryFromSlot(ent, out var battery, slotComponent))
         {
-            _alerts.ClearAlert(uid, AlertType.BorgBattery);
-            _alerts.ShowAlert(uid, AlertType.BorgBatteryNone);
+            _alerts.ClearAlert(ent, ent.Comp.BatteryAlert);
+            _alerts.ShowAlert(ent, ent.Comp.NoBatteryAlert);
             return;
         }
 
@@ -269,13 +269,13 @@ public sealed partial class BorgSystem : SharedBorgSystem
 
         // we make sure 0 only shows if they have absolutely no battery.
         // also account for floating point imprecision
-        if (chargePercent == 0 && _powerCell.HasDrawCharge(uid, cell: slotComponent))
+        if (chargePercent == 0 && _powerCell.HasDrawCharge(ent, cell: slotComponent))
         {
             chargePercent = 1;
         }
 
-        _alerts.ClearAlert(uid, AlertType.BorgBatteryNone);
-        _alerts.ShowAlert(uid, AlertType.BorgBattery, chargePercent);
+        _alerts.ClearAlert(ent, ent.Comp.NoBatteryAlert);
+        _alerts.ShowAlert(ent, ent.Comp.BatteryAlert, chargePercent);
     }
 
     /// <summary>
index ec00a570f96478938c9a2b6bca9b378727bd6790..3bfa12f26938e73251be6554cffada1fee8f46a5 100644 (file)
@@ -1,7 +1,9 @@
 using Content.Server.Temperature.Systems;
+using Content.Shared.Alert;
 using Content.Shared.Atmos;
 using Content.Shared.Damage;
 using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Temperature.Components;
 
@@ -78,4 +80,10 @@ public sealed partial class TemperatureComponent : Component
     /// </summary>
     [DataField]
     public bool TakingDamage = false;
+
+    [DataField]
+    public ProtoId<AlertPrototype> HotAlert = "Hot";
+
+    [DataField]
+    public ProtoId<AlertPrototype> ColdAlert = "Cold";
 }
index 6c9e99e5f3b960dcb6281d8cbe839ff924727754..23c8cb6783f13826f345f2e49e986f7314fc3708 100644 (file)
@@ -12,6 +12,7 @@ using Content.Shared.Inventory;
 using Content.Shared.Rejuvenate;
 using Content.Shared.Temperature;
 using Robust.Shared.Physics.Components;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Temperature.Systems;
 
@@ -33,6 +34,9 @@ public sealed class TemperatureSystem : EntitySystem
 
     private float _accumulatedFrametime;
 
+    [ValidatePrototypeId<AlertCategoryPrototype>]
+    public const string TemperatureAlertCategory = "Temperature";
+
     public override void Initialize()
     {
         SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage);
@@ -180,13 +184,13 @@ public sealed class TemperatureSystem : EntitySystem
 
     private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureChangeEvent args)
     {
-        AlertType type;
+        ProtoId<AlertPrototype> type;
         float threshold;
         float idealTemp;
 
         if (!TryComp<TemperatureComponent>(uid, out var temperature))
         {
-            _alerts.ClearAlertCategory(uid, AlertCategory.Temperature);
+            _alerts.ClearAlertCategory(uid, TemperatureAlertCategory);
             return;
         }
 
@@ -203,12 +207,12 @@ public sealed class TemperatureSystem : EntitySystem
 
         if (args.CurrentTemperature <= idealTemp)
         {
-            type = AlertType.Cold;
+            type = temperature.ColdAlert;
             threshold = temperature.ColdDamageThreshold;
         }
         else
         {
-            type = AlertType.Hot;
+            type = temperature.HotAlert;
             threshold = temperature.HeatDamageThreshold;
         }
 
@@ -230,7 +234,7 @@ public sealed class TemperatureSystem : EntitySystem
                 break;
 
             case > 0.66f:
-                _alerts.ClearAlertCategory(uid, AlertCategory.Temperature);
+                _alerts.ClearAlertCategory(uid, TemperatureAlertCategory);
                 break;
         }
     }
diff --git a/Content.Shared/Alert/AlertCategory.cs b/Content.Shared/Alert/AlertCategory.cs
deleted file mode 100644 (file)
index 7450f58..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace Content.Shared.Alert;
-
-/// <summary>
-/// Every category of alert. Corresponds to category field in alert prototypes defined in YML
-/// </summary>
-public enum AlertCategory
-{
-    Pressure,
-    Temperature,
-    Breathing,
-    Buckled,
-    Health,
-    Internals,
-    Stamina,
-    Piloting,
-    Hunger,
-    Thirst,
-    Toxins,
-    Battery
-}
diff --git a/Content.Shared/Alert/AlertCategoryPrototype.cs b/Content.Shared/Alert/AlertCategoryPrototype.cs
new file mode 100644 (file)
index 0000000..7c7d047
--- /dev/null
@@ -0,0 +1,14 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Alert;
+
+/// <summary>
+/// This is a prototype for a category for marking alerts as mutually exclusive.
+/// </summary>
+[Prototype]
+public sealed partial class AlertCategoryPrototype : IPrototype
+{
+    /// <inheritdoc/>
+    [IdDataField]
+    public string ID { get; } = default!;
+}
index c784af4cd48a08ac5b0d1b4ad4b89d48b102f70e..c5c3a7643eca5d56686a2b74794adbaf8503f29f 100644 (file)
@@ -1,5 +1,5 @@
-using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.Manager;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
 
 namespace Content.Shared.Alert;
 
@@ -11,13 +11,13 @@ namespace Content.Shared.Alert;
 [Serializable, NetSerializable]
 public struct AlertKey
 {
-    public AlertType? AlertType { get; private set; } = Alert.AlertType.Error;
-    public readonly AlertCategory? AlertCategory;
+    public ProtoId<AlertPrototype>? AlertType { get; private set; } = default!;
+    public readonly ProtoId<AlertCategoryPrototype>? AlertCategory;
 
     /// NOTE: if the alert has a category you must pass the category for this to work
     /// properly as a key. I.e. if the alert has a category and you pass only the alert type, and you
     /// compare this to another AlertKey that has both the category and the same alert type, it will not consider them equal.
-    public AlertKey(AlertType? alertType, AlertCategory? alertCategory)
+    public AlertKey(ProtoId<AlertPrototype>? alertType, ProtoId<AlertCategoryPrototype>? alertCategory)
     {
         AlertCategory = alertCategory;
         AlertType = alertType;
@@ -49,7 +49,7 @@ public struct AlertKey
     /// <param name="category">alert category, must not be null</param>
     /// <returns>An alert key for the provided alert category. This must only be used for
     /// queries and never storage, as it is lacking an alert type.</returns>
-    public static AlertKey ForCategory(AlertCategory category)
+    public static AlertKey ForCategory(ProtoId<AlertCategoryPrototype> category)
     {
         return new(null, category);
     }
index 8279d592b4bc5d8e446f85d57b168fc8f2a35b14..af4241a27e71c13d3ab75cabb23e73ca5372fe7f 100644 (file)
@@ -7,7 +7,7 @@ namespace Content.Shared.Alert
     /// <summary>
     /// Defines the order of alerts so they show up in a consistent order.
     /// </summary>
-    [Prototype("alertOrder")]
+    [Prototype]
     [DataDefinition]
     public sealed partial class AlertOrderPrototype : IPrototype, IComparer<AlertPrototype>
     {
@@ -15,7 +15,7 @@ namespace Content.Shared.Alert
         [IdDataField]
         public string ID { get; private set; } = default!;
 
-        [DataField("order")]
+        [DataField]
         private (string type, string alert)[] Order
         {
             // why would paul do this to me.
@@ -46,10 +46,10 @@ namespace Content.Shared.Alert
                     switch (type)
                     {
                         case "alertType":
-                            _typeToIdx[Enum.Parse<AlertType>(alert)] = i++;
+                            _typeToIdx[alert] = i++;
                             break;
                         case "category":
-                            _categoryToIdx[Enum.Parse<AlertCategory>(alert)] = i++;
+                            _categoryToIdx[alert] = i++;
                             break;
                         default:
                             throw new ArgumentException();
@@ -58,17 +58,17 @@ namespace Content.Shared.Alert
             }
         }
 
-        private readonly Dictionary<AlertType, int> _typeToIdx = new();
-        private readonly Dictionary<AlertCategory, int> _categoryToIdx = new();
+        private readonly Dictionary<ProtoId<AlertPrototype>, int> _typeToIdx = new();
+        private readonly Dictionary<ProtoId<AlertCategoryPrototype>, int> _categoryToIdx = new();
 
         private int GetOrderIndex(AlertPrototype alert)
         {
-            if (_typeToIdx.TryGetValue(alert.AlertType, out var idx))
+            if (_typeToIdx.TryGetValue(alert.ID, out var idx))
             {
                 return idx;
             }
             if (alert.Category != null &&
-                _categoryToIdx.TryGetValue((AlertCategory) alert.Category, out idx))
+                _categoryToIdx.TryGetValue(alert.Category.Value, out idx))
             {
                 return idx;
             }
@@ -78,20 +78,25 @@ namespace Content.Shared.Alert
 
         public int Compare(AlertPrototype? x, AlertPrototype? y)
         {
-            if ((x == null) && (y == null)) return 0;
-            if (x == null) return 1;
-            if (y == null) return -1;
+            if (x == null && y == null)
+                return 0;
+            if (x == null)
+                return 1;
+            if (y == null)
+                return -1;
             var idx = GetOrderIndex(x);
             var idy = GetOrderIndex(y);
             if (idx == -1 && idy == -1)
             {
                 // break ties by type value
                 // Must cast to int to avoid integer overflow when subtracting (enum's unsigned)
-                return (int)x.AlertType - (int)y.AlertType;
+                return string.Compare(x.ID, y.ID, StringComparison.InvariantCulture);
             }
 
-            if (idx == -1) return 1;
-            if (idy == -1) return -1;
+            if (idx == -1)
+                return 1;
+            if (idy == -1)
+                return -1;
             var result = idx - idy;
             // not strictly necessary (we don't care about ones that go at the same index)
             // but it makes the sort stable
@@ -99,7 +104,7 @@ namespace Content.Shared.Alert
             {
                 // break ties by type value
                 // Must cast to int to avoid integer overflow when subtracting (enum's unsigned)
-                return (int)x.AlertType - (int)y.AlertType;
+                return string.Compare(x.ID, y.ID, StringComparison.InvariantCulture);
             }
 
             return result;
index 248cc00ba4011e0dc387ce40ca2d6cfaac07fc84..f53da27c0dea15d50fec0c4ecd3cdcb347b1ea25 100644 (file)
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
 
-namespace Content.Shared.Alert
+namespace Content.Shared.Alert;
+
+/// <summary>
+/// An alert popup with associated icon, tooltip, and other data.
+/// </summary>
+[Prototype]
+public sealed partial class AlertPrototype : IPrototype
 {
     /// <summary>
-    /// An alert popup with associated icon, tooltip, and other data.
+    /// Type of alert, no 2 alert prototypes should have the same one.
     /// </summary>
-    [Prototype("alert")]
-    public sealed partial class AlertPrototype : IPrototype
-    {
-        [ViewVariables]
-        string IPrototype.ID => AlertType.ToString();
-
-        /// <summary>
-        /// Type of alert, no 2 alert prototypes should have the same one.
-        /// </summary>
-        [IdDataField]
-        public AlertType AlertType { get; private set; }
-
-        /// <summary>
-        /// List of icons to use for this alert. Each entry corresponds to a different severity level, starting from the
-        /// minimum and incrementing upwards. If severities are not supported, the first entry is used.
-        /// </summary>
-        [DataField("icons", required: true)]
-        public List<SpriteSpecifier> Icons = new();
-
-        /// <summary>
-        /// An entity used for displaying the <see cref="Icons"/> in the UI control.
-        /// </summary>
-        [DataField]
-        public EntProtoId AlertViewEntity = "AlertSpriteView";
-
-        /// <summary>
-        /// Name to show in tooltip window. Accepts formatting.
-        /// </summary>
-        [DataField("name")]
-        public string Name { get; private set; } = "";
-
-        /// <summary>
-        /// Description to show in tooltip window. Accepts formatting.
-        /// </summary>
-        [DataField("description")]
-        public string Description { get; private set; } = "";
-
-        /// <summary>
-        /// Category the alert belongs to. Only one alert of a given category
-        /// can be shown at a time. If one is shown while another is already being shown,
-        /// it will be replaced. This can be useful for categories of alerts which should naturally
-        /// replace each other and are mutually exclusive, for example lowpressure / highpressure,
-        /// hot / cold. If left unspecified, the alert will not replace or be replaced by any other alerts.
-        /// </summary>
-        [DataField("category")]
-        public AlertCategory? Category { get; private set; }
-
-        /// <summary>
-        /// Key which is unique w.r.t category semantics (alerts with same category have equal keys,
-        /// alerts with no category have different keys).
-        /// </summary>
-        public AlertKey AlertKey => new(AlertType, Category);
-
-        /// <summary>
-        /// -1 (no effect) unless MaxSeverity is specified. Defaults to 1. Minimum severity level supported by this state.
-        /// </summary>
-        public short MinSeverity => MaxSeverity == -1 ? (short) -1 : _minSeverity;
-
-        [DataField("minSeverity")] private short _minSeverity = 1;
-
-        /// <summary>
-        /// Maximum severity level supported by this state. -1 (default) indicates
-        /// no severity levels are supported by the state.
-        /// </summary>
-        [DataField("maxSeverity")]
-        public short MaxSeverity = -1;
-
-        /// <summary>
-        /// Indicates whether this state support severity levels
-        /// </summary>
-        public bool SupportsSeverity => MaxSeverity != -1;
-
-        /// <summary>
-        /// Defines what to do when the alert is clicked.
-        /// This will always be null on clientside.
-        /// </summary>
-        [DataField("onClick", serverOnly: true)]
-        public IAlertClick? OnClick { get; private set; }
-
-        /// <param name="severity">severity level, if supported by this alert</param>
-        /// <returns>the icon path to the texture for the provided severity level</returns>
-        public SpriteSpecifier GetIcon(short? severity = null)
-        {
-            var minIcons = SupportsSeverity
-                ? MaxSeverity - MinSeverity
-                : 1;
+    [IdDataField]
+    public string ID { get; private set; } = default!;
 
-            if (Icons.Count < minIcons)
-                throw new InvalidOperationException($"Insufficient number of icons given for alert {AlertType}");
+    /// <summary>
+    /// List of icons to use for this alert. Each entry corresponds to a different severity level, starting from the
+    /// minimum and incrementing upwards. If severities are not supported, the first entry is used.
+    /// </summary>
+    [DataField(required: true)]
+    public List<SpriteSpecifier> Icons = new();
 
-            if (!SupportsSeverity)
-                return Icons[0];
+    /// <summary>
+    /// An entity used for displaying the <see cref="Icons"/> in the UI control.
+    /// </summary>
+    [DataField]
+    public EntProtoId AlertViewEntity = "AlertSpriteView";
 
-            if (severity == null)
-            {
-                throw new ArgumentException($"No severity specified but this alert ({AlertKey}) has severity.", nameof(severity));
-            }
+    /// <summary>
+    /// Name to show in tooltip window. Accepts formatting.
+    /// </summary>
+    [DataField]
+    public string Name { get; private set; } = string.Empty;
 
-            if (severity < MinSeverity)
-            {
-                throw new ArgumentOutOfRangeException(nameof(severity), $"Severity below minimum severity in {AlertKey}.");
-            }
+    /// <summary>
+    /// Description to show in tooltip window. Accepts formatting.
+    /// </summary>
+    [DataField]
+    public string Description { get; private set; } = string.Empty;
 
-            if (severity > MaxSeverity)
-            {
-                throw new ArgumentOutOfRangeException(nameof(severity), $"Severity above maximum severity in {AlertKey}.");
-            }
+    /// <summary>
+    /// Category the alert belongs to. Only one alert of a given category
+    /// can be shown at a time. If one is shown while another is already being shown,
+    /// it will be replaced. This can be useful for categories of alerts which should naturally
+    /// replace each other and are mutually exclusive, for example lowpressure / highpressure,
+    /// hot / cold. If left unspecified, the alert will not replace or be replaced by any other alerts.
+    /// </summary>
+    [DataField]
+    public ProtoId<AlertCategoryPrototype>? Category { get; private set; }
+
+    /// <summary>
+    /// Key which is unique w.r.t category semantics (alerts with same category have equal keys,
+    /// alerts with no category have different keys).
+    /// </summary>
+    public AlertKey AlertKey => new(ID, Category);
 
-            return Icons[severity.Value - _minSeverity];
+    /// <summary>
+    /// -1 (no effect) unless MaxSeverity is specified. Defaults to 1. Minimum severity level supported by this state.
+    /// </summary>
+    public short MinSeverity => MaxSeverity == -1 ? (short) -1 : _minSeverity;
+
+    [DataField("minSeverity")] private short _minSeverity = 1;
+
+    /// <summary>
+    /// Maximum severity level supported by this state. -1 (default) indicates
+    /// no severity levels are supported by the state.
+    /// </summary>
+    [DataField]
+    public short MaxSeverity = -1;
+
+    /// <summary>
+    /// Indicates whether this state support severity levels
+    /// </summary>
+    public bool SupportsSeverity => MaxSeverity != -1;
+
+    /// <summary>
+    /// Defines what to do when the alert is clicked.
+    /// This will always be null on clientside.
+    /// </summary>
+    [DataField(serverOnly: true)]
+    public IAlertClick? OnClick { get; private set; }
+
+    /// <param name="severity">severity level, if supported by this alert</param>
+    /// <returns>the icon path to the texture for the provided severity level</returns>
+    public SpriteSpecifier GetIcon(short? severity = null)
+    {
+        var minIcons = SupportsSeverity
+            ? MaxSeverity - MinSeverity
+            : 1;
+
+        if (Icons.Count < minIcons)
+            throw new InvalidOperationException($"Insufficient number of icons given for alert {ID}");
+
+        if (!SupportsSeverity)
+            return Icons[0];
+
+        if (severity == null)
+        {
+            throw new ArgumentException($"No severity specified but this alert ({AlertKey}) has severity.", nameof(severity));
+        }
+
+        if (severity < MinSeverity)
+        {
+            throw new ArgumentOutOfRangeException(nameof(severity), $"Severity below minimum severity in {AlertKey}.");
         }
+
+        if (severity > MaxSeverity)
+        {
+            throw new ArgumentOutOfRangeException(nameof(severity), $"Severity above maximum severity in {AlertKey}.");
+        }
+
+        return Icons[severity.Value - _minSeverity];
     }
 }
index effd9522036a214713dd117fb0c0807a184923da..d6309f6b4265cd517fd7e9e06511c3f5f305bccc 100644 (file)
@@ -1,3 +1,4 @@
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Alert;
@@ -9,5 +10,5 @@ public struct AlertState
     public (TimeSpan, TimeSpan)? Cooldown;
     public bool AutoRemove;
     public bool ShowCooldown;
-    public AlertType Type;
+    public ProtoId<AlertPrototype> Type;
 }
diff --git a/Content.Shared/Alert/AlertType.cs b/Content.Shared/Alert/AlertType.cs
deleted file mode 100644 (file)
index b989b8d..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-namespace Content.Shared.Alert
-{
-    /// <summary>
-    /// Every kind of alert. Corresponds to alertType field in alert prototypes defined in YML
-    /// NOTE: Using byte for a compact encoding when sending this in messages, can upgrade
-    /// to ushort
-    /// </summary>
-    public enum AlertType : byte
-    {
-        Error,
-        LowOxygen,
-        LowNitrogen,
-        LowPressure,
-        HighPressure,
-        Fire,
-        Cold,
-        Hot,
-        Weightless,
-        Stun,
-        Handcuffed,
-        Ensnared,
-        Buckled,
-        HumanCrit,
-        HumanDead,
-        HumanHealth,
-        BorgBattery,
-        BorgBatteryNone,
-        PilotingShuttle,
-        Peckish,
-        Starving,
-        Thirsty,
-        Parched,
-        Stamina,
-        Pulled,
-        Pulling,
-        Magboots,
-        Internals,
-        Toxins,
-        Muted,
-        VowOfSilence,
-        VowBroken,
-        Essence,
-        Corporeal,
-        Bleed,
-        Pacified,
-        Debug1,
-        Debug2,
-        Debug3,
-        Debug4,
-        Debug5,
-        Debug6,
-        SuitPower,
-        BorgHealth,
-        BorgCrit,
-        BorgDead,
-        Deflecting
-    }
-
-}
index 5b888e30c4c72d4ce790c68bf41757c3cad7b40f..83c6fcd0dd74f015d6829092ff9564de895f5107 100644 (file)
@@ -11,7 +11,7 @@ public abstract class AlertsSystem : EntitySystem
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IGameTiming _timing = default!;
 
-    private FrozenDictionary<AlertType, AlertPrototype> _typeToAlert = default!;
+    private FrozenDictionary<ProtoId<AlertPrototype>, AlertPrototype> _typeToAlert = default!;
 
     public IReadOnlyDictionary<AlertKey, AlertState>? GetActiveAlerts(EntityUid euid)
     {
@@ -20,23 +20,23 @@ public abstract class AlertsSystem : EntitySystem
             : null;
     }
 
-    public short GetSeverityRange(AlertType alertType)
+    public short GetSeverityRange(ProtoId<AlertPrototype> alertType)
     {
         var minSeverity = _typeToAlert[alertType].MinSeverity;
         return (short)MathF.Max(minSeverity,_typeToAlert[alertType].MaxSeverity - minSeverity);
     }
 
-    public short GetMaxSeverity(AlertType alertType)
+    public short GetMaxSeverity(ProtoId<AlertPrototype> alertType)
     {
         return _typeToAlert[alertType].MaxSeverity;
     }
 
-    public short GetMinSeverity(AlertType alertType)
+    public short GetMinSeverity(ProtoId<AlertPrototype> alertType)
     {
         return _typeToAlert[alertType].MinSeverity;
     }
 
-    public bool IsShowingAlert(EntityUid euid, AlertType alertType)
+    public bool IsShowingAlert(EntityUid euid, ProtoId<AlertPrototype> alertType)
     {
         if (!EntityManager.TryGetComponent(euid, out AlertsComponent? alertsComponent))
             return false;
@@ -51,7 +51,7 @@ public abstract class AlertsSystem : EntitySystem
     }
 
     /// <returns>true iff an alert of the indicated alert category is currently showing</returns>
-    public bool IsShowingAlertCategory(EntityUid euid, AlertCategory alertCategory)
+    public bool IsShowingAlertCategory(EntityUid euid, ProtoId<AlertCategoryPrototype> alertCategory)
     {
         return EntityManager.TryGetComponent(euid, out AlertsComponent? alertsComponent)
                && alertsComponent.Alerts.ContainsKey(AlertKey.ForCategory(alertCategory));
@@ -78,7 +78,7 @@ public abstract class AlertsSystem : EntitySystem
     ///     be erased if there is currently a cooldown for the alert)</param>
     /// <param name="autoRemove">if true, the alert will be removed at the end of the cooldown</param>
     /// <param name="showCooldown">if true, the cooldown will be visibly shown over the alert icon</param>
-    public void ShowAlert(EntityUid euid, AlertType alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null, bool autoRemove = false, bool showCooldown = true )
+    public void ShowAlert(EntityUid euid, ProtoId<AlertPrototype> alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null, bool autoRemove = false, bool showCooldown = true )
     {
         // This should be handled as part of networking.
         if (_timing.ApplyingState)
@@ -131,7 +131,7 @@ public abstract class AlertsSystem : EntitySystem
     /// <summary>
     /// Clear the alert with the given category, if one is currently showing.
     /// </summary>
-    public void ClearAlertCategory(EntityUid euid, AlertCategory category)
+    public void ClearAlertCategory(EntityUid euid, ProtoId<AlertCategoryPrototype> category)
     {
         if(!TryComp(euid, out AlertsComponent? alertsComponent))
             return;
@@ -150,7 +150,7 @@ public abstract class AlertsSystem : EntitySystem
     /// <summary>
     /// Clear the alert of the given type if it is currently showing.
     /// </summary>
-    public void ClearAlert(EntityUid euid, AlertType alertType)
+    public void ClearAlert(EntityUid euid, ProtoId<AlertPrototype> alertType)
     {
         if (_timing.ApplyingState)
             return;
@@ -286,13 +286,13 @@ public abstract class AlertsSystem : EntitySystem
 
     protected virtual void LoadPrototypes()
     {
-        var dict = new Dictionary<AlertType, AlertPrototype>();
+        var dict = new Dictionary<ProtoId<AlertPrototype>, AlertPrototype>();
         foreach (var alert in _prototypeManager.EnumeratePrototypes<AlertPrototype>())
         {
-            if (!dict.TryAdd(alert.AlertType, alert))
+            if (!dict.TryAdd(alert.ID, alert))
             {
                 Log.Error("Found alert with duplicate alertType {0} - all alerts must have" +
-                          " a unique alertType, this one will be skipped", alert.AlertType);
+                          " a unique alertType, this one will be skipped", alert.ID);
             }
         }
 
@@ -303,7 +303,7 @@ public abstract class AlertsSystem : EntitySystem
     /// Tries to get the alert of the indicated type
     /// </summary>
     /// <returns>true if found</returns>
-    public bool TryGet(AlertType alertType, [NotNullWhen(true)] out AlertPrototype? alert)
+    public bool TryGet(ProtoId<AlertPrototype> alertType, [NotNullWhen(true)] out AlertPrototype? alert)
     {
         return _typeToAlert.TryGetValue(alertType, out alert);
     }
index fe7ca97e4c270abd66ff3e27ecac28a33227c201..43dd086b5628bef1148820717e223d6f23927f15 100644 (file)
@@ -1,4 +1,5 @@
-using Robust.Shared.Serialization;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
 
 namespace Content.Shared.Alert;
 
@@ -8,9 +9,9 @@ namespace Content.Shared.Alert;
 [Serializable, NetSerializable]
 public sealed class ClickAlertEvent : EntityEventArgs
 {
-    public readonly AlertType Type;
+    public readonly ProtoId<AlertPrototype> Type;
 
-    public ClickAlertEvent(AlertType alertType)
+    public ClickAlertEvent(ProtoId<AlertPrototype> alertType)
     {
         Type = alertType;
     }
index 72c92ebf84b926d87d8b085017d1f005c14bfa4c..9a19cea0c9a7e351d2222e062824533e71f6bbb0 100644 (file)
@@ -3,6 +3,7 @@ using Content.Shared.Alert;
 using Content.Shared.Whitelist;
 using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Buckle.Components;
@@ -115,7 +116,7 @@ public sealed partial class StrapComponent : Component
     /// </summary>
     [DataField]
     [ViewVariables(VVAccess.ReadWrite)]
-    public AlertType BuckledAlertType = AlertType.Buckled;
+    public ProtoId<AlertPrototype> BuckledAlertType = "Buckled";
 
     /// <summary>
     /// The sum of the sizes of all the buckled entities in this strap
index 0d67473ffee9a7aa5a39551c47dd855e053ba747..4e94c6134b4a73a9dd56795cf771987bb80dfeb8 100644 (file)
@@ -40,6 +40,9 @@ public abstract partial class SharedBuckleSystem
         SubscribeLocalEvent<BuckleComponent, UpdateCanMoveEvent>(OnBuckleUpdateCanMove);
     }
 
+    [ValidatePrototypeId<AlertCategoryPrototype>]
+    public const string BuckledAlertCategory = "Buckled";
+
     private void OnBuckleComponentStartup(EntityUid uid, BuckleComponent component, ComponentStartup args)
     {
         UpdateBuckleStatus(uid, component);
@@ -165,7 +168,7 @@ public abstract partial class SharedBuckleSystem
         }
         else
         {
-            _alerts.ClearAlertCategory(uid, AlertCategory.Buckled);
+            _alerts.ClearAlertCategory(uid, BuckledAlertCategory);
         }
     }
 
index 0d0d59f89f5fff656f78ab3a666842b2251232d7..0d074ff38b69a2a3354751cc4224fcd998efc92f 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Alert;
 using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -16,4 +17,7 @@ public sealed partial class MagbootsComponent : Component
 
     [DataField("on"), AutoNetworkedField]
     public bool On;
+
+    [DataField]
+    public ProtoId<AlertPrototype> MagbootsAlert = "Magboots";
 }
index 6d94c087af6a6d372cf7ddc8ca66a827015f1503..a927e1a6970208551e2f392aaa50e5826019d4e1 100644 (file)
@@ -7,7 +7,6 @@ using Content.Shared.Interaction.Events;
 using Content.Shared.Popups;
 using Content.Shared.Throwing;
 using Content.Shared.Weapons.Ranged.Events;
-using Content.Shared.Weapons.Ranged.Systems;
 using Robust.Shared.Timing;
 
 namespace Content.Shared.CombatMode.Pacification;
@@ -109,7 +108,7 @@ public sealed class PacificationSystem : EntitySystem
             _actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false);
         }
 
-        _alertsSystem.ShowAlert(uid, AlertType.Pacified);
+        _alertsSystem.ShowAlert(uid, component.PacifiedAlert);
     }
 
     private void OnShutdown(EntityUid uid, PacifiedComponent component, ComponentShutdown args)
@@ -121,7 +120,7 @@ public sealed class PacificationSystem : EntitySystem
             _combatSystem.SetCanDisarm(uid, true, combatMode);
 
         _actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, true);
-        _alertsSystem.ClearAlert(uid, AlertType.Pacified);
+        _alertsSystem.ClearAlert(uid, component.PacifiedAlert);
     }
 
     private void OnBeforeThrow(Entity<PacifiedComponent> ent, ref BeforeThrowEvent args)
index 464ef778851c5e053b154f2165a06160c6fbba03..96081e5dc67e73f07ce76ca6911ca9e16d086631 100644 (file)
@@ -1,4 +1,6 @@
+using Content.Shared.Alert;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 
 namespace Content.Shared.CombatMode.Pacification;
 
@@ -42,4 +44,6 @@ public sealed partial class PacifiedComponent : Component
     [DataField]
     public EntityUid? LastAttackedEntity = null;
 
+    [DataField]
+    public ProtoId<AlertPrototype> PacifiedAlert = "Pacified";
 }
index 5da6fa41a5fd033b49b76a12ccedb79cfe880a78..4ddfe1b53ee12f8b1165022adf9e780387d509db 100644 (file)
@@ -1,6 +1,8 @@
+using Content.Shared.Alert;
 using Content.Shared.Damage;
 using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 using Robust.Shared.Utility;
 
@@ -39,6 +41,9 @@ public sealed partial class CuffableComponent : Component
     /// </summary>
     [DataField("canStillInteract"), ViewVariables(VVAccess.ReadWrite)]
     public bool CanStillInteract = true;
+
+    [DataField]
+    public ProtoId<AlertPrototype> CuffedAlert = "Handcuffed";
 }
 
 [Serializable, NetSerializable]
index 0077f5a358efb6cd30ffe62c0932b3a36a38efd6..f0f9a949839a23462c672cbe7e1ee6ecac4ebb76 100644 (file)
@@ -172,9 +172,9 @@ namespace Content.Shared.Cuffs
             _actionBlocker.UpdateCanMove(uid);
 
             if (component.CanStillInteract)
-                _alerts.ClearAlert(uid, AlertType.Handcuffed);
+                _alerts.ClearAlert(uid, component.CuffedAlert);
             else
-                _alerts.ShowAlert(uid, AlertType.Handcuffed);
+                _alerts.ShowAlert(uid, component.CuffedAlert);
 
             var ev = new CuffedStateChangeEvent();
             RaiseLocalEvent(uid, ref ev);
index 5a2fba4970164ebdf0a93a64bad2be81a06a5f6d..14c3f6d9f5381820d379c16db8a402e51e840099 100644 (file)
@@ -1,4 +1,6 @@
+using Content.Shared.Alert;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
 
 namespace Content.Shared.Damage.Components;
@@ -51,4 +53,7 @@ public sealed partial class StaminaComponent : Component
     [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
     [AutoPausedField]
     public TimeSpan NextUpdate = TimeSpan.Zero;
+
+    [DataField]
+    public ProtoId<AlertPrototype> StaminaAlert = "Stamina";
 }
index 840b2e0431183e9e76997aec1472f57461835d6b..1f9a7f1dd841f0e08332ae343e55dea767a7aa9e 100644 (file)
@@ -79,8 +79,7 @@ public sealed partial class StaminaSystem : EntitySystem
         {
             RemCompDeferred<ActiveStaminaComponent>(uid);
         }
-
-        SetStaminaAlert(uid);
+        _alerts.ClearAlert(uid, component.StaminaAlert);
     }
 
     private void OnStartup(EntityUid uid, StaminaComponent component, ComponentStartup args)
@@ -204,13 +203,10 @@ public sealed partial class StaminaSystem : EntitySystem
     private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null)
     {
         if (!Resolve(uid, ref component, false) || component.Deleted)
-        {
-            _alerts.ClearAlert(uid, AlertType.Stamina);
             return;
-        }
 
         var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, component.CritThreshold - component.StaminaDamage), component.CritThreshold, 7);
-        _alerts.ShowAlert(uid, AlertType.Stamina, (short) severity);
+        _alerts.ShowAlert(uid, component.StaminaAlert, (short) severity);
     }
 
     /// <summary>
index 553f6df1c77d394f4df264fa346853981e61eaa8..2536fac4edcc561a5b61467f26a63ad98cee1b60 100644 (file)
@@ -1,5 +1,7 @@
+using Content.Shared.Alert;
 using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Ensnaring.Components;
@@ -40,6 +42,9 @@ public sealed partial class EnsnareableComponent : Component
 
     [DataField("state")]
     public string? State;
+
+    [DataField]
+    public ProtoId<AlertPrototype> EnsnaredAlert = "Ensnared";
 }
 
 [Serializable, NetSerializable]
index 100d2ee74fb8a5ac6a2313974af65275571f4916..df13be51fd4e87ea264a00801d385315828b51c8 100644 (file)
@@ -17,6 +17,9 @@ namespace Content.Shared.Gravity
         [Dependency] private readonly AlertsSystem _alerts = default!;
         [Dependency] private readonly InventorySystem _inventory = default!;
 
+        [ValidatePrototypeId<AlertPrototype>]
+        public const string WeightlessAlert = "Weightless";
+
         public bool IsWeightless(EntityUid uid, PhysicsComponent? body = null, TransformComponent? xform = null)
         {
             Resolve(uid, ref body, false);
@@ -93,11 +96,11 @@ namespace Content.Shared.Gravity
 
                 if (!ev.HasGravity)
                 {
-                    _alerts.ShowAlert(uid, AlertType.Weightless);
+                    _alerts.ShowAlert(uid, WeightlessAlert);
                 }
                 else
                 {
-                    _alerts.ClearAlert(uid, AlertType.Weightless);
+                    _alerts.ClearAlert(uid, WeightlessAlert);
                 }
             }
         }
@@ -106,11 +109,11 @@ namespace Content.Shared.Gravity
         {
             if (IsWeightless(ev.Euid))
             {
-                _alerts.ShowAlert(ev.Euid, AlertType.Weightless);
+                _alerts.ShowAlert(ev.Euid, WeightlessAlert);
             }
             else
             {
-                _alerts.ClearAlert(ev.Euid, AlertType.Weightless);
+                _alerts.ClearAlert(ev.Euid, WeightlessAlert);
             }
         }
 
@@ -118,11 +121,11 @@ namespace Content.Shared.Gravity
         {
             if (IsWeightless(uid))
             {
-                _alerts.ShowAlert(uid, AlertType.Weightless);
+                _alerts.ShowAlert(uid, WeightlessAlert);
             }
             else
             {
-                _alerts.ClearAlert(uid, AlertType.Weightless);
+                _alerts.ClearAlert(uid, WeightlessAlert);
             }
         }
 
index e97d3672a2153480a013a4c067a8c17eb2a08c34..0e37cf9b10e85ca5161763c5bfdccbdea91a29fc 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Alert;
 using Content.Shared.FixedPoint;
 using Content.Shared.Mobs.Systems;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Mobs.Components;
@@ -24,13 +25,16 @@ public sealed partial class MobThresholdsComponent : Component
     /// Used for alternate health alerts (silicons, for example)
     /// </summary>
     [DataField("stateAlertDict")]
-    public Dictionary<MobState, AlertType> StateAlertDict = new()
+    public Dictionary<MobState, ProtoId<AlertPrototype>> StateAlertDict = new()
     {
-        {MobState.Alive, AlertType.HumanHealth},
-        {MobState.Critical, AlertType.HumanCrit},
-        {MobState.Dead, AlertType.HumanDead},
+        {MobState.Alive, "HumanHealth"},
+        {MobState.Critical, "HumanCrit"},
+        {MobState.Dead, "HumanDead"},
     };
 
+    [DataField]
+    public ProtoId<AlertCategoryPrototype> HealthAlertCategory = "Health";
+
     /// <summary>
     /// Whether or not this entity should display damage overlays (robots don't feel pain, black out etc.)
     /// </summary>
@@ -53,19 +57,19 @@ public sealed class MobThresholdsComponentState : ComponentState
 
     public MobState CurrentThresholdState;
 
-    public Dictionary<MobState, AlertType> StateAlertDict = new()
-    {
-        {MobState.Alive, AlertType.HumanHealth},
-        {MobState.Critical, AlertType.HumanCrit},
-        {MobState.Dead, AlertType.HumanDead},
-    };
+    public Dictionary<MobState, ProtoId<AlertPrototype>> StateAlertDict;
 
     public bool ShowOverlays;
 
     public bool AllowRevives;
 
-    public MobThresholdsComponentState(Dictionary<FixedPoint2, MobState> unsortedThresholds, bool triggersAlerts, MobState currentThresholdState,
-        Dictionary<MobState, AlertType> stateAlertDict, bool showOverlays, bool allowRevives)
+    public MobThresholdsComponentState(Dictionary<FixedPoint2, MobState> unsortedThresholds,
+        bool triggersAlerts,
+        MobState currentThresholdState,
+        Dictionary<MobState,
+        ProtoId<AlertPrototype>> stateAlertDict,
+        bool showOverlays,
+        bool allowRevives)
     {
         UnsortedThresholds = unsortedThresholds;
         TriggersAlerts = triggersAlerts;
index 59d9fb4c2390384f8625a3018887923332df3f07..b11de9eac56d874f00a344e42faac1a267ba5adb 100644 (file)
@@ -431,7 +431,7 @@ public sealed class MobThresholdSystem : EntitySystem
     private void MobThresholdShutdown(EntityUid target, MobThresholdsComponent component, ComponentShutdown args)
     {
         if (component.TriggersAlerts)
-            _alerts.ClearAlertCategory(target, AlertCategory.Health);
+            _alerts.ClearAlertCategory(target, component.HealthAlertCategory);
     }
 
     private void OnUpdateMobState(EntityUid target, MobThresholdsComponent component, ref UpdateMobStateEvent args)
index db889e7e3bd9e436f18bca498be84a56a7b1749c..100cd9d6d3e6db70454f6b5ded5ee8b03c7ea6e9 100644 (file)
@@ -1,4 +1,6 @@
+using Content.Shared.Alert;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 
 namespace Content.Shared.Movement.Pulling.Components;
 
@@ -36,4 +38,7 @@ public sealed partial class PullableComponent : Component
     [Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)]
     [AutoNetworkedField, DataField]
     public bool PrevFixedRotation;
+
+    [DataField]
+    public ProtoId<AlertPrototype> PulledAlert = "Pulled";
 }
index 1fc9b731bd5ff8df14c84fa4b0c740ccd38c3f7b..061ec13ed2ab49cac57fe3946005c886fb9405c5 100644 (file)
@@ -1,5 +1,7 @@
-using Content.Shared.Movement.Pulling.Systems;
+using Content.Shared.Alert;
+using Content.Shared.Movement.Pulling.Systems;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
 
 namespace Content.Shared.Movement.Pulling.Components;
@@ -38,4 +40,7 @@ public sealed partial class PullerComponent : Component
     /// </summary>
     [DataField]
     public bool NeedsHands = true;
+
+    [DataField]
+    public ProtoId<AlertPrototype> PullingAlert = "Pulling";
 }
index 81b2fee5695a269a8ec8bdf33d6e129b805d84f0..2781c4952989ef5ff086bc48e3068ca1501fe674 100644 (file)
@@ -223,7 +223,7 @@ public sealed class PullingSystem : EntitySystem
         if (TryComp<PullerComponent>(oldPuller, out var pullerComp))
         {
             var pullerUid = oldPuller.Value;
-            _alertsSystem.ClearAlert(pullerUid, AlertType.Pulling);
+            _alertsSystem.ClearAlert(pullerUid, pullerComp.PullingAlert);
             pullerComp.Pulling = null;
             Dirty(oldPuller.Value, pullerComp);
 
@@ -237,7 +237,7 @@ public sealed class PullingSystem : EntitySystem
         }
 
 
-        _alertsSystem.ClearAlert(pullableUid, AlertType.Pulled);
+        _alertsSystem.ClearAlert(pullableUid, pullableComp.PulledAlert);
     }
 
     public bool IsPulled(EntityUid uid, PullableComponent? component = null)
@@ -460,8 +460,8 @@ public sealed class PullingSystem : EntitySystem
 
         // Messaging
         var message = new PullStartedMessage(pullerUid, pullableUid);
-        _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling);
-        _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled);
+        _alertsSystem.ShowAlert(pullerUid, pullerComp.PullingAlert);
+        _alertsSystem.ShowAlert(pullableUid, pullableComp.PulledAlert);
 
         RaiseLocalEvent(pullerUid, message);
         RaiseLocalEvent(pullableUid, message);
index 0f3bff265cbacce88200c4ae9a931f3e219ac5ce..91c816df5c935cd8ca7b720d375e91e193081b0c 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Alert;
 using Content.Shared.Ninja.Systems;
 using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
@@ -53,4 +54,7 @@ public sealed partial class SpaceNinjaComponent : Component
     /// </summary>
     [DataField]
     public EntProtoId SpiderChargeObjective = "SpiderChargeObjective";
+
+    [DataField]
+    public ProtoId<AlertPrototype> SuitPowerAlert = "SuitPower";
 }
index 9ac82ba283c9dab4b28904b97d8dde938136ad99..79d895ddae66d6c3d7fb1a7bfdea6294e401044e 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Alert;
 using Content.Shared.Damage;
 using Content.Shared.Nutrition.EntitySystems;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
@@ -65,15 +66,18 @@ public sealed partial class HungerComponent : Component
     /// <summary>
     /// A dictionary relating hunger thresholds to corresponding alerts.
     /// </summary>
-    [DataField("hungerThresholdAlerts", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, AlertType>))]
+    [DataField("hungerThresholdAlerts")]
     [AutoNetworkedField]
-    public Dictionary<HungerThreshold, AlertType> HungerThresholdAlerts = new()
+    public Dictionary<HungerThreshold, ProtoId<AlertPrototype>> HungerThresholdAlerts = new()
     {
-        { HungerThreshold.Peckish, AlertType.Peckish },
-        { HungerThreshold.Starving, AlertType.Starving },
-        { HungerThreshold.Dead, AlertType.Starving }
+        { HungerThreshold.Peckish, "Peckish" },
+        { HungerThreshold.Starving, "Starving" },
+        { HungerThreshold.Dead, "Starving" }
     };
 
+    [DataField]
+    public ProtoId<AlertCategoryPrototype> HungerAlertCategory = "Hunger";
+
     /// <summary>
     /// A dictionary relating HungerThreshold to how much they modify <see cref="BaseDecayRate"/>.
     /// </summary>
index 731346401fd9d8b836a002d0891c14818b903e3f..f3ac881361fc5cf0f30e696cc2193db5fb94974a 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Shared.Alert;
 using Content.Shared.Nutrition.EntitySystems;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
 
 namespace Content.Shared.Nutrition.Components;
@@ -56,11 +57,14 @@ public sealed partial class ThirstComponent : Component
         {ThirstThreshold.Dead, 0.0f},
     };
 
-    public static readonly Dictionary<ThirstThreshold, AlertType> ThirstThresholdAlertTypes = new()
+    [DataField]
+    public ProtoId<AlertCategoryPrototype> ThirstyCategory = "Thirst";
+
+    public static readonly Dictionary<ThirstThreshold, ProtoId<AlertPrototype>> ThirstThresholdAlertTypes = new()
     {
-        {ThirstThreshold.Thirsty, AlertType.Thirsty},
-        {ThirstThreshold.Parched, AlertType.Parched},
-        {ThirstThreshold.Dead, AlertType.Parched},
+        {ThirstThreshold.Thirsty, "Thirsty"},
+        {ThirstThreshold.Parched, "Parched"},
+        {ThirstThreshold.Dead, "Parched"},
     };
 }
 
index 4de4e4d5feb05aa25196252f290b730f20f60133..bff15f06ff9c7dd3d222938e129f36e3d9ebf291 100644 (file)
@@ -61,7 +61,7 @@ public sealed class HungerSystem : EntitySystem
 
     private void OnShutdown(EntityUid uid, HungerComponent component, ComponentShutdown args)
     {
-        _alerts.ClearAlertCategory(uid, AlertCategory.Hunger);
+        _alerts.ClearAlertCategory(uid, component.HungerAlertCategory);
     }
 
     private void OnRefreshMovespeed(EntityUid uid, HungerComponent component, RefreshMovementSpeedModifiersEvent args)
@@ -142,7 +142,7 @@ public sealed class HungerSystem : EntitySystem
         }
         else
         {
-            _alerts.ClearAlertCategory(uid, AlertCategory.Hunger);
+            _alerts.ClearAlertCategory(uid, component.HungerAlertCategory);
         }
 
         if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier))
index 8ea7d9140c36bc78edca6bc06baa4c7815879550..205d8d6cde323d52bb7e4959afd6182aba51e54d 100644 (file)
@@ -165,7 +165,7 @@ public sealed class ThirstSystem : EntitySystem
         }
         else
         {
-            _alerts.ClearAlertCategory(uid, AlertCategory.Thirst);
+            _alerts.ClearAlertCategory(uid, component.ThirstyCategory);
         }
 
         switch (component.CurrentThirstThreshold)
index 947c1a4b3fc6a254453963550a85aabe9b20c6d9..d7fb28ef13607b4e8f64b2dc957a19cedae647e4 100644 (file)
@@ -1,4 +1,5 @@
 using System.Numerics;
+using Content.Shared.Alert;
 using Content.Shared.FixedPoint;
 using Content.Shared.Store;
 using Content.Shared.Whitelist;
@@ -200,6 +201,9 @@ public sealed partial class RevenantComponent : Component
     public EntityWhitelist? MalfunctionBlacklist;
     #endregion
 
+    [DataField]
+    public ProtoId<AlertPrototype> EssenceAlert = "Essence";
+
     #region Visualizer
     [DataField("state")]
     public string State = "idle";
index 1a6927cf813df184a580d6a8f1ea82dedc4f7d6e..cb42db4436fc1abe3fed92672d50af155a6f46d1 100644 (file)
@@ -1,7 +1,9 @@
 using System.Numerics;
+using Content.Shared.Alert;
 using Content.Shared.Movement.Systems;
 using Robust.Shared.GameStates;
 using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 
 namespace Content.Shared.Shuttles.Components
@@ -32,6 +34,9 @@ namespace Content.Shared.Shuttles.Components
         [ViewVariables]
         public ShuttleButtons HeldButtons = ShuttleButtons.None;
 
+        [DataField]
+        public ProtoId<AlertPrototype> PilotingAlert = "PilotingShuttle";
+
         public override bool SendOnlyToOwner => true;
     }
 }
index 71d3a7bd166c7b36caa6208f428a9c8405482e61..e1776873da9107f671f19d402911e05b111d53c6 100644 (file)
@@ -1,6 +1,8 @@
-using Content.Shared.Whitelist;
+using Content.Shared.Alert;
+using Content.Shared.Whitelist;
 using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Silicons.Borgs.Components;
@@ -76,6 +78,12 @@ public sealed partial class BorgChassisComponent : Component
     [DataField("noMindState")]
     public string NoMindState = string.Empty;
     #endregion
+
+    [DataField]
+    public ProtoId<AlertPrototype> BatteryAlert = "BorgBattery";
+
+    [DataField]
+    public ProtoId<AlertPrototype> NoBatteryAlert = "BorgBatteryNone";
 }
 
 [Serializable, NetSerializable]
index ae9e26879ebb991b69cda05d14f7ef7525578ebf..8b1f84e4d81a07ece0e7b6cc9fa7891b790e1b3b 100644 (file)
@@ -10,7 +10,7 @@ namespace Content.Shared.StatusEffect
         public string ID { get; private set; } = default!;
 
         [DataField("alert")]
-        public AlertType? Alert { get; private set; }
+        public ProtoId<AlertPrototype>? Alert { get; private set; }
 
         /// <summary>
         ///     Whether a status effect should be able to apply to any entity,
index f3e3e12bd8cc77c16a9d3690671d9f970ab3f5b4..9806077f9bb87f9ff29280a746a20ccd0ee65bca 100644 (file)
@@ -219,7 +219,7 @@ namespace Content.Shared.StatusEffect
         ///     This is mostly for stuns, since Stun and Knockdown share an alert key. Other times this pretty much
         ///     will not be useful.
         /// </remarks>
-        private (TimeSpan, TimeSpan)? GetAlertCooldown(EntityUid uid, AlertType alert, StatusEffectsComponent status)
+        private (TimeSpan, TimeSpan)? GetAlertCooldown(EntityUid uid, ProtoId<AlertPrototype> alert, StatusEffectsComponent status)
         {
             (TimeSpan, TimeSpan)? maxCooldown = null;
             foreach (var kvp in status.ActiveEffects)
index 36dbedb4cb16079fdf63b17c62c4abd6cf7f3783..03ad97edff270497434be613feb1848c71c64ea2 100644 (file)
@@ -42,6 +42,9 @@ public sealed class ReflectSystem : EntitySystem
     [Dependency] private readonly StandingStateSystem _standing = default!;
     [Dependency] private readonly AlertsSystem _alerts = default!;
 
+    [ValidatePrototypeId<AlertPrototype>]
+    private const string DeflectingAlert = "Deflecting";
+
     public override void Initialize()
     {
         base.Initialize();
@@ -296,11 +299,11 @@ public sealed class ReflectSystem : EntitySystem
 
     private void EnableAlert(EntityUid alertee)
     {
-        _alerts.ShowAlert(alertee, AlertType.Deflecting);
+        _alerts.ShowAlert(alertee, DeflectingAlert);
     }
 
     private void DisableAlert(EntityUid alertee)
     {
-        _alerts.ClearAlert(alertee, AlertType.Deflecting);
+        _alerts.ClearAlert(alertee, DeflectingAlert);
     }
 }
index 2d5f6af5a7f1cb871c6cc415f20bc0239b7fe452..c57df63d5b7dbfa2e2254e52b0ebe527e6bc8bce 100644 (file)
@@ -1,6 +1,5 @@
 using System.IO;
 using Content.Client.Alerts;
-using Content.Server.Alert;
 using Content.Shared.Alert;
 using NUnit.Framework;
 using Robust.Shared.GameObjects;
@@ -45,15 +44,15 @@ namespace Content.Tests.Shared.Alert
             prototypeManager.Initialize();
             prototypeManager.LoadFromStream(new StringReader(PROTOTYPES));
 
-            Assert.That(alertsSystem.TryGet(AlertType.LowPressure, out var lowPressure));
-            Assert.That(lowPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
-            Assert.That(alertsSystem.TryGet(AlertType.HighPressure, out var highPressure));
-            Assert.That(highPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
+            Assert.That(alertsSystem.TryGet("LowPressure", out var lowPressure));
+            Assert.That(lowPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
+            Assert.That(alertsSystem.TryGet("HighPressure", out var highPressure));
+            Assert.That(highPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
 
-            Assert.That(alertsSystem.TryGet(AlertType.LowPressure, out lowPressure));
-            Assert.That(lowPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
-            Assert.That(alertsSystem.TryGet(AlertType.HighPressure, out highPressure));
-            Assert.That(highPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
+            Assert.That(alertsSystem.TryGet("LowPressure", out lowPressure));
+            Assert.That(lowPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
+            Assert.That(alertsSystem.TryGet("HighPressure", out highPressure));
+            Assert.That(highPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
         }
     }
 }
index 56f76d46a9277851d2dc07cff5d99ac04ba27435..efcd59acbbb09ecaf712c1c30e43a04c2fc91cd7 100644 (file)
@@ -85,24 +85,24 @@ namespace Content.Tests.Shared.Alert
             var alerts = prototypeManager.EnumeratePrototypes<AlertPrototype>();
 
             // ensure they sort according to our expected criteria
-            var expectedOrder = new List<AlertType>();
-            expectedOrder.Add(AlertType.Handcuffed);
-            expectedOrder.Add(AlertType.Ensnared);
-            expectedOrder.Add(AlertType.HighPressure);
+            var expectedOrder = new List<string>();
+            expectedOrder.Add("Handcuffed");
+            expectedOrder.Add("Ensnared");
+            expectedOrder.Add("HighPressure");
             // stuff with only category + same category ordered by enum value
-            expectedOrder.Add(AlertType.Peckish);
-            expectedOrder.Add(AlertType.Hot);
-            expectedOrder.Add(AlertType.Stun);
-            expectedOrder.Add(AlertType.LowPressure);
-            expectedOrder.Add(AlertType.Cold);
-            // stuff at end of list ordered by enum value
-            expectedOrder.Add(AlertType.Weightless);
-            expectedOrder.Add(AlertType.PilotingShuttle);
+            expectedOrder.Add("Peckish");
+            expectedOrder.Add("Hot");
+            expectedOrder.Add("Stun");
+            expectedOrder.Add("LowPressure");
+            expectedOrder.Add("Cold");
+            // stuff at end of list ordered by ID
+            expectedOrder.Add("PilotingShuttle");
+            expectedOrder.Add("Weightless");
 
             var actual = alerts.ToList();
             actual.Sort(alertOrder);
 
-            Assert.That(actual.Select(a => a.AlertType).ToList(), Is.EqualTo(expectedOrder));
+            Assert.That(actual.Select(a => a.ID).ToList(), Is.EqualTo(expectedOrder));
         }
     }
 }
index d95acb8aff49e58a5e4de8bde0a5f3f2a9487b7c..43ae98b452b49bb9701058d81ce47e8349424504 100644 (file)
@@ -39,9 +39,9 @@ namespace Content.Tests.Shared.Alert
         [Test]
         public void TestAlertKey()
         {
-            Assert.That(new AlertKey(AlertType.HumanHealth, null), Is.Not.EqualTo(AlertKey.ForCategory(AlertCategory.Health)));
-            Assert.That((new AlertKey(null, AlertCategory.Health)), Is.EqualTo(AlertKey.ForCategory(AlertCategory.Health)));
-            Assert.That((new AlertKey(AlertType.Buckled, AlertCategory.Health)), Is.EqualTo(AlertKey.ForCategory(AlertCategory.Health)));
+            Assert.That(new AlertKey("HumanHealth", null), Is.Not.EqualTo(AlertKey.ForCategory("Health")));
+            Assert.That((new AlertKey(null, "Health")), Is.EqualTo(AlertKey.ForCategory("Health")));
+            Assert.That((new AlertKey("Buckled", "Health")), Is.EqualTo(AlertKey.ForCategory("Health")));
         }
 
         [TestCase(0, "/Textures/Interface/Alerts/Human/human.rsi/human0.png")]
index 47ae3ef74a68993ac91b6326438e7a92f68597c4..bcc32e13deeda18ea7cd5bb4843da2015cc94535 100644 (file)
@@ -15,6 +15,9 @@ namespace Content.Tests.Shared.Alert
     public sealed class ServerAlertsComponentTests : ContentUnitTest
     {
         const string PROTOTYPES = @"
+- type: alertCategory
+  id: Pressure
+
 - type: alert
   id: LowPressure
   category: Pressure
@@ -49,10 +52,10 @@ namespace Content.Tests.Shared.Alert
             var alertsComponent = new AlertsComponent();
             alertsComponent = IoCManager.InjectDependencies(alertsComponent);
 
-            Assert.That(entManager.System<AlertsSystem>().TryGet(AlertType.LowPressure, out var lowpressure));
-            Assert.That(entManager.System<AlertsSystem>().TryGet(AlertType.HighPressure, out var highpressure));
+            Assert.That(entManager.System<AlertsSystem>().TryGet("LowPressure", out var lowpressure));
+            Assert.That(entManager.System<AlertsSystem>().TryGet("HighPressure", out var highpressure));
 
-            entManager.System<AlertsSystem>().ShowAlert(alertsComponent.Owner, AlertType.LowPressure, null, null);
+            entManager.System<AlertsSystem>().ShowAlert(alertsComponent.Owner, "LowPressure");
 
             var getty = new ComponentGetState();
             entManager.EventBus.RaiseComponentEvent(alertsComponent, getty);
@@ -60,17 +63,17 @@ namespace Content.Tests.Shared.Alert
             var alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!;
             Assert.That(alertState, Is.Not.Null);
             Assert.That(alertState.Alerts.Count, Is.EqualTo(1));
-            Assert.That(alertState.Alerts.ContainsKey(lowpressure.AlertKey));
+            Assert.That(alertState.Alerts.ContainsKey(lowpressure!.AlertKey));
 
-            entManager.System<AlertsSystem>().ShowAlert(alertsComponent.Owner, AlertType.HighPressure, null, null);
+            entManager.System<AlertsSystem>().ShowAlert(alertsComponent.Owner, "HighPressure");
 
             // Lazy
             entManager.EventBus.RaiseComponentEvent(alertsComponent, getty);
             alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!;
             Assert.That(alertState.Alerts.Count, Is.EqualTo(1));
-            Assert.That(alertState.Alerts.ContainsKey(highpressure.AlertKey));
+            Assert.That(alertState.Alerts.ContainsKey(highpressure!.AlertKey));
 
-            entManager.System<AlertsSystem>().ClearAlertCategory(alertsComponent.Owner, AlertCategory.Pressure);
+            entManager.System<AlertsSystem>().ClearAlertCategory(alertsComponent.Owner, "Pressure");
 
             entManager.EventBus.RaiseComponentEvent(alertsComponent, getty);
             alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!;
diff --git a/Resources/Prototypes/Alerts/categories.yml b/Resources/Prototypes/Alerts/categories.yml
new file mode 100644 (file)
index 0000000..2365422
--- /dev/null
@@ -0,0 +1,35 @@
+- type: alertCategory
+  id: Pressure
+
+- type: alertCategory
+  id: Temperature
+
+- type: alertCategory
+  id: Breathing
+
+- type: alertCategory
+  id: Buckled
+
+- type: alertCategory
+  id: Health
+
+- type: alertCategory
+  id: Internals
+
+- type: alertCategory
+  id: Stamina
+
+- type: alertCategory
+  id: Piloting
+
+- type: alertCategory
+  id: Hunger
+
+- type: alertCategory
+  id: Thirst
+
+- type: alertCategory
+  id: Toxins
+
+- type: alertCategory
+  id: Battery