;;---------------------------------------------------------------------------------------------------------------
;#MIT License                                                                                                   #
;#Copyright (c) 2021 Cyb3rApes                                                                                  #
;#                                                                                                              #
;#Permission is hereby granted, free of charge, to any person obtaining a copy 					                #
;#of this software and associated documentation files (the "Software"), 					                    #
;#to deal in the Software without restriction, including without limitation the rights to use, copy, 		    #
;#modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 				            #
;#and to permit persons to whom the Software is furnished to do so, subject to the following conditions:	    #
;#														                                                        #
;#The above copyright notice and this permission notice shall be included in all copies or substantial 		    #
;#portions of the Software.											                                            #
;#														                                                        #
;#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 		    #
;#NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	    #
;#IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,	    #
;#WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 		    #
;#SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.							                            #
;################################################################################################################

;#GPL License
;#This file is part of "The Capeture".
;#
;#"The Capeture" is free software: you can redistribute it and/or modify
;#it under the terms of the GNU General Public License as published by
;#the Free Software Foundation, either version 3 of the License, or
;#(at your option) any later version.
;#
;#"The Capeture"  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 General Public License for more details.
;#
;#You should have received a copy of the GNU General Public License
;#along with "The Capeture".  If not, see https://www.gnu.org/licenses/.
;;----------------------------------------------------------------------------------------------------------------


.include "cpctelera.h.s"
.include "entity.h.s"

.globl sys_render_one_entity

;; Formato entidades:
;; Type
;; Entity
;; X
;; Y
;; VX
;; VY
;; w
;; h
;; DirPrevia (upper byte)
;; DirPrevia (lower byte)
;; SPRITE upper byte ya que son punteros!
;; Sprite lower byte
;; orientacion ;; 0->abajo, 1->derecha, 2->izq, 3->arriba
;; prevx
;; prevy
;; contador_animacion ;; Iteraciones restantes para cambiar su sprite
;; Tipo Sprite que tiene puesto (esto solo servira para animaciones)

;; Initial templates:
player_template: .db (e_type_physics | e_type_input | e_type_render | e_type_collision),0x00, 39, 99, 0, 0, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 1, 0
bullet_template: .db (e_type_physics | e_type_render | e_type_collision),0x01, 0, 0, 0, 0, 1, 2, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 1, 0
mina_template: .db (e_type_render | e_type_collision | e_type_animated),0x02, 70, 120, 0, 0, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x01, 50, 0, 50, 0
valla_template: .db (e_type_render | e_type_collision),0x03, 70, 120, 0, 0, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 1, 0
explosion_template: .db (e_type_render | e_type_animated),0x04, 70, 120, 0, 0, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x01, 1, 0, 1, 0
rotatorio_template: .db (e_type_render | e_type_physics | e_type_collision | e_type_animated ),0x05, 70, 120, 2, 0, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 2, 0
torreta_template: .db (e_type_render | e_type_collision | e_type_animated),0x06, 70, 120, 1, 0, 8, 16, 0x00, 0x00, 0x00, 0x00, 0x02, 0, 0, 10, 0
arachnoid_template: .db (e_type_render | e_type_physics | e_type_collision | e_type_animated ),0x07, 70, 120, 0, 1, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x01, 0, 0, 10, 0
fuego_template: .db (e_type_render | e_type_animated),0x08, 70, 120, 0, 0, 2, 3, 0x00, 0x00, 0x00, 0x00, 0x01, 1, 0, 10, 0
puerta_template: .db (e_type_render | e_type_collision | e_type_animated),0x09, 70, 120, 0, 0, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x01, 1, 0, 3, 0
switch_template: .db (e_type_render | e_type_collision ),0x0A, 70, 120, 0, 0, 4, 4, 0x00, 0x00, 0x00, 0x00, 0x01, 1, 0, 10, 0
cchamber_template: .db (e_type_render | e_type_collision | e_type_animated),0x0B, 70, 120, 3, 3, 8, 16, 0x00, 0x00, 0x00, 0x00, 1, 0, 0, 10, 0
cyborg_template: .db (e_type_ia | e_type_render | e_type_physics | e_type_collision), 0x0C, 70, 120, 0, 0, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x02, 0, 0, 10, 0
chica_template: .db (e_type_render | e_type_collision | e_type_animated), 0x0D, 37, 92, 0, 0, 4, 16, 0x00, 0x00, 0x00, 0x00, 0x02, 37, 94, 10, 0
mono_template: .db (e_type_render | e_type_collision | e_type_animated), 0x0E, 60, 64, 0, 0, 8, 16, 0x00, 0x00, 0x00, 0x00, 0x02, 60, 64, 10, 0


;; Variables

entities_created:: .db 0
entity_iterator:: .dw 0 ;; Variable para iterar entidades
dir_funcion: .dw 0
patron: .db 0
next_free_entity:: .dw entities ;; Inicialmente como estara vacio, apuntara a la primera posicion
player: .ds entity_size ;; Aqui guardaremos el jugador!
entities:: .ds num_entities*entity_size ;; Como cada entidad son 5 bytes, tendremos un total de 50 bytes!
zero_type_at_the_end:: .db 0 ;; Para que siempre haya un byte con el valor de 0 al final para simular el invalido (0x00) y que asi se detenga! Define el final del array
level_output:: .db 2 ;; Esto valdra 0 o 1 o 3, asi que el 2 significara que la partida sigue in progress (3 significa nivel arcoiris)


;; Funciones del manager de las entidades

man_entity_init:: ;; Funcion para inicializar de 0 todo el array. Esto es solo para ver visualmente la memoria reservada!
    ld de, #player
    ld a, #0x00
    ld bc, #entity_size ;;Cantidad de bytes que hemos reservado
    call cpct_memset_asm

    ld de, #entities
    ld a, #0x00
    ld bc, #num_entities*entity_size ;;Cantidad de bytes que hemos reservado
    call cpct_memset_asm
    ret


    
man_entity_create::

    ;; Aumentamos el entities_created:
    ld ix, #entities_created
    inc (ix)

    ld ix, (next_free_entity) ;;Cargamos la direccion que tenemos libre para introducir la entidad (lo cargamos en bc porque hl se altera en la llamada a la funcion)

    ;; Actualizamos la variable next_free_entity
    ld hl, (next_free_entity)
    ld de, #entity_size
    add hl, de ;; Sumamos movemos entity_size posiciones el puntero
    ld (next_free_entity), hl ;;Almacenamos la nueva posicion

    ret

;; Input:  HL-> template, BC->sprite
;; 
man_entity_create_init_values::
    push ix
    pop de ;; Pasamos la direccion de la entidad creada (la tenemos en la pila) al registro de
    
    push bc
    ld bc, #entity_size
    ldir ;; Escribimos en memoria los valores por defecto

    ;; Asignamos su sprite
    pop hl
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l
    ret


man_entity_create_cyborg::
    call man_entity_create
    ld hl, #cyborg_template
    ld bc, #_spr_cyborgR
    call man_entity_create_init_values
    ret 

man_entity_create_mono::
    call man_entity_create
    ld hl, #mono_template
    ld bc, #_spr_mono_1
    call man_entity_create_init_values
    ret 

man_entity_create_chica::
    call man_entity_create
    ld hl, #chica_template
    ld bc, #_spr_chica_0
    call man_entity_create_init_values
    ret 

man_entity_create_player::
    
    ld ix, #player
    push ix
    pop de ;; Pasamos la direccion de la entidad creada (la tenemos en la pila) al registro de

    ld hl, #player_template
    ld bc, #entity_size
    ldir ;; Escribimos en memoria los valores por defecto

    ;; Asignamos su sprite
    ld hl, #_spr_pers_R
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l

    ret 

man_entity_create_mina::
    call man_entity_create
    ld hl, #mina_template
    ld bc, #_spr_mina_0
    call man_entity_create_init_values
    ret 

man_entity_create_valla::
    call man_entity_create
    ld hl, #valla_template
    ld bc, #_spr_valla
    call man_entity_create_init_values
    ret 

man_entity_create_puerta::

    call man_entity_create
    ld hl, #puerta_template
    ld bc, #_spr_puerta_0
    call man_entity_create_init_values
    ret 

man_entity_create_switch::
    call man_entity_create
    ld hl, #switch_template
    ld bc, #_spr_switch_0
    call man_entity_create_init_values
    ret 

;; Input IY: entidad que ha explotado
man_entity_create_explosion::
    call man_entity_create
    ld hl, #explosion_template
    ld bc, #_spr_explosion_0
    call man_entity_create_init_values

    ;; Asignamos las coordenadas de la entidad en IY
    ld a, e_x(iy)
    ld e_x(ix), a

    ld a, e_y(iy)
    ld e_y(ix), a

    ret 

man_entity_create_fuego::
    call man_entity_create
    ld hl, #fuego_template
    ld bc, #_spr_fire_0
    call man_entity_create_init_values
    ret 

man_entity_create_rotatorio::
    call man_entity_create
    ld hl, #rotatorio_template
    ld bc, #_spr_rotatorioR_0
    call man_entity_create_init_values
    ret 

man_entity_create_cchamber::
    call man_entity_create
    ld hl, #cchamber_template
    ld bc, #_spr_cchamber_h_0
    call man_entity_create_init_values

    ;; Inicializamos sus valores de vida y estado
    ld a, #cchamber_life
    ld e_vx(ix), a

    ld a, #3
    ld e_vy(ix), a

    ret 

man_entity_create_arachnoid::
    call man_entity_create

    push ix
    pop de ;; Pasamos la direccion de la entidad creada (la tenemos en la pila) al registro de
    
    ld hl, #arachnoid_template
    ld bc, #entity_size
    ldir ;; Escribimos en memoria los valores por defecto

    ;; Asignamos su sprite. Como no queremos que esten sincronizados (unos empezaran yendo para arriba y otros para abajo)
    ;; Pues generamos un numero aleatorio (0 o 1) para determinar su direccion!

    call cpct_getRandom_mxor_u8_asm ;; Obtenemos un numero random de 8 bits 0-255
    ld a, l

    and #0x00000001 ;; Generamos un numero 0 o 1

    cp #0
    jr z, generar_arachnoid_down

    ;; si es uno, generamos un arachnoid para arriba:
    ;; Pintamos su sprite
    ;; Ponemos su vy a -4
    ld hl, #_spr_arachnoid_up_0
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l

    ld e_vy(ix), #-1
    ld e_ts(ix), #0 ;; Tipo de sprite colocado
    ld e_o(ix), #orientation_up
    ret

    generar_arachnoid_down:
    ;; si es cero, generamos un arachnoid para abajo:
    ;; Pintamos su sprite
    ;; Ponemos su vy a +4
    ld hl, #_spr_arachnoid_down_0
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l

    ld e_vy(ix), #1
    ld e_ts(ix), #0 ;; Tipo de sprite colocado
    ld e_o(ix), #orientation_down
    ret 

;; Input: A->random para la orientacion de la torreta
man_entity_create_torreta::
    call man_entity_create

    push ix
    pop de ;; Pasamos la direccion de la entidad creada (la tenemos en la pila) al registro de
    
    ld hl, #torreta_template
    ld bc, #entity_size
    ldir ;; Escribimos en memoria los valores por defecto

    ;; La torreta va a tener 4 orietnaciones, y como no queremos crear todas con la misma orientacion, vamos a usar un numero aleatorio de 0 a 3, para ver que orientacion ponemos
    ;; y asi dar al mapa mayor variedad!
    call cpct_getRandom_mxor_u8_asm ;; Obtenemos un numero random de 8 bits 0-255
    ld a, l

    and #0x00000011 ;; Generamos un numero entre 0-3)

    cp #0
    jr z, generar_o_0

    cp #1
    jr z, generar_o_1

    cp #2
    jr z, generar_o_2

    ;; Ultima opcion:
    ld hl, #_spr_torreta_3 
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l
    ld e_o(ix), #orientation_right
    ret

    generar_o_0:
    ld hl, #_spr_torreta_2 
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l
    ld e_o(ix), #orientation_down
    ret

    generar_o_1:
    ld hl, #_spr_torreta_1 
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l
    ld e_o(ix), #orientation_left
    ret

    generar_o_2:
    ;; Asignamos su sprite
    ld hl, #_spr_torreta_0 
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l
    ld e_o(ix), #orientation_up
    ret 


    
   

;; Esta funcion lo que hara sera actualizar la velocidad de las balas en funcion a su orientacion. Future todo: Actualizar el sprite a pintar!. Future todo: Separar esto en sus sistemas correspondientes
;; Tambien se encargara de posicionar las balas en la posicion del jugador en funcion a su orientacion
;; TAmbien se encarga de asignar su sprite dependiendo de su direccion (horizontal o vertical)
;; Input: Entidad en IX, Jugador en IY, constante del tamaño X en C y la mitad del tamaño Y en L
;; Logica de la posicion de la bala: Dependiendo de la direccion a la que dispare, la pintare en un sitio u otro. Siempre la pintare una direccion más!
;; Esta tarea es del manager y no del fisics, porque a pesar de que estoy haciendo calculos de posicion, es solo para su creacion, nada mas!

compute::
    ld a, e_o(ix) 

    cp #orientation_left
    jr z, direccionIzquierda

    cp #orientation_right
    jr z, direccionDerecha

    cp #orientation_down
    jr z, direccionAbajo

    ;; Si llega aqui es porque tiene que ir para arriba!
    ld e_vy(ix),#-4

    ld a, e_x(iy)
    ld b, c
    add a, b
    ld e_x(ix), a
    ld a, e_y(iy)
    ld e_y(ix), a
    dec e_y(ix)
    dec e_y(ix)
    dec e_y(ix)

    ; Asignamos su sprite
    ld hl, #_spr_bala
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l

    jr terminado


    direccionIzquierda:
        ld e_vx(ix),#-2

        ld a, e_x(iy)
        ld e_x(ix), a
        dec e_x(ix)
        dec e_x(ix)
        ld a, e_y(iy)
        ld b, l
        add a,b ;; Para que aparezca en el centro
        ld e_y(ix), a

        ; Asignamos su sprite
        ld hl, #_spr_bala
        ld e_spriteupperbyte(ix), h
        ld e_spritelowerbyte(ix), l

        jr terminado

    direccionDerecha:
        ld e_vx(ix),#2

        ld a, e_x(iy)
        ld b, e_w(iy)
        add a,b 
        ld e_x(ix), a
        inc e_x(ix)
    
        ld a, e_y(iy)
        ld b, l
        add a,b ;; Para que aparezca en el centro
        ld e_y(ix), a

        ; Asignamos su sprite
        ld hl, #_spr_bala
        ld e_spriteupperbyte(ix), h
        ld e_spritelowerbyte(ix), l

        jr terminado

    direccionAbajo:
        ld e_vy(ix),#4

        ld a, e_x(iy)
        ld b, c
        add a, b
        ld e_x(ix), a

        ld a, e_y(iy)
        ld b, e_h(iy)
        add a,b
        ld e_y(ix), a
        inc e_y(ix)


        ; Asignamos su sprite
        ld hl, #_spr_bala
        ld e_spriteupperbyte(ix), h
        ld e_spritelowerbyte(ix), l


    terminado:

    ret

;; Esta funcion solo sera llamada desde el sistema de input
;; El JUGADOR SIEMPRE ESTARA EN LA PRIEMRA POSICION, POR LO QUE LO DEJAMOS ASI!
man_entity_create_bullet::
    call man_entity_create

    push ix
    pop de ;; Pasamos la direccion de la entidad creada (la tenemos en la pila) al registro de

    ld hl, #bullet_template
    ld bc, #entity_size
    ldir ;; Escribimos en memoria los valores por defecto

    ld iy, #player ; Cargamos direccion del jugador
    ld a, e_o(iy)
    ld e_o(ix), a ;; Le metemos la misma orientacion que el jugador

    ld c, #mitad_jugador_x
    ld l, #mitad_jugador_y
    call compute

    ret

;; Input: IY -> Torreta
man_entity_create_proyectil::
    call man_entity_create

    push ix
    pop de ;; Pasamos la direccion de la entidad creada (la tenemos en la pila) al registro de

    ld hl, #bullet_template
    ld bc, #entity_size
    ldir ;; Escribimos en memoria los valores por defecto

    ld a, e_o(iy)
    ld e_o(ix), a ;; Le metemos la misma orientacion que la torreta

    ld c, #mitad_torreta_x
    ld l, #mitad_torreta_y
    call compute

    ret

;; Input: IY -> arachnoid
man_entity_create_bullet_arachnoid::
    call man_entity_create

    push ix
    pop de ;; Pasamos la direccion de la entidad creada (la tenemos en la pila) al registro de

    ld hl, #bullet_template
    ld bc, #entity_size
    ldir ;; Escribimos en memoria los valores por defecto

    ;; Disparara aleatoriamente a una direcion u otra:
    call cpct_getRandom_mxor_u8_asm ;; Obtenemos un numero random de 8 bits 0-255
    ld a, l

    and #0x00000001 ;; Generamos un numero 0 o 1

    cp #0
    jr z, generar_arachnoid_bala_right

    ;; Si estamos aqui, llegamos que disparar para la izquierda
    ld e_vx(ix),#-2
    ld a, e_x(iy)
    ld e_x(ix), a
    dec e_x(ix)
    dec e_x(ix)
    ld a, e_y(iy)
    ld b, #mitad_jugador_y ;; Reusamos este porque tiene el mismo tamaño xd
    add a,b ;; Para que aparezca en el centro
    ld e_y(ix), a

    ; Asignamos su sprite
    ld hl, #_spr_bala
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l
    ret


    generar_arachnoid_bala_right:
    ld e_vx(ix),#2

    ld a, e_x(iy)
    ld b, e_w(iy)
    add a,b 
    ld e_x(ix), a
    ;inc e_x(ix)

    ld a, e_y(iy)
    ld b, #mitad_jugador_y
    add a,b ;; Para que aparezca en el centro
    ld e_y(ix), a

    ; Asignamos su sprite
    ld hl, #_spr_bala
    ld e_spriteupperbyte(ix), h
    ld e_spritelowerbyte(ix), l
    ret


;; Input: Entity in IX
man_entity_set4destruction:: 

    ;; Marcaremos el bit para destruir a 1 para indicarle al destruction que debe de destruir la entidad

    ld a, e_type(ix) ;; Cargamos el type actual
    ld b, #e_type_set4destruction
    or b ;; Activamos el bit que indica que la queremos destruir!

    ld e_type(ix), a ;; Ponemos el nuevo valor!

    ;; Logica de destrucciones:

    ld a, e_e(ix)
    cp #entity_valla
    jr z, explosion_create

    cp #entity_mina
    jr z, explosion_create

    cp #entity_cyborg
    jr z, explosion_create
    
    ;; De momento, si no es ni una valla o una mina, no hacemos nada mas
    ret

    ;; Si llegamos aqui, es porque debemos de crear una explosion justo en el mismo
    explosion_create:
    push ix
    pop iy
    call man_entity_create_explosion
    ret

