diff --git a/Content.Client/Alerts/GenericCounterAlertSystem.cs b/Content.Client/Alerts/GenericCounterAlertSystem.cs new file mode 100644 index 0000000000..de9d97d063 --- /dev/null +++ b/Content.Client/Alerts/GenericCounterAlertSystem.cs @@ -0,0 +1,90 @@ +using System.Numerics; +using Content.Shared.Alert.Components; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; + +namespace Content.Client.Alerts; + +/// +/// This handles +/// +public sealed class GenericCounterAlertSystem : EntitySystem +{ + [Dependency] private readonly SpriteSystem _sprite = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnUpdateAlertSprite); + } + + private void OnUpdateAlertSprite(Entity ent, ref UpdateAlertSpriteEvent args) + { + var sprite = args.SpriteViewEnt.Comp; + + var ev = new GetGenericAlertCounterAmountEvent(args.Alert); + RaiseLocalEvent(args.ViewerEnt, ref ev); + + if (!ev.Handled) + return; + + // It cannot be null if its handled, but good to check to avoid ugly null ignores. + if (ev.Amount == null) + return; + + // How many digits can we display + var maxDigitCount = GetMaxDigitCount((ent, ent, sprite)); + + // Clamp it to a positive number that we can actually display in full (no rollover to 0) + var amount = (int) Math.Clamp(ev.Amount.Value, 0, Math.Pow(10, maxDigitCount) - 1); + + // This is super wack but ig it works? + var digitCount = ent.Comp.HideLeadingZeroes + ? amount.ToString().Length + : maxDigitCount; + + if (ent.Comp.HideLeadingZeroes) + { + for (var i = 0; i < ent.Comp.DigitKeys.Count; i++) + { + if (!_sprite.LayerMapTryGet(ent.Owner, ent.Comp.DigitKeys[i], out var layer, false)) + continue; + + _sprite.LayerSetVisible(ent.Owner, layer, i <= digitCount - 1); + } + } + + // ReSharper disable once PossibleLossOfFraction + var baseOffset = (ent.Comp.AlertSize.X - digitCount * ent.Comp.GlyphWidth) / 2 * (1f / EyeManager.PixelsPerMeter); + + for (var i = 0; i < ent.Comp.DigitKeys.Count; i++) + { + if (!_sprite.LayerMapTryGet(ent.Owner, ent.Comp.DigitKeys[i], out var layer, false)) + continue; + + var result = amount / (int) Math.Pow(10, i) % 10; + _sprite.LayerSetRsiState(ent.Owner, layer, result.ToString()); + + if (ent.Comp.CenterGlyph) + { + var offset = baseOffset + (digitCount - 1 - i) * ent.Comp.GlyphWidth * (1f / EyeManager.PixelsPerMeter); + _sprite.LayerSetOffset(ent.Owner, layer, new Vector2(offset, 0)); + } + } + } + + /// + /// Gets the number of digits that we can display. + /// + /// The number of digits. + private int GetMaxDigitCount(Entity ent) + { + for (var i = ent.Comp1.DigitKeys.Count - 1; i >= 0; i--) + { + if (_sprite.LayerExists((ent.Owner, ent.Comp2), ent.Comp1.DigitKeys[i])) + return i + 1; + } + + return 0; + } +} diff --git a/Content.Client/Alerts/UpdateAlertSpriteEvent.cs b/Content.Client/Alerts/UpdateAlertSpriteEvent.cs index 4f182c458c..d8222c2340 100644 --- a/Content.Client/Alerts/UpdateAlertSpriteEvent.cs +++ b/Content.Client/Alerts/UpdateAlertSpriteEvent.cs @@ -11,11 +11,14 @@ public record struct UpdateAlertSpriteEvent { public Entity SpriteViewEnt; + public EntityUid ViewerEnt; + public AlertPrototype Alert; - public UpdateAlertSpriteEvent(Entity spriteViewEnt, AlertPrototype alert) + public UpdateAlertSpriteEvent(Entity spriteViewEnt, EntityUid viewerEnt, AlertPrototype alert) { SpriteViewEnt = spriteViewEnt; + ViewerEnt = viewerEnt; Alert = alert; } } diff --git a/Content.Client/Revenant/RevenantSystem.cs b/Content.Client/Revenant/RevenantSystem.cs index 0534522b40..21d2d7888d 100644 --- a/Content.Client/Revenant/RevenantSystem.cs +++ b/Content.Client/Revenant/RevenantSystem.cs @@ -1,4 +1,6 @@ using Content.Client.Alerts; +using Content.Shared.Alert; +using Content.Shared.Alert.Components; using Content.Shared.Revenant; using Content.Shared.Revenant.Components; using Robust.Client.GameObjects; @@ -15,7 +17,7 @@ public sealed class RevenantSystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnAppearanceChange); - SubscribeLocalEvent(OnUpdateAlert); + SubscribeLocalEvent(OnGetCounterAmount); } private void OnAppearanceChange(EntityUid uid, RevenantComponent component, ref AppearanceChangeEvent args) @@ -40,14 +42,14 @@ public sealed class RevenantSystem : EntitySystem } } - private void OnUpdateAlert(Entity ent, ref UpdateAlertSpriteEvent args) + private void OnGetCounterAmount(Entity ent, ref GetGenericAlertCounterAmountEvent args) { - if (args.Alert.ID != ent.Comp.EssenceAlert) + if (args.Handled) return; - var essence = Math.Clamp(ent.Comp.Essence.Int(), 0, 999); - _sprite.LayerSetRsiState(args.SpriteViewEnt.AsNullable(), RevenantVisualLayers.Digit1, $"{(essence / 100) % 10}"); - _sprite.LayerSetRsiState(args.SpriteViewEnt.AsNullable(), RevenantVisualLayers.Digit2, $"{(essence / 10) % 10}"); - _sprite.LayerSetRsiState(args.SpriteViewEnt.AsNullable(), RevenantVisualLayers.Digit3, $"{essence % 10}"); + if (ent.Comp.EssenceAlert != args.Alert) + return; + + args.Amount = ent.Comp.Essence.Int(); } } diff --git a/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs b/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs index 5c19512038..3fe553be3b 100644 --- a/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs +++ b/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs @@ -98,7 +98,8 @@ public sealed class AlertsUIController : UIController, IOnStateEntered(spriteViewEnt, out var sprite)) return; - var ev = new UpdateAlertSpriteEvent((spriteViewEnt, sprite), alert); + var ev = new UpdateAlertSpriteEvent((spriteViewEnt, sprite), player, alert); EntityManager.EventBus.RaiseLocalEvent(player, ref ev); + EntityManager.EventBus.RaiseLocalEvent(spriteViewEnt, ref ev); } } diff --git a/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs b/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs index 847b253586..fe22ebba40 100644 --- a/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs +++ b/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs @@ -57,10 +57,15 @@ namespace Content.Client.UserInterface.Systems.Alerts.Controls _sprite = _entityManager.System(); TooltipSupplier = SupplyTooltip; Alert = alert; + + HorizontalAlignment = HAlignment.Left; _severity = severity; _icon = new SpriteView { - Scale = new Vector2(2, 2) + Scale = new Vector2(2, 2), + MaxSize = new Vector2(64, 64), + Stretch = SpriteView.StretchMode.None, + HorizontalAlignment = HAlignment.Left }; SetupIcon(); diff --git a/Content.Shared/Alert/Components/GenericCounterAlertComponent.cs b/Content.Shared/Alert/Components/GenericCounterAlertComponent.cs new file mode 100644 index 0000000000..d0c7fc1ad1 --- /dev/null +++ b/Content.Shared/Alert/Components/GenericCounterAlertComponent.cs @@ -0,0 +1,63 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Alert.Components; + +/// +/// This is used for an alert which simply displays a generic number over a texture. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class GenericCounterAlertComponent : Component +{ + /// + /// The width, in pixels, of an individual glyph, accounting for the space between glyphs. + /// A 3 pixel wide glyph with one pixel of space between it and the next would be a width of 4. + /// + [DataField] + public int GlyphWidth = 6; + + /// + /// Whether the numbers should be centered on the glyph or just follow a static position. + /// + [DataField] + public bool CenterGlyph = true; + + /// + /// Whether leading zeros should be hidden. + /// If true, "005" would display as "5". + /// + [DataField] + public bool HideLeadingZeroes = true; + + /// + /// The size of the alert sprite. + /// Used to calculate offsets. + /// + [DataField] + public Vector2i AlertSize = new(32, 32); + + /// + /// Digits that can be displayed by the alert, represented by their sprite layer. + /// Order defined corresponds to the digit it affects. 1st defined will affect 1st digit, 2nd affect 2nd digit and so on. + /// In this case ones would be on layer "1", tens on layer "10" etc. + /// + [DataField] + public List DigitKeys = new() + { + "1", + "10", + "100", + "1000", + "10000" + }; +} + +/// +/// Event raised to gather the amount the alert will display. +/// +/// The alert which is currently requesting an update. +/// The number to display on the alert. +[ByRefEvent] +public record struct GetGenericAlertCounterAmountEvent(AlertPrototype Alert, int? Amount = null) +{ + public bool Handled => Amount.HasValue; +} diff --git a/Content.Shared/Revenant/SharedRevenant.cs b/Content.Shared/Revenant/SharedRevenant.cs index 485ad26dd2..c44e4408aa 100644 --- a/Content.Shared/Revenant/SharedRevenant.cs +++ b/Content.Shared/Revenant/SharedRevenant.cs @@ -70,11 +70,3 @@ public enum RevenantVisuals : byte Stunned, Harvesting, } - -[NetSerializable, Serializable] -public enum RevenantVisualLayers : byte -{ - Digit1, - Digit2, - Digit3 -} diff --git a/Resources/Prototypes/Alerts/revenant.yml b/Resources/Prototypes/Alerts/revenant.yml index 38933df4fe..ab2b13905d 100644 --- a/Resources/Prototypes/Alerts/revenant.yml +++ b/Resources/Prototypes/Alerts/revenant.yml @@ -18,12 +18,15 @@ id: AlertEssenceSpriteView categories: [ HideSpawnMenu ] components: + - type: GenericCounterAlert + centerGlyph: false + hideLeadingZeroes: false - 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" ] + - map: [ "1" ] offset: 0.25, 0 + - map: [ "10" ] + offset: 0.125, 0 + - map: [ "100" ] diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/0.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/0.png new file mode 100644 index 0000000000..8eb85f36dc Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/0.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/1.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/1.png new file mode 100644 index 0000000000..8a9a17bc02 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/1.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/2.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/2.png new file mode 100644 index 0000000000..8a0fd90ff3 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/2.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/3.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/3.png new file mode 100644 index 0000000000..181f425acc Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/3.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/4.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/4.png new file mode 100644 index 0000000000..fe5680eb41 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/4.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/5.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/5.png new file mode 100644 index 0000000000..2361ca7f1d Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/5.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/6.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/6.png new file mode 100644 index 0000000000..a636e7890b Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/6.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/7.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/7.png new file mode 100644 index 0000000000..d29d6192de Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/7.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/8.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/8.png new file mode 100644 index 0000000000..90deae2876 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/8.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/9.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/9.png new file mode 100644 index 0000000000..6325fbdabc Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/9.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/base.png b/Resources/Textures/Interface/Alerts/generic_counter.rsi/base.png new file mode 100644 index 0000000000..cedd5f78fa Binary files /dev/null and b/Resources/Textures/Interface/Alerts/generic_counter.rsi/base.png differ diff --git a/Resources/Textures/Interface/Alerts/generic_counter.rsi/meta.json b/Resources/Textures/Interface/Alerts/generic_counter.rsi/meta.json new file mode 100644 index 0000000000..16cc2761e3 --- /dev/null +++ b/Resources/Textures/Interface/Alerts/generic_counter.rsi/meta.json @@ -0,0 +1,44 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Created by EmoGarbage404", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + }, + { + "name": "0" + }, + { + "name": "1" + }, + { + "name": "2" + }, + { + "name": "3" + }, + { + "name": "4" + }, + { + "name": "5" + }, + { + "name": "6" + }, + { + "name": "7" + }, + { + "name": "8" + }, + { + "name": "9" + } + ] +}