; ; ; ; MIT License
; ; ; ; 
; ; ; ; Copyright (c) 2021 Ramiro Hernán García Iten / Raúl Ripoll Pérez / Alexandru Marius Cozma
; ; ; ; 
; ; ; ; 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.

; ; ; ; ----------------- AUTHORS ------------------
; ; ; ;     Ramiro Hernán García Iten: rhgi1@alu.ua.es
; ; ; ;     Raúl Ripoll Pérez: rrp42@alu.ua.es
; ; ; ;     Alexandru Marius Cozma: amc246@alu.ua.es
; ; ; ; 
; ; ; ; Art by Sara Alfosea - IG: @Slinfir
; ; ; ; ---------------------------------------------

; ; ; ; Third Party source code used
; ; ; ; ----------------------------
; ; ; ; CPCtelera - owned by ronaldo / (Cheesetea, Fremos, ByteRealms) - GNU Lesser General Public License.


;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of CPCtelera: An Amstrad CPC Game Engine 
;;  Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR)
;;
;;  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/>.
;;-------------------------------------------------------------------------------


.include "cpctelera.h.s"

; Contador de entidades a comprobar
_collisionIndex: .db 0x0

;;; ==========================================
;;; ==========================================
;;; COLLISION SYSTEM
;;; ==========================================
;;; ==========================================

;;Comprueba las colisiones de las  entidades (Dado que solo colisiona el pj con el resto solo necesitamos recorrer el array una vez)
;;Destruye HL, AF, BC, DE, IX
sys_collision_update::
      call  man_entity_getArray  ; Cargamos el array en IX y A
      ld    iy, #_entity_array   ; Cargamos la información del jugador en IY

      ;Itero en el array
   _loop:
      call  man_entity_nextEntity ; Siguiente elemento
      dec   a
      ret   z

      ld    (_collisionIndex), a
      call  sys_collision_check
      ld    a, (_collisionIndex)
   jr _loop

;; Comprueba si existe colisión entre el jugador y un objeto
;; Destruye AF 
;; Parámetros de entrada:
;;    IX: Entidad a comprobar
;;    IY: Jugador
;; Retorna c -> 1 colisión 
;;              0 no colisión
sys_collision_check::
   ld    a, e_life(ix)  ; Si no tiene vida, ignoramos esta colisión
   cp    #0
   ret   z
   
   ld    a, e_type(ix)
   cp    #e_cmp_hit
   ret   z

   ; DERECHA
   ld    a, e_x(ix)  ; entity_x
   ld    b, a        
   add   e_w(ix)     ; + entity_w
   dec   a           ; <
   sub   e_x(iy)     ; jugador_x
   ret   c           ; Si no se genera acarreo, seguimos comprobando

   ; IZQUIERDA
   ld    a, e_x(iy)  ; jugador_x
   add   e_w(iy)     ; + jugador_w
   dec   a           ; <
   sub   b           ; entity_x
   ret   c

   ld    a, e_type(ix)              ; La comprobación de la colisión vertical cambia
   sub   #e_cmp_enemy               ; cuando se trata de una plataforma
   jp    c, collision_checkFloor

; COLISIÓN PARA ENEMIGOS (e_cmp_enemy)
;collision_checkEnemy:
      ; ARRIBA
      ld    a, e_y(iy)  ; jugador_y
      ld    b, a
      add   e_h(iy)     ; + jugador_h
      dec   a           ; <
      sub   e_y(ix)     ; entity_y
      ret   c

      ; ABAJO
      ld    a, e_y(ix)  ; entity_y
      add   e_h(ix)     ; + entity_h
      dec   a           ; <
      sub   b           ; jugador_y
      ret   c

   ; EFECTO ENEMIGO
      cpctm_setBorder_asm HW_RED
      ;Le resta al PJ el daño del enemigo
      ld a, e_life(iy)
      sub e_damage(ix)
      ; Si ha perdido toda la vida muere
      jr z, _player_died
      jr c, _player_died
         ld    e_life(iy), a     ; Si no, le actualizamos la vida
         ld    e_life(ix), #0    ; Cuando un enemigo se choca con nosotros, muere (ENEMIGO JAPONÉS)
   ret
      _player_died:
      pop   af    ; Vaciamos la pila de las llamadas anteriores
      pop   af    
      pop   af    
      ld hl, #level_lose
      jp (hl)

   ; COLISIÓN PARA PLATAFORMAS (e_cmp_floor)
collision_checkFloor:

      ld    a, (player_jump)
      cp    #1
      ret    nz    ; Si el salto está yendo hacia ABAJO ...

      ; ARRIBA
         ld    a, e_y(iy)  ; jugador_y
         ld    b, a
         add   e_h(iy)     ; + jugador_h
         dec   a           ; <
         sub   e_y(ix)     ; entity_y
         sub   e_vy(iy)    ; - jugador_vy
         ret   nc

      ; EFECTO COLISIÓN PLATAFORMAS
            ld    e_vy(iy), #0      ; ... reseteamos la velocidad y
            ld    a, #-1            ; el índice del salto.
            ld    (player_jump), a
            xor   a
            ld    (jump_index), a

            ld    a, e_y(ix)        ; Y dejamos la altura del personaje
            sub   a, e_h(iy)        ; al borde de la plataforma/suelo.
            ld    e_y(iy), a
            ret


sys_collision_attack::
   call  man_entity_getArray  ; Cargamos el array en IX y A
   ld    iy, #_entity_array   ; Cargamos la información del jugador en IY
   _loop_sa:
      call  man_entity_nextEntity ; Siguiente elemento
      dec   a
      ret z
      push af                    ; Respaldamos el número de entidades

      ; Solo comprobamos si es un enemigo
      ld a, e_type(ix)
      cp #e_cmp_enemy
      jr nz, _endLoop_sa    
      
      ;Comprobación de Posiciones y distancia
      ld    a, e_x(ix)        ; Guardamos la X de la entidad
      sub   e_x(iy)           ; Le restamos la X del jugador C =>  - derecha [1] | + izquierda[0] (C)
      jr nc, no_negative      ; Si es negativo lo transformamos a positivo
         ld    a, #1
         jp    negative
      no_negative:
         ld    a, #0
      negative:

      ;Posicion Correcta? "Mirada" hacia el enemigo
      cp e_info(iy)        ;Donde esta mirando el jugador 0(I) 1 (D)
      jr z, _endLoop_sa   ; es la direccion de la entidad

      ;Distancia Correcta? (EJE X)
      cp #0                ;Dependiendo de donde este le sumamos el ancho del PJ o del npc
      jr z, w_entity
      ;Añadimos el ancho de jugador como resta ya que a la derecha sera: Distancia - ancho jugador
         ld a, e_w(iy)
         neg
         jp continue
      w_entity:
      ;Añadimos el ancho de la entidad
         ld a, e_w(ix)
         neg
      continue:
      add a, b
      ;Si es mayor que hitDistanceX acabo (no le golpea)
      cp #hit_distanceX
      jr c, _endLoop_sa

      ld a, e_y(ix)
      add a, #5      ;Tamaño "cabeza" (golpea desde el torso)
      sub e_y(iy)     ;Le resto la coordenada y de C 
      jr z, _get_hit   ;Si es 0 es golpeado
      jr nc, _greather_than  ;Si es positivo significa que A > C

      _greather_than:
      sub e_h(iy)     ;Le resto la altura del enemigo
      jr z, _get_hit  ;Si es 0 o es negativo, significa que entra dentro del rango
      jr c, _get_hit
      jp _endLoop_sa  ;Si no no es golpeado

      _less_than:    
      add e_h(iy)     ;Mismo que arriba pero a la inversa
      jp c, _endLoop_sa

      ;Ha sido golpeado por lo cual le resto vida
      _get_hit:
      ld a, e_life(ix)
      sub e_damage(iy)
      ;cp #0
      jr z, died           ;Sin comentarios bastante descriptivo 
      jr c, died
         ld e_life(ix), a
   _endLoop_sa:
      pop af
   jr _loop_sa

   died:  
      ld    e_life(ix), #0    
      ld    a, e_info(ix)
      ld    b, a
      ld    a, (currentEnemy)
      and   b
      jr    z, noProgress
         ld    a, (levelProgress)
         inc   a
         ld    (levelProgress), a
         call  sys_collision_drawProgress
    noProgress:
      pop   af
   jr _loop_sa

; Aprovechamos el doble buffer para simular estrellas titilando
sys_collision_drawProgress:

 starLocation_C0 = . + 1
   ld    hl, #0xF008
   ld    (hl), #0xEE

 starLocation_80_1 = . + 1
   ld    hl, #0xA80A
   ld    (hl), #0xF4
 starLocation_80_2 = . + 1
   ld    hl, #0xB00A
   ld    (hl), #0xF4
 starLocation_80_3 = . + 1
   ld    hl, #0xB80A
   ld    (hl), #0xF4

   ld    a, (starLocation_C0)
   cp    #0x41
   jr    nz, updateC0
      ld    a, #0x52      ; Cada 5 estrellas, pasamos 4 líneas más abajo
      ld    (starLocation_C0), a
      ld    (starLocation_80_1), a
      ld    (starLocation_80_2), a
      ld    (starLocation_80_3), a
 updateC0:
   ld    a, (starLocation_C0)
   add   #0x0E     ; La siguiente estrella se dibujará 7 píxeles más a la derecha
   ld    (starLocation_C0), a
   ld    (starLocation_80_1), a
   ld    (starLocation_80_2), a
   ld    (starLocation_80_3), a

   ret