Archivo de la categoría: Retro

ZX Spectrum – Cargando BASIC de manera personalizada (II): cuenta atrás

Ahora empezamos a ponerle cosas “raras” a nuestro programa, y como vamos a grabar el juego un montón de veces voy a utilizar la variante de Crash (para no tener que escribir un montón de veces las instrucciones de grabación). Ya sabemos cómo cargar un BASIC como CODE, se lo podemos servir en bandeja a diferentes rutinas de carga. Empezaremos por una de las fáciles: la rutina de carga con contador publicada en Microhobby en el número 191.

Leyendo las instrucciones, vemos que no hay muchas cosas que hacer… hacemos un CLEAR, cargamos la rutina en 64768, la pokeamos un rato (si queremos) y la ponemos a cargar un bloque CODE con USR 65313. Aquí hay un cambio con lo que hemos hecho antes: no creo que sea buena idea cargar nuestro bloque de datos con un CLEAR modificado. Así que (por si las moscas) vamos a grabar nuestro basic con un CLEAR 64767. Lo ponemos en la línea 9999, de forma que quede así:

9999 CLEAR 64767:
     LET STKEND=PEEK 23653+256*PEEK 23654:
     SAVE "basic" CODE 23552,STKEND-23500:
     RUN 7600

Además, es muy mala idea modificar las variables del sistema, por lo que un RANDOMIZE USR 65313 no es aconsejable. Podemos poner PRINT USR, que no toca las variables del sistema y no nos dará problemas. El cargador nos quedaría así:

10 BORDER 0: PAPER 0: INK 0: CLEAR 64767
20 LOAD "" CODE: PRINT USR 65313

Salvamos nuestro cargador, salvamos la rutina de Microhobby y después salvamos nuestro BASIC usando el GO TO 9999. Ya tenemos nuestro programa grabado con contador.

Enlaces interesantes:

Anuncios

ZX Spectrum – Cargando BASIC de manera personalizada (I): BASIC como CODE

Este es un mini-tutorial casero sobre cómo hacer que programas BASIC carguen de maneras “raras”.

Esto no es un tutorial sobre protecciones (hay cientos), aunque indirectamente se impida hacer un MERGE “”, y a estas alturas de la historia tampoco recomendaría proteger un juego de Spectrum. Simplemente, es para hacer el chulo. Si vas a usar algunos de estos trucos, te recomendaría que guardes una copia desprotegida; también estaría bien que dejes que otra gente espíe tus proyectos y pueda aprender de ellos.

No soy un especialista en programación, así que para todos estos ejemplos he pillado rutinas publicadas en revistas o internet (además, no tiene sentido reinventar la rueda). Por eso no hay una rutina con contador y turbo a la vez… es que básicamente no la he encontrado y no me veo capaz de desarrollarla.

Empecemos…

¿Qué es lo que necesitamos?

Aunque hay muchas rutinas que pueden hacer cargas no estándar para juegos en código máquina, no hay ninguna que lo haga para juegos en BASIC. ¿Por qué? Pues se me ocurren un montón de razones, pero la primera de todas es que no hacen falta. El BASIC acaba siendo también una secuencia de bytes en memoria, así que puede ser también grabado como CODE, y todas las rutinas no estándar aceptan bloques CODE.

Por supuesto, la cosa no es tan sencilla (aunque tampoco es mucho más complicada). Para hacer funcionar un programa BASIC, el Spectrum necesita saber una serie de cosas, como la longitud del BASIC, las variables, cuál es la siguiente instrucción a ejecutar… cuando cargas un bloque con LOAD “”, estos datos los va rellenando con lo que se encuentra en la cabecera; cuando cargas con LOAD “” CODE se limita a meter las cosas a martillazos en memoria. Afortunadamente, si has cargado el juego de una manera normal, el Spectrum ya conoce estos datos y los tiene en memoria. Todo esto está bien guardadito en el área de variables (dirección 23552 en adelante). Teniendo en cuenta que después del área de variables viene el BASIC en sí, podríamos empezar a grabar desde ahí y no tendríamos problemas.

Lo que no vamos a necesitar es la memoria de pantalla (aunque luego podrías querer poner una pantalla de carga), el buffer de impresora (esto es MUY importante… en los 128k esto puede hacer que casque el equipo), la pila (de nuevo: peligro de bloqueo/reseteo) y los UDG (la mayor parte de las veces se generan en el BASIC).

Nuestro juego de prueba va a ser el “Almacén Lunar”, publicado en la Microhobby número 100 (y la cinta correspondiente de Microhobby Semanal). ¿Por qué este juego? Pues principalmente, porque es un juego bastante hermoso (unos 30k) escrito únicamente en BASIC, tiene autorun en la línea 7600 y además me tocó los cojones intentando depurar un error (al final lo resolvió NeilParsons del Proyecto BASIC ZX). La versión que voy a utilizar está modificada (ver línea 7601) para funcionar en un 128k, por lo demás es la misma.

Grabando BASIC como CODE:

Ya sabemos dónde debemos empezar a grabar (23552), así que ahora queda averiguar cuánto debemos grabar. A partir de aquí tenemos dos alternativas: la mía y la publicada en Crash (número 34). La diferencia es que la mía no deja “restos” en el programa BASIC, y la de Crash necesita incluir una línea BASIC especial.

Empecemos por la teoría. Como he dicho antes, el Spectrum guarda en el área de variables un montón de datos, entre ellos la dirección de inicio del BASIC, de las variables, de la línea de comandos, del calculador… si sabemos qué viene detrás del BASIC (vale, son las variables, pero también podemos querer grabarlas), podemos hacer un bloque CODE que empiece en 23552 y acabar en la última dirección “interesante”.

La revista Crash sugiere añadir esta línea al programa:

9999 LET STKEND=PEEK 23653+256*PEEK 23654:
     SAVE "basic" CODE 23552,STKEND-23500:
     RUN 7600

En este caso, utilizan la variable del sistema STKEND para calcular el tamaño del programa. Esta variable marca el inicio de la memoria “libre” del Spectrum.  Al ejecutar un GO TO 9999, se grabará todo el BASIC como CODE. Dos observaciones acerca de esto:

  • Como grabamos todas las variables del sistema incluyendo la línea e instrucción que se está ejecutando, al terminar de cargar ejecutará ese RUN 7600 y lanzará el programa.
  • El autor del truco ha grabado un cacho más (concretamente 52 bytes) de lo que necesitaba. Creo que aquí no es necesario, pero tampoco hace daño.

Mi variante es algo más basta e implica el uso de la variable K_CUR (23643) que indica la posición de memoria del cursor. Si estás metiendo una instrucción, eso apuntará a la línea de instrucciones, pasados el BASIC y el área de variables del BASIC.

Así que cargamos el juego con MERGE “” y ejecutamos PRINT PEEK 23643+256*PEEK 23644. En mi caso, el Spectrum me devuelve 52908. Así que la longitud de lo que voy a grabar será 52908-23552+50 (para hacer sitio a mi línea de comandos). Eso da un resultado de 29406. En este caso sí que debo grabar más datos de los necesarios, ya que en la cinta van a ir el BASIC y la línea de comandos.

Así que ahora hago un SAVE “basic” CODE 23552,29406: RUN 7600 y obtendré un bloque CODE que luego puedo cargar sin problemas.

El método de grabación es lo de menos. Por lo general os diría que usáseis el publicado en Crash (por si tenéis que hacer muchas pruebas). En cuanto al cargador, eso va a ser muy sencillo:

10 BORDER 0: PAPER 0: INK 0: CLS
20 LOAD "" CODE

NOTA: Otra variante sin cálculos tan complejos es hacer un SAVE “basic” CODE 16384,49152: RUN 7600. Este método lo veo muy desaconsejable ya que váis a grabar toooda la RAM ocupando innecesariamente espacio en cinta (y alargando el tiempo de carga). Además, luego no quedará espacio para meter otras cosas, como cargas turbo o compresores.

Enlaces interesantes:

  • Almacén Lunar: El fichero conteniendo todas las versiones de este programa.