The field-VM opcode census: does any scene on the disc use op X?
asset field-op-census walks every field-VM bytecode carrier on the disc, decodes it, and counts opcode occurrences, with the sub-dispatched opcodes (0x4C, 0x43, 0x45, 0x49, 0x34) broken out by sub-arm. It answers one question for any opcode: does a shipped scene carry it at a decoded instruction boundary? Its zeros are the point - they separate "no test drives this handler yet" from "the disc has nothing to drive it".
Running it
asset field-op-census extracted/PROT --cdname extracted/CDNAME.TXT \
--csv target/field-op-census.csv
asset field-op-census extracted/PROT --cdname extracted/CDNAME.TXT \
--only '4C CF' --context
--only <op> lists the carriers of one op (4C CF, 4CCF and 39 all parse); --context prints the decoded neighbourhood of each clean hit; --csv writes the whole carrier × op table. The output is regenerable from the disc and is never committed. Before it, three censuses each covered one family of ops (system flags, motion flags, the op-0x49 windows); an op outside those had no instrument at all.
Decode, don't scan
A field-VM record embeds Shift-JIS message text, and every opcode byte value occurs in prose. Scanning PROT.DAT for the bytes 4C EA finds the pair inside dialogue at whatever rate two bytes occur. The census instead walks each record from its first-opcode offset with the field-VM disassembler and counts only on an instruction boundary. It walks three kinds of carrier, and each holds scripts the others do not:
| Carrier | What it is |
|---|---|
bundle | the scene bundle's MAN (the type 0x03 descriptor, LZS-packed) |
stream | a type 0x03 chunk inside a DATA_FIELD stream: the per-scene variant MAN, which carries cutscene records the bundle MAN does not |
event | a raw event-script carrier, where a .PCH scene's prescript records live (the PROT entry after the .PCH table) |
Inside a MAN every record of all three partitions is walked, each from the first-opcode offset its own partition's header shape gives. The three shapes differ, and one formula applied to all of them starts a whole record class three bytes late - which is how an entire class of door records once went missing from a count.
clean versus total, and what a zero means
45 6C has hundreds of total hits and no clean one, because 45 6C is "El" in ASCII.- A clean zero means no shipped scene reaches that arm through the field VM's own bytecode, so a runtime-reach row is not waiting on a replay fixture. It does not mean the handler is dead: a cross-context dispatch can still reach it.
- A clean hit is a lead until its record is read. A linear walk can stay error-free through message text and re-sync on a byte that is no opcode, so a rare op's few hits get
--contextand a reading. - It under-counts, never over-counts. An occurrence behind an earlier desync in its own record is invisible to
clean. - Cross-checked. The camera tests' own per-arm counter over the same corpus reports the census's
totalexactly for four0x4Carms, and the same scene counts for the two rare ones.
What the census settled
| Op | Finding |
|---|---|
4C EA scripted game-over | Three clean occurrences, one in each kingdom world-map bundle: a named scene change, a self-looping jump, the game-over, a wait and another self-loop - a hand-off that never returns. Driving it is a story-state fixture, not a missing carrier. |
4C 52 take item | Seventy clean occurrences across twenty-five scenes, all the same shape: a "Treasure Chest!" line, then the take, then the scene-fade pair - the chest and key-item scripts consuming the item just used. An earlier walk counted three because it stopped at each record's first text segment. |
4C CF script camera focus | Fifty clean occurrences, every one in uru, beside camera applies and camera-config writes (MENU_CTRL). |
43 0C, 43 09 wipe and tween | Zero clean occurrences and 31 incoherent ones, every one inside a record that had already desynced. The row that asked for a scene issuing them has no evidence behind it, but it stays open until those 31 are read. |
Reading the summary table
The default run prints one row per key, clean first, with the number of distinct scenes each op's clean hits span. The scene column counts CDNAME blocks, in extraction-index space. The header line carries the walk's own health - carriers, MAN payloads, records, desynced records, decode errors, script bytes - because a per-op count is only as good as the walk that produced it, and roughly half of all records desync somewhere, most of them text-heavy.