;; Input:
;; hl: direccion de la entidad que queremos destruir
man_entity_destroy::

    ld bc, (next_free_entity) 

    ld a, #entity_size

    sigueDecrementando:
        dec bc ;; Restamos 13 a la posicion de next entity para ir a la ultima! ld (next_free_entity), bc ;; Actualizamos su valor!
        dec a
        jr nz, sigueDecrementando

    ld (next_free_entity), bc ;; Actualizamos su valor!

    ;; Comparamos si hl == bc! Zero=1 si arg1==a!

    ld a, h ;; Comparamos primer byte
    cp b

    jr z, compararSegundoByte ;; Si salta significa que el primer byte eran iguales, si no, ya descartamos que sean iguales
    jr noSonIguales

    compararSegundoByte:

    ld a, l
    cp c

    jr z, sonIguales ;; Si salta es porque el primer y segundo byte coinciden -> Son iguales

    ;; Si llega aqui significa que no son iguales

    noSonIguales:

    ;; Si no son iguales copiamos el ultimo (direccion bc) a la posicion que borramos (hl)
    ex de,hl ;; Copiamos a donde queremos escribir

    ld h, b
    ld l, c ;; Copiamos que queremos copiar!

    ld bc, #entity_size
    ldir

    sonIguales:

    ;; Y por ultimo, invalidamos!
    ld ix, (next_free_entity)
    ld e_type(ix), #e_type_invalid

    ;; Como hemos borrado una entidad, decrementamos el numero de entidades creadas
    ld ix, #entities_created
    dec (ix)
   
    ret




man_entity_update::

    ld hl, #player ;; Cargamos el primer elemento!
    ld (entity_iterator), hl ;; Nuestro iterador!

    inicioWhile2:
        ld hl, (entity_iterator)
        ld a, (hl) ;; Cargamos en a el e->type de la entidad actual que estamos iterando
        cp #e_type_invalid ;; Si e->type != e_type_invalid -> Zero reset

        jr z, finWhile2 ;; Si Zero es Set, significa que el type es invalid, por lo tanto nos vamos

        ;;Si llegamos aqui, significa que no es una entidad invalida, pero puede estar marcada para ser destruida, por lo tanto, debemos de marcarlo
        ld hl, (entity_iterator)

        ;; Hago un and con e_type_e_type_set4destrution, si estaba marcada, la destruimos!
        ld a, (hl)
        and #e_type_set4destruction 

        ld b, #e_type_set4destruction ;; Comparamos para ver si estaba marcada
        cp b
        jr nz, noDestruir 

        ;; En hl ya tenemos la direccion, por lo que no la tocamos!
        call man_entity_destroy
        jr continue3 ;; Como hemos destruido, no aumentamos puntero porque sobreescribimos otra en esta posicion!

        noDestruir:

        ;; Como era una entidad valida, aumentamos a la siguiente
        ld hl, (entity_iterator)
        ld de, #entity_size
        add hl, de
        ld (entity_iterator), hl

        continue3:

        jr inicioWhile2
    
    finWhile2:

    ret

;; HL: Entidad a comprobar
;;  A: Patron a cumplir
;; Return en A: 1 si cumple, 0 sino.
cumple_patron:
    ld b, a
    ld a, (hl) ;; Cargamos en a el e->type 
    and b ;; Hacemos un and con el patron a cumplir!

    cp b ;; Comparamos a (resultado del and) con b (patron de bits a cumplir)

    jr z, cumplePatron2
    jr noCumplePatron2

    cumplePatron2:
        ld a, #1
        jr salir_funcion
    
    noCumplePatron2:
        ld a, #0
    salir_funcion:
    
    ret

