rgmechex
@rgmechex

In this last article about the Super Mario Bros. 2 slot machines, I'm going to take a look at the logic that checks for a proper match and awards lives appropriately. It turns out that in the All-Stars release, this code was completely rewritten!

Slot machine in Super Mario Bros. 2 showing 777Have you been practicing your slots timings yet?


The code that is responsible for paying out lives at the slot machine has two separate things to check for. The first of which is if all three reels show the same icon--the classic winning combination. The other thing though is to test for a certain number of cherries. Cherries will only pay out if they show up in the first or first two reels. (So cherry-star-star will pay out 1 life, but star-star-cherry will pay out nothing.)

The NES version of Mario 2 and also its predecessor, Doki Doki Panic, sort of check for these things at the same time. This makes the code a bit more efficient, but the control flow is not very intuitive. Here's the code:

; $7B89: check for matches on the 3 reels
CheckForMatches:
  LDY #0 ; Y holds lives rewarded
  LDX Reel0
  LDA Reel0Icons,X
  BNE +
  INY ; Y++ if reel 0 is cherry
  
+ LDX Reel1
  CMP Reel1Icons,X
  BNE .done ; exit if first two icons don't match
  CMP #ICON_CHERRY
  BNE +
  INY ; Y++ if reel 0 is cherry
  
+ LDX Reel2
  CMP Reel2Icons,X
  BNE .done ; exit if first & last icons don't match
  INY ; Y++ if all reels match
  CMP #ICON_CHERRY
  BNE .done
  INY ; \ Y += 2 if reel 0 is cherry
  INY ; /
  
.done:
  TYA ; transfer lives to A

Note that the variables Reel0, Reel1, and Reel2 hold the index of the reel, 0-7. This then has to be used as an index into the table that holds which icons are on each reel in order. While the icon of the first reel is loaded into the accumulator, the other two reels are just compared against. This is how the cherry comparisons work.

The first block above checks if the first reel shows a cherry. The Y register holds the number of lives to award, so if it is a cherry this will be incremented to one. The second block checks if the first two reels match. If they don't, that's all that needs to be done so it jumps ahead. Otherwise if they do match, it checks if the first reel shows a cherry and increments Y if it is. Since the first and second reels match at this point, checking if the first reel is a cherry is the same as checking if the second reel is a cherry. Clever!

The third block then checks if the first and third reels match. Again, since at this point the first and second reels match, there is no need to check the second reel again. If all reels match, Y is incremented regardless of what the icons are. Then if the first reel is a cherry again (which means all of them are), Y is incremented by an additional two so that the payout totals five for the triple cherry.

This is what a flowchart of this code looks like:

Flow chart depicting how SMB2 checks for the slot machine payoutSeeing it organized like this makes it seem way less complicated.


Now let's see how this code was changed for All-Stars. The slots in this game had a third thing to check for: the 3 coins service event for getting a cherry-seven-seven. Unlike the NES version that checks for two things at a time, the Super NES version checks for each of the three things individually, which makes the code a bit easier to follow:

;$118F3A: check for matches on the 3 reels
CheckForMatches:
    LDY #0 ; Y holds lives rewarded
    LDX Reel0Icon ; check for cherries first
    BNE .check3OfAKind
    INY ; Y++ if reel 0 is cherry
    LDA Reel1Icon
    BNE .check3CoinService
    INY ; Y++ if reel 1 is cherry
    LDA Reel2Icon
    BNE .check3CoinService
    INY ; Y++ if reel 2 is cherry
    BRA .done

; check for cherry-seven-seven
; can only get here if reel 0 is cherry
.check3CoinService:
    LDA Reel1Icon         ; \ if reel 1
    CMP Reel2Icon         ; | and reel 2
    BNE .check3OfAKind    ; / match
    CMP #ICON_SEVEN       ; \ and they are
    BNE .check3OfAKind    ; / both sevens
    LDA ThreeCoinsService ; \ and haven't given
    BNE .check3OfAKind    ; / bonus already
    LDA #1
    STA ThreeCoinsService

; X contains reel 0 icon
.check3OfAKind:
    CPX Reel1Icon   ; \ if reel 1 and
    BNE .done       ; / reel 0 match
    CPX Reel2Icon   ; \ and if reel 2 and
    BNE .done       ; / reel 0 match
    INY             ; \ Y += 2 if all reels match
    INY             ; /
    CPX #ICON_SEVEN ; \ if all reels match and
    BNE .done       ; / they are all sevens
    LDY #10         ; Y set to 10
    
.done:
    TYA ; transfer lives to A

The first block of code checks specifically for cherries only. If the first reel does not show a cherry, it doesn't even need to check for the coins service, so it skips that block entirely at that point. The second block checks for the coins service. Since that code is only reachable if the first reel is a cherry, it only has to check if the second and third reels are sevens.

Then the final block just checks if all the reels match, and gives a flat two lives for everything (except for the triple sevens, which is hardcoded to a flat 10 lives).

Now, what I think is interesting is that, due to this rewrite of the code, the triple cherry now only pays out 3 lives instead of 5. This is because the first block completely exits after detecting the third cherry. The NES version specifically checked for the triple cherry and awarded an additional two lives for it (2 for the first 2 cherries, 1 for the general match, and then 2 more as a bonus). This means that the cherry nerf was probably intentional. If it was intended for the triple cherry to continue to pay out 5 lives, either Y would have been incremented by 3 instead of 1, or the BRA instruction would branch to the middle of the third block right where it increments Y by two, in order to get a total of three there.

Here's a flow chart of this code by the way, with the two things I just mentioned highlighted:

Flow chart depicting how SMB2 checks for the slot machine payoutThe gray markings are two potential ways the 5-life triple cherry could be restored.


You can support Retro Game Mechanics Explained on Patreon here! Any and all support is greatly appreciated!


You must log in to comment.