ClearAlerts?.Invoke(this, EventArgs.Empty);
}
- public void AlertClicked(AlertType alertType)
+ public void AlertClicked(ProtoId<AlertPrototype> alertType)
{
RaiseNetworkEvent(new ClickAlertEvent(alertType));
}
using Content.Client.Alerts;
-using Content.Shared.Alert;
using Content.Shared.Revenant;
using Content.Shared.Revenant.Components;
using Robust.Client.GameObjects;
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;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
+using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.Systems.Alerts;
SyncAlerts();
}
- private void OnAlertPressed(object? sender, AlertType e)
+ private void OnAlertPressed(object? sender, ProtoId<AlertPrototype> e)
{
_alertsSystem?.AlertClicked(e);
}
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;
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))
_alertControls.Clear();
}
- public event EventHandler<AlertType>? AlertPressed;
+ public event EventHandler<ProtoId<AlertPrototype>>? AlertPressed;
private bool SyncRemoveControls(IReadOnlyDictionary<AlertKey, AlertState> alertStates)
{
}
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);
if (args.Event.Function != EngineKeyFunctions.UIClick)
return;
- AlertPressed?.Invoke(this, control.Alert.AlertType);
+ AlertPressed?.Invoke(this, control.Alert.ID);
}
}
using Robust.Client.UserInterface;
using Robust.Server.Player;
using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
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));
});
// 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);
// 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));
});
using Content.Server.Gravity;
using Content.Shared.Alert;
+using Content.Shared.Gravity;
using Robust.Shared.GameObjects;
namespace Content.IntegrationTests.Tests.Gravity
var entityManager = server.ResolveDependency<IEntityManager>();
var alertsSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AlertsSystem>();
+ var weightlessAlert = SharedGravitySystem.WeightlessAlert;
EntityUid human = default;
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);
});
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);
await server.WaitAssertion(() =>
{
- Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless));
+ Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert));
});
await pair.RunTicksSync(10);
+using Content.Shared.Alert;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
/// </summary>
[DataField("vowCooldown")]
public TimeSpan VowCooldown = TimeSpan.FromMinutes(5);
+
+ [DataField]
+ public ProtoId<AlertPrototype> VowAlert = "VowOfSilence";
+
+ [DataField]
+ public ProtoId<AlertPrototype> VowBrokenAlert = "VowBroken";
+
}
}
using Content.Server.Popups;
-using Content.Server.Speech.Muting;
using Content.Shared.Actions;
using Content.Shared.Actions.Events;
using Content.Shared.Alert;
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);
}
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);
}
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);
}
}
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);
}
}
}
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;
}
short? severity1 = sevint == -1 ? null : sevint;
- alertsSystem.ShowAlert(attachedEntity, alert.AlertType, severity1, null);
+ alertsSystem.ShowAlert(attachedEntity, alert.ID, severity1, null);
}
}
}
+using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
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";
}
}
+using Content.Shared.Alert;
using Content.Shared.Damage;
using Robust.Shared.Physics.Collision.Shapes;
+using Robust.Shared.Prototypes;
namespace Content.Server.Atmos.Components
{
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float FirestackFade = -0.1f;
+
+ [DataField]
+ public ProtoId<AlertPrototype> FireAlert = "Fire";
}
}
_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)
{
_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
{
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;
}
}
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)
{
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;
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public TimeSpan StatusTime;
+
+ [DataField]
+ public ProtoId<AlertPrototype> BleedingAlert = "Bleed";
}
}
+using Content.Shared.Alert;
+using Robust.Shared.Prototypes;
+
namespace Content.Server.Body.Components
{
/// <summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public TimeSpan Delay = TimeSpan.FromSeconds(3);
+
+ [DataField]
+ public ProtoId<AlertPrototype> InternalsAlert = "Internals";
}
}
-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;
/// 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";
}
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;
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)
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)
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)
}
ent.Comp.BreathToolEntity = toolEntity;
- _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
+ _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
}
public void DisconnectTank(InternalsComponent? component)
_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)
_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;
}
/// <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.
if (Clear && Time <= 0)
{
- alertSys.ClearAlert(args.SolutionEntity, Type);
+ alertSys.ClearAlert(args.SolutionEntity, AlertType);
}
else
{
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);
}
}
if (state)
{
- _alerts.ShowAlert(parent, AlertType.Magboots);
+ _alerts.ShowAlert(parent, component.MagbootsAlert);
}
else
{
- _alerts.ClearAlert(parent, AlertType.Magboots);
+ _alerts.ClearAlert(parent, component.MagbootsAlert);
}
}
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);
}
}
/// </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);
}
}
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)
{
component.SubscribedPilots.Add(entity);
- _alertsSystem.ShowAlert(entity, AlertType.PilotingShuttle);
+ _alertsSystem.ShowAlert(entity, pilotComponent.PilotingAlert);
pilotComponent.Console = uid;
ActionBlockerSystem.UpdateCanMove(entity);
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);
private void OnMapInit(EntityUid uid, BorgChassisComponent component, MapInitEvent args)
{
- UpdateBatteryAlert(uid);
+ UpdateBatteryAlert((uid, component));
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
}
private void OnPowerCellChanged(EntityUid uid, BorgChassisComponent component, PowerCellChangedEvent args)
{
- UpdateBatteryAlert(uid);
+ UpdateBatteryAlert((uid, component));
if (!TryComp<PowerCellDrawComponent>(uid, out var draw))
return;
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;
}
// 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>
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;
/// </summary>
[DataField]
public bool TakingDamage = false;
+
+ [DataField]
+ public ProtoId<AlertPrototype> HotAlert = "Hot";
+
+ [DataField]
+ public ProtoId<AlertPrototype> ColdAlert = "Cold";
}
using Content.Shared.Rejuvenate;
using Content.Shared.Temperature;
using Robust.Shared.Physics.Components;
+using Robust.Shared.Prototypes;
namespace Content.Server.Temperature.Systems;
private float _accumulatedFrametime;
+ [ValidatePrototypeId<AlertCategoryPrototype>]
+ public const string TemperatureAlertCategory = "Temperature";
+
public override void Initialize()
{
SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage);
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;
}
if (args.CurrentTemperature <= idealTemp)
{
- type = AlertType.Cold;
+ type = temperature.ColdAlert;
threshold = temperature.ColdDamageThreshold;
}
else
{
- type = AlertType.Hot;
+ type = temperature.HotAlert;
threshold = temperature.HeatDamageThreshold;
}
break;
case > 0.66f:
- _alerts.ClearAlertCategory(uid, AlertCategory.Temperature);
+ _alerts.ClearAlertCategory(uid, TemperatureAlertCategory);
break;
}
}
+++ /dev/null
-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
-}
--- /dev/null
+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!;
+}
-using Robust.Shared.Serialization;
-using Robust.Shared.Serialization.Manager;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
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;
/// <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);
}
/// <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>
{
[IdDataField]
public string ID { get; private set; } = default!;
- [DataField("order")]
+ [DataField]
private (string type, string alert)[] Order
{
// why would paul do this to me.
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();
}
}
- 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;
}
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
{
// 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;
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];
}
}
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Alert;
public (TimeSpan, TimeSpan)? Cooldown;
public bool AutoRemove;
public bool ShowCooldown;
- public AlertType Type;
+ public ProtoId<AlertPrototype> Type;
}
+++ /dev/null
-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
- }
-
-}
[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)
{
: 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;
}
/// <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));
/// 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)
/// <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;
/// <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;
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);
}
}
/// 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);
}
-using Robust.Shared.Serialization;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
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;
}
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;
/// </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
SubscribeLocalEvent<BuckleComponent, UpdateCanMoveEvent>(OnBuckleUpdateCanMove);
}
+ [ValidatePrototypeId<AlertCategoryPrototype>]
+ public const string BuckledAlertCategory = "Buckled";
+
private void OnBuckleComponentStartup(EntityUid uid, BuckleComponent component, ComponentStartup args)
{
UpdateBuckleStatus(uid, component);
}
else
{
- _alerts.ClearAlertCategory(uid, AlertCategory.Buckled);
+ _alerts.ClearAlertCategory(uid, BuckledAlertCategory);
}
}
+using Content.Shared.Alert;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
[DataField("on"), AutoNetworkedField]
public bool On;
+
+ [DataField]
+ public ProtoId<AlertPrototype> MagbootsAlert = "Magboots";
}
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;
_actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false);
}
- _alertsSystem.ShowAlert(uid, AlertType.Pacified);
+ _alertsSystem.ShowAlert(uid, component.PacifiedAlert);
}
private void OnShutdown(EntityUid uid, PacifiedComponent component, ComponentShutdown args)
_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)
+using Content.Shared.Alert;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
namespace Content.Shared.CombatMode.Pacification;
[DataField]
public EntityUid? LastAttackedEntity = null;
+ [DataField]
+ public ProtoId<AlertPrototype> PacifiedAlert = "Pacified";
}
+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;
/// </summary>
[DataField("canStillInteract"), ViewVariables(VVAccess.ReadWrite)]
public bool CanStillInteract = true;
+
+ [DataField]
+ public ProtoId<AlertPrototype> CuffedAlert = "Handcuffed";
}
[Serializable, NetSerializable]
_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);
+using Content.Shared.Alert;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Damage.Components;
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
[AutoPausedField]
public TimeSpan NextUpdate = TimeSpan.Zero;
+
+ [DataField]
+ public ProtoId<AlertPrototype> StaminaAlert = "Stamina";
}
{
RemCompDeferred<ActiveStaminaComponent>(uid);
}
-
- SetStaminaAlert(uid);
+ _alerts.ClearAlert(uid, component.StaminaAlert);
}
private void OnStartup(EntityUid uid, StaminaComponent component, ComponentStartup args)
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>
+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;
[DataField("state")]
public string? State;
+
+ [DataField]
+ public ProtoId<AlertPrototype> EnsnaredAlert = "Ensnared";
}
[Serializable, NetSerializable]
[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);
if (!ev.HasGravity)
{
- _alerts.ShowAlert(uid, AlertType.Weightless);
+ _alerts.ShowAlert(uid, WeightlessAlert);
}
else
{
- _alerts.ClearAlert(uid, AlertType.Weightless);
+ _alerts.ClearAlert(uid, WeightlessAlert);
}
}
}
{
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);
}
}
{
if (IsWeightless(uid))
{
- _alerts.ShowAlert(uid, AlertType.Weightless);
+ _alerts.ShowAlert(uid, WeightlessAlert);
}
else
{
- _alerts.ClearAlert(uid, AlertType.Weightless);
+ _alerts.ClearAlert(uid, WeightlessAlert);
}
}
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;
/// 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>
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;
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)
+using Content.Shared.Alert;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
namespace Content.Shared.Movement.Pulling.Components;
[Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)]
[AutoNetworkedField, DataField]
public bool PrevFixedRotation;
+
+ [DataField]
+ public ProtoId<AlertPrototype> PulledAlert = "Pulled";
}
-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;
/// </summary>
[DataField]
public bool NeedsHands = true;
+
+ [DataField]
+ public ProtoId<AlertPrototype> PullingAlert = "Pulling";
}
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);
}
- _alertsSystem.ClearAlert(pullableUid, AlertType.Pulled);
+ _alertsSystem.ClearAlert(pullableUid, pullableComp.PulledAlert);
}
public bool IsPulled(EntityUid uid, PullableComponent? component = null)
// 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);
+using Content.Shared.Alert;
using Content.Shared.Ninja.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
/// </summary>
[DataField]
public EntProtoId SpiderChargeObjective = "SpiderChargeObjective";
+
+ [DataField]
+ public ProtoId<AlertPrototype> SuitPowerAlert = "SuitPower";
}
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;
/// <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>
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;
{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"},
};
}
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)
}
else
{
- _alerts.ClearAlertCategory(uid, AlertCategory.Hunger);
+ _alerts.ClearAlertCategory(uid, component.HungerAlertCategory);
}
if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier))
}
else
{
- _alerts.ClearAlertCategory(uid, AlertCategory.Thirst);
+ _alerts.ClearAlertCategory(uid, component.ThirstyCategory);
}
switch (component.CurrentThirstThreshold)
using System.Numerics;
+using Content.Shared.Alert;
using Content.Shared.FixedPoint;
using Content.Shared.Store;
using Content.Shared.Whitelist;
public EntityWhitelist? MalfunctionBlacklist;
#endregion
+ [DataField]
+ public ProtoId<AlertPrototype> EssenceAlert = "Essence";
+
#region Visualizer
[DataField("state")]
public string State = "idle";
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
[ViewVariables]
public ShuttleButtons HeldButtons = ShuttleButtons.None;
+ [DataField]
+ public ProtoId<AlertPrototype> PilotingAlert = "PilotingShuttle";
+
public override bool SendOnlyToOwner => true;
}
}
-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;
[DataField("noMindState")]
public string NoMindState = string.Empty;
#endregion
+
+ [DataField]
+ public ProtoId<AlertPrototype> BatteryAlert = "BorgBattery";
+
+ [DataField]
+ public ProtoId<AlertPrototype> NoBatteryAlert = "BorgBatteryNone";
}
[Serializable, NetSerializable]
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,
/// 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)
[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();
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);
}
}
using System.IO;
using Content.Client.Alerts;
-using Content.Server.Alert;
using Content.Shared.Alert;
using NUnit.Framework;
using Robust.Shared.GameObjects;
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"))));
}
}
}
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));
}
}
}
[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")]
public sealed class ServerAlertsComponentTests : ContentUnitTest
{
const string PROTOTYPES = @"
+- type: alertCategory
+ id: Pressure
+
- type: alert
id: LowPressure
category: Pressure
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);
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!;
--- /dev/null
+- 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