;;
;; ENTITY MANAGER
;;

.include "cpctelera.h.s"

.area _CODE



;;; VARAIABLES PARA ARRAY DE ENTIDADES

max_entities_num:
entity_size  == 33

max_projectiles == 12
n_entities == 5
max_entities == n_entities+max_projectiles

;; COSTANTES PARA LAS ENTIDADES


;; CONSTANTES GENERALES
e_tipo==0
e_x ==1
e_y ==2
e_w ==3
e_h ==4
e_vx ==5
e_vy ==6


;; ANIMACIONES
e_puntero ==9
e_next_anim ==11
e_cont_anim ==13

e_dir ==14
e_dir_ant ==15

e_posicion_borrado ==16 
e_vida == 18
e_cont_no_hit ==19
e_cont_velocidad == 20

;; PLAYER
e_at ==7
e_at_dir==8

e_atack_spr == 21
e_atack_anim == 23
e_atack_cont == 25
e_atack_w == 26
e_atack_h == 27
e_atack_posx == 28
e_atack_posy == 29
e_atack_pos_antx == 30
e_atack_pos_anty == 31


;IA
e_xdest==7
e_ydest ==8

e_eje_follow == 24
e_comportamiento_ia == 25
e_t_disparo == 26
e_max_vel == 27

e_final == 32



;;; TIPOS DE ENTIDADES 
_e_type_invalid ==  0x00 ;;
_e_type_render == 0x01 ;;Entity for render  
_e_type_movable == 0x02 ;; Entity for move 
_e_type_input == 0x04 ;; Entity for input 
_e_type_animable == 0x20 ;; Entity for input 
_e_type_projectile == 0x10
_e_type_ia == 0x08;; Entity for ia 
_e_type_dead == 0x80 
_e_type_default == 0x7F 




;;;;; TIPOS DE ENEMIGOS/OBEJTOS
_e_type_ia_follow == 0x10;; Entity for ia follow
_e_type_ia_patroll == 0x20;; Entity for ia patrol
_e_type_ia_archer == 0x40
_e_type_ia_salto == 0x80
_e_type_ia_vida == 0x01



;; VARIABLES PARA PROYECTILES
_num_proyectiles:: .db 0
temp_disparando:: .db 0
temp::  .db 0
temp2:: .db 0



_last_elem_ptr_colision:: .dw _entity_colision_array
_entity_colision_array:: .ds max_entities*2 
.db 0



_entity_size:: .db entity_size
_num_entities:: .db 0
_last_elem_ptr:: .dw _entity_array
_entity_array:: .ds max_entities*entity_size 
.db 0






;;; BORRADO DE DATOS 

init_entity_array::
    ld hl, #_entity_array
    ld e, #max_entities*entity_size
    init_loop:
    ld (hl), #0
    inc hl
    dec e
    jr nz, init_loop

ret

init_vector_colision::
    ld hl, #_entity_colision_array
    ld e, #max_entities*2
    init_col_loop:
    ld (hl), #0
    inc hl
    dec e
    jr nz, init_col_loop

ret




;;; FUNCIONES PARA EL USO DE LAS ENTIDADES

entity_man_get_Size::
    ld      bc, (_entity_size)
ret


entity_man_getEntityArray_IX::
    ld      ix, #_entity_array
ret

get_start_colition_array::
    ld      hl, #_entity_colision_array
ret

entity_man_getNumEntities_A::
    ld      a, (_num_entities)
ret






;;;; CREACION DE ENTIDAD

entity_man_create::
    ld      ix , (_last_elem_ptr)
    ld      de, (_last_elem_ptr)
    ld      bc, #entity_size
    ldir    

    ld      a, (_num_entities)
    inc     a
    ld      (_num_entities), a

    
    call add_colissionable
    not_add_col:

    ld      ix , (_last_elem_ptr)
    
    ld      hl, (_last_elem_ptr)
    ld      bc, #entity_size
    add     hl, bc 
    ld      (_last_elem_ptr), hl
    
ret





;;; RECORRE TODAS LAS ENTIDADES LLAMANDO LA FUNCION QUE SE PASE


man_entity_forall::
    call  entity_man_getEntityArray_IX  ;; array de entidades  -> IX 
    call  entity_man_getNumEntities_A
    ld (function_hl),hl

    
    bucle_forall:
    
    push af
    function_hl=.+1
    call function_hl

    ld bc, #entity_size
    add ix, bc

    
    pop af



    dec a
    jr nz, bucle_forall


ret




add_colissionable:
    ld ix, (_last_elem_ptr_colision)
    ld hl, (_last_elem_ptr)
    ld 0(ix), l
    ld 1(ix), h
    
    ld      bc, #2
    add     ix, bc 
    ld      (_last_elem_ptr_colision), ix


ret









