Results 1 to 14 of 14

Thread: Super Mario Bros. - 128 Lives Fix

  1. #1
    Cherry (Level 1)
    Join Date
    Oct 2010
    Location
    Milwaukie (Oak Grove), Oregon
    Posts
    351
    Thanks Thanks Given 
    1
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default Super Mario Bros. - 128 Lives Fix

    It is well known that there is a bug in Super Mario Bros. for the NES that, if you manage to score 128 or more lives, you will get Game Over the next time you die.

    My question is, which code would I modify to correct this data, so that obtaining 128 lives and beyond won't mean Game Over anymore, and would also cap 255 ($ff) as the maximum, without resetting to zero? Subsequent remakes such as Super Mario All-Stars (SNES) and Super Mario Bros. Deluxe (Game Boy Color) acknowledged the bug and the resulting side effect from the original NES port, and so have fixed this issue, thus capping the extra life amount to 127.

    Thank you,



    Ben

  2. #2
    Red (Level 21) Jorpho's Avatar
    Join Date
    Jul 2002
    Location
    We're all mad here
    Posts
    13,554
    Thanks Thanks Given 
    2
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Are you sure about that? I thought the bug persisted in SMB in Super Mario All-Stars. (Of course, the number of lives will at least display correctly.)

    Anyway, you might want to take your question to a more specialized board. It's probably possible, given that there's a complete annotated disassembly of the SMB ROM out there, but I doubt it's straightforward – things probably have to be rearranged substantially.
    "There is much pleasure to be gained from useless knowledge." --Bertrand Russel (attributed)

  3. #3
    Cherry (Level 1)
    Join Date
    Oct 2010
    Location
    Milwaukie (Oak Grove), Oregon
    Posts
    351
    Thanks Thanks Given 
    1
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Quote Originally Posted by Jorpho View Post
    Are you sure about that? I thought the bug persisted in SMB in Super Mario All-Stars. (Of course, the number of lives will at least display correctly.)

    Anyway, you might want to take your question to a more specialized board. It's probably possible, given that there's a complete annotated disassembly of the SMB ROM out there, but I doubt it's straightforward – things probably have to be rearranged substantially.
    It indeed stops at 127 lives in SMAS and SMBDX.

    What I did so far for the original SMB was to change the instruction at $91D9 in the PRG-ROM so that it branches on not equal (BNE) instead of equal (BEQ) (to get Game Over after losing your last life, not when it goes into negative territory at 128 and beyond). I must give due thanks to KingMike at Romhacking.net for that bit of help.

    ~Ben
    Last edited by ColecoFan1981; 09-27-2014 at 01:39 AM.

  4. #4
    Strawberry (Level 2) Custom rank graphic
    FoxNtd's Avatar
    Join Date
    Mar 2010
    Location
    USA/米国
    Posts
    570
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    4
    Thanked in
    4 Posts

    Default

    Is this basically a 6502 assembly question? Ok then...

    In general, architecture aside, there are a few things you could try. Change the variable to unsigned so that the limit effectively becomes 255. (No idea why the game uses a signed 8-bit integer, it's not like there is any meaningful use for negative lives. That's what causes your game over surely, because any negative is less than 0 and that represents game over.) You could modify the routine which is incrementing the lives counter and add a bounds check to insure it does not increment once the maximum is reached. Assuming that Famicom supports 16-bit variables (I really don't know lol) allocate more memory for the lives counter. An unsigned 16-bit int will get you a cap of 65,535. The game has trouble displaying numbers on the life total screen that are greater than 9 I think so I'm not sure what side-effects there may be by trying to make the variable 16-bit instead of 8-bit...

  5. #5
    Cherry (Level 1)
    Join Date
    Dec 2005
    Location
    Augusta, Georgia, USA
    Posts
    268
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    2
    Thanked in
    2 Posts

    Default

    The code must just simply be checking the 6502 N flag... In which case the fix you applied may be fine, assuming there aren't any other side effects based on the number of lives.

    I looked at the disassembly... here is the code.

    PlayerLoseLife:
    inc DisableScreenFlag ;disable screen and sprite 0 check
    lda #$00
    sta Sprite0HitDetectFlag
    lda #Silence ;silence music
    sta EventMusicQueue
    dec NumberofLives ;take one life from player
    bpl StillInGame ;if player still has lives, branch
    lda #$00
    sta OperMode_Task ;initialize mode task,
    lda #GameOverModeValue ;switch to game over mode
    sta OperMode ;and leave
    rts

    Changing "bpl StillInGame" to "bne StillInGame" should make it so the game only ends when the variable is 0, not 128-255. However, the check will be one less than normal, so test this and see if the game ends when you have one life left instead of 0.

    There may another side effect to this simple patch, though. At the end of each world, the game sets the lives to 255 when you press B. It may cause some issue. It looks like it may get set back to 3 when the game restarts anyway, so maybe not.
    Last edited by Pete Rittwage; 09-27-2014 at 10:38 AM.
    -
    Pete Rittwage
    C64 Preservation Project
    http://c64preservation.com

  6. #6
    Cherry (Level 1)
    Join Date
    Oct 2010
    Location
    Milwaukie (Oak Grove), Oregon
    Posts
    351
    Thanks Thanks Given 
    1
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Quote Originally Posted by Pete Rittwage View Post
    The code must just simply be checking the 6502 N flag... In which case the fix you applied may be fine, assuming there aren't any other side effects based on the number of lives.

    I looked at the disassembly... here is the code.

    PlayerLoseLife:
    inc DisableScreenFlag ;disable screen and sprite 0 check
    lda #$00
    sta Sprite0HitDetectFlag
    lda #Silence ;silence music
    sta EventMusicQueue
    dec NumberofLives ;take one life from player
    bpl StillInGame ;if player still has lives, branch
    lda #$00
    sta OperMode_Task ;initialize mode task,
    lda #GameOverModeValue ;switch to game over mode
    sta OperMode ;and leave
    rts

    Changing "bpl StillInGame" to "bne StillInGame" should make it so the game only ends when the variable is 0, not 128-255. However, the check will be one less than normal, so test this and see if the game ends when you have one life left instead of 0.

    There may another side effect to this simple patch, though. At the end of each world, the game sets the lives to 255 when you press B. It may cause some issue. It looks like it may get set back to 3 when the game restarts anyway, so maybe not.
    Still no Game Over.

    Thus, I ask: I wonder how this logic works in both Super Mario All-Stars and Super Mario Bros. Deluxe? SMAS relies on the more advanced 65816 code, whereas SMBDX relies on Z80 code.

    ~Ben
    Last edited by ColecoFan1981; 09-27-2014 at 12:28 PM.

  7. #7
    Red (Level 21) Jorpho's Avatar
    Join Date
    Jul 2002
    Location
    We're all mad here
    Posts
    13,554
    Thanks Thanks Given 
    2
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    It was my understanding that the code used in SMAS is in fact extremely close to the NES original and is not particularly redesigned to take advantage of any advanced 65816 features.
    "There is much pleasure to be gained from useless knowledge." --Bertrand Russel (attributed)

  8. #8
    Insert Coin (Level 0)
    Join Date
    Oct 2014
    Posts
    68
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Seems like a pointless fix as getting that many lives is extremely rare not a bug I ever ran into or even knew about after playing the game for 20+ years, you'd be better off asking the romhacking forum as theirs people that have done all kinds of crazy things with SMB1.

  9. #9
    Red (Level 21) Jorpho's Avatar
    Join Date
    Jul 2002
    Location
    We're all mad here
    Posts
    13,554
    Thanks Thanks Given 
    2
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Well, it's easy enough to do accidentally if you're doing one of the extra life tricks like in 3-1.

    Anyway, yes, there is now a thread at RH.net.
    "There is much pleasure to be gained from useless knowledge." --Bertrand Russel (attributed)

  10. #10
    Insert Coin (Level 0)
    Join Date
    Oct 2014
    Posts
    68
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Quote Originally Posted by Jorpho View Post
    Well, it's easy enough to do accidentally if you're doing one of the extra life tricks like in 3-1.

    Anyway, yes, there is now a thread at RH.net.
    Yeah I can see how it could be done but I don't really think anybody would need more than 20 or so lives to beat the game, if you're going to the trouble of hacking that bug out of the game you might as well just disable the lives system altogether. Only bug I've ever really disliked in the game is the one where you can accidentally get stuck in blocks.
    Last edited by drunk3nj3sus; 10-08-2014 at 12:40 AM.

  11. #11
    Cherry (Level 1)
    Join Date
    Oct 2010
    Location
    Milwaukie (Oak Grove), Oregon
    Posts
    351
    Thanks Thanks Given 
    1
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Sorry to re-open this thread, but now I've figured it out.

    In Super Mario All-Stars, this was how it got fixed:
    Code:
    CheckLives:
        INC NumberofLives ;increment the lives counter by one
        LDA NumberofLives ;then reload it to see if player has 128 lives
        CMP #$80             
        BCC WereGood      ;if not past 128 lives yet, we're good
        LDA #$7F             
        STA NumberofLives ;otherwise, set A=128 lives
    WereGood:
        RTL               ;end of routine
    Another way to do this:
    Code:
    CheckLives:
        INC NumberofLives ;increment the lives counter by one
        LDA NumberofLives ;then reload it to see if we have more than 128 lives
        BPL WereGood      ;if not past 128 lives yet, we're good
        DEC NumberofLives ;otherwise decrement counter by one to prevent overflow
    WereGood:
        RTL              ;end of routine
    ~Ben (ColecoFan1981)
    Last edited by ColecoFan1981; 01-07-2024 at 08:34 PM.

  12. The Following User Says Thank You to ColecoFan1981 For This Useful Post:

    Nz17 (08-28-2023)

  13. #12
    Bell (Level 8)
    Join Date
    Dec 2008
    Posts
    1,672
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    5
    Thanked in
    5 Posts

    Default

    Why would you LDA and INC the number of lives in that second example? It's pointless.

  14. The Following User Says Thank You to SparTonberry For This Useful Post:

    ColecoFan1981 (01-07-2024)

  15. #13
    Cherry (Level 1)
    Join Date
    Oct 2010
    Location
    Milwaukie (Oak Grove), Oregon
    Posts
    351
    Thanks Thanks Given 
    1
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Quote Originally Posted by SparTonberry View Post
    Why would you LDA and INC the number of lives in that second example? It's pointless.
    The same would apply to the first example, too... I too would like to know why not to INC right after LDA? It might be because INC is like LDA #$01+STA.

    A better way to do this would be:
    Code:
    CheckLives:
        lda NumberofLives ;load the lives counter
        cmp #$7f          ;check if player has 127 lives
        bcs EndCheckL     ;skip to end of routine if so
        inc NumberofLives ;otherwise increment counter by one
    EndCheckL:
        rtl
    Saves a lot of bytes.

    Another way...
    Code:
    CheckLives:
        lda NumberofLives ;load the lives counter
        bmi EndCheckL     ;skip to end if negative flag set
        inc NumberofLives ;otherwise increment counter by one
    EndCheckL:
        rtl
    ~Ben
    Last edited by ColecoFan1981; 08-30-2023 at 10:25 PM.

  16. #14
    Cherry (Level 1)
    Join Date
    Oct 2010
    Location
    Milwaukie (Oak Grove), Oregon
    Posts
    351
    Thanks Thanks Given 
    1
    Thanks Thanks Received 
    1
    Thanked in
    1 Post

    Default

    Quote Originally Posted by SparTonberry View Post
    Why would you LDA and INC the number of lives in that second example? It's pointless.
    OK, I fixed the examples I listed. In SMAS, the lives counter is incremented first, and then reloaded to see if the target result has been met.

    ~Ben

Similar Threads

  1. Super Mario Bros. Toy - Two Ladders & Mario Luigi Figures
    By ZackyH in forum Buying and Selling
    Replies: 5
    Last Post: 10-31-2007, 02:06 AM
  2. FS: N64 Mario Kart 64, Mario Golf, Super Smash Bros $35
    By Perkar in forum Buying and Selling
    Replies: 2
    Last Post: 08-24-2006, 11:31 PM
  3. NEW Super Mario Bros. an evolution of classic 2D Mario
    By Jasoco in forum Classic Gaming
    Replies: 28
    Last Post: 05-19-2005, 03:25 PM
  4. FA: Mario Bros / Zelda Toy Chest, Super Mario 2 Inside Out
    By TisLord in forum Buying and Selling
    Replies: 2
    Last Post: 10-21-2004, 09:25 AM
  5. Everybody Rejoice ---- Super Mario Bros. Super Show! - Vol 1
    By www.consolegames.org in forum Classic Gaming
    Replies: 11
    Last Post: 06-28-2004, 04:28 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •