7 KiB
PSX JL-9 In-Level Event Investigation
This note isolates one question from the broader JL-9 work on PlayStation SLUS_002.68:
- what natural in-level event writes
psx_debug_extra_channel_gateand makes the later hiddenL0SR+R1 + Circlepath unlockJL-9?
Current status
The downstream half is now closed.
- user validation proved that forcing
0x8006739d = 0x01, then enteringL0SR, then pressingR1 + Circlesuccessfully addsJL-9 - therefore the remaining mystery is entirely on the natural gate-arm side
MFM4is no longer the main mystery; it is only the strongest natural prime candidate
Current best interpretation:
- the more direct thing being bypassed by the manual poke is the in-level event itself
- natural
MFM4failing meansMFM4alone is not sufficient - the missing event is most likely an uncommon or optional scripted/control event in a small late-level family
Proven sink-side mechanics
Gate byte
psx_debug_extra_channel_gate=0x8006739d- writer:
0x800232f0 - reader:
0x8002fff4 - storage is byte-wide (
sbwrite,lburead) - late check is nonzero-based, not literal-value-based
Natural gate-arm branch
Natural arm still converges on psx_set_debug_extra_channel_gate at 0x800230e4.
The exact write branch is:
- tuple:
(slot=0x0f, arg1=0x0a, arg2=0x04) - hidden must still be off
psx_level_runtime_header_statemust be3- only then does
0x800232f0store1to0x8006739d
Hidden trigger half
Later JL-9 unlock still requires:
- hidden passcode branch
L0SR/?0SR - input code
0x1e - practical mapping
R1 + Circle
That later path reads 0x8006739d at 0x8002fff4 and performs the extra 0x0d unlock when nonzero.
Proven dispatcher path
Sink feeder
0x800214ac..0x800215f8 is now promoted as:
psx_level_gate_slot_dispatch_from_action_record
Recovered structure:
- dispatch slot byte comes from pointer at
record + 0x00 arg1byte comes from pointer atrecord + 0x08arg2byte comes from pointer atrecord + 0x0c- handler call is indirect through
psx_level_gate_slot_handler_table[slot]at0x800640a0
Important table entries:
psx_level_gate_slot_handler_table[0x0d] = 0x80022c6cpsx_level_gate_slot_handler_table[0x0e] = 0x80022ea8psx_level_gate_slot_handler_table[0x0f] = 0x800230e4
Recovered slot-family behavior
Slot 0x0d
0x80022c6c is now named:
psx_control_event_slot0d_handler
Recovered strong branch:
(0x0a,0x02)=> mission-complete passcode generation/display lane
Slot 0x0e
0x80022ea8 is now named:
psx_control_event_slot0e_handler
Recovered branches:
(0x0a,0x01)=> mission-complete passcode generation/display lane using quad index0x0f(0x0a,0x02..0x04)=> mode/timer setup branches(0x0a,0x06)=> selector/stage apply lane that force-applies selector0x0f
Slot 0x0f
0x800230e4 remains:
psx_set_debug_extra_channel_gate
Recovered 0x0a cases:
12340x2e
The JL-9 natural arm branch is specifically:
(0x0a,0x04)
Host-level narrowing
The recovered gate family is still:
{54,55,56,57,58,82}
Best current host ranking:
545556578258
Why 54 remains the best anchor:
MFM4is the only ordinary published code that statically satisfies the prime-side conditions- selector
0x0fmaps to map/level54 DAT_80063e68[54] = 0x0f
Why this still does not close the event:
- user-tested natural
MFM4did not produceJL-9 - so level-family membership alone is not sufficient
- the missing event now looks optional, late, rare, or route-specific
Upstream producer state
What still exists as topology
The older behavior/subop chain still exists in tables:
psx_behavior_opcode_handler_table[54] = 0x80027eccpsx_behavior_subop_handler_table[49] = 0x800214ac
0x80027ecc is now named conservatively:
psx_behavior_subopcode_dispatch
Why it is weaker now
The only currently proven caller into psx_object_behavior_opcode_dispatch is still range-limited:
- known caller path bounds
(opcode_word - 1) < 0x0aat0x80026710 - that means the known active path can only reach indices
0..9 - so
54 -> 49is still valid topology, but it is no longer the best active explanation
Current practical reading:
- keep
54 -> 49alive as structure - deprioritize it as the leading runtime explanation until a second active caller/context is recovered
Strongest event hypothesis now
The strongest remaining hypothesis is:
- the natural gate-arm is a sibling in the same late control-event family as mission-complete / transition handlers around
0x80022c6c..0x80023390 - it is probably an uncommon or optional in-level scripted/control outcome
- it is more likely tied to a rare objective-path or late-event branch than to ordinary mission completion itself
Why this is stronger than the older theories:
- the sink-side tuple and slot family are concrete
- mission-complete siblings are already proven in adjacent handlers
- hard-clear / beat-the-game theory stayed weak
- direct forced-gate tests show the real unknown is the natural writer event, not the hidden code
Ghidra changes applied in this event pass
Functions / blocks
0x800204fc->psx_show_mission_complete_congrats_text0x80020f7c->psx_control_event_apply_level_channel_preset0x800214ac->psx_level_gate_slot_dispatch_from_action_record0x80022c6c->psx_control_event_slot0d_handler0x80022ea8->psx_control_event_slot0e_handler0x80027ecc->psx_behavior_subopcode_dispatch
Tables / data
0x80063e54->psx_selector_to_map_id_table0x80063e68->psx_map_id_to_gate_slot_table0x80063eac->psx_map_progression_table0x80063610->psx_behavior_subop_handler_table0x800640a0->psx_level_gate_slot_handler_table0x800641ac->psx_behavior_opcode_handler_table
Key comments added
0x800214bc0x800215bc0x800215cc0x800215dc0x800215e00x800230e40x800232f00x800267100x8002685c0x80027f0c0x80034d60
Best next code targets
- Fully classify the control-event family around
0x80022c6c..0x80023390as one switch/tuple cluster and align each sibling branch with concrete player-facing outcomes. - Recover one actual authored producer for
(slot=0x0f, arg1=0x0a, arg2=0x04)by tracing the action-record inputs feeding0x800215cc/0x800215e0. - Find a second active caller/context into
psx_object_behavior_opcode_dispatchor an alternate feeder into0x800214acthat can justify a high-index producer path in live gameplay.
Deferred emulator experiments
Keep these queued for later:
- Experiment 2: hard-clear / beat-the-game test
- Experiment 4: compare
MFM4against another header-state-3code under matched in-level actions - Experiment 5: hold map/event family constant and vary only the suspected scripted event
- Experiment 6: ordering test (
event -> L0SR -> triggerversusL0SR -> event -> trigger)