;##################################################################
;
;   Allecto-Z80 (Enemies)
;
;   Programmed by Patrick Davidson (pad@calc.org)
;        
;   This program is in the public domain.  There is no warranty.
;
;   This file was last updated February 10, 2001.
;
;##################################################################     

;############## Enemy routines
;
; Calls the code specified by the enemy 'type'.  The 'type', which must
; be a multiple of 3, is an index into the table of jumps for enemy code.
; Enemy routines should move the enemy and draw its image.  They are
; called with HL pointing to the enemy entry, and can change all registers.

enemies:
        xor     a                       ;Reset list of used swoop patterns
        ld      (misc_flags),a          ;(used to prevent multiple entries
                                        ;of the same pattern in one frame)
        dec     a                       ;Set enemy-processing flag (used by
        ld      (doing_enemies),a       ;code handling both enemies and
                                        ;something else to tell which it is
                                        ;being called for) 
        ld      hl,e_array
        ld      b,e_num
loop_enemies:
        ld      a,(hl)
        ld      (do_enemy+1),a
        push    hl
        push    bc
        call    do_enemy
        pop     bc
        pop     hl
        ld      de,e_size
        add     hl,de
        djnz    loop_enemies
        ret

        jp      exploding_enemy        ; This is offset -5

do_enemy:
        jr      point_to_enemy_code
point_to_enemy_code:

;############## Enemy routine table starts here

no_enemy:
        ld      (hl),0
        ret
        jp      standard_enemy         ;3
        jp      figure_eight           ;6
        jp      figure_eight_waiting   ;9
        jp      standard_boss          ;12
        jp      bounce_enemy           ;15
        jp      advanced_boss          ;18
        jp      spinner                ;21
        jp      spinner_rampage        ;24
        jp      super_boss             ;27
        jp      operator_wait          ;30
        jp      operator_main          ;33
        jp      swooping_enemy_wait    ;36
        jp      swoop_down             ;39
        jp      swoop_horiz            ;42
        jp      swoop_up               ;45

;############## Swooping horizontally
;
; e_phase holds X velocity
; e_timer holds X coordinate of destinatin

swoop_horiz:
        call    swoop_draw
        inc     hl                      ;HL -> e_phase
        ld      a,(hl)                  ;A = X velocity
        inc     hl
        inc     hl                      ;HL -> X coordinate
        add     a,(hl)
        ld      (hl),a                  ;Update X coordinate
        dec     hl
        cp      (hl)                    ;Compare X coordinate to destinatio
        ret     nz
        dec     hl
        dec     hl
        ld      (hl),45
        ret

;############## Swooping enemy going up

swoop_up:
        call    swoop_draw
        ld      de,e_y
        add     hl,de
        dec     (hl)
        ret     nz
        inc     hl
        ld      (hl),0
        ld      de,-e_h
        add     hl,de
        ld      (hl),36
        ret

;############## Swooping down
;
; e_phase holds Y coordinate of destination of this movement
; e_phase will hold X velocity for the horizontal movement
; e_timer holds X coordinate of destination of horizontal movement

swoop_down:
        call    swoop_draw              ;Handle display
        ld      de,e_y
        push    hl
        add     hl,de                   ;HL -> e_y
        inc     (hl)                    ;Increment Y coordinate
        ld      a,(hl)                  ;Load Y coordinate into A
        pop     hl                      ;HL -> e_type
        inc     hl                      ;HL -> e_phase
        cp      (hl)                    ;Compare to destination coordinate
        ret     nz                      ;Exit if not there      
        inc     hl
        ld      a,(hl)                  ;A = X destination
        dec     hl
        ld      (hl),2                  ;Initially set X velocity to 1
        bit     6,a                     ;Check if X destination >= 64
        jr      nz,swoop_not_left       ;If so, not going lef
        ld      (hl),-2                 ;If going left, change XV to -1
swoop_not_left:
        dec     hl
        ld      (hl),42                 ;Set type to horizontal movement
        ret 

;############## Draw swooping enemy at any point and handle firing
;
; called with HL -> e_y
; returns with HL unchanged

swoop_draw:
        push    hl
        inc     hl
        inc     hl
        inc     hl                      ;HL -> X coordinate
        ld      d,(hl)                  ;D = X coordinate

        call    FAST_RANDOM            ;randomly decide whether to fire
        and     %11011011
        jr      nz,swoop_no_shoot

        inc     (hl)                    ;temporarily increase X coord to
        inc     (hl)                    ;fire from right position
        push    de
        push    hl
        call    fire_big_bullet
        pop     hl
        pop     de
        dec     (hl)
        dec     (hl)

swoop_no_shoot:
        inc     hl
        inc     hl                      ;HL -> Y coordinate
        ld      e,(hl)                  ;E = Y coordinate

        ld      a,(game_timer)          ;Choose image based on timer
        rrca
        jr      c,swoop_stage2

swoop_stage1:
        ld      hl,swoop_l_stage1
        push    de
        call    drw_spr
        pop     de
        ld      a,8
        add     a,d
        ld      d,a
        ld      hl,swoop_r_stage1
        call    drw_spr
        pop     hl
        ret

swoop_stage2:
        ld      hl,swoop_l_stage2
        push    de
        call    drw_spr
        pop     de
        ld      a,8
        add     a,d
        ld      d,a
        ld      hl,swoop_r_stage2
        call    drw_spr
        pop     hl
        ret

;############## Swooping enemy waiting to enter

swooping_enemy_wait:
        ld      a,(game_timer)
        and     15
        ret     nz
        call    FAST_RANDOM            ;Choose pattern (0 - 3)
        and     3
        add     a,a
        add     a,a
        ld      (smc_hl_storage+1),hl
        ld      hl,swoop_data
        call    ADD_HL_A                ;HL -> pattern data
        ld      de,misc_flags           ;DE -> flags of which patterns used
        ld      a,(de)
        and     (hl)                    ;Check flag; if already set, exit
        ret     nz                      ;since this pattern already entered
        ld      a,(de)                  
        or      (hl)
        ld      (de),a                  ;set the flag

smc_hl_storage:
        ld      de,0                    ;DE -> enemy data
        ld      a,39
        ld      (de),a                  ;set type to swooping down
        inc     hl                      ;HL -> entry
        inc     de                      ;DE -> enemy info byte 1
        ldi                             ;copy Y destination
        ldi                             ;copy X destination
        ldi                             ;copy X entry
        ldi
        ex      de,hl                   ;HL -> e_w
        ld      (hl),11                 ;width = 11
        inc     hl
        ld      (hl),2                  ;Y = 2
        inc     hl
        ld      (hl),8                  ;height = 8
        ret

;############## Swooping enemy data
;
; Flag bit mask, Y destination, X destination, X entry

swoop_data:                     
        .db     1,59,102,14
        .db     2,50,30,90
        .db     4,41,78,42
        .db     8,32,54,66

;############## Operator main code

operator_main:
        call    rampage_move
        push    hl
        ld      hl,(is_operator)
        call    drw_spr
        pop     hl
        jp      semi_aim_shoot_nodraw

;############## Operating waiting

operator_wait:
        ld      (hl),33
        inc     hl
        ld      (hl),1
        inc     hl
        ld      (hl),1
        inc     hl
        call    FAST_RANDOM
        and     63
        add     a,28
        ld      (hl),a
        inc     hl
        ld      (hl),8
        inc     hl
        call    FAST_RANDOM
        and     15
        ld      (hl),a
        inc     hl
        ld      (hl),8
        inc     hl
        ld      (hl),40
        ret

;############## Super-boss

sboss_shoot:
        ld      a,13
        add     a,(hl)
        ld      (hl),a
        push    hl
        call    fire_big_bullet
        pop     hl
        ld      a,-13
        add     a,(hl)
        ld      (hl),a
        push    hl
        call    fire_big_bullet
        pop     hl
        jr      sboss_shot

super_boss:
        call    boss_move
        ld      a,(game_timer)
        and     %111111
        jr      z,sboss_shoot
sboss_shot:
        ld      d,(hl)
        inc     hl
        inc     hl
        ld      e,(hl)
        push    de
        ld      hl,(is_boss3l)
        call    drw_spr
        pop     de
        ld      a,9
        add     a,d
        ld      d,a
        ld      hl,(is_boss3r)
        jp      drw_spr

;############## Rampaging spinning enemy

spinner_rampage:
        call    rampage_move
        inc     hl
        inc     hl
        inc     hl                      ; HL -> e_img
        call    spinner_image
        dec     hl
        dec     hl
        dec     hl                      ; HL -> e_y
        jp      semi_aim_shoot_nodraw

;############## Rampaging movement

rampage_move:
        inc     hl
        ld      b,(hl)                  ; E = XV
        inc     hl
        ld      c,(hl)                  ; D = YV
        inc     hl
        ld      a,(hl)
        add     a,b                     ; A = new X
        ld      (hl),a
        ld      d,a                     ; D = new X
        cp      16
        jr      c,rampage_right
        cp      40
        jr      z,rampage_choosex
        cp      71
        jr      z,rampage_choosex
        cp      93
        jr      z,rampage_choosex
        cp      105
        jr      nc,rampage_left
rampage_xdone:
        inc     hl
        inc     hl                      ; HL -> e_y
        ld      a,(hl)
        add     a,c                     ; A = new Y
        ld      (hl),a
        ld      e,a                     ; E = new X
        cp      41
        jr      c,rampage_down
        cp      51
        jr      z,rampage_choosey
        cp      59
        jr      nc,rampage_up
rampage_ydone:
        push    hl
        dec     hl
        dec     hl
        dec     hl                      ; HL -> YV
        ld      (hl),c
        dec     hl                      ; HL -> VV
        ld      (hl),b
        pop     hl                      ; HL -> e_y
        ret

rampage_choosex:
        call    FAST_RANDOM
        rrca
        jr      c,rampage_left
rampage_right:
        ld      b,1
        jr      rampage_xdone
rampage_left:
        ld      b,-1
        jr      rampage_xdone

rampage_choosey:
        call    FAST_RANDOM
        rrca
        jr      c,rampage_up
rampage_down:
        ld      c,1
        jr      rampage_ydone
rampage_up:
        ld      c,-1
        jr      rampage_ydone

;############## Spinning enemy

spinner:
        ld      a,(enemies_left)
        cp      9
        jr      nc,no_rampage
        ld      (hl),24
        inc     hl
        ld      (hl),1
        inc     hl
        ld      (hl),1
        dec     hl
        dec     hl
        jr      spinner_rampage

no_rampage:
        inc     hl                      ; HL -> e_phase
        ld      a,(hl)
        ld      (which_phase+1),a
        inc     hl                      ; HL -> e_timer
        inc     (hl)
        ld      a,(hl)
        rrca
        jr      nc,no_move_enemy_s
        cp      $88
        jr      nz,not_s_phase_end

        ld      (hl),0
        dec     hl                      ; HL -> e_phase
        ld      a,(hl)
        inc     a
        inc     a
        inc     a
        inc     a
        and     12
        ld      (hl),a
        inc     hl                      ; HL -> e_timer
not_s_phase_end:
        inc     hl                      ; HL -> e_x
        push    hl
        call    which_phase

spinner_final:
        ld      e,(hl)                  ; E = e_y
        pop     bc                      ; BC -> e_x
        ld      a,(bc)
        ld      d,a                     ; D = x coord
        inc     hl
        inc     hl
        inc     hl                      ; E -> e_img
        call    spinner_image
        dec     hl
        dec     hl
        dec     hl

        call    FAST_RANDOM
        and     %01110110
        ret     nz
        jp      semi_aim_shoot_now
        
