HUD: ability/cooldown bar (sockets 1-4 + dash); socket-0 charge strip removed

AbilityBarSystem (own UIDocument, sortingOrder 49, the B5 sibling pattern): per-slot Spark
initials/name from the AbilityDatabase blob, archetype tint, drain overlay + seconds countdown +
ready flash; dash rides DashCooldown vs TuningConfig.DashCooldownTicks (Defaults() fallback).
HudSystem's single-socket blue charge strip removed (it tracked socket 0 only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 13:28:08 -07:00
parent 2aebc37115
commit 040463ad07
3 changed files with 250 additions and 31 deletions
@@ -49,7 +49,7 @@ namespace ProjectM.Client
bool _themed; // HudTheme + PanelBox present (drives sprite-tint vs flat-colour retint)
// vitals
VisualElement _healthFill, _cooldownFill, _shieldRow, _cdRow;
VisualElement _healthFill, _shieldRow;
Label _healthText;
// threat
@@ -327,7 +327,7 @@ namespace ProjectM.Client
// ---- Per-player vitals ----
bool found = false;
float hp = 0f, maxHp = 1f, cdFrac = 1f;
float hp = 0f, maxHp = 1f;
bool dead = false, shielded = false;
foreach (var (health, effChar, cd, invuln, entity) in
@@ -340,19 +340,7 @@ namespace ProjectM.Client
maxHp = effChar.ValueRO.MaxHealth > 0f ? effChar.ValueRO.MaxHealth : health.ValueRO.Max;
dead = SystemAPI.IsComponentEnabled<Dead>(entity);
// Cooldown bar = socket 0 (the primary Spark) of the 4-socket kit (the legacy single
// AbilityCooldown died — LANTERN purge). EffectiveSocketStats row 0 supplies the duration.
uint nextFire = cd.ValueRO.Get(0);
int cdTicks = 0;
if (SystemAPI.HasBuffer<EffectiveSocketStats>(entity))
{
var effSockets = SystemAPI.GetBuffer<EffectiveSocketStats>(entity);
if (effSockets.Length > 0) cdTicks = effSockets[0].CooldownTicks;
}
var nextTick = new NetworkTick(nextFire);
cdFrac = (haveTick && nextFire != 0 && cdTicks > 0 && nextTick.IsValid && nextTick.IsNewerThan(nt.ServerTick))
? Mathf.Clamp01(1f - nextTick.TicksSince(nt.ServerTick) / (float)cdTicks)
: 1f;
// (07-21 UI rework: socket/dash cooldown readouts moved to AbilityBarSystem.)
uint invulnUntil = invuln.ValueRO.UntilTick;
var invulnTick = new NetworkTick(invulnUntil);
@@ -381,9 +369,6 @@ namespace ProjectM.Client
_healthText.text = Mathf.CeilToInt(Mathf.Max(0f, hp)) + " / " + Mathf.CeilToInt(maxHp);
_shieldRow.style.display = shielded ? DisplayStyle.Flex : DisplayStyle.None;
HudUi.SetFill(_cooldownFill, cdFrac);
// A READY weapon (full bar) recedes; a CHARGING one is bright — so the inverted-vs-health polarity reads.
if (_cdRow != null) _cdRow.style.opacity = cdFrac >= 1f ? 0.4f : 1f;
if (dead)
{
// Client-local countdown: latch the death edge; the baked (non-replicated) DelayTicks is the
@@ -649,19 +634,8 @@ namespace ProjectM.Client
_shieldRow.style.display = DisplayStyle.None;
panel.Add(_shieldRow);
// cooldown row: weapon icon + thin bar
_cdRow = new VisualElement();
_cdRow.style.flexDirection = FlexDirection.Row;
_cdRow.style.alignItems = Align.Center;
_cdRow.style.marginBottom = 6;
_cdRow.pickingMode = PickingMode.Ignore;
var cdIcon = HudUi.Icon(theme != null ? theme.CooldownIcon : null, 22, AetherCyan);
cdIcon.style.marginRight = 8;
_cdRow.Add(cdIcon);
var cdBar = HudUi.Bar(420, 12, new Color(0.4f, 0.8f, 1f), out _cooldownFill);
_cdRow.Add(cdBar);
panel.Add(_cdRow);
// 07-21 UI rework: the single socket-0 charge strip is gone — AbilityBarSystem (bottom-center)
// now shows ALL socket cooldowns + dash.
// health row: health icon + big bar with numeric overlay
var hpRow = new VisualElement();
hpRow.style.flexDirection = FlexDirection.Row;