
; Big Baps.
; (C) Copyright 2007 Jonathan Cauldwell.
; An entry for the 2007 Minigame competition, 4k category.

; Project started      06.07.2007 @ 15:58.
; Project completed    10.07.2007 @ 14:24.


; Definitions.

LADDER equ 14




; Start address.  As usual for 4K minigames it's in a BASIC REM statement.

       org 23769



; Initialisation.
; Set up UDGs.

       ld hl,udgs          ; UDG graphics.
       ld (23675),hl       ; set the system variable to point to them.

; Set up the blank sprite.

       ld hl,blkspr        ; blank sprite.
       ld (hl),255         ; write first byte.
       inc hl              ; second byte.
       ld (hl),192         ; write second byte.
       dec hl              ; start of sprite.
       ld de,blkspr+2      ; next line down.
       ld bc,18            ; 18 more bytes left.
       ldir                ; set up first sprite.

; Screen colours.

       xor a               ; zero is code for black.
       call 8859           ; set the border colour.
       ld hl,23693         ; permanent attributes system variable.
       ld (hl),71          ; set to bright white on black.


; Wait for player to start game.

waitg  call 654            ; fetch keypress.
       ld a,e              ; result in accumulator.
       cp 33               ; ENTER key pressed?
       jr nz,waitg         ; no, wait.

; Okay, let's play.

       call 3503           ; clear the screen.

; Display the extra lives icon at the side of the screen.

       ld hl,164+208*256   ; load coordinates of extra lives sprite into hl.
       ld (dispx),hl       ; sprite routine coordinates.
       ld hl,psplr         ; player sprite, left/right.
       call sprite         ; show lives icon.
       ld de,pantxt        ; panel text.
       ld bc,droom-pantxt  ; length of string.
       call 8252           ; show string.

; Variable initialisation.

       ld a,3              ; default lives.
       ld (numlif),a       ; initialise lives.
       ld hl,levdat        ; level data.
       ld (levptr),hl      ; set up level pointer.
       ld hl,xydat         ; item position data.
       ld (xyptr),hl       ; set up coords pointer.

       ld a,255            ; set all bits.
       ld (matrix+9),a     ; enable ketchup bottle.

       ld hl,matrix        ; grid.
       ld de,matrix+1      ; second byte.
       ld bc,9             ; 9 positions on grid + bonus.
       ld (hl),255         ; clear first position.
       ldir                ; clear rest of grid.

       ld a,90             ; seconds required to complete level.
       ld (time),a         ; set up time.
       ld a,5              ; dull cyan on black.
       ld (gcolou),a       ; set initial girder colours.
       ld hl,23695         ; temporary attributes system variable.
       ld (hl),69          ; cyan ink on black background.
       ld hl,0             ; zero in hl pair.
       call sscor          ; set and show score.

newlev call assem          ; assemble level.
       ld a,(gcolou)       ; girder colours.
       xor 70              ; toggle magenta/cyan.
       ld (gcolou),a       ; set new girder colours.

; Show status panel text.

rstart call dlife          ; show number of lives.
       call dtime          ; show time.
       call droom          ; show level.

; Initialise enemies.

       xor a
       ld (saus1),a        ; enable first sausage.
       ld (saus2),a        ; enable first sausage.

       ld hl,8+48*256      ; coordinates.
       ld (saus1+1),hl     ; set sausage coords.
       ld ix,saus1         ; sausage pointer.
       call dsaus          ; display sausage.

       ld hl,8+96*256      ; coordinates.
       ld (saus2+1),hl     ; set sausage coords.
       ld ix,saus2         ; sausage pointer.
       call dsaus          ; display sausage.

; Set up player.

       ld hl,128           ; coordinates.
       ld (playx),hl       ; set up player starting position.
       call dplay          ; display player.

       call onesec         ; wait for one second.
       ld a,b              ; zero in accumulator.
       ld (23672),a        ; clear low byte of clock.

; Initialise collectables.

       call itoff          ; remove item from screen.

mloop  ld hl,(playx)       ; player coordinates.
       ld (oplayx),hl      ; store old coordinates before we move.
       halt
       call dplay          ; delete player.
       call getkey         ; get key state in accumulator.
       and 2               ; test for left.
       call nz,mpl         ; key is pressed, move that way.
       ld a,(joyval)       ; keypress state.
       rra                 ; is right pressed?
       call c,mpr          ; yes, go right.
       ld a,(joyval)       ; keypress state.
       and 8               ; is up pressed?
       call nz,mpu         ; yes, go up.
       ld a,(joyval)       ; keypress state.
       and 4               ; is down pressed?
       call nz,mpd         ; yes, go there.

       call dplay          ; display at new position.

       ld hl,(playx)       ; new player position.
       ld de,(oplayx)      ; previous coordinates.
       and a               ; clear carry flag.
       sbc hl,de           ; are they identical?
       call nz,cbuf        ; no - check blocks underfoot.

       ld a,(23672)        ; clock low.
       cp 50               ; another second elapsed?
       call nc,second      ; another second gone.

       ld ix,saus1         ; first sprite.
       halt
       call msaus          ; move sausage.
       ld ix,saus2         ; second sausage.
       call msaus          ; process it.

       ld ix,saus1         ; first sprite.
       call soscol         ; check for collision with player.
       ld ix,saus2         ; second sausage.
       call soscol         ; has he caught the player?
       call pitem          ; process items.
       call emerge         ; prevent sausages emerging together.

       jr mloop            ; back to start of main loop.



; Collectable objects processing.


pitem  ld a,(itemno)       ; present item on screen.
       inc a               ; is there one?
       jr nz,itonsc        ; yes, item on screen routine.

; No object on screen.

       ld hl,itcnt         ; item counter.
       inc (hl)            ; increment.
       ret nz              ; not reached zero yet.
       call random         ; random number.
       and 13              ; 1 in 8 chance.
       cp 9                ; is it the shot?
       jr z,newit0         ; yes, that'll do.

newitm call ranitm         ; get random item number.
       ld b,a              ; store in b register.
       call getmat         ; get matrix position address.
       ld a,(hl)           ; find contents there.
       inc a               ; is it empty?
       jr nz,newitm        ; no, try another.
       ld a,b              ; restore item number.
newit0 ld (itemno),a       ; set up that item no.
       call random         ; random position.
       and 2               ; only 2 per level.
       ld hl,(xyptr)       ; x and y positions.
       call addac1
       ld de,itemxy        ; item coordinates.
       ldi                 ; copy x coord.
       ldi                 ; same for y.

; Drop through into display/delete object routine.

dobj   ld a,(itemno)       ; item number.
       ld hl,(itemxy)      ; coordinates.
       ld (dispx),hl       ; display position.
       jp ditem            ; show sprite.

itonsc ld hl,itcnt         ; counter.
       inc (hl)            ; keep going.
       jp z,itofsc         ; timed out, remove item.

       ld bc,(playx)       ; player coordinates.
       ld hl,(itemxy)      ; item coordinates.

; Check (l, h) for collision with (c, b), strict enforcement.

colx16 ld a,l              ; x coord.
       sub c               ; subtract x.
       add a,15            ; add maximum distance.
       cp 31               ; within x range?
       ret nc              ; no - they've missed.
       ld a,h              ; y coord.
       sub b               ; subtract y.
       add a,15            ; add maximum distance.
       cp 31               ; within y range?
       ret nc              ; there's no collision.

; Player has picked up the item.

       call dobj           ; delete item.
       call tinkle         ; sound effect.
       ld a,(itemno)       ; item number.
       cp 9                ; is it the bonus item?
       call z,shot         ; do grid shot routine.
       call getmat         ; get matrix position address.
       ld a,(hl)           ; present value.
       cpl                 ; toggle it.
       ld (hl),a           ; new value.
       call filmat         ; check for full matrix.

       ld hl,itcnt         ; item counter.
       ld (hl),0           ; start counting from zero.
       inc hl              ; item number.
       ld (hl),255         ; remove from screen.
       ret


itofsc call dobj           ; delete item.
itoff  ld a,255            ; all bits set = off.
       ld (itemno),a       ; remove item.
       ret


filmat ld (hl),a           ; fill position.
       ld a,(itemno)       ; item number.
       call dgridp         ; display grid position.

; Now check if matrix lines are filled.

cfill  ld hl,matrix        ; address of grid.
       ld b,9              ; items to check.
film0  ld a,(hl)           ; fetch current cell contents.
       inc a               ; is it empty?
       ret z               ; yes, so grid not full.
       inc hl              ; next matrix position.
       djnz film0          ; repeat for rest of grid.

       ld hl,numlif        ; number of lives.
       inc (hl)            ; add 1.
       call remov          ; remove items from grid.
       jp dlife            ; show lives.

shot   call chirp          ; play brief sound.
       call debou          ; debounce keys.
shot2  call ranitm         ; random item number.
       ld hl,chosen        ; last chosen position.
       cp (hl)             ; are they the same?
       jr z,shot2          ; yes, try another.
       ld (chosen),a       ; set new chosen value.
       call dblspr         ; display sprite.
       ld b,12             ; shot skill time.
shot0  push bc             ; store loop counter.
       halt                ; wait for interrupt.
       call getkey         ; get keyboard input.
       pop bc              ; restore loop counter.
       and a               ; anything pressed?
       jr nz,shot1         ; yes, we've chosen this square.
       djnz shot0          ; repeat.
       ld a,(chosen)       ; chosen square.
       call dblspr         ; display sprite.
       jp shot2
shot1  call beep0          ; sound effect.
       ld a,(chosen)       ; chosen square.
       ld (itemno),a       ; set up item number.
       call dblspr         ; delete block.
       ld a,(chosen)       ; return with square in accumulator.
       ret


ranitm call random         ; random number.
       and 15              ; mask away unwanted bits.
       cp 9                ; only 9 positions.
       jr nc,ranitm        ; not within range.
       ret


; Display blank square sprite.

dblspr call gridc          ; set up grid coordinates.
       ld hl,dispx         ; x position.
       dec (hl)            ; look up.
       dec (hl)            ; look up.
       ld hl,dispy         ; y position.
       dec (hl)            ; look left.
       dec (hl)            ; look left.
       ld hl,blkspr        ; blank sprite.
       call sprite         ; display sprite.
       ld a,(dispx)        ; x coord.
       push af             ; remember it.
       add a,10            ; 10 pixels down.
       ld (dispx),a        ; new position.
       ld hl,blkspr        ; blank sprite.
       call sprite         ; display sprite.
       ld a,(dispy)        ; y coord.
       add a,10            ; 10 pixels right.
       ld (dispy),a        ; new position.
       ld hl,blkspr        ; blank sprite.
       call sprite         ; display sprite.
       pop af              ; remember first x coord.
       ld (dispx),a        ; restore coord.
       ld hl,blkspr        ; blank sprite.
       call sprite         ; display sprite.
       ret


; Remove filled positions.

remov  ld hl,matrix+8      ; grid.
       ld b,9              ; positions to check.
remov0 push hl             ; store position.
       push bc             ; store counter.
       ld a,(hl)           ; get cell contents.
       inc a               ; is something there to be removed?
       call nz,remcel      ; yes, remove cell.
       pop bc
       pop hl
       dec hl              ; previous position.
       djnz remov0         ; repeat.
       ret

remcel ld (hl),255         ; reset position.
       ld a,b              ; position number.
       dec a               ; one less.
       call dgridp         ; display grid position.
       ret


; Play find the pea for time bonus.

pea    call spams          ; screen parameters.
       ldir                ; store screen..
       call swap           ; play find the pea.

       call spams          ; screen parameters.
       ex de,hl            ; switch back.
       ldir                ; restore screen.
       call dtime          ; restore new time setting.
onesec ld b,50             ; one second.

delay  halt
       djnz delay
       ret


; Screen copy parameters.

spams  ld hl,16384         ; physical screen.
       ld de,tmpscr        ; temp screen.
       ld bc,6912          ; data to copy.
       ret




; Display item at grid position held in accumulator.

dgridp push af             ; store item number.
       call gridc          ; set up grid coordinates.
       pop af              ; restore item number.
       jp ditem            ; show item.

; Copy grid coordinates into dispx.

gridc  rlca                ; multiple of 2.
       ld e,a              ; low byte of table displacement.
       ld d,0              ; no high byte needed.
       ld hl,gridxy        ; grid x and y positions.
       add hl,de           ; point to coordinates.
       ld de,dispx         ; display coords.
       ldi                 ; copy 2 bytes to coordinates.
       ldi
       ret


; Matrix coordinates.

gridxy defb 12,196,12,216,12,236
       defb 32,196,32,216,32,236
       defb 52,196,52,216,52,236


; Assemble next level.

; Clear the area.

assem  ld hl,screen        ; screen area.
       ld de,screen+1      ; second byte.
       ld bc,24*32-1       ; size of screen.
       ld (hl),l           ; clear first byte.
       ldir                ; clear rest of buffer.

; Draw basic girders.

       ld b,4              ; number of platforms.
       ld hl,screen+3*24   ; first platform address.
gird1  ld a,24             ; width of screen.
gird0  ld (hl),1           ; draw girder.
       dec a               ; one less to draw.
       inc hl              ; next block along.
       jr nz,gird0         ; repeat for rest of girder.
       ld de,4*24          ; distance to next platform.
       add hl,de           ; point there.
       djnz gird1          ; repeat for all levels.

; Draw the burgers.

dfood  ld a,8              ; default items needed = 2 burgers, 2 * 4.
       ld (numfel),a       ; set burger bits remaining.
       ld hl,(levptr)      ; level pointer.
       ld a,(hl)           ; fetch byte.
       cp 48               ; end of data?
       jr nz,dfood0        ; no, not yet.
       ld hl,xydat         ; item position data.
       ld (xyptr),hl       ; set up coords pointer.
       ld hl,levdat        ; restart at first level.
       ld a,(hl)           ; get first byte.

dfood0 inc hl              ; next byte.
       push hl             ; store pointer.

       ld bc,buntop        ; bread top.
       ld hl,screen+3*24   ; first platform.
       ld e,a              ; column number.
       ld d,0              ; no high byte.
       add hl,de           ; point to address.
       call food           ; transfer food to data.
       ld bc,cheese        ; cheese.
       call food4          ; transfer it.

       pop hl              ; restore pointer.
       ld a,(hl)           ; fetch byte.
       inc hl              ; next byte.
       push hl             ; store pointer.

       ld bc,buntop        ; bread top.
       ld hl,screen+3*24   ; first platform.
       ld e,a              ; column number.
       ld d,0              ; no high byte.
       add hl,de           ; point to address.
       call food2          ; transfer food to data.
       ld bc,burger        ; burger.
       call food3          ; transfer burger.

       pop hl              ; restore pointer.
       ld a,(hl)           ; fetch byte.
       inc hl              ; next byte.
       cp 24               ; beyond range of screen?
       jp nc,putlad        ; yes, only 2 burgers.
       push hl             ; store pointer.

       ld bc,buntop        ; bread top.
       ld hl,screen+3*24   ; first platform.
       ld e,a              ; column number.
       ld d,0              ; no high byte.
       add hl,de           ; point to address.
       call food           ; transfer food to data.
       ld bc,cheese        ; cheese.
       call food4          ; transfer it.
       pop hl              ; restore pointer.

       ld a,12             ; items needed to hit plates.
       ld (numfel),a       ; set burger bits remaining.


; Now put ladders into level.

putlad ld b,(hl)           ; number of ladders.
       inc hl              ; first ladder address low.

putld0 push bc             ; store number of ladders.
       ld e,(hl)           ; ladder low address.
       inc hl              ; second byte of address.
       ld d,(hl)           ; ladder high address.
       inc hl              ; point to next ladder.
       push hl             ; store level data pointer.

       ex de,hl            ; make hl screen buffer address.

       ld de,23            ; distance to next byte.
       ld bc,LADDER+5*256  ; ladder byte and height.
putld1 ld (hl),c           ; restore left side of ladder.
       inc hl              ; next byte.
       ld (hl),c           ; restore right side of ladder.
       add hl,de           ; point to next line down.
       djnz putld1
       pop hl              ; restore decompression address.
       pop bc              ; restore ladder count.
       djnz putld0         ; repeat for all ladders.

       ld (levptr),hl      ; store next level position.
       ret


food4  call food           ; transfer 4 lines of burger data.
food3  call food           ; transfer 3 lines.
food2  call food           ; transfer 2 lines.

; Transfer burger data to level.

food   ld e,4              ; bytes to transfer.
food0  ld a,(bc)           ; source byte.
       ld (hl),a           ; target area.
       inc bc              ; next source.
       inc hl              ; next target.
       dec e               ; one less block to copy.
       jr nz,food0         ; repeat.
       ld de,4*24+20       ; distance to next line down.
       add hl,de           ; next address.
       ret




; Player input and movement routines.
; Get keyboard input.

getkey ld d,0              ; zeroise result.

       ld bc,63486         ; top row 6 - 0.
       call getbt2         ; put bit 2 into carry status.

       ld bc,64510         ; top row 1 - 5.
       call getbt2         ; put bit 2 into carry status.

       ld bc,61438         ; second row Q - T.
       call getbt2         ; put bit 2 into carry status.

       ld e,1              ; bit to test.
       call getbit         ; carry status.

       ld a,d              ; result in accumulator.
       ld (joyval),a       ; store result.
       ret

getbt2 ld e,2              ; bit to test.
getbit in a,(c)            ; read keyboard port.
       and e               ; test relevant bit.
       cp e                ; if not set then set carry flag.
       rl d                ; rotate into d register.
       ret

; Debounce controls.

debou  call getkey         ; read all control keys.
       and a               ; anything pressed?
       jr nz,debou         ; yes, wait for release.
       ret



; Divide hl by d and return in hl.
; Alas, we have to do this manually.

idiv   xor a               ; HL = HL / D
       ld c,a              ; zeroise c.
       ld e,a              ; zeroise e.
       call idiv4          ; do 8-bit division.
       push af             ; store result on stack.
       xor a               ; zero in accumulator.
       ld c,a              ; clear c register.
       ld d,a              ; clear d register.
       call idiv4          ; second 8-bit division.
       pop hl              ; restore first result.
       ld l,h              ; low byte of result.
       ld h,a              ; that's the high byte.
       ret
idiv4  ld b,8              ; 8 bits per byte.
idiv1  rr d                ; divide de by 2.
       rr e
       rr c
       ex af,af'           ; store flag.
       xor a               ; zeroise accumulator.
       cp c                ; is c zero?
       jr z,idiv2          ; yes.
       ex af,af'           ; restore flags.
idiv3  rla                 ; rotate into right of accumulator.
       and a               ; reset carry.
       djnz idiv1          ; repeat 8 times.
       ret
idiv2  ex af,af'
       ld (mtbuff),hl      ; store number we're dividing.
       sbc hl,de           ; do subtraction.
       ccf                 ; reverse carry.
       jr c,idiv3          ; carry set, bit 
       ld hl,(mtbuff)      ; subtracted too much so restore last value.
       jr idiv3            ; repeat.



; Align player with ladder.

aligl  ld a,(joyval)       ; fetch control byte.
       and 3               ; moving left/right?
       ret nz              ; yes, don't align.
       jp mpl              ; align left.

aligr  inc hl              ; look to next cell.
       ld a,(hl)           ; examine contents.
       cp LADDER           ; is it a ladder?
       ret nz              ; no, don't move player.
       ld a,(joyval)       ; fetch control byte.
       and 3               ; moving left/right?
       ret nz              ; yes, don't align.
       jp mpr              ; align right.

; Move player up.

mpu    ld bc,(playx)       ; coordinates.
       ld a,15             ; distance to last pixel of sprite.
       add a,c             ; find x coordinate.
       ld c,a              ; new coord.
       call gsblk          ; fetch character block.
       cp LADDER           ; is it a ladder?
       jp nz,aligr         ; no, can't go there then.
       inc hl              ; look to next square.
       ld a,(hl)           ; fetch block.
       cp LADDER           ; is it a ladder?
       ret nz              ; no, can't go there then.
       ld a,(playy)        ; horizontal.
       and 7               ; is sprite on 8-pixel boundary?
       jp nz,aligl         ; no, try to align horizontally.
       ld hl,playx         ; coordinate.
       dec (hl)            ; move up.
       dec (hl)
       xor a               ; direction is up.
       ld (playd),a        ; set facing direction.
       ret

; Move player down.

mpd    ld bc,(playx)       ; coordinates.
       ld a,16             ; distance to pixel below sprite.
       add a,c             ; find x coordinate.
       cp 144              ; past bottom girder?
       ret nc              ; yes, can't go there.
       ld c,a              ; new coord.
       call gsblk          ; fetch character block.
       cp LADDER           ; is it a ladder?
       jp nz,aligr         ; no, can't move there then.
       inc hl              ; look to next square.
       ld a,(hl)           ; fetch block.
       cp LADDER           ; is it a ladder?
       ret nz              ; no, can't go there then.
       ld a,(playy)        ; horizontal.
       and 7               ; is sprite on 8-pixel boundary?
       jp nz,aligl         ; no, can't move vertically.
       ld hl,playx         ; coordinate.
       inc (hl)            ; move down.
       inc (hl)
       ld a,2              ; direction is down.
       ld (playd),a        ; set facing direction.
       ret

; Move player left.

mpl    call checkx         ; check x coord is valid.
       ret nz              ; can't move left or right.
       ld hl,playy         ; coordinate.
       ld a,(hl)           ; present value.
       and a               ; at left edge already?
       ret z               ; yes, go no further.
       dec (hl)            ; move left.
       dec (hl)
       ld a,3              ; direction is left.
       ld (playd),a        ; set facing direction.
       ret

checkx ld a,(playx)        ; vertical coordinate.
       cp 8                ; is it the top platform?
       ret z               ; that's okay.
       cp 48               ; second platform?
       ret z               ; that's okay.
       cp 88               ; third platform?
       ret z               ; that's okay.
       cp 128              ; fourth platform?
       ret                 ; return with zero flag indicating status.

; Move player right.

mpr    call checkx         ; check x coord is valid.
       ret nz              ; can't move left or right.
mpr0   ld hl,playy         ; coordinate.
       ld a,(hl)           ; present value.
       cp 176              ; reached right edge?
       ret nc              ; yes, go no further.
       inc (hl)            ; move right.
       inc (hl)
       ld a,1              ; direction is right.
       ld (playd),a        ; set facing direction.
       ret

; Check burger underfoot.

cbuf   ld bc,(playx)       ; player position.
       ld a,16             ; platforms are 16 pixels below player.
       add a,c             ; add to x position.
       ld c,a              ; coordinate to check.
       call gsblk          ; find block there.
       cp 2                ; is it before range?
       jr c,cbuf0          ; yes, try next block.
       cp LADDER           ; is it past range?
       jr c,pbd            ; no, push down.
cbuf0  inc hl              ; next cell.
       ld a,(hl)           ; get block type.
       cp 2                ; is it before range?
       jr c,cbuf1          ; yes, try next block.
       cp LADDER           ; is it past range?
       jr c,pbd            ; no, push down.
cbuf1  ld a,b              ; y coordinate.
       and 7               ; straddling cells?
       ret z               ; no, job done.
       inc hl              ; final cell to check.
       ld a,(hl)           ; get block type.
       cp 2                ; is it before range?
       ret c               ; yes, nothing to do.
       cp LADDER           ; is it past range?
       ret nc              ; yes, job done.

; Push bit of burger down.

pbd    ld (hl),1           ; restore girder.
       ld de,24            ; distance to next cell down.
       add hl,de           ; point there.
       ld (hl),a           ; write item.
       push hl             ; store address of block we've written.
       push af             ; store block.
       call setbxy         ; set x and y based on hl.
       pop af              ; restore block address.
       call dchar          ; display food at new pos.
       ld hl,(dispx)       ; coordinates.
       dec l               ; up one.
       dec h               ; left one.
       ld (dispx),hl       ; new coords.
       ld a,1              ; need a girder.
       call dchar          ; show girder.

; Now check to see if whole item is detached.
; Find the left edge first.

cbdet  pop hl              ; restore food block address.
cbdet0 dec hl              ; look left.
       ld a,(hl)           ; get item there.
       and a               ; is it space?
       jr z,cbdet1         ; yes, check for 4 detached blocks.
       cp LADDER           ; is it a ladder?
       jr z,cbdet1         ; yes, found end.
       jr cbdet0           ; until we find start.
cbdet1 ld b,4              ; number to check.
cbdet2 inc hl              ; look right.
       ld a,(hl)           ; get block there.
       and a               ; space?
       ret z               ; end of block.
       cp LADDER           ; ladder?
       ret z               ; end of block.
       djnz cbdet2         ; until end of block.

; It's completely detached.

       ld de,21            ; distance to start of next row.
       add hl,de           ; point to block start.

       push hl             ; store address.
       call chirp          ; noise.
       halt                ; synch with display.
       pop hl              ; restore block address.


; See what's below.

       ld b,4              ; block count.
       ld c,0              ; reset collision flag, block count 4.
cbdet3 ld a,(hl)           ; first block.
       and a               ; space?
       jr z,cbdet4         ; that's okay.
       inc c               ; got some sort of collision.
       cp 1                ; girder?
       jr z,cbdet4         ; that's fine.
       call setbxy         ; find coordinate.
       ld a,(dispx)        ; vertical position.
       cp 19               ; reached bottom bit?
       jr nc,cbdet6        ; yes, just land on plate.
       ld a,(hl)           ; restore block.
       ld de,24            ; distance to third row.
       add hl,de           ; point there.
       ld (hl),a           ; knock it out.
       ld de,65512         ; distance back again.
       add hl,de           ; point there.
cbdet4 inc hl              ; point to next square.
       djnz cbdet3         ; repeat.
       ld de,65532         ; distance to start of 2nd row.
       add hl,de           ; point there.
       push hl             ; store destination address.
       ld de,65512         ; distance to start of 1st row.
       add hl,de           ; point there.
       pop de              ; restore 2nd row address.
       ld a,c              ; fetch "hit" flag.
       ld (tmp2),a         ; store it.
       ld bc,4             ; bytes to copy.
       push de             ; destination - 2nd row.
       push hl             ; store source - 1st row.
       ldir                ; do the copy.
       pop hl              ; restore old position.
       push hl             ; store again.
       ld b,4              ; spaces to write.
cbdet5 ld (hl),0           ; write a space.
       inc hl              ; next character.
       djnz cbdet5         ; repeat 4 times.
       pop hl              ; restore top row.
       call dburg          ; delete falling burger.
       pop hl              ; restore 2nd row.
       push hl             ; store for next line check.
       call dburg          ; show falling burger.
       pop hl              ; restore address of food.
       ld a,(tmp2)         ; did we hit anything?
       and a               ; zero means we didn't.
       jr z,cbdet0         ; no, just keep falling.
       ld a,(dispx)        ; position.
       cp 19               ; reached bottom bit?
       ret nc              ; yes, so stop.
       ld de,24            ; distance to start of next row.
       add hl,de           ; point there.
       jr cbdet0           ; keep falling.
cbdet6 call scor5          ; add to score.
       ld hl,numfel        ; number of items needed to hit plate.
       dec (hl)            ; decrement total remaining.
       ret nz              ; not yet, keep playing.

; Completed last item, so move to next level.

       pop de              ; remove return address from stack.
       ld hl,(xyptr)       ; item positions.
       ld de,4             ; 2 * 2 bytes.
       add hl,de           ; point to next positions.
       ld (xyptr),hl       ; next pointer.
       call tinkle         ; brief sound effect.
       call onesec         ; short delay.
       call pea            ; find the pea.
       jp newlev           ; restart.


; Display piece of burger.

dburg  call setbxy         ; set burger x and y based on address.
       ld a,(dispx)        ; x coordinate.
       rlca                ; multiply by 8.
       rlca
       rlca
       ld e,a              ; pixel coordinate.
       ld a,(dispy)        ; y coordinate.
       rlca                ; multiply by 8.
       rlca
       rlca
       ld d,a              ; pixel coordinate.
       ld ix,saus1         ; sausage.
       push de             ; store burger pixel coords.
       call bscol          ; check for burger/sausage collision.
       pop de              ; restore coords in de.
       ld ix,saus2         ; sausage.
       call bscol          ; check for burger/sausage collision.

       ld b,4              ; blocks to show.
dburg0 ld a,(hl)           ; piece to display.
       push bc             ; store loop.
       push hl             ; store position.
       call dchar          ; show character.
       pop hl              ; retrieve position.
       inc hl              ; next piece.
       pop bc              ; loop.
       djnz dburg0
       ret

; Burger/sausage collision check.

bscol  ld a,(ix+1)         ; sausage coordinate.
       cp e                ; direct hit?
       ret nz              ; no, missed sausage.
       ld a,(ix+2)         ; sausage y.
       add a,15            ; look at rightmost edge.
       sub d               ; is it to left of burger?
       ret c               ; yes, burger has missed.
       cp 32+15            ; is it within range of burger?
       ret nc              ; no, it's missed.

       push hl             ; store details.
       push bc             ; remember hit status.

       call scor10         ; add to score.

       ld hl,(dispx)       ; burger display coords.
       push hl             ; store them.
       call dsaus          ; delete it.
       pop hl              ; fetch display coords.
       ld (dispx),hl       ; restore them.
       ld (ix),4           ; switch it off.
       ld (ix+1),200       ; set x coordinate off screen.

       pop bc              ; restore hit flag.
       pop hl              ; restore character string address.
       ret

; Set burger x and y based on hl address.

setbxy push hl             ; store address of blocks.
       push bc             ; store bc pair.
       ld de,screen        ; screen.
       and a               ; clear carry.
       sbc hl,de           ; find displacement.
       push hl             ; store block address.
       ld d,24             ; block line length.
       call idiv           ; find row number.
       ld a,l              ; horizontal position.
       ld (dispx),a        ; set cursor x.
       rlca                ; multiply by 8.
       rlca
       rlca
       ld e,a              ; low byte.
       ld d,0              ; zero high byte.
       pop hl              ; restore displacement.
       and a               ; clear carry.
       sbc hl,de           ; subtract x * 8.
       sbc hl,de           ; subtract x * 16.
       sbc hl,de           ; subtract x * 24.
       ld a,l              ; remainder is y.
       ld (dispy),a        ; set up coordinate.
       pop bc              ; restore bc.
       pop hl              ; restore address.
       ret

; Get screen block address at (c, b).

gsblk  ld a,c              ; x coordinate.
       and 248             ; only want multiples of 8.
       ld e,a              ; low byte of displacement.
       ld d,0              ; no high byte.
       ld hl,screen        ; screen blocks data.
       add hl,de           ; 8 x coordinate.
       add hl,de           ; 16 x coordinate.
       add hl,de           ; 24 x coordinate.
       ld a,b              ; y position.
       rra                 ; divide by 8.
       rra
       rra
       and 31              ; remove bits shifted in.
       ld e,a              ; low byte of displacement.
       add hl,de           ; point to address of block.
       ld a,(hl)           ; fetch its contents.
       ret



; Enemy routines and AI.


; Move a sausage.

msaus  call getabc         ; get direction and coordinates.
       cp 4                ; is it dead?
       jr c,msaus0         ; no - process normally.
       inc a               ; count up.
       ld (ix),a           ; new value.
       and a               ; reached zero yet?
       ret nz              ; no.
       call tinkle         ; sound to reintroduce enemy.
       ld hl,screen+456    ; start of line below last girder.
       ld b,255            ; just before first column.
msaus1 inc b               ; next column
       ld a,(hl)           ; get char there.
       cp LADDER           ; is it the ladder?
       inc hl              ; point to next char.
       jr nz,msaus1        ; no ladder, keep looking.
       ld a,b              ; column number.
       rlca                ; multiply by 8.
       rlca
       rlca
       ld (ix+1),160       ; set x coord at which to appear.
       ld (ix+2),a         ; set y coord at which to appear.
       jp dsaus            ; show sausage.
msaus0 call dsaus          ; delete sausage.
       call getabc         ; restore details.
       and a               ; going up?
       jp z,msosu
       dec a               ; right?
       jr z,msosr
       dec a               ; moving down?
       jp z,msosd
msosl  ld a,b              ; fetch y again.
       and a               ; at left edge?
       jp z,msoss          ; yes, turn around.
       ld a,16             ; distance to blocks underfoot.
       add a,c             ; add to x.
       ld c,a              ; new x.
       dec b               ; look left.
       dec b
       call gsblk          ; get block there.
       and a               ; is it space?
       jp z,msoss          ; yes, change direction switch left/right.
       call getabc         ; restore details.
       dec b               ; move left.
       dec b
       call setabc         ; set new direction.

; Ladder checking.

       ld a,b              ; y position.
       and 7               ; on cell boundary?
       jp nz,dsaus         ; no, display at new position and finish.
       call random         ; random number.
       cp 80               ; chance we won't use it.
       jp c,dsaus          ; don't bother with it.
       cp 160              ; chance we will use it.
       jr c,msosl0         ; use it.
       ld a,(playx)        ; player x.
       cp c                ; same as sausage x?
       jp z,dsaus          ; yes, don't use ladder.

; Check for presence of ladders.

msosl0 ld a,c              ; x coord.
       add a,15            ; look at feet.
       ld c,a              ; x coordinate to check.
       call gsblk          ; find block type there.
       cp LADDER           ; is it a ladder?
       jr nz,msosl1        ; no, can't go up.
       inc hl              ; look to next cell.
       ld a,(hl)           ; what's there?
       cp LADDER           ; is it a ladder?
       jr nz,msosl1        ; no, can't go up.
msosgu call getabc         ; restore details.
       xor a               ; direction up.
       jp sosdon           ; set details and display.
msosl1 call getabc         ; get details.
       ld a,c              ; x.
       add a,16            ; look below feet.
       cp 144              ; past bottom girder?
       jp nc,dsaus         ; yes, can't go down.
       ld c,a              ; x coordinate to check.
       call gsblk          ; find block type there.
       cp LADDER           ; is it a ladder?
       jp nz,dsaus         ; no, can't go down.
       inc hl              ; look to next cell.
       ld a,(hl)           ; what's there?
       cp LADDER           ; is it a ladder?
       jp nz,dsaus         ; no, can't go down.
msosgd call getabc         ; restore details.
       ld a,2              ; direction down.
       jr sosdon           ; set details and display.
msosr  ld a,b              ; fetch y again.
       cp 176              ; at right edge?
       jp nc,msoss         ; yes, turn around.
       ld a,16             ; distance to blocks underfoot.
       add a,c             ; add to x.
       ld c,a              ; new x.
       ld a,b              ; y position.
       add a,16            ; look 16 pixels right.
       ld b,a              ; y coord to check.
       call gsblk          ; get block there.
       and a               ; is it space?
       jp z,msoss          ; yes, change direction switch left/right.
       call getabc         ; restore details.
       inc b               ; move right.
       inc b
       call setabc         ; set new position.

; Ladder checking.

       ld a,b              ; y position.
       and 7               ; on cell boundary?
       jp nz,dsaus         ; no, display at new position and finish.
       call random         ; random number.
       cp 80               ; chance we won't use it.
       jp c,dsaus          ; don't bother with it.
       cp 160              ; chance we will use it.
       jr c,msosl0         ; use it.
       ld a,(playx)        ; player x.
       cp c                ; same as sausage x?
       jp z,dsaus          ; yes, don't use ladder.

; Check for presence of ladders.

msosr0 ld a,c              ; x coord.
       add a,15            ; look at feet.
       ld c,a              ; x coordinate to check.
       call gsblk          ; find block type there.
       cp LADDER           ; is it a ladder?
       jr nz,msosr1        ; no, can't go up.
       inc hl              ; look to next cell.
       ld a,(hl)           ; what's there?
       cp LADDER           ; is it a ladder?
       jr nz,msosr1        ; no, can't go up.
       jr msosgu           ; go up.
msosr1 call getabc         ; get details.
       ld a,c              ; x.
       add a,16            ; look below feet.
       cp 144              ; past bottom girder?
       jp nc,dsaus         ; yes, can't go down.
       ld c,a              ; x coordinate to check.
       call gsblk          ; find block type there.
       cp LADDER           ; is it a ladder?
       jp nz,dsaus         ; no, can't go up.
       inc hl              ; look to next cell.
       ld a,(hl)           ; what's there?
       cp LADDER           ; is it a ladder?
       jp nz,dsaus         ; no, can't go up.
       jr msosgd           ; go down.
msosu  ld a,c              ; x coordinate.
       add a,15            ; look at feet.
       ld c,a              ; coordinate to check.
       call gsblk          ; find block there.
       cp LADDER           ; is it a ladder?
       jr nz,msosu0        ; no, switch direction.
       inc hl              ; look right.
       ld a,(hl)           ; fetch block there.
       cp LADDER           ; is it a ladder?
       jr nz,msosu0        ; no, switch direction.
       call getabc         ; fetch details again.
       dec c               ; up.
       dec c
sosdon call setabc         ; set new details.
       jp dsaus            ; display at new position.
msosu0 call random         ; random number.
       rra                 ; rotate lowest bit into carry.
       jr nc,msosgr        ; no carry, so move right.
msosgl call getabc         ; fetch details again.
       ld a,3              ; direction left.
       jp sosdon           ; job done.
msosgr call getabc         ; fetch details again.
       ld a,1              ; direction right.
       jp sosdon           ; job done.
msosd  ld a,c              ; x coordinate.
       add a,16            ; look below feet.
       ld c,a              ; coordinate to check.
       call gsblk          ; find block there.
       cp LADDER           ; is it a ladder?
       jp nz,msosu0        ; no, switch direction.
       inc hl              ; look right.
       ld a,(hl)           ; fetch block there.
       cp LADDER           ; is it a ladder?
       jr nz,msosu0        ; no, switch direction.
       call getabc         ; fetch details again.
       inc c               ; descend.
       inc c
       jp sosdon           ; done.

; Switch sausage direction.

msoss  call getabc         ; fetch details.
       xor 2               ; switch left/right.
       jp sosdon           ; display at new point.

; Set coordinates and direction.

setabc ld (ix),a           ; get direction.
setbc  ld (ix+1),c         ; x coordinate.
       ld (ix+2),b         ; y position.
       ret

; Fetch coordinates and direction.

getabc ld a,(ix)           ; get direction.
       ld c,(ix+1)         ; x coordinate.
       ld b,(ix+2)         ; y position.
       ret

; Sausages emerging together check.

emerge ld a,(saus1)        ; sausage 1 dead check.
       cp 4                ; is it alive?
       ret c               ; yes, nothing to do.
       cp 240              ; is it to emerge soon?
       ret c               ; no.
       ld a,(saus2)        ; sausage 2 flag.
       cp 4                ; is it alive?
       ret c               ; yes, do nothing.
       cp 240              ; is it to emerge soon?
       ret c               ; no.
       ld a,200            ; new total.
       ld (saus2),a        ; reset counter to stagger them.
       ret


; Sausage collision detection.

soscol call colc16         ; check for collision.
       ret nc              ; no collision.

; Player is dead then.
; Remove return address from stack and deal with it here.
; Removing return addresses from the stack in this way isn't good
; practice generally, but with only 4K to play with things are tight.

dead   pop de              ; remove return address from stack.
       call noisa          ; sound effect.
       ld hl,numlif        ; lives remaining.
       dec (hl)            ; one less.
       jp z,waitg          ; game over.
       ld a,90             ; seconds to complete level.
       ld (time),a         ; set up time.
       jp rstart           ; restart.

; Collision check with corner clipping.

colc16 ld a,(ix)           ; sausage status.
       cp 4                ; is it enabled?
       ret nc              ; no, skip collision check.
       ld hl,(playx)       ; get player's coords.
       ld a,l              ; x coord.
       sub (ix+1)          ; subtract sausage x.
       jr nc,colc1a        ; result is positive.
       neg                 ; make negative positive.
colc1a cp 16               ; within x range?
       ret nc              ; no - they've missed.
       ld e,a              ; store difference.
       ld a,h              ; y coord.
       sub (ix+2)          ; subtract y.
       jr nc,colc1b        ; result is positive.
       neg                 ; make negative positive.
colc1b cp 16               ; within y range?
       ret nc              ; no - they've missed.
       add a,e             ; add x difference.
       cp 26               ; only 5 corner pixels touching?
       ret                 ; carry set if there's a collision.





; Sprite routines.

; Display or delete the item.

ditem  rrca                ; multiply by 32.
       rrca
       rrca
       ld e,a              ; store in e.
       and 1               ; high bit.
       ld d,a              ; high byte of displacement.
       ld a,e              ; restore shift.
       and 224             ; multiple of 32.
       ld e,a              ; that's the low byte.
       ld hl,objspr        ; first item sprite.
       add hl,de           ; add displacement for graphic address.
       jp sprite           ; transfer sprite to display.


; Display sausage.

dsaus  ld a,(ix)           ; enemy direction.
       rra                 ; moving up or down?
       jr nc,dsausv        ; yes, display vertical sprite.

       ld hl,sauslr        ; left/right sprites.
dsaus1 ld c,(ix+1)         ; x coordinate of sprite.
       ld a,(ix+2)         ; y coordinate.
       ld b,a              ; y coordinate.
dsaus0 ld (dispx),bc       ; set up sprite routine coords.
       rlca                ; multiply by 32.
       rlca                ; 6 is already a multiplication by 2,
       rlca                ; so we need 4 shifts.
       rlca
       and 96              ; remove high bits.
       ld d,0              ; there's no high byte.
       ld e,a              ; displacement should now be in de.
       add hl,de           ; add displacement for this sprite.
       jr sprite           ; call sprite routine.

dsausv ld hl,sausud        ; vertical sprites.
       ld a,(ix+1)         ; x coordinate of sprite.
       ld b,(ix+2)         ; y coordinate.
       ld c,a              ; x coordinate.
       jr dsaus0

; Display player sprite.

dplay  ld hl,(playx)       ; player's coordinates.
       ld (dispx),hl       ; coords used by sprite routine.
       ld a,(playd)        ; player direction.
       rra                 ; moving up or down?
       jr nc,dplayv        ; yes, display spud vertical.
dplayh ld a,h              ; y coordinate determines which frame to use.
       ld hl,psplr         ; player sprite left/right.
       jr dplay0
dplayv ld a,l              ; x coordinate determines which frame to use.
       ld hl,pspud         ; player sprite left/right.
dplay0 and 6               ; 0, 2, 4 or 6.
       rrca                ; multiply by 32.
       rrca                ; already a multiple of 2,
       rrca                ; so we need 4 shifts instead of 5.
       rrca
       ld e,a              ; low byte in e register.
       ld d,0              ; no high byte.
       add hl,de           ; add to sprite address.
       jr sprite



; This is my main sprite routine and expects coordinates in (dispx,dispy)
; where dispx is the vertical coord from the top of the screen (0-176), and
; dispy is the horizontal coord from the left of the screen (0 to 240).
; Sprite data is stored as you'd expect in its unshifted form as this
; routine takes care of all the shifting itself.  This means that sprite
; handling isn't particularly fast but the graphics only take 1/8th of the
; space they would require in pre-shifted form.

; On entry HL must point to the unshifted sprite data.

sprit7 xor 7               ; complement last 3 bits.
       inc a               ; add one for luck!
sprit3 rl d                ; rotate left...
       rl c                ; ...into middle byte...
       rl e                ; ...and finally into left character cell.
       dec a               ; count shifts we've done.
       jr nz,sprit3        ; return until all shifts complete.

; Line of sprite image is now in e + c + d, we need it in form c + d + e.

       ld a,e              ; left edge of image is currently in e.
       ld e,d              ; put right edge there instead.
       ld d,c              ; middle bit goes in d.
       ld c,a              ; and the left edge back into c.
       jr sprit0           ; we've done the switch so transfer to screen.

sprite ld a,(dispx)        ; draws sprite (hl).
       ld (tmp1),a         ; store vertical.
       call scadd          ; calculate screen address.
       ld a,16             ; height of sprite in pixels.
sprit1 ex af,af'           ; store loop counter.
       push de             ; store screen address.
       ld c,(hl)           ; first sprite graphic.
       inc hl              ; increment poiinter to sprite data.
       ld d,(hl)           ; next bit of sprite image.
       inc hl              ; point to next row of sprite data.
       ld (tmp0),hl        ; store in tmp0 for later.
       ld e,0              ; blank right byte for now.
       ld a,b              ; b holds y position.
       and 7               ; how are we straddling character cells?
       jr z,sprit0         ; we're not straddling them, don't bother shifting.
       cp 5                ; 5 or more right shifts needed?
       jr nc,sprit7        ; yes, shift from left as it's quicker.
       and a               ; oops, carry flag is set so clear it.
sprit2 rr c                ; rotate left byte right...
       rr d                ; ...through middle byte...
       rr e                ; ...into right byte.
       dec a               ; one less shift to do.
       jr nz,sprit2        ; return until all shifts complete.
sprit0 pop hl              ; pop screen address from stack.
       ld a,(hl)           ; what's there already.
       xor c               ; merge in image data.
       ld (hl),a           ; place onto screen.
       inc l               ; next character cell to right please.
       ld a,(hl)           ; what's there already.
       xor d               ; merge with middle bit of image.
       ld (hl),a           ; put back onto screen.
       inc hl              ; next bit of screen area.
       ld a,(hl)           ; what's already there.
       xor e               ; right edge of sprite image data.
       ld (hl),a           ; plonk it on screen.
       ld a,(tmp1)         ; temporary vertical coordinate.
       inc a               ; next line down.
       ld (tmp1),a         ; store new position.
       and 63              ; are we moving to next third of screen?
       jr z,sprit4         ; yes so find next segment.
       and 7               ; moving into character cell below?
       jr z,sprit5         ; yes, find next row.
       dec hl              ; left 2 bytes.
       dec l               ; not straddling 256-byte boundary here.
       inc h               ; next row of this character cell.
sprit6 ex de,hl            ; screen address in de.
       ld hl,(tmp0)        ; restore graphic address.
       ex af,af'           ; restore loop counter.
       dec a               ; decrement it.
       jp nz,sprit1        ; not reached bottom of sprite yet to repeat.
       ret                 ; job done.
sprit4 ld de,30            ; next segment is 30 bytes on.
       add hl,de           ; add to screen address.
       jp sprit6           ; repeat.
sprit5 ld de,63774         ; minus 1762.
       add hl,de           ; subtract 1762 from physical screen address.
       jp sprit6           ; rejoin loop.


; Calculating a screen address from a pixel coordinate can be tricky!
; The Spectrum screen display is organized into 3 segments of 2048 bytes,
; all containing 8 rows of 32 character squares, each with 8 lines.
; Hence 8 * 32 * 8 * 3 = 6144 bytes.
; Low resolution colour filter = 32 * 8 character squares = 768 bytes.
; Total = 6144 + 768 = 6912 bytes, 16384 to 23295 inclusive.

scadd  ld a,(dispx)        ; Returns screen address of coordinates
       ld b,a              ; (dispx, dispy) in de.
       and 7               ; Line 0-7 within character square.
       add a,64            ; 64 * 256 = 16384 (Start of screen display)
       ld d,a              ; Line * 256.
       ld a,b              ; fetch x coord again.
       rrca                ; divide pixel displacement by 8.
       rrca
       rrca
       and 24              ; Segment 0-2 multiplied by 8.
       add a,d             ; Add to h (so multiply by 8 * 256 = 2048)
       ld d,a
       ld a,b              ; 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 e,a              ; Vertical coordinate calculation done.
       ld a,(dispy)        ; y coordinate.
       ld b,a              ; remember horizontal position for later.
       rrca                ; now need to divide by 8.
       rrca
       rrca
       and 31              ; Squares 0 - 31 across screen.
       add a,e             ; Add to total so far.
       ld e,a              ; de = address of screen.
       ret



; Player left/right.

psplr  defb 0,0,3,192,5,160,47,244,111,246,238,119,198,99,219,219
       defb 236,55,239,247,15,240,127,254,63,252,3,192,123,222,120,30
       defb 3,192,5,160,47,244,111,246,236,55,246,111,235,195,204,55
       defb 247,246,247,240,55,252,79,252,63,248,7,128,247,188,240,60
       defb 3,192,5,160,15,240,47,244,108,54,246,111,203,211,220,59
       defb 239,247,239,247,15,240,127,252,63,248,3,192,123,222,120,30
       defb 0,0,3,192,37,160,111,244,239,246,238,119,198,103,235,211
       defb 108,47,15,239,127,236,127,242,63,252,1,224,61,239,60,15

; Player up/down.

pspud  defb 3,198,7,231,111,243,239,243,207,247,135,230,235,212,236,56
       defb 111,252,31,252,63,252,31,252,239,248,247,128,7,188,0,60
       defb 3,192,103,230,239,247,207,243,207,247,231,231,235,215,108,54
       defb 47,244,31,248,63,252,63,252,7,224,123,222,123,222,0,0
       defb 99,192,231,224,207,246,207,247,239,243,103,225,43,215,28,55
       defb 63,246,63,248,63,252,63,248,31,247,1,239,61,224,60,0
       defb 3,192,103,230,239,247,207,243,239,243,231,231,107,215,44,54
       defb 31,244,63,248,127,252,63,252,7,224,123,222,123,222,0,0



; Sausage left/right.

sauslr defb 67,128,55,197,103,226,39,229,19,228,15,248,1,240,1,240
       defb 3,240,3,224,7,224,15,224,23,208,19,144,56,24,120,60
       defb 0,0,3,128,7,192,87,229,39,226,83,237,15,241,1,240
       defb 1,240,3,240,3,224,7,224,15,240,23,200,227,134,224,15
       defb 3,128,7,192,7,224,7,224,67,224,35,241,253,250,33,247
       defb 3,242,3,225,7,224,15,224,23,208,19,144,56,24,120,60
       defb 3,128,7,192,7,224,87,229,35,226,83,253,13,241,1,240
       defb 3,240,3,224,7,224,7,224,7,224,3,160,15,112,15,112

; Sausage up/down.

sausud defb 1,192,195,224,199,224,39,224,47,192,31,243,15,143,15,128
       defb 15,192,7,216,7,246,7,247,59,224,33,192,224,0,224,0
       defb 1,192,3,224,7,224,199,227,207,207,63,240,15,128,15,128
       defb 15,192,7,192,55,232,47,244,227,231,225,199,0,0,0,0
       defb 1,192,3,227,7,227,7,228,15,200,207,240,223,128,47,128
       defb 15,192,63,192,231,224,231,240,3,232,1,196,0,7,0,7
       defb 1,192,3,224,7,224,199,227,207,207,63,240,15,128,15,128
       defb 15,192,7,192,55,232,47,244,227,231,225,199,0




; Collectables.

; Mushroom.

objspr defb 0,0,0,192,1,240,2,56,5,92,5,78,4,150,1,215
       defb 7,227,31,235,127,211,223,139,239,38,246,28,116,0,56,0

; Fish slice.

       defb 24,0,60,0,118,0,235,0,213,128,106,192,53,128,27,0
       defb 14,128,4,64,0,32,0,24,0,28,0,14,0,5,0,3

; Toast.

       defb 1,192,3,0,6,240,13,176,27,240,54,248,111,216,219,248
       defb 191,108,187,254,47,246,61,188,7,248,0,240,0,96,0,0

; Sausages.

       defb 0,240,1,216,57,236,125,244,116,254,244,122,252,127,244,61
       defb 252,63,254,31,122,31,127,31,61,159,63,142,31,128,15,0

; Cutlery.

       defb 42,32,42,48,42,56,62,56,62,60,28,60,8,60,8,60
       defb 8,60,28,48,28,56,28,56,28,56,28,56,28,56,28,56

; Cheese.

       defb 28,224,28,240,15,176,29,28,63,182,39,127,35,19,38,18
       defb 63,60,125,248,119,224,35,224,35,192,119,128,126,0,0,0

; Egg.

       defb 0,0,1,240,7,252,31,254,63,254,127,254,127,250,255,250
       defb 255,246,255,244,127,252,127,232,63,216,31,112,7,192,0,0

; Tea.

       defb 0,0,6,0,15,128,11,224,16,248,28,62,60,12,60,223
       defb 120,251,121,249,241,243,243,246,63,252,15,224,3,192,0,192

; Frying pan.

       defb 64,0,160,0,112,0,56,0,28,240,15,156,6,102,5,250
       defb 13,251,11,253,11,253,13,251,5,250,6,102,3,156,0,240

; Ketchup.

       defb 0,224,3,224,3,0,0,192,0,240,1,248,1,60,2,28
       defb 2,30,2,14,2,15,2,31,3,255,3,254,1,248,0,96


