;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of Nightmare Fortress: An Amstrad CPC Game 
;;  Copyright (C) 2017 Natalia Bernal Pérez / Álvaro Esteve Bernabeu / Plácido Antonio López Ávila
;;
;;  Nightmare Fortress is free software: you can redistribute it and/or modify
;;  it under the terms of the GNU Lesser General Public License as published by
;;  the Free Software Foundation, either version 3 of the License, or
;;  (at your option) any later version.
;;
;;  Nightmare Fortress 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 Lesser General Public License for more details.
;;
;;  You should have received a copy of the GNU Lesser General Public License
;;  along with Nightmare Fortress.  If not, see <http://www.gnu.org/licenses/>.
;;-------------------------------------------------------------------------------

.area _DATA
.area _CODE


;;-----------------------------------------------------------------------
;;PRIVATE DATA 
;;-----------------------------------------------------------------------
.include "cpctelera.h.s"
.include "keyboard/keyboard.s"
.include "utils.h.s"
.include "macros.h.s"
.include "sprites/sprites.h.s"
.include "actors/shoot.h.s"
.include "gameController.h.s"
.include "dobleBuffer.h.s"
.include "gameController.h.s"
.include "stage.h.s"

.globl isr
.globl isr_void
.globl isr50

 pauseText: .asciz "PAUSE"

;;--------------------------------------------
playerShootPeriod: .db #11             ;;PARAMETRO PARA CONTROLAR LA CADENCIA DE DISPARO DEL JUGADOR (SOLUCION TEMPORAL)
playerShootPeriodORG: .db #11           ;;VARIABLE AUXILIAR PARA REESTABLECER LA ORIGINAL CUANDO LLEGUE A 0
                                        ;;MENOS VALOR EN LAS 2 VARIABLES = CADENCIA DE TIRO MAS RAPIDA
;;--------------------------------------------
playerActionPeriod: .db #0              ;;PARAMETRO PARA CONTROLAR LA VELOCIDAD DEL JUGADOR (SOLUCION TEMPORAL)
playerActionPeriodORG: .db #0           ;;VARIABLE AUXILIAR PARA REESTABLECER LA ORIGINAL CUANDO LLEGUE A 0
;;--------------------------------------------
                                                                                                                                                                                                    
defineEntity char, 12, 150, 4, 16, #_g_sprite_front_1, 0, 12, 150, 12, 150, 0, #_g_sprite_front_1, #_g_sprite_front_2, #_g_sprite_side_1, #_g_sprite_side_2, #_g_sprite_back_1, #_g_sprite_back_2, 12, #_g_sprite_left_1, #_g_sprite_left_2, 0, 4




;;defineEntity char, 39, 36, 4, 16, #_g_warrior1_front_1, 0, 39, 36, 39, 36, 0, #_g_warrior1_front_1, #_g_warrior1_front_2, #_g_warrior1_side_1, #_g_warrior1_side_2, #_g_warrior1_back_1, #_g_warrior1_back_2, 12, #_g_warrior1_left_1, #_g_warrior1_left_2, 0, 4
;;defineEntity char, 39, 36, 4, 16, #_g_evilwizard_front_1, 0, 39, 36, 39, 36, 0, #_g_evilwizard_front_1, #_g_evilwizard_front_2, #_g_evilwizard_side_1, #_g_evilwizard_side_2, #_g_evilwizard_back_1, #_g_evilwizard_back_2, 12, #_g_evilwizard_left_1, #_g_evilwizard_left_2, 0, 4

;;-----------------------------------------------------------------------
;;PUBLIC FUNCTIONS
;;-----------------------------------------------------------------------


;;------------------------------------------------
;; Devuelve un puntero al primer atributo del personaje
;;
;;	<- IX ahora apuntara a los datos del personaje
;;------------------------------------------------
character_getPtrIX::
    ld ix, #char_data
    ret


character_getPtrIX_hl::
    ld hl, #char_data
    ret

character_getPtrIX_iy::
    ld iy, #char_data
    ret


;;ESTADOS
;; 0-Parado, 1-Ataque, 2-Derecha, 3-Abajo, 4-Izquierda, 5-Arriba
;;------------------------------------------------
;; Dibuja el personaje con la animacion correspondiente (TEMPORAL, NECESITA MEJORA)
;; 
;;------------------------------------------------
character_draw::
    
    call character_getPtrIX
    call entity_state

    ret
;;--------------------------------------------------------------------------------------------------------






;;--------------------------------------------------------------------------------------------------------
;;  Carga en IX el puntero a la entidad que se quiera borrar y redibuja el fondo que estaba detras
;;--------------------------------------------------------------------------------------------------------

character_erase::
    call character_getPtrIX
    call entity_erase
    ret



;;-----------------------------------------------------------------------
;;  Comprueba que teclas han sido pulsadas por el jugador y realiza la accion pertinente
;;-----------------------------------------------------------------------
character_check_input::

    call character_getPtrIX

    ;;PARA CONTROLAR LA VELOCIDAD DEL JUGADOR
    ;;--------------------------
   ; ld a, (playerActionPeriod)          ;; Comprobamos si el jugador ha completado 1 periodo para saber si puede volver a moverse
   ; cp #0
   ; jp z, comprobar_teclado            ;; Si la variable es 0 entonces el jugador podra moverse
   ;     dec a                           ;; En caso de que no sea 0 se decrementa la variable, se guarda y no se deja mover al jugador
   ;     ld (playerActionPeriod), a  
   ;     ret
   ; comprobar_teclado:
   ; ld a, (playerActionPeriodORG)
   ; ld (playerActionPeriod), a
    ;;-----------------------------




	ld a, (char_state)				;; Guardamos el estado actual del jugador en el estado anterior
	ld (char_last_state), a			;; |
    ld a, #0
    ld (char_moving), a

    ld a, (playerShootPeriod)
    cp #0
    jp z, checkShootKey
        dec a
        ld (playerShootPeriod), a


    checkShootKey:
    call cpct_scanKeyboard_f_asm

    call cpct_isAnyKeyPressed_f_asm ;;Si no hay ninguna tecla pulsada salimos de la rutina
    cp #0                           ;; A == 0?
    ret z                           ;; |


    ld hl, #Key_P
    call cpct_isKeyPressed_asm
    cp #0
    jr z, pause_not_pressed
    call print_pause
        ;;PAUSE PRESSED 
        suelta_tecla:
            call cpct_scanKeyboard_f_asm
            ld hl, #Key_P
            call cpct_isKeyPressed_asm
            cp #0
            jp nz, suelta_tecla
        loop_pause:
            call cpct_scanKeyboard_f_asm
            ld hl, #Key_P
            call cpct_isKeyPressed_asm
            cp #0
            jp z, loop_pause
        suelta_tecla2:
            call cpct_scanKeyboard_f_asm
            ld hl, #Key_P
            call cpct_isKeyPressed_asm
            cp #0
            jp nz, suelta_tecla2
            call erase_pause



    pause_not_pressed:
    ld hl, #Key_Space
    call cpct_isKeyPressed_asm
    cp #0
    jr z, space_not_pressed
        ;;SPACE IS PRESSED
        ld a, (playerShootPeriod)
        cp #0
        jp nz, space_not_pressed

            ld a, (playerShootPeriodORG)
            ld (playerShootPeriod), a
            call character_getPtrIX
            call try_spawn_shoot
            jp s_not_pressed


    space_not_pressed:

    ld hl, #Key_D
    call cpct_isKeyPressed_asm
    cp #0
    jr z, d_not_pressed				;;

         ;;D IS PRESSED
        ld a, (char_x)              ;;Si la letra pulsada ha sido D, cambiamos la posicion del jugador en el eje X
        cp #0x4B
        jp nc, d_not_pressed
        ld a, (char_x)
        inc a
        ld (char_x), a

        ;call comprobar_pared            ;; Comprueba si el tile de abajo es suelo para poder moverse
        

        ld a, #2
        ld (char_state), a          ;;Actualizamos el estado del jugador
        ld a, #1
        ld (char_moving), a
        call tile_collision
        cp #1                   ;; A - 1 sin modificar A
        jp z, d_pressed_pared           ;; IF (A-1) == 0 en la posicion hay pared ELSE es suelo la siguiente posicion
        jp a_not_pressed            ;;Si se ha pulsado D, no se comprobara si se ha pulsado A
  
    ;;--

    d_not_pressed:

    ld hl, #Key_A
    call cpct_isKeyPressed_asm
    cp #0
    jr z, a_not_pressed             ;;
        ;;A IS PRESSED
        ld a, (char_x)              ;;Si la letra pulsada ha sido A, cambiamos la posicion del jugador en el eje X
        cp #02
        jp c, a_not_pressed
        ld a, (char_x)
        dec a
        ld (char_x), a


        ld a, #4
        ld (char_state), a          ;;Actualizamos el estado del jugador
        ld a, #1
        ld (char_moving), a
        call tile_collision
        cp #1                   ;; A - 1 sin modificar A
        jp z, a_pressed_pared           ;; IF (A-1) == 0 en la posicion hay pared ELSE es suelo la siguiente posicion
        
    ;;--
        

    a_not_pressed:

    ld hl, #Key_W
    call cpct_isKeyPressed_asm
    cp #0
    jr z, w_not_pressed             ;;
        ;;W IS PRESSED
        ld a, (char_y)              ;;Si la letra pulsada ha sido W, cambiamos la posicion del jugador en el eje Y
        cp #02
        jp c, w_not_pressed
        ld a, (char_y)
        sub #2
        ld (char_y), a



        ld a, #5
        ld (char_state), a          ;;Actualizamos el estado del jugador
        ld a, #1
        ld (char_moving), a
        call tile_collision            ;; Comprueba si el tile de abajo es suelo para poder moverse
    	cp #1                   ;; A - 1 sin modificar A
    	jp z, w_pressed_pared           ;; IF (A-1) == 0 en la posicion hay pared ELSE es suelo la siguiente posicion
        jp s_not_pressed            ;;Si se ha pulsado W, no se comprobara si se ha pulsado S   

    ;;--

    w_not_pressed:

    ld hl, #Key_S
    call cpct_isKeyPressed_asm
    cp #0   
    jr z, s_not_pressed             ;;
        ;;S IS PRESSED
        ld a, (char_y)              ;;Si la letra pulsada ha sido S, cambiamos la posicion del jugador en el eje Y
        cp #182
        jp z, s_not_pressed
        ld a, (char_y)
        add #2
        ld (char_y), a



        ld a, #3
        ld (char_state), a          ;;Actualizamos el estado del jugador
        ld a, #1
        ld (char_moving), a
        call tile_collision
        cp #1                   ;; A - 1 sin modificar A
        jp z, s_pressed_pared           ;; IF (A-1) == 0 en la posicion hay pared ELSE es suelo la siguiente posicion
    
      
    ;;--
    s_not_pressed:
    ret


    ;; Se trata del salto cuando se pulsa D y no se puede acceder a la posicion porque es una pared
    d_pressed_pared:
        ld a, (char_x)              ;; Cargamos en A el valor de la X del personaje
        dec a                   ;; Decrementamos la posicion del personaje en el eje
        ld (char_x), a              ;; Cargamos en X el nuevo valor del personaje ya actualizado
        jp a_not_pressed

    ;; Se trata del salto cuando se pulsa A y no se puede acceder a la posicion porque es una pared
    a_pressed_pared:
        ld a, (char_x)              ;; Cargamos en A el valor de la X del personaje
        inc a                   ;; Incrementamos la posicion del personaje en el eje
        ld (char_x), a              ;; Cargamos en X el nuevo valor del personaje ya actualizado
        jp a_not_pressed

    ;; Se trata del salto cuando se pulsa W y no se puede acceder a la posicion porque es una pared
    w_pressed_pared:
        ld a, (char_y)              ;; Cargamos en A el valor de la Y del personaje
        add #2                  ;; Incrementamos la posicion del personaje en el eje
        ld (char_y), a              ;; Cargamos en Y el nuevo valor del personaje ya actualizado
        jp s_not_pressed

    ;; Se trata del salto cuando se pulsa S y no se puede acceder a la posicion porque es una pared
    s_pressed_pared:
        ld a, (char_y)              ;; Cargamos en A el valor de la Y del personaje
        sub #2                  ;; Decrementamos la posicion del personaje en el eje
        ld (char_y), a              ;; Cargamos en Y el nuevo valor del personaje ya actualizado
        jp s_not_pressed

;;------------------------------------------------
;; Llama a la funcion generica que modifica las x y las y para el doble buffer
;;
;;  -> IX es el puntero a la entidad que se quiere modificar
;;------------------------------------------------
character_update_xy::
    call entity_update_xy
    ret



print_pause:
  ld hl, #isr_void
  call cpct_setInterruptHandler_asm
  call cpct_akp_stop_asm

  ld hl, (pointerScreen)
  ex de, hl
  ld c, #32
  ld b, #96
  ;ld c, #31
  ;ld b, #130
  call cpct_getScreenPtr_asm 
  ex de, hl
  ld   hl, #pauseText              ;; HL = Pointer to the start of the string
  ld   bc, #0x090D              ;; B = Background colour, C = Foreground colour
  call cpct_drawStringM0_asm 

  call switchBuffers

  ld hl, (pointerScreen)
  ex de, hl
  ld c, #32
  ld b, #96
  ;ld c, #31
  ;ld b, #130
  call cpct_getScreenPtr_asm 
  ex de, hl
  ld   hl, #pauseText              ;; HL = Pointer to the start of the string
  ld   bc, #0x090D              ;; B = Background colour, C = Foreground colour
  call cpct_drawStringM0_asm 

  call switchBuffers

  ret

erase_pause:

    ld c, #32
    srl c
    ld b, #96
    srl b
    srl b

    ld d, #2
    ld e, #10

    ld a, #40
    ld hl, #0x0041  ;; Guardamos en la pila el puntero al tilemap, para llamar a la funcion de abajo
    push hl             ;;
    ld hl, (pointerScreen)     ;; Guardamos en la pila el puntero a la direccion de memoria de video donde se debe pintar
    push hl

    call  cpct_etm_drawTileBox2x4_asm

    call switchBuffers

    ld c, #32
    srl c
    ld b, #96
    srl b
    srl b

    ld d, #2
    ld e, #10

    ld a, #40
    ld hl, #0x0041  ;; Guardamos en la pila el puntero al tilemap, para llamar a la funcion de abajo
    push hl             ;;
    ld hl, (pointerScreen)     ;; Guardamos en la pila el puntero a la direccion de memoria de video donde se debe pintar
    push hl

    call  cpct_etm_drawTileBox2x4_asm
    call switchBuffers

    ld ix, (currentStage)
    ld a, num_level(ix)
    cp #18
    ret z
    cp #19
    jp z, esMusica19
    cp #4
    call z, pinta_phantis_pausa
    ld hl, #isr
    call cpct_setInterruptHandler_asm
    ret

    esMusica19:
        ld hl, #isr50
        call cpct_setInterruptHandler_asm
        ret


check_reset_key::
    call cpct_scanKeyboard_f_asm
    call cpct_isAnyKeyPressed_f_asm ;;Si no hay ninguna tecla pulsada salimos de la rutina
    cp #0                           ;; A == 0?
    ret z                           ;; |


    ld hl, #Key_R
    call cpct_isKeyPressed_asm
    cp #0
    jp nz, reset
        ld a, #0
        ret

    reset:
        ld a, #1 
        ret
