Home > Z80 Assembly > How To Write ZX Spectrum Games – Chapter 10

## Scores and High Scores

Note: This article was originally written by Jonathan Cauldwell and is reproduced here with permission.

More Scoring Routines

Up until now we have gotten away with an unsophisticated scoring routine.  Our score is held as a 16-bit number stored in a register pair, and to display it we have made use of the Sinclair ROM’s line number print/display routine.  There are two main drawbacks to this method, firstly we are limited to numbers 0-9999, and secondly it looks awful.

We could convert a 16-bit number to ASCII ourselves like this:

```; Show number passed in hl, right-justified.

shwnum ld a,48 (or 32)     ; leading zeroes (or spaces).
ld de,10000         ; ten thousands column.
call shwdg          ; show digit.
ld de,1000          ; thousands column.
call shwdg          ; show digit.
ld de,100           ; hundreds column.
call shwdg          ; show digit.
ld de,10            ; tens column.
call shwdg          ; show digit.
or 16               ; last digit is always shown.
ld de,1             ; units column.
shwdg  and 48              ; clear carry, clear digit.
shwdg1 sbc hl,de           ; subtract from column.
jr c,shwdg0         ; nothing to show.
or 16               ; something to show, make it a digit.
inc a               ; increment digit.
jr shwdg1           ; repeat until column is zero.
shwdg0 add hl,de           ; restore total.
push af
rst 16              ; show character.
pop af
ret```

This method works well, though we’re still limited to a five-digit score of no more than 65535. For a more professional-looking affair complete with any number of leading zeroes we need to hold the score as a string of ASCII digits.

I have used the same scoring technique for something like 15 years now, it isn’t terribly sophisticated but it’s good enough to do what we need. This method uses one ASCII character per digit, which makes it easy to display. Incidentally, this routine is taken from the shoot-em-up More Tea, Vicar?

```score  defb '000000'
uscor  ld a,(hl)           ; current value of digit.
ld (hl),a           ; place new digit back in string.
cp 58               ; more than ASCII value '9'?
ret c               ; no - relax.
sub 10              ; subtract 10.
ld (hl),a           ; put new character back in string.
uscor0 dec hl              ; previous character in string.
inc (hl)            ; up this by one.
ld a,(hl)           ; what's the new value?
cp 58               ; gone past ASCII nine?
ret c               ; no, scoring done.
sub 10              ; down by ten.
ld (hl),a           ; put it back
jp uscor0           ; go round again.```

To use this we point hl at the digit we would like to increase, place the amount we want to add in the b register, then call uscor. For example, to add 250 to the score requires 6 lines:

```; Add 250 to the score.

ld hl,score+3       ; point to hundreds column.
ld b,2              ; 2 hundreds = 200.
call uscor          ; increment the score.
ld hl,score+4       ; point to tens column.
ld b,5              ; 5 tens = 50.
call uscor          ; up the score.```

Simple, but it does the job. Pedants would no doubt point out that this could be done using BCD, and that all the opcodes for this are in the Z80 instruction set.

High Score Tables

High Score routines are not especially easy to write for a beginner, but once you have written one it can be re-used again and again.  The basic principle is that we start at the bottom of the table and work our way up until we find a score that is greater than, or equal to, the player’s score.  We then shift all the data in the table below that point down by one position, and copy our player’s name and score into the table at that point.

We can set the hl or ix register pair to the first digit of the bottom score in the table and work our way comparing each digit to the corresponding one in the player’s score.  If the digit in the player’s score is higher we move up a position, if it is lower we stop there and copy the player’s score into the table one place below.  If both digits are the same we move to the next digit and repeat the check until the digits are different or we have checked all the digits in the score.  If the scores are identical we place the player’s entry in the table one place below.  This is repeated until a score in the table is higher than the player’s score, or we reach the top of the table.

When first initialising a high score table it may be tempting to place your own name at the top with a score that is very difficult to beat.  Try to resist this temptation.  High score tables are for the player to judge his own performance, and there is no point in frustrating the player by making it difficult to reach the top position.