.include "keyboard/keyboard.h.s"
.include "physics.h.s"
.include "man/entity.h.s"
.include "man/game.h.s"
.include "man/entity_templates.h.s"
.include "cpctelera.h.s"

.globl bool_disparo

registroAuxiliar2: .dw 0x0000

move_right:

    ld e_last_dir(ix), #1
    ld e_vx(ix), #1
ret 

move_up:
    ld e_last_dirY(ix), #-4
    ld e_vy(ix), #-4
ret 

move_left:
    ld e_last_dir(ix), #-1
    ld e_vx(ix), #-1
    ;ld e_last_dir(ix), #3 ;; Cuando mire hacia la izquierda, la ultima direccion sera 3
ret 

move_down:
    ld e_last_dirY(ix), #4
    ld e_vy(ix), #4
    ;ld e_last_dir(ix), #2 ;; Cuando mire hacia abajo, la ultima direccion sera 2
ret


;; ===================
;; METODO PARA DISPARAR
;; Comprueba que no se haya generado un disparo y crea una nueva entidad disparo
;; ===================
dispara:
    ld a, #0x01
    ld (bool_disparo), a
    
    ld a, e_player_shot(ix)
    cp #0
    jr nz, disparo_lanzado
        ;; Si no se ha disparado, es decir, player_shot = 0
        ;add #1
        ;ld e_player_shot(ix), a
        ld e_atacando(ix), #1
        ld e_player_shot(ix), #1

        push ix
        push iy

        ;; Hacemos que IY => ix (player)
        ld (registroAuxiliar2), ix
        ld iy, (registroAuxiliar2)
        
        ld de, #shot1
        call game_create_template ;; IX => Shot

        ;; Metemos las posiciones y direcciones del Player en Shot
        ld a, e_last_dir(iy)
        ld e_vx(ix), a
        ld a, e_last_dirY(iy)
        ld e_vy(ix), a
        ; La posicion del disparo será el centro del personaje (Y NO LA PARTE DE ARRIBA A LA IZQUIERDA)
        ld a, e_y(iy)               ;; / 
        add #0x08                   ;; | B = Y_player + (Height/2)
        ld e_y(ix), a               ;; \

        ld a, e_x(iy)         ;; A = X
        add #0x01             ;; A = A + 3 (si le ponemos 3, cuando colisiona con el castillo en la parte drcha no colisiona)
        ld e_x(ix), a

        ;; Meto en el ptr pertenece de la bala (ix), un puntero al player (iy)
        ld (registroAuxiliar2), iy
        ld bc, (registroAuxiliar2)
        ld e_perteneceL(ix), c
        ld e_perteneceH(ix), b

        pop iy
        pop ix
        
    disparo_lanzado:

    push hl
    call cpct_akp_SFXStopAll_asm
    pop hl
ret 

;; Tabla para las acciones del teclado
key_actions:
    ;.dw Key_CursorRight, move_right
    .dw Key_P, move_right
    ;.dw Joy0_Right, move_right

    ;.dw Key_CursorLeft, move_left
    .dw Key_O, move_left
    ;.dw Joy0_Left, move_left

    ;.dw Key_CursorUp, move_up
    .dw Key_Q, move_up
    ;.dw Joy0_Up, move_up

    ;.dw Key_CursorDown, move_down
    .dw Key_A, move_down
    ;.dw Joy0_Down, move_down

    .dw Key_Space, dispara
    ;.dw Joy0_Fire1, dispara
    .dw 0

key_actions2:
    .dw Key_CursorRight, move_right
    .dw Key_CursorLeft, move_left
    .dw Key_CursorUp, move_up
    .dw Key_CursorDown, move_down
    .dw Key_Return, dispara
    .dw 0


;; ===============================
;; INPUT TECLADO
;; Input:
;; Output:
;; ===============================
physics_keyboard:
    ld e_vx(ix), #0
    ld e_vy(ix), #0

    ;; Comprueba el teclado
    call cpct_scanKeyboard_asm    

    ;; Bucle para recorrer las acciones del teclado
    ld iy, #key_actions-4 ;; la primera vez que entro no hay que hacer el iy++, asi que al principio resto 4 para que al sumarle luego 4 se quede apuntando a la primera KEY

    ;; Comprobamos si el player 2 para cambiar el key_Actions
    ld (registroAuxiliar2), ix
    ld hl, (registroAuxiliar2)
    ld a, h
    cp #>entity_vector
    jr z, no_Cambio_teclado
        ;; Si no coincide la parte alta, es el player 2
       ld iy, #key_actions2-4
    no_Cambio_teclado:

    ld a, l
    cp #<entity_vector
    jr z, no_Cambio_teclado2
        ;; Si no coincide la parte baja, es el player 2
       ld iy, #key_actions2-4
    no_Cambio_teclado2:
    

    loop_keys:

        ;; IY -> NextKey (iy++)
        ld bc, #4
        add iy, bc

        ;; HL = next key
        ld l, 0(iy)
        ld h, 1(iy)

        ;; Comprobamos si Key=NULL (hemos llegado al final de las acciones)
        ld a, l     ; A = L
        or h        ; A = L | H 
        ret z       ; if (key=NULL) ret

        ;; Comprobamos si Key estaba pulsada
        call cpct_isKeyPressed_asm
        jr z, loop_keys

        ;; Se esta pulsando la tecla
        ld hl, #loop_keys   ;; /  Meto en la pila la dirección a la que quiero que vuelva despues de que
        push hl             ;; \  se haga el ret, cuando voy a jp(hl) (porque no ponemos call)

        ;; HL = puntero a funcion de la accion
        ld l, 2(iy)        
        ld h, 3(iy)        
        
        jp (hl)            ;; Salto a la funcion de acción


actualiza_last_dir:
    ; Si solo nos movemos en un eje, e_last_dir debe ser actualizado
        ld a, e_vx(ix)
        cp #0
        jr z, no_solo_un_eje
            ;; si vx != 0, comprobamos si vy == 0
            ld a, e_vy(ix)
            cp #0 
            jr nz, no_solo_un_eje
                ; vx!=0 & vy==0
                ld e_last_dirY(ix), #0
                jr sigue_recorriendo_keys
        no_solo_un_eje:
        ; vx == 0
        ld a, e_vy(ix)
        cp #0 
        jr z, sigue_recorriendo_keys
            ;; vy != 0  &  vx == 0
            ld e_last_dir(ix), #0

        sigue_recorriendo_keys:
ret

;; ===============================
;; ACTUALIZAR UNA ENTIDAD
;; Input:
;; Output:
;; ===============================
physics_update_one:
    ;; SI LA ENTIDAD TIENE INPUT COMPROBAR TECLADO 
    ld a, e_cmps(ix)
    and #e_cmp_input
    cp #e_cmp_input
    jr nz, no_input
        call physics_keyboard

        call actualiza_last_dir

    no_input:

    ;; Comprobamos (contActualizarPhysics == iteracionMax)
    ld a, e_actualizaMove(ix)
    sub e_contMove(ix)
    cp #0
    jr nz, siguiente_iteracion

        ;; contActualizarPhysics = iteracionMax --> Actualizamos posicion
        ld e_contMove(ix), #0x00    ; cont = 0

        ;; COMPROBAMOS LA POSICION DE LA ENTIDAD
        ;; PARA VER SI ESTA EN UN BORDE

        ;; ---------- X - PARTE IZQUIERDA ----------
        ld a, e_x(ix)
        cp #6
        jr nz, actualizaXizq
            ;; Estoy en X = 0
            ld hl, #no_actualizaX
            ld (metodoCheckBorder), hl
            ld a, e_vx(ix)      ;; a = vx
            cp #0               
            jp m, check_tipo_bala_en_el_borde ;; if (vx < 0)  no_actualizaX
        
        ;; X = 0 y VX positiva
        actualizaXizq:


        ;; ---------- X - PARTE DERECHA  ----------
        ld a, #0x50-#6      ; A = X_derecha
        ld c, e_w(ix)
        sub a, c
        ld b, a             ; B = X_derecha - Player_Width
        ld a, e_x(ix)       ; A = playerX

        cp b
        jr nz, actualizaXdrcha ; if (x == bordeDrcha-anchoSprite) actulizaDrcha
            ;; Estoy en X = bordeDrcha
            ld hl, #no_actualizaX
            ld (metodoCheckBorder), hl
            ld a, e_vx(ix)      ;; a = vx
            cp #0               

            jp p, check_tipo_bala_en_el_borde ;; if (vx > 0)  no_actualizaX

            actualizaXdrcha:
        ;;  x = x + vx
        ld a, e_x(ix)
        add e_vx(ix)
        ld e_x(ix), a

        no_actualizaX:


        ;; ---------- Y - PARTE ARRIBA ----------
        ld a, e_y(ix)
        cp #32

        jr nz, actualizaYarriba
            ;; Estoy en Y = 0
            ld hl, #no_actualizaY
            ld (metodoCheckBorder), hl

            ld a, e_vy(ix)      ;; a = vy
            cp #0         
            jp m, check_tipo_bala_en_el_borde ;; if (vy < 0)  no_actualizaX
        
        ;; X = 0 y VX positiva
        actualizaYarriba:


        ;; ---------- Y - PARTE ABAJO ----------
        ld a, #0xC8-#24     ; A = Y_ABAJO
        ld c, e_h(ix)       ; C = Player_height
        sub a, c            ; A = y_abajo - playerHeigjt
        ld b, a
        ld a, e_y(ix)       ; A = playerY
        cp b

        jr nz, actualizaYabajo ; if (x == bordeDrcha-anchoSprite) actulizaDrcha
            ;; Estoy en X = bordeDrcha
            ld hl, #no_actualizaY
            ld (metodoCheckBorder), hl
            ld a, e_vy(ix)      ;; a = vx
            cp #0               
            jp p, check_tipo_bala_en_el_borde ;; if (vx > 0)  no_actualizaX

            actualizaYabajo:
        ;;  y = y + vy
        ld a, e_y(ix)
        add e_vy(ix)
        ld e_y(ix), a

        no_actualizaY:

ret

siguiente_iteracion:
    inc e_contMove(ix)
ret

; Si una bala llega al borde, se elimina
check_tipo_bala_en_el_borde:
    ld a, e_tipo(ix)
    cp #e_type_shot
    metodoCheckBorder = . + 1
    jp nz, #no_actualizaX

    ;; Es una bala en el borde, entonces la borramos
    call entity_set4destruction

    ;; Metemos en HL la direccion de la entidad a la que pertenece
    ;; Esto es: si la bala es del player1, pues ptr->player1, si la bala es del arquero ptr->arquero
    ld l, e_perteneceL(ix)
    ld h, e_perteneceH(ix)
    ;; IY = HL
    ld__iy_hl

    ;; Actualizamos el player_shot del (player1, arquero... o lo que indique la bala)
    ld e_player_shot(iy), #0
ret


;; ===============================
;; EJECUTA PARA TODAS LAS ENTIDADES
;; Input:
;; Output:
;; ===============================
physics_update:
    ;; COMPROBAR SIGNATURE CON entity_doForAll_matching
    ld hl, #physics_update_one
    ld b, #e_cmp_movable
    call entity_doForAll_matching
ret