--- /dev/null
+using Content.Shared.Alert;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Alerts;
+
+/// <summary>
+/// Event raised on an entity with alerts in order to allow it to update visuals for the alert sprite entity.
+/// </summary>
+[ByRefEvent]
+public record struct UpdateAlertSpriteEvent
+{
+ public Entity<SpriteComponent> SpriteViewEnt;
+
+ public AlertPrototype Alert;
+
+ public UpdateAlertSpriteEvent(Entity<SpriteComponent> spriteViewEnt, AlertPrototype alert)
+ {
+ SpriteViewEnt = spriteViewEnt;
+ Alert = alert;
+ }
+}
+using Content.Client.Alerts;
+using Content.Shared.Alert;
using Content.Shared.Revenant;
using Content.Shared.Revenant.Components;
using Robust.Client.GameObjects;
base.Initialize();
SubscribeLocalEvent<RevenantComponent, AppearanceChangeEvent>(OnAppearanceChange);
+ SubscribeLocalEvent<RevenantComponent, UpdateAlertSpriteEvent>(OnUpdateAlert);
}
private void OnAppearanceChange(EntityUid uid, RevenantComponent component, ref AppearanceChangeEvent args)
args.Sprite.LayerSetState(0, component.State);
}
}
+
+ private void OnUpdateAlert(Entity<RevenantComponent> ent, ref UpdateAlertSpriteEvent args)
+ {
+ if (args.Alert.AlertType != AlertType.Essence)
+ return;
+
+ var sprite = args.SpriteViewEnt.Comp;
+ var essence = Math.Clamp(ent.Comp.Essence.Int(), 0, 999);
+ sprite.LayerSetState(RevenantVisualLayers.Digit1, $"{(essence / 100) % 10}");
+ sprite.LayerSetState(RevenantVisualLayers.Digit2, $"{(essence / 10) % 10}");
+ sprite.LayerSetState(RevenantVisualLayers.Digit3, $"{essence % 10}");
+ }
}
using Content.Client.UserInterface.Systems.Alerts.Widgets;
using Content.Client.UserInterface.Systems.Gameplay;
using Content.Shared.Alert;
+using Robust.Client.GameObjects;
+using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
public sealed class AlertsUIController : UIController, IOnStateEntered<GameplayState>, IOnSystemChanged<ClientAlertsSystem>
{
+ [Dependency] private readonly IPlayerManager _player = default!;
+
[UISystemDependency] private readonly ClientAlertsSystem? _alertsSystem = default;
private AlertsUI? UI => UIManager.GetActiveUIWidgetOrNull<AlertsUI>();
SystemOnSyncAlerts(_alertsSystem, alerts);
}
}
+
+ public void UpdateAlertSpriteEntity(EntityUid spriteViewEnt, AlertPrototype alert)
+ {
+ if (_player.LocalEntity is not { } player)
+ return;
+
+ if (!EntityManager.TryGetComponent<SpriteComponent>(spriteViewEnt, out var sprite))
+ return;
+
+ var ev = new UpdateAlertSpriteEvent((spriteViewEnt, sprite), alert);
+ EntityManager.EventBus.RaiseLocalEvent(player, ref ev);
+ }
}
using Content.Client.Actions.UI;
using Content.Client.Cooldown;
using Content.Shared.Alert;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
private short? _severity;
private readonly IGameTiming _gameTiming;
- private readonly AnimatedTextureRect _icon;
+ private readonly IEntityManager _entityManager;
+ private readonly SpriteView _icon;
private readonly CooldownGraphic _cooldownGraphic;
+ private EntityUid _spriteViewEntity;
+
/// <summary>
/// Creates an alert control reflecting the indicated alert + state
/// </summary>
public AlertControl(AlertPrototype alert, short? severity)
{
_gameTiming = IoCManager.Resolve<IGameTiming>();
+ _entityManager = IoCManager.Resolve<IEntityManager>();
TooltipSupplier = SupplyTooltip;
Alert = alert;
_severity = severity;
- var specifier = alert.GetIcon(_severity);
- _icon = new AnimatedTextureRect
+
+ _spriteViewEntity = _entityManager.Spawn(Alert.AlertViewEntity);
+ if (_entityManager.TryGetComponent<SpriteComponent>(_spriteViewEntity, out var sprite))
{
- DisplayRect = {TextureScale = new Vector2(2, 2)}
- };
+ var icon = Alert.GetIcon(_severity);
+ if (sprite.LayerMapTryGet(AlertVisualLayers.Base, out var layer))
+ sprite.LayerSetSprite(layer, icon);
+ }
- _icon.SetFromSpriteSpecifier(specifier);
+ _icon = new SpriteView
+ {
+ Scale = new Vector2(2, 2)
+ };
+ _icon.SetEntity(_spriteViewEntity);
Children.Add(_icon);
- _cooldownGraphic = new CooldownGraphic();
+ _cooldownGraphic = new CooldownGraphic
+ {
+ MaxSize = new Vector2(64, 64)
+ };
Children.Add(_cooldownGraphic);
}
/// </summary>
public void SetSeverity(short? severity)
{
- if (_severity != severity)
- {
- _severity = severity;
- _icon.SetFromSpriteSpecifier(Alert.GetIcon(_severity));
- }
+ if (_severity == severity)
+ return;
+ _severity = severity;
+
+ if (!_entityManager.TryGetComponent<SpriteComponent>(_spriteViewEntity, out var sprite))
+ return;
+ var icon = Alert.GetIcon(_severity);
+ if (sprite.LayerMapTryGet(AlertVisualLayers.Base, out var layer))
+ sprite.LayerSetSprite(layer, icon);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
+ UserInterfaceManager.GetUIController<AlertsUIController>().UpdateAlertSpriteEntity(_spriteViewEntity, Alert);
+
if (!Cooldown.HasValue)
{
_cooldownGraphic.Visible = false;
_cooldownGraphic.FromTime(Cooldown.Value.Start, Cooldown.Value.End);
}
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ _entityManager.DeleteEntity(_spriteViewEntity);
+ }
+ }
+
+ public enum AlertVisualLayers : byte
+ {
+ Base
}
}
return false;
component.Essence += amount;
+ Dirty(uid, component);
if (regenCap)
FixedPoint2.Min(component.Essence, component.EssenceRegenCap);
if (TryComp<StoreComponent>(uid, out var store))
_store.UpdateUserInterface(uid, uid, store);
- _alerts.ShowAlert(uid, AlertType.Essence, (short) Math.Clamp(Math.Round(component.Essence.Float() / 10f), 0, 16));
+ _alerts.ShowAlert(uid, AlertType.Essence);
if (component.Essence <= 0)
{
[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>
/// <returns>the icon path to the texture for the provided severity level</returns>
public SpriteSpecifier GetIcon(short? severity = null)
{
- if (!SupportsSeverity && severity != null)
- {
- throw new InvalidOperationException($"This alert ({AlertKey}) does not support severity");
- }
-
var minIcons = SupportsSeverity
- ? MaxSeverity - MinSeverity : 1;
+ ? MaxSeverity - MinSeverity
+ : 1;
if (Icons.Count < minIcons)
throw new InvalidOperationException($"Insufficient number of icons given for alert {AlertType}");
namespace Content.Shared.Revenant.Components;
[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState]
public sealed partial class RevenantComponent : Component
{
/// <summary>
/// The total amount of Essence the revenant has. Functions
/// as health and is regenerated.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
public FixedPoint2 Essence = 75;
[DataField("stolenEssenceCurrencyPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<CurrencyPrototype>))]
Stunned,
Harvesting,
}
+
+[NetSerializable, Serializable]
+public enum RevenantVisualLayers : byte
+{
+ Digit1,
+ Digit2,
+ Digit3
+}
- alertType: Magboots
- alertType: Pacified
+- type: entity
+ id: AlertSpriteView
+ categories: [ hideSpawnMenu ]
+ components:
+ - type: Sprite
+ layers:
+ - map: [ "enum.AlertVisualLayers.Base" ]
+
- type: alert
id: LowOxygen
category: Breathing
icons:
- sprite: /Textures/Interface/Alerts/essence_counter.rsi
state: essence0
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence1
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence2
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence3
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence4
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence5
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence6
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence7
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence8
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence9
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence10
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence11
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence12
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence13
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence14
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence15
- - sprite: /Textures/Interface/Alerts/essence_counter.rsi
- state: essence16
+ alertViewEntity: AlertEssenceSpriteView
name: alerts-revenant-essence-name
description: alerts-revenant-essence-desc
- minSeverity: 0
- maxSeverity: 16
- type: alert
id: Corporeal
icons: [ /Textures/Mobs/Ghosts/revenant.rsi/icon.png ]
name: alerts-revenant-corporeal-name
- description: alerts-revenant-corporeal-desc
\ No newline at end of file
+ description: alerts-revenant-corporeal-desc
+
+- type: entity
+ id: AlertEssenceSpriteView
+ categories: [ hideSpawnMenu ]
+ components:
+ - type: Sprite
+ sprite: /Textures/Interface/Alerts/essence_counter.rsi
+ layers:
+ - map: [ "enum.AlertVisualLayers.Base" ]
+ - map: [ "enum.RevenantVisualLayers.Digit1" ]
+ - map: [ "enum.RevenantVisualLayers.Digit2" ]
+ offset: 0.125, 0
+ - map: [ "enum.RevenantVisualLayers.Digit3" ]
+ offset: 0.25, 0
"name": "essence0"
},
{
- "name": "essence1"
+ "name": "0"
},
{
- "name": "essence2"
+ "name": "1"
},
{
- "name": "essence3"
+ "name": "2"
},
{
- "name": "essence4"
+ "name": "3"
},
{
- "name": "essence5"
+ "name": "4"
},
{
- "name": "essence6"
+ "name": "5"
},
{
- "name": "essence7"
+ "name": "6"
},
{
- "name": "essence8"
+ "name": "7"
},
{
- "name": "essence9"
+ "name": "8"
},
{
- "name": "essence10"
- },
- {
- "name": "essence11"
- },
- {
- "name": "essence12"
- },
- {
- "name": "essence13"
- },
- {
- "name": "essence14"
- },
- {
- "name": "essence15"
- },
- {
- "name": "essence16"
+ "name": "9"
}
]
}