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.
- Startup 6Winding up. The attack box comes out on frame 6.
- Active 6The attack box is out: anything it touches gets hit.
- Recovery 16The box is gone, but Ryu can't act until frame 28.
- 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
st.MP
StartupWinding up. The attack box comes out on frame 7.
- Startup
- Active
- Recovery
- Frozen
- Hitstun
- Can act
More on st.MPWhiff, hit and blockBoxes through time (3D)Attack record 1For wiki editors
- 22912+1+13–42912129
- 732433−5−98–932433132124
- 10shot3747−9−1110–1137471213741
- 221013003–4210131210
- 11219310−47–821931122119
- 961933Launches−414–1561933162119
- 22912+1+13–42912129
- 632432−5−97–832432132421
- 10shot4151−13−1510–1141511214141
- 521420−4−43–4214201214
- 781226+1−38–981226181221
- 10162045Knockdown−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
Tied fastest, with 1 otherst.LP, st.LK, cr.LP
11th best of 16, tied with 1 otherst.LP, cr.LP
4th fastest of 16, tied with 1 otherwalking forward
13th quickest of 16, tied with 1 otherneutral jump
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.
- 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
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.
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
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:
- start16Damage byteRyu's st.HP, record +$00
- × 38/3219Damage levelthe board's factory setting
- × 31–33/3218–19Random31, 32 or 33: a quarter, half and quarter of the time
- × 32/32 each18–19Damage taken, combo scaling and gutsRyu at round start, first hit, full life
- 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.
- Base damage +$008
- Damage level× 38/329
- Random× 31, 32, 33 /328–9
- Defender damage taken× 32/328–9
- Combo hit 1× 32/328–9
- 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
- Damage level, a game setting: 34, 38, 44 or 48 over 32. A factory-default board uses 38.
- Attacker power, 32/32 at the start of a match.
- Random: the record's
+$01picks a row of 32 entries; row 0, used by normals, is 31, 32 or 33 (a quarter, half and a quarter of the time). - 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.
- 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+$04bit 5 set use a gentler table at$0E9BBA. - Guts: a defender below 96, 32 or 16 life takes 30, 20 or 16 thirty-seconds. This step only
applies to records whose
+$04high nibble is 0 or has bit 4 set. - 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
- Gambit142
- War Machine124
- Wolverine121
- Chun-Li118
- Spider-Man116
- Strider116
- Morrigan116
- Captain America107
- Captain Commando105
- Jin104
- Mega Man104
- Ryu102
- Venom90
- Roll89
- Hulk81
- 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
| Character | Walk forward | Walk back | Jump frames | Jump height | Forward reach | Super jump frames | Super jump height | Damage taken |
|---|---|---|---|---|---|---|---|---|
| War Machine | 3 | −2.5 | 46 | 124 | 138 | 71 | 315 | 103% |
| Captain America | 2.5 | −2 | 44 | 107 | 154 | 95 | 353 | 97% |
| Hulk | 2 | −1.5 | 42 | 81 | 105 | 79 | 293 | 88% |
| Wolverine | 3 | −2.5 | 47 | 121 | 165 | 87 | 361 | 109% |
| Gambit | 3 | −2.5 | 51 | 142 | 120 | 82 | 361 | 103% |
| Venom | 2.25 | −2 | 43 | 90 | 107 | 70 | 243 | 97% |
| Spider-Man | 3 | −2.5 | 43 | 116 | 151 | 86 | 337 | 106% |
| Roll | 3 | −2.5 | 46 | 89 | 107 | 103 | 332 | 109% |
| Ryu | 4 | −3 | 45 | 102 | 144 | 81 | 320 | 100% |
| Captain Commando | 4 | −3 | 41 | 105 | 123 | 82 | 323 | 100% |
| Chun-Li | 5 | −4 | 49 | 118 | 135 | 85 | 333 | 106% |
| Jin | 2.5 | −2 | 44 | 104 | 114 | 81 | 320 | 100% |
| Zangief | 2 | −1.75 | 33 | 72 | 99 | 70 | 267 | 91% |
| Strider | 3.5 | −3 | 43 | 116 | 151 | 86 | 337 | 106% |
| Morrigan | 3.25 | −2.75 | 46 | 116 | 155 | 81 | 320 | 109% |
| Mega Man | 3.5 | −3 | 47 | 104 | 104 | 103 | 332 | 106% |
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.
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:
- start$20Character IDMega Man
- ÷ 216Entryone slot per character in each directory
- $0E68AE + 16 × 4$0E68EESlot in movepropthe attack-record directory
- read the long$0F6852Attack tableMega Man's 80 records, 32 bytes each
- + 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.
- +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.
The directories, the records, and the same tables in MSH vs. SF and X-Men vs. SF
| Directory | Base | Points to |
|---|---|---|
moveprop | $0E68AE | attack records, 32 bytes each |
anim | $0E676C | the animation tree |
hitbox | $0E6852 | box rows, 16 bytes each |
boxshape | $0E67F6 | box rectangles, $3A0000 + entry × $800 |
| palettes | $1C7268 | palette 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 group | What it holds | MvC2 group |
|---|---|---|
| 0 to 6 | walking, jumping, dashing, crouching, turning, blocking, air blocking | the same numbers |
| 7 | three animations with no attack box; MvC1 only | none |
| 8 | standing punches | 7 |
| 9 | standing kicks | 8 |
| 10 | crouching punches | 9 |
| 11 | crouching kicks | 10 |
| 12 | air punches | 11 |
| 13 | air kicks | 12 |
| 16 | throws | 15 |
| 21 | command and alternate normals | 20 |
| 22 | special moves | 21 |
| 23 | hyper combos | 22 |
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.
| Offset | Size | What it is |
|---|---|---|
+$00 | word | attribute. Bit 7 of the low byte keeps the frame moving during hitstop, bit 6 and the low nibble steer it there |
+$02 | word | hold: bits 0 to 14 are how many updates the frame stays up; bit 15 marks the last frame |
+$04 | long | the sprite list |
+$08 | long | unknown; when the low 5 bits of byte +$0A are set, the game calls a routine as the frame loads |
+$0C | word | unknown |
+$0E | word | the 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 offset | What it holds |
|---|---|
+$0C, +$10 | x and y, 16.16 fixed point |
+$14, +$1C | horizontal and vertical speed |
+$34, +$3C, +$3E | current frame, its attribute, its countdown |
+$52 | character ID |
+$70 to +$7F | the current box row |
+$80 | the attack record index |
+$85 | hitstop counter |
+$8C | the record that last hit this fighter |
+$B0 | action ($28 a normal, $2A a special, $24 guarding, $36 hitstun, $04 a jump starting) |
+$120 | hit counter for combo scaling |
+$270, +$274 | life (144 at full) and meter level |
| Address | What it holds |
|---|---|
$FF4000 | game phase ($0800 during a fight) |
$FFF95E | damage level setting |
$FFF960 | game 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
$0000C0to$FFFFand 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.