;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of The Last Fungus: An Amstrad CPC Game 
;;  Copyright (C) 2021 Miguel Perez Tarruella / Antonio Jose Fernandez Belliure / 
;;                     David Martinez Garcia / Ocacho Games (@OcachoGames)
;;
;;  This program is free software: you can redistribute it and/or modify
;;  it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
;;
;;  You should have received a copy of the GNU Lesser General Public License
;;  along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;------------------------------------------------------------------------------

;;====================================================================
;; GLOBL INCLUDES
;;====================================================================
.include "cpctelera.h.s"
.include "sys/ai.h.s"

;;Managers
.include "man/entity.h.s"
.include "man/game.h.s"
.include "man/patrol.h.s"

;;Resources
.include "resources/templates.h.s"

;;Global includes
.include "global/global.h.s"

;;Macros
.include "macros/math.h.s"


;;====================================================================
;; PRIVATE ENTITY CLASS VARIABLES
;;====================================================================
m_function_given_ai:                .dw #0x0000 ;;Memory direction of the function that we want to execute      
m_bullet_is_stopped:                .db 0   ;;Flag to know if the bullet is stopped or not
m_ai_shoot_cadence_ghost_easy::     .db 0   ;;Number of times that have to pass so the ghost_easy can shoot
m_ai_shoot_cadence_ghost::          .db 0   ;;Number of times that have to pass so the  ghost to shoot
m_ai_shoot_cadence_walker_easy::    .db 0   ;;Number of times that have to pass so the  walker_easy to shoot
m_ai_shoot_cadence_walker::         .db 0   ;;Number of times that have to pass so the  walker to shoot

;;====================================================================
;; AI INIT
;;====================================================================
sys_ai_init::
    SET_VARIABLE_VALUE m_ai_shoot_cadence_ghost_easy, shoot_cadence_ghost_easy_initial
    SET_VARIABLE_VALUE m_ai_shoot_cadence_ghost, shoot_cadence_ghost_easy_initial
    SET_VARIABLE_VALUE m_ai_shoot_cadence_walker_easy, shoot_cadence_walker_easy
    SET_VARIABLE_VALUE m_ai_shoot_cadence_walker, shoot_cadence_ghost_easy_initial

    ret

;;====================================================================
;; AI MOVEMENT FUNCTIONS 
;;====================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to stop moving or doing anything
;; Objetive: Set the velocity to 0 and other things to set the enemy to stand_by
;; Modifies: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_stand_by::

    ld e_vel_x(ix), #0
    ld e_vel_y(ix), #0
    
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;; Objetive: Set the velocity to know if the enemy has to move left or right
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_move_to_x:
    ;;Check the X pos
    ld a, e_move_to_pos_x(ix)           ;; A = move_to_x
    sub e_pos_x(ix)                     ;; A = move_to_x - pos_x
    jr nc, move_to_x_grater_or_equal    ;; if(move_to_x - pos_x > 0)

    move_to_x_lower:
        ld e_vel_x(ix), #mov_speed_left
        ld e_facing_right(ix), #-1
        ret

    move_to_x_grater_or_equal:
        jr z, arrived_x
        ld e_vel_x(ix), #mov_speed_right
        ld e_facing_right(ix), #1
        ret
    arrived_x:
        ld e_vel_x(ix), #0

    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;; Objetive: Set the velocity to know if the enemy has to move up or down
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_move_to_y:
    
    ;;Check the Y pos
    ld a, e_move_to_pos_y(ix)           ;; A = move_to_y
    sub e_pos_y(ix)                     ;; A = move_to_y - pos_y
    jr nc, move_to_y_grater_or_equal    ;; if(move_to_y - pos_y > 0)

    move_to_y_lower:
        ld e_vel_y(ix), #mov_speed_up
        ret

    move_to_y_grater_or_equal:
        jr z, arrived_y
        ld e_vel_y(ix), #mov_speed_down
        ret
    arrived_y:
        ld e_vel_y(ix), #0

    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;;  - IY: should contain the entity's memory direction of the player

