This page is a mirror of Tepples' nesdev forum mirror (URL TBD).

# How to store and draw score

Hi,

New to this forum, I know this question must have been asked many times so maybe you can point me to a post or article explaining this, else, how to I store score (I as more than 1 byte will be needed for sure) and most important how to I translate the value to the score text on screen?
I like to keep it simple for numbers that must be displayed on screen and are not used in complex calculations: each digit is a byte. Additions are performed one byte at a time, and after doing each digit you manually check for overflows (digit > 9) and set the carry so this overflow is carried over to the next digit.

For displaying, you just add each byte to the index of the tile that contains the digit "0", and write the result to the name tables or OAM, depending on whether your score display is drawn as background or sprites.

EDIT: Here's an example of how I would add two 3-digit (i.e. 0 to 999) numbers (num1 = num1 + num2):
Code:
clc
lda num1+0
sta num1+0 ;assume no overflow
sbc #9 ;subtract 10
bcc + ;skip if the result is indeed less than 10
sta num1+0 ;store the corrected result
+   lda num1+1
sta num1+1 ;assume no overflow
sbc #9 ;subtract 10
bcc + ;skip if the result is indeed less than 10
sta num1+1 ;store the corrected result
+   lda num1+2
sta num1+2 ;assume no overflow
sbc #9 ;subtract 10
bcc + ;skip if the result is indeed less than 10
sta num1+2 ;store the corrected result
+

You could use a loop instead of unrolling everything like in the example, and/or make a subroutine that uses pointers to access the numbers, so you can use the same routine for numbers anywhere in RAM.

EDIT 2: A generic subroutine could look something like this:
Code:

ldx #6 ;do 6 digits

lda (Num1), y ;get digit from memory location [Num1+Y]
sta (Num1), y ;assume no overflow
sbc #9 ;subtract 10
bcc + ;skip if the result is indeed less than 10
sta (Num1), y ;store the corrected result
+   iny ;move on to the next digit
dex ;decrement the digit counter

rts ;return
sempressimo wrote:
how to I store score (I as more than 1 byte will be needed for sure) and most important how to I translate the value to the score text on screen?

For a 16-bit value, you store bits 15-8 in one byte and bits 7-0 in another. To add 16-bit numbers, you clear carry, add the low bytes, and then add the high bytes without clearing carry.

To display the score when it has changed, you can convert it to decimal and store the digits in whatever buffer you use to draw text to the screen.
tepples wrote:

700 cycles? That seems kinda steep.
Thanks!
tomaitheous wrote:
tepples wrote:

700 cycles? That seems kinda steep.

It's not quite as steep for something you do only every few frames when you're not also pushing something else to video memory. When you update the score, set the "status bar dirty" flag, and then your "check for dirty things" routine will eventually pick it up and spend the 2.5% of active picture time turning it into a VRAM update.

I also made an 8-bit version in 80 cycles, which allows storing the score in base 100 like this:
Code:
clc
lda score_ones
cmp #100
bcc :+
sbc #100  ; and carry is still set
:
sta score_ones
lda score_hundreds
cmp #100
bcc :+
sbc #100
:
sta score_hundreds

Thwaite uses this base 100 technique.
If you can allow for it, you might be able to split the calculation across several frames.
What tokumaru said...
Quote:
keep it simple for numbers that must be displayed on screen and are not used in complex calculations: each digit is a byte

Don't bother converting to decimal. Just do the math a hex-digit at a time and adjust for overflow (A-F).
Are HUDs usually hard coded, or are they tied to a text engine?
psycopathicteen wrote:
Are HUDs usually hard coded, or are they tied to a text engine?

I'm not sure how others do it, but I use a combination of the two.
That is, I use values starting from \$F0, for hard-coded subroutines in the main text engine.
tokumaru's method of using one byte per digit is called "unpacked BCD", by the way, and it happens to be what I'm using for the clone of Pac-Man I'm currently writing. I simply wrote a routine that adds two BCD numbers together and defined any numbers I was using my code like this:

Code:
Points200: .byte 0,0,0,2,0,0

After points are added, I also have to check if the new score is greater than the current high score. For that, just compare the two scores starting at the leftmost digit. If they're equal, proceed to the next digit, and so on until one of them differs. The carry flag will then tell you which score is higher.

You can look at my code if you like, though it's a bit messy as of this writing. Search for ".macro AddDigit".
What I do was based on a suggetion by Tepples, a sugettion so excellent that I took it !
It's a compromise between storing it in full BCD (each digit is stored separatedly in memory) and storing it in binary.

Each pair of digits is encoded in one byte, and is encoded in binary in the 0-99 range. Since I had to have a binary->display routine for numbers between 0 and 99 anyway, it didn't cost me anything to do that. But thanks to encoding pair of digits, the score is stored in 3 RAM bytes instead of 6. This only works if the number of digits of your score is even.

Castlevania games stores the score in "true" BCD where each digit takes a nybble, but then it's extremely annoying to do addition/substractions operations since BCD mode is absent. I suspect most other games stores each digit separately, since it's the simplest.

Storing in binary would be in my opinion dumb, unless your game uses a lot of binary numbers elsewhere anyway, and as such the "price" of storing a large binary->decimal conversion routine becomes worth paying.