;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of Nightmare Fortress: An Amstrad CPC Game 
;;  Copyright (C) 2017 Natalia Bernal Pérez / Álvaro Esteve Bernabeu / Plácido Antonio López Ávila
;;
;;  Nightmare Fortress 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.
;;
;;  Nightmare Fortress 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 Nightmare Fortress.  If not, see <http://www.gnu.org/licenses/>.
;;-------------------------------------------------------------------------------

.area _DATA
.area _CODE


.include "cpctelera.h.s"
.include "macros.h.s"
.include "dobleBuffer.h.s"
.include "gameController.h.s"
.include "actors/shoot.h.s"
.include "actors/enemy.h.s"
.include "stage.h.s"
.globl _g_palette
.globl _g_song_game


;;***********************************************************************
;;							PUBLIC DATA
;;***********************************************************************


initial_speed: .db #3 ;; Velocidad del cambio de frame

num_animacion: .db #2 ;; Indica si hay que cambiar al sprite 1 o al 2

;num_animation: .db #2 ;; Indica si hay que cambiar al sprite 1 o al 2

;;***********************************************************************
;;							PUBLIC FUNCTIONS
;;***********************************************************************

;;------------------------------------------------
;; Desactiva el firmware, establece la paleta requerida y establece el modo de video a 0
;;------------------------------------------------
initialize::
    call cpct_disableFirmware_asm
    ld hl, #_g_palette
    ld de, #16
    call cpct_setPalette_asm
    ld c, #0
    call cpct_setVideoMode_asm
    ;; Llena toda la memoria desde 8000 hasta C000 de 0
    ;ld de, #0x8000 
    ;ld a, #0
    ;ld bc, #0x4000
    ;call cpct_memset_asm
    ;;Inicializa la musica
    ;ld de, #_g_song_game
    ;call cpct_akp_musicInit_asm
    
    ld    hl, #0x5410        		;; Establecemos el color de borde a NEGRO 
  	call  cpct_setPALColour_asm		;; |
ret

;;------------------------------------------------
;; Borra una entidad (sprite) y repinta el fondo de atras
;;
;;  -> IX es el puntero a la entidad
;;------------------------------------------------
entity_erase::

	ld a, previousLast_x(ix)
	cp #0xFE
	ret z
   ld a, previousLast_x(ix)          ;; Hallamos el tile sobre el que esta situado el borde superior izquierdo de la entidad (tile X)
   cp #0
   ret z
       
   ld c, a          	
   srl c        		;; Dividimos la coordenada X de la entidad entre 2 para saber sobre que tile (eje X) esta
         
   ld b, previousLast_Y(ix)          ;; Hallamos el tile sobre el que esta situado el borde superior izquierdo de la entidad (tile Y) 
   srl b
   srl b   				;; Dividimos la coordenada Y de la entidad entre 4 para saber sobre que tile (eje Y) esta
   
   ld e, width(ix)      ;; Dividimos la anchura de la entidad entre 2 para saber cuantos tiles ocupa (eje X)
   srl e 
   inc e                ;; Incrementamos en 1 el numero de tiles a repintar en el eje X por si se diera el caso de que se encontrara en medio de varios tiles
  
   ld d, height(ix)     ;; Dividimos la altura de la entidad entre 4 para saber cuantos tiles ocupa (eje Y)
   srl d
   srl d
   inc d                ;; Incrementamos el 1 el numero de tiles a repintar en el eje Y por si se diera el caso de que se encontrara en medio de varios tiles
                        ;; El resultado no lo metemos en la pila porque hemos acabado las operaciones y tenemos el valor en el registro necesario (D)

   ld a, score_or_hp(ix)
   cp #123
   jp nz, noPuerta
   	dec d
   	dec h

	noPuerta:
   ld a, #40            ;; A = ancho total del tilemap

    ld hl, #0x0041  ;; Guardamos en la pila el puntero al tilemap, para llamar a la funcion de abajo
    push hl             ;;
    ld hl, (pointerScreen)     ;; Guardamos en la pila el puntero a la direccion de memoria de video donde se debe pintar
    push hl

    call  cpct_etm_drawTileBox2x4_asm   ;; Se llama a la funcion para que redibuje lo que habia detras de la entidad
  
    ret

;;------------------------------------------------
;; Dibuja una entidad creada a partir de la macro defineEntity
;;
;; 	-> IX es el puntero a la entidad que se quiere dibujar
;;------------------------------------------------
entity_draw::

	ld a, x(ix)
    cp #0xFE
    ret z
    

    call obtener_puntero_pantalla
    ex de, hl



    ld c, width(ix)
    ld b, height(ix)

    ld l, sprite_l(ix)
    ld h, sprite_h(ix)
    call cpct_drawSpriteMasked_asm 

    ret

    not_draw:
    ret

;;------------------------------------------------
;; Mueve las X y las Y de las entidades para dibujar y borrar con doble buffer
;;
;; 	-> IX es el puntero a la entidad que se quiere dibujar
;;------------------------------------------------
entity_update_xy::

	ld a, last_x(ix) ;; La anterior x pasa a ser la anterior de la anterior
	ld previousLast_x(ix), a ;; |
	ld a, x(ix) ;; La x actual pasa a ser la anterior
	ld last_x(ix), a ;; |

	ld a, last_y(ix)
	ld previousLast_Y(ix), a
	ld a, y(ix)
	ld last_y(ix), a

ret

;;------------------------------------------------
;; Mueve las X y las Y de cada una de las entidades de los arrays de enemigos y disparos
;; LLama a la funcion que updatea las xy de las entidades
;;
;; 	-> IX es el puntero a la entidad que se quiere dibujar
;;------------------------------------------------
array_update_xy::
	recorrer_array:
		ld a, x(ix) ;; Si la x del array es FF, significa que es el final del array								
		cp #0xFF ;; |							
		jp z, fin_array ;; Salimos del bucle porque ha terminado el array
		
		call entity_update_xy

		ld b, #00		     ;; por fila, para que pase al siguiente disparo
		add ix, bc ;; |							
		jp recorrer_array ;; Empezamos otra vez a actualizar los valores del siguiente disparo
		ret	

		fin_array:
		ret

;;------------------------------------------------
;; Rutina para eliminar del juego una entidad
;; -> IX debe apuntar a la entidad que se quiere borrar
;;------------------------------------------------
entity_destroy::
	ld a, x(ix)
	cp #0xFE
	jr z, second_time
	ld a, #0xFE
	ld x(ix), a
	ret

	second_time:
		ld a, #0
		ld x(ix), a
		ret
		
;;------------------------------------------------
;; (NO TESTEADA)(NO TESTEADA)(NO TESTEADA)(NO TESTEADA)(NO TESTEADA)(NO TESTEADA)
;;
;; Comprueba si 2 entidades han colisionado o no (HECHA CON REGISTROS IX e IY)
;; 	-> IX es el puntero a la entidad 1
;;	-> IY es el puntero a la entidad 2
;;
;;	<- A es el resultado de la colision (1 hay colision, 0 NO hay colision)
;;------------------------------------------------
check_collision_e::
	;;;IF (x1 + w1 <= x2) no collision
	;ld c, x(ix)
	;ld a, width(ix)
	;add c
;
	;ld b, x(iy)
	;sub b
	;jp z, no_collision
	;jp m, no_collision
;
	;;;IF (x2 + w2 <= x1) no collision
	;ld c, x(iy)
	;ld a, width(iy)
	;add c
;
	;ld b, x(ix)
	;sub b
	;jp z, no_collision
	;jp m, no_collision
;
;
	;;;IF (y1 + h1 <= y2) no collision
	;ld c, y(ix)
	;ld a, height(ix)
	;add c
;
	;ld b, y(iy)
	;sub b
	;jp z, no_collision
	;jp m, no_collision
;
	;;;IF (y2 + h2 <= y1) no collision
	;ld c, y(iy)
	;ld a, height(iy)
	;add c
;
	;ld b, y(ix)
	;sub b
	;jp z, no_collision
	;jp m, no_collision

	;ret

;;------------------------------------------------
;; Comprueba si 2 entidades han colisionado o no (HECHA SIN REGISTROS ESPECIALES)
;; 	-> HL es el puntero a la entidad 1
;;	-> DE es el puntero a la entidad 2
;;
;;	<- A es el resultado de la colision (1 hay colision, 0 NO hay colision)
;;------------------------------------------------
check_collision::
	push hl
	push de

	;;IF (x1 + w1 <= x2) no collision
	ld a, (hl)			;; A = x1							
	ld c, a				;; C = A	

	inc hl						
	inc hl				;; HL apunta a w1

	ld a, (hl)			;; A = w1						
	add c				;; A = x1 + w1	
	ld c, a				;; C = A = x1 + w1
	ld a, (de)			;; A = x2
	ld b, a				;; B = A = x2
	ld a, c				;; A = C = x1 + w1
	sub b				;; A = A - B = x1 + w1 - x2
								
	jp z, no_collision
	jp m, no_collision

	;;IF (x2 + w2 <= x1) no collision
	dec hl
	dec hl				;; HL apunta a x1

	ld a, (de)			;; A = x2							
	ld c, a				;; C = A	

	inc de						
	inc de

	ld a, (de)			;; A = w2						
	add c				;; A = x2 + w2	
	ld c, a				;; C = A = x2 + w2
	ld a, (hl)			;; A = x1
	ld b, a				;; B = A = x1
	ld a, c				;; A = C = x2 + w2
	sub b				;; A = A - B = x2 + w2 - x1
								
	jp z, no_collision
	jp m, no_collision

	;;IF (y1 + h1 <= y2) no collision
	dec de				;; HL apunta a y2
	inc hl				;; HL apunta a y1

	ld a, (hl)			;; A = y1							
	ld c, a				;; C = A	

	inc hl						
	inc hl				;; HL apunta a h1

	ld a, (hl)			;; A = h1						
	add c				;; A = y1 + h1	
	ld c, a				;; C = A = y1 + h1
	ld a, (de)			;; A = y2
	ld b, a				;; B = A = y2
	ld a, c				;; A = C = y1 + h1
	sub b				;; A = A - B = y1 + h1 - y2
								
	jp z, no_collision
	jp m, no_collision

	;;IF (y2 + h2 <= y1) no collision
	dec hl
	dec hl

	ld a, (de)			;; A = y2							
	ld c, a				;; C = A	

	inc de						
	inc de

	ld a, (de)			;; A = h2						
	add c				;; A = y2 + h2	
	ld c, a				;; C = A = y2 + h2	
	ld a, (hl)			;; A = y1
	ld b, a				;; B = A = y1
	ld a, c				;; A = C = y2 + h2	
	sub b				;; A = A - B = y2 + h2 - y1
								
	jp z, no_collision
	jp m, no_collision

	pop de				;; Recuperamos los valores de DE y HL
	pop hl
	ld a, #1			;; Devolvemos 1 en A, lo que significa colision
	ret
	no_collision:
		pop de
		pop hl
		ld a, #0		;; Devolvemos 0 en A, lo que significa que NO hay colision
		ret



;;------------------------------------------------
;; Comprueba si una entidad esta colisionando con un tile colisionable
;;	IX -> puntero a la entidad de la que se quiere obtener informacion sobre colisiones con tiles
;;
;;
;;------------------------------------------------
tile_collision::
	ld a, x(ix)
	cp #0
	ret z
	cp #0xFE
	ret z

	ld d, x(ix)
	srl d 
	ld e, y(ix)
	srl e
	srl e
	
	ld b, width(ix)
	srl b
	ld c, height(ix)
	srl c 
	srl c 
	
	push bc 
	ld a, state(ix)
	cp #2
	jp z, check_right 
	cp #3
	jp z, check_down
	cp #4
	jp z, check_left 
	jp  check_up
	ret


	check_left:
		
		ld a, e
		add c
		ld e, a

		call check_tile
		pop bc
		cp #1
		ret z

		ld a, e
		srl c
		sub c
		ld e, a
		call check_tile

		ret
		
	check_right:
		
		ld a, e
		add c
		ld e, a

		ld a, d
		add b
		ld d, a 

		call check_tile
		pop bc
		cp #1
		ret z

		ld a, e
		srl c
		sub c
		ld e, a
		call check_tile

		ret

	check_down:
		
		ld a, e
		add c
		ld e, a
		call check_tile
		pop bc
		cp #1
		ret z 

		ld a, d
		add b
		ld d, a
		call check_tile

		ret

	check_up:
		ld a, e
		add c
		dec a 
		dec a 
		ld e, a
		call check_tile
		pop bc
		cp #1
		ret z 
		
		ld a, d 
		add b
		ld d, a
		call check_tile 
		cp #1
		ret z


		inc e			;;CASO ESPECIAL DISPARO ARRIBA
		call check_tile
		ret


	ret


;; 1 = TILE COLISIONABLE, 0 = TILE NO COLISIONABLE 
check_tile::
	ld hl, #0x0041			;;HL apunta a la matriz de tiles
	ld b, #0			;; Cargamos en BC la posicion Tile_X de la entidad
	ld c, d 			;; |
	add hl, bc			;; Se la sumamos a HL (HL + Tile_x)
	ld b, #0			;; Cargamos el ancho (40) de la matriz en bc
	ld c, #40			;; |
	ld a, e				;; A = Tile_Y
	
	_loop_tile:			;; Bucle de multiplicacion
		add hl, bc		;; Hl = HL + 40 (el ancho)
		dec a			;; Decrementamos A para seguir con el bucle de la multiplicacion
		jp nz, _loop_tile	;; Si A todavia no es cero, la multiplicacion no ha terminado


	ld a, (hl)			;; A = el elemento (tile_x, tile_y) de la matriz
	
	push ix
	ld ix, (currentStage)
	ld b, min_tile(ix)
	pop ix

	cp b
	jp c, A_to_cero
	ld a, #1
	ret 

	A_to_cero:
		ld a, #0
		ret



;;------------------------------------------------
;; Calcula la distancia entre 2 entidades en el eje 
;; X e Y por separado (LOS PRIMEROS BYTES DE LAS ENTIDADES DEBEN SER POS_X Y POS_Y)
;;
;; 	-> HL es el puntero a la entidad 1
;;	-> DE es el puntero a la entidad 2
;;
;;	<- B es la distancia en el eje X
;;	<- C es la distancia en el eje Y
;;------------------------------------------------
distance_between::
	push hl
	push de
	;; |x1 - x2|
	ld a, (hl)			;; A = x1
	ld c, a				;; C = A
	ld a, (de)			;; A = x2
	sub c				;; A = A - C
	call absolute_A			;; A = |A|
	ld b, a				;; B = A, distancia en eje X


	inc hl				;;Movemos el puntero de la entidad 1 a su atributo Y
	inc de				;;Movemos el puntero de la entidad 2 a su atributo Y

	;; |y1 - y2|
	ld a, (hl)			;; A = y1
	ld c, a				;; C = A
	ld a, (de)			;; A = y2
	sub c				;; A = A - C
	call absolute_A			;; A = |A|
	ld c, a				;; C = A, distancia en eje Y

	pop de
	pop hl

	ret

;;------------------------------------------------
;; Calcula el valor absoluto de un numero
;; 	-> A es el valor de entrada 
;;	<- A es el valor de salida
;;------------------------------------------------
absolute_A::
    or a
    ret p
    neg         
    ret


;;------------------------------------------------
;; The following routine divides d by e and places the quotient in d and the remainder in a 
;; 	-> D es dividendo
;;	-> E es el divisor
;;
;;  <- D es el cociente
;;	<- A es el resto
;;------------------------------------------------
div_d_e::
;	xor	a
;    ld	b, #8
;
;_loop:
;   	sla	d
;   	rla
;   	cp	e
;   	jr	c, .+4
;   	sub	e
;   	inc	d
;   
;   	djnz	_loop
;   
;   	ret


;;------------------------------------------------
;; Devuelve el puntero a la direccion de pantalla desde los valores de una entidad
;;	-> ix es el puntero a la entidad
;;
;;  	<- hl donde se almacena la dirección correspondiente
;;------------------------------------------------
obtener_puntero_pantalla::
	ld hl, (pointerScreen)
	ex de, hl			;; Direccion de la primera posicion de pantalla		
        ld c, x(ix)			;; c = posicion X
        ld b, y(ix)			;; b = posicion Y
        call cpct_getScreenPtr_asm	;; Llamada para obtener la posicion (almacena en hl)
	ret


;;------------------------------------------------
;; Comprueba si la entidad se encuentra en colision con una pared del mapa
;;	-> ix es el puntero a la entidad
;;
;;  	<- a - Almacena el valor de colision (colision con una pared: 1 / No colision: 0)
;;------------------------------------------------
comprobar_pared::

	;ld hl, (pointerScreen)
	;ex de, hl			;; Direccion de la primera posicion de pantalla		
       ; ld 	c, x(ix)			;; c = posicion X
       ; ld 	a, y(ix)			;; Almaceno Y en A
       ; ld	b, s1(ix)			;; Almaceno el desplazamiento para la colision de los pies en B
       ; add	a, b				;; A + B
       ; ld	b, a				;; Cargo el valor de A en B
       ; call cpct_getScreenPtr_asm		;; Llamada para obtener la posicion (almacena en hl)
;
	;ld	a, (hl)				;; Introduzco el valor del tile en A
	;cp	#91				;; Compuebo si el tile corresponde al valor del suelo
	;jp	nz, pared			;; En caso de ser distinto a 0 (no es suelo, es pared), salta a la posicion de pared
;
	;ld hl, (pointerScreen)
	;ex de, hl			;; Direccion de la primera posicion de pantalla	
       ; ld	a, y(ix)			;; Almaceno Y en A
       ; ld	b, s1(ix)			;; Almaceno el desplazamiento para la colision de los pies en B
       ; add	a, b				;; A + B
       ; ld	b, a				;; Cargo el valor de A en B	
;
	;ld	a, width(ix)			;; Cargo en A el ancho
	;add	a, x(ix)			;; Desplazo la A a la posicion Ancho + tamaño de la X
	;dec	a				;; A--
	;ld	c, a				;; Cargo A en C
;
	;call cpct_getScreenPtr_asm		;; Llamada para obtener la posicion (almacena en hl)
;
	;ld	a, (hl)				;; Introduzco el valor del tile en A				
	;cp	#91				;; Compuebo si el tile corresponde al valor del suelo
	;jp	nz, pared			;; En caso de ser distinto a 0 (no es suelo, es pared), salta a la posicion de pared
;
	;ld hl, (pointerScreen)
	;ex de, hl			;; Direccion de la primera posicion de pantalla	
       ; ld 	c, x(ix)			;; Cargo en C el valor de la X
;
	;ld	a, height(ix)			;; Cargo en A en valor de la altura
	;add	a, y(ix)			;; Le añado a A el alto 
	;ld	b, a				;; Cargo en B el valor de A
;
	;call cpct_getScreenPtr_asm		;; Llamada para obtener la posicion (almacena en hl)
;
	;ld	a, (hl)				;; Introduzco el valor del tile en A
	;cp	#91				;; Compuebo si el tile corresponde al valor del suelo
	;jp	nz, pared			;; En caso de ser distinto a 0 (no es suelo, es pared), salta a la posicion de pared
;
	;ld hl, (pointerScreen)
	;ex de, hl			;; Direccion de la primera posicion de pantalla	
       ; ld	a, width(ix)			;; Cargo en A el ancho
	;add	a, x(ix)			;; Le añado a A el ancho
	;dec	a				;; A--
	;ld	c, a				;; Cargo en C el valor de A
;
	;ld	a, height(ix)			;; Cargo en A la altura
	;add	a, y(ix)			;; Le añado a A el alto
	;ld	b, a				;; Cargo en B el valor de A
;
	;call cpct_getScreenPtr_asm		;; Llamada para obtener la posicion (almacena en hl)
;
	;ld	a, (hl)				;; Introduzco el valor del tile en A
	;cp	#91				;; Compuebo si el tile corresponde al valor del suelo
	;jp	nz, pared			;; En caso de ser distinto a 0 (no es suelo, es pared), salta a la posicion de pared
;
	;ld	a, #0				;; A es 0 en el caso de que el movmiento sea correcto
	;ret
;
	;pared:
	;ld	a, #1				;; A es 1 en el caso de que el movimiento sea incorrecto
	ret



;;------------------------------------------------
;; Convierte un valor numerico guardado en memoria en un string (valor numerico de 16 bits, es decir < 65556)
;;  	-> HL  numero a convertir (DEBE SER MENOR QUE 65556) 
;;	-> DE  puntero al string ascii (DEBE SER DE LONGITUD 5, POR EJEMPLO "00000")
;; 	<- Ningun valor de salida, pero el string habra sido actualiado
;;------------------------------------------------
Num2Dec16b::
  ld  bc, #-10000
  call  Num1
  ld  bc, #-1000
  call  Num1
  ld  bc, #-100
  call  Num1
  ld  c, #-10
  call  Num1
  ld  c,b
Num1:
 ld  a,#'0'-1
Num2:
  inc a
  add hl,bc
  jr  c,Num2
  sbc hl,bc

  ld  (de),a
  inc de
  ret


;;------------------------------------------------
;; Convierte un valor numerico guardado en memoria en un string (valor numerico de 8 bits, es decir < 256)
;;  	-> HL  numero a convertir (DEBE SER MENOR QUE 256) 
;;	-> DE  puntero al string ascii (DEBE SER DE LONGITUD 3, POR EJEMPLO "000")
;; 	<- Ningun valor de salida, pero el string habra sido actualiado
;;------------------------------------------------
Num2Dec8b::
  ld  bc, #-100
  call  Num1b
  ld  c, #-10
  call  Num1b
  ld  c,b
Num1b:
 ld  a,#'0'-1
Num2b:
  inc a
  add hl,bc
  jr  c,Num2b
  sbc hl,bc

  ld  (de),a
  inc de
  ret

;;------------------------------------------------
;; Indica que numero de los introducidos es mayor
;;	-> b es el primer valor
;;	-> c es el segundo valor
;;
;; 	<- a . Almacena el valor 1 si b es el mayor y 0 si c es el menor
;; 2 1  1 1  1 0   2  4  1 4  1 3  0  3  1 2 1 1
;;------------------------------------------------
comparar::

	ld	a, b
	cp	c

	jp	c, b_menor
	ld	a, #1

	ret

	b_menor:
	ld	a, #0

	ret


;;------------------------------------------------
;; Descompime un tilemap codificado en 1 byte = 4 tiles.
;;	-> HL apunta al tilemap comprimido
;; IMPORTANTE!!!!!!!!!!!!!!!!!!!!!!!! -> 0x0041 ES EL BUFER DE DECOMPRESION, NO SOBREESCRIBIR
;;------------------------------------------------
descomprimir_tilemap::
	ld ix, #0x0041
	ld de, #450
	__bucle:
		ld a, (hl)
		
		ld b, #0
		bit 6, a
		call nz, setCero
		bit 7, a
		call nz, setUno

		ld (ix), b
		inc ix 

		ld b, #0
		bit 4, a
		call nz, setCero
		bit 5, a
		call nz, setUno

		ld (ix), b
		inc ix 

		ld b, #0
		bit 2, a
		call nz, setCero
		bit 3, a
		call nz, setUno

		ld (ix), b
		inc ix 

		ld b, #0
		bit 0, a
		call nz, setCero
		bit 1, a
		call nz, setUno

		ld (ix), b
		inc ix 

		inc hl
		dec de
		ld a, d
		cp #0
		jp nz, __bucle
		ld a, e
		cp #0
		jp nz, __bucle

	ret


setUno:
	set 1, b
	ret


setCero:
	set 0, b
	ret

;;------------------------------------------------
;; Dibuja el sprite adecuado dependiendo del estado en el que se encuentre la entidad
;; 	-> IX es el puntero a la entidad 
;;------------------------------------------------
entity_state::

    ld a, last_state(ix) ;; Comprueba si el estado actual es igual al estado anterior
    ld b, state(ix) ;; |
    cp b ;; |
    jr nz, restart_counter ;; En caso de que no sea el mismo estado, reiniciamos el valor de las etiquetas
    jp check_state ;; Si es el mismo estado, mantenemos el valor de las etiquetas

restart_counter: ;; Reinicia el valor de las etiquetas
    ld a, last_state(ix) ;; Si el ultimo estado era 0, no se reinicia
    cp #0 ;; |
    jr z, check_state ;; Si era 0, saltamos a comprobar el estado actual
    ld a, (initial_speed) ;; Reinicia la velocidad de la transicion (5)
    ld speed_animation(ix), a ;; |
    ld a, #2 ;; Reinicia el numero de sprite
    ld num_animation(ix), a ;; |

check_state: ;; Comprueba el estado actual
    ld a, state(ix)

    cp #2
    jp z, estado_2
    cp #3
    jp z, estado_3
    cp #4
    jp z, estado_4
    cp #5
    jp z, estado_5
    cp #0
    jp z, estado_0
    cp #1
    jp z, estado_1

    continue_drawing: ;; Dibuja con el sprite que se ha metido en hl
   
        ld sprite_l(ix), l
        ld sprite_h(ix), h

    draw:
        call entity_draw
        ret

    estado_0: ;; Parado
        jp draw

    estado_1: ;; Atacando. No se usa
        ld a, b
        ld h, front1_h(ix)
        ld l, front1_l(ix)
        jp finishStates

    estado_2: ;; Derecha
    	ld a, num_animation(ix) ;; Comprueba si tiene que pintar el sprite 1 o 2
    	cp #1 ;; |
    	jr z, lado1 ;; Si es 1, salta a pintar el sprite1

        ld a, speed_animation(ix) ;; Comprueba que hayan pasado los 5 ciclos
        dec a ;; |
        ld speed_animation(ix), a ;; |
        ld h, side1_h(ix) ;; |
        ld l, side1_l(ix) ;; |
    	cp #0 ;; |
    	jp nz, finishStates ;; Si no han pasado, se pinta el sprite anterior

 	ld h, side2_h(ix) ;; Si han pasado los ciclos, se pinta el nuevo sprite
 	ld l, side2_l(ix) ;; |
 	ld a, (initial_speed) ;; Se reinicia la velocidad
 	ld speed_animation(ix), a ;; |
 	ld a, #1 ;; Se inidica que se puede pasar al sprite 1
 	ld num_animation(ix), a ;; |
 	jp finishStates ;; |

        lado1:
            ld a, speed_animation(ix)
            dec a
            ld speed_animation(ix), a
            ld h, side2_h(ix)
 	    ld l, side2_l(ix)
    	    cp #0
    	    jp nz, finishStates

            ld h, side1_h(ix)
            ld l, side1_l(ix)
            ld a, (initial_speed)
            ld speed_animation(ix), a
            ld a, #2
            ld num_animation(ix), a
            jp finishStates

    estado_3: ;; Abajo
        ld a, num_animation(ix)
    	cp #1
    	jr z, frente1

        ld a, speed_animation(ix)
        dec a
        ld speed_animation(ix), a
        ld h, front1_h(ix)
        ld l, front1_l(ix)
    	cp #0
    	jp nz, finishStates

 	ld h, front2_h(ix)
 	ld l, front2_l(ix)
 	ld a, (initial_speed)
 	ld speed_animation(ix), a
 	ld a, #1
 	ld num_animation(ix), a
 	jp finishStates

        frente1:
            ld a, speed_animation(ix)
            dec a
            ld speed_animation(ix), a
            ld h, front2_h(ix)
 	    ld l, front2_l(ix)
    	    cp #0
    	    jp nz, finishStates

            ld h, front1_h(ix)
            ld l, front1_l(ix)
            ld a, (initial_speed)
            ld speed_animation(ix), a
            ld a, #2
            ld num_animation(ix), a
            jp finishStates

    estado_4: ;; Izquierda
    	ld a, num_animation(ix)
    	cp #1
    	jr z, ladoI1

        ld a, speed_animation(ix)
        dec a
        ld speed_animation(ix), a
        ld h, left1_h(ix)
        ld l, left1_l(ix)
    	cp #0
    	jp nz, finishStates

 	ld h, left2_h(ix)
 	ld l, left2_l(ix)
 	ld a, (initial_speed)
 	ld speed_animation(ix), a
 	ld a, #1
 	ld num_animation(ix), a
 	jp finishStates

        ladoI1:
            ld a, speed_animation(ix)
            dec a
            ld speed_animation(ix), a
            ld h, left2_h(ix)
 	    ld l, left2_l(ix)
    	    cp #0
    	    jp nz, finishStates

            ld h, left1_h(ix)
            ld l, left1_l(ix)
            ld a, (initial_speed)
            ld speed_animation(ix), a
            ld a, #2
            ld num_animation(ix), a
            jp finishStates

    estado_5: ;; Arriba
        ld a, num_animation(ix)
    	cp #1
    	jr z, arriba1

        ld a, speed_animation(ix)
        dec a
        ld speed_animation(ix), a
        ld h, back1_h(ix)
        ld l, back1_l(ix)
    	cp #0
    	jp nz, finishStates

 	ld h, back2_h(ix)
 	ld l, back2_l(ix)
 	ld a, (initial_speed)
 	ld speed_animation(ix), a
 	ld a, #1
 	ld num_animation(ix), a
 	jp finishStates

        arriba1:
            ld a, speed_animation(ix)
            dec a
            ld speed_animation(ix), a
            ld h, back2_h(ix)
 	    ld l, back2_l(ix)
    	    cp #0
    	    jp nz, finishStates

            ld h, back1_h(ix)
            ld l, back1_l(ix)
            ld a, (initial_speed)
            ld speed_animation(ix), a
            ld a, #2
            ld num_animation(ix), a
            jp finishStates

    finishStates:

        ld a, moving(ix) ;; Comprueba que se esta movimiento para dibujar la animacion o no
    	cp #0 ;; |
    	jp z, draw ;; Si no se esta moviendo, no actualiza el sprite
        jp continue_drawing
    	
ret


;;--------------------------------------------------------------------------------------------------------
;;  Pinta el tilemap seleccionado
;;--------------------------------------------------------------------------------------------------------
background_paint::

   ld hl, #0x0041                  ;;En HL se guarda el puntero al tilemap que se quiera pintar
   push hl
   ld hl, (pointerScreen)
   push hl


   ld b, #0                             ;; Coordenada Y EN TILES de donde empieza el cuadrado en el tilemap
   ld c, #0                             ;; Coordenada X EN TILES de donde empieza el cuadrado en el tilemap
   ld e, #40                            ;; Anchura del cuadrado de tilemap que se quiere pintar 
   ld d, #45                           ;; Altura de cuadrado de tilemap que se quiere pintar
   ld a, #40                            ;; Anchura total del mapa EN TILES
   call  cpct_etm_drawTileBox2x4_asm

  ret


equal_entity::

  ld a, (hl)
  ld b, a
  ld a, (de)

  cp b
  jp nz, distinto

  inc hl
  inc de

  ld a, (hl)
  ld b, a
  ld a, (de)

  dec hl
  dec de

  cp b
  jp nz, distinto

  ld a, #1
  ret

  distinto:
  ld	a, #0
  ret



;;------------------------------------------------
;; Comprueba si se realizan colisiones en el mapa con otros enemigos
;;
;;  -> DE es el puntero a la entidad que se desea comprobar con el resto
;;------------------------------------------------
check_enemy_collision::

    push ix
    pop hl

    loop_collison:

        ld  a, (hl)
        cp  #0xff
        jp  z, end_loop_enemy
        cp #0
        jp z, next

        call equal_entity
        cp  #0
        jp  nz, next

        call check_collision
        cp #0
        jp  nz, collision_enemigo

        next:

        ld  bc, (enemy_size_in_bytes)
        ld  b, #00
        add ix, bc
        push ix
        pop hl
        jp  loop_collison


    collision_enemigo:
    ld  a, #1
    ret

    end_loop_enemy:
    ld  a, #0
    ret


