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!
Have 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:
Seeing 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:
The 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!