referenceUpdated Oct 25, 202621 min read$43

MvC1 Frame Data for 16 Characters, Measured in the Game and Read From the ROM

Startup, active, recovery and frame advantage for every MvC1 ground normal, each character's command list with its specials and hypers measured, walk and jump values, and the damage formula. Measured in a running game, checked against the ROM's own tables, and downloadable as CSV and JSON.

Help shape what comes next ↓
cps2marvel-vs-capcommvc2frame-datahitboxes
CPS-2 Reverse EngineeringPart 54 of 54
Browse all writing
On this page

A community request asked a fair question: how much of MvC1's character data is understood, and could anyone get real numbers out of it? MvC2 has a public attack-data reference. MvC1 had nothing like it. Now it does.

Reading a frame meterRyu's st.MP. One square is one frame, a sixtieth of a second.
  1. Startup 6Winding up. The attack box comes out on frame 6.
  2. Active 6The attack box is out: anything it touches gets hit.
  3. Recovery 16The box is gone, but Ryu can't act until frame 28.
  4. Frame 28Ryu can act again.

−5 on block means the opponent acts 5 frames first.

Minus isn't always bad: it's only punishable when the gap is at least as long as the opponent's fastest move takes to come out.

Try any normal in the training room

Pick a fighter and a button, then press play or tap the screen. Whiff, Hit, Block changes what happens; Setup changes the opponent, their stance, the distance and the speed. Call it is a quick quiz: plus, safe or punishable?

Mega Man

Marvel
Capcom

st.MP

StartupWinding up. The attack box comes out on frame 7.

Mega Man3frozen 823
Ryufrozen 11hitstun 18
  • Startup
  • Active
  • Recovery
  • Frozen
  • Hitstun
  • Can act
More on st.MPWhiff, hit and blockBoxes through time (3D)Attack record 1For wiki editors
Sort
  • 22912+1+13–42912129
  • 732433−5−98–932433132124
  • Shot10shot3747−9−1110–1137471213741
  • 221013003–4210131210
  • 11219310−47–821931122119
  • Super jump cancel961933Launches−414–1561933162119
  • 22912+1+13–42912129
  • 632432−5−97–832432132421
  • Shot10shot4151−13−1510–1141511214141
  • Low521420−4−43–4214201214
  • Low781226+1−38–981226181221
  • Low10162045Knockdown−1714–15162045116212041

Frame 1 is the move's first frame, and Total is its length in frames. Advantage is Ryu's first free frame minus the attacker's, so plus means you act first; the bars share one scale of ±24 frames, and longer ones are cut. Damage is the range the random step allows at the default damage level, on Ryu at round start. Mega Man is character $20, measured against Ryu on the stock game (MAME set mvsc) at Normal speed. Pick a move to play it in the training room above.

How Mega Man compares with the cast

Fastest normal2f

Tied fastest, with 1 otherst.LP, st.LK, cr.LP

Best normal on block+1

11th best of 16, tied with 1 otherst.LP, cr.LP

Walk speed3.5px/f

4th fastest of 16, tied with 1 otherwalking forward

Jump, time in the air47f

13th quickest of 16, tied with 1 otherneutral jump

Damage taken106%

10th lowest of 16, tied with 3 othersat round start

Get the data

Download mvc1-frame-data.zip: one folder per character, the movement and damage tables, and a README on how each number was measured. The scripts that rebuild it from a stock mvsc.zip are in the harness I use for these ports.

For wiki editors: Customize in the training room switches startup to the count the MvC2 reference and SuperCombo use (the frames before the attack box) and move names to 5LP or Jab, Strong and Fierce. Share copies a link, a picture, or a filled-in AttackData-Marvel vs Capcom block.

Every number was checked twice

I measured each move in the running game, then worked the same number out from the ROM's tables without running anything. Where the two agree, the tables are understood.

The ROM's tables predict the running game 90 to 100% of the time
  • Normals' timing, read from the animation data: 280 of 28897%

    The other 8 are moves whose code takes over the animation. They use the measured number.

  • First hit frame, from the boxes: 185 of 191 ground normals97%

    The other 6 hit with something they spawn, not with a box on the fighter.

  • Attacker's recovery after a hit or block: 352 of 37494%

    Two-hit normals freeze twice, and two moves' code runs their animation.

  • Normals' damage inside the formula's range: every hit100%

    178 normals that hit once, and each hit of the 9 that hit twice.

  • Specials' and hypers' hits inside the formula's range: 654 of 68296%

    The rest go through damage steps the formula here leaves out.

  • Walk and jump table values: 415 of 41699.8%

    War Machine's forward super jump leaves at half its table speed.

  • Commands found by trying every input: 109 of 12190%

    The other 12 need a mode or a distance, or share an animation with another command.

How the measuring runs worked

I ran the stock Euro 980123 program in a headless build of FBNeo (the core Fightcade uses) and drove it with ordinary inputs, the way a player would:

  • Normal speed. With factory settings my runs played at a Turbo speed, which adds an extra logic tick every few frames and makes frame counts drift. The game reads its speed setting from $FFF960; I set it to Normal before the match.
  • Ryu as the dummy, standing, with player 1 on the left. "Close" means walking forward until the gap stops shrinking.
  • Frame 1 is the first frame of the move. An input made on one frame shows on the next, for attacks, jumps and walking alike, so that delay cancels out.
  • When can each side act again? Player 1 holds back after the move; holding back can't cancel anything, so the first frame player 1 walks is the end of the move. Player 2 holds up from the frame after contact, so the first frame player 2 starts a jump is the end of its stun.
  • Advantage is player 2's first free frame minus player 1's.

One detail matters for blockstun. The last few frames of the guard animation can be cancelled into a jump or an attack but not into walking, so a dummy that just holds back looks stuck for about six frames longer than it really is. The jump probe catches the true end.

Launchers and knockdowns are labelled as such. Their "advantage" is the time until the opponent lands or gets up, which is not what anyone means by plus or minus.

The animation data already holds the timing

Each animation frame stores how long it stays up and which box row it uses. Add up the holds, mark the frames whose row has an attack box, and you have startup, active and recovery without running the game. Here is one move's boxes, frame by frame:

Venom's standing HP, boxes through time

Startup
13
Active
8
Recovery
42
Total
62
Venom's standing HP: 8 animation frames over 53 game frames. The 3D view stacks each frame's boxes along a frame axis; the slice shows one frame's boxes to scale.
Frame 13 of 53Attack box outkeeps moving while frozen

Pixels on the 384-wide screen, measured from where the fighter stands; forward is right. This move's code runs its animation, so the game takes 62 frames; the stack shows the animation's 53.

Venom's standing HP has two attack boxes on frames 13 to 17, then one reaching 240 pixels on frames 18 to 20. The tendril's own hurt box (dashed) stays stretched out to 217 pixels until frame 36, long after the attack box is gone.
The two rules, the 8 exceptions and the contact check

Two rules make the static reading work:

  • An attack box is in slot 0 of the box row, or in slot 1 when that slot's flag bits are clear. Slot 1 normally holds a flagged box that isn't an attack.
  • The last frame of an animation is followed by a pointer. When the last hold runs out, the engine jumps there, usually back to the start of the loop. A normal move ends at that point because its state code sees the end.

For air normals the reading covers startup and active frames, since landing ends them. The 8 normals it misses are moves whose code takes over the animation: War Machine's and Venom's standing HP, Captain Commando's standing HK, Jin's standing MK and HK, crouching MK and HK, and jumping LK. Some loop until the code stops them; others end on a landing or link to another animation. For those, the measured number is the right one, and the training room's frame meters follow it.

The boxes also say when a move connects. Stand Ryu in his idle stance (animation group 0, number 0) with the two push boxes touching, the way the measuring runs left him, and find the first frame whose attack box overlaps one of his hurt boxes. For 185 of the 191 ground normals with a measured hit, that is the frame the running game hit on. The other 6 have no attack box on the fighter at all: War Machine's standing and crouching HP and MK and Mega Man's standing and crouching HP hit with something they spawn.

That check is narrower than it sounds. At point blank all 185 touch on their first attack-box frame, so it confirms where the boxes sit (with the attacker left unmirrored, none of them touch at all), not how far they reach. The training room uses the same rule to move Ryu back until a move stops reaching him, and to crouch him (crouching idle is group 3, number 1), so its reach and crouching results are what the boxes predict, not measured. By the boxes, six standing normals never touch a crouching Ryu: War Machine's, Captain America's, Gambit's, Zangief's and Morrigan's standing LP, and Gambit's standing HP.

Hitstop doesn't freeze everything

A hit freezes both fighters, but some animation frames keep moving through the freeze, so the attacker can recover sooner than the hitstop value says. Mega Man's standing MP has 11 frames of hitstop and only gets 8 frames longer:

Mega Man's standing MP

Startup
7
Active
3
Recovery
24
Hitstop
11
On hit
−5
On block
−9
standing MP: startup 7, active 3, recovery 24, total 33, −5 on hit, −9 on block, 8–9 damage. Whiff: 1–6 startup, 7–9 active, 10–33 recovery; acts on frame 34. On hit: Mega Man 1–6 startup, 7–9 active, 10 recovery, 11–18 hitstop, 19–41 recovery, acts on 42; Ryu 7 stun, 8–18 hitstop, 19–36 stun, acts on 37. On block: Mega Man acts on 42; Ryu acts on 33.
The hit lands on frame 7. Mega Man's animation keeps moving through frames 8 to 10 (the dots), then freezes on frame 11 for 8 frames. Ryu is frozen for the full 11.
The routine, and the two attribute bits that decide it

The reason is in the routine that runs while a fighter's hitstop counter (+$85) is non-zero:

; stock mvsc, decrypted CPU view; a6 = the attacker
$0145A4  move.b  $3D(a6),d5        ; low byte of the frame's attribute word
$0145A8  bpl.b   $0145D6           ; bit 7 clear: stay frozen
$0145AA  movea.l $34(a6),a4
$0145AE  jsr     $001DD8           ; bit 7 set: advance the animation one tick
$0145B4  cmp.b   $3D(a6),d5        ; did that load a frame with a different attribute?
$0145B8  beq.b   $0145D6
$0145BA  btst    #6,d5
$0145BE  bne.b   $0145D8           ; bit 6: jump by the low 6 bits instead
$0145C0  andi.w  #$F,d5            ; low nibble n
$0145C4  beq.b   $0145D6           ; 0: carry on into the new frame
$0145C6  subq.w  #1,d5             ; otherwise go back n - 1 frames
...

So each frame decides for itself:

  • Bit 7 of the frame's attribute word keeps it moving during hitstop. Mega Man's standing MP sets it on its two active frames, which play out before the freeze starts.
  • The attribute's low nibble makes the frame loop during hitstop instead of moving on. Captain America's standing LP sets it on its active frame, so his fist stays out for the whole freeze and the move gets the full 10 frames longer.

Those two rules reproduce the attacker's measured recovery on 352 of 374 hits and blocks. The 22 they miss belong to 11 normals: the 9 that hit twice, which freeze twice, and Captain Commando's standing HK and Jin's crouching HK, whose code runs the animation.

Damage is one byte through a chain of multipliers

The attack record's damage byte isn't the damage you see. The routine at $01C952 runs it through a chain of multipliers:

Ryu's st.HP: 16 in the record, 18 to 19 off the life barEach step multiplies by a table value over 32 and rounds down.
  1. start16Damage byteRyu's st.HP, record +$00
  2. × 38/3219Damage levelthe board's factory setting
  3. × 31–33/3218–19Random31, 32 or 33: a quarter, half and quarter of the time
  4. × 32/32 each18–19Damage taken, combo scaling and gutsRyu at round start, first hit, full life
  5. at least 118–19Life lostwhat the running game takes off

The same hit on Hulk, who takes 28/32 at the start of a round, does 15 to 16.

Work out any normal's damage, on anyone

From the record's damage byte to life lost

The routine at $01C952 multiplies by one table value over 32 per step and rounds down.

  1. Base damage +$008
  2. Damage level× 38/329
  3. Random× 31, 32, 33 /328–9
  4. Defender damage taken× 32/328–9
  5. Combo hit 1× 32/328–9
  6. Guts and minimum 1× 32/328–9

The random step: 32 equally likely entries, each shown as the damage it leads to

8 on 8 of 32 (25%)9 on 24 of 32 (75%)

The same move as hits 1 to 12 of a combo, with the usual scaling

Hit number, and the combo's total so farStriped: what the random step can add

Not modelled: the attacker's power (32/32 at the start of a match), states that scale damage further, and throws, which take another path. The defense level starts each round at 4; the game moves it with the life gap between the teams.

Every step's table, and the check against the game
  1. Damage level, a game setting: 34, 38, 44 or 48 over 32. A factory-default board uses 38.
  2. Attacker power, 32/32 at the start of a match.
  3. Random: the record's +$01 picks a row of 32 entries; row 0, used by normals, is 31, 32 or 33 (a quarter, half and a quarter of the time).
  4. Damage taken: each character has a row of ten values. A round starts at level 4, where Ryu takes 32/32, Mega Man 34/32 and Hulk 28/32. The game moves that level with the life gap between the teams.
  5. Combo scaling by the hit number: 32, 32, 30, 28, 26, 20, 16, 14, 12, 10, 8, 6, 4, then 2. The row belongs to the attacker. The routine picks it through the defender's +$C4, which holds the opponent's ID, and Hulk's row is steeper: 32, 32, 30, 24, 20, 16, 12, 10, 8, 6, 4, 2, 1, then 0. Records with +$04 bit 5 set use a gentler table at $0E9BBA.
  6. Guts: a defender below 96, 32 or 16 life takes 30, 20 or 16 thirty-seconds. This step only applies to records whose +$04 high nibble is 0 or has bit 4 set.
  7. At least 1.

The check: all 178 normals that hit Ryu once land inside the predicted range, and so does each hit of the 9 that hit twice. For the multi-hit specials and hypers, 654 of 682 hits land inside it; the rest go through steps this model leaves out.

Walking and jumping: 415 of 416 values match

Three tables hold every character's walk speeds, jumps and super jumps. I checked all 416 values against the running game, and only one is off: War Machine's forward super jump leaves at 4 pixels a frame, not the table's 8. The chart uses what the game does.

Walking, jumping and taking damage, all 16 side by side

From the walk ($0E860A), jump ($0E877A) and super jump ($0E8F06) tables, in pixels and frames on the 384-pixel-wide screen. Mega Man is highlighted.

Jump height, in pixels, highest first

  1. Gambit142
  2. War Machine124
  3. Wolverine121
  4. Chun-Li118
  5. Spider-Man116
  6. Strider116
  7. Morrigan116
  8. Captain America107
  9. Captain Commando105
  10. Jin104
  11. Mega Man104
  12. Ryu102
  13. Venom90
  14. Roll89
  15. Hulk81
  16. Zangief72

Every jump, to scale

  • War Machine

    124 px high46 frames in air138 px forward138 px back

  • Captain America

    107 px high44 frames in air154 px forward132 px back

  • Hulk

    81 px high42 frames in air105 px forward105 px back

  • Wolverine

    121 px high47 frames in air165 px forward165 px back

  • Gambit

    142 px high51 frames in air120 px forward95 px back

  • Venom

    90 px high43 frames in air107 px forward107 px back

  • Spider-Man

    116 px high43 frames in air151 px forward172 px back

  • Roll

    89 px high46 frames in air107 px forward107 px back

  • Ryu

    102 px high45 frames in air144 px forward167 px back

  • Captain Commando

    105 px high41 frames in air123 px forward103 px back

  • Chun-Li

    118 px high49 frames in air135 px forward123 px back

  • Jin

    104 px high44 frames in air114 px forward109 px back

  • Zangief

    72 px high33 frames in air99 px forward99 px back

  • Strider

    116 px high43 frames in air151 px forward172 px back

  • Morrigan

    116 px high46 frames in air155 px forward158 px back

  • Mega Man

    104 px high47 frames in air104 px forward104 px back

Every value in one table
Walk, jump and damage-taken values for each character.
CharacterWalk forwardWalk backJump framesJump heightForward reachSuper jump framesSuper jump heightDamage taken
War Machine3−2.54612413871315103%
Captain America2.5−2441071549535397%
Hulk2−1.542811057929388%
Wolverine3−2.54712116587361109%
Gambit3−2.55114212082361103%
Venom2.25−243901077024397%
Spider-Man3−2.54311615186337106%
Roll3−2.54689107103332109%
Ryu4−34510214481320100%
Captain Commando4−34110512382323100%
Chun-Li5−44911813585333106%
Jin2.5−24410411481320100%
Zangief2−1.753372997026791%
Strider3.5−34311615186337106%
Morrigan3.25−2.754611615581320109%
Mega Man3.5−347104104103332106%