;;; UPDATE DEL VECTOR DE COLISIONES, BORRA EL ULTIMO SI HAY UNA ENTIDAD MUERTA


update_colisionable_SI::

    ld hl, #_entity_colision_array

    comprobar_dead_col:
    ld b, (hl)
    inc hl
    ld a, (hl)
    or a,b
    ret z
    dec hl ;; COMPROBAR SI ES EL ULTIMO DEL ARRAY

    push hl

    ld a, (hl)
    inc hl
    ld b, (hl)
    ld l, a
    ld h, b  ;; PONER EL VALOR DENTRO DE HL EN HL

    ld b, #_e_type_dead
    ld a, (hl)
    and b      
    cp a,b      
    jr nz, next_updt_col_SI ;; COMPROBAR SI ES DEAD

    pop hl
    ex de, hl           ;; DE ES LA POSICION ACTUAL AHORA

    ld hl, (_last_elem_ptr_colision)
    ld bc, #-2
    add hl, bc  
    ld (_last_elem_ptr_colision), hl   ;;; DECREMENTAR LAS POSICION DEL ULTIMO ELEMENTO

    


    actualizar_col:
    ld hl, (_last_elem_ptr_colision)
    ld (hl),#0
    inc hl
    ld (hl),#0
    inc hl 
    jp comprobar_dead_col
    ret



    ; NO ES DEAD
    next_updt_col_SI:
    pop hl
    inc hl 
    inc hl 
    jp comprobar_dead_col

ret








;; INPUT 
entity_set4destroy::
    
    ld a,  #_e_type_dead ;;cargo en a el tipo_invalido
    ld e_tipo(ix), a
    
ret





;;; UPDATE DEL ARRAY DE ENTIDADES

entity_update:: 
    call  entity_man_getEntityArray_IX  
    call  entity_man_getNumEntities_A   
    jr _desloop
destruir:
    call entity_destroy

_desloop:
    ld a, e_tipo(ix) 
    or a 
    ret z

    ld a, e_tipo(ix) 
    ld b, #_e_type_dead 
    and a, b 
    jr z, _next 
    jr destruir

_next:

    ld      bc,#entity_size 
    add     ix, bc  
jr       _desloop






;;INPUT IX PUNTERO A DESTRUIR
entity_destroy:: 
        
    call  entity_man_getNumEntities_A 
    
    ld hl, (_last_elem_ptr)
    ld bc, #-entity_size
    add hl,bc
    ld (_last_elem_ptr),hl  ;;; DECREMENTA EL LAST_POINTER




    dec a
    ld (_num_entities),a


    push ix
    pop de
    sbc hl,de
    jr z ,actualizar

    ld hl,(_last_elem_ptr)
    ld bc,#entity_size
    ldir 

actualizar:
    ld hl, (_last_elem_ptr)
    ld (hl) ,#0
   

ret





destroy_all_entities::
    
    call init_entity_array
    ld hl, #_entity_array
    ld (_last_elem_ptr), hl

    call init_vector_colision
    ld hl, #_entity_colision_array
    ld (_last_elem_ptr_colision),hl

    ld a, #0
    ld (_num_entities), a
    ld (_num_proyectiles), a


ret


;;; DEVUELVE SI HAY ESPACIO EN EL ARRAY
entity_free_space::
    ld a, (_num_entities)
    ld b,a
    ld a, #max_entities 
    sbc a, b 





ret 



entity_arrow_free_space::
    ld a, (_num_proyectiles)
    ld b,a
    ld a, #max_projectiles ;; cargamos en hl el max_entities 
    sbc a, b ;; max_entities - _num_entities

ret 






;;; COMPRUEBA LA MUERTE DEL JUGADOR // LA MUERTE DE TODOS LOS ENEMIGOS

estado_nivel::

    call entity_man_getEntityArray_IX
    ld a, e_vida(ix)
    or a
    jr z, muerte_jugador


    ;;; CASO1 TODOS LOS ENEMIGOS MUEREN
    ld a, (final_nivel)
    dec a 
    jr nz, comprovar_vacio
    ld a, #0
    ld (final_nivel), a
    call cpct_akp_stop_asm
    call carga_next_mapa

    comprovar_vacio:
    ld a, (_num_entities)
    dec a
    ret nz
    call render_puerta
    call generator_salto
    



    ret


    ;;; CASO2 EL JUGADOR MUERE // PIERDE UNA VIDA
    muerte_jugador:

    ld a, (intentos_partida)
    dec a
    jr z, final_partida 
    ld (intentos_partida),a
    call cpct_akp_stop_asm
    call soft_reset_game
    ret
    
    ;;; CASO3 EL JUGADOR MUERE // NO LE QUEDAN VIDAS
    final_partida:
    call cpct_akp_stop_asm
    call reset_completo_game

ret





