Commit Graph

22 Commits

Author SHA1 Message Date
gamer147
169075fe37 feat: curate story-flags into registry + docs (Task 6)
Bootstrap 56 high-signal skeletons; name game_mode/route_branch/scjump_decision_out2,
recategorize CONFIG-written globals as non-story. Docs: name-resolution.md registry
section, CLAUDE.md canonical+SoT tables + trigger (root, untracked), tools-reference rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:33:51 -04:00
gamer147
f0d7775d15 feat: story_flags --bootstrap seeds skeletons into globals.toml (Task 5)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:27:31 -04:00
gamer147
681737604c feat: static story-flag miner -> candidates JSON (Task 4)
Mines 1261 branch-read globals (205 story-flag candidates); build/story-flags-
candidates.json is generated (build/ gitignored). Known anchors 0x3234/0xa57 verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:26:03 -04:00
gamer147
69c788b65a feat: sys4load labels globals from merged build/globals.json (Task 3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:24:36 -04:00
gamer147
84a8da765f feat: globals_build --build merge + generated JSON/MD (Task 2)
build/globals.json is generated (build/ is gitignored, regenerable via
globals_build.py --build); docs/global-reference.md is the tracked human view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:23:17 -04:00
gamer147
7306423505 feat: globals.toml registry source + loader/lint (Task 1)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:21:59 -04:00
gamer147
16fe754422 feat(frida): capture_gfx_objects + finding — drift is state-divergence
Live capture (esi=engine ctx via operand-fetch, poll object-record array
[esi+0x53d64] stride 120). KEY FINDING: through the full real opening, the record
array holds only 3 persistent UI objects — NO CG objects. The real game does NOT
draw opening CGs via the 0x212-0x21a positioned-object path our headless VM uses;
with state it takes a different (direct) branch. So the bg/sprite drift is a
STATE-DIVERGENCE artifact of the unseeded headless VM, not a missing native op —
the fix is the Phase B state/choices flow (makes label_12649 take the if-branch).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 00:04:49 -04:00
gamer147
fbc78b0c00 feat(frida): probe_handlers — confirms interpreter runs from module 0x400000
operand-fetch (call 0x41b940) fires ~8500/sec => the VM interpreter executes
from the in-place unpacked module at 0x400000 (NOT the heap copy) => handlers are
hookable by dump address. gfx-family(0x212-0x215)=0 at the title (no CG commands
until a scene runs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:51:18 -04:00
gamer147
70db77af46 fix(frida): dump_engine — use ptr.readByteArray (frida 17), skip system DLLs
Dump validated: AGE.EXE is unpacked in-place at 0x400000 in memory (AGF-decoder
landmark @0x474f1f reads real code with the 'BM' 0x4D42 check). Kelebek handler
VAs map directly (VA-0x400000 = file offset). Handler ABI: thiscall (esi=engine
context), operands fetched via call 0x41b940, per-object command-type table at
[esi+idx*120+0x53d88]. 0x215 is part of a native gfx command-buffer manager.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:43:54 -04:00
gamer147
f16e5bd7b8 feat(frida): dump_engine.py — dump unpacked engine code from live process
Both on-disk engine images are the same packed binary, so native handler code
exists only unpacked in memory. dump_engine attaches, enumerates ranges, and
dumps the AGE.EXE module + large r-x heap regions (chunked) to build/engine-dump/
for offline disassembly (locate 0x215 @ VA 0x421160 via the dispatch table).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:33:02 -04:00
gamer147
2951425108 docs(opcodes): 0x215 = native graphics-object query (root cause of gfx drift)
Investigation upgrade: 0x215 queries the native object manager by element
handle-id (0x62455[idx]) and returns the object's slot/status; sign-tested to
drive label_12649's slot-select. Stubbing it collapses all draws onto slot 0 →
the anchor-preserve geometry reads foreign textures → cumulative bg/sprite
drift. Keystone for the graphics object-manager; exact return via unicorn
(handler @0x421160).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:21:08 -04:00
gamer147
10f6656c2d feat(a2b): first-pass texture render — full-screen event-CG layer
Wire asset resolution into a live Godot render. VM executes set-texture ->
ResourceMap resolves (scene,resId) -> files[section_base+resId] across all
archives -> pre-converted BMP -> composite behind the dialogue. The full-screen
event-CG layer (EV052*) renders end-to-end from the executed bytecode.

- Age.Engine/Sys4/ResourceMap.cs: Resolve + BMP TexturePath; Paths: asset JSONs
- GodotAdvHost: create/set/draw-texture -> TextureRect in a _stage layer
- IHost.DrawTexture + VM dispatch extended with dst x/y (draw-texture args 7/8)
- project.godot 800x600; convert_agf.py all-archive + --scene batch
- engine 8/8, C# --selftest still byte-matches vm0 trace (VM behaviour unchanged)

Known limitations (next chunk = graphics geometry/blend subsystem):
- sprites + BG* via the CG-load subroutine get garbage dst/size — native ops
  stubbed (0x208 get-texture-size + sprite position/anim chain)
- AE* fades draw opaque/instant (no alpha); no chromakey
- slot model approximates the game's immediate-mode blit-onto-slot-0 canvas
- AGF pre-converted to BMP offline (runtime decoder deferred)
See docs/phase-a-slice-plan.md (A2b section).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 21:22:42 -04:00
gamer147
a61c0c9abd feat(assets): solve asset resolution (SYS4INI per-scene section manifest)
resId -> files[section_base(scene) + resId]. SYS4INI's file list is
sectioned, one per scene (SCxxxx.BIN + its cross-archive asset manifest);
file_number is the index within the section. Unified for set-texture,
play-bgm, play-voice. Fully static/general -> no per-scene capture.

- tools/parse_sys4ini.py: SYS4INI (S4IC422, LZSS) -> build/asset-index.json
- tools/resolve_asset.py: sections + (scene,resId) resolver -> build/asset-sections.json
- validated: 97% structural, SC0000 17/17 vs Frida, 586/595 captured loads
- opcodes.toml: set-texture/create/draw-texture, play-bgm/voice enriched (frida-grounded)
- Frida tooling (capture_load_order all-archive, correlate_scope, ...) + vm0 --settex
- docs: asset-resolution-re (step2 SOLVED), global-memory-re (shelved), tools-reference

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 20:48:22 -04:00
gamer147
b92e815850 feat(a2b): asset-RE tooling + findings; render blocked on asset resolution
- tools/convert_agf.py (AGF->BMP stills), tools/frida/ (capture harness + README; Frida 17.15.3)
- docs/asset-resolution-re.md: foundational RE steering doc (resId->file; graphics+audio; not
  machine-verifiable -> Frida ground truth + human oracle). RE plan: parse SYS4INI, crack resId->name,
  backend render (A2b plan Tasks 3-5), audio, movies.
- Finding: SC0000 bg = slot-0 slideshow (res 0x23 first); resolution opaque (CGINIT not a name map,
  SYS4INI S4IC needs RE, Frida file-I/O noisy/memory-mapped, opening mixes MPEG movies).
- slice plan updated; texture ops already engine-driven (Task 1, prior commit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 16:36:17 -04:00
gamer147
a8a91e48f6 feat(a1): CLI (run/trace) + vm0.py --trace + per-scene differential test (A1 green)
C# VM is byte-identical to vm0.py across all 297 SC/SP scenes (offsets+halt+steps);
RECOVER passes; SC0000 = 27994 steps / 186 lines matching the Python prototype.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:55:11 -04:00
gamer147
9f140fda83 feat(opcodes): migrate to opcodes.toml as single source of truth; regenerate artifacts
- 248 opcodes seeded from Kelebek + corpus arg-types; 23 inferences migrated
- source = provenance (frida/unicorn methods = inference + confirm_by, not grounded)
- 0x90/0x97 enriched with depends_on + details
- differential-verified: SC0830/MENU disasm byte-identical, vm0 --test PASS, sweep 282/294

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:11:33 -04:00
gamer147
cee746250b feat(opcodes): emit opcodes.json, opcode-reference.md, coverage
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:04:35 -04:00
gamer147
9f37a6c31e feat(opcodes): emit drop-in age_opcodes_himegari.py shim; wire --build/--lint
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:03:33 -04:00
gamer147
5d2efa1249 feat(opcodes): bootstrap seeds 248 skeletons from Kelebek + corpus arg-types
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:02:28 -04:00
gamer147
503eb70359 feat(opcodes): linter (dangling-ref, confidence-ceiling, vocabulary)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:01:20 -04:00
gamer147
9f15aa0336 feat(opcodes): data model + loader for opcodes.toml
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:00:31 -04:00
gamer147
463877773c chore: initialize age-reimpl repo
Reverse-engineering + open reimplementation workspace for Eushully's AGE/SYS4
engine (first target: Himegari). The repo root is age-reimpl/; the original game
install and the extracted ALF data are siblings outside the repo and are never
tracked. build/ (derived corpora) is gitignored and regenerated by the tools.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 12:58:30 -04:00