Routine for handling large scores?

edited March 2014 in Development
I want to store various numbers for scores and levels etc. Some of these can be very large so will need to be held in multiple bytes. I need to be able to increment and decrement these values. Anyone got some useful z80 routines before I start writing my own?
Post edited by Mr Millside on

Comments

  • edited March 2014
    Useful tip :

    Often scores are increased not by 1,2,3 but by bigger numers - like 100 points for shooting an enemy.

    If he last digits are always 0s you don't need to store them as part of actual number. Just print the 0s on the screen and print the part that changes in front on them

    By adding 2 dumb zeroes you can have up to 6,5 million score held only in 2 bytes, instead of usual 65536
  • edited March 2014
    I simply store scores as one byte per digit. It makes them a hell of a lot easier to print on the screen. I store them as lowest digit first. I also use a special code (e.g. 10) to signify an usused higher digit that doesn't need printing. Or if your font for scores goes 0-9, character 10 can be a blank space, instead of printing leading zeroes.

    Then I have a routine that can add two scores together, working from the bottom byte up, and accounting for carrying and to convert '10s' as '0s' before adding to them.

    Then I write the additive score into a temporary buffer (which should mostly be zeroes - typically you only set one byte to set a score, e.g. 100), call the add routine, and re-display the score.

    The only other thing you might need is a byte-by-byte comparison that can tell if one score is bigger than another. You don't need a full maths library.
    Joefish
    - IONIAN-GAMES.com -
  • edited March 2014
    For most situations that would work fine. Unfortunately I also need numbers that count down in ones. I have a bonus that decreases over time (starting at 100). Although this would fit in a single register I still need code to convert from a number into the appropriate number image.

    At the moment I use this code to increment numbers held in a byte array:
     ; a = the amount to increase the number block by  EG: 1 = '10' 2 = '20' 20 = '200' etc 
     ; hl = points to a column of the score, level or bonus number block
     IncNumberBlock  ld b, 0
                     add a, (hl)
                     ld (hl), a
                     cp 10
                     ret c
     DoDecTen        inc b
                     sub 10
                     cp 10
                     jp nc, DoDecTen
                     ld (hl), a
                     dec hl
                     ld a, b
                     jp IncNumberBlock
      
      
     ScoreData1      defb 0 ; Start of the Score data block (6 bytes)
     ScoreData2      defb 0
     ScoreData3      defb 0
     ScoreData4      defb 0
     ScoreData5      defb 0
     ScoreData6      defb 0
    
    This works fine for increments but I was having problems creating similar code to do a decrement. I thought that I may start from scratch then thought I?d ask here to see if anyone has some code that?ll do what I need.
  • edited March 2014
    Unfortunately I also need numbers that count down in ones. I have a bonus that decreases over time (starting at 100).

    I've seen quite a few games that simply store scores and timers in ASCII. Something like
    dec_timer:
    	ld hl,time
    	
    next_digit:	
    	dec (hl)
    	ld a,$2f	; '0'-1
    	cp (hl)
    	ret nz		; not got below '0' so done
    	ld (hl),'9'
    	inc hl
    	jr next_digit
    	
    time:
    	defm '001'	; 100 in ASCII backwards 
    

    Jon
  • edited March 2014
    I wrote a routine (or more likely altered something I found in a game!) about 25 years ago that's on one of my MGT disk images. If I can find it I'll plonk a link to the image here. It just took a value in a 16 bit register and added it to a series of bytes (from 2 to 256) representing the individual digits of the score.

    i.e.

    score bytes 00 00 02 01 00 08 07 (representing 21087)

    Add HL=001A (26)

    score now= 00 00 02 01 01 01 03 (representing 21113)

    simples!:)
  • edited March 2014
    Just have the number 100 stored as 3 bytes and write a bit of code that can subtract one from it, and do the carrying.

    Something else you might consider with a byte-per-digit system is, instead of adding or subtracting a number of the same length, write code that can add or subtract one digit at an arbitrary point in the score, and do the carrying. So you can subtract 1 or add 5000 just by targeting one significant digit. Th eonly drawback would be, say, to add 250 you'd need to call it twice - once for the 2 and again for the 5.
    Joefish
    - IONIAN-GAMES.com -
  • edited March 2014
    Another vote for storing as ASCII, can be as long as you like and easy to manipulate digits.

    I'd recommend having a butcher's at Jonathan Cauldwell's routines via Arjun's chuntey blog. The first one shows using 65535 max but the second one I'm recommending uses the ASCII, here it is in fact:
    ; 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.
           ret
    
    score  defb '000000'
    uscor  ld a,(hl)           ; current value of digit.
           add a,b             ; add points to this 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.
    
  • edited March 2014
    I also use Jonathan's routine in my games. I even converted it to MC68K for my Amiga projects :)
  • edited March 2014
    Here's a BASIC routine which adds or subtracts 16-digit integers. Just change every occurrence of '16' to the maximum size of your numbers. Lines 41-45 do the operation on a single pair of digits and add in any carry leftwards. It just adds the ASCII values for the digits, so the operation is adjusted by -48 when adding and +48 when subtracting so that the result maintains the correct ASCII code for the digit.
      12 INPUT "operation [+-]: ";o$'
               "number 1: "'y$'
               ("plus" AND (o$="+" OR o$<>"-"));("minus" AND o$="-")'
               "number 2: "'z$:
         LET o$="+-"((o$="-")+1): LET n$="-+"((o$="-")+1)
      15 LET y$=y$( TO 16-(16-LEN y$ AND LEN y$<16))
      16 LET z$=z$( TO 16-(16-LEN z$ AND LEN z$<16))
      20 LET a$="0000000000000000"(TO 16-LEN y$)+y$
      21 LET b$="0000000000000000"(TO 16-LEN z$)+z$
      30 PRINT AT 0,0;a$;TAB 15;o$'b$;TAB 15;"="'',,
    
      40 FOR d=16 TO 2 STEP -1
      41 LET aa=CODE a$(d): LET bb=CODE b$(d): LET res=VAL ("aa"+o$+"bb"+n$+"48")
      43   IF res<48 THEN LET res=res+10: LET b$(d-1)=CHR$ (CODE b$(d-1)+1)
      44   IF res>57 THEN LET res=res-10: LET b$(d-1)=CHR$ (CODE b$(d-1)+1)
      45   LET a$(d)=CHR$ res: PRINT AT 4,d-1;a$(d)
      49 NEXT d
    
      51 LET aa=CODE a$(d): LET bb=CODE b$(d): LET res=VAL ("aa"+o$+"bb"+n$+"48")
      53 IF res<48 THEN LET res=res+10: PRINT FLASH 1; INK 2;"underflow"
      54 IF res>57 THEN LET res=res-10: PRINT FLASH 1; INK 2;"overflow"
      55 LET a$(d)=CHR$ res: PRINT AT 4,d-1;a$(d)
      59 GO TO 12
    
  • edited March 2014
    From one of my games:
    TypeScore
    	LD HL,(Score)
    	EXX
    	LD HL,16384+67				;screen position
    	EXX							
    	
    	LD DE,10000
    	CALL TypeScoreDigit
    	LD DE,1000
    	CALL TypeScoreDigit
    	LD DE,100
    	CALL TypeScoreDigit
    	LD DE,10
    	CALL TypeScoreDigit
    	LD DE,1
    	CALL TypeScoreDigit
    	RET	
    
    TypeScoreDigit
    ;DE-divider:10000,1000 and so on
    	XOR A
    TypeScoreDigit11
    	INC A						;find digit
    	SBC HL,DE
    	JR NC,TypeScoreDigit11
    	ADD HL,DE
    	DEC A
    	
    	EXX
    	PUSH HL						;store screen adress
    	CALL TypeNumber
    	POP HL
    	INC L						;screen position right
    	EXX
    	RET
    
  • edited March 2014
    Ralf wrote: »
    From one of my games:
    TypeScore
    	LD HL,(Score)
    	EXX
    	LD HL,16384+67				;screen position
    	EXX							
    	
    	LD DE,10000
    	CALL TypeScoreDigit
    	LD DE,1000
    	CALL TypeScoreDigit
    	LD DE,100
    	CALL TypeScoreDigit
    	LD DE,10
    	CALL TypeScoreDigit
    	LD DE,1
    	CALL TypeScoreDigit
    	RET	
    
    TypeScoreDigit
    ;DE-divider:10000,1000 and so on
    	XOR A
    TypeScoreDigit11
    	INC A						;find digit
    	SBC HL,DE
    	JR NC,TypeScoreDigit11
    	ADD HL,DE
    	DEC A
    	
    	EXX
    	PUSH HL						;store screen adress
    	CALL TypeNumber
    	POP HL
    	INC L						;screen position right
    	EXX
    	RET
    


    Yep, that's how I did the number printing in Bozxle. :)
    So far, so meh :)
Sign In or Register to comment.