Files
OpenMaidEngine/tools/probe_leads.py
gamer147 aa3da00bfa 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

75 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""Corpus-wide candidate-opcode histogram.
T3 entries point at [0x8F, 0, line#] records embedded in CODE. The dword right
after each 3-dword T3 record is the lead of the next statement -> candidate
opcode. Histogram those leads over all root-override + DATA1 scripts.
Also: histogram the dword immediately preceding each `0x02 <off>` string ref
(candidate "takes-a-string" opcodes), with example files.
"""
import os, sys, collections
from pathlib import Path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import paths
import sys4load
# authoritative set: game-dir overrides shadow extracted/DATA1
files = paths.scripts()
print(f"{len(files)} scripts (overrides win)")
lead_hist = collections.Counter() # dword after each T3 record
lead_examples = collections.defaultdict(set)
pre_str = collections.Counter() # dword before each 0x02 <off> ref
pre_str_ex = collections.defaultdict(set)
first_dword = collections.Counter()
t3_rec_shape_ok = 0
t3_rec_total = 0
bad = 0
for name, p in sorted(files.items()):
try:
scr = sys4load.load(p)
except Exception as e:
bad += 1
continue
dw = scr.dwords
code_len = scr.code_len
first_dword[dw[0]] += 1
# statement leads via T3 records
for e in scr.table_entries("T3"):
if not (0 <= e < code_len):
continue
t3_rec_total += 1
if e + 2 < code_len and dw[e] == 0x8F and dw[e+1] == 0:
t3_rec_shape_ok += 1
nxt = e + 3
if nxt < code_len:
v = dw[nxt]
lead_hist[v] += 1
if len(lead_examples[v]) < 3:
lead_examples[v].add(name)
# dword preceding string refs (ref index i+1 holds offset; tag at i)
for ref_idx in scr.string_refs: # ref_idx points at the offset dword
tag_idx = ref_idx - 1 # the 0x02
if tag_idx - 1 >= 0:
v = dw[tag_idx - 1]
pre_str[v] += 1
if len(pre_str_ex[v]) < 3:
pre_str_ex[v].add(name)
print(f"parse failures: {bad}")
print(f"T3 records with shape [0x8F,0,*]: {t3_rec_shape_ok}/{t3_rec_total}")
print("\n== first body dword ==")
for v, c in first_dword.most_common(8):
print(f" {v:#06x} {c}")
print(f"\n== statement leads after T3 records (top 40 of {len(lead_hist)}) ==")
total = sum(lead_hist.values())
for v, c in lead_hist.most_common(40):
ex = ",".join(sorted(lead_examples[v]))
print(f" {v:#06x} {c:>7} ({100*c/total:5.2f}%) e.g. {ex}")
print(f"\n== dword preceding `0x02 <off>` string refs (top 25 of {len(pre_str)}) ==")
tot2 = sum(pre_str.values())
for v, c in pre_str.most_common(25):
ex = ",".join(sorted(pre_str_ex[v]))
print(f" {v:#06x} {c:>7} ({100*c/tot2:5.2f}%) e.g. {ex}")