Alerts System and UI (#2529)

* #272 add bordered panel for effects bar

* #272 avoid mouse overlapping tooltip when near edges,
change tooltip colors to match mockups

* #272 WIP defining status effect states as YML and
sending them as encoded integers

* #272 refactor to use new alert system

* #272 refactor to use new alert system

* #272 fix various bugs with new alert system and update
alerts to have color

* #272 WIP

* #272 rename status effects to alerts

* #272 WIP reworking alert internals to avoid code dup
and eliminate enum

* #272 refactor alerts to use
categories and fix various bugs

* #272 more alert bugfixes

* #272 alert ordering

* #272 callback-based approach for alert clicks

* #272 add debug commands for alerts

* #272 utilize new GridContainer capabilities for sizing of alerts tab

* #272 scale alerts height based on
window size

* #272 fix tooltip flicker

* #272 transparent alert panel

* #272 adjust styles to match injazz mockups more, add cooldown info in tooltip

* #272 adjust styles to match injazz mockups more, add cooldown info in tooltip

* #272 alert prototype tests

* #272 alert manager tests

* #272 alert order tests

* #272 simple unit test for alerts component

* #272 integration test for alerts

* #272 rework alerts to use enums instead
of id / category

* #272 various cleanups for PR

* #272 use byte for more compact alert messages

* #272 rename StatusEffects folder to Alerts,
add missing NetSerializable
This commit is contained in:
chairbender
2020-11-09 20:22:19 -08:00
committed by GitHub
parent c82199610d
commit 5f788c3318
86 changed files with 2305 additions and 598 deletions

View File

@@ -6,6 +6,7 @@ using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems.DoAfter;
using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.ActionBlocking;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.EntitySystems;
@@ -115,7 +116,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
CanStillInteract = _hands.Hands.Count() > CuffedHandCount;
OnCuffedStateChanged.Invoke();
UpdateStatusEffect();
UpdateAlert();
UpdateHeldItems();
Dirty();
}
@@ -181,17 +182,17 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
/// <summary>
/// Updates the status effect indicator on the HUD.
/// </summary>
private void UpdateStatusEffect()
private void UpdateAlert()
{
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
if (Owner.TryGetComponent(out ServerAlertsComponent status))
{
if (CanStillInteract)
{
status.RemoveStatusEffect(StatusEffect.Cuffed);
status.ClearAlert(AlertType.Handcuffed);
}
else
{
status.ChangeStatusEffectIcon(StatusEffect.Cuffed, "/Textures/Interface/StatusEffects/Handcuffed/Handcuffed.png");
status.ShowAlert(AlertType.Handcuffed);
}
}
}
@@ -282,7 +283,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
CanStillInteract = _hands.Hands.Count() > CuffedHandCount;
OnCuffedStateChanged.Invoke();
UpdateStatusEffect();
UpdateAlert();
Dirty();
if (CuffedHandCount == 0)

View File

@@ -2,6 +2,7 @@
using System.Runtime.CompilerServices;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.Interfaces.GameObjects;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
@@ -22,7 +23,7 @@ namespace Content.Server.GameObjects.Components.Atmos
public void Update(float airPressure)
{
if (!Owner.TryGetComponent(out IDamageableComponent damageable)) return;
Owner.TryGetComponent(out ServerStatusEffectsComponent status);
Owner.TryGetComponent(out ServerAlertsComponent status);
var highPressureMultiplier = 1f;
var lowPressureMultiplier = 1f;
@@ -50,11 +51,11 @@ namespace Content.Server.GameObjects.Components.Atmos
if (pressure <= Atmospherics.HazardLowPressure)
{
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure2.png", null);
status.ShowAlert(AlertType.LowPressure, 2);
break;
}
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure1.png", null);
status.ShowAlert(AlertType.LowPressure, 1);
break;
// High pressure.
@@ -72,16 +73,16 @@ namespace Content.Server.GameObjects.Components.Atmos
if (pressure >= Atmospherics.HazardHighPressure)
{
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure2.png", null);
status.ShowAlert(AlertType.HighPressure, 2);
break;
}
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure1.png", null);
status.ShowAlert(AlertType.HighPressure, 1);
break;
// Normal pressure.
default:
status?.RemoveStatusEffect(StatusEffect.Pressure);
status?.ClearAlertCategory(AlertCategory.Pressure);
break;
}

View File

@@ -4,6 +4,7 @@ using Content.Server.Atmos;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.Components.Temperature;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Chemistry;
using Content.Shared.Damage;
@@ -93,15 +94,15 @@ namespace Content.Server.GameObjects.Components.Atmos
FireStacks = MathF.Min(0, FireStacks + 1);
}
Owner.TryGetComponent(out ServerStatusEffectsComponent status);
Owner.TryGetComponent(out ServerAlertsComponent status);
if (!OnFire)
{
status?.RemoveStatusEffect(StatusEffect.Fire);
status?.ClearAlert(AlertType.Fire);
return;
}
status?.ChangeStatusEffect(StatusEffect.Fire, "/Textures/Interface/StatusEffects/Fire/fire.png", null);
status.ShowAlert(AlertType.Fire, onClickAlert: OnClickAlert);
if (FireStacks > 0)
{
@@ -153,6 +154,14 @@ namespace Content.Server.GameObjects.Components.Atmos
}
}
private void OnClickAlert(ClickAlertEventArgs args)
{
if (args.Player.TryGetComponent(out FlammableComponent flammable))
{
flammable.Resist();
}
}
public void CollideWith(IEntity collidedWith)
{
if (!collidedWith.TryGetComponent(out FlammableComponent otherFlammable))

View File

@@ -7,6 +7,7 @@ using Content.Server.GameObjects.Components.Mobs.State;
using Content.Server.GameObjects.Components.Pulling;
using Content.Server.GameObjects.Components.Strap;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Buckle;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Strap;
@@ -37,7 +38,7 @@ namespace Content.Server.GameObjects.Components.Buckle
[Dependency] private readonly IGameTiming _gameTiming = default!;
[ComponentDependency] public readonly AppearanceComponent? AppearanceComponent = null;
[ComponentDependency] private readonly ServerStatusEffectsComponent? _serverStatusEffectsComponent = null;
[ComponentDependency] private readonly ServerAlertsComponent? _serverAlertsComponent = null;
[ComponentDependency] private readonly StunnableComponent? _stunnableComponent = null;
[ComponentDependency] private readonly MobStateManagerComponent? _mobStateManagerComponent = null;
@@ -100,21 +101,31 @@ namespace Content.Server.GameObjects.Components.Buckle
/// </summary>
private void UpdateBuckleStatus()
{
if (_serverStatusEffectsComponent == null)
if (_serverAlertsComponent == null)
{
return;
}
if (Buckled)
{
_serverStatusEffectsComponent.ChangeStatusEffectIcon(StatusEffect.Buckled, BuckledTo!.BuckledIcon);
_serverAlertsComponent.ShowAlert(BuckledTo != null ? BuckledTo.BuckledAlertType : AlertType.Buckled,
onClickAlert: OnClickAlert);
}
else
{
_serverStatusEffectsComponent.RemoveStatusEffect(StatusEffect.Buckled);
_serverAlertsComponent.ClearAlertCategory(AlertCategory.Buckled);
}
}
private void OnClickAlert(ClickAlertEventArgs args)
{
if (args.Player.TryGetComponent(out BuckleComponent? buckle))
{
buckle.TryUnbuckle(args.Player);
}
}
/// <summary>
/// Reattaches this entity to the strap, modifying its position and rotation.
/// </summary>

View File

@@ -0,0 +1,166 @@
using System;
using Content.Server.Commands;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Server.Interfaces.Console;
using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Players;
namespace Content.Server.GameObjects.Components.Mobs
{
[RegisterComponent]
[ComponentReference(typeof(SharedAlertsComponent))]
public sealed class ServerAlertsComponent : SharedAlertsComponent
{
protected override void Startup()
{
base.Startup();
if (EntitySystem.TryGet<WeightlessSystem>(out var weightlessSystem))
{
weightlessSystem.AddAlert(this);
}
else
{
Logger.WarningS("alert", "weightlesssystem not found");
}
}
public override void OnRemove()
{
if (EntitySystem.TryGet<WeightlessSystem>(out var weightlessSystem))
{
weightlessSystem.RemoveAlert(this);
}
else
{
Logger.WarningS("alert", "weightlesssystem not found");
}
base.OnRemove();
}
public override ComponentState GetComponentState()
{
return new AlertsComponentState(CreateAlertStatesArray());
}
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null)
{
base.HandleNetworkMessage(message, netChannel, session);
if (session == null)
{
throw new ArgumentNullException(nameof(session));
}
switch (message)
{
case ClickAlertMessage msg:
{
var player = session.AttachedEntity;
if (player != Owner)
{
break;
}
// TODO: Implement clicking other status effects in the HUD
if (AlertManager.TryDecode(msg.EncodedAlert, out var alert))
{
PerformAlertClickCallback(alert, player);
}
else
{
Logger.WarningS("alert", "unrecognized encoded alert {0}", msg.EncodedAlert);
}
break;
}
}
}
}
public sealed class ShowAlert : IClientCommand
{
public string Command => "showalert";
public string Description => "Shows an alert for a player, defaulting to current player";
public string Help => "showalert <alertType> <severity, -1 if no severity> <name or userID, omit for current player>";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
var attachedEntity = player.AttachedEntity;
if (args.Length > 2)
{
var target = args[2];
if (!Commands.CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
}
if (!CommandUtils.ValidateAttachedEntity(shell, player, attachedEntity)) return;
if (!attachedEntity.TryGetComponent(out ServerAlertsComponent alertsComponent))
{
shell.SendText(player, "user has no alerts component");
return;
}
var alertType = args[0];
var severity = args[1];
var alertMgr = IoCManager.Resolve<AlertManager>();
if (!alertMgr.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
{
shell.SendText(player, "unrecognized alertType " + alertType);
return;
}
if (!short.TryParse(severity, out var sevint))
{
shell.SendText(player, "invalid severity " + sevint);
return;
}
alertsComponent.ShowAlert(alert.AlertType, sevint == -1 ? (short?) null : sevint);
}
}
public sealed class ClearAlert : IClientCommand
{
public string Command => "clearalert";
public string Description => "Clears an alert for a player, defaulting to current player";
public string Help => "clearalert <alertType> <name or userID, omit for current player>";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
var attachedEntity = player.AttachedEntity;
if (args.Length > 1)
{
var target = args[1];
if (!CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
}
if (!CommandUtils.ValidateAttachedEntity(shell, player, attachedEntity)) return;
if (!attachedEntity.TryGetComponent(out ServerAlertsComponent alertsComponent))
{
shell.SendText(player, "user has no alerts component");
return;
}
var alertType = args[0];
var alertMgr = IoCManager.Resolve<AlertManager>();
if (!alertMgr.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
{
shell.SendText(player, "unrecognized alertType " + alertType);
return;
}
alertsComponent.ClearAlert(alert.AlertType);
}
}
}

View File

@@ -1,152 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Atmos;
using Content.Server.GameObjects.Components.Buckle;
using Content.Server.GameObjects.Components.Movement;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Pulling;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Players;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Mobs
{
[RegisterComponent]
[ComponentReference(typeof(SharedStatusEffectsComponent))]
public sealed class ServerStatusEffectsComponent : SharedStatusEffectsComponent
{
[ViewVariables]
private readonly Dictionary<StatusEffect, StatusEffectStatus> _statusEffects = new Dictionary<StatusEffect, StatusEffectStatus>();
public override IReadOnlyDictionary<StatusEffect, StatusEffectStatus> Statuses => _statusEffects;
protected override void Startup()
{
base.Startup();
EntitySystem.Get<WeightlessSystem>().AddStatus(this);
}
public override void OnRemove()
{
EntitySystem.Get<WeightlessSystem>().RemoveStatus(this);
base.OnRemove();
}
public override ComponentState GetComponentState()
{
return new StatusEffectComponentState(_statusEffects);
}
public override void ChangeStatusEffectIcon(StatusEffect effect, string icon)
{
if (_statusEffects.TryGetValue(effect, out var value) && value.Icon == icon)
{
return;
}
_statusEffects[effect] = new StatusEffectStatus()
{Icon = icon, Cooldown = value.Cooldown};
Dirty();
}
public void ChangeStatusEffectCooldown(StatusEffect effect, ValueTuple<TimeSpan, TimeSpan> cooldown)
{
if (_statusEffects.TryGetValue(effect, out var value)
&& value.Cooldown == cooldown)
{
return;
}
_statusEffects[effect] = new StatusEffectStatus()
{
Icon = value.Icon, Cooldown = cooldown
};
Dirty();
}
public override void ChangeStatusEffect(StatusEffect effect, string icon, ValueTuple<TimeSpan, TimeSpan>? cooldown)
{
_statusEffects[effect] = new StatusEffectStatus()
{Icon = icon, Cooldown = cooldown};
Dirty();
}
public override void RemoveStatusEffect(StatusEffect effect)
{
if (!_statusEffects.Remove(effect))
{
return;
}
Dirty();
}
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null)
{
base.HandleNetworkMessage(message, netChannel, session);
if (session == null)
{
throw new ArgumentNullException(nameof(session));
}
switch (message)
{
case ClickStatusMessage msg:
{
var player = session.AttachedEntity;
if (player != Owner)
{
break;
}
// TODO: Implement clicking other status effects in the HUD
switch (msg.Effect)
{
case StatusEffect.Buckled:
if (!player.TryGetComponent(out BuckleComponent buckle))
break;
buckle.TryUnbuckle(player);
break;
case StatusEffect.Piloting:
if (!player.TryGetComponent(out ShuttleControllerComponent controller))
break;
controller.RemoveController();
break;
case StatusEffect.Pulling:
EntitySystem
.Get<SharedPullingSystem>()
.GetPulled(player)?
.GetComponentOrNull<SharedPullableComponent>()?
.TryStopPull();
break;
case StatusEffect.Fire:
if (!player.TryGetComponent(out FlammableComponent flammable))
break;
flammable.Resist();
break;
default:
player.PopupMessage(msg.Effect.ToString());
break;
}
break;
}
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Mobs.State;
@@ -17,10 +18,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
appearance.SetData(DamageStateVisuals.State, DamageState.Critical);
}
if (entity.TryGetComponent(out ServerStatusEffectsComponent status))
if (entity.TryGetComponent(out ServerAlertsComponent status))
{
status.ChangeStatusEffectIcon(StatusEffect.Health,
"/Textures/Interface/StatusEffects/Human/humancrit-0.png"); //Todo: combine humancrit-0 and humancrit-1 into a gif and display it
status.ShowAlert(AlertType.HumanCrit); //Todo: combine humancrit-0 and humancrit-1 into a gif and display it
}
if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlay))

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Mobs.State;
@@ -18,10 +19,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
appearance.SetData(DamageStateVisuals.State, DamageState.Dead);
}
if (entity.TryGetComponent(out ServerStatusEffectsComponent status))
if (entity.TryGetComponent(out ServerAlertsComponent status))
{
status.ChangeStatusEffectIcon(StatusEffect.Health,
"/Textures/Interface/StatusEffects/Human/humandead.png");
status.ShowAlert(AlertType.HumanDead);
}
if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlayComponent))

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Mobs.State;
@@ -51,9 +52,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
// TODO: Might want to add an OnRemove() to IMobState since those are where these components are being used
base.OnRemove();
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
if (Owner.TryGetComponent(out ServerAlertsComponent status))
{
status.RemoveStatusEffect(StatusEffect.Health);
status.ClearAlert(AlertType.HumanHealth);
}
if (Owner.TryGetComponent(out ServerOverlayEffectsComponent overlay))

