Tier G - carrying a RAM patch on disc
On a --super-arts-pack disc each character has ten Super Arts - five retail, five new, each with its own name banner, hit count and animation, fired by its own arts chain. The five new ones are the Super Arts Pack, a community mod by ZetaPhoenix - and he wrote it for a GameShark, not a disc. This rung is how a RAM patch built for a cheat device becomes a cold-boot disc patch, with the author's bytes installed byte-for-byte.
At a glance
- Payload
- ZetaPhoenix's 3,764-byte block at
0x801FD000: trigger tables, fifteen names, four MIPS routines, 34 animation edit-lists - Parking
- Two 2,048-byte sectors in the
DMY.DATannex (dev-fixture space the game never reads); disc size unchanged, PPF-safe - Loader
- 12-instruction stub in verified-dead arena 1 (
0x8007AE00), entered from battle init; calls the game's own readerFUN_8005E4D4, then BIOSFlushCache - Hooks
- Fourteen same-size words across ten sites - the author's own hook set, installed verbatim; the battle-load detour is the carrier's one addition
- Edit class
- In place throughout (annex sectors already exist)
- Confidence
- Confirmed - interpreter oracle over all 30 trigger chains + emulator probe of the live CD read
- Oracle
super_arts_pack_real.rs
What the payload does
A retail Super Art is a find-and-replace: the queue builder tokenizes your arrow chain into a byte queue of action constants on the battle actor (actor+0x1DF), and the applier (FUN_801EF9E4) scans a five-row-per-character trigger table over the finished queue - a matching tail is overwritten with that row's replace string, the 0x1A special starter plus the Super's finisher constants. The pack widens exactly this mechanism: its own tables carry ten rows per character (rows 0-4 are the retail rows byte-for-byte; 5-9 are new), plus routines that give the new rows names, hit counts and animations. The cleverest part is the animation scheme: the added Supers reuse seventeen existing action constants, and a routine applies a per-constant (offset, values) edit-list over the live art record on the way in - and its inverse on the way out. A self-reversing patch over game state, carrying no copied game data.
Free RAM is a claim that needs evidence
The payload's home, 0x801FD000, is above everything the game loads - and "above everything" is exactly the kind of claim this project has been burned by before ("zero is not dead"). Three measurements back it:
- No overlay covers it: slot A - where the battle overlay PROT 0898 loads - ends at
0x801F7018, and nothing loads higher. - Across the project's save-state library - 60 states, battles included -
0x801FD000..0x801FE000is all-zero in every one. - The deepest observed stack use is
0x801FE420, still 1,388 bytes above the block's end.
0x801F7018..0x801FD000 at every battle load, wiping the persistent effect state the field overlay leaves there.The loader: annex sectors plus a streaming stub
The payload is written into the DMY.DAT annex - a bump allocator over sectors of dev-fixture data the retail game never reads, so the disc keeps its exact size and the whole install stays a PPF. A 12-instruction stub in the executable's verified-dead arena streams it in at every battle load:
FlushCache matters: the payload is code, and the R3000's instruction cache is not DMA-coherent.The hooks: reading them out of the payload
The pack's fourteen hook words across ten sites are the author's own, installed verbatim. Before he published them, though, most were reconstructed from the payload alone - and the method generalises to any payload written in his style. Each routine replays the exact retail instruction it displaces and ends with a jump back to the instruction after its hook, so the routine pins its own site; the stride retarget is forced by the payload's table strides meeting the applier's own address arithmetic (one doubled register turns t5×65 / t5×80 into the 10-row strides).
The instructive part is where reconstruction and author differed. Everywhere the payload could pin a word, the two matched. The deltas sat exactly where the payload is silent - and one was a genuine miss: the row loop's exit seed, a li a1,5 the match arm uses to fall out of the scan, which must widen to 10 alongside the loop bound. Neither word is referenced by any routine, so the payload cannot pin them; without the seed, every match resumed scanning against the already-rewritten queue (end-state identical on his tables, a third more work per match). The law this leaves behind: when reconstructing hooks from a payload, every un-pinned loop immediate is a place to suspect a paired edit.
The full hook table, the delay-slot relocation trick his queue hook uses, and the loop-immediate pairing are laid out in the randomizer reference.
The authorship boundary
Carrying a third-party mod draws a line the earlier rungs never needed: the payload is the author's work, and the carrier's whole job is delivery without alteration. The block ships as a data file installed byte-for-byte; the hook words are his; the loader stub is the carrier's one addition, because a RAM cheat had nothing to load. The patcher refuses rather than adapts: every hook site must carry its exact retail word, the payload's retail rows must match the disc's own trigger tables byte-for-byte, and the embedded block's size, routine entries and baked return addresses are checked against the hook map - so a swapped-out blob can never install against hooks derived from a different one.
The same boundary governs his follow-up arts name-length fix (shipped as part of the pack), with one documented exception that proves the rule: his fix parks its routine in an all-zero run inside the executable's SsAPI sound-table window - the exact cluster where this project once learned that zero padding between live tables is not dead space. The carrier installs his instruction stream unchanged but parks it in read-watch-verified arena space, moving only the hook's jump target.
How we know
| Claim | Evidence | Reference |
|---|---|---|
0x801FD000 is free RAM | All-zero across the 60-state save library; slot A extent from the based overlay images; stack low-water from the same states | static-overlay-pipeline |
| Every hook site carries its known retail word | Applier + queue builder + banner routines disassembled at their recovered bases; the plan fingerprints all ten sites before writing | battle-action |
| The pack actually fires | Disc-gated oracle: the patched applier's real instructions, with the payload read back out of the annex, run in a MIPS interpreter over all 30 trigger chains - added chains rewrite the queue and index the right name; retail chains come out untouched | super_arts_pack_real.rs |
| The CD read works live | PCSX-Redux probe: boot the patched disc, walk into a random encounter, check 0x801FD000 was clear before and holds the payload at the stub's return | pcsx-redux-automation |
| Nothing else moved | Byte-diff oracle: only the planned words and the annex sectors differ from the clean image, every touched sector stays EDC-valid, and a rerun is byte-identical | super_arts_pack_real.rs |
Details: adding a tier-G mod
Park the payload with DiscPatcher::annex_blob (whole sectors, returns the LBA the stub bakes in). Prove the target RAM free the same three ways: no overlay covers it, all-zero across the save-state library, clear of the observed stack floor. Enter the loader from a load path that already waited for its own CD read, call the game's own reader, and FlushCache if the payload is code. Fingerprint every hook word; if the payload is someone else's, install it verbatim, check any rows it duplicates against the disc's own tables, and keep the authorship boundary in the docs as well as the code.