Remove AlertType and AlertCategory (#27933)

This commit is contained in:
Nemanja
2024-05-23 22:43:04 -04:00
committed by GitHub
parent 594a898260
commit 8a95cb186c
69 changed files with 483 additions and 386 deletions

View File

@@ -91,7 +91,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
ClearAlerts?.Invoke(this, EventArgs.Empty); ClearAlerts?.Invoke(this, EventArgs.Empty);
} }
public void AlertClicked(AlertType alertType) public void AlertClicked(ProtoId<AlertPrototype> alertType)
{ {
RaiseNetworkEvent(new ClickAlertEvent(alertType)); RaiseNetworkEvent(new ClickAlertEvent(alertType));
} }

View File

@@ -1,5 +1,4 @@
using Content.Client.Alerts; using Content.Client.Alerts;
using Content.Shared.Alert;
using Content.Shared.Revenant; using Content.Shared.Revenant;
using Content.Shared.Revenant.Components; using Content.Shared.Revenant.Components;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
@@ -42,7 +41,7 @@ public sealed class RevenantSystem : EntitySystem
private void OnUpdateAlert(Entity<RevenantComponent> ent, ref UpdateAlertSpriteEvent args) private void OnUpdateAlert(Entity<RevenantComponent> ent, ref UpdateAlertSpriteEvent args)
{ {
if (args.Alert.AlertType != AlertType.Essence) if (args.Alert.ID != ent.Comp.EssenceAlert)
return; return;
var sprite = args.SpriteViewEnt.Comp; var sprite = args.SpriteViewEnt.Comp;

View File

@@ -7,6 +7,7 @@ using Robust.Client.GameObjects;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers; using Robust.Client.UserInterface.Controllers;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.Systems.Alerts; namespace Content.Client.UserInterface.Systems.Alerts;
@@ -43,7 +44,7 @@ public sealed class AlertsUIController : UIController, IOnStateEntered<GameplayS
SyncAlerts(); SyncAlerts();
} }
private void OnAlertPressed(object? sender, AlertType e) private void OnAlertPressed(object? sender, ProtoId<AlertPrototype> e)
{ {
_alertsSystem?.AlertClicked(e); _alertsSystem?.AlertClicked(e);
} }

View File

@@ -4,6 +4,7 @@ using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Input; using Robust.Shared.Input;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.Systems.Alerts.Widgets; namespace Content.Client.UserInterface.Systems.Alerts.Widgets;
@@ -21,8 +22,10 @@ public sealed partial class AlertsUI : UIWidget
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
} }
public void SyncControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype, public void SyncControls(AlertsSystem alertsSystem,
IReadOnlyDictionary<AlertKey, AlertState> alertStates) AlertOrderPrototype? alertOrderPrototype,
IReadOnlyDictionary<AlertKey,
AlertState> alertStates)
{ {
// remove any controls with keys no longer present // remove any controls with keys no longer present
if (SyncRemoveControls(alertStates)) if (SyncRemoveControls(alertStates))
@@ -46,7 +49,7 @@ public sealed partial class AlertsUI : UIWidget
_alertControls.Clear(); _alertControls.Clear();
} }
public event EventHandler<AlertType>? AlertPressed; public event EventHandler<ProtoId<AlertPrototype>>? AlertPressed;
private bool SyncRemoveControls(IReadOnlyDictionary<AlertKey, AlertState> alertStates) 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) && 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 // key is the same, simply update the existing control severity / cooldown
existingAlertControl.SetSeverity(alertState.Severity); existingAlertControl.SetSeverity(alertState.Severity);
@@ -155,6 +158,6 @@ public sealed partial class AlertsUI : UIWidget
if (args.Event.Function != EngineKeyFunctions.UIClick) if (args.Event.Function != EngineKeyFunctions.UIClick)
return; return;
AlertPressed?.Invoke(this, control.Alert.AlertType); AlertPressed?.Invoke(this, control.Alert.ID);
} }
} }

View File

@@ -5,7 +5,6 @@ using Content.Shared.Alert;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
{ {
@@ -45,8 +44,8 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
Assert.That(alerts, Is.Not.Null); Assert.That(alerts, Is.Not.Null);
var alertCount = alerts.Count; var alertCount = alerts.Count;
alertsSystem.ShowAlert(playerUid, AlertType.Debug1); alertsSystem.ShowAlert(playerUid, "Debug1");
alertsSystem.ShowAlert(playerUid, AlertType.Debug2); alertsSystem.ShowAlert(playerUid, "Debug2");
Assert.That(alerts, Has.Count.EqualTo(alertCount + 2)); 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. // 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)); Assert.That(clientAlertsUI.AlertContainer.ChildCount, Is.GreaterThanOrEqualTo(3));
var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c); var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c);
var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray(); var alertIDs = alertControls.Select(ac => ac.Alert.ID).ToArray();
var expectedIDs = new[] { AlertType.HumanHealth, AlertType.Debug1, AlertType.Debug2 }; var expectedIDs = new[] { "HumanHealth", "Debug1", "Debug2" };
Assert.That(alertIDs, Is.SupersetOf(expectedIDs)); Assert.That(alertIDs, Is.SupersetOf(expectedIDs));
}); });
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
alertsSystem.ClearAlert(playerUid, AlertType.Debug1); alertsSystem.ClearAlert(playerUid, "Debug1");
}); });
await pair.RunTicksSync(5); 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 // we should be seeing 2 alerts now because one was cleared
Assert.That(clientAlertsUI.AlertContainer.ChildCount, Is.GreaterThanOrEqualTo(2)); Assert.That(clientAlertsUI.AlertContainer.ChildCount, Is.GreaterThanOrEqualTo(2));
var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c); var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c);
var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray(); var alertIDs = alertControls.Select(ac => ac.Alert.ID).ToArray();
var expectedIDs = new[] { AlertType.HumanHealth, AlertType.Debug2 }; var expectedIDs = new[] { "HumanHealth", "Debug2" };
Assert.That(alertIDs, Is.SupersetOf(expectedIDs)); Assert.That(alertIDs, Is.SupersetOf(expectedIDs));
}); });

View File

@@ -1,5 +1,6 @@
using Content.Server.Gravity; using Content.Server.Gravity;
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.Gravity;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
namespace Content.IntegrationTests.Tests.Gravity namespace Content.IntegrationTests.Tests.Gravity
@@ -38,6 +39,7 @@ namespace Content.IntegrationTests.Tests.Gravity
var entityManager = server.ResolveDependency<IEntityManager>(); var entityManager = server.ResolveDependency<IEntityManager>();
var alertsSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AlertsSystem>(); var alertsSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AlertsSystem>();
var weightlessAlert = SharedGravitySystem.WeightlessAlert;
EntityUid human = default; EntityUid human = default;
@@ -56,7 +58,7 @@ namespace Content.IntegrationTests.Tests.Gravity
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
// No gravity without a gravity generator // 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); generatorUid = entityManager.SpawnEntity("WeightlessGravityGeneratorDummy", entityManager.GetComponent<TransformComponent>(human).Coordinates);
}); });
@@ -66,7 +68,7 @@ namespace Content.IntegrationTests.Tests.Gravity
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless), Is.False); Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert), Is.False);
// This should kill gravity // This should kill gravity
entityManager.DeleteEntity(generatorUid); entityManager.DeleteEntity(generatorUid);
@@ -76,7 +78,7 @@ namespace Content.IntegrationTests.Tests.Gravity
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless)); Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert));
}); });
await pair.RunTicksSync(10); await pair.RunTicksSync(10);

View File

@@ -1,3 +1,4 @@
using Content.Shared.Alert;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -47,5 +48,12 @@ namespace Content.Server.Abilities.Mime
/// </summary> /// </summary>
[DataField("vowCooldown")] [DataField("vowCooldown")]
public TimeSpan VowCooldown = TimeSpan.FromMinutes(5); public TimeSpan VowCooldown = TimeSpan.FromMinutes(5);
[DataField]
public ProtoId<AlertPrototype> VowAlert = "VowOfSilence";
[DataField]
public ProtoId<AlertPrototype> VowBrokenAlert = "VowBroken";
} }
} }

View File

@@ -1,5 +1,4 @@
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Speech.Muting;
using Content.Shared.Actions; using Content.Shared.Actions;
using Content.Shared.Actions.Events; using Content.Shared.Actions.Events;
using Content.Shared.Alert; using Content.Shared.Alert;
@@ -54,7 +53,7 @@ namespace Content.Server.Abilities.Mime
private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args) private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args)
{ {
EnsureComp<MutedComponent>(uid); EnsureComp<MutedComponent>(uid);
_alertsSystem.ShowAlert(uid, AlertType.VowOfSilence); _alertsSystem.ShowAlert(uid, component.VowAlert);
_actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid); _actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid);
} }
@@ -115,8 +114,8 @@ namespace Content.Server.Abilities.Mime
mimePowers.VowBroken = true; mimePowers.VowBroken = true;
mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown; mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown;
RemComp<MutedComponent>(uid); RemComp<MutedComponent>(uid);
_alertsSystem.ClearAlert(uid, AlertType.VowOfSilence); _alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
_alertsSystem.ShowAlert(uid, AlertType.VowBroken); _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
_actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity); _actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity);
} }
@@ -138,8 +137,8 @@ namespace Content.Server.Abilities.Mime
mimePowers.ReadyToRepent = false; mimePowers.ReadyToRepent = false;
mimePowers.VowBroken = false; mimePowers.VowBroken = false;
AddComp<MutedComponent>(uid); AddComp<MutedComponent>(uid);
_alertsSystem.ClearAlert(uid, AlertType.VowBroken); _alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
_alertsSystem.ShowAlert(uid, AlertType.VowOfSilence); _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid); _actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);
} }
} }

View File

@@ -40,13 +40,13 @@ namespace Content.Server.Alert.Commands
var alertType = args[0]; var alertType = args[0];
var alertsSystem = _e.System<AlertsSystem>(); 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); shell.WriteLine("unrecognized alertType " + alertType);
return; return;
} }
alertsSystem.ClearAlert(attachedEntity, alert.AlertType); alertsSystem.ClearAlert(attachedEntity, alert.ID);
} }
} }
} }

View File

@@ -41,7 +41,7 @@ namespace Content.Server.Alert.Commands
var alertType = args[0]; var alertType = args[0];
var severity = args[1]; var severity = args[1];
var alertsSystem = _e.System<AlertsSystem>(); 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); shell.WriteLine("unrecognized alertType " + alertType);
return; return;
@@ -53,7 +53,7 @@ namespace Content.Server.Alert.Commands
} }
short? severity1 = sevint == -1 ? null : sevint; short? severity1 = sevint == -1 ? null : sevint;
alertsSystem.ShowAlert(attachedEntity, alert.AlertType, severity1, null); alertsSystem.ShowAlert(attachedEntity, alert.ID, severity1, null);
} }
} }
} }

View File

@@ -1,5 +1,7 @@
using Content.Shared.Alert;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.FixedPoint; using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
namespace Content.Server.Atmos.Components namespace Content.Server.Atmos.Components
{ {
@@ -46,5 +48,13 @@ namespace Content.Server.Atmos.Components
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public bool HasImmunity = false; public bool HasImmunity = false;
[DataField]
public ProtoId<AlertPrototype> HighPressureAlert = "HighPressure";
[DataField]
public ProtoId<AlertPrototype> LowPressureAlert = "LowPressure";
[DataField]
public ProtoId<AlertCategoryPrototype> PressureAlertCategory = "Pressure";
} }
} }

View File

@@ -1,5 +1,7 @@
using Content.Shared.Alert;
using Content.Shared.Damage; using Content.Shared.Damage;
using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Prototypes;
namespace Content.Server.Atmos.Components namespace Content.Server.Atmos.Components
{ {
@@ -77,5 +79,8 @@ namespace Content.Server.Atmos.Components
/// </summary> /// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)] [DataField, ViewVariables(VVAccess.ReadWrite)]
public float FirestackFade = -0.1f; public float FirestackFade = -0.1f;
[DataField]
public ProtoId<AlertPrototype> FireAlert = "Fire";
} }
} }

View File

@@ -245,7 +245,7 @@ namespace Content.Server.Atmos.EntitySystems
_adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking low pressure damage"); _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) 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"); _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 else
{ {
@@ -275,13 +275,13 @@ namespace Content.Server.Atmos.EntitySystems
switch (pressure) switch (pressure)
{ {
case <= Atmospherics.WarningLowPressure: case <= Atmospherics.WarningLowPressure:
_alertsSystem.ShowAlert(uid, AlertType.LowPressure, 1); _alertsSystem.ShowAlert(uid, barotrauma.LowPressureAlert, 1);
break; break;
case >= Atmospherics.WarningHighPressure: case >= Atmospherics.WarningHighPressure:
_alertsSystem.ShowAlert(uid, AlertType.HighPressure, 1); _alertsSystem.ShowAlert(uid, barotrauma.HighPressureAlert, 1);
break; break;
default: default:
_alertsSystem.ClearAlertCategory(uid, AlertCategory.Pressure); _alertsSystem.ClearAlertCategory(uid, barotrauma.PressureAlertCategory);
break; break;
} }
} }

View File

@@ -415,11 +415,11 @@ namespace Content.Server.Atmos.EntitySystems
if (!flammable.OnFire) if (!flammable.OnFire)
{ {
_alertsSystem.ClearAlert(uid, AlertType.Fire); _alertsSystem.ClearAlert(uid, flammable.FireAlert);
continue; continue;
} }
_alertsSystem.ShowAlert(uid, AlertType.Fire); _alertsSystem.ShowAlert(uid, flammable.FireAlert);
if (flammable.FireStacks > 0) if (flammable.FireStacks > 0)
{ {

View File

@@ -1,5 +1,6 @@
using Content.Server.Body.Systems; using Content.Server.Body.Systems;
using Content.Server.Chemistry.EntitySystems; using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent; using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage; using Content.Shared.Damage;
@@ -171,5 +172,8 @@ namespace Content.Server.Body.Components
/// </summary> /// </summary>
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public TimeSpan StatusTime; public TimeSpan StatusTime;
[DataField]
public ProtoId<AlertPrototype> BleedingAlert = "Bleed";
} }
} }

View File

@@ -1,3 +1,6 @@
using Content.Shared.Alert;
using Robust.Shared.Prototypes;
namespace Content.Server.Body.Components namespace Content.Server.Body.Components
{ {
/// <summary> /// <summary>
@@ -18,5 +21,8 @@ namespace Content.Server.Body.Components
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
[DataField] [DataField]
public TimeSpan Delay = TimeSpan.FromSeconds(3); public TimeSpan Delay = TimeSpan.FromSeconds(3);
[DataField]
public ProtoId<AlertPrototype> InternalsAlert = "Internals";
} }
} }

View File

@@ -1,8 +1,8 @@
using Content.Server.Atmos;
using Content.Server.Body.Systems; using Content.Server.Body.Systems;
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.Body.Components; 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. /// The type of gas this lung needs. Used only for the breathing alerts, not actual metabolism.
/// </summary> /// </summary>
[DataField] [DataField]
public AlertType Alert = AlertType.LowOxygen; public ProtoId<AlertPrototype> Alert = "LowOxygen";
} }

View File

@@ -392,11 +392,11 @@ public sealed class BloodstreamSystem : EntitySystem
component.BleedAmount = Math.Clamp(component.BleedAmount, 0, component.MaxBleedAmount); component.BleedAmount = Math.Clamp(component.BleedAmount, 0, component.MaxBleedAmount);
if (component.BleedAmount == 0) if (component.BleedAmount == 0)
_alertsSystem.ClearAlert(uid, AlertType.Bleed); _alertsSystem.ClearAlert(uid, component.BleedingAlert);
else else
{ {
var severity = (short) Math.Clamp(Math.Round(component.BleedAmount, MidpointRounding.ToZero), 0, 10); 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; return true;

View File

@@ -144,12 +144,12 @@ public sealed class InternalsSystem : EntitySystem
private void OnInternalsStartup(Entity<InternalsComponent> ent, ref ComponentStartup args) 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) 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) 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); var gasTank = Comp<GasTankComponent>(ent.Comp.GasTankEntity!.Value);
args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume); args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume);
// TODO: Should listen to gas tank updates instead I guess? // 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) public void DisconnectBreathTool(Entity<InternalsComponent> ent)
@@ -173,7 +173,7 @@ public sealed class InternalsSystem : EntitySystem
DisconnectTank(ent); 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) public void ConnectBreathTool(Entity<InternalsComponent> ent, EntityUid toolEntity)
@@ -184,7 +184,7 @@ public sealed class InternalsSystem : EntitySystem
} }
ent.Comp.BreathToolEntity = toolEntity; ent.Comp.BreathToolEntity = toolEntity;
_alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
} }
public void DisconnectTank(InternalsComponent? component) public void DisconnectTank(InternalsComponent? component)
@@ -196,7 +196,7 @@ public sealed class InternalsSystem : EntitySystem
_gasTank.DisconnectFromInternals((component.GasTankEntity.Value, tank)); _gasTank.DisconnectFromInternals((component.GasTankEntity.Value, tank));
component.GasTankEntity = null; 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) public bool TryConnectTank(Entity<InternalsComponent> ent, EntityUid tankEntity)
@@ -208,7 +208,7 @@ public sealed class InternalsSystem : EntitySystem
_gasTank.DisconnectFromInternals((ent.Comp.GasTankEntity.Value, tank)); _gasTank.DisconnectFromInternals((ent.Comp.GasTankEntity.Value, tank));
ent.Comp.GasTankEntity = tankEntity; ent.Comp.GasTankEntity = tankEntity;
_alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
return true; return true;
} }

View File

@@ -10,8 +10,8 @@ public sealed partial class AdjustAlert : ReagentEffect
/// <summary> /// <summary>
/// The specific Alert that will be adjusted /// The specific Alert that will be adjusted
/// </summary> /// </summary>
[DataField("alertType", required: true)] [DataField(required: true)]
public AlertType Type; public ProtoId<AlertPrototype> AlertType;
/// <summary> /// <summary>
/// If true, the alert is removed after Time seconds. If Time was not specified the alert is removed immediately. /// 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) if (Clear && Time <= 0)
{ {
alertSys.ClearAlert(args.SolutionEntity, Type); alertSys.ClearAlert(args.SolutionEntity, AlertType);
} }
else else
{ {
@@ -52,7 +52,7 @@ public sealed partial class AdjustAlert : ReagentEffect
if ((ShowCooldown || Clear) && Time > 0) if ((ShowCooldown || Clear) && Time > 0)
cooldown = (timing.CurTime, timing.CurTime + TimeSpan.FromSeconds(Time)); 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);
} }
} }

View File

@@ -29,11 +29,11 @@ public sealed class MagbootsSystem : SharedMagbootsSystem
if (state) if (state)
{ {
_alerts.ShowAlert(parent, AlertType.Magboots); _alerts.ShowAlert(parent, component.MagbootsAlert);
} }
else else
{ {
_alerts.ClearAlert(parent, AlertType.Magboots); _alerts.ClearAlert(parent, component.MagbootsAlert);
} }
} }

View File

@@ -163,8 +163,8 @@ public sealed partial class EnsnareableSystem
public void UpdateAlert(EntityUid target, EnsnareableComponent component) public void UpdateAlert(EntityUid target, EnsnareableComponent component)
{ {
if (!component.IsEnsnared) if (!component.IsEnsnared)
_alerts.ClearAlert(target, AlertType.Ensnared); _alerts.ClearAlert(target, component.EnsnaredAlert);
else else
_alerts.ShowAlert(target, AlertType.Ensnared); _alerts.ShowAlert(target, component.EnsnaredAlert);
} }
} }

View File

@@ -102,20 +102,23 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem
/// </summary> /// </summary>
public void SetSuitPowerAlert(EntityUid uid, SpaceNinjaComponent? comp = null) 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; return;
} }
if (GetNinjaBattery(uid, out _, out var battery)) if (GetNinjaBattery(uid, out _, out var battery))
{ {
var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, battery.CurrentCharge), battery.MaxCharge, 8); 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 else
{ {
_alerts.ClearAlert(uid, AlertType.SuitPower); _alerts.ClearAlert(uid, comp.SuitPowerAlert);
} }
} }

View File

@@ -141,7 +141,7 @@ public sealed partial class RevenantSystem : EntitySystem
if (TryComp<StoreComponent>(uid, out var store)) if (TryComp<StoreComponent>(uid, out var store))
_store.UpdateUserInterface(uid, uid, store); _store.UpdateUserInterface(uid, uid, store);
_alerts.ShowAlert(uid, AlertType.Essence); _alerts.ShowAlert(uid, component.EssenceAlert);
if (component.Essence <= 0) if (component.Essence <= 0)
{ {

View File

@@ -317,7 +317,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
component.SubscribedPilots.Add(entity); component.SubscribedPilots.Add(entity);
_alertsSystem.ShowAlert(entity, AlertType.PilotingShuttle); _alertsSystem.ShowAlert(entity, pilotComponent.PilotingAlert);
pilotComponent.Console = uid; pilotComponent.Console = uid;
ActionBlockerSystem.UpdateCanMove(entity); ActionBlockerSystem.UpdateCanMove(entity);
@@ -339,7 +339,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem
if (!helm.SubscribedPilots.Remove(pilotUid)) if (!helm.SubscribedPilots.Remove(pilotUid))
return; return;
_alertsSystem.ClearAlert(pilotUid, AlertType.PilotingShuttle); _alertsSystem.ClearAlert(pilotUid, pilotComponent.PilotingAlert);
_popup.PopupEntity(Loc.GetString("shuttle-pilot-end"), pilotUid, pilotUid); _popup.PopupEntity(Loc.GetString("shuttle-pilot-end"), pilotUid, pilotUid);

View File

@@ -84,7 +84,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
private void OnMapInit(EntityUid uid, BorgChassisComponent component, MapInitEvent args) private void OnMapInit(EntityUid uid, BorgChassisComponent component, MapInitEvent args)
{ {
UpdateBatteryAlert(uid); UpdateBatteryAlert((uid, component));
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid); _movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
} }
@@ -183,7 +183,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
private void OnPowerCellChanged(EntityUid uid, BorgChassisComponent component, PowerCellChangedEvent args) private void OnPowerCellChanged(EntityUid uid, BorgChassisComponent component, PowerCellChangedEvent args)
{ {
UpdateBatteryAlert(uid); UpdateBatteryAlert((uid, component));
if (!TryComp<PowerCellDrawComponent>(uid, out var draw)) if (!TryComp<PowerCellDrawComponent>(uid, out var draw))
return; return;
@@ -256,12 +256,12 @@ public sealed partial class BorgSystem : SharedBorgSystem
args.Cancel(); 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.ClearAlert(ent, ent.Comp.BatteryAlert);
_alerts.ShowAlert(uid, AlertType.BorgBatteryNone); _alerts.ShowAlert(ent, ent.Comp.NoBatteryAlert);
return; return;
} }
@@ -269,13 +269,13 @@ public sealed partial class BorgSystem : SharedBorgSystem
// we make sure 0 only shows if they have absolutely no battery. // we make sure 0 only shows if they have absolutely no battery.
// also account for floating point imprecision // also account for floating point imprecision
if (chargePercent == 0 && _powerCell.HasDrawCharge(uid, cell: slotComponent)) if (chargePercent == 0 && _powerCell.HasDrawCharge(ent, cell: slotComponent))
{ {
chargePercent = 1; chargePercent = 1;
} }
_alerts.ClearAlert(uid, AlertType.BorgBatteryNone); _alerts.ClearAlert(ent, ent.Comp.NoBatteryAlert);
_alerts.ShowAlert(uid, AlertType.BorgBattery, chargePercent); _alerts.ShowAlert(ent, ent.Comp.BatteryAlert, chargePercent);
} }
/// <summary> /// <summary>

View File

@@ -1,7 +1,9 @@
using Content.Server.Temperature.Systems; using Content.Server.Temperature.Systems;
using Content.Shared.Alert;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.FixedPoint; using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
namespace Content.Server.Temperature.Components; namespace Content.Server.Temperature.Components;
@@ -78,4 +80,10 @@ public sealed partial class TemperatureComponent : Component
/// </summary> /// </summary>
[DataField] [DataField]
public bool TakingDamage = false; public bool TakingDamage = false;
[DataField]
public ProtoId<AlertPrototype> HotAlert = "Hot";
[DataField]
public ProtoId<AlertPrototype> ColdAlert = "Cold";
} }

View File

@@ -12,6 +12,7 @@ using Content.Shared.Inventory;
using Content.Shared.Rejuvenate; using Content.Shared.Rejuvenate;
using Content.Shared.Temperature; using Content.Shared.Temperature;
using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.Temperature.Systems; namespace Content.Server.Temperature.Systems;
@@ -33,6 +34,9 @@ public sealed class TemperatureSystem : EntitySystem
private float _accumulatedFrametime; private float _accumulatedFrametime;
[ValidatePrototypeId<AlertCategoryPrototype>]
public const string TemperatureAlertCategory = "Temperature";
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage); SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage);
@@ -180,13 +184,13 @@ public sealed class TemperatureSystem : EntitySystem
private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureChangeEvent args) private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureChangeEvent args)
{ {
AlertType type; ProtoId<AlertPrototype> type;
float threshold; float threshold;
float idealTemp; float idealTemp;
if (!TryComp<TemperatureComponent>(uid, out var temperature)) if (!TryComp<TemperatureComponent>(uid, out var temperature))
{ {
_alerts.ClearAlertCategory(uid, AlertCategory.Temperature); _alerts.ClearAlertCategory(uid, TemperatureAlertCategory);
return; return;
} }
@@ -203,12 +207,12 @@ public sealed class TemperatureSystem : EntitySystem
if (args.CurrentTemperature <= idealTemp) if (args.CurrentTemperature <= idealTemp)
{ {
type = AlertType.Cold; type = temperature.ColdAlert;
threshold = temperature.ColdDamageThreshold; threshold = temperature.ColdDamageThreshold;
} }
else else
{ {
type = AlertType.Hot; type = temperature.HotAlert;
threshold = temperature.HeatDamageThreshold; threshold = temperature.HeatDamageThreshold;
} }
@@ -230,7 +234,7 @@ public sealed class TemperatureSystem : EntitySystem
break; break;
case > 0.66f: case > 0.66f:
_alerts.ClearAlertCategory(uid, AlertCategory.Temperature); _alerts.ClearAlertCategory(uid, TemperatureAlertCategory);
break; break;
} }
} }

View File

@@ -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
}

View File

@@ -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!;
}

View File

@@ -1,5 +1,5 @@
using Robust.Shared.Serialization; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization;
namespace Content.Shared.Alert; namespace Content.Shared.Alert;
@@ -11,13 +11,13 @@ namespace Content.Shared.Alert;
[Serializable, NetSerializable] [Serializable, NetSerializable]
public struct AlertKey public struct AlertKey
{ {
public AlertType? AlertType { get; private set; } = Alert.AlertType.Error; public ProtoId<AlertPrototype>? AlertType { get; private set; } = default!;
public readonly AlertCategory? AlertCategory; public readonly ProtoId<AlertCategoryPrototype>? AlertCategory;
/// NOTE: if the alert has a category you must pass the category for this to work /// 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 /// 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. /// 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; AlertCategory = alertCategory;
AlertType = alertType; AlertType = alertType;
@@ -49,7 +49,7 @@ public struct AlertKey
/// <param name="category">alert category, must not be null</param> /// <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 /// <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> /// 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); return new(null, category);
} }

View File

@@ -7,7 +7,7 @@ namespace Content.Shared.Alert
/// <summary> /// <summary>
/// Defines the order of alerts so they show up in a consistent order. /// Defines the order of alerts so they show up in a consistent order.
/// </summary> /// </summary>
[Prototype("alertOrder")] [Prototype]
[DataDefinition] [DataDefinition]
public sealed partial class AlertOrderPrototype : IPrototype, IComparer<AlertPrototype> public sealed partial class AlertOrderPrototype : IPrototype, IComparer<AlertPrototype>
{ {
@@ -15,7 +15,7 @@ namespace Content.Shared.Alert
[IdDataField] [IdDataField]
public string ID { get; private set; } = default!; public string ID { get; private set; } = default!;
[DataField("order")] [DataField]
private (string type, string alert)[] Order private (string type, string alert)[] Order
{ {
// why would paul do this to me. // why would paul do this to me.
@@ -46,10 +46,10 @@ namespace Content.Shared.Alert
switch (type) switch (type)
{ {
case "alertType": case "alertType":
_typeToIdx[Enum.Parse<AlertType>(alert)] = i++; _typeToIdx[alert] = i++;
break; break;
case "category": case "category":
_categoryToIdx[Enum.Parse<AlertCategory>(alert)] = i++; _categoryToIdx[alert] = i++;
break; break;
default: default:
throw new ArgumentException(); throw new ArgumentException();
@@ -58,17 +58,17 @@ namespace Content.Shared.Alert
} }
} }
private readonly Dictionary<AlertType, int> _typeToIdx = new(); private readonly Dictionary<ProtoId<AlertPrototype>, int> _typeToIdx = new();
private readonly Dictionary<AlertCategory, int> _categoryToIdx = new(); private readonly Dictionary<ProtoId<AlertCategoryPrototype>, int> _categoryToIdx = new();
private int GetOrderIndex(AlertPrototype alert) private int GetOrderIndex(AlertPrototype alert)
{ {
if (_typeToIdx.TryGetValue(alert.AlertType, out var idx)) if (_typeToIdx.TryGetValue(alert.ID, out var idx))
{ {
return idx; return idx;
} }
if (alert.Category != null && if (alert.Category != null &&
_categoryToIdx.TryGetValue((AlertCategory) alert.Category, out idx)) _categoryToIdx.TryGetValue(alert.Category.Value, out idx))
{ {
return idx; return idx;
} }
@@ -78,20 +78,25 @@ namespace Content.Shared.Alert
public int Compare(AlertPrototype? x, AlertPrototype? y) public int Compare(AlertPrototype? x, AlertPrototype? y)
{ {
if ((x == null) && (y == null)) return 0; if (x == null && y == null)
if (x == null) return 1; return 0;
if (y == null) return -1; if (x == null)
return 1;
if (y == null)
return -1;
var idx = GetOrderIndex(x); var idx = GetOrderIndex(x);
var idy = GetOrderIndex(y); var idy = GetOrderIndex(y);
if (idx == -1 && idy == -1) if (idx == -1 && idy == -1)
{ {
// break ties by type value // break ties by type value
// Must cast to int to avoid integer overflow when subtracting (enum's unsigned) // 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 (idx == -1)
if (idy == -1) return -1; return 1;
if (idy == -1)
return -1;
var result = idx - idy; var result = idx - idy;
// not strictly necessary (we don't care about ones that go at the same index) // not strictly necessary (we don't care about ones that go at the same index)
// but it makes the sort stable // but it makes the sort stable
@@ -99,7 +104,7 @@ namespace Content.Shared.Alert
{ {
// break ties by type value // break ties by type value
// Must cast to int to avoid integer overflow when subtracting (enum's unsigned) // 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; return result;

View File

@@ -1,120 +1,116 @@
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility; 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> /// <summary>
/// An alert popup with associated icon, tooltip, and other data. /// Type of alert, no 2 alert prototypes should have the same one.
/// </summary> /// </summary>
[Prototype("alert")] [IdDataField]
public sealed partial class AlertPrototype : IPrototype public string ID { get; private set; } = default!;
/// <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();
/// <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]
public string Name { get; private set; } = string.Empty;
/// <summary>
/// Description to show in tooltip window. Accepts formatting.
/// </summary>
[DataField]
public string Description { get; private set; } = string.Empty;
/// <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);
/// <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)
{ {
[ViewVariables] var minIcons = SupportsSeverity
string IPrototype.ID => AlertType.ToString(); ? MaxSeverity - MinSeverity
: 1;
/// <summary> if (Icons.Count < minIcons)
/// Type of alert, no 2 alert prototypes should have the same one. throw new InvalidOperationException($"Insufficient number of icons given for alert {ID}");
/// </summary>
[IdDataField]
public AlertType AlertType { get; private set; }
/// <summary> if (!SupportsSeverity)
/// List of icons to use for this alert. Each entry corresponds to a different severity level, starting from the return Icons[0];
/// 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> if (severity == null)
/// 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 throw new ArgumentException($"No severity specified but this alert ({AlertKey}) has severity.", nameof(severity));
? MaxSeverity - MinSeverity
: 1;
if (Icons.Count < minIcons)
throw new InvalidOperationException($"Insufficient number of icons given for alert {AlertType}");
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];
} }
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];
} }
} }

View File

@@ -1,3 +1,4 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Alert; namespace Content.Shared.Alert;
@@ -9,5 +10,5 @@ public struct AlertState
public (TimeSpan, TimeSpan)? Cooldown; public (TimeSpan, TimeSpan)? Cooldown;
public bool AutoRemove; public bool AutoRemove;
public bool ShowCooldown; public bool ShowCooldown;
public AlertType Type; public ProtoId<AlertPrototype> Type;
} }

View File

@@ -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
}
}

View File

@@ -11,7 +11,7 @@ public abstract class AlertsSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IGameTiming _timing = 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) public IReadOnlyDictionary<AlertKey, AlertState>? GetActiveAlerts(EntityUid euid)
{ {
@@ -20,23 +20,23 @@ public abstract class AlertsSystem : EntitySystem
: null; : null;
} }
public short GetSeverityRange(AlertType alertType) public short GetSeverityRange(ProtoId<AlertPrototype> alertType)
{ {
var minSeverity = _typeToAlert[alertType].MinSeverity; var minSeverity = _typeToAlert[alertType].MinSeverity;
return (short)MathF.Max(minSeverity,_typeToAlert[alertType].MaxSeverity - 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; return _typeToAlert[alertType].MaxSeverity;
} }
public short GetMinSeverity(AlertType alertType) public short GetMinSeverity(ProtoId<AlertPrototype> alertType)
{ {
return _typeToAlert[alertType].MinSeverity; 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)) if (!EntityManager.TryGetComponent(euid, out AlertsComponent? alertsComponent))
return false; 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> /// <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) return EntityManager.TryGetComponent(euid, out AlertsComponent? alertsComponent)
&& alertsComponent.Alerts.ContainsKey(AlertKey.ForCategory(alertCategory)); && 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> /// 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="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> /// <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. // This should be handled as part of networking.
if (_timing.ApplyingState) if (_timing.ApplyingState)
@@ -131,7 +131,7 @@ public abstract class AlertsSystem : EntitySystem
/// <summary> /// <summary>
/// Clear the alert with the given category, if one is currently showing. /// Clear the alert with the given category, if one is currently showing.
/// </summary> /// </summary>
public void ClearAlertCategory(EntityUid euid, AlertCategory category) public void ClearAlertCategory(EntityUid euid, ProtoId<AlertCategoryPrototype> category)
{ {
if(!TryComp(euid, out AlertsComponent? alertsComponent)) if(!TryComp(euid, out AlertsComponent? alertsComponent))
return; return;
@@ -150,7 +150,7 @@ public abstract class AlertsSystem : EntitySystem
/// <summary> /// <summary>
/// Clear the alert of the given type if it is currently showing. /// Clear the alert of the given type if it is currently showing.
/// </summary> /// </summary>
public void ClearAlert(EntityUid euid, AlertType alertType) public void ClearAlert(EntityUid euid, ProtoId<AlertPrototype> alertType)
{ {
if (_timing.ApplyingState) if (_timing.ApplyingState)
return; return;
@@ -286,13 +286,13 @@ public abstract class AlertsSystem : EntitySystem
protected virtual void LoadPrototypes() protected virtual void LoadPrototypes()
{ {
var dict = new Dictionary<AlertType, AlertPrototype>(); var dict = new Dictionary<ProtoId<AlertPrototype>, AlertPrototype>();
foreach (var alert in _prototypeManager.EnumeratePrototypes<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" + 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 /// Tries to get the alert of the indicated type
/// </summary> /// </summary>
/// <returns>true if found</returns> /// <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); return _typeToAlert.TryGetValue(alertType, out alert);
} }

View File

@@ -1,4 +1,5 @@
using Robust.Shared.Serialization; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Alert; namespace Content.Shared.Alert;
@@ -8,9 +9,9 @@ namespace Content.Shared.Alert;
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed class ClickAlertEvent : EntityEventArgs 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; Type = alertType;
} }

View File

@@ -3,6 +3,7 @@ using Content.Shared.Alert;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Buckle.Components; namespace Content.Shared.Buckle.Components;
@@ -115,7 +116,7 @@ public sealed partial class StrapComponent : Component
/// </summary> /// </summary>
[DataField] [DataField]
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public AlertType BuckledAlertType = AlertType.Buckled; public ProtoId<AlertPrototype> BuckledAlertType = "Buckled";
/// <summary> /// <summary>
/// The sum of the sizes of all the buckled entities in this strap /// The sum of the sizes of all the buckled entities in this strap

View File

@@ -40,6 +40,9 @@ public abstract partial class SharedBuckleSystem
SubscribeLocalEvent<BuckleComponent, UpdateCanMoveEvent>(OnBuckleUpdateCanMove); SubscribeLocalEvent<BuckleComponent, UpdateCanMoveEvent>(OnBuckleUpdateCanMove);
} }
[ValidatePrototypeId<AlertCategoryPrototype>]
public const string BuckledAlertCategory = "Buckled";
private void OnBuckleComponentStartup(EntityUid uid, BuckleComponent component, ComponentStartup args) private void OnBuckleComponentStartup(EntityUid uid, BuckleComponent component, ComponentStartup args)
{ {
UpdateBuckleStatus(uid, component); UpdateBuckleStatus(uid, component);
@@ -165,7 +168,7 @@ public abstract partial class SharedBuckleSystem
} }
else else
{ {
_alerts.ClearAlertCategory(uid, AlertCategory.Buckled); _alerts.ClearAlertCategory(uid, BuckledAlertCategory);
} }
} }

View File

@@ -1,3 +1,4 @@
using Content.Shared.Alert;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -16,4 +17,7 @@ public sealed partial class MagbootsComponent : Component
[DataField("on"), AutoNetworkedField] [DataField("on"), AutoNetworkedField]
public bool On; public bool On;
[DataField]
public ProtoId<AlertPrototype> MagbootsAlert = "Magboots";
} }

View File

@@ -7,7 +7,6 @@ using Content.Shared.Interaction.Events;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Throwing; using Content.Shared.Throwing;
using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Shared.CombatMode.Pacification; namespace Content.Shared.CombatMode.Pacification;
@@ -109,7 +108,7 @@ public sealed class PacificationSystem : EntitySystem
_actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false); _actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false);
} }
_alertsSystem.ShowAlert(uid, AlertType.Pacified); _alertsSystem.ShowAlert(uid, component.PacifiedAlert);
} }
private void OnShutdown(EntityUid uid, PacifiedComponent component, ComponentShutdown args) private void OnShutdown(EntityUid uid, PacifiedComponent component, ComponentShutdown args)
@@ -121,7 +120,7 @@ public sealed class PacificationSystem : EntitySystem
_combatSystem.SetCanDisarm(uid, true, combatMode); _combatSystem.SetCanDisarm(uid, true, combatMode);
_actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, true); _actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, true);
_alertsSystem.ClearAlert(uid, AlertType.Pacified); _alertsSystem.ClearAlert(uid, component.PacifiedAlert);
} }
private void OnBeforeThrow(Entity<PacifiedComponent> ent, ref BeforeThrowEvent args) private void OnBeforeThrow(Entity<PacifiedComponent> ent, ref BeforeThrowEvent args)

View File

@@ -1,4 +1,6 @@
using Content.Shared.Alert;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.CombatMode.Pacification; namespace Content.Shared.CombatMode.Pacification;
@@ -42,4 +44,6 @@ public sealed partial class PacifiedComponent : Component
[DataField] [DataField]
public EntityUid? LastAttackedEntity = null; public EntityUid? LastAttackedEntity = null;
[DataField]
public ProtoId<AlertPrototype> PacifiedAlert = "Pacified";
} }

View File

@@ -1,6 +1,8 @@
using Content.Shared.Alert;
using Content.Shared.Damage; using Content.Shared.Damage;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -39,6 +41,9 @@ public sealed partial class CuffableComponent : Component
/// </summary> /// </summary>
[DataField("canStillInteract"), ViewVariables(VVAccess.ReadWrite)] [DataField("canStillInteract"), ViewVariables(VVAccess.ReadWrite)]
public bool CanStillInteract = true; public bool CanStillInteract = true;
[DataField]
public ProtoId<AlertPrototype> CuffedAlert = "Handcuffed";
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]

View File

@@ -172,9 +172,9 @@ namespace Content.Shared.Cuffs
_actionBlocker.UpdateCanMove(uid); _actionBlocker.UpdateCanMove(uid);
if (component.CanStillInteract) if (component.CanStillInteract)
_alerts.ClearAlert(uid, AlertType.Handcuffed); _alerts.ClearAlert(uid, component.CuffedAlert);
else else
_alerts.ShowAlert(uid, AlertType.Handcuffed); _alerts.ShowAlert(uid, component.CuffedAlert);
var ev = new CuffedStateChangeEvent(); var ev = new CuffedStateChangeEvent();
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);

View File

@@ -1,4 +1,6 @@
using Content.Shared.Alert;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Damage.Components; namespace Content.Shared.Damage.Components;
@@ -51,4 +53,7 @@ public sealed partial class StaminaComponent : Component
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
[AutoPausedField] [AutoPausedField]
public TimeSpan NextUpdate = TimeSpan.Zero; public TimeSpan NextUpdate = TimeSpan.Zero;
[DataField]
public ProtoId<AlertPrototype> StaminaAlert = "Stamina";
} }

View File

@@ -79,8 +79,7 @@ public sealed partial class StaminaSystem : EntitySystem
{ {
RemCompDeferred<ActiveStaminaComponent>(uid); RemCompDeferred<ActiveStaminaComponent>(uid);
} }
_alerts.ClearAlert(uid, component.StaminaAlert);
SetStaminaAlert(uid);
} }
private void OnStartup(EntityUid uid, StaminaComponent component, ComponentStartup args) 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) private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null)
{ {
if (!Resolve(uid, ref component, false) || component.Deleted) if (!Resolve(uid, ref component, false) || component.Deleted)
{
_alerts.ClearAlert(uid, AlertType.Stamina);
return; return;
}
var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, component.CritThreshold - component.StaminaDamage), component.CritThreshold, 7); 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> /// <summary>

View File

@@ -1,5 +1,7 @@
using Content.Shared.Alert;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Ensnaring.Components; namespace Content.Shared.Ensnaring.Components;
@@ -40,6 +42,9 @@ public sealed partial class EnsnareableComponent : Component
[DataField("state")] [DataField("state")]
public string? State; public string? State;
[DataField]
public ProtoId<AlertPrototype> EnsnaredAlert = "Ensnared";
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]

View File

@@ -17,6 +17,9 @@ namespace Content.Shared.Gravity
[Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly InventorySystem _inventory = 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) public bool IsWeightless(EntityUid uid, PhysicsComponent? body = null, TransformComponent? xform = null)
{ {
Resolve(uid, ref body, false); Resolve(uid, ref body, false);
@@ -93,11 +96,11 @@ namespace Content.Shared.Gravity
if (!ev.HasGravity) if (!ev.HasGravity)
{ {
_alerts.ShowAlert(uid, AlertType.Weightless); _alerts.ShowAlert(uid, WeightlessAlert);
} }
else else
{ {
_alerts.ClearAlert(uid, AlertType.Weightless); _alerts.ClearAlert(uid, WeightlessAlert);
} }
} }
} }
@@ -106,11 +109,11 @@ namespace Content.Shared.Gravity
{ {
if (IsWeightless(ev.Euid)) if (IsWeightless(ev.Euid))
{ {
_alerts.ShowAlert(ev.Euid, AlertType.Weightless); _alerts.ShowAlert(ev.Euid, WeightlessAlert);
} }
else else
{ {
_alerts.ClearAlert(ev.Euid, AlertType.Weightless); _alerts.ClearAlert(ev.Euid, WeightlessAlert);
} }
} }
@@ -118,11 +121,11 @@ namespace Content.Shared.Gravity
{ {
if (IsWeightless(uid)) if (IsWeightless(uid))
{ {
_alerts.ShowAlert(uid, AlertType.Weightless); _alerts.ShowAlert(uid, WeightlessAlert);
} }
else else
{ {
_alerts.ClearAlert(uid, AlertType.Weightless); _alerts.ClearAlert(uid, WeightlessAlert);
} }
} }

View File

@@ -2,6 +2,7 @@ using Content.Shared.Alert;
using Content.Shared.FixedPoint; using Content.Shared.FixedPoint;
using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Systems;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Mobs.Components; namespace Content.Shared.Mobs.Components;
@@ -24,13 +25,16 @@ public sealed partial class MobThresholdsComponent : Component
/// Used for alternate health alerts (silicons, for example) /// Used for alternate health alerts (silicons, for example)
/// </summary> /// </summary>
[DataField("stateAlertDict")] [DataField("stateAlertDict")]
public Dictionary<MobState, AlertType> StateAlertDict = new() public Dictionary<MobState, ProtoId<AlertPrototype>> StateAlertDict = new()
{ {
{MobState.Alive, AlertType.HumanHealth}, {MobState.Alive, "HumanHealth"},
{MobState.Critical, AlertType.HumanCrit}, {MobState.Critical, "HumanCrit"},
{MobState.Dead, AlertType.HumanDead}, {MobState.Dead, "HumanDead"},
}; };
[DataField]
public ProtoId<AlertCategoryPrototype> HealthAlertCategory = "Health";
/// <summary> /// <summary>
/// Whether or not this entity should display damage overlays (robots don't feel pain, black out etc.) /// Whether or not this entity should display damage overlays (robots don't feel pain, black out etc.)
/// </summary> /// </summary>
@@ -53,19 +57,19 @@ public sealed class MobThresholdsComponentState : ComponentState
public MobState CurrentThresholdState; public MobState CurrentThresholdState;
public Dictionary<MobState, AlertType> StateAlertDict = new() public Dictionary<MobState, ProtoId<AlertPrototype>> StateAlertDict;
{
{MobState.Alive, AlertType.HumanHealth},
{MobState.Critical, AlertType.HumanCrit},
{MobState.Dead, AlertType.HumanDead},
};
public bool ShowOverlays; public bool ShowOverlays;
public bool AllowRevives; public bool AllowRevives;
public MobThresholdsComponentState(Dictionary<FixedPoint2, MobState> unsortedThresholds, bool triggersAlerts, MobState currentThresholdState, public MobThresholdsComponentState(Dictionary<FixedPoint2, MobState> unsortedThresholds,
Dictionary<MobState, AlertType> stateAlertDict, bool showOverlays, bool allowRevives) bool triggersAlerts,
MobState currentThresholdState,
Dictionary<MobState,
ProtoId<AlertPrototype>> stateAlertDict,
bool showOverlays,
bool allowRevives)
{ {
UnsortedThresholds = unsortedThresholds; UnsortedThresholds = unsortedThresholds;
TriggersAlerts = triggersAlerts; TriggersAlerts = triggersAlerts;

View File

@@ -431,7 +431,7 @@ public sealed class MobThresholdSystem : EntitySystem
private void MobThresholdShutdown(EntityUid target, MobThresholdsComponent component, ComponentShutdown args) private void MobThresholdShutdown(EntityUid target, MobThresholdsComponent component, ComponentShutdown args)
{ {
if (component.TriggersAlerts) if (component.TriggersAlerts)
_alerts.ClearAlertCategory(target, AlertCategory.Health); _alerts.ClearAlertCategory(target, component.HealthAlertCategory);
} }
private void OnUpdateMobState(EntityUid target, MobThresholdsComponent component, ref UpdateMobStateEvent args) private void OnUpdateMobState(EntityUid target, MobThresholdsComponent component, ref UpdateMobStateEvent args)

View File

@@ -1,4 +1,6 @@
using Content.Shared.Alert;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Movement.Pulling.Components; namespace Content.Shared.Movement.Pulling.Components;
@@ -36,4 +38,7 @@ public sealed partial class PullableComponent : Component
[Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)] [Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)]
[AutoNetworkedField, DataField] [AutoNetworkedField, DataField]
public bool PrevFixedRotation; public bool PrevFixedRotation;
[DataField]
public ProtoId<AlertPrototype> PulledAlert = "Pulled";
} }

