fix: complete retail parity stability pass
All checks were successful
CI / linux-portable (push) Successful in 3m41s
CI / windows-gate (push) Successful in 6m49s
CI / release (push) Successful in 3m22s

This commit is contained in:
Erik 2026-08-28 20:01:39 +02:00
parent d3df4cb20a
commit f7aa8e0eb7
131 changed files with 7765 additions and 1190 deletions

View file

@ -306,41 +306,9 @@ internal sealed class CharacterCreationSkillsPage : IDisposable
_infoTitle = UiElement.FindDescendant(pageRoot, 0x100003FBu) as UiText;
_infoText = UiElement.FindDescendant(pageRoot, 0x100003FCu) as UiText;
// R3-3 (Campaign CC gate round 1 re-test 2): the title
// (0x100003fb, Y=435, Height=100) and description (0x100003fc,
// Y=460, Height=100) panes' own AUTHORED boxes overlap by 75px
// (live-DAT-measured) — retail relies on vertical JUSTIFICATION,
// not disjoint rects, to keep the two visually separate. Neither
// element authors dat property 0x15 (live-DAT-probe-confirmed
// absent on both), so both fall to whatever the unauthored default
// resolves to. Byte-traced against retail's own
// UIElement_Text::UIElement_Text ctor @0x004685ff
// (this->m_eVerticalJustification = 4) cross-referenced with
// UIElement_Text::CalcJustification @0x00467260 (the ACTUAL
// enum semantics: ecx_5==1 -> Center, ecx_5==3||5 -> the FAR edge
// (Bottom), any other value including the ctor's own default of 4
// -> edi=0, the NEAR edge, i.e. Top): the correct unauthored
// default is TOP, not Center. This port's shared
// ElementReader/DatWidgetFactory VJustify mapping and field
// default both currently resolve an absent 0x15 to Center — a
// client-wide mismatch with real retail semantics that is NOT
// fixed here (filed as ISSUES.md #410; the blast radius spans
// every already-shipped DAT-imported UiText that relies on the
// CURRENT Center default, so a global remap needs its own
// dedicated investigation + regression sweep, not a bundled
// fix inside this page). Scoped correction: force these two
// specific panes to the value retail's ctor actually resolves
// to. Under Top justification the title (OneLine, ~1 line) sits
// near its box's own top (global Y~435) and the description
// (multi-line, honoring the SAME justification via
// ConfigureDatState's _honorDatVerticalJustification) starts near
// ITS box's own top (global Y~460) — the two boxes' TOP edges are
// 25px apart, so short/typical content no longer collides even
// though the boxes' full 100px extents still overlap on paper.
if (_infoTitle is { } infoTitle)
infoTitle.VerticalJustify = VJustify.Top;
if (_infoText is { } infoText)
infoText.VerticalJustify = VJustify.Top;
// The two panes author no 0x15. The shared importer now applies
// retail's constructor default (raw 4 -> Top), so no page-local
// justification correction is needed.
// R4-3 (Campaign CC gate round 1 re-test 3): the description pane's
// own raw box (0x100003fc, Y=460 H=100 -> bottom Y=560, live-DAT-