;assemble it - game 2 - single player
;blast 'em game

;in this tutorial, we will show you how
;to code a 1 player blast 'em game. this
;will involve eight sprites. one will be
;the player ship, one will be a bullet
;and the remaining six will become
;missiles

;also in this tutorial, you'll be seeing
;how sprite animations work, and how we
;control the sprite priorities

;we'll also be adding levels, which will
;engage the speed of the missiles to
;make the game a tad on the difficult
;side.

;there'll also be a shield generator and
;a scoreboard. we'll also be adding some
;credits on the front of the screen as
;well as game over. anyway, enough of
;chitty chatty clag, let's move on to
;the hard stuff - the game coding of
;course :)

;variables for the game

spritepos = $0370    ;positions for the
                     ;sprites

collision = $03f0    ;collision dection

firelockup = $0330   ;debugged firemode

gameon   = $0331     ;to check if game
                     ;is on, or not

levelct  = $0332     ;our level counter

missleft = $0333     ;missile counter

pointer  = $0340     ;pointer for multi
                     ;purpose animation
                     ;with sprites

nomovebull = $0342

destroy  = $0350     ;pointer to check
                     ;explosion anim
plrdestroy = $0351

gameover = $0352




         *= $3800 ;where we start our
                  ;jmp address

restart  sei      ;set irq flag

         lda #$31  ;we use these
         ldx #$ea  ;routines here to
         sta $0314 ;turn off the irq
         stx $0315 ;so that the game
         lda #$00  ;wont keep crashing
         sta $d019 ;when restarting
         sta $d01a ;during an irq
         lda #$81  ;routine player.
         sta $dc0d ;
         sta $dd0d ;
         lda #$00  ;no sound
         sta $d418 ;
         lda #$08  ;turn off screen
         sta $d016 ;multicolour

         lda #$00  ;black the frame and
         sta $d021 ;background
         sta $d020 ;

         ldx #$00    ;
title    lda #$0f    ;
         sta $d800,x ; draw the title
         sta $d900,x ; screen, and
         sta $da00,x ; set colour to
         sta $dae8,x ; grey
         lda $3400,x ;
         sta $0400,x ;
         lda $3500,x ;
         sta $0500,x ;
         lda $3600,x ;
         sta $0600,x ;
         lda $36e8,x ;
         sta $06e8,x ;
         inx         ;
         bne title

         lda #$1a    ;charset type
         sta $d018   ;read from $2800

         lda #$00    ;no sprites on
         sta $d015   ;screen

space    lda $dc01   ;check for spacebar
         cmp #$ef    ;to be pressed
         bne space

main     lda #$ff    ;this is where we
         sta $d015   ;setup and init.
         sta $d01c   ;all the sprites
         lda #$0b    ;for our game
         sta $d025   ;
         lda #$01    ;
         sta $d026   ;
         lda #$80    ;
         sta $07f8   ;
         lda #$83    ;
         sta $07f9   ;
         lda #$8a    ;
         sta $07fa   ;
         sta $07fb   ;
         sta $07fc   ;
         sta $07fd   ;
         sta $07fe   ;
         sta $07ff   ;

;reposition sprites according to
;postable.

         ldx #$00
possprts lda postable+$00,x
         sta spritepos+$00,x
         inx
         cpx #$10
         bne possprts

;all sprite multi-colour is grey 3

         ldx #$00
spcols   lda #$0f
         sta $d027,x
         inx
         cpx #$08
         bne spcols

;draw the space background from reading
;the stored screen ($3000-$33e8)

         ldx #$00
spacebgr lda $3000,x
         sta $0400,x
         lda $3100,x
         sta $0500,x
         lda $3200,x
         sta $0600,x
         lda $32e8,x
         sta $06e8,x
         lda #$0b
         sta $d800,x
         sta $d900,x
         sta $da00,x
         sta $dae8,x
         inx
         bne spacebgr

         lda #$18  ;turn on screen
         sta $d016 ;multicolour mode
         lda #$1a  ;turn on charset
         sta $d018 ;fron $2800

         lda #$06  ;use blue for
         sta $d023 ;multicolour 1
         lda #$0e  ;and lt blue for
         sta $d022 ;multicolour 2

         ldx #$00    ;read 40 chars to
status   lda $2700,x ;paste the score
         sta $0400,x ;from $2700 to the
         lda #$07    ;screen ram ($400)
         sta $d800,x ;
         inx         ;
         cpx #$28    ;
         bne status  ;

         lda #$01    ; disable destroy
         sta destroy ; and set levelct
         sta levelct ; to level1
         lda #$00    ; init the no of
         sta missleft; missiles blasted

         lda #$00       ;disable the
         sta firelockup ;functions to
         sta plrdestroy ;lock controls

         sta pointer    ;initialise the
         sta pointer+$01;pointers and
         sta nomovebull ;bullet status
         sta gameover   ;disable
                        ;game over

         lda #$08
         jsr $ffd2 ;disable shift+cbm

         lda #<int ;this is where że
         ldx #>int ;initialise and
         ldy #$00  ;we prepare to play
         sta $0314 ;the irq request
         stx $0315 ;flag, to run a
         sty $d012 ;continuous loop
         lda #$7f  ;to perform more
         sta $dc0d ;tasks.
         sta $dd0d ;
         lda #$01  ;
         sta $d019 ;
         sta $d01a ;
         lda #$00  ;
         tax       ;
         tay       ;
         jsr $1000 ;
         cli
hold     jmp hold
int      inc $d019 ;our main irq flag

         lda gameover ;is game over? if
         cmp #$01     ;so, end the game
         beq endgame

         jsr expand   ;call expand
         jsr mvplayer ;call mvplayer
         jsr bulletmv ;call bulletmv
         jsr shipcol  ;call shipcol
         jsr missile  ;call missile
         jsr animate  ;call animate
         jsr bullcol  ;call bullcol
         jsr chkhit   ;call chkhit
         jsr random   ;call random
         jsr colroll  ;call colroll
         jsr $1003    ;play music
         jmp $ea31    ;irq loop
endgame  jsr explplr  ;call explplr
         jsr colroll  ;
         jsr $1003    ;play music
         jmp $ea31

;expand sprite positions and put read
;data from spritepos into the main
;sprite position formats ($d000-$d00f)

expand   ldx #$00
xloop    lda spritepos+$01,x
         sta $d001,x
         lda spritepos+$00,x
         asl a      ;x position is more
         ror $d010  ;than 256 pixels
         sta $d000,x
         inx
         inx
         cpx #$10
         bne xloop
         rts

;read the joystick in port 2 and move
;the player around the screen. pressing
;firebutton will make the player shoot
;a rocket. you should already know how
;the joystick control works. so no help
;is really reqired here.

mvplayer lda $dc00        ;read joystick
up       lsr a            ;check up
         bcs down         ;not up
         ldy spritepos+$01;
         dey              ;move player
         dey              ;up, until it
         cpy #$48         ;reaches #$48
         bcs setup        ;then stop
         ldy #$48         ;moving player
setup    sty spritepos+$01
down     lsr a            ;check down
         bcs left         ;not down
         ldy spritepos+$01;
         iny              ;move player
         iny              ;down until it
         cpy #$ec         ;reaches #$ec
         bcc setdown      ;then stop
         ldy #$ec         ;moving player
setdown  sty spritepos+$01
left     lsr a            ;read left
         bcs right        ;not left
         ldy spritepos+$00
         dey              ;as with up
         cpy #$0c         ;and down, but
         bcs setleft      ;moving left
         ldy #$0c         ;
setleft  sty spritepos+$00
right    lsr a            ;read right
         bcs fire         ;not right
         ldy spritepos+$00
         iny              ;as up and
         cpy #$9e         ;down but
         bcc setright     ;moving right
         ldy #$9e
setright sty spritepos+$00
fire     lsr a            ;read fire
         bcs nojoy        ;not fire
         lda firelockup   ;
         cmp #$01         ;check
         beq nojoy        ;firelockup
                          ;if not locked
         lda spritepos+$00;place bullet
         sta spritepos+$02;on ship and
         lda spritepos+$01;fire bullet
         sta spritepos+$03
         lda #$01         ;lock fire
         sta firelockup   ;until bullet
                          ;finish its
                          ;functional
                          ;process
nojoy    rts

;the moving bullet

;this routine (as you already seen
;before) will check whether the bullet
;is at its home position, or is moving
;if the bullet is not moving then we
;call moveit, else we just jump on to
;nomovebl which ignores the bullet
;moving process.

