using AcDream.Core.Combat;
using AcDream.Core.Player;
namespace AcDream.UI.Abstractions.Panels.Vitals;
///
/// ViewModel for the vitals HUD panel. Reads live health percentage for the
/// local player from (which is fed by the server's
/// UpdateHealth (0x01C0) GameEvent).
///
///
/// Sources:
///
///
///
/// - HP — (percent-only,
/// updated by UpdateHealth (0x01C0)).
/// - Stamina / Mana — 's
/// StaminaPercent / ManaPercent, populated from the
/// CreatureProfile embedded in PlayerDescription
/// (0x0013). When no is wired
/// (older constructor / tests), both stay null and
/// VitalsPanel simply skips those bars.
///
///
///
/// GUID timing: the local player's server GUID isn't known at
/// OnLoad (pre-login). Construct with
/// left as 0; GameWindow calls the setter when the live session
/// receives its guid at EnterWorld. Before the GUID is set,
/// returns 1.0 (via CombatState's safe
/// default for unknown guids) — the bar reads "full", which is harmless.
///
///
public sealed class VitalsVM
{
private readonly CombatState _combat;
private readonly LocalPlayerState? _local;
private uint _localPlayerGuid;
///
/// Build a VitalsVM bound to a and (optionally)
/// a . The GUID starts at 0; call
/// once the live session assigns it.
/// When is null (back-compat),
/// stamina + mana stay null and VitalsPanel skips those bars.
///
public VitalsVM(CombatState combat, LocalPlayerState? localPlayer = null)
{
_combat = combat ?? throw new ArgumentNullException(nameof(combat));
_local = localPlayer;
_localPlayerGuid = 0;
}
///
/// Push the authoritative local-player GUID from WorldSession.
/// One-way setter — only GameWindow should call it, exactly once
/// per live session.
///
public void SetLocalPlayerGuid(uint guid) => _localPlayerGuid = guid;
///
/// Current health percent (0..1) for the local player. Returns 1.0
/// before login or if the server has never sent an UpdateHealth for
/// this GUID.
///
public float HealthPercent => _combat.GetHealthPercent(_localPlayerGuid);
///
/// Stamina percent (0..1), or null when no
/// is wired or it hasn't received a
/// PlayerDescription with both current and max yet. Reads
/// through to the cache every access — no VM-side caching.
///
public float? StaminaPercent => _local?.StaminaPercent;
///
/// Mana percent (0..1), or null under the same conditions as
/// .
///
public float? ManaPercent => _local?.ManaPercent;
// ── Absolute values for HUD overlays ──────────────────────────────────
/// Current health value (server-authoritative absolute) or
/// null if hasn't received the
/// vital snapshot yet.
public uint? HealthCurrent => _local?.Get(LocalPlayerState.VitalKind.Health)?.Current;
/// Max health value, accounting for attribute contribution
/// + active enchantment buffs + vitae. null if no vital
/// snapshot yet.
public uint? HealthMax => _local?.GetMaxApprox(LocalPlayerState.VitalKind.Health);
/// Current stamina value.
public uint? StaminaCurrent => _local?.Get(LocalPlayerState.VitalKind.Stamina)?.Current;
/// Max stamina including buffs + vitae.
public uint? StaminaMax => _local?.GetMaxApprox(LocalPlayerState.VitalKind.Stamina);
/// Current mana value.
public uint? ManaCurrent => _local?.Get(LocalPlayerState.VitalKind.Mana)?.Current;
/// Max mana including buffs + vitae.
public uint? ManaMax => _local?.GetMaxApprox(LocalPlayerState.VitalKind.Mana);
}