;ship layout
define ShipCenterL     $10 ; screen location of ship center, low byte
define ShipCenterH     $11 ; screen location of ship center, high byte

define ShipLeftL     $12 ; screen location of ship left part, low byte
define ShipLeftH     $13 ; screen location of ship left part, high byte

define ShipRightL     $14 ; screen location of ship right part, low byte
define ShipRightH     $15 ; screen location of ship right part, high byte

define ShipGunL     $16 ; screen location of ship gun, low byte
define ShipGunH     $17 ; screen location of ship gun, high byte

;bullets
define BulletStart    $21 ; start of the bullet memory
define BulletNumber     $19 ;amount of available bullets

define currentBulletL $32 ; the current addres of a possible bullet
define currentBulletH $34

define currentEnemyL $36 ; the current addres of a enemy
define currentEnemyH $38

define currentEnemyNumber $3A

; ASCII values of keys controlling the spaceship
define ASCII_w      $77
define ASCII_a      $61
define ASCII_d      $64

; System variables
define sysLastKey   $ff
define zero $f0

;screen boundaries
define ShipLeftBound $1A
define ShipRightBound $1B

define EnemyArrayStart $40 ; the array starts at address 40

define AmountOfEnemies $0f ; 15 enemies
define AmountOfEnemiesAddress $0a ; address is at location 10

define currentTicksAddress $05 ; current ticks counter at address 05
define delay $1D ; delay of 5 ticks

define amountOfBullets $05 ; maximum 8 bullets can be active at a time


define score $0F
initBoundaries:
lda #$FF
sta ShipRightBound

lda #$E0
sta ShipLeftBound

initShip:
lda #$EF
sta ShipCenterL
lda #$05
sta ShipCenterH

lda #$EE
sta ShipLeftL
lda #$05
sta ShipLeftH

lda #$F0
sta ShipRightL
lda #$05
sta ShipRightH

lda #$CF
sta ShipGunL
lda #$05
sta ShipGunH

initVar:
lda #amountOfBullets
sta BulletNumber

lda #0
sta zero
sta score

lda #$0F
sta delay

initGameInfo:
              LDA #AmountOfEnemies
              STA AmountOfEnemiesAddress

              LDA #EnemyArrayStart
              STA AddEnemyPointer

;Initliaze the enemies
initEnemies:
            LDX #00 ; offset of 0
            LDY #00 ; amount of enemies is 0
            LDA #01 ; the first one starts at 01, the other need to keep atleast 1 space inbetween so next is 03
            STA $00 ; keep this counter at memory address 00
            initLoop:
                     LDA $00 ; load into a the counter stored at address 00
                     STA EnemyArrayStart,X ; Load 00 into the first address
                     LDA #02 ; load 02
                     INX ; increment the offset
                     STA EnemyArrayStart,X ; load 02 into the higher order byte
                     INX ; increment the offset
                     INC $00 ; increment the counter twice
                     INC $00 ; increment the counter twice
                     INY ; increment amount of enemies initliazed
                     CPY AmountOfEnemiesAddress ; compare y with the amount of enemies variables
                     BNE initLoop; if not equal initliaze more enemies

loop:
jsr UnDrawShip
JSR undrawEnemies ; undraw the enemy

; check if the enemies need to be updated
INC currentTicksAddress ; increment the value in the current ticks address
LDA currentTicksAddress ; load into the a the current ticks
CMP delay ; compare it with the delay
BNE continueLoop ; if it is not equal to the delay then dont update

JSR resetTick
JSR decrementDelay
JSR updateEnemies ; update the enemies

continueLoop:
jsr readKeys
JSR drawEnemies ; color them
jsr drawShip
jsr clearKey ; otherwise the ship keeps moving
jsr bullet

jsr CheckCollision ; check collision
jsr whait
jmp loop

bullet:
jsr unDrawBullets
jsr updateBullet
jsr drawBullets
rts

drawShip:
  ldx #0
  lda #5
  ldy #0
  sta (ShipCenterL,x)
  sta (ShipGunL,x)
  sta (ShipLeftL,x)
  sta (ShipRightL,x)
  rts

  UnDrawShip:
  ldy #0
  ldx #0
  lda #0
  sta (ShipCenterL,x)
  sta (ShipGunL,x)
  sta (ShipLeftL,x)
  sta (ShipRightL,x)
  rts


drawBullets:
ldy #0
lda #1
ldx #00

jsr DrawFirstBullet
jsr DrawSecondBullet
jsr DrawThirdBullet
jsr DrawFouthBullet
jsr DrawFifthBullet
jsr DrawSixthBullet
jsr DrawSeventhBullet
jsr DrawEithBullet
rts

unDrawBullets:
ldy #0
lda #0
ldx #01 ;values need to be checked against 0 and 1

jsr DrawFirstBullet
jsr DrawSecondBullet
jsr DrawThirdBullet
jsr DrawFouthBullet
jsr DrawFifthBullet
jsr DrawSixthBullet
jsr DrawSeventhBullet
jsr DrawEithBullet
rts

resetTick:
LDA #00
STA currentTicksAddress ; reset the current ticks
RTS

readKeys:
  lda sysLastKey
  cmp #ASCII_w
  beq fire
  cmp #ASCII_d
  beq rightKey
  cmp #ASCII_a
  beq leftKey
  rts

  clearKey:
  lda #0
  sta sysLastKey
  rts


  leftKey:
  lda ShipLeftBound
  cmp ShipLeftL
  beq skip

  dec ShipCenterL
  dec ShipGunL
  dec ShipLeftL
  dec ShipRightL
  rts

  rightKey:
  lda ShipRightBound
  cmp ShipRightL
  beq skip

  inc ShipCenterL
  inc ShipGunL
  inc ShipLeftL
  inc ShipRightL
  rts

  fire:
  jsr findFirstEmptyBullet

  lda zero
  ldy zero
  cmp (currentBulletH),y
  bne skip

  lda ShipGunH
  sta (currentBulletH),y

  lda ShipGunL
  sec
  sbc #$20
  sta (currentBulletL),y

  RTS

updateBullet:
ldx #00
ldy #00
lda #BulletStart
sta currentBulletH
sta currentBulletL
dec currentBulletL
jmp updateBulletFirstOne

bulletupdateloop:
inx
cpx BulletNumber
beq skip

inc currentBulletH
inc currentBulletH
inc currentBulletL
inc currentBulletL

updateBulletFirstOne:
lda (currentBulletH),y
cmp zero
beq bulletupdateloop

lda (currentBulletL),y
sec
sbc #$20
sta (currentBulletL),y
bcc decBulletH
jmp bulletupdateloop
decBulletH:
lda (currentBulletH),y
sbc #00
CLC
sta (currentBulletH),y
jmp bulletupdateloop

skip:
rts

findFirstEmptyBullet:
lda #BulletStart
sta currentBulletH
ldy #0
lda (currentBulletH),y
cmp zero
beq bulletFound

ldx #00

CheckBulletLoop:
inx
cpx BulletNumber
beq skip

inc currentBulletH
inc currentBulletH
lda (currentBulletH),y
cmp zero
bne CheckBulletLoop

bulletFound:
ldy currentBulletH
dey
sty currentBulletL
rts


  ;drawing Bullets
 DrawFirstBullet:
 cmp $21
 beq skip
 cpx $21
 beq skip
 sta ($20),y
 rts
 DrawSecondBullet:
 cmp $23
 beq skip
 cpx $23
 beq skip
 sta ($22),y
 RTS
 DrawThirdBullet:
 cmp $25
 beq skip
 cpx $25
 beq skip
 sta ($24),y
 RTS
 DrawFouthBullet:
 cmp $27
 beq skip
 cpx $27
 beq skip
 sta ($26),y
 RTS
 DrawFifthBullet:
 cmp $29
 beq skip
 cpx $29
 beq skip
 sta ($28),y
 rts
 DrawSixthBullet:
 cmp $2B
 beq skip
 cpx $2B
 beq skip
 sta ($2A),y
 rts
 DrawSeventhBullet:
 cmp $2D
 beq skip
 cpx $2D
 beq skip
 sta ($2C),y
 rts
 DrawEithBullet:
 cmp $2F
 beq skip
 cpx $2F
 beq skip
 sta ($2E),y
 rts

undrawEnemies:
              LDA #00 ; load the color red
              LDX #00 ; address offset of 0
              LDY #00 ; amount of enemies is 0
              colorLoop:
                        STA (EnemyArrayStart, X) ; Load the colour red in 0200 -> which is stored in the enemyArrayStart
                        INX ; increment the offset twice to get the next enemy variable
                        INX ; increment the offset twice to get the next enemy variable
                        INY ; increment the amount of enemies
                        CPY AmountOfEnemiesAddress ; check if equal to the amount of enemies
                        BNE colorLoop ; if not loop over more enemies
              RTS ; return

drawEnemies:
              LDA #02 ; load the color red
              LDX #00 ; address offset of 0
              LDY #00 ; amount of enemies is 0
              colorLoop:
                        STA (EnemyArrayStart, X) ; Load the colour red in 0200 -> which is stored in the enemyArrayStart
                        INX ; increment the offset twice to get the next enemy variable
                        INX ; increment the offset wtwice to get the next enemy variable
                        INY ; increment the amount of enemies
                        CPY AmountOfEnemiesAddress ; check if equal to the amount of enemies
                        BNE colorLoop ; if not loop over more enemies
              RTS ; return

updateEnemies:
              LDX #00 ; address offset of 0
              STX shouldIncreaseMore ; store false into the should increase more boolean
              LDY #00 ; amount of enemies is 0
              updateLoop:
                         LDA EnemyArrayStart, X ; load the lower order byte
                         CLC ; clear carry flag
                         ADC #$20 ; add 20 to this value -> increasing line by 1
                         STA EnemyArrayStart, X ; store it back at the lower order byte
                         BCS increaseEnemyH ; go to another quadrant
                         INX ; increment the offset twice to get the next enemy variable
                         INX ; increment the offset twice to get the next enemy variable
                         INY ; increment the amount of enemies
                         CPY AmountOfEnemiesAddress ; check if equal to the amount of enemies
                         BNE updateLoop  ; if not loop over more enemies
              RTS ; return

increaseEnemyH:

               INX ; increase the offset by 1 to get the high order byte
               LDY EnemyArrayStart,X ; load the high order byte into Y
               CPY #05 ; compare y with 04
               BNE increase ; just increase the value if the "border" has not been hit yet
               jsr unDrawBullets
               JSR endGame
               increase:
               INC EnemyArrayStart,X ; increment the position -> goes down
               DEX ; decrement it to go back to the original X
               JSR increaseNextEnemyH ; increase the next enemy so it is synchronised
               RTS ; return

increaseNextEnemyH:
                   INX ; increase twice to go to the next enemy
                   INX ; increase twice to go to the next enemy
                   LDA EnemyArrayStart, X ; load the lower order byte
                   CLC ; clear carry flag
                   ADC #$20 ; add 20 to this value -> increasing line by 1
                   STA EnemyArrayStart, X ; store it back at the lower order byte
                   BCS increaseEnemyH ; go to another quadrant
                   DEX ; decrease twice to go to the original enemy
                   DEX ; decrease twice to go to the original enemy
                   RTS ; return
decrementDelay:
                lda #04 ;the minimum delay to no make it impossible
                CMP delay ; check if its the same
                beq continue ; if its already the minimum skip decremention
                dec delay ;decrement the delay
                RTS
RTS
CheckCollision:
ldx #00
ldy #00
lda #BulletStart
sta currentBulletH
sta currentBulletL
dec currentBulletL
jmp checkfirstBullet

checkbulletupdateloop:
inx
cpx BulletNumber
beq continue

inc currentBulletH
inc currentBulletH
inc currentBulletL
inc currentBulletL

checkfirstBullet:
lda (currentBulletH),y
cmp zero
beq checkbulletupdateloop

jsr checkenemyLoop
jmp checkbulletupdateloop



checkenemyLoop:
sty currentEnemyNumber ;reset it to 0
lda #EnemyArrayStart
sta currentEnemyL
sta currentEnemyH
inc currentEnemyH
jmp checkfirstenemy

checkenemyupdateloop:
inc currentEnemyNumber
lda currentEnemyNumber
cmp AmountOfEnemiesAddress
beq continue

inc currentEnemyH
inc currentEnemyH
inc currentEnemyL
inc currentEnemyL

checkfirstenemy:
lda (currentEnemyH),y
cmp zero
beq checkenemyupdateloop

jsr compareBulletAndEnemy
jmp checkenemyupdateloop


compareBulletAndEnemy:
; first compare the low order bytes
LDA (currentBulletL),y ; load the currentBulletL into A
CMP (currentEnemyL),y
BNE continue ; go back if not equal
; now compare high order bytes
LDA (currentBulletH),y ; load the currentBulletH into A
CMP (currentEnemyH),y
BNE continue ; go back if not equal
JSR deleteBulletAndEnemy
RTS
continue:
RTS ;return

deleteBulletAndEnemy:
jsr unDrawBullets
lda #00
sta (currentBulletH),y
lda #01
sta (currentEnemyH),y
inc score
RTS

whait:
  ldx #0
spinloop:
  dex
  bne spinloop
  rts

endGame:
lda #02
ldx #00
endGameLoop:
sta $0200,x
sta $0300,x
sta $0400,x
sta $0500,x
inx
cpx #$FF
beq end
jmp endGameLoop
end:
sta $0200,x
sta $0300,x
sta $0400,x
sta $0500,x
brk