bulletmv lda nomovebull
         cmp #$01
         beq nomovebl
moveit   ldy spritepos+$03
         dey
         dey
         dey
         dey
         dey
         dey
         dey
         dey
         cpy #$0b
         bcs stopbull
         ldy #$00
         sty spritepos+$02
         lda #$00
         sta firelockup
stopbull sty spritepos+$03
         lda #$83
         sta $07f9
         rts
nomovebl rts

;check and perform the enemy to bullet
;collision detection. if bullet smacks
;the enemy, add points to the score.
;you already seen this sort of routine
;in our previous 2 player game tutorial
;you will also notice that this routine
;also works with control loops. where
;we kill the enemies.

bullcol  lda spritepos+$02
         sec
         sbc #$06
         sta collision+$00
         clc
         adc #$0c
         sta collision+$01
         lda spritepos+$03
         sec
         sbc #$0c
         sta collision+$02
         clc
         adc #$18
         sta collision+$03

;can you see what i mean. okay, this
;process is doing exactly the same as
;the player collision, but it works
;the bullet. when an enemy hits the
;player's bullet, it will die. else we
;just ignore the process. we add a score
;to any missile hit, and if 100 missiles
;is shot. we increase the speed for the
;next level - else ignore the process.

         ldx #$00
chkbcol  lda spritepos+$04,x
         cmp collision+$00
         bcc nohit
         cmp collision+$01
         bcs nohit
         lda spritepos+$05,x
         cmp collision+$02
         bcc nohit
         cmp collision+$03
         bcs nohit
         lda #$00
         sta spritepos+$05,x
         lda ranpos+$00
         sta spritepos+$04,x

         lda #$00    ;turn on bullet
         sta destroy ;explosion

;this is how we add points to the score
;increment the character at screen ram
;$040b (the last zero digit on screen)
;by one, and then we call a loop, which
;will use the previous five zero digits
;to increment each number after reaching
;the nearest digit (after reaching '9'
;we increment each digit - and so on

         inc $040b
         ldx #$05
score    lda $0406,x
         cmp #$3a
         bne setscore
         lda #$30
         sta $0406,x
         inc $0405,x
setscore dex
         bne score

;this is where we increment the amount
;of missiles that have been shot. if
;100 missiles have not been shot then
;ignore the rest of the process. else
;add 1 to levelct - which will increase
;the playing speed. also increment the
;character at $0427, which is the char
;at the end of the screen.

         inc missleft
         lda missleft
         cmp #$64
         bne stoploop
         lda #$00
         sta missleft
         inc $0427
         inc levelct
         lda levelct
         cmp #$09
         bne stoploop
         lda #$01
         sta levelct
         lda #$31
         sta $0427
stoploop rts
nohit
         inx
         inx
         cpx #$0c
         bne chkbcol
         rts

;since the bullet has hit the missile,
;we need to check if the destroy
;pointer is turned on, so that we can
;show the explosion animation for the
;enemy :)

chkhit   lda destroy
         cmp #$01
         beq nodestroy
         lda #$01
         sta nomovebull
exploop1 ldx pointer+$01
         lda expltbl+$00,x
         sta $07f9
         inx
         cpx #$12
         beq reset2
         inc pointer+$01
         rts

;reset the pointer and turn off the
;explosion generator for the bullet

reset2   ldx #$00
         stx pointer+$01
         ldx #$01
         stx destroy
         ldx #$00
         stx firelockup
         stx nomovebull
         ldx #$0b
         stx spritepos+$03
         stx spritepos+$02
nodestroy rts

;missile to ship collision. if missile
;hits the player, make the player lose
;a shield from the ship and replace the
;enemy missile

shipcol  lda spritepos+$00 ;read player
         sec               ;sprite and
         sbc #$06          ;calculate
         sta collision+$04 ;the position
         clc
         adc #$0c
         sta collision+$05
         lda spritepos+$01
         sec
         sbc #$0c
         sta collision+$06
         clc
         adc #$18
         sta collision+$07

;this is where we read the collision
;detection for the player ship. if the
;player ship does not hit an enemy
;(collision+$04 - collision+$07) then
;this routine jumps to noshpcol, showing
;that there is no collision detected
;during the working process. however if
;collision+$04 to collision+$05 is read
;the missile is replaced at zero y-pos
;and we stop the player bullet and
;convert it into an explosion.

         ldx #$00
shipchk  lda spritepos+$04,x
         cmp collision+$04
         bcc noshpcol
         cmp collision+$05
         bcs noshpcol
         lda spritepos+$05,x
         cmp collision+$06
         bcc noshpcol
         cmp collision+$07
         bcs noshpcol
         lda #$00
         sta spritepos+$05,x
         lda ranpos+$00
         sta spritepos+$04,x

;decrement the player's shield. if the
;player has lost all shields, switch on
;game over (where we destroy the player
;ship) to lock other functions.

         dec $0419
         lda $0419
         cmp #$30
         bne stopscol
         lda #$01
         sta gameover
stopscol rts

;nothing has hit the player ship

noshpcol inx           ;where there is
         inx           ;no collision
         cpx #$0c
         bne shipchk
         rts

;move those missiles.

;in this routine, we call a loop, which
;will move all the enemy missiles. we
;use levelct to control the speed of
;the missiles going down, and we use
;zero (adc #$00) to control the x-speed
;of the missiles. using #$00 does not
;move the x-position.

missile  ldx #$00
falloop  lda spritepos+$04,x
         clc
         adc #$00  ;don't move x-pos
         sta spritepos+$04,x
         lda spritepos+$05,x
         clc
         adc levelct
         sta spritepos+$05,x
         inx
         inx
         cpx #$0c
         bne falloop
         rts

;multi-purpose animator routine

animate  ldx pointer
animloop lda misstbl+$00,x
         sta $07fa
         sta $07fb
         sta $07fc
         sta $07fd
         sta $07fe
         sta $07ff
         lda plrtble+$00,x
         sta $07f8
         inx
         cpx #$18
         beq reset
         inc pointer
         rts
reset    ldx #$00
         stx pointer
         rts

;a control loop to read the random
;position table - to make the game more
;interesting :)

random   lda ranpos+$00
         sta ranpos+$18
         ldx #$00
ranloop  lda ranpos+$01,x
         sta ranpos+$00,x
         inx
         cpx #$18
         bne ranloop
         rts

;game is over and the player is dead so
;now we create our own explosion routine

explplr  ldx pointer+$01
eloop    lda expltbl+$00,x
         sta $07f8
         inx
         cpx #$12
         beq reset3
         inc pointer+$01
         rts
reset3   ldx #$00
         stx pointer+$01
         jmp restart

colroll  lda colours+$00
         sta colours+$28
         ldx #$00
col1     lda colours+$01,x
         sta colours+$00,x
         lda colours+$00,x
         sta $d800,x
         inx
         cpx #$28
         bne col1
         rts

colours  .byte $06,$06,$02,$02,$04,$04
         .byte $05,$05,$03,$03,$07,$07
         .byte $01,$01,$07,$07,$03,$03
         .byte $05,$05,$04,$04,$02,$02
         .byte $06,$06,$06,$06,$06,$06
         .byte $06,$06,$06,$06,$06,$06
         .byte $06,$06,$06,$06,$06,$06
         .byte $06,$06,$06,$06,$06,$06
         .byte $06

postable .byte $58,$e0,$00,$00,$0c,$30
         .byte $32,$40,$5c,$50,$82,$60
         .byte $45,$70,$75,$80

plrtble
         .byte $80,$80,$80,$80,$80,$80
         .byte $81,$81,$81,$81,$81,$81
         .byte $80,$80,$80,$80,$80,$80
         .byte $81,$81,$81,$81,$81,$81
         .byte $81

misstbl  .byte $8a,$8a,$8a,$8b,$8b,$8b
         .byte $8c,$8c,$8c,$8d,$8d,$8d
         .byte $8e,$8e,$8e,$8f,$8f,$8f
         .byte $90,$90,$90,$91,$91,$91
         .byte $91

expltbl  .byte $84,$84,$84,$85,$85,$85
         .byte $86,$86,$86,$87,$87,$87
         .byte $88,$88,$88,$89,$89,$89
         .byte $91

ranpos   .byte $58,$75,$0c,$45,$32,$82
         .byte $5c,$7c,$15,$4c,$3c,$88
         .byte $15,$4c,$85,$6c,$2c,$95
         .byte $3c,$55,$7c,$45,$3c,$1c
         .byte $91

