Now for some rather small addition, which however feels like a bigger step: Score/Live/Level display.
We already have a text display function, so we add a new default text for the display with initial 00000 values. Note that the score doesn't fit into a byte easily. We only update the numbers on the screen, we do not store the score in another location.
This makes it quite easy to update. For every step we start at the right most digit and increase it. If it hits the digit after '9', set to '0' again and repeat the step on char to the left. For retro sake we don't start at the right most score digit, but the second right most (making increase steps always being 10). If you look closer at a lot of older games you'll see that their right most score digit never changes (Bubble Bobble, etc.)
Small text entry:
TEXT_DISPLAY
!text " SCORE: 000000 LIVES: 03 LEVEL: 00 *"
Increase score bit:
;------------------------------------------------------------
;increases score by A
;note that the score is only shown
; not held in a variable
;------------------------------------------------------------
!zone IncreaseScore
IncreaseScore
sta PARAM1
stx PARAM2
sty PARAM3
.IncreaseBy1
ldx #4
.IncreaseDigitinc SCREEN_CHAR + ( 23 * 40 + 8 ),x
lda SCREEN_CHAR + ( 23 * 40 + 8 ),x
cmp #58
bne .IncreaseBy1Done
;looped digit, increase next
lda #48
sta SCREEN_CHAR + ( 23 * 40 + 8 ),x
dex
;TODO - this might overflowjmp .IncreaseDigit
.IncreaseBy1Donedec PARAM1
bne .IncreaseBy1
;increase complete, restore x,y
ldx PARAM2
ldy PARAM3
rts
Another neat effect is the display of the level number and lives. Due to the hard coded screen position I've made two specialized functions instead of a generic one.
Interesting anecdote:
When I first had to display a decimal number I was stumped due to no available div operator. You actually need to divide by yourself (subtract divisor and increase count until done). That's what the call to DivideBy10 does.
;------------------------------------------------------------
;displays level number
;------------------------------------------------------------
!zone DisplayLevelNumber
DisplayLevelNumber
lda LEVEL_NR
clcadc #1
jsr DivideBy10
pha
;10 digit
tya
clcadc #48
sta SCREEN_CHAR + ( 23 * 40 + 37 )
pla
clcadc #48
sta SCREEN_CHAR + ( 23 * 40 + 38 )
rts
;------------------------------------------------------------
;displays live number
;------------------------------------------------------------
!zone DisplayLiveNumber
DisplayLiveNumber
lda PLAYER_LIVES
jsr DivideBy10
pha
;10 digit
tya
clcadc #48
sta SCREEN_CHAR + ( 23 * 40 + 24 )
pla
clcadc #48
sta SCREEN_CHAR + ( 23 * 40 + 25 )
rts
;------------------------------------------------------------
;divides A by 10
;returns remainder in A
;returns result in Y
;------------------------------------------------------------
!zone DivideBy10
DivideBy10
sec
ldy #$FF
.divloop
iny
sbc #10
bcs .divloop
adc #10
rts