case study8 min read$34

The Partner Hyper Draws Its Background

DHC v8 is out. The partner handoff's missing background was a stalled Hyper script waiting for an animation event nobody sent; six bytes send it. Level 4 of the meter turns yellow from a tile the game already had. What was verified, at what tier, and the trailer.

All versions · Every public patch

cps2marvel-vs-capcomdhcrom-hackingreverse-engineering
CPS-2 Reverse EngineeringPart 40 of 43
Browse all writing
On this page

Direct Hyper Cancel v8 for arcade Marvel vs. Capcom is out: REMIX and ARCADE from one patch-only installer, on the downloads page. This post is about the two things that changed between the last testing build and the file you can download, and about what the release receipt does and does not claim.

clip · loops · audio available
The trailer // 2:37 · every chain runs start to finish · headless MAME runs of the release build plus hand-played arcade-mode clips · a cut, not evidence.

The symptom

On a partner handoff in REMIX, the incoming fighter's Hyper drew no background. The outgoing fighter's background cleared and nothing replaced it: a flash, then the bare stage. Same-fighter chains were unaffected and still advanced through their variants. The product post carried it as a known issue.

Four fixes that were wrong

The first diagnosis was that the Super presentation is owned per side rather than per fighter: a pointer records which fighter owns the side's presentation, a mismatch tears the side down, and the partner route never re-arms it. That mechanism is real — the teardown routine is there and it fires — but it is not why the background was missing. Four patches were written against it, and every one of them was withdrawn:

All four were "verified" on captures that could not distinguish a real background from whatever the stage or VRAM already held. The fixture that finally gated them — a headless run that forces the team through the select screen, drives the project's own route end to end and repeats the handoff command during the Hyper — rejects all four.

The mechanism

A Hyper is driven by a per-action script whose step lives in the fighter object at $0008(a6):

$00E714   dispatch by character  ($0052)   chun-li 0x16 -> $04DE3C
$04DE3C   dispatch by action     ($00E6)
$04E32A   dispatch by step       ($0008)   table of word offsets at $04E336

Step 2 of a Hyper script waits for an event from the animation driver:

04E3A8   jsr    $0001DD8          ; animation driver
04E3AE   tst.b  $003C(a6)         ; event delivered?
04E3B2   beq    -> skip           ; no -> sit at step 2
04E3B8   addq.w #2,$0008(a6)      ; advance
04E3D0   jsr    $000983F4         ; the background graphics load

The driver at $0001DD8 writes $003C from the animation frame data, but only once the frame timer at $003E expires. The cross route hands the incoming fighter a Hyper without initialising its animation state. The timer never runs, the event never arrives, the script never leaves step 2, and the graphics load at $0983F4 is never reached. The display was left showing whatever was already there. The presentation ownership story was true and beside the point: nothing ever asked for a background.

The edit

$3D25E6 is inside the v8 author's own post-commit hook for the incoming fighter, which carries thirty-two bytes of reserved nops. By that point a6 is already the incoming fighter and the REMIX style gate has passed. Three of the nops become one instruction:

$3D25E6   4e71 4e71 4e71   ->   1d7c 0001 003c     move.b #1,$003C(a6)

1 is the value the engine's own driver writes there. No stub, no register saves, no byte of the base program touched. Measured on the fixture, the incoming fighter's handler goes from 24 instruction fetches to 50 and reaches $0983F4; the regression over a 125-second ordinary-play scenario is 1,501 log lines with zero differences against the base. It was then confirmed in play by hand, which is the tier that counts for a presentation change, and it is what shipped.

Level 4 turns yellow

The five-level meter was already in v8. What changed is one fill colour. The game does not colour the bar through the palette; it tells the levels apart by tile. One eleven-tile bar sprite is drawn out of OBJ palette row 20: $7020 is drawn with pen 8 (yellow), $7030 with pen 9 (red), $6E44 is the empty bar. Same shape, same row, different pen, which is how one player can show yellow while the other shows red out of a single shared palette row.

Only those two filled variants exist in the art. Sweeping eighty tile numbers through the bar sprite turned up no third solid fill. So without new tile art the meter has exactly two fill colours to hand out, and levels 1 and 2 already claim both. MvC2's level-4 fill is (238,238,119); MvC1's pen 8 is (255,204,51). Close enough that level 4 can simply point at the tile that already exists.

v8's REMIX HUD routine at $3F8300 (P1) and $3F8336 (P2) puts the bar tile in d4 and the level in d5, then jumps to the base game's draw at $6B76 / $6BF6. Each jump now goes through a stub:

cmpi.w  #4,d5
bne.s   .out
move.w  #$7020,d4
.out    jmp     (original target)

Forty-four bytes. No palette row is written, and levels 1, 2, 3 and 5 are byte-for-byte stock — level 5 keeps its cycling MAX bar. Forty frames with Supers firing continuously and both meters cycling all five levels, patched against stock and diffed whole-frame: thirteen frames differ, and every differing pixel is inside the meter strip.

The approach that was withdrawn

The previous attempt gave levels 3 and 4 their own palette rows, 16 and 17, and repainted them from the meter hook. It corrupted the stage, the health bars and the portraits the moment a Super fired. Rows 16 and 17 are not free: measured over about 3,400 frames of Supers and hits, sprites referenced row 16 4,760 times, and rows 21 through 26 as well. The check that had cleared those rows sampled two single frames of a calm match. Two rules came out of it. No OBJ palette row can be assumed free — all thirty-two are rewritten every few frames, and which ones are referenced varies by character, stage and what is on screen. And writing fixed palette addresses is unsafe, because the palette base cannot be assumed constant. Blue at level 3 and green at MAX need new tile art in the graphics ROMs, not a palette trick.

What the receipt says, and what it doesn't

The release receipt carries one status per check, each with its scope and tier in the same line:

  • The installer was generated from the clean parent and the candidate on two machines and came out byte-identical. PASS, static.
  • The Python patcher was driven through twelve hostile-archive cases: clean, reordered, corrupt member, truncated archive, wrong revision, duplicate, missing and unexpected members, already patched, existing output, existing receipt, broken output link. PASS, container.
  • The background fix: confirmed in play, with the fixture regression behind it. Diagnostic tier plus hand confirmation.
  • The meter change: verified by whole-frame diff on the headless rig. Diagnostic tier.
  • The pinned Mac lane table: ran on the r4 candidate underneath, not on the two fixes. Not sealed on this build.
  • The Windows PowerShell path of this exact installer: not run yet. The Mac step that runs the existing hostile-archive gate is in the repo.

A missing check is written as not run. It is not written as passed.

Get it

Download DHC v8. One installer, REMIX or ARCADE from the STYLE SELECT screen. Patch-only: it verifies your own clean Euro mvsc dump, refuses anything else, and writes a separate mvsc_dhc_v8.zip beside it. The v7 parity and roster installers stay in the archive with their checksums.

Work note

I confirmed the background fix by hand after the fixture said it worked, chose the tile-based meter change over the palette approach that had corrupted the stage, and set the rule that every check in the receipt names its own tier. AI agents built the fixture, traced the stalled script, wrote and withdrew the four earlier patches, produced the installer and the trailer, and drafted this post from the retained measurements.

This is an unaffiliated fan modification. Marvel vs. Capcom and its characters belong to their respective owners. The download contains patch data; you supply your own lawful game dump.

Written by Daniel Plas Rivera · 1,665 words · $34

ShareXLinkedIn