View File

@@ -1,5 +1,6 @@
using Content.Server.GameObjects.Components.Damage;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Mobs.State;
@@ -27,15 +28,14 @@ namespace Content.Server.GameObjects.Components.Mobs.State
public override void UpdateState(IEntity entity)
{
if (!entity.TryGetComponent(out ServerStatusEffectsComponent status))
if (!entity.TryGetComponent(out ServerAlertsComponent status))
{
return;
}
if (!entity.TryGetComponent(out IDamageableComponent damageable))
{
status.ChangeStatusEffectIcon(StatusEffect.Health,
"/Textures/Interface/StatusEffects/Human/human0.png");
status.ShowAlert(AlertType.HumanHealth, 0);
return;
}
@@ -49,10 +49,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
return;
}
var modifier = (int) (ruinable.TotalDamage / (threshold / 7f));
var modifier = (short) (ruinable.TotalDamage / (threshold / 7f));
status.ChangeStatusEffectIcon(StatusEffect.Health,
"/Textures/Interface/StatusEffects/Human/human" + modifier + ".png");
status.ShowAlert(AlertType.HumanHealth, modifier);
break;
}
@@ -63,10 +62,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
return;
}
var modifier = (int) (damageable.TotalDamage / (threshold / 7f));
var modifier = (short) (damageable.TotalDamage / (threshold / 7f));
status.ChangeStatusEffectIcon(StatusEffect.Health,
"/Textures/Interface/StatusEffects/Human/human" + modifier + ".png");
status.ShowAlert(AlertType.HumanHealth, modifier);
break;
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Alert;
using Content.Shared.Chemistry;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Movement;
@@ -89,7 +90,7 @@ namespace Content.Server.GameObjects.Components.Mobs
}
if (!StunStart.HasValue || !StunEnd.HasValue ||
!Owner.TryGetComponent(out ServerStatusEffectsComponent status))
!Owner.TryGetComponent(out ServerAlertsComponent status))
{
return;
}
@@ -102,7 +103,7 @@ namespace Content.Server.GameObjects.Components.Mobs
if (progress >= length)
{
Owner.SpawnTimer(250, () => status.RemoveStatusEffect(StatusEffect.Stun), StatusRemoveCancellation.Token);
Owner.SpawnTimer(250, () => status.ClearAlert(AlertType.Stun), StatusRemoveCancellation.Token);
LastStun = null;
}
}

