namespace AcDream.UI.Abstractions.Panels.Vitals; /// /// First real UI panel — shows the local player's vitals as progress bars. /// Backend-agnostic; renders exclusively through /// so the same file works under ImGui.NET (D.2a) and the future custom /// retail-look toolkit (D.2b). /// /// /// D.2a shows only HP (percent). / /// return null until a /// LocalPlayerState is wired (follow-up issue). When they start /// returning non-null, this panel picks them up automatically. /// /// public sealed class VitalsPanel : IPanel { private const float BarWidth = 200f; private readonly VitalsVM _vm; public VitalsPanel(VitalsVM vm) { _vm = vm ?? throw new ArgumentNullException(nameof(vm)); } /// public string Id => "acdream.vitals"; /// public string Title => "Vitals"; /// public bool IsVisible { get; set; } = true; /// public void Render(PanelContext ctx, IPanelRenderer renderer) { if (!renderer.Begin(Title)) { renderer.End(); return; } // HP — always available from CombatState. If LocalPlayer has the // absolute values too, prefer "current/max (percent)" overlay. float hp = _vm.HealthPercent; renderer.Text("HP"); renderer.SameLine(); renderer.ProgressBar(hp, BarWidth, overlay: FormatOverlay( hp, _vm.HealthCurrent, _vm.HealthMax)); // Stamina — show only when the VM has a real value. if (_vm.StaminaPercent is float stam) { renderer.Text("Stam"); renderer.SameLine(); renderer.ProgressBar(stam, BarWidth, overlay: FormatOverlay( stam, _vm.StaminaCurrent, _vm.StaminaMax)); } // Mana — show only when the VM has a real value. if (_vm.ManaPercent is float mana) { renderer.Text("Mana"); renderer.SameLine(); renderer.ProgressBar(mana, BarWidth, overlay: FormatOverlay( mana, _vm.ManaCurrent, _vm.ManaMax)); } renderer.End(); } /// /// Format a vital-bar overlay. Prefers current / max (percent%) /// when absolute values are available; falls back to percent-only /// when not (e.g. HP pre-PlayerDescription, where only the /// CombatState percent has been wired). /// private static string FormatOverlay(float percent, uint? current, uint? max) { if (current is uint c && max is uint m && m > 0) return $"{c} / {m} ({percent * 100f:F0}%)"; return $"{percent * 100f:F0}%"; } }