Cite as
SMB2 Discombobulated
Original
https://github.com/Xkeeper0/smb2
Pinned
Xkeeper0/smb2 @ b73415e1953d7fdffd4957d5fb43fa7a13844c1c
Accessed
2026-10-21
Licence
none stated
Credit
Disassembly and comments by Xkeeper and kmck, with contributions through the project's pull requests. It builds the USA PRG0 and PRG1 releases and Super Mario USA.
Notes
Each character's jump speeds, gravities, and run speeds are a stats table in src/prg-a-b.asm; the player's physics are in src/prg-0-1.asm. Velocities are 4.4 fixed point (ApplyPlayerPhysics).

Cited on

Claims (41)

Super Mario Bros. 2's cartridge ROM (USA, PRG0), counted by part of the game: each stretch of code or data goes to the part its code shows it serves, and the value sums the bytes of each part.smb2.asm L89–160Code
Super Mario Bros. 2 keeps speeds as 4.4 fixed point; ApplyPlayerPhysics takes whole pixels from a speed's upper nibble.src/prg-0-1.asm L3003–3021Code
PlayerStartJump first checks quicksand: sunk with QuicksandDepth 2 or more, the player takes off at JumpHeightQuicksand, $E0 for all four (quicksand), and the table is skipped. Otherwise it picks the take-off speed from the character's table by three bits: running (horizontal speed of $08 or more), a charged crouch (CrouchJumpTimer at $3C), and holding an item. A charged jump clears the running bit.src/prg-0-1.asm L2535–2588Code
Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area (probes/super-mario-bros-2/movement.mjs), empty-handed Mario's jumps leave the ground at -5 standing, -5.625 running, and -6.5 px/frame from a charged crouch, and each frame adds 0.25 px/frame with A held and 0.4375 without: MarioStats' $B0, $A6, and $98, and its gravities $04 and $07. With an item, see carry-stats.src/prg-a-b.asm L271–290Verified
Luigi takes off far slower but falls under a far lighter gravity. Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area, empty-handed, his jumps leave the ground at -2.625 standing, -3 running, and -3.4375 px/frame charged, and each frame adds 0.0625 px/frame with A held and 0.125 without: LuigiStats' $D6, $D0, and $C9, and its gravities $01 and $02. With an item, see carry-stats.src/prg-a-b.asm L321–343Verified
PlayerGravity adds the character's lighter gravity on any frame the jump button is held and the heavier one otherwise, and adds none once a fall has reached $39 (3.5625 px/frame). The last add can carry the fall past that, up to $3F (3.9375 px/frame) under a gravity of $07. Two branches come first: sunk in quicksand (QuicksandDepth 2 or more), the routine adds GravityQuicksand, $08 for all four (quicksand), at any speed; and while the Princess floats, it sets her speed outright from FloatingYVelocity and adds nothing (float).src/prg-0-1.asm L2606–2659Code
The Princess's Floating Time is $3C; the other three have 0. With the button held once her rise has slowed to -$04 or less, each frame sets her vertical speed from FloatingYVelocity, cycling up, still, down, still, until the timer runs out. Letting go ends the float for that jump. Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area, a jump with A held floats for 60 frames, holding each speed of the cycle for 8 frames, and then falls.src/prg-a-b.asm L346–360src/prg-0-1.asm L2619–2656src/prg-0-1.asm L2662–2666Verified
Holding B raises the top speed by half: running right with nothing carried, from $18 to $24 (1.5 to 2.25 px/frame). Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area, all four characters run right at 1.5 px/frame and, with B, 2.25 px/frame.src/prg-0-1.asm L2848–2856Verified
The run button's half is added to whatever cap applies, the carrying speed (carry-speed) or quicksand's $04 as well as the unladen $18. To the left the cap is negative, and halving it with the carry set rounds it away from zero: a cap of $EB to the left becomes $E0, where $15 to the right becomes $1F.src/prg-0-1.asm L2848–2856src/prg-0-1.asm L2865–2872Code
Health is $0F for one mark of the life meter and $10 more for each further mark, up to $3F for four. A hit takes $10, one mark, and sets DamageInvulnTime to $7F, during which DamagePlayer returns at once; the timer drops every frame. If the health left is $10 or more, two marks or more, the hit also launches the player upward at $C0 and sideways at four times the screen distance from the enemy. A hit on the last mark (health under $10) stores no health and sets no invulnerability: it turns the enemy toward the player (for the types before Enemy_BeezoDiving), stuns it for $10 frames, sets the player's vertical speed to $C0 and PlayerStateTimer to $20, and jumps to KillPlayer, which sets the dying state and health to 0. A dying player holds still for those 32 frames, then rises at $C0 and falls back, gaining $02 a frame up to $39, and loses a life once below the screen.src/prg-2-3.asm L11362–11388src/prg-e-f.asm L3171–3177src/ram.asm L291–298src/prg-2-3.asm L11404–11439src/prg-e-f.asm L5154–5159src/prg-0-1.asm L1995–2014src/defs.asm L270–274Code
Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area, empty-handed Toad's jumps leave the ground at -4.875 standing, -5.1875 running, and -6.5 px/frame charged, and fall under Mario's gravity, 0.25 px/frame a frame with A held and 0.4375 without: ToadStats' $B2, $AD, and $98, and $04 and $07. With an item, see carry-stats.src/prg-a-b.asm L296–318Verified
Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area, the empty-handed Princess's jumps leave the ground at -4.8125 standing, -5.25 running, and -6.5 px/frame charged, and fall under Mario's gravity, 0.25 px/frame a frame with A held and 0.4375 without, apart from her float (float): PrincessStats' $B3, $AC, and $98, and $04 and $07. With an item, see carry-stats.src/prg-a-b.asm L346–368Verified
Each character's stats table holds a second take-off for each kind of jump, used while carrying something. Standing, charged, and running, they are: Mario $B0, $98, $AA; Luigi $D6, $C9, $D4; Toad $B2, $98, $AD; the Princess $B3, $98, $B3. Against the empty-handed ones (mario-stats and the rest), an item lowers only the running jump: Mario's and Luigi's by $04, and the Princess's to her standing one; Toad's are unchanged. The same tables hold the ground caps, $18 empty-handed for all four, and carrying $18, $16, $1D, and $15 (carry-speed).src/prg-a-b.asm L271–290src/prg-a-b.asm L321–343src/prg-a-b.asm L296–318src/prg-a-b.asm L346–368Code
On ordinary ground, holding right adds $02 to the speed each frame, so a character reaches walking speed, $18 (1.5 px/frame), 12 frames from a standstill; with neither direction held the ground takes $03 a frame off the speed, to zero. Measured in Mesen (MesenCE 2.2.1) from power-on, on the floor at the bottom of 1-1's first area, each character reaches 1.5 px/frame in 12 frames from a standstill; letting go of everything at 2.25 px/frame drops the speed to the 1.5 cap at once, and friction stops the character 8 frames later.src/prg-0-1.asm L2424–2426src/prg-0-1.asm L2498–2519src/prg-0-1.asm L2668–2697Verified
Left and right push at the same $02 a frame in the air, and with neither held the air keeps the speed. Any push resets a crouch jump's charge (crouch-charge). Crouched on the ground, left and right do nothing, and the ground's friction slows the player. On ice the push comes on one frame in four and the friction on one in sixteen.src/prg-0-1.asm L2461–2495src/prg-0-1.asm L2498–2522src/prg-0-1.asm L2668–2697src/prg-0-1.asm L3210–3213Code
What the player carries sets the ground cap: an enemy, a mushroom block, or a POW block uses the character's carrying speed (Mario $18, Luigi $16, Toad $1D, the Princess $15), and anything else (vegetables, shells, coins, bombs, rockets, keys, potions) the empty-handed $18. Sunk 4 pixels or more into quicksand, every character's cap is $04. B raises each by half (run-cap).src/prg-0-1.asm L2823–2850Code
Pulling something up, from the ground or off an enemy's or a block's top, holds a first pose for 6 frames, then steps through six more poses whose waits are the character's pick-up speeds, read from last to first: Mario's and Luigi's 7, 4, 1, 2, 4, 0, Toad's 2, 1, 1, 1, 1, 0, and the Princess's 12, 6, 2, 4, 6, 0, a wait of 0 lasting one frame. A small vegetable or dug sand takes Toad's waits whoever pulls it. Measured in Mesen (MesenCE 2.2.1) from power-on, pulling the large vegetable on the ledge in 1-1's first area, Mario and Luigi lift for 25 frames, Toad for 13, and the Princess for 37.src/prg-0-1.asm L3627–3636src/prg-2-3.asm L11101–11103src/prg-0-1.asm L2036–2071src/prg-0-1.asm L2091–2105src/prg-a-b.asm L271–277Verified
B throws what the player carries, unless it is sand from digging. A bomb, rocket, mushroom block, POW block, key, or potion needs room in the tile ahead; enemies, vegetables, shells, and coins fly at once. Those fly forward at $30 (3 px/frame), rising at $08 (0.5 px/frame) if the player was moving at $08 or more and falling at $18 if not. The others fly forward at $30 level if the player was moving, and if standing are set down 16 px ahead, falling at $18.src/prg-0-1.asm L2880–2925src/prg-0-1.asm L2942–2985src/prg-0-1.asm L2800–2819Code
Holding Down on the ground charges the crouch jump for 60 frames, except on a flying carpet or in quicksand. Crouched on the ground, left and right do nothing; in the air, with Down held, they still steer. Let go of Down before then and the charge is lost; let go after and it is kept until left or right is pressed or the player jumps.src/prg-0-1.asm L2461–2495src/prg-0-1.asm L2516–2519Code
Standing in quicksand sinks the player at $01 a frame, or $08 in the fast kind, and sinking 12 pixels into the next row of tiles kills them. Sunk 4 pixels or more, they jump at $E0 (2 px/frame), fall under gravity $08, run no faster than $04 (carry-speed), and can't charge a crouch jump.src/prg-0-1.asm L7691–7698src/prg-0-1.asm L7721–7763src/prg-0-1.asm L2543–2550src/prg-0-1.asm L2607–2612Code
On a vine, chain, or ladder the player climbs up at $F0 (1 px/frame), down at $20 (2 px/frame), and sideways at 1 px/frame. Holding up and down together reads past the end of the table, the byte $A5, and sends the player up at 5.6875 px/frame. Holding left and right together reads past the end of the sideways table too, again a byte $A5, the first of HandlePlayerState_Climbing, and sets the sideways speed to 5.6875 px/frame to the left.src/prg-0-1.asm L2107–2131src/prg-e-f.asm L3328–3336Code
Every eighth enemy defeated, counted as it falls off the screen, comes back as a heart 96 px above where it left; stray bullets and bosses don't count, and the count carries over deaths until the level ends. A heart adds one mark, up to the meter's length.src/prg-2-3.asm L1023–1027src/prg-2-3.asm L1058–1083src/prg-2-3.asm L10942–10958src/prg-e-f.asm L1348–1358Code
A level has up to two Subspace mushrooms, each adding a mark to the life meter and refilling it. One taken stays taken, and the extra marks stay, through deaths until the level ends, a game over, or a warp, which set PlayerHealth to PlayerHealth_2_HP and PlayerMaxHealth to 0: a meter of two marks, both full.src/prg-6-7.asm L3747–3762src/prg-2-3.asm L3402–3407src/prg-e-f.asm L1348–1357Code
A thrown potion that lands makes a door in a puff of smoke, except in a vertical area, where only the smoke is left. Through the door, Subspace lasts 96 ticks of four frames, about 384 frames, and ends early if the player dies. Its grass gives coins on the level's first two visits that pull a coin, and small vegetables after.src/prg-2-3.asm L3553–3593src/prg-0-1.asm L4859–4860src/prg-2-3.asm L4831–4846src/prg-0-1.asm L5676–5683src/prg-0-1.asm L3811–3828Code
The fifth large vegetable pulled since the level began or the player last died is a stopwatch, and the count starts over.src/prg-0-1.asm L3604–3617src/prg-e-f.asm L1314–1318Code
The Bonus Chance after a level spins three reels of eight positions, one coin a spin. Each position holds one of four symbols: a Snifit, a turnip, a star, or a cherry. Each reel steps every 4 frames, and A stops the leftmost still spinning. A cherry on the first reel wins a life, cherries on the first two win two, three cherries five, and three of another symbol one; lives stop at 255. Each reel holds one cherry.src/defs.asm L248–251src/prg-e-f.asm L1652–1665src/prg-e-f.asm L1693–1732src/prg-e-f.asm L2114–2160src/prg-a-b.asm L580–607Code
Doki Doki Panic's disk holds Super Mario Bros. 2's character stats table, 92 bytes in the same layout. Mario's, Toad's, and the Princess's 23 bytes each equal the first, second, and fourth blocks on the disk. Luigi's block, the third, differs only in its six take-off speeds, each $02 lower in SMB2, so read as SMB2 reads them, Luigi leaves the ground 0.125 px/frame faster than the disk's block would. The four offsets before the table hold the same values, with the last two swapped.src/prg-a-b.asm L264–268src/prg-a-b.asm L321–333Code
Super Mario Bros. 2's manual gives B a third use, running faster, and its code raises the top speed by half while B is held (smb2/run-cap). Doki Doki Panic's manual gives B only lifting and throwing. Both manuals say every character runs at the same speed.src/prg-0-1.asm L2848–2856Manual
Both games have the charged crouch jump. Doki Doki Panic's manual says the character flashes while Down is held and then jumps about 1.5 times as high as a standing jump, and Super Mario Bros. 2's manual says the same of its power squat jump. SMB2's code charges it after 60 frames of crouching on the ground (smb2/jump-start).src/prg-0-1.asm L2482–2486Manual
Both games start the life meter at two marks and let it grow to four. Doki Doki Panic's manual says so, as does Super Mario Bros. 2's, whose code sets health from a table of three values, two to four marks, by the number of extra marks found, and sets two marks again when a level ends, on a game over, and on a warp.src/prg-e-f.asm L3314–3324src/prg-e-f.asm L1348–1352Manual
Super Mario Bros. 2 shrinks a character whose life meter is down to one mark. Chris Kohler's report on Kensuke Tanabe's talk says it was added because growing and shrinking was one of Mario's best-known traits. SMB2's cartridge keeps a full-size and a small tile bank for each character; Doki Doki Panic's disk has one tile file for each of its four, IMAJIN-C, LINA-C, MAMA-C, and PAPA-C, of 832 bytes.src/prg-0-1.asm L1925–1938src/defs.asm L784–791Interview
Doki Doki Panic's manual says the two children are saved only if the whole family beats Mamu, so each of the four must clear the last page. In Super Mario Bros. 2 the last level leads to the ending whichever character clears it; the end of each level adds one to the character's count of levels cleared, which the ending shows.src/prg-e-f.asm L1512–1529Manual
Super Mario Bros. 2's magic potion is Doki Doki Panic's magic lamp: in both manuals, the item thrown makes a door appear, and Up at the door enters the other side, Subspace in SMB2. SMB2's code turns a thrown potion into a door where it lands, except in a vertical area, where it puffs away.src/prg-2-3.asm L3553–3593Manual
Both games turn the grass on the other side into money for only two visits an area: medals in Doki Doki Panic's manual, coins in Super Mario Bros. 2's. SMB2's code counts a Subspace visit that pulled at least one coin, and after two, grass in Subspace gives small vegetables.src/prg-0-1.asm L3811–3823src/prg-e-f.asm L1258–1265src/prg-0-1.asm L3514–3521Manual
Super Mario Bros. 2's code puts a mushroom in Subspace that adds a mark to the life meter and refills it, where Doki Doki Panic's manual describes a heart. SMB2's manual names the mushroom in its item list, but its Subspace paragraph still calls it a heart that increases the life meter.src/prg-6-7.asm L5147–5158src/prg-2-3.asm L3402–3407Manual
Both games end a level with a Bonus Chance, and Doki Doki Panic's disk holds Super Mario Bros. 2's 24 bytes of slot-machine reels with two exceptions. Where SMB2's first reel has a turnip (its second symbol) and a Snifit (its fifth), the disk has $00, the value SMB2's code reads as a cherry, so that reel holds three of SMB2's cherry values on the disk and one in SMB2. A cherry on the first reel wins a life.src/prg-a-b.asm L581–589src/prg-e-f.asm L1692–1697Code
Both games have 20 levels in seven parts: Doki Doki Panic's manual calls them pages in seven chapters, and Super Mario Bros. 2's calls them areas in seven worlds. SMB2's table of each world's first level, three levels a world and two in the last, is on Doki Doki Panic's disk byte for byte.src/prg-e-f.asm L209–217Manual
Most of Super Mario Bros. 2's enemy tiles occur on Doki Doki Panic's disk: 234 of the 244 non-blank tiles in its four banks of world enemies occur in the disk's tile files, byte for byte, and 80 of the 122 in its two banks of common enemies. Of the 199 non-blank tiles in Doki's four character files, 2 occur in SMB2's CHR ROM. Tiles are counted as often as they occur.src/prg-e-f.asm L5781–5788Code
Super Mario Bros. 2's cartridge keeps Doki Doki Panic data that it never shows. The 24 bytes the disassembly calls MysteryData14439, copied to RAM and unused, are on Doki's disk unchanged, and so are the 32 bytes of sprite entries it labels as the heads of Imajin, Lina, Mama, and Papa. After the heads, SMB2 has a PPU write of 20 blank tiles ($FB) at $20C6, which the disassembly labels BonusChanceUnused_BONUS_CHANCE; the disk's write at the same place holds text (bonus-chance-text).src/prg-a-b.asm L381–387src/prg-a-b.asm L611–618src/prg-a-b.asm L621–627Code
Where Super Mario Bros. 2 writes 20 blank tiles at $20C6, Doki Doki Panic's disk writes 20 tiles that, decoded through SMB2's own letter codes, read "--- BONUS CHANCE ---", the text the disassembly's comment guessed from the write's place and length. This is a decode, not a byte match: the letters are SMB2's codes from its "NO BONUS", "PUSH (A) BUTTON", and title-card text, and how Doki Doki Panic draws its own text is unread.src/prg-a-b.asm L621–627src/prg-a-b.asm L631–636src/prg-a-b.asm L638–641src/prg-a-b.asm L676–690Code
Super Mario Bros. 2's ending still writes $80 to $4080, a sound register of the Famicom Disk System, which a cartridge game has no use for; the disassembly marks it as a leftover.src/prg-e-f.asm L1851–1855Code