+  RHDN Forum Archive
|-+  Romhacking
| |-+  ROM Hacking Discussion
| | |-+  SMB - 128 or More Lives is Game Over - How to Fix?
Pages: [1]
Author Topic: SMB - 128 or More Lives is Game Over - How to Fix?  (Read 2 times)
SMB2J-2Q
Guest
« on: November 29, 2009, 04:06:06 am »

Hi,

Does anyone here know of a fix for the game Super Mario Bros. for the NES in which if Mario/Luigi gets 128 or more lives, that the counter regards these numbers as negative? The fix involves not recognizing the numbers 128-255 in the lives counter as negative.

I know the extra life count maxes out at 128 on this and Super Mario Bros.: The Lost Levels as represented on Super Mario All-Stars for the Super NES and on Super Mario Bros. Deluxe for the Game Boy Color.

Again, said fix should be as simple as the fix regarding the arcade Donkey Kong where the kill screen bug is fixed by changing the part of that game's code which was originally represented as:
Code:
0F7A 3A2962 - LD A,(#6229) ; Load A with level number
0F7D 47 - LD B,A ; Copy this number into B
0F7E A7 - AND A ; Perform bitwise AND of A with A
0F7F 17 - RLA ; Rotate left the bits in A (multiply by 2)
0F80 A7 - AND A ; Perform bitwise AND of A with A
0F81 17 - RLA ; Rotate left the bits in A (multiply by 2)
0F82 A7 - AND A ; Perform bitwise AND of A with A
0F83 17 - RLA ; Rotate left the bits in A (multiply by 2)
0F84 80 - ADD A,B ; A = A + B
0F85 80 - ADD A,B ; A = A + B
0F86 C628 - ADD A,#28 ; A = A + #28 (40 decimal)
0F88 FE51 - CP #51 ; Is A >= #51 (81 decimal)?
0F8A 3802 - JR C,#0F8E ; No, then skip ahead to #0F8E
0F8C 3E50 - LD A,#50 ; Yes, then A = #50 (80 decimal)
0F8E 21B062 - LD HL,#62B0 ; Load HL address to store the result
0F91 0603 - LD B,#03 ; For B = 1 to 3
0F93 77 - LD (HL),A ; Stores A in #62B0, #62B1 and #62B2
0F94 2C - INC L ; L = L + 1
0F95 10FC - DJNZ #0F93 ; Next B

Into... (credit to Don Hodges and Jeff Kulczycki):
Code:
0F7A 3A2962 - LD A,(#6229) ; Load A with level number
0F7D FE04 - CP #04 ; Is the level # >= 4?
0F7F 3802 - JR C,#0F83 ; If not, jump ahead and compute bonus normally
0F81 3E04 - LD A,#04 ; If it is, then set A = 4
0F83 47 - LD B,A ; Copy A into B
0F84 A7 - AND A ; Clear the carry flag
0F85 17 - RLA ; Rotate left the bits of A
0F86 A7 - AND A ; Clear the carry flag
0F87 17 - RLA ; Rotate left the bits of A
0F88 A7 - AND A ; Clear the carry flag
0F89 17 - RLA ; Rotate left the bits of A
0F8A 80 - ADD A,B ; A = A + B
0F8B 80 - ADD A,B ; A = A + B
0F8C C628 - ADD A,#28 ; A = A + #28 (40 decimal)
0F8E 21B062 - LD HL,#62B0 ; Load HL address to store the result

As you all know, the new code that Hodges and Kulczycki devised which fixes the kill screen fits in the same space as the original.

~Ben

 
KingMike
Guest
« Reply #1 on: November 29, 2009, 05:04:11 pm »

From the SMB disassembly, it looks like these are the lines you'd have to change:
(RAM $075A is the number of lives)
Code:
PrimaryGameSetup:
      lda #$01
      sta FetchNewGameTimerFlag   ;set flag to load game timer from header
      sta PlayerSize              ;set player's size to small
      lda #$02
      sta NumberofLives           ;give each player three lives
      sta OffScr_NumberofLives

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

TransposePlayers:
           sec                       ;set carry flag by default to end game
           lda NumberOfPlayers       ;if only a 1 player game, leave
           beq ExTrans
           lda OffScr_NumberofLives  ;does offscreen player have any lives left?
           bmi ExTrans               ;branch if not

lda NumberofLives        ;otherwise, check number of lives
               clc                      ;and increment by one for display
               adc #$01
               cmp #10                  ;more than 9 lives?
               bcc PutLives
               sbc #10                  ;if so, subtract 10 and put a crown tile
               ldy #$9f                 ;next to the difference...strange things happen if
               sty VRAM_Buffer1+7       ;the number of lives exceeds 19
The issue is that PlayerLoseLife and PlayerTranspose use the negative flag to determine if the game is over. Meaning it is treating the lives counter as a signed value.
The negative flag is set when the highest bit of the lives is 1.

I'll leave that as an exercise to the reader, since it took exactly five minutes to find, fix and test.
SMB2J-2Q
Guest
« Reply #2 on: November 29, 2009, 07:08:11 pm »

So I'd have to think that this was all hard-coded. Right?

~Ben
Tauwasser
Guest
« Reply #3 on: November 29, 2009, 10:03:30 pm »

Well, it's asm source, so most stuff is "hard-coded" in the sense that all relevant bytes inside the asm script.
While the original source may have used defines, these don't get saved in a table or something but are directly embedded into the code.
The usual concept of hard-coding is something different, because it usually applies to programs that are flexible and multi-purpose. Here, the situation is quite different. It was made for a platform with a specific concept in mind, so it is not desirable that the amount of lives can be changed by the user via some magic config file on the cart or something.

cYa,

Tauwasser
Pages: [1]  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC