diff --git a/docs/name-resolution.md b/docs/name-resolution.md index 161ce27..b0ddbb7 100644 --- a/docs/name-resolution.md +++ b/docs/name-resolution.md @@ -46,8 +46,10 @@ on disk to read. Resolving it needs one of: **Update (2026-07-07):** SCJUMP's *decision logic* is now decoded — `(chapter_mode, guards) → decision value` — see `docs/scjump-progression.md` and `tools/scjump_decode.py`. That confirmed SCJUMP is not the `call-script` registry (it produces a decision value, not a script id). The -decision→scene hop itself is a **native op (`u00428010`)**, engine-level, in the same bucket as -`call-script`; both await the engine dump / Frida. +decision→scene hop is **native and still unidentified** — an earlier guess that op `u00428010` +resolved it was **disproven via Ghidra** (that op is a graphics command-buffer op; see +`docs/engine-re.md`). It's the same engine-level bucket as `call-script`; the Ghidra + MCP loop (and +its recovered opcode-dispatch table) is now the tool to crack the `call-script`/script-load handler. --- diff --git a/docs/opcode-reference.md b/docs/opcode-reference.md index 5e36dd7..fd5a7d2 100644 --- a/docs/opcode-reference.md +++ b/docs/opcode-reference.md @@ -27,15 +27,13 @@ - **grounding:** source=investigation, confidence=high - **evidence:** By-ear confirmed (2026-07-06): SC0000 prologue voices play on their lines via Godot AudioStreamPlayer. Off-by-one disproven structurally: manifest interleaves graphics/voice (files[35]=EV049AA, [36]=MAN999, [37]=EV052CA, [38]=SYL0001), so files[base+id] lands voices on OGGs while files[base+id-1] would land them on .AGF graphics (silent) -- and they play, so the offset is exactly 0. Lily's lines are correctly form-gated (G[0xa57/0xa58/0xa59]) and stay silent when no form flag is seeded -- not a bug. -## compute - -### 0x1a2 `resolve-handle?` (u00428010, argc 1) -- **summary:** 1 local-ptr from lookup-array, then create-texture — resolves a looked-up resource/handle -- **grounding:** source=inference, confidence=low -- **evidence:** confirm via frida - ## draw +### 0x1a2 `gfx-cmd-register` (u00428010, argc 1) +- **summary:** graphics command-buffer op: sets current gfx-object cmd-type=3 and registers a '%c%8.8x' key from operand 1 +- **grounding:** source=investigation, confidence=med +- **evidence:** Ghidra: real handler FUN_0042d360 (via dispatch table ctx[0x26c93+op]); sets *(ctx+0x53d88+ctx[0x53d14]*0x78)=3, sprintf("%c%8.8x",3,op1), FUN_0042cf70. NOT save/scene (raw Kelebek VA 0x428010 drifted to op 0x1ac save handler). See docs/engine-re.md + ### 0x1f7 `ui-elem?` (u00420270, argc 2) - **summary:** 2 args; 0x420 family, pairs with 0x1fa — create/begin a UI element - **grounding:** source=inference, confidence=med diff --git a/tools/age_opcodes_himegari.py b/tools/age_opcodes_himegari.py index e8e7696..b9dd8f6 100644 --- a/tools/age_opcodes_himegari.py +++ b/tools/age_opcodes_himegari.py @@ -9,7 +9,7 @@ INFERRED: dict[int, dict] = { 0x90: dict(name='hotspot-branch', category='input', noop=True, confidence='high', source='investigation', summary='cursor/input hotspot hit-test: rect (x,y,w,h) -> 3-way branch on interaction, else fall through to pc+1'), 0x97: dict(name='hotspot-reg?', category='input', noop=True, confidence='med', source='inference', summary='companion register-hotspot / set-widget-action (argc5: v1 v2 1 1 ; NO code targets)'), 0xb6: dict(name='snd-ctrl?', category='audio', noop=False, confidence='low', source='inference', summary='1 imm; self-chains, 0x41D family near play-sound-effect/0xb5 — sound channel/volume/stop control'), - 0x1a2: dict(name='resolve-handle?', category='compute', noop=False, confidence='low', source='inference', summary='1 local-ptr from lookup-array, then create-texture — resolves a looked-up resource/handle'), + 0x1a2: dict(name='gfx-cmd-register', category='draw', noop=False, confidence='med', source='investigation', summary="graphics command-buffer op: sets current gfx-object cmd-type=3 and registers a '%c%8.8x' key from operand 1"), 0x1bc: dict(name='block-mark', category='marker', noop=True, confidence='high', source='inference', summary='zero-arg; follows jcc/mov, precedes mov/ret — block boundary'), 0x1bf: dict(name='call-end', category='marker', noop=True, confidence='med', source='inference', summary='zero-arg; call->0x1bf->stmt-end — end-of-call-statement marker'), 0x1d2: dict(name='stmt-desc?', category='marker', noop=True, confidence='med', source='harness', summary='2 imm; immediately after stmt-begin 0x1f4 — statement descriptor?'), diff --git a/vm-map/opcodes.toml b/vm-map/opcodes.toml index 928eaf4..e1b3e2b 100644 --- a/vm-map/opcodes.toml +++ b/vm-map/opcodes.toml @@ -3435,14 +3435,14 @@ argc = 1 abi_source = "kelebek+decode-validated" [opcode.semantics] -name = "resolve-handle?" -category = "compute" -summary = "1 local-ptr from lookup-array, then create-texture — resolves a looked-up resource/handle" +name = "gfx-cmd-register" +category = "draw" +summary = "graphics command-buffer op: sets current gfx-object cmd-type=3 and registers a '%c%8.8x' key from operand 1" noop_headless = false -source = "inference" -confidence = "low" +source = "investigation" +confidence = "med" depends_on = [] -evidence = "confirm via frida" +evidence = "Ghidra: real handler FUN_0042d360 (via dispatch table ctx[0x26c93+op]); sets *(ctx+0x53d88+ctx[0x53d14]*0x78)=3, sprintf(\"%c%8.8x\",3,op1), FUN_0042cf70. NOT save/scene (raw Kelebek VA 0x428010 drifted to op 0x1ac save handler). See docs/engine-re.md" [[opcode.semantics.args]] i = 1