The Hyper meter in arcade Marvel vs. Capcom stops at three levels. It stops there because of one instruction.
The cap is one byte
The meter lives on each fighter object: a level byte at +$274, and a
0..$90 fraction at +$272. The gain routine adds to the fraction, and every
time it crosses $90 it promotes one level:
$01CD58 moveq #$3,d1 ; <- the cap
$01CD5A cmp.b $274(a6),d1
$01CD5E ble.w $1cde6 ; already capped, no gain at all
...
$01CD74 add.w $272(a6),d0 ; gain + stored fraction
$01CD78 cmpi.w #$90,d0 ; one level costs $90
$01CD7C ble.b $1cd94
$01CD80 subi.w #$90,d0
$01CD84 addq.b #$1,$274(a6) ; level++
$01CD88 cmp.b $274(a6),d1
$01CD8C bgt.b $1cd94
$01CD8E move.b d1,$274(a6) ; clamp
$01CD94 move.w d0,$272(a6)moveq #$3,d1 becomes moveq #$5,d1. In the encrypted member that is the word
84CD becoming 81C7. That is the entire cap.
It is also the entire trap, because four other places arrived at "three" on their own.
The four places that also knew about three
Three of the four have no room to grow. The voice table at $01CDBE is
immediately followed by live code; the team-Hyper table at $016E2A is
followed by an rts that is a real branch target; the indicator table at
$006B9A has its index-4 slot occupied by a non-numeric state. Extending any
of them in place would overwrite something that runs.
The team-Hyper table did not need to exist. Its four entries are $0000,
$00C0, $0180, $0240 — level times $C0. The three instructions that read
it are exactly as long as three instructions that multiply:
; before, 10 bytes ; after, 10 bytes
move.w d0,d1 move.w d0,d1
add.w d1,d1 mulu.w #$c0,d1
move.w $16e2a(pc,d1.w),$50(a6) move.w d1,$50(a6)No hook, no payload, and it extends to five levels by construction.
The voice table got a private copy with a clamped index, so levels 4 and 5 announce with the level-3 sound rather than reading whatever bytes follow the original table.
The HUD was the part that could have needed art
The level indicator is a sprite. The drawing routine reads the level byte,
scales it by four, and pulls a tile code out of the table at $006B9A:
$006B4C move.b -$4d8c(a5),d5 ; P1 meter level
$006B52 tst.w -$3fcc(a5) ; special state?
$006B58 move.b #$4,d5 ; ...then index 4
$006B6E add.w d5,d5
$006B70 add.w d5,d5
$006B72 move.w $6b9a(pc,d5.w),d2 ; tile code
$006B76 movem.w d0-d3,(a0) ; x, y, tile, attributeThe table's tile codes are $6AB4, $6AB5, $6AB6, $6AB7 for levels 0 to 3.
Consecutive. That is a promising shape, but the first attempt to confirm it
decoded tile $6AB4 out of the graphics ROM and got a fragment of character
artwork, not a numeral.
The sprite engine adds $10000. Decoding $16AB4 instead:

So the answer to "does a five-level meter need new artwork" is no, and it was
answerable without running the game at all. $6AB8 draws 4 and $6AB9 draws
5, and a payload routine now computes $6AB4 + level instead of reading a
table that had no room for them.
The gauge bar itself needs nothing. It is nine tiles wide with sixteen fill
steps each — moveq #$8,d6 for the loop, cmpi.w #$10,d2 for the clamp,
$90 total, which is exactly one level. Levels do not add bars; the bar refills
and the numeral counts. Only the "the bar reads full" comparison had to move
from 3 to 5.
The trap that cost the most time
Two of the tables above are read PC-relative, like
move.w $6b9a(pc,d5.w),d2. One nearby table is read through an address
register, like movea.l (a2)+,a1.
On CPS-2 that distinction decides which bytes you are looking at. The 68000 uses program space for PC-relative addressing and data space for everything else, and the C-board decrypts program space only. So:
A table read PC-relative comes back decrypted. The identical bytes reached
through (a2)+ come back raw. In the HUD and meter code both kinds appear
within a few hundred bytes of each other. Read the wrong view and a perfectly
ordinary table looks like noise — or, worse, noise looks like a table.
The tell was a table of long pointers at $006F1C that reads as
E62A 48CB 3D5F 58A2 in the decrypted image and as 00006F40 00006F62 00006F62 00006F62 in the raw member. Clean pointers, in the raw view, for a
table the code reaches with movea.l (a2)+,a1. Once that is understood, the
tables that only make sense decrypted and the tables that only make sense raw
stop contradicting each other.
Every edit
- 1HUD — gauge and level indicator$000000–$007000 · 28 KBFull-bar threshold, special-state index, and the two indicator draw sites.
- 2team-Hyper meter value$007000–$017000 · 64 KB
- 3meter gain, cap and level-up voice$017000–$01D000 · 24 KB
- 4everything else — untouched by this feature$01D000–$100000 · 908 KB
- Athe cap$01CD58 · marker
- Bgauge full$006C4A · marker
- Clevel glyph$006B6E · marker
- Dteam value$016E08 · marker
| site | was | now |
|---|---|---|
$01CD58 | moveq #$3,d1 | moveq #$5,d1 |
$006C4A, $006C90 | cmpi.b #$3,d4 | cmpi.b #$5,d4 |
$006B58, $006BD8 | move.b #$4,d5 (special state) | move.b #$6,d5 — 4 is a real level now |
$006B6E, $006BEE | lea + the stock boolean | jmp to a payload routine that computes $6AB4 + level |
$006B8C, $006C0C | second table read | move.w d4,d2 — the routine left the frame tile there |
$01CDA8 | 4-entry voice table read | jmp to a clamped private copy |
$016E08 | 4-entry value table read | mulu.w #$C0,d1 |
$025B98–$025BAA, $0D45D6–$0D45E8 | grant-full writes 3 | writes 5 |
156 bytes of new payload in an existing $FF run. No member changes size.
How the edits were checked
There is no m68k assembler in the build environment, so every instruction was hand-encoded next to the mnemonic it is supposed to be:
Ins("0c400005", "cmpi.w #$5, d0"),
Ins("c0fc0060", "mulu.w #$60, d0"),
Ins("207c001861c0", "movea.l #$1861c0, a0"),and a verifier disassembles each one with capstone and refuses the build on any
mismatch. It has already earned its place twice: it caught move.w #$6BDA,d4
written where d2 was meant, and it caught a two-byte edit that had been
positioned in the middle of a four-byte instruction. Both would have shipped.
Afterwards a second pass reads the built ROM back, decrypts each edited address, and compares the plaintext to what the author wrote. Sixty-one checks, zero failures.
What this does not claim
Every claim above comes from the ROM: decrypted listings, raw preimages, decoded tile bitmaps, byte-exact round-trips. None of it comes from a long play session. A five-level meter also changes the game's economy — no Hyper cost was rebalanced, and the level-3 Hypers still cost three. That is a design decision left open, not an oversight.
The meter change rides inside the combined build alongside the Super-to-Super work and the six-color palette system. It is not a separate download.