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:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user