Archive for septiembre 2022

Usando inputs del usuario como mensajes del juego en DAAD para Spectrum.

20 septiembre, 2022

Los aficionados con los que coincido en foros, chats y RRSS han podido aburrirse oyéndome contar la batallita de que para el concurso de aventuras de Bytemaniacos del 2017 llegué a poner en marcha un motor de juegos del tipo «elige tu propia aventura» para el DAAD pero… para cuando acabó el plazo de entrega no llegó a ocurrírseme ninguna aventura con la que utilizarlo XDD

Así que el motor quedó abandonado y, literalmente, muerto de la risa esperando su momento de rescate. Pasaron cuatro largos años y una pandemia y un buen día me encontré en el brete de proyectar contenido para el stand de Zona FI de RetroParla 2021 en un momento en el que todavía se mantenían un montón de restricciones para exponer en un acto público. En esa situación lo mejor que se me ocurrió fue preparar una mesa más bien minimalista con un cartel en el que pondría un código QR que enlazaría a un pequeño juego tipo ETPA que crearía con Twine en su modalidad Chapbook, maravillosamente jugable en móvil. Con ello evitaría todo contacto con teclados potencialmente usados por decenas de visitantes y tendría una excusa para regalar revistas, fanzines del CAAD, y un par de libros a quienes terminasen la aventura allí mismo. La idea funcionó tan bien que, de haber podido volver a tener tiempo para asistir como expositor a eventos posteriores, la hubiera repetido con entusiasmo, pero la «vida real», como suele suceder, dispuso las cosas de otra manera.

En cualquier caso, la aventura que usé para la ocasión no surgió de la nada. Estaba basada en el ejemplo de juegos tipo ETPA que usó Tim Hartnell (autor que fue muy querido por sus libros de programación e inteligencia artificial en los felices 80) en su libro Creating Adventure Games on Your Computer (Ballantine Books, 1984). El juego se llamaba Werewolves and Wanderers y básicamente consistía en recorrer un castillo abandonado usando una moneda para decidir, a cara o cruz, los encuentros aleatorios con monstruos y el resultado de su lucha con ellos. Como algo tan dependiente del azar no se ajustaba bien a lo que necesitaba, ya que no sería del todo justo hacer depender los regalos a la pura suerte, eliminé ese elemento cambiándolo por una pequeña trama en la que habría que resolver un puzle sencillito que cualquiera podría acabar en cuestión de minutos, manteniendo del juego original el mapeado y las descripciones de localidades libremente traducidas a nuestro idioma. Si alguno tiene curiosidad por ver el resultado, retitulado como Explorando el castillo maldito, todavía se puede encontrar por AQUÍ.

Portada de la versión Twine de Explorando el castillo maldito
Momento del juego
Libros del recordado Tim Hartnell. Tiene su encanto leer ahora sobre la visión que se tenía de la inteligencia artificial hace treinta y muchos años 🙂
El juego Werewolves and Wanderers sobre el papel

Posteriormente el tema de cómo crear juegos ETPA con herramientas de creación para aventuras de texto basadas en parser para ordenadores de 8 bits (como el PAWS o el DAAD) continuó saliendo periódicamente en chats como el grupo de Telegram de Retroaventuras y yo seguía contando la historia de mi «motor sin aventura» hecho para DAAD que… un momento… ¿cómo que no tenía una aventura? ¡Por supuesto que la tenía! XDD El Castillo maldito sería el conejillo de indias ideal para ponerlo a prueba.

Ante todo, con perdón por la obviedad, hay que dejar claro que los ETPA y las conversacionales clásicas son dos tipos de «bestia» sustancialmente distintos entre sí:

– La aventura conversacional, aventura de texto, o poniéndonos pomposos, ficción interactiva basada en parser, se distingue por tener una estructura cuyos elementos comúnmente suelen ser localidades, objetos (que pueden ser personajes), un vocabulario y una suerte de puzles que se crean combinando todo lo anterior.

– Los ETPA o librojuegos, o, siendo pomposos otra vez, la ficción interactiva basada en opciones, se construyen a partir de lo que podemos llamar «escenas» o «situaciones» que pueden ser, o en las que puede pasar, cualquier cosa. No dependen ni se edifican a partir de un mapeado geográfico ni de los objetos dispersos por éste. Un error habitual es confundir las «localidades» de las aventuras de texto con las «escenas» de los librojuegos. Lo único que tienen en común es que son «átomos» que componen la base de sus respectivos tipos de obra.

– Un tercero en discordia, por completismo, serían las aventuras de texto basadas en menús. Lejos de ser una suerte de «eslabón perdido» entre los otros dos, son en realidad un modelo mucho más cercano al parser que a las opciones. Básicamente son conversacionales clásicas en las que se ha sustituido el interfaz de usuario por una serie de menús que hacen referencia a… localidades, objetos y acciones, o sea, lo mismo pero de otra manera. En ocasiones los dos modelos han demostrado ser intercambiables, como en los clásicos de Legend Entertaiment donde se podía jugar indistintamente de un modo u otro. A pesar de su cercanía al modelo de parser, la interfaz condiciona mucho el tipo de historia que puedes contar con ella, ya que no es lo mismo avanzar a través de ella teniendo que ocurrisele a uno la acción a realizar que escogiendo la clásica combinación «acción – objeto» entre las disponibles en un menú.

Ejemplos con fotitos:

Juegos de FI basada en parser: Aventura original (Aventuras AD), Colossal Adventure (Level 9) y Classic Adventure (Melbourne House). Todos ellos versiones del mismo clásico.
Aventuras de texto basadas en menús. La Aventura espacial y Sam Mallard.
Juegos ETPA propiamente dichos: The Archers y la serie de Adrian Mole (Level 9) y Está en la casa (Relevo Videogames).
Las fronteras entre estos estilos de juegos de texto no eran infranqueables. Aquí varios librojuegos de papel de la serie Fighting Fantasy adaptados a aventura conversacional (con parser) por Adventuresoft.

Toda la divagación anterior para al final llegar a una conclusión bastante simple: una herramienta de creación pensada para el modelo de parser nunca será la opción ideal para crear un ETPA ni viceversa. Es, por supuesto, enteramente posible, pero el resultado siempre saldrá… raro…
En el caso del Castillo maldito, partía de una obra originalmente concebida como librojuego para papel (y una monedita 🙂 ) que estaba, eso sí, más basada en recorrer localidades que en desarrollar escenas. Un esquema muy facilito de implementar en el DAAD, pero que produce un efecto «extraño» al jugarse, ya que el desplazamiento mediante opciones en las que una determinada dirección no va a coincidir siempre con la misma posición de opción puede llegar a ser más confuso que el tradicional de teclear puntos cardinales, a pesar de que éste tiene la mala fama de ser el módelo más antiguo y obtuso. Pero eso ya podrán juzgarlo quienes lo prueben.

Por lo demás, traducir de Twine a DAAD no tuvo mucha más historia que reemplazar toda la parte de análisis de las órdenes del jugador por un nuevo bucle que se limitase a discriminar entre las pulsaciones de teclado correspondientes a cada opción, y eso era todo…

¿Todo? ¡No! 🙂 Faltaba algo…

En el Twine original se me ocurrió meter la posibilidad de que el jugador ponga su nombre al personaje. Algo trivial en Twine y en cualquier lenguaje de programación de alto nivel que habremos visto en cientos de juegos. Pero las herramientas de creación de conversacionales basadas en máquinas virtuales, llamense Quill, PAWS, GAC, DAAD o la mismísima máquina Z, sencillamente no están pensadas para ello. Pueden manejar los mensajes que introduzcan en su base de datos durante la compilación, pero no convertir en ellos una cadena de caracteres introducida por el jugador en tiempo de juego. Así el clásico «Introduzca el nombre del jugador» es una maniobra que, en principio, el DAAD no puede realizar… O al menos, no sin ayuda.

En Inform esto se puede resolver dando un rodeo a base de reservar espacio en una matriz, y lo que vamos a hacer en DAAD es, salvando muchas distancias, algo parecido.

El truco está en reservar este espacio (de un número predeterminado de caracteres) en alguna parte de la zona de mensajes de la base de datos de la aventura en DAAD. Cuando pidamos la entrada al jugador, un condacto EXTERN se encargará de llamar a una rutina externa en código máquina que copiará el mensaje introducido desde el buffer donde se almacena la última órden tecleada por el jugador a este espacio reservado en el area de mensajes.

Vamos a desmenuzar todo esto en partes más pequeñas:

Lo primero es determinar donde está el buffer de texto donde se guarda el último input del jugador. En cualquier emulador (las pruebas se hicieron para Spectrum) se puede examinar la memoria en tiempo de ejecución. De un vistazo rapidito de puede localizar en la memoria la palabra que estés introduciendo. En el caso de Speccy se halla en la dirección 33052 y la cadena introducida va siempre seguida por un caracter 13

Localizando a ojo el buffer del input en el volcado de memoria del debugger de un emulador de Spectrum.

Lo siguiente es determinar donde se almacenan los mensajes en la base de datos de la aventura hecha con DAAD. Aquí ya tenemos que inventarnos un convenio arbitrario para hacernos la vida más fácil y este va a ser que reservaremos un espacio de 10 caracteres para nuestro propósito (ponerle un nombre al personaje jugador en tiempo de ejecución del juego) en el mensaje número 0 de la tabla de mensajes del usuario.
En DAAD los 2 bytes que hay en la posición 16 de la cabecera de la base de datos .DDB apuntan a una tabla de palabras (valores a su vez de 2 bytes) con la posición en la memoria de todos y cada uno de los mensajes. Como para complicarnos lo mínimo vamos a usar el primer mensaje, el nº 0, nos basta saber a donde apunta el valor al que apunta la posición 16. En Spectrum el DDB se aloja siempre en 33792, por lo que miraremos lo que hay en 33792 + 16, o sea 33808.

Sabiendo todo esto, la ñapa consistirá en pedir al jugador que introduzca el nombre, recibirlo mediante un condacto PARSE 0 y, en la siguiente entrada, invocar con otro condacto EXTERN a una pequeña rutina en código máquina que pase byte a byte el contenido del buffer (hasta 10 caracteres o hasta que encuentre un caracter 13) al espacio de 10 caraceters que hemos reservado en el mensaje 0.

¡Suena más difícil de lo que realmente es! 🙂 aunque hay más detallitos a tener en cuenta:

DAAD enmascara sus mensajes (para que no se puedan leer tal cual haciendo un simple volcado de memoria) mediante un XOR 255, así que hay que hacerle ese mismo XOR 255 a cada byte al pasarlo a la zona de mensajes para que luego se pueda leer adecuadamente. En código máquina de Z80 es más efectivo hacer un CPL (gracias a Sergio The Pope por el apunte 🙂 )

Y aún hay más. Para que todo funcione damos por hecho que el mensaje 0 de la sección /MTX del código fuente de la aventura consistirá en exactamente 10 espacios reservados, que inicialmente pueden ser cualquier cosa, donde se albergará finalmente el nombre introducido por el jugador. Pero ojito !!! Si al compilar usamos la opción de comprimir los mensajes, y la práctica totalidad de veces lo haremos por el bien de la sufrida y escasa memoria de los ordenadores de 8 bits, el compilador la aplicará a nuestro mensaje 0, dándose la posibilidad de que el espacio que ocupe al finalizar sea inferior. En mis primeras pruebas puse confiadamente un mensaje de 10 espacios en blanco para comprobar que nada funcionaba porque el compresor, muy eficientemente, los había reducido a 2. XDD
El truco para evitar esto es afortunadamente muy sencillo. DAAD comprime buscando en los textos apariciones de los tokens de compresión que hay en la sección /TOK del código fuente. Basta con poner en el mensaje 0 una serie de caracteres que no coincidan con ninguno de ellos. Algo como 10 asteriscos dará perfectamente el pego en la mayoría de los casos. En la plantilla por defecto del DAAD no hay asteriscos en /TOK, y si usas una sección /TOK personalizada, ya sea con la propia herramienta que aporta el DAAD o por alguna de terceros, como la incluida en NAPS, todo es cuestión de buscar una sucesión de caracteres que no se comprima.

Nuestro mensaje 0 será una cadena de 10 asteriscos **********

Si hemos llegado hasta aquí y nada se ha torcido, en cualquier momento del juego podremos llamar al mensaje 0 y saldrá lo que haya introducido el jugador. Eso sí, en GLORIOSAS MAYÚSCULAS XDD, ya que el código interno del condacto PARSE provoca esa transformación y en principio no hay una manera sencilla de interceptarlo.

Todo esto no pretende ser un juego nuevo completo sino una pequeña demo que ilustre el proceso y pueda servir de ayuda a quien quisiera aplicarlo a su juego. Sólo se requiere ser un poco manitas con el ensamblador de Z80. En el enlace se puede jugar al Twine original, a la versión de Spectrum en línea, y descargar el código fuente del juego en formato SCE (sorry, no funcionará con Daad Ready ni con Maluva salvo grandes modificaciones en una y otra parte, aunque todo es ponerse 🙂 ). El código fuente también incluye el de la rutina externa en código máquina para Spectrum, detalladamente comentado. Este último sería bastante fácil de convertir para el DAAD de otros ordenadores de 8 bits cambiando unas pocas direcciones (siempre teniendo en cuenta la regla de que la dirección de la tabla de mensajes se halla en la posición 16 de la cabecera de la base de datos) así que no costaría mucho trabajo adaptarlo a MSX o CPC. Yo mismo lo haría, pero sólo haberlo hecho para Spectrum y escribir este post me ha quitado el poco tiempo libre que he tenido en el último mes y medio, así que la cosa pinta muy malita 😦

Podéis mirarlo todo en:

https://zonafi.es/ecm/

Introduciendo el nombre del jugador en la versión Twine.
Haciendo lo propio en la versión de DAAD para Spectrum.