;;-----------------------------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
;;-------------------------------------------------------------------------------
.ClearNSprites
; clear enemy sprites, then calcs new addresses, move for this frame must be done before this
; is called
; clear sprites
; simply pop the 16 screen addresses for each sprite of current work screen and clear
; inactive sprites assumed to provide legal dummy to avoid checking
    ld (CNSprExit+1),sp ; preserve stack
    ld a,(WorkScr)
    bit 6,a
    jr nz,CNSprHighClear
; current buffer is low screen, point sp to low scr addr list and d to high byte of low scr lu table
    ld sp,ESprLowAddr
    ld d,LowScrLUTable/256
    jr CNSprSkipHigh
.CNSprHighClear
; current buffer is high screen, point sp to high scr addr list and d to high byte of high scr lu table
    ld sp,ESprHighAddr
    ld d,HighScrLUTable/256
.CNSprSkipHigh
; there are 9 enemy sprites and each enemy sprite is 4 bytes wide and 16 pixels high, with 16 addresses
; this loop is partially unrolled, containing 8 line clears for half a sprite, so there needs to be 2*9=18 iterations
    ld b,18 ; sprites x2, unrolled for half a sprite below
    xor a ; clear byte
.CNSprLoop
    pop hl ; get a screen address to clear
; clear next 4 bytes
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
; repeat
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
; repeat
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
; repeat
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
; repeat
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
; repeat
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
; repeat
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
; repeat
    pop hl
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    inc l
    ld (hl),a
    djnz CNSprLoop ; repeat
; sp now at top of appropriate screen address list for the current buffer
; so jump straight to calculating the new screen addresses for the sprites
; this means the sprite move needs to be done prior to the sprite clear
    ld a,d ; get the current lu table high byte
    exx
    ld h,a ; get lu table base page set into h'
    exx
    ld hl,EnemyYX+17 ; point hl to x co-ord of 'last' sprite
;
    ld iy,CalcEnemyReturn ; a subroutine is used to calc addresses, but cannot be called
                          ; so iy holds the return address
    ld bc,&90f ; there are 9 sprites, and each sprite addr calc starts at bottom, so add 15 to y co-ord
.CalcEnemySprLoop
    ld a,(hl) ; get x co-ord
; either valid (0-127) or 192
    and a,&7f
    srl a
    dec l
    ex af,af' ; preserve x
    ld a,(hl) ; get y co-ord
    add a,c ; c = offset for sprite height
    bit 0,a ; different routine for even or odd co-ords, which are optimised into pairs
; note if sprite on even line, then after adding 15 for height, will be odd, so jump to even on nz
    jr nz,GetEnemySpriteAddrEven
    jr GetEnemySpriteAddrOdd
.CalcEnemyReturn
    dec l ; get hl to point to x of next sprite
    djnz CalcEnemySprLoop ; repeat for all 9
; once sprite addr calculated determine if sprites display will be blocked by display of time bonus
    ld a,(TimeBonusDspTimer)
    or a
    jr z,CalcEnemySetSprDsp ; sprites to be displayed
; time bonus display text triggered, display that and skip sprite display
    call DisplayTimeBonus
    jr CNSprExit ; skip sprite display trigger
.CalcEnemySetSprDsp
; signal to interrupt handler that sprites ready to display with new addresses
    ld a,1
    ld (PrnEnemy),a

.CNSprExit
; restore stack and exit routine
    ld sp,0
    ret

.GetEnemySpriteAddrEven
; if sprite is on even lines, we need only read 8 pairs of screen addresses
; as each line above will one bit reset away from the line below
    exx
    ld l,a ; get hl pointing to addr lu table for line 15 of the sprite
    ex af,af' ; get sprite x offset back
    ld c,a ; preserve the x co-ord for use
    or a,(hl) ; add to base of low byte of this screen address
    ld e,a ; put low byte into e
    inc h ; point to high byte of scr addr
    ld d,(hl) ; and get into d
    push de ; write line 15 of the sprite to addr list for current buffer
    res 3,d ; change addr to point to line above
    push de ; write line 14 of the sprite to addr list for current buffer
;
    dec l ; skip addr for line 14 as already done
    dec l ; now pointing to line 13
    ld d,(hl) ; get high byte of scr addr to d
    dec h ; move lu table ptr to low byte of screen addr
    ld a,c ; get sprite x offset back to a
    or a,(hl) ; and add to low byte
    ld e,a ; put sum into e
    push de ; write line 13 of the sprite to addr list for current buffer 
    res 3,d ; change addr to point to line above
    push de ; write line 12 of the sprite to addr list for current buffer
; repeat the above process until all 16 screen addresses are calculated
    dec l
    dec l
    ld a,c
    or a,(hl)
    ld e,a
    inc h
    ld d,(hl)
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld d,(hl)
    dec h
    ld a,c
    or a,(hl)
    ld e,a
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld a,c
    or a,(hl)
    ld e,a
    inc h
    ld d,(hl)
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld d,(hl)
    dec h
    ld a,c
    or a,(hl)
    ld e,a
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld a,c
    or a,(hl)
    ld e,a
    inc h
    ld d,(hl)
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld d,(hl)
    dec h
    ld a,c
    or a,(hl)
    ld e,a
    push de
    res 3,d
    push de
;
    exx
;
    jp (iy) ; return to address previously stored in iy

.GetEnemySpriteAddrOdd
; if sprite is on odd lines, we need to read 7 pairs of screen addresses as above for even
; but there will also be 2 lu table reads for individual screen addresses
    exx
    ld l,a ; get hl pointing to addr lu table for line 15 of the sprite
    ex af,af' ; get sprite x offset back
    ld c,a ; preserve the x co-ord for use
    or a,(hl) ; add to base of low byte of this screen address
    ld e,a ; put low byte into e
    inc h ; point to high byte of scr addr
    ld d,(hl) ; and get into d
    push de ; write line 15 of the sprite to addr list for current buffer
; continue with sprite line address pairs as for the even routine above
    dec l
    ld d,(hl)
    dec h
    ld a,c
    or a,(hl)
    ld e,a
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld a,c
    or a,(hl)
    ld e,a
    inc h
    ld d,(hl)
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld d,(hl)
    dec h
    ld a,c
    or a,(hl)
    ld e,a
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld a,c
    or a,(hl)
    ld e,a
    inc h
    ld d,(hl)
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld d,(hl)
    dec h
    ld a,c
    or a,(hl)
    ld e,a
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld a,c
    or a,(hl)
    ld e,a
    inc h
    ld d,(hl)
    push de
    res 3,d
    push de
;
    dec l
    dec l
    ld d,(hl)
    dec h
    ld a,c
    or a,(hl)
    ld e,a
    push de
    res 3,d
    push de
; one more final address
    dec l
    dec l
    ld a,c
    or a,(hl)
    ld e,a
    inc h
    ld d,(hl)
    push de
    dec h ; was one extra address read, so need to set h back to pointing to low byte of scr addr lu table
;
    exx
;
    jp (iy) ; return to enemy sprite addr calc routine

.PrintEnemySprites
; called from interrupt so stack can be used to read screen addresses without corrupting them
; for subsequent clear
    ld (PrnESprExit+1),sp ; preserve stack
    ld a,(WorkScr)
    bit 6,a
    jr nz,EnemySprHighPrint
; printing to low screen buffer, set sp to low screen buffer addr list
    ld sp,ESprLowAddr
    jr PrnEnemySprSkipHigh
.EnemySprHighPrint
; printing to high screen buffer, set sp to high screen buffer addr list
    ld sp,ESprHighAddr
.PrnEnemySprSkipHigh
    ld hl,EnemyData2 ; points to sprite table containing frame part
; use res/set 6,l to get to yx table
    ld b,9 ; number of sprites
.PrnESprLoop
    ld a,(hl) ; get frame
    inc l
    res 6,l ; now pointing to x co-ord
    bit 0,(hl)
    jr z,PrnESprLeft
; print the right frame
    inc a ; right shifted sprite frames have sprite frame id 1 higher than left shifted
.PrnESprLeft
    add a,a ; double sprite frame id to calc sprite lu table entry
    exx
    ld h,BossFrameLU/256 ; put high byte of sprite frame lu table into h
    ld l,a ; table is page aligned, so put a stright into l to get entry for sprite frame
    ld e,(hl) ; get low byte of sprite frame address
    inc l ; point to high byte
    ld d,(hl) ; and get high byte of sprite frame address
    ex de,hl ; put sprite frame address into hl
    jp (hl) ; and jump to it - these are compiled sprites - see SpritesBossFrames8_reduced.asm
.EnemySpritePrintReturn ; each compiled sprite routine jumps back here
    exx
    set 6,l
    inc l ; hl now back to pointing to frame of next sprite
    djnz PrnESprLoop ; repeat for all 9 sprites
; restore stack and exit print routine
.PrnESprExit
    ld sp,0
    ret

