;; This file is part of Moonsters
;;  Copyright (C) 2021 Dam Studios
;;
;;     Moonsters 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.
;; 
;;     SHOOT TO MOVE 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 Moonsters  If not, see <https://www.gnu.org/licenses/>.


.include "sys/collisions.h.s"
.include "man/entity_manager.h.s"
.include "cpctelera.h.s"

_entity_count:: .db 0

.globl load_level
;; esto es una simple etiqueta para el linker
.module sys_collisions

;;----------------------------------------------------------------------------------------
;; get pointer to entity array and save it for future use
sys_collisions_init::
    call man_entity_getArray
   ; ld (_collisions_array), ix
ret


;;
;;does something based on the type of collision
;;input->
;; ix: entity 1
;; iy: entity 2
sys_collision_happened::

   ; ld e_type(iy), #e_type_destroy

   ;;Si la entidad 1 es el personaje principal
    ;;En player siempre va a ser IX
    ld a, e_type(ix)
    cp #e_type_default
    jr nz, no_entidadPlayer

entidadPlayer:
    ;;si la segunda entidad es estatica
    ld a, e_type(iy)
    cp #e_type_static
    jr nz, no_player_static
    player_static:
      ;  saveSetBorder HW_RED

        ;;comprobamos si colisiona al mover solo la x
        ld a, #0
        ld e_vy(ix), a

        ld b, e_x(ix)
        ld a, e_oldX(ix)
        ld e_x(ix), a
        call sys_collisions_check
        jr c, _no_collision_x
        _collision_x:
            ld a, b
            ld e_x(ix), b

        _no_collision_x:

        ;;comprobamos si colisiona al mover solo la y
        ld b, e_y(ix)
        ld a, e_oldY(ix)
        ld e_y(ix), a
        call sys_collisions_check
        jr c, _no_collision_y
        _collision_y:
            ld a, b
            ld e_y(ix), b

        _no_collision_y:

    no_player_static:

    ld a, e_type(iy)
    cp #e_type_bullet_enemy
    jr nz, no_player_bullet
    player_bullet:

        ld a, #01
        ld (load_level), a

    no_player_bullet:


    ld a, e_type(iy)
    cp #e_type_static_dmg
    jr nz, no_player_static_dmg
    player_static_dmg:

        ld a, #01
        ld (load_level), a

    no_player_static_dmg:


no_entidadPlayer:

    ld a, e_type(ix)
    cp #e_type_enemy
    jr nz, no_entidadEnemy    
entidadEnemy:

    ld a, e_type(iy)
    cp #e_type_bullet
    jr nz, no_entidadEnemy

    ld e_type(ix), #e_type_destroy

no_entidadEnemy:


    ld a, e_type(ix)
    cp #e_type_bullet
    jr nz, no_entidadBullet
entidadBullet:

    ld a, e_type(iy)
    cp #e_type_enemy
    jr nz, no_entidadBullet

    ld e_type(ix), #e_type_destroy

no_entidadBullet:


    ld a, e_type(ix)
    cp #e_type_static
    jr nz, no_entidadStatic
entidadStatic:

    ld a, e_type(iy)
    cp #e_type_bullet
    jr nz, no_entidadStatic

    ld e_type(iy), #e_type_destroy

no_entidadStatic_enemy:

    ld a, e_type(iy)
    cp #e_type_bullet_enemy
    jr nz, no_entidadStatic

    ld e_type(iy), #e_type_destroy

no_entidadStatic:






    ret

;;----------------------------------------------------------------------------------------
;; updates the collisions 
sys_collisions_update::
    ;saveSetBorder HW_GREEN
   call sys_collisions_checkScreen

   ld ix, #collisions_array


loopCol:

    ld__iy_ix
    ld de, #2
    add iy, de


loopColInt:

    push ix
    push iy

    ld__hl_ix
    ld d, (hl)
    inc hl
    ld e, (hl)
    ld__ix_de

    ld__hl_iy
    ld d, (hl)
    inc hl
    ld e, (hl)
    ld__iy_de
    

    call sys_collisions_check
    jr c, _no_collision
    _collision:
        ;; aqui ponemos lo que sea en caso de colision
      
        ;ld e_type(iy), #e_type_destroy

        call sys_collision_happened

        jr continue_inner
    _no_collision:
        ;; aqui ponemos lo que sea en caso de no colision
        ;saveSetBorder HW_GREEN

   

continue_inner:

     pop iy
    pop ix


    ld de, #2
    add iy, de

      ld a, (iy)
    cp #0xFF
    jr z, finalLoopColInt

    jr loopColInt


finalLoopColInt:

    ld de, #02
    add ix, de

    ld a, (ix)
    cp #0xFF
    ret z

    ld__hl_ix
    ld de, #02
    add hl, de

    ld a, (hl)
    cp #0xFF
    ret z




    jr loopCol

    ret
;;----------------------------------------------------------------------------------------
;; Destroys AF
;; returns c value --> Carry (1) no collision Carry (0) collision
sys_collisions_check::
    ;; in x-dimension -----------------------
    ;; if (e_x(ix) + e_w(ix) - e_x(iy) < 0) __no_collision
    ld a, e_x(ix)
    add e_w(ix)
    sub e_x(iy)
    ret c    ;; if (e_x(iy) + e_w(iy) - e_x(ix) < 0) __no_collision
    ld a, e_x(iy)
    add e_w(iy)
    sub e_x(ix)
    ret c    ;; in y-dimension -----------------------
    ;; if (e_y(ix) + e_h(ix) - e_y(iy) < 0) __no_collision
    ld a, e_y(ix)
    add e_h(ix)
    sub e_y(iy)
    ret c    ;; if (e_y(iy) + e_h(iy) - e_y(ix) < 0) __no_collision
    ld a, e_y(iy)
    add e_h(iy)
    sub e_y(ix)
    ;; no needed ret c here
ret



sys_collisions_checkScreen:

    ld hl, #collisions_array
    ld (first_col_free), hl
    ld hl, #sys_collisions_checkScreen_one_entity
    call man_entity_forall

    ld a, #0xFF
    ld hl, (first_col_free)
    ld (hl), a

    ret

sys_collisions_checkScreen_one_entity:

    .globl sys_render_getScroll
    call sys_render_getScroll
    ld b, a
    add a, b
    ld b, a
    ld a, e_x(ix)
    ld c, e_w(ix)
    add a, c
    sub a, b
    jr c, leftCol    ;; if (e_x(iy) + e_w(iy) - e_x(ix) < 0) __no_collision
    add #1
    jr nc, no_leftCol    ;; if (e_x(iy) + e_w(iy) - e_x(ix) < 0) __no_collision

leftCol:
    ret

no_leftCol:

    ;;comprobamos si estan mas a la derecha
    call sys_render_getScroll
    ld b, a
    add a, b
    ld b, #81
    add a, b
    ld b, a
    ld a, e_x(ix)
    ld c, e_w(ix)
    add a, c
    sub b
    ret nc

    ;;if inside screen include in pointer array
    ld hl, (first_col_free)

    ld__de_ix
    ld (hl), d
    inc hl
    ld (hl), e
    inc hl
    ld (first_col_free), hl

    ret


.macro DefinePointerArray _N  ;;Ponemos un nombre aleatorio para la macro
    .rept _N
        .dw 0x0000
    .endm
.endm

first_col_free: .dw collisions_array
collisions_array:
DefinePointerArray 30

