An explanation about different score structures

tl;dr Scores can be saved as decimal, hexdecimal or ASCII, in big or little order, and sometimes may need an additional zero on the end.

So far I’ve looked at the high score files for 1941,1942,1943, Bank Panic, BombJack, Bubble Bobble, Rainbow Islands, Ghosts N Goblins, Pang!, Missile Command, Marble Madness, Hypersports, Robotron, R-Type, R-Type 2, Rygar and Wonderboy. I thought I should write a post about the different formats and structures I’ve seen so far.

The highscore files are stored in a binary file, and from what I’ve read is a snapshot of certain areas of a games memory as identified in the highscore.dat files. This means when read the bytes area displayed as hexdecimal and generally need converting to decimal, but its not as simple as that may seem.

Here’s an example of the scores in Ghosts N Goblins

This image has an empty alt attribute; its file name is image-8.png

The scores here are decimal, the score 00 05 15 00 is the current high score which is 51500, however, 15 as a byte is not 15, but 21 as the values are shown as hex which means a conversion is needed.

def DecConvert(n):
    #converts a hex number to decimal
    tens = int(n / 16)
    dec = n - (tens * 6)
    return dec

For cataloguing these, I use “d” for decimal. However, whilst Ghosts N Goblins is in order, others are not.

Above is the data from Bubble Bobble. The first three bytes is the top score, but in reverse order
10 34 08, which should be 08 34 10 0. The conversion is needed for each byte, but they need to be appended in reverse order. As the intent of reading in the high scores is to display, I append each byte as a string in this case “08” + “34” + “10”. In these examples I categorise them as “dr” for decimal reversed.

The appending zero depends on the game. The vast majority of games don’t have high scores with increments under tens (Robotron being an exception), so there is no need to store the additional character, just add “0” onto the value. In these cases I add a “0” to the categorisation, “d0” for decimal extra zero, or “dr0” for decimal reverse extra zero.

Some games aren’t as concerned with saving memory and use an entire byte for a single digit. Bank Panic is an example of this. Forgive the messiness of the following image

Bank Panic is an interesting example of a high score table as it also saves the round and it saves the duration of the game, but for now I’m just going to focus on the score. The top score in this example is 153350, but the seven bytes used save only one byte. This makes it easy for appending onto a string and for categorisation I label this “o”. I’ll come back to Bank Panic at a later date but the bytes circled in purple and white are seconds. The first is a hexdecimal value storing between 0 and 255 seconds. The second byte is multiples of 256.

The next type is a score saved as ASCII and can be seen in Wonderboy

The blue circled values are the score. 20 is a space, but 30 to 39 are the ASCII values for 0 to 9. As can be seen in the preview, the score is clearly visiable, although it does need an additional zero. Thus the categorisation is “a0” “a” for ASCII and “0” for add an extra zero.

The final example I’ve seen so far is one in hex, and has been documented in detail in Marble Madness

The first three bytes are score. 0038A4 = 14500. The names are more difficult to figure out, but check out the link above.

So that’s it for now. The different formats I’ve got so far are:
“d” = decimal
“dr” = decimal reversed
“d0” = decimal add extra zero
“dr0” = decimal reversed add extra zero
“o” = decimal but one digit per byte
“a0” = ASCII add extra zero
“h” = hexdecimal

And a sneaky peak at the code.

        for j in range(scoreFirstByte,scoreFirstByte + scoreByteLength ): 
          # loop from the first byte that holds the score, to the end of thatsegment
            if numberType == "d" or numberType == "d0": 
              #if the numberType is a decimal and in the correct order
                tempScore = tempScore + str(DecConvert(byteArray[i][j])).zfill(2) 
                # take the previous string and append the byte as a 
                # two digit string on the end
            if numberType == "a0": 
              #if the score is already in ascii
                tempScore = tempScore + charArray[byteArray[i][j]] 
                #append the character onto end of the string
            if numberType == "h": 
              # a hex based score. 0A = 10, 10 = 16
              tempIntScore.append(byteArray[i][j])
              tempScore = str(int.from_bytes(tempIntScore,byteorder='big'))
              #converts the byte array to int 00 38 A4 becomes 14500
            if numberType == "o": 
              #a score the a byte is just one digit
                tempScore = tempScore + str(byteArray[i][j]).zfill(1)
            if numberType == "dr0" or numberType == "dr": 
              #number is decimal but stored in reverse order 
                tempScore =  str(DecConvert(byteArray[i][j])).zfill(2) + tempScore
This entry was posted in Uncategorized. Bookmark the permalink.