;; Objetive: Set the facing_right property depending on where the player is in X
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_look_at_x:
    ;;Check if the player is on enemy's right or left side
    ld a, e_pos_x(iy)                   ;; A = move_to_x
    sub e_pos_x(ix)                     ;; A = move_to_x - pos_x
    jr nc, look_to_x_grater_or_equal    ;; if(move_to_x - pos_x > 0)

    look_to_x_lower:
        ld e_facing_right(ix), #-1
        ret

    look_to_x_grater_or_equal:
        ld e_facing_right(ix), #1
    
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify

;; Objetive: Check if the enemy has arrived to its move_to_pos_x
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;====================================================================
;; PATROL MOVEMENTS
;;====================================================================

sys_ai_arrived_move_to_pos_x:
    ;;Check the coordinates to change step
    ld a, e_pos_x(ix)
    cp e_move_to_pos_x(ix)
    jr z, in_the_move_to_pos_x

        ;;Not in the move_to_pos_x
        call sys_ai_move_to_x
        ret

    ;; The enemy is in the position to change step
    in_the_move_to_pos_x:
        ld e_vel_x(ix), #0
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify

;; Objetive: Check if the enemy has arrived to its move_to_pos_y
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_arrived_move_to_pos_y:
    ;;Check the coordinates to change step
    ld a, e_pos_y(ix)
    cp e_move_to_pos_y(ix)
    jr z, in_the_move_to_pos_y

        ;;Not in the move_to_pos
        call sys_ai_move_to_y
        ret

    ;; The enemy is in the position to to change step
    in_the_move_to_pos_y:
        ld e_vel_y(ix), #0
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify

;; Objetive: Check if the enemy has arrived to its move_to_pos
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_arrived_move_to_pos_ghost:
    call sys_ai_arrived_move_to_pos_x
    call sys_ai_arrived_move_to_pos_y
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;; Objetive: Change the move_to_pos x by using the patrol coordinates
;; Modifies: A, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_patrol_walker:
    ;;hl points to the patrol step
    call man_entity_load_patrol_ref

    ;;Check if x != -1
    ld a, (hl)                  ;;a = X
    cp #patrol_invalid_move_x
    jr z, reset_walker_patrol
    ;;Check if x != 0
    cp #patrol_jump_move
    jr z, make_enemy_jump

    ;;Set the move_to_pos_x
    ld e_move_to_pos_x(ix), a
    jr change_patrol_step_ref
    
    ;;Enemy has arrived to a jump point
    make_enemy_jump:
    call sys_ai_jump

    change_patrol_step_ref:
    ;;Set new e_ai_patrol_step
    call man_entity_increment_patrol_step
    ret

    reset_walker_patrol:
        call man_entity_reset_patrol
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;; Objetive: Change the move_to_pos x and y by using the patrol coordinates
;; Modifies: A, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_patrol_ghost:
    ;;hl points to the patrol step
    call man_entity_load_patrol_ref

    ;;Check if x != -1
    ld a, (hl)                  ;;a = X
    cp #patrol_invalid_move_x
    jr z, reset_ghost_patrol

    ;;Set the new move_to_pos_x and y
    ld e_move_to_pos_x(ix), a
    inc hl                      ;;Point to Y
    ld a, (hl)                  ;;a = Y
    ld e_move_to_pos_y(ix), a

    ;;Set e_ai_patrol_step + 2 (he have a previous inc)
    call man_entity_increment_patrol_step
    ret

    reset_ghost_patrol:
        call man_entity_reset_patrol
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the enemy's memory direction
;;  - IY: should contain the player's memory direction
;; Objetive: Change the move_to_pos x and y by using the patrol coordinates
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_ghost_seek_player::
    ld a, e_pos_y(iy)
    ld e_move_to_pos_y(ix), a
    ret

;;====================================================================
;; AI MECHANICS
;;====================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the enemy's memory direction 
;; Objetive: Make the enemy jumps
;; Modifies: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_jump:
    ld a, e_is_grounded(ix)
	IS_EQUALS 1
	ret nz

	;;If it's grounded
    ld a, (#jump_force)
	ld e_vel_y(ix), a
	ld e_is_grounded(ix), #0
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;; Objetive: Check if the enemy is in the same Y as the player an if it has bullet, then shoot
;; Modifies: DE, IX, IY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_shoot_player:
    push iy ;;Save player memory direction

    ld de, #bullet_tmpl
    call man_game_create_template_bullet

    pop iy ;;Get player memory direction
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set its intelligence
;; Objetive: Call the enemy's bullet behaviour
;; Modifies: IX, BC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_control_bullet:
    push ix ;;Save enemy memory direction
    
    ld c, e_bullet_ref_b1(ix)
    ld b, e_bullet_ref_b2(ix)

    ld  a, (bc)		;;Is the type of the bullet invalid
	cp #e_type_invalid
    jr nz, enemy_has_valid_bullet
    pop ix
    ret
    enemy_has_valid_bullet:
    ld__ix_bc
    call sys_ai_behaviour_enemy_bullet

    pop ix ;;Get enemy memory direction
    ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set its intelligence
;;  - IY: Should contain the player's memory direction
;; Objetive: Make that the enmy can skip the bullet by jumping
;; Modifies: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_skip_bullet:
    ld  c, e_bullet_ref_b1(iy)
	ld 	b, e_bullet_ref_b2(iy)

    ld__iy_bc

    ;;Check if the enemy is looking to the bullet
    ld a, e_facing_right(ix)    ;;Get bullet facing_right
    cp e_facing_right(iy)       ;;Compare with bullet facing_right
    ret z

    ld b, e_pos_x(iy)   ;;Get bullet pos_x
    ld a, e_pos_x(ix)   ;;Get enemy pos_x
    sub b               ;; A = enemy_pos_x - bullet_pos_x
    jr c, bullet_on_the_right

    ;;bullet_on_the_left
    sub #safe_skip_distance
    jr c, check_y_bullet
    ret

    bullet_on_the_right:
    ld a, e_pos_x(iy)   ;;Get bullet pos_x
    ld b, e_pos_x(ix)   ;;Get enemy pos_x
    sub b               ;; A = bullet_pos_x - enemy_pos_x
    sub #safe_skip_distance
    jr c, check_y_bullet
    ret

    check_y_bullet:
    ld a, e_pos_y(iy)   ;;Get bullet y
    sub #7
    cp e_pos_y(ix)
    call z, sys_ai_jump
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set its intelligence
;;  - B: should contain the X coord of the platform
;;  - C: should contain the Y coord of the platform
;; Objetive: Make that the enmy can jump in platforms
;; Modifies: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_jump_platform::
    ;;Jump condition if the enemy is on the big platform
    ld a, e_pos_y(ix)
    cp b
    ret nz

    ;;Jump condition if its in the midle of the platform
    ld a, e_pos_x(ix)
    cp c
    ret nz

    call sys_ai_jump
    ret

;;====================================================================
;; ENEMIES' BEHAVIOURS
;;====================================================================

.macro SYS_AI_COMMON_WALKER_BEHAVIOUR _wlakerType
    ;;Skip bullet
    push iy
    call sys_ai_skip_bullet
    pop iy
    
   ;;Check if the enemy is in the same Y as the player
    ld a, e_pos_y(iy)
    sub e_pos_y(ix)
    jr nz, not_same_y_'_wlakerType'

    ;;Check if the '_wlakerType' cadence is 0 to shoot
    ld a, (#m_ai_shoot_cadence_'_wlakerType')
    IS_EQUALS 0
    jr nz, cadence_shoot_'_wlakerType'_not_0

    ;;Check where is the player and look at him
    call sys_ai_look_at_x
    call sys_ai_shoot_player

    ;;Decrement the cadence of the '_wlakerType'
    ld a, #0
    SET_VARIABLE_VALUE m_ai_shoot_cadence_'_wlakerType', shoot_cadence_'_wlakerType'
    jr not_same_y_'_wlakerType'

    ;;Enemy cannot shoot yet because cadence is not 0
    cadence_shoot_'_wlakerType'_not_0:
    dec a
    ld (#m_ai_shoot_cadence_'_wlakerType'), a

    not_same_y_'_wlakerType':
    ;;5.- Decdie what to do with the bullet
    call sys_ai_control_bullet

    ;;Check if it has arrived to its move_to_pos_x
    ld a, e_vel_x(ix)
    or a
    ret nz
.endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set its intelligence
;;  - IY: should contain the player's memory direction (set in forall_matching)
;; Objetive: Execute the behaviour of the ai of the enemy. This will control de AI intelligence
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_behaviour_enemy_walker::
    ;;Charge on iy the player memeory direction
    ld iy, #m_entities
    
    ;;walker_hard_behaviour
    ld a, (#m_bullet_is_stopped)
    ld b, #1 ;;Bullet is stopped
    cp b
    jr z, bullet_stopped_not_move_walker
    
    ;;Check if the enemy has arrived to its move_to_pos
    call sys_ai_arrived_move_to_pos_x

    ;;Make the enemy jump in platforms
    ld b, #138
    ld c, #45
    call sys_ai_jump_platform

    ld b, #138
    ld c, #31
    call sys_ai_jump_platform

    ld b, #138
    ld c, #49
    call sys_ai_jump_platform

    ld b, #138
    ld c, #35
    call sys_ai_jump_platform

    bullet_stopped_not_move_walker:
    SYS_AI_COMMON_WALKER_BEHAVIOUR walker
    
    ld a, (#m_bullet_is_stopped)
    ld b, #1 ;;Bullet is stopped
    cp b
    ret z
    
    ;;Change the move_to_pos with the patrol
    call sys_ai_patrol_walker
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set its intelligence
;;  - IY: should contain the player's memory direction (set in forall_matching)
;; Objetive: Execute the behaviour of the ai of the enemy. This will control de AI intelligence
;; Modifies: AF, BC, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_behaviour_enemy_walker_easy::
    ;;Charge on iy the player memeory direction
    ld iy, #m_entities

    ;;Check if the walker_easy has bullet reference to know if he can move or not
    ld  c, e_bullet_ref_b1(ix)
	ld 	b, e_bullet_ref_b2(ix)

    ld  a, b		;;Is the bullet reference null
	cp #00
	jr z, walker_easy_has_no_bullet

	ld  a, (bc)		;;Is the type of the bullet invalid
	cp #e_type_invalid
    jr nz, walker_easy_has_bullet

    walker_easy_has_no_bullet:
    call sys_ai_arrived_move_to_pos_x

    ;;Make the enemy jump in platforms
    ld b, #142
    ld c, #32
    call sys_ai_jump_platform

    ;;Make the enemy jump in platforms
    ld b, #142
    ld c, #38
    call sys_ai_jump_platform

    ;;Make the enemy jump in platforms
    ld b, #142
    ld c, #26
    call sys_ai_jump_platform
    
    SYS_AI_COMMON_WALKER_BEHAVIOUR walker_easy

    ;;Change the move_to_pos with the patrol
    call sys_ai_patrol_walker
    ret

    walker_easy_has_bullet:
    ld e_vel_x(ix), #0
    call sys_ai_look_at_x
    call sys_ai_control_bullet

    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; maCRO FOR COMMON GHOST BEHAVIOUR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.macro SYS_AI_COMMON_GHOST_BEHAVIOUR _ghostType
    ;;Shoot player if it is in the same Y as the player
    ld a, e_pos_y(iy)
    cp e_pos_y(ix)
    jr nz, not_same_y_'_ghostType'

    ;;Check if the '_ghostType' cadence is 0 to shoot
    ld a, (#m_ai_shoot_cadence_'_ghostType')
    IS_EQUALS 0
    jr nz, cadence_shoot_'_ghostType'_not_0

    ;;Check where is the player and look at him
    call sys_ai_look_at_x
    call sys_ai_shoot_player

    ;;Decrement the cadence of the ghost
    ld a, #0
    SET_VARIABLE_VALUE m_ai_shoot_cadence_'_ghostType', shoot_cadence_'_ghostType'
    jr not_same_y_'_ghostType'

    ;;Enemy cannot shoot yet because cadence is not 0
    cadence_shoot_'_ghostType'_not_0:
    dec a
    ld (#m_ai_shoot_cadence_'_ghostType'), a

    not_same_y_'_ghostType':
    ;;Decdie what to do with the bullet
    call sys_ai_control_bullet
.endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set its intelligence
;;  - IY: should contain the player's memory direction (set in forall_matching)
;; Objetive: Execute the behaviour of the ai of the ghost enemy. This will control de AI intelligence
;; Modifies: AF, BC, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_behaviour_enemy_ghost_easy::
    ld iy, #m_entities
    ;;1.- Set AI behaviour to nothing.
    call sys_ai_stand_by

    ;;Check if the walker_easy has bullet reference to know if he can move or not
    ld  c, e_bullet_ref_b1(ix)
	ld 	b, e_bullet_ref_b2(ix)

    ld  a, b		;;Is the bullet reference null
	cp #00
	jr z, ghost_easy_has_no_bullet

	ld  a, (bc)		;;Is the type of the bullet invalid
	cp #e_type_invalid
    jr nz, ghost_easy_has_bullet

    ghost_easy_has_no_bullet:
    call sys_ai_arrived_move_to_pos_ghost

    SYS_AI_COMMON_GHOST_BEHAVIOUR ghost_easy
     
    ;; 6.- If the enemy is on its move_to_pos, vel_x and vel_y are 0, change patrol step
    ld a, e_vel_x(ix)
    or a
    ret nz
    ld a, e_vel_y(ix)
    or a
    ret nz
    
    ;;7.- Change the move_to_pos with the patrol rutine
    call sys_ai_patrol_ghost
    ret

    ghost_easy_has_bullet:
    ld e_vel_x(ix), #0
    call sys_ai_look_at_x
    call sys_ai_control_bullet

    ret

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set its intelligence
;;  - IY: should contain the player's memory direction (set in forall_matching)
;; Objetive: Execute the behaviour of the ai of the ghost enemy. This will control de AI intelligence
;; Modifies: AF, BC, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_behaviour_enemy_ghost::
    ld iy, #m_entities
    ;;1.- Set AI behaviour to nothing
    call sys_ai_stand_by

    ;;Check if the bullet is stopped
    ld a, (#m_bullet_is_stopped)
    ld b, #1 ;;Bullet is stopped
    cp b
    jr z, bullet_stopped_not_move_ghost

    ;;Check if the enemy has arrived to its move_to_pos
    call sys_ai_arrived_move_to_pos_ghost

    bullet_stopped_not_move_ghost:

    SYS_AI_COMMON_GHOST_BEHAVIOUR ghost

    ;;Seek for the player y_pos
    call sys_ai_ghost_seek_player
    
    ;;continue_normal_patrol:
    ;; 6.- If the enemy is on its move_to_pos, vel_x and vel_y are 0, change patrol step
    ;;If the bullet is stopped, do not call update the patrol
    ;;ld a, (#m_bullet_is_stopped)
    ;,ld b, #1 ;;Bullet is stopped
    ;;cp b
    ;;ret z

    ;;Check if the enemy has arrive to its move_to_pos_x
    ld a, e_vel_x(ix)
    or a
    ret nz

    call sys_ai_patrol_walker
    ret

;;====================================================================
;; BULLET FUNCTIONS 
;;====================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the bulelt's memory direction we want to modify
;; Objetive: Increase the velocity of the bullet
;; Modifies: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_increase_bullet_velocity:
    ld 	a, e_facing_right(ix)
	
	IS_EQUALS -1
	jr z, enemy_bullet_facing_left_increase

	;;bullet_facing_right
	ld a, e_vel_x(ix)
	INCREMENT_REGISTER_1_BYTE a, 1

	IS_HIGHER 3
	jr c, enemy_bullet_vel_can_increase

	ret
	enemy_bullet_facing_left_increase:

	ld a, e_vel_x(ix)
	DECREMENT_REGISTER_1_BYTE a, 1

	IS_EQUALS -3
	ret z
	enemy_bullet_vel_can_increase:

	ld e_vel_x(ix), a
    ;;Activate flag to say that the bullet is not stopped
    ld a, #0
    ld (#m_bullet_is_stopped), a
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the bulelt's memory direction we want to modify
;; Objetive: Decrease the velocity of the bullet
;; Modifies: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_decrease_bullet_velocity:

	ld e_vel_x(ix), #0
    ;;Activate flag to say that the bullet is not stopped
    ld a, #1
    ld (#m_bullet_is_stopped), a
    ret

;;====================================================================
;; BULLET BEHAVIOUR 
;;====================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the bullet's memory direction we want to modify
;;  - IY: Should contain the player's memory direction
;; Objetive: Set the velocity of the bullet
;; Modifies: AF, BC, DE, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_behaviour_enemy_bullet::
    ;;1.- Check if player's y_vel
    ld a, e_vel_y(iy) ;; A contains player's vel_y
    or a
    jr z, player_is_grounded

    IS_HIGHER #0xF5
    jr nc, player_is_jumping
        ;;Player is falling
        call sys_ai_increase_bullet_velocity
        ret

    ;;Player is jumping
    player_is_jumping:
        ;;Probability range - bwtween 0 and 15
        call cpct_getRandom_xsp40_u8_asm
        and #0x0F
        cp #2
        ret nz

        ;;The bullet is not stopped, we can decrease its velocity
        call sys_ai_decrease_bullet_velocity

        ;;Stop the enemy in order to not commit suicide
        push iy
        INCREMENT_REGISTER_2_BYTES iy, sizeof_e ;;Now iy ocntains the enemy memory direction
        ld e_vel_x(iy), #0
        pop iy
        ret

    ;;Player is Grounded
    player_is_grounded:
    ld 	a, e_facing_right(ix)
	
	IS_EQUALS -1
	jr z, enemy_bullet_facing_left

	;;bullet_facing_right
	;;Distance = player_x - bullet_x
    ld a, e_pos_x(iy)
    sub e_pos_x(ix)

	jr change_bullet_velocity
	enemy_bullet_facing_left:
    ;;Distance = bullet_x - player_x
    ld a, e_pos_x(ix)
    sub e_pos_x(iy)

    change_bullet_velocity:

    IS_HIGHER 40
    jr nc, increase_enemy_bullet_velocity
    ret
    increase_enemy_bullet_velocity:
    call sys_ai_increase_bullet_velocity
    ret

;;====================================================================
;; UPDATE FUNCTIONS 
;;====================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to update the ai 
;; Objetive: Update the ai for one entity.
;;
;; Modifies: -
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_ai_update_one_entity:

    ;;Charge in de the memory direction of the AI behaviour function
    ld e, e_ai_bhv_b1(ix)
    ld d, e_ai_bhv_b2(ix)

    ld (#m_function_given_ai), de

    ;;Execute the AI given fucntion for one entity
    ld hl, (#m_function_given_ai)
    jp (hl)

ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  -
;; Objetive: Update the ai for all the entities matching with the signature
;; Modifies: HL, A, C
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
signature_ai = (e_cmp_ai)
sys_ai_update::
    ld hl, #sys_ai_update_one_entity

    ;;C will contain the signature for the man_entity_forall_matching
    ld  a, #signature_ai
    ld c, a

    call man_entity_forall_matching
ret