;;-----------------------------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
;;-------------------------------------------------------------------------------

; DA_FastSHot2 is trial of different colour, if not successful, use BH_FastShot2
; need to update move for actual pos every frame, as well as store last actual point on screen for clearing
; routine so when clearing buffered screen, all you do is clear from 'last' position from that screen
; meanwhile, active screen prints whole frame on first screen refresh, then updates trailing/leading
; ends in subsequent refreshes. the movement in actual pos is updated at the beginning of each display
; at the end of each partial print, it also writes current y to that frames 'last pos', will not
; occur on first frame as that is never the last, so helps balance cpu load
; checking y co-ordinate for being too low and ending move of laser only occurs on 17fps level during
; and not required to occur every refresh. note that the pop list of addressess will require
; some buffer behind as pop does not loop back to start of page, as is done with 8 bit dec with other
; address lookup routines

; clear under interupt so can use stack for retrieving addresses
.ClearFastShot
; before this called, interupt pre-loads c with 0, then exx instruction issued
    ld (ClrFSExit+1),sp ; preserve stack pointer so can use it to read screen addresses
    ld a,(WorkScr)
    bit 6,a
    jr nz,ClrFSHighScr
    ld de,FastShotYXLow ; list of last positions on low screen
    ld c,LowScrLUTableLinear/256
    jr ClrFSSkipHigh
.ClrFSHighScr
    ld de,FastShotYXHigh ; list of last positions on high screen
    ld c,HighScrLUTableLinear/256
.ClrFSSkipHigh
    ld b,8
ClrFSLp
    ld a,(de) ; get y for this laser
    inc e ; point to x
    add a,a
    ld l,a
    ld a,0 ; zero a while preserving carry
    adc a,c ; calculate high byte of screen address for clearing bullet, as these tables are two pages long
    ld h,a ; hl now points to top of screen addr lu table for current enemy laser sprite
    ld sp,hl ; load into the sp for reading below
    ld a,(de) ; get x for this laser
    sra a ; halve it to get byte address
    exx
    ld b,a ; preserve x byte co-ord
    pop hl ; get addr from lu table, is left side of screen
    or a,l ; mask in x co-ord
    ld l,a ; put addr with x co-ord offset into hl
    ld (hl),c ; clear that scr addr
    pop hl ; repeat
    ld a,b ; restore x co-ord to a
    or a,l
    ld l,a
    ld (hl),c
    pop hl
    ld a,b
    or a,l
    ld l,a
    ld (hl),c
    pop hl
    ld a,b
    or a,l
    ld l,a
    ld (hl),c
    exx
    inc e ; point to y of next laser shot
    djnz ClrFSLp ; repeat for all 8 lasers, whether on screen or not
.ClrFSExit
    ld sp,0 ; restore sp from value stored at start of this routine
    ret

.PrintFastShot
; first check if first or subsequent screen refresh of current game frame
; first frame will check for and create new fast laser shot if required
; then for each on screen laser, it will move down and print entire shot, left or right bit
; as required
; in subsequent frames will clear top pixel, move down one, write new bottom pixel, and write
; current y back to current y table for high/low screen for next clear.  x coord needs to
; written in to all three tables on creation of fast shot

;; note: no sub pixel element required for fast shot coords as it moves a straight single pixel
;; down each screen refresh

    ld (PrnFSExit+1),sp
    exx
    ld a,(WorkScr)
    bit 6,a
    jr z,PrnFSHighScr ; inverted to normal check - if work scr is low, need to update high screen, as this works on visible screen
    ld bc,LowScrLUTableLinear
    ld de,FastShotYXLow ; only used on subsequent refreshes
    jr PrnFSSkipHigh
.PrnFSHighScr
    ld bc,HighScrLUTableLinear
    ld de,FastShotYXHigh ; only used on subsequent refreshes
.PrnFSSkipHigh
    exx

    ld a,(int_1_game_FrameCtr+1) ; get screen refresh counter to see if first refresh of current frame
    or a
    jp nz,PrnFSSubsequentRefresh ; is not first screen refresh of current frame
; is first screen refresh of current game frame
; first check if a new fast laser shot required to be created
    ld hl,FastShotYX
    ld a,(NewFastShotY)
    or a ; check new shot trigger, if non zero contains y of new shot
    jr z,PrnFSFirstNoNewShot
    ld b,8 ; check the 8 fast shot slots for free space to store shot details
    ld c,a ; save y value
    xor a
.FindNewFSLp
    cp a,(hl)
    jr z,FoundNewFS
    inc l
    inc l
    djnz FindNewFSLp
; no slot free for new fast shot, clear trigger and continue with current ones
    jr PrnFSFirstClearNewShotTrigger
.FoundNewFS
; found new fast shot slot, write in y
    ld (hl),c ; y in current pos table
    inc l
    ld a,(NewFastShotX) ; get the x of the new shot
    ld c,a ; preserve x co-ord
    ld (hl),c ; write x to current pos table
    ld a,&10
    add a,l
    ld l,a
    ld (hl),c ; write x to low scr pos table
    ld a,&10
    add a,l
    ld l,a
    ld (hl),c ; write x to high scr pos table
.PrnFSFirstClearNewShotTrigger
; clear new shot trigger so not created in subsequent frames
    xor a
    ld (NewFastShotY),a
; new shot writen to table if required, now continue with display update of first refresh of fast shots
.PrnFSFirstNoNewShot
; second part of first refresh, write every pixel of active fast shots
    ld de,FastShotYX
    ld b,8 ; number of possible lasers in play
.PrnFSFirstLp
    ld a,(de) ; get y
    or a
    jr z,PrnFSFirstSkip ; if y=0 then bullet inactive, dont display or move
    inc a
    ld (de),a ; store updated y in current y pos table
    exx
    ld h,c ; scr addr table is page aligned, so c=0
    ld l,a
    add hl,hl
    add hl,bc
    ld sp,hl ; sp now points to base screen addr for top of this fast laser shot
    exx
    inc e ; point to x
    ld a,(de) ; get x
    sra a
    ld c,a ; preserve x co-ord for ading to each of the screen addresses
    jr c,PrnFSFirstRight ; 
; print fast shot first refresh on left of byte of screen memory
    pop hl ; get screen address from lu table, left side of screen
    or a,l
    ld l,a ; masked in the x co-ord so hl now points to screen addr for first/top screen byte of laser
    ld a,(hl)
    or a,34 ; or in the laser graphic bits
    ld (hl),a ; and write back to screen
; unrolled loop, repeat for next 3 pixels of the laser
    pop hl
    ld a,c
    or a,l
    ld l,a
    ld a,(hl)
    or a,34
    ld (hl),a
; third byte
    pop hl
    ld a,c
    or a,l
    ld l,a
    ld a,(hl)
    or a,34
    ld (hl),a
; fourth byte
    pop hl
    ld a,c
    or a,l
    ld l,a
    ld a,(hl)
    or a,34
    ld (hl),a
.PrnFSFirstSkipReturn
    inc e ; point to next fast laser y
    djnz PrnFSFirstLp
.PrnFSExit
    ld sp,0 ; restore sp to previous location, saved at beginning of routine
    ret
.PrnFSFirstSkip ; if skipping bullet, need to progress pointer to fast laser table
    inc e ; point to x
    jr PrnFSFirstSkipReturn
.PrnFSFirstRight
; print fast shot first refresh on left of byte of screen memory
    pop hl ; get screen address from lu table, left side of screen
    or a,l
    ld l,a ; masked in the x co-ord so hl now points to screen addr for first/top screen byte of laser
    ld a,(hl)
    or a,17 ; or in the laser graphic bits
    ld (hl),a ; and write back to screen
; unrolled loop, repeat for next 3 pixels of the laser
    pop hl
    ld a,c
    or a,l
    ld l,a
    ld a,(hl)
    or a,17
    ld (hl),a
; third byte
    pop hl
    ld a,c
    or a,l
    ld l,a
    ld a,(hl)
    or a,17
    ld (hl),a
; fourth byte
    pop hl
    ld a,c
    or a,l
    ld l,a
    ld a,(hl)
    or a,17
    ld (hl),a
    inc e ; point to next bullet y
    djnz PrnFSFirstLp
    jr PrnFSExit ; if finished last fast laser shot, go to common exit to restore sp

.PrnFSSubsequentRefresh
; is subsequent screen refresh of current game frame
    ld de,FastShotYX
    ld b,8
.PrnFSSubsequentLp
    ld a,(de) ; get current y
    or a
    jr z,PrnFSSubsSkip ; if y=0 then bullet inactive, dont display or move
    inc a ; move laser down one pixel
    ld (de),a ; and write back to co-ord table
    exx
    ld (de),a ; write to table used by clearfastprint, so if this is the last update, it clears from
              ; the correct position
    inc e
    inc e ; now pointed to y co-ord of next fast shot entry for next iteration
    ld h,c ; scr addr table is page aligned, so c=0
    ld l,a
    dec l ; want to clear the pixel above the new top position
    add hl,hl ; two bytes to each addr
    add hl,bc ; ad base of current lookup table
    ld sp,hl ; sp now points to base screen addr for top of this fast shot
    exx
    inc e ; point to x co-ord
    ld a,(de) ; get x
    sra a ; need to halve the x co-ord to get byte co-ord, and find if it is the left or right pixel
    ld c,a ; put x byte offset into c
    jr c,PrnFSSubsRight ; if carry, then is pixel in right of byte
; print fast shot subsequent refresh on left of byte of screen memory
    pop hl ; get the address for left of screen of previous top pixel
    or a,l ; add the x byte offset
    ld l,a ; hl now contains scr addr of top byte
    ld a,(hl) ; get byte
    and a,&dd ; mask out the fast laser bits
    ld (hl),a ; and write back
; skip the next 3 lines
    pop hl
    pop hl
    pop hl
; and now get address for the new bottom pixel
    pop hl
    ld a,c ; get the x byte offset
    or a,l ; and combine
    ld l,a ; to get scr addr for new lowest pixel for the fast shot
    ld a,(hl) ; get the byte
    or a,34 ; mask in the new laser bits
    ld (hl),a ; and write back
.PrnFSSubsSkipReturn
    inc e ; point to next bullet y
    djnz PrnFSSubsequentLp
    jr PrnFSExit
.PrnFSSubsSkip
; skipping, so move pointers along
    inc e ; point to x co-ord for this fast shot
    exx
; now pointing to table used by clearfastshot to increment pointer to that table
    inc e ; skip x, it never changes
    inc e ; point to next y of table used by clearfastshot
    exx
    jr PrnFSSubsSkipReturn
.PrnFSSubsRight
; print fast shot subsequent refresh on right of byte of screen memory
; this is identical to above code for left byte, except the mask bits differ
    pop hl
    or a,l
    ld l,a
    ld a,(hl)
    and a,&ee
    ld (hl),a
    pop hl
    pop hl
    pop hl
    pop hl
    ld a,c
    or a,l
    ld l,a
    ld a,(hl)
    or a,17
    ld (hl),a
    inc e ; point to next bullet y
    djnz PrnFSSubsequentLp
    jr PrnFSExit
