Tier C - rewriting field-VM bytecode
Some of the most player-visible content - what's in a chest, what a shop sells, what a zone throws at you - isn't stored as data at all. It's an operand inside the per-scene field-VM script. Editing it means treating the scene's MAN as code: decode the bytecode, rewrite one opcode's inline argument, recompress within the script's original footprint. The trap is finding the operand without mistaking data for an instruction.
Mechanism at a glance
- Target
- an opcode's inline operand in a per-scene MAN's field-VM script (dispatcher
FUN_801DE840) - Find
- an opcode-aware, dialogue-skipping walk from each record's true entry PC - never a raw byte scan
- Write
- overwrite the operand same-size, recompress the MAN, keep the stream within its footprint budget
- Budget
- distance from the MAN's
data_offsetto the next descriptor's - read from the boundary, not the rewritten stream, so multi-pass edits stay stable - Opcodes
- chest
0x39+ display0xC2· shop0x49· encounter formation ids · house-door0xA3 0xF8 - Oracles
chest_patch_real.rs·shop_patch_real.rs·encounter_patch_real.rs·house_door_patch_real.rs
The reversing: don't mistake data for an instruction
Field-VM bytecode is variable-width and interleaved with inline dialogue - runs of 0x1F-led glyph segments that are not opcodes. A chest's GIVE_ITEM (0x39 item_id) almost always sits after the dialogue that announces it, so a naive scan for the byte 0x39 would trip over a glyph or an operand byte and rewrite the wrong thing. The site finder instead walks each partition-1 record with the field-VM disassembler from its true entry PC, decoding opcode by opcode: a decode error at a 0x1F is treated as a dialogue segment to skip (advance past it, consume glyphs to the terminating 0x00), and decoding resumes - the inter-segment control bytes stay in sync, so the walk reaches the real post-dialogue give. Any other decode error stops the walk, and each record's walk is bounded to the next record's start, so it can never run off into unrelated data. An earlier walk that stopped at the first 0x1F silently missed the give in ~85% of sites - the kind of bug a byte scan hides.
Two pins make the rest exact: each opcode's operand encoding comes from the field-VM dispatcher (FUN_801DE840, see script VM), and a chest's announcement text renders its item name from a separate 0xC2 id dialogue token - patch only the 0x39 give and the flavor text still names the old item, so both bytes move together.
The footprint budget
After the operand is rewritten the MAN is recompressed, and the new stream must still fit where the old one lived - the gap to the next asset's descriptor. The budget is read from the descriptor boundary, not the just-written stream, which matters because several passes (encounter, chest, shop) each decode and re-pack the same MAN: our packer is often a touch tighter, so reading the budget back from a shorter stream would shrink it each pass and make a later pass overflow a scene it should have edited.
Worked examples
Treasure chests & town shops
Chests rewrite the 0x39 give operand and the matching 0xC2 display token together. Shops reassign the inline op-0x49 stock list - the gold-merchant's wares are bytecode operands in the scene script, not a separate table (mind the unsellable template tail that over-counts stock).
Random encounters & house doors
Encounters rewrite a formation's monster-id bytes while preserving the leading count/reserved bytes, so the formation shape is intact. House doors shuffle the player-warp operands of the intra-town 0xA3 0xF8 move-to ops, class-preserving across the named IN/OUT records so interiors still connect sensibly.
Composition
Tier C edits are same-size at the operand level, but several can target the same scene MAN, so they share one rule: every pass reads the footprint budget from the descriptor boundary, never from a previously-rewritten stream. With that, encounter, chest, and shop passes over one scene compose cleanly. The variable-length cousin - when an edit must change a byte count - is tier D.
Mods using this technique
- Treasure chests (
--chests) · Town shops (--shops) · Random encounters (--encounters) · House doors (--house-doors)
Adding a tier-C mod: find sites with an opcode-aware walk bounded to each record (never a raw byte scan), patch any paired display token alongside the operand, recompress reading the budget from the descriptor boundary, skip scenes that overflow, and add a disc-gated oracle.