155 KiB
PSX JL-9 / Hidden Passcode Investigation
This note is the compact fact-first summary for the active PlayStation SLUS_002.68 investigation around JL-2, JL-9, hidden passcodes, the extra post-cheat weapon lane, the checked VRAM dump, and the checked 2 MiB main RAM dump.
Natural in-level gate-arm event work now has its own companion note: docs/psx/jl-9-in-level-event.md.
Executive summary
Authored producer reachability correction pass (2026-04-12 live MCP)
This pass pushed farther on the authored producer side across
psx_load_type_state_banks -> psx_object_create_simple_record -> psx_run_object_behavior_program_tick -> psx_object_behavior_opcode_dispatch -> psx_behavior_subopcode_dispatch -> psx_level_gate_slot_dispatch_from_action_record.
Strongest producer-context update
- Loader/constructor provenance remains closed:
psx_load_type_state_banks(0x8003917c) installspsx_type_simple_component_bank[type]from level/LSET payload.psx_object_create_simple_record(0x800249f4) seeds componentprogram_base/pcfrom that bank.
- Behavior tick guard was revalidated at instruction level:
0x80026710checks(record_word0 - 1) < 0x0a, which is arg-count bound.- opcode is loaded separately from
record_word1(lw a0,0x4(a3)), so opcode54is not excluded by this guard.
- Subdispatch linkage is therefore viable as authored-program context (not guard-blocked):
- opcode table entry
54at0x80064284points topsx_behavior_subopcode_dispatch(0x80027ecc), - subop table entry
49at0x800636d4points topsx_level_gate_slot_dispatch_from_action_record(0x800214ac).
Best current candidate producer context
Strongest current candidate is still the type-state behavior program record lane:
- simple-record object instance in late final-mission family (
map_id_to_gate_slot == 0x0f) - component program emits opcode
54 - subop
49frame resolves to sink0x800214ac - sink record bytes resolve to tuple
(slot,arg1,arg2)=(0x0f,0x0a,0x04)
This is now stronger than the old "high opcode not proven active" read, because that old read depended on misinterpreting 0x80026710 as opcode clamp.
Authored-static vs runtime-remapped read (updated)
Current strongest classification remains:
- authored-static source lane at the behavior program record level,
- with optional runtime remap transport via arg-mask/index resolution in
psx_object_behavior_opcode_dispatch.
Reason: arg resolver can pass direct pointers to record words (static bytes) or map arg words through slot-index tables (base + index*4) when mask bits are set. Exact mask choice of the emitting shipped record remains open.
Live Ghidra changes applied in this pass
Decompiler comments updated:
0x80026710(arg-count guard correction; opcode still independent)0x8002685c(opcode table index semantics + entry 54 viability)0x80027f0c(subop dispatch viability depends on authored records, not guard exclusion)
No renames were applied in this pass.
Synthesis-only conservative-stabilization pass (2026-04-12 live MCP)
This pass was synthesis-only: no new lane expansion, only decision cleanup on what to stabilize in live naming/comments from the callback/countdown/progression clue set.
Updated concise natural-event synthesis
- Natural JL-9 arm remains a timing-sensitive in-level event lane, not a passcode-decoder-only effect.
0x8002745cand0x80027548remain indirect callback-table targets (no recovered direct callers), so they are transition/progression context, not standalone proven tuple emitters.0x80020794remains world-frame countdown/control flow with map-54 boundary split (<=54 -> 0x1a,>54 -> 0x1b) and no recovered direct edge into slot-dispatch sink0x800214ac.- Best current miss model is unchanged: late transition/progression can consume the active window before slot-
0x0ftuple(0x0a,0x04)reaches the arm write.
Live Ghidra changes applied in this pass
Decompiler comments were normalized to conservative evidence wording:
0x8002745c(psx_control_callback_apply_level_preset_or_resume): indirect callback-table target + branch split; explicitly marked not a standalone proven direct slot-0x0ffeeder.0x80027548(psx_control_callback_apply_progression_target_level): indirect callback-table target + progression-state timing lane; explicitly marked as non-proof of tuple emission by itself.0x80020794(psx_control_event_countdown_transition_tick): world-frame countdown/control lane + explicit no-direct-edge statement to sink0x800214ac.
No new renames were applied in this pass.
Names intentionally left conservative
- No tuple-specific rename for
0x8002745c(insufficient direct feeder proof). - No deterministic gate-arm rename for
0x80027548(supports timing influence, not guaranteed tuple production). 0x800230e4remainspsx_control_event_slot0f_handler(slot-family scope retained; no narrowing to a single branch writer name).
Progression latch timing pass (2026-04-12 live MCP)
This pass revisited psx_control_callback_apply_progression_target_level (0x80027548) to decide whether map 54 -> 55 progression can preempt natural slot-0x0f tuple arm (0x0a,0x04).
Strongest new timing implication
0x80027548readspsx_map_progression_table[current_map_id]and writes it throughpsx_level_session_set_next_map_id(0x8002ba84, renamed this pass).psx_level_session_set_next_map_idonly stages deferred next-map latchDAT_800678d0; it does not immediately changecurrent_map_id.psx_level_session_loopcommitscurrent_map_id <- DAT_800678d0at rollover (0x80031edc) after inner world-frame loop exit.- Practical consequence: this is not a same-tick overwrite race, but it still creates a preemption window if transition logic exits the map-54 loop before slot-
0x0ftuple branch(0x0a,0x04)is emitted.
54->55 miss-window read (updated)
54 -> 55remains the most likely natural miss window.- The key mechanism is deferred rollover ordering, not direct tuple clobber.
- Countdown/control map split at
0x800208f0(<=54 -> 0x1a,>54 -> 0x1b) plus staged progression target explains why natural tuple opportunity can disappear at the boundary.
Live Ghidra artifacts applied in this pass
Renames:
0x8002ba84->psx_level_session_set_next_map_id
Decompiler comments:
0x800275600x8002ba840x80031edc0x800208f0
Countdown-vs-slot frame-order closure pass (2026-04-12 live MCP)
This pass targeted one question only: whether the map-54 countdown split around 0x800208f0 can plausibly suppress or precede natural slot-0x0f arm tuple (0x0a,0x04).
Strongest causality clue recovered
Recovered world-frame order is now explicit in disassembly/decompile:
0x8002b830:psx_control_event_countdown_transition_tick0x8002b844:psx_run_live_object_behavior_callbacks0x8002b864:psx_update_motion_and_nearby_interactions0x8002b86c:psx_flush_deferred_control_queue
So countdown runs earlier in frame than the later behavior/deferred-control lanes that can eventually reach slot dispatch and slot-0x0f arm sink 0x800232f0.
Map-54 split relevance and branch read
- At
0x800208f0, countdown terminal handoff selects mode by map boundary:
current_map_id <= 54->0x1acurrent_map_id > 54->0x1b
- At
0x80020900, countdown immediately appliespsx_control_set_mode_and_reset_runtime_flags, writing shared control globals (DAT_800675e4,DAT_80067379). - Slot-
0x0farm branch(0x0a,0x04)inpsx_control_event_slot0f_handleralso writes the same control-mode family before/with gate write.
Updated relevance ranking
- Boundary timing is most relevant (strongest): early countdown split+mode write can narrow later slot-event windows in the same/next frame.
- Failure-side suppression is plausible but secondary: no direct countdown->slot call edge was recovered, but shared mode-state writes can still preempt tuple opportunity.
- Pure countdown-success branch is weakest: no recovered success-path edge deterministically forcing tuple
(0x0f,0x0a,0x04).
Live Ghidra artifacts applied in this pass
No renames in this pass.
Decompiler comments added:
0x8002b830: frame-order anchor (countdown before behavior/deferred lanes)0x80020900: boundary handoff writes shared mode/state before later slot lanes0x800232f0: slot-0x0farm sink is later lane than countdown tick
Slot-0x0f subcase taxonomy pass (2026-04-12 live MCP)
This pass classified psx_control_event_slot0f_handler (0x800230e4) subcases beyond tuple (0x0a,0x04) to narrow natural JL-9 semantics without overfitting a single folklore path.
Compact taxonomy (slot 0x0f family)
param2=0x0a, param3=0x01/0x02/0x03
- Transition/objective-state setup (not direct reward grant).
- Evidence: each branch writes shared control mode/timer state (
DAT_80067340/44), plays a CD-XA cue (0x1a/0x1b/0x1dvia0x80049014), and clears per-event runtime latches. param3=0x03additionally setsDAT_80067354=1.
param2=0x0a, param3=0x2e
- Opcode-stream transition/reset lane.
- Evidence: switches opcode stream index (
psx_control_assign_opcode_stream_by_index(...,1)) and performs the same latch-clear pattern.
param2=0x01, param3=0x01
- Countdown/objective-pressure arm lane.
- Evidence: writes
DAT_8006734d/4e/4f, which are read bypsx_control_event_countdown_transition_tickandpsx_draw_clock_digits_overlay.
param2=0x04, param3=0x01
- Per-level message/objective-notice lane.
- Evidence: loads text from
DAT_8006754c + index, sets timer/control globals, and drives shared countdown-style object iteration side effects.
param2=0x06, param3=0x42
- Type-gated control transition lane.
- Evidence: writes only global mode latches (
DAT_800675e4,DAT_80067379,DAT_80067350) and reset helpers; no constructor/resource-bind call.
param2=0x0a, param3=0x04(anchor case)
- Eligibility arm latch for hidden follow-up, not immediate reward.
- Evidence: only this subcase writes
psx_debug_extra_channel_gate(0x800232f0) underpsx_hidden_passcode_flag==0 && psx_level_runtime_header_state==3.
Implication for (0x0a,0x04)
The surrounding slot-0x0f family is dominated by transition/countdown/objective-state control lanes and messaging, not direct reward payout handlers. That makes (0x0a,0x04) best interpreted as a late objective-state eligibility arm inside that control family, rather than a standalone reward/failure terminal event.
Live Ghidra artifacts applied in this pass
Renames:
0x80049014->psx_audio_cdxa_select_and_play_cue
Decompiler comments added:
0x80023154(slot0f0x0a/1transition setup)0x800231b0(slot0f0x0a/2countdown/objective-state setup)0x8002321c(slot0f0x0a/3sibling objective-state branch)0x80023334(slot0f0x0a/0x2eopcode-stream reset lane)0x80023390(slot0f0x01/1countdown-overlay/objective-pressure lane)0x800236d8(slot0f0x04/1level-message objective cue lane)0x800237cc(slot0f0x06/0x42type-gated control transition lane)
Transition callback provenance pass (2026-04-11 live MCP)
This pass traced the newly recovered transition callbacks at 0x8002745c and 0x80027548 to determine provenance, state effects, and impact on the slot-0x0f tuple lane.
Provenance (best current)
- Neither callback has a recovered direct caller xref (
get_callersreturns none for both entries). - Both are data-referenced from a contiguous function-pointer region near
0x800641f0..0x80064220:
0x80064200 -> 0x8002745c0x80064210 -> 0x80027548
- Current best classification is therefore indirect callback-table dispatch from an unresolved transition/control dispatcher, not direct static callsites.
State effects recovered
0x8002745c(psx_control_callback_apply_level_preset_or_resume):
- if
DAT_80078a14 == 0, it callspsx_control_event_apply_level_channel_preset(0x80020f7c) thenpsx_control_reset_runtime_flag_67780. - else it takes an alternate resume lane (
FUN_80044074) and setsDAT_800673c4 = 1.
0x80027548(psx_control_callback_apply_progression_target_level):
- computes
next = psx_map_progression_table[current_map_id]and applies it viaFUN_8002ba84.
Slot-0x0f tuple carry/suppress read
0x8002745ccan carry tuple opportunity when it takes theDAT_80078a14 == 0branch because that branch executes0x80020f7c(the known level/channel apply helper in this late control lane).- The alternate branch in
0x8002745ccan suppress or defer tuple opportunity for that tick because it skips0x80020f7cand takes resume/state handling instead. 0x80027548increases timing sensitivity: it advances map progression before later control-event handling, so slot-0x0ftuple(0x0a,0x04)only carries if emitted after/within the progressed state window; otherwise progression can outrun the arm branch.- For map
54 -> 55, this is not a simple family exit (both are still slot-0x0ffamily), but it is a real state-transition step that can change event ordering and reduce deterministic tuple timing.
Live Ghidra artifacts applied in this pass
Comments added:
0x8002745c: table-dispatch provenance + carry/suppress branch semantics.0x80027548: progression callback provenance + timing-sensitive tuple implication.0x80064200: callback-table-region note for0x8002745centry.0x80064210: callback-table-region note for0x80027548entry.
No additional renames were applied in this pass (existing callback names remained conservative and evidence-backed).
Multi-map last-mission chain check (2026-04-11 live MCP)
This pass tested the specific hunch that the last mission is split across multiple maps and that this split explains why the JL-9 gate-arm family is level-grouped (54/55/56/57/58) instead of single-map.
Fresh table evidence (live bytes)
Recovered directly from active SLUS_002.68 memory tables:
- Selector anchor into the family:
psx_selector_to_map_id_table[0x0f]at0x80063e63is0x36(map54).
- Gate-slot family closure for the target chain:
psx_map_id_to_gate_slot_table[54..58]at0x80063e9e..0x80063ea2is0x0f,0x0f,0x0f,0x0f,0x0f.
- Progression chain closure:
psx_map_progression_table[54..58]at0x80063ee2..0x80063ee6is0x37,0x38,0x39,0x3a,0xff(55,56,57,58,terminal).
Net result: this is a concrete contiguous progression chain that stays inside one gate-slot family (0x0f) until terminal progression marker 0xff.
Control/transition helper evidence for split-flow behavior
psx_control_event_countdown_transition_tick(0x80020794) has an explicit map boundary at0x800208f0:
current_map_id <= 54uses mode0x1acurrent_map_id > 54uses mode0x1b
psx_control_event_slot0e_handlerhas a late feeder branch at0x80023074that writes selector0x0fthen callspsx_control_event_apply_level_channel_preset.psx_control_event_apply_level_channel_presetreads both:
psx_map_progression_table[current_map_id](0x80020fa4)psx_map_id_to_gate_slot_table[current_map_id](0x80020fbc)
This supports a staged final-mission flow where late transition/control logic can traverse 54..58 while remaining in the same slot-0x0f gate family.
Best reconstruction (current)
- Normal passcode selector path anchors entry at map
54(selector 0x0f -> map 54). - Late control/transition logic advances through progression chain
54 -> 55 -> 56 -> 57 -> 58. - Across that chain, gate dispatch stays in slot family
0x0f. - Terminal progression marker at map
58(0xff) indicates end-of-chain behavior rather than another ordinary progression handoff.
JL-9 implication update
This strengthens, not weakens, the level 54 natural-host read:
54remains the only member with direct selector anchor from the recovered normal passcode path.55..58are now better interpreted as downstream split-phase transition maps in the same family.- The family-wide slot-
0x0fmapping now looks like deliberate multi-map mission staging, which explains why JL-9 gate logic is host-family scoped while still leaving54as the strongest reproducible natural entry.
Live Ghidra artifacts applied in this pass
Disassembly comments added:
0x80063e63(selector0x0f-> map54anchor)0x80063e9e(map54slot-0x0ffamily start)0x80063ea2(map58slot-0x0fterminal-edge note)0x80063ee2(progression54 -> 55chain start)0x80063ee6(progression58 -> 0xffterminal marker)0x800208f0(map-54 boundary split0x1a/0x1b)0x80023074(slot-0x0elate feeder back into selector0x0ffamily)0x80020fa4(progression-table read and54..58staged flow note)
Level-54 boundary clue pass (2026-04-11 live MCP)
This pass focused on one narrow question: why natural MFM4 can still miss even when map 54 remains the best host anchor.
Strongest level-54-specific clue
psx_control_event_countdown_transition_tick (0x80020794) has an explicit map boundary at 0x36 (54):
- at terminal countdown handoff, it chooses control mode code
0x1awhencurrent_map_id <= 0x36 - and chooses
0x1bwhencurrent_map_id > 0x36
This is a concrete level-54 split in late control flow, not a generic family-level observation.
Supporting progression/control evidence recovered in the same pass:
psx_control_callback_apply_progression_target_level(0x80027548) appliespsx_map_progression_table[current_map_id]viaFUN_8002ba84- for map
54, that progression target is55 psx_level_gate_slot05_handler(0x80021fac) has tuple branch(param2=0x0a,param3=0x28)that callspsx_control_event_apply_level_channel_presetand reset helpers, giving an optional late state-advance lane before slot0x0f(0x0a,0x04)arm may fire
Practical interpretation for natural MFM4 failures
Current best read is now sharper:
MFM4still correctly primes the strongest known host (selector 0x0f -> map 54,runtime_header_state=3).- Failure is most likely a timing/optional-path miss inside late control-event progression around the map-54 boundary split, not wrong-host decode.
- The rare miss model is: a transition/control branch (including map-54-specific
0x1alane and optional slot05 branching) can advance or reroute state before slot0x0f(0x0a,0x04)writespsx_debug_extra_channel_gate.
Live Ghidra artifacts applied in this pass
Renames:
0x80020794->psx_control_event_countdown_transition_tick0x800205e8->psx_control_event_apply_countdown_step0x80020d54->psx_control_set_mode_and_reset_runtime_flags- created
0x8002745c->psx_control_callback_apply_level_preset_or_resume - created
0x80027548->psx_control_callback_apply_progression_target_level
Comments:
0x800208f0: level-54 boundary (<=54 -> 0x1a,>54 -> 0x1b) and timing implication0x80022068: slot05(0x0a,0x28)optional late-event/preset lane note0x80027560: progression callback note (next = map_progression_table[current_map_id])
Slot-handler sibling recovery around table 0x800640a0 (2026-04-11 live pass)
Focused scope for this pass was the still-raw slot-handler siblings referenced by
psx_level_gate_slot_handler_table (0x800640a0), with emphasis on whether any
0x0a sibling branch competes with or narrows tuple (0x0a,0x04) in slot 0x0f.
Recovered sibling handler roles (table entries)
Newly created and named from table boundaries (address range split by next table entry):
0x800215fc->psx_level_gate_slot01_handler0x80021810->psx_level_gate_slot02_handler0x800219e4->psx_level_gate_slot03_handler0x80021fac->psx_level_gate_slot05_handler0x80022214->psx_level_gate_slot06_handler0x800222e8->psx_level_gate_slot07_handler0x800223cc->psx_level_gate_slot08_handler0x800226e0->psx_level_gate_slot09_handler0x800227ac->psx_level_gate_slot0a_handler0x80022b50->psx_level_gate_slot0c_handler0x80023854->psx_level_gate_slot00_handler0x80023af0->psx_level_gate_slot10_return_true
Existing slot siblings kept/updated:
0x80022c6c=psx_control_event_slot0d_handler0x80022ea8=psx_control_event_slot0e_handler0x800230e4=psx_control_event_slot0f_handler0x80022940renamed topsx_level_gate_slot0b_control_pair_handler- table entry still points to
0x8002293c(first prologue instruction), now preserved via comment.
New interpretation of the 0x0a subcase family
Current strongest narrowing is now sibling-explicit across slots 0x0a..0x0f:
- Slot
0x0a(0x800227ac) has(0x0a,0x01..0x03)control/timer branches and does not writepsx_debug_extra_channel_gate. - Slot
0x0b(0x80022940)(0x0a,0x02)sets policy bitDAT_80078a88 |= 0x0400, but is not a gate-byte writer. - Slot
0x0c(0x80022b50)0x0afamily is control/message gated byDAT_80078a88 & 0x200, with no recovered gate-byte write. - Slot
0x0d(0x80022c6c)(0x0a,0x02)is mission-complete passcode text lane (quad index 0x0e). - Slot
0x0e(0x80022ea8)(0x0a,0x01)is mission-complete passcode text lane (quad index 0x0f);(0x0a,0x06)is late selector/apply transition. - Slot
0x0f(0x800230e4)(0x0a,0x04)remains the only recovered sibling in this family that can armpsx_debug_extra_channel_gate(write at0x800232f0) under non-hidden + header-state-3 predicates.
So (0x0a,0x04) is now narrower than before: it is not just “one 0x0a case in slot0f”, it is the only recovered 0x0a-family sibling across adjacent slot handlers that actually sets the JL-9 gate byte.
0x0a control-family semantic closure (2026-04-11 live pass)
This pass was restricted to the late control family around:
0x80022c6c(psx_control_event_slot0d_handler)0x80022ea8(psx_control_event_slot0e_handler)0x800230e4(renamed this pass topsx_control_event_slot0f_handler)0x80020f7c(psx_control_event_apply_level_channel_preset)
Best semantic classification for (0x0a,0x04)
Current best read is control-event eligibility arm (pre-hidden gate latch), not a reward payload by itself.
Evidence:
(0x0a,0x04)is in slot0x0fhandler and writespsx_debug_extra_channel_gateonly under:
psx_hidden_passcode_flag == 0psx_level_runtime_header_state == 3
- The write is a single byte latch (
sb) at0x800232f0, then consumed later by the hidden/debug grant lane at0x8002fff4. - Sibling
0x0acases in slot0x0d/0x0eare mission-complete text/transition/control setup branches, which places(0x0a,0x04)inside a broader control progression family rather than a standalone "grant now" event.
Sibling-case comparison table (param_2 == 0x0a)
| Handler slot | Address | Subcase (param_3) |
Strongest semantics | Direct effect |
|---|---|---|---|---|
0x0d |
0x80022c6c |
0x02 |
mission-complete passcode text branch | generates encoded quad index 0x0e, writes congratulations text |
0x0e |
0x80022ea8 |
0x01 |
mission-complete passcode text branch | generates encoded quad index 0x0f, writes congratulations text |
0x0e |
0x80022ea8 |
0x02..0x04 |
transition/setup control branches | mode/timer/runtime control setup |
0x0e |
0x80022ea8 |
0x06 |
late selector/channel transition | sets selector 0x0f, calls psx_control_event_apply_level_channel_preset and psx_passcode_apply_mission_selector_and_stage |
0x0f |
0x800230e4 |
0x01..0x03 |
sibling control/event setup | runtime/control side effects without gate-byte arm |
0x0f |
0x800230e4 |
0x04 |
pre-hidden eligibility arm latch | conditional write psx_debug_extra_channel_gate = 1 at 0x800232f0 |
Net: (0x0a,0x04) is best classified as a control-arm/preset-eligibility latch for the later hidden completion path, not as direct reward completion.
Sink-side feeder closure (2026-04-11 live pass)
This pass was restricted to the sink-side feeder and argument sourcing around 0x800214ac..0x800215f8.
Recovered action-record dispatch structure
Recovered function body is now promoted in live Ghidra as:
0x800214ac->psx_level_gate_slot_dispatch_from_action_record
Observed layout used by this dispatcher:
record+0x00-> pointer to slot byte (slot = *(*(record+0x00)))record+0x08-> pointer to arg1 byte (arg1 = *(*(record+0x08)))record+0x0c-> pointer to arg2 byte (arg2 = *(*(record+0x0c)))
Dispatch mechanics:
- level gate compare uses
psx_map_id_to_gate_slot_table[current_map_id](0x80063e68) - indirect call uses
psx_level_gate_slot_handler_table[slot](0x800640a0) - slot
0x0fentry points to0x800230e4(psx_set_debug_extra_channel_gate) at table address0x800640dc
JL-9 gate-arm tuple remains explicit and unchanged:
- slot
0x0f arg1 = 0x0aarg2 = 0x04
which reaches the gate-byte write branch at 0x800232f0.
Upstream producer status (what is proven)
Proven table topology into the sink feeder:
psx_behavior_opcode_handler_table[54] = 0x80027ecc(psx_behavior_subopcode_dispatch) at0x80064284psx_behavior_subop_handler_table[49] = 0x800214ac(psx_level_gate_slot_dispatch_from_action_record) at0x800636d4
Current proof boundary remains the same:
- known gameplay caller lane into
psx_object_behavior_opcode_dispatchstill enforces(opcode_word-1) < 0x0aat0x80026710 - therefore
54 -> 49 -> 0x800214acis retained as proven table topology, not yet proven active on the currently recovered caller path
Host-level family closure for natural JL-9 gate-arm (2026-04-11 live pass)
Scope of this pass was restricted to the host-side family {54,55,56,57,58,82} with direct MCP evidence for:
- selector mapping (
psx_selector_to_map_id_table,0x80063e54) - level/map gate-slot mapping (
psx_map_id_to_gate_slot_table,0x80063e68) - progression/completion transitions (
psx_map_progression_table,0x80063eac, plusFUN_80020f7ccallers)
Exact mapping closure used for ranking
- Published normal-code selector closure still anchors on selector
0x0f:
psx_selector_to_map_id_table[0x0f] = 0x36(map id54)
- Slot-family closure for natural gate-arm dispatch:
psx_map_id_to_gate_slot_table[54] = 0x0fpsx_map_id_to_gate_slot_table[55] = 0x0fpsx_map_id_to_gate_slot_table[56] = 0x0fpsx_map_id_to_gate_slot_table[57] = 0x0fpsx_map_id_to_gate_slot_table[58] = 0x0fpsx_map_id_to_gate_slot_table[82] = 0x0f
- Reciprocal passcode-validation behavior in caller flow around
0x80034d60..0x80034d7cremains strongest for map54:
- map id
54round-trips throughslot 0x0f -> map 54by reverse lookup - sibling family members (
55..58,82) share slot0x0fbut do not have the same direct selector round-trip anchor in recovered normal passcode tables
Late objective/completion hosting evidence
FUN_80020f7c remains the strongest late transition hub in this lane. Live callers include:
0x800220680x80022e580x800230800x8002748c
and the helper itself reads both:
psx_map_progression_table[current_map_id](0x80020fa4)psx_map_id_to_gate_slot_table[current_map_id](0x80020fbc)
Progression bytes for the host family are now explicit:
- map
54 -> 0x37(55) - map
55 -> 0x38(56) - map
56 -> 0x39(57) - map
57 -> 0x3a(58) - map
58 -> 0xff(terminal marker in this table) - map
82 -> 0x53(83)
This keeps a completion-timing explanation live: transition-heavy late events can move execution across the same slot-0x0f family, but not all members are equally stable for deterministic player replication.
Ranked host levels/maps (current best)
- Map/level 54 (best host)
- only family member directly anchored by recovered normal selector path (
0x0f -> 54) - satisfies both prime-side and slot-family-side constraints in one static route
- Map/level 55
- immediate progression successor of 54 and still in slot-
0x0ffamily - plausible if gate-arm event is late-transition-bound rather than early-in-map
- Map/level 56
- same slot family, but one transition further away from direct passcode anchor
- Map/level 57
- same slot family, lower reproducibility due to additional transition depth
- Map/level 82
- valid slot-family host (
0x0f) but weak for this specific user scenario because no direct published selector anchor was recovered
- Map/level 58
- slot-family valid, but progression entry marks terminal (
0xff) and is therefore most likely to race/exit through completion paths rather than offer stable pre-hidden gate-arm timing
Best current explanation for failed natural MFM4
After the failed natural MFM4 trial, the best-supported explanation remains event-host/timing failure, not decode failure:
MFM4still fits the strongest static prime (runtime_header_state==3, selector family leading to map54).- The missing piece is still the in-level/control dispatch that must reach slot
0x0fwith tuple(0x0a,0x04)before hidden-mode trigger. - Completion/transition hubs (
FUN_80020f7ccallers) can move state through family members and potentially past the required gate-arm moment. - So a natural run can fail even with correct passcode if:
- the specific tuple event never fired,
- it fired outside the required hidden-flag polarity window,
- or progression/completion moved the run into a less stable timing state before hidden-input trigger.
Net result for this pass: map 54 remains the best host candidate, but MFM4 alone is not expected to be sufficient without the concrete in-level event timing.
Late-objective / mission-complete clue pass (2026-04-11, live MCP)
Focused this pass only on concrete late-objective and reward-event clues that can naturally arm the JL-9 gate path (psx_debug_extra_channel_gate), with emphasis on mission-complete text handlers, transition siblings, and uncommon branch outcomes.
Hard evidence (high confidence)
- Mission-complete congratulations strings are anchored at:
0x80063f10: congrats template with next-passcode tail.0x80063f74: shorter congrats variant.
- Two adjacent control-event handlers are concrete mission-complete/passcode writers:
0x80022c6c(DAT_800640a0[0x0d]): slot-0x0dbranch generates encoded passcode index0x0eand writes congrats text.0x80022ea8(DAT_800640a0[0x0e]): slot-0x0ebranch generates encoded passcode index0x0fand writes congrats text.
- Slot-
0x0ehas a concrete late-transition branch that force-loads selector0x0f:
- at
0x80023040(param2=0x0a,param3=6branch), code setsDAT_80078a8c=0x0fand callspsx_passcode_apply_mission_selector_and_stage.
- Selector/channel mapping remains decisive for natural gate-arm routing:
selector 0x0f -> level 0x36 (54) -> DAT_80063e68[level]=0x0f.- in sampled selector range, this is the only selector that maps directly into channel family
0x0f.
- Natural gate-arm write remains bounded to slot-
0x0fcase(param2=0x0a,param3=4):
- write at
0x800232f0setsDAT_8006739donly ifpsx_hidden_passcode_flag==0andpsx_level_runtime_header_state==3.
Text-display siblings and uncommon branch clues
- Slot-
0x0ftext-display sibling at0x800236dc(param2=4,param3=1) callsui_message_set_active_text(DAT_8006754c + idx).
- This is resource-table driven, distinct from hardcoded congratulations templates.
- It is a strong clue for optional scripted outcomes/messages tied to level-authored text resources.
- Slot-
0x0euncommon outcomes include:
param3=5: writesDAT_80078a10=2(state-only branch).param3=6: direct selector apply to0x0f(late transition behavior, not ordinary text-only flow).
Strongest natural late-objective candidate events from this pass
slot 0x0emission-complete transition branch (0x80022ea8,param2=0x0a,param3=6) as the clearest upstream feeder into selector/channel0x0ffamily.slot 0x0fevent branch (0x800230e4,param2=0x0a,param3=4) as the proven natural JL-9 gate-arm writer under non-hidden + runtime-state-3 predicates.slot 0x0ftext-resource branch (0x800236dc,param2=4,param3=1) as the strongest sibling clue for uncommon/optional scripted objective messaging that likely co-occurs with late transition states.
What is still speculation
- Exact player-visible authored event sequence inside the level (the concrete map script moment) that emits
slot 0x0fwith(0x0a,4)remains unclosed. - Any claim that one specific congratulation screen alone implies gate-arm is still speculative; current proof is branch-level and table-level, not full authored mission-script closure.
0x0a family case-map closure around natural JL-9 gate arm (2026-04-11 live pass)
This pass was restricted to the control-event family around 0x80022c6c..0x80023390 with live MCP decompile/disassembly and conservative in-database naming.
Recovered sibling handlers and table roles
- Slot-handler table bytes at
0x800640d4/0x800640d8/0x800640dcconfirm sibling entries:
- slot
0x0d->0x80022c6c - slot
0x0e->0x80022ea8 - slot
0x0f->0x800230e4(psx_set_debug_extra_channel_gate)
- Sink dispatch block
0x800214ac..0x800215f8remains the slot-gated tuple sink:
- compare slot byte with
DAT_80063e68[current_level] - if equal, call
DAT_800640a0[slot]with tuple(param_2,param_3)loaded from record-byte pointers.
Concrete 0x0a family mapping (best current)
For these three sibling handlers, param_2 == 0x0a is the family selector and param_3 is the subcase index.
- Slot
0x0dhandler (0x80022c6c):
(0x0a,0x02): generates passcode quad index0x0e, writes encoded chars to0x80063f6e..0x80063f71, shows congratulations text.
- Slot
0x0ehandler (0x80022ea8):
(0x0a,0x01): same mission-complete passcode lane but quad index0x0f.(0x0a,0x02..0x04): mode/timer setup branches.(0x0a,0x06): applies mission selector and stage.
- Slot
0x0fhandler (0x800230e4):
(0x0a,0x01..0x04,0x2e)switch family.- critical branch
(0x0a,0x04)at0x800232f0: setspsx_debug_extra_channel_gate=1only whenpsx_hidden_passcode_flag==0andpsx_level_runtime_header_state==3.
Interpretation of tuple (0x0a,0x04)
Strongest conservative interpretation is unchanged but now better bounded: this is the natural pre-hidden arm event branch in the slot-0x0f family, sibling to mission-complete/control subcases in slots 0x0d/0x0e/0x0f, and it is the direct writer path for the later hidden debug grant extra-lane check.
Practical consequence:
(0x0a,0x04)is not an isolated special; it belongs to a coherent control-event sibling family.- Its placement next to mission-complete style tuple branches strengthens the read that the missing natural trigger is an in-level authored control-event emission, not a separate passcode-screen operation.
Natural in-level event synthesis and conservative naming sweep (2026-04-11 live pass)
This pass was restricted to the natural in-level gate-arm event lane for JL-9, not the broader hidden/debug chain.
Event-only synthesis (current best conservative read)
- Natural arm still centers on in-level control/event dispatch into the slot-gated sink block at
0x800214ac..0x800215f8. - Inside that sink, current-level family is checked against the slot index and then dispatches through slot-handler table entry
slot 0x0f -> 0x800230e4(psx_set_debug_extra_channel_gate). - Actual gate write remains constrained to tuple branch
(param_2 == 0x0a, param_3 == 0x04)at0x800232f0, plus existing non-hidden/header-state predicates. - Upstream behavior-opcode topology (
opcode 54 -> subop 49 -> sink) is still structurally supported by table links, but active reachability from the only proven gameplay caller lane remains unproven because the recovered guard at0x80026710bounds the known lane to(opcode_word-1) < 0x0a.
Live Ghidra conservative rename/comment sweep applied
Renamed data/labels (only still-raw central entities):
0x800640a0:PTR_LAB_800640a0->psx_level_gate_slot_handler_table0x800641ac:PTR_LAB_800641ac->psx_behavior_opcode_handler_table0x80063610:PTR_LAB_80063610->psx_behavior_subop_handler_table0x800214ac:LAB_800214ac->psx_level_gate_slot_dispatch_block_800214ac0x80027ecc:LAB_80027ecc->psx_behavior_subop_dispatch_block_80027ecc
Added disassembly comments (evidence/uncertainty preserving):
0x800215dc: level-family compare + slot-table indirect-call behavior (slot0x0fsink relevance).0x800232f0: exact gate-arm tuple and predicate reminder.0x8002685c: opcode-table dispatch note plus proven caller-lane bound reminder.0x80027f0c: sub-op table dispatch note with explicit reachability uncertainty.0x800214ac: event-sink dispatch-role note.
Unresolved on purpose
- Exact player-visible authored in-level event that naturally emits the
(0x0f, 0x0a, 0x04)sink tuple. - Proof of an additional active caller/context that can reach high behavior-opcode entries beyond the known
< 0x0alane. - Any stronger semantic name for
0x80027eccthan conservative sub-op dispatch block labeling.
Event-only synthesis continuation (2026-04-11 live pass)
Scope of this continuation pass was intentionally narrow: keep sink-side natural-event naming durable without promoting unproven upstream producer semantics.
Updated concise synthesis (event-only)
- Natural JL-9 pre-hidden arm remains a slot-family control-event branch, not a passcode-screen branch.
- Sink path is unchanged and still strongest:
psx_level_gate_slot_dispatch_from_action_record(0x800214ac) validates current-level family, then dispatches throughpsx_level_gate_slot_handler_table[slot]. - Slot
0x0fresolves topsx_control_event_slot0f_handler(0x800230e4), where tuple(0x0a,0x04)at0x800232f0conditionally writespsx_debug_extra_channel_gateonly underhidden==0 && runtime_header_state==3. - Upstream
opcode 54 -> subop 49 -> sinkremains table-valid topology, but active gameplay reachability is still unproven past the known caller lane bounded by(opcode_word-1) < 0x0a.
Exact live Ghidra artifacts changed in this continuation pass
Renamed function:
0x800230e4:psx_set_debug_extra_channel_gate->psx_control_event_slot0f_handler
Renamed table-entry labels:
0x800640d4->psx_level_gate_slot_handler_slot0d_entry0x800640d8->psx_level_gate_slot_handler_slot0e_entry0x800640dc->psx_level_gate_slot_handler_slot0f_entry
Added/updated comments:
0x800230e4: slot-0x0ffamily role comment; gate write classified as one subcase.0x800232f0: exact natural gate-arm tuple + predicate comment.0x800640dc: slot-0x0ftable-entry comment with tuple anchor.0x80064284: opcode-table entry54comment preserving topology-vs-reachability split.0x800636d4: subop-table entry49comment preserving topology-vs-reachability split.
Deliberately unresolved / refused names
- Refused rename:
psx_behavior_subopcode_dispatch(0x80027ecc) to any stronger event-producer name.
- Why refused: no direct recovered caller currently proves active high-index opcode reachability on gameplay path.
- Refused rename:
psx_level_gate_slot_dispatch_from_action_record(0x800214ac) to mission-specific or JL-9-specific wording.
- Why refused: sink dispatch behavior is generic slot-family machinery beyond JL-9.
Published mission code sweep closure (2026-04-11 live pass)
Focused live pass on the user-supplied ordinary PSX mission code table was used to answer one narrow question: does any published non-hidden mission code already satisfy the static JL-9 preconditions, or do they all fail before the hidden/debug stage?
Exact decode-space closure
- Ordinary passcode rows are decode indices
i = 0x00..0x0e. - Special passcodes are the next three rows:
i = 0x0f=>?RTNfamilyi = 0x10=>?0SRfamilyi = 0x11=>?QQQfamily
- For ordinary rows, selector space is offset by one:
- ordinary decoded row
ireturns selectors = i + 1
- First-character difficulty only affects
psx_level_runtime_header_state; it does not choose the selector/current-level lane.
Strongest published-code candidate
MFM4 is now the strongest ordinary published JL-9 setup candidate.
Reasoning:
- Suffix
FM4matches ordinary decode rowi = 0x0e. - First char
Myields accepted delta3, so normal decode writespsx_level_runtime_header_state = 3. - Ordinary row
i = 0x0ereturns selectors = 0x0f. - Live table bytes then map:
DAT_80063e54[0x0f] = 0x36(54decimal)DAT_80063e68[54] = 0x0f
- Therefore
MFM4is the only currently recovered published mission code that statically satisfies both known preconditions at once:
- non-hidden prime with
runtime_header_state == 3 - current-level family that can reach slot-
0x0fdispatch
Strong negatives from the same sweep
LRTN/MRTN/PRTNare not ordinary mission primes; they are the special?RTNfamily and clearpsx_level_runtime_header_stateto0.- the older contradiction in this investigation came from mixing decode-row space (
i) with returned selector space (s);MFM4works because ordinaryi = 0x0estill returns selector0x0f. - no published mission code currently closes the full JL-9 route by itself; even
MFM4still needs the in-level gate-arm event and then the later hidden/input trigger. - the user-supplied level-11 strings containing
Oshould be treated cautiously as written becauseOis not present in the recovered passcode alphabet (BCDFGHJKLMNPQRSTVWXZ0123456789).
Practical consequence
Current best actionable static route is now:
- Enter
MFM4as the ordinary prime. - In the same running session, hit the in-level scripted/control event that emits dispatch tuple
(0x0f,0x0a,0x04)and armspsx_debug_extra_channel_gate. - Enter hidden
L0SR/?0SR. - Press
R1 + Circle.
This is still not a fully closed player recipe because step 2 remains the missing concrete event, but it is now the strongest evidence-backed published-code path rather than a generic “some normal code with state 3” placeholder.
Hard-clear theory check and manual gate-poke closure (2026-04-11 live pass)
Two follow-up questions were tested after MFM4 was isolated as the strongest published prime candidate:
- is the missing in-level trigger actually tied to beating the game, especially on hard?
- if not, is manual arming of the known gate byte enough to make hidden
L0SRplus the trigger input unlockJL-9?
Hard-clear theory verdict
Current evidence keeps the "beat the game on hard, then enter L0SR" theory in the weak-to-medium bucket, not the lead explanation.
What was actually recovered:
- congratulation/completion text paths do exist near unnamed code around
0x800204fc,0x80022d20, and0x80022f68. - those paths are plausible mission-complete / transition / UI handlers, but no direct write to
psx_debug_extra_channel_gate(0x8006739d) was recovered from them. - no better persistent JL-9-specific latch was recovered than the already-known gate byte itself.
- the strongest executable-backed model still points to an in-level scripted/event dispatch lane, not a post-credits reward lane.
So the current read is narrower than folklore but not fully closed:
MFM4plausibly matters because it is the only published prime that setsruntime_header_state = 3and reaches the slot-0x0fgate family.- but beating the final mission on hard is not yet proven to be the missing arm event.
- the unresolved gap remains the same concrete in-level producer for dispatch tuple
(0x0f,0x0a,0x04).
Manual gate-poke closure
The practical emulator test is now strong enough to state directly.
psx_debug_extra_channel_gateis runtime byte0x8006739d.- writer at
0x800232f0usessb, so storage is byte-wide. - reader at
0x8002fff4useslbuthen branches on zero, so the gate is checked as nonzero, not as one exact magic literal. - no second direct writer or clear for
0x8006739dhas been recovered in the inspected session/load/menu paths.
Practical manual test sequence
The strongest current poke test is:
- set byte
0x8006739d = 0x01 - enter hidden
L0SR/?0SR - press
R1 + Circle
Expected result if the trigger path executes normally:
- hidden input path reaches
psx_debug_grant_weapon_channels_and_ammo - late read at
0x8002fff4sees nonzero gate byte - extra unlock path at
0x80030004runs for channel/index0x0d(JL-9lane)
Practical caveats
- the poke bypasses the natural writer-side predicates (
hidden==0,runtime_header_state==3), so it does not validate the true in-level event by itself. - hidden mode still has to be active when the input trigger is pressed.
- if the emulator uses uncached/physical mirrors, the same byte may appear as
0x0006739ddepending on the UI, but the logical KSEG0 runtime address is0x8006739d. - if a manual test fails with gate byte set, the next most likely cause is that hidden mode timed out or the input chord did not decode to
0x1e.
User-validated downstream closure
User emulator verification now confirms the downstream half directly:
- set main-memory byte
0x8006739d = 0x01 - enter
L0SR - start gameplay and press
R1 + Circle - result:
JL-9appears in inventory next toJL-2
Practical meaning of that success:
- this validates the late hidden/input grant half of the model, not the natural writer path.
- the poke directly pre-satisfies the nonzero check at
0x8002fff4, so the test does not prove thatMFM4or the natural in-level gate-arm event occurred. - among those two upstream elements, the more direct thing bypassed is the in-level trigger itself, because the poke replaces the writer result (
psx_debug_extra_channel_gate = 1) rather than recreating the natural writer predicates that would normally produce it. MFM4is therefore best read now as the strongest natural prime candidate, not as a required part of the forced test.
User experiment follow-up (2026-04-11)
Additional emulator trials now tighten the natural-versus-forced split further.
- Natural
MFM4trial:
- user entered
MFM4, allowed the level to load, then later returned to menu and attempted the hidden/input phase. - result: no
JL-9; only ordinaryJL-2was present. - practical meaning: current evidence no longer supports
MFM4by itself as a sufficient natural route.
- Forced-gate control with non-hard final-level code:
- user entered
JFM4(final map on easy), returned to menu, set0x8006739d = 0x01, enteredL0SR, started a level, and pressedR1 + Circle. - result:
JL-9still appeared. - practical meaning: the forced downstream route does not depend on
MFM4specifically; manual gate arm is enough even when the prime code is not the hard-difficulty candidate.
Current best interpretation after these trials:
MFM4remains the strongest natural prime candidate because it matches the writer-side predicates statically.- but it is no longer the lead bottleneck for the overall mystery.
- the missing natural in-level event is now the dominant unknown.
Deferred user experiments
Keep these queued for later follow-up:
- 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: strict ordering test (
event -> L0SR -> triggerversusL0SR -> event -> trigger)
NRTN / ?RTN passcode path closure (2026-04-11 live pass)
Focused live MCP pass on active SLUS_002.68 for:
psx_passcode_decode_to_mission_selector(0x8003ec8c)psx_passcode_apply_mission_selector_and_stage(0x80021138)- caller block around
0x80034c14..0x80034ddc
Exact decode and selector behavior
- The special
?RTNrow is decode indexi=0x0finpsx_passcode_decode_to_mission_selector. - At
0x8003ed10, this branch clearspsx_level_runtime_header_state(DAT_80068ab0) to0. - Function return is not
0on this branch.
- Due to delay-slot flow (
0x8003ecac,0x8003ed04),v0remains0x10on return.
psx_passcode_screen_eval_current_entrystores raw decode return0x10intoDAT_80068a8cand maps throughDAT_80063e54[0x10].
- From live table bytes,
DAT_80063e54[0x10] = 0x3f.
- In caller flow (
0x80034d84),s0is this mapped value (0x3f), sobeq s0,zerodoes not fire.
Exact apply/load behavior for NRTN / ?RTN lane
- Because
s0 != 0, caller reachesjal 0x80021138at0x80034dcc. psx_passcode_apply_mission_selector_and_stagereads raw selector fromDAT_80068a8c; for this path it is0x10.- Switch case for raw selector
0x10is0x8002142c(index0x0fafterselector-1).
- writes
DAT_800675e4 = 0x1d - sets mode byte
DAT_80067379 = 2 - calls common apply helper with
a0 = 0x36
- This is consistent with the commonly described office-loading lane, but the exact user-facing mission label remains conservatively treated as "developer-office candidate" until runtime label capture in the same session.
JL-9 gate-arm compatibility answer
- NRTN / ?RTN cannot itself satisfy gate-arm precondition
psx_level_runtime_header_state == 3. - It explicitly forces that state to
0in decoder (0x8003ed10). - Therefore it does not coexist with the required non-hidden gate-arm predicate at
0x800232c0..0x800232f0(hidden==0 && runtime_header_state==3) unless another later path re-primes header state to3.
Confidence:
- high (
~0.95) on decode return/write/apply control flow above (direct disassembly evidence) - medium-high (
~0.78) on exact player-visible "developer office" naming fora0=0x36without paired runtime UI/string capture
NRTN -> Office Event -> ?0SR/L0SR -> 0x1e hypothesis check (2026-04-11 live pass)
Target hypothesis tested against live SLUS_002.68 structure:
- enter
NRTNto load dev office - let an in-level office event arm
psx_debug_extra_channel_gate - enter hidden
?0SR/L0SR - press input code
0x1e(R1 + Circle)
Verdict: structurally plausible but currently unproven as an exact deterministic player script.
Exact reasons from live code evidence:
psx_debug_extra_channel_gateremains one-writer/one-reader in this image:- write at
0x800232f0inpsx_set_debug_extra_channel_gate - read at
0x8002fff4inpsx_debug_grant_weapon_channels_and_ammo
- write at
- gate-arm writer requires
hidden_flag==0andruntime_header_state==3at the write site (0x800232c0..0x800232f0), so arming is structurally pre-hidden. - hidden path (
?0SR/L0SR, special index0x10) setspsx_hidden_passcode_flagat0x8003ed28and returns selector0, with selector-0branch skip around0x80034d84. - grant trigger path requires hidden mode and input
0x1e(0x80013154..0x80013174), so trigger is structurally post-hidden. - in-level gate-arm routing is real and dispatch-based (
0x800214ac..0x800215f8): it compares againstDAT_80063e68[current_level], then indirect-callsDAT_800640a0[index]; slot0x0fresolves to0x800230e4and uses byte args from the action record.
Why this is not yet fully proven:
- static evidence still does not name one exact player-visible "office event" that deterministically emits the required writer tuple (
slot 0x0f,param_2==0x0a,param_3==0x04) in dev office specifically. - special-passcode sibling behavior (
?RTNlane clearsruntime_header_statein decoder) means the exactNRTNpractical role still needs one runtime trace confirmation in the same session, not another folklore inference.
Confidence split for this exact hypothesis:
- high (
0.89) that the two-phase shape (pre-hidden arm, post-hidden trigger) is structurally correct. - medium (
0.67) that the concrete user recipe starting specifically fromNRTNis correct as stated. - overall classification for the exact
NRTN -> office event -> ?0SR/L0SR -> 0x1eclaim: currently unproven, plausible.
Latest live MCP ownership pass on active SLUS_002.68 now tightens the storage model around your dump split (0x801456fc..0x80145748 static across dumps, 0x8014574c..0x801457d0 changed):
- code-side ownership is channel-state based, not a direct contiguous owned-id array:
- enable/query bit is byte
psx_marker_channel_runtime_block[(channel*4)+0x34] - per-channel step/ammo state is byte
psx_marker_channel_runtime_block[(channel*4)+0x6c] - active selected channel is byte
psx_marker_channel_runtime_block+0x32
- enable/query bit is byte
- this lines up with the dump boundary: if runtime block base is near
0x80145718, then+0x34is exactly0x8014574c(start of the changed range), and+0x6c/+0x84/+0x8calso sit inside the changed range. - commit/resolver path remains table-driven (
channel*10rows), not contiguous-id-list driven:psx_apply_channel_effect_and_commit_selected_item_idloadschannel_commit_row_table[(channel*10)+9]at0x8002f15c- that committed id then resolves weapon rows via
idx*0x26from0x8006466a
- debug bulk grant is now explicitly separated from single-channel unlock helper in the live database:
0x8002fd90renamed topsx_debug_grant_weapon_channels_and_ammo- function bulk-calls channel unlocks
0x04..0x0cand conditionally0x0dbehindpsx_debug_extra_channel_gateread at0x8002fff4
Current best read is stable on four points:
JL-9is a real executable-backed weapon-definition row in the PSX build, not a stray string.JL-9is now also user-verified in emulator memory editing as a working selectable weapon with unique sprite/behavior, not just a table-resident leftover.- the extra hidden/debug-conditioned late weapon lane maps to
JL-9, notJL-2. - step 2 of the old JL-9 recipe is now much clearer: it is not a second passcode-screen action, but an indirect in-level scripted handler dispatch that reaches
psx_set_debug_extra_channel_gatethrough slot0x0fwith byte args0x0a,0x04. - hidden
?0SR/L0SRalso no longer looks like a level-loading code; the hidden branch returns selector0in the shared passcode-screen caller and skips the normal mission/apply-load path. - the checked
binary/Crusader - No Remorse Memdump Weapons.binartifact is a PSX VRAM dump and does not directly expose weapon-slot RAM. - the checked
binary/Crusader - No Remorse Weapons Main Ram.binartifact is plausible main RAM, but it still does not by itself distinguish the selectedJL-?slot asJL-2versusJL-9. - the current JL-9 debug-path read is now tighter in two separate ways: input code
0x1eis now closed to pad mask0x2800and high-confidenceR1 + Circle, while the remaining recipe gap is the exact pre-hidden player action that reaches theparam_2==0x0a,param_3==4gate-arm writer path.
What step 2 actually means (2026-04-11 clarification)
The earlier wording for step 2 was too abstract. Current live code evidence says:
- Step 2 is not "enter something else on the passcode screen before the level loads."
- Step 2 is not the hidden passcode itself.
- Step 2 is an in-level scripted/control event that indirectly dispatches handler slot
0x0f, which ispsx_set_debug_extra_channel_gate. - The actual gate-arm write only happens when that handler is called with byte args
0x0aand0x04.
So the practical model is now:
- step 1: use a normal passcode path that leaves
runtime_header_state == 3 - level loads / control flow continues into gameplay
- step 2: some scripted in-level event fires and reaches the slot-
0x0fhandler with args0x0a,0x04, armingpsx_debug_extra_channel_gate - step 3: use the hidden passcode path (
?0SR/L0SR) to set hidden mode without taking the ordinary level-load branch - trigger: press
R1 + Circle(0x1e) while hidden is active so debug grant runs and consumes the already-latched extra gate
The remaining unknown is therefore not "what button do I press for step 2?" but "what concrete in-level scripted event emits slot 0x0f with args 0x0a,0x04?"
Gate survivability across load/menu transitions (2026-04-11 live pass)
Scope of this pass was the exact user question: does psx_debug_extra_channel_gate (0x8006739d) survive level loads, passcode transitions, main-menu returns, and hidden-passcode activation in one running session.
Direct executable evidence:
psx_debug_extra_channel_gatestill has exactly one recovered writer and one recovered reader in this image.
- writer:
0x800232f0inpsx_set_debug_extra_channel_gate(0x800230e4) - reader:
0x8002fff4inpsx_debug_grant_weapon_channels_and_ammo(0x8002fd90) - a direct neighborhood write scan over
0x80067380..0x800673b0found many writes to nearby state bytes (0x80067384,0x8006738c,0x8006739c,0x800673a0,0x800673a4), but no additional write to0x8006739d.
- Level-load/session loop logic does not recover a static clear of
0x8006739d.
psx_level_session_loop(0x8002b8ec) loads WDL bundles and resets several per-session flags, and it does clearpsx_hidden_passcode_flagon timer expiry at0x8002b9e4.- no direct store to
0x8006739dappears in this loop.
- Main-menu/UI reset helpers seen in this lane do not recover a static clear of
0x8006739d.
FUN_800350e4andFUN_800352d4reset menu/passcode state (DAT_80067384, selector bytes, control flags, runtime-header staging), but no write to0x8006739dis recovered.
- Hidden passcode activation and normal passcode application diverge exactly where expected.
- decoder special index
0x10setspsx_hidden_passcode_flag=1inpsx_passcode_decode_to_mission_selectorat0x8003ed28and returns selector0. - in the passcode caller block around
0x80034d84, selector0skips the apply/load branches (psx_passcode_apply_selector_to_mode_0x0d,psx_passcode_apply_selector_to_mode_0x15,psx_passcode_apply_mission_selector_and_stage) because of the explicitbeq s0,zero,...branch. - practical consequence: hidden-code entry does not itself force the same normal apply/load branch used by nonzero mission selectors.
- Gate-arm and grant-entry still require opposite hidden-flag states.
- gate arm at
0x800232f0requirespsx_hidden_passcode_flag==0andpsx_level_runtime_header_state==3. - debug grant entry at
0x80013154..0x80013174requirespsx_hidden_passcode_flag!=0and input code0x1e.
Answer to the two-phase feasibility question:
- In one running session, the two-phase recipe remains feasible.
- Strongest current ordering is still: arm gate first in non-hidden state, then activate hidden mode and trigger input code
0x1e. - Based on current static evidence, step 2 (hidden activation + trigger) is after the gate-arm event and can happen after a level load in the same process/session; no static clear of
0x8006739dwas recovered across the inspected load/menu transition helpers. - Step 2 before gate-arm is not consistent with the recovered predicates, because gate-arm explicitly requires hidden flag off.
Confidence:
- high (
~0.92) on one-writer/one-reader gate model in this image - high (
~0.88) on hidden-vs-nonhidden polarity constraint forcing a two-phase order - medium-high (
~0.76) on practical persistence through all menu/load routes, because static evidence found no clear but an unresolved pointer-indirect/runtime write path is still theoretically possible
Passcode screen semantics closure: what step 1 and step 3 mean (2026-04-11 live pass)
This closure pass targeted user-facing behavior, not just branch predicates: are normal and hidden passcodes entered on the same screen, do they immediately transition out, and is the current numbered sequence operationally safe.
Direct code-backed findings:
- Normal and hidden passcodes are decoded through the same passcode-screen evaluator.
psx_passcode_screen_eval_current_entry(0x80034e38) builds the same 4-byte candidate from current screen-entry bytes and always callspsx_passcode_decode_to_mission_selector.- Hidden special decode (
index 0x10,?0SR/L0SR) is set in that shared decoder at0x8003ed28(psx_hidden_passcode_flag = 1), not in a separate hidden-only input UI.
- The immediate passcode-screen control flow is value-sensitive in the unnamed caller block around
0x80034c14.
- On the first eval site (
0x80034c14), return0follows the reset/early-return branch (0x80034c24..0x80034cdc) rather than the acceptance/transition path. - Nonzero eval values proceed through
0x80034d00(store selected result) and then into transition/setup calls (0x800380d8,0x8003a46c) before additional per-level setup (0x80034d2conward).
- User-facing meaning of the sequence steps is now tighter:
- Step 1 (normal passcode with delta=>state 3) means: in the same passcode-entry screen, enter a normal code that reaches the non-special first-char delta lane and writes
psx_level_runtime_header_state = 3at0x8003ed58. - Step 3 (hidden passcode) also means: use that same passcode-entry screen/evaluator path to hit special decode
0x10(0x8003ed28), not a separate hidden-code menu.
- Operational risk in the old sequence wording:
- Because hidden decode and normal decode share this screen and the caller path has distinct zero/nonzero branches, a literal read of "do in-level step 2, then return later for step 3" is not yet proven as one deterministic minimal player script.
- Current conservative status is therefore: branch predicates are closed, but exact user-visible ordering remains partially unresolved until the
param_2==0x0a,param_3==4producer is observed in one live trace.
Conservative verdict on sequence correctness:
- The old sequence is directionally correct about the two-phase logic (
pre-hidden gate arm+hidden input trigger), - but it is operationally under-specified and should not be treated as a guaranteed one-try recipe without the remaining caller-context closure.
Confidence:
- high (
~0.90) that hidden and normal passcodes are entered through the same screen/evaluator path - high (
~0.85) that the caller block has immediate branch-divergent behavior for return0vs nonzero - medium (
~0.64) on exact practical player-order script, pending direct producer closure for the0x0a/4gate-arm event
Gate-arm caller path closure around 0x800230e4 (2026-04-11 live pass)
Scope of this pass was the exact writer condition at 0x800232f0 and the concrete upstream state flow that can make it true before hidden+input grant.
Direct code facts now pinned:
- The gate write at
0x800232f0is inpsx_set_debug_extra_channel_gate(0x800230e4) and is only reachable in the local jump-table branch forparam_2==0x0aandparam_3==4.
- jump table at
0x80010550maps entry4to block0x800232a0 - that block performs
FUN_8002ba90()andFUN_8002ba78()then evaluates hidden/state guards and conditionally stores1toDAT_8006739d
- The exact store predicate is now explicit and comment-anchored in-session:
- hidden must still be off:
DAT_80067454 == 0(0x800232c0,0x800232d0branch) - runtime header must be
3:DAT_80078ab0 == 3(0x800232dc,0x800232e4branch) - only then store:
sb 1, DAT_8006739dat0x800232f0
runtime_header_state==3comes from normal (non-special) passcode decode math, not the hidden/special branches.
psx_passcode_decode_to_mission_selector(0x8003ec8c) normal lane writes:DAT_80078ab0 = code[0] - (DAT_80064bbc[idx] + 0x1b)at0x8003ed58- accepted only when result
<=3
- special branches do not produce the required prime state:
- index
0x10(?0SR/ hidden) setsDAT_80067454=1 - index
0x0f(?RTN) forcesDAT_80078ab0=0
- index
- The strongest player-facing prime model is now: valid non-hidden mission/passcode entry in the normal decode lane with first-char delta resolving to
3.
- this yields the required precondition
DAT_80078ab0==3while hidden is still0 - once the
param_2==0x0a,param_3==4event path runs,DAT_8006739dcan latch to1
- Hidden+input grant remains a later, separate phase with opposite hidden flag polarity.
- grant entry in
psx_object_update_runtime_input_modesrequiresDAT_80067454!=0and input code0x1eat0x80013154..0x80013174 - grant helper reads
DAT_8006739dat0x8002fff4and only then executes extraunlock(0x0d)at0x80030004
Additional caller-path closure from later passes:
- The gate writer is reached through an indirect level-gated dispatcher, not a direct passcode callback.
- dispatcher block at
0x800214ac..0x800215f8 0x800215bccompares opcode index againstDAT_80063e68[current_level]0x800215dccallsDAT_800640a0[index]viajalr- slot
0x0finDAT_800640a0resolves to0x800230e4(psx_set_debug_extra_channel_gate) - handler byte args are loaded from action-record pointers at
0x800215ccand0x800215e0 - current best narrowed trigger tuple is therefore
(dispatch slot 0x0f, param_2 0x0a, param_3 0x04)in a small level-scripted family, not a manual UI/menu callback
Practical sequence now supported by executable evidence:
- Enter a normal valid passcode whose first-char delta lane sets
runtime_header_stateto3(hidden remains off). - Let gameplay continue until the in-level scripted/control event fires that reaches slot
0x0f/psx_set_debug_extra_channel_gatewithparam_2==0x0a,param_3==4, soDAT_8006739dis armed. - Enter hidden passcode (
?0SR/ canonicalL0SRwhen selector is0); current passcode-screen flow evidence says this shared decoder branch sets hidden flag but skips the normal nonzero mission/apply-load branch. - Perform input code
0x1e(project mapping currentlyR1+Circle) to run debug grant; extra0x0dunlock executes because gate is already set.
Confidence:
- high (
~0.91) on gate write predicate and branch identity (0x800232a0path) - high (
~0.88) thatruntime_header_state==3prime comes from normal decode lane, not special hidden/sibling specials - medium (
~0.62) on one exact user-visible action name for step 2 (param_2==0x0a,param_3==4producer), because this pass closed the argument/value lane and surrounding passcode state flow but did not yet recover a single named UI handler with clean function boundaries in the0x80022e8..0x800230e0block
Executable-only JL-9 validation lane (2026-04-11)
Scope of this pass was strict: recover an exact user-facing JL-9 enable sequence from executable evidence only across passcode decode, input chord decode, gate write, grant call, and selected-id commit path.
Recovered chain (all executable-backed):
- Hidden passcode decode arm:
psx_passcode_decode_to_mission_selector(0x8003ec8c) setspsx_hidden_passcode_flagat0x8003ed28on special decode index0x10.- index
0x10bypasses first-character validation and uses only theentry[1..3]transformed triplet check (-0x1b) against0x80064bd0/0x80064be4/0x80064bf8.
- Input chord decode to grant trigger:
psx_object_update_runtime_input_modes(0x80012c30) gates the grant path onpsx_hidden_passcode_flag!=0and decoded input code0x1e(0x80013154..0x80013174).psx_input_map_install_profile(0x80042ec4) maps code0x1eto pad mask0x2800in all recovered profile branches, so the practical chord remainsR1 + Circleunder the project pad-bit model.
- Extra JL-9 gate write:
psx_set_debug_extra_channel_gate(0x800230e4) writespsx_debug_extra_channel_gate=1at0x800232f0only when both conditions hold:psx_hidden_passcode_flag == 0(0x800232c0/0x800232d0branch)psx_level_runtime_header_state == 3(0x800232dc..0x800232e4)
- Grant call and final extra unlock:
psx_object_update_runtime_input_modescallspsx_debug_grant_weapon_channels_and_ammoat0x80013174.- grant helper reads gate at
0x8002fff4; if nonzero, branch at0x80030004unlocks channel0x0d(JL-9 lane).
- Selected-id commit sink used by watched selected-byte lane:
psx_apply_channel_effect_and_commit_selected_item_idloads committed row id fromchannel_commit_row_selected_item_id[(channel*10)+9]at0x8002f15cand stores to nested runtime+0x1cat0x8002f168, also mirroring tocommitted_selected_item_idat0x8002f170.- this is the executable-backed row-id commit path that underpins the observed selected-byte
00..0dbehavior (0x0dfor JL-9).
Exact-sequence blocker from executable evidence only:
- one link remains unclosed for a fully deterministic player-facing recipe: the concrete user-visible action/context that drives the
param_2=='\\n'/case 4path inpsx_set_debug_extra_channel_gate(0x800230e4) while hidden flag is still0. - without that mapping, code proves a two-phase ordering requirement but not one exact minimal button/menu script that always arms the gate before hidden grant input.
Minimal next probe to close the blocker:
- in one live trace, breakpoint/log
0x800232f0and caller args into0x800230e4(especiallyparam_2/param_3) while performing candidate player actions around passcode entry and mode transitions. - first observed user-facing action that reaches this writer under
hidden=0 && runtime_header_state=3closes the final exact-step gap.
Focused live follow-up on 0x80067944 and the surrounding 0x80067938..0x80067958 block now narrows one unresolved identity question:
0x80067944has no recovered static xrefs in this image under word, halfword, or byte probe passes (get_data_uses+ operand scans), so it is currently not supported as a selected local weapon id or selected row id owner.0x80067938is reaffirmed aspsx_ctor_placement_section_ptr, installed inwdl_resource_bundle_load_by_indexand consumed inpsx_apply_deferred_control_commandas constructor/deferred-control section state, not as weapon selection state.- nearby block ownership remains mixed:
0x8006793c/0x80067940/0x80067948are consumed bypsx_object_update_runtime_input_modesfor input-mode dispatch helpers, while0x80067954/0x80067958are draw/disp environment flip/progress state used by present/spec-upload helpers. - one unnamed helper was promoted conservatively from direct behavior evidence:
FUN_800461d0->psx_draw_progress_overlay_and_swap_drawenv.
The newest user-provided emulator verification replaces the earlier JL-?=11 shorthand with a stronger selected-weapon mapping, while the starter-only compare still retracts one earlier storage claim:
- verified selected-weapon byte at
0x8014577emaps directly as row-id domain:00no weapon / invalid gun01RP-1602RP-2203RP-3204SG-A105AC-8806PA-3107EM-408PL-109UV-90AGL-3030BAR-70CJL-20DJL-9
- the new starter-only RAM compare shows
0x1456fc..0x145748is static across dumps and therefore is not the owned-weapon inventory list - the dynamic region is instead
0x14574c..0x1457d0, with the strongest current field closure at0x14577e:- all-weapons dump byte at
0x14577e:0c - starter-only dump byte at
0x14577e:02 - current best read: selected weapon row-id byte inside a nested runtime state block, not a contiguous owned-id slot array
- all-weapons dump byte at
- the separate watched field at file offset
0x67944still changes (0x0000000bvs0x00000001), but live executable passes did not recover direct static xrefs for0x80067944, so it remains an unproven watch field rather than a safe patch target
New correction from live MCP reconciliation with the user-verified selected-weapon byte mapping:
- treat the verified byte mapping at
0x8014577eas the selected-weapon row-id domain (00..0d: none/invalid throughJL-9). - keep the argument domain at
0x8002ef34separate: callers pass a compact channel/local code, then0x8002f15cconverts throughchannel_commit_row_selected_item_id[(channel*10)+9]into the committed row id that is written to the nested runtime field at+0x1c(0x8002f168). - practical correction: prior shorthand that could read as "local id equals committed row id" is too loose; the robust model is now
caller channel/local code -> commit table -> committed row id (00..0d), and the user-verified byte at0x8014577ebelongs to that committed row-id domain. - static xrefs cannot directly prove absolute runtime RAM addresses such as
0x8014577e, so address closure remains runtime-evidence-backed plus commit-path-backed rather than static-xref-backed.
The strongest remaining unknown is no longer whether JL-9 exists. It is now split into two narrower questions:
- what exact runtime conditions make the late
JL-9unlock visible in normal play timing, - and what
JL-2actually is as a normal ammo-using weapon, sinceJL-2 AMMOis present while no matching plainJL-9 AMMOstring has been recovered.
Gate and hidden-flag lifecycle closure (2026-04-11 live pass)
Scope of this pass was the exact lifecycle of psx_debug_extra_channel_gate (0x8006739d) and psx_hidden_passcode_flag (0x80067454) across session init, passcode entry, and debug grant.
Recovered reference set is now tight:
psx_debug_extra_channel_gate(0x8006739d):- writer:
0x800232f0inpsx_set_debug_extra_channel_gate - reader:
0x8002fff4inpsx_debug_grant_weapon_channels_and_ammo - recovered static clears/resets: none
- writer:
psx_hidden_passcode_flag(0x80067454):- sets:
0x8003ed28(psx_passcode_decode_to_mission_selector, special index0x10),0x8002bab8(psx_hidden_passcode_arm_runtime_state) - clear/reset:
0x8002b9e4(psx_level_session_loop, timer-expiry branch) - readers:
0x80013154(psx_object_update_runtime_input_modes),0x800232c0(psx_set_debug_extra_channel_gate)
- sets:
State-machine facts now closed:
- Extra unlock gate arm condition is strict and opposite to the grant-entry hidden condition.
- At
0x800232c0..0x800232f0,psx_set_debug_extra_channel_gatewritespsx_debug_extra_channel_gate=1only when:psx_hidden_passcode_flag == 0psx_level_runtime_header_state == 3
- Debug grant entry requires hidden mode to be active.
- At
0x80013154..0x80013174,psx_object_update_runtime_input_modesreturns early unlesspsx_hidden_passcode_flag != 0. - If active, decoded input code
0x1ecallspsx_debug_grant_weapon_channels_and_ammo.
- Extra JL-9 unlock check is a separate late latch.
- At
0x8002fff4, grant helper readspsx_debug_extra_channel_gate. - If nonzero, branch at
0x80030004unlocks channel0x0d(JL-9 lane).
- Hidden flag has explicit timed clear behavior; extra gate currently does not.
psx_hidden_passcode_arm_runtime_stateseedsDAT_800673cc=2000and sets hidden flag at0x8002bab8.psx_level_session_loopclears hidden flag at0x8002b9e4when timer reaches zero.- No recovered static clear path writes
0topsx_debug_extra_channel_gatein this image.
Practical persistence answer for the requested A -> B -> R1+Circle model:
- Strongest executable-backed result is yes: the gate can persist long enough for a two-phase flow because we recovered one set and no static clear for
psx_debug_extra_channel_gate, while hidden mode can be armed later and used within its own timer window. - This supports sequence shape:
- step A: satisfy the non-hidden gate-arm condition (
hidden=0, header-state3) sopsx_debug_extra_channel_gatebecomes1 - step B: enter hidden passcode (
0x10decode branch, canonicalL0SRform when selector is0) to arm hidden mode - trigger: press input code
0x1e(practical mapping in this project remainsR1 + Circle) before hidden timer expiry - effect: debug grant path runs and late extra branch includes
unlock(0x0d)
- step A: satisfy the non-hidden gate-arm condition (
Confidence:
- high (
~0.93) on writer/reader/clear sets listed above (direct xref and instruction evidence) - high (
~0.90) on two-phase ordering requirement (opposite hidden-flag conditions between gate arm and grant entry) - medium-high (
~0.78) on persistence duration beyond hidden timer window, because no static clear is recovered for the extra gate but pointer-indirect or un-recovered dynamic writes are still theoretically possible
RP-16 status closure (2026-04-11 pass)
Scope of this pass was narrowed to user-observed selected-weapon id 0x01 and whether it should be treated as a real usable RP-16 lane, an invalid slot, an earlier variant, or a startup placeholder.
Direct executable findings:
- Weapon-definition row is real and populated.
- row
0x01at0x80064690decodes asRP-16and carries nonzero row fields (+0x1c=0x01,+0x20=0x03e8,+0x24=0x06), unlike pure null/blank filler.
- Primary shop acquire lane does not include row
0x01.
psx_weapon_shop_try_apply_entryfront path (param_1 < 10) uses direct unlock helperpsx_weapon_channel_unlock_and_seed_markersand shop table bytes03 04 05 06 07 08 09 0a 0b 0c.- practical consequence: direct shop unlock progression reaches
JL-2(0x0c) but excludesRP-16(0x01) andRP-22(0x02).
0x01appears in shop lookup, but in secondary ammo branch, not direct unlock branch.
- shop table slot
10byte is0x01(0x80064b9a), but this path enters the0x0a..0x0ebranch that calls0x8002e32c(ammo top-up helper), not unlock helper0x8002e5f0. - this supports "defined id in economy tables" but not "normal explicit acquisition of RP-16 weapon row" from this lane.
- Hidden/debug lane remains focused on late ids, not
0x01.
psx_debug_grant_weapon_channels_and_ammostill closes around normal progression plus extra0x0dgate behavior; no new fixed immediate0x01-specific unlock site was recovered in this pass.
HUD/name path closure for RP-16 in this pass:
- full weapon-name identity remains row-driven: row
0x01inline bytes at0x80064690+2decode toRP-16. - HUD short-label rendering uses selected-id-indexed lookup bytes in
FUN_800455d4from tables around0x80064e90and0x80064e9c(selected id minus one). - this supports RP-16 as a represented display id, even where normal-lane unlock evidence is weaker than row existence.
Current classification for RP-16 (best supported):
- not invalid/empty: row is concrete and populated.
- not currently proven as normal direct unlock lane: primary shop/loadout unlock path evidence emphasizes
>=0x03progression and caps at0x0cin the direct shop lane. - strongest fit right now: real defined early weapon row that behaves like a legacy/startup/placeholder-capable entry in this image, with table presence and UI representation but no newly recovered dedicated normal acquisition proof in this pass.
Confidence:
- high (
~0.89) that row0x01is real structured weapon data (RP-16), not random padding. - high (
~0.84) that direct shop unlock progression excludes0x01in the primary acquisition branch. - medium (
~0.61) on final gameplay role label (legacy/startup/placeholder) until one concrete non-debug in-mission acquisition or initialization writer is recovered.
RP-16 startup/default-init closure (2026-04-11 pass)
Focused live MCP pass on active SLUS_002.68 to answer only this question: does RP-16 (row/id 0x01) get seeded as startup/default weapon via fresh-game init, difficulty-driven starts, mode transitions, or mission/loadout init?
Direct startup/init findings:
- Post-load reset explicitly clears selected-id state before init dispatch.
psx_level_post_load_runtime_resetwritescommitted_selected_item_id = 0at0x80039f68.- from the same function, startup path then dispatches mode actions (
8, optionally2, then4), not a fixed0x01commit.
- Mission/loadout init does not perform a fixed RP-16 selected-id write.
psx_weapon_channels_init_mode_loadout(0x8002f814) is mode-table driven frompsx_level_channel_table_80063e68and applies unlock/ammo helpers via fallthrough; no fixed immediate0x01selected-id commit is present.psx_weapon_channels_apply_mode_transition_state(0x8002f278) sets active channel state to2or3in the observed startup branch (0x8002f468/0x8002f49c), not channel/id0x01.
- The selected-id global has only two recovered writers in this image.
- writer A: reset-to-zero at
0x80039f68. - writer B: table-based commit sink in
psx_apply_channel_effect_and_commit_selected_item_idat0x8002f170. - no dedicated startup writer with a fixed immediate
0x01was recovered.
- Fixed-immediate commit callsites found in this pass do not support RP-16-as-default.
- recovered immediate dispatches use
a0=0x11,a0=0x12, and one context-specifica0=0x01action lane in unnamed gameplay/control handlers (0x8001ede8,0x8001ef08,0x8001f068,0x80021930,0x80022624), not the named startup/loadout reset path. - this keeps low-id usage structurally possible outside startup, but does not convert RP-16 into a proven default-start weapon.
- Default/loadout table context remains non-startup evidence.
- shop/channel map bytes at
0x80064b90still include0x01(... 0c 01 05 04 ...), but this remains economy/action-path evidence rather than a startup seed proof.
Current startup/default verdict for RP-16:
- not proven startup/default weapon in fresh-game init, difficulty/mode-transition apply, or mission/loadout init paths recovered in this pass.
JL-9 producer-side authored-source closure pass (2026-04-11 live MCP)
Scope of this pass was limited to the producer side of the action-record pointer frame consumed by
psx_level_gate_slot_dispatch_from_action_record (0x800214ac), with priority on finding one concrete
upstream authored context for tuple (slot 0x0f, arg1 0x0a, arg2 0x04).
Strongest producer-side clue recovered
The strongest new clue is now loader/constructor explicit:
psx_load_type_state_banks(0x800391f0) installspsx_type_simple_component_bank[type]from the level bundle type-state blob (SPEC_A.WDL/L*.WDLpath viawdl_resource_bundle_load_by_indexat0x8003977c).psx_object_create_simple_recordseeds componentprogram_baseandpcfrom that exact bank at0x80024c60and0x80024c88.psx_run_object_behavior_program_tickthen executes words from that component stream and callspsx_object_behavior_opcode_dispatchat0x80026740.psx_object_behavior_opcode_dispatchroutes opcode54throughpsx_behavior_opcode_handler_table(0x800641ac) topsx_behavior_subopcode_dispatch(0x80027ecc), which then routes subop49throughpsx_behavior_subop_handler_table(0x80063610) to sink0x800214ac.
Practical implication: the pointer-frame lane feeding slot/arg bytes into 0x800214ac is now best
modeled as authored type-state behavior program content loaded per level, not sink-local constants.
Tuple classification update
Current best classification for (0x0f,0x0a,0x04) is now:
- authored-static at source context (type-state behavior payload in level bundle),
- then runtime-index resolved in dispatcher frame construction when mask bits request
base + index*4slot-pointer mapping.
So this tuple is not strongest as a pure runtime remap invention; runtime remap appears to be the transport mechanism over authored behavior-program operands.
Exact live Ghidra changes in this pass
Decompiler comments added:
0x80039250: producer provenance note onpsx_type_simple_component_bank[type]install from level/LSET type-state blob.0x80024c60: constructor note that component program base/pc come frompsx_type_simple_component_bank[type](upstream authored source lane).0x80026740: behavior-tick note that opcode/mask/args are read from component pc stream and feedpsx_object_behavior_opcode_dispatch.
No function renames were applied in this pass.
Remaining open item (narrowed)
Still open is one concrete type row + map context instance whose loaded behavior stream emits the
exact 54 -> 49 producer record that resolves to (slot 0x0f, arg1 0x0a, arg2 0x04) at runtime.
The unresolved part is now specific row attribution, not producer subsystem identity.
- still a real executable-backed row with non-startup lane presence.
- best current label: placeholder/legacy-capable early row with unresolved normal acquisition role, not a demonstrated startup default.
Confidence (startup/default question only):
- high (
~0.86) that current named startup/loadout/mode-transition initializers do not hard-seed selected id0x01. - medium (
~0.63) that no indirect startup-side table commit resolves to0x01in unseen/unnamed init stubs, because several nearby callsites still live in undefined function ranges.
RP-16 startup/default recheck (2026-04-11 live MCP follow-up)
This follow-up pass pushed specifically on undefined nearby init stubs, startup selected-id writes, active-channel writes, and difficulty/mode tables to test any indirect RP-16 (0x01) seed route.
Direct findings:
committed_selected_item_idstill has exactly two recovered writes in this image.
- reset write:
0x80039f68inpsx_level_post_load_runtime_reset(=0) - commit sink write:
0x8002f170inpsx_apply_channel_effect_and_commit_selected_item_id - no third startup/default writer was recovered.
- Startup mode-action dispatch remains bounded and non-committing.
- startup callsites dispatch
mode_action=8then2/4(0x80039fa4,0x8003a014,0x8003a01c; additional observed stub callsite at0x8003e6a0dispatching8). - these actions drive loadout/transition/seed tables but do not directly call the selected-id commit sink.
- Active-channel writes in startup lanes do not imply RP-16 commit.
psx_weapon_channels_apply_mode_transition_statesetspsx_marker_channel_runtime_block+0x32to2or3in the startup branch.- loadout unlock/ammo helpers only initialize when
+0x32==0, then write the channel argument used by that helper path; no startup helper immediate observed here seeds channel0x01as selected-id commit.
- Difficulty/mode table path still does not resolve to selected-id
0x01.
psx_level_channel_table_80063e68feedsDAT_80078a8cin startup (0x8002f2a0,0x8002f868,0x8002f978,0x80039fe8).- table-driven startup channels resolve into commit-row selected bytes at
channel_commit_row_selected_item_id(0x80064355,+9in each 10-byte row), and scanned rows0x00..0x19contain nosel=0x01byte.
- Undefined nearby commit callsites found in this pass do not establish startup-default RP-16.
- recovered no-function callsites into commit helper include
0x8001ede8and0x8001ef08(a0=0x11), plus additional gameplay/control lanes from prior passes. - these are outside the named startup reset/loadout transition chain.
Conservative live Ghidra artifact updates from this pass:
- rename:
0x8002fd80->psx_marker_channel_set_mode6_only - decompiler comments:
0x80039f68(startup reset selected-id clear)0x8002f170(commit sink table-write semantics)0x8002f2a0(mode-table source and non-0x01implication)- disassembly comments:
0x80064355(selected-id table semantics and no0x01in scanned rows)0x8003e6a0(observed startup/transition stub dispatching mode action8)
Updated verdict after this follow-up:
- startup/default RP-16 remains ruled out in recovered startup/init code paths for active
SLUS_002.68. - RP-16 (
0x01) remains a real row and remains reachable in non-startup contexts, but this pass found no evidence of startup/difficulty/mode-init seeding to selected-id0x01.
Legit Acquisition Closure (2026-04-11 pass)
Scope of this pass was narrowed to legitimate JL-9 acquisition paths versus hidden/debug leftovers, with emulator verification treated as ground truth for selected weapon id domain (0x8014577e, 0x0c=JL-2, 0x0d=JL-9).
Direct executable findings by lane:
- Normal loadout lane (
psx_weapon_channels_init_mode_loadout):
- fallthrough switch seeds baseline unlock/ammo progression and reaches ordinary channels, but does not perform a fixed immediate unlock of channel
0x0d - this lane supports normal progression to
JL-2(0x0c) and earlier channels, not a direct hardcodedJL-9grant
- Shop lane (
psx_weapon_shop_try_apply_entry):
- unlock front-path is gated by
param_1 < 10 DAT_80064b90[0..9]is03 04 05 06 07 08 09 0a 0b 0c- practical result: direct shop unlock path is capped at
0x0c(JL-2) and does not directly issue0x0d(JL-9)
- Scripted packed-action/pickup lane (
psx_section0_dispatch_root_apply_packed_channel_actions):
- action type
3dispatchespsx_weapon_channel_unlock_and_seed_markers(channel_byte)from decoded triplet data - triplet table is seeded at runtime by
psx_section0_dispatch_root_seed_marker_channel_tablefrom section0 marker records - this means scripted non-debug
0x0dis structurally possible only if authored level marker data actually supplies channel0x0d; this pass did not recover a shipped-map proof row that does so in normal play
- Hidden/debug lane (
psx_object_update_runtime_input_modes->psx_debug_grant_weapon_channels_and_ammo):
psx_hidden_passcode_flaggate at0x80013154must be active before input code0x1ecan call debug grant- debug grant always unlocks through
0x0c, and conditionally unlocks0x0donly whenpsx_debug_extra_channel_gateis nonzero - this remains the only recovered fixed-immediate
unlock(0x0d)call site (0x80030004) in the current executable
Current verdict from executable evidence:
- strongest supported path to
JL-9remains hidden/debug-conditioned - strongest supported normal gameplay acquisition lanes close at
<= 0x0c(JL-2) - non-debug scripted
0x0dremains the only plausible legitimate exception, but is still unproven without a concrete shipped section0 marker/action row
Confidence:
- high (
~0.87) that fixed-code normal/shop paths do not directly grantJL-9 - high (
~0.90) that hidden/debug path can grantJL-9via the0x0dconditional unlock - medium (
~0.52) on whether shipped non-debug section0 data ever drives a legitimate scripted0x0dunlock
Executable-side condition closure (2026-04-11 pass)
Focused live MCP pass on active SLUS_002.68 to close the exact gate chain around your verified selected-weapon byte watch (0x8014577e) and the JL-9 late unlock lane.
What this pass closes directly:
psx_debug_extra_channel_gate(0x8006739d) is still a one-writer/one-reader gate in this image:
- writer:
psx_set_debug_extra_channel_gate(0x800232f0) - reader:
psx_debug_grant_weapon_channels_and_ammo(0x8002fd90) at0x8002fff4
psx_hidden_passcode_flag(0x80067454) writer/reader set is now explicit:
- writers:
psx_passcode_decode_to_mission_selector(0x8003ed28),psx_hidden_passcode_arm_runtime_state(0x8002ba9c), and clear/reset points inpsx_level_session_loop(0x8002b9e4) - readers:
psx_set_debug_extra_channel_gate(0x800232c0) andpsx_object_update_runtime_input_modes(0x80013154)
- Unlock-capable call families for channel
0x0dare now bounded:
- debug bulk grant:
psx_debug_grant_weapon_channels_and_ammo(always includes0x0c, includes0x0donly whenpsx_debug_extra_channel_gate != 0) - scripted packed actions:
psx_section0_dispatch_root_apply_packed_channel_actionscan callpsx_weapon_channel_unlock_and_seed_markers(channel)for data-driven channel bytes - normal loadout/shop paths call the same unlock helper but are mode/slot constrained; shop front path (
param_1 < 10) maps channels0x03..0x0cand does not directly include0x0d
- Commit/read chain for visible selected weapon remains stable:
- commit:
psx_apply_channel_effect_and_commit_selected_item_id->channel_commit_row_selected_item_id[(channel*10)+9] - sinks: nested player runtime field (
... + 0x1c) andcommitted_selected_item_id(0x80078a90) - consumers include spawn/HUD-adjacent lanes (
FUN_80014d04,FUN_80014eac,psx_spawn_contact_burst_simple_records)
0x8014577e closure status in this pass:
- direct static xrefs from
get_data_uses(0x8014577e)are still empty (expected for heap/runtime fields) - executable-side chain strongly supports that this watch sits in the same nested player runtime object family as the committed selected-id lane, but this pass did not recover one direct static instruction with absolute
0x8014577e
Practical classification after this pass:
- strongest debug-only lane: hidden-passcode-gated input path that reaches
psx_debug_grant_weapon_channels_and_ammo, then conditionally unlocks0x0dthroughpsx_debug_extra_channel_gate - plausible shipped-reachable lane: section0/script packed-action dispatcher can grant channels by data (including potential
0x0dif authored data uses it), but no new map/script row proving shipped non-debug0x0dauthoring was recovered in this pass - strongest normal-lane evidence remains
<= 0x0cvia loadout/shop constraints and earlier commit-table/model work
Final JL-9 enable sequence closure (2026-04-11 pass)
Focused live MCP pass on active SLUS_002.68 against the exact target points:
psx_hidden_passcode_arm_runtime_state(0x8002ba9c)psx_set_debug_extra_channel_gatewrite site (0x800232f0, inside function entry0x800230e4)psx_debug_grant_weapon_channels_and_ammo(0x8002fd90)- extra gate read / extra unlock branch (
0x8002fff4/0x80030004)
Direct gate facts now closed
- Final extra JL-9 unlock is definitely gated by
psx_debug_extra_channel_gate:
- disassembly at
0x8002fff4readslbu v0,0x9d(gp)(DAT_8006739d) - if nonzero, branch executes
jal 0x8002e5f0witha0=0x0dat0x80030004 - this is the only extra post-
0x0cunlock site in this helper and maps to channel/id0x0d(JL-9lane)
- The extra gate is written only under a strict precondition:
- writer instruction at
0x800232f0stores1toDAT_8006739d - immediate guards in the same block require:
psx_hidden_passcode_flag == 0(lw v1,0x7454(v1)thenbne v1,zero,...)psx_level_runtime_header_state == 3(lw v1,-0x7550(v1)thenbne v1,3,...)
- practical write condition is therefore:
- set extra gate only when hidden-passcode flag is currently off and runtime-header state is
3
- set extra gate only when hidden-passcode flag is currently off and runtime-header state is
- Calling the grant helper requires the opposite hidden-flag condition:
- in
psx_object_update_runtime_input_modes(0x80013154), debug path returns early unlesspsx_hidden_passcode_flag != 0 - only then can decoded input code
0x1ereachpsx_debug_grant_weapon_channels_and_ammo(call at0x80013174`)
- Hidden-passcode flag lifecycle remains bounded and explicit:
- set in
psx_passcode_decode_to_mission_selector(0x8003ed28, special index0x10path) - armed/set in
psx_hidden_passcode_arm_runtime_state(0x8002ba9c) with timer seedDAT_800673cc=2000 - cleared/reset in
psx_level_session_loop(0x8002b9e4) when timed armed state expires
Exact precondition model for JL-9 extra unlock
To execute the extra 0x0d unlock inside psx_debug_grant_weapon_channels_and_ammo, executable evidence now requires both:
psx_debug_extra_channel_gate != 0at0x8002fff4(gate read)- hidden debug input path active (
psx_hidden_passcode_flag != 0and input code0x1e) to enter the helper
And the gate itself is only set in a prior state where:
psx_hidden_passcode_flag == 0psx_level_runtime_header_state == 3
One hidden action or two?
Current executable-side verdict is now:
- strongest model is a two-phase hidden flow for guaranteed JL-9 extra unlock, because gate-write and grant-entry require opposite hidden-flag states (
==0vs!=0) - a single hidden action could only be sufficient if one action simultaneously establishes both states across time (for example gate already latched from an earlier phase), which is not directly proven in this pass
Safest practical sequence from code evidence alone:
- Reach the gate-write condition (
hidden flag off, runtime-header state3) sopsx_debug_extra_channel_gateis latched. - Arm/reactivate hidden-passcode state (
psx_hidden_passcode_flag != 0). - Trigger decoded input code
0x1eto callpsx_debug_grant_weapon_channels_and_ammo. - Helper runs normal grants through
0x0c, then executes extra0x0dunlock because gate is already set.
Confidence for this sequence shape: high (~0.86) from direct write/read disassembly and guarded call flow; medium (~0.63) on exact player-facing button/passcode choreography for each phase.
Special passcode priming closure (?0SR / ?RTN / ?QQQ) (2026-04-11 live pass)
Scope of this pass was to answer one specific question: can one of the recovered special passcodes (?0SR, ?RTN, ?QQQ) by itself prime psx_level_runtime_header_state or psx_debug_extra_channel_gate so JL-9 enable is one-code, or does executable evidence still force a two-code flow.
Direct decode/write facts (all from psx_passcode_decode_to_mission_selector, 0x8003ec8c):
?RTNbranch (special index0x0f) writespsx_level_runtime_header_state = 0at0x8003ed10.?0SRbranch (special index0x10) writespsx_hidden_passcode_flag = 1at0x8003ed28.?QQQbranch (special index0x11) returns sentinel0x12and does not writepsx_hidden_passcode_flagorpsx_level_runtime_header_statein that branch.- All three special branches bypass the normal first-char delta calculation path that writes runtime-header state in the non-special lane (
0x8003ed3c..0x8003ed58).
Direct gate-arm facts (from psx_set_debug_extra_channel_gate, 0x800230e4 / store at 0x800232f0):
psx_debug_extra_channel_gateis set to1only when both are true at that branch:
psx_hidden_passcode_flag == 0(0x800232d0guard)psx_level_runtime_header_state == 3(0x800232e4guard)
- This gate is read later at
0x8002fff4inpsx_debug_grant_weapon_channels_and_ammofor the extraunlock(0x0d)branch.
Implication for one-code versus two-code:
- None of
?0SR/?RTN/?QQQcan by itself satisfy the gate-arm condition for JL-9 extra unlock:?RTNforces header state to0, not3.?0SRforces hidden flag to1, but gate arm requires hidden flag0.?QQQdoes not set header state to3and does not arm the gate by itself.
- So the strongest executable-backed result remains a two-phase flow where gate arm must come from a separate pre-hidden state, then hidden mode is armed for the input-triggered grant.
Strongest exact passcode sequence currently provable:
- Prime phase: use a non-hidden passcode/state path that leaves
psx_hidden_passcode_flag==0and reachespsx_level_runtime_header_state==3before the0x800232f0gate-arm check runs. - Hidden phase: enter
?0SR(canonicalL0SRwhen selector is0) to setpsx_hidden_passcode_flag=1. - Trigger phase: execute input code
0x1eto enterpsx_debug_grant_weapon_channels_and_ammo; with gate latched, helper executes extraunlock(0x0d).
Practical status of the sibling specials in this model:
?RTN: anti-prime for JL-9 gate arm (explicitly clears runtime-header state).?QQQ: neutral/side-effect-special in this context (no recovered direct gate-prime write).
Confidence:
- high (
~0.91) that recovered special passcodes do not directly prime JL-9 gate arm by themselves (direct branch/store evidence) - high (
~0.88) that the strongest current model is two-phase rather than one-code for guaranteed0x0dextra unlock - medium (
~0.66) on which exact non-special prime code is used in real play, because this pass intentionally focused on the recovered special-code trio and gate predicates
Core proven facts
1. Weapon table identity is direct
- weapon-definition table base is
0x8006466a - row stride is
0x26 JL-2row is0x80064832(index0x0c)JL-9row is0x80064858(index0x0d)
Recovered visible order remains:
INVALID GUNRP-16RP-22RP-32SG-A1AC-88PA-31EM-4PL-1UV-9GL-303AR-7JL-2JL-9
The strongest stable row split is:
- shared:
+0x1c = 0x18,+0x23 = 0x0e - diverged:
JL-2 +0x24 = 0x4b,JL-9 +0x24 = 0x0f
1b. Compact local id to weapon row id conversion is table-driven
The runtime values near selected/inventory state (0x0001, 0x0002, 0x000b, 0x000c) now reconcile cleanly with the weapon table as follows:
- Callers pass a compact channel/local code to
psx_apply_channel_effect_and_commit_selected_item_id(0x8002ef34) (for example at0x8001d3fc). 0x8002f15cthen loads the committed weapon id fromchannel_commit_row_selected_item_id[(channel*10)+9].- That committed id is consumed as the weapon-table index in
psx_weapon_def_get_u16_with_mode_gate(0x800315d8), which resolvesidx*0x26from base0x8006466a.
This means the caller-side compact channel/local code to final selected weapon row-id step is implemented through channel-table lookup, not a dedicated global +1 conversion helper.
Concrete JL pair from this path:
- compact local/channel
0x0bresolves through table slot+9to committed row0x0c(0x80064832,JL-2) - compact local/channel
0x0cresolves through table slot+9to committed row0x0d(0x80064858,JL-9)
This matches the stronger user-verified selected-weapon byte mapping where 0x0c = JL-2 and 0x0d = JL-9 at 0x8014577e.
Correction for domain clarity:
- the user-verified selected-weapon byte mapping (
00 none,01 RP-16,02 RP-22,03 RP-32,04 SG-A1,05 AC-88,06 PA-31,07 EM-4,08 PL-1,09 UV-9,0A GL-303,0B AR-7,0C JL-2,0D JL-9) is row-id-domain and aligns with weapon table row identities. - this does not contradict the
0x8002ef34call path: it clarifies that the call argument and the committed/stored selected id can be from different domains linked by thechannel_commit_row_selected_item_idlookup.
2. Extra late unlock maps to JL-9
The strongest current chain is direct and no longer only inferential:
psx_apply_channel_effect_and_commit_selected_item_id(0x8002ef34) commits the selected item id fromchannel_commit_row_selected_item_id.- the channel
0x0drow commits item id0x0d. - weapon-definition helpers index rows as
0x8006466a + idx*0x26. - row
0x0dis0x80064858, whose visible name bytes areJL-9. - row
0x0cis0x80064832, whose visible name bytes areJL-2.
This closes the late extra lane as:
0x0c=JL-20x0d=JL-9
Upstream producer structure recovery for 0x800214ac (2026-04-11 live pass)
Scope of this pass was restricted to upstream production of the action-record pointer bytes consumed by psx_level_gate_slot_dispatch_from_action_record (0x800214ac).
Best recovered producer structure (current strongest model)
Recovered chain in live SLUS_002.68:
psx_behavior_subopcode_dispatch(0x80027ecc) calls subop handler table entry with:
- context argument from
local_60[10] - action-record pointer frame from
local_60+1
psx_level_gate_slot_dispatch_from_action_record(0x800214ac) receives that frame asrecordand consumes:
record+0x00pointer -> mode byte (*(*(record+0x00)))record+0x04pointer -> slot byte (*(*(record+0x04)))record+0x08pointer ->arg1byte (*(*(record+0x08)))record+0x0cpointer ->arg2byte (*(*(record+0x0c)))
- Upstream per-argument pointer production occurs in
psx_object_behavior_opcode_dispatch(0x8002677c):
- if argument mask bit is clear, argument word is used as direct pointer
- if set, argument word is treated as slot index and resolved by
base + index*4 - resolver base is object-local slot table (
*(object_state+0x18)), except when mask0x100forces global baseDAT_800789e0
This makes the producer structure a pointer-vector frame (local_60) populated by opcode-dispatch argument resolution, then forwarded to subop handler 49 (0x800214ac) through psx_behavior_subop_handler_table.
Concrete authored-data clue (bounded but real)
The sink tuple still closes as (slot,arg1,arg2)=(0x0f,0x0a,0x04) for the gate arm branch, but upstream formation is now better constrained:
- These values are not required to be hardcoded literals in executable code.
- They are produced as dereferenced bytes via pointer fields in the behavior action-record frame.
- Because each pointer field can be either direct or slot-index-resolved (
base + index*4), authored behavior script data can feed this tuple either as direct byte pointers or as slot-table indices resolved at runtime.
This is the strongest concrete authored-data clue recovered in this pass: the tuple is behavior-script produced pointer data, not a fixed immediate triple in the sink function.
Exact Ghidra changes applied in this pass
- Function rename:
0x800268a4:FUN_800268a4->psx_behavior_arg_index_to_slot_ptr
- Decompiler comments:
0x80026814: argument resolver semantics (index*4pointer mapping and base selection)0x80027f0c: producer frame field map (local_60[0..4]plus context atlocal_60[10])0x800215cc: sink-side field mapping (record+4/+8/+0cto slot/arg1/arg2)
Conservative confidence split:
- high (
~0.9) on pointer-frame field mapping and resolver behavior (direct decompile evidence) - medium (
~0.65) on exact authored object/mission row currently producing(0x0f,0x0a,0x04)in shipped gameplay without runtime trace
3. Hidden passcode path reaches the JL-9 lane
The strongest recovered control path is:
psx_passcode_decode_to_mission_selector(0x8003ec8c) setspsx_hidden_passcode_flagpsx_object_update_runtime_input_modescheckspsx_hidden_passcode_flag- on gated input code
0x1e, it callspsx_debug_grant_weapon_channels_and_ammo - that helper always unlocks through
0x0cand conditionally unlocks0x0dwhenpsx_debug_extra_channel_gate != 0
This is the strongest current executable-backed explanation for how the extra PSX-only lane reaches JL-9.
The newest narrow passes now sharpen the trigger story in a more useful way:
- code now clearly supports
hidden passcode active -> gated input code 0x1e -> psx_debug_grant_weapon_channels_and_ammo -> extra 0x0d unlock behind psx_debug_extra_channel_gate - input-map closure now ties
0x1eto pad mask0x2800, which is high-confidenceR1 + Circleunder the active digital-pad bit layout - the remaining JL-9 trigger uncertainty is no longer the chord; it is the exact pre-hidden player-visible action that reaches the gate-arm writer path at
0x800232f0
4. JL-2 is now the stronger normal ammo-lane unknown
The current practical split is:
JL-2sits in ordinary acquisition space (0x0c)JL-9sits in the extra hidden/debug-conditioned late lane (0x0d)- the visible string
JL-2 AMMOexists at0x800642b6 - no matching plain
JL-9 AMMOstring has been recovered in the same string family
That does not fully decode JL-2, but it does shift the next unknown toward JL-2 rather than back toward JL-9 existence proof.
5. The checked dump is VRAM, not slot RAM
The user-supplied binary/Crusader - No Remorse Memdump Weapons.bin is now best read as a PSX VRAM capture:
- file size is exactly
0x100000(1,048,576) bytes, matching PlayStation VRAM size - the dump contains VRAM-like repeated 16-bit pixel patterns rather than compact inventory rows
- inspection found HUD and icon-atlas style regions, but not a direct weapon-slot RAM structure
Current safest conclusion:
- the dump is useful as a presentation artifact
- it is not a direct source for weapon-slot storage values
- it does not currently distinguish
JL-2fromJL-9with confidence
6. The checked 2 MiB main RAM dump is plausible RAM, but still inconclusive
The user-supplied binary/Crusader - No Remorse Weapons Main Ram.bin is not rejected as the wrong broad domain.
Current safest read:
- file size is
0x200000(2,097,152) bytes, matching PlayStation main RAM size - no plain ASCII
JL-2,JL-9, orJL-strings were recovered in the dump - no immediately self-identifying weapon-slot table was recovered from this pass alone
So the main-RAM dump currently lands in a narrower state than the VRAM dump:
- it is plausible runtime state memory,
- but not yet a self-decoding proof of whether the selected
JL-?weapon with10clips and0loaded bullets isJL-2orJL-9, - because the identity still appears to depend on numeric runtime ids that must be cross-referenced back to the executable-side weapon table and HUD/name resolver logic.
The newest inventory-oriented pass did at least tighten where to look next inside that dump:
- candidate compact 16-byte slot-like records were noticed very early in the file (for example around file offsets
0xA0,0xB0,0xC0) - those records are not self-labeled and were not enough on their own to map
RP-32 ... JL-? - the most useful next RAM step is now to map one confirmed executable-side inventory or HUD pointer onto the dump, instead of continuing a blind whole-image sweep
The starter-only compare forces a narrower and more defensible RAM read:
- file offset
0x1456fcdoes still begin a compact sequence of 8-byte records whose first 16-bit field climbs0x0002 .. 0x000b - however, the same sequence is unchanged in the starter-only dump, so it cannot be the live owned-weapon inventory list
- the dynamic block starts immediately after that static table, at
0x14574c, and remains changed through at least0x1457d0 - the strongest current field closure inside that block is:
- byte
0x14577e = 0x0cin the all-weapons dump - byte
0x14577e = 0x02in the starter-only dump - executable-side write path now supports this as selected/committed weapon row-id state inside a player/runtime state block
- byte
0x67944separately changes from0x0000000bto0x00000001, but this field still lacks direct static ownership in the current image and should not be treated as a closed selected-weapon home yet
Current strongest practical consequence:
- the earlier
0x145744 -> 0x000c/0x67944 -> 0x0000000cpatch recommendation is retracted - current evidence supports a channel-state ownership model plus a dynamic current-weapon row field at
0x14577e, not a contiguous owned-id inventory list that can be safely patched in place from this evidence alone - the next RAM step should target ownership-state bytes/flags in the dynamic runtime block and the channel-runtime block model, not the static
0x1456fctable
The latest follow-up also narrows one false lead and one stronger lead inside the same dump:
- the candidate commit-table field at
DAT_80064355[(channel*10)+9]does not show plain0x0c/0x0dvalues in the sampled rows of this dump, so that exact byte is not acting like a direct final JL row id here - however, denser table-like clusters of
0x0c/0x0ddo appear much later in RAM, especially around file offsets0x133000and nearby0x133416/0x1335d4, which are now stronger candidates for real runtime weapon-slot or inventory-state structures than the earlier blind slot guess
The newest pass tightened those late clusters one step further:
- the
0x133000neighborhood now looks more like a compact fixed-record runtime table than random data, with the strongest candidate stride landing near0x40 - values in that area are dominated by small enum-like bytes such as
0x0dand0x0f, which fit a runtime index/flag table better than text or raw pixel data - one additional pass also found an alternative clue region around
0x422c..0x4440where triplet-like patterns such as0x0c 0x0a 0x00could plausibly encode aJL-2 / 10 clips / 0 loadedstyle state, but that interpretation is not yet strong enough to replace the0x133000cluster as the main RAM lead - the remaining blocker is now very specific: one executable-side HUD/inventory anchor still has to be tied to one of these RAM regions before the dump can be read as a confirmed runtime weapon list
Current best practical consequence:
- no ask-user re-dump was forced from this pass, because the file does look like the right broad memory domain,
- but a stronger runtime closure still needs either a more targeted live memory capture around the player/inventory struct or a resolved id->name/UI chain inside the executable.
Evidence detail
Weapon table and row consumers
psx_weapon_def_get_u16_with_mode_gate(0x800315d8) computesidx*0x26and reads row fields from the0x8006466afamilypsx_weapon_def_apply_spawn_profile_by_index(0x8003d02c) fans row fields into live-named globals:psx_weapon_spawn_typepsx_weapon_spawn_audio_event_idpsx_weapon_spawn_state_selector
- current best art read stays narrow:
JL-2andJL-9share base type/art lane via+0x1c = 0x18- they diverge on selector/state lane via
+0x24 = 0x4bvs0x0f
Channel commit and HUD presentation
-
channel_commit_row_tableis the per-channel commit source table -
committed_selected_item_idmirrors the committed item id after0x8002f15c -
psx_hud_draw_selected_item_tile_bar(0x800424ac) is the strongest currently named HUD-side consumer lane -
psx_ui_color_cycle_state,psx_hud_selected_item_color,psx_hud_selected_tile_color_a, andpsx_hud_selected_tile_color_bnow cover the nearby UI-tail state that was previously left as rawDAT_labels -
latest pass also tightened the selected/equipped chain with fresh comments at
0x8002ef34,0x8002f15c,0x800315d8,0x8003d02c, and0x800424ac, plus explicit extra-unlock naming at0x80030004->psx_weapon_channel_unlock_and_seed_markers -
latest pass also renamed the known writer for the extra late unlock gate:
0x800232f0->psx_set_debug_extra_channel_gate -
the newest input-side pass also renamed
0x8001E37C->psx_handle_special_input_code, which is now the strongest current upstream candidate for consuming the special0x1edebug-trigger code range -
the newest ammo-side pass also tightened the marker/runtime helper family with live names such as
psx_marker_channel_mode_is_enabled,psx_marker_channel_get_mode_step_value,psx_marker_channel_runtime_state_snapshot,psx_marker_channel_runtime_state_restore, andpsx_marker_channel_dispatch_mode_action, which are now the strongest nearby candidates for the actual ammo/count mutation lane even though the exactclipsversusloaded bulletsfields are still not closed -
Evidence note: no alternate per-slot source was found — HUD item id is resolved via the channel commit table (DAT_80064355[(channel*10)+9]) -> committed_selected_item_id -> weapon-definition table at
0x8006466a->psx_weapon_def_apply_spawn_profile_by_index-> HUD draw.
This lane helps explain what the HUD is drawing, but it is still weaker than the channel-commit chain for direct JL-2 vs JL-9 identity.
Confirmed resolver chain (evidence-backed):
-
commit source:
DAT_80064355[(channel*10)+9]is loaded at0x8002f15cand supplies the committed item id for a channel. -
id -> row resolver:
psx_weapon_def_get_u16_with_mode_gate(0x800315d8) computesidx * 0x26and indexes the weapon-definition table at0x8006466ato select the weapon row. -
row -> display:
psx_weapon_def_apply_spawn_profile_by_index(0x8003d02c) fans row fields into spawn/art/selectors consumed by HUD code;psx_hud_draw_selected_item_tile_bar(0x800424ac) consumes those selectors to draw the on-screen tile/art. Name/label bytes live in the weapon row and are therefore resolved implicitly by theidx*0x26table access rather than a separate string-lookup UI helper.0x8003ec8c->psx_passcode_decode_to_mission_selector0x80021138->psx_passcode_apply_mission_selector_and_stage
-
transformed compare tables:
0x80064bbc0x80064bd00x80064be40x80064bf8
-
key hidden decoder behavior:
- hidden index
0x0f: writespsx_level_runtime_header_state = 0, returns selector0x10 - hidden index
0x10: writespsx_hidden_passcode_flag = 1, returns selector0 - hidden index
0x11: returns selector0x12
- hidden index
Current safest read is that the hidden compare path is real and transformed/table-driven, even though the exact folklore string mapping is still not fully closed at runtime.
Current interpretation
What is now solid
JL-9is realJL-9is the extra late hidden/debug laneJL-2is the neighboring ordinary lane and now has stronger explicit ammo-label evidence- the checked dump is VRAM, not direct slot RAM
- the checked 2 MiB main RAM dump is plausible runtime RAM, but still needs executable-side id resolution before it can close
JL-2vsJL-9
What is still open
- exact runtime timing for
psx_hidden_passcode_flagandpsx_debug_extra_channel_gate - exact role of the denser
0x0c/0x0dRAM clusters near0x133000, and whether one of them is the real live inventory/slot table - exact executable-side anchor that proves whether the main RAM lead is the
0x133000cluster or the smaller0x422c..0x4440candidate region - direct UI label/display resolver that prints
JL-9from committed runtime state in one instruction chain - exact
JL-2ammo decrement/storage path - exact
JL-9sprite/frame identity - exact shipped-map placement for either JL row
Input code 0x1e button-chord closure (2026-04-11 pass)
Focused live MCP pass on active SLUS_002.68 to close the exact input-side decode path around:
psx_object_update_runtime_input_modes(0x80012c30)psx_input_map_get_code_and_edge(0x8002adbc, renamed this pass)psx_input_map_update_state_for_pad(0x8002abe0, renamed this pass)psx_input_map_install_profile(0x80042ec4, renamed this pass)
Direct closure:
local_14in runtime input mode update is read from the input-map state table.
psx_object_update_runtime_input_modescallspsx_input_map_get_code_and_edge(1,&local_18,&local_14).local_14 == 0x1eis the exact compare that gates the debug grant helper whenpsx_hidden_passcode_flag != 0.
- Input code resolution is exact-match against a 0x32-entry mask table.
psx_input_map_update_state_for_padpolls raw pad mask fromFUN_80048d04and scans0x80090d34 + pad*0xfcfor exact value equality.- matched index is written to current-code state (
0x80090e24 + pad*0xfc) and returned bypsx_input_map_get_code_and_edge.
- Input code
0x1eis mapped to pad mask0x2800in all recovered profile cases.
psx_input_map_install_profilewrites map entries withpsx_input_map_set_code_to_padmask(1, code, mask).- every switch branch in this function writes code
0x1e -> 0x2800.
- Using the same PSX digital mask legend implied by nearby known controls (
0x08start, d-pad nibble patterns, shoulder/face combos),0x2800resolves toR1 (0x0800) + Circle (0x2000).
Practical trigger statement now supported:
- after hidden passcode state is active, the JL-9 debug grant path is triggered by the decoded special input code
0x1e, which maps to the controller chordR1 + Circle. - because map lookup is exact-match, extra simultaneously held buttons can produce a different code and miss the
0x1egate.
Confidence:
- high (
~0.93) that0x1e -> 0x2800is the actual decode mapping in this executable. - high (
~0.88) that0x2800corresponds toR1 + Circleunder the active digital-pad bit layout.
Selected-weapon-adjacent pointer reclassification (2026-04-11)
The user-reported pointer delta near the selected-weapon watch block is now closed as render-state, not inventory state:
- all-weapons dump: pointer-like value
0x80078248 - starter-only dump: pointer-like value
0x800782b8
Live MCP decompile/xref evidence on SLUS_002.68 shows these are the two double-buffer draw-environment records:
psx_platform_init(0x80042b38) initializes them withSetDefDrawEnv((DRAWENV *)&DAT_80078248, ...)andSetDefDrawEnv((DRAWENV *)&DAT_800782b8, ...)- the paired display environments are at
0x800782a4and0x80078314(+0x5cfrom each draw-env base), matching a packed per-buffer draw/disp environment layout DAT_80067954is the active draw-env pointer toggled each frame in:psx_present_frame_and_flip(0x80044188)render_reset_draw_state(0x80042be8)FUN_800461d0(0x800461d0)
Practical consequence:
- the observed
0x80078248 <-> 0x800782b8change is a frame-buffer/render flip artifact - this pointer pair does not encode selected weapon id, HUD selected-item row, or inventory ownership state
- weapon selection/inventory evidence remains stronger in the channel-commit and weapon-definition lanes (
DAT_80064355,committed_selected_item_id,0x8006466a + idx*0x26)
Runtime block classification around 0x8014574c..0x801457d0 (2026-04-11)
Current strongest executable-backed interpretation for the user-targeted RAM block:
- this region is most likely a live player-object nested runtime-state block, not a HUD color cache and not the static channel-commit table
- the watched byte at file offset
0x14577e(RAM0x8014577e) is most strongly the active selected weapon row-id byte within the nested+0x1cruntime field family - this byte behaves like current-weapon metadata, not ownership-bitset storage and not direct ammo-count storage
Concrete evidence chain:
psx_apply_channel_effect_and_commit_selected_item_idwrites the committed item id fromchannel_commit_row_selected_item_id[(channel*10)]into two sinks:
- global
committed_selected_item_id(0x80078a90) - nested player runtime field at
*( *( *(DAT_800789f8 + 8) + 0x18) + 0x1c )
psx_set_debug_extra_channel_gateclears that same nested+0x1cfield in several mode-reset branches, alongside nearby nested fields (+0x14,+0x16, low byte of+0x18), consistent with runtime weapon-mode/state reset behavior.psx_object_create_simple_recordinitializes the nested block rooted at*(obj_component + 0x18)as a large runtime state area and stores back-pointer/object runtime linkage there, matching a heap-resident per-object state block.- The dump delta at byte
0x14577e(0x0call-weapons vs0x02starter-only) fits this as a selected weapon row-id change rather than ownership-table cardinality or HUD palette animation.
Interpretation confidence:
0x14577eas selected weapon row-id byte (nested +0x1cfield family): high- broader
0x8014574c..0x801457d0region as player nested runtime-state block: medium-high - region as primary inventory ownership table: low
- region as primary ammo counters table: low
- region as HUD-only cache: low
Starter-only compare correction (2026-04-11)
The follow-up compare against binary/Crusader - No Remorse RAM starter weapon only.bin corrects one earlier overreach in this note.
What changed:
0x1456fc..0x145748is identical in the all-weapons and starter-only dumps, even though the observed weapon inventory is very different- therefore that attractive
0x0002 .. 0x000b8-byte record sequence is a static table or static-adjacent runtime seed, not the live owned-weapon list - the real dynamic lane starts at
0x14574cand includes:0x14577e: 0x000c -> 0x0002- nearby count/flag-like deltas around
0x14575c..0x14578c
- the separate watched field at
0x67944also changes cleanly (0x0000000b -> 0x00000001), but the current image still has no recovered static xrefs for0x80067944
Current safest wording after that compare:
- no contiguous owned-weapon id list has been recovered yet
- the storage model is better explained by channel-state ownership plus one or more dynamic current-weapon fields in the runtime block
- the earlier patch-target recommendation on
0x145744should be considered withdrawn
Speculation and folklore
Keep speculation bounded here rather than mixing it into the evidence chain.
Current plausible but not fully closed reads:
L0SRremains the strongest current executable-backed cheat-mode candidate because it fits the recovered four-symbol hidden branch better thanL0SERR1 + Circle when L0SR is activeis now the strongest executable-backed button-chord read for the gated input route; the remaining folklore-level uncertainty is about the exact pre-hidden gate-arm action, not the0x1echord mapping itselfXXXXstill plausibly maps to the hidden-pictures folklore because the decoder has a second hidden-special lane consistent with a transformed secret path- the VRAM dump likely contains the weapon HUD/icon atlas, but without labeled reference icons or a cleaner runtime capture it does not yet let us separate
JL-2fromJL-9visually - the main RAM dump likely contains the relevant runtime inventory state, but current evidence is split between a nearby commit-table neighborhood that does not show plain final JL ids and stronger later clusters around
0x133000that still need one executable-side anchor to decode - the strongest current input-side static closure now turns the special
0x1ecode into pad mask0x2800and a high-confidenceR1 + Circleinterpretation, while still leaving the upstream pre-hidden gate-arm producer unresolved
None of those points are needed for the current core conclusion that the extra late executable-backed lane is JL-9.
Best next steps
- Capture a runtime sample after the hidden passcode/debug gate is active and log which weapon channels are actually unlocked, especially
0x0d. - Decode the controller-button mapping that produces the gated input code reaching
psx_debug_grant_weapon_channels_and_ammo, so theL0SRtrigger path is either confirmed or corrected. - Trace all reads and writes of
psx_debug_extra_channel_gateto close the late extra-unlock precondition. - Trace the direct
JL-2 AMMOUI path and the underlying ammo decrement/storage lane. - Decode the denser
0x0c/0x0dRAM clusters around0x133000using one confirmed executable-side inventory/HUD anchor, instead of continuing whole-image sweeps. - If that anchor still does not land cleanly, test the smaller
0x422c..0x4440candidate region against the same runtime meaning before requesting another dump or capture.
Weapon acquisition systems vs id 0x0d / 0x01 (2026-04-11 broad pass)
Focused live MCP pass on active SLUS_002.68 to classify which acquisition families can produce the verified selected ids JL-9=0x0d and RP-16?=0x01.
Systems analyzed
- default loadout/init:
psx_weapon_channels_init_mode_loadout(0x8002f814) - mission transition mode application:
psx_weapon_channels_apply_mode_transition_state(0x8002f278) - pickups/action-coded grants: accepted-code dispatch lane at
0x8001d3fc - shop path:
psx_weapon_shop_try_apply_entry(0x8003de68) usingDAT_80064B90 - scripted awards:
psx_section0_dispatch_root_apply_packed_channel_actions(0x800311f4) - debug grants:
psx_debug_grant_weapon_channels_and_ammo(0x8002fd90)
Concrete results
- id
0x0d(JL-9) remains gated from ordinary loadout/shop paths.
- loadout init has fixed unlock/ammo calls through
0x0cand does not directly unlock0x0d - mission transition state helper does not add a
0x0ddirect unlock path - shop front path (
param<10) maps throughDAT_80064B90[0..9] = 03 04 05 06 07 08 09 0a 0b 0c, so no direct0x0dthere
- id
0x0dis directly produced by debug grant and is possible in data-driven scripted/pickup lanes.
- debug:
0x8002fff4conditionally callspsx_weapon_channel_unlock_and_seed_markers(0x0d)only whenpsx_debug_extra_channel_gate != 0 - scripted awards: packed-action decoder (
0x80031250) callsunlock(channel)from seededDAT_8008F120rows (runtime-seeded from section0 markers) - pickup/action-coded lane (
0x8001d3fc) range-check path still commits accepted codes throughpsx_apply_channel_effect_and_commit_selected_item_id(a0), including0x0d
- id
0x01is not excluded and appears in non-debug systems.
- shop table byte dump confirms
DAT_80064B90 = 03 04 05 06 07 08 09 0a 0b 0c 01 05 04 03 02 07 - while
0x01is outside the first ten direct-unlock shop slots, it is still present in shop's alternate branch (param_1=10) via the same channel map - pickup/action-coded commit path accepts low ids (including
0x01) and routes them to commit - scripted packed actions are data-driven and can target
0x01when authored in section0 records
Exclusion read after this pass
0x0d: strongest current read is "not part of baseline ordinary progression," with explicit debug-gated production and only data-driven/scripted/pickup exceptions.0x01: not excluded; it appears in normal non-debug content paths (shop mapping plus accepted low-id action path).
Notes on evidence quality
- The packed-action LUT base (
0x8008F120) is runtime-seeded and can be uninitialized in static reads; classification therefore uses the seeding/writer and decoder call behavior, not a static full table dump. - The core
0x0dgate remains directly evidenced at0x8002fff4in liveSLUS_002.68.
Appendix: key anchors
Weapon rows and helpers
-
0x8006466aweapon-definition table base -
0x80064832JL-2row (0x0c) -
0x80064858JL-9row (0x0d) -
0x800315d8psx_weapon_def_get_u16_with_mode_gate -
Live field map (evidence):
row+0x20is read as a 16-bit row field (loaded at0x8003160c),row+0x22is a 1-byte mode/gate field (loaded at0x8003163c), androw+0x24contains a per-row state/selector used by HUD/ammo resolver (example:JL-2shows0x4B,JL-9shows0x0F). The nearby ASCIIJL-2 AMMOat0x800642b6aligns with code reads from the0x800642b2/0x800642b4region, supporting a small adjacent string/table used for ammo text resolution. -
0x8003d02cpsx_weapon_def_apply_spawn_profile_by_index
Channel commit and HUD
0x8002ef34psx_apply_channel_effect_and_commit_selected_item_id0x8002f15ccommitted item-id load from channel commit row0x800424acpsx_hud_draw_selected_item_tile_bar0x800350a8psx_render_mode_dispatch
Hidden passcode and extra unlock
0x80034e38psx_passcode_screen_eval_current_entry0x8003ec8cpsx_passcode_decode_to_mission_selector0x80013154psx_object_update_runtime_input_modes0x8002fd90psx_debug_grant_weapon_channels_and_ammo0x800232f0psx_set_debug_extra_channel_gate0x80030004extra0x0dunlock call site
Runtime dump artifacts
binary/Crusader - No Remorse Memdump Weapons.bin-> VRAM-sized HUD/presentation artifactbinary/Crusader - No Remorse Weapons Main Ram.bin-> 2 MiB plausible main RAM artifact, currently not self-decoding enough to closeJL-2vsJL-9- stronger current unresolved RAM cluster candidates for live weapon-slot state: around file offsets
0x133000,0x133416, and0x1335d4 - secondary smaller RAM candidate for
JL-2 / 10 clips / 0 loadedstyle state: around file offsets0x422c..0x4440
Live-named globals used in this note
psx_hidden_passcode_flagpsx_debug_extra_channel_gatepsx_level_runtime_header_statechannel_commit_row_tablechannel_commit_row_selected_item_idcommitted_selected_item_idpsx_weapon_spawn_typepsx_weapon_spawn_audio_event_idpsx_weapon_spawn_state_selectorpsx_ui_color_cycle_statepsx_hud_selected_item_colorpsx_hud_selected_tile_color_apsx_hud_selected_tile_color_b
Hidden passcode decode closure (2026-04-11 pass)
Focused live MCP pass on active SLUS_002.68 against:
psx_passcode_screen_eval_current_entry(0x80034e38)psx_passcode_decode_to_mission_selector(0x8003ec8c)- passcode tables at
0x80064bbc,0x80064bd0,0x80064be4,0x80064bf8 - helper
psx_passcode_generate_encoded_quad(0x8003ec30)
Closed transform logic
Decode path (0x8003ec8c) compares transformed input, not direct ASCII:
entry[1..3]are normalized by-0x1band matched against table triplets:
T1 = [0x80064bd0 + i]T2 = [0x80064be4 + i]T3 = [0x80064bf8 + i]- valid
irange is0..0x11(18entries)
- If no
imatches all three, decode fails. - For ordinary entries (
i != 0x0f/0x10/0x11):
delta = entry[0] - (0x1b + [0x80064bbc + i])psx_level_runtime_header_state = delta(stored at0x80068ab0)- accept only when
delta < 4; return selectori+1
Special branches:
i == 0x0f: clearspsx_level_runtime_header_stateand returns0x10(delay-slot flow preservesv0=0x10)i == 0x10: setspsx_hidden_passcode_flag = 1(0x80067454) and returns0i == 0x11: returns sentinel0x12
Important closure: all three special branches bypass the first-character delta check, so their first character is effectively wildcarded by the decoder.
Recovered table values
Read directly from 0x80064bb0..0x80064c20:
T0 (0x80064bbc)=01 03 0B 0E 0F 06 07 0A 09 12 01 02 03 03 06 08 08 12T1 (0x80064bd0)=10 11 08 13 02 15 16 17 18 19 1A 1B 1C 04 03 0D 14 12T2 (0x80064be4)=0B 0C 0D 0A 19 00 01 02 03 04 05 06 07 08 09 0F 0E 12T3 (0x80064bf8)=02 0B 0C 03 0E 0F 10 11 12 13 14 15 16 17 18 0A 0D 12
Symbol alphabet (0x80063ef0) for passcode glyph indexes is:
BCDFGHJKLMNPQRSTVWXZ0123456789
Concrete recovered hidden/debug strings
Generator (0x8003ec30) emits:
out[0] = T0[i] + psx_level_runtime_header_stateout[1] = T1[i]out[2] = T2[i]out[3] = T3[i]
Mapped through 0x80063ef0, special rows are:
i=0x10(setspsx_hidden_passcode_flag):?0SR
- canonical when selector state is
0:L0SR - decoder confirms first character wildcard for this branch
i=0x0f(clears selector state):?RTN
- canonical when selector state is
0:LRTN - first character wildcard for this branch
i=0x11(sentinel return0x12):?QQQ
- canonical when selector state is
0:XQQQ - first character wildcard for this branch
Debug JL-9 path tie-in
This pass tightens the two-phase gate model using direct branch conditions:
- Hidden branch (
i=0x10) setspsx_hidden_passcode_flag(0x80067454) at0x8003ed28. - Input-mode handler (
0x80013154) only calls debug grant (0x8002fd90) on input code0x1ewhen hidden flag is nonzero. - Extra JL-9 unlock (
0x80030004, channel0x0d) still requirespsx_debug_extra_channel_gate != 0at0x8002fff4. - Gate write (
0x800232f0) still requires hidden flag zero pluspsx_level_runtime_header_state == 3.
Current best practical read remains: extra JL-9 requires a staged hidden/debug flow; no single direct ordinary-lane unlock for 0x0d was recovered.
Shipped section0 slot-0x14 closure (2026-04-11 pass)
Focused live MCP + scene-cache pass on active SLUS_002.68 to answer one narrow question: can shipped non-debug authored section0/script bytes ever drive the unlock(0x0d) lane used by JL-9.
Executable closure
- Packed-action dispatch behavior is explicit at
psx_section0_dispatch_root_apply_packed_channel_actions(0x800311c4):
- decoder uses
slot = (action_byte & 0x3f)into seeded tripletsDAT_8008f120/121/124 - triplet kind
3path callspsx_weapon_channel_unlock_and_seed_markers(channel)
- Seed mapping is explicit at
psx_section0_dispatch_root_seed_marker_channel_table(0x8002f518):
psx_section0_dispatch_root_find_marker_record_by_channel(0x14, 3, 0x0d)- therefore slot
0x14maps to action-kind3, channel0x0d
- Live naming cleanup applied:
0x8002fd90renamed topsx_debug_grant_weapon_channels_and_ammoto resolve the duplicate-name collision with0x8002e5f0
Shipped authored-data closure
Cross-map scan of shipped PSX scene-cache root-dispatch records (.cache/scene-cache/psx-remorse/map-*/.../scene.json) parsed packed action dwords from record raw words and checked for bytes where (byte & 0x3f) == 0x14.
Results:
- scanned root-dispatch records:
3298 - slot-
0x14authored-byte hits:119 - maps with at least one slot-
0x14hit:22 - map ids with hits:
1,2,3,4,5,22,23,26,27,28,29,47,63,64,80,82,88,89,104,106,108,122
Representative shipped records:
- map
1,item:21:psx-section0_dispatch_roots:left:8, raw words0045 1d3b 0d43 0014 0000 0020(packed dword0x00140d43) - map
5,item:11:psx-section0_dispatch_roots:right:8, raw words004e 1b83 0943 0014 0000 0020(packed dword0x00140943) - map
63, slot-0x14hits present (2) - map
89, slot-0x14hits present (30)
Practical verdict for JL-9 legit-path question
- Ruled in: shipped non-debug section0/script authored data does include packed action bytes that resolve to slot
0x14, and executable seed/dispatch logic maps slot0x14tounlock(channel 0x0d). - Not fully universal: this does not prove every campaign route triggers those records during normal play timing, but it does prove the non-debug shipped-data lane exists and is executable-reachable in principle.
Confidence:
- high (
~0.93) that slot0x14is anunlock(0x0d)-capable packed-action slot in this build - high (
~0.91) that shipped non-debug section0 root records contain authored slot-0x14bytes - medium-high (
~0.77) that this yields legitimate in-play JL-9 acquisition in at least some non-debug scenarios (remaining uncertainty is trigger/reachability timing, not byte-path existence)
Step-2 caller narrowing for gate-arm event (0x800230e4/0x800232f0) (2026-04-11 live pass)
Goal of this pass was to close the immediate caller/event side for the gate writer branch (param_2==0x0a, param_3==4) inside psx_set_debug_extra_channel_gate.
Exact executable evidence recovered
- The gate writer remains exactly
sb v0,0x739d(at)at0x800232f0inpsx_set_debug_extra_channel_gate(0x800230e4) under local branchparam_2==0x0aand caseparam_3==4. - Direct caller xrefs stay empty because this lane is indirect-dispatch based.
- A concrete indirect dispatcher block was recovered at
0x800214ac..0x800215f8:
0x800215bc: compares dispatch index (a2) against per-level table byteDAT_80063e68[current_level].0x800215dc: loads handler pointer from jump tableDAT_800640a0[a2]andjalrs.0x800215cc+0x800215e0: handler arguments are loaded as bytes from pointer fields in the action record (a1=*(*(record+8)),a2=*(*(record+0xc))).
- Table slot proof:
DAT_800640a0[0x0f] = 0x800230e4(the target handler).- therefore the gate-arm branch requires this record-level triplet at dispatch time:
- dispatch index byte =
0x0f(to pick handler0x800230e4), - first argument byte =
0x0a, - second argument byte =
0x04.
- dispatch index byte =
- Per-level gating proof from
DAT_80063e68:
- indices where table byte is
0x0f:54,55,56,57,58,82. - outside those level indices, this exact
0x0f -> 0x800230e4lane is not selected by the recovered level gate compare.
Inferred player-facing meaning (narrowed)
- strongest read is now a late/level-scripted control-event lane, not a random global input callback: the branch is reached through a level-gated action dispatcher and a control-handler jump table.
- practical narrow set: player-visible triggers tied to scripted/control progression events in level-index set
{54..58,82}that emit dispatch triple(0x0f,0x0a,0x04). - still not fully singular: static analysis in this pass did not recover one uniquely named UI/menu function boundary that can be asserted as the only producer of that exact triple.
Confidence update
- high (
~0.90) that call reachability into0x800230e4is through0x800214ac..0x800215f8+DAT_800640a0indirect dispatch. - high (
~0.87) that branch trigger shape is exactly(dispatch_index=0x0f, param_2=0x0a, param_3=0x04). - medium-high (
~0.76) that player-facing source is a small late-level scripted/control action family (54..58,82), not a single global menu button.
Live Ghidra artifacts changed
- conservative disassembly comments added:
0x800215bc(level-gated dispatch compare againstDAT_80063e68[current_level])0x800215cc(argument-byte extraction from action record pointers)0x800215dc(jump-table dispatch throughDAT_800640a0, slot0x0f -> 0x800230e4)
Mission 16 / developer office mapping correction (2026-04-11 live pass)
An older interpretation in this note treated the ?RTN / NRTN special branch as if it directly selected DAT_80063e54[0x0f] = 0x36, which would have put Mission 16 / dev-office content inside the DAT_80063e68 == 0x0f gate family.
That interpretation is now superseded.
Correct runtime flow
- The
?RTNspecial branch is decode indexi = 0x0f, but it does not return0x0f.
- it clears
psx_level_runtime_header_stateat0x8003ed10 - due to the decoder's return flow, raw selector returned to caller is
0x10
psx_passcode_screen_eval_current_entrythen maps throughDAT_80063e54[0x10], notDAT_80063e54[0x0f].
- live table bytes now anchor this as
DAT_80063e54[0x10] = 0x3f
- Caller state at
0x80034d84therefore uses mappeds0 = 0x3f, not0x36. - Apply path still reaches selector-
0x10case at0x8002142c, which writesDAT_800675e4 = 0x1d, setsDAT_80067379 = 2, and calls the common helper witha0 = 0x36.
Practical consequence for the dev-office hypothesis
a0 = 0x36in the selector-0x10apply case may still be related to the user-observed developer-office lane, but that is not the same claim ascurrent_level_map_id == 0x36orDAT_80063e68[current_level] == 0x0f.- so the previously attractive chain
?RTN -> map 54 -> gate family 0x0fshould be treated as withdrawn. - the surviving office hypothesis is weaker and narrower:
?RTN/NRTNmay still route into office-like content, but current static evidence does not prove that this places the session directly inside the slot-0x0fgate-arm family.
Confidence update
- high (
~0.95) that the correct caller mapping is?RTN index 0x0f -> raw selector 0x10 -> DAT_80063e54[0x10] = 0x3f - high (
~0.91) that the olderDAT_80063e54[0x0f] = 0x36interpretation was the wrong table index for the runtime?RTNpath - medium (
~0.66) thata0 = 0x36in the apply case still corresponds to the same player-facing developer-office concept without one runtime label capture
Live Ghidra artifacts changed
- conservative comments added in later follow-up:
0x8003ed100x80034d840x8002142c
Step-2 producer-path closure (control-opcode lane) (2026-04-11 live pass)
Goal of this pass was to close the unresolved upstream producer for the gate-arm dispatcher block (0x800214ac..0x800215f8) by tracing backward from 0x800215cc / 0x800215e0 into the parent script/control lane.
Exact executable evidence recovered
0x800215cc/0x800215e0byte loads are inside unnamed control helper0x800214ac.
- it reads pointer arguments from
record+8andrecord+0xc(arg1=*(*(record+8)),arg2=*(*(record+0xc))), then dispatches throughDAT_800640a0[slot]after level gate compare at0x800215bc.
0x800214acis now proven as table entryDAT_80063610[49](address0x800636d4).- Upstream call chain for that entry is now explicit:
psx_object_behavior_opcode_dispatch(0x8002677c) dispatches throughDAT_800641ac[opcode_index].- table entry
DAT_800641ac[54] = 0x80027ecc. 0x80027eccperforms a second dispatch by loading sub-opcode from*(*(a1+0))and jumping throughDAT_80063610[subop].- when
subop==49, it reaches0x800214ac.
- Therefore the unresolved writer tuple path is no longer a free-floating callback; it is a nested behavior/control opcode producer path:
- behavior opcode index
54-> secondary sub-opcode49->0x800214ac-> slot tableDAT_800640a0.
- The gate-arm writer tuple remains unchanged at the sink:
- slot
0x0fselectspsx_set_debug_extra_channel_gate(0x800230e4), and branch write requires args0x0a,0x04.
What this closes and what remains open
- closed: where the action-record bytes come from structurally.
- they are produced from the object behavior/control stream argument pack used by opcode-54 handler
0x80027eccand its sub-dispatch intoDAT_80063610[49]. - still open: one singular player-facing mission event label.
- static executable evidence now identifies the producer subsystem and dispatch indexes, but does not yet uniquely name one authored script instance as "the" office event.
Narrowed map/event set in this pass
- executable gate compare lane remains constrained by
DAT_80063e68[current_level] == 0x0f(current narrowed level-id family from prior pass:{54..58,82}). - cache-side cross-check in this pass:
- available scene-cache member from that family was map
82only in current catalog snapshot. - map
82section0 root records showed no direct slot-0x0fpacked-byte hits, which is consistent with this pass's new upstream finding that the writer can be produced by the object control-opcode stream lane (not only section0 root packed-action bytes).
Practical player-visible status
- status is now stronger than "unknown source":
- this is a scripted in-level behavior/control opcode event lane (nested opcode
54 -> 49), i.e., a real gameplay/script progression path rather than a menu-only artifact. - but still not fully singular:
- one concrete authored trigger instance (exact mission script/object instance) is still unresolved.
Confidence update
- high (
~0.94) that producer path isbehavior opcode 54 -> sub-op 49 -> 0x800214ac -> slot 0x0f handler 0x800230e4. - high (
~0.90) that action-byte arguments at0x800215cc/0x800215e0are sourced from opcode argument-pointer records, not direct UI input. - medium (
~0.74) that a single map-82-like scripted control event family is the practical player-visible source, pending one final authored-instance bind.
Step-2 producer-path reachability correction (2026-04-11 live pass)
This follow-up rechecked whether the previously claimed opcode 54 -> sub-op 49 -> 0x800214ac chain is currently proven reachable in active SLUS_002.68.
Direct executable evidence from live script/ref scans
DAT_800641acdoes contain high-index entries:
DAT_800641ac[49] = 0x80027d2cDAT_800641ac[54] = 0x80027ecc
0x80027eccstill dispatches throughDAT_80063610[subop], andDAT_80063610[49] = 0x800214acremains true.- But static reachability in this image is currently narrower than that table topology suggests:
- only recovered caller to
psx_object_behavior_opcode_dispatch(0x8002677c) is at0x80026740 - that caller guards with
(opcode_word - 1) < 0x0aat0x80026710 - therefore this known path only selects
DAT_800641ac[0..9]
0x80027ecccurrently has only one recovered incoming reference, and it is data-only (0x80064284table slot), not a direct call/jump xref.0x800214aclikewise currently has data-only incoming evidence (0x800636d4table slot), not a direct call xref.
Practical correction
- The earlier
54 -> 49statement should now be treated as table-topology evidence, not yet as a proven active runtime producer path. - What remains high-confidence is the sink-side gate-writer shape:
0x800214ac..0x800215f8is a real level-gated slot dispatcher.DAT_800640a0[0x0f] = 0x800230e4and sink args remain0x0f,0x0a,0x04.- The open upstream question is now more precise:
- recover a second proven caller path into
0x8002677c(or alternate path into0x800214ac) that can actually feed high dispatch indices.
Live Ghidra artifacts changed
- conservative disassembly comments added:
0x80026710(known caller path bounds dispatch index to< 0x0a)0x8002685c(documentsDAT_800641ac[a0]use and known caller-path bound)0x80027f0c(documents secondaryDAT_80063610[subop]use under0x80027ecc)
Confidence update (corrected)
- high (
~0.93) that sink-side slot dispatch into0x800230e4viaDAT_800640a0[0x0f]is real. - high (
~0.89) that current static refs do not yet prove active reachability ofDAT_800641ac[54] -> 0x80027eccfrom the known caller path. - medium (
~0.71) that high-index behavior-opcode producers still exist in runtime via currently un-recovered caller/context lanes.
Natural gate-arm active-caller recheck (2026-04-11 live pass)
Scope of this pass was narrow and read-only: verify whether any currently proven gameplay caller path can really feed the sink-side dispatcher at 0x800214ac..0x800215f8 with the known tuple (slot 0x0f, arg1 0x0a, arg2 0x04).
New direct evidence
- Sink-side facts remain unchanged and strong:
0x800214acperforms level-gated indirect slot dispatch throughDAT_800640a0[a2].- slot
0x0fstill resolves to0x800230e4(psx_set_debug_extra_channel_gate) from table entry address0x800640dc. - sink arg bytes are still loaded as
a1=*(*(record+8))anda2=*(*(record+0xc)).
- Upstream topology is still true but only as topology:
0x80027eccis still table-backed atDAT_800641ac[54](0x80064284).0x80027d2cis still table-backed atDAT_800641ac[49](0x80064270).0x800214acis still table-backed atDAT_80063610[49](0x800636d4).
- Proven active gameplay caller lane into behavior-op dispatch remains bounded:
- callers into
psx_run_object_behavior_program_tick(0x80026690) includepsx_object_integrate_motion_and_route_visiblecallsites (0x80012668,0x800131d0) plus two additional runtime callsites (0x80011e78,0x80011f78). - the dispatch handoff at
0x80026740is still guarded by(opcode_word - 1) < 0x0aat0x80026710. - therefore this proven gameplay lane can only select
DAT_800641ac[0..9], not index54.
- No additional direct caller/xref path into
0x8002677c,0x80027ecc, or0x800214acwas recovered in this pass.
Practical interpretation update
- strongest active producer candidate is now the currently proven gameplay behavior-tick lane:
psx_object_integrate_motion_and_route_visible -> psx_run_object_behavior_program_tick -> psx_object_behavior_opcode_dispatch. - but that lane currently cannot feed the
54 -> 49 -> 0x800214acchain because of the< 0x0aguard. - so the older
54 -> 49chain should stay in the model only as valid table topology, and be deprioritized as an immediate natural-event explanation until a second real caller/context is recovered.
New concrete static target
Next high-value target is to recover the missing caller/context lane that reaches psx_object_behavior_opcode_dispatch with indices above 9, or an alternate feeder that reaches DAT_80063610[49] directly.
Most concrete first pivot for that is the mode/transition hub around FUN_80020f7c (0x80020f7c) and its active callers (0x80022068, 0x80022e58, 0x80023080, 0x8002748c), because this is now the strongest live non-table-only control lane that already consumes level-family state (DAT_80063e68) and is visibly active in runtime transitions.
Confidence update
- high (
~0.95) that sink-side tuple shape and slot mapping remain correct. - high (
~0.92) that the currently proven gameplay behavior-op lane is bounded to0..9. - medium-high (
~0.79) that the natural gate-arm event still exists in an unrecovered alternate caller/context lane rather than in the currently proven0..9path.
Dispatcher caller/context reassessment around 0x80026690 / 0x8002677c (2026-04-11 live pass)
This pass was dedicated to finding an active context that can naturally feed the JL-9 sink dispatcher chain, with explicit focus on behavior dispatch around 0x80026690/0x8002677c and sibling control-program runners.
Direct caller closure (behavior lane)
psx_object_behavior_opcode_dispatch(0x8002677c) still has one recovered direct caller:
0x80026740insidepsx_run_object_behavior_program_tick(0x80026690).
- That caller still enforces
(opcode_word - 1) < 0x0aat0x80026710before calling0x8002677c. - Therefore the only proven active behavior lane currently dispatches indices
0..9, not high indices such as54.
Secondary-dispatch topology (still valid, still not active-proven)
DAT_800641ac[54] = 0x80027eccremains true.0x80027eccdispatches throughDAT_80063610[subop];DAT_80063610[49] = 0x800214acremains true.0x800214acremains the level-gated sink block that can route slot0x0finto0x800230e4.- But no additional caller/xref path was recovered that proves runtime entry into
0x80027eccor0x800214acfrom an active lane beyond table topology.
Strongest active context candidate now
The strongest active context remains the object update loop:
psx_object_integrate_motion_and_route_visible- calls
psx_run_object_behavior_program_tickat0x80012668and0x800131d0 - also calls sibling
psx_object_run_control_opcodeat0x80012ae0
This makes the behavior/control sibling pair the best live context family, but only the behavior half is currently connected to 0x8002677c, and that half is still bounded to < 0x0a.
54 -> 49 status update
- keep
54 -> 49as structurally correct table evidence. - retire it as an immediate active-caller explanation for now.
- working priority should stay on recovering a second active caller/context into
0x8002677c(or alternate proven feeder into0x800214ac).
Live Ghidra artifacts changed in this pass
- Created function:
0x80027ecc->psx_behavior_subopcode_dispatch(body0x80027ecc..0x80027f34).
- Renamed function:
0x80020f7c->psx_control_event_apply_level_channel_preset.
- Added decompiler comments:
0x80026710: documents< 0x0aproven caller bound.0x80027f0c: documents secondary sub-op dispatch and unresolved active reachability of entry49.0x80020f7c: documents role as level-channel preset helper used by control-event slot handlers.
JL-9 natural-event synthesis from new clues (2026-04-11 live pass)
Scope of this pass was narrow and evidence-only: integrate the two new clues (timed failure segment and "last mission is multi-map") into a ranked natural-arm model, then apply conservative live Ghidra artifacts only where call/xref evidence is explicit.
Ranked hypothesis list (current best)
- Optional scripted event within countdown/transition chain (strongest)
- slot-
0x0farm remains indirect-only (0x800640dc -> 0x800230e4) and tuple-specific (0x0a,0x04), which fits a conditional scripted branch better than a guaranteed branch. - progression callback lane is table-driven (
0x80064210 -> 0x80027548) and therefore naturally optional/contextual.
- Countdown-failure branch timing miss
- countdown tick is on active world-frame path (
0x8002b9a0 -> 0x8002b738 -> 0x80020794). - map boundary split at
0x800208f0(<=54 -> 0x1a,>54 -> 0x1b) gives a concrete timed bifurcation where a natural run can miss tuple timing.
- Map-to-map transition interaction
- multi-map clue is code-backed via
psx_map_progression_tablereads in both preset and callback lanes (0x80020fa4,0x80027560). - this supports "state advanced before arm tuple" as a real mechanism, but currently weaker than #1 because no single transition branch is proven to always suppress arm.
- Countdown-success branch itself (weakest of the four)
- no recovered direct evidence that plain success path alone arms
psx_debug_extra_channel_gatewithout the tuple-specific slot0x0fbranch. - success/failure appears to gate mode flow, while arm remains a separate control-event tuple branch.
Strongest new reason to test one path first
Most decisive next test target is the optional scripted-event path inside the countdown/transition chain.
Reason:
- this is the only ranked path simultaneously supported by all new evidence anchors in one chain:
- frame-timed countdown integration (
0x8002b738 -> 0x80020794), - map-54 bifurcation (
0x800208f0), - multi-map progression callbacks (
0x80020fa4,0x80027548/0x80027560), - and indirect slot-
0x0ftuple arm (0x800640dc -> 0x800230e4,(0x0a,0x04)).
- frame-timed countdown integration (
So the best discriminating runtime probe is now: observe whether tuple (0x0a,0x04) is skipped when the countdown branch/preset path takes the map-boundary/progression route before slot-0x0f dispatch.
Live Ghidra artifacts changed in this pass
No new function renames were applied in this pass (conservative threshold not met for additional naming).
Decompiler comments added:
0x80020794: countdown tick call-chain note (level_session_loop -> world_frame_tick -> countdown_transition_tick).0x800208f0: explicit map-54 boundary bifurcation note (<=54 -> 0x1a,>54 -> 0x1b).0x80020fa4: progression-table read note with multi-map timing implication.0x80027548: callback-table-driven progression note (xref via 0x80064210).0x800230e4: indirect-only slot-table reachability reminder (0x800640dc), preserving tuple-branch specificity.