.include "entity.h.s"
.include "sys/physics.h.s"
.include "man/entity_templates.h.s"
.include "man/game.h.s"

.globl _spr_shotArcoiris_0
.globl _spr_shotArcoiris_1
.globl _spr_shotArcoiris_2
.globl _spr_shotArcoiris_3


entity_vector:
    DefineNEntities entity_vector k_max_num_entities


num_entities: .db 00            
next_entity : .dw entity_vector
registro_ix : .dw 0x0000
bool_create_enemy: .db 0x00
create_enemy_type: .dw 0x0000

registroH: .db 0x00
registroL: .db 0x00

;; ===============================
;; REGISTRA UNA ENTIDAD
;; Output: HL --> Entidad creada 
;; Destroys: AF, BC, HL
;; ===============================
entity_register:
    ; Update the counter of num_entities (num_entities++)
    ld a, (num_entities)
    inc a
    ld (num_entities), a

    ; EntityVector points to the next entity
    ld hl, (next_entity)
    ld bc, #k_size_entity
    add hl, bc
    ld (next_entity), hl

    or a        ;; elimina el posible acarraeo
    sbc hl, bc  ;; resta con accarreo HL = HL - BC (deja HL como estaba antes --> CurrentEntity)

ret


;; ===============================
;; CREA UNA ENTIDAD
;; Output: HL, IX --> Entidad creada 
;; ===============================
entity_create:
    call entity_register

    ;; IX = HL (entidad creada)
    ld (registro_ix), hl
    ld ix, (registro_ix)

ret

;; ===============================
;; COPIA UNA ENTIDAD
;; Input: HL -> Entidad Origen (tmp)
;;        DE -> Entidad Destino (entidad creada)
;;
;; Output: HL -->Entidad Creada
;;         IX -->Entidad Creada
;; ===============================
entity_copy:

    ld bc, #k_size_entity
    ldir    ;; copy from HL to DE, bc bytes
    
    ex de, hl       ;; HL -> Siguiente Entidad
    sbc hl, bc      ;; HL = HL - EntidadSize (Entidad Nueva)
    
ret


entity_doForAll:
    ld a, (num_entities)
    cp #0 
    jr z, noEntitiesForAll

    ld ix, #entity_vector
    ld (metodoForAll), hl
   
    bucleForAll:
        push af

        ;;comprobamos si la entidad es valida o no
        ld a, e_tipo(ix) 
        cp #e_type_invalid
        jr z, noEntitiesForAll
        
        push bc
        metodoForAll=.+1 ;;la direccion que quiero modificar (la actual mas 1)
        call physics_update_one
        pop bc
       
        pop af
        ld de, #k_size_entity
        add ix, de ;;paso a la siguiente
        
        dec a
        jp nz, bucleForAll

    noEntitiesForAll:
ret




;; ===============================
;; EJECUTA PARA TODAS LAS ENTIDADES CON COMPROBACION
;; Input: HL -> Rutina a ejecutar
;;        B  -> Signature a comprobar
;; Output:
;; ===============================
entity_doForAll_matching:
    ld a, (num_entities)
    cp #0 
    jr z, noEntities

    ld ix, #entity_vector
    ld (metodo), hl
   
    bucle:
        ld c, a

        ;;comprobamos si la entidad es valida o no
        ld a, e_tipo(ix) 
        cp #e_type_invalid
        jr z, noEntities
        
        push bc
        ;; Comprobar que el estado de la entidad coincide con la mascara que pasan por el registro B
        
        ld a, e_cmps(ix) 
        and b
        cp b
        jr nz, no_matching
            push bc
            metodo=.+1 ;;la direccion que quiero modificar (la actual mas 1)
            call physics_update_one
            pop bc

        no_matching:
       
        pop bc
        ld a, c
        ld de, #k_size_entity
        add ix, de ;;paso a la siguiente
        
        dec a
        jp nz, bucle

    noEntities:
ret


;; ===============================
;; EJECUTA PARA TODAS LAS ENTIDADES CON COMPROBACION DE DOS EN DOS
;; Input: HL -> Rutina a ejecutar
;;        B  -> Signature a comprobar
;; Output:
;; ===============================
entity_doForAll_pairs_matching:
    ld a, (num_entities)
    cp #0 
    jr z, noEntities1

    ld ix, #entity_vector ;; ix => primera entidad
    ld (metodoPair), hl
   
    bucle1:
        
        ld c, a
        ;;comprobamos si la entidad es valida o no
        ld a, e_tipo(ix) 
        cp #e_type_invalid
        jr z, noEntities1
        
        push bc
        ;; Comprobar que el estado de la entidad coincide con la mascara que pasan por el registro B
        ld a, e_cmps(ix) 
        and b
        cp b
        jr nz, no_matching1

           ;; IY => Siguiente entidad (a la de la derecha de IX)
           ld de, #k_size_entity    ;; DE = tamEntity
           ld (registro_ix), ix     ;; regIX = Entidad1
           ld hl, (registro_ix)     ;; HL = Entidad1
           add hl, de               ;; HL = HL + DE = Entidad2
           ld (registro_ix), hl     ;; regIX = Entidad2
           ld iy, (registro_ix)     ;; IY => Entidad 2

            bucle2:
                ;;comprobamos si la entidad2 es valida o no
                ld a, e_tipo(iy) 
                cp #e_type_invalid
                jr z, no_matching1

                ;; Comprobar que el estado de la entidad coincide con la mascara que pasan por el registro B (collider)
                ld a, e_cmps(iy) 
                and b
                cp b
                jr nz, no_matching2
                    push bc
                    ;; ENtidades son colisionables
                    ;; Comprobamos si Entidad1 (en IX) colisiona con ENtidad2 (en IY)
                    ;e_collidesAgainst(ix)

                    metodoPair=.+1 ;;la direccion que quiero modificar (la actual mas 1)
                    call physics_update_one
                    pop bc

                no_matching2:
                ld de, #k_size_entity
                add iy, de ;;paso a la siguiente
                jr bucle2

        no_matching1:

        pop bc
        ld a, c
        ld de, #k_size_entity
        add ix, de ;;paso a la siguiente
        
        dec a
        jp nz, bucle1

    noEntities1:
ret




;; ===============================
;; MARCAR PARA DEDSTRUIR
;; Input: IX -> Entidad a marcar
;; Destroy: A
;; ===============================
entity_set4destruction:
    ld e_cmps(ix), #muriendo_tmp_cmps
    ld e_tipo(ix), #e_type_dead
ret


;; ===============================
;; MARCAR PARA CREAR (por defecto zombie)
;; Input: DE -> TEMPLATE DE ENTIDAD A CREAR 
;;        A -->  X de la nueva entidad
;;        B -->  Y de la nueva entidad
;;        C --> VX de la nueva entidad
;;        H --> VY de la nueva entidad
;;        L --> numero de entidades a crear      
;;        IX --> Ptr a la entidad a la que pertence
;; OJOO!! DESTROYS IX
;; ===============================
entity_set4creation:

    ;; RegistroIX => Ptr a pertence
    ld (registro_ix), ix
    ;ld iy, (registro_ix)

    ;; IX => Template
    ld (create_enemy_type), de
    ld ix, (create_enemy_type)

    ;; Cambiamos los datos para la template
    ld e_x(ix),  a
    ld e_y(ix),  b
    ld e_vx(ix), c
    ld e_vy(ix), h

    ;; En registroIX => Entidad a la que pertenece la nueva entidad (ARQUERO)
    ld bc, (registro_ix)
    ld e_perteneceL(ix), c
    ld e_perteneceH(ix), b
    
    ld a, l
    ld (bool_create_enemy), a
ret



;; ===============================
;; BORRAR TODAS LAS ENTIDADES QUE LE PASAN
;; Input: IX -> Entidad actual
;; Destroy: AF, DE, IY, HL
;; ===============================
entity_destroy:
    ;; Do HL --> LastEntity
    ld hl, (next_entity)  ;; the one which doesnt exist yet

    ;; hl = hl - 8
    ld de, #-k_size_entity
    add hl, de

    ;; Next Entity = next_entity - sizeEntity
    ld (next_entity), hl

    ; Do DE --> IX (EntityDeleting)
    ld (registro_ix), ix
    ld de, (registro_ix)
                
    ; Copy last entity data into the deleting one (copia hl en de)
    call entity_copy
                
    ;ld iy, (next_entity)
    ld iy, (next_entity)

    ;; IY -> Last ENtity
    ld e_tipo(iy), #e_type_invalid

    ;; num_entities--
    ld a, (num_entities)
    dec a
    ld (num_entities), a

    ;; ix = ix - 8
    ld de, #-k_size_entity
    add ix, de

ret 


tabla_disparos_direcciones:
    .db #-1,  #0
        .dw #_spr_shotArcoiris_0
    .db #0 ,  #4
        .dw #_spr_shotArcoiris_1
    .db #0 , #-4
        .dw #_spr_shotArcoiris_3

;; ===============================
;; VER SI LAS ENTIDADES SE TIENEN QUE BORRAR e_type_dead = 0x80
;; Y ADEMAS CREAMOS NUEVAS ENTIDADES
;; Input: 
;; Destroy: AF, IX, BC
;; ===============================
entity_update:
    ld a, (num_entities)
    cp #0 
    jr z, sinEntities

    ld ix, #entity_vector
    ld (metodo), hl
   
    buscarDead:
        ld b, a

        ;;comprobamos si la entidad es valida o no
        ld a, e_tipo(ix) 
        cp #e_type_invalid
        jr z, sinEntities
        
        push bc
        ;; si esta en mitad de una animacion no miro el tipo
        ld a, e_anim_especial(ix)
        cp #1
        jp z, noDestroy

        ;; Comprobar que el estado de la entidad coincide con la mascara que pasan por el registro B
        ld a, e_tipo(ix) 
        cp #e_type_dead
        jr nz, noDestroy
            call entity_destroy
        noDestroy:

        pop bc
        ld a, b
        
        ld bc, #k_size_entity
        add ix, bc ;;paso a la siguiente
        
        dec a
        jp nz, buscarDead

    sinEntities:


    ;; CREAMOS ENTIDADES (de momento las creo en COLISION y asi me ahorro el primer if)
    ;; Falta comprobar que no nos pasamos --> if (num_entities < k_max_num_entities) 
    ;; Falta crear un enemigo en X e Y (primero estaticas, luego le pondremos aleatoriedad, y que las coja de una tabla)
    ld de, (create_enemy_type) ;; DE => Template de la entidad a crear
    ld b, #0 ;; contador a 0

    checkEntidadesRestantes:

    ld a, (bool_create_enemy)       ; A = num_Entidades_Restantes 
    cp #0                           ; if (num_Entidades_Restantes  != 0)
    jr z, no_crea_entidad

        ld a, b
        cp #0
        jr z, primeraIteracionBucle
            ;; Hay varias entidades a crear (4 disparos), por lo que hay que cambiar sus direcciones

            ; Obtenemos la velocidad dependiendo de la iteracion (si b=1 --> X=-1 Y=0; si b=2 -->X=0 ,Y=....)
            ld ix, #tabla_disparos_direcciones
            ;; While (b>0) ix++
            ld a, b
            dec a
            checkear_IX:
            cp #0
            jr z, tenemos_IX_bien
                ;; Si estamos en la iteracion 2 o 3, IX++
                inc ix
                inc ix
                inc ix
                inc ix
                dec a
                jr checkear_IX
            tenemos_IX_bien:

            ld h, 0(ix) ;; H = VX
            ld l, 1(ix) ;; L = VY

            ;; meto el sprite en memoria
            ld a, 3(ix) 
            ld (registroH), a     
            ld a, 2(ix)
            ld (registroL), a 

            ; IX = template
            ld ix, #shot1
            ld e_vx(ix), h      ; modifico VX de la template
            ld e_vy(ix), l      ; modifico VY de la template

            ;ld e_w(ix), #0x06
            ;ld e_h(ix), #0x1C

            ld a, (registroH)    ;; /
            ld e_spriteH(ix), a  ;; | Modifico el Sprite de la template
            ld a, (registroL)    ;; | Primero bitH y luego bitL
            ld e_spriteL(ix), a  ;; \

        primeraIteracionBucle:

        push bc

        ;; Si (num_Entidades_Restantes  != 00) 
        push de
        call game_create_template ;; creamos entidad
        pop de

        ;; bool_create_enemy--
        ld a, (bool_create_enemy)
        dec a
        ld (bool_create_enemy), a

        pop bc
        inc b   ;; b++

        ;; Si hemos disparado ya 4 veces, ponemos el template de SHOT con el disparo azul
        ld a, b
        cp #4
        jr nz, no_reset_tmp_shot
            ; Se han creado 4 disparos
            ld ix, #shot1
            ld de, #_spr_shotArcoiris_2
            ld e_spriteH(ix), d
            ld e_spriteL(ix), e

        no_reset_tmp_shot:


        jr checkEntidadesRestantes



    no_crea_entidad:

    
    ld de, #0x0000
    ld (create_enemy_type), de


ret

;; Devuelve en IX la segunda entidad
getEntity2:
    ld ix, #entity_vector
    ld bc, #k_size_entity
    add ix, bc
ret

;; freespace, entity_doForAll_matching