;; Input: a -> bits to match!
;; Input: hl -> Function to call
man_entity_forall_matching::

    ld (dir_funcion), hl ;; Almacenamos la direccion de la funcin a llamar en una variable para usarla luego
    ld hl, #player ;; Cargamos el primer elemento!

    ld (entity_iterator), hl ;; Nuestro iterador!
    ld (patron), a ;;Almacenamos el patron a cumplir 

    beginWhile:
        ld a, (hl) ;; Cargamos en a el e->type de la entidad actual que estamos iterando
        cp #e_type_invalid ;; Si e->type != e_type_invalid -> Zero reset

        jr z, endWhile ;; Si Zero es Set, significa que el type es invalid, por lo tanto nos vamos

        ;;Si llegamos aqui, significa que es una entidad valida, asi que procesamos su type!
        ld hl, (entity_iterator)
        ld a, (patron)
        call cumple_patron

        cp #1 ;; Si es true, se ha cumplido

        jr z, cumplePatron
        jr noCumplePatron

        cumplePatron:
            push hl
            pop ix
            
            ld hl, (dir_funcion) 
            jp (hl) ;; Saltamos a la funcion
            ret_artificial::
        
        noCumplePatron:

        ;; Y ya solo me quedaria aumentar el contador a la sigueinte entidad!
        ld hl, (entity_iterator)
        ld de, #entity_size
        add hl, de
        ld (entity_iterator), hl

        jr beginWhile
    
    endWhile:

    ret

;; Input: HL: function to call
;; Futura mejora: tener un array de todas las entidades colisionables, asi no tenemos que comporobr esto!
man_entity_forall_pairing::

    ld (dir_funcion), hl
    ld hl, #player ;; Cargamos el primer elemento!
    ld (entity_iterator), hl ;; Nuestro iterador!
    ld (patron), a ;;Almacenamos el patron a cumplir 

    buclePrincipal:
        ld a, (hl) ;; Cargamos en a el e->type de la entidad actual que estamos iterando
        cp #e_type_invalid ;; Si e->type != e_type_invalid -> Zero reset

        jr z, finBuclePrincipal ;; Si Zero es Set, significa que el type es invalid, por lo tanto nos vamos

        ;;Si llegamos aqui, significa que es una entidad valida, Si cumple con el patron 
        ;; pasamos a procesar sus parejas
        ld a, (patron)
        call cumple_patron
        cp #1 ;; Si es true, se ha cumplido

        jr z, es_colisionable
        jr no_es_colisionable

        es_colisionable:
        push hl
        pop ix ;; Guardamos en IX la primera entidad de la pareja, ahora con un bucle recorremos sus posibles parejas:

        bucleAnidado:
            ld  de, #entity_size
            add hl, de

            ld a, (hl) 
            cp #e_type_invalid ;; Si e->type != e_type_invalid -> Zero reset

            jr z, finBucleAnidado ;; Si Zero es Set, significa que el type es invalid, por lo tanto nos vamos

            ;; Si no es invalida, comprobamos si cumple patron para procesar la pareja de entidades:
            push hl
            pop  iy ;; Almacenamos en iy por si lo cumple
            ld a, (patron)
            call cumple_patron
            cp #1 ;; Si es true, se ha cumplido

            jr z, pareja_colisionable
            jr pareja_no_colisionable

            pareja_colisionable:

            ld hl, (dir_funcion)
            jp (hl)
            ret_collision::

            pareja_no_colisionable:

            push iy
            pop  hl ;; Para procesar la siguiente entidad!

            jr bucleAnidado
        finBucleAnidado:
        
        no_es_colisionable:

        ;; Y ya solo me quedaria aumentar el contador a la sigunte entidad!
        ld  hl, (entity_iterator)
        ld  de, #entity_size

        add hl, de
        
        ld  (entity_iterator), hl

        jr buclePrincipal
    
    finBuclePrincipal:

    ret 




