;; 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 "../man/sprites.h.s"

.globl _man_entity_forall
.globl cpct_getScreenPtr_asm
.globl cpct_drawSolidBox_asm
.globl cpct_drawSprite_asm

.globl _player
.globl _num_entities_final

.area _CODE

actual_screen:: .db #0xC0

;;////////////////////////////////////////////////////////
;;  Reset the position of the player when is crouched
;;////////////////////////////////////////////////////////
sys_render_reset_player_pointer_agachado::

    call get_inverse_screen_pointer
    ld d, a
    ld e, #0
    ld c, P_X(ix)
    ld b, P_Y(ix)
    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER

    ld P_PREV_POINTER1(ix), l
    ld P_PREV_POINTER1+1(ix), h


    ld a, (actual_screen)
    ld d, a
    ld e, #0
    ld c, P_X(ix)
    ld b, P_Y(ix)
    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER

    ld P_PREV_POINTER2(ix), l
    ld P_PREV_POINTER2+1(ix), h


    ret

;;//////////////////////////////////////////////////////////////////
;;  Draw the ground when the levels correspond to the meadow theme 
;;//////////////////////////////////////////////////////////////////
sys_render_draw_ground::
    ld de, #0xC000
    ld c, #0
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_ground
    call cpct_drawSprite_asm 

    ld de, #0xC000
    ld c, #40
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_ground
    call cpct_drawSprite_asm

    ld de, #0x8000
    ld c, #0
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_ground
    call cpct_drawSprite_asm 

    ld de, #0x8000
    ld c, #40
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_ground
    call cpct_drawSprite_asm

    ret

;;//////////////////////////////////////////////////////////////////
;;  Draw the ground when the levels correspond to the desert theme 
;;//////////////////////////////////////////////////////////////////
sys_render_draw_ground_desierto::
    ld de, #0xC000
    ld c, #0
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundDesierto
    call cpct_drawSprite_asm 

    ld de, #0xC000
    ld c, #40
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundDesierto
    call cpct_drawSprite_asm

    ld de, #0x8000
    ld c, #0
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundDesierto
    call cpct_drawSprite_asm 

    ld de, #0x8000
    ld c, #40
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundDesierto
    call cpct_drawSprite_asm

    ret


;;//////////////////////////////////////////////////////////////////
;;  Draw the ground when the levels correspond to the halloween theme 
;;//////////////////////////////////////////////////////////////////
sys_render_draw_ground_halloween::
    ld de, #0xC000
    ld c, #0
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundHalloween
    call cpct_drawSprite_asm 

    ld de, #0xC000
    ld c, #40
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundHalloween
    call cpct_drawSprite_asm

    ld de, #0x8000
    ld c, #0
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundHalloween
    call cpct_drawSprite_asm 

    ld de, #0x8000
    ld c, #40
    ld b, #170

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #40
    ld b, #30
    ld hl, #_groundHalloween
    call cpct_drawSprite_asm

    ret


;;//////////////////////////////////////////////////////////////////
;;  Draw death sprite 
;;//////////////////////////////////////////////////////////////////
sys_render_draw_death::


    ld de, #0x8000
    ld c, #35
    ld b, #80

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #14
    ld b, #24
    ld hl, #_muerte
    call cpct_drawSprite_asm


    ld de, #0xC000
    ld c, #35
    ld b, #80

    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ld c, #14
    ld b, #24   
    ld hl, #_muerte
    call cpct_drawSprite_asm

    ret


;;//////////////////////////////////////////////////////////////////
;;  Gets the player screen pointer
;;//////////////////////////////////////////////////////////////////
sys_render_get_player_screenPtr::
    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER
    ld d, h
    ld e, l

    ret

;;//////////////////////////////////////////////////////////////////
;;  Deletes the player from the screen 
;;//////////////////////////////////////////////////////////////////
sys_render_borrar_player::
    ld ix, #_player

    ld e, P_PREV_POINTER2(ix)
    ld d, P_PREV_POINTER2+1(ix)

    ld c, P_W(ix)
    ld b, P_H(ix)
    ld a, #0x00
    call cpct_drawSolidBox_asm      ;; BORRAMOS LA POSICION ANTERIOR

    ret

;;//////////////////////////////////////////////////////////////////
;;  Deletes the player from the screen when the player has died
;;//////////////////////////////////////////////////////////////////
sys_render_borrar_player_muerte::
    ld ix, #_player

    ld e, P_PREV_POINTER2(ix)
    ld d, P_PREV_POINTER2+1(ix)

    ld c, P_W(ix)
    ld b, P_H(ix)
    ld a, #0x00
    call cpct_drawSolidBox_asm      ;; BORRAMOS LA POSICION ANTERIOR


    ld e, P_PREV_POINTER1(ix)
    ld d, P_PREV_POINTER1+1(ix)

    ld c, P_W(ix)
    ld b, P_H(ix)
    ld a, #0x00
    call cpct_drawSolidBox_asm      ;; BORRAMOS LA POSICION ANTERIOR

    ret

;;//////////////////////////////////////////////////////////////////
;;  Draw the player in the screen
;;//////////////////////////////////////////////////////////////////
sys_render_pintar_player::

    ld ix, #_player
    ld a, (actual_screen)
    ld d, a
    ld e, #0

    ld c, P_X(ix)
    ld b, P_Y(ix)
    call sys_render_get_player_screenPtr     ;; GET SCREEN POINTER

    ld a, P_PREV_POINTER1(ix)
    ld P_PREV_POINTER2(ix), a
    ld a, P_PREV_POINTER1+1(ix)
    ld P_PREV_POINTER2+1(ix), a

    ld P_PREV_POINTER1(ix), l
    ld P_PREV_POINTER1+1(ix), h


    ex de, hl
    ld h, P_SPR+1(ix) ;accedemos a la parte alta
    ld l, P_SPR(ix) 
    ld c, P_W(ix)
    ld b, P_H(ix)
    call cpct_drawSprite_asm 

    ret

;;///////////////////////////////////////////////////////////////////////
;; FUNCION PARA RENDERIZAR AL JUGADOR
;;
;; PARAMETROS: NADA
;;
;; REGISTROS MODIFICADOS: HL
;;
;; RETURN: NADA
;;///////////////////////////////////////////////////////////////////////
_sys_render_draw_player::
    call sys_render_borrar_player
    call sys_render_pintar_player
    ret



;; DE POSICION DE LA ENTIDAD
_sys_render_update_one_entity::        
    push hl     ;; GUARDAMOS EL VALOR DE HL
    push de
    pop ix
    push de


    ld a, E_COMPONENTE(ix)
    cp #2
    jr z, _no_renderabe

    ld a, E_OFFSET_L(ix)
    inc a 
    dec a
    jr nz, _render_end      ;; SI EL BIT SUPERIOR NO ESTA A 0 NO RENDERIZAMOS

    ld a, E_OFFSET_H(ix)
    ld b, #75
    cp b                ;; SI EL SEGUNDO BIT ES MENOR DE 80

    jp nc, _render_end      ;; SI EL BYTE INFERIOR ES MAYOR DE 80 NO SE RENDERIZA


    ;; SI NO, PINTAMOS LA ENTIDAD
    _pintando:
        call sys_render_draw_entity
        pop de
        pop hl
        ret

    _no_renderabe:
        pop de
        pop hl
        ret

    _render_end:
    pop de
    ld de, #_num_entities_final
    pop hl
    ret



;;//////////////////////////////////////////////////////////////////
;;  Deletes the previous drawing
;;//////////////////////////////////////////////////////////////////
sys_render_delete_prevEntity::
    ld c, 5(ix)
    inc c
    inc c

    ld a, E_Y(ix)
    ld b, E_X(ix)

    sub b
    ld b, a                         ;; CALCULAMOS LA Y PREVIA

    ld a, (actual_screen)
    ld d, a
    ld e, #0
    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER

    ld d, h
    ld e, l
    ld a, #0x00
    ld c, E_W(ix)
    ld b, E_H(ix)
    call cpct_drawSolidBox_asm

    ret


;;//////////////////////////////////////////////////////////////////
;;  Draw the new player position in the screen
;;//////////////////////////////////////////////////////////////////
sys_render_draw_entity::
    ld a, (actual_screen)
    ld d, a
    ld e, #0
    ld c, 5(ix)
    ld b, E_Y(ix)
    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER

    ld d, h
    ld e, l

    ld h, E_SPR_H(ix) ;;accedemos a la parte alta 
    ld l, E_SPR_L(ix) ;;parte baja

    ld c, E_W(ix)
    ld b, E_H(ix)
    call cpct_drawSprite_asm 

    ret


;;///////////////////////////////////////////////////////////////////////
;; FUNCION PARA RENDERIZAR TODAS LA ENTIDADES
;;
;; PARAMETROS: NADA
;;
;; REGISTROS MODIFICADOS: HL
;;
;; RETURN: NADA
;;///////////////////////////////////////////////////////////////////////
_sys_render_update::
    call _sys_render_draw_player
    ld hl, #_sys_render_update_one_entity
    call _man_entity_forall
    call change_screen
    ret


;;//////////////////////////////////////////////////////////////////
;;  Deletes the entity 
;;//////////////////////////////////////////////////////////////////
_sys_render_delete_entity::
    push de
    pop ix

    call sys_render_hard_delete_entity

    ret


;;//////////////////////////////////////////////////////////////////
;;  Deletes the previous drawing
;;//////////////////////////////////////////////////////////////////
sys_render_hard_delete_entity::
    push de

    ;; BORRAMOS EL DIBUJADO ANTERIOR
    ld a, (actual_screen)
    ld d, a
    ld e, #0
    ld c, 5(ix)
    inc c
    ld b, E_Y(ix)
    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER

    ld d, h
    ld e, l
    ld a, #0x00
    ld c, E_W(ix)
    ld b, E_H(ix)
    call cpct_drawSolidBox_asm


    call get_inverse_screen_pointer
    ld d, a
    ld e, #0
    ld c, 5(ix)
    ld b, E_Y(ix)
    call cpct_getScreenPtr_asm      ;; GET SCREEN POINTER

    ld d, h
    ld e, l
    ld a, #0x00
    ld c, E_W(ix)
    ld b, E_H(ix)
    call cpct_drawSolidBox_asm

    pop de

    ret


;; D = REGISTRO
;; E = VALOR
set_crtc:
    ld bc, #0xBC00
    out (c), d
    inc b
    out (c), e
    ret

;;//////////////////////////////////////////////////////////////////
;;  All this functions are in charge of managing the double buffer
;;//////////////////////////////////////////////////////////////////
change_screen::
f_change_screen = . + 1
    jp change_screen_to_8000


change_screen_to_8000:
    ld de, #0x0C20
    call set_crtc

    ;; CAMBIAMOS LA POSICION DE MEMORIA
    ld hl, #actual_screen
    ld (hl), #0xC0

    ld hl, #change_screen_to_C000
    ld (f_change_screen), hl

    ret

change_screen_to_C000:
    ld de, #0x0C30
    call set_crtc

    ;; CAMBIAMOS LA POSICION DE MEMORIA
    ld hl, #actual_screen
    ld (hl), #0x80

    ld hl, #change_screen_to_8000
    ld (f_change_screen), hl

    ret



get_inverse_screen_pointer::

    ld a, (actual_screen)
    cp a, #0xC0

    jr z, _is_C0
    ld a, #0xC0
    ret

    _is_C0:
        ld a, #0x80
        ret
