Invincibility frames
A window after a hit in which the player can't be hurt again.
Invincibility frames are a window after a hit in which the player can’t be hurt again. The game starts a timer when the hit lands and skips the contact check until it runs out. The Legend of Zelda and Metroid, both released in 1986, do it this way1,2,3,4. In both, the same hit also pushes the character away3,5.
- Frame timerMetroid (1986). A 50-frame blink.5,4,6,7,8Mega Man (1987). A fixed spell of invincibility after each hit.9,10Mega Man 2 (1988). A fixed spell of invincibility after each hit, as in Mega Man.11,10Super Mario Bros. 2 (1988). A hit sets 127 frames, counted every frame.12Super Mario Bros. 3 (1988). A hit sets a blink in which further hits are ignored.13Castlevania III: Dracula's Curse (1989). After a hit the character flickers for a fixed count.14Mega Man 3 (1990). A spell of invincibility that starts once the knockback ends.15Super Mario World (1990). After the power-down animation, 127 frames counted every frame.16The Legend of Zelda: A Link to the Past (1991). 58 frames, counted down every frame.17Sonic the Hedgehog 2 (1992). After a hit he blinks, safe, for a while counted from his landing.18The Legend of Zelda: Link's Awakening (1993). 80 frames, counted down every frame.19,20Sonic 3 & Knuckles (1994). A blinking spell after a hit, counted again from the landing.21
- Slow timerSuper Mario Bros. (1985). After a hit he can't be hurt again for about two and a half seconds.22Super Mario Bros.: The Lost Levels (1986). Super Mario Bros.'s blink after a hit.23The Legend of Zelda (1986). 24 on a timer that counts down every other frame.3,24,25,26,27Zelda II: The Adventure of Link (1987). A timer of 4 that ticks once every 21 frames, 64 to 84 frames in all.28
#How it works
on contact with an enemy:
if timer > 0: nothing happens
else: take damage; timer = T; start the knockback
every frame the game counts:
if timer > 0: timer -= 1
The window is times the frames per step. The check happens on contact, so an enemy still touching the player when the timer reaches 0 hurts again on that frame25.
#Implementations
#The Legend of Zelda (1986)
A hit sets Link’s timer to 243. DecrementInvincibilityTimer counts it down only on even frames, so a timer of lasts frames24,24. Measured in the ROM, a monster held against Link hurts him every 47 or 48 frames25, depending on the frame’s parity25. The comment in the code calls the 24 “frames”3.
Monsters use the same timer and routine. A weapon’s hit sets a monster’s timer to 16, which lasts 32 frames26. The clock adds 16 to Link’s timer every frame, which keeps him invincible27.
#Metroid (1986)
A hit sets Samus’s blink counter to $32, which is 505,5. The comment beside it says 32 frames5. The counter drops on every frame of game logic, and the collision code skips enemies while it is above 06,4. Measured in the ROM, hits land 50 frames7 of game logic apart; lag frames can stretch that on screen7.
Lava uses the blink against the player. It holds the counter at 50, which keeps enemies off Samus, while the lava’s own damage keeps coming8.
#Later games
Mega Man 3 starts the window after the knockback: when the hurt state ends, it sets the timer to 60 and counts it down every frame15. Mega Man 2 sets 111 at the moment of the hit15. The atlas hasn’t traced how Mega Man 3 ignores contact during the hurt state itself15.
A hit in Sonic the Hedgehog 2 sets the count to 120, and landing sets it to 120 again; it counts down only in the control routine, so Sonic blinks for 120 frames after he lands18. Where Zelda and Metroid start the window with the push3,5, Sonic’s begins at the landing. Sonic 3 & Knuckles stores the count in a byte, still 120, set by the hit and again on landing21.
A hit in Castlevania III: Dracula’s Curse sets a counter to 120, which counts down once a frame while the character flickers; one branch of the hit code returns at once while it is nonzero14. Reading that counter as invincibility is the atlas’s interpretation14.
#Compared
| The Legend of Zelda | Metroid | |
|---|---|---|
| Timer set by a hit | 243 | 505 |
| Counts down | on even frames24 | every frame of logic6 |
| Next hit, measured | 47 or 48 frames25 | 50 frames of logic7 |
| Enemies have one | yes, 32 frames26 | no claim yet |
| Damage that ignores it | no claim yet | lava8 |
| What the code’s comment says | “$18 frames”, 24 steps3 | “32 frames”, hex $325 |
Both comments miscount their games’ windows: Zelda’s counts timer steps as frames, and Metroid’s reads hex as decimal3,5.
Games
| Game | Year | How | Note |
|---|---|---|---|
| Metroid | 1986 | Frame timer | a 50-frame blink |
| Mega Man | 1987 | Frame timer | a fixed spell of invincibility after each hit |
| Mega Man 2 | 1988 | Frame timer | a fixed spell of invincibility after each hit, as in Mega Man |
| Super Mario Bros. 2 | 1988 | Frame timer | a hit sets 127 frames, counted every frame |
| Super Mario Bros. 3 | 1988 | Frame timer | a hit sets a blink in which further hits are ignored |
| Castlevania III: Dracula's Curse | 1989 | Frame timer | after a hit the character flickers for a fixed count |
| Mega Man 3 | 1990 | Frame timer | a spell of invincibility that starts once the knockback ends |
| Super Mario World | 1990 | Frame timer | after the power-down animation, 127 frames counted every frame |
| Metroid II: Return of Samus | 1991 | Frame timer | a 51-frame timer that drops each time Samus is drawn |
| Sonic the Hedgehog | 1991 | Frame timer | after a hit he blinks, safe, for a while counted from his landing |
| The Legend of Zelda: A Link to the Past | 1991 | Frame timer | 58 frames, counted down every frame |
| Sonic the Hedgehog 2 | 1992 | Frame timer | after a hit he blinks, safe, for a while counted from his landing |
| Mega Man 6 | 1993 | Frame timer | the timer starts only once the push ends, for a second and a half in all |
| The Legend of Zelda: Link's Awakening | 1993 | Frame timer | 80 frames, counted down every frame |
| Sonic 3 & Knuckles | 1994 | Frame timer | a blinking spell after a hit, counted again from the landing |
| Super Metroid | 1994 | Frame timer | 96 frames after an enemy's touch |
| The Legend of Zelda: Oracle of Seasons and Oracle of Ages | 2001 | Frame timer | 34 frames after a standard enemy's touch, read from a collision table |
| The Legend of Zelda: The Minish Cap | 2004 | Frame timer | 30 frames after an Octorok's touch, read from a collision matrix |
| Super Mario Bros. | 1985 | Slow timer | after a hit he can't be hurt again for about two and a half seconds |
| Super Mario Bros.: The Lost Levels | 1986 | Slow timer | Super Mario Bros.'s blink after a hit |
| The Legend of Zelda | 1986 | Slow timer | 24 on a timer that counts down every other frame |
| Zelda II: The Adventure of Link | 1987 | Slow timer | a timer of 4 that ticks once every 21 frames, 64 to 84 frames in all |
Every claim about this mechanic, by game (32)
References
- ^Wikidata lists Nintendo and Nintendo Entertainment Analysis & Development as the developers of The Legend of Zelda and Nintendo as its publisher; it dates the game 21 February 1986, with no place or platform, and its NES release in North America 22 August 1987.WikidataWikidata
How we know
+1986-02-21T00:00:00Z … +1987-11-15T00:00:00Z … +1987-08-22T00:00:00Z
Q12395, P178 developer, P123 publisher, and P577 publication date qualified by P291 place and P400 platform · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^Wikidata lists Nintendo Research & Development 1 as the developer of Metroid and Nintendo as its publisher, and dates its release on the Famicom Disk System in Japan 6 August 1986.WikidataWikidata
How we know
+1986-08-06T00:00:00Z … +1987-08-15T00:00:00Z … +1987-08-00T00:00:00Z
Q2530723, P178 developer, P123 publisher, and P577 publication date qualified by P291 place and P400 platform · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-21.
- ^ abcdefghiA monster that touches Link while his invincibility timer is above 0 does nothing; a hit sets the timer to 24 and his shove distance to 32 px.Codealdonunez/zelda1-disassembly · “Legend of Zelda, The (USA) (Rev 1)”
How we know
5610 ; If Link is invincible, or we have the magic clock, 5611 ; or Link is stunned, or the monster is stunned; 5612 ; then return no collision. 5613 LDA ObjInvincibilityTimer 5614 ORA InvClock 5615 ORA ObjStunTimer 5616 ORA ObjStunTimer, X 5617 BNE L73A9_Exit
src/Z_01.asm lines 5610–5617 at 50a1c86 · upstream ↗ 6589 ; If Link is invincible, return without shoving. 6590 LDA ObjInvincibilityTimer 6591 BNE @Exit ⋮ 6601 ; Mark Link invincible $18 frames, and should move $20 pixels. 6602 LDA #$18 6603 STA ObjInvincibilityTimer 6604 LDA #$20 6605 STA ObjShoveDistance
src/Z_01.asm lines 6589–6605 at 50a1c86 · upstream ↗ In the cartridge (“Legend of Zelda, The (USA) (Rev 1)”): bank 1 BeginShove, run from RAM at $7E26. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcEach frame, the crash detection skips the contact check between Samus and the enemies while
SamusBlinkis above 0.Codenmikstas/metroid-disassembly · “Metroid (USA)”How we know
7696* ldy #$00 7697 lda SamusBlink 7698 bne NextEnemy 7699 jsr IsSamusDead 7700 beq NextEnemy 7701 jsr LF140 7702 jsr LF282
Source_Files/Bank07.asm lines 7696–7702 at 4270d57 · upstream ↗ In the cartridge (“Metroid (USA)”): bank 7 crash detection, $F034, which ends by calling SubtractHealth. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdefghiA hit sets
SamusBlinkto$32, which is 50, gives Samus an upward speed of$FDwith the hit gravity$38, and takes the push direction from the hit; the comment says "Set blink for 32 frames".Codenmikstas/metroid-disassembly · “Metroid (USA)”How we know
2421CheckHealthStatus: 2422LCDFA: lda SamusHit ; 2423 and #$20 ;Has Samus been hit? 2424 beq +++ ;If not, branch to check if still blinking from recent hit. 2425 lda #$32 ; 2426 sta SamusBlink ;Samus has been hit. Set blink for 32 frames. ⋮ 2428 sta DmgPushDir ⋮ 2431 beq ++ ⋮ 2434* lda SamusHit 2435 and #$08 2436 lsr 2437 lsr ⋮
Source_Files/Bank07.asm lines 2421–2443 at 4270d57 · upstream ↗ In the cartridge (“Metroid (USA)”): bank 7 CheckHealthStatus, $CDFA. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abc
CheckHealthStatus, which Samus's routines call once per frame, lowersSamusBlinkby 1 each time, so the blink lasts 50 frames of game logic.Codenmikstas/metroid-disassembly · “Metroid (USA)”How we know
2448* lda SamusBlink 2449 beq CheckHealthBeep 2450 dec SamusBlink
Source_Files/Bank07.asm lines 2448–2450 at 4270d57 · upstream ↗ 2342LCD7E:* JSR CheckHealthStatus ;($CDFA)Check if Samus hit, blinking or Health low.Source_Files/Bank07.asm line 2342 at 4270d57 · upstream ↗ In the cartridge (“Metroid (USA)”): bank 7 CheckHealthStatus. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdMeasured 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“Metroid (USA)” · nmikstas/metroid-disassembly
How we know
In the cartridge (“Metroid (USA)”): bank 7 CheckHealthStatus, which the probe's hits run. We don't reproduce the bytes.
2449 beq CheckHealthBeep 2450 dec SamusBlink
Source_Files/Bank07.asm lines 2421–2504 at 4270d57 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Metroid (USA) (SHA-1
2080059bea45…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abcIn 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
SubtractHealthhalves it to 0.3 units.Codenmikstas/metroid-disassembly · “Metroid (USA)”revisedHow we know
5432LE27B: sty DmgPushDir ;Don't push Samus from lava damage. 5433LE27D: jsr ClearHealthChange ;($F323)Clear any pending health changes to Samus. 5434LE280: lda #$32 ; 5435LE282: sta SamusBlink ;Make Samus blink. ⋮ 5441LE28F: lsr ;This portion of the code causes Samus to be damaged by 5442LE290: and #$03 ;lava twice every 8 frames if she does not have the varia 5443LE292: bne ++ ;but only once every 8 frames if she does. ⋮ 5448LE29D:* lda #$07 ; 5449LE29F: sta HealthLoChange ;Samus takes lava damage. 5450LE2A1: jsr SubtractHealth ;($CE92)
Source_Files/Bank07.asm lines 5432–5450 at 4270d57 · upstream ↗ 2523LCEAC: lda SamusGear ; 2524LCEAF: and #gr_VARIA ;Check is Samus has Varia. ⋮ 2526LCEB3: lsr HealthLoChange ;If Samus has Varia, divide damage by 2.
Source_Files/Bank07.asm lines 2523–2527 at 4270d57 · upstream ↗ In the cartridge (“Metroid (USA)”): bank 7 LavaAndMoveCheck, $E269. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Revised after a check by a second AI model, 2026-10-21: The Varia suit halves lava damage, to 0.3 units.
- ^A hit sets
zmegaman_invincibility_timeto 111 ($6F); while it is nonzero no contact damages Mega Man, and the stage loop counts it down by 1 on each pass that runs the enemies.Codelsmmega/mm1How we know
123@not_death: 124 LDA z:z0D 125 AND #objects_right 126 EOR #objects_right 127 ORA #$03 128 STA aobject_flag 129 LDA #$6F 130 STA z:zmegaman_invincibility_time 131 RTS
engine/check_megaman_damaged.asm lines 123–131 at b606a84 · upstream ↗ 18 LDA z:zmegaman_invincibility_time 19 BNE @cant_damage
engine/check_megaman_damaged.asm lines 18–19 at b606a84 · upstream ↗ 41 LDA aobject_flag 42 AND #%00001111 43 CMP #can_collide_map 44 BEQ @can_collide_map 45 JSR _run_weapons_trajectory 46 JSR _run_bosses_ai 47 LDA z:zmegaman_invincibility_time 48 BEQ @no_invincibility 49 DEC z:zmegaman_invincibility_time ⋮ 51@no_invincibility: 52 JSR _check_megaman_damaged
engine/stage_loop.asm lines 41–52 at b606a84 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abMega Man 2 keeps Mega Man's hit numbers too, 111 frames of invincibility (
$6F) and a knockback of 1.25 px/frame up and 0.5625 back.Codelsmmega/mm1 · lsmmega/mm2How we know
129 LDA #$6F 130 STA z:zmegaman_invincibility_time
engine/check_megaman_damaged.asm lines 129–130 at b606a84 · upstream ↗ 64 .BYTE $12, $01 | $40engine/handle_special_megaman_objects.asm line 64 at b606a84 · upstream ↗ 12 .BYTE $00 | $90data/special_xcoord_speed_table.asm line 12 at b606a84 · upstream ↗ 11 LDA #$6F 12 STA z:zmegaman_invincibility_time 13 LDA #$01 14 STA aobject_ycoord_speed 15 LDA #$40 16 STA aobject_ycoord_speed_fraction 17 LDA #$00 18 STA aobject_xcoord_speed 19 LDA #$90 20 STA aobject_xcoord_speed_fraction
home/megaman_hit.asm lines 11–20 at 94f0bf3 · 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 sets
zmegaman_invincibility_timeto 111 ($6F); contact damage is skipped while it is nonzero, and it counts down by 1 each time Mega Man's sprite is processed, hiding him on alternate pairs of frames.Codelsmmega/mm2How we know
11 LDA #$6F 12 STA z:zmegaman_invincibility_time
home/megaman_hit.asm lines 11–12 at 94f0bf3 · upstream ↗ 34 LDA z:zmegaman_invincibility_time 35 BNE @skip_1
home/object_hit.asm lines 34–35 at 94f0bf3 · upstream ↗ 277_is_megaman_object: 278 TAY 279 CPX #1 280 BCS @not_megaman_object 281 LDA z:zmegaman_invincibility_time 282 BEQ @skip 283 DEC z:zmegaman_invincibility_time 284 LDA z:znmi_frame 285 AND #%00000010 286 BEQ @skip ⋮ 288@is_out_of_screen: 289 JMP _skip_draw
home/sprites.asm lines 277–289 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Health is
$0Ffor one mark of the life meter and$10more for each further mark, up to$3Ffor four. A hit takes$10, one mark, and setsDamageInvulnTimeto$7F, during whichDamagePlayerreturns at once; the timer drops every frame. If the health left is$10or more, two marks or more, the hit also launches the player upward at$C0and 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 beforeEnemy_BeezoDiving), stuns it for$10frames, sets the player's vertical speed to$C0andPlayerStateTimerto$20, and jumps toKillPlayer, which sets the dying state and health to 0. A dying player holds still for those 32 frames, then rises at$C0and falls back, gaining$02a frame up to$39, and loses a life once below the screen.CodeSMB2 DiscombobulatedrevisedHow we know
11362DamagePlayer: 11363 LDA DamageInvulnTime 11364 BNE locret_BANK3_BA31 ⋮ 11366 LDA PlayerHealth 11367 SEC 11368 SBC #$10 11369 BCC loc_BANK3_BA32 ⋮ 11371 STA PlayerHealth 11372 LDY #$7F 11373 STY DamageInvulnTime 11374 LDY #$00 11375 STY PlayerYVelocity ⋮
src/prg-2-3.asm lines 11362–11388 at b73415e · upstream ↗ 3171 ; Decrement player state timers 3172 LDX #$03 3173DecrementPlayerStateTimers_Loop: 3174 LDA PlayerStateTimer, X ⋮ 3177 DEC PlayerStateTimer, X
src/prg-e-f.asm lines 3171–3177 at b73415e · upstream ↗ 291PlayerStateTimer: ⋮ 297DamageInvulnTime:
src/ram.asm lines 291–298 at b73415e · upstream ↗ 11404loc_BANK3_BA32: 11405 TXA ⋮ 11407loc_BANK3_BA33: 11408 PHA 11409 LDX byte_RAM_12 11410 LDA ObjectType, X 11411 CMP #Enemy_BeezoDiving 11412 BCS loc_BANK3_BA48 ⋮ 11414 JSR EnemyFindWhichSidePlayerIsOn ⋮ 11416 INY 11417 TYA 11418 CMP EnemyMovementDirection, X ⋮
src/prg-2-3.asm lines 11404–11439 at b73415e · upstream ↗ 5154KillPlayer: 5155 LDA #PlayerState_Dying ; Mark player as dead 5156 STA PlayerState 5157 LDA #$00 ; Clear some variables 5158IFNDEF RESPAWN_INSTEAD_OF_DEATH 5159 STA PlayerHealth
src/prg-e-f.asm lines 5154–5159 at b73415e · upstream ↗ 1995HandlePlayerState_Dying: 1996 LDA PlayerStateTimer 1997 BNE locret_BANK0_8A86 ⋮ 1999 LDA PlayerScreenYHi 2000 CMP #02 2001 BEQ LoseALife ⋮ 2003 JSR ApplyPlayerPhysicsY ⋮ 2005 LDA PlayerYVelocity 2006 BMI loc_BANK0_8A72 ⋮ 2008 CMP #$39 2009 BCS locret_BANK0_8A86 ⋮ 2011loc_BANK0_8A72: ⋮
src/prg-0-1.asm lines 1995–2014 at b73415e · upstream ↗ 270; enum PlayerHealthValues 271PlayerHealth_1_HP = $0F 272PlayerHealth_2_HP = $1F 273PlayerHealth_3_HP = $2F 274PlayerHealth_4_HP = $3F
src/defs.asm lines 270–274 at b73415e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-26.
Checked by a second AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-26.
- ^A hit that doesn't kill Mario, including one that only takes Kuribo's Shoe, sets
Player_FlashInvto$71, andPlayer_GetHurtignores hits while it is nonzero.Player_Drawcounts it down each time it runs, blinking Mario in 2-tick halves.CodeSouthbird's SMB3 disassemblyHow we know
5620Player_GetHurt: 5621 ; If Player is... 5622 LDA Player_FlashInv ; ... flashing invincible ... ⋮ 5629 BNE PRG000_D9B7 ; ... then jump to PRG000_D9B7 (RTS)
PRG/prg000.asm lines 5620–5629 at 09b1bd8 · upstream ↗ 5744PRG000_DA6D: 5745 LDA #$71 5746 STA Player_FlashInv ; Player_FlashInv = $71
PRG/prg000.asm lines 5744–5746 at 09b1bd8 · upstream ↗ 423 LDA Player_FlashInv 424 BEQ PRG029_CED7 ; If Player_FlashInv = 0, jump to PRG029_CED7 ⋮ 426 DEC Player_FlashInv ; Player_FlashInv-- 427 AND #$02 428 BEQ PRG029_CED7 ; Every 2 ticks, draw Player
PRG/prg029.asm lines 423–429 at 09b1bd8 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-26.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-26.
- ^ abcA hit in Dracula's Curse sets $80 to 120, which the player's update counts down once a frame while flickering the character; one branch of the hit handling returns at once while $80, or $AD, is nonzero.Codevinheim3/castlevania3-disasmrevised
How we know
lda #$78 … sta $80
code/playerStateProcessing_b1c.s#L298-L299 · upstream ↗ lda $80 … dec $80 … ldy #$80 … lda wGameStateLoopCounter … and #$01 … sty wEntityState.w
code/playerStateProcessing_b1c.s#L166-L176 · upstream ↗ lda $80 … ora $ad … bne B28_012b
code/playerStateProcessing_b1c.s#L257-L259 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^ abcdMega Man 3 starts the invincibility after the knockback: when the hurt state ends it sets
invincibility_timerto 60 ($3C), which the prelude counts down every frame. Mega Man 2 sets 111 at the moment of the hit.Codeplasticsmoke/megaman3-disassembly-ca65 · lsmmega/mm2How we know
828player_knockback_set_invincible: sta player_state ; set return player state 829 lda #$3C ; $39 = $3C (60 frames invincibility) 830 sta invincibility_timer ; 60 frames of invincibility
src/fixed/player_states.asm lines 828–830 at 58ca1c3 · upstream ↗ 657prelude_invincibility_timer: lda invincibility_timer ; load invincibility timer 658 beq prelude_charge_shot_check ; zero → skip 659 dec invincibility_timer ; decrement timer
src/fixed/game_loop.asm lines 657–659 at 58ca1c3 · upstream ↗ 141 lda invincibility_timer ; skip if invincibility active 142 bne metatile_cleanup_return ; immune → skip hazard check
src/fixed/collision.asm lines 141–142 at 58ca1c3 · upstream ↗ 11 LDA #$6F 12 STA z:zmegaman_invincibility_time
home/megaman_hit.asm lines 11–12 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^
HurtMarioreturns at once whileIFrameTimeris nonzero. After the power-down animation Super Mario World sets it to$7F, and the timer loop counts it down on every frame the sprites aren't locked.CodeSMWDisXHow we know
13490HurtMario: ⋮ 13492 BNE Return00F628 ; / 13493 LDA.W IFrameTimer ; \ If flashing... 13494 ORA.W InvinsibilityTimer ; | ...or have star... 13495 ORA.W EndLevelTimer ; | ...or level ending... 13496 BNE Return00F628 ; / ...return
bank_00.asm lines 13490–13496 at 30643c7 · upstream ↗ 9443 LDA.W PlayerAniTimer 9444 BEQ CODE_00D140 ⋮ 9452 LDA.W PlayerAniTimer ⋮ 9457CODE_00D140: 9458 LDA.B #$7F 9459 STA.W IFrameTimer
bank_00.asm lines 9442–9459 at 30643c7 · upstream ↗ 7903 BNE CODE_00C569 ; / 7904 INC.B EffFrame 7905 LDX.B #$13 7906CODE_00C508: 7907 LDA.W ColorFadeTimer,X 7908 BEQ + 7909 DEC.W ColorFadeTimer,X 7910 + DEX 7911 BNE CODE_00C508
bank_00.asm lines 7902–7911 at 30643c7 · upstream ↗ 1640ColorFadeTimer: skip 1 1641PlayerAniTimer: skip 1 1642IFrameTimer: skip 1
rammap.asm lines 1640–1642 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A monster's touch does nothing while Link's blink timer is above 0. A hit sets it to 58, and Link's sprite routine counts it down once a frame, so the protection lasts 58 frames.Codespannerisms/usdasm
How we know
22715#AttemptDamageToLinkPlusRecoil: 22716|06F3DB| LDA.w $031F 22717|06F3DE| ORA.w $037B 22718|06F3E1| BNE .no_damage
bank_06.asm lines 22715–22718 at bcdd96e · upstream ↗ 146|0780B4| LDA.w $031F 147|0780B7| BNE .have_iframes ⋮ 149|0780B9| LDA.b #$3A 150|0780BB| STA.w $031F
bank_07.asm lines 146–150 at bcdd96e · upstream ↗ 4530|0DAA46| LDA.b $11 4531|0DAA48| BNE .check_stair_visibility ⋮ 4533|0DAA4A| LDA.w $031F 4534|0DAA4D| BEQ .check_stair_visibility ⋮ 4536|0DAA4F| DEC A 4537|0DAA50| STA.w $031F
bank_0D.asm lines 4530–4537 at bcdd96e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abA hit sets
invulnerable_timeto$78(120) and landing sets it to 120 again; it counts down only in the control routine, so Sonic has 120 frames of blinking invulnerability after he lands.Codesonicretro/s2disasmHow we know
85696 move.w #$78,invulnerable_time(a0)s2.asm line 85696 at 4ef457c · upstream ↗ 38262 btst #status.player.in_air,status(a0) 38263 bne.s return_1B1C8 ⋮ 38271 move.w #$78,invulnerable_time(a0)
s2.asm lines 38262–38271 at 4ef457c · upstream ↗ 36325Sonic_Display: ⋮ 36328 subq.w #1,invulnerable_time(a0) ; decrease invulnerability frames 36329 lsr.w #3,d0 ; check every 3 or 4 frames
s2.asm lines 36325–36330 at 4ef457c · upstream ↗ 85635 tst.w invulnerable_time(a0) 85636 bne.s Touch_NoHurt
s2.asm lines 85633–85636 at 4ef457c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A monster's touch does nothing while Link's invincibility counter is above 0; a hit sets it to
$50, and the main loop counts it down every frame, so the protection lasts 80 frames.Codezladx/LADX-Disassembly · “Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev 2)”revisedHow we know
ld a, [wInvincibilityCounter] … jp nz, setCarryAndReturn
src/code/entities/bank3.asm#L5300-L5307 · upstream ↗ 5347 ld a, $50 ;; 03:6DB2 $3E $50src/code/entities/bank3.asm lines 5347–5348 at 2a5c2c0 · upstream ↗ 1500 ; If wInvincibilityCounter > 0, decrement itsrc/code/bank0.asm lines 1500–1505 at 2a5c2c0 · upstream ↗ In the cartridge (“Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev 2)”): the same decrement in the 1993 release, bank 0 (ld hl,$DBC7; ld a,[hl]; and a; jr z; dec [hl]); the 1993 release's hit code, from the counter test to the `$50` store (game-boy-hit). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^The 1993 Game Boy release has the same hit code as DX without the tunic check. It reads the damage from its health-group table, applies the Guardian Acorn's rule, and stores the same
$50in the invincibility counter.Code“Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev 2)” · zladx/LADX-DisassemblyrevisedHow we know
In the cartridge (“Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev 2)”): bank 3; from the counter test to the `$50` store, DX's bytes less the 7-byte tunic test. We don't reproduce the bytes.
5323 ld a, [wTunicType] ;; 03:6D94 $FA $0F $DC 5324 cp TUNIC_BLUE ;; 03:6D97 $FE $02 5325 jr z, .takeHalfDamages ;; 03:6D99 $28 $0E
src/code/entities/bank3.asm lines 5323–5325 at 2a5c2c0 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Revised after a check by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abThe invulnerability count is now a byte but still 120, set by the hit and again on landing, and still blinks the sprite.Codesonicretro/skdisasm · sonicretro/s1disasm · sonicretro/s2disasmrevised
How we know
21146 move.b #120,invulnerability_timer(a0)sonic3k.asm line 21146 at 73de97c · upstream ↗ 24545 move.b #2*60,invulnerability_timer(a0)sonic3k.asm line 24545 at 73de97c · upstream ↗ 22074 move.b invulnerability_timer(a0),d0 22075 beq.s loc_10CA6 22076 subq.b #1,invulnerability_timer(a0) 22077 lsr.b #3,d0
sonic3k.asm lines 22073–22078 at 73de97c · upstream ↗ 410 move.w #2*60,flashtime(a0) ; set temporary invulnerability time to 2 seconds_incObj/Sonic ReactToItem.asm line 410 at 15dfa3a · upstream ↗ 85696 move.w #$78,invulnerable_time(a0)s2.asm line 85696 at 4ef457c · upstream ↗ 38271 move.w #$78,invulnerable_time(a0)s2.asm line 38271 at 4ef457c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^A hit on big Mario sets
InjuryTimerto 8, and enemy contact is skipped until it is back at 0. It is one of the interval timers, whichDecTimerscounts down once every 21 frames, so the window lasts 8 such ticks, 148 to 168 frames while the game's timers run.CodeXkeeper0/smb1How we know
10583InjurePlayer: 10584 LDA InjuryTimer ; check again to see if injured invincibility timer is 10585 BNE ExInjColRoutines ; at zero, and branch to leave if so ⋮ 10591 LDA #$08 10592 STA InjuryTimer ; set injured invincibility timer
src/prg.asm lines 10583–10592 at 1cc3c92 · upstream ↗ 127 LDX #$14 ; load end offset for end of frame timers 128 DEC IntervalTimerControl ; decrement interval timer control, 129 BPL DecTimersLoop ; if not expired, only frame timers will decrement 130 LDA #$14 131 STA IntervalTimerControl ; if control for interval timers expired, 132 LDX #$23 ; interval timers will decrement along with frame timers
src/prg.asm lines 126–139 at 1cc3c92 · upstream ↗ 60Timers = $0780 ⋮ 78InjuryTimer = $079e
src/ram.asm lines 60–78 at 1cc3c92 · 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 on big Mario sets
InjuryTimerto 8, as in Super Mario Bros., and the timer counts down once every 21 frames with the interval timers, through the same timer loop as Super Mario Bros.'s.Codedoppelganger's SMB2J disassembly · Xkeeper0/smb1revisedHow we know
10424 lda InjuryTimer ;check again to see if either of the two 10425 ora StarInvincibleTimer ;invincibility timers have expired, branch if not 10426 bne ExInjColRoutines ⋮ 10428ForceInjury: 10429 ldx PlayerStatus ;check player's status 10430 beq KillPlayer ;branch if small 10431 sta PlayerStatus ;otherwise set player's status to small 10432 lda #$08 10433 sta InjuryTimer ;set injured invincibility timer
sm2main.asm lines 10424–10433 at 9c40114 · upstream ↗ 928 ldx #$14 ;set offset to decrement only frame timers 929 dec IntervalTimerControl ;if interval timer control not expired, branch 930 bpl DecrTheTimers ;to skip and thus decrement only frame timers 931 lda #$14 932 sta IntervalTimerControl ;otherwise reset interval timer control to 20 frames 933 ldx #$23 ;and load offset to decrement frame and interval timers
sm2main.asm lines 928–933 at 9c40114 · upstream ↗ 81Timers = $0780 ⋮ 99InjuryTimer = $079e
sm2main.asm lines 81–99 at 9c40114 · upstream ↗ 10583InjurePlayer: 10584 LDA InjuryTimer ; check again to see if injured invincibility timer is 10585 BNE ExInjColRoutines ; at zero, and branch to leave if so ⋮ 10587ForceInjury: 10588 LDX PlayerStatus ; check player's status 10589 BEQ KillPlayer ; branch if small 10590 STA PlayerStatus ; otherwise set player's status to small 10591 LDA #$08 10592 STA InjuryTimer ; set injured invincibility timer
src/prg.asm lines 10583–10592 at 1cc3c92 · upstream ↗ 126DecTimers: 127 LDX #$14 ; load end offset for end of frame timers 128 DEC IntervalTimerControl ; decrement interval timer control, 129 BPL DecTimersLoop ; if not expired, only frame timers will decrement 130 LDA #$14 131 STA IntervalTimerControl ; if control for interval timers expired, 132 LDX #$23 ; interval timers will decrement along with frame timers 133DecTimersLoop: 134 LDA Timers,x ; check current timer 135 BEQ SkipExpTimer ; if current timer expired, branch to skip, 136 DEC Timers,x ; otherwise decrement the current timer 137SkipExpTimer: ⋮
src/prg.asm lines 126–139 at 1cc3c92 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-26.
- ^ abcd
DecrementInvincibilityTimerlowers an object's invincibility timer by 1 only on frames whenFrameCounteris even, so a timer of lasts frames.Codealdonunez/zelda1-disassembly · “Legend of Zelda, The (USA) (Rev 1)”How we know
5782DecrementInvincibilityTimer: 5783 LDA ObjInvincibilityTimer, X 5784 BEQ @Exit ; If the timer is already zero, then return. 5785 LDA FrameCounter ; Every two frames, decrease the timer. 5786 LSR 5787 BCS @Exit 5788 DEC ObjInvincibilityTimer, X
src/Z_07.asm lines 5782–5788 at 50a1c86 · upstream ↗ In the cartridge (“Legend of Zelda, The (USA) (Rev 1)”): bank 7 $FE98. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdeMeasured in Rev 1, a Tektite held against Link hurts him every 47 or 48 frames, taking half a heart each time; from three hearts, five hits leave
$20and$7D, 3/256 of a heart under a half heart.Verified“Legend of Zelda, The (USA) (Rev 1)” · aldonunez/zelda1-disassemblyHow we know
In the cartridge (“Legend of Zelda, The (USA) (Rev 1)”): bank 1, the contact check and damage the probe exercises. We don't reproduce the bytes.
5769 LDA HeartPartial 5770 CMP $0E 5771 BCC @BorrowHeart 5772 SEC 5773 SBC $0E 5774 STA HeartPartial ⋮ 5784 SEC ⋮ 5796 SEC ⋮ 5802 DEC HeartValues 5803 LDA #$FF 5804 STA HeartPartial ⋮ 5817 STA HeartPartial
src/Z_01.asm lines 5600–5822 at 50a1c86 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Legend of Zelda, The (USA) (Rev 1) (SHA-1
4671517d72d0…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abcA weapon that hurts a monster sets the monster's invincibility timer to 16, which lasts 32 frames, and shoves it 64 px in the weapon's direction, unless the monster is already invincible or immune to the weapon's damage type.Codealdonunez/zelda1-disassembly · “Legend of Zelda, The (USA) (Rev 1)”
How we know
6503BeginShove: 6504 ; If a weapon attacks a monster, and the weapon's damage 6505 ; type matches the monster's invincibility mask; 6506 ; then return without shoving.
src/Z_01.asm lines 6503–6514 at 50a1c86 · upstream ↗ 6636 ; Set the shove direction to the weapon's direction, ⋮ 6653 ; If the monster is invincible, then return without shoving. 6654 LDA ObjInvincibilityTimer, X 6655 BNE @Exit2 ⋮ 6671 BNE @Exit2 ⋮ 6676 BNE @Exit2 ⋮ 6687 ; Mark the monster invincible $10 frames, and should move $40 pixels. 6688 LDA #$40 6689 STA ObjShoveDistance, X 6690 LDA #$10 6691 STA ObjInvincibilityTimer, X
src/Z_01.asm lines 6636–6691 at 50a1c86 · upstream ↗ In the cartridge (“Legend of Zelda, The (USA) (Rev 1)”): bank 1 BeginShove. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abWhile Link holds the clock,
BeginUpdateWorldadds 16 to his invincibility timer every frame, and monsters' contact checks return no collision.Codealdonunez/zelda1-disassembly · “Legend of Zelda, The (USA) (Rev 1)”How we know
1876BeginUpdateWorld: 1877 ; If we have the clock, then 1878 ; force the player's invincibility. 1879 LDA InvClock 1880 BEQ @NotInvincible 1881 LDA ObjInvincibilityTimer 1882 CLC 1883 ADC #$10 1884 STA ObjInvincibilityTimer
src/Z_07.asm lines 1876–1884 at 50a1c86 · upstream ↗ In the cartridge (“Legend of Zelda, The (USA) (Rev 1)”): bank 7 $EC7A, these lines only; BeginUpdateWorld differs in Rev 1 further on. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^A hit sets Link's immunity timer to 4 and his injured timer to 32. The game counts the injured timer down every frame but the immunity timer only once every 21 frames, so the immunity lasts 64 to 84 frames, depending on where in the cycle the hit lands.CodeFiendsOfTheElements/z2disassembly · “Zelda II - The Adventure of Link (USA)”
How we know
5461 STA $050C ; 0x1e35e $E34E 8D 0C 05 ; Timer for Link being in injured state ⋮ 5463 STA $0518 ; 0x1e363 $E353 8D 18 05 ; Timer for Link being immune (0 = vulnerable)
src/prg7.asm lines 5460–5463 at c4c3a4c · upstream ↗ 5414 LDA $0518 ; 0x1e301 $E2F1 AD 18 05 ; Timer for Link immunity (0 = vulnerable)src/prg7.asm lines 5412–5416 at c4c3a4c · upstream ↗ 398 DEC $0501,x ; 0x1c18c $C17C DE 01 05 ; decrease all 5xx timers (if > 0)src/prg7.asm lines 388–401 at c4c3a4c · upstream ↗ In the cartridge (“Zelda II - The Adventure of Link (USA)”): bank 7 $C169-$C181, the timer loop; the source's `BPL :-` assembles to the wrong target, and the ROM's F5 branches back to $C177. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Sources
Code
- Núñez, Aldo. 2021. “zelda1-disassembly: A complete disassembly of The Legend of Zelda.” Commit 50a1c86. aldonunez/zelda1-disassembly @ 50a1c86 · licence, all uses
- n.d. “Legend of Zelda, The (USA) (Rev 1).” · licence, all uses
- nmikstas and Kent Hansen. 2025. “metroid-disassembly: Metroid software disassembly.” Commit 4270d57. nmikstas/metroid-disassembly @ 4270d57 · licence, all uses
- n.d. “Metroid (USA).” · licence, all uses
- plasticsmoke. 2026. “Mega Man 3 (U), annotated ca65 disassembly (plasticsmoke).” Commit 58ca1c3. plasticsmoke/megaman3-disassembly-ca65 @ 58ca1c3 · licence, all uses
- lsmmega. 2026. “mm2: Mega Man 2 disassembly (lsmmega/mm2).” Commit 94f0bf3. lsmmega/mm2 @ 94f0bf3 · licence, all uses
- Sonic Retro contributors. 2026. “s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm).” Commit 4ef457c. sonicretro/s2disasm @ 4ef457c · licence, all uses
- Sonic Retro contributors. 2026. “skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm).” Commit 73de97c. sonicretro/skdisasm @ 73de97c · licence, all uses
- Sonic Retro contributors. 2026. “s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm).” Commit 15dfa3a. sonicretro/s1disasm @ 15dfa3a · licence, all uses
- vinheim3. 2020. “castlevania3-disasm: a disassembly of Castlevania III: Dracula's Curse.” Commit 3272648. vinheim3/castlevania3-disasm @ 3272648 · licence, all uses
Secondary
- Wikidata contributors. 2026. “Wikidata.” Wikimedia Foundation. original · licence, all uses