;;-----------------------------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 "entity.h.s"
.include "cpctelera.h.s"

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

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

;;System
.include "sys/input.h.s"


;;====================================================================
;; PRIVATE ENTITY CLASS VARIABLES
;;====================================================================
m_function_given_forall_matching:	.dw #0x0000    		;;Memory direction of the function that we want to execute
m_entities: 						.ds e_total_size	;;Reserved memory for the entities
m_next_free_entity: 				.ds 2				;;Reserved memory for the pointer of the next free entity


;;====================================================================
;; FUNCTIONS
;;====================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  -
;; Objetive: Initialize the entities establishing their values to 0
;; Also m_next_free_entity points to the first free entity to write
;;
;; Modifies: A, BC, DE, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_init::

	ld de, #m_entities
	ld a, #0x00 
	ld bc, #e_total_size

	call cpct_memset_asm
	
	;;Next free entity should point towards m_entities
	ld hl, #m_entities
	ld (#m_next_free_entity), hl
ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  -
;; Objetive: Increase m_num_entities and increase m_next_free_entity
;; to point towards the next free entity
;;
;; Modifies: A, IY
;;
;; Returns: In DE and IY, returns the direction of the entity created
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;   
man_entity_create::
	ld de, (#m_next_free_entity)
	ld iy, (#m_next_free_entity)

	INCREMENT_VARIABLE m_next_free_entity, sizeof_e
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - HL: should contain the memory direction for the given function to be called
;;  - C: contains a signature that needs to be true to call the function in hl
;; Objetive: Updates all the entities for their components in case those
;; match the signature given in C
;;
;; Modifies: IX, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_forall_matching::
	ld ix, #m_entities
	ld (m_function_given_forall_matching), hl

	ld  a, #max_entites
	repeat_man_entity_forall_matching:

		push af

		IS_ENTITY_INVALID ix
		jr z, entity_should_loop_again

		IS_ENTITY_MATCHING_SIGNATURE
		jr nz, entity_should_loop_again

		;;Keeping the signature for the next loop
		push bc

		;;Call the funcion given registered in m_function_given_forall_matching

		ld hl, #position_after_function_given_matching
		push hl

		ld hl, (#m_function_given_forall_matching)
		jp (hl)

		position_after_function_given_matching:
		
		;;Recovering the signature for the next loop
		pop bc

		entity_should_loop_again:
		
		INCREMENT_REGISTER_2_BYTES ix, sizeof_e

		pop af
		dec a
	jr nz, repeat_man_entity_forall_matching

	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  -
;; Objetive: Updates the entities by destroying all marked entities as dead
;;
;; Modifies: 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
man_entity_update::
	ld ix, #m_entities

	ld  a, #max_entites
	repeat_man_entity_update:
	
	push af

	IS_ENTITY_GIVEN_TYPE_IX e_type_dead
	jr nz, destroy_dead_entity

	jr final_man_entity_update

	destroy_dead_entity:

		call man_entity_destroy

	final_man_entity_update:
		INCREMENT_REGISTER_2_BYTES ix, sizeof_e
		pop af
		dec a
	jr nz, repeat_man_entity_update
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set
;; 		 to do an animation before die
;; Objetive: Change the entity's type to e_type_dying_animation
;;			 This way, our entity before die will play an animation
;; Modifies: A, C
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_set_type_to_dying_animation::

	ld a, e_type(ix)
	or #e_type_dying_animation
	ld e_type(ix), a

	IS_ENTITY_GIVEN_TYPE_IX e_type_bullet
	jr nz, dying_animation_bullet

	ld a, e_cmp(ix)
	sub a, #e_cmp_movable

	ret

	dying_animation_bullet:

	ld a, #e_cmp_render
	add a, #e_cmp_animation
	ld e_cmp(ix), a

ret	


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set4destruction 
;; Objetive: Add entity_type_dead to the entity type
;;
;; Modifies: A, B
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_set4destruction::
	ld 		a, e_type(ix)
	ld 		b, #e_type_dead

	or 		b

	ld e_type(ix), a
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the memory direction for the entity
;;
;; Objetive: Mark the dead entity as invalid and copy the last entity
;; into the dead entity memory position, also updates the m_next_free_entity
;; pointer

;; Modifies: IX, IY, HL, BC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
man_entity_destroy:
	;;TRICK!! Supposing only bullets will be destroyed

	;;The destroyed entity type now is invalid
	ld e_type(ix), #e_type_invalid

	push ix
	
	;;The bullet is invalid, change the input behaviour for the owner
	ld l, e_bullet_ref_b1(ix)
	ld h, e_bullet_ref_b2(ix)
	ld__ix_hl
	call man_entity_set_input_behaviour_not_shooting

	pop ix	
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to change the behaviour
;; Objetive: Change entity's input behaviour while is not shooting
;;
;; Modifies: HL, A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_set_input_behaviour_not_shooting::

	IS_ENTITY_GIVEN_TYPE_IX e_type_player1
	jr nz, type_player1_no_shoot

	;;type_player2:
	ld hl, #sys_input_behaviour_player2_no_shoot
	jr update_input_bhv_no_shoot

	type_player1_no_shoot:
	ld hl, #sys_input_behaviour_player1_no_shoot

	update_input_bhv_no_shoot:

	ld e_input_bhv_b1(ix), l   
	ld e_input_bhv_b2(ix), h
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to change the behaviour
;; Objetive: Change entity's input behaviour while is shooting
;;
;; Modifies: HL, A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_set_input_behaviour_shooting::

	IS_ENTITY_GIVEN_TYPE_IX e_type_player1
	jr nz, type_player1_shoot

;;type_player2:
	ld a, e_facing_right(ix)
	IS_EQUALS 1
	jr z, input_bhv_facing_right_p2

	;;input_bhv_facing_left_p2
		ld hl, #sys_input_behaviour_player2_shoot_left
		jr update_input_bhv_no_shoot

	input_bhv_facing_right_p2:
		ld hl, #sys_input_behaviour_player2_shoot_right
		jr update_input_bhv_shoot

type_player1_shoot:
	ld a, e_facing_right(ix)
	IS_EQUALS 1
	jr z, input_bhv_facing_right_p1

	;;input_bhv_facing_left_p1
		ld hl, #sys_input_behaviour_player1_shoot_left
		jr update_input_bhv_no_shoot

	input_bhv_facing_right_p1:
		ld hl, #sys_input_behaviour_player1_shoot_right

	update_input_bhv_shoot:

	ld e_input_bhv_b1(ix), l   
	ld e_input_bhv_b2(ix), h
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;		-
;; Objetive: Disable the cmp movable for players
;; Modifies: A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_disable_player_move::

	ld hl, #m_entities
	inc hl
	ld a, (hl)
	sub #e_cmp_movable
	ld (hl), a

	INCREMENT_REGISTER_2_BYTES hl, sizeof_e

	ld a, (hl)
	sub #e_cmp_movable
	ld (hl), a

ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set is grounded
;; Objetive: Change entity's is_grounded to 1 (true)
;;
;; Modifies: -
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_set_is_grounded::
	ld e_is_grounded(ix), #1
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to set is grounded
;; Objetive: Change entity's is_grounded to 1 (true)
;;
;; Modifies: -
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_set_is_in_air::
	ld e_is_grounded(ix), #0
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;; Objetive: Change the patrol step reference of the enemy to start again the patrol
;; Modifies: A, HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_reset_patrol::
    ;;Get the next 2 bytes pointed by hl -> points to the start of the patrol
    inc hl
    ld a, (hl)
    inc hl
    ld h, (hl)
    ;;Reset patrol step
    ld e_ai_patrol_step_l(ix), a
    ld e_ai_patrol_step_h(ix), h
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pre requirements
;;  - IX: should contain the entity's memory direction we want to modify
;; Objetive: Change the patrol step reference of the enemy
;; Modifies: HL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
man_entity_load_patrol_ref::
;;hl points to the next X patrol step
    ld l, e_ai_patrol_step_l(ix)
    ld h, e_ai_patrol_step_h(ix)
    ret

man_entity_increment_patrol_step::
	;;Set new e_ai_patrol_step
    inc hl
    ld e_ai_patrol_step_l(ix), l
    ld e_ai_patrol_step_h(ix), h
	ret