.include "ia.h.s"
.include "man/entity.h.s"
.include "man/entity_templates.h.s"
.include "man/game.h.s"
.include "sys/collision.h.s"

.globl bool_multijugador
.globl bool_disparo

registro_aux_ix2: .db 0x0000 ;; registro auxiliar

timer_direccion: .db #0x30
timer_ia_variable: .db #0d100

ia_mover_drcha_izq:
    ;; EN IX tenemos la entidad
    ;ld b, e_vy(ix)
    ;ld e_last_dirY(ix), b
    ld e_vy(ix), #0 ;; Si solo queremos que se mueva hacia los lados, nunca tendra velocidad en Y
                    ;; Por si acaso, se la quito
    ld a, e_vx(ix)
    cp #0
    jp nz, fin_comprobacion_vx
        ld a, e_last_dir(ix) ;;Comprobamos que direccion estaba llevando 
        cp #0                ;;antes de nada porque si no tuviera velocidad,
        jp m, negativo       ;;este metodo por si solo no mueve nada
            ld e_vx(ix), #1
            ld e_last_dir(ix), #1 ;; Cuando movamos la ia, tambien cambiamos la ultima direccion
            jp fin_comprobacion_vx
        negativo:
            ld e_vx(ix), #-1

    fin_comprobacion_vx:
    ld a, e_x(ix)
    cp #0x6
    jr nz, no_borde_izq
        ;; Cambia hacia la derecha
        ld e_vx(ix), #1
        ld e_last_dir(ix), #1 ;; Cuando movamos la ia, tambien cambiamos la ultima direccion
        ret
    no_borde_izq:

    cp #0x44 ;; borde drecha - tam_Enemigo

    jr nz, no_borde_drcha
        ;; Cambia hacia la izq
        ld e_vx(ix), #-1
        ld e_last_dir(ix), #-1 ;; Cuando movamos la ia, tambien cambiamos la ultima direccion
        ret
    no_borde_drcha:

ret 


ia_mover_arriba_abajo:
    ;; EN IX tenemos la entidad
    ;; Al igual que antes, si solo se mueve de arriba a abajo
    ;; le quitamos la velocidad en X no vaya a ser que llegue con velocidad
    ld e_vx(ix), #0

    ld a, e_vy(ix)
    cp #0
    jp nz, fin_comprobacion_vy
        ld a, e_last_dirY(ix) ;;Comprobamos que direccion estaba llevando 
        cp #0                 ;;antes de nada porque si no tuviera velocidad,
        jp m, negativoY       ;;este metodo por si solo no mueve nada
            ld e_vy(ix), #4
            ld e_last_dirY(ix), #4 ;; Cuando movamos la ia, tambien cambiamos la ultima direccion
            jp fin_comprobacion_vy
        negativoY:
            ld e_vy(ix), #-4

    fin_comprobacion_vy:

    ld a, e_y(ix)
    cp #0x20
    jr nz, no_borde_arriba
        ;; Cambia hacia la derecha
        ld e_vy(ix), #4
        ld e_last_dirY(ix), #4 ;; Cuando movamos la ia, tambien cambiamos la ultima direccion
        ret
    no_borde_arriba:

    cp #0x94 ;; borde drecha - tam_Enemigo

    jr nz, no_borde_abajo
        ;; Cambia hacia la izq
        ld e_vy(ix), #-4
        ld e_last_dirY(ix), #-4 ;; Cuando movamos la ia, tambien cambiamos la ultima direccion
        ret
    no_borde_abajo:

ret 



move_to:
    ;; COMPROBAMOS LA X
    ld a, e_x(ix) ;; A = Enemigo_X
    sub a, e_aim_X(ix) ;; a = enemy_x - player_x
    
    jr c, enemigo_derecha_player ;; Si la resta es negativa, -->  player_X  > enemigo_X
    jr z, misma_posicion_x
        ld e_vx(ix), #-1         ;; Por tanto, hay que mover el enemigo hacia la izq
        jr check_y               ;; Pasamos a comprobar la y

    enemigo_derecha_player:      ;; Si es positiva, la x del enemigo esta mas a la derecha que la del player
    ld e_vx(ix), #1              ;; Por tanto, hay que mover el enemigo hacia la drcha
    jr check_y

    misma_posicion_x:
    ld e_vx(ix), #0
    
    ;; COMPROBAMOS LA Y
    check_y:
    ld a, e_y(ix)  ;; A = Enemy_Y
    sub a, e_aim_Y(ix) ;; A = Enemy_Y - Player_Y
    
    jr c, enemigo_arriba_player ;; Si hay carry (EnemyY - PlayerY < 0 --> Hay carry)
    jr z, misma_posicion_y
        ; no hay carry y no es cero --> EnemyY > Player_Y --> Enemigo Abajo
        ld e_vy(ix), #-4        ;; ENEMIGO se mueve hacia ARRIBA
        ret                 

    enemigo_arriba_player:      ;; Si es positiva, la x del enemigo esta mas a la derecha que la del player
    ld e_vy(ix), #4             ;; Por tanto, hay que mover el enemigo hacia la izquierda restando posiciones
    ret

    misma_posicion_y:
    ld e_vy(ix), #0
    

ret


;; IA 2 - ARQUERO
ia_arquero:
    ;; EN IX tenemos la entidad Arquero
    ;; Movemos al enemigo 
    ;call ia_mover_drcha_izq

    call ia_mover_arriba_abajo
 
    ;; Comprobamos si podemos disparar con arquero_player_shot
    ld a, e_player_shot(ix)
    cp #0
    ret nz
    ;; Comprobamos si vemos al player para dispararle
    ld iy, #entity_vector ;; Cargamos los datos del jugador en iy

    ;; if (X_enemy == X_arquero)
    ld a, e_x(iy)
    cp e_x(ix)

    jr nz, no_lo_veo
        ld a, #1
        ld (bool_disparo), a
        ;; Si coinciden las X, el arquero dispara 
        ld e_player_shot(ix), #1
        ld e_atacando(ix), #1
        
        ;; Creamos un disparo
        ld de, #shot_arquero
        
        ;; Tenemos que ver si el disparo va hacia arriba o hacia abajo
        ld a, e_y(iy)
        cp e_y(ix)
        jp m, arquero_abajo
            ;; Dispara hacia abajo 
            ld h, #4
            ld e_vy(ix), #4 ;; Al verlo abajo, cambiamos la dirección del arquero
            jr acaba_ia_arquero
        arquero_abajo:
            ;; Dispara hacia arriba
            ld h, #-4
            ld e_vy(ix), #-4 ;; Al verlo abajo, cambiamos la dirección del arquero
            
            
        acaba_ia_arquero:

        ld a, e_x(ix)  ;; X_shot = X_arquero 
        ld b, e_y(ix)
        ld c, #0       ;; VX_shot = 0
        ld l, #1

        push ix

        call entity_set4creation
        pop ix
        
    
    no_lo_veo:

ret

boll_create: .db #0


;; IA 1 - ZOMBIE
ia_seguimiento_player:

    ;; Cogemos los datos del jugador y nos los ponemos como objetivo
    call target_player  

    ;; Llamamos a MoveTo
    call move_to
    
ret

target_player:
    ld iy, #entity_vector ;; Cargamos los datos del jugador en iy
    ld b, e_x(iy)
    ld c, e_y(iy)
    ld e_aim_X(ix), b
    ld e_aim_Y(ix), c

    ;push iy

    ld a, (bool_multijugador)
    cp #1
    jr nz, no_multi_player

        ;; CALCULO DISTANCIA CON PLAYER 1, y lo guardo en C
        ld a, e_x(iy)   ;; A = PlayerX
        sub e_x(ix)      ;; A = playerX - enemyX
        ld b, a         ;; B = A 
        ;;
        ld a, e_y(ix)
        sub e_y(ix)
        ;;
        add b           ;; A = diferenciaX + diferencia Y (con player1)
        ld c, a         ;; C = A


        ;; IY => PLAYER 2
        ld de, #k_size_entity
        add iy, de


        ;; CALCULO DIFERENCIAS CON PLAYER 2, y lo guardo en A
        ld a, e_x(iy)   ;; A = PlayerX
        sub e_x(ix)      ;; A = playerX - enemyX
        ld b, a         ;; B = A 

        ld a, e_y(ix)
        sub e_y(ix)
        
        add b           ;; A = diferenciaX + diferencia Y (con player1)
        

        ; si la diferencia en A < C (objetivo del player2)
        cp c
        jp m, no_multi_player
            ;; player 1 mas cerca
            ld b, e_x(iy)
            ld c, e_y(iy)

            ld e_aim_X(ix), b
            ld e_aim_Y(ix), c

    no_multi_player:
    
    ;pop iy
    

    ;; Metemos la posicion objetivo del Zombie en los datos de la entidad aim_X y aim_Y
    
ret 

velocidades_enemigo_patron:
    .db #1, #4 ;; velocidad abajo derecha
    .db #1, #-4 ;; velocidad arriba derecha
    .db #-1, #4 ;; velocidad abajo izquierda
    .db #-1, #-4 ;; velocidad arriba izquierda

ia_patron:
    ld a, (timer_direccion)
    cp #0
    jr nz, no_move
        ;; Si el tiempo llega a 0
        call cambia_direccion_patron
        ld a, #0x30
    no_move:
    dec a
    ld (timer_direccion), a
ret

cambia_direccion_patron:
    call cpct_getRandom_mxor_u8_asm ;; Destroys AF, BC, DE, HL
    ld a, l
    and #0x03   ; Me devuelve una de estas opciones --> 00 01 10 11 (0,1,2 o 3 en A)

    ld hl, #velocidades_enemigo_patron

    comprueba_aleatorio:
    or a
    cp #0
    jr z, encontrada
        inc hl
        inc hl
        dec a
        jr comprueba_aleatorio
    encontrada:

    ld (registro_aux_ix2), hl

    ld iy, (registro_aux_ix2)
    ld a, 0(iy)
    ld b, 1(iy)
    ld e_vx(ix), a
    ld e_vy(ix), b
ret

ia_topo:

    ;; IX => Topo

    ;; Miramos si tenemos objetivo
    ld a, e_aim_X(ix)
    cp #0
    jr nz, ya_tenemos_objetivo
        ;; NO tenemos un objetivo

        ;; Cogemos los datos del jugador y nos los ponemos como objetivo
        call target_player  

        ;; le quitamos 1 a la X (porque peta en el borde drcho)
        ld a, e_aim_X(ix)   ; A = 44
        cp #0x40            ; A = 44 - 40
        jp m, no_resto_X
            ;; Si estoy en el borde derecho
            dec e_aim_X(ix)
            dec e_aim_X(ix)
        no_resto_X:

    ya_tenemos_objetivo:

    ;; Llamamos a MoveTo
    call move_to

    ;; Si la velocidad del topo (Vx==0 y Vy==0) --> habré llegado al objetivo
    ld a, e_vx(ix)
    cp #0
    jr nz, no_ha_llegado_a_objetivo
        ;; VX == 0 
        ld a, e_vy(ix)
        cp #0
        jr nz, no_ha_llegado_a_objetivo

            ;; VX == 0 y VY==0  --> topo llega al objetivo

            ;; Ya no es invencible
            ld e_invencibilidad(ix), #0x00

            inc e_player_shot(ix)
            ld a, e_player_shot(ix)
            cp #0x40        ;; Esto es lo que debe tardar la animacion del topo cuando esta arriba
            jr nz, contador_no_ha_acabado
                ;; Si el topo ha estado parado un rato entonces, resetea el objetivo a 0, para que se vuelva a mover
                ld a, #0
                ld e_aim_X(ix), a
                ld e_aim_Y(ix), a

                ;; Resetea tamb el contador
                ld e_player_shot(ix), a

                ;; Y ahora ya es invencible (pasa a estar bajo tierra)
                ld e_invencibilidad(ix), #0x01

            contador_no_ha_acabado:
            ret
    no_ha_llegado_a_objetivo:
        ld e_invencibilidad(ix), #0x01
    
ret

ia_cangrejo:

    push ix

    ;; Reseteamos la invencibilidad (se le puede disparar)
    ld a, #0
    ld e_invencibilidad(ix), a

    ;; Miramos si hay un disparo vivo desde hace mucho
    ld a, (num_entities)
    ld ix, #entity_vector
    ld bc, #k_size_entity
    add ix, bc

    recorremosEntidades: ;; menos el player

        ld b, a ; B = num_entidades_restantes

        ;;comprobamos si la entidad es valida o no
        ld a, e_tipo(ix) 
        cp #e_type_invalid
        jr z, noHayValidas

        ;; Comprobamos si es de tipo disparo
        cp #e_type_shot
        jr nz, no_Es_disparo
            ;; Es un disparo

            ;; Comprobamos si lleva vivo X tiempo if(a > 10)
            ld a, e_player_shot(ix)
            cp #0x0A
            jp m, no_se_protege
                jr cangrejo_protegete
            no_se_protege:
        no_Es_disparo:

        push bc

        ;; Pasamos a la siguiente entidad
        ld bc, #k_size_entity
        add ix, bc 
        
        pop bc 
        ld a, b
        dec a
        jr nz, recorremosEntidades

    noHayValidas:

    pop ix

    call ia_seguimiento_player

ret

cangrejo_protegete:

    pop ix

    ld a, #0x00 

    ;; Lo dejamos parado
    ld e_vx(ix), a 
    ld e_vy(ix), a

    ; Invencibilidad = true
    ld a, #1
    ld e_invencibilidad(ix), a
  

    ;; Cambiamos sprite ¿depende de reichel, a lo mejor no hace falta tampoco?

    
ret


;; Esta IA es para los disparos del player. Simplemente actualiza el contador (se va a reutilizar la variable player_Shot)
;; PlayerShot se supone que es para el player (0-puede disparar // 1-no puede pq ya habia disparado)
;; Pues para el Shot, es un contador de cuantas iteraciones lleva vivo el disparo. Se usa para que los cangrejos/escuderos se escondan
ia_update_cont_shot:
    ;; IX => Disparo
    inc e_player_shot(ix)

ret

ia_variable_tiempo:
;; Si el timer es mayor de 80, tomamos ia de arriba a abajo, si es mayor de 40 de izquierda a derecha y si es menor que te siga
    ld a, (timer_ia_variable)
    cp #50
    jp p, mueve_arriba
        push af
        call ia_mover_drcha_izq ;; Esta es la llamada que ejecuta el comportamiento 1 >>>>>>>>>>
        pop af
        jp modificar_timer
        ;; Si quisieramos cambiar los dos comportamientos que siguen, solo cambiamos la linea de arrriba y la de abajo
    mueve_arriba:
    push af
    call ia_mover_arriba_abajo ;; y esta el comportamiento 2 >>>>>>>>>>>>>

    pop af
    
    modificar_timer:
    dec a
    cp #0
    jp nz, timer_no_cero
        ld a, #100
    timer_no_cero:
    ld (timer_ia_variable), a
ret

ia_update_one:
    ld l, e_iaL(ix)
    ld h, e_iaH(ix)

    ;ld hl, e_ia(ix)
    ld (metodo_IA), hl
    metodo_IA = . + 1
    call ia_mover_drcha_izq
ret


ia_update:
    ;; COMPROBAR SIGNATURE CON entity_doForAll_matching
    ld hl, #ia_update_one
    ld b , #e_cmp_ia
    call entity_doForAll_matching
ret