Research
This commit is contained in:
parent
28cbbe3470
commit
a9153546ae
56 changed files with 6731 additions and 258 deletions
230
docs/psx/jl-9-in-level-event.md
Normal file
230
docs/psx/jl-9-in-level-event.md
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
# PSX JL-9 In-Level Event Investigation
|
||||
|
||||
This note isolates one question from the broader JL-9 work on PlayStation `SLUS_002.68`:
|
||||
|
||||
- what natural in-level event writes `psx_debug_extra_channel_gate` and makes the later hidden `L0SR` + `R1 + Circle` path unlock `JL-9`?
|
||||
|
||||
## Current status
|
||||
|
||||
The downstream half is now closed.
|
||||
|
||||
- user validation proved that forcing `0x8006739d = 0x01`, then entering `L0SR`, then pressing `R1 + Circle` successfully adds `JL-9`
|
||||
- therefore the remaining mystery is entirely on the natural gate-arm side
|
||||
- `MFM4` is no longer the main mystery; it is only the strongest **natural prime candidate**
|
||||
|
||||
Current best interpretation:
|
||||
|
||||
- the more direct thing being bypassed by the manual poke is the in-level event itself
|
||||
- natural `MFM4` failing means `MFM4` alone is not sufficient
|
||||
- the missing event is most likely an uncommon or optional scripted/control event in a small late-level family
|
||||
|
||||
## Proven sink-side mechanics
|
||||
|
||||
### Gate byte
|
||||
|
||||
- `psx_debug_extra_channel_gate` = `0x8006739d`
|
||||
- writer: `0x800232f0`
|
||||
- reader: `0x8002fff4`
|
||||
- storage is byte-wide (`sb` write, `lbu` read)
|
||||
- late check is nonzero-based, not literal-value-based
|
||||
|
||||
### Natural gate-arm branch
|
||||
|
||||
Natural arm still converges on `psx_set_debug_extra_channel_gate` at `0x800230e4`.
|
||||
|
||||
The exact write branch is:
|
||||
|
||||
- tuple: `(slot=0x0f, arg1=0x0a, arg2=0x04)`
|
||||
- hidden must still be off
|
||||
- `psx_level_runtime_header_state` must be `3`
|
||||
- only then does `0x800232f0` store `1` to `0x8006739d`
|
||||
|
||||
### Hidden trigger half
|
||||
|
||||
Later JL-9 unlock still requires:
|
||||
|
||||
- hidden passcode branch `L0SR` / `?0SR`
|
||||
- input code `0x1e`
|
||||
- practical mapping `R1 + Circle`
|
||||
|
||||
That later path reads `0x8006739d` at `0x8002fff4` and performs the extra `0x0d` unlock when nonzero.
|
||||
|
||||
## Proven dispatcher path
|
||||
|
||||
### Sink feeder
|
||||
|
||||
`0x800214ac..0x800215f8` is now promoted as:
|
||||
|
||||
- `psx_level_gate_slot_dispatch_from_action_record`
|
||||
|
||||
Recovered structure:
|
||||
|
||||
- dispatch slot byte comes from pointer at `record + 0x00`
|
||||
- `arg1` byte comes from pointer at `record + 0x08`
|
||||
- `arg2` byte comes from pointer at `record + 0x0c`
|
||||
- handler call is indirect through `psx_level_gate_slot_handler_table[slot]` at `0x800640a0`
|
||||
|
||||
Important table entries:
|
||||
|
||||
- `psx_level_gate_slot_handler_table[0x0d] = 0x80022c6c`
|
||||
- `psx_level_gate_slot_handler_table[0x0e] = 0x80022ea8`
|
||||
- `psx_level_gate_slot_handler_table[0x0f] = 0x800230e4`
|
||||
|
||||
## Recovered slot-family behavior
|
||||
|
||||
### Slot `0x0d`
|
||||
|
||||
`0x80022c6c` is now named:
|
||||
|
||||
- `psx_control_event_slot0d_handler`
|
||||
|
||||
Recovered strong branch:
|
||||
|
||||
- `(0x0a,0x02)` => mission-complete passcode generation/display lane
|
||||
|
||||
### Slot `0x0e`
|
||||
|
||||
`0x80022ea8` is now named:
|
||||
|
||||
- `psx_control_event_slot0e_handler`
|
||||
|
||||
Recovered branches:
|
||||
|
||||
- `(0x0a,0x01)` => mission-complete passcode generation/display lane using quad index `0x0f`
|
||||
- `(0x0a,0x02..0x04)` => mode/timer setup branches
|
||||
- `(0x0a,0x06)` => selector/stage apply lane that force-applies selector `0x0f`
|
||||
|
||||
### Slot `0x0f`
|
||||
|
||||
`0x800230e4` remains:
|
||||
|
||||
- `psx_set_debug_extra_channel_gate`
|
||||
|
||||
Recovered `0x0a` cases:
|
||||
|
||||
- `1`
|
||||
- `2`
|
||||
- `3`
|
||||
- `4`
|
||||
- `0x2e`
|
||||
|
||||
The JL-9 natural arm branch is specifically:
|
||||
|
||||
- `(0x0a,0x04)`
|
||||
|
||||
## Host-level narrowing
|
||||
|
||||
The recovered gate family is still:
|
||||
|
||||
- `{54,55,56,57,58,82}`
|
||||
|
||||
Best current host ranking:
|
||||
|
||||
1. `54`
|
||||
2. `55`
|
||||
3. `56`
|
||||
4. `57`
|
||||
5. `82`
|
||||
6. `58`
|
||||
|
||||
Why `54` remains the best anchor:
|
||||
|
||||
- `MFM4` is the only ordinary published code that statically satisfies the prime-side conditions
|
||||
- selector `0x0f` maps to map/level `54`
|
||||
- `DAT_80063e68[54] = 0x0f`
|
||||
|
||||
Why this still does not close the event:
|
||||
|
||||
- user-tested natural `MFM4` did **not** produce `JL-9`
|
||||
- so level-family membership alone is not sufficient
|
||||
- the missing event now looks optional, late, rare, or route-specific
|
||||
|
||||
## Upstream producer state
|
||||
|
||||
### What still exists as topology
|
||||
|
||||
The older behavior/subop chain still exists in tables:
|
||||
|
||||
- `psx_behavior_opcode_handler_table[54] = 0x80027ecc`
|
||||
- `psx_behavior_subop_handler_table[49] = 0x800214ac`
|
||||
|
||||
`0x80027ecc` is now named conservatively:
|
||||
|
||||
- `psx_behavior_subopcode_dispatch`
|
||||
|
||||
### Why it is weaker now
|
||||
|
||||
The only currently proven caller into `psx_object_behavior_opcode_dispatch` is still range-limited:
|
||||
|
||||
- known caller path bounds `(opcode_word - 1) < 0x0a` at `0x80026710`
|
||||
- that means the known active path can only reach indices `0..9`
|
||||
- so `54 -> 49` is still valid topology, but it is no longer the best **active** explanation
|
||||
|
||||
Current practical reading:
|
||||
|
||||
- keep `54 -> 49` alive as structure
|
||||
- deprioritize it as the leading runtime explanation until a second active caller/context is recovered
|
||||
|
||||
## Strongest event hypothesis now
|
||||
|
||||
The strongest remaining hypothesis is:
|
||||
|
||||
- the natural gate-arm is a sibling in the same late control-event family as mission-complete / transition handlers around `0x80022c6c..0x80023390`
|
||||
- it is probably an uncommon or optional in-level scripted/control outcome
|
||||
- it is more likely tied to a rare objective-path or late-event branch than to ordinary mission completion itself
|
||||
|
||||
Why this is stronger than the older theories:
|
||||
|
||||
- the sink-side tuple and slot family are concrete
|
||||
- mission-complete siblings are already proven in adjacent handlers
|
||||
- hard-clear / beat-the-game theory stayed weak
|
||||
- direct forced-gate tests show the real unknown is the natural writer event, not the hidden code
|
||||
|
||||
## Ghidra changes applied in this event pass
|
||||
|
||||
### Functions / blocks
|
||||
|
||||
- `0x800204fc` -> `psx_show_mission_complete_congrats_text`
|
||||
- `0x80020f7c` -> `psx_control_event_apply_level_channel_preset`
|
||||
- `0x800214ac` -> `psx_level_gate_slot_dispatch_from_action_record`
|
||||
- `0x80022c6c` -> `psx_control_event_slot0d_handler`
|
||||
- `0x80022ea8` -> `psx_control_event_slot0e_handler`
|
||||
- `0x80027ecc` -> `psx_behavior_subopcode_dispatch`
|
||||
|
||||
### Tables / data
|
||||
|
||||
- `0x80063e54` -> `psx_selector_to_map_id_table`
|
||||
- `0x80063e68` -> `psx_map_id_to_gate_slot_table`
|
||||
- `0x80063eac` -> `psx_map_progression_table`
|
||||
- `0x80063610` -> `psx_behavior_subop_handler_table`
|
||||
- `0x800640a0` -> `psx_level_gate_slot_handler_table`
|
||||
- `0x800641ac` -> `psx_behavior_opcode_handler_table`
|
||||
|
||||
### Key comments added
|
||||
|
||||
- `0x800214bc`
|
||||
- `0x800215bc`
|
||||
- `0x800215cc`
|
||||
- `0x800215dc`
|
||||
- `0x800215e0`
|
||||
- `0x800230e4`
|
||||
- `0x800232f0`
|
||||
- `0x80026710`
|
||||
- `0x8002685c`
|
||||
- `0x80027f0c`
|
||||
- `0x80034d60`
|
||||
|
||||
## Best next code targets
|
||||
|
||||
1. Fully classify the control-event family around `0x80022c6c..0x80023390` as one switch/tuple cluster and align each sibling branch with concrete player-facing outcomes.
|
||||
2. Recover one actual authored producer for `(slot=0x0f, arg1=0x0a, arg2=0x04)` by tracing the action-record inputs feeding `0x800215cc` / `0x800215e0`.
|
||||
3. Find a second active caller/context into `psx_object_behavior_opcode_dispatch` or an alternate feeder into `0x800214ac` that can justify a high-index producer path in live gameplay.
|
||||
|
||||
## Deferred emulator experiments
|
||||
|
||||
Keep these queued for later:
|
||||
|
||||
1. Experiment 2: hard-clear / beat-the-game test
|
||||
2. Experiment 4: compare `MFM4` against another header-state-`3` code under matched in-level actions
|
||||
3. Experiment 5: hold map/event family constant and vary only the suspected scripted event
|
||||
4. Experiment 6: ordering test (`event -> L0SR -> trigger` versus `L0SR -> event -> trigger`)
|
||||
Loading…
Add table
Add a link
Reference in a new issue