fix(chargen): Campaign CC gate round 1 Batch A — GF-15 input, GF-5 skills rows, GF-13 GM toggles
GF-15 (the gate blocker): the Summary name field and Finish button were
NOT structurally broken — live repro over the project's own local ACE
test server showed clicks correctly focus the field and land characters.
The real bug only surfaces after the first dialog opens: pressing Finish
empty successfully creates the NoName RetailMessageDialogView (visible,
correct 400x95 geometry) but it renders nothing and silently absorbs
every click across the whole canvas. Root cause: CharacterCreationUiController.Tick
and CharacterManagementUiController.Tick both call UiRoot.BringToFront(Root)
unconditionally every frame (needed so chargen stays above the occluded
management screen, AP-229); a dialog root is a direct sibling under the
same UiRoot, and RetailWindowManager.BringToFront is "highest ZOrder among
siblings + 1" — whichever BringToFront runs last in a frame wins.
RetailDialogFactory.Tick never re-asserted its own dialogs' z-order, so
the next frame's screen Tick buried the dialog behind the screen's opaque
backdrop while it stayed the registered Modal with exclusive input
priority. Fixed by having RetailDialogFactory.Tick re-raise every open
dialog (in open-order) each tick, matching retail's always-on-top dialog
behavior. Live-verified the complete user sequence end to end: click
field, type, press Finish empty, dialog now visibly renders, OK dismisses
cleanly, field still typable afterward. The "[ Name" prefill question is
closed as a non-bug: neither CharGenState::RandomizeCharacter nor
gmCGSummaryPage::InitializePage write text into the field in the decomp;
retail's field is genuinely empty on open, matching acdream already.
GF-5: CharacterCreationSkillsPage.RebuildRows resolved the wrong listbox
template (Templates[0], retail's own 3-child bucket-header row) and
required the root to be a UiButton (it's a plain container). Byte-traced
gmCGSkillsPage::DoSkillRecords + tagSkillRecord's copy-ctor field order
to map every child id in the real row (Templates[1]): name, level/cost
text, and the two real per-row up/down arrow buttons. Wired the arrows to
retail's own plain-click dispatch, retiring (narrowing) AP-213's
click-to-advance/double-click-retreat single-button substitution.
GF-13: dat property 0x3B (Invisible) was never read by the importer.
Elements 0x10000403/0x10000494 ("Non-Admin"/"Non-Envoy") author it true.
A blast-radius sweep found 1,083 elements client-wide author the same
flag, so this fix stays chargen-scoped only (ElementInfo.Invisible /
UiElement.AuthoredInvisible are pure data additions; only
CharacterCreationUiController acts on them, by the authored flag, not a
hardcoded id list). General importer-wide honor filed as ISSUES.md #408;
register row AP-230 records the split.
Gates: solution build green; App 5266/3 skips/0 failed; Runtime 1735/0;
full-solution run 0 failures anywhere. Register: AP-230 filed, AP-213
narrowed. ISSUES: #408 filed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
6699e0f88c
commit
1d9de5e095
11 changed files with 823 additions and 78 deletions
|
|
@ -225,6 +225,25 @@ public sealed class ElementInfo
|
|||
/// </summary>
|
||||
public uint ScrollbarElementId;
|
||||
|
||||
/// <summary>
|
||||
/// GF-13 (Campaign CC gate round 1, Batch A): the authored Invisible flag
|
||||
/// from dat property <c>0x3B</c> (<c>BoolBaseProperty</c>). Retail
|
||||
/// <c>UIElement::OnSetAttribute @0x00462d80</c>'s case 8
|
||||
/// (<c>BaseProperty::GetPropertyName(esi) - 0x33 == 8</c>, i.e. property
|
||||
/// id <c>0x33 + 8 = 0x3B</c>): <c>this->vtable->SetVisible(value == 0)</c> —
|
||||
/// an authored <c>true</c> HIDES the element at construction. Populated the
|
||||
/// same way as <see cref="TabTable"/>/<see cref="ScrollbarElementId"/>
|
||||
/// (recomputed fresh from the effective merged state every call), but this
|
||||
/// is a PURE DATA ADDITION: the shared <see cref="LayoutImporter"/>/
|
||||
/// <see cref="DatWidgetFactory"/> path does not act on it. 1,083 elements
|
||||
/// author this flag client-wide (docs/ISSUES.md #408, its own separately-
|
||||
/// gated general-honor item) — only screens that explicitly walk their own
|
||||
/// mounted subtree and check this field may hide elements by it (see
|
||||
/// <c>CharacterCreationUiController</c>'s chargen-scoped honor, register
|
||||
/// AP-230).
|
||||
/// </summary>
|
||||
public bool Invisible;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a property for a state using retail's DirectState-as-base rule. A
|
||||
/// named state's key overrides DirectState by presence, including false/zero.
|
||||
|
|
@ -529,6 +548,16 @@ public static class ElementReader
|
|||
// (DataId), UnsignedValue 100683031/100683033 == 0x06004D17/0x06004D19).
|
||||
info.LedCheckedSprite = ReadReferencedElementId(info, 0x10000082u);
|
||||
info.LedUncheckedSprite = ReadReferencedElementId(info, 0x10000083u);
|
||||
|
||||
// GF-13: Invisible (0x3B), BoolBaseProperty. Retail
|
||||
// UIElement::OnSetAttribute @0x00462d80 case 8 — SetVisible(value == 0),
|
||||
// so an authored true HIDES the element. Read via the same
|
||||
// TryGetEffectiveBool the DirectState/default-state resolution rules
|
||||
// already use for every other canonical-projection property above.
|
||||
if (info.TryGetEffectiveBool(0x3Bu, out bool invisible))
|
||||
{
|
||||
info.Invisible = invisible;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<UiTabTableEntry> ReadTabTable(ElementInfo info)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue