; Turbomania. ; (C) Copyright 2005 Jonathan Cauldwell. ; A somewhat late entry for the 2005 minigame programming contest, ; written for the ZX Spectrum 16/48/128K in 1K of code. ; Project started 30.09.2005 @ 17:12 BST. ; Project completed 01.10.2005 @ 15:06 BST. ; Second version started 07.10.2005 @ 17:25 BST. ; Second version completed 30.10.2005 @ 15:26 GMT. ; Constants. YELLOW equ 49 ; dull yellow attribute. YELLOB equ YELLOW + 64 ; bright yellow attribute. CYAN equ 41 ; dull cyan attribute. AT equ 98 ENDCHR equ 99 EFFCTR equ 16415 ; chequered flag effect counter. EFFPOS equ EFFCTR+256 ; chequered flag effect position. ; Main game code. org 24250 ; Clear the screen to give a pleasant blue background. menusc call chf ; do fancy screen clear. menu1 ld hl,23693 ; system variable for attributes. ld (hl),79 ; want white ink on bright blue background. call 3503 ; clear the screen. xor a ; zero is code for black. call 8859 ; set the border colour. call silenc ; make sure there's no noise. ld hl,mscr ; menu screen. inc (hl) ; choose next one. ld a,(hl) ; get new option. and 3 ; 4 screen cycle. jp z,dishs ; time to show high score. cp 2 ; is it sequence 2? jp z,demom ; yes, let's activate the demo mode. ; Menu screen. ld hl,mtxt0 ; menu text. call dfont ; show the text. menu ld b,0 ; delay of approx 10 seconds. menu0 halt push bc ; store count. call 654 ; keyboard routine. pop bc ; restore count. ld a,e ; test key returned. cp 36 ; keyboard selected? jp z,game cp 28 ; Kempston joystick option? jp z,game cp 20 ; is it redefine keys? jp z,redkey ; redefine them then. djnz menu0 jp menu1 mscr defb 0 ; menu screen number. redkey call 654 ; D=shift, E=key. ld a,e ; get value. inc a ; is it 255? jr nz,redkey ; yes - loop until key is released. call 3503 ; ROM routine to clear screen. ld hl,keys ; redefined keys. ld de,keys+1 ld bc,5 ld (hl),255 ldir ; clear keys. ld hl,ktxt0 ; prompt to display. call dfont ; display prompt for next key. call redky0 ; wait for keypress. ld a,e ld (keys),a ; set this as up key. call noise ld hl,ktxt1 ; prompt to display. call dfont ; display prompt for next key. call redky0 ; wait for keypress. ld a,e ld (keys+1),a ; set this as down key. call noise ld hl,ktxt2 ; prompt to display. call dfont ; display prompt for next key. call redky0 ; wait for keypress. ld a,e ld (keys+2),a ; set this as left key. call noise ld hl,ktxt3 ; prompt to display. call dfont ; display prompt for next key. call redky0 ; wait for keypress. ld a,e ld (keys+3),a ; set this as right key. call noise ld hl,ktxt4 ; prompt to display. call dfont ; display prompt for next key. call redky0 ; wait for keypress. ld a,e ld (keys+4),a ; set this as spin key. call noise ld hl,ktxt5 ; prompt to display. call dfont ; display prompt for next key. call redky0 ; wait for keypress. ld a,e ld (keys+5),a ; set this as stake key. call noise jp menusc ; back to main menu now. ktxt0 defb AT,2,9 defb 16,18,5,19,19,0,11,5,25,0,6,15,18,37,37,37 defb AT,5,11 defb 21,16,AT,5,21 defb ENDCHR ktxt1 defb AT,7,11 defb 4,15,23,14,AT,7,21 defb ENDCHR ktxt2 defb AT,9,11 defb 12,5,6,20,AT,9,21 defb ENDCHR ktxt3 defb AT,11,11 defb 18,9,7,8,20,AT,11,21 defb ENDCHR ktxt4 defb AT,13,11 defb 20,18,1,14,19,6,15,18,13,AT,13,21 defb ENDCHR ktxt5 defb AT,15,11 defb 16,1,21,19,5,AT,15,21 defb ENDCHR ktxt6 defb 2,8,25,33,32,20,7,22 defb 14,10,21,34,31,18,6,3 defb 13,11,9,35,30,5,4,24 defb 37,12,15,36,29,23,19,26 defb 37,37,16,27,28,17,1,37 redky0 call 654 ; D=shift, E=key. ld a,e ; get value. inc a ; is it 255? jr z,redky0 ; yes - loop until something pressed. ld a,(keys) ; first key. cp e ; is this the same? jr z,redky0 ; yes - try again. ld a,(keys+1) ; down key. cp e ; is this the same? jr z,redky0 ; yes - try again. ld a,(keys+2) ; left key. cp e ; is this the same? jr z,redky0 ; yes - try again. ld a,(keys+3) ; right key. cp e ; is this the same? jr z,redky0 ; yes - try again. ld a,(keys+4) ; fire key. cp e ; is this the same? jr z,redky0 ; yes - try again. ld a,(keys+5) ; stake key. cp e ; is this the same? jr z,redky0 ; yes - try again. push de ld hl,ktxt6 ; table of key names. ld d,0 add hl,de ; name of key in look-up table. ld a,(hl) ; want result in DE. call dchar ; routine to display character. pop de ret ; Key test routine. ktest ld c,a ; key to test in c. and 7 ; mask bits d0-d2 for row. inc a ; in range 1-8. ld b,a ; place in b. srl c ; divide c by 8 srl c ; to find position within row. srl c ld a,5 ; only 5 keys per row. sub c ; subtract position. ld c,a ; put in c. ld a,254 ; high byte of port to read. ktest0 rrca ; rotate into position. djnz ktest0 ; repeat until we've found relevant row. in a,(254) ; read port (a=high, 254=low). ktest1 rra ; rotate bit out of result. dec c ; loop counter. jp nz,ktest1 ; repeat until bit for position in carry. ret ; User defined keys. keys defb 28,29,27,35,16,1 contrl defb 0 ; control method, 0=keys, 1=Kempston. ; Noise - beeper white noise low. noise ld b,16 ; length of step. noise0 call random ; random value. and 248 ; don't change border colour. out (254),a ; write to port. ld a,250 noise1 dec a jr nz,noise1 djnz noise0 ret noisf ld hl,440 ; start pitch. ld b,20 ; number of outer loops. noisf1 push bc ; puch loop counter onto stack. ld b,50 ; inner loops. noisf0 push hl ; store pitch. ld de,4 ; duration. call 949 ; ROM beeper routine. pop hl ; restore pitch. inc hl ; pitch down slightly. djnz noisf0 ; repeat inner loop. ld de,65526 ; displacement to next pitch. add hl,de ; next starting pitch. pop bc ; restore outer loop from stack. djnz noisf1 ; repeat until done. ret ; Screeching sound effects. noisg ld hl,320 ; starting pitch. ld b,4 ; outer loops. noisg1 push bc ; outer loop counter. ld b,40 ; number of iterations. noisg0 push hl ; store pitch. push bc ; store loop counter. ld de,0 ; duration zero. call 949 ; ROM beeper routine. pop bc ; restore loop counter. pop hl ; restore stored pitch. inc hl ; pitch going down. djnz noisg0 ; repeat inner loop. ld de,65480 ; distance to next pitch. add hl,de ; adjust pitch. pop bc ; restore outer loop counter. djnz noisg1 ; one less to do. ret ; Menu text. mtxt0 defb AT,1,11 defb 20,21,18,2,15,13,1,14,9,1 defb AT,7,9 defb 28,37,0,11,5,25,2,15,1,18,4 defb AT,9,9 defb 29,37,0,11,5,13,16,19,20,15,14 defb AT,11,9 defb 30,37,0,18,5,4,5,6,9,14,5,0,11,5,25,19 defb AT,23,3 defb 39,0,29,27,27,32,0,10,15,14,1,20,8,1,14 defb 0,3,1,21,12,4,23,5,12,12 defb AT,16,13 defb 19,5,12,5,3,20 defb ENDCHR ; Display high-score table. dishs ld hl,hstxt0 ; title at the top. call dfont ; show header. ld b,6 ; number of entries to display. ld hl,hstab ; high score table. dishs0 push bc push hl ld a,9 ; top of table. sub b rlca inc a ld (dispx),a ; set vertical position. ld a,8 ; column number. ld (dispy),a ; set horizontal now. ld bc,8 ; length of name. call hstxt ; display name. ld hl,dispy ; y coordinate. inc (hl) ; move along one. pop hl push hl ld de,8 ; length of each name. add hl,de ; add to pointer to find score. ld bc,6 ; number of digits in score. call hstxt ; show digits. pop hl pop bc ld de,14 ; distance to next name. add hl,de djnz dishs0 ; repeat for all entries. jp menu ; return to menu. hstxt push bc ; store registers. push hl ld a,(hl) ; get char. call dchar ; display it. pop hl ; restore registers. pop bc inc hl ; point to next one. dec c ; one less char. jr nz,hstxt ; repeat. ret ; High score table text. hstxt0 defb AT,2,10 defb 15,21,20,0,9,14,0,6,18,15,14,20 defb ENDCHR hstab defb 10,15,14,1,20,8,1,14 defb 27,27,27,32,27,27 defb 7,1,25,12,5,0,0,0 defb 27,27,27,31,27,27 defb 7,1,18,25,0,0,0,0 defb 27,27,27,30,27,27 defb 13,5,7,8,1,14,0,0 defb 27,27,27,29,27,27 defb 10,1,3,15,2,0,0,0 defb 27,27,27,28,27,27 defb 9,1,14,0,0,0,0,0 defb 27,27,27,27,27,32 hstxt2 defb AT,6,9 defb 7,18,5,1,20,0,4,18,9,22,9,14,7 defb AT,9,8 defb 5,14,20,5,18,0,25,15,21,18,0,14,1,13,5 defb ENDCHR hstxt3 equ $ ; Try high score table to see if score qualifies. tryhs ld hl,hstab+78 ; end of high score table. ld b,6 ; number of scores to check. tryhs0 push bc ; store list counter. ld de,points ; player's score. push hl ; store position in table. ld b,6 ; digits to compare. tryhs3 ld a,(de) ; player's score digit. cp (hl) ; table digit. jr c,tryhs1 ; score is greater. jr nz,tryhs2 ; score is lower. inc hl ; digit is the same - go to next column. inc de djnz tryhs3 jr tryhs1 ; score is same, first registered comes first. tryhs2 pop hl ld de,65522 ; 65536 - 14. add hl,de ; subtract 14 - next entry in table. pop bc djnz tryhs0 ld hl,hstab+8 ; top of table. tryhs4 push hl ld de,65528 add hl,de ld d,h ld e,l ld hl,hstab+84 and a sbc hl,de ld b,h ld c,l ld hl,hstab+69 ld de,hstab+83 lddr pop hl ld de,points ; player's score. ex de,hl ld bc,6 ; number of digits to transfer. ldir ; copy to table. ld hl,65522 ; minus 14. add hl,de ; go back to start of name. ex de,hl ; Address of name in de. push de call ent ; enter name. pop de ld hl,buffer ; place where name is stored. ld bc,8 ; length of name. ldir ; copy to high score table. ret tryhs1 pop hl pop bc ld a,b cp 6 ; failed at bottom of table? ret z ; yes - no high score then. ld de,14 ; next element down. add hl,de ; point to next in list. jr tryhs4 ; put in table at this point. nament defb AT,16,12 buffer defb 8,5,12,12,15,0,0,0 defb ENDCHR gotxt defb AT,23,0 defb 0,0,0,0,0,0 defb 7,0,1,0,13,0,5,0 defb 0,0,0,0 defb 0,15,0,22,0,5,0,18 defb 0,0,0,0,0,0 defb ENDCHR txbuf defw buffer ent call 3503 ; clear screen. ld hl,hstxt2 ; high score text. call dfont ; prompt for name. ld hl,buffer ; input line in buffer. ld (txbuf),hl ld de,buffer+1 ; second char of buffer. ld bc,7 ; 8 characters maximum. ld (hl),b ; make first character a space. ldir ; copy to rest of buffer. xor a ld (23560),a ; clear keypress. ld (23658),a ; turn off caps lock. ent00 call curon ; switch on cursor. ld hl,nament ; string we're typing in. call dfont ; display on screen. ld hl,23560 ; keypress system variable. ld a,(hl) ; what was key pressed? and a ; anything pressed? jr z,ent00 ; no, wait until it is. ld (hl),0 ; clear buffer. ld c,a ; store keypress. call curoff ; remove cursor. ld a,c ; restore keypress. cp 13 ; enter. jp z,ent13 cp 8 ; left. jp z,ent08 cp 9 ; right. jp z,ent09 cp 12 ; delete. jp z,ent12 cp 32 ; is it space? call z,ent32 ; frig a space character. sub 96 ; below space/letter 'A'? jr c,ent00 ; yes, don't accept. ld c,a ; put key in c. cp 27 ; above letter 'Z'? jr nc,ent00 ; yes, that's invalid. ent00a ld a,(buffer+7) ; last char. and a ; is it space? jp nz,ent00 ; no more room on line. ld hl,(txbuf) ; pointer to place in string. ent00b ld a,(hl) ; get character we'll overwrite. ld (hl),c ; place character there. ld c,a ; get character overwritten. inc hl ; point to next in string. ld a,(hl) ; get this character. cp ENDCHR ; end of buffer? jr nz,ent00b ; no, keep going. ld hl,(txbuf) ; text position. call curoff ; cursor is already off, just want address. ld a,l ; put into accumulator. cp 19 ; reached end of string? jp z,ent00 ; yes, cursor is at end of string. ld hl,(txbuf) ; get buffer position. inc hl ; point to next one. ld (txbuf),hl ; store pointer. jp ent00 ; wait for next character. ent08 call curoff ; get address in l. ld a,l ; y position now in accumulator. cp 12 ; reached the minimum? jp z,ent00 ; yes. ld hl,(txbuf) ; buffer position. dec hl ; back a character. ld (txbuf),hl ; new position. jp ent00 ; back to input routine. ent09 call curoff ; get address in l. ld a,l ; y position now in accumulator. cp 19 ; reached the end? jp z,ent00 ; yes, wait for next character. ld hl,(txbuf) ; text pointer. inc hl ; next character. ld (txbuf),hl ; point there. jp ent00 ; next letter. ent12 call curoff ; position on screen. ld a,l ; y position now in accumulator. cp 12 ; at left edge? jp z,ent00 ; yes, no more please. ld hl,(txbuf) ; text position. ld d,h ; copy to de. ld e,l dec hl ; left a character. ld (txbuf),hl ; new pointer. ent12b ld a,(de) ; get buffer character. cp ENDCHR ; reached the end? jr z,ent12a ; no, keep going. ld (hl),a ; write new character. inc hl ; next in buffer. inc de ; ditto. jr ent12b ; repeat uuntil end of string. ent12a ld (hl),0 ; one character below letter A. jp ent00 ent13 ld hl,buffer ; point to buffer. ld b,8 ; length. ent13b ld a,(hl) ; get char. and a ; is it a space? jr nz,ent13a ; no, something entered then. inc hl ; next char. djnz ent13b ; repeat for entire buffer. ; Oh dear, how boring. Let's put something else in for him. entemp ld hl,namep ; blank name substitute. entob0 ld de,buffer ; text buffer. ld bc,8 ; number of chars to copy. ldir ; copy name into buffer. ret ent13a ld hl,buffer ; point to buffer. call word ; find word in list. and a ; is it recognised? ret z ; no, it's okay as it is then. cp 2 ; is it naughty? jr z,entob ; replace rudeness. cp 4 ; is it the cheat? ret nz ; no, it's okay as it is then. xor a ; opcode for a NOP. ld (cheatb),a ; set cheat mode. ld hl,namec ; cheat name. jr entob0 entob ld hl,name ; obscenity substitute. jr entob0 ; use this name instead. ent32 ld a,96 ; 96 - 96 = 0, SPACE code in our font. ld c,a ; put it into c register as well. ret curoff ld b,0 ; cursor off. jr curset ; draw cursor. curon ld b,124 ; cursor on. curset ld hl,(txbuf) ; buffer position. ld de,buffer-12 ; buffer minus 12 chars for centre of screen. and a ; clear carry. sbc hl,de ; find number of chars along. ld h,87 ; final segment, last line. ld (hl),b ; set sursor. ret ; Check if a known word has been entered. ; On entry HL points to the buffer. word ld de,vocab ; table of naughty words. word3 ld hl,buffer ; name we wish to check. word0 ld a,(de) ; DE=char in vocabulary table. inc de cp (hl) ; do they match? jr nz,word1 ; no - find next word. cp 255 ; end of listed word? jr z,word2 ; yes - try next word in table. inc hl ; next buffer char. jr word0 word1 cp 255 ; end of word? jr z,word4 ; yes - return verb number. word2 ld a,(de) ; character in lexicon. inc de ; point to next one. cp 255 ; have we reached end of word in table? jr nz,word2 ; no, loop round again. ld a,(de) ; which word is this? inc de ; point to start of first letter. cp 255 ; is it the last one? jr nz,word3 ; no. xor a ; return 0 (not found) in A. ret word4 ld a,(de) ; name number returned in A. ret ; This is the recognised naughty word list. vocab defb 6,21,3,11,255,2 ; swear words. defb 3,21,14,20,255,2 ; swear words. defb 2,15,12,12,15,3,11,19,255,2 defb 1,18,19,5,255,2 defb 19,8,9,20,255,2 defb 23,1,14,11,255,2 defb 18,7,255,4 ; RG cheat. defb 10,16,13,255,4 ; JPM cheat. defb 2,6,7,255,4 ; BFG cheat. defb 5,4,6,5,0,19,21,24,255,4 ; EDGE SUX cheat. defb 255,255 namec defb 16,5,20,18,15,12,0,0 ; petrol. namep defb 3,18,1,19,8,5,4,0 ; crashed. name defb 23,8,5,5,12,9,5,0 ; wheelie. ; Chequered flag screen clear routine. chf xor a ; start at zero. ld (EFFCTR),a ; store counter. chf3 xor a ; top coord. ld (dispx),a ; set it up. ld a,(EFFCTR) ; effect start coord. ld (EFFPOS),a ; put in y coord. chf1 ld hl,chpat ; default pattern start. ld a,(EFFPOS) ; effect start coord. and a ; anything to display on this line? jr z,chf2 ; no, we're done. dec a ; one column across. ld (EFFPOS),a ; new position. cp 32 ; past max? jr c,chf4 ; no, we're okay. ; Pattern starting to move off left edge, so we need the displacement ; to the start of the pattern. sub 32 ; always 32 on screen. ld e,a ; displacement from pattern start. cp 32 ; reached max extent of pattern? jr c,chf6 ; no, we're okay. ld e,32 ; stick here. chf6 ld d,0 add hl,de ; point to new pattern start. xor a ; start at left edge. jr chf5 ; Pattern hasn't scrolled entirely onto screen, so we need to find ; horizontal position at which to start. chf4 ld b,a ; effect in b. ld a,31 ; maximum right coordinate. sub b ; find coordinate. ; Set up y coordinate and transfer pattern across. chf5 ld (dispy),a ; put in y coord. call atadd ; attribute address in de. chf0 ldi ; transfer to screen. ld a,e ; low byte of attribute position. and 31 ; reached end of line? jr nz,chf0 ; not yet we haven't. ld a,(dispx) ; coords for next line. inc a ; one line down. ld (dispx),a ; next line. cp 24 ; reached the end? jr c,chf1 ; not yet, keep going. ; Now for the next frame. chf2 halt ; pause. ld a,(EFFCTR) ; frame counter. inc a ; next one. ld (EFFCTR),a ; next value. cp 89 ; reached the end yet? ret nc ; job done then. jr chf3 ; no, keep going. chpat defb 127,0,127,0,127,0,127,0,127,0,127,0,127,0,127,0 defb 127,0,127,0,127,0,127,0,127,0,127,0,127,0,127,0 defb 73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73 defb 73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73 ; Demo mode. demom ld a,45 ; nine plus code for keyboard. game sub 36 ; 36 is code for keyboard. ld (contrl),a ; set control. ld hl,points ; score. ld de,points+1 ; next digit. ld (hl),27 ; set first char to zero. ld bc,5 ; extra digits. ldir ; copy to rest of string. xor a ; zeroise accumulator. ld (levno),a ; set level number. ld (chance),a ; set up "last chance flag" for poor players. ; Seed the random number generator. ld a,(23672) ; low byte of clock. ld (seed),a ; seed the random number generator. ; Now shuffle end-of-level games around. ld b,20 ; loop iterations. game0 push bc ; keep count. call random ; random number. and 3 ; in the range zero to 3. inc a ; now it's 1 to 4. call getlv0 ; point to level. ld b,h ; copy address to ld c,l ; bc register pair. call random ; another random number. and 3 ; in the range zero to 3. call getlv0 ; point to level. ex af,af' ; store that level. ld a,(bc) ; first level. ld (hl),a ; copy first to second. ex af,af' ; restore second level. ld (bc),a ; copy to first. pop bc ; remember loop counter. djnz game0 ; repeat. ; Set initial difficulty. ld a,12 ; default bonus delay loop. ld (delayt),a ; set traffic light delay length. ld a,50 ; 50 in 256. ld (aidif0+1),a ; chance of car changing direction. ld a,40 ; 40 in 256. ld (aidif1+1),a ; chance of car hunting player. ld a,28 ; 28 = code for '1'. ld (flags),a ; set up default flags. ld a,30 ; digit '3'. ld (cars),a ; set up default cars. ld a,255 ; set all bits. ld (encar3),a ; disable third car. ld hl,tune1 ; start tune. ld a,(contrl) ; control method. cp 9 ; is it in demo mode? call nz,pditty ; no, so play the tune. ; Clear the screen to give red around the edges. stlev ld hl,23693 ; system variable for attributes. ld (hl),87 ; want a red background. call 3503 ; clear the screen. ; Clear down level data. ld hl,rmdat ; room data. ld de,rmdat+1 ld (hl),1 ; set up a shadow block. ld bc,16 ; length of room minus first byte. ldir ; copy to rest of first row. ld bc,160 ; length of room minus first row. ld (hl),b ; clear first byte. ldir ; clear room data. xor a ; put zero is accumulator. ld (nchang),a ; no changes wanted yet. ld a,8 ; starting complexity. ld (popbl3+1),a ; set up number of blocks to add. ld a,27 ; digit '0'. ld (cups),a ; initialise number of trophies collected. ; Set up the default blocks. ld c,15 ; last block position. popbl0 ld b,9 ; last row. popbl1 call filblk ; fill the block. dec b ; one column up. jr z,popbl2 ; done column, move on. dec b ; and again. jr popbl1 popbl2 dec c ; move on row. jr z,popbl3 ; done column, move on. dec c ; next row. jr popbl0 ; Now draw the bits unique to this level. popbl3 ld b,12 ; number of blocks to insert. popbl5 push bc ; store counter. call random ; get a random number. and 6 ; even numbers in range 0-6 please. add a,2 ; make it 2-8. ld b,a ; that's the column. popbl4 call random ; another number. and 14 ; even numbers 0-12 wanted. cp 14 ; higher than we want? jr nc,popbl4 ; yes, try again. inc a ; place it in range 1-13. ld c,a ; that's the row. call filblk ; fill block. popbl6 call random ; another random number. and 14 ; only want 0-8. cp 9 ; above number we want? jr nc,popbl6 ; try again. inc a ; make it 1-9. ld b,a ; vertical coordinate. call random ; get horizontal block. and 14 ; even, 0-14. ld c,a ; y position. call filblk ; fill in that square. pop bc ; restore count. djnz popbl5 ; one less to do. call atroom ; show current level layout. ; Continue level from here. conlev ld hl,fuel ; fuel. ld (hl),32 ; set first char to 5. inc hl ; next char. ld (hl),27 ; set next char to zero. inc hl ; next char. ld (hl),27 ; set next char to zero. ld hl,16384 ; screen address. ld de,16385 ; next byte of screen. ld bc,6143 ; size minus one byte. ld (hl),l ; clear first byte. ldir ; copy to rest of screen. xor a ; clear register. ld (stopfl),a ; reset cars stopped flag. cpl ; set all bits. ld (item),a ; disable collectable. ld (snd),a ; clear blip sound buffer. xor a ; zero. ld hl,playi ; player's intended direction. ld (hl),a ; default direction. inc hl ; point to display direction. ld (hl),a ; default direction. inc hl ; player's next direction. ld (hl),a ; default direction. out (254),a ; set border colour while we're at it. defb 33,168,8 ; coordinates. ld (encar2+1),hl ; set up second car position. call random ; random number. and 1 ; zero or one. ld (encar2),a ; set initial direction. defb 33,8,8 ; coordinates. ld (encar1+1),hl ; set up first car position. call random ; random number. and 1 ; zero or one. inc a ; direction 1 or 2. ld (encar1),a ; set initial direction. defb 33,8,232 ; coordinates. ld (playx),hl ; start player off here. call random ; random number. and 1 ; zero or one. add a,2 ; direction 1 or 2. ld (playd),a ; set player's initial direction. ld (playi),a ; set player's intended direction. ld (nplayd),a ; ensure player car won't turn too quickly. defb 33,168,232 ; coordinates. ld (encar3+1),hl ; set up third car position. ; call random ; random number. ; and 1 ; zero or one. ; dec a ; zero or minus one. ; and 3 ; zero or three. ; ld (encar3),a ; set initial direction. ld ix,encar1 ; first car. call scar ; show it. ld ix,encar2 ; second car. call scar ; show it. ld ix,encar3 ; third car. call scar ; show it. call dplayr ; show player sprite. call blkcar ; make player's car black. call panels ; initialise status panels. ; Two-second delay before we start. ld b,100 ; delay length. call delay ; do the delay. mloop xor a ; clear the accumulator. ld (donext),a ; initialise done extras marker. ld (donoth),a ; initialise done other stuff marker. halt ; electron beam in top left. call dplayr ; delete player. ; Make attributes blue ink again. call gpatts ; get player attributes. defb 17,239,41 ; remove green paper, add blue paper + ink. call attblk ; set road colours. ; Move player's car. ld a,(playd) ; player direction. ld bc,(playx) ; player coordinates. call movp ; move coords. ld hl,(dispx) ; new coords. ld (playx),hl ; set new player position. ; Can we change direction? ld a,(playi) ; player's intended direction. ld bc,(playx) ; player coordinates. call movp ; move coords. call z,setpn ; set player's new direction. ; Change direction. ld a,(nplayd) ; new player direction. ld (playd),a ; set current direction. call dplayr ; redisplay at new position. ; Set attributes of car. call blkcar ; make player car black. call joykey ; do control routines. ; Enemy cars. ld a,(encar1+1) ; enemy car 1 vertical. cp 40 ; above second horizontal strip? call c,extras ; yes, wait for electron beam to pass. ld ix,encar1 ; enemy car 1. call procar ; process the car. call coldet ; check for collisions. call chang ; change track layout. halt ; synchronise with display. ld ix,encar2 ; enemy car 2. call procar ; process the car. ld a,(encar3+1) ; enemy car 3 vertical. cp 24 ; above second horizontal strip? call c,other ; yes, wait for electron beam to pass. ld ix,encar3 ; enemy car 3. call procar ; process the car. ld ix,encar2 ; enemy car 2. call coldet ; check for collisions. ld ix,encar3 ; enemy car 2. ld a,(ix) ; get car status. inc a ; is it enabled? call nz,coldet ; yes so check for collisions. call extras ; count remaining yellow spaces. call other ; other bits and bobs. call fuelp ; fuel processing. call items ; items processing. ; End of main loop. jp mloop ; Final bits and bobs. other ld a,(donoth) ; done other processing flag. and a ; have they been done already? ret nz ; yes, don't repeat them. inc a ; set flag. ld (donoth),a ; won't repeat this now. ; Test for pause key. ld a,(keys+5) ; pause key. call ktest ; has it been pressed? call nc,pause ; yes - go to pause routine. ; delay loop. ld b,0 ; 256 iterations. other2 ld a,(ix) ; waste some time. djnz other2 ; repeat delay. ; Sound effects. call fxplay ; do AY sound effects. ld a,(snd) ; check sound to play. cp 255 ; any sound selected? jr z,other1 ; no, other processing please. cp 25 ; is it white noise? jr z,other0 ; yes, play that instead. ld a,255 ; set all bits. ld (snd),a ; reset sound. jr other1 ; done that now. other0 ld b,2 ; duration - very short. call noise0 ; brief sound. ld a,255 ; set all bits. ld (snd),a ; clear the effect now it's done. other1 ld hl,stopfl ; cars stopped flag. ld a,(hl) ; check cars status. and a ; are they moving? ret z ; yes, so everything's fine. dec (hl) ; not moving so reduce timer. ret fueld ld a,(23672) ; frame number. and 6 ; every 4 frames. ret nz ; not time to decrement fuel yet. fueldn ld hl,fuel+2 ; fuel counter. fueld0 dec (hl) ; one less. ld a,(hl) ; fetch new digit. cp 27 ; less than zero? jp nc,fueld1 ; no, it's okay. ld (hl),36 ; set it to nine. dec hl ; previous digit. jp fueld0 ; repeat. fueld1 ld hl,fuel ; first character of fuel string. ld a,(hl) ; find its contents. cp 27 ; is it zero? ret nz ; no, fuel not reached zero yet. inc hl ; next digit. ld a,(hl) ; find its contents. cp 27 ; is it zero? ret nz ; no, fuel not reached zero yet. inc hl ; next digit. ld a,(hl) ; find its contents. cp 27 ; is it zero? ret ; Process items. items ld a,(item) ; item flag. inc a ; is it switched on? jp nz,icol ; yes, check for collision with player. ld a,(23672) ; frame number. and 62 ; every 64 frames. ret nz ; not time to decrement fuel yet. call random ; get random number. cp 36 ; make something appear yet? ret nc ; not yet. ld de,rtabob ; random object table. call ranlst ; fetch item from the list. ld (item),a ; got the item. call random ; fetch x coordinate. and 96 ; in valid range please. add a,40 ; take account of top border. ld (itemx),a ; set x coordinate. call random ; fetch x coordinate. and 224 ; in valid range please. add a,8 ; take account of left border. ld (itemy),a ; set y coordinate. xor a ; clear accumulator. ld (itemt),a ; reset timer. ld hl,aysnd2 ; appear noise. ld (sptr),hl ; set pointer. ; Display or delete the item. ditem ld a,(item) ; item number. rrca ; multiply by 32. rrca rrca ld e,a ld d,0 ; no high byte. ld hl,flgspr ; first item sprite. add hl,de ; add displacement for graphic address. ex de,hl ; we want the address in de though. ld bc,(itemx) ; fetch coords. jp sprite ; transfer sprite to display. ; Item disappears from screen. igone call ditem ; delete item. ld hl,aysnd1 ; disappearing noise. ld (sptr),hl ; set pointer. ld a,255 ; set all bits. ld (item),a ; remove item. ret ; Item collision detection. icol ld hl,itemt ; item timer. dec (hl) ; one less loop. jr z,igone ; too late, item has disappeared. ld hl,(playx) ; player's coordinates. ld de,(itemx) ; item coordinates. ld a,h ; player y. sub d ; subtract item y. jr nc,icol0 ; result was positive, sign is okay. neg ; it was negative, reverse the sign. icol0 cp 16 ; are they within 16 pixels? ret nc ; no. ld a,l ; player x. sub e ; subtract item x. jr nc,icol1 ; result was positive, sign is okay. neg ; it was negative, reverse the sign. icol1 cp 16 ; are they within 16 pixels? ret nc ; no. call ditem ; remove item from screen. ld hl,aysnd0 ; collect noise. ld (sptr),hl ; set pointer. ld hl,item ; make hl point to item. ld a,(hl) ; get item type. ld (hl),255 ; reset it now it's collected. and a ; is it the flag? jp z,flag ; rearrange the track. dec a ; the cup perhaps? jr z,trophy ; collect trophy. dec a ; petrol pump? jr z,mfuel ; more fuel. dec a ; the camera? jr z,camera ; undo player's work. cpl ; accumulator to 254. ld (stopfl),a ; set car stop timer. ret ; Picked up the speed camera. camera ld hl,22561 ; first track attribute. ld bc,702 ; number of cells to check. makyel ld a,(hl) ; get cell contents. and 63 ; ignore brightness. cp CYAN ; is it cyan? call z,makye0 ; yes, make it yellow again. inc hl ; point to next cell. dec bc ; one less cell to check. ld a,b ; high byte of cells remaining. or c ; combine with low byte for zero check. jr nz,makyel ; repeat for all attributes. ret makye0 ld a,(hl) ; fetch cell again. and 247 ; remove blue paper element for green. or 16 ; add red element to make it yellow. ld (hl),a ; set new colour. ret ; Collect trophy and award player a points bonus. trophy ld hl,cups ; point to total collected so far. ld a,(hl) ; fetch total. cp 36 ; reached maximum? jr z,troph0 ; yes, no more please. inc (hl) ; increment total. troph0 ld b,5 ; amount to add. ld hl,points+4 ; tens column. call uscor ; increment score. jp lpanel ; show lower panel. ; Give player some more fuel and ten points. mfuel ld hl,fuel ; fuel counter string. inc (hl) ; 100 more fuel points. ld a,(hl) ; get column digit. cp 32 ; reached 500? ret c ; no, it's okay. inc hl ; point to second digit. ld (hl),27 ; make that zero. inc hl ; final digit. ld (hl),27 ; make that zero. ld b,1 ; single figure to add. ld hl,points+4 ; tens column. call uscor ; add to tally. ret ; Pick up flag and award ten points. flag ld hl,flags ; number of flags. ld a,(hl) ; total to date. cp 36 ; at max already? ret z ; yep, don't increase. inc (hl) ; one more to the collection. ld b,1 ; single figure to add. ld hl,points+4 ; tens column. call uscor ; add to tally. jp lpanel ; show new total. ; Joystick and keyboard reading routines. joykey ld a,(contrl) ; control flag. cp 9 ; demo mode? jr z,joydem ; yes, move around maze. and a ; is it the keyboard? jr nz,joyjoy ; no, it's joystick. ; Controls. ld a,(keys+3) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,1 ; direction right. call nc,setpd ; yes, set player direction. ld a,(keys+2) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,3 ; direction left. call nc,setpd ; yes, set player direction. ld a,(keys) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,0 ; direction up. call nc,setpd ; set direction. ld a,(keys+1) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,2 ; direction down. call nc,setpd ; set direction. ld a,(keys+4) ; fetch key from definitions table. call ktest ; see if it's being pressed. kfire call c,nofire ; not pressed, set release flag. call nc,fire ; use flag - if we have one. ret ; Kempston joystick. joyjoy xor a ; clear port high byte. in a,(31) ; read port 31. ld e,1 ; direction right. rra ; rotate bit into carry. push af ; store result. call c,setpd ; set player direction. pop af ; restore result. ld e,3 ; direction left. rra ; rotate bit into carry. push af ; store result. call c,setpd ; set player direction. pop af ; restore result. ld e,2 ; direction down. rra ; rotate bit into carry. push af ; store result. call c,setpd ; set player direction. pop af ; restore result. ld e,0 ; direction up. rra ; rotate bit into carry. push af ; store result. call c,setpd ; set player direction. pop af ; restore result. ccf ; reverse carry flag. jr kfire ; keyboard fire/no fire tests. ; Demo mode. joydem call 654 ; look for keypress. inc e ; any key pressed? jr nz,exdemo ; yes, exit demo mode. ld bc,(playx) ; player coordinates. ld a,(playd) ; current direction. call movc ; move the car. jr z,joydm3 ; can move there, don't force around. ; Force a change of direction. call random ; get a random number. rra ; rotate bit into carry. jr c,joydm1 ; go clockwise half the time. ld a,(playd) ; direction. dec a ; go anticlockwise. jr joydm0 joydm1 ld a,(playd) ; direction. inc a ; go anticlockwise. joydm0 and 3 ; keep within range. call movc ; move the car there. jr z,joydm2 ; it's good, so set new direction. xor 2 ; flip 180 degrees to see if that works. call movc ; try moving car there. jr z,joydm2 ; it's good, so set new direction. ld a,(playd) ; current direction. add a,2 ; about-face. and 3 ; keep within range. joydm2 ld (nplayd),a ; set new direction. ld (playi),a ; set intended direction. ret exdemo pop de ; remove return address from stack. jp menu1 ; return from demo mode. ; Don't need to turn but we might if we can. joydm3 call random ; get random number. cp 168 ; one third chance. ret nc ; don't turn. rra ; rotate bit into carry. jr c,joydm5 ; go clockwise half the time. ld a,(playd) ; direction. dec a ; go anticlockwise. jr joydm4 joydm5 ld a,(playd) ; direction. inc a ; go anticlockwise. joydm4 and 3 ; keep within range. call movc ; move the car there. jr z,joydm2 ; it's good, so set new direction. ret ; Fire not pressed - set flag to indicate this. nofire ld a,0 ; zero in accumulator, keep carry set. ld (firefl),a ; reset fire pressed flag. ret fire ld a,(firefl) ; check the flag. and a ; has it been released? ret nz ; no, wait until it has. cpl ; set accumulator. ld (firefl),a ; set fire pressed flag. ld a,(nchang) ; are we already changing track? and a ; non-zero means we are. ret nz ; don't use a flag here. ld hl,flags ; number of flags. ld a,(hl) ; total to date. cp 27 ; any left? ret z ; no, so nothing to use. dec (hl) ; another one bites the dust. call random ; get a random number. and 15 ; in range 0-15 please. add a,30 ; minimum number of rearrangements. ld (nchang),a ; set number of changes. jp lpanel ; show new total. nchang defb 0 ; number of track changes. firefl defb 0 ; fire pressed flag. stopfl defb 0 ; CPU cars stopped flag. ; Change track layout. chang ld a,(nchang) ; number of changes. and a ; any left to make? ret z ; no. ld a,r rra ; decide whether it's horizontal or vertical. jp c,chang0 ; it's horizontal. ld de,rtabvx ; list of random x coords. call ranlst ; get random x coordinate from list. ld (dispx),a ; set the vertical. call random ; another random number. and 28 ; put within range. ret z ; jr z,chdone ; don't use zero. dec a ; put in range 3-27. chang1 ld (dispy),a ; set horizontal position. call atadd ; find attribute address. ld a,(de) ; fetch attribute. and 4 ; green ink means it's solid. jr z,chang2 ; it's a space, make it solid. ld hl,65504 ; minus 32 bytes is the row above. add hl,de ; look one cell up. ld a,(hl) ; examine contents. ld hl,blkatt ; default is blank space. and 4 ; is it a solid block? jr z,chang3 ; no, don't need a shadow. ; Remove a block. ld hl,blkatt+4 ; shadow block instead. chang3 call appcol ; apply the colour. ld hl,30 ; distance to next cell down. add hl,de ; point to cell. set 6,(hl) ; make it bright. inc l ; next cell. set 6,(hl) ; make it bright. jr chdone ; job done. ; Fill in a block. chang2 call random ; random number. ; cp 84 ; one third chance. cp 84 ; one third chance. ret nc ; don't fill in a block. ld hl,(dispx) ; get chosen coordinates. add hl,hl ; double them. add hl,hl ; multiplied by four. add hl,hl ; doubled again so multiplied by eight. ld bc,(encar1+1) ; car 1 coordinates. call chcol ; make sure we're not trapping this car. ret c ; failed test but still a collision. ld bc,(encar2+1) ; car 2 coordinates. call chcol ; make sure we're not trapping this car. ret c ; failed test but still a collision. ld bc,(encar3+1) ; car 3 coordinates. call chcol ; make sure we're not trapping this car. ret c ; failed test but still a collision. ld bc,(playx) ; player car coordinates. call chcol ; make sure we're not trapping this car. ret c ; failed test but still a collision. ; No collisions so we're okay to fill in this block. ld hl,blkchq ; chequered pattern. call appcol ; apply the colours. ld hl,30 ; distance to next cell down. add hl,de ; point to cell. ld a,(hl) ; get cell contents. and 4 ; is it solid? jr nz,chdone ; yes, no shadow to apply. res 6,(hl) ; make it shadow. inc l ; last cell. res 6,(hl) ; make that shadow. chdone ld hl,nchang ; changes remaining. dec (hl) ; one less to do. ld a,25 ; code for a white noise. ld (snd),a ; set flag for sound effect. ret chang0 ld de,rtabhx ; list of random x coords. call ranlst ; get random x coordinate from list. ld (dispx),a ; set the vertical. call random ; another random number. and 28 ; put within range. ; call z,chang4 ; turn zero into 1. inc a ; put in range 1-29. jp chang1 ; fill this block. chang4 xor a ; set to left of screen. ret ; Apply colour block. appcol call atadd ; fetch attribute address. ldi ; transfer colour to cell. ldi ; transfer colour to cell. ex de,hl ; switch source and destination. ld bc,30 ; distance to next row. add hl,bc ; point to next cell. ex de,hl ; switch back source and target. ldi ; transfer colour to cell. ldi ; transfer colour to cell. ret item defb 0 ; item present flag. itemx defb 0 ; item x coordinate. itemy defb 0 ; item y coordinate. itemt defb 0 ; item timer. ; Extras processing. extras ld a,(donext) ; done extras flag. and a ; have they been done already? ret nz ; yes, don't repeat them. call spanel ; show panel. inc a ; set flag. ld (donext),a ; won't repeat this now. ; Count remaining yellow spaces. ld hl,22560 ; address. ld bc,704 ; attributes to count. ld a,YELLOB ; attribute we're seeking. cpir ; count characters. ld a,b ; high byte of result. or c ; combine with low byte. ret nz ; some left, continue with game. ld hl,22560 ; address. ld bc,704 ; attributes to count. ld a,YELLOW ; attribute we're seeking. cpir ; count characters. ld a,b ; high byte of result. or c ; combine with low byte. ret nz ; some left, continue with game. call silenc ; make sure there's no AY noise. ld hl,tune2 ; congratulations theme. call pditty ; play the ditty. pop de ; remove return address from stack. call random ; random number. and 1 ; zero or one. dec a ; zero or minus one. and 3 ; zero or three. ld (encar3),a ; setup third enemy car. call bonus ; do the bonus, jp stlev ; start a new level. donext defb 0 ; done extras processing flag. donoth defb 0 ; done other processing flag. spanel ld hl,panel ; status panel text. jp dfont ; show status, score etc. lpanel ld hl,lpan ; lower status panel text. jp dfont ; show flags etc. ; Black car on cyan paper. blkcar call gpatts ; get player attributes. defb 17,232,40 ; remove red paper/blue ink, add blue paper. ; Set 16x16 pixel attribute block. attblk call attlin ; paint horizontal line. call attlin ; paint another line. ld a,c ; vertical position. and 7 ; is it straddling cells? ret z ; no, so no third line. attlin call setatt ; paint the road. call setatt ; and again. ld a,b ; horizontal position. and 7 ; straddling blocks? jr z,attln0 ; no, leave third cell as it is. call setatt ; set attribute. dec l ; back one cell again. attln0 push de ; preserve colours. ld de,30 ; distance to next one. add hl,de ; point to next row down. pop de ; restore colour masks. ret ; Set single cell attribute. setatt ld a,(hl) ; fetch attribute cell contents. and e ; remove colour elements in c register. or d ; add those in b to form new colour. ld (hl),a ; set colour. inc l ; next cell. ret ; Pause mode. pause call silenc ; silence. pause0 ld a,(keys+5) ; pause key. call ktest ; has it been pressed? jr nc,pause0 ; wait until pause key is released. pause1 ld a,(keys+5) call ktest jr c,pause1 ; pause game until pause key pressed. pause2 ld a,(keys+5) call ktest jr nc,pause2 ; wait until pause key is released. ret ; Collision detection, based on coordinates. coldet call getabc ; get coords. ld a,(playx) ; horizontal position. sub c ; compare against car x. jr nc,coldt0 ; result was positive. neg ; it was negative, reverse sign. coldt0 cp 16 ; within 15 pixels? ret nc ; no collision. ld a,(playy) ; player y. sub b ; compare against car y. jr nc,coldt1 ; result was positive. neg ; it was negative, reverse sign. coldt1 cp 16 ; within 15 pixels? ret nc ; no collision. pop de ; remove return address from stack. call silenc ; make sure there's no AY noise. call noise ; short crash noise. call noise ; short crash noise. call noise ; short crash noise. call noise ; short crash noise. dead ld a,(contrl) ; check control mode. cp 9 ; is it in demo mode? jp z,menu1 ; yes, so we're done. ld b,50 ; delay length. call delay ; do the delay. ld hl,cars ; number of cars. cheatb dec (hl) ; decrement it. call spanel ; show panel. ld b,12 ; number of turns to make. dead0 push bc ; store counter. ; ld b,8 ; delay in fiftieths of a second. ; call delay ; delay loop. call noisg ; make screeching noise. halt ; delay/synchronise with picture. call dplayr ; delete player. ld a,(playd) ; player direction. dec a ; turn car. and 3 ; keep within correct range. ld (playd),a ; set new direction. call dplayr ; show player. pop bc ; restore turn counter. djnz dead0 ; repeat anim. ld b,50 ; delay length. call delay ; do the delay. xor a ; zero. ld (mscr),a ; set restart menu screen. ld a,(cars) ; get new cars total. cp 27 ; reached zero yet? jr z,eog ; yes, game over. call gpatts ; get player attributes. defb 17,239,41 ; remove green paper, add blue paper + ink. call attblk ; set road colours. jp conlev ; restart level. ; Fuel processing. fuelp call fueld ; decrement fuel. ret nz ; not zero, it's okay. jr dead ; out of fuel, player finished. ; End of game. eog ld a,(chance) ; last chance flag. and a ; are we to give player a final chance? jr nz,eog0 ; no, finish the game. call bonus ; play bonus for one last chance. jp z,stlev ; player won - start level again. call nobon ; play failure tune. eog0 ld hl,gotxt ; game over text. call dfont ; display message. ld hl,23264 ; bottom attributes. ld de,23265 ; next cell. ld (hl),250 ; red/white flashing. ld bc,31 ; number of copies to make. ldir ; copy across bottom line. ld b,100 ; delay length. call delay ; pause. call tryhs ; try high-score table. jp menusc setpd ex af,af' ld a,e ; direction. ld (playi),a ; set intended direction. ex af,af' ret setpn ld a,(playi) ; new intended direction. ld (nplayd),a ; set next direction. ret ; Move coordinates of player in relevant direction. movp ld (dispx),bc ; default position. and a ; direction zero. jr z,movpu ; move up. dec a ; direction 1. jr z,movpr ; move up. dec a ; direction 2. jr z,movpd ; move up. movpl dec b ; left one pixel. dec b ; left again. movp0 call chkpix ; check pixel attributes. ld (dispx),bc ; new coords. ret movpu dec c ; up a pixel. dec c ; and again. jr movp0 movpr inc b ; right one pixel. inc b ; right again. jr movp0 movpd inc c ; down a pixel. inc c ; once more. jr movp0 ; Move coordinates of sprite in relevant direction. movc ld (tmpdir),a ; remember direction on entry. ld (dispx),bc ; default position. and a ; direction zero. jr z,movcu ; move up. dec a ; direction 1. jr z,movcr ; move up. dec a ; direction 2. jr z,movcd ; move up. movcl dec b ; left one pixel. dec b ; left again. movc0 ld hl,(encar1+1) ; first car. call chcol ; check bc coords for collision. ld hl,(encar2+1) ; second car. call chcol ; check bc coords for collision. ld a,(encar3) ; third car enabled flag. ld hl,(encar3+1) ; third car. inc a ; make sure car is enabled first. call nz,chcol ; check bc coords for collision. call chkpix ; check pixel attributes. ld a,(tmpdir) ; restore original direction. ld (dispx),bc ; new coords. ret movcu dec c ; up a pixel. dec c ; and again. jr movc0 movcr inc b ; right one pixel. inc b ; right again. jr movc0 movcd inc c ; down a pixel. inc c ; once more. jr movc0 ; Check new position for collision with another CPU car. chcol ld a,b ; y coordinate. sub h ; was it negative? jr nc,chcol0 ; no, skip negation. neg ; make it positive. chcol0 cp 16 ; within 16 pixels? ret nc ; no collision. ld e,a ; store difference. ld a,c ; coordinate. sub l ; check against other CPU car. jr nc,chcol1 ; no, skip negation. neg ; make it positive. chcol1 cp 16 ; within 16 pixels? ret nc ; no collision. add a,e ; add total x + y difference. cp 3 ; are they really close? ret c ; yes, it's the same car you twonk. ; xor a ; lowest note. ; ld (snd),a ; set effect. jp chkpx0 ; no, it's a collision. ; Check pixel attributes for collision. ; Any cells with green or lighter ink are solid. chkpix call ataddp ; get pixel attribute address. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. inc hl ; next square to the right. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. inc hl ; next square to the right. ld a,b ; horizontal position. and 7 ; straddling cells? jr z,chkpx1 ; no, look down next. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. chkpx1 ld de,30 ; distance to next cell down. add hl,de ; point there. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. inc hl ; next square to the right. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. inc hl ; next square to the right. ld a,b ; horizontal position. and 7 ; straddling cells? jr z,chkpx2 ; no, look down next. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. chkpx2 ld a,c ; distance from top of screen. and 7 ; are we straddling cells vertically? ret z ; no, move is therefore okay. add hl,de ; point there. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. inc hl ; next square to the right. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. inc hl ; next square to the right. ld a,b ; horizontal position. and 7 ; straddling cells? ret z ; no, move is fine. ld a,(hl) ; get attributes. and 4 ; check ink colours. jr nz,chkpx0 ; invalid, block the move. ret ; go ahead. chkpx0 pop de ; remove return address from stack. ld a,(tmpdir) ; restore original direction. ld bc,(dispx) ; restore default position. ret gfram defb 0 ; frame number. ; Fill a block in the map. ; Get block address. filblk ld a,b ; row number. rlca ; multiply by 16. rlca rlca rlca add a,c ; add to displacement total. ld e,a ; that's displacement low. ld d,0 ; no high byte required. ld hl,rmdat ; room data address. add hl,de ; add to block address. ; Block address is in hl, let's fill it. ld (hl),2 ; set block on. ld de,16 ; distance to next block down. add hl,de ; point there. ld a,(hl) ; check it. and a ; is it set yet? ret nz ; yes, don't overwrite. ld (hl),1 ; set the shadow. ret ; Draw a screen consisting entirely of attribute blocks. atroom ld hl,rmdat ; room data. ld a,1 ; start at row 1. ld (dispx),a ; set up coordinate. ld b,11 ; row count. atrm0 push bc ; store counter. ld b,15 ; column count. ld a,1 ; column number. ld (dispy),a ; set to left of screen. atrm1 push bc ; store counter. ld a,(hl) ; get next block type. push hl ; store address of data. rlca ; double block number. rlca ; and again for multiple of 4. ld e,a ; displacement to block address. ld d,0 ; no high byte required. ld hl,blkatt ; block attributes. add hl,de ; point to block we want. call atadd ; get address for screen position. ldi ; transfer first block. ldi ; and the second. ld bc,30 ; distance to next row. ex de,hl ; switch cell and screen address. add hl,bc ; point to next row down. ex de,hl ; switch them back. ldi ; do third cell. ldi ; fourth attribute cell. ld hl,dispy ; column number. inc (hl) ; move across one cell. inc (hl) ; and another. pop hl ; restore room address. pop bc ; restore column counter. inc hl ; point to next block. djnz atrm1 ; do rest of row. inc hl ; skip one char so lines are round 16. ld a,(dispx) ; vertical position. add a,2 ; look 2 cells down. ld (dispx),a ; new row. pop bc ; restore column counter. djnz atrm0 ; do remaining rows. ret ; Background block attributes. blkatt defb YELLOB,YELLOB ; space. defb YELLOB,YELLOB defb YELLOW,YELLOW ; shadow space. defb YELLOB,YELLOB blkchq defb 124,68 ; black/white chequered flag pattern. defb 68,124 ; Calculate address of attribute for character at (dispx, dispy). atadd push hl ; need to preserve hl pair. ld hl,(dispx) ; coords to check, in char coords. add hl,hl ; multiply x and y by 8. add hl,hl add hl,hl ld b,h ; copy y coord to b. ld c,l ; put x coord in c. call ataddp ; get pixel address. ex de,hl ; put address in de. pop hl ; restore hl. ret ; Get player attributes. gpatts ld bc,(playx) ; player coordinates. ; Calculate address of attribute for pixel at (c, b). ataddp ld a,c ; Look at the vertical first. rlca ; divide by 64. rlca ; quicker than 6 rrca operations. ld l,a ; store in l register for now. and 3 ; mask to find segment. add a,88 ; attributes start at 88*256=22528. ld h,a ; that's our high byte sorted. ld a,l ; vertical/64 - same as vertical*4. and 224 ; want a multiple of 32. ld l,a ; vertical element calculated. ld a,b ; get horizontal position. rra ; divide by 8. rra rra and 31 ; want result in range 0-31. add a,l ; add to existing low byte. ld l,a ; that's the low byte done. ld a,(hl) ; get cell contents. ret ; attribute address now in hl. ; Move an enemy car. mcar ld a,(stopfl) ; computer cars stopped flag. and a ; are they still moving? ret nz ; no, so wait. ld a,(nchang) ; number of track changes left. and a ; is track changing? jr z,mcar2 ; no, so just move car. ld a,(23672) ; game frame. and 2 ; every other frame. ret z ; don't move at all. mcar2 call getabc ; fetch coordinates and direction. call movc ; move the car. jr nz,mcarf ; can't move there, turn around. ld a,c ; store x pos in c. ld (ix+1),a ; x position. sub 8 ; take border into account. ld l,a ; store in l for now. ld a,b ; get y pos. ld (ix+2),a ; new y placing. sub 8 ; take border into account. or l ; combine the two. and 31 ; find position straddling cells. ; cp 8 ; are we at a valid turning point? ret nz ; no, can't change direction. call random ; get a random number. aidif0 cp 50 ; check it's below this value. ret nc ; it isn't, don't change. aidif1 cp 40 ; check it's below this value. jr c,hcar ; hunter killer car. rra ; rotate bit into carry. jr c,mcar1 ; go clockwise. ld a,(ix) ; direction. dec a ; go anticlockwise. jr mcar0 mcar1 ld a,(ix) ; direction. inc a ; go anticlockwise. mcar0 and 3 ; keep within range. call movc ; move the car there. jr z,newcd ; it's good, so set new direction. xor 2 ; flip 180 degrees to see if that works. call movc ; try moving car there. jr z,newcd ; it's good, so set new direction. ret ; just forget it then. ; Set the new car direction. newcd ld (ix),a ; set direction. ret hcar ld a,(ix) ; get direction. rra ; is it horizontal? jr c,hcarv ; yes, hunt vertically. hcarh ld a,(playy) ; player's y coord. cp b ; to right of player? jr c,hcarl ; look left then. ret z ; on track already. hcarr ld a,1 ; look right. hcarc call movc ; check for validity. jr z,newcd ; that's okay. ret ; never mind. hcarl ld a,3 ; look right. jp hcarc ; change direction if we can. hcarv ld a,(playx) ; player's x coord. cp b ; below the player? jr c,hcaru ; look up then. ret z ; on track already. hcard ld a,2 ; look down. jp hcarc ; change direction if we can. hcaru xor a ; look up. jp hcarc ; change direction if we can. ; Move car - force a change of direction. mcarf call random ; get a random number. rra ; rotate bit into carry. jr c,mcarf1 ; go clockwise half the time. ld a,(ix) ; direction. dec a ; go anticlockwise. jr mcarf0 mcarf1 ld a,(ix) ; direction. inc a ; go anticlockwise. mcarf0 and 3 ; keep within range. call movc ; move the car there. jr z,newcd ; it's good, so set new direction. xor 2 ; flip 180 degrees to see if that works. call movc ; try moving car there. jr z,newcd ; it's good, so set new direction. aboutf ld a,(ix) ; current direction. add a,2 ; about-face. and 3 ; keep within range. jp newcd ; that's the way out. ; Fetch car coordinates and direction. getabc ld a,(ix) ; get direction. ld c,(ix+1) ; x coordinate. ld b,(ix+2) ; y position. ret ; Process car to which ix points. procar ld a,(ix) ; get car on/off flag. inc a ; is it switched on? ret z ; disabled, ignore it. call scar ; delete car. call mcar ; move car. ; Show enemy car. scar call getabc ; get coords and direction. cp 255 ; is car switched on? ret z ; no, it's disabled. jr dplay0 ; Display player sprite. dplayr ld bc,(playx) ; player coords. ld a,(playd) ; player direction. dplay0 rrca ; multiply by 128. ld e,a ; sprite * 32 in low byte. and 1 ; mask away low bits. ld d,a ; high byte. ld a,e ; restore shift result. and 128 ; just one low bit wanted. ld e,a ; place in e register. ld hl,cargfx ; car graphics. add hl,de ; add displacement to sprite. ld a,b ; horizontal placement. and 6 ; find the position straddling cells. rrca ; divide by 2 to get 0-3. rrca ; multiply by 32. rrca rrca ld e,a ; that's low byte of displacement. ld d,0 ; no high byte for this. add hl,de ; point to shifted frame. ex de,hl ; put that into de. ; jr sprite ; show the sprite. ; This is the sprite routine and expects coordinates in (c ,b) form, ; where c is the vertical coord from the top of the screen (0-176), and ; b is the horizontal coord from the left of the screen (0 to 240). ; Sprite data is stored in pre-shifted form to reduce flicker. ; On entry DE must point to the shifted sprite data. sprite ld (dispx),bc ; store coords in dispx for now. ld a,b ; pre-shifted so find y coord. and 6 ; position within byte boundary. ld hl,spmask ; pointer to mask table. ld c,a ; low byte of table displacement. ld b,0 ; no high byte. add hl,bc ; add displacement to pointer. ld c,(hl) inc hl ld b,(hl) call scadd ; calculate screen address. ld a,16 ; vertical lines. ex af,af' ; store line counter away in alternate registers. sprit0 ld a,(de) ; graphic data. and c ; mask away what's not needed. xor (hl) ; XOR with what's there. ld (hl),a ; bung it in. inc de ; next graphic. inc l ; next screen address. ld a,(de) ; second bit of data. xor (hl) ; XOR with what's there. ld (hl),a ; bung it in. dec de ; go back to first graphic byte. inc l ; next screen address. ld a,(de) ; fetch data. and b ; mask away unwanted bits. xor (hl) ; XOR with what's there. ld (hl),a ; bung it in. inc de ; point to next line of data. inc de ex af,af' ; restore line counter. dec a ; one less to go. ret z ; none left so exit. ex af,af' ; store line counter away again. ld a,(dispx) ; next pixel line. inc a ; look down one pixel. ld (dispx),a ; next coordinate. cp 192 ; reached the bottom of the screen? ret nc ; yes, sprite is drawn. and 63 ; switching screen segments? jr z,sprit1 and 7 ; moving into next character cell? jr z,sprit2 inc h ; next pixel down within current cell. dec l ; one character cell to the left. dec l ; another char left. jp sprit0 sprit1 push de ld de,30 ; distance to next segment. add hl,de ; point to new position. pop de jp sprit0 sprit2 push de ld de,63774 ; negative distance to next line. add hl,de ; point to new position. pop de jp sprit0 spmask defb 255,0,63,192,15,240,3,252 ; This routine returns a screen address for (dispx, dispy) in hl. scadd ld a,(dispx) ; Returns screen address of coordinates ld l,a ; (dispx, dispy) in hl. and 7 ; Line 0-7 within character square. add a,64 ; 64 * 256 = 16384 (Start of screen display) ld h,a ; Line * 256. ld a,l rrca rrca rrca and 24 ; Segment 0-2 multiplied by 8 add a,h ; Add to h (so multiply by 8 * 256 = 2048) ld h,a ld a,l ; 8 character squares per segment. rlca ; Divide x by 8 and multiply by 32, rlca ; net calculation: multiply by 4. and 224 ; Mask off bits we don't want. ld l,a ; Vertical coordinate calculation done. ld a,(dispy) ; y coordinate. rrca ; Only need to divide by 8. rrca rrca and 31 ; Squares 0 - 31 across screen. add a,l ; Add to total so far. ld l,a ; hl = address of screen. ret ; Return character cell address of block at (dispx, dispy). chadd ld a,(dispx) ; vertical position. ld e,a ; store in e. and 24 ; which segment, 1 to 3? add a,64 ; 64*256 = 16384, Spectrum's screen memory. ld d,a ; this is our high byte. ld a,e ; what was that vertical position again? and 7 ; which row within segment? rrca ; multiply row by 32. rrca rrca ld e,a ; low byte. ld a,(dispy) ; add on y coordinate. add a,e ; mix with low byte. ld e,a ; address of screen position in de. ret ; Display an ENDCHR-terminated string at hl. ; Note that this version is for a bespoke 8*5 font, and ; additionally lacks attribute support. dfont ld a,(hl) ; get char from hl. inc hl ; point to next char. cp ENDCHR ; is it a null terminator? ret z ; yes, job done. call dchar ; display char. jp dfont ; repeat. dchar cp AT ; is it the AT code? jr z,dchar0 ; yes, set x and y coordinates. push hl ; store pointer to string. ld e,a ; store char number in e. rlca ; multiply char number by 4. rlca add a,e ; four plus one is five. ld e,a ; store shift in e. ld d,0 ; no high byte for this font. ld hl,font ; point to font. add hl,de ; address of char image. call chadd ; get screen address in de. inc d ; one pixel lower to centralise. defb 1,99,5 ; set b to 8 and c out of the way. dchar1 ldi ; transfer byte to screen. inc d ; next screen line down. dec de ; back one char as ldi moved us on. djnz dchar1 ; repeat for all lines. ld hl,dispy ; y position. inc (hl) ; move to next column. pop hl ; restore string pointer. ret dchar0 ld e,(hl) ; get first control code. inc hl ; point to next one. ld d,(hl) ; get that code too. inc hl ; point to next valid character. ld (dispx),de ; set coordinates. ret ; back to main loop. fwltxt defb AT,8,13 defb 2,15,14,21,19,0,19,20,1,7,5 defb AT,11,14 defb 6,15,12,12,15,23,0,20,8,5,0 defb AT,13,14 defb 12,5,1,4,5,18,0,6,15,18 defb ENDCHR trftxt defb AT,8,13 defb 2,15,14,21,19,0,19,20,1,7,5 defb AT,11,11 defb 19,20,15,16,0,12,9,7,8,20,19,0,15,14 defb AT,13,11 defb 7,18,5,5,14,0,6,15,18,0,5,24,20,18,1 defb ENDCHR tcptxt defb AT,8,10 defb 2,15,14,21,19,0,19,20,1,7,5 defb AT,10,6 defb 19,20,15,16,0,30,0,20,18,15,16,8,25,0 defb 19,25,13,2,15,12,19 defb AT,15,8 defb 6,15,18 defb ENDCHR bontx0 defb AT,15,12 defb 16,15,9,14,20,19,0,2,15,14,21,19,37 defb ENDCHR bontx1 defb AT,15,13 defb 3,1,18,0,2,15,14,21,19,37 defb ENDCHR bontx2 defb AT,15,12 defb 15,14,5,0,12,1,19,20,0,3,1,18 defb ENDCHR ; Three cups / General sub-game window. wintx0 defb 22,7,4,16,0,17,7,23,28,0 defb 22,8,4,23,28,0 defb 22,9,4,23,28,0 defb 22,10,4,23,28,0 defb 22,11,4,23,28,0 defb 22,12,4,23,28,0 defb 22,13,4,23,28,0 defb 22,14,4,23,28,0 defb 22,15,4,23,28,0 defb 22,16,4,23,28,0 ; Traffic light window. wintx1 defb 22,7,4,16,7,17,0 defb 23,8,0,17,1,23,28,0,17,0 defb 22,8,4,23,8,0,17,1,23,28,0,17,0 defb 22,9,4,23,8,0,17,1,23,28,0,17,0 defb 22,10,4,23,8,0,17,1,23,28,0,17,0 defb 22,11,4,23,8,0,17,1,23,28,0,17,0 defb 22,12,4,23,8,0,17,1,23,28,0,17,0 defb 22,13,4,23,8,0,17,1,23,28,0,17,0 defb 22,14,4,23,8,0,17,1,23,28,0,17,0 defb 22,15,4,23,8,0,17,1,23,28,0,17,0 defb 22,16,4,23,8,0,17,1,23,28,0,17,0 defb 22,8,5,16,2,19,1,32,32 ; red light. defb 22,9,5,32,32 defb 22,14,5,16,4,32,32 ; green light. defb 22,15,5,32,32 defb 22,11,5,19,0,16,6,32,32 ; amber light. defb 22,12,5,32,32 ; Pairs window. wintx2 defb 22,5,4,16,0,17,4,23,28,0 defb 22,6,4,23,28,0 defb 22,7,4,23,28,0 defb 22,8,4,23,28,0 defb 22,9,4,23,28,0 defb 22,10,4,23,28,0 defb 22,11,4,23,28,0 defb 22,12,4,23,28,0 defb 22,13,4,23,28,0 defb 22,14,4,23,28,0 defb 22,15,4,23,28,0 defb 22,16,4,23,28,0 defb 22,17,4,23,28,0 ; This is the bonus routine. bonus ld hl,levno ; level number. ld a,(hl) ; get present stage. inc a ; point to next. ld (chance),a ; set "no more chances" flag. cp 5 ; reached the end? jr c,bonus3 ; not yet we haven't. xor a ; start at beginning again. bonus3 ld (hl),a ; next level number. ld hl,popbl3+1 ; get screen complexity. inc (hl) ; more complex next time. ld a,(aidif0+1) ; chance of car changing direction. add a,30 ; increase chances. jr c,maxdif ; passed max difficulty. ld (aidif0+1),a ; commit new setting to memory. ld a,(aidif1+1) ; chance of car changing direction. add a,30 ; increase chances. ld (aidif1+1),a ; set new value. ; Draw screen for relevant game. maxdif call getlev ; get subgame to use. ld hl,binits ; bonus intro sequence. call addrhl ; fetch address in hl pair. jp (hl) ; call the intro sequence. ; Code returns to here after intro. ; Establish what we're playing for. prize ld a,(cars) ; number of cars remaining. cp 27 ; is this the last car? jr z,bonus2 ; yes, display "final chance" text. cp 32 ; reached the maximum already? jr z,bonus1 ; yes, play bonus for points then. ld a,(cups) ; number of cups collected by player. cp 30 ; reached minimum number? jp nc,bonus0 ; yes, bonus is for extra life. ; Playing for fuel bonus. bonus1 call getlev ; level number. ld hl,bontx0 ; points bonus message. cp 4 ; is it the pairs game? call nz,dfont ; no, show the text. call getlev ; get level again. ld hl,bgames ; bonus games list. call addrhl ; put game start address in hl. ld de,bonu1a ; address to which we want to return. jp (hl) ; play the bonus game. bonu1a jp nz,nobon ; no bonus. ld hl,points+3 ; hundreds column. ld b,5 ; number to add. call uscor ; add to tally. call noise ; do noise. ld b,50 ; one second. call delay ; do the delay. ; Add the fuel bonus. bonus4 ld hl,points+5 ; units column. ld b,1 ; number to add. call uscor ; increment score. call fueldn ; decrement fuel. ret z ; fuel reached zero so exit. ld hl,gfram ; game frame. inc (hl) ; move it along. ld a,(hl) ; fetch frame number. and 3 ; every 4 frames. call z,banim ; do bonus anim. jr bonus4 ; fuel not reached zero yet. ; Playing for final chance. bonus2 call getlev ; level number. ld hl,bontx2 ; final car text. cp 4 ; is it the pairs game? call nz,dfont ; no, show the text. call getlev ; get level again. ld hl,bgames ; bonus games list. call addrhl ; put game start address in hl. ld de,bonu2a ; address to which we want to return. jp (hl) ; play the bonus game. bonu2a ret nz ; game over then. ld hl,22559 ; cars remaining. set 7,(hl) ; make it flash. ld hl,cars ; number of cars. inc (hl) ; increment lives. call noise ; noise. call spanel ; show new lives total. ld b,100 ; delay length. call delay ; wait. ld hl,22559 ; cars remaining. res 7,(hl) ; stop flashing. xor a ; set flag to indicate success. ret banim call spanel ; show top panel. ld a,(fuel) sub 27 ; convert 0-9. rlca ; multiply by 16, rlca rlca rlca ld l,a ; store in l for now. ld a,(fuel+1) sub 27 ; convert 0-9. add a,l ; add to total. ld h,1 ; high byte 1 to be safe. ld de,0 ; virtually no duration. jp 949 ; Playing for extra life. bonus0 call getlev ; level number. ld hl,bontx1 ; life bonus text. cp 4 ; is it the pairs game? call nz,dfont ; no, show the text. call getlev ; get level again. ld hl,bgames ; bonus games list. call addrhl ; put game start address in hl. ld de,bonu0a ; address to which we want to return. jp (hl) ; play the bonus game. bonu0a jp nz,bonus4 ; no car bonus, just add points. call noise ; do noise. ld hl,cars ; number of cars remaining. inc (hl) ; add one. jp bonus4 ; add fuel bonus. nobon ld hl,tune3 ; failure tune. call pditty ; play the tune. ret getlev ld a,(levno) ; level number. getlv0 ld e,a ; low byte of displacement. ld d,0 ; no high byte. ld hl,levtab ; level table. add hl,de ; point to random levels. ld a,(hl) ; get game for this level. ret levtab defb 2,0,1,3,4 ; table of sub-game numbers. ; Bonus game initialisation sequences. binits defw rcinit,tcinit,trinit,fwinit,painit ; Bonus games. bgames defw racgam,tcpgam,trfgam,fwlgam,paigam ; Return bonus routine address in hl. addrhl rlca ; multiply by 2. ld e,a ; put into low byte. ld d,0 ; no high byte required. add hl,de ; point to address of initialisation routine. ld e,(hl) ; low byte of routine. inc hl ; point to next byte. ld d,(hl) ; high byte of routine. ex de,hl ; swap into hl pair. ret ; Traffic light game intro. trinit ld de,wintx1 ; clear window text. ld bc,wintx2-wintx1 ; length of string. call 8252 ; clear space in window. xor a ; light at top. call shwlgt ; show light. ld hl,trftxt ; first part of bonus message. call dfont ; show the text. jp prize ; now decide on prize then play game. ; Three cups game intro. tcinit ld de,wintx0 ; clear window text. ld bc,wintx1-wintx0 ; length of string. call 8252 ; clear space in window. ld hl,tcptxt ; first part of bonus message. call dfont ; show the text. jp prize ; now decide on prize then play game. ; Follow-the-leader intro. fwinit ld a,56 ; temporary colours. ld (23695),a ; write to system variable. ld de,wintx0 ; clear window text. ld bc,wintx1-wintx0 ; length of string. call 8252 ; clear space in window. ld hl,fwltxt ; first part of bonus message. call dfont ; show the text. jp prize ; now decide on prize then play game. ; Race game intro. rcinit ld de,wintx0 ; clear window text. ld bc,wintx1-wintx0 ; length of string. call 8252 ; clear space in window. ld hl,ractxt ; first part of bonus message. call dfont ; show the text. jp prize ; now decide on prize then play game. ; Pairs game intro. painit ld de,wintx2 ; clear window text. ld bc,bonus-wintx2 ; length of string. call 8252 ; clear space in window. ld hl,paitxt ; first part of bonus message. call dfont ; show the text. jp prize ; now decide on prize then play game. ; Bonus games. ; Traffic light game. trfgam push de ; push return address onto stack. ld b,100 ; 2 seconds. call delay ; short delay. ld a,(flags) ; number of flags. ld (gfram),a ; store for later. ld a,12 ; delay. ld a,(delayt) ; delay loop. sub 4 ; make it shorter. cp 6 ; below minimum? jr c,trfgm0 ; yes, don't do lower. ld (delayt),a ; set new delay loop. trfgm0 call random ; get a random number. and 15 ; put it in a useful range. call noisf ld a,(delayt) ; delay length. ld b,a ; put count in b register. trfgm3 push bc ; store counter. halt ; synchronise with display. call bonkey ; fetch bonus control byte. pop bc ; restore count. ld a,(firefl) ; get fire pressed flag. and a ; is it being pressed? jr nz,trfgm2 ; yes, so exit loop. djnz trfgm3 ; repeat for rest of delay. ; Delete last light. ld a,(laspos) ; get last position. push af ; store last light number. call shwlgt ; remove last light. pop bc ; restore last light into b register. ; Choose new light. trfgm4 ld de,rtablt ; random table for light. call ranlst ; get new position. trfgm1 cp b ; same as last time? jr z,trfgm4 ; yes, choose again. call shwlgt ; show new light. jr trfgm0 trfgm2 ld b,100 ; delay length. call delay ; wait. ld a,(laspos) ; get light position. cp 2 ; set zero flag if we're on green. ret ; Three cups game. tcpgam push de ; place return address on stack. ld b,100 ; delay length. call delay ; wait for player to prepare. ld a,18 ; delay. ld (delayl),a ; default delay loop. defb 33,96,96 ; left sprite coordinates. ld (symbx),hl ; set coordinates. call tcpgm ; select symbol. ret nz ; bad symbol, game over. ret tcpgm ld a,(delayl) ; delay loop. sub 4 ; make it shorter. cp 4 ; below minimum? jr c,trfgm0 ; yes, don't do lower. ld (delayl),a ; set new delay loop. tcpgm1 ld de,rtasym ; random object table. ld a,(nchang) ; previous item chosen. ld b,a ; place in b register. tcpgm4 call ranlst ; fetch item from the list. cp b ; same as last time? jr z,tcpgm4 ; 'fraid so, let's try something different. ld (nchang),a ; store it temporarily. call shwsym ; show the symbol. tcpgm0 call random ; get a random number. and 15 ; put it in a useful range. call noisf ld a,(delayl) ; delay length. ld b,a ; put count in b register. tcpgm3 push bc ; store counter. halt ; synchronise with display. call bonkey ; fetch bonus control byte. pop bc ; restore count. ld a,(firefl) ; get fire pressed flag. and a ; is it being pressed? jr nz,tcpgm2 ; yes, so exit loop. djnz tcpgm3 ; repeat for rest of delay. ; Delete previous symbol. call shwsym ; show the symbol. jr tcpgm1 ; repeat until symbol selected. tcpgm2 call noise ; brief noise. call noisf ; short crash noise. ld b,50 ; delay length. call delay ; wait. ld a,(nchang) ; get selected symbol. and a ; is it a trophy? ret nz ; no - no bonus due then. ld a,(symby) ; sprite placement. add a,24 ; move 24 pixels right. cp 168 ; is this a fourth column? ret z ; yes, player is victorious. ld (symby),a ; set new column position. jr tcpgm ; continue with game. ; Show selected symbol. shwsym ld a,(nchang) ; fetch symbol required. ld hl,tcsym ; address of symbols. call addrhl ; put address of symbol in hl. ex de,hl ; switch it into de instead. ld bc,(symbx) ; coordinates. call sprite ; display it. ld a,(nchang) ; get symbol again. ld hl,tccol ; colours for symbols. ld e,a ; displacement to colour in e. ld d,0 ; table is small. add hl,de ; point to new colours. ld d,(hl) ; new colours are in d. ld bc,(symbx) ; coordinates. call ataddp ; find address of attributes. ld e,248 ; remove old ink. call attblk ; set new colours. ret symbx defb 0 ; symbol position. symby defb 0 ; symbol position. tcsym defw cupspr,flgspr,camspr,chrspr,cargfx defw spaspr,cargfx+128,whlspr,chqspr,cargfx+256 defw trispr,owyspr,noespr,strspr,tyrspr,kplspr tccol defb 57,59,56,58,57 defb 48,58,104,120,59 defb 58,57,58,48,13,79 ; Follow the leader game. fwlgam push de ; put return address onto stack. ld a,56 ; temporary colours. ld (23695),a ; write to system variable. ld de,cargfx ; graphics. ld b,4 ; 1 each for left, right, up and down. fwgam0 push bc ; store counter. ld a,4 ; go from 0 to 3. sub b ; positions are in range 0-3. push af call coords ; fetch sprite coordinates. call sprite ; show sprite. pop af ; restore position. call curcol ; set colours. ld hl,96 ; distance to next sprite frame. add hl,de ; add to current address. ex de,hl ; keep that in de. pop bc ; restore counter. djnz fwgam0 ; one less to display. ld a,(23693) ; temporary colours. ld (23695),a ; write to system variable. ld b,50 ; one-second pause. call delay ; wait. call fwset ; set up random sequence. ld a,4 ; start with 4 notes to play. call fwseq ; play chosen sequence. ret nz ; player failed. ld a,6 ; now 6 notes to play. call fwseq ; play chosen sequence. ret nz ; player failed. ld a,8 ; finally 8 notes to play. call fwseq ; play chosen sequence. ret ; return success in zero flag. fwseq ld hl,repseq ; address of sequence. ld (numrep),a ; number of repeats. ld b,50 ; delay in 50ths of a second. call delay0 ; pause for a second. ld b,a ; set counter. fwseq0 push bc ; store counter for later. ld a,(hl) ; get position. push hl ; store address. call fwply ; play note. pop hl inc hl ; point to next note. pop bc ; restore counter. djnz fwseq0 ; repeat sequence. ld hl,repseq ; sequence address. ld (repptr),hl ; set repeat pointer. fwseq1 call bonkey ; fetch control. ld a,(firefl) ; get control byte. and a ; nothing doing? jr z,fwseq1 ; wait. cp 255 ; fire pressed? jr z,fwseq1 ; yes, ignore that. dec a ; adjust value returned. call fwply ; play it. ld a,(firefl) ; get control byte. dec a ; adjust value returned. ld hl,(repptr) ; fetch sequence pointer. cp (hl) ; does player's input match? ret nz inc hl ; point to next one. ld (repptr),hl ; set repeat pointer. ld hl,numrep ; number of repeats required. dec (hl) ; one less to do. ret z ; we're done. fwseq2 call bonkey ; check control again. ld a,(firefl) ; have we released? and a ; zero means we have. jr nz,fwseq2 ; debounce. jr fwseq1 ; repeat until all done. fwply push af ; store position. call coords ; fetch coords for this item in sequence. call ataddp ; get attribute address. or 64 ; set brightness bit. call carcol ; colour the car. and 7 ; get ink colour. halt ; synch with display. call 8859 ; set border to match. pop af ; restore position. push af ; store it again. call pnote ; play the note. pop af ; restore position. push af ; store it again. call pnote ; play the note. pop af ; restore position. call coords ; fetch coords for this item in sequence. call ataddp ; get attribute address. and 191 ; clear brightness bit. call carcol ; colour the car. xor a ; code for black. call 8859 ; reset border colour. ld b,10 ; delay length. call delay ; short delay. ret ; Set up a random sequence. fwset ld b,8 ld hl,repseq ; sequence address. fwset0 push hl ; store address pointer. ld de,rtabfw ; random position table. call ranlst ; get random number. pop hl ; restore address. ld (hl),a ; store in sequence. inc hl ; point to next one. djnz fwset0 ret curcol push de ; store sprite pointer. ld c,a ; displacement to colour. ld b,0 ; zero high byte. ld hl,cursat ; cursor attributes. add hl,bc ; point to attributes. ld a,(hl) ; fetch attribute. ex af,af' ; store attribute. ld a,c ; sprite number. call coords ; fetch coords. call ataddp ; get attribute address. ex af,af' ; restore colours. call carcol ; do colours. pop de ; restore pointer to sprites. ret carcol ld (hl),a ; set attribute. inc l ; next cell. ld (hl),a ; set attribute. ld bc,31 ; distance to cell 3. add hl,bc ; point to cell. ld (hl),a ; set attribute. inc l ; next cell. ld (hl),a ; set attribute. ret ; Fetch cursor coordinates. coords rlca ; multiply position by 2. ld c,a ; that's the low byte. ld b,0 ; no high byte. ld hl,cursxy ; cursor coordinates table. add hl,bc ; point to relevant ones. ld c,(hl) ; fetch x coord of car. inc hl ; point to y. ld b,(hl) ; fetch y coord of car. ret cursat defb 58,60,59,57 ; cursor attributes. cursxy defb 72,56 defb 88,72 defb 104,56 defb 88,40 ; sequence to repeat. repseq defb 0,0,0,0,0,0,0,0 numrep defb 4 repptr defw 0 ; pointer to next in sequence. racgam push de ; place the return address onto the stack. defb 33,80,40 ; enemy car coordinates. ld (encar1+1),hl ; set coordinates. defb 33,96,40 ; player car coordinates. ld (playx),hl ; set those up too. ld a,1 ; direction = right. ld (playd),a ; set player direction. ld (encar1),a ; CPU car also. call srace ; show race. ld b,100 call delay ; prepare yourself... xor a ; clear accumulator. ld (nchang),a ; store in nchang for now. racgm1 call bonkey ; get player actions. halt call srace ; delete cars. ld a,(firefl) ; fetch direction. cp 2 ; is it right? jr z,racgm2 ; yes. cp 4 ; is it left? jr nz,racgm3 ; no, don't move player. racgm2 ld hl,nchang ; previous control method. cp (hl) ; are they identical? jr z,racgm3 ; yes, no change then. ld (hl),a ; remember this direction. ld hl,playy ; player y coordinate. inc (hl) ; move right. inc (hl) racgm3 ld a,(23672) ; read clock. and 3 ; check every fourth frame. jr nz,racgm0 ; don't move rival car. ld hl,encar1+2 ; rival's y position. inc (hl) ; move two pixels right. inc (hl) ld a,250 ; rightmost coord plus top note. sub (hl) ; find pitch. ld l,a ; put into l. ld h,0 ; no high byte for pitch. ld de,2 ; duration. call 949 ; short blip. racgm0 call srace ; show new positions. ld a,(playy) ; check player y. cp 200 ; reached the end? ret z ; huzzah, player has won. ld a,(encar1+2) ; CPU y. cp 200 ; has CPU won? jr nz,racgm1 ; no, continue race. and a ; ensure zero flag not set. ret srace ld ix,encar1 ; first car. call scar ; show it. call dplayr ; show player's car. ld bc,(encar1+1) ; coordinates. call ataddp ; find attributes. defb 17,120,122 ; make it red. call attblk ; set attributes block. ld bc,(playx) ; coordinates. call ataddp ; find attributes. defb 17,120,120 ; make it black. call attblk ; set attributes block. ret ractxt defb AT,8,8 defb 2,5,1,20,0,20,8,5,0,18,5,4,0,3,1,18 defb AT,15,8 defb 6,15,18 defb ENDCHR paitxt defb AT,7,17 defb 13,1,20,3,8,0,20,8,5 defb AT,9,17 defb 19,25,13,2,15,12 defb ENDCHR ; Pair game. paigam push de ; push return address onto stack. ld b,20 ; number of swaps. swap0 push bc call random ; random number. and 15 ; only 16 symbols. call getpa ; get pair address. push hl call random and 15 ; only 16 symbols. call getpa ; get pair address. pop de ; first pair in de. ld c,(hl) ; get second pair. ld a,(de) ; first pair in de. ld (hl),a ; copy to second. ex de,hl ld (hl),c ; copy second to first. pop bc djnz swap0 ld a,48 ; vertical start. ld (symbx),a ; set symbol x. xor a ; starting symbol. ld (pairno),a ; set symbol number. ld b,4 ; number of rows. showp1 push bc ; store row counter. ld b,4 ; number of columns. ld a,40 ; start at this left edge. ld (symby),a ; set y position. showp0 push bc ; store column counter. ld hl,pairno ; symbol number. ld a,(hl) ; fetch current. inc (hl) ; move along to next one. call getpa ; get pair symbol. ld (nchang),a ; set symbol. call shwsym ; show that symbol. call noisf ; sound effect. ld a,(symby) ; horizontal position. add a,24 ; move 3 chars to the right. ld (symby),a ; set new position. pop bc ; column pointer. djnz showp0 ; repeat. ld a,(symbx) ; vertical. add a,24 ; 3 character positions down. ld (symbx),a ; set symbol x. pop bc ; row pointer. djnz showp1 ; repeat. ld b,100 ; two seconds of interrupts. call delay ; do the delay. ; Hide the pairs now. ld a,48 ; vertical start. ld (symbx),a ; set symbol x. ld b,4 ; number of rows. hidep1 push bc ; store row counter. ld b,4 ; number of columns. ld a,40 ; start at this left edge. ld (symby),a ; set y position. hidep0 push bc ; store column counter. ld bc,(symbx) ; coordinates. call ataddp ; find address of attributes. defb 17,192,45 ; make it cyan on cyan. call attblk ; set new colours. call noisf ; sound effect. ld a,(symby) ; horizontal position. add a,24 ; move 3 chars to the right. ld (symby),a ; set new position. pop bc ; column pointer. djnz hidep0 ; repeat. ld a,(symbx) ; vertical. add a,24 ; 3 character positions down. ld (symbx),a ; set symbol x. pop bc ; row pointer. djnz hidep1 ; repeat. ; Show pair wanted. call random ; random pair number. and 15 ; need it in range 0-15. ld (nchang),a ; that's what we need. ld (pairno),a ; store pair we want. defb 33,72,192 ; coordinates. ld (symbx),hl ; set up dispx for display. call shwsym ; show symbol required. ; Now ask player to select the pair. defb 33,40,32 ; top-left coordinates. ld (dispx),hl ; set them up. xor a ; default symbol code. ld (nchang),a ; remember it. selpa0 ld bc,(dispx) ; fetch cursor coords. call ataddp ; find address. ld a,242 ; colour wanted. call shcur ; show cursor around symbol. ld b,5 ; number of iterations. selpa2 push bc ; store count. call noise ; do noise. pop bc ; restore loop count. djnz selpa2 ; repeat. selpa1 call bonkey ; get bonus control byte. ld a,(firefl) ; find direction. and a ; any player input? jr z,selpa1 ; no. ; Something's going on so delete cursor. ld bc,(dispx) ; fetch cursor coords. call ataddp ; find address. ld a,96 ; bright green background colour. call shcur ; show cursor around symbol. ld a,(firefl) ; check player response. cp 1 ; going up? jr z,mcuru ; move cursor up. cp 2 ; going up? jr z,mcurr ; move cursor right. cp 3 ; going up? jr z,mcurd ; move cursor down. cp 4 ; going up? jr z,mcurl ; move cursor left. jr spair ; must be fire so select pair. mcuru ld hl,dispx ; vertical coordinate. ld a,(hl) ; what is it? cp 40 ; already at the top? jr z,selpa0 ; yes, can't move. sub 24 ; move up 32 pixels. ld (hl),a ; new coordinate. ld a,(nchang) ; selected symbol code. sub 4 ; back 4 items. ld (nchang),a ; new symbol code. jr selpa0 mcurd ld hl,dispx ; vertical coordinate. ld a,(hl) ; what is it? cp 112 ; already at the top? jr z,selpa0 ; yes, can't move. add a,24 ; move down 32 pixels. ld (hl),a ; new coordinate. ld a,(nchang) ; selected symbol code. add a,4 ; 4 along in list. ld (nchang),a ; new symbol code. jr selpa0 mcurl ld hl,dispy ; horizontal coordinate. ld a,(hl) ; what is it? cp 32 ; already at left edge? jr z,selpa0 ; yes, can't move. sub 24 ; move left 32 pixels. ld (hl),a ; new coordinate. ld hl,nchang ; selected symbol code. dec (hl) ; next one. jr selpa0 mcurr ld hl,dispy ; horizintal coordinate. ld a,(hl) ; what is it? cp 104 ; already at right edge? jp z,selpa0 ; yes, can't move. add a,24 ; move down 32 pixels. ld (hl),a ; new coordinate. ld hl,nchang ; selected symbol code. inc (hl) ; next one. jp selpa0 spair ld hl,(dispx) ; cursor coords. defb 17,8,8 ; displacement to symbol. add hl,de ; new coords. ld (dispx),hl ; set those up in dispx. ld a,(nchang) ; selected symbol code. ld e,a ; displacement to table entry. ld d,0 ; no high byte. ld hl,pairt ; table of symbols. add hl,de ; point to correct symbol. ld e,(hl) ; get symbol number. ld hl,tccol ; list of attributes. add hl,de ; point to relevant colour. ld d,(hl) ; that's what we want. ld e,192 ; remove previous ink/paper combination. ld bc,(dispx) ; coordinates. call ataddp ; find address of attributes. call attblk ; set new colours. ld b,50 ; one second. call delay ; short delay. ld a,(nchang) ; selected symbol. ld hl,pairt ; pair table. ld e,a ; displacement in e. ld d,0 ; no displacement high. add hl,de ; point to symbol chosen. ld a,(pairno) ; pair number wanted. cp (hl) ; are they the same? ret ; zero flag set if player has won. shcur ld (hl),a ; set colours. inc l ; next cell. ld (hl),a ; set colours. inc l ; next cell. ld (hl),a ; set colours. inc l ; next cell. ld (hl),a ; set colours. ld de,29 ; distance to next cell. add hl,de ; point to next cell on next row. ld (hl),a ; set colours. inc l ; next cell. inc l ; next cell. inc l ; next cell. ld (hl),a ; set colours. add hl,de ; point to next cell on next row. ld (hl),a ; set colours. inc l ; next cell. inc l ; next cell. inc l ; next cell. ld (hl),a ; set colours. add hl,de ; point to next cell on next row. ld (hl),a ; set colours. inc l ; next cell. ld (hl),a ; set colours. inc l ; next cell. ld (hl),a ; set colours. inc l ; next cell. ld (hl),a ; set colours. ret getpa ld e,a ; displacement in e. ld d,0 ; no high byte for displacement. ld hl,pairt ; pair table. add hl,de ; point to pair. ld a,(hl) ; get pair number. ret pairno defb 0 pairt defb 0,1,2,3,8,9,10,11 defb 4,5,6,7,12,13,14,15 ; Bonus subgames joystick and keyboard reading routines. bonkey xor a ; clear all bits. ld (firefl),a ; reset fire flag. ld a,(contrl) ; control flag. and a ; is it the keyboard? jr nz,bonjoy ; no, it's joystick. ; Keyboard control - check for fire key and directions. ld a,(keys+3) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,2 ; direction right. call nc,bonsd ; yes, set player direction. ld a,(keys+2) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,4 ; direction left. call nc,bonsd ; yes, set player direction. ld a,(keys) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,1 ; direction up. call nc,bonsd ; set direction. ld a,(keys+1) ; fetch key from definitions table. call ktest ; see if it's being pressed. ld e,3 ; direction down. call nc,bonsd ; set direction. ld a,(keys+4) ; fetch key from definitions table. call ktest ; see if it's being pressed. jr nc,bonfir ; yes, select pressed. ret ; Kempston joystick - test fire. bonjoy xor a ; clear port high byte. in a,(31) ; read port 31. ld e,2 ; direction right. rra ; rotate bit into carry. call c,bonsd ; set player direction. ld e,4 ; direction left. rra ; rotate bit into carry. call c,bonsd ; set player direction. ld e,3 ; direction down. rra ; rotate bit into carry. call c,bonsd ; set player direction. ld e,1 ; direction up. rra ; rotate bit into carry. call c,bonsd ; set player direction. jr z,bonfir ; set fire. ret ; Fire was pressed so set up fire flag. bonfir ld a,255 ; set all bits. ld (firefl),a ; set fire flag. ret bonsd ld hl,firefl ; fire flag. ld (hl),e ; set it. ret ; Random trac light table. rtablt defb 0,0,0,1,1,2,2,2 ; Random three-cups symbol table. rtasym defb 0,1,2,3,0,3,4,0 ; Random follow-the-leader position table. rtabfw defb 0,1,2,3,2,3,0,1 ; Random object table. rtabob defb 0,0,1,1,2,2,3,4 ; Random block coordinates. rtabvx defb 1,21,5,9,13,17,21,1 rtabhx defb 3,19,15,7,11,15,19,3 panels call spanel ; show panel. call lpanel ; show lower panel. ld a,(contrl) ; get control mode. cp 9 ; is it demo mode? jr z,paneld ; show demo text. ld hl,hstab+8 ; highest score in table. ld de,hscore ; high score display on panel. ld bc,6 ; number of digits to transfer. ldir ; copy them across. ld hl,hpanel ; high score panel. jp dfont ; show that. paneld ld hl,dpanel ; demo mode display panel. jp dfont ; show that. delayt defb 18 ; delay loop length (traffic lights). delayl defb 18 ; delay loop length (cups). laspos defb 0 ; last light position. pditty ld (nptr0),hl ; store tune pointer. pdit0 call random ; random colour. ld (23624),a ; set border colour. ld hl,(nptr0) ; fetch note pointer. ld a,(hl) ; duration low. ld e,a ; we need that in e. inc hl ; next byte in list. ld d,(hl) ; duration high. or d ; combine both bytes of duration. jr z,pdit2 ; they're zero, so ditty has finished. inc hl ; point to next one. ld c,(hl) ; pitch low. inc hl ; point to next one. ld b,(hl) ; pitch high. inc hl ; point to next note. ld (nptr0),hl ; store pointer. ld l,c ; copy bc low to hl low. ld h,b ; copy bc high to hl high. halt ; synchronise display. call 949 ; play note. ld b,0 ; we'll need 256 loop iterations. pdit1 dec b ; first decrement. dec b ; second. djnz pdit1 ; third decrement. jp pdit0 pdit2 xor a ; code for black. jp 8859 ; set border colour. nptr0 defw 0 ; tune pointer. pnote rlca ; multiply note * 4. rlca ld e,a ; displacement to note in e. ld d,0 ; zero in high byte. ld hl,notes ; note data. add hl,de ; add displacement for this note. ld e,(hl) ; duration low byte. inc hl ld d,(hl) ; DE = duration. inc hl ld a,(hl) ; pitch high byte. inc hl ld h,(hl) ld l,a ; HL = pitch. jp 949 ; ROM routine to toggle loudspeaker. ; Show light at position 0, 1 or 2 for red, amber or green. shwlgt ld (laspos),a ; set last light position. rlca ; multiply by 8. rlca rlca ld c,a ; place that in c. rlca ; multiple of 16. add a,c ; 8 + 16 = multiple of 24. add a,64 ; top of lights. ld c,a ; that's the x position. ld b,40 ; y always on left. ld de,trfspr ; point to traffic light sprite. jp sprite ; draw the sprite. ; Scoring routine. ; The score is held as an ASCII string. This simply increases the ASCII ; value of the appropriate digit, then checks we're not exceeding the ; value for '9' (57) - if we do, we subtract ten and increase the previous ; character in the string. 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 37 ; more than char 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 37 ; gone past charset nine? ret c ; no, scoring done. sub 10 ; down by ten. ld (hl),a ; put it back jp uscor0 ; go round again. ; Pseudo-random number generator. ; Steps a pointer through the ROM (held in seed), returning the contents ; of the byte at that location. random ld hl,(seed) ; pointer to ROM. res 5,h ; stay within first 8K of ROM. ld a,r ; bad random number. xor (hl) ; combine with number from location. xor l ; more randomness. inc hl ; increment pointer, just for a change. ld (seed),hl ; new position. ret ; Get random number from 8-digit list at DE. ranlst call random ; random number. and 7 ; range 0-7. ld l,a ; low byte. ld h,0 ; no high byte. add hl,de ; point to table. ld a,(hl) ; fetch random number from table. ret seed defw 0 ; random number seed. delay ld a,(contrl) ; control method. cp 9 ; is it in demo mode? ret z ; yes, no delay required. delay0 halt ; wait for interrupt. djnz delay0 ; repeat. ret ; AY-3-8912 routines. ; Write the contents of our AY buffer to the AY registers. w8912 ld hl,chaton ; Sound effects buffer. ld e,0 ; register to start with. ld d,14 ; number of registers to write. w8912a ld a,e ld bc,65533 ; port 65533=select soundchip register. out (c),a ; tell chip which register we're writing. ld a,(hl) ; value to write. ld bc,49149 ; port 49149=write value to register. out (c),a ; this is what we're putting there. inc e ; next sound chip register. inc hl ; next byte to write. dec d ; decrement loop counter. jr nz,w8912a ; repeat until done. ret fxoff ld a,63 ; mixer byte. ld (smixer),a ; tone/noise mixer. xor a ; zero volume. fxvol ld (chavol),a ; volume channel A. ld (chbvol),a ; volume channel B. ld (chcvol),a ; volume channel C. jp w8912 fxtona ld (chaton),de ; clear channel A tone. ret fxtonb ld (chbton),de ; clear channel B tone. ret fxtonc ld (chcton),de ; clear channel C tone. ret fxvola ld hl,chavol ; channel A volume. ld (hl),b ; set the volume. ret fxvolb ld hl,chbvol ; channel B volume. ld (hl),b ; set the volume. ret fxvolc ld hl,chcvol ; channel C volume. ld (hl),b ; set the volume. ret ; 0 = silence ; 1 = tone A ; 2 = tone B ; 3 = tone C ; 4 = tone ABC ; 5 = set mixer ; 6 = volume A ; 7 = volume B ; 8 = volume C ; 9 = volume ABC ; 10 = rest ; 11 = white noise period ; 12 = jump ; 255 = play fxplay ld hl,(sptr) ; get sound pointer. ld a,(hl) ; get instruction. and a ; at the end? jp z,fxoff ; yes, nothing to do. inc hl ; point to next instruction. ld (sptr),hl cp 255 ; is it a play instruction? jr z,w8912 ; play the noise. cp 254 ; is it a rest? ret z ; do nothing this turn. cp 5 ; 1-4 = set tones. jp c,fxtone ; set tones. jp z,fxmix ; set mixer. cp 10 ; 6-9 = set volumes. jp c,fxvolm ; set tones. cp 11 ret fxmix ld a,(hl) ; get mixer byte. inc hl ; point to next instruction. ld (sptr),hl ; set sound pointer. ld (smixer),a ; set mixer. jp fxplay ; driver loop. fxwn ld a,(hl) ; fetch white noise period. inc hl ; point to next byte. ld (sptr),hl ; set pointer for next time. ld (wnprd),a ; set the white noise period. jp fxplay ; back to loop. fxjmp ld e,(hl) ; low byte of new address. inc hl ; next byte. ld d,(hl) ; next byte of address. ld (sptr),hl ; new sound pointer. jp fxplay ; continue. ; Set tones. fxtone ld e,(hl) ; tone low. inc hl ; next byte. ld d,(hl) ; tone high. inc hl ld (sptr),hl ; set sound pointer. cp 1 call z,fxtona cp 2 call z,fxtonb cp 3 call z,fxtonc cp 4 call z,fxtona call z,fxtonb call z,fxtonc jp fxplay ; back to loop. ; Set volumes. fxvolm ld b,(hl) ; volume. inc hl ; next byte. ld (sptr),hl ; set sound pointer. cp 6 call z,fxvola cp 7 call z,fxvolb cp 8 call z,fxvolc cp 9 call z,fxvola call z,fxvolb call z,fxvolc jp fxplay ; back to loop. sptr defw snd0 snd0 defb 0 ; silence. snd1 defb 4 ; all tones. defw 336 ; tone. defb 5,56 ; tone on, noise off. defb 255 ; play. defb 4 ; all tones. defw 252 ; tone. defb 255,0 ; play, end. silenc ld hl,aysnd5 ; silence. ld (sptr),hl ; set sound pointer. jp fxplay ; stop noise. ; Sound data to write. chaton defw 0 ; tone registers, channel A. chbton defw 0 ; channel B tone registers. chcton defw 0 ; as above, channel C. wnprd defb 0 ; white noise period. smixer defb 60 ; tone/noise mixer control. chavol defb 16 ; channel A amplitude/envelope generator. chbvol defb 16 ; channel B amplitude/envelope. chcvol defb 0 ; channel C amplitude/envelope. defw 6000 ; duration of each note. defb 0 aysnd0 defb 1 defw 500 defb 2 defw 400 defb 3 defw 300 defb 5,56,9,15,255 defb 1 defw 475 defb 2 defw 380 defb 3 defw 290 defb 255 defb 1 defw 450 defb 2 defw 360 defb 3 defw 280 defb 255 defb 1 defw 425 defb 2 defw 340 defb 3 defw 270 defb 255 ayfade defb 9,14,255 defb 9,13,255 defb 9,12,255 defb 9,10,255 defb 9,8,255 defb 9,5,255 defb 9,0,255,0 aysnd1 defb 5,7,11,31,9,15,255 defb 11,27,9,13,255 defb 11,23,9,11,255 defb 11,19,9,9,255 defb 11,15,9,7,255 defb 11,11,9,5,255 defb 9,0,255,0 aysnd2 defb 1 defw 500 defb 2 defw 600 defb 3 defw 700 defb 5,56,9,15,255,10 defb 1 defw 600 defb 2 defw 800 defb 3 defw 950 defb 255 defb 12 defw ayfade aysnd5 defb 9,0,255,0 chance defb 255 ; last chance flag. ; Top panel. panel defb AT,0,0 defb 19,3,15,18,5,0 points defb 28,27,27,27,27,27 defb 0,0,0 defb 6,21,5,12,0 fuel defb 27,27,27 defb 0,0,0 defb 3,1,18,19,0 cars defb 30 defb ENDCHR ; Lower panel. lpan defb AT,23,0 defb 6,12,1,7,19,0 flags defb 27 defb 0,0,0 defb 20,18,15,16,8,9,5,19,0 cups defb 27 defb ENDCHR ; High-score panel. hpanel defb AT,23,23 defb 8,9,0 hscore defb 27,27,27,27,27,27 defb ENDCHR ; Demo mode panel. dpanel defb AT,23,23 defb 4,5,13,15,0 defb 13,15,4,5 defb ENDCHR ; Ditties. ; Start game tune. tune1 defw 108,1460,108,1460,36,1460 defw 42,1297,88,1223,42,1297 defw 36,1460,32,1643,36,1460 defw 84,1297,224,1959 defw 0 tune2 defw 11,2475,12,2202,14,1959 defw 30,1847,33,2475,15,1847,14,1959,15,1847 defw 32,1643,36,2202,12,2202,14,1959,15,1847 defw 18,1460,16,1643,16,1643,15,1847 defw 15,1847,14,1959,12,2202 defw 14,1959,120,1847 defw 0 ; Unsuccessful tune. tune3 defw 45,1847,11,2475,10,2624 defw 11,2475,36,2335,66,2475 defw 42,1959,45,1847 defw 0 ; Musical note data. notes defw 8,3314 ; 0 defw 9,3127 ; 1 defw 9,2950 ; 2 defw 10,2783 ; 3 defw 10,2624 ; 4 defw 11,2475 ; 5 defw 12,2335 ; 6 defw 12,2202 ; 7 defw 13,2077 ; 8 defw 14,1959 ; 9 defw 15,1847 ; 10 defw 15,1742 ; 11 defw 16,1643 ; 12 defw 17,1548 ; 13 defw 18,1460 ; 14 defw 19,1373 ; 15 defw 21,1297 ; 16 defw 22,1223 ; 17 defw 23,1152 ; 18 defw 25,1086 ; 19 defw 26,1023 ; 20 defw 28,964 ; 21 defw 29,908 ; 22 defw 31,856 ; 23 defw 33,806 ; 24 ; Sprite graphic data. ; Going up first. cargfx defb 49,140,123,222,123,222,127,254,55,236,15,240,31,248,30,120 defb 29,184,108,54,246,111,255,255,247,239,246,111,103,230,3,192 defb 12,99,158,247,158,247,159,255,13,251,3,252,7,254,7,158 defb 7,110,155,13,253,155,255,255,253,251,253,155,153,249,0,240 defb 195,24,231,189,231,189,231,255,195,126,0,255,129,255,129,231 defb 129,219,102,195,255,102,255,255,255,126,255,102,102,126,0,60 defb 48,198,121,239,121,239,249,255,176,223,192,63,224,127,224,121 defb 224,118,217,176,191,217,255,255,191,223,191,217,153,159,0,15 ; Second image looks right. defb 60,0,126,14,126,31,61,223,11,238,127,248,252,254,217,127 defb 217,127,252,254,127,248,11,238,61,223,126,31,126,14,60,0 defb 15,0,159,131,223,135,207,119,130,251,31,254,191,63,246,95 defb 246,95,191,63,31,254,130,251,207,119,223,135,159,131,15,0 defb 3,192,231,224,247,225,243,221,224,190,135,255,239,207,253,151 defb 253,151,239,207,135,255,224,190,243,221,247,225,231,224,3,192 defb 0,240,57,248,125,248,124,247,184,47,225,255,251,243,255,101 defb 255,101,251,243,225,255,184,47,124,247,125,248,57,248,0,240 ; Third is pointing down. defb 3,192,103,230,246,111,247,239,255,255,246,111,108,54,29,184 defb 30,120,31,248,15,240,55,236,127,254,123,222,123,222,49,140 defb 0,240,153,249,253,155,253,251,255,255,253,155,155,13,7,110 defb 7,158,7,254,3,252,13,251,159,255,158,247,158,247,12,99 defb 0,60,102,126,255,102,255,126,255,255,255,102,102,195,129,219 defb 129,231,129,255,0,255,195,126,231,255,231,189,231,189,195,24 defb 0,15,153,159,191,217,191,223,255,255,191,217,217,176,224,118 defb 224,121,224,127,192,63,176,223,249,255,121,239,121,239,48,198 ; Last car looks left. defb 0,60,112,126,248,126,251,188,119,208,31,254,127,63,254,155 defb 254,155,127,63,31,254,119,208,251,188,248,126,112,126,0,60 defb 0,15,156,31,190,31,62,239,29,244,135,255,223,207,255,166 defb 255,166,223,207,135,255,29,244,62,239,190,31,156,31,0,15 defb 192,3,231,7,239,135,207,187,7,125,225,255,247,243,191,233 defb 191,233,247,243,225,255,7,125,207,187,239,135,231,7,192,3 defb 240,0,249,193,251,225,243,238,65,223,248,127,253,252,111,250 defb 111,250,253,252,248,127,65,223,243,238,251,225,249,193,240,0 ; Other sprites. ; Flag sprite. flgspr defb 0,0,96,0,124,0,127,128,127,240,127,254,127,240,127,128 defb 124,0,96,0,96,0,96,0,96,0,96,0,96,0,0,0 ; Trophy sprite. cupspr defb 0,0,0,0,31,248,127,254,255,255,223,251,223,251,127,254 defb 63,252,15,240,7,224,3,192,1,128,7,224,31,248,0,0 ; Petrol sprite. petspr defb 3,192,15,240,12,48,29,184,28,56,13,240,15,240,3,192 defb 1,128,7,224,15,240,15,240,31,248,31,248,31,248,31,248 ; Speed camera sprite. camspr defb 0,0,127,128,252,192,251,64,251,80,252,212,255,215,255,215 defb 231,215,219,215,189,212,189,196,219,220,231,192,127,128,0,0 ; Stop sign sprite. stpspr defb 31,248,63,252,127,254,255,255,255,255,136,136,189,170,141,168 defb 237,171,141,139,255,255,255,255,255,255,127,254,63,252,31,248 ; Traffic light sprite. trfspr defb 0,0,0,0,3,192,13,48,23,200,31,168,47,212,63,244 defb 47,252,43,244,21,248,19,232,12,176,3,192,0,0,0,0 ; Cherries sprite. chrspr defb 12,0,7,0,3,128,3,192,7,160,15,160,7,16,12,24 defb 63,62,61,122,127,255,127,255,63,126,63,126,12,24,0,0 ; Spanner sprite. spaspr defb 0,56,0,112,0,224,0,225,0,227,0,255,1,254,3,252 defb 7,192,15,128,31,0,62,0,124,0,248,0,176,0,224,0 ; Wheel sprite. whlspr defb 7,224,31,248,60,60,112,14,96,6,224,7,192,3,193,131 defb 199,227,223,251,252,63,112,14,112,14,60,60,31,248,7,224 ; Diagonal chequered flag. chqspr defb 28,113,8,32,28,113,190,251,255,255,190,251,28,113,8,32 defb 28,113,190,251,255,255,190,251,28,113,8,32,28,113,190,251 ; Ball sprite. ;balspr defb 7,224,28,216,51,52,115,50,76,206,204,205,179,51,179,51 ; defb 204,205,204,205,179,51,115,50,76,206,44,204,27,56,7,224 ; Red triangle. trispr defb 0,0,3,128,7,192,7,192,15,224,30,240,28,112,60,120 defb 56,56,120,60,240,30,240,30,255,254,127,252,63,248,0,0 ; One way sign. owyspr defb 0,0,0,0,0,0,127,254,127,254,123,254,115,254,96,2 defb 64,2,96,2,115,254,123,254,127,254,127,254,0,0,0,0 ; No entry sign. noespr defb 7,224,31,248,63,252,127,254,127,254,255,255,128,1,128,1 defb 128,1,128,1,255,255,127,254,127,254,63,252,31,248,7,224 ; Stripes. strspr defb 225,225,195,195,135,135,15,15,30,30,60,60,120,120,240,240 defb 225,225,195,195,135,135,15,15,30,30,60,60,120,120,240,240 ; Tyre pattern. tyrspr defb 0,0,153,153,204,204,102,102,51,51,102,102,204,204,153,153 defb 204,204,102,102,51,51,102,102,204,204,153,153,0,0,0,0 ; Keep left signs. kplspr defb 248,31,224,7,192,3,128,33,128,113,0,248,17,240,27,224 defb 31,192,31,128,31,0,159,129,159,193,192,3,224,7,248,31 ; 8 x 5 font. font defb 0,0,0,0,0 defb 124,130,130,254,130 defb 252,130,252,130,252 defb 126,128,128,128,126 defb 240,136,132,130,252 defb 126,128,248,128,126 defb 126,128,248,128,128 defb 124,128,190,130,126 defb 130,130,254,130,130 defb 16,16,16,16,16 defb 2,2,2,130,124 defb 134,152,224,152,134 defb 128,128,128,128,126 defb 108,146,146,130,130 defb 252,130,130,130,130 defb 124,130,130,130,124 defb 252,130,130,252,128 defb 124,130,130,134,126 defb 252,130,140,240,142 defb 126,128,124,2,252 defb 254,16,16,16,16 defb 130,130,130,130,124 defb 130,130,68,40,16 defb 130,130,146,146,108 defb 130,108,56,108,130 defb 130,130,108,16,16 defb 254,6,56,192,254 defb 124,130,130,130,124 defb 16,48,16,16,56 defb 252,2,124,128,254 defb 252,2,28,2,252 defb 8,40,72,254,8 defb 254,128,252,2,252 defb 124,128,252,130,124 defb 254,2,12,16,16 defb 124,130,124,130,124 defb 124,130,126,2,124 defb 0,0,0,0,16 defb 16,0,0,0,0 defb 68,186,162,186,68 ; Variables used by the game. encar1 defb 0,0,0 ; enemy car 1. encar2 defb 0,0,0 ; enemy car 2. encar3 defb 0,0,0 ; enemy car 3. tmpdir defb 0 ; temporary direction. gframe defb 255 ; game frame. levno defb 5 ; level number. playi defb 0 ; intended direction when turn is possible. playd defb 0 ; player's current direction. nplayd defb 0 ; next player direction. playx defb 0 ; player x. playy defb 0 ; player's y coordinate. dispx defb 'J' ; general-use coordinates. dispy defb 'A' snd defb 'C' rmdat defb 'Yes, this is the' defb ' buffer message.' defb ' This 16K game ' defb 'is a sort of tha' defb 'nk-you for all t' defb 'hose Spectrum ow' defb 'ners who have su' defb 'pported Cronosof' defb 't and Retro-Soft' defb '. Have fun! JC' defb ', 29th Oct. 2005' termin equ $ ; end of variables.