feat(D.2b): VitalsController — bind live vitals data by element id
Mirrors retail gmVitalsUI::PostInit: grab Health/Stamina/Mana meters from the imported layout by their dat element ids (0x100000E6 / EC / EE) and wire Func<float> fill + Func<string> label providers. Missing ids are silently skipped (no throw). Slice sprites + dat font already set by the factory — this is pure data wiring, not graphics. 3 TDD tests: single-meter fill+label, all-three distinct providers, missing-id no-throw. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9a55a688ca
commit
9d2527d9c8
2 changed files with 166 additions and 0 deletions
64
src/AcDream.App/UI/Layout/VitalsController.cs
Normal file
64
src/AcDream.App/UI/Layout/VitalsController.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
|
||||
namespace AcDream.App.UI.Layout;
|
||||
|
||||
/// <summary>
|
||||
/// Per-window controller for the vitals layout (LayoutDesc 0x2100006C).
|
||||
/// Mirrors retail <c>gmVitalsUI::PostInit</c>: grab the three meter elements
|
||||
/// by their dat element ids and bind live data providers (fill fraction + cur/max
|
||||
/// text) to each. This is the ONLY per-window code in the whole importer — pure
|
||||
/// data wiring, not graphics.
|
||||
///
|
||||
/// <para>The slice sprites + dat font on each <see cref="UiMeter"/> are already
|
||||
/// set by <see cref="DatWidgetFactory"/> during tree construction; this controller
|
||||
/// only binds the dynamic vitals data. Do not touch meter rendering fields here.</para>
|
||||
/// </summary>
|
||||
public static class VitalsController
|
||||
{
|
||||
/// <summary>Dat element id for the Health meter (0x100000E6).</summary>
|
||||
public const uint Health = 0x100000E6;
|
||||
/// <summary>Dat element id for the Stamina meter (0x100000EC).</summary>
|
||||
public const uint Stamina = 0x100000EC;
|
||||
/// <summary>Dat element id for the Mana meter (0x100000EE).</summary>
|
||||
public const uint Mana = 0x100000EE;
|
||||
|
||||
/// <summary>
|
||||
/// Bind live vitals data providers to the Health, Stamina, and Mana meter
|
||||
/// elements found in <paramref name="layout"/>. Any meter whose id is absent
|
||||
/// from the layout is silently skipped — partial layouts (e.g. test fakes)
|
||||
/// do not cause errors.
|
||||
/// </summary>
|
||||
/// <param name="layout">Imported vitals layout tree.</param>
|
||||
/// <param name="healthPct">Provider returning Health fill fraction [0..1].</param>
|
||||
/// <param name="staminaPct">Provider returning Stamina fill fraction [0..1].</param>
|
||||
/// <param name="manaPct">Provider returning Mana fill fraction [0..1].</param>
|
||||
/// <param name="healthText">Provider returning Health "cur/max" overlay text.</param>
|
||||
/// <param name="staminaText">Provider returning Stamina "cur/max" overlay text.</param>
|
||||
/// <param name="manaText">Provider returning Mana "cur/max" overlay text.</param>
|
||||
public static void Bind(
|
||||
ImportedLayout layout,
|
||||
Func<float> healthPct,
|
||||
Func<float> staminaPct,
|
||||
Func<float> manaPct,
|
||||
Func<string> healthText,
|
||||
Func<string> staminaText,
|
||||
Func<string> manaText)
|
||||
{
|
||||
BindMeter(layout, Health, healthPct, healthText);
|
||||
BindMeter(layout, Stamina, staminaPct, staminaText);
|
||||
BindMeter(layout, Mana, manaPct, manaText);
|
||||
}
|
||||
|
||||
private static void BindMeter(
|
||||
ImportedLayout layout, uint id,
|
||||
Func<float> pct,
|
||||
Func<string> text)
|
||||
{
|
||||
if (layout.FindElement(id) is UiMeter m)
|
||||
{
|
||||
m.Fill = () => pct();
|
||||
m.Label = () => text();
|
||||
}
|
||||
// Silently skip if the id is absent — missing meters are not an error.
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue