;; MIT License
;; 
;; Copyright (c) 2021 capAI / Aitana Devis  Ávila (@AitanaDevis) / Carlos Peñarrubia Morcillo  (@carlospm12) / Pablo Ruiz Ponce (@pabloruizp)
;; 
;; 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 "cpctelera.h.s"
.include "../man/entity.h.s"
.include "collisions.h.s"

game_over_text: .asciz "  You died!  "
press_key_text: .asciz "Press any key"
auxControlJump: .db 0
auxIsInAir: .db 1
   ;;Esta constante tambien está en physiscs.s pero deberia estar en entity.h.s

PARTE_BAJA_P = #P_H_INITIAL-2

sys_collision_update:
    ld a, #1
    ld (auxIsInAir), a   ;; Asumo que el player está en el aire
    ld hl, #sys_collision_check
    call _man_entity_forall

    call sys_collision_check_suelo
    dec a
    jr nz, continuar_collision_update
    call set_aux_air_false      ;; Como hay colision hay que poner a false el byte de aire
    call sys_collision_with_suelo

    continuar_collision_update:

    ld a, (auxIsInAir)
    cp #1
    jr z, is_in_air
    ret
    is_in_air:
    call sumar_gravedad
    ret


;;///////////////////////////////////////////////////////////////////////
;; FUNCION PARA COMPROBAR SI COLISIONA EL JUGADOR CON UNA ENTIDAD
;;
;; PARAMETROS: DE (ENTIDAD)
;;
;; REGISTROS MODIFICADOS: IX, IY, A, B (+ LAS QUE MODIFIQUE LA FUNCION A LA QUE LLAMAMOS)
;;
;; RETURN: NADA
;;///////////////////////////////////////////////////////////////////////
sys_collision_check:
    ld ix, #_player     ;;CARGO EL JUGADOR

    push de
    pop iy      ;;PONGO LA ENTIDAD EN IY

    call sys_collision_check_entity
    dec a
    jr nz, finish_coll_check

    ;;; SI HA LLEGADO HASTA AQUÍ ES QUE HAY COLISION
    call set_aux_air_false      ;; Como hay colision hay que poner a false el byte de aire
    call sys_collision_check_type_entity
    jp finish_coll_check

    finish_coll_check:
    ret

sys_collision_check_entity:
    ld a, E_OFFSET_L(iy)
    cp #0
    jp nz, no_collision_with_entity

    ld a, P_X(ix)   
    add P_W(ix)   ;;Esta en a el punto más a la derecha del player
    sub #1 ;Le resto un byte para que no sea tan estricta la colision
    sub E_OFFSET_H(iy)   ;;Se le resta a la posicion más a la derecha de player la posicion más a la izquierda de entidad
    jr c, no_collision_with_entity   

    ld a, E_OFFSET_H(iy)
    add E_W(iy)
    sub #3   ;;Este 3 es porque la entidad tiene 2 bytes por dentras que son de color fondo y +1 para más margen
    sub P_X(ix)
    jr c, no_collision_with_entity 

    ld a, P_Y(ix)
    add P_H(ix)
    sub E_Y(iy)
    jr c, no_collision_with_entity 

    ld a, E_Y(iy)
    add E_H(iy)
    sub #1  ;Le resto un byte para que no sea tan estricta la colision
    sub P_Y(ix)
    jr c, no_collision_with_entity 
    
    ld a, #1
    ret
    no_collision_with_entity:
    ld a, #0
    ret


sys_collision_check_type_entity:
    ;;;COMPRUEBO SI ES UN BLOQUE LA ENTIDAD CON AL QUE HA CHOCADO PLAYER
    ld a, E_TIPO(iy)
    and #2    ;SUSTITUIR ESTO POR VARIABLE
    jr z, next_pincho_check  ;;Si da 0 no era un bloque
    call sys_collision_with_platform
    ret

    ;;;COMPRUEBO SI ES UN PINCHO LA ENTIDAD CON AL QUE HA CHOCADO PLAYER
    next_pincho_check:
    ld a, E_TIPO(iy)    
    and #4   ;SUSTITUIR ESTO POR VARIABLE
    jr z, next_bonus_check
    call coll_die_player
    ret

    next_bonus_check:
    ld a, E_TIPO(iy)    
    and #8   ;SUSTITUIR ESTO POR VARIABLE
    jr z, next_finalEntity_check
    call sys_collision_with_bonus
    ret

    next_finalEntity_check:
    ld a, E_TIPO(iy)    
    and #16   ;SUSTITUIR ESTO POR VARIABLE
    jr z, next_entity_check
    call coll_finalEntity_player
    ret

    next_entity_check:
    ret

sys_collision_with_platform:
    call sys_collision_check_strict_platform
    dec a
    jr nz, fin_collision_with_platform

    ld a, P_JUMP(ix)
    dec a
    jr z, borrar_player_pos_anterior
    dec a
    jr z, borrar_player_pos_anterior
    ret
    borrar_player_pos_anterior:
    ld P_VY(ix), #0  ;;Poner la velocidad a 0 de player
    ld P_JUMP(ix), #0    ;;Pongo P_Jump a 0
    ld a, E_Y(iy)
    sub P_H(ix)
    ld P_Y(ix), a  ;; Pongo a el jugador justo encima del bloque
    
    fin_collision_with_platform:
    ret

sys_collision_check_strict_platform:

    ld a, P_Y(ix)
    add P_H(ix)
    sub E_Y(iy)
    jr c, fin_check_strict_platform 

    ld a, P_Y(ix)
    add P_H(ix)
    sub #5
    ld b, a

    ld a, E_Y(iy)
    add #5

    cp b
    jr c, fin_check_strict_platform

    ld a, #1
    ret
    fin_check_strict_platform:
    call coll_die_player
    ld a, #0
    ret


sys_collision_check_suelo:
    ld a, P_Y(ix)
    add P_H(ix)
    cp #NIVEL_SUELO
    jr nc, there_is_coll_suelo   ;; Si no hay carry es que el player está más abajo del suelo
    ld a, #0
    ret
    there_is_coll_suelo:
    ld a, #1
    ret

sys_collision_with_suelo:
    ld a, P_JUMP(ix)
    dec a
    jr z, continuar_set_vy_0
    dec a
    jr z, continuar_set_vy_0
    ret
    continuar_set_vy_0:
    ld P_VY(ix), #0  ;;Poner la velocidad a 0 de player
    ld P_JUMP(ix), #0    ;;Pongo P_Jump a 0
    ld a, #NIVEL_SUELO
    sub P_H(ix)
    ld P_Y(ix), a
    ret

sys_collision_with_bonus:
    push de
    push hl
    push ix
    ld l, E_PREV(iy)
    ld h, E_PREV+1(iy)
    ld bc, #continuar_sys_collision_with_bonus
    push bc
    jp (hl)

    continuar_sys_collision_with_bonus:
    push iy
    pop de
    call _man_entity_bonus_consume
    pop ix
    pop hl
    pop de
    ret
    

sumar_gravedad:
    ld a, (auxControlJump)
    cp #0
    jr z, sub_VY_Gravity
    ld a, #0
    ld (auxControlJump), a

    ret
    sub_VY_Gravity:
    ld a, P_VY(ix)
    add #GRAVITY
    ld P_VY(ix), a
    ld a, #1
    ld (auxControlJump), a

    ret

set_aux_air_false:
    ld a, #0
    ld (auxIsInAir), a   ;; Pongo a falso porque o ha chocado contra el suelo o contra una entidad
    ret

coll_die_player:
    push de
    push hl
    push ix
    push iy
    ld P_PREV(ix), #1

    call sys_render_borrar_player_muerte

    ;call print_die_player
    call sys_render_draw_death

    call wait_for_pulsacion

    call _sub_25_score

    pop iy
    pop ix
    pop hl
    pop de
    ret



coll_finalEntity_player:
    push de
    push hl
    push iy
    push ix
    ld P_PREV(ix), #1
    ld hl, #_nivel
    inc (hl)
    call wait_for_pulsacion
    call _add_50_score
    pop ix
    pop iy
    pop hl
    pop de
    ret

wait_for_pulsacion:
    call cpct_scanKeyboard_asm
    call cpct_isAnyKeyPressed_f_asm
    
    cp #0
    jr z, loop_wait_for_pulsacion
    
    loop_wait_for_no_pulsacion:
    call cpct_scanKeyboard_asm
    call cpct_isAnyKeyPressed_f_asm
    cp #0
    jr nz, loop_wait_for_no_pulsacion

    loop_wait_for_pulsacion:
    call cpct_scanKeyboard_asm
    call cpct_isAnyKeyPressed_f_asm
    inc a
    dec a
    jr z, loop_wait_for_pulsacion

    ret

print_die_player:
    ld l, #15
    ld h, #10
    call cpct_setDrawCharM0_asm

    ld iy, #game_over_text
    ld hl, #0xC380
    call cpct_drawStringM0_asm

    ld iy, #game_over_text
    ld hl, #0x8380
    call cpct_drawStringM0_asm

    ld iy, #press_key_text
    ld hl, #0xC3D0
    call cpct_drawStringM0_asm

    ld iy, #press_key_text
    ld hl, #0x83D0
    call cpct_drawStringM0_asm

    ret