| Air control | | | | | |
| Ammunition | uses | | | - Samus has one missile count and one power bomb count, each with a maximum. A missile tank adds 5 to both the missile count and its maximum, unless the maximum would pass 255; a power bomb tank adds 2 to both, up to 254. The missile types the downloads add (super, ice, and diffusion missiles, flags in
weaponsStatus) draw on that one count. Zero Mission keeps separate counts for missiles, super missiles, and power bombs, and its missile tank also adds 5, or 2 on Hard. Code
| - Missiles, super missiles, and power bombs each have their own maximum and count, and each tank adds to both: 5 missiles, 2 super missiles, or 2 power bombs on Easy and Normal, and 2, 1, or 1 on Hard, from a start of 0 (mzm/start-energy). Missile tanks stop adding past 50 tanks' worth, 250 missiles, or 100 on Hard (computed). Metroid has missiles only, and its tank adds 5 to both the count and the capacity. Code
|
| Coyote time | | | | | |
| Damage formula | | | | | |
| Gravity | | uses | | - Out of liquid,
SamusUpdatePhysics sets the vertical acceleration to 6 and the vertical speed cap to 128, and SamusUpdateVelocityPosition takes 6 from yVelocity on every frame of the airborne poses while the velocity is above -220, whether A is held or not: 0.1875 px/frame², with rises and falls both capped at 4 px/frame (computed). In water, lava, or acid without the Gravity Suit or the flag the decompilers name SMF_SA_X_SUIT, the acceleration drops to 4 and the cap to 48, 0.125 px/frame² and 1.5 px/frame. Zero Mission's gravity is 10, 0.3125 px/frame², with the same 4 px/frame fall cap (computed). Code
| - Out of liquid (or in it with the Gravity Suit) and not held by a Metroid,
SamusUpdatePhysics sets the vertical acceleration to 10 each frame, and SamusUpdateVelocityPosition takes it from yVelocity on every frame of the airborne poses while the velocity is at least -231, whether A is held or not: 0.3125 px/frame² (computed). A fall moves at most 128, 4 px/frame. In water, lava, or acid without the Gravity Suit, or out of liquid in a Metroid's grip, the acceleration halves to 5 and both caps drop to 40, 1.25 px/frame. Metroid's jump gravity is 0.09375 px/frame² (0.0703 with the High Jump Boots), and its falls reach 5 px/frame. Code
|
| HDMA | | | - In rooms whose water is set to wave, an indirect HDMA channel writes BG2's X scroll on every line. Above the water each line points at the plain scroll; below it the lines walk through a ring of 16 values, the scroll plus a displacement of 0, 1, 1, 0, 0, −1, −1, 0 repeating, so the background ripples a pixel either way in an 8-line pattern that shifts one line every 6 frames. Code
- The Ceres haze is an indirect HDMA table on the sub-screen backdrop color, used for color math. Its first entry covers 64 lines and 15 more cover 8 lines each; while the room fades in, the routine raises the bands' intensities over 16 frames, ending with 0 at the top and 1 to 15 in the bands below, a gradient down the screen. Code
| | |
| Health upgrade | | | | - When
SamusInit runs with no file loading (gIsLoadingFile clear) and an unnamed flag, gUnk_3000be3, clear, it copies sEquipment_Empty into gEquipment: 99 energy of 99, 10 missiles of 10, 10 power bombs of 10, and no weapon flags (MBF_NONE). The atlas reads this as a new game's start. Zero Mission starts with the same 99 energy, but with every ammunition count at 0. Code - An energy tank adds 100 to Samus's maximum energy and sets her energy to the new maximum, unless the new maximum would pass
MAX_ENERGY_AMOUNT, 20 tanks plus the starting 99, or 2099. The tank code reads no difficulty. Zero Mission's tank also adds 100 and refills, or 50 on Hard, and stops at 12 tanks: 1299 on Easy and Normal and 699 on Hard (computed). Code
| - When a game starts rather than loads a file (
gIsLoadingFile clear), SamusInit fills gEquipment with zeros and then sets Samus's maximum and current energy to 99, so she starts with 99 energy, no tanks, and no missiles, super missiles, or power bombs. Metroid starts her with 30 units. Code - On Easy and Normal an energy tank adds 100 to Samus's maximum energy, and on Hard 50, and sets her energy to the new maximum. A tank adds nothing if the maximum plus one more tank would pass 12 tanks plus the starting 99, so the maximum is 1299, or 699 on Hard (computed). In Metroid each tank holds 100 units, up to 6 tanks and 699.9 units, with the same refill. Code
|
| Hitbox | | | | | |
| Invincibility frames | - A hit sets
SamusBlink to $32, which is 50, gives Samus an upward speed of $FD with the hit gravity $38, and takes the push direction from the hit; the comment says "Set blink for 32 frames". Code - Each frame, the crash detection skips the contact check between Samus and the enemies while
SamusBlink is above 0. Code CheckHealthStatus, which Samus's routines call once per frame, lowers SamusBlink by 1 each time, so the blink lasts 50 frames of game logic. Code- Measured in the ROM, a crawler held against Samus in Brinstar's first room takes 8 units with each hit, and the next hit lands 50 game frames later; one of the two gaps also held 2 lag frames, for 52 frames of video. Verified
- In lava, Samus's blink is set to 50 on every frame, so enemies can't touch her, while the lava takes 0.7 units twice every 8 frames without a push; the Varia suit cuts that to once, and
SubtractHealth halves it to 0.3 units. Code
| | | | |
| Item drop table | - When an enemy dies, a
RandomNumber1 below 16 drops nothing; otherwise its low 3 bits pick from ItemDropTbl, which holds a missile at 0 and 3, energy at 1, 4, and 6, and $89 at 2, 5, and 7. Code - Item
$89 drops only for an enemy whose byte in the area's table at $968B has bit 0 set, and Samus collects it as 20 units of energy; the table's comment calls it "No item". Code - Each door re-rolls the room's caps from
RandomNumber1, 0 to 15 missile drops and 64 to 94 energy drops, and zeroes the counts. A drop that would pass its cap is lost; one that passes the test adds to its count, even a $89 roll that the enemy then can't drop. Code - Until the first door, the caps on missile and energy drops are 39 when the game starts in Brinstar, because
SamusInit stores the mirroring value $27 into them, or 47 ($2F) elsewhere. Code - A small energy ball gives Samus 5 units and a
$89 ball 20; a missile gives 2 missiles; an enemy whose data index carries the 30-unit flag gives 30 units or 30 missiles instead. Code - In Tourian, enemies with data index 2 or 4 drop nothing, and any other kill that would drop nothing resets both caps to 1 and both counts to 0 and rolls the same
RandomNumber1 again, skipping the test for 16. Code - Called in the ROM for all 256 values of
RandomNumber1, the drop code gives a Brinstar enemy of data index 0 60 missiles, 90 small energy balls, 90 $89 balls, and 16 nothing; index 3, whose byte in the table LF74B reads ($968B + data index, kept in $00) has bit 0 clear, gives 106 nothing and no $89. Verified
| | | - Touching an absorbable X parasite runs
SamusAbsorbX, which refills by its color: a red X (SSC_RED_X_PARASITE) 500 energy, 100 missiles, and 10 power bombs; a green X 2 missiles; any other (yellow) X 10 energy. SpriteUtilRefillSamus adds missiles only once a missile flag is set and power bombs only once the power bomb flag is, and stops each at its maximum. Code - When a dying sprite's countdown ends,
SpriteDying sets its pose to 0x5B (the decompilers' SPRITE_POSE_TURNING_INTO_X) unless it is a secondary sprite, and an enemy's AI (Choot's, for one) runs XParasiteInit in that pose. The X it becomes takes its color from a number from 1 to 1024, made from the low 2 bits of gSpriteRandomNumber and the 8-bit frame counter, against three weights in that sprite's row of sPrimarySpriteStats: the top red-weight values give red and the next green-weight values green, each only when its weight is above 0, and everything left below the green bound gives yellow, whatever the yellow weight is, unless it is 0, which deletes the X instead. A would-be green X turns yellow when missiles are full and energy isn't, or Samus has no missiles yet; a would-be yellow X turns green when energy is full and missiles aren't. An X from a core X is green when gSpriteRandomNumber is below 5 or that energy test holds, and otherwise yellow; an X placed in a room is yellow. All of this applies only to an X whose sprite property is SSP_X_ABSORBABLE_BY_SAMUS: one marked SSP_X_UNABSORBABLE_BY_SAMUS, or the unnamed SSP_UNKNOWN_40, is always yellow, and any other property deletes the X. Code
| |
| Jump | - Every jump takes off with the whole part of Samus's vertical speed at
$FC, 4 px/frame up. The High Jump Boots change the gravity, not the speed: SetSamusJump sets SamusGravity to $18, or $12 with the boots. Code - A jump from a standstill starts after the press frame's move:
SamusStand calls SetSamusData, which moves her, and then SetSamusJump, so she first rises on the next frame. A running jump's handler calls SetSamusJump (LCD40) before SetSamusData, so she rises on the press frame, and there it sets her top speed for the jump, SamusHorzSpdMax, to $12. Code - Moving down, and not in the ball, Samus stops when
MoveSamusDown finds a solid tile under her: StopVertMovement clears her vertical speed, SamusGravity is set to 0, and the frame goes on to her horizontal move. A jump from a standstill ends on the next frame: SamusJump finds SamusGravity at 0 and calls StopHorzMovement, which stops her and makes her stand, so she doesn't move that frame, and a jump press then does nothing, since the jumping handler starts a jump only in lava. In the ball (sa_Roll), a landing halves her downward speed and turns it upward, a bounce, until the halved whole speed is 0 and she stops. Code - Blocked moving up, Samus's vertical speed, whole byte and fraction, is shifted right one bit with the sign bit set (
sec, ror ObjVertSpeed, ror VertCntrLinear). An upward speed is halved and stays upward, though the comment says the shift reverses her direction. The rest of that frame's rise is dropped. Each later frame that would still move her up is blocked and halved again, until gravity turns her speed downward. Code
| | | - A jump sets Samus's upward
yVelocity to 170 (SAMUS_LOW_JUMP_VELOCITY), or 220 with the High Jump, with no separate suitless speed. The velocity counts eighths of a subpixel and a pixel is 4 subpixels, so these are 5.3125 and 6.875 px/frame (computed). Movement caps the velocity at 128 (16 subpixels, 4 px), so a jump's first 8 frames each rise 4 px, and a High Jump's first 16 (computed). Zero Mission's jump takes off at 192, or 232 with the High Jump, under a cap of 192: 6 px/frame from the first frame. Code - Stepping the code's arithmetic with A held, out of liquid, a jump from the ground peaks about 71 px up (283 subpixels) on its 28th frame, and a High Jump 104 px (416 subpixels) on its 36th (computed: each frame moves
yVelocity capped at 128 and shifted right 3, then takes 6 from it). The same stepping gives Zero Mission about 59 px on the 19th frame and 83 px on the 23rd (mzm/jump-height), so Fusion's jump is higher and slower. Code
| - A jump sets Samus's upward
yVelocity to 192 (SAMUS_LOW_JUMP_VELOCITY), 232 with the High Jump active, or 212 without the suit, which is checked first. The velocity counts eighths of a subpixel and a pixel is 4 subpixels, so these are 6, 7.25, and 6.625 px/frame (computed). Movement caps the velocity at 192 (24 subpixels, 6 px), so the High Jump's first five frames each rise 6 px (computed). Metroid's jump always takes off at 4 px/frame, and its High Jump Boots lower the gravity instead of raising the speed. Code - Stepping the code's arithmetic with A held, out of liquid, a jump from the ground peaks about 59 px up (235 subpixels) on its 19th frame, and a High Jump about 83 px (331 subpixels) on its 23rd (computed: each frame moves
yVelocity capped at 192 and shifted right 3, then takes 10 from it). Code
|
| Knockback | | | | | |
| Morph ball | | - 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. Code - In the morph ball, A starts a jump only with the Spring Ball, from a counter of
$2E. Code
| | | |
| Password and battery save | - Metroid's password holds 18 bytes; bytes 0-7 carry one bit for each of 59 items, doors, and Tourian objects collected, byte 8 the starting area (bits 0-5) and whether Samus wears her suit (bit 7), byte 9 her equipment, byte 10 her missile count, bytes 11-13 her age, byte 15 the Kraid and Ridley statue and defeat bits, byte 14 a copy of the RAM byte after the age, which nmikstas labels unused, byte 16 a scramble count, and byte 17 a check byte. Code
- Metroid writes the 18 bytes as 24 characters of 6 bits each, three bytes to every four characters, from a 64-symbol set of 0-9, A-Z, a-z, ?, and -; the entry grid's 65th symbol, a space, enters as $FF, all 8 bits set. Code
- To make a password, Metroid sums bytes 0-16 into byte 17, then rotates bytes 0-15 right as one 128-bit number, one bit at a time, as many times as byte 16 says; byte 16 is the low 4 bits of a random byte, redrawn until it is not 0. Code
- When the player presses Start, Metroid rebuilds the 18 bytes from the 24 characters, rotates bytes 0-15 back left by byte 16's count, and compares their sum with byte 17; on a mismatch it plays the wrong-password sound and shows ERROR TRY AGAIN for 120 frames, and on a match it starts the game; nothing else in the password is checked. Code
- Metroid compares the first 16 characters entered with NARPASSWORD00000 before anything else and, on a match, sets a flag and ignores the rest; while that flag is set, the game engine writes $03 to Samus's health high byte, $FF to her equipment byte, and 5 to her missile count, every frame. Code
- If Mother Brain has been destroyed when Metroid makes a password, it clears her bit and every Tourian bit in bytes 6 and 7, so the password brings back Mother Brain, the zebetites, and Tourian's missile doors. Code
- Computed from the decoder's lines, the password JUSTIN BAILEY ------ ------ passes; after 255 rotations, its bytes 0-16 sum to $FF mod 256, which equals its check byte, byte 17, and byte 8's bit 7 is set, which the game loads as Samus without her suit. Code
| | | | |
| Random number generator | | | | | |
| Raster effects | | | uses | | |
| Running | - On the ground Samus accelerates at
$30/256 (0.1875) px/frame² toward SamusHorzSpdMax/16 px/frame, which VertAccelerate sets to $18 (1.5 px/frame) while she is grounded. With no direction held, StopHorzMovement clears her horizontal speed at once. Code - From a standstill, the first frame with Left or Right held doesn't move Samus.
SamusStand picks the running state, calls SetSamusData, which moves her at her speed of 0, and only then calls SetSamusRun, which sets her acceleration. Her speed rises from the next frame. Code - Running on the ground, Left or Right against Samus's facing turns her and sets the acceleration toward the new side on that frame, through
SetSamusRun, but leaves her speed as it is. She slows by 0.1875 px/frame each frame, passes 0, and speeds up the other way: from 1.5 px/frame, 16 frames to 1.5 px/frame the other way (computed). Code - On the ground, the running handler checks Samus's animation before it reads A or the d-pad (
LCDBF). Unless it is the running animation (or, with Up held, running and aiming up), it sets that animation and skips the rest of the handler for the frame. A jump press or a released d-pad on that frame is ignored, and she accelerates toward her facing. That happens on her first frame on the ground after a running jump or a fall, and on the frame after a turn: SetSamusRun gives Samus the running animation only if her animation was standing (an_SamusStand), and otherwise the running-and-aiming-up animation (an_SamusRunPntUp). Code
| | | | |
| Screw Attack | | | | | |
| Space Jump | - Samus's gear byte,
SamusGear, has one bit each for the bombs, High Jump, Long Beam, Screw Attack, Maru Mari, Varia, Wave Beam, and Ice Beam: all eight bits, none for a Space Jump. Code
| | | | |
| Status bar split | | | | | |
| Variable jump height | | | | | - On any frame Samus rises (
yVelocity above 0) without A held, the mid-air handlers set yVelocity to 0, at any height: SamusMidAir, SamusTurningAroundMidAir, and SamusSpinning, which runs the spin jump, the Space Jump, and the Screw Attack. The check is each handler's last step, so a frame whose earlier branch returns, such as a Space Jump or wall jump press, skips it. Metroid lets a release stop the rise only after 32 px. Code
|
| Wall jump | uses | | | | |