; Kilopede. ; (c)2003 Jonathan Cauldwell. ; An entry for the 2003 Minigame Competition, 1k category. ; Project started 18.07.2003 @ 14:00. ; Project completed 18.07.2003 @ 19:39. ; Start address to which we're compiling. ; As we're working in 1k let's locate it in a REM statement. org 23770 ; We want a black screen. ld a,71 ; white on black, bright. ld (23693),a ; screen colours. ld (23624),a ; permanent border colours. inc a out (254),a ; temporary border colour. ; Set up the graphics. ld hl,blocks ; address of user-defined graphics data. ld (23675),hl ; make UDGs point to it. ; Any key to start game. restrt ld hl,23560 ; last keypress. ld (hl),l rstrt0 ld a,(hl) ; keypress? cp l jr z,rstrt0 ; no, wait until something pressed. ; Okay, let's start the game. call 3503 ; ROM routine - clears screen and opens chan #2. ; Number of lives. ld a,3 ; We'll start with three lives. ld (lives),a ld hl,0 ; zeroise score. ld (score),hl ; Initialise coordinates. defb 33,21,15 ; load hl pair with starting coords for player. ld (plx),hl ; set player coords. slevel call dbat ; remove bat if already on screen. call dscor ; display the score. ld a,1 ; lower screen. call 5633 ; open channel. ld a,22 rst 16 ld a,1 ; bottom line of screen. rst 16 ld a,30 ; right edge. rst 16 call splayr ; show player base symbol. call white ld a,(lives) add a,48 ; ASCII code for zero. rst 16 ; display lives. call uscrn ; restore upper screen printing. defb 33,255,255 ; default values to switch off player's bullets. ld (pbx),hl ; set bullet coords. defb 33,255,255 ; load hl pair with starting coords for bat. ld (batx),hl ; set player coords. xor a ; zeroise accumulator. ld (dead),a ; set flag to say player is alive. ; Initialise segments. ld a,8 ; number of segments. ld (numseg),a ; used to establish how many are still on screen. ld b,a ; number of segments to initialise. ld hl,segmnt ; segment table. segint ld (hl),1 ; start off moving right. inc hl ld (hl),0 ; start at top. inc hl ld (hl),b ; use B register as y coordinate. inc hl djnz segint ; repeat until all initialised. ; Now we want to fill the play area with mushrooms. ld a,16 ; ASCII code for INK control. rst 16 ld a,4 ; 4 = colour green. rst 16 ; we want all mushrooms in this colour! ld b,32 ; start with a few. mushlp ld a,22 ; ASCII code for coordinate control character. rst 16 call random ; get a 'random' number. and 15 ; want vertical in range 0 to 15. rst 16 call random ; want another pseudo-random number. and 31 ; want horizontal in range 0 to 31. rst 16 ld a,146 ; UDG 'C' is the mushroom graphic. rst 16 ; put mushroom on screen. djnz mushlp ; loop back until all mushrooms displayed. ; This is the main game loop. mloop equ $ ; Delete the player. call basexy ; set the x and y positions of the player. call wspace ; leave white on black behind. ; Now we've deleted the player we can move him before redisplaying him ; at his new coordinates. Unfortunately in 1k there's no room for fancy ; keyboard/joystick routines so we'll just read a single row of keys. ld bc,63486 ; port for keyboard row 1-5 / joystick port 2. in a,(c) ; see what keys are pressed. ld b,a ; remember the value. and 1 ; outermost bit = key 1. call z,mpl ; it's being pressed, move player left. ld a,b ; restore value. and 2 ; next bit along (value 2) = key 2. call z,mpr ; being pressed, so move player right. ld a,b ; restore value. and 4 ; next bit (value 4) = key 3. call z,mpd ; being pressed, so move player down. ld a,b ; restore value. and 8 ; next bit (value 8) reads key 4. call z,mpu ; it's being pressed, move player up. ld a,b ; restore value. and 16 ; next bit (value 16) reads key 5. call z,fire ; being pressed, so move player down. ; Now he's moved we can redisplay the player. call basexy ; set the x and y positions of the player. call splayr ; show player. ; Now for the bullet. First let's check to see if it's hit anything. call bchk call dbull ; delete bullets. call moveb ; move bullets. call bchk ; check new position of bullets. call pbull ; print bullets at new position. ; Time to sort out the bat. call batchk ; hit anything? call dbat ; delete bat. call mbat ; move bat. call batchk ; hit anything at this new position? call pbat ; print bullets at new position. call sbat ; see if we can start the bat. ld hl,1152 ; pitch. ld de,6 ; duration. call 949 ; ROM routine to produce BEEP. ; Now for the centipede segments. ld ix,segmnt ; table of segment data. ld b,8 ; number of segments in table. censeg push bc ld a,(ix) ; is segment switched on? inc a ; 255=off, increments to zero. call nz,proseg ; it's active, process segment. pop bc ld de,3 ; 3 bytes per segment. add ix,de ; get next segment in ix registers. djnz censeg ; repeat for all segments. halt ; delay. ld a,(numseg) ; number of segments remaining on screen. and a ; same as cp 0 but saves 1 byte. jp z,slevel ; start next level. ld a,(dead) ; was the player killed by a segment? and a jp nz,killed ; player killed - lose a life. ; Jump back to beginning of main loop. jp mloop ; Move player left. mpl ld hl,ply ; remember, y is the horizontal coord! ld a,(hl) ; what's the current value? and a ; is it zero? ret z ; yes - we can't go any further left. ld de,(plx) ; current coords. dec d ; look 1 square to the left. ld (dispx),de ; set up general-purpose x and y coords. call atadd ; get address of attribute at this position. cp 68 ; mushroom attributes are bright (64) + green (4). ret z ; there's a mushroom - we can't move there. dec (hl) ; subtract 1 from y coordinate. ret ; Move player right. mpr ld hl,ply ; remember, y is the horizontal coord! ld a,(hl) ; what's the current value? cp 31 ; is it at the right edge (31)? ret z ; yes - we can't go any further left. ld de,(plx) ; current coords. inc d ; look 1 square to the right. ld (dispx),de ; set up general-purpose x and y coords. call atadd ; get address of attribute at this position. cp 68 ; mushroom attributes are bright (64) + green (4). ret z ; there's a mushroom - we can't move there. inc (hl) ; add 1 to y coordinate. ret ; Move player up. mpu ld hl,plx ; remember, x is the vertical coord! ld a,(hl) ; what's the current value? cp 12 ; is it half-way up (12)? ret z ; yes - we can go no further then. ld de,(plx) ; current coords. dec e ; look 1 square higher. ld (dispx),de ; set up general-purpose x and y coords. call atadd ; get address of attribute at this position. cp 68 ; mushroom attributes are bright (64) + green (4). ret z ; there's a mushroom - we can't move there. dec (hl) ; subtract 1 from x coordinate. ret ; Move player down. mpd ld hl,plx ; remember, x is the vertical coord! ld a,(hl) ; what's the current value? cp 21 ; is it already at the bottom (21)? ret z ; yes - we can't go down any more. ld de,(plx) ; current coords. inc e ; look 1 square down. ld (dispx),de ; set up general-purpose x and y coords. call atadd ; get address of attribute at this position. cp 68 ; mushroom attributes are bright (64) + green (4). ret z ; there's a mushroom - we can't move there. inc (hl) ; add 1 to x coordinate. ret ; Start the bat. sbat ld a,(batx) ; bat vertical coord. inc a ; 255 is default value, increments to zero. ret nz ; bat currently on screen, can't start again. call random ; want random number 0-255. cp 32 ; 1 in 256 chance of starting the bat. ret nz ; don't start the bat off. call random ; fetch another random number. and 31 ; need it in range 0-31. ld (baty),a ; use this as y coordinate. xor a ; a=0, top of screen. ld (batx),a ; set bat vertical. ret batchk ld a,(batx) ; bat vertical. inc a ; is it at 255 (default)? ret z ; yes, not on screen. ld hl,(batx) ; bat's coordinates. ld a,(pbx) ; bullet coordinates. cp l ; x match? jr nz,batck0 ; no, try player collision instead. ld a,(pby) ; bullet y. cp h ; does it match bat y? jr nz,batck0 ; no, check player coords instead. ; So the bat has collided with the bullet. call dbull ; delete bullet. call kilbul ; kill the bullet. ld hl,(score) ; get current score. ld de,10 ; increment by 10. add hl,de ld (score),hl ; update score. call dscor ; show new points tally on screen. kilbat ld a,255 ; 255=off. ld (batx),a ; switch bat off. ret batck0 ld a,(ply) ; bullet y. cp h ; does it match bat y? ret nz ; no collision. ld a,(plx) cp l ; x match? ret nz ; no player collision. ; So the bat has collided with the player. jp killpl ; kill the player. ; Fire a missile. fire ld a,(pbx) ; bullet vertical coord. inc a ; 255 is default value, increments to zero. ret nz ; bullet currently on screen, can't fire again. ld hl,(plx) ; player coordinates. dec l ; 1 square higher up. ld (pbx),hl ; set bullet coords. ret bchk ld a,(pbx) ; bullet vertical. inc a ; is it at 255 (default)? ret z ; yes, no bullet on screen. ld hl,(pbx) ; get coords. ld (dispx),hl ; set up general-purpose fields. call atadd ; find attribute here. cp 68 ; mushroom attributes are bright (64) + green (4). jr z,hmush ; hit a mushroom! ret hmush ld a,22 ; AT control code. rst 16 ld a,(pbx) ; bullet vertical. rst 16 ld a,(pby) ; bullet horizontal. rst 16 call wspace ; set INK colour to white. ld hl,(score) ; get score. inc hl ; add 1 to it. ld (score),hl ; put score back. call dscor ; display score. kilbul ld a,255 ; x coord of 255 = switch bullet off. ld (pbx),a ; destroy bullet. ret ; This routine moves the bullet up the screen 1 character position at a time. moveb ld a,(pbx) ; bullet vertical. inc a ; is it at 255 (default)? ret z ; yes, no bullet on screen. sub 2 ; 1 row up. ld (pbx),a ret ; Set up the x and y coordinates for the player's gunbase position, ; this routine is called prior to display and deletion of gunbase. basexy ld a,22 ; AT code. rst 16 ld a,(plx) ; player vertical coord. rst 16 ; set vertical position of player. ld a,(ply) ; player's horizontal position. rst 16 ; set the horizontal coord. ret splayr ld a,16 ; colour control. rst 16 ld a,5 ; colour 5 = cyan. rst 16 ld a,144 ; ASCII code for UDG 'A'. rst 16 ; delete player. ret pbull ld a,(pbx) ; bullet vertical. inc a ; is it at 255 (default)? ret z ; yes, no bullet on screen. call bullxy ld a,16 ; INK control char. rst 16 ld a,6 ; 6 = yellow. rst 16 ld a,147 ; UDG 'D' is used for player bullets. rst 16 ret dbull ld a,(pbx) ; bullet vertical. inc a ; is it at 255 (default)? ret z ; yes, no bullet on screen. call bullxy wspace call white ; set INK colour to white. ld a,32 ; SPACE character. rst 16 ret white ld a,16 ; INK control char. rst 16 ld a,6 ; 7 = white. rst 16 ret ; Set up the x and y coordinates for the player's bullet position, ; this routine is called prior to display and deletion of bullets. bullxy ld a,22 ; AT code. rst 16 ld a,(pbx) ; player bullet vertical coord. rst 16 ; set vertical position of player. ld a,(pby) ; bullet's horizontal position. rst 16 ; set the horizontal coord. ret pbat ld a,(batx) ; bat vertical. inc a ; is it at 255 (default)? ret z ; yes, no bullet on screen. call batxy ; set up bat coords. ld a,16 ; INK control char. rst 16 ld a,3 ; 3 = magenta. rst 16 ld a,148 ; UDG 'E' is used for the bat. rst 16 ret dbat ld a,(batx) ; bat vertical. inc a ; is it at 255 (default)? ret z ; yes, no bullet on screen. call batxy ; set up bat coords. jp wspace ; draw a white space. ; Set up the x and y coordinates for the player's bullet position, ; this routine is called prior to display and deletion of bullets. batxy ld a,22 ; AT code. rst 16 ld a,(batx) ; player bullet vertical coord. rst 16 ; set vertical position of player. ld a,(baty) ; bullet's horizontal position. rst 16 ; set the horizontal coord. ret ; This routine moves the bat down the screen 1 character position at a time. mbat ld a,(batx) ; bat vertical. inc a ; is it at 255 (default)? ret z ; yes, it's not on screen. cp 22 ; past bottom of screen? jp z,kilbat ; gone past so kill bat off. ld (batx),a ; new bat x coordinate. ret proseg call segcol ; segment collision detection. ld a,(ix) ; check if segment was switched off inc a ; by collision detection routine. ret z ; it was, so this segment is now dead. call segxy call wspace ; leave white on black attributes behind. call segmov ; move segment. call segcol ; new segment position collision check. ld a,(ix) ; check if segment was switched off inc a ; by collision detection routine. ret z ; it was, so this segment is now dead. call segxy ld a,16 ; INK character code. rst 16 ld a,2 ; 2 = red segment. rst 16 ld a,145 ; UDG 'B' to display segment. rst 16 ret segmov ld a,(ix+1) ; x coord. ld (dispx),a ; GP x area. ld a,(ix+2) ; y coord. ld (dispy),a ; GP y area. ld a,(ix) and a ; is the segment heading left? jr z,segml ; going left - jump to that bit of code. ; so segment is going right then! segmr ld a,(ix+2) ; y coord. cp 31 ; already at right edge of screen? jr z,segmd ; yes - move segment down. inc a ; look right. ld (dispy),a ; set up GP y coord. call atadd cp 68 ; mushroom attributes are bright (64) + green (4). jr z,segmd ; mushroom to right, move down instead. inc (ix+2) ; no obstacles, so move right. ret ; so segment is going left then! segml ld a,(ix+2) ; y coord. and a ; already at left edge of screen? jr z,segmd ; yes - move segment down. dec a ; look right. ld (dispy),a ; set up GP y coord. call atadd cp 68 ; mushroom attributes are bright (64) + green (4). jr z,segmd ; mushroom to left, move down instead. dec (ix+2) ; no obstacles, so move left. ret ; so segment is going down then! segmd ld a,(ix) ; segment direction. xor 1 ; reverse it, so left becomes right and vice versa. ld (ix),a ; store new direction. ld a,(ix+1) ; y coord. cp 21 ; already at bottom of screen? jr z,segmt ; yes - move segment to the top. ; At this point we're moving down regardless of any mushrooms that may block ; the segment's path. Anything in the segment's way will be obliterated. inc (ix+1) ; haven't reached the bottom yet, so move down. ret ; moving segment to the top of the screen. segmt xor a ; same as ld a,0 but faster and saves 1 byte. ld (ix+1),a ; new x coordinate = top of screen. ret ; Segment collision detection. ; Checks for collisions with player and player's bullets. segcol ld a,(ply) ; bullet y position. cp (ix+2) ; is it identical to segment y coord? jr nz,bulcol ; y coords differ, try bullet instead. ld a,(plx) ; player x coord. cp (ix+1) ; same as segment? jr nz,bulcol ; x coords differ, try bullet instead. ; So we have a collision with the player. killpl ld (dead),a ; set flag to say that player is now dead. ret ; Let's check for a collision with the player's bullet. bulcol ld a,(pbx) ; bullet x coords. inc a ; at default value? ret z ; yes, no bullet to check for. cp (ix+1) ; is bullet x coord same as segment x coord? ret nz ; no, so no collision. ld a,(pby) ; bullet y position. cp (ix+2) ; is it identical to segment y coord? ret nz ; no - no collision this time. ; So we have a collision with the player's bullet. call dbull ; delete bullet. ld a,22 ; AT code. rst 16 ld a,(pbx) ; player bullet vertical coord. inc a ; 1 line down. rst 16 ; set vertical position of mushroom. ld a,(pby) ; bullet's horizontal position. rst 16 ; set the horizontal coord. ld a,16 ; ASCII code for INK control. rst 16 ld a,4 ; 4 = colour green. rst 16 ; we want all mushrooms in this colour! ld a,146 ; UDG 'C' is the mushroom graphic. rst 16 ; put mushroom on screen. call kilbul ; kill the bullet. ld (ix),a ; kill the segment. ld hl,numseg ; number of segments. dec (hl) ; decrement it. ld hl,(score) ; score. ld de,5 ; increment by 5. add hl,de ld (score),hl ; new score. jp dscor ; display new score. ; Set up the x and y coordinates for an individual segment's position, ; this routine is called prior to display and deletion of segments. segxy ld a,22 ; AT code. rst 16 ld a,(ix+1) ; segment vertical coord. rst 16 ; set vertical position of player. ld a,(ix+2) ; segment horizontal position. rst 16 ; set the horizontal coord. ret killed ld hl,lives ; number of lives. dec (hl) ; decrease by one. jp z,restrt ; none left - game ends so jump to restart point. call 3503 ; clear screen. jp slevel ; start level again. ; Score display routine. dscor ld a,1 ; lower screen. call 5633 ; open channel. ld a,22 rst 16 ld a,1 ; bottom line of screen. rst 16 xor a ; zero = left edge. rst 16 ld bc,(score) call 6683 ; ROM routine - displays number in BC registers. uscrn ld a,2 ; 2 = upper screen. jp 5633 ; open channel. numseg defb 0 ; number of segments. lives defb 0 ; number of lives remaining. score defw 0 ; score. dead defb 0 ; flag - player is dead when this is non-zero. plx defb 0 ; player's coordinates. ply defb 0 pbx defb 255 ; player's bullet coordinates. pby defb 255 batx defb 255 ; bat coordinates. baty defb 255 dispx defb 0 ; general purpose coordinates. dispy defb 0 ; 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 ld a,h and 31 ; keep it within first 8k of ROM. ld h,a ld a,(hl) ; Get "random" number from location. inc hl ; Increment pointer. ld (seed),hl ret seed defw 0 ; Calculate address of attribute for character at (dispx, dispy). atadd ld a,(dispx) ; vertical coordinate. rrca ; multiply by 32. rrca ; Shifting right with carry 3 times is rrca ; quicker than shifting left 5 times. ld e,a and 3 add a,88 ; 88x256=22528, address of screen attributes. ld d,a ld a,e and 224 ld e,a ld a,(dispy) ; horizontal position. add a,e ld e,a ; de=address of attributes. ld a,(de) ; return with attribute in accumulator. ret ; We'll use some rather naff UDG graphics to save space. blocks defb 16,16,56,56,124,124,254,254 ; player base. defb 24,126,126,255,255,126,126,24 ; segment. defb 24,126,255,255,60,60,60,60 ; mushroom. defb 0,102,102,102,102,102,102,0,0 ; player's bullets. defb 130,198,214,186,214,124,56,16 ; bat. ;10000010 ;11000110 ;11010110 ;10111010 ;11010110 ;01111100 ;00111000 ;00010000 ;00000000 ; Table of segments. ; Format: 3 bytes per entry. ; byte 1: 255=segment off, 0=left, 1=right. ; byte 2 = x (vertical) coordinate. ; byte 3 = y (horizontal) coordinate. segmnt equ $