I didn't analyzeWithout analyzing the code, but I'd risk to say that the state of Mario consists of 2 different variables:
Now why are there 2 variables/states for the same thing? probablyBecause there's a transition from big to small and reverse. When the level is completed, the transition isn't done / is aborted before it can happen, and Mario remains big.
Now you can find a comprehensive SMB 6502 disassembly on github. It seems to confirm what I suspected:
PlayerSize = $0754
PlayerStatus = $0756
as you see, there is one variable for speed purposessize and another one for status.
The status variable is changed here:
Shroom_Flower_PUp:
lda PlayerStatus ;if player status = small, branch
beq UpToSuper
cmp #$01 ;if player status not super, leave
bne NoPUp
ldx ObjectOffset ;get enemy offset, not necessary
lda #$02 ;set player status to fiery
sta PlayerStatus
jsr GetPlayerColors ;run sub to change colors of player
ldx ObjectOffset ;get enemy offset again, and again not necessary
lda #$0c ;set value to be used by subroutine tree (fiery)
jmp UpToFiery ;jump to set values accordingly
The size isn't changed there. It's easier to pre-computedone somewhere else.
The transition code uses a statethird variable PlayerChangeSizeFlag
, and as predicted, when changingthe flag reaches a given value, an inversion of the size variable is done (using eor #$01
on it), than to recomputewhich explains that if the size is big, it each timebecomes small:
InitChangeSize:
ldy PlayerChangeSizeFlag ;if growing/shrinking flag already set
bne ExitBoth ;then branch to leave
sty PlayerAnimCtrl ;otherwise initialize player's animation frame control
inc PlayerChangeSizeFlag ;set growing/shrinking flag
lda PlayerSize
eor #$01 ;invert player's size
sta PlayerSize
ExitBoth: rts ;leave
Note that InitChangeSize
is the same routine used to make Mario bigger when he gets a mushroom, specially on those not-that-fast processorsor smaller when he's hit.