;;---------------------------------------------------------------------------------------------------------------
;#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/.
;;----------------------------------------------------------------------------------------------------------------


;;
;; Game manager declaration
;;
.include "cpctelera.h.s"
.include "man/entity.h.s"

.globl man_entity_create
.globl man_entity_init
.globl sys_physics_update
.globl sys_render_update
.globl cpct_waitVSYNC_asm
.globl man_entity_update
.globl sys_render_init
.globl man_entity_create_player
.globl sys_physics_update
.globl sys_input_update
.globl sys_render_player_orientate
.globl sys_collision_update
.globl man_entity_create_mina
.globl sys_collision_aftermatch 
.globl man_entity_update 
.globl sys_collision_tiles
.globl cpct_waitHalts_asm
.globl man_level_map
.globl sys_render_animations_update
.globl man_entity_create_valla
.globl man_init_level_boss;;carga el nivel boss
.globl man_init_level_arco;;carga el nivel arcoiris
.globl man_init_level1;;carga el nivel de 1
.globl man_init_level2;;carga el nivel de 2
.globl man_init_level3;;carga el nivel de 3
.globl man_init_level4;;carga el nivel de 1
.globl man_init_level5;;carga el nivel de 2
.globl man_init_level6;;carga el nivel de 3
.globl man_init_level7;;carga el nivel de 1
.globl man_init_level8;;carga el nivel de 2
.globl man_init_level9;;carga el nivel de 3
.globl level_output
.globl entities
.globl next_free_entity
.globl entities_created
.globl intentos
.globl draw_score
.globl man_entity_create_rotatorio
.globl man_entity_create_torreta
.globl man_entity_create_arachnoid
.globl man_entity_create_fuego
.globl man_entity_create_switch
.globl man_entity_create_puerta
.globl man_entity_create_cchamber
.globl is_switch_on
.globl play_lvl1_music
.globl play_lvl2_music
.globl play_lvl3_music
.globl play_lvl9_music
.globl play_lvl4_music
.globl play_lvl5_music
.globl play_lvl6_music
.globl play_lvl7_music
.globl play_lvl_arco_music
.globl play_lvl_Boss_music
.globl play_lvl8_music
.globl man_entity_create_cyborg
.globl sys_physics_ia_update
.globl man_entity_create_chica
.globl man_entity_create_mono
.globl entities_created
.globl is_switch_on

tamColumnas: .db 20
tamFilas: .db 25
posx: .db 0
posy: .db 0
dir_tile: .dw 0

wait::
    ld h, #4
    inicio:
        ld b, #2
        call cpct_waitHalts_asm
        call cpct_waitVSYNC_asm

        dec h
        jr nz, inicio
    ret

game_init::
    ;; Resetear el output del nivel
    ld a, #2
    ld (level_output), a

    ;; Resetear las variables creadas
    ld a, #0
    ld (entities_created), a
    ld (dir_tile), a
    ld (posx), a
    ld (posy), a
    ld (is_switch_on), a

    ;; Resetear el puntero
    ld hl, #entities
    ld (next_free_entity), hl

    ld a, #20
    ld (tamColumnas), a 

    ld a, #25
    ld (tamFilas), a 

    call sys_render_init
    call man_entity_init

    ret

game_play::
    bucle_inf:
      call sys_physics_ia_update
      call sys_physics_update
      call sys_input_update
      call sys_render_player_orientate
      call sys_collision_update
      call sys_collision_aftermatch ;; Procesar el aftermatch de las colisiones
      call sys_collision_tiles
      call cpct_waitVSYNC_asm
      call sys_render_update
      call man_entity_update ;; Procesara las entidades que estan marcadas para destruir
      call sys_render_animations_update

      ld a, (level_output)

      cp #0
      jr z, fin_nivel

      cp #1
      jr z, fin_nivel

      cp #3
      jr z, fin_nivel
    jr bucle_inf

    fin_nivel:

    ret 

game_play_boss::
    bucle_inf_boss:

     ;; Logica para el final boss:
     ld a, (entities_created)
     cp #9
     jr nz, girl_is_not_safe
     
     ;; Ponemos a on el switch:
     ld a, #1
     ld (is_switch_on), a
 
     girl_is_not_safe:

    call sys_physics_ia_update
    call sys_physics_update
    call sys_input_update
    call sys_render_player_orientate
    call sys_collision_update
    call sys_collision_aftermatch ;; Procesar el aftermatch de las colisiones
    call sys_collision_tiles
    call cpct_waitVSYNC_asm
    call sys_render_update
    call man_entity_update ;; Procesara las entidades que estan marcadas para destruir
    call sys_render_animations_update

    ld a, (level_output)

    cp #0
    jr z, fin_nivel_boss

    cp #1
    jr z, fin_nivel_boss

    jr bucle_inf_boss

fin_nivel_boss:

ret 


;; 
;; El objetivo de esta funcion sera recorrer los tipos de tiles del nivel para poder generar las entidades que correspondan
;; Input: HL -> Direccion de memoria inicial de los datos del tile
compute_tiles::

    recorre:
        ld (dir_tile), hl
        ld a, (hl) ;; Cargamos el dato del tile

        cp #40
        jp z, tile_player

        cp #44
        jp z, tile_arachnoid

        cp #43
        jp z, tile_cyborg

        cp #47
        jp z, tile_cyborg_spawner

        cp #45
        jp z, tile_torreta

        cp #46
        jp z, tile_rotatorio

        cp #42
        jp z, tile_mina

        cp #9
        jp z, tile_fuego_barril

        cp #11
        jp z, tile_fuego_coche

        cp #22
        jp z, tile_fuego_coche

        cp #41
        jp z, tile_valla

        cp #48
        jp z, tile_puerta

        cp #49
        jp z, tile_switch

        ;; Si llega aqui no es ningun tipo de tile Spawn, por lo que lo ignoramos y pasamos al siguiente:
        jp siguiente_tile


        tile_cyborg:
            call man_entity_create_cyborg
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_cyborg_spawner:
            call man_entity_create_cchamber
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_torreta:
            call man_entity_create_torreta
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile
        
        tile_fuego_barril:
            call man_entity_create_fuego
            ld a, (posx)
            inc a
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_fuego_coche:
            call man_entity_create_fuego
            ld a, (posx)
            inc a
            ld e_x(ix), a

            ld a, (posy)
            inc a
            inc a
            ld e_y(ix), a

            ;; Modificamos su sprite
            ld hl, #_spr_fire_3 
            ld e_spriteupperbyte(ix), h
            ld e_spritelowerbyte(ix), l
            ld e_ts(ix), #4
            jp siguiente_tile

        tile_arachnoid:
            call man_entity_create_arachnoid
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_player:
            call man_entity_create_player
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_rotatorio:
            call man_entity_create_rotatorio
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_mina:
            call man_entity_create_mina            
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile


        tile_valla:
            call man_entity_create_valla
            
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_puerta:
            call man_entity_create_puerta
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            ld e_y(ix), a
            jp siguiente_tile

        tile_switch:
            call man_entity_create_switch
            ld a, (posx)
            ld e_x(ix), a

            ld a, (posy)
            dec a
            dec a
            dec a
            dec a
            ld e_y(ix), a
            jp siguiente_tile

        siguiente_tile:

        ld a, (tamColumnas)
        dec a
        
        jp nz, sigueLaFila

        ;; Si llega aqui, hemos llegado al final de la fila, por lo tanto:
        ld a, #20
        ld (tamColumnas), a ;; Reseteamos su valor
        ld hl, (dir_tile)
        inc hl ;; Pasamos a la siguiente posicion del tile

        ;; Pasamos a la siguiente fila:
        ld a, (tamFilas)
        dec a

        jr z, finalFila

        ;; Si llega aqui, significa que aun tenemos filas por iterar!
        ld (tamFilas), a

        ;; Reseteamos el valor de la X:
        ld a, #0
        ld (posx), a

        ;; Aumentamos la Y en 8 (ya que los tiles tienen 8 bytes de alto)
        ld a, (posy)
        ld b, #8
        add a, b
        ld (posy), a

        jp recorre

        finalFila:
            ;; Si llega aqui, significa que ya se ha terminado el bucle, por lo tanto terminamos
            ret

        ;; Si llega aqui, significa que aun queda fila por recorrer
        sigueLaFila: 
            ld (tamColumnas), a ;; Ponemos el nuevo valor de A
            ld hl, (dir_tile)
            inc hl ;; Apuntamos a la siguiente posicion!

            ;; Actualizamos la X actual 
            ld a, (posx)
            ld b, #4

            add a, b ;; Sumamos 4 bytes! Ya que el tile tiene 4 bytes de ancho
            ld (posx), a
            jp recorre    
    ret

play_lvl::

    inicio_lvl:
    call game_init
    ld hl, #man_level_map
    call compute_tiles
    call draw_score
    call game_play

    ;; El juego puede salir con dos estados, 0 o 1. Si sale con un 1, significa que el jugador ha conseguido llegar a la puerta objetivo.
    ;; Si sale con estado 0, significa que el jugador ha muerto en la pantalla.
    ;; Jugamos con esto para crear la logica:

    ld a, (level_output)
    cp #1
    jr z, output_success

    cp #3
    jr z, output_success

    ;; Si llegamos aqui, significa que el jugador ha muerto, por lo tanto, vemos si le quedan intentos para seguir pasandose el nivel:

    ;; Si nos quedan intentos,  respawneamos, si no, game over:
    ld a, (intentos)
    dec a

    jr z, cero_intentos 

    ;; Si llegamos aqui, significan que le quedan intentos, por lo que le damos una oportunidad mas volviendo a cargar el mismo nivel:
    ld (intentos), a ;; Escribimos los intentos y ya
    jp inicio_lvl

    cero_intentos:
    output_success:

    ld a, (level_output)
  
    ret


play_lvl_boss_ingame::

    inicio_lvl_boss:
    call game_init
    ld hl, #man_level_map
    call compute_tiles
    call man_entity_create_chica
    call man_entity_create_mono
    call draw_score
    call game_play_boss

    ;; El juego puede salir con dos estados, 0 o 1. Si sale con un 1, significa que el jugador ha conseguido llegar a la puerta objetivo.
    ;; Si sale con estado 0, significa que el jugador ha muerto en la pantalla.
    ;; Jugamos con esto para crear la logica:

    ld a, (level_output)
    cp #1

    jr z, output_success_boss

    ;; Si llegamos aqui, significa que el jugador ha muerto, por lo tanto, vemos si le quedan intentos para seguir pasandose el nivel:

    ;; Si nos quedan intentos,  respawneamos, si no, game over:
    ld a, (intentos)
    dec a

    jr z, cero_intentos_boss

    ;; Si llegamos aqui, significan que le quedan intentos, por lo que le damos una oportunidad mas volviendo a cargar el mismo nivel:
    ld (intentos), a ;; Escribimos los intentos y ya
    jp inicio_lvl_boss

    cero_intentos_boss:
    output_success_boss:

    ld a, (level_output)

ret

play_lvl_boss::
    call play_lvl_Boss_music
    call man_init_level_boss
    call play_lvl_boss_ingame
    ret

play_lvl_arco::
    call play_lvl_arco_music
    call man_init_level_arco
    call play_lvl
    ret

play_lvl_1::
    call play_lvl1_music
    call man_init_level1
    call play_lvl
    ret

play_lvl_2::
    call play_lvl2_music
    call man_init_level2
    call play_lvl
    ret

play_lvl_3::
    call play_lvl3_music
    call man_init_level3
    call play_lvl
    ret

play_lvl_4::
    call play_lvl4_music
    call man_init_level4
    call play_lvl
    ret

play_lvl_5::
    call play_lvl5_music
    call man_init_level5
    call play_lvl
    ret

play_lvl_6::
    call play_lvl6_music
    call man_init_level6
    call play_lvl
    ret

play_lvl_7::
    call play_lvl7_music
    call man_init_level7
    call play_lvl
    ret

play_lvl_8::
    call play_lvl8_music
    call play_lvl8_music
    call man_init_level8
    call play_lvl
    ret

play_lvl_9::
    call play_lvl9_music
    call man_init_level9
    call play_lvl
    ret