War Machine's forward super jump moves 4.0078125 pixels a frame across in the running game, not the table's 8; the drawing uses what the game does. Every other walk, jump and super jump value matches the table.

Where the movement tables are, and how they're stored

The values are 8.8 fixed point, in pixels per frame at the game's 384-pixel width:

  • Walk at $0E860A: forward and back, 4 bytes per entry.
  • Jumps at $0E877A: neutral, forward and back, each as vertical speed, gravity, horizontal speed and horizontal drag. 24 bytes per entry. The horizontal values are stored for a fighter facing left.
  • Super jumps at $0E8F06, same layout.

Mega Man's values are the same as in MvC2, where the reference lists them too. The check covered walk forward and back, and vertical speed, gravity, horizontal speed and drag for all three jumps and all three super jumps, for 16 characters. I haven't found what halves War Machine's forward super jump; in the game he leaves at 4 and slows by the table's drag.

Specials and hypers come from Capcom's own command list

MvC1 ships Capcom's symbol names. A table of PLnn_COM_C records at $0E648E points at the code that recognizes each character's commands, and each command is a short descriptor: the motion, the buttons, ground or air, and whether it's a hyper. So every command list here comes straight from the ROM, and the Specials tab in the training room shows it.

109 of 121 commands measuredOne square per command in Capcom's list.

Hollow squares weren't measured. Most need a mode first (Ryu's Ken and Akuma styles, Zangief's Iron Body) or a distance (Zangief's 360 hypers); the rest share an animation with another command.

How the commands were measured, and the 12 the search missed

The game jumps through a copy of those addresses at $018DF0, which also covers the secret characters. To measure the moves, I tried every common motion with every button and button pair, from far away and at point blank, then kept the inputs that started a special or hyper animation. Each one was measured like the normals, and the record that hit came from the dummy itself, since the game writes it there on contact.

That search reproduced 109 of the 121 commands. The 12 it missed need a mode (Zangief's Iron Body, Ryu's Ken and Akuma styles) or a particular distance (Zangief's 360 hypers), or they share an animation with another command, so the search couldn't tell them apart.

Two caveats for these rows. Damage is the life loss in one run, so it includes the random step, and hypers ran with the meter set to level 3.

For ROM hackers: where everything lives

Here's the game finding Mega Man's standing HK, one pointer at a time:

Mega Man's st.HK record is at $0F68F2Every table works the same way: a directory of pointers, one per character.
  1. start$20Character IDMega Man
  2. ÷ 216Entryone slot per character in each directory
  3. $0E68AE + 16 × 4$0E68EESlot in movepropthe attack-record directory
  4. read the long$0F6852Attack tableMega Man's 80 records, 32 bytes each
  5. + 32 × 5$0F68F2Record 5st.HK's attack data

IDs go up by 2, from War Machine at $02 to Mega Man at $20, and the secret characters follow. The other directories' bases are in the first section below.

The attack record is MvC2's, two bytes later. I lined Mega Man's and Strider's records up against their MvC2 rows and almost every column matched: MvC1 has two extra bytes right after Damage and stores two fields as words instead of bytes, 28 + 2 + 2 = 32.

Mega Man, attack record 5

$0F68F2, 32 bytes. Point at a byte or a field to link the two.

Mega Man record 5: 32 bytes at $0F68F2. The list gives every field with its value.
+00Damage13
Base damage. The damage formula multiplies it (see the damage section). MvC2 +00.
+01DamageRandomRow0
Picks one of 8 random-multiplier rows for the damage formula (& 7). 0 on normals. Not in MvC2.
+02unk023
3 on every normal. Not in MvC2.
+03HitReaction66
$00 RegularHitstun, $40 AirAttackHitstun, $08 SweepKD, as in MvC2. MvC2 +01.
+04BlockFlagseither
$04 must be blocked low, $02 must be blocked high, $00 either. MvC2 +02.
+05HitstunOrPushback??/DamageType11 / Normal
High nibble matches MvC2's HitstunOrPushback??; low nibble DamageType (0 Normal). MvC2 +03.
+06Undizzy1
4 / 2 / 1 for light / medium / heavy, as in MvC2. MvC2 +04.
+07Hitstop10
Frames both fighters stop on contact. The attacker keeps moving through frames whose attribute has bit 7 set. MvC2 +05.
+08unk0624
10 / 16 / 24, as in MvC2. MvC2 +06.
+09KDDuration0
0 on normals, as in MvC2. MvC2 +07.
+0AJuggleX0
Matches MvC2 on every row checked but one. MvC2 +08.
+0BJuggleY11
Matches MvC2. MvC2 +09.
+0CunkFlags0a128
112 / 128 / 96, as in MvC2. MvC2 +0A.
+0DHitsparkHeavy
0 / 1 / 2 = Light / Medium / Heavy. MvC2 +0B.
+0Eunk0c12
4 / 8 / 12, as in MvC2. MvC2 +0C.
+0FImpactSound22
Twice MvC2's number: an index into 2-byte entries. MvC2 +0D.
+10unk0e0
0, as in MvC2. MvC2 +0E.
+11unk0f50
20 / 40 / 50, as in MvC2. MvC2 +0F.
+12KeyFrameID28
A word in MvC1, a byte in MvC2. MvC2 +10.
+14unk11134
Also widened to a word. MvC2 +11.
+16flagsNoYBoost + LauncherVisualEffect
$04 NoYBoost, $40 LauncherVisualEffect, $80 FlyingScreenTrigger. MvC2 +12.
+17+17 to +1F00 00 00 00 00 00 00 00 00
Nine bytes not mapped yet. Their values don't line up with MvC2's last nine bytes either.
Mega Man's standing HK, the record the chain above lands on. The field names are the MvC2 reference's own, question marks included.
The directories, the records, and the same tables in MSH vs. SF and X-Men vs. SF
DirectoryBasePoints to
moveprop$0E68AEattack records, 32 bytes each
anim$0E676Cthe animation tree
hitbox$0E6852box rows, 16 bytes each
boxshape$0E67F6box rectangles, $3A0000 + entry × $800
palettes$1C7268palette data

These are data reads, and CPS-2 encryption only touches instructions, so the raw ROM bytes are the real values. The secret characters borrow: Red Venom, Gold War Machine, Shadow Lady and Lilith point at their base character's attack, box-row and box tables, and Orange Hulk has his own attack table. ID $00 has a full set of tables too, but no one on the select screen uses it.

Record n sits at the character's attack pointer + 32 × n. Records 0 to 17 are usually the normals, in MvC2's order (standing LP to HK, crouching, then air), with specials and hypers after them. Not always: Captain America's standing MP and HP, crouching LP, MP and HP and jumping MP and HP use records 18 to 24, Ryu's jumping MP uses 21 and 22, Captain Commando's standing HK 25 and Chun-Li's jumping HK 25 and 26. The second hit of a two-hit normal usually comes from a record past 24, and Mega Man's two buster normals hit with record 48, the shot's own. Select a move in the training room to see the record that hits.

Two fields are new since the first version of this map: +$01 picks the damage formula's random row (0 on every normal), and +$07 is hitstop, the value both fighters freeze for, though the attacker can keep moving through it.

MSH vs. SF uses the same formats. Its directories sit at $13775A (animation), $1377F6 (boxes), $13785E (box rows) and $1378C6 (attack records) in the US program, and its records have the same 32-byte layout, field for field. X-Men vs. SF's directories start at $08A946. Neither has been measured in a running game yet.

Animation groups, and the 16-byte animation frame

A character's animations hang off a two-level tree at its anim pointer: 31 group offsets, then a list of animations per group, then 16-byte frames. MvC1 has MvC2's groups plus one at 7.

MvC1 groupWhat it holdsMvC2 group
0 to 6walking, jumping, dashing, crouching, turning, blocking, air blockingthe same numbers
7three animations with no attack box; MvC1 onlynone
8standing punches7
9standing kicks8
10crouching punches9
11crouching kicks10
12air punches11
13air kicks12
16throws15
21command and alternate normals20
22special moves21
23hyper combos22

An earlier draft of this map said MvC1's extra group was 11. The running game says otherwise: the standing LP is animation 8/0, and the extra group is 7. Everything on this page uses the corrected numbers.

OffsetSizeWhat it is
+$00wordattribute. Bit 7 of the low byte keeps the frame moving during hitstop, bit 6 and the low nibble steer it there
+$02wordhold: bits 0 to 14 are how many updates the frame stays up; bit 15 marks the last frame
+$04longthe sprite list
+$08longunknown; when the low 5 bits of byte +$0A are set, the game calls a routine as the frame loads
+$0Cwordunknown
+$0Ewordthe box row for this frame

The routine that plays animations is at $001DD8. It counts the hold down at fighter +$3E, loads the next frame when it reaches zero, and follows the pointer after the last frame. A hold of 0 is loaded and replaced in the same update, so no one ever sees it.

Watching it live in the MAME debugger

Player 1's fighter is at $FF3000 and player 2's at $FF3400.

Fighter offsetWhat it holds
+$0C, +$10x and y, 16.16 fixed point
+$14, +$1Chorizontal and vertical speed
+$34, +$3C, +$3Ecurrent frame, its attribute, its countdown
+$52character ID
+$70 to +$7Fthe current box row
+$80the attack record index
+$85hitstop counter
+$8Cthe record that last hit this fighter
+$B0action ($28 a normal, $2A a special, $24 guarding, $36 hitstun, $04 a jump starting)
+$120hit counter for combo scaling
+$270, +$274life (144 at full) and meter level
AddressWhat it holds
$FF4000game phase ($0800 during a fight)
$FFF95Edamage level setting
$FFF960game speed setting (0 is Normal)
Read it yourself: a Python script for any character's normals

This needs Python 3 and a stock mvsc.zip. It prints every animation in the four ground-normal groups with its timing read off the animation data. A * marks frames with an attack box, and ! marks frames that keep moving during hitstop.

import sys, zipfile
 
PROGRAM = [('mvce.03a', 0x000000), ('mvce.04a', 0x080000), ('mvc.05a', 0x100000),
           ('mvc.06a', 0x180000), ('mvc.07', 0x200000), ('mvc.08', 0x280000),
           ('mvc.09', 0x300000), ('mvc.10', 0x380000)]
MOVEPROP, ANIM, HITBOX = 0x0E68AE, 0x0E676C, 0x0E6852   # one long per entry (entry = ID / 2)
GROUPS = {8: 'standing punches', 9: 'standing kicks', 10: 'crouching punches', 11: 'crouching kicks'}
 
def load_program(zip_path):
    rom = bytearray(0x400000)
    with zipfile.ZipFile(zip_path) as z:
        for name, base in PROGRAM:
            data = z.read(name)
            rom[base:base + len(data)] = data
    rom[0::2], rom[1::2] = rom[1::2], rom[0::2]   # members store each word byte-swapped
    return bytes(rom)
 
def u16(rom, a): return int.from_bytes(rom[a:a + 2], 'big')
def u32(rom, a): return int.from_bytes(rom[a:a + 4], 'big')
def table(rom, directory, char_id): return u32(rom, directory + (char_id // 2) * 4)
 
def animations(rom, char_id, group):
    """(index, first-frame address) for each animation in a group. A list ends where the
    next group's list or the first animation begins; an empty slot keeps its index."""
    base = table(rom, ANIM, char_id)
    offsets = [u16(rom, base + 2 * g) for g in range(31)]
    first = min(base + o + u16(rom, base + o) for o in offsets if o)
    start = base + offsets[group]
    end = min([base + o for o in offsets if o > offsets[group]] + [first])
    slots = [u16(rom, p) for p in range(start, end, 2)]
    return [(index, start + off) for index, off in enumerate(slots) if off]
 
def frames(rom, char_id, addr):
    rows = table(rom, HITBOX, char_id)
    while True:
        attr, ctrl, row = u16(rom, addr), u16(rom, addr + 2), u16(rom, addr + 14)
        s0, s1 = u16(rom, rows + row * 16), u16(rom, rows + row * 16 + 2)
        attack = bool(s0 & 0x1FFF) or (bool(s1 & 0x1FFF) and not s1 & 0xE000)
        yield ctrl & 0x7FFF, attack, bool(attr & 0x80)
        if ctrl & 0x8000:
            return
        addr += 16
 
def timing(shown):
    holds = [h for h, a, i in shown]
    act = [k for k, (h, a, i) in enumerate(shown) if a]
    if not act:
        return f'total {sum(holds)}'
    return (f'startup {sum(holds[:act[0]]) + 1}, active {sum(h for h, a, i in shown[act[0]:act[-1] + 1] if a)}, '
            f'recovery {sum(holds[act[-1] + 1:])}, total {sum(holds)}')
 
if __name__ == '__main__':
    rom = load_program(sys.argv[1])            # path to mvsc.zip
    char_id = int(sys.argv[2], 16)             # character ID in hex, e.g. 20 = Mega Man
    for group, label in GROUPS.items():
        for index, addr in animations(rom, char_id, group):
            shown = [f for f in frames(rom, char_id, addr) if f[0]]
            holds = ' '.join(f'{h}{"*" if a else ""}{"!" if i else ""}' for h, a, i in shown)
            print(f'{group}/{index} {label:18} {holds:30} {timing(shown)}')
    attacks = table(rom, MOVEPROP, char_id)
    print(f'attack records at ${attacks:06X}; record 0 is {rom[attacks:attacks + 32].hex()}')

Run it as python3 mvc1_frames.py mvsc.zip 20. The ID is hex; 20 is Mega Man. His first line shows 1 2* 4 2 3 with startup 2, active 2, recovery 9, total 12, the same as the training room at the top of the page. For most characters, animations 0, 1 and 2 of a group are the light, medium and heavy buttons. A few aren't: Captain America's standing HP (8/4), crouching MP and HP (10/4 and 10/5) and jumping MP and HP (12/6 and 12/7), Chun-Li's jumping HK (13/5), and Ryu's jumping MK and HK, which sit in group 21 (21/4 and 21/5). The training room shows the animation each move uses.

What's still open

  • Move names. The command lists give inputs, not names; the data pack has a column for them.
  • Box slot roles. Slots 2 to 5 act like hurt boxes and slot 6 like a push box. The hidden test menu's hit editor would name them (set the word at $0000C0 to $FFFF and switch the board to development mode).
  • Two-hit normals and code-driven moves, which are measured but not predicted.
  • Two damage steps: the attacker's power level during a match, and throws.
  • War Machine's forward super jump, which goes half as far as its table says.
  • MSH vs. SF and X-Men vs. SF, which share these formats but haven't been run yet.

If you work any of these out, or catch something here that's wrong, tell me and I'll update the post with credit.

Why the page looks like this

The layout borrows from recent research on reading charts and on attention. None of these papers tests a frame-data page or ADHD readers of articles, so each line says what was borrowed. The dates are arXiv upload dates.

  • Nothing moves until you ask. In Juicy Interactive Visualization (October 2026), the clearest engagement gains came from feedback after an interaction, not from stronger effects. The training room waits on its first frame.
  • Play stops on each phase. Cutting instructional videos into one-step segments with fixed pauses helped everyone in Leveling the Playing Field (July 2026), and helped learners with ADHD more. Loop plays straight through.
  • One line of setup. Removing distractions made videos easier to watch for viewers with ADHD in FocusView (July 2025), whose authors suggest keeping options few so adjusting them doesn't distract too. A study of r/ADHD posts (October 2026) found tools often demand the self-regulation they're meant to support, so nothing here needs setting first.
  • A sentence, then the chart. Text first led readers to confirm its claim, and a chart first led them to explore, in Multimodal Data Comprehension (July 2026, revised October). Chart titles shape what people see in them (Quick-View Takeaways, September 2026), so the titles here state the result.
  • One real case, step by step. Interactive worked examples beat passive ones in a February 2026 study. The frame meter, the damage chain and the pointer chain each follow one move.
  • The same colors everywhere. Under divided attention, designs that break expected mappings cost more time and accuracy (Divided Attention, August 2026). Startup is always green, active amber and recovery cyan, and a longer bar always means more frames.
  • Common words, one name per idea. Fewer words can still mean harder words: in an October 2026 comparison, shortened rewrites were predicted to take longer per word, because the words were longer and rarer.

These studies shape the presentation. They don't establish anything about MvC1; that comes from the ROM and the running game.

Community input · This article

What should I work on next?

Choose up to 3 priorities. No account needed.

Written by Daniel Plas Rivera · 4,679 words · $43

ShareXLinkedIn