Metroid II: Return of Samus
Nintendo R&D1's 1991 side-view action-adventure for the Game Boy, read through alex-west's M2RoS disassembly.
On this page
The atlas reads Metroid II: Return of Samus through alex-west’s M2RoS disassembly, which reassembles the World release byte for byte1. Labels and comments cited here are the disassembly’s. Nothing here has been measured in the ROM yet.
Samus’s jump has no gravity. While A is held, she rises at a fixed 2 px per frame for up to 15 frames, or 3 px for up to 31 with the Hi-Jump Boots2. A table then moves her a whole number of pixels each frame through the top of the arc and the fall3. She walks at a steady 1.5 px per frame, and the Varia Suit raises it to 24.
A hit gives 51 frames5 of invincibility5 and throws Samus along a fixed arc away from the enemy6. A jump press during that arc starts a jump in midair and ends the invincibility7.
Samus can roll into the morph ball from the start8, and the Spring Ball lets the ball jump9. The Space Jump restarts a spin jump at a new press, but only during part of the fall10.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Jump | Table | a held linear rise, then one pixel step per frame from a 79-entry table |
| Variable jump height | Hold timer | A holds a 2 px/frame rise for up to 15 frames, 31 at 3 px/frame with the Hi-Jump Boots |
| Running | Instant | 1.5 px/frame from 1- and 2-pixel steps, 2 px/frame with the Varia Suit |
| Air control | Direct | 1 px/frame toward a held direction in a plain jump, none without |
| Hitbox | Points and a box | up to five points per side against the background, a box against enemies |
| Invincibility frames | Frame timer | a 51-frame timer that drops each time Samus is drawn |
| Knockback | Table arc | a fixed arc from its own table, 3 px/frame up and 1 sideways, which a jump press cancels |
| Health upgrade | Whole containers | up to 5 energy tanks, each one refilling her energy |
| Ammunition | One pool | 30 missiles at the start, 10 more per missile tank, up to 999 |
| Morph ball | Spring upgrade | available from the start; the Spring Ball lets it jump |
| Space Jump | Window in the arc | a new press restarts a spin jump during 20 entries of the arc's fall |
| Screw Attack | Any spin | any spin jump, from its start pose |
| Status bar split | Window layer | the HUD is the window's bottom 8 lines, raised to 16 for save and item messages; the Queen's head takes the window in her room |
| Gravity | None | no gravity in a jump; the arc table sets every frame's step |
| Coyote time | None | running off a ledge starts a fall, and a fall jumps only just after an unmorph |
Every claim about this game, by concept (18)
References
- ^alex-west's M2RoS disassembly of Metroid II, assembled with rgbds, equals Metroid II - Return of Samus (World) byte for byte.Code“Metroid II - Return of Samus (World)” · alex-west/M2RoS
How we know
In the cartridge (“Metroid II - Return of Samus (World)”): bank 0 $184A, jumpArcTable, the bytes the jump claims below read. We don't reproduce the bytes.
13The resultant file should have this hash: `md5: 9639948ad274fa15281f549e5f9c4d87`readme.md line 13 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A jump sets
samus_jumpArcCounterto$31, or$21with the Hi-Jump Boots. While A is held and the counter is below$40,poseFunc_jumplifts Samus 2 px each frame, 3 with the boots, and adds 1 to the counter: up to 15 frames, or 31. Letting go sets the counter to$56, which the comment calls the start of the arc's falling portion. Before this,poseFunc_jumpStartlifts her 2 to 3 px a frame for up to 6 frames while A is held.Codealex-west/M2RoSHow we know
3328 ; High jump parameters 3329 ld a, samus_jumpArrayBaseOffset - $1F ;$21 3330 ld [samus_jumpArcCounter], a ⋮ 3337 ; Normal jump parameters 3338 ld a, samus_jumpArrayBaseOffset - $0F ;$31 3339 ld [samus_jumpArcCounter], a
SRC/bank_000.asm lines 3328–3339 at 031aea3 · upstream ↗ 3884 ; Check if in linear portion of ascent 3885 ld a, [samus_jumpArcCounter] 3886 cp samus_jumpArrayBaseOffset ⋮ 3892 ; Set speed, subtracting an extra 1 from it if we have high jump ⋮ 3901 ; If A is not pressed, start falling portion of arc 3902 ld a, samus_jumpArrayBaseOffset + $16 ;56 3903 ld [samus_jumpArcCounter], a
SRC/bank_000.asm lines 3884–3903 at 031aea3 · upstream ↗ 3937 ; Increment jump counter 3938 ld a, [samus_jumpArcCounter] 3939 inc a 3940 ld [samus_jumpArcCounter], a
SRC/bank_000.asm lines 3937–3940 at 031aea3 · upstream ↗ 4206poseFunc_jumpStart: ;{ 00:19E2 - $09 and $0A - Starting to jump 4207 ; Check if A is pressed ⋮ 4211 ; Move up 2 pixel/frame, with an extra pixel 2 out of 4 frames ⋮ 4224 ; Increment jump-start counter ⋮ 4228 ; Branch ahead if counter has expired 4229 cp $06
SRC/bank_000.asm lines 4206–4229 at 031aea3 · upstream ↗ 26def samus_jumpArrayBaseOffset = $40SRC/constants.asm line 26 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Past the held ascent, a jump follows a table: each frame
poseFunc_jumpmoves Samus by the next entry ofjumpArcTable, a signed whole number of pixels from 2 up to 3 down, and the$80that ends the table starts a fall.Codealex-west/M2RoSHow we know
3906 ; Get vertical speed from jumpArcTable 3907 sub samus_jumpArrayBaseOffset 3908 ld hl, jumpArcTable ⋮ 3913 ; Start falling pose if at the end of the table 3914 cp samus_jumpArrayBaseOffset + $40 ;$80 3915 jr z, .startFalling
SRC/bank_000.asm lines 3906–3915 at 031aea3 · upstream ↗ 3927.moveVertical: 3928 call samus_moveVertical
SRC/bank_000.asm lines 3927–3928 at 031aea3 · upstream ↗ 4857samus_moveVertical: ;{ 00:1D4E - move down 4858 ; Move up if negative 4859 bit 7, a 4860 jr nz, .moveUp
SRC/bank_000.asm lines 4857–4860 at 031aea3 · upstream ↗ 3991; Jump arc table 3992; - This starts being referenced when the jump counter is $40 ⋮ 3994jumpArcTable: ;{ 00:184A - Jump arc table 3995 db $fe, $fe, $fe, $fe, $ff, $fe, $ff, $fe, $ff, $ff, $ff, $ff, $ff, $ff, $00, $ff ⋮ 3999 db $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $03, $80
SRC/bank_000.asm lines 3991–3999 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Walking has no speed variable to build up:
samus_walkRightadds 1 or 2 px to Samus's X position on alternate frames (1.5 px/frame), 2 px/frame with the Varia Suit, and 1 px/frame in water.Codealex-west/M2RoSHow we know
4596 ld b, $01 4597 ; Check if touching water ⋮ 4605 ; Varia walking speed 4606 ld b, $02 ⋮ 4609 ; Normal walking speed (1.5 px/f) 4610 ldh a, [frameCounter] 4611 and $01 4612 add $01 4613 ld b, a ⋮ 4616 ; Move Samus right 4617 ldh a, [hSamusXPixel] 4618 add b
SRC/bank_000.asm lines 4596–4618 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abAn enemy hit sets
samusInvulnerableTimerto$33(51), and while it is above 0 the hit code returns before any damage.drawSamustakes 1 from it each time it draws her, once per frame of play, and blinks her 4 frames on, 4 off.Codealex-west/M2RoSHow we know
7802 ; Exit if i-frames are active 7803 ld a, [samusInvulnerableTimer] 7804 and a 7805 ret nz ⋮ 7810 ; Give Samus i-frames 7811 ld a, $33 7812 ld [samusInvulnerableTimer], a
SRC/bank_000.asm lines 7802–7812 at 031aea3 · upstream ↗ 560drawSamus: ;{ 01:4BD9 Draw Samus ⋮ 562 ; Check if damage frames are active 563 ld a, [samusInvulnerableTimer] 564 and a 565 jr z, .endIf_A 566 dec a 567 ld [samusInvulnerableTimer], a 568 ; 4 frames on, 4 frames off
SRC/bank_001.asm lines 560–568 at 031aea3 · upstream ↗ 740 call drawSamus_longJump ; Draw SamusSRC/bank_000.asm line 740 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A hit sends Samus away from the side of the enemy she touched along a fixed arc from
.bombArcTable, 3 px a frame up at first, and 1 px a frame sideways. She can't change direction until the arc's counter reaches$56, which the comment calls the end of the rising portion.Codealex-west/M2RoSHow we know
7824 ; Set travel direction to damage boost direction 7825 ld a, [samus_damageBoostDirection] 7826 ld [samusAirDirection], a ⋮ 7832 ld [samusAirDirection], a ⋮ 7835 ; Set jump arc counter to base 7836 ld a, samus_jumpArrayBaseOffset
SRC/bank_000.asm lines 7824–7836 at 031aea3 · upstream ↗ 8840 ; If Samus was on the left side of the enemy ⋮ 8845 ; If so, change the damage boost value to the left 8846 ld a, $ff 8847 ld [samus_damageBoostDirection], a
SRC/bank_000.asm lines 8840–8847 at 031aea3 · upstream ↗ 2439poseFunc_bombed: ;{ 00:0F6C - $11: Bombed (standing) 2440 ; Load y speed from bombArcTable
SRC/bank_000.asm lines 2439–2442 at 031aea3 · upstream ↗ 2469 ; Don't let Samus change aerial direction during the rising portion of the knockback 2470 cp samus_jumpArrayBaseOffset + $16 ; $56
SRC/bank_000.asm lines 2469–2470 at 031aea3 · upstream ↗ 2525.bombArcTable: ; 00:0FF6 2526 db $fd, $fd, $fd, $fd, $fe, $fd, $fe, $fd, $fe, $fe, $fe, $fe, $fe, $fe, $ff, $fe
SRC/bank_000.asm lines 2525–2529 at 031aea3 · upstream ↗ 2491 ; Move right if applicable 2492 ld a, [samusAirDirection] 2493 cp $01 2494 jr nz, .endIf_F 2495 call samus_moveRightInAir.noTurn
SRC/bank_000.asm lines 2491–2495 at 031aea3 · upstream ↗ 4785.noTurn: ; 00:1CFA Alternate entry 4786 ; Set speed 4787 ld a, $01 4788 ld b, a
SRC/bank_000.asm lines 4785–4788 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^During knockback a jump press clears
samusInvulnerableTimerand starts a jump in the air with a ground jump's counter,$31or$21.Codealex-west/M2RoSHow we know
2350poseFunc_hurt: ;{ 00:0EF7 - $0F - Knockback 2351 ; Go to "bombed" pose handler if jump is not pressed ⋮ 2355 ; Do a mid-air jump ⋮ 2361 ; Clear i-frames 2362 xor a 2363 ld [samusInvulnerableTimer], a ⋮ 2366 ld a, samus_jumpArrayBaseOffset - $1F ;$21 ⋮ 2375 ld a, samus_jumpArrayBaseOffset - $0F ;$31
SRC/bank_000.asm lines 2350–2376 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^The morph ball needs no item: a Down press while crouching calls
samus_morphOnGround, and the item bits list bombs, Hi-Jump, Screw Attack, Space Jump, Spring Ball, Spider Ball, and Varia, with no bit for the ball. A new game starts with no item bits set.Codealex-west/M2RoSHow we know
3705; Handle down input 3706 ; Rising edge 3707 ldh a, [hInputRisingEdge] 3708 bit PADB_DOWN, a 3709 jr z, .endIf_L 3710 call samus_morphOnGround
SRC/bank_000.asm lines 3705–3710 at 031aea3 · upstream ↗ 4524samus_morphOnGround: ;{ 00:1BA4 4525 ; Set pose 4526 ld a, pose_morph 4527 ld [samusPose], a
SRC/bank_000.asm lines 4524–4527 at 031aea3 · upstream ↗ 49def itemMask_bomb = %00000001 ; 01: Bombs ⋮ 53def itemMask_spring = %00010000 ; 10: Spring ball 54def itemMask_spider = %00100000 ; 20: Spider ball 55def itemMask_varia = %01000000 ; 40: Varia suit 56def itemMask_UNUSED = %10000000 ; 80: Unused
SRC/constants.asm lines 49–56 at 031aea3 · upstream ↗ 20 db $00 ; Samus' equipmentSRC/data/initialSave.asm line 20 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^In the morph ball, A starts a jump only with the Spring Ball, from a counter of
$2E.Codealex-west/M2RoSHow we know
3780 ; Handle spring ball 3781 ; Check if A is pressed 3782 ldh a, [hInputPressed] 3783 bit PADB_A, a 3784 jr z, .endIf_C 3785 ; Check if we have spring ball 3786 ld a, [samusItems] 3787 bit itemBit_spring, a 3788 jr z, .endIf_C 3789 ; Set jump parameter 3790 ld a, samus_jumpArrayBaseOffset - $12 ;$2e
SRC/bank_000.asm lines 3780–3793 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^In a spin jump with the Space Jump, a new A press restarts the jump only on frames whose
spaceJumpTableentry is nonzero: entries 44 to 63, wherejumpArcTablefalls 1 to 3 px a frame. The restart sets the counter to$28, or$18with the Hi-Jump Boots, below$40, so a held A gives a new linear ascent.Codealex-west/M2RoSHow we know
4002; Space Jump Table 4003; - $00 means no space jumping on that frame 4004; - Non-zero values mean that you can space jump on that frame ⋮ 4006spaceJumpTable: ;{ 00:1899 ⋮ 4009 db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $02, $01, $02, $02 4010 db $02, $02, $03, $02, $02, $03, $02, $02, $03, $02, $03, $02, $03, $02, $03, $02 4011 db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $80
SRC/bank_000.asm lines 4002–4011 at 031aea3 · upstream ↗ 3997 db $00, $01, $01, $00, $01, $01, $01, $01, $01, $01, $02, $01, $02, $01, $02, $02 3998 db $02, $02, $03, $02, $02, $03, $02, $02, $03, $02, $03, $02, $03, $02, $03, $02
SRC/bank_000.asm lines 3997–3998 at 031aea3 · upstream ↗ 4014poseFunc_spinJump: ;{ 00:18E8 - $02: Spin jumping ⋮ 4016 ldh a, [hInputRisingEdge] ⋮ 4023 ; If jump timer is > $40, then jump ahead 4024 ld a, [samus_jumpArcCounter] 4025 cp samus_jumpArrayBaseOffset 4026 jr nc, .endIf_B 4027 ; Handle linear ascent of the jump ⋮ 4030 bit PADB_A, a ⋮ 4034 ld a, [samusItems] ⋮ 4053 ; Skip ahead if not holding jump 4054 ldh a, [hInputRisingEdge] 4055 bit PADB_A, a ⋮
SRC/bank_000.asm lines 4014–4078 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Sources
Code
- 1991. “Metroid II - Return of Samus (World).” · licence, all uses
- alex-west. 2026. “M2RoS: Return of Samus Disassembly.” Commit 031aea3. alex-west/M2RoS @ 031aea3 · licence, all uses