Commit graph

1 commit

Author SHA1 Message Date
Erik
0591b9a026 fix(chargen): Campaign CC gate round 1 Batch C — rich text + labels + backdrops
Commit 1/3: chargen-scoped, low blast-radius fixes.

- New DatRichText helper: escape-normalize + word-wrap + per-segment
  palette color, porting UIElement_Text::SetStringInfoWithFont /
  AppendStringInfoWithFont's composition model. Routes the Heritage
  (GF-2), Town (GF-11a), and Profession (GF-3) description boxes
  through it instead of a raw unwrapped single-Line LinesProvider.
  Heritage headers use font-color palette index 1 (green), bodies
  index 0 (white), matching AppendStringInfoWithFont's own font-index
  argument. Town's diagnosed GF-11a root cause: a single un-wrapped
  line meant the town-specific suffix rendered past the clipped
  viewport, so switching towns looked like "text never changes" even
  though the underlying composed string genuinely differed.

- GF-3: bind the Profession page's description textbox (0x100003e0,
  gmCGProfessionPage::InitializePage @0x00483068) and compose its
  per-template text (UpdateProfession @0x004821b0's CustomText/
  BowText/SwashText/LifeText/WarText/WayText/SoldierText, plain
  SetStringInfo — no palette).

- GF-4: UiButton gains a coexisting ValueLabel/ValueBox/ValueFont/
  ValueColor slot alongside Label. Retail's chargen display buttons
  (avail/health/stamina/mana credits, 0x100003e2-e5/0x100003f9)
  author their caption directly on P0x17 AND carry a separate,
  media-less Type-12 value child that UiButton.ConsumesDatChildren
  used to drop entirely — pages substituted the button's own Label,
  destroying the caption. DatWidgetFactory.BuildButton now surfaces
  that child (gated on ReferenceEquals(labelInfo, info) — own-caption
  buttons only) instead. The six Profession slider name labels
  (0x100002ed, CharGenState::GetAttributeName @0x005C3A20's six
  hardcoded literals) resolve as UiButton in this port (live-DAT-
  measured Type 1 — retail's UIElement_Button is DynamicCast(0xc)-
  compatible with UIElement_Text) and are written once at
  construction, matching retail's own single InitializePage write.

- GF-6/AP-218: gmCGAppearancePage::Update writes a heritage-flavored
  STATIC caption to the Hair/Eyes/Skin spins (plain / GearText_* /
  OlthoiText_* variants) — never an index. Removed the prior 1-based-
  ordinal/gear-name substitution entirely; the other six spins keep
  their DAT-authored caption untouched, matching retail exactly.

- Root 1d: wire the Heritage (0x100003be, 13 states) and Profession
  (0x100003d8, 7 states) backdrop SetState cascades
  (gmCGHeritagePage::Update / gmCGProfessionPage::UpdateProfession).

- AP-216/AP-217 (partial, register updated honestly): swatches beyond
  the current part's real color count now hide (DoColorSpots' blank-
  blit half); the GradCircle now blanks for Eyes (DoGradDisk's blank-
  plug half). The "paint with the actual represented/current color"
  halves stay open — they need a PalSet/Palette-id -> RGB pipeline no
  chargen page reads at runtime yet, judged disproportionate to add
  alongside this batch's other ~10 fixes.

Register: AP-215 rewritten (item 2's "ordinal" framing is stale after
GF-6; restated as the icon-thumbnail gap), AP-216/AP-217 rewritten
(partially closed), AP-218 retired, AD-103 retired (the swallowed-
child Label substitution AD-103 tracked is replaced by ValueLabel's
own-geometry surfacing).

22 new tests (DatRichText unit tests, UiButton/DatWidgetFactory
ValueLabel tests, live-DAT structural pins, controller behavioral
tests) — all green. Full App suite (Release, live-DAT):
5300 passed / 1 pre-existing unrelated flake (PortalProjectionTests
allocation test, passes in isolation) / 3 skipped, up from the
baseline 5282/3.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 12:18:53 +02:00