View 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.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Movement.Pulling.Components; namespace Content.Shared.Movement.Pulling.Components;
@@ -38,4 +40,7 @@ public sealed partial class PullerComponent : Component
/// </summary> /// </summary>
[DataField] [DataField]
public bool NeedsHands = true; public bool NeedsHands = true;
[DataField]
public ProtoId<AlertPrototype> PullingAlert = "Pulling";
} }

View File

@@ -223,7 +223,7 @@ public sealed class PullingSystem : EntitySystem
if (TryComp<PullerComponent>(oldPuller, out var pullerComp)) if (TryComp<PullerComponent>(oldPuller, out var pullerComp))
{ {
var pullerUid = oldPuller.Value; var pullerUid = oldPuller.Value;
_alertsSystem.ClearAlert(pullerUid, AlertType.Pulling); _alertsSystem.ClearAlert(pullerUid, pullerComp.PullingAlert);
pullerComp.Pulling = null; pullerComp.Pulling = null;
Dirty(oldPuller.Value, pullerComp); 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) public bool IsPulled(EntityUid uid, PullableComponent? component = null)
@@ -460,8 +460,8 @@ public sealed class PullingSystem : EntitySystem
// Messaging // Messaging
var message = new PullStartedMessage(pullerUid, pullableUid); var message = new PullStartedMessage(pullerUid, pullableUid);
_alertsSystem.ShowAlert(pullerUid, AlertType.Pulling); _alertsSystem.ShowAlert(pullerUid, pullerComp.PullingAlert);
_alertsSystem.ShowAlert(pullableUid, AlertType.Pulled); _alertsSystem.ShowAlert(pullableUid, pullableComp.PulledAlert);
RaiseLocalEvent(pullerUid, message); RaiseLocalEvent(pullerUid, message);
RaiseLocalEvent(pullableUid, message); RaiseLocalEvent(pullableUid, message);

View File

@@ -1,3 +1,4 @@
using Content.Shared.Alert;
using Content.Shared.Ninja.Systems; using Content.Shared.Ninja.Systems;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -53,4 +54,7 @@ public sealed partial class SpaceNinjaComponent : Component
/// </summary> /// </summary>
[DataField] [DataField]
public EntProtoId SpiderChargeObjective = "SpiderChargeObjective"; public EntProtoId SpiderChargeObjective = "SpiderChargeObjective";
[DataField]
public ProtoId<AlertPrototype> SuitPowerAlert = "SuitPower";
} }

View File

@@ -2,6 +2,7 @@ using Content.Shared.Alert;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Nutrition.EntitySystems;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
@@ -65,15 +66,18 @@ public sealed partial class HungerComponent : Component
/// <summary> /// <summary>
/// A dictionary relating hunger thresholds to corresponding alerts. /// A dictionary relating hunger thresholds to corresponding alerts.
/// </summary> /// </summary>
[DataField("hungerThresholdAlerts", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, AlertType>))] [DataField("hungerThresholdAlerts")]
[AutoNetworkedField] [AutoNetworkedField]
public Dictionary<HungerThreshold, AlertType> HungerThresholdAlerts = new() public Dictionary<HungerThreshold, ProtoId<AlertPrototype>> HungerThresholdAlerts = new()
{ {
{ HungerThreshold.Peckish, AlertType.Peckish }, { HungerThreshold.Peckish, "Peckish" },
{ HungerThreshold.Starving, AlertType.Starving }, { HungerThreshold.Starving, "Starving" },
{ HungerThreshold.Dead, AlertType.Starving } { HungerThreshold.Dead, "Starving" }
}; };
[DataField]
public ProtoId<AlertCategoryPrototype> HungerAlertCategory = "Hunger";
/// <summary> /// <summary>
/// A dictionary relating HungerThreshold to how much they modify <see cref="BaseDecayRate"/>. /// A dictionary relating HungerThreshold to how much they modify <see cref="BaseDecayRate"/>.
/// </summary> /// </summary>

View File

@@ -1,6 +1,7 @@
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Nutrition.EntitySystems;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Nutrition.Components; namespace Content.Shared.Nutrition.Components;
@@ -56,11 +57,14 @@ public sealed partial class ThirstComponent : Component
{ThirstThreshold.Dead, 0.0f}, {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.Thirsty, "Thirsty"},
{ThirstThreshold.Parched, AlertType.Parched}, {ThirstThreshold.Parched, "Parched"},
{ThirstThreshold.Dead, AlertType.Parched}, {ThirstThreshold.Dead, "Parched"},
}; };
} }

View File

@@ -61,7 +61,7 @@ public sealed class HungerSystem : EntitySystem
private void OnShutdown(EntityUid uid, HungerComponent component, ComponentShutdown args) 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) private void OnRefreshMovespeed(EntityUid uid, HungerComponent component, RefreshMovementSpeedModifiersEvent args)
@@ -142,7 +142,7 @@ public sealed class HungerSystem : EntitySystem
} }
else else
{ {
_alerts.ClearAlertCategory(uid, AlertCategory.Hunger); _alerts.ClearAlertCategory(uid, component.HungerAlertCategory);
} }
if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier)) if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier))

View File

@@ -165,7 +165,7 @@ public sealed class ThirstSystem : EntitySystem
} }
else else
{ {
_alerts.ClearAlertCategory(uid, AlertCategory.Thirst); _alerts.ClearAlertCategory(uid, component.ThirstyCategory);
} }
switch (component.CurrentThirstThreshold) switch (component.CurrentThirstThreshold)

View File

@@ -1,4 +1,5 @@
using System.Numerics; using System.Numerics;
using Content.Shared.Alert;
using Content.Shared.FixedPoint; using Content.Shared.FixedPoint;
using Content.Shared.Store; using Content.Shared.Store;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
@@ -200,6 +201,9 @@ public sealed partial class RevenantComponent : Component
public EntityWhitelist? MalfunctionBlacklist; public EntityWhitelist? MalfunctionBlacklist;
#endregion #endregion
[DataField]
public ProtoId<AlertPrototype> EssenceAlert = "Essence";
#region Visualizer #region Visualizer
[DataField("state")] [DataField("state")]
public string State = "idle"; public string State = "idle";

View File

@@ -1,7 +1,9 @@
using System.Numerics; using System.Numerics;
using Content.Shared.Alert;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Shared.Shuttles.Components namespace Content.Shared.Shuttles.Components
@@ -32,6 +34,9 @@ namespace Content.Shared.Shuttles.Components
[ViewVariables] [ViewVariables]
public ShuttleButtons HeldButtons = ShuttleButtons.None; public ShuttleButtons HeldButtons = ShuttleButtons.None;
[DataField]
public ProtoId<AlertPrototype> PilotingAlert = "PilotingShuttle";
public override bool SendOnlyToOwner => true; public override bool SendOnlyToOwner => true;
} }
} }

View File

@@ -1,6 +1,8 @@
using Content.Shared.Whitelist; using Content.Shared.Alert;
using Content.Shared.Whitelist;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Silicons.Borgs.Components; namespace Content.Shared.Silicons.Borgs.Components;
@@ -76,6 +78,12 @@ public sealed partial class BorgChassisComponent : Component
[DataField("noMindState")] [DataField("noMindState")]
public string NoMindState = string.Empty; public string NoMindState = string.Empty;
#endregion #endregion
[DataField]
public ProtoId<AlertPrototype> BatteryAlert = "BorgBattery";
[DataField]
public ProtoId<AlertPrototype> NoBatteryAlert = "BorgBatteryNone";
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]

View File

@@ -10,7 +10,7 @@ namespace Content.Shared.StatusEffect
public string ID { get; private set; } = default!; public string ID { get; private set; } = default!;
[DataField("alert")] [DataField("alert")]
public AlertType? Alert { get; private set; } public ProtoId<AlertPrototype>? Alert { get; private set; }
/// <summary> /// <summary>
/// Whether a status effect should be able to apply to any entity, /// Whether a status effect should be able to apply to any entity,

View 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 /// This is mostly for stuns, since Stun and Knockdown share an alert key. Other times this pretty much
/// will not be useful. /// will not be useful.
/// </remarks> /// </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; (TimeSpan, TimeSpan)? maxCooldown = null;
foreach (var kvp in status.ActiveEffects) foreach (var kvp in status.ActiveEffects)

View File

@@ -42,6 +42,9 @@ public sealed class ReflectSystem : EntitySystem
[Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly StandingStateSystem _standing = default!;
[Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly AlertsSystem _alerts = default!;
[ValidatePrototypeId<AlertPrototype>]
private const string DeflectingAlert = "Deflecting";
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@@ -296,11 +299,11 @@ public sealed class ReflectSystem : EntitySystem
private void EnableAlert(EntityUid alertee) private void EnableAlert(EntityUid alertee)
{ {
_alerts.ShowAlert(alertee, AlertType.Deflecting); _alerts.ShowAlert(alertee, DeflectingAlert);
} }
private void DisableAlert(EntityUid alertee) private void DisableAlert(EntityUid alertee)
{ {
_alerts.ClearAlert(alertee, AlertType.Deflecting); _alerts.ClearAlert(alertee, DeflectingAlert);
} }
} }

View File

@@ -1,6 +1,5 @@
using System.IO; using System.IO;
using Content.Client.Alerts; using Content.Client.Alerts;
using Content.Server.Alert;
using Content.Shared.Alert; using Content.Shared.Alert;
using NUnit.Framework; using NUnit.Framework;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -45,15 +44,15 @@ namespace Content.Tests.Shared.Alert
prototypeManager.Initialize(); prototypeManager.Initialize();
prototypeManager.LoadFromStream(new StringReader(PROTOTYPES)); prototypeManager.LoadFromStream(new StringReader(PROTOTYPES));
Assert.That(alertsSystem.TryGet(AlertType.LowPressure, out var lowPressure)); 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(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(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(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(alertsSystem.TryGet("LowPressure", out lowPressure));
Assert.That(lowPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png")))); 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(alertsSystem.TryGet("HighPressure", out highPressure));
Assert.That(highPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png")))); Assert.That(highPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
} }
} }
} }

View File

@@ -85,24 +85,24 @@ namespace Content.Tests.Shared.Alert
var alerts = prototypeManager.EnumeratePrototypes<AlertPrototype>(); var alerts = prototypeManager.EnumeratePrototypes<AlertPrototype>();
// ensure they sort according to our expected criteria // ensure they sort according to our expected criteria
var expectedOrder = new List<AlertType>(); var expectedOrder = new List<string>();
expectedOrder.Add(AlertType.Handcuffed); expectedOrder.Add("Handcuffed");
expectedOrder.Add(AlertType.Ensnared); expectedOrder.Add("Ensnared");
expectedOrder.Add(AlertType.HighPressure); expectedOrder.Add("HighPressure");
// stuff with only category + same category ordered by enum value // stuff with only category + same category ordered by enum value
expectedOrder.Add(AlertType.Peckish); expectedOrder.Add("Peckish");
expectedOrder.Add(AlertType.Hot); expectedOrder.Add("Hot");
expectedOrder.Add(AlertType.Stun); expectedOrder.Add("Stun");
expectedOrder.Add(AlertType.LowPressure); expectedOrder.Add("LowPressure");
expectedOrder.Add(AlertType.Cold); expectedOrder.Add("Cold");
// stuff at end of list ordered by enum value // stuff at end of list ordered by ID
expectedOrder.Add(AlertType.Weightless); expectedOrder.Add("PilotingShuttle");
expectedOrder.Add(AlertType.PilotingShuttle); expectedOrder.Add("Weightless");
var actual = alerts.ToList(); var actual = alerts.ToList();
actual.Sort(alertOrder); 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));
} }
} }
} }

View File

@@ -39,9 +39,9 @@ namespace Content.Tests.Shared.Alert
[Test] [Test]
public void TestAlertKey() public void TestAlertKey()
{ {
Assert.That(new AlertKey(AlertType.HumanHealth, null), Is.Not.EqualTo(AlertKey.ForCategory(AlertCategory.Health))); Assert.That(new AlertKey("HumanHealth", null), Is.Not.EqualTo(AlertKey.ForCategory("Health")));
Assert.That((new AlertKey(null, AlertCategory.Health)), Is.EqualTo(AlertKey.ForCategory(AlertCategory.Health))); Assert.That((new AlertKey(null, "Health")), Is.EqualTo(AlertKey.ForCategory("Health")));
Assert.That((new AlertKey(AlertType.Buckled, AlertCategory.Health)), Is.EqualTo(AlertKey.ForCategory(AlertCategory.Health))); Assert.That((new AlertKey("Buckled", "Health")), Is.EqualTo(AlertKey.ForCategory("Health")));
} }
[TestCase(0, "/Textures/Interface/Alerts/Human/human.rsi/human0.png")] [TestCase(0, "/Textures/Interface/Alerts/Human/human.rsi/human0.png")]

View File

@@ -15,6 +15,9 @@ namespace Content.Tests.Shared.Alert
public sealed class ServerAlertsComponentTests : ContentUnitTest public sealed class ServerAlertsComponentTests : ContentUnitTest
{ {
const string PROTOTYPES = @" const string PROTOTYPES = @"
- type: alertCategory
id: Pressure
- type: alert - type: alert
id: LowPressure id: LowPressure
category: Pressure category: Pressure
@@ -49,10 +52,10 @@ namespace Content.Tests.Shared.Alert
var alertsComponent = new AlertsComponent(); var alertsComponent = new AlertsComponent();
alertsComponent = IoCManager.InjectDependencies(alertsComponent); alertsComponent = IoCManager.InjectDependencies(alertsComponent);
Assert.That(entManager.System<AlertsSystem>().TryGet(AlertType.LowPressure, out var lowpressure)); Assert.That(entManager.System<AlertsSystem>().TryGet("LowPressure", out var lowpressure));
Assert.That(entManager.System<AlertsSystem>().TryGet(AlertType.HighPressure, out var highpressure)); 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(); var getty = new ComponentGetState();
entManager.EventBus.RaiseComponentEvent(alertsComponent, getty); entManager.EventBus.RaiseComponentEvent(alertsComponent, getty);
@@ -60,17 +63,17 @@ namespace Content.Tests.Shared.Alert
var alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!; var alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!;
Assert.That(alertState, Is.Not.Null); Assert.That(alertState, Is.Not.Null);
Assert.That(alertState.Alerts.Count, Is.EqualTo(1)); 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 // Lazy
entManager.EventBus.RaiseComponentEvent(alertsComponent, getty); entManager.EventBus.RaiseComponentEvent(alertsComponent, getty);
alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!; alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!;
Assert.That(alertState.Alerts.Count, Is.EqualTo(1)); 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); entManager.EventBus.RaiseComponentEvent(alertsComponent, getty);
alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!; alertState = (AlertsComponent.AlertsComponent_AutoState) getty.State!;

View File

@@ -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