View File

@@ -1,6 +1,7 @@
#nullable enable
using Content.Server.GameObjects.Components.Buckle;
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Strap;
@@ -31,9 +32,9 @@ namespace Content.Server.GameObjects.Components.Movement
private bool _movingRight;
/// <summary>
/// The icon to be displayed when piloting from this chair.
/// ID of the alert to show when piloting
/// </summary>
private string _pilotingIcon = default!;
private AlertType _pilotingAlertType;
/// <summary>
/// The entity that's currently controlling this component.
@@ -137,7 +138,7 @@ namespace Content.Server.GameObjects.Components.Movement
if (_controller != null ||
!entity.TryGetComponent(out MindComponent? mind) ||
mind.Mind == null ||
!Owner.TryGetComponent(out ServerStatusEffectsComponent? status))
!Owner.TryGetComponent(out ServerAlertsComponent? status))
{
return;
}
@@ -145,7 +146,15 @@ namespace Content.Server.GameObjects.Components.Movement
mind.Mind.Visit(Owner);
_controller = entity;
status.ChangeStatusEffectIcon(StatusEffect.Piloting, _pilotingIcon);
status.ShowAlert(_pilotingAlertType, onClickAlert: OnClickAlert);
}
private void OnClickAlert(ClickAlertEventArgs args)
{
if (args.Player.TryGetComponent(out ShuttleControllerComponent? controller))
{
controller.RemoveController();
}
}
/// <summary>
@@ -177,9 +186,9 @@ namespace Content.Server.GameObjects.Components.Movement
/// <param name="entity">The entity to update</param>
private void UpdateRemovedEntity(IEntity entity)
{
if (Owner.TryGetComponent(out ServerStatusEffectsComponent? status))
if (Owner.TryGetComponent(out ServerAlertsComponent? status))
{
status.RemoveStatusEffect(StatusEffect.Piloting);
status.ClearAlert(_pilotingAlertType);
}
if (entity.TryGetComponent(out MindComponent? mind))
@@ -211,13 +220,13 @@ namespace Content.Server.GameObjects.Components.Movement
{
base.ExposeData(serializer);
serializer.DataField(ref _pilotingIcon, "pilotingIcon", "/Textures/Interface/StatusEffects/Buckle/buckled.png");
serializer.DataField(ref _pilotingAlertType, "pilotingAlertType", AlertType.PilotingShuttle);
}
public override void Initialize()
{
base.Initialize();
Owner.EnsureComponent<ServerStatusEffectsComponent>();
Owner.EnsureComponent<ServerAlertsComponent>();
}
/// <inheritdoc />

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Mobs;
@@ -70,11 +71,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
}
public static readonly Dictionary<HungerThreshold, string> HungerThresholdImages = new Dictionary<HungerThreshold, string>
public static readonly Dictionary<HungerThreshold, AlertType> HungerThresholdAlertTypes = new Dictionary<HungerThreshold, AlertType>
{
{ HungerThreshold.Overfed, "/Textures/Interface/StatusEffects/Hunger/Overfed.png" },
{ HungerThreshold.Peckish, "/Textures/Interface/StatusEffects/Hunger/Peckish.png" },
{ HungerThreshold.Starving, "/Textures/Interface/StatusEffects/Hunger/Starving.png" },
{ HungerThreshold.Overfed, AlertType.Overfed },
{ HungerThreshold.Peckish, AlertType.Peckish },
{ HungerThreshold.Starving, AlertType.Starving },
};
public void HungerThresholdEffect(bool force = false)
@@ -89,15 +90,15 @@ namespace Content.Server.GameObjects.Components.Nutrition
}
// Update UI
Owner.TryGetComponent(out ServerStatusEffectsComponent statusEffectsComponent);
Owner.TryGetComponent(out ServerAlertsComponent alertsComponent);
if (HungerThresholdImages.TryGetValue(_currentHungerThreshold, out var statusTexture))
if (HungerThresholdAlertTypes.TryGetValue(_currentHungerThreshold, out var alertId))
{
statusEffectsComponent?.ChangeStatusEffectIcon(StatusEffect.Hunger, statusTexture);
alertsComponent?.ShowAlert(alertId);
}
else
{
statusEffectsComponent?.RemoveStatusEffect(StatusEffect.Hunger);
alertsComponent?.ClearAlertCategory(AlertCategory.Hunger);
}
switch (_currentHungerThreshold)

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Mobs;
@@ -62,11 +63,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
{ThirstThreshold.Dead, 0.0f},
};
public static readonly Dictionary<ThirstThreshold, string> ThirstThresholdImages = new Dictionary<ThirstThreshold, string>
public static readonly Dictionary<ThirstThreshold, AlertType> ThirstThresholdAlertTypes = new Dictionary<ThirstThreshold, AlertType>
{
{ThirstThreshold.OverHydrated, "/Textures/Interface/StatusEffects/Thirst/OverHydrated.png"},
{ThirstThreshold.Thirsty, "/Textures/Interface/StatusEffects/Thirst/Thirsty.png"},
{ThirstThreshold.Parched, "/Textures/Interface/StatusEffects/Thirst/Parched.png"},
{ThirstThreshold.OverHydrated, AlertType.Overhydrated},
{ThirstThreshold.Thirsty, AlertType.Thirsty},
{ThirstThreshold.Parched, AlertType.Parched},
};
public override void ExposeData(ObjectSerializer serializer)
@@ -87,15 +88,15 @@ namespace Content.Server.GameObjects.Components.Nutrition
}
// Update UI
Owner.TryGetComponent(out ServerStatusEffectsComponent statusEffectsComponent);
Owner.TryGetComponent(out ServerAlertsComponent alertsComponent);
if (ThirstThresholdImages.TryGetValue(_currentThirstThreshold, out var statusTexture))
if (ThirstThresholdAlertTypes.TryGetValue(_currentThirstThreshold, out var alertId))
{
statusEffectsComponent?.ChangeStatusEffectIcon(StatusEffect.Thirst, statusTexture);
alertsComponent?.ShowAlert(alertId);
}
else
{
statusEffectsComponent?.RemoveStatusEffect(StatusEffect.Thirst);
alertsComponent?.ClearAlertCategory(AlertCategory.Thirst);
}
switch (_currentThirstThreshold)

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Content.Server.GameObjects.Components.Buckle;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.Strap;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Verbs;
@@ -27,7 +28,7 @@ namespace Content.Server.GameObjects.Components.Strap
private StrapPosition _position;
private string _buckleSound = null!;
private string _unbuckleSound = null!;
private string _buckledIcon = null!;
private AlertType _buckledAlertType;
/// <summary>
/// The angle in degrees to rotate the player by when they get strapped
@@ -65,10 +66,10 @@ namespace Content.Server.GameObjects.Components.Strap
public string UnbuckleSound => _unbuckleSound;
/// <summary>
/// The icon to be displayed as a status when buckled
/// ID of the alert to show when buckled
/// </summary>
[ViewVariables]
public string BuckledIcon => _buckledIcon;
public AlertType BuckledAlertType => _buckledAlertType;
/// <summary>
/// The sum of the sizes of all the buckled entities in this strap
@@ -137,7 +138,7 @@ namespace Content.Server.GameObjects.Components.Strap
serializer.DataField(ref _position, "position", StrapPosition.None);
serializer.DataField(ref _buckleSound, "buckleSound", "/Audio/Effects/buckle.ogg");
serializer.DataField(ref _unbuckleSound, "unbuckleSound", "/Audio/Effects/unbuckle.ogg");
serializer.DataField(ref _buckledIcon, "buckledIcon", "/Textures/Interface/StatusEffects/Buckle/buckled.png");
serializer.DataField(ref _buckledAlertType, "buckledAlertType", AlertType.Buckled);
serializer.DataField(ref _rotation, "rotation", 0);
var defaultSize = 100;

View File

@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
@@ -74,43 +75,43 @@ namespace Content.Server.GameObjects.Components.Temperature
damageType = DamageType.Cold;
}
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
if (Owner.TryGetComponent(out ServerAlertsComponent status))
{
switch(CurrentTemperature)
{
// Cold strong.
case var t when t <= 260:
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold3.png", null);
status.ShowAlert(AlertType.Cold, 3);
break;
// Cold mild.
case var t when t <= 280 && t > 260:
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold2.png", null);
status.ShowAlert(AlertType.Cold, 2);
break;
// Cold weak.
case var t when t <= 292 && t > 280:
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold1.png", null);
status.ShowAlert(AlertType.Cold, 1);
break;
// Safe.
case var t when t <= 327 && t > 292:
status.RemoveStatusEffect(StatusEffect.Temperature);
status.ClearAlertCategory(AlertCategory.Temperature);
break;
// Heat weak.
case var t when t <= 335 && t > 327:
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot1.png", null);
status.ShowAlert(AlertType.Hot, 1);
break;
// Heat mild.
case var t when t <= 345 && t > 335:
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot2.png", null);
status.ShowAlert(AlertType.Hot, 2);
break;
// Heat strong.
case var t when t > 345:
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot3.png", null);
status.ShowAlert(AlertType.Hot, 3);
break;
}
}