Código fuente de Mag the Magician para ZXUno, con rutinas en ASM para usar en Z88DK (modo radastaniano)

Software para o relacionado con el core ZX Spectrum / Software for or related to the ZX Spectrum core
Responder
Avatar de Usuario
Radastan
Mensajes: 389
Registrado: 05 Oct 2015, 14:39

Código fuente de Mag the Magician para ZXUno, con rutinas en ASM para usar en Z88DK (modo radastaniano)

Mensaje por Radastan » 01 Sep 2020, 14:24

Aquí os dejo el código fuente del juego, que incluye rutinas en ASM para manejar el modo Radastaniano.
codigo TAP zxuno.zip
Código fuente de Mag the Magician
(528.1 KiB) Descargado 174 veces
Empezamos por un borrado de pantalla a un color de la paleta:

Código: Seleccionar todo

// ___________________________________________
// Borra la pantalla a un color
// ___________________________________________

void cls (int color)
{
	#asm
		ld hl,2			;pasamos la variable de entrada al acumulador
		add hl,sp
		ld a, (hl)
		rla			;rotamos 4 bits a la izquierda
		rla
		rla
		rla			;ya tenemos el color del primer pixel
		add a, (hl)		;añadimos el color del segundo pixel
		
		ld hl, 16384
		ld de, 16385
		ld bc, 6143
		ld (hl), a
		ldir
	#endasm
}
Para definir la paleta, tenemos esta rutina:

Código: Seleccionar todo

// ___________________________________________
// Definir paleta de color
// ___________________________________________
void escribe_paleta (int indice, int color)
{
	// Los bits del color van en forma GGGRRRBB
	port_out (48955, indice);
	port_out (65339, color);
}
Empezamos con lo interesante, posicionar un tile/sprite de 8x8 pixels radastanianos en pantalla:

Código: Seleccionar todo

// ___________________________________________
// Posiciona un Sprite de 8x8 a color
// ___________________________________________

void put_sprite_x8 (unsigned char *posicion, unsigned int x, unsigned int y)
{
	// -------------------------------------------
	// RUTINA DE IMPRESION DE UN SPRITE 8x8 PIXELS
	// EN CUALQUIER POSICION DE BYTES (cada byte dos pixels horizontales)
	// ENTRADAS:
	// D será la posición del cursor vertical en pixels
	// E será la posición del cursor horizontal en parejas de pixels
	// HL es la posición de memoria donde tenemos el sprite
	// SALIDAS: se escribe en el mapa de pantalla
	// ADVERTENCIAS: no comprueba límites de pantalla
	// -------------------------------------------
	#asm
		ld hl,2		; Pasamos la variable de entrada al acumulador
		add hl,sp
		ld d, (hl)	; D es el valor Y
		inc hl
		inc hl
		ld e, (hl)	; E es el valor X
		inc hl
		inc hl
		ld a, (hl)
	    	inc hl
	    	ld h, (hl)
	    	ld l, a		; HL es el puntero al sprite
	
		ld a, d		; recuperamos el valor vertical
		rrca
	        rrca		; rotamos para dejar su valor en múltiplos de 64 (linea, de dos en dos pixels)
		and 192		; borramos el resto de bits por si las moscas
		or e		; sumamos el valor horizontal
		ld e, a		; e preparado
		ld a, d		; cargamos el valor vertical
		rrca
		rrca		; rotamos para quedarnos con los bits altos
		and 63		; borramos el resto de bits
		or 64		; nos posicionamos a partir de 16384 (16384=64+0 en dos bytes)
		ld d, a		; d preparado, ya tenemos la posición en pantalla
	
		ld b,8		; Indicamos que vamos a pintar 8 líneas
		.draw		; dibujamos 8 pixels (4 bytes)
		ld c,4		; Indicamos que vamos a pintar 4 pares de pixels
		ldi
		ldi
		ldi
		ldi
		ld a,e
		add a,60	; incrementamos una línea y retornamos los pixels dibujados
		ld e,a
		jr nc, sigue
		inc d		; incrementamos D si sale acarrero al incrementar E en 64 bytes
		.sigue
		djnz, draw
	
		ret
	
	#endasm
}
Esta mola más, pone un sprite de 8x8 pixels en pantalla, pero usa el color de paleta con índice 0 para usarlo de máscara:

Código: Seleccionar todo

// ___________________________________________
// Posiciona un Sprite de 8x8 a color con máscara
// ___________________________________________

void put_msprite_x8 (unsigned char *posicion, unsigned int x, unsigned int y)
{
	// -------------------------------------------
	// RUTINA DE IMPRESION DE UN SPRITE 8x8 PIXELS CON MÁSCARA
	// EN CUALQUIER POSICION DE BYTES (cada byte dos pixels horizontales)
	// El color de la máscara es el 0, no necesita máscara adicional
	// ENTRADAS:
	// D será la posición del cursor vertical en pixels
	// E será la posición del cursor horizontal en parejas de pixels
	// HL es la posición de memoria donde tenemos el sprite
	// SALIDAS: se escribe en el mapa de pantalla
	// ADVERTENCIAS: no comprueba límites de pantalla
	// -------------------------------------------
	#asm
		ld hl,2		; Pasamos la variable de entrada al acumulador
		add hl,sp
		ld d, (hl)	; D es el valor Y
		inc hl
		inc hl
		ld e, (hl)	; E es el valor X
		inc hl
		inc hl
		ld a, (hl)
	    	inc hl
	    	ld h, (hl)
	    	ld l, a		; HL es el puntero al sprite
	
		ld a, d		; recuperamos el valor vertical
		rrca
	        rrca		; rotamos para dejar su valor en múltiplos de 64 (linea, de dos en dos pixels)
		and 192		; borramos el resto de bits por si las moscas
		or e		; sumamos el valor horizontal
		ld e, a		; e preparado
		ld a, d		; cargamos el valor vertical
		rrca
		rrca		; rotamos para quedarnos con los bits altos
		and 63		; borramos el resto de bits
		or 64		; nos posicionamos a partir de 16384 (16384=64+0 en dos bytes)
		ld d, a		; d preparado, ya tenemos la posición en pantalla
	
		ld b,8		; Indicamos que vamos a pintar 8 líneas
		.mdraw1		; dibujamos 8 pixels (4 bytes)
		ld a, (hl)
		cp 0
		jr z, nodraw1	;si los pixels son 0 saltamos
		ld (de),a
		.nodraw1
		inc hl
		inc de
		ld a, (hl)
		cp 0
		jr z, nodraw2	;si los pixels son 0 saltamos
		ld (de),a
		.nodraw2
		inc hl
		inc de
		ld a, (hl)
		cp 0
		jr z, nodraw3	;si los pixels son 0 saltamos
		ld (de),a
		.nodraw3
		inc hl
		inc de
		ld a, (hl)
		cp 0
		jr z, nodraw4	;si los pixels son 0 saltamos
		ld (de),a
		.nodraw4
		inc hl
		inc de

		ld a,e
		add a,60	; incrementamos una línea y retornamos los pixels dibujados
		ld e,a
		jr nc, msigue
		inc d		; incrementamos D si sale acarrero al incrementar E en 64 bytes
		.msigue
		djnz, mdraw1
	
		ret
	
	#endasm
}
Para poder reponer el fondo, uso esta rutina, que recoge un fondo de 8x8 de la pantalla para meterlo en memoria:

Código: Seleccionar todo

// ___________________________________________
// Recoge un Sprite de 8x8 a color de pantalla
// ___________________________________________

void get_sprite_x8 (unsigned char *posicion, unsigned int x, unsigned int y)
{
	// -------------------------------------------
	// RUTINA DE CAPTURA DE UN SPRITE 8x8 PIXELS
	// EN CUALQUIER POSICION DE BYTES (cada byte dos pixels horizontales)
	// ENTRADAS:
	// D será la posición del cursor vertical en pixels
	// E será la posición del cursor horizontal en parejas de pixels
	// HL es la posición de memoria donde tenemos el sprite
	// SALIDAS: se escribe en el mapa de pantalla
	// ADVERTENCIAS: no comprueba límites de pantalla
	// -------------------------------------------
	#asm
		ld hl,2		; Pasamos la variable de entrada al acumulador
		add hl,sp
		ld d, (hl)	; D es el valor Y
		inc hl
		inc hl
		ld e, (hl)	; E es el valor X
		inc hl
		inc hl
		ld a, (hl)
	    	inc hl
	    	ld h, (hl)
	    	ld l, a		; HL es el puntero al sprite
	
		ld a, d		; recuperamos el valor vertical
		rrca
	        rrca		; rotamos para dejar su valor en múltiplos de 64 (linea, de dos en dos pixels)
		and 192		; borramos el resto de bits por si las moscas
		or e		; sumamos el valor horizontal
		ld e, a		; e preparado
		ld a, d		; cargamos el valor vertical
		rrca
		rrca		; rotamos para quedarnos con los bits altos
		and 63		; borramos el resto de bits
		or 64		; nos posicionamos a partir de 16384 (16384=64+0 en dos bytes)
		ld d, a		; d preparado, ya tenemos la posición en pantalla

		ex de,hl	; intercambiamos DE y HL
	
		ld b,8		; Indicamos que vamos a recoger 8 líneas
		.gdraw		; recogemos 8 pixels (4 bytes)
		ld c,4		; Indicamos que vamos a pintar 4 pares de pixels
		ldi
		ldi
		ldi
		ldi
		ld a,l
		add a,60	; incrementamos una línea y retornamos los pixels leidos
		ld l,a
		jr nc, gsigue
		inc h		; incrementamos H si sale acarrero al incrementar E en 64 bytes
		.gsigue
		djnz, gdraw
	
		ret
	
	#endasm
}
Y para finalizar, os dejo una rutinilla que vuelca una pantalla completa:

Código: Seleccionar todo

// ___________________________________________
// Pone una pantalla completa
// ___________________________________________

void put_screen (unsigned char *posicion)
{
	// -------------------------------------------
	// RUTINA DE IMPRESION DE UNA PANTALLA
	// 128x96 pixels
	// -------------------------------------------
	#asm
		ld hl,2		; Pasamos la variable de entrada al acumulador
		add hl,sp
		ld a, (hl)
	    	inc hl
	    	ld h, (hl)
	    	ld l, a		; HL es el puntero al sprite
		ld de, 16384	; DE es el puntero a pantalla
	
		ld bc, 6144
		ldir
		ret
	
	#endasm
}
Con todo esto es posible escribir un juego en C, o ASM, de forma muy sencilla.
Lo bueno es que no tenéis que preocuparos de convertir los gráficos, ya que podéis usar la herramienta en java que realicé. Con ella podéis crear una paleta y convertir los tiles/sprites a golpe de clic.

Avatar de Usuario
Radastan
Mensajes: 389
Registrado: 05 Oct 2015, 14:39

Re: Código fuente de Mag the Magician para ZXUno, con rutinas en ASM para usar en Z88DK (modo radastaniano)

Mensaje por Radastan » 01 Sep 2020, 14:27

Podemos inicializar el modo radastaniano desde Z88DK gracias a la rutina chorra que tengo creada:

Código: Seleccionar todo

	// Inicializamos el modo Radastaniano
	port_out (64571,64);
	port_out (64827,3);
La función port_out es bien sencilla:

Código: Seleccionar todo

// ___________________________________________
// Función para sacar un dato por un puerto
// ___________________________________________

void port_out (int port, int value)
{
	#asm
	ld hl,2
	add hl,sp
	ld a, (hl)
	inc hl
	inc hl
	ld c, (hl)
	inc hl
	ld b, (hl)
	out (c),a
	#endasm
}
Para definir la paleta del tirón, la meto en un fichero de texto paleta.h (generado por mi conversor), y basta hacer esto al comienzo del código en C:

Código: Seleccionar todo

// Definimos la paleta
	for (a=0;a<16;++a)
	{
		escribe_paleta (a,paleta[a]);
	}

Avatar de Usuario
Radastan
Mensajes: 389
Registrado: 05 Oct 2015, 14:39

Re: Código fuente de Mag the Magician para ZXUno, con rutinas en ASM para usar en Z88DK (modo radastaniano)

Mensaje por Radastan » 01 Sep 2020, 14:45

Os recuerdo a todos el hilo donde podéis descargar el conversor:
viewtopic.php?f=39&t=2889

Avatar de Usuario
desUBIKado
Mensajes: 1002
Registrado: 05 Ago 2016, 22:33

Re: Código fuente de Mag the Magician para ZXUno, con rutinas en ASM para usar en Z88DK (modo radastaniano)

Mensaje por desUBIKado » 01 Sep 2020, 18:40

Me he descargado la versión .rom del juego que es para usar con el Interface 2, y si la cargo desde el navegador NMI del Dr Slump que usa la utilidad .ownrom para hacerlo, se ve la casa de tejado amarillo del inicio, pero si se pulsa SPACE el paper y el border se vuelven blancos durante un instante, y vuelve a aparecer la pantalla con la casa de tejado amarillo y el juego no empieza.

No es un problema importante ya que la versión .TAP, tanto de la normal como la de modo readastaniano funcionan perfectamente, pero es curioso que no funcione la .rom en el ZX-Uno cargándola con .ownrom.

Avatar de Usuario
Radastan
Mensajes: 389
Registrado: 05 Oct 2015, 14:39

Re: Código fuente de Mag the Magician para ZXUno, con rutinas en ASM para usar en Z88DK (modo radastaniano)

Mensaje por Radastan » 02 Sep 2020, 07:45

Raro, raro, porque la rom es la misma con la que se grabó el juego en cartucho físico.

Avatar de Usuario
Radastan
Mensajes: 389
Registrado: 05 Oct 2015, 14:39

Re: Código fuente de Mag the Magician para ZXUno, con rutinas en ASM para usar en Z88DK (modo radastaniano)

Mensaje por Radastan » 02 Sep 2020, 10:18

Aquí tienes el código fuente del juego para cartucho, por si sirve de algo:
codigo IF2.zip
Código fuente Mag para IF2
(544.32 KiB) Descargado 218 veces

Responder