;JET SET MINER (formally PLAT 3064)
;
;Written by Tom Walker
;Original in 2003 (for Minigame 2003 4K competition) for C64
;BBC/Electron conversion in 2009
;
;To be assembled with P65 and probably Swift
;
;I was 15 when I wrote this, so don't complain about the horrible coding
;This was written to fit in 4K, however some of the coding seems a bit 'big'
;Could probably be improved. If I'd made the more obvious size optimisations,
;it could have had twice as many levels as it does and still been 4K.
;
;The entire game has been made OS legal. This means it runs on any BBC or Electron
;with 32k of RAM. Older versions weren't OS legal, this meant they could run on
;a Model A.
;
;Suggestions for improvements :
;
; - More levels (obv). You could fit ~50 levels into an extra 4k.
; - Move enemies (would need an extra entry in the enemy tables, unless it's one
;   type per level)
; - More types of block per level. This would reduce the efficiency of the compression. 
; - Colour. Mode 5 should be easy, though some changes would be needed to collision
;   detection. Mode 1 or 2 would need more changes to the drawing routines
; - Sound. Should be fairly easy.

;    Copyright 2003, 2009 Tom Walker

;    tommowalker@yahoo.co.uk
;    http://www.tommowalker.co.uk

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

.org $2000

relocate:                ;Relocates game data down to $E00
        sei ;Disable interrupts - don't want to be interrupted doing this
        
        lda #140   ;Select tape filing system - removes any NMI hooks
        jsr $FFF4
        
        lda #$40
        sta $D00   ;Put an RTI at $D00 to disable any NMIs
        
        lda #<gamedata
        sta $70
        lda #>gamedata
        sta $71
        lda #0
        sta $72
        lda #$E
        sta $73
        
        ldx #$10        ;Copies 4K - if the game is modified this will probably
        ldy #0          ;need to be increased
*       lda ($70),y
        sta ($72),y
        iny
        bne -
        inc $71
        inc $73 
        dex
        bne -
        
        jmp $E00

gamedata:
.org $E00

.alias OSBYTE   $FFF4
.alias EVNTV    $0220 

.alias PLX      $00B0 ;Player position
.alias PLY      $00B1
.alias PLF      $00B2 ;Player falling?
.alias PLD      $00B3 ;Direction player is facing
.alias PLJ      $00B4 ;Player jumping?
.alias KEYSLEFT $00B5 ;Number of keys left in level
.alias COLLIDE  $00B6 ;Collision detected?
.alias CHKCOL   $00B7 ;Check collisions when drawing sprites
.alias LEVEL    $00B8 ;Level number (0-3)
.alias DEAD     $00B9 ;Player dead?
.alias LEVCOMP  $00BA ;Level completed?
.alias LIVES    $00BB ;Player lives left
.alias LCOMP    $00BC ;Current level (not limited to 0-3)
.alias VSYNCCNT $00BF ;Vsync count
.alias LEVELOVR $0084 ;Level over?
.alias OLDEVNTV $0085
.alias TIME     $380  ;Time left
.alias TIMEL    $388  ;Time limit for current round of levels
.alias lev1     $400  ;Level data is decompressed to here
.alias ENMY     $900 ;Byte 0 - X pos  Byte 1 - Y pos  Byte 2 - X min  Byte 3 - X max  Byte 4 - direction

main:   lda EVNTV       ;back up old event handler
        sta OLDEVNTV
        lda EVNTV+1
        sta OLDEVNTV+1
        
        lda #<eventh    ;and install our own
        sta EVNTV
        lda #>eventh
        sta EVNTV+1

        lda #14    ;enable vsync event
        ldx #4
        jsr OSBYTE
        
        cli        ;and enable interrupts
        
        lda #0
        ldx #15
*       sta $B0,x
        dex
        bpl -
        
        sta LEVELOVR        
                
	jsr clear

	ldx #0       ;Set up title text
dotitl: lda title,x  ;Title text is just bitmap saying 'PRESS FIRE'
	sta $6C78,x
	inx
	cpx #80
	bne dotitl

	lda #0       ;Draw player sprites on title screen
	ldx #0
	ldy #0
	jsr drawspr
	lda #0
	ldx #18
	ldy #0
	jsr drawspr
	lda #0
	ldx #36
	ldy #0
	jsr drawspr
	lda #0
	ldx #54
	ldy #0
	jsr drawspr

	lda #1
	ldx #240
	ldy #0
	jsr drawspr
	lda #1
	ldx #222
	ldy #0
	jsr drawspr
	lda #1
	ldx #204
	ldy #0
	jsr drawspr
	lda #1
	ldx #186
	ldy #0
	jsr drawspr

wait:   lda #$81
        ldx #$B6     ;Check RETURN key
        ldy #255
        jsr OSBYTE
        cpx #255
	bne wait

init:   lda #0      ;Start on level 0
	sta LEVEL
	sta LCOMP
	lda #3      ;3 lives
	sta LIVES
	lda #9      ;Time starts at 999
	sta TIMEL
dothelv: lda #0     ;Not dead!
	sta DEAD
	lda #$99    ;Set time to (TIMEL*100)+99
	sta TIME
	lda TIMEL
	sta TIME+1
	sta LEVCOMP
	jsr start   ;Run level
	cmp #1      ;Did we die?
	beq dodie   ;Then jump to death code
nxtlev:	jmp dothelv ;Otherwise run next level

dodie:  dec LIVES   ;Decrease our lives
	bmi endgame ;End the game if out
	jmp nxtlev  ;Otherwise start level again

endgame: jmp main   ;Restart game if out of lives

start:  jsr clear   ;Clear screen

        lda #0
        sta LEVELOVR
        
	lda LEVEL      ;Get level number
	asl
	asl
	tax
	stx $30a
	lda levtab+1,x ;Put address into X,Y
	tay
	lda levtab,x
	tax
	jsr decomp     ;And decompress
	ldx $30a
	lda levtab+3,x
	tay
	lda levtab+2,x
	tax
	jsr dolh       ;Copy level header to current level
        jsr drawlev    ;Draw level

	jsr mkdispb    ;Make status text ('display bottom')

        ldx #0
enmyl1: lda levhead+10,x ;Copy enemy data from level header into enemy structure
        sta ENMY,x
        inx
        cpx #20
        bne enmyl1

        lda #4        ;Reset number of keys left
        sta KEYSLEFT
	lda #0
	sta COLLIDE

        ldx #8        ;Player always starts in same position
        stx PLX
        ldy #136
        sty PLY
        lda #0        ;Neither dropping nor jumping
        sta PLD
        sta PLJ
        jsr drawspr   ;Place initial player sprite on screen (at X,Y)
        
        ldx ENMY      ;Get first enemy coordinates
        ldy ENMY+1
        lda ENMY+4    ;Get enemy sprite number
	cmp #$ff      ;Does enemy actually exist?
	beq en21      ;Jump if not
        ora #2        
        jsr drawspr   ;Otherwise draw
en21:   ldx ENMY+5    ;Repeat for other enemies (could do with a loop)
        ldy ENMY+6
        lda ENMY+9
	cmp #$ff
	beq en31
        ora #2
        jsr drawspr
en31:   ldx ENMY+10
        ldy ENMY+11
        lda ENMY+14
	cmp #$ff
	beq en41
        ora #2
        jsr drawspr
en41:   ldx ENMY+15
        ldy ENMY+16
        lda ENMY+19
	cmp #$ff
	beq en51
        ora #2
        jsr drawspr
en51:	lda #0      ;Disable collision detection
	sta CHKCOL

loop:   jsr vsync    ;Wait 5 vsyncs (locks to 10 fps - fairly arbitary)
        lda PLD
        ldx PLX
        ldy PLY
        jsr drawspr  ;Erase player
        ldx ENMY
        ldy ENMY+1
        lda ENMY+4
	cmp #$ff
	beq en22
        ora #2
        jsr drawspr  ;Erase enemies
en22:   ldx ENMY+5
        ldy ENMY+6
        lda ENMY+9
	cmp #$ff
	beq en32
        ora #2
        jsr drawspr
en32:   ldx ENMY+10
        ldy ENMY+11
        lda ENMY+14
	cmp #$ff
	beq en42
        ora #2
        jsr drawspr
en42:   ldx ENMY+15
        ldy ENMY+16
        lda ENMY+19
	cmp #$ff
	beq en52
        ora #2
        jsr drawspr
en52:   jsr guymove  ;Check input and move player
	jsr chkspk   ;See if we hit any spikes
        jsr doenemy  ;Move enemies
        lda PLD
        ldx PLX
        ldy PLY
        jsr drawspr  ;Draw player
	lda #1       ;Re-enable collision detection
	sta CHKCOL
        ldx ENMY     ;Draw enemies
        ldy ENMY+1
        lda ENMY+4
	cmp #$ff
	beq en2
        ora #2
        jsr drawspr
en2:    ldx ENMY+5
        ldy ENMY+6
        lda ENMY+9
	cmp #$ff
	beq en3
        ora #2
        jsr drawspr
en3:    ldx ENMY+10
        ldy ENMY+11
        lda ENMY+14
	cmp #$ff
	beq en4
        ora #2
        jsr drawspr
en4:    ldx ENMY+15
        ldy ENMY+16
        lda ENMY+19
	cmp #$ff
	beq en5
        ora #2
        jsr drawspr
en5:	lda #0       ;Disable collision detection
	sta CHKCOL
	lda COLLIDE  ;And test results of previous checks
	bne die      ;Jump if a collision - ie monster collided with player
        jsr chkover  ;Check if level completed
	lda DEAD     ;Redundant? die: should sort this
	bne endital
	lda LEVCOMP  ;If LEVCOMP=FF then we've completed the level, exit loop
	eor #$ff     ;This ensures A=0 when we exit
	beq endital
	jsr updb     ;Update status ('display bottom')
	jsr uptime   ;Update time
        jmp loop     ;Jump back to start

endital: rts

die:    lda #1       ;Set DEAD flag and return (A=1)
	sta DEAD
	rts

chkover: lda LEVELOVR ;If level is over
         bne nextlev  ;Then enter next one
         rts

chkexit: rts ;Redundant - needed in C64 version

nextlev: lda #0      ;Reset completion flags
        sta LEVELOVR
        lda #$ff
	sta LEVCOMP
	sed
	lda LCOMP    ;Increment level number (used in status display)
	clc
	adc #1
	sta LCOMP
	cld
	inc LEVEL    ;Increment actual level number (AND 3 cos there are 4 levels)
	lda LEVEL
	and #3
	sta LEVEL
	beq chgtime  ;If back to level 0 then we need to change the time limit
	rts

chgtime: dec TIMEL   ;Decrease time limit
	rts          ;No checks as when time gets to 099 no-one will be able to complete a level

;makexit - puts an exit in the level
makexit: lda levhead+8  ;Get exit position from level header
        clc
        adc #4
        sta 2
        lda levhead+9
        sta 4
        lda #0
        sta 3           ;Do some address calculation
        asl 2
        asl 2
        asl 2
        rol 3
        lda 4
        asl 
        asl 
        asl
        tax             ;Get Y address
        lda ytab1,x     ;Use as lookup in ytab
        clc
        adc 2
        sta 6
        lda ytab2,x
        adc 3
        clc
        adc #$5D
        sta 7           ;And finish screen address calculation
        
;*       jmp -
              
        ldy #15         ;Copy top half of door sprite onto screen
*       lda doorspr,y
        sta (6),y
        dey
        bpl -
        
        lda 6           ;Move down one character line
        clc
        adc #$40
        sta 6
        lda 7
        adc #1
        sta 7 

        ldy #15         ;And copy bottom half
*       lda doorspr+16,y
        sta (6),y
        dey
        bpl -
        
        lda levhead+8  ;Use door position to lookup level data
        sta 2
        lda levhead+9
        sta 3
        lda #0
        sta 4
        asl 3 ;x2 - max 40
        asl 3 ;x4 - max 80
        asl 3 ;x8 - max 160
        asl 3 ;x16 - max 320
        rol 4
        asl 3 ;x32 - max 640
        rol 4
        lda 3
        clc
        adc #<lev1
        sta 3
        lda 4
        adc #>lev1
        sta 4
        ldy 2
        lda #$80      ;Store $80 at locations door occupies
        sta (3),y     ;Once all keys are gone, scanning rountine will see this as exit
        iny
        sta (3),y
        lda 3
        clc
        adc #32
        sta 3
        dey
        lda #$80        
        sta (3),y
        iny
        sta (3),y                

        rts
;        jmp keyret

chkspk: lda PLX      ;Get player location
	lsr          ;And shift down to use as level index
	lsr
	lsr
	tax
	lda PLY
	lsr
	lsr
	lsr
	tay
	stx $A02    ;Store
	sty $A03
	jsr getblk1 ;Get block
	cmp #3      ;Is is 3? (spike)
	beq hitspk  ;Jump if we hit
	ldx $A02    ;Repeat for all surrounding blocks
	ldy $A03
	inx
	jsr getblk1
	cmp #3
	beq hitspk
	ldx $A02
	ldy $A03
	iny
	jsr getblk1
	cmp #3
	beq hitspk
	ldx $A02
	ldy $A03
	inx
	iny
	jsr getblk1
	cmp #3
	beq hitspk
	ldx $A02
	ldy $A03
	iny
	iny
	sty $A03
	jsr getblk1
	cmp #3
	beq hitspk
	ldx $A02
	ldy $A03
	inx
	jsr getblk1
	cmp #3
	beq hitspk
	rts

hitspk: jmp die     ;If you hit a spike you die!

doenemy: lda #<ENMY ;Get enemy data address into $fe (for indirect Y mode)
        sta $fe
        lda #>ENMY
        sta $ff
        ldy #0
enmyl2: ldy #4      ;Get index 4 (direction)
        lda ($fe),y
	cmp #$ff
	beq enmynxt ;If $FF then enemy doesn't exist
	lda ($fe),y
        bne enemyl  ;If it's not 0 then it's left

enemyr: ldy #0      ;Else it's right
        lda ($fe),y ;Get index 0 (X position)
        clc
        adc #2      ;Move him right
        sta ($fe),y
        ldy #3      ;Get index 3 (rightmost position)
        cmp ($fe),y 
        bne enmynxt ;If enemy isn't there then jump
        ldy #4      ;Otherwise reverse direction
        lda #1
        sta ($fe),y
        jmp enmynxt

enemyl: ldy #0      ;Get index 0 (X position)
        lda ($fe),y
        sec
        sbc #2      ;Move him left
        sta ($fe),y
        ldy #2      ;Get index 2 (leftmost position)
        cmp ($fe),y
        bne enmynxt ;If enemy isn't there then jump
        ldy #4      ;Overwise reverse direction
        lda #0
        sta ($fe),y

enmynxt: lda $fe    ;Move $FE pointer on 5 bytes (next enemy)
	clc
	adc #5
	sta $fe
	cmp #20     ;Are we at 20 (4 enemies * 5 bytes each)?
	bne enmyl2  ;No, then jump to top of loop
	rts         ;Otherwise return

drawlev: lda #<lev1 ;Put level address into 2/3
        sta 2
        lda #>lev1
        sta 3

        lda #20     ;Number of rows to draw (20)
        sta 8
        lda #$5D    ;Starting screen address (4 columns from start of screen)
        sta 5
        lda #32
        sta 4

drawvl:  ldy #0 ;Start at horizontal position 0
drawhl:   lda (2),y  ;Get tile number     
                     ;(2) = map (6) = tile addr  (4) = screen addr
          asl        ;Multiply by 8, to use as an index into tiles
          asl 
          asl 
          clc
          adc #<tiles ;Add tile address
          sta 6
          lda #0
          adc #>tiles
          sta 7

          tya
          pha
          ldy #7

tileloop:  lda (6),y     ;Copy tile (8 bytes, 8x8 pixels in mode 4)
           sta (4),y
           dey
           bpl tileloop

          pla
          tay

          lda 4     ;Move screen address on 8
          clc
          adc #8
          sta 4
          lda 5
          adc #0
          sta 5

          iny        ;We at end of row?
          cpy #32
          bne drawhl ;Loop if not

         lda 4     ;Move screen down a line and back 32 characters
         clc
         adc #64
         sta 4
         lda 5
         adc #0
         sta 5

         lda 2     ;Move level data address down a row
         clc
         adc #32
         sta 2
         lda 3
         adc #0
         sta 3

         dec 8      ;Decrease rows left count
         bne drawvl ;and jump back

;Draw key sprites onto screen
        ldy #0 ;Start with key 0
keysprl: lda levhead,y ;Get location out of level header
        clc
        adc #4
        sta 2
        lda levhead+1,y
        sta 4
        lda #0
        sta 3
        asl 2          ;And do address calculations
        asl 2
        asl 2
        rol 3
        lda 4
        asl 
        asl 
        asl
        tax
        lda ytab1,x
        clc
        adc 2
        sta 6
        lda ytab2,x
        adc 3
        clc
        adc #$5D
        sta 7

        tya
        pha
                
        ldy #7       ;Copy key graphic (was a sprite on C64) onto screen
*       lda keyspr,y
        sta (6),y
        dey
        bpl - 
        
        pla
        pha
        tay
        
        lda levhead,y   ;Get key location again
        sta 2           ;and index into level data
        lda levhead+1,y
        sta 3
        lda #0
        sta 4
        asl 3 ;x2 - max 40
        asl 3 ;x4 - max 80
        asl 3 ;x8 - max 160
        asl 3 ;x16 - max 320
        rol 4
        asl 3 ;x32 - max 640
        rol 4
        lda 3
        clc
        adc #<lev1
        sta 3
        lda 4
        adc #>lev1
        sta 4
        ldy 2
        lda #$80     ;$80 means key when there are still keys left
        sta (3),y
        
        pla
        tay
                 
        iny          ;Increment key pointer
        iny
        cpy #8       ;At the end? (4 keys * 2 bytes each)
        bne keysprl

        rts


vsync:  lda VSYNCCNT
        cmp #5        ;Wait til vsync count >=5
        bcc vsync
        lda #0
        sta VSYNCCNT  ;Clear VSYNCCNT
        rts

falldie: lda #0
        sta PLF 
        jmp die

guyfall: lda PLX     ;Update falling player
        lsr          ;Get player position and shift down to block addresses
        lsr
        lsr
        tax
        lda PLY
        clc
        adc #16+7
        lsr
        lsr
        lsr
        tay
        jsr getblk   ;Get blocks immediately below player
        bne stopf    ;If it's not air then stop falling
        inc PLY      ;Otherwise move player down
        inc PLY
        inc PLY
        inc PLY
	inc PLF      ;Increase fall distance
        rts

stfall:  lda #1      ;Start fall - set PLF flag to one 
        sta PLF
        jmp guyfall  ;then process fall

stopf:  lda PLF     ;Stop falling - see how far we've fallen
        cmp #12     ;If we've fallen far enough (6 blocks)
        bcs falldie ;then kill player
        lda #0      ;clear PLF flag
        sta PLF
        lda PLY      ;Then adjust player Y so we're directly on a block
        clc
        adc #7
        and #$F8
        sta PLY
        rts

startj:  lda #7      ;Start jump - set maximum upwards momentum in PLJ
        sta PLJ
guyjump: jmp guyj    ;Then process jump

guymove: lda PLJ     ;Are we jumping?
        bne guyjump  ;Then process jump
        lda PLF      ;Are we falling?
        bne guyfall  ;Then process fall
        lda PLX      ;Get player position
        lsr          ;Shift down to block numbers
        lsr
        lsr
        tax
	stx $340     ;And store
        lda PLY
        clc
        adc #16      ;+16 - the block immediately under the player's feet
        lsr
        lsr
        lsr
        tay
	sty $341
        jsr getblk   ;Check blocks immediately under player
        beq stfall   ;If it's just air then start falling

        lda #0
        sta $f
        
        ;Get Z and X keys
        lda #$81
        ldx #$9E ;'Z'
        ldy #255
	jsr OSBYTE ;If we get them now then player can't change direction during jump
	cpx #255
	bne +
	lda #1
	sta $f    ;Store for later

*       lda #$81
        ldx #$BD ;'X'
        ldy #255
	jsr OSBYTE
	cpx #255
	bne +
	lda $f
	ora #2
	sta $f
	
*       lda #$81
        ldx #$B6     ;Check RETURN key
        ldy #255
        jsr OSBYTE
        cpx #255
        beq startj  ;Start jumping if RETURN down
        
chkdir: lda $f
	and #1 ;'Z'
	bne guyleft ;Move left if Z held down
        
        lda $f
        and #2 ;'X'
        bne guyright ;Move right if X held down

        rts

guyleft: dec PLX   ;Move player left
        dec PLX
        lda #1     ;Set direction to left (so player faces that direction)
        sta PLD
        lda PLX    ;Shift coordinates down again
        lsr
        lsr
        lsr
        tax
        lda PLY
        lsr
        lsr
        lsr
        tay
        stx $70     ;We now check blocks immediately to the left of player 
        sty $71     ;to see if player could actually move that direction
        jsr getblk1 ;Check just one block
        cmp #2      ;If it's a wall
        beq noleft  ;Then jump to move player back again
        ldx $70     ;Also check block below the one we just checked
        ldy $71
        iny
        jsr getblk1
        cmp #2
        beq noleft
        rts

noleft:  inc PLX
        inc PLX
        rts

guyright: inc PLX   ;Much the same as above, just right instead of left!
        inc PLX
        lda #0
        sta PLD
        lda PLX
        clc         ;Player coordinates are the left half of the player, so
        adc #8      ;we need add a block to get the block at his right      
        lsr
        lsr
        lsr
        tax
        lda PLY
        lsr
        lsr
        lsr
        tay
        stx $70
        sty $71
        jsr getblk1
        cmp #2
        beq noright
        ldx $70
        ldy $71
        iny
        jsr getblk1
        cmp #2
        beq noright
        rts

noright: dec PLX
        dec PLX
        rts

;stopj4:  jmp stopj5  ;Branch instructions on 6502 are annoyingly limited
;Handle jumping
guyj:    lda PLY
        sec          ;Subtract PLJ from PLY to move player up/down
        sbc PLJ      ;(PLJ can be negative, which is how the player moves down again)
        sta PLY
        ldx PLJ      ;Update PLJ
        dex
        bne ndecj    ;Skip over 0, as PLJ=0 means not jumping!
        dex          ;move straight to -1 instead
ndecj:   stx PLJ
        cpx #$F7     ;Have we reached -8?
        beq stopj    ;Then stop jumping (player will probably start falling)
;        lda PLY      
;        cmp #200     ;Make sure player doesn't move off top or bottom of screen
;        bcs stopj4   ;Stop jump in that case
        jsr chkdir   ;Keep player moving left/right
        lda PLJ      ;Need to check if we hit ceiling/floor
        bpl chkc     ;Check jump sign to see which
;Check floor
        lda PLX      ;For floor we check immediately underneath player
        lsr
        lsr
        lsr
        tax
        lda PLY
        clc
        adc #16+7
        lsr
        lsr
        lsr
        tay
        jsr getblk
        bne stopj2
        rts
;Check ceiling
chkc:   lda PLX     ;For ceiling we check immediately above
        lsr
        lsr
        lsr
        tax

        lda PLY
        lsr
        lsr
        lsr
        tay
        stx $70
        sty $71
        jsr getblk1
        cmp #2
        beq stopj3
        ldx $70
        inx
        ldy $71
        jsr getblk1
        cmp #2
        beq stopj3
        rts

stopj2: lda PLY      ;Stop jumping if we've hit floor
        and #$F8     ;Update player Y so he's immediately above the floor
        sta PLY      ;(he could be partway through)
        lda PLX
        lsr
        lsr
        lsr
        tax
        lda PLY
        clc
        adc #16+7
        lsr
        lsr
        lsr
        tay
        jsr getblk  ;Not sure why we need to check this, I'm loathe to change it
        bne stopj
        lda PLY
        clc
        adc #4
        sta PLY
stopj:  lda #0     ;Clear PLJ flag
        sta PLJ
        rts

stopj5: lda #0     ;Stop jumping if hit the top of the screen
        sta PLY     ;Limit player to 0
        jmp stopj

stopj3: inc PLJ    ;Stop jumping if we hit ceiling
        lda PLY
        clc
        adc PLJ
        and #$F8    ;Make sure player isn't partway through the ceiling
        sta PLY
        jmp stopj

blkzero: lda #0 ;Used if player jumps off the top of the screen
        cpx #0
        beq +
        cpx #31
        beq +
        rts     ;just returns empty air

*       lda #2 ;But return a brick wall if about to jump off the edge
        rts
                
;Return block number at block X,Y
getblk: cpy #20
        bcs blkzero
        stx 2 ;Actually this returns the block at X,Y ORed with X+1,Y 
        sty 3  ;This is needed for ceiling/floor calculations
        lda #0 ;as player is 2 blocks wide
        sta 4
        asl 3 ;x2 - max 40
        asl 3 ;x4 - max 80
        asl 3 ;x8 - max 160
        asl 3 ;x16 - max 320
        rol 4
        asl 3 ;x32 - max 640
        rol 4
        lda 3
        clc
        adc #<lev1
        sta 3
        lda 4
        adc #>lev1
        sta 4
        ldy 2
        lda (3),y
        iny
        ora (3),y
        and #$7f
        rts

;Return block number at block X,Y
getblk1: cpy #20
        bcs blkzero 
        stx 2   ;This only checks 1 block
        sty 3    ;But also checks for keys/exit at the same time
        stx $70
        sty $72
        lda #0
        sta 4
        asl 3 ;x2 - max 40
        asl 3 ;x4 - max 80
        asl 3 ;x8 - max 160
        asl 3 ;x16 - max 320
        rol 4
        asl 3 ;x32 - max 640
        rol 4
        lda 3
        clc
        adc #<lev1
        sta 3
        lda 4
        adc #>lev1
        sta 4
        ldy 2
        lda (3),y
        bmi gotkey ;If block number is negative then it's either key or door
       
        rts

setlo:  lda #1       ;Set level over flag
        sta LEVELOVR
        lda #0       ;Then return 0, for empty air
        rts
        
gotkey: lda KEYSLEFT ;Do we have any keys left?
        beq setlo    ;If not then it's a door - set level over
        lda #0       ;Else it's a key - remove it from the map
        sta (3),y
        
        sta $71      ;Remove it from the screen as well
        lda $70      ;This is just a repeat of the plotting code
        clc
        adc #4
        asl        
        asl
        asl        
        rol $71
        sta $70        
        lda $72
        asl 
        asl 
        asl
        tax
        lda ytab1,x
        clc
        adc $70
        sta 6
        lda ytab2,x
        adc $71
        clc
        adc #$5D
        sta 7
         
        ldy #7
*       lda keyspr,y
        eor (6),y      ;EOR it off the screen
        sta (6),y
        dey
        bpl - 
        
        dec KEYSLEFT  ;Decrease the key count
        beq mkexit2   ;If that's the last key then put the door in place        
        
        lda #0        ;Return empty air
        rts
        
mkexit2: jsr makexit  ;Put exit on screen
        lda #0        ;Return empty air
        rts
        
;Level header
;This is replaced with whatever level is being played
levhead: .byte 15,0,1,16,11,2,30,16 ;These are the 4 keys, alternating X,Y locations
        .byte 1,17                  ;Door location

        .byte 112,136,112,238,0     ;Enemies - initial X, initial Y, leftmost X, 
	.byte 160,0,160,238,0       ;rightmost X, starting direction (0=left, 1=right)
	.byte 160,16,160,238,0
	.byte 160,32,160,238,0


tiles:   .BYTE %00000000     ;Tiles - all 8x8 1 bit per pixel, so easy to change!
        .BYTE %00000000      ;This one is air
        .BYTE %00000000
        .BYTE %00000000
        .BYTE %00000000
        .BYTE %00000000
        .BYTE %00000000
        .BYTE %00000000

        .BYTE %11111111      ;Floor that can be walked and jumped through
        .BYTE %10101011
        .BYTE %11010101
        .BYTE %10101011
        .BYTE %11010101
        .BYTE %10101011
        .BYTE %11010101
        .BYTE %11111111

        .BYTE %11101110      ;Brick wall
        .BYTE %11101110
        .BYTE %11101110
        .BYTE %00000000
        .BYTE %01110111
        .BYTE %01110111
        .BYTE %01110111
        .BYTE %00000000

        .BYTE %00010000      ;Spike
        .BYTE %00010000
        .BYTE %00111000
        .BYTE %00111000
        .BYTE %01111100
        .BYTE %01111100
        .BYTE %11111110
        .BYTE %11111110

;A=sprite num, X=X, Y=Y
drawspr: sta 2
        stx 3
        sty 4

        txa       ;Calculate X offset to screen address
        and #$F8
        clc
        adc #32
        sta 6
        lda #$5D
        adc #0
        sta 7

        tya
        tax
        lda #15
        sta 5

        lda 2         ;Get sprite start
        sta $20
        lda #0
        sta $21
        asl $20       ;x2 - max 8
        asl $20       ;x4 - max 16
        asl $20       ;x8 - max 32
        asl $20       ;x16 - max 64
        asl $20       ;x32 - max 128
        asl $20       ;x64 - max 256
        rol $21
        asl $20       ;x128 - max 512
        rol $21

        lda $20        ;Get full sprite address
        clc
        adc #<sprites
        sta $A         ;And put in $A/$B
        lda $21
        adc #>sprites
        sta $B
        lda 3         ;Sprites are preshifted, 4 based on X position
        and #6        ;so get index to correct one
        asl
        asl
        asl
        asl
        clc
        adc $A
        sta $A
        lda $B
        adc #0
        sta $B

	lda CHKCOL   ;Do we need to check collisions?
	bne spryl2   ;Yes, then jump to collision detecting loop

spryl:  cpx #200     ;Don't draw row if it's off the screen 
        bcs skipdraw1
        lda ytab1,x  ;Otherwise normal loop
        clc          ;Get address through Y tables
        adc 6
        sta 8
        lda ytab2,x
        adc 7
        sta 9
        ldy #0
        lda ($a),y   ;Get sprite data
        eor ($8),y   ;EOR with what's on screen
        sta ($8),y   ;And story
        iny
        lda ($a),y   ;Get second byte of sprite data for this row
        ldy #8
        eor ($8),y   ;and EOR and store
        sta ($8),y
skipdraw1: lda $a       ;Update sprite address
        clc
        adc #2
        sta $a
        lda $b
        adc #0
        sta $b
;        inc $a
;        inc $a
;        inx
        inx
        dec 5       ;Decrease row count
        bpl spryl   ;And loop

        rts

spryl2: cpx #200     ;Don't draw row if it's off the screen 
        bcs skipdraw2
        lda ytab1,x ;Get address through Y table
        clc
        adc 6
        sta 8
        lda ytab2,x
        adc 7
        sta 9
        ldy #0
	lda ($a),y  ;Get sprite data
	and ($8),y  ;AND with screen data
	bne coll    ;Jump if not 0 (if not 0 then collision!)
donecol: lda ($a),y ;Plot as normal
        eor ($8),y
        sta ($8),y

        iny
        lda ($a),y  ;Collision again
        ldy #8
	and ($8),y
	bne coll2
doncol: ldy #1
	lda ($a),y  ;And plot again
	ldy #8
        eor ($8),y
        sta ($8),y
skipdraw2: lda $a      ;Update address
        clc
        adc #2
        sta $a
        lda $b
        adc #0
        sta $b
        inx
        dec 5
        bpl spryl2

        rts

coll:   lda #1      ;Set collision flag
	sta COLLIDE
	jmp donecol

coll2:  lda #1      ;Two of these loops, so it can continue at the right point
	sta COLLIDE
	jmp doncol

;Screen Y lookup table - low bytes first
ytab1:  .BYTE $00,$01,$02,$03,$04,$05,$06,$07,$40,$41,$42,$43,$44,$45,$46,$47
        .BYTE $80,$81,$82,$83,$84,$85,$86,$87,$c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7
        .BYTE $00,$01,$02,$03,$04,$05,$06,$07,$40,$41,$42,$43,$44,$45,$46,$47
        .BYTE $80,$81,$82,$83,$84,$85,$86,$87,$c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7
        .BYTE $00,$01,$02,$03,$04,$05,$06,$07,$40,$41,$42,$43,$44,$45,$46,$47
        .BYTE $80,$81,$82,$83,$84,$85,$86,$87,$c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7
        .BYTE $00,$01,$02,$03,$04,$05,$06,$07,$40,$41,$42,$43,$44,$45,$46,$47
        .BYTE $80,$81,$82,$83,$84,$85,$86,$87,$c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7
        .BYTE $00,$01,$02,$03,$04,$05,$06,$07,$40,$41,$42,$43,$44,$45,$46,$47
        .BYTE $80,$81,$82,$83,$84,$85,$86,$87,$c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7

;Then high bytes
ytab2:  .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$01
        .BYTE $02,$02,$02,$02,$02,$02,$02,$02,$03,$03,$03,$03,$03,$03,$03,$03
        .BYTE $05,$05,$05,$05,$05,$05,$05,$05,$06,$06,$06,$06,$06,$06,$06,$06
        .BYTE $07,$07,$07,$07,$07,$07,$07,$07,$08,$08,$08,$08,$08,$08,$08,$08
        .BYTE $0a,$0a,$0a,$0a,$0a,$0a,$0a,$0a,$0b,$0b,$0b,$0b,$0b,$0b,$0b,$0b
        .BYTE $0c,$0c,$0c,$0c,$0c,$0c,$0c,$0c,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d
        .BYTE $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$10,$10,$10,$10,$10,$10,$10,$10
        .BYTE $11,$11,$11,$11,$11,$11,$11,$11,$12,$12,$12,$12,$12,$12,$12,$12
        .BYTE $14,$14,$14,$14,$14,$14,$14,$14,$15,$15,$15,$15,$15,$15,$15,$15
        .BYTE $16,$16,$16,$16,$16,$16,$16,$16,$17,$17,$17,$17,$17,$17,$17,$17

;Sprite data - 16x16, 1 bit per pixel
sprites: 
.BYTE %00000000,%00000000 ;Player right
.BYTE %00000000,%00000000
.BYTE %00011000,%00000000
.BYTE %00111100,%00000000
.BYTE %00111100,%00000000
.BYTE %00111100,%00000000
.BYTE %00011000,%00000000
.BYTE %00111100,%00000000
.BYTE %01111110,%00000000
.BYTE %01111110,%00000000
.BYTE %11111111,%00000000
.BYTE %11111011,%00000000
.BYTE %00111100,%00000000
.BYTE %00111000,%00000000
.BYTE %01100110,%00000000
.BYTE %01110111,%00000000
.BYTE %00000000,%00000000
.BYTE %00000110,%00000000
.BYTE %00001111,%00000000
.BYTE %00001111,%00000000
.BYTE %00001111,%00000000
.BYTE %00000110,%00000000
.BYTE %00001111,%00000000
.BYTE %00011111,%10000000
.BYTE %00011111,%10000000
.BYTE %00011111,%10000000
.BYTE %00011111,%10000000
.BYTE %00001111,%00000000
.BYTE %00001111,%00000000
.BYTE %00000110,%00000000
.BYTE %00000110,%00000000
.BYTE %00000111,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000011,%00000000
.BYTE %00000111,%10000000
.BYTE %00000111,%10000000
.BYTE %00000111,%10000000
.BYTE %00000011,%00000000
.BYTE %00000111,%10000000
.BYTE %00001111,%11000000
.BYTE %00001111,%11000000
.BYTE %00011111,%11100000
.BYTE %00011111,%01100000
.BYTE %00000111,%10000000
.BYTE %00000111,%00000000
.BYTE %00001100,%11000000
.BYTE %00001110,%11100000
.BYTE %00000000,%00000000
.BYTE %00000000,%01100000
.BYTE %00000000,%11110000
.BYTE %00000000,%11110000
.BYTE %00000000,%11110000
.BYTE %00000000,%01100000
.BYTE %00000000,%11110000
.BYTE %00000001,%11111000
.BYTE %00000011,%11111100
.BYTE %00000011,%11111100
.BYTE %00000111,%11111110
.BYTE %00000110,%11110110
.BYTE %00000000,%11110000
.BYTE %00000001,%10011000
.BYTE %00000011,%00001100
.BYTE %00000011,%10001110
.BYTE %00000000,%00000000 ;Player left
.BYTE %00000110,%00000000  
.BYTE %00001111,%00000000
.BYTE %00001111,%00000000
.BYTE %00001111,%00000000
.BYTE %00000110,%00000000
.BYTE %00001111,%00000000
.BYTE %00011111,%10000000
.BYTE %00111111,%11000000
.BYTE %00111111,%11000000
.BYTE %01111111,%11100000
.BYTE %01101111,%01100000
.BYTE %00001111,%00000000
.BYTE %00011001,%10000000
.BYTE %00110000,%11000000
.BYTE %01110001,%11000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%11000000
.BYTE %00000001,%11100000
.BYTE %00000001,%11100000
.BYTE %00000001,%11100000
.BYTE %00000000,%11000000
.BYTE %00000001,%11100000
.BYTE %00000011,%11110000
.BYTE %00000011,%11110000
.BYTE %00000111,%11111000
.BYTE %00000110,%11111000
.BYTE %00000001,%11100000
.BYTE %00000000,%11100000
.BYTE %00000011,%00110000
.BYTE %00000111,%01110000
.BYTE %00000000,%00000000
.BYTE %00000000,%01100000
.BYTE %00000000,%11110000
.BYTE %00000000,%11110000
.BYTE %00000000,%11110000
.BYTE %00000000,%01100000
.BYTE %00000000,%11110000
.BYTE %00000001,%11111000
.BYTE %00000001,%11111000
.BYTE %00000001,%11111000
.BYTE %00000001,%11111000
.BYTE %00000000,%11110000
.BYTE %00000000,%11110000
.BYTE %00000000,%01100000
.BYTE %00000000,%01100000
.BYTE %00000000,%11100000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00011000
.BYTE %00000000,%00111100
.BYTE %00000000,%00111100
.BYTE %00000000,%00111100
.BYTE %00000000,%00011000
.BYTE %00000000,%00111100
.BYTE %00000000,%01111110
.BYTE %00000000,%01111110
.BYTE %00000000,%11111111
.BYTE %00000000,%11011111
.BYTE %00000000,%00111100
.BYTE %00000000,%00011100
.BYTE %00000000,%01100110
.BYTE %00000000,%11101110

.BYTE %00000000,%00000000 ;Worm (enemy) left
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00011000,%00000000
.BYTE %00111100,%00000000
.BYTE %01111110,%00000000
.BYTE %01100110,%00000000
.BYTE %11100111,%00000000
.BYTE %01100110,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00001111,%10000000
.BYTE %01111111,%11110000
.BYTE %11111111,%11111000
.BYTE %01110000,%01110000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %01111111,%11111110
.BYTE %11111111,%11111111
.BYTE %01111111,%11111110
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000001,%11110000
.BYTE %00001111,%11111110
.BYTE %00011111,%11111111
.BYTE %00001110,%00001110
.BYTE %00000000,%00000000 ;Worm right
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00001111,%10000000
.BYTE %01111111,%11110000
.BYTE %11111111,%11111000
.BYTE %01110000,%01110000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %01111111,%11111110
.BYTE %11111111,%11111111
.BYTE %01111111,%11111110
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000001,%11110000
.BYTE %00001111,%11111110
.BYTE %00011111,%11111111
.BYTE %00001110,%00001110
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00000000
.BYTE %00000000,%00011000
.BYTE %00000000,%00111100
.BYTE %00000000,%01111110
.BYTE %00000000,%01100110
.BYTE %00000000,%11100111
.BYTE %00000000,%01100110


doorspr:.BYTE %11011011   ;Door sprite - 16x16, 1 bit per pixel
        .BYTE %10110110   ;This is stored in screen format (ie 4 8x8 chunks)
        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        
        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        .BYTE %01101101
        .BYTE %11011011

        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        .BYTE %01101101
        .BYTE %11011011
        
        .BYTE %10110110
        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        .BYTE %01101101
        .BYTE %11011011
        .BYTE %10110110
        .BYTE %01101101

keyspr: .BYTE %00001100  ;Key sprite - 8x8, 1 bit per pixel
        .BYTE %00010010
        .BYTE %00100001
        .BYTE %00100001
        .BYTE %00010010
        .BYTE %10101100
        .BYTE %01000000
        .BYTE %10000000


;Levels - headers first
lev1h: 	.BYTE 15,0,1,16,11,2,30,16
      	.BYTE 1,17

      	.BYTE 112,136,112,238,0
	.BYTE 0,200,1,238,255
	.BYTE 0,200,1,238,255
	.BYTE 0,200,1,238,255

lev2h: 	.BYTE 1,4,30,4,30,16,16,4
      	.BYTE 29,11

      	.BYTE 64,136,8,232,1
	.BYTE 72,40,72,112,0
	.BYTE 128,40,128,168,0
	.BYTE 192,40,192,232,0

lev3h: 	.BYTE 1,0,30,0,1,6,30,6
      	.BYTE 29,17

      	.BYTE 8,24,8,64,0
	.BYTE 8,72,8,64,0
	.BYTE 232,24,176,232,1
	.BYTE 232,72,176,232,1

lev4h: 	.BYTE 1,3,30,3,14,3,17,3
      	.BYTE 29,17

      	.BYTE 48,96,48,88,0
	.BYTE 136,96,104,136,1
	.BYTE 152,96,152,192,0
	.BYTE 48,128,48,192,0

;Then compressed data
;Compression format is :
; bits 0-1 - block type (0=air, 1=floor, 2=wall, 3=spike)
; bits 2-7 - block count minus 1
;255 marks the end of level data
;Levels are 32x20 blocks

levv1:   .BYTE 6
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 60
.BYTE 14
.BYTE 48
.BYTE 10
.BYTE 40
.BYTE 22
.BYTE 60
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 32
.BYTE 37
.BYTE 52
.BYTE 10
.BYTE 84
.BYTE 7
.BYTE 32
.BYTE 10
.BYTE 64
.BYTE 13
.BYTE 8
.BYTE 6
.BYTE 32
.BYTE 10
.BYTE 84
.BYTE 6
.BYTE 32
.BYTE 10
.BYTE 68
.BYTE 33
.BYTE 20
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 60
.BYTE 5
.BYTE 56
.BYTE 10
.BYTE 44
.BYTE 5
.BYTE 72
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 28
.BYTE 5
.BYTE 88
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 16
.BYTE 7
.BYTE 100
.BYTE 6
.BYTE 125+4
.BYTE $FF

levv2: .BYTE 6
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 21
.BYTE 12
.BYTE 89
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 20
.BYTE 13
.BYTE 88
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 32
.BYTE 17
.BYTE 48
.BYTE 25
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 12
.BYTE 81
.BYTE 28
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 6
.BYTE 125+4
.BYTE $FF

levv3: .BYTE 6
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 37
.BYTE 48
.BYTE 37
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 44
.BYTE 9
.BYTE 16
.BYTE 13
.BYTE 40
.BYTE 10
.BYTE 40
.BYTE 5
.BYTE 76
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 37
.BYTE 48
.BYTE 37
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 48
.BYTE 5
.BYTE 32
.BYTE 5
.BYTE 32
.BYTE 10
.BYTE 72
.BYTE 5
.BYTE 44
.BYTE 10
.BYTE 60
.BYTE 5
.BYTE 56
.BYTE 10
.BYTE 48
.BYTE 5
.BYTE 68
.BYTE 10
.BYTE 36
.BYTE 5
.BYTE 80
.BYTE 10
.BYTE 120
.BYTE 6
.BYTE 125+4
.BYTE $FF

levv4: .BYTE 6
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 17
.BYTE 40
.BYTE 11
.BYTE 40
.BYTE 17
.BYTE 10
.BYTE 48
.BYTE 25
.BYTE 48
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 20
.BYTE 9
.BYTE 20
.BYTE 5
.BYTE 16
.BYTE 5
.BYTE 20
.BYTE 9
.BYTE 20
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 32
.BYTE 5
.BYTE 8
.BYTE 5
.BYTE 28
.BYTE 5
.BYTE 8
.BYTE 5
.BYTE 28
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 20
.BYTE 81
.BYTE 20
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 16
.BYTE 5
.BYTE 80
.BYTE 5
.BYTE 16
.BYTE 10
.BYTE 120
.BYTE 10
.BYTE 20
.BYTE 83
.BYTE 20
.BYTE 6
.BYTE 125+4
.BYTE $FF

dolh:   stx 6          ;Copy level header pointed to by X/Y
	sty 7          ;to levhead
	lda #<levhead
	sta 4
	lda #>levhead
	sta 5
	ldy #0
headl:  lda (6),y
	sta (4),y
	iny
	cpy #30        ;It's 30 bytes
	bne headl
	rts
	
;Level decompression
decomp: lda #<lev1     ;Get normal level address
        sta 4
        lda #>lev1
        sta 5
        stx 6          ;Store compressed level address (X/Y)
        sty 7
        ldy #0

deloop: lda (6),y      ;Get next byte
        cmp #$ff       ;If $FF then end of level data
        beq deend
	sta $b0        ;Save
	lsr
	lsr
	tax            ;Get run length number (top 6 bits)
	lda $b0
	and #3         ;Get tile number
	
        inc 6          ;Increase source address
        bne nodinc2
        inc 7
nodinc2: nop
dewloop: sta (4),y     ;Store tile
        inc 4          ;Increase dest address
        bne nodeinc
        inc 5
nodeinc: dex           ;Decrease run length count
        bne dewloop    ;and loop
        jmp deloop     ;Byte over - jump to start of loop

deend:  rts

;Make status display (why did I call it 'display bottom'?)
mkdispb: ldx #0
mkdbl:   lda dispbot,x ;Copy 'LIVES' text
	sta $79e0,x
	inx
	cpx #48
	bne mkdbl
	ldx #0
mkdbl3:  lda timedb,x  ;Copy 'TIME' text
	sta $7a68,x
	inx
	cpx #40
	bne mkdbl3
	lda #$10
	ldx #0
	rts

;enddat:  .BYTE $A,$D,$C,$D,$A,$E,$F,$FF


livenum:.BYTE %00111100 ;Numbers 0-9
	.BYTE %01111110 ;This is a horrible font
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %01111110
	.BYTE %00111100

	.BYTE %00011000
	.BYTE %00111000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %11111111
	.BYTE %11111111

	.BYTE %00111100
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %00001100
	.BYTE %00110000
	.BYTE %11000000
	.BYTE %11111111
	.BYTE %11111111

	.BYTE %00111100
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %00001110
	.BYTE %00001110
	.BYTE %11000011
	.BYTE %11111111
	.BYTE %00111100

	.BYTE %00111100
	.BYTE %00111100
	.BYTE %01101100
	.BYTE %01101100
	.BYTE %11111111
	.BYTE %11111111
	.BYTE %00001100
	.BYTE %00001100

	.BYTE %11111111
	.BYTE %11111111
	.BYTE %11000000
	.BYTE %11111110
	.BYTE %00000011
	.BYTE %00000011
	.BYTE %11111110
	.BYTE %11111100

	.BYTE %01111111
	.BYTE %11111111
	.BYTE %11000000
	.BYTE %11111110
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %00111100

	.BYTE %11111111
	.BYTE %11111111
	.BYTE %00000111
	.BYTE %00000110
	.BYTE %00001100
	.BYTE %00001100
	.BYTE %00011000
	.BYTE %00011000

	.BYTE %00111100
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %00111100
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %00111100

	.BYTE %01111110
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %01111111
	.BYTE %00000011
	.BYTE %00000011
	.BYTE %00000011


dispbot:.BYTE %11000000 ;'LIVES' text
	.BYTE %11000000
	.BYTE %11000000
	.BYTE %11000000
	.BYTE %11000000
	.BYTE %11000000
	.BYTE %11000000
	.BYTE %01111111

	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000

	.BYTE %11000011
	.BYTE %11000011
	.BYTE %01000010
	.BYTE %01000010
	.BYTE %01100110
	.BYTE %01111110
	.BYTE %00011000
	.BYTE %00011000

	.BYTE %01111111
	.BYTE %11111111
	.BYTE %11000000
	.BYTE %11111000
	.BYTE %11111000
	.BYTE %11000000
	.BYTE %11111111
	.BYTE %01111111

	.BYTE %00111100
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %00110000
	.BYTE %00001100
	.BYTE %11000011
	.BYTE %11111111
	.BYTE %00111100

	.BYTE %00000000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00000000

timedb:	.BYTE %11111111 ;'TIME' text
	.BYTE %11111111
	.BYTE %00111100
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000

	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000

	.BYTE %11100111
	.BYTE %11100111
	.BYTE %11011011
	.BYTE %11011011
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11000011

	.BYTE %01111111
	.BYTE %11111111
	.BYTE %11000000
	.BYTE %11111000
	.BYTE %11111000
	.BYTE %11000000
	.BYTE %11111111
	.BYTE %01111111

	.BYTE %00000000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00000000

title:  .BYTE %11111100 ;'PRESS FIRE' text
	.BYTE %11111110
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11111110
	.BYTE %11111100
	.BYTE %11000000
	.BYTE %11000000

	.BYTE %11111110
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11111100
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %11000011

	.BYTE %01111111
	.BYTE %11111111
	.BYTE %11000000
	.BYTE %11111000
	.BYTE %11111000
	.BYTE %11000000
	.BYTE %11111111
	.BYTE %01111111

	.BYTE %00111100
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %00110000
	.BYTE %00001100
	.BYTE %11000011
	.BYTE %11111111
	.BYTE %00111100

	.BYTE %00111100
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %00110000
	.BYTE %00001100
	.BYTE %11000011
	.BYTE %11111111
	.BYTE %00111100

	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00000000
	.BYTE %00000000

	.BYTE %01111111
	.BYTE %11111111
	.BYTE %11000000
	.BYTE %11111000
	.BYTE %11111000
	.BYTE %11000000
	.BYTE %11000000
	.BYTE %11000000

	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000
	.BYTE %00011000

	.BYTE %11111110
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %11000011
	.BYTE %11111100
	.BYTE %11111111
	.BYTE %11000011
	.BYTE %11000011

	.BYTE %01111111
	.BYTE %11111111
	.BYTE %11000000
	.BYTE %11111000
	.BYTE %11111000
	.BYTE %11000000
	.BYTE %11111111
	.BYTE %01111111

;Draw a number on the status bar
dodbnum: asl  ;Multiply number by 8
	asl
	asl
	clc   ;for character address lookup
	adc #<livenum
	sta 4
	lda #>livenum
	adc #0
	sta 5 ;Character source now in 4/5
	ldy #0
updbl1:  lda (4),y  ;Copy character across
	sta (8),y
	iny
	cpy #8      ;8 bytes
	bne updbl1
	rts

;Update status bar
updb:	lda LIVES  ;Lives first (1 digit only)
	ldx #$7a   ;Store screen address ($7A90)
	stx $9
	ldx #$10
	stx $8
	jsr dodbnum ;And display number
	lda TIME   ;First (last on the display) digit of time
	and #$f
	ldx #$7a   ;Address is $7B20
	stx $9
	ldx #$a0
	stx $8
	jsr dodbnum ;And display
	lda TIME   ;Middle digit now
	lsr        ;Shift to get it
	lsr
	lsr
	lsr
	ldx #$7a   ;Address is $7B18 
	stx $9
	ldx #$98
	stx $8
	jsr dodbnum ;And display
	lda TIME+1 ;And finally last digit (first on display)
	and #$f
	ldx #$7a   ;Address is $7B10
	stx $9
	ldx #$90
	stx $8
	jsr dodbnum ;And display
	lda LCOMP  ;Now level number
	sed        ;Add 1, so level numbers aren't 0 based anymore
	clc
        adc #1
	cld
	and #$f
	ldx #$7a   ;Address $7B58
	stx $9
	ldx #$d8
	stx $8
	jsr dodbnum ;And display
	lda LCOMP  ;Other digit (you decide if it's first or last)
	sed        ;Add 1, so level numbers aren't 0 based anymore
	clc
	adc #1
	cld
	lsr
	lsr
	lsr
	lsr
	ldx #$7a  ;Address $7B50   
	stx $9
	ldx #$d0
	stx $8
	jsr dodbnum ;And display
	rts 

uptime: sed         ;Update time - use BCD decimal mode
	lda TIME
	sec
	sbc #1      ;Subtract 1 from time
	sta TIME
	lda TIME+1  ;Then update second byte
	sbc #0
	sta TIME+1
	cld
	lda TIME    ;Is time = 000?
	ora TIME+1
	beq timeup  ;Then time's up so kill the player
	rts

timeup: jmp die

clear:  lda #0       ;Clear the screen - this is _not_ small
        ldx #0       ;It was a 4K compo game, why did I make the code as big as
clrloop: sta $5800,x ;possible?
        sta $5900,x  ;I'm an idiot really
        sta $5A00,x
        sta $5B00,x
        sta $5C00,x
        sta $5D00,x
        sta $5E00,x
        sta $5F00,x
        sta $6000,x
        sta $6100,x
        sta $6200,x
        sta $6300,x
        sta $6400,x
        sta $6500,x
        sta $6600,x
        sta $6700,x
        sta $6800,x
        sta $6900,x
        sta $6A00,x
        sta $6B00,x
        sta $6C00,x
        sta $6D00,x
        sta $6E00,x
        sta $6F00,x
        sta $7000,x
        sta $7100,x
        sta $7200,x
        sta $7300,x
        sta $7400,x
        sta $7500,x
        sta $7600,x
        sta $7700,x
        sta $7800,x
        sta $7900,x
        sta $7A00,x
        sta $7B00,x
        sta $7C00,x
        sta $7D00,x
        sta $7E00,x
        sta $7F00,x
        inx
        bne clrloop
        
        rts


levtab: .WORD levv1,lev1h ;Level address tables - first word compressed data
	.WORD levv2,lev2h ;second word is header
	.WORD levv3,lev3h
	.WORD levv4,lev4h

;Our event handler. This looks for vsync and increments the VSYNCCNT
eventh: cmp #4 ;is this vsync?
        bne +  ;jump if isn't
        inc VSYNCCNT ;increment VSYNCCNT
*       jmp (OLDEVNTV) ;and jump to old handler