Programming:Display and update Scores

From CPCWiki - THE Amstrad CPC encyclopedia!
Revision as of 18:32, 20 September 2007 by Executioner (Talk | contribs) (Multiple BCD Bytes)

Jump to: navigation, search

Methods for Storing Scores in Memory

There are a number of methods for storing a Score in memory, here are a few examples:

A Single Word

This is the simplest and smallest method for storing the score in memory, but it has a couple of disadvantages over some other methods. It can only hold a score up to 65535 (although you can add an extra '0' or two on the display to make that 655350 or 6553500), converting it to digits for display requires a relatively slow algorithm, and adding extra lives every 10000 points for example can take a complex routine. The advantage of using a straight Word is that the maths required to add points to the score is very simple and fast.

To define the score:

.score dw 0

To add some points (in BC):

.add_score_bc
ld hl,(score)
add hl,bc
ld (score),hl
ret

To display the score requires converting to a decimal:

.show_score
ld hl,score
ld bc,-10000
call show_digit
ld bc,-1000
call show_digit
ld bc,-100
call show_digit
ld bc,-10
call show_digit
ld a,l
add '0'
jp show_char

.show_digit
ld a,'0' - 1
.inc_digit
inc a
add hl,bc
jr nc,inc_digit
or a
sbc hl,bc
add '0'
jp show_char	; This assumes the show_char routine doesn't corrupt HL

Checking for every 10000 points is complicated, this would normally done in the add_score routine, and I'm not going to write the code. It would however, be quite simple to add an extra life every multiple of 256 units (eg. 10240 points) by checking the most significant byte. eg:

.add_score_bc
ld hl,(score)
ld a,h
add hl,bc
ld (score),hl
sub h
cp 2
ret c
ld hl,lives
inc (hl)
ret

A Double Word

Like the above method, this provides a simple and efficient way to store and add points, but the routine required to convert the number to decimal for display is even more difficult, as is the extra lives every 10000 points.

To define the score:

.score ds 4

To add BC points to the score:

.add_score_bc
ld hl,(score)
add hl,bc
ld (score),hl
ret nc
ld hl,(score + 2)
inc hl
ld (score + 2),hl
ret

Displaying the score is much more tricky since it involves a lot of DWord subtractions etc. Most Z80 assemblers (including WinAPE) can't handle DWord values, so you need to get your calculator out to figure out what the values are to subtract for successive digits. The score can go as high as 4294967295, but I wouldn't recommend doing the maths for all possible digits. The code to display a DWord value is too complicated for this document.

A Single BCD Word

This is similar to the above method, but the score is treated as Binary Coded Decimal. It's main disadvantage is that it can hold even less values than the single Word, restricting the score to 10000 possible combinations (one again with extra zeroes if required). Depending on the type of game and difficulty, this could be a good method to use. It's easy to store in memory and pass around, displaying and adding points are all relatively easy.

To define the score is exactly the same as for a Single Word:

.score dw 0

Adding BC points is also fairly straightforward (here with the extra life check every 1000 units):

.add_score_BC
ld hl,(score)
ld d,h
ld a,l
add c
daa
ld l,a
ld a,h
adc b
daa
ld h,a
ld (score),hl
sub d
cp #10
ret c
ld hl,lives
inc (hl)
ret

And the routine to display the score:

.show_score
ld hl,(score)
.bcd_hl
ld a,h
call bcd_a
ld a,l
.bcd_a
ld h,a
rra:rra:rra:rra
and #0f
add '0'
call show_char
ld a,h
and #0f
add '0'
jp show_char

A Double BCD Word

This is actually one of the best methods of storing and displaying a score since the maths and display methods remain fairly simple, and your score can now hold up to 8 digits. Luckily the Z80 has just enough fast 16 bit registers (ie. Non-index registers) to be able to handle all the things you require.

To define the score:

.score ds 4

To add BC points to the score (here with the extra life check every 10000 units):

ld hl,(score)
ld a,l
add c
daa
ld l,a
ld a,h
adc b
daa
ld h,a
ld (score),hl
ret nc
ld hl,lives
inc (hl)
ld hl,(score + 2)
ld a,l
add 1
daa
ld l,a
ld a,h
adc 0
daa
ld h,a
ld (score + 2),hl
ret

Displaying the score is relatively simple too, using the same routine as above:

.show_score
ld hl,(score + 2)
call bcd_hl
ld hl,(score)
.bcd_hl
.
.
.

Multiple BCD Bytes

This is very similar to the above method, but the values are stored and manipulated in a slightly different way. With this method, you can determine exactly how many digits you require. Maths is pretty straightforward, as is extra lives and display. One advantage this method has is that if you want to add 100 to the score, you don't have to add the two zeroes since you can start at the second BCD digit. With this method, you can store the score either little-endian (least significant bytes first) or big-endian. Big-endian has the advantage that you can read the score in a memory editor left-to-right. eg. 1234500 points is displayed as 01 23 45 00. This can make debugging easier.

To define the score (6 digits):

.score ds 3

To add C points to the score:

ld b,2		; This is the number of score bytes - 1
.add_part
ld hl,score + 2
ld a,(hl)
add c
daa
ld (hl),a
ret nc
.add_loop
dec hl
ld a,(hl)
adc 0
daa
ld (hl),a
djnz add_loop
ret

Displaying the score is relatively simple too, using the same routine as above:

.show_score
ld hl,score
ld b,3
.show_loop
ld a,(hl)
inc hl
call bcd_a
djnz show_loop
ret

More to come...

Executioner 01:27, 21 September 2007 (CEST)