udgs   defb 62,0,0,0,62,0,0,0
       defb 62,0,0,0,0,0,0,0


; Short chirp.

chirp  ld hl,0         ; starting pitch.
       ld b,20         ; loop counter.
chirp0 push hl         ; store pitch.
       ld de,0         ; duration of note.
       call 949        ; call ROM sound routine.
       pop hl          ; restore pitch.
       ld de,5         ; speed of pitch bend.
       add hl,de       ; add to pitch.
       djnz chirp0     ; repeat.
       ret

; Quiet "tinkle" sound.

tinkle ld b,192            ; outer loop counter.
tinkl0 ld a,248            ; set all non-border bits.
       out (254),a         ; write to speaker.
       ld a,r              ; poor man's random number.
       or b                ; combine with main loop counter.
tinkl1 dec a               ; decrement.
       jr nz,tinkl1        ; delay loop.
       ld a,r              ; random number.
       and 248             ; mask off border colour information.
       out (254),a         ; write to speaker port.
       djnz tinkl0         ; repeat.
       ret

beep0  ld hl,806           ; pitch.
       ld de,33            ; duration.
       call 949            ; call beeper routine.
       ld hl,856           ; pitch.
       ld de,31            ; duration.
       jp 949              ; call beeper routine.

beep1  ld hl,1643          ; pitch.
       ld de,4             ; duration.
       jp 949


; Crash sound.

noisa  ld e,250            ; starting point.
noisa2 ld b,32             ; length of step.
noisa0 call random
       and 248             ; mask away border bits.
       out (254),a         ; drive speaker.
       ld a,e
       cpl
noisa1 dec a               ; decrement counter.
       jr nz,noisa1        ; inner delay loop.
       djnz noisa0         ; end of middle loop.
       ld a,e
       sub 23              ; size of step.
       cp 32               ; end of range.
       ret c               ; that's enough.
       ld e,a
       cpl                 ; toggle bits to find delay.
noisa3 ld b,40             ; silent period.
noisa4 djnz noisa4         ; inner delay.
       dec a               ; decrement counter.
       jr nz,noisa3        ; repeat.
       jr noisa2           ; back to start of outer loop.


; 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,(hl)           ; get "random" number from location.
       inc hl              ; increment pointer.
       res 5,h             ; stay within "random" part of ROM.
       ld (seed),hl
       ret

; Get matrix position address.

getmat ld hl,matrix        ; grid positions.
addac1 ld e,a              ; displacement in de.
       ld d,0              ; no high byte.
       add hl,de           ; point to appropriate slot.
       ret

scor5  ld de,5             ; amount to add.
       jr scorx
scor10 ld de,10            ; amount to score.
scorx  ld hl,(score)       ; player's score.
       add hl,de           ; add to total.
sscor  ld (score),hl       ; store new total.
dscor  ld bc,6*256+7       ; line and column.
       call 3545           ; set cursor position.
       ld hl,(score)       ; score.
       ld a,l              ; copy hl to lh for BASIC line number format.
       ld l,h              ; high byte to low byte.
       ld h,a              ; low byte to high byte.
rjust  ld (dnum),hl        ; set up display number.
       ld hl,dnum          ; display number.
       jp 6696             ; display score.

; Timer.

second sub 50              ; subtract 1 second from clock.
       ld (23672),a        ; new clock setting.
       ld hl,time          ; time remaining.
       dec (hl)            ; one second less.
       jp z,dead           ; time up.
dtime  ld bc,9*256+7       ; 9 lines up, 7 from edge.
       call 3545           ; set cursor position.
       ld a,(time)         ; seconds left.
       ld h,a              ; put seconds into h.
       ld l,0              ; never more than 255 so no high byte.
       jr rjust            ; call ROM routine to show right-justified.


; Display lives remaining.

dlife  ld bc,3*256+4       ; 3 from bottom, 4 from edge.
       call 3545           ; set cursor position.
       ld a,(numlif)       ; number of lives remaining.
       add a,'0'           ; add ASCII code for zero.
       rst 16              ; display character.
       ret

pantxt defb 22,17,25,16,7
       defb 'SCORE'
       defb 22,14,26
       defb 'TIME'



; Draw character window.

droom  ld hl,screen        ; point to this screen.
       xor a               ; top coordinate.
       ld (dispx),a        ; set coordinate.
       ld (numobj),a       ; set number of objects.
       ld b,24             ; height in blocks.
droom0 push bc             ; store row counter.
       xor a               ; left coordinate.
       ld (dispy),a        ; set horizontal starting point.
       ld b,24             ; width in blocks.
droom1 push bc             ; store column counter.
       ld a,(hl)           ; get character.
       push hl             ; store character address.
       call dchar          ; draw the character.
       pop hl              ; restore pointer to address.
       inc hl              ; next block.
       pop bc              ; restore column count.
       djnz droom1
       ld a,(dispx)        ; vertical position.
       inc a               ; move down.
       ld (dispx),a        ; next line starts here.
       pop bc              ; restore row count.
       djnz droom0
       ret


; Draw character block in accumulator.

dchar  ld hl,chatts        ; block attributes.
       ld e,a              ; displacement to attribute.
       ld d,0              ; no high byte for attributes.
       add hl,de           ; point to attribute value.
       ex af,af'           ; store char number.
       call atadd          ; get attribute address.
       ldi                 ; transfer to screen.
       ex af,af'           ; restore char number.
       rlca                ; multiply by 8.
       rlca
       rlca
       ld d,a              ; store shift in d.
       and 248             ; mask away high byte bits.
       ld e,a              ; place result in e.
       ld a,d              ; restore shift.
       and 7               ; mask off the low byte bits.
       ld d,a              ; set high byte for displacement.
       ld hl,chgfx         ; character block graphics.
       add hl,de           ; point to character graphics.
       call chadd          ; get screen character address.
       ld bc,8*256+99      ; 8 lines to write.
dchar0 ldi                 ; transfer to screen.
       dec de              ; back one char.
       inc d               ; next screen line down.
       djnz dchar0         ; repeat for all lines.
       ld hl,dispy         ; horizontal position.
       inc (hl)            ; move right one square.
       ret


