feat(D.2b): Character Attributes tab — 9-row list (icons + values + vitals) + footer State-A
Pass 1 of the Attributes tab interactive controller. Replaces the placeholder
UiText attribute list with 9 real manual-layout rows matching retail's
gmAttributeUI::PostInit (0x0049db70) structure:
- 6 attribute rows (Strength/Endurance/Coordination/Quickness/Focus/Self) in
retail display order (Coord enum 4 before Quick enum 3 — spec §1)
- 3 vital rows (Health/Stamina/Mana) with cur/max format per
Attribute2ndInfoRegion::Update (0x004f19e0)
- Each row: icon (UiText.BackgroundSprite = 0x06xxxxxx RenderSurface via spriteResolve),
name (left-justified), value (new RightAligned mode)
Icon DataIDs from SubMap 0x25000006/0x25000007 via spec §2:
STR 0x060002C8, END 0x060002C4, COORD 0x060002C9, QUICK 0x060002C6,
FOCUS 0x060002C5, SELF 0x060002C7, HP 0x06004C3B, SP 0x06004C3C, MP 0x06004C3D
Footer State-A (DisplayDefaultFooter 0x0049cde0):
0x1000024e title = "", 0x10000243 line-1-value = "Select an Attribute to Improve",
0x10000245 line-2-value = SkillCredits (InqInt(0x18))
Other changes:
- UiText: add RightAligned bool (single-line right-justified, mirrors Centered path)
- CharacterSheet: add SkillCredits property (retail InqInt(0x18))
- SampleData: update to spec fixture values (Str/Quick=200, rest=10, SkillCredits=96,
Health=5/5, Stamina=10/10, Mana=10/10)
- FixtureProvider: pass stack.ResolveChrome as spriteResolve for icon rendering
- Tests: 13 targeted tests (9-row count, row order, attr+vital values,
icon DataIDs, RightAligned flag, footer State-A all 5 elements)
Pass 2 (selection/raise buttons) is separate per spec.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>