;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of Dragon Attack - An entry for CPCRetroDev2016
;;  Copyright (C) 2016  Paul Kooistra
;;
;;  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/>.
;;
;;  For questions about the source you can PM me, Axelay, on the CPCWiki forums
;;-------------------------------------------------------------------------------
.ClearNBullets
; simply pop the 256 screen addresses for every bullet of current work screen and clear
; any inactive bullets assumed to provide legal dummy to avoid need for checking address is valid
    ld (CNBExit+1),sp ; preserve stack, wont need addresses in this list anymore, so dont worry about interrupts
    ld a,(WorkScr)
    bit 6,a
    jr nz,CNBHighClear
    ld sp,EBLowAddr ; buffer is low screen, so point sp to that list
    jr CNBSkipHigh
.CNBHighClear
    ld sp,EBHighAddr ; buffer is high screen, so point sp to that list
.CNBSkipHigh
; first clear the 4 shrapnel rings/balls
    ld b,4
    xor a
.ClrSRLoop
; these are 6 lines high and 3 pixels wide, so that's 6 pops to fetch addresses
; then two writes to clear the 3 pixels, whether the rings are left or right pixel shifted
; does not matter
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    djnz ClrSRLoop
; now clear the main bullets
    ld b,32
.CNBLoop
; each bullet requires 2 pops and 2 writes, but the loop has been unrolled to speed it up
; as djnz would add significantly to the execution time if executed for each bullet
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    pop hl
    ld (hl),a
    djnz CNBLoop
.CNBExit
; restore stack pointer
    ld sp,0
    ret

.PrintBullets
    ld (PNBExit+1),sp
    ld a,(WorkScr)
    bit 6,a
    jr nz,PNBHighPrint
; current buffer is low screen
    ld sp,EBLowAddr+&400+&30 ; extra for rings
    exx
    ld h,LowScrLUTable/256 ; high byte of lookup table for low screen (&8000)
    jr PNBSkipHigh
.PNBHighPrint
; current buffer is high screen
    ld sp,EBHighAddr+&400+&30 ; extra for rings
    exx
    ld h,HighScrLUTable/256 ; high byte of lookup table for high screen (&c000)
.PNBSkipHigh
    exx
; no counter required as will be done when l=0 (256)
    ld hl,EBY ; point to y co-ordinate, sub pixel co-ord not required
.PNBLoop
    ld a,(hl) ; get y
    inc h ; point to x
    exx
    ld l,a    ; use it to point to low byte of screen address in lu table
    ld e,(hl)
    inc h
    ld d,(hl) ; base address in de
    exx
    ld a,(hl) ; get x co-ord of bullet
    exx
    ex de,hl ; get screen addr into hl, addr lu into de
    srl a ; x = 0-127, halved as 64 bytes, bit 0 determines pixel position in byte
    jr c,PNBRight1 ; now print the bullet right pixel shifted
; Print first enemy bullet left pixel shifted
    ld c,a ; preserve the x component
    or a,l
    ld l,a ; hl now holds address
    set 1,(hl) ; write in bit for left shifted pixel
    push hl ; push address to list
    inc e ; move to next address line below for second pixel of bullet
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c ; add x offset to low byte of screen addr
    ld l,a ; hl now holds second address of bullet
    set 1,(hl) ; write in bit for left shifted pixel
    push hl ; push second address to list
    ex de,hl ; get lu table back in hl
    exx ; go back to pointer to bullet co-ords
; now do second bullet
; the loop does two bullets at a time so the pointer the the x&y co-ordinates, which are
; spread over two pages, does not waste time reading y,x,y,x with additional incs or decs
; instead, each pair of co-ordinates is read y,x then x,y
    inc l ; set hl to point to y co-ord for next bullet
    ld a,(hl) ; get x because already pointing to it
    ex af,af' ; save for later
    dec h
    ld a,(hl) ; get the y co-ord
    exx
;;;;;;
    ld l,a    ; use it to point to low byte of screen address in lu table
    ld e,(hl)
    inc h
    ld d,(hl) ; base address in de
    ex de,hl ; get screen addr into hl
    ex af,af' ; get back the x co-ord
    srl a ; x = 0-127, halved as 64 bytes, bit 0 determines pixel position in byte
    jr c,PNBRight2
.PNBLeft2
; Print second enemy bullet left, identical to first left pixel print
    ld c,a
    or a,l
    ld l,a
    set 1,(hl)
    push hl
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    set 1,(hl)
    push hl
    ex de,hl
    exx
    inc l ; set hl to point to y co-ord for next bullet
    jr nz,PNBLoop ; if l=0 then have done all 256 bullets
    jr PrnNBMainDone ; jump to print bullet rings next
.PNBRight1
; Print first enemy bullet right
; identical to left shifted print, except that set 0 used intead of set 1 for print
    ld c,a
    or a,l
    ld l,a
    set 0,(hl)
    push hl
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    set 0,(hl)
    push hl
    ex de,hl
    exx
; now do second bullet
    inc l ; set hl to point to y co-ord for next bullet
    ld a,(hl) ; get x because already pointing to it
    ex af,af' ; save for later
    dec h
    ld a,(hl) ; get the y co-ord
    exx
;;;;;;
    ld l,a    ; use it to point to low byte of screen address in lu table
    ld e,(hl)
    inc h
    ld d,(hl) ; base address in de
    ex de,hl ; get screen addr into hl
    ex af,af' ; get back the x co-ord
    srl a ; x = 0-127, halved as 64 bytes, bit 0 determines pixel position in byte
    jr nc,PNBLeft2
.PNBRight2
; Print second enemy bullet right
; identical to right shifted print above, see comments in left shifted print for reason
; why there are duplicated prints
    ld c,a
    or a,l
    ld l,a
    set 0,(hl)
    push hl
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    set 0,(hl)
    push hl
    ex de,hl
    exx
    inc l ; set hl to point to y co-ord for next bullet
    jr nz,PNBLoop ; if l=0 then have done all 256 bullets
.PrnNBMainDone
; main 256 bullets have been printed
; now do shrapnel rings -24 addresses, 48 bytes of stack space for 4 rings
    ld hl,EBRingYX+1 ; point to y co-ordinate, sub pixel co-ord not required
    ld b,4
.PNBRingLoop
    ld a,(hl) ; get y
    inc l ; skip sub pixel offset
    inc l ; point to x
    exx
    ld l,a    ; use it to point to low byte of screen address in lu table
    ld e,(hl)
    inc h
    ld d,(hl) ; base address in de
    exx
    ld a,(hl) ; get x co-ord of ring
    exx
    ex de,hl ; get screen addr into hl
    srl a ; x = 0-127, halved as 64 bytes, bit 0 determines pixel position in byte
    jp c,PNBRingRight
; Print enemy bullet ring left pixel shifted
    ld c,a
    or a,l
    ld l,a
    push hl ; address calculated so store
; and then print while we have the address
    ld a,(hl)
    or a,5 ; rings are black, requiring 2 bits
    ld (hl),a
; second line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c ; add x offset to low byte of new address
    ld l,a
    push hl
    ld (hl),15
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
; before continuing, determine type as it might be a hollow ring or solid ball
; so next two pixel lines will differ on type
    exx
    set 4,l
    ld a,(hl) ; get type indicator for ring/ball - is angle of shots for ball, unused for ring
    res 4,l
    exx
    or a
    jr nz,PNBRingLeftFilled
; is hollow ring
; third line
    inc e
    ld a,(de)
    or a,c
    ld l,a
    inc d
    ld a,(de)
    ld h,a
    push hl
    ld a,(hl)
    or a,10
    ld (hl),a
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
; fourth line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    push hl
    ld a,(hl)
    or a,10
    ld (hl),a
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
    jr PNBRingLeftCommon
.PNBRingLeftFilled
; is filled ring, or ball type
; third line
    inc e
    ld a,(de)
    or a,c
    ld l,a
    inc d
    ld a,(de)
    ld h,a
    push hl
    ld (hl),15
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
; fourth line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    push hl
    ld (hl),15
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
.PNBRingLeftCommon
; fifth line - both ball and ring are identical on last two lines, as they were for the first two
    inc e
    ld a,(de)
    or a,c
    ld l,a
    inc d
    ld a,(de)
    ld h,a
    push hl
    ld (hl),15
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
; sixth line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    push hl
    ld a,(hl)
    or a,5
    ld (hl),a
; done
    ex de,hl ; put lu table ptr back into hl
    exx ; go back to ring co-ord list
; now do next bullet ring
    inc l ; skip sub pixel offset
    inc l ; set hl to point to y co-ord for next ring
    dec b
    jp nz,PNBRingLoop
.PNBExit
; restore stack and return
    ld sp,0
    ret

.PNBRingRight
; Print enemy bullet ring right
; this routine is identical to the left shifted ring routine above
; except that the print data masked in (or a,??) is for right shifted rings/balls
    ld c,a ; preserve x
    or a,l ; add low address to x offset to get first screen address for this ring
    ld l,a
    push hl ; push first address to list with stack
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
; second line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    push hl
    ld a,(hl)
    or a,5
    ld (hl),a
    inc l
    ld (hl),15
; before continuing, determine type
    exx
    set 4,l
    ld a,(hl)
    res 4,l
    exx
    or a
    jr nz,PNBRingRightFilled
; is hollow ring
; third line
    inc e
    ld a,(de)
    or a,c
    ld l,a
    inc d
    ld a,(de)
    ld h,a
    push hl
    ld a,(hl)
    or a,5
    ld (hl),a
    inc l
    ld a,(hl)
    or a,5
    ld (hl),a
; fourth line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    push hl
    ld a,(hl)
    or a,5
    ld (hl),a
    inc l
    ld a,(hl)
    or a,5
    ld (hl),a
    jr PNBRingRightCommon
.PNBRingRightFilled
; is filled ring
; third line
    inc e
    ld a,(de)
    or a,c
    ld l,a
    inc d
    ld a,(de)
    ld h,a
    push hl
    ld a,(hl)
    or a,5
    ld (hl),a
    inc l
    ld (hl),15
; fourth line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    push hl
    ld a,(hl)
    or a,5
    ld (hl),a
    inc l
    ld (hl),15
.PNBRingRightCommon
; fifth line
    inc e
    ld a,(de)
    or a,c
    ld l,a
    inc d
    ld a,(de)
    ld h,a
    push hl
    ld a,(hl)
    or a,5
    ld (hl),a
    inc l
    ld (hl),15
; sixth line
    inc e
    ld a,(de)
    ld h,a
    dec d
    ld a,(de)
    or a,c
    ld l,a
    push hl
    inc l
    ld a,(hl)
    or a,10
    ld (hl),a
; done
    ex de,hl
    exx
; now do next bullet ring
    inc l
    inc l ; set hl to point to y co-ord for next bullet
    dec b
    jp nz,PNBRingLoop
    jp PNBExit ; have finished so go to common exit to restore sp