Native-RE (Ghidra) cracked call-script <id> (opcode 0x03): its handler FUN_0041bc90 -> loader FUN_0040e980 -> resolver FUN_0044f390 indexes an 80-byte record table at base + id*0x50 == the SYS4INI record layout. So `call-script <id>` is a direct RAW index into the SYS4INI global file table (the asset index we already parse) -- there is no separate on-disk id->code registry. This resolves name-resolution.md #1, statically, no Frida. Confirmed: all 297 distinct corpus call-script ids resolve to a .BIN script with a semantically-exact name (0x1ab->ADDITEM, 0x2ae7->MES, 0x143->BUNKI, 0x329d->CALCREVISE), 0 out-of-range, 0 alternate-pack. Companion op 0x8f `call` is an intra-script JSR (FUN_0041fba0), not cross-script. - parse_sys4ini.py: preserve `raw_index` per entry (= the engine file id; index the RAW records incl. '@' placeholders) + emit build/callscript-names.json (id->name). - sys4load.py: annotate `call-script 0x1ab =ADDITEM.BIN`. - opcodes.toml 0x03/0x8f refined (source=investigation, confidence high, handler VAs) + rebuilt opcode-reference.md. - docs: engine-re.md (op 0x03 section + backlog re-aimed), name-resolution.md #1 (SOLVED), script-inventory.md (call graph + living-reference decision), tools-reference.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.7 KiB
DATA1 Script Inventory — 481 .BIN files
All scripts share the magic header SYS4422 (8 bytes), confirming a uniform SYS4
bytecode format (engine version 4.4.2.2) across the entire set. Header is followed
by what appear to be little-endian u32 fields (version/section table — to be mapped
during disassembler work).
Source: extracted\DATA1\ (extracted from DATA1.ALF).
Patch overrides: 52 loose .BIN files sit in the game root directory and shadow
their DATA1 counterparts at runtime (sizes differ slightly — e.g. FIELD.BIN root
200,536 vs archive 200,224). These are the v1.03 / append-patch versions and should be
treated as authoritative over the archive copies. Two engine files exist only in
the root: SYS4INI.BIN (272 KB) and SYS4AB.BIN (1.08 MB).
Breakdown by series
| Series | Count | Total size | Role (inferred) |
|---|---|---|---|
SC#### |
136 | 15.6 MB | Scenario/event scripts (numbered 0000–1690, step 10) |
SP#### |
163 | 10.6 MB | Secondary scene series (0010–1369; incl. SP0051A/B split) — likely character/H-events |
| Named scripts | 175 | ~7.5 MB | Engine subsystems, data tables, UI, battle logic |
DEBUG* |
5 | 1.4 MB | Debug tools (DEBUGADV.BIN alone is 1.4 MB — a scene viewer/jump menu) |
RTN_M### / RTN_B### |
26 | ~70 KB | Small routine scripts (map routines M001–M061, battle routines B001–B004) |
SC series notes
- Numbered
SC0000–SC0880(main chapters, largest files — up to 700 KB) andSC1000–SC1690(smaller; likely sub-events, endings, appendix content). SCJUMP.BIN(778 KB) is almost certainly the master scene-dispatch/jump table.SCINIT.BIN(88 KB) initializes scenario state.
Named scripts by subsystem (inferred from names)
Engine core / boot flow
SYSTEM4.BIN (config root), INIT.BIN (64 bytes — smallest script, ideal first
disassembly target), INITCONFIG, LOADCONFIG, CONFIG, TUNE, LOGO, OP,
ED, TITLE, GAMESTART, GAMECLEAR, STAGECLEAR
Data-table INIT scripts (likely static game data, not logic)
Large, table-like scripts — prime candidates for data extraction:
STINIT(579 KB) — stages/scenario tablesEBINIT(338 KB) — enemy battle dataMPINIT(330 KB) — mapsSCINIT(88 KB),CGINIT(79 KB — CG gallery),ITINIT(70 KB — items),RTINIT(67 KB),CCINIT(41 KB),SKINIT(37 KB — skills),CDINIT(31 KB),BTANINIT(105 KB — battle animations)- Smaller:
AFINIT,ALINIT,CIINIT,CNINIT,CTINIT,CVINIT,ILINIT,LAINIT,MAINIT,OBINIT,SPINIT,TRINIT,VIINIT
Message/string tables (*MES)
ITMES (64 KB — item text), VIMES (43 KB), EIMES (37 KB), SKMES (31 KB — skill
text), CIMES (15 KB), MAMES, INFOMES, MES — where most translatable text
outside scenes lives.
Battle system
BTL (61 KB — main battle loop), BTRTN, ROUND, AIM, ATSEEK, MVSEEK,
MVRTN, MAGIC, USEMAGIC, SUMMON, EXILE, DISARM, RECOVER, COUNTUNIT,
SETOCC, and the CALC* family: CALCBTPARAM, CALCDMG (16 KB — damage formula!),
CALCSCOPE, CALCOCC, CALCREVISE, CALCCC, CALCILL, CALCARR
Dungeon/map engine
FIELD (200 KB — the core dungeon-crawl loop), DRAWMAP, RENDERMAP,
DRAWMINIMAP, DRAWCH/DRAWCHP/DRAWENP/DRAWOBJ/DRAWTIP/DRAWVOL,
SETCH/SETEN/SETLAND/SETOBJ/SETROUTE/SETMVWORK,
DELCH/DELEN/DELENMASS/DELLAND, RESETLAND, WARPU/WARPD, LOOK,
READICON
Unit/party management
ADDEXP, ADDSKILL, ADDEN, ADDITEM, ADDRANDOMITEM, LOSTRANDOMITEM,
ADDILL/ADDILLSUB, EVOLVE, IMPROVE (37 KB), TRAIN, STUDY, UNITECH,
REMOVECH, SHOWGROW, STATUS, USEITEM, SETCH
Base/facility gameplay
CAMP, ROOM, FORT, ALCHEMY (40 KB), SALLY (40 KB — sortie/deployment),
READY (39 KB — pre-battle prep), SELSTAGE (34 KB), SELACT (30 KB)
Menus / UI / meta
MENU, CHMENU (69 KB — character menu), INFO/INFOAF/INFOCH/INFOEN/
INFOIT/INFOVO (info panels: characters, enemies, items, voices), SAVE (40 KB),
HISTORY, HIDEWIN, CLOSE, INPUTNAME (28 KB), CGMODE (24 KB — gallery),
MMODE (music mode), HMODE (22 KB — scene replay)
Flow control / branching
BUNKI (分岐 = branch, 15 KB), SBUNKI, BUNKIMOVE, SBUNKIMOVE, SCJUMP
Callbacks (engine → script hooks)
CALLBACK_LOAD, CALLBACK_LOST, CALLBACK_SETTING, CALLBACK_WINDOW
Debug
DEBUG, DEBUGADV (1.4 MB), DEBUGANIME, DEBUGBTL, DEBUGMAP (+2 numbered)
Call graph — scripts are addressable by call-script <id> (2026-07-07)
call-script <id> (opcode 0x03) loads another script by a raw index into the SYS4INI file table
(id = the entry's raw_index = its global position in SYS4INI). This is the resolved call-graph
registry — there is no separate id→code table; SYS4INI is it. Mechanism: engine-re.md (op 0x03
section); id→name single source: build/callscript-names.json (from parse_sys4ini.py); sys4load
and the regenerated build/disasm/*.asm corpus now render targets by name
(call-script 0x1ab =ADDITEM.BIN). 297 distinct scripts are called across the corpus (3002 sites);
the hottest are HISTORY (backlog), MENU, HIDEWIN, BUNKI (branch), MES (message), ADDITEM,
ADDEN, LOOK, RENDERMAP. Scenes (SCxxxx.BIN) load through the same id-indexed loader.
Living-reference decision: no separate generated markdown call-script reference is kept. Unlike
opcode-reference.md / global-reference.md (rendered from curated knowledge bases), the id→name
mapping is purely mechanical (SYS4INI index → filename) with no semantics to curate — it already lives
in the build artifact and in the named disasm corpus. Full call-graph edges (caller→callee counts) are
derivable on demand from the corpus; materialize a doc only if a consumer needs it.
Implications for the port
- Much more game logic lives in bytecode than expected. Damage formulas
(
CALCDMG), the dungeon loop (FIELD), battle flow (BTL,ROUND), and unit progression (ADDEXP,EVOLVE) are all scripts —AGE.EXEis closer to a pure VM/renderer. This strengthens the case for re-implementing the AGE VM in Godot rather than transpiling every script by hand (the doc's open question #12). - Disassembler bootstrapping order (small → large, system → scene):
INIT.BIN(64 B) →ED.BIN/OP.BIN/LOGO.BIN(~230 B) →CALLBACK_LOST(176 B) →MENU.BIN(3 KB) →CALCDMG→ a mid-sizeSC####. - The
*INITgiants are likely data tables, decodable early even with a partial opcode map — instant win for extracting item/skill/enemy/stage databases. - Use root-directory overrides, not archive copies, for the 52 patched scripts.