no_move_enemy_s:
        inc     hl                      ; HL -> e_x
        push    hl
        inc     hl
        inc     hl
        jr      spinner_final

spinner_image:
        push    hl
        call    LD_HL_MHL               ; HL = e_img
        push    hl
        call    drw_spr
        pop     hl                      ; HL = e_img
        ld      de,10
        add     hl,de                   ; HL -> next image
        ld      a,(hl)                  ; Test for end of list
        inc     a
        jr      nz,spinner_image_ok
        ld      de,-40
        add     hl,de                   ; Go back to start of list
spinner_image_ok:
        ex      de,hl
        pop     hl                      ; HL -> img
        ld      a,(game_timer)
        rrca
        ret     c
        ld      (hl),e
        inc     hl                      ; HL -> e_img + 1
        ld      (hl),d                  
        dec     hl                      ; HL -> e_img
        ret
                                        
;############## Advanced boss

aboss_shoot:
        ld      a,11
        add     a,(hl)
        ld      (hl),a
        push    hl
        call    fire_big_bullet
        pop     hl
        ld      a,-11
        add     a,(hl)
        ld      (hl),a
        push    hl
        call    fire_big_bullet
        pop     hl
        jr      aboss_shot

advanced_boss:
        call    boss_move
        ld      a,(game_timer)
        and     %111111
        jr      z,aboss_shoot
aboss_shot:
        ld      d,(hl)
        inc     hl
        inc     hl
        ld      e,(hl)
        push    de
        ld      hl,(is_boss2l)
        call    drw_spr
        pop     de
        ld      a,8
        add     a,d
        ld      d,a
        ld      hl,(is_boss2r)
        jp      drw_spr

;############## Boss

boss_shoot:
        ld      a,14
        add     a,(hl)
        ld      (hl),a
        push    hl
        call    fire_aimed_bullet
        pop     hl
        ld      a,-14
        add     a,(hl)
        ld      (hl),a
        push    hl
        call    fire_aimed_bullet
        pop     hl
        jr      boss_shot

standard_boss:
        call    boss_move
        ld      a,(game_timer)
        and     %111111
        jr      z,boss_shoot
boss_shot:
        ld      d,(hl)
        inc     hl
        inc     hl
        ld      e,(hl)
        push    de
        ld      hl,(is_boss1l)
        call    drw_spr
        pop     de
        ld      a,8
        add     a,d
        ld      d,a
        ld      hl,(is_boss1r)
        jp      drw_spr

boss_move:
        inc     hl
        ld      a,(hl)
        or      a
        jr      z,boss_descending

        inc     hl
        dec     (hl)
        jr      nz,boss_no_reverse
        neg
        dec     hl
        ld      (hl),a
        inc     hl
        ld      (hl),90
boss_no_reverse:
        inc     hl
        add     a,(hl)
        ld      (hl),a
        ret

boss_descending:
        inc     hl
        dec     (hl)
        jr      nz,not_entered
        dec     hl
        ld      (hl),-1
        inc     hl
        ld      (hl),83
not_entered:
        inc     hl
        inc     hl
        inc     hl
        inc     (hl)
        dec     hl
        dec     hl
        ret

;############## Figure-eight waiting code

figure_eight_waiting:
        inc     hl
        dec     (hl)
        ret     nz
        dec     hl
        ld      (hl),6
        inc     hl
        ld      (hl),32
        inc     hl
        ld      (hl),0
        inc     hl
        ld      a,(level)
        cp      SPLIT_LEVEL
        jr      nz,nosplit
        bit     0,b
        jr      nz,nosplit
        ld      (hl),72
        jr      f8split
nosplit:
        ld      (hl),16
f8split:
        inc     hl
        ld      (hl),8
        inc     hl
        ld      (hl),24
        inc     hl
        ld      (hl),8
        inc     hl
        ld      (hl),13
        inc     hl
        ld      bc,3
        jp      OTH_CLEAR

;############## Figure-eight enemy code

figure_eight:
        inc     hl
        ld      a,(hl)                  ; hl -> e_phase (holds timer info)
        or      a
        jr      z,next_phase
        dec     (hl)
        inc     hl                      ; hl -> e_timer (holds phase info)
        jr      figure_phase

next_phase:
        inc     hl
        inc     (hl)
        ld      a,(hl)
restart_phase:
        ld      b,a
        add     a,a
        add     a,b
        ex      de,hl                   ; de -> e_timer
        dec     a
        ld      hl,(pattern)
        call    ADD_HL_A
        ld      a,(hl)
        or      a
        jr      z,restart_pattern
        dec     de                      ; de -> e_phase
        ld      (de),a
        inc     de                      ; de -> e_timer
        inc     hl                      ; hl -> phase direction data
        jr      phase_located

restart_pattern:
        ex      de,hl
        inc     a
        ld      (hl),a
        jr      restart_phase

figure_phase:
        ld      a,(hl)
        ld      b,a
        add     a,a
        add     a,b
        ex      de,hl                   ; de -> e_timer
        ld      hl,(pattern)
        call    ADD_HL_A               ; hl -> phase direction data

phase_located:
        ex      de,hl                   ; de -> direction data, hl -> e_timer
        ld      bc,8
        add     hl,bc                   ; hl -> e_data
        ld      a,(de)
        add     a,(hl)
        ld      b,a
        and     15
        ld      (hl),a
        ld      a,b
        sra     a
        sra     a
        sra     a
        sra     a
        ld      bc,-7
        add     hl,bc                   ; hl -> e_x
        add     a,(hl)
        ld      (hl),a

        inc     de
        ld      bc,8
        add     hl,bc                   ; hl -> e_data
        ld      a,(de)
        add     a,(hl)
        ld      b,a
        and     15
        ld      (hl),a
        ld      a,b
        sra     a
        sra     a
        sra     a
        sra     a
        ld      bc,-6
        add     hl,bc                   ; hl -> e_y
        add     a,(hl)
        ld      (hl),a

        ld      e,a
        push    hl
        dec     hl
        dec     hl
        ld      d,(hl)
        ld      hl,(is_enemy3)
semi_aim_shoot:
        call    drw_spr
        pop     hl

semi_aim_shoot_nodraw:
        call    FAST_RANDOM
        and     %01111110
        ret     nz

semi_aim_shoot_now:
        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,figurefireleft
        cp      b
        jp      c,fire_enemy_bullet_std
        jp      fire_bullet_half_right

figurefireleft:
        neg
        cp      b
        jp      c,fire_enemy_bullet_std
        jp      fire_bullet_half_left

;############## Standard enemy code

standard_enemy:
        inc     hl                      ; HL -> e_phase

        ld      a,(swing_type)
        or      a

        ld      a,(hl)
        jr      z,not_galaxian
        inc     hl
        bit     7,(hl)
        dec     hl
        jr      nz,not_galaxian
        or      4
not_galaxian:
     
        ld      (which_phase+1),a
        inc     hl                      ; HL -> e_timer
        inc     (hl)
        ld      a,(hl)
        rrca
        jr      nc,no_move_enemy
        cp      $88
        jr      nz,not_phase_end

        ld      (hl),0
        dec     hl                      ; HL -> e_phase
        ld      a,(hl)
        add     a,4
        and     12
        ld      (hl),a
        inc     hl                      ; HL -> e_timer
not_phase_end:
        inc     hl                      ; HL -> e_x
        push    hl
        call    which_phase

enemy_display:
        ld      e,(hl)                  ; E = e_y
        inc     hl
        inc     hl
        inc     hl                      ; E -> e_img
        call    LD_HL_MHL               ; HL = e_img
        pop     bc
        ld      a,(bc)
        ld      d,a
        jp      drw_spr

no_move_enemy:
        inc     hl                      ; HL -> e_x
        push    hl
        inc     hl
        inc     hl
        call    FAST_RANDOM
        and     %01111110
        push    hl
        call    z,normal_enemy_shoot
        pop     hl
        jr      enemy_display

which_phase:
        jr      phase1
phase0: inc     hl
        inc     hl
        inc     (hl)
        ret
phase1: inc     (hl)
        inc     hl
        inc     hl
        ret
phase2: inc     hl
        inc     hl
        dec     (hl)
        ret
phase3: dec     (hl)
        inc     hl
        inc     hl
        ret

;############## Exploding enemy

exploding_enemy:
        push    hl
        inc     hl
        ld      a,(game_timer)
        rrca
        jr      c,no_next_step
        inc     (hl)

no_next_step:
        ld      b,(hl)
        inc     hl
        inc     hl                      ; HL -> e_x     
        ld      d,(hl)                  ; D = X
        inc     hl
        inc     hl                      ; HL -> e_y
        ld      e,(hl)                  ; E = Y
        inc     hl
        inc     hl                      ; HL -> e_pwr

        ld      a,(doing_enemies)
        or      a
        jr      z,no_protect

        ld      (hl),100                ; Don't let explosion be killed

no_protect:
        ld      hl,image_explosion
        ld      a,b
        add     a,a
        add     a,a
        add     a,a
        call    ADD_HL_A                ; HL -> explosion image

        ld      a,(hl)
        inc     a
        jr      z,end_of_explosion      ; -1 -> end of list

        pop     bc                      ; Restore X, Y
        jp      drw_spr

end_of_explosion:
        pop     hl
        ld      (hl),a

        ld      a,(doing_enemies)
        or      a
        ret     z

        push    hl
        ld      hl,enemies_left
        dec     (hl)
        pop     hl

        call    FAST_RANDOM
        and     %01011000
        ret     nz

        ld      de,e_y
        add     hl,de                   ; HL -> e_y
        jp      deploy_bonus

;############## Bouncing enemies

bounce_enemy:
        inc     hl
        ld      c,(hl)                  ;C = YV (bit 1 - right, bit 0 - fast)
        inc     hl
        ld      b,(hl)                  ;B = XV (bit 1 - down, bit 0 - fast)
        inc     hl

        ld      a,(game_timer)
        or      b
        rrca
        jr      nc,bounce_nox
        bit     1,b
        jr      z,bounce_left
bounce_right:
        inc     (hl)
        ld      a,107
        cp      (hl)
        jr      nz,bounce_nox
        dec     hl
        call    FAST_RANDOM
        and     1
        ld      (hl),a
        inc     hl
        jr      bounce_nox
bounce_left:
        dec     (hl)
        ld      a,13
        cp      (hl)
        jr      nz,bounce_nox
        dec     hl
        call    FAST_RANDOM
        and     1
        or      2
        ld      (hl),a
        inc     hl
bounce_nox:

        ld      d,(hl)
        inc     hl
        inc     hl

        ld      a,(game_timer)
        or      c
        rrca
        jr      nc,bounce_noy
        bit     1,c
        jr      z,bounce_up
bounce_down:
        inc     (hl)
        ld      a,60
        cp      (hl)
        jr      nz,bounce_noy
        push    hl
        ld      bc,-4
        add     hl,bc
        call    FAST_RANDOM
        and     1
        ld      (hl),a
        pop     hl
        jr      bounce_noy
bounce_up:
        dec     (hl)
        ld      a,31
        cp      (hl)
        jr      nz,bounce_noy
        push    hl
        ld      bc,-4
        add     hl,bc
        call    FAST_RANDOM
        and     1
        or      2
        ld      (hl),a
        pop     hl
bounce_noy:

        ld      e,(hl)
        push    hl
        ld      hl,(is_bounce)
        jp      semi_aim_shoot
