The title screen looks somewhat empty, doesn't it? Well, let's fill it with highscores! Lazy as I am I'm storing the highscore scores and names in two separate texts which are simply displayed with the common display routine.
After Game Over we check for a new spot. If we manage to enter the list all lower entries are moved down. For now that happens automatically and only affects the scores. Name entry follows up next.
First the newly added text fields, note that '-' is used as line break and '*' as end of text marker.
Another note: If you default fill high scores always have an easily beatable top score. People like to be better than someone else.
HIGHSCORE_SCORE
!text "00050000-"
!text "00040000-"
!text "00030000-"
!text "00020000-"
!text "00010000-"
!text "00001000-"
!text "00000300-"
!text "00000100*"
HIGHSCORE_NAME
!text "SUPERNATURAL-"
!text "SUPERNATURAL-"
!text "SUPERNATURAL-"
!text "SUPERNATURAL-"
!text "SUPERNATURAL-"
!text "SUPERNATURAL-"
!text "SUPERNATURAL-"
!text "SUPERNATURAL*"
In the title screen layout code we add the display routines:
;display high scores
;x,y pos of name
lda #6
sta PARAM1
lda #10
sta PARAM2
lda #<HIGHSCORE_NAME
sta ZEROPAGE_POINTER_1
lda #>HIGHSCORE_NAME
sta ZEROPAGE_POINTER_1 + 1
jsr DisplayText
;x,y pos of score
lda #25
sta PARAM1
lda #10
sta PARAM2
lda #<HIGHSCORE_SCORE
sta ZEROPAGE_POINTER_1
lda #>HIGHSCORE_SCORE
sta ZEROPAGE_POINTER_1 + 1
jsr DisplayText
And last but not least, the actual checking for a highscore. You'll see that the score is not actually kept in a variable. Instead the screen chars at the display are used to compare against the text.
;------------------------------------------------------------
;check if the player got a new highscore entry
;------------------------------------------------------------
!zone CheckForHighscore
CheckForHighscore
lda #0
sta PARAM1
ldy #0
.CheckScoreEntry
ldx #0
sty PARAM2
.CheckNextDigit
lda SCREEN_CHAR + ( 23 * 40 + 8 ),x
cmp HIGHSCORE_SCORE,y
bcc .NotHigher
bne .IsHigher
;need to check next digit
iny
inx
cpx #HIGHSCORE_SCORE_SIZE
beq .IsHigher
jmp .CheckNextDigit
.NotHigherinc PARAM1
lda PARAM1
cmp #HIGHSCORE_ENTRY_COUNT
beq .NoNewHighscore
;y points somewhere inside the score, recalc next line pos
lda PARAM2
clcadc #( HIGHSCORE_SCORE_SIZE + 1 )
tay
jmp .CheckScoreEntry
.NoNewHighscorejmp TitleScreen
.IsHigher;shift older entries down, add new entry
lda #( HIGHSCORE_ENTRY_COUNT - 1 )
sta PARAM2
;y carries the offset in the score text, position at start of second last entry
ldy #( ( HIGHSCORE_SCORE_SIZE + 1 ) * ( HIGHSCORE_ENTRY_COUNT - 2 ) )
.CopyScore
lda PARAM2
cmp PARAM1
beq .SetNewScore
;copy score
ldx #0
.CopyNextScoreDigit
lda HIGHSCORE_SCORE,y
sta HIGHSCORE_SCORE + ( HIGHSCORE_SCORE_SIZE + 1 ),y
iny
inx
cpx #HIGHSCORE_SCORE_SIZE
bne .CopyNextScoreDigit
tya
sec
sbc #( HIGHSCORE_SCORE_SIZE + HIGHSCORE_SCORE_SIZE + 1 )
tay
dec PARAM2
jmp .CopyScore
.SetNewScore;y points at score above the new entry
tya
clcadc #( HIGHSCORE_SCORE_SIZE + 1 )
tay
ldx #0
.SetNextScoreDigit
lda SCREEN_CHAR + ( 23 * 40 + 8 ),x
sta HIGHSCORE_SCORE,y
iny
inx
cpx #HIGHSCORE_SCORE_SIZE
bne .SetNextScoreDigit
jmp TitleScreen