;MIT License

;Copyright (c) 2021 Fedora Adventures Pixeltronics

;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.
.include "physics.h.s"
.include "man/entity.h.s"
.include "game.h.s"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE ACTUALIZACION DE TODAS LAS FISICAS
;;
;; Descripcion
;;
;; Parametros de entrada
;;
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_update:
; Llamo a la funcion de actualizar la fisica del personaje
    call sys_physics_update_pj
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE ACTUALIZACION DE LA FISICA DEL PERSONAJE
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_update_pj:

    ;compruebo si el personaje se tiene que mover a la izquierda
    call sys_physics_pj_move_left
    ;compruebo si el personaje se tiene que mover a la derecha
    call sys_physics_pj_move_right
    ;actualizo componente X
    ld b, e_vx(ix)
    ld a, e_x(ix)
    add b
    ld e_x(ix), a
    ;compruebo si el personaje esta en accion de caida
    call sys_physics_pj_fall
    ;compruebo si el personaje esta en accion de salto
    call sys_physics_pj_jump
    ;actualizo componente Y
    ld b, e_vy(ix)
    ld a, e_y(ix)
    add b
    ld e_y(ix), a
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE COMIENZO DEL SALTO
;;
;; Descripcion
;;    Se actualiza la velocidad vertical del personaje y se obtiene la altura maxima a la que puede llegar el pj con ese salto, 
;;    considerando siempre que el personaje no este ya saltando (para evitar multiples pulsaciones del boton de salto), ni
;;    cayendo (porque si el pj no esta apoyado en una supercicie, no puede saltar)
;; Parametros de entrada
;; - IX: puntero a la entidad personaje
;; Parametros de salida
;;
;; Modifica los registros
;; - AF, B
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_initialize_pj_jump:
    ;compruebo si el pj esta saltando ya, o esta cayendo
    ld a, #(e_cmps_phy_jumping | e_cmps_phy_falling)  ;cargo el vector de componentes en a
    and e_cmps_physics(ix)                    
    jr nz, fin_funcion_spipj            ;si alguna de las dos componentes es 1, esta comparacion no sera 0, por lo que no debo inicializar
    ;;inicializo el salto
    ld  a, e_y(ix)                      ;posicion actual
    sub e_altura_salto(ix)              ;altura que puede saltar el pj
    jr c, cargar_0_spipj
    ld e_maxy(ix), a                    ;altura maxima a la que llegara el pj durante el salto
    jr continuar_funcion_spipj
cargar_0_spipj:
    ld  e_maxy(ix), #0                  ;el maximo es 0 porque choca con el techo
continuar_funcion_spipj:
    ld e_vy(ix), #-1                    ;velocidad vertical, porque esta saltando

    ld a, e_cmps_physics(ix)            ;cargo el vector de componentes
    or #(e_cmps_phy_jumping)            ;añado la componente de salto al vector
    ld e_cmps_physics(ix), a            ;guardo el vector actualizado
fin_funcion_spipj:
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE SALTO
;;
;; Descripcion
;; 
;; Parametros de entrada
;; - IX: Puntero a la entidad personaje
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_pj_jump:
    ;compruebo si estoy saltando (el bit de salto esta activo)
    ld a, #(e_cmps_phy_jumping)
    ld b, e_cmps_physics(ix)                    ;cargo el vector de componentes en a
    and b                               ;miro solo la componente de salto
    ;si no estoy saltando, voy al final
    jr z, fin_funcion_sppj
    ;si estoy saltando
    ; compruebo si ya he llegado al maximo de la altura que puedo saltar
    ld a, e_y(ix)
    ld b, e_maxy(ix)
    sub b                                   ;comparo ambas posiciones
    jr z, actualizar_flags_pj_sppj          ;si es cero, he llegado al maximo y tengo que empezar a bajar
    ; compruebo si choco contra la parte inferior de alguna plataforma
    call sys_physics_check_all_collisions_move_up
    ;si choco con alguna tengo que dejar de saltar y empezar a caer
    cp a, #1    
    jr z, actualizar_flags_pj_sppj
    ;si no he chocado con ninguna y puedo seguir subiendo, pongo la velocidad de subida en -1 para ir para arriba
    ld e_vy(ix), #-1
    jr fin_funcion_sppj
actualizar_flags_pj_sppj:                   ;actualizo los flags de salto y caída
    ;pongo a 0 el flag e_cmps_phy_jumping
    ld b, #(e_cmps_phy_jumping)
    ld a, e_cmps_physics(ix)                    ;cargo el vector de componentes en a
    xor b                               ;pongo en flag en 0
    ;pongo a 1 el flag e_cmps__phy_falling
    ld b, #(e_cmps_phy_falling)
    or b
    ld e_cmps_physics(ix), a
fin_funcion_sppj:                           ;fin de la funcion
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE MOVIMIENTO A LA IZQUIERDA
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_pj_move_left:
    
    ld a, e_cmps_physics(ix)                    ;cargo el vector de componentes
    and #(e_cmps_phy_left)
    jr z, fin_funcion_sppml                     ;si no estoy moviendo a la izquierda, voy al final
    ld a, e_x(ix)
    cp a, #0                                ;compruebo si estoy a la izquierda del todo de la pantalla
    jr z, fin_funcion_sppml                 ;en caso de estar, simplemente no muevo al personaje y salgo de la funcion
    ;compruebo si choco contra la parte derecha de alguna plataforma
    call sys_physics_check_all_collisions_move_left
    cp a, #1
    jr z, fin_funcion_sppml
    ;si no choco con nada y no estoy a la izquierda de la pantalla, pongo la velocidad a -1 para ir a la izquierda
    ld e_vx(ix), #-1
fin_funcion_sppml:
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE MOVIMIENTO A LA DERECHA
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_pj_move_right:

    ld a, e_cmps_physics(ix)                    ;cargo el vector de componentes
    and #(e_cmps_phy_right)
    jr z, fin_funcion_sppmr                     ;si no estoy moviendo a la izquierda, voy al final
    ;compruebo si estoy a la derecha del todo de la pantalla
    ld b, e_w(ix)
    ld a, e_x(ix)
    add b                                   ;a la coordenada x le sumo el ancho del objeto, para ver si toco la pared derecha
    cp a, #80
    jr z, fin_funcion_sppmr                 ;en caso de estar, simplemente no muevo al personaje y salgo de la funcion
    ;compruebo si choco contra la parte derecha de alguna plataforma
    call sys_physics_check_all_collisions_move_right
    cp a, #1
    jr z, fin_funcion_sppmr
    ;si no choco con nada y no estoy a la derecha de la pantalla, pongo la velocidad a 1 para ir a la derecha
    ld e_vx(ix), #1
fin_funcion_sppmr:
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE ACTUALIZACION DE LA CAIDA DEL PERSONAJE
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_pj_fall:
    ;compruebo si estoy en trayectoria ascendente durante un salto. Es el unico momento donde no puedo caer
    ld a, #(e_cmps_phy_jumping)  
    ld b, e_cmps_physics(ix)                    ;cargo el vector de componentes en a
    and b
    ;salgo de la funcion porque no se aplica
    jr nz, fin_funcion_sppf
    ;compruebo si estoy en la parte inferior de la pantalla, pues ahi muero
    ld a, e_y(ix)
    ld b, e_h(ix)
    add b
    cp a, #200
    jr nz, sppf_continue
    call sys_game_die
;    jr fin_funcion_sppf
    ;compruebo si choco contra la parte superior de alguna plataforma
sppf_continue:
    call sys_physics_check_all_collisions_move_down
    cp a, #1
    ;si he colisionado con una plataforma, dejo de caer
    jr z, sppf_detener_caida                
sppf_caer: 
    ld e_vy(ix), #1
    ;marcar el flag de caida a 1
    ld a, e_cmps_physics(ix)
    ld b, #(e_cmps_phy_falling)             ;cargo el vector de componentes en a
    or b                                ;pongo en flag en 1
    ld e_cmps_physics(ix), a
    ;salgo de la funcion de caida
    jr fin_funcion_sppf  
sppf_detener_caida:
    ld e_vy(ix), #0                         ;velocidad de caida = 0
    ;marcar el flag de caida a 0 
    ld a, e_cmps_physics(ix)                    ;cargo el vector de componentes en a
    res 4, a                               ;pongo en flag en 0  
    ld e_cmps_physics(ix), a  
fin_funcion_sppf:    
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE ESTA DE PIE SOBRE ALGUN OBJETO
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;; - IY: Puntero a una entidad plataforma
;; - IX: Puntero a la entidad personaje
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, c, DE, IX, IY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_all_collisions_move_down:
    ;cargo en IX el puntero del personaje
;    call man_entity_put_player_in_ix
    ;hay que recorrer todos los objetos de tipo plataforma del juego. Para ello tengo que hacer dos cosas:
    ;cargo el puntero a la primera entidad en el registro IY
    call man_entity_put_platforms_in_iy
    call getNumEntities
    ld c, #3
    sub c
    ld c, a              ;cargo el numero de entidades menos cuatro, que son el personaje, la lava, la puerta y el tesoro    
bucle_spcacmd:    
    call sys_physics_check_collisions_move_down         ;compruebo que no chocan el personaje yl tesoro actual
    cp a, #1
    jr z, spcacmd_return_1                              ;si chocan, he acabado el bucle y retorno 1
    ;si no, hago la siguiente iteracion del bucle
spcacmd_preparar_siguiente_iteracion:
    dec c
    jr z, spcacmd_return_0                  ;si ya no me quedan entidades que revisar, salgo del bucle y retorno 0
    ;si no, paso a la siguiente plataforma a comprobar y vuelvo al principio del bucle
    ld de, #entity_size
    add iy, de                              ;siguiente plataforma
    jr bucle_spcacmd
spcacmd_return_0:
    ld a, #0
    jr fin_funcion_spcacmd  
spcacmd_return_1:
    ld a, #1
fin_funcion_spcacmd:    
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE ESTA DE PIE SOBRE UN OBJETO CONCRETO
;;
;; Descripcion
;;   Comprueba si las coordenadas X e Y del personaje y una entidad indicada se solapan en algun punto.
;;
;; Parametros de entrada
;; - IX: puntero a la entidad plataforma
;; - IY: puntero a la entidad personaje
;;
;; Parametros de salida
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, B
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_collisions_move_down:
    ;obtengo la coordenada Y del personaje y le sumo su altura. Esa es su parte inferior
    ld a, e_y(ix)
    add e_h(ix)
    ld b, e_y(iy)               ;cargo la coordenada Y del tesoro
    cp b                        ;comparo ambas coordenadas Y a ver si son iguales
    jr nz, spccmd_poner_a_a_0   ;si son distintas, he terminado de comprobar porque el pj yl tesoro están a distinta altura
    ;si son iguales, entonces he detectado que el personaje puede estar pisando esa plataforma concreta. Hay que comprobar las coordenadas X
    ld a, e_x(ix)               ;cargo la coordenada X del personaje
    add e_w(ix)               ;cargo la anchura del personaje y los sumo
    ld b, a                     ;guardo el valor en el registro B
    ld a, e_x(iy)               ;cargo la coordenada X del tesoro               
    sub b                       ;si al restar, obtengo negativo, es porque la parte derecha del personaje es menor que la parte izquierda del tesoro, por lo que no se tocan
    jr nc, spccmd_poner_a_a_0
    ;pero si el carry es cero, hay que comprobar el choque por el otro lado del tesoro
    ld a, e_x(iy)               ;cargo la coordenada X del tesoro
    add e_w(iy)               ;cargo la anchura del tesoro y las sumo
    ld b, a                     ;guardo el valor en B
    ld a, e_x(ix)               ;cargo la coordenada X del personaje
    sub b                       ;si al restar obtengo negativo, es porque el personaje está más a la derecha que la parte derecha del tesoro, y por tanto no chocan
    jr nc, spccmd_poner_a_a_0
    ld a, #1
    jr fin_funcion_spccmd
spccmd_poner_a_a_0:    
    ld a, #0
fin_funcion_spccmd:
ret 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE SE DA EN LA CABEZA CON ALGUNA PLATAFORMA
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;; - IX: Puntero a una entidad plataforma
;; - IY: Puntero a la entidad personaje
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, C, DE, IX, IY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_all_collisions_move_up:
    ;cargo en IY el puntero del personaje
;    call man_entity_put_player_in_ix
    ;hay que recorrer todos los objetos de tipo plataforma del juego. Para ello tengo que hacer dos cosas:
    ;cargo el puntero a la primera entidad en el registro IX
    call man_entity_put_platforms_in_iy
    call getNumEntities
    ld c, #3
    sub c
    ld c, a              ;cargo el numero de entidades menos cuatro, que son el personaje, la lava, la puerta y el tesoro     
bucle_spcacmu:    
    call sys_physics_check_collisions_move_up         ;compruebo que no chocan el personaje yl tesoro actual
    cp a, #1
    jr z, spcacmu_return_1                              ;si chocan, he acabado el bucle y retorno 1
    ;si no, hago la siguiente iteracion del bucle
spcacmu_preparar_siguiente_iteracion:
    dec c
    jr z, spcacmu_return_0                  ;si ya no me quedan entidades que revisar, salgo del bucle y retorno 0
    ;si no, paso a la siguiente plataforma a comprobar y vuelvo al principio del bucle
    ld de, #entity_size
    add iy, de                              ;siguiente plataforma
    jr bucle_spcacmu
spcacmu_return_0:
    ld a, #0
    jr fin_funcion_spcacmu 
spcacmu_return_1:
    ld a, #1
fin_funcion_spcacmu:    
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE SE DA EN LA CABEZA CON UN OBJETO CONCRETO
;;
;; Descripcion
;;   Comprueba si las coordenadas X e Y del personaje y una entidad indicada se solapan en algun punto.
;;
;; Parametros de entrada
;; - IX: puntero a la entidad plataforma
;; - IY: puntero a la entidad personaje
;;
;; Parametros de salida
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, B
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_collisions_move_up:
    ;obtengo la coordenada Y del tesoro y le sumo la altura 
    ld a, e_y(iy)
    ld b, e_h(iy)
    add b
    ld b, e_y(ix)               ;cargo la coordenada Y del personaje
    cp b                        ;comparo ambas coordenadas Y a ver si son iguales
    jr nz, spccmu_poner_a_a_0   ;si son distintas, he terminado de comprobar porque el pj yl tesoro están a distinta altura
    ;si son iguales, entonces he detectado que el personaje puede estar golpeando esa plataforma concreta. Hay que comprobar las coordenadas X
    ld a, e_x(ix)               ;cargo la coordenada X del personaje
    ld b, e_w(ix)               ;cargo la anchura del personaje y los sumo
    add b
    ld b, a                     ;guardo el valor en el registro B
    ld a, e_x(iy)               ;cargo la coordenada X del tesoro               
    sub b                       ;si al restar, obtengo negativo, es porque la parte derecha del personaje es menor que la parte izquierda del tesoro, por lo que no se tocan
    jr nc, spccmu_poner_a_a_0
    ;pero si el carry es cero, hay que comprobar el choque por el otro lado del tesoro
    ld a, e_x(iy)               ;cargo la coordenada X del tesoro
    ld b, e_w(iy)               ;cargo la anchura del tesoro y las sumo
    add b
    ld b, a                     ;guardo el valor en B
    ld a, e_x(ix)               ;cargo la coordenada X del personaje
    sub b                       ;si al restar obtengo negativo, es porque el personaje está más a la derecha que la parte derecha del tesoro, y por tanto no chocan
    jr nc, spccmu_poner_a_a_0
    ld a, #1
    jr fin_funcion_spccmu
spccmu_poner_a_a_0:    
    ld a, #0
fin_funcion_spccmu:
ret  

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE CHOCA CONTRA CON ALGUNA PLATAFORMA QUE ESTE A SU IZQUIERDA
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;; - IX: Puntero a una entidad plataforma
;; - IY: Puntero a la entidad personaje
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, B, DE, IX, IY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_all_collisions_move_left:
    ;cargo en IX el puntero del personaje
    call man_entity_put_player_in_ix
    ;hay que recorrer todos los objetos de tipo plataforma del juego.
    ;cargo el puntero a la primera entidad en el registro IY
    call man_entity_put_platforms_in_iy
    call getNumEntities
    ld c, #3
    sub c
    ld c, a              ;cargo el numero de entidades menos cuatro, que son el personaje, la lava, la puerta y el tesoro 
bucle_spcacml:    
    call sys_physics_check_collisions_move_left         ;compruebo que no chocan el personaje yl tesoro actual
    cp a, #1
    jr z, spcacml_return_1                              ;si chocan, he acabado el bucle y retorno 1
    ;si no, hago la siguiente iteracion del bucle
spcacml_preparar_siguiente_iteracion:
    dec c
    jr z, spcacml_return_0                  ;si ya no me quedan entidades que revisar, salgo del bucle y retorno 0
    ;si no, paso a la siguiente plataforma a comprobar y vuelvo al principio del bucle
    ld de, #entity_size
    add iy, de                              ;siguiente plataforma
    jr bucle_spcacml
spcacml_return_0:
    ld a, #0
    jr fin_funcion_spcacml 
spcacml_return_1:
    ld a, #1
fin_funcion_spcacml:    
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE CHOCA A LA IZQUIERDA CON UN OBJETO CONCRETO
;;
;; Descripcion
;;   Comprueba si las coordenadas X e Y del personaje y una entidad indicada se solapan en algun punto.
;;
;; Parametros de entrada
;; - IX: puntero a la entidad plataforma
;; - IY: puntero a la entidad personaje
;;
;; Parametros de salida
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, B
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_collisions_move_left:
    ;obtengo la coordenada X del tesoro y le sumo su anchura
    ld a, e_x(iy)
    ld b, e_w(iy)
    add b
    ld b, e_x(ix)               ;cargo la coordenada X del personaje
    cp b                        ;comparo ambas coordenadas X a ver si son iguales
    jr nz, spccml_poner_a_a_0   ;si son distintas, he terminado de comprobar porque el pj yl tesoro están a distinta distancia
    ;si son iguales, entonces he detectado que el personaje puede estar golpeando esa plataforma concreta. Hay que comprobar la coordenada Y
    ld a, e_y(iy)               ;cargo la coordenada Y del tesoro
    ld b, e_h(iy)               ;cargo la altura del tesoro y los sumo. Esto es la parte inferior del tesoro
    add b
    ld b, a                     ;guardo el valor de la cabeza en el registro B
    ld a, e_y(ix)               ;cargo la coordenada Y del personaje . Esto es su cabeza              
    sub b                       ;si al restar, obtengo negativo, es porque la cabeza del personaje esta por debajo que la parte inferior del tesoro, por lo que no se tocan
    jr nc, spccml_poner_a_a_0
    ;pero si el carry es cero, hay que comprobar los pies del personaje
    ld a, e_y(ix)               ;cargo la coordenada Y del personaje
    ld b, e_h(ix)               ;cargo la altura del personaje y los sumo. Esa es la altura de los pies
    add b
    dec a
    ld b, e_y(iy)               ;cargo la coordenada Y del tesoro (la altura)
    sub b                       ;si al restar obtengo negativo, es porque los pies del personaje estan por encima del tesoro, y por tanto no chocan
    jr c, spccml_poner_a_a_0
    ld a, #1
    jr fin_funcion_spccml
spccml_poner_a_a_0:    
    ld a, #0
fin_funcion_spccml:
ret  

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE CHOCA CONTRA CON ALGUNA PLATAFORMA QUE ESTE A SU DERECHA
;;
;; Descripcion
;; 
;; Parametros de entrada
;;
;; Parametros de salida
;; - IX: Puntero a una entidad plataforma
;; - IY: Puntero a la entidad personaje
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, B, DE, IX, IY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_all_collisions_move_right:
    ;cargo en IY el puntero del personaje
;    call man_entity_put_player_in_iy
    ;hay que recorrer todos los objetos de tipo plataforma del juego.
    ;cargo el puntero a la primera entidad en el registro IX
    call man_entity_put_platforms_in_iy
    call getNumEntities
    ld c, #3
    sub c
    ld c, a              ;cargo el numero de entidades menos cuatro, que son el personaje, la lava, la puerta y el tesoro 
bucle_spcacmr:    
    call sys_physics_check_collisions_move_right        ;compruebo que no chocan el personaje yl tesoro actual
    cp a, #1
    jr z, spcacmr_return_1                              ;si chocan, he acabado el bucle y retorno 1
    ;si no, hago la siguiente iteracion del bucle
spcacmr_preparar_siguiente_iteracion:
    dec c
    jr z, spcacmr_return_0                  ;si ya no me quedan entidades que revisar, salgo del bucle y retorno 0
    ;si no, paso a la siguiente plataforma a comprobar y vuelvo al principio del bucle
    ld de, #entity_size
    add iy, de                              ;siguiente plataforma
    jr bucle_spcacmr
spcacmr_return_0:
    ld a, #0
    jr fin_funcion_spcacmr
spcacmr_return_1:
    ld a, #1
fin_funcion_spcacmr:    
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION PARA COMPROBAR SI EL PERSONAJE CHOCA A LA DERECHA CON UN OBJETO CONCRETO
;;
;; Descripcion
;;   Comprueba si las coordenadas X e Y del personaje y una entidad indicada se solapan en algun punto.
;;
;; Parametros de entrada
;; - IX: puntero a la entidad plataforma
;; - IY: puntero a la entidad personaje
;;
;; Parametros de salida
;; - A: 1 si el personaje choca contra alguna plataforma, 0 si no chocan
;;
;; Modifica los registros
;; AF, B
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_collisions_move_right:
    ;obtengo la coordenada X del personaje y le sumo su anchura
    ld a, e_x(ix)
    ld b, e_w(ix)
    add b
    ld b, e_x(iy)               ;cargo la coordenada X del tesoro
    cp b                        ;comparo ambas coordenadas X a ver si son iguales
    jr nz, spccmr_poner_a_a_0   ;si son distintas, he terminado de comprobar porque el pj yl tesoro están a distinta distancia
    ;si son iguales, entonces he detectado que el personaje puede estar golpeando esa plataforma concreta. Hay que comprobar la coordenada Y
    ld a, e_y(ix)               ;cargo la coordenada Y del personaje
    ld b, e_h(ix)               ;cargo la altura del personaje y los sumo
    add b
    ld b, a                     ;guardo el valor de la cabeza en el registro B
    ld a, e_y(iy)               ;cargo la coordenada Y del tesoro               
    sub b                       ;si al restar, obtengo negativo, es porque la cabeza del personaje esta por debajo que la parte inferior del tesoro, por lo que no se tocan
    jr nc, spccmr_poner_a_a_0
    ;pero si el carry es cero, hay que comprobar los pies del personaje
    ld a, e_y(iy)               ;cargo la coordenada Y del tesoro
    ld b, e_h(iy)               ;cargo la altura del tesoro y las sumo
    add b
    dec a
    ld b, e_y(ix)               ;cargo la coordenada Y del personaje (los pies)
    sub b                       ;si al restar obtengo negativo, es porque los pies del personaje estan por encima del tesoro, y por tanto no chocan
    jr c, spccmr_poner_a_a_0
    ld a, #1
    jr fin_funcion_spccmr
spccmr_poner_a_a_0:    
    ld a, #0
fin_funcion_spccmr:
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE CHOQUE DEL JUGADOR CON EL DIAMANTE
;;
;; Descripcion
;;
;; Parametros de entrada
;; - IX: Puntero de la entidad que se mueve y colisiona
;; - IY: Puntero de la entidad que esta fija y algo choca contra ella
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_collision:
    ; EJE HORIZONTAL
    ; IY < IX
    ld a, e_x(iy)           ;Coordenada X del tesoro
    ld b, a                 ;Muevo a b para usarlo más tarde
    add e_w(iy)
    ld c, e_x(ix)           ;Anchura del tesoro. La cargo en C para reutilizar mas abajo
    sub c                   ;Coordenada X del personaje
    ret c                   ;Si la resta es < 0, Carry = 1. No hay colision. Fin de la funcion
    ; IX < IY
    ld a, c                 ;Coordenada X del personaje
    add e_w(ix)             ;Anchura de del personaje. La sumo directamente
    sub b                   ;Resto la coordenada X del tesoro
    ret c                   ;Si la resta es < 0, Carry = 1. No hay colision. Fin de la funcion
    ; EJE VERTICAL
    ; IY < IX
    ld a, e_y(iy)           ;Coordenada Y del tesoro
    ld b, a                 ;Muevo a b para usarlo más tarde
    add e_h(iy)
    ld c, e_y(ix)           ;Altura del tesoro. La cargo en C para reutilizar mas abajo
    sub c                   ;Coordenada Y del personaje
    ret c                   ;Si la resta es < 0, Carry = 1. No hay colision. Fin de la funcion
    ; IX < IY
    ld a, c                 ;Coordenada Y del personaje
    add e_h(ix)             ;Altura de del personaje. La sumo directamente
    sub b                   ;Resto la coordenada Y del tesoro
    ;No es necesario hacer el ultimo ret. El carry se respeta al volver, y es lo que hay que usar como retorno de la funcion   
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; FUNCION DE CHOQUE DEL JUGADOR CON LA PUERTA
;;
;; Descripcion
;;
;; La funcion va a reutilizar componentes de la puerta que no se usan, para construir una bounding box mas pequeña. Las componentes son:
;;
;; Nueva X: E_vX
;; Nueva Y: E_VY
;; Nueva H: E_ALTURA_SALTO
;; Nueva W: E_MAXY
;;
;;
;; Parametros de entrada
;; - IX: Puntero de la entidad que se mueve y colisiona
;; - IY: Puntero de la entidad que esta fija y algo choca contra ella
;; Parametros de salida
;;
;; Modifica los registros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sys_physics_check_door_collision:
    ; EJE HORIZONTAL
    ; IY < IX
    ld a, e_vx(iy)           ;Coordenada X del tesoro
    ld b, a                 ;Muevo a b para usarlo más tarde
    add e_maxy(iy)
    ld c, e_x(ix)           ;Anchura del tesoro. La cargo en C para reutilizar mas abajo
    sub c                   ;Coordenada X del personaje
    ret c                   ;Si la resta es < 0, Carry = 1. No hay colision. Fin de la funcion
    ; IX < IY
    ld a, c                 ;Coordenada X del personaje
    add e_w(ix)             ;Anchura de del personaje. La sumo directamente
    sub b                   ;Resto la coordenada X del tesoro
    ret c                   ;Si la resta es < 0, Carry = 1. No hay colision. Fin de la funcion
    ; EJE VERTICAL
    ; IY < IX
    ld a, e_vy(iy)           ;Coordenada Y del tesoro
    ld b, a                 ;Muevo a b para usarlo más tarde
    add e_altura_salto(iy)
    ld c, e_y(ix)           ;Altura del tesoro. La cargo en C para reutilizar mas abajo
    sub c                   ;Coordenada Y del personaje
    ret c                   ;Si la resta es < 0, Carry = 1. No hay colision. Fin de la funcion
    ; IX < IY
    ld a, c                 ;Coordenada Y del personaje
    add e_h(ix)             ;Altura de del personaje. La sumo directamente
    sub b                   ;Resto la coordenada Y del tesoro
    ;No es necesario hacer el ultimo ret. El carry se respeta al volver, y es lo que hay que usar como retorno de la funcion   
ret