Claim set · data/claims/metroid-save.yaml

Metroid's password (nmikstas's disassembly)

Game: Metroid.

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. metroid-save/layout

About: Metroid Password and battery save

Value
{
 "bytes": 18,
 "fields": [
  {
   "bytes": "0-7",
   "what": "item history, one bit per unique item (59)"
  },
  {
   "bytes": "8",
   "bits": "0-5",
   "what": "starting area (InArea)"
  },
  {
   "bytes": "8",
   "bits": "7",
   "what": "suitless Samus (JustInBailey)"
  },
  {
   "bytes": "9",
   "what": "SamusGear"
  },
  {
   "bytes": "10",
   "what": "MissileCount"
  },
  {
   "bytes": "11-13",
   "what": "SamusAge"
  },
  {
   "bytes": "14",
   "what": "SamusStat01 ($6880), a RAM byte labeled unused"
  },
  {
   "bytes": "15",
   "bits": "4-7",
   "what": "Ridley defeated, Ridley statue up, Kraid defeated, Kraid statue up"
  },
  {
   "bytes": "16",
   "what": "scramble count, 1-15"
  },
  {
   "bytes": "17",
   "what": "check byte, the sum of bytes 0-16"
  }
 ]
}
Codemetroid-disassembly: Metroid software disassembly · Source_Files/Metroid_Defines.asm#L615-L632.alias PasswordByte00 $6988 ;Stores status of items 0 thru 7. … .alias PasswordByte07 $698F ;Stores status of items 56 thru 58(bits 0 thru 2). .alias PasswordByte08 $6990 ;start location(bits 0 thru 5), Samus suit status (bit 7). .alias PasswordByte09 $6991 ;Stores SamusGear. .alias PasswordByte0A $6992 ;Stores MissileCount. … .alias PasswordByte0E $6996 ;Stores no data. .alias PasswordByte0F $6997 ;Stores Statue statuses(bits 4 thu 7). .alias PasswordByte10 $6998 ;Stores value RandomNumber1. .alias PasswordByte11 $6999 ;Stores sum of $6988 thru $6998(Checksum).metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1655-L1697L8C9E:* LDA InArea ;Store InArea in bits 0 thru 5 in … L8CA7: ORA #$80 ;Sets MSB of $6990 is Samus is suitless. L8CA9:* STA PasswordByte08 ; L8CAC: LDA SamusGear ; L8CAF: STA PasswordByte09 ;SamusGear stored in $6991. L8CB2: LDA MissileCount ; L8CB5: STA PasswordByte0A ;MissileCount stored in $6992. … L8CF2: STA PasswordByte0F ;Stores statue statuses in 4 MSB at $6997. … L8CF5: LDY #$03 ; …metroid-disassembly: Metroid software disassembly · Source_Files/Metroid_Defines.asm#L589-L592.alias SamusAgeLo $687D ;Low byte of Samus' age. … .alias SamusStat01 $6880 ;Unused memory address for storing Samus info.metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1549-L1560L8BDD: LDA #$3B ; L8BDF: STA $07 ;Maximum number of unique items(59 or #$3B).Checked by claude, 2026-10-22 — read CalculatePassword and the PasswordByte definitions at the pinned commit; the age loop runs Y from 3 to 0, so it copies four bytes, $687D-$6880, into bytes 11-14

nmikstas's comment on PasswordByte0E says it stores no data; the loop writes SamusStat01 there, and LoadPasswordData's matching loop copies it back. The item bits follow ItemData's order (Bank00.asm, from L9029), which mixes items, red doors, Mother Brain, and the zebetites. Byte 16's range of 1-15 is the encoder's; the decoder accepts any value there.

Cited by: Password and battery save

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. metroid-save/characters

About: Metroid Password and battery save

Value
{
 "characters": 24,
 "bitsPerCharacter": 6,
 "alphabet": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?-",
 "space": 255
}
Codemetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1884-L1885;The following code takes the 18 password bytes and converts them into 24 characters ;to be displayed to the player as the password. NOTE: the two MSBs will always be 0.metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1962-L1995SixUpperBits: L8F2D: LDA PasswordByte00,Y ;Uses six upper bits to create a new byte. … TwoLoAndFourUp: … FourLoAndTwoUp: … SixLowerBits: L8F5A: LDA PasswordByte00,Y ;Discard bits 6 and 7.metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L3016-L3034PasswordRow0: ; 0 1 2 3 4 5 6 7 8 9 A B C … PasswordRow4: ; q r s t u v w x y z ? - SpaceChecked by claude, 2026-10-22 — read LoadPasswordChar, its four bit-packing helpers, and the five rows of the entry grid at the pinned commit

Symbols 0-63 run 0-9, A-Z, a-z, ?, - in the grid's order. The screen shows the password as two lines of 12 characters, each split into two groups of 6 (CursorPosTbl).

Cited by: Password and battery save

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. metroid-save/checksum

About: Metroid Password and battery save

Value
{
 "check": "sum of bytes 0-16, mod 256",
 "scramble": "rotate bytes 0-15 right by n bits",
 "n": "1-15"
}
Codemetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1698-L1704L8D00:* JSR $C000 ; L8D03: LDA RandomNumber1 ; L8D05: AND #$0F ;Store the value of $2E at $6998 L8D07: BEQ - ;When any of the 4 LSB are set. (Does not L8D09: STA PasswordByte10 ;allow RandomNumber1 to be a multiple of 16). L8D0C: JSR PswrdChksmNScrmbl ;($8E17)Calculate checksum and scramble password.metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1835-L1866L8E17: JSR PasswordChecksum ;($8E21)Store the combined added value of L8E1A: STA PasswordByte11 ;addresses $6988 thu $6998 in $6999. L8E1D: JSR PasswordScramble ;($8E2D)Scramble password. … L8E25:* CLC ;Add the values at addresses L8E26: ADC PasswordByte00,Y ;$6988 thru $6998 together. … L8E3B:* ROR PasswordByte00,X ;Rotate right, including carry, all values in L8E3E: INX ;addresses $6988 thru $6997. … L8E42: ROR $00 ;Rotate right $6988 to ensure the LSB L8E44: LDA $00 ;from address $6997 is rotated to the …Checked by claude, 2026-10-22 — read PasswordChecksum and PasswordScramble at the pinned commit; traced the carry through one pass: byte 0's bits move toward byte 15, and byte 15's lowest bit becomes byte 0's highest

The check byte and the count are not scrambled, so the count is readable in characters 21 and 22 of every password.

Cited by: Password and battery save

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. metroid-save/reject

About: Metroid Password and battery save

Codemetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1625-L1637L8C5E: JSR ConsolidatePassword ;($8F60)Convert password characters to password bytes. L8C61: JSR ValidatePassword ;($8DDE)Verify password is correct. L8C64: BCS + ;Branch if incorrect password. L8C66: JMP InitializeGame ;($92D4)Preliminary housekeeping before game starts. L8C69:* LDA MultiSFXFlag ; L8C6C: ORA #$01 ;Set IncorrectPassword SFX flag. … L8C73: STA Timer3 ;Set Timer3 time for 120 frames (2 seconds).metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1818-L1825L8DF7:* JSR UnscramblePassword ;($8E4E)Unscramble password. L8DFA: JSR PasswordChecksum ;($8E21)Calculate password checksum. L8DFD: CMP PasswordByte11 ;Verify proper checksum. L8E00: BEQ + ; L8E02: SEC ;If password is invalid, sets carry flag.metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1868-L1882L8E4E: LDA PasswordByte10 ;Stores random number used to scramble the password. … L8E5A:* ROL PasswordByte00,X ;The following loop rolls left the first 16 bytesmetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L2274-L2276L9169: LDA Timer3 ; L916B: BEQ + ; L916D: LDA #$59 ;metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L809-L811;The following error message is diplayed if the player enters an incorrect password. ; E R R O R _ T R Y _ A G A I N L8759: .byte $0E, $1B, $1B, $18, $1B, $FF, $1D, $1B, $22, $FF, $0A, $10, $0A, $12, $17Checked by claude, 2026-10-25 — read CheckPassword, ValidatePassword, UnscramblePassword, and EnterPassword's message branch at the pinned commit; the message's bytes at L8759 spell ERROR TRY AGAIN in the password font's order (0-9 then A=$0A to Z=$23, $FF blank)

Timer3 counts down once every 10 frames (Metroid_Defines.asm, line 58), so its 12 is 120 frames. The decoder takes byte 16 as the count whatever it holds; at 0 the loop runs 256 times, a full turn of 128 bits twice, which leaves the bytes as they were.

Cited by: Password and battery save

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. metroid-save/narpassword

About: Metroid Password and battery save

Codemetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1806-L1833L8DE5:* LDA PasswordChar00,Y ; L8DE8: CMP NARPASSWORDTbl,Y ;If NARPASSWORD was entered at the L8DEB: BNE + ;password screen, activate invincible L8DED: DEY ;Samus, else continue to process password. … ;NOTE: any characters after the 16th character will be ignored if the first 16 characters ;match the values below. … ; N A R P A S S W O R D 0 0 0 0 0metroid-disassembly: Metroid software disassembly · Source_Files/Bank07.asm#L1592-L1599LC931: lda NARPASSWORD ; LC934: beq + ; LC936: lda #$03 ;The following code is only accessed if LC938: sta HealthHi ;NARPASSWORD has been entered at the LC93B: lda #$FF ;password screen. Gives you new health, LC93D: sta SamusGear ;missiles and every power-up every frame. LC940: lda #$05 ; LC942: sta MissileCount ;Checked by claude, 2026-10-22 — read ValidatePassword, NARPASSWORDTbl, and the top of GameEngine at the pinned commit

HealthHi's high nibble is the energy tank count and its low nibble the tens digit (metroid/health-format), so the $03 written each frame is no full tanks and a tens digit of 3; nmikstas's comment calls $FF in SamusGear every power-up. The path that sets the flag returns with the carry still set from the last comparison, so the first Start may report ERROR TRY AGAIN; that hasn't been run in the game.

Cited by: Password and battery save

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. metroid-save/mother-brain-reset

About: Metroid Password and battery save

Codemetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1647-L1654L8C8A: LDA PasswordByte07 ; L8C8D: AND #$04 ;Check to see if mother brain has been defeated, L8C8F: BEQ + ;If so, restore mother brain, zeebetites and L8C91: LDA #$00 ;all missile doors in Tourian as punishment for L8C93: STA PasswordByte07 ;dying after mother brain defeated. Only reset in the L8C96: LDA PasswordByte06 ;password. Continuing without resetting will not L8C99: AND #$03 ;restore those items. L8C9B: STA PasswordByte06 ;Checked by claude, 2026-10-22 — read CalculatePassword at the pinned commit

The game keeps bits 0 and 1 of byte 6, items 48 and 49, and clears the rest of byte 6 and all of byte 7.

Cited by: Password and battery save

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. metroid-save/justin-bailey

About: Metroid Password and battery save

Value
{
 "bytes": [
  166,
  243,
  142,
  164,
  185,
  101,
  36,
  169,
  209,
  127,
  255,
  255,
  255,
  255,
  255,
  255,
  255,
  255
 ],
 "sum": 255
}
Codemetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L2000-L2020L8F60: LDY #$00 ;Password characters #$00 and #$01. L8F62: JSR SixLowerAndTwoUpper ;($8FF1) L8F65: STA PasswordByte00 ;Store results.metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L2057-L2086SixLowerAndTwoUpper: L8FF1: LDA PasswordChar00,Y ;Remove upper two bits and transfer … FourLoNFiveThruTwo: … TwoLowerAndSixLower: L9011: LDA PasswordChar00,Y ;Shifts two lower bits to two higest bitsmetroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1868-L1882L8E4E: LDA PasswordByte10 ;Stores random number used to scramble the password.metroid-disassembly: Metroid software disassembly · Source_Files/Bank00.asm#L1712-L1716L8D1F: LDA PasswordByte08 ;If MSB in PasswordByte08 is set, L8D22: AND #$80 ;Samus is not wearing her suit. L8D24: BEQ + ; L8D26: INY ; L8D27:* STY JustInBailey ;Checked by claude, 2026-10-22 — reimplemented ConsolidatePassword, UnscramblePassword, and PasswordChecksum in JavaScript from the pinned lines and decoded the 24 characters JUSTINBAILEY------------ (the space in the usual spelling is the screen's gap between groups); not entered in the game

The decoded bytes also give a starting area of $11 (byte 8's low 6 bits), SamusGear $7F, 255 missiles, and all four statue bits. The 255 rotations are 127 more than a full turn of 128 bits.

Cited by: Password and battery save