;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of CPCtelera: An Amstrad CPC Game Engine 
;;  Copyright (C) 2021 Daniel José García Evans, Iván Alejandro Ontano Herrera,
;;  Sergio Izquierdo Pintado (PyroClastic Software)
;;
;;  Special Thanks to Ennio Fernando Velásquez Berlingeri (PyroBombastic)
;;
;;  This program 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.
;;
;;  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

;;
;;COLLISION SYSTEM
;;

.include "../globals.h.s"

collision_counter: .db #0
collision_counter_iy: .db #0

cmps_collider = (e_cmps_alive | e_cmps_physics | e_cmps_collider)
cmps_collisionable = (e_cmps_alive | e_cmps_collisionable)

sys_collision_update::
    call man_entity_first           ;;loop_elem_ptr en ix
    ld a, #max_entities
    
    collision_loop:
        ld (collision_counter), a       ;;actualizo el contador
        ld a, e_cmps(ix)
        ld b, #cmps_collider
        and b
        cp b
        jr nz, next_iteration    ;;si no cumple la mascara me salto esta entidad ix
            call man_entity_first_iy        ;;loop_elem_ptr_iy en iy
            ld a, #max_entities

            collision_loop_iy:
                ld (collision_counter_iy), a    
                ld a, e_cmps(iy)
                ld b, #cmps_collisionable
                and b
                cp b
                jr nz, next_iteration_iy     ;;si no cumple la mascara me salto esta entidad iy ;;######aqui no entra ninguna entidad
                    ;;call sys_collision_update_II                           ;;#####################con esto deberia provocar un bucle infinito aposta
                    call sys_collision_check_collision  ;;metodo de comprobacion de colisiones

                next_iteration_iy:
                call man_entity_next_iy         ;;loop_elem_ptr_iy en iy
                ld a, (collision_counter_iy)    ;;cargo el contador
                dec a                           ;;decremento el contador
                jr nz, collision_loop_iy

        next_iteration:
        call man_entity_next        ;;loop_elem_ptr en ix
        ld a, (collision_counter)   ;;cargo el contador
        dec a                       ;;decremento el contador
        jr nz, collision_loop


    ret


;;IX collider
;;IY collisionable 
sys_collision_check_collision:
    ;;COLLIDER: IX
    ;;COLLISIONABLE: IY

    ;;EJE VERTICAL
        ;;caso 1 (si el COLLIDER esta arriba del COLLISIONABLE): IX.y < IY.y
    ld a, e_y(iy)
    ld b, a
    add e_h(iy)
    dec a
    ld c, e_y(ix)
    sub e_y(ix)
    ret c   ;;si no se solapan para

        ;;caso 2 (si el COLLIDER esta debajo del COLLISIONABLE): IY.y < IX.y
    ld a, c
    add e_h(ix)
    dec a
    sub e_y(iy)   ;;resto e_x(iy)
    ret c   ;;si no se solapan para 


    ;;EJE HORIZONTAL
        ;;caso 3 (si el COLLIDER esta a la izquierda del COLLISIONABLE): IX.x < IY.x
        ;;if( IY.x + IY.w - 1 < IX.x )
        ;;IY.x + IY.w - 1 - IX.x < 0
    ld b, #2    ;:numero de pixeles de margen
    ld a, e_x(iy)               ;;(ix.x + 1 < iy.x - 1) ;;2 pixeles de margen   (ix.x < iy.x - 2)
    add e_w(iy)
    sub b
    ld c, e_x(ix)
    sub e_x(ix)
    ret c   ;;si no se solapan para   ;;si el numero es negativo, se activa el flag de carry, es que no hay colision

        ;;caso 4 (si el COLLIDER esta a la derecha del COLLISIONABLE): IY.x < IX.x
    ld a, c                     ;;(ix.y + 1 < iy.x - 1) ;;2 pixeles de margen   (iy.x < ix.x - 2)
    add e_w(ix)
    sub b   ;;dec a
    sub e_x(iy)   ;;resto e_x(iy)
    ret c   ;;si no se solapan para 

    call sys_collision_check_type_collision

    ret 



sys_collision_check_type_collision::
    ;;##########RESUMEN###############
    ;;si no tiene gravedad es la espada
        ;;si tiene gravedad es el personaje o el duende
        ;;si no es un enemigo es el personaje
            ;;con el personaje compruebo si colisiona con un enemigo o una plataforma, se muere el personaje o se pone encima de la plataforma respectivamente
        ;;si es un enemigo es el duende
            ;;con el duende compruebo si colisiona con un enemigo o una plataforma, no hace nada o se pone encima de la plataforma respectivamente
    ;;con la espada compruebo si colisiona con un enemigo o una plataforma, mato al enemigo o mato la espada respectivamente

    ld a, e_cmps(ix)
    and #e_cmps_gravity         ;;puede ser el personaje o el duende, pero la espada no
    jr z, sword_collisions      ;;si no tiene gravedad es la espada
        ;;hero or goblin
        ld a, e_cmps(ix)
        and #e_cmps_enemy
        jr nz, enemy_collisions
            ;;colisiones del personaje
            ;;hero_collision:
            ld a, e_cmps(iy) 
            and #e_cmps_enemy
            jr z, put_over_platform     ;;si no es un enemigo se va al codigo de ponerse encima de las plataformas
            ;;#####MUERTE DEL PERSONAJE
            ld a, e_cmps + e_size(ix)   ;;se cargan las mascaras de la espada
            and #e_cmps_alive    ;;1000 0000
            ret nz  ;;si la espada esta viva el personaje es inmortal

            ld a, e_cmps(ix)    ;;se cargan las mascaras del personaje
            and #e_cmps_dead    ;;se pone a 0 la mascara de alive
            ld e_cmps(ix), a    ;;se actualizan las mascaras del personaje
            ;;call sys_render_clear_pos_entity

            ;;ld a, e_cmps + e_size(ix)    ;;se cargan las mascaras de la espada
            ;;and #e_cmps_dead           ;;se pone a 0 la mascara de alive
            ;;ld e_cmps + e_size(ix), a    ;;se actualizan las mascaras de la espada
            ;;call sys_render_clear_pos_entity

            ld a, (lives)               ;;3 vivo, R 2 revivo, R 1 revivo, R 0 no revivo
            dec a
            ld (lives), a               ;;actualiza las vidas hasta que son 0
            call man_ui_delete_heart    ;;borro un corazon

            ld a, (lives)
            and a
            ret nz
                call man_screen_gameOver    ;;muestro la pantalla de game over
            ret

        enemy_collisions:
            ld a, e_cmps(iy)    ;;compruebo si es una colision enemigo y enemigo
            and #e_cmps_enemy
            ret nz              ;;si son enemigos termina

        ;;pongo el enemigo (o personaje) encima de la plataforma
        put_over_platform:
        ld a, e_y(iy)
        sub e_h(iy)
        ld e_y(ix), a
        xor a
        ld e_velY(ix), a
        ret

    sword_collisions:  
        ld a, e_cmps(iy)                ;;cargo las mascaras de la colision
        and #e_cmps_enemy               ;;si la espada toca un enemigo
        jr nz, sword_enemy_collision
        
            sword_platform_collision:
            ld a, e_cmps(ix)            ;;cargo las mascaras de la espada
            and #e_cmps_dead            ;;pongo un 0 en la mascara alive de la espada
            ld e_cmps(ix), a            ;;actualizo las mascaras de la espada


            call sys_render_clear_prev_pos_entity   ;;esto borra los rastros anteriores de la espada al caer en una plataforma
            ld e_x(ix), #0 
            ld e_y(ix), #16    ;;justo debajo de la plataforma central, donde apenas molesta
            ld e_posPrev + 0(ix), #0xF0 
            ld e_posPrev + 1(ix), #0xC0
            ;;call sys_render_clear_pos_entity
            ;;falta borrar la espada y tal
            ;;call sys_render_clear_pos_entity

            ret
        sword_enemy_collision:
        ;;#####MUERTE DEL ENEMIGO
        ld e_velY - e_size(ix), #-7 ;;hago que el personaje rebote hacia arriba

        ld a, e_cmps(iy)            ;;cargo las mascaras del enemigo
        and #e_cmps_dead            ;;pongo un 0 en la mascara alive del enemigo
        ld e_cmps(iy), a            ;;actualizo las mascaras del enemigo

        ;;ld e_sprite(iy), #<_main_char_16
        ;;ld e_sprite + 1(iy), #>_main_char_16
        ;;call sys_render_draw_entity_iy
        ;;call sys_render_clear_pos_entity_iy ;;borro al enemigo porque el render ahora solo actua cuando el reloj del enemigo esta a 0

        call man_entity_update_score

        call man_entity_change_difficulty

        jp next_iteration   ;;salto a la siguiente entidad si quiero que la espada solo mate a un enemigo cada vez
    ret