Claim set · data/claims/contra.yaml

Contra (vermiceli's annotated disassembly of the US NES release)

Game: Contra.

While the title screen scrolls in, the US NES Contra compares each new d-pad, A, or B press with a ten-entry table, Up Up Down Down Left Right Left Right B A. A wrong press sets the count to $FF, which stops the check until the title starts over. The full sequence sets a flag, and a new game then gives each player 29 lives in reserve instead of 2: 30 lives instead of 3. contra/konami-code

About: Contra Cheat code

Value: 30 lives

CodeContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L749-L752game_routine_01: jsr konami_input_check ; check if current input is part of Konami code (30-lives code)Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L930-L955konami_input_check: ldy KONAMI_CODE_NUM_CORRECT ; load the number of successful inputs of Konami code bmi konami_code_exit ; if #$ff (invalid Konami input), exit lda CONTROLLER_STATE_DIFF ; buttons pressed (only care on input change so held button doesn't affect code) and #$cf ; only care about input from d-pad and A/B buttons (not select nor start) beq konami_code_exit ; if no input detected, exit cmp konami_code_lookup_table,y ; compare with Konami code sequence at index y beq konami_input_index_correct ; on success, goto konami_input_index_correct lda #$ff ; incorrect sequence for Konami code sta KONAMI_CODE_NUM_CORRECT ; since incorrect set KONAMI_CODE_NUM_CORRECT (number of successful inputs) to $ff … cpy #$0a ; Konami code is 10 inputs, compare against how many successfully entered …Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L716-L720game_routine_00: … sty KONAMI_CODE_NUM_CORRECT ; initialize konami check to #$00 (see konami_input_check)Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L1165-L1174init_player_lives: lda #$02 ; start off with #$02 lives ldy KONAMI_CODE_STATUS ; 30-lives code switch ($01 = code activated) beq init_player_num_lives ; if KONAMI_CODE_STATUS is not set, then just set 2 lives lda #$1d ; KONAMI_CODE_STATUS active so set lives to #$1d (29 decimal) … sta P1_NUM_LIVES,x ; if X is 1, then set P2_NUM_LIVES to accumulator (a is either #$02 or #$1d)Checked by claude, 2026-10-21 — read konami_input_check, its table, the reset in game_routine_00, the call in game_routine_01, and init_player_lives at the pinned commit

The table's bit values are the disassembly's controller layout: Up $08, Down $04, Left $02, Right $01, B $40, A $80. The lives byte counts reserve lives: a death with it at 0 is game over (contra/lives).

Cited by: Cheat code, Contra, Gradius

A new game of the US NES Contra gives each player 2 lives in reserve (3 in all) and the game 3 continues. A death with none in reserve puts that player in game over, and each game over spends a continue; with none left, the CONTINUE/END choice is skipped. contra/lives

About: Contra Continue

Value
{
 "lives": 3,
 "continues": 3
}
CodeContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L1143-L1147init_score_player_lives: … lda #$03 ; a = #$03 sta NUM_CONTINUES ; continues remainingContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L1165-L1166init_player_lives: lda #$02 ; start off with #$02 livesContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L5150-L5161init_player_dec_num_lives: … lda P1_NUM_LIVES,x ; load player number of lives beq @set_game_over ; branch if no more lives dec P1_NUM_LIVES,x ; decrement player number of lives … @set_game_over: lda #$01 ; a = #$01 sta P1_GAME_OVER_STATUS,x ; game over state of player (1 = game over)Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L3289-L3307show_game_over_screen: … dec NUM_CONTINUES ; subtract from number of continues remaining bmi @no_continues_remaining ; if run out of continues, jump lda #$0e ; a = #$0e (continue end)Checked by claude, 2026-10-21 — read init_score_player_lives, init_player_lives, init_player_dec_num_lives, and show_game_over_screen at the pinned commit

The count starts at 3 and is decremented before the test, so game overs 1 to 3 offer CONTINUE and the fourth doesn't.

Cited by: Continue, Contra

The US NES Contra awards its first extra life at 20,000 points and each later one 30,000 points past the last threshold, and caps lives at 99. contra/extra-life

About: Contra Extra life

Value
{
 "first": 20000,
 "every": 30000,
 "max_lives": 99
}
CodeContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L1177-L1178lda #$c8 ; set default high score. #$c8 is 200 decimal sta EXTRA_LIFE_SCORE_LOW ; starting score for extra life (20,000)Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L1283-L1294; every time an extra life is obtained, #$12c is added to points required to get next extra life (300 decimal, 30,000 in game score) … lda #$2c ; a = #$2c (12c = 300 decimal) (high byte will be set to #$01 a few lines down) … adc EXTRA_LIFE_SCORE_LOW,y ; add 300 decimal to low byte of score required to get extra lifeContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L1310-L1314inc P1_NUM_LIVES,x ; if X is $01, then set P2 number of lives lda P1_NUM_LIVES,x ; load incremented number into memory cmp #$63 ; compare to #$63 (99 decimal) bcc @set_num_lives ; can't have more than 99 lives lda #$63 ; a = #$63 (63 = 99 decimal)Checked by claude, 2026-10-21 — read the extra-life setup in init_player_num_lives and @extra_life_logic in add_player_score at the pinned commit

Scores are kept in hundreds, so $C8 (200) is 20,000 and $12C (300) is 30,000. The routine stops awarding once the threshold's high byte reaches $75 (L1288-L1290), past 2.9 million points.

Cited by: Contra, Extra life

Touching a weapon item in the US NES Contra adds 1,000 points and dispatches on the item's type: R sets the rapid-fire bit, M, F, S, and L replace the gun (keeping rapid fire only when the new gun is the one held), B starts an invincibility timer at $80 ($90 on level 7), and the falcon destroys the enemies on screen. A death resets the gun to the default. contra/weapon-pickup

About: Contra Weapon pickup

CodeContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L6884-L6955pick_up_weapon_item: … lda #$0a ; a = #$0a sta $00 ; set score to add to player as #$0a (1,000 points) … lda ENEMY_ATTRIBUTES,y ; get weapon item attributes and #$07 ; keep bits 0-2 (attributes) beq @set_rapid_flag ; set rapid flag for weapon if attribute is #$00 cmp #$05 ; check for b weapon (barrier). Gives invincibility bcc @compare_and_set_weapon ; branch if less than #$05 (MFSL) beq @set_invincibility_timer ; branch for barrier weapon jsr destroy_all_enemies ; falcon weapon effect - destroy all enemies …Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L5150-L5151init_player_dec_num_lives: jsr init_player_and_weapon ; initialize player variables to 0Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L5338-L5340init_player_and_weapon: lda #$00 ; a = #$00 sta P1_CURRENT_WEAPON,x ; reset current player's weaponChecked by claude, 2026-10-21 — read pick_up_weapon_item through remove_current_enemy, init_player_dec_num_lives, and init_player_and_weapon at the pinned commit

Item types 1 to 4 are M, F, S, and L (the weapon byte's low nibble, ram.asm L727-L735). The disassembly notes that the barrier timer counts down every 8 frames, about 17 seconds at $80; the atlas hasn't read that decrement.

Cited by: Contra, Weapon pickup

Each completed loop of the US NES Contra and the strongest gun either player holds both shorten the timer between random soldiers: from the level's start value (144 on level 1), 40 comes off per loop, counting up to 3, and 5 per point of weapon strength (S 3, M and L 2, F 1, the default 0). contra/rank

About: Contra Rank

Value
{
 "per_loop": 40,
 "max_loops": 3,
 "per_strength": 5,
 "strength": {
  "default": 0,
  "M": 2,
  "F": 1,
  "S": 3,
  "L": 2
 },
 "level_1_start": 144
}
CodeContra (US), annotated disassembly (vermiceli) · src/bank2.asm#L1736-L1779adjust_generation_timer: jsr get_soldier_gen_timer_for_lvl sta SOLDIER_GENERATION_TIMER ; soldier generation timer ldy GAME_COMPLETION_COUNT ; load the number of times the game has been completed beq @adjust_timer_for_weapon ; branch if haven't yet beat the game any times tya cmp #$04 ; compare GAME_COMPLETION_COUNT to #$04 bcc @continue ; branch if GAME_COMPLETION_COUNT < #$04 ldy #$03 ; maximum multiplier of increase chance for generating soldier is #$03 … lda #$28 ; lower soldier generation timer … …Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L3270inc GAME_COMPLETION_COUNT ; increment game completion count, used mainly to increase enemy difficulty every play-throughContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L3920-L3926set_frame_scroll_weapon_strength: … sta PLAYER_WEAPON_STRENGTH ; clear player weapon strengthContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L4096-L4116set_player_weapon_strength: … lda weapon_strength,y ; load how strong the weapon is cmp PLAYER_WEAPON_STRENGTH ; compare against current weapon strength bcc @exit ; exit and do not lower player's current weapon strength sta PLAYER_WEAPON_STRENGTH ; store current weapon strength code (#$00-#$03) … weapon_strength: .byte $00 ; Regular = Weak .byte $02 ; M = Strong .byte $01 ; F = Medium .byte $03 ; S = Very Strong …Checked by claude, 2026-10-21 — read adjust_generation_timer and its table, the loop counter's increment, and the per-frame clear and maximum of PLAYER_WEAPON_STRENGTH at the pinned commit

Each frame clears the strength and then raises it to each living player's gun (run_player_invincibility_and_weapon_strength, L3940-L3958), so it tracks the stronger of the two. The same two numbers raise enemy hit points and fire rates elsewhere (vermiceli's docs/Game Completion Modifier.md lists them); this claim covers only the soldier timer.

Cited by: Contra, Rank

A jump in the US NES Contra sets the 16-bit vertical speed to $FB.$F0, a rise of 4.06 px/frame ($FC.$90, 3.44 px/frame, in the indoor base levels), and the jump routine adds $23 to it every airborne frame, 0.137 px/frame², without reading a button: the jump's height doesn't depend on holding A. contra/jump

About: Contra Jump

Value: 1040 1/256 px/frame

CodeContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L4533-L4557set_jump_status_and_y_velocity: … lda LEVEL_LOCATION_TYPE ; 0 = outdoor; 1 = indoor lsr lda #$fb ; a = #$fb (-5) ldy #$f0 ; y = #$f0 (.94) bcc @set_y_velocity ; branch if outdoor level (use Y velocity -5.94) lda #$fc ; indoor level, (Y velocity -4.56), set fast velocity to #$fc (-4) ldy #$90 ; set fractional Y velocity to #$90 (.56) … sta PLAYER_Y_FAST_VELOCITY,x ; set Y fast velocity to a tya ; transfer fractional velocity to a …The atlas reads this differently: The fraction byte is unsigned and carries into the whole byte, so $FB.$F0 is −5 + 240/256 = −4.0625 px/frame and $FC.$90 is −3.4375, not −5.94 and −4.56.Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L4708-L4757handle_jump: lda PLAYER_Y_FAST_VELOCITY,x ; load player Y fast velocity bmi @check_collision_above ; branch if player is still ascending … @apply_gravity: jsr apply_gravity ; increments Y fractional velocity by #$23 (applying gravity) … @set_y_pos: jsr player_jumping_set_y_pos ; set player Y position based on PLAYER_JUMP_COEFFICIENT and velocityContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L5113-L5130player_jumping_set_y_pos: … lda PLAYER_JUMP_COEFFICIENT,x ; load player's jump modifier (alters height of jump) clc ; clear carry in preparation for addition adc PLAYER_Y_FRACT_VELOCITY,x ; add to player's fractional Y velocity sta PLAYER_JUMP_COEFFICIENT,x ; update player's jump modifier (alters height of jump) lda SPRITE_Y_POS,x ; load player's Y position adc PLAYER_Y_FAST_VELOCITY,x ; add (subtract) the fast Y velocity (with jump coefficient overflow)Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L5139-L5147apply_gravity: clc lda PLAYER_Y_FRACT_VELOCITY,x ; load player's Y fractional velocity adc #$23 ; add #$23 to Y fractional velocity (.1367 decimal)Checked by claude, 2026-10-21 — read set_jump_status_and_y_velocity, handle_jump (every path but landing reaches @apply_gravity, and none reads the controller's A bit), player_jumping_set_y_pos, and apply_gravity at the pinned commit

The position adds the fraction with carry and then the whole byte, so $FB.$F0 is −5 + 240/256 = −4.0625 px/frame and $FC.$90 is −3.4375. The disassembly's comments read them as −5.94 and −4.56. Screen Y grows downward, so negative is up. PLAYER_JUMP_COEFFICIENT is the position's fraction, not a modifier.

Cited by: Contra

On the side-scrolling levels of the US NES Contra the screen moves only while a player passes X 128 (176 when two are playing), by that player's speed, and not while the other player is left of X 33; on the boss's screen it takes over and scrolls on its own to reveal the boss. contra/scroll

About: Contra Auto-scroll

CodeContra (US), annotated disassembly (vermiceli) · src/bank7.asm#L5164-L5208set_frame_scroll_if_appropriate: … lda SPRITE_X_POS,x ; load player X position cmp horizontal_scroll_point_tbl,y ; load horizontal scroll point position bcc @exit ; if not yet reached point to initiate horizontal scroll, exit cpy #$02 ; see if both players are active bne @set_horizontal_level_frame_scroll ; if both players aren't active, begin setting scroll … lda SPRITE_X_POS,y ; load other player's X position cmp #$21 ; compare other player to left edge of screen bcc @stop_player_x_velocity ; don't scroll if other player is preventing it by being too far to the left … …Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L5228-L5229horizontal_scroll_point_tbl: .byte $80,$80,$b0Contra (US), annotated disassembly (vermiceli) · src/bank7.asm#L6552-L6566set_boss_auto_scroll: … cmp LEVEL_SCREEN_NUMBER ; screen number bne @exit ; exit if not on the appropriate screen to start auto scroll … lda auto_scroll_timer_tbl,y ; load the appropriate auto scroll timer for the level sta AUTO_SCROLL_TIMER_00 ; start auto scroll to reveal the bossChecked by claude, 2026-10-21 — read set_frame_scroll_if_appropriate, horizontal_scroll_point_tbl, and set_boss_auto_scroll at the pinned commit

The table is indexed by PLAYER_GAME_OVER_BIT_FIELD, where 2 means both players are active. Vertical levels (the waterfall) use their own scroll point (L5231 on).

Cited by: Auto-scroll, Contra