; Return character cell screen address for (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

; Calculate address of attribute for character at (dispx, dispy).

atadd  ld a,(dispx)        ; x position.
       rrca                ; multiply by 32.
       rrca
       rrca
       ld e,a              ; store away in e.
       and 3               ; mask bits for high byte.
       add a,88            ; 88*256=22528, start of attributes.
       ld d,a              ; high byte done.
       ld a,e              ; get x*32 again.
       and 224             ; mask low byte.
       ld e,a              ; put in l.
       ld a,(dispy)        ; get y displacement.
       add a,e             ; add to low byte.
       ld e,a              ; hl=address of attributes.
       ret



; Character block graphics.

chgfx  defb 0,0,0,0,0,0,0,0

; buns = 02 03 03 04   02 03 03 04
;        05 05 05 05   10 11 12 13
;        06 06 06 06   06 06 06 06
;        07 08 08 09   07 08 08 09



       defb 255,255,0,124,62,31,255,255        ; girder = 1.
       defb 7,30,55,127,127,255,255,255        ; bun top left = 2.
       defb 221,247,191,251,255,255,255,255    ; bun middle = 3.
       defb 224,184,236,254,254,255,255,255    ; bun top right = 4.

       defb 62,127,255,255,255,255,254,124     ; pickles = 5.

       defb 255,170,255,85,255,170,255,85      ; meat = 6.

       defb 255,255,255,127,127,63,31,7        ; base left = 7.
       defb 255,255,255,255,255,255,255,255    ; base middle = 8.
       defb 255,255,255,254,254,252,248,224    ; base right = 9.

       defb 255,255,255,207,207,255,252,248    ; cheese = 10-13.
       defb 255,231,195,195,231,255,255,127
       defb 195,231,255,255,255,251,241,251
       defb 255,255,243,225,225,243,255,255

       defb 0,0,0,255,0,0,0,0                  ; ladder = 14.
       defb 255,255,0,0,0,0,0,0                ; plate = 15.



; Character block attributes.

chatts defb 71

gcolou defb 67                                 ; girder colour.
       defb 6,6,6,68
       defb 2,6,6,6,70,70,70,70
       defb 71,69


; Find the Pea bonus game.

swap   ld de,swptx0        ; text.
       ld bc,swpbon-swptx0 ; length.
       call 8252           ; show text.
       ld hl,swpbon        ; swap bonuses.
       ld a,4              ; number to display.
swap0  push af             ; store on stack.
       push hl             ; store bonus pointer.
       call dswapb         ; display swap bonus.
       call beep0          ; sound effect.
       ld b,7              ; fraction of a second.
       call delay          ; short pause.
       pop hl              ; restore bonus pointer.
       inc hl              ; next bonus.
       pop af              ; restore counter from stack.
       dec a               ; one less value to show.
       jr nz,swap0
       call onesec         ; pause for one second.

       ld de,swpat         ; at code.
       ld bc,swpbon-swpat  ; length.
       call 8252           ; show text.
       ld a,4              ; number to display.
swap1  push af             ; store on stack.
       ld a,'-'            ; hide character.
       rst 16              ; display it.
       ld a,'-'            ; hide character.
       rst 16              ; display it.
       call d2spc          ; display 2 spaces.
       call beep1          ; short sound.
       ld b,7              ; fraction of a second.
       call delay          ; short pause.
       pop af              ; restore counter from stack.
       dec a               ; one less value to show.
       jr nz,swap1
       call onesec         ; pause for one second.
       ld b,11             ; number of swaps.
swap2  push bc
       call swapv
       pop bc
       djnz swap2

; Select bonus.

       xor a
       ld (chosen),a       ; selected square.
select call shosel         ; show selected square.
       call debou          ; debounce.
selec0 call getkey         ; get keyboard input.
       and a               ; any input?
       jr z,selec0         ; no.
       call shosel         ; unhighlight position.
       ld a,(joyval)       ; result of keyboard input.
       cp 1                ; move right?
       jr z,selr           ; move that way.
       cp 2                ; move left?
       jr z,sell           ; move that way.
       and 12              ; up and/or down?
       jr z,select         ; no, wait for up/down.
       call shosel         ; show selected square.
       ld b,25             ; delay length.
       call delay          ; pause.

; Show final positions.

       ld de,swpat         ; at code.
       ld bc,swpbon-swpat  ; length.
       call 8252           ; show text.
       ld a,4              ; number to display.
       ld hl,swpbon        ; swap bonuses.
selec1 push af             ; store on stack.
       push hl             ; store bonus pointer.
       call dswapb         ; display swap bonus.
       pop hl              ; restore bonus pointer.
       inc hl              ; next bonus.
       pop af              ; restore counter from stack.
       dec a               ; one less value to show.
       jr nz,selec1

       ld hl,23695         ; temporary attributes system variable.
       ld (hl),69          ; cyan ink on black background.

       call shosel         ; show selected square.
       call tinkle         ; sound effect.
       ld b,25             ; delay length.
       call delay          ; short pause.
       ld a,(chosen)       ; chosen square.
       ld hl,swpbon        ; swap bonuses.
       call addac1         ; find value.

; Increase time visual.

       ld a,(hl)           ; amount to transfer.
       ld b,a              ; loop counter.
uptim0 push bc             ; store counter.
       ld hl,time          ; time remaining.
       ld a,(hl)           ; present value.
       inc a               ; increment it.
       jr z,uptim1         ; reached max.
       ld (hl),a           ; new value.
uptim1 call dtime          ; show time remaining.
       call beep1          ; sound effect.
       pop bc              ; restore counter.
       djnz uptim0
       ret


sell   ld a,(chosen)       ; chosen square.
       and a               ; at edge already?
       jr z,select         ; yes, can't move again.
       dec a               ; move to new square.
       ld (chosen),a       ; new value.
       jp select

selr   ld a,(chosen)       ; chosen square.
       cp 3                ; at edge already?
       jp z,select         ; yes, can't move again.
       inc a               ; move to new square.
       ld (chosen),a       ; new value.
       jp select

shosel ld a,(chosen)       ; find selected.
       rlca                ; multiply by 4.
       rlca
       add a,100           ; attribute low.
       ld l,a              ; low byte.
       ld h,89             ; high byte of attribute.
       ld a,(hl)           ; fetch attribute.
       xor 41              ; toggle attributes.
       ld (hl),a           ; new value.
       inc l               ; next cell.
       ld (hl),a           ; colour that too.
       ret

; Display swap bonuses.

dswapb ld c,(hl)           ; fetch bonus value from table.
       ld b,0              ; no high byte.
       call 6683           ; show number.
d2spc  ld a,32             ; space character.
       rst 16              ; move along.
       ld a,32             ; space character.
       rst 16              ; move along.
       ret


; Choose right value to swap.

swapv  call random         ; random number.
       and 3               ; in range 0-3.
       jr z,swapv          ; only want 1-3.
       push af             ; store value.
       ld hl,swpbon        ; swap bonuses.
       call addac1         ; find table address.
       ld a,(hl)           ; present value.
       dec hl              ; point to left value.
       ld b,(hl)           ; get its value.
       ld (hl),a           ; new setting for left value.
       inc hl              ; right value.
       ld (hl),b           ; original left value.
       pop af              ; restore right value.
       rlca                ; multiply by 4.
       rlca
       ld (coly),a         ; set column position.

       ld b,6
       ld de,swaptx        ; text pointer.
swapv0 push bc             ; store counter.
       ld a,22             ; at code.
       rst 16              ; write at code.
       ld a,11             ; line number.
       rst 16              ; send line code.
       ld a,(coly)         ; column position.
       rst 16              ; set column.
       ld bc,6             ; length of string.
       call 8252           ; display animation frame.
       halt                ; delay.
       halt
       pop bc              ; restore counter.
       djnz swapv0         ; repeat.
       ret



swptx0 defb 22,10,3,16,6,17,1
       defb 23,20,99
       defb 22,11,3,23,20,99
       defb 22,12,3,23,20,99
swpat  defb 22,11,4
swpbon defb 45,30,20,15

swaptx defb '--  ',145,145
       defb ' --',145,145,' '
       defb '  ',144,144,'  '
       defb ' ',145,145,'-- '
       defb 145,145,'  --'
       defb '--  --'





levdat equ $

       defb 15,4,99,8
       defw screen+3*24+1,screen+3*24+12
       defw screen+8*24+9,screen+8*24+20
       defw screen+13*24,screen+13*24+12,screen+13*24+22
       defw screen+18*24+10

       defb 2,10,17,9
       defw screen+3*24,screen+3*24+14,screen+3*24+22
       defw screen+8*24+7,screen+8*24+21
       defw screen+13*24,screen+13*24+8,screen+13*24+14
       defw screen+18*24+22

       defb 17,3,11,8
       defw screen+3*24,screen+3*24+22
       defw screen+8*24,screen+8*24+8,screen+8*24+15
       defw screen+13*24+8,screen+13*24+22
       defw screen+18*24+15

       defb 10,17,3,8
       defw screen+3*24+8,screen+3*24+15
       defw screen+8*24,screen+8*24+14
       defw screen+13*24,screen+13*24+7,screen+13*24+22
       defw screen+18*24+8

       defb 3,11,19,7
       defw screen+3*24+8,screen+3*24+16
       defw screen+8*24,screen+8*24+16
       defw screen+13*24+8,screen+13*24+16
       defw screen+18*24

       defb 19,3,11,6
       defw screen+3*24,screen+3*24+8
       defw screen+8*24+16
       defw screen+13*24,screen+13*24+8
       defw screen+18*24+16

xydat  defb 48,160,88,16
       defb 8,56,128,176
       defb 8,64,128,4
       defb 8,172,128,116
       defb 8,128,88,64
       defb 8,4,128,128

; Burger data.

buntop defb 2,3,3,4
pickle defb 5,5,5,5
cheese defb 10,11,12,13
burger defb 6,6,6,6
bunbot defb 7,8,8,9
plate  defb 15,15,15,15




; Variables used by the game.

tmp0   equ 32768
tmp1   equ tmp0 + 2
tmp2   equ tmp1 + 1        ; temporary, used in burger drop routine.
numobj equ tmp2 + 1        ; number of objects.
dispx  equ numobj + 1      ; display x coord.
dispy  equ dispx + 1       ; display y coord.
playx  equ dispy + 1       ; player x coord.
playy  equ playx + 1       ; player y coord.
playd  equ playy + 1       ; player direction.
saus1  equ playd + 1       ; first enemy sprite.
saus2  equ saus1 + 3       ; second enemy sprite.
numfel equ saus2 + 3       ; number of items fallen.
score  equ numfel + 1      ; player's score.
joyval equ score + 2       ; controls.
mtbuff equ joyval + 1      ; maths buffer.
levnum equ mtbuff + 2      ; current level.
oplayx equ levnum + 1      ; old player x coord.
oplayy equ oplayx + 1      ; old player y coord.
seed   equ oplayy + 1      ; random number seed.
numlif equ seed + 2        ; number of lives.
levptr equ numlif + 1      ; level data pointer.
itcnt  equ levptr + 2      ; item counter.
itemno equ itcnt + 1       ; item number.
itemxy equ itemno + 1      ; item coords.
xyptr  equ itemxy + 2      ; item coords pointer.
matrix equ xyptr + 2       ; grid.
chosen equ matrix + 10     ; chosen grid position.
time   equ chosen + 1      ; time remaining.
dnum   equ time + 1        ; display number.
coly   equ dnum + 2        ; column position.


screen equ 49152
blkspr equ screen + 1024   ; blank sprite.

tmpscr equ blkspr + 256    ; temporary storage area for screen display.



