;##################################################################
;
;   Allecto-Z80 (Enemy firing)
;
;   Programmed by Patrick Davidson (pad@calc.org)
;        
;   This program is in the public domain.  There is no warranty.
;
;   This file was last updated March 31, 2001.
;
;##################################################################     

;############## Deploy cash bonus (HL -> enemy Y coordinate)

bonus_data:
        .db     6
        .db     0
        .db     5
        .db     7

deploy_bonus:
        ld      de,bonus_data
        jr      fire_enemy_bullet
        ret

;############## Fire standard enemy bullet (HL -> enemy Y coordinate)

big_ebullet_data:
        .db     3
        .db     2
        .db     3
        .db     3

huge_ebullet_data:
        .db     3
        .db     2
        .db     5
        .db     5

standard_ebullet_data:
        .db     3           ; Type
        .db     1           ; Power
        .db     2           ; Width
        .db     2           ; Height

left_ebullet_data:
        .db     9           ; Type
        .db     1           ; Power
        .db     2           ; Width
        .db     2           ; Height

right_ebullet_data:
        .db     12          ; Type
        .db     1           ; Power
        .db     2           ; Width
        .db     2           ; Height

half_left_ebullet_data:
        .db     15          ; Type
        .db     1           ; Power
        .db     2           ; Width
        .db     2           ; Height

half_right_ebullet_data:
        .db     18          ; Type
        .db     1           ; Power
        .db     2           ; Width
        .db     2           ; Height

arrow_ebullet_data:
        .db     21
        .db     1
        .db     3
        .db     7

;############## Fire a large, fully-aimed bullet (HL -> X)

fire_big_bullet:
        inc     hl
        inc     hl
        ld      a,(player_y)
        sub     (hl)
        ret     c
        srl     a
        srl     a
        ld      b,a                     ; B = (PY - EY)
        srl     a
        add     a,b
        ret     z
        ld      b,a                     ; B = (3/8) * (PY - EY)
        dec     hl
        dec     hl
        ld      a,(player_x)
        sub     (hl)                    ; A = PX - EX
        inc     hl
        inc     hl
        jr      c,fire_big_left
        call    get_angle
        ld      a,c
        
deploy_big:
        ld      bc,(which_shot)
        bit     7,c
        jr      nz,deploy_huge
        add     a,27
        ld      de,big_ebullet_data
        ld      (de),a
        jr      fire_enemy_bullet

deploy_huge:
        add     a,36
        ld      de,huge_ebullet_data
        ld      (de),a
        jr      fire_enemy_bullet

fire_big_left:
        neg
        call    get_angle
        ld      a,c
        neg
        jr      deploy_big

get_angle:
        ld      c,0
        sub     b
        ret     c                       ; DX < (3/8) DY -> straight down
        inc     c
        sub     b
        ret     c                       ; DX < (3/4) DY -> slight angle
        inc     c
        sub     b
        ret     c                       ; DX < (3/2) DY -> 45 deg angle
        sub     b
        ret     c
        inc     c                       ; DX > (3/2) DY -> high angle
        ret

;############## Standard firing routines

normal_enemy_shoot:
        ld      a,(which_shot)
        rrca
        jr      nc,fire_enemy_bullet_std
        ld      de,arrow_ebullet_data
        jr      fire_enemy_bullet

fire_enemy_bullet_std:
        ld      de,standard_ebullet_data

;############## Fire any type of bullet (HL -> Y coordinate, DE -> info)

fire_enemy_bullet:

        push    hl
        push    de

        call    locate_enemy_bullet    ; HL -> enemy bullet entry

        pop     de                      ; DE -> bullet description
        pop     bc                      ; BC -> enemy Y coordinate
        ex      de,hl                   ; HL -> bullet description
                                        ; DE -> enemy bullet entry

        ldi                             ; Copy type, BC -> enemy width
        ldi                             ; Copy power, BC -> enemy X
        ld      a,(bc)
        add     a,2
        ld      (de),a                  ; Store ebullet X
        inc     de
        ldi                             ; Copy width, BC -> enemy X - 1
        inc     bc
        inc     bc
        inc     bc                      ; BC -> enemy Y
        ld      a,(bc)
        add     a,7
        ld      (de),a                  ; Store ebullet Y
        inc     de
        ldi                             ; Copy height
        ret

;############## Fire an aimed bullet (HL -> X coordinate)

fire_aimed_bullet:
        ld      a,(player_x)
        add     a,30
        cp      (hl)                    ; PlayerX + 30 - ShootX
        jr      c,fire_bullet_left      ; If ShootX > PlayerX + 30
        sub     60                      ; PlayerX - 30
        jr      c,fire_bullet_std       ; If PlayerX < 30
        cp      (hl)                    ; PlayerX - 30 - ShootX
        jr      nc,fire_bullet_right    ; If ShootX <= PlayerX - 30
fire_bullet_std:
        inc     hl
        inc     hl
        ld      de,standard_ebullet_data
        jr      fire_enemy_bullet

fire_bullet_left:
        inc     hl
        inc     hl
        ld      de,left_ebullet_data
        jr      fire_enemy_bullet

fire_bullet_right:
        inc     hl
        inc     hl
        ld      de,right_ebullet_data
        jr      fire_enemy_bullet

fire_bullet_half_left:
        ld      de,half_left_ebullet_data
        jr      fire_enemy_bullet

fire_bullet_half_right:
        ld      de,half_right_ebullet_data
        jr      fire_enemy_bullet

;############## Locate an unused enemy bullet

locate_enemy_bullet:
        ld      hl,eb_array
        ld      b,eb_num
        ld      de,eb_size
loop_locate_eb:
        ld      a,(hl)
        or      a
        ret     z
        add     hl,de
        djnz    loop_locate_eb
        pop     hl
        pop     de
        pop     hl
        ret
