Skip to content

Port: fix the Help and Monica inventory crashes and effects stuck bright - #122

Merged
Adubbz merged 3 commits into
TheMoonPeople:masterfrom
carrdylan52:pr/crash-fixes
Oct 19, 2026
Merged

Adubbz merged 3 commits into
TheMoonPeople:masterfrom
carrdylan52:pr/crash-fixes

Conversation

@carrdylan52

@carrdylan52 carrdylan52 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Two crashes and one regression that leaves effects stuck at full brightness. All three were found in playtesting and reproduce on current master. Each fix is its own commit.

Opening Help from the dungeon menu crashes (Release builds)
Before: MenuManualInit fills five 10-row Help columns (entries 0–49), but manual_boot_event_no has 47 entries. In the PAL ELF the 94-byte table sits at 0x3597d0 and the next pointer table at 0x359830. So entry 47 reads two padding bytes, and entries 48–49 read the first pointer. In C++ that read is undefined. In Release builds (-O3, ThinLTO), the last column's loop in the generated code has no exit. It writes values[], value_width[] and item_mes[] past the window until it faults.
After: Help opens. The PC copy of menuop.cpp pads the table to 50 entries with -1, so rows 47–49, which have no manual page, stay locked. The PS2 source and its data layout are unchanged.
How: a new fixup in scripts/port/header_fixups.py, covered by scripts/port/test_header_fixups.py.

Effects stuck at full brightness when their action ends (regression from c0f07fe)
Before: each action's channels are sliced to its KEY interval and posed at local frames clamped to the action's end. The material, camera and vertex channels still go through MotionProc. On an action's last frame it picks the final key as both endpoints and divides by their zero frame difference, so material alpha and colour become NaN. As a result:

  • the chest-opening light motes stay lit under "Obtained …"
  • the weapon build-up sunburst stays lit
  • Max's charged-attack rings flash back after release
    After: auxiliary channels at or past their last key take that key's value through the blend form of MotionProc, which doesn't divide. Frames before an action's end are unchanged.

Opening the inventory in Monica's prologue crashes when the mouse moves
Before: the bait hit-test looked up Max's esa0 part before checking which page was open. Monica's form has no esa0, so GetPartInfo reached a freed part with a null name, and strcmp read address 0 (menu_mouse_item.cpp BaitHit → GetPartInfo → strcmp).
After: the page is checked first, and the mouse code looks parts up with MenuMouseFindPart, which skips freed parts as GetPutPosXY already does.

Tests:

  • CharacterMotion.MaterialAlphaHoldsItsLastKeyAtAndPastTheActionEnd, CharacterMotion.MaterialColourHoldsItsLastKeyAtTheActionEnd and CharacterMotion.BlendIntoAnActionEndKeepsItsMaterialAlpha. These produce NaN without the fix.
  • The header-fixup test for the Help table.

Headless replays, each run on master and then on this branch:

  • tools/input/help-mouse.input from --jump dungeon:0:1: master segfaults; this branch shows the Help list.
  • tools/input/area-dungeon-treasure.input at frame 3700: master shows the chest motes lit under the "Obtained" message; this branch shows none.
  • tools/input/area-dungeon-ranged.input at frame 3298: master shows the charge rings back after release; this branch shows none.
  • From --jump opening, open Item and move the mouse: master crashes in BaitHit; this branch doesn't.

@carrdylan52
carrdylan52 marked this pull request as draft October 19, 2026 00:55
MenuManualInit fills five 10-row Help columns (entries 0-49) and reads
manual_boot_event_no[entry] for each, but the table has 47 entries. Retail
reads the table's padding and the next table's pointer there. In C++ that read
is undefined, and since Release builds moved to -O3 with ThinLTO clang drops
the loop exit for the last column (MenuDCMsg[8]). The loop then writes
values[], value_width[] and item_mes[] past the window until it faults, so
opening Help from the dungeon menu crashed.

The PC copy of menuop.cpp now gives the table 50 entries. Entries 47-49 have
no manual page and no event flag, so they stay locked. The PS2 source and its
data layout are unchanged.
Since the native motion rework (c0f07fe) each action's channels are
sliced to its KEY interval and posed at local frames clamped to the
action's end. The material, camera and vertex channels still go through
the game's MotionProc, which interpolates toward the next key; at an
action's last frame there is none, so it divides zero by zero and the
material alpha and colour become NaN. The full retail motion carried on
past the KEY interval, so the game never hit this.

Effects that fade out by material transparency then drew at full
brightness when their action ended: the chest-opening light motes and
the weapon build-up sunburst stayed lit for as long as the effect was
held, and Max's and Monica's charge burst flashed back for the frames
it sat on its last key.

Auxiliary channels at or past their last key now take that key's value
through the blend form of MotionProc, which reads it without dividing.
Frames before an action's end render byte-identically.
The bait hit-test looked up Max's esa0 part before checking the page.
Monica's form has no esa0, so GetPartInfo walked onto a freed part
with a null name and strcmp read address 0. Opening the inventory
in the prologue battle crashed as soon as the mouse moved.

Check the page first, and look parts up in the mouse code with a
lookup that skips freed parts, as GetPutPosXY already does.
@carrdylan52 carrdylan52 changed the title Port: fix the Help, frog and Monica inventory crashes and effects stuck bright Port: fix the Help and Monica inventory crashes and effects stuck bright Oct 19, 2026
@carrdylan52
carrdylan52 marked this pull request as ready for review October 19, 2026 01:34
@Adubbz
Adubbz merged commit 8560c1a into TheMoonPeople:master Oct 19, 2026
3 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants