Tutorial: Introducción práctica a InPAWS

Este tutorial pretende ser una aproximación directa a la programación de aventuras para las plataformas de 8 bits con InPAWS. También te puede servir si simplemente estás curioseando la herramienta y quieres hacerte una idea del tipo de cosas que se pueden hacer y cómo. Vamos a crear una sencilla aventura de dos localidades y dos puzzles, explicando paso a paso el proceso inicial de desarrollo.

Preparación

Se supone que en el momento de comenzar este tutorial, ya debes tener montado un entorno para la compilación y ejecución de tu aventura. Si no es así, tienes una propuesta en este tutorial.

Comenzamos cargando en el editor el esqueleto básico de toda aventura: el fichero nueva-esp.paw, localizado en el directorio Español/demo del zip de Inpaws. Este archivo contiene una lista de verbos y comandos básicos, como coger, dejar, etc, así como las definiciones mínimas que toda aventura en PAW debe tener: una localidad, un objeto, y 55 mensajes del sistema (61 en el caso del Amstrad CPC). Los mensajes y los verbos los dejamos como están, pero la localidad y objeto definidos los borramos para sustituirlos por los de nuestra aventura.

Localidad inicial

Nos posicionamos tras el bloque DEFAULTS y escribimos nuestra primera localidad, aquella en la que comienza el jugador. (Se han partido las cadenas de texto en varias líneas para mayor claridad):

Location Entrada
{
    " Estás frente al mítico templo de Okt. Junto a la
    entrada puedes ver un extraño boquete en la pared.";
}

Toda localidad comienza por la palabra clave Location, seguida del bloque que define a la localidad. En este caso símplemente su descripción. También podríamos haber indicado las salidas obvias desde esta localidad a las aledañas. En ese caso el bloque quedaría como sigue:

Location Entrada
{
    " Estás frente al mítico templo de Okt. Junto a la
    entrada puedes ver un extraño boquete en la pared.";
    CONNECTIONS { ENTRA TO InteriorTemplo SUR to Bosque };
}

Pero en nuestro caso el acceso al templo es en sí mismo un puzzle, y volver al bosque no tiene mucho sentido dentro de la aventura, así que sencillamente ignoramos la claúsula CONNECTIONS.

Todas las palabras reservadas de InPAWS, así como los símbolos y palabras de vocabulario son insensibles a mayúsculas, de forma que podríamos haber escrito Connections, CONNEctions o connections.

Mensaje de presentación de la aventura

En las aventuras hechas con PAW, era costumbre que la localidad numerada con el 0, en la que PAW posiciona al jugador al comenzar la aventura, sirviera como presentación de la misma. Esta localidad no era habitualmente jugable, y simplemente mostraba un mensaje de bienvenida o introducción al jugador, pasándo seguidamente a trasladarle a la localidad inicial "real", que en el caso de nuestra aventura es la que acabamos de definir.

Para asegurarnos de esa localidad coincida con la número cero al trasladar nuestra aventura a PAW, debemos indicárselo expresamente a InPAWS. Esto se hace de la siguiente manera:

// La localidad de inicio debe ser siempre la cero,
// y suele mostrar una introducción a la aventura
LOCATION Inicio 0
{
	"^^Tras meses de exploración en lo profundo de la selva,
	y después de haber sido perseguido, mordido, enfermado,
	pasado hambre y renunciado al sexo, ahora por fin has
	encontrado lo que buscabas, el Templo de Okt, donde según
	cuenta la leyenda se guarda el Gran Diamante del Rajá
	Al-Meredin, rechazado por su amada y condenado a ser
	encerrado eternamente en lo profundo de la selva.^^
	Hasta hoy.";
}

En el trozo de código anterior, observamos varias novedades que paso a explicar a continuación.

Se pueden añadir comentarios al código mediante el uso de la doble barra, al estilo de C++ o Java. Todo lo que venga a continuación de una doble barra, hasta el final de la línea actual será ignorado por el compilador.

Se puede indicar el código de la localidad tras el nombre, en cuyo caso InPAWS forzará a que ese sea el código asignado al generar la aventura. También se permite definir una localidad únicamente por su número, al estilo del viejo PAWS. La utilidad de esto último es dudosa, pero poderse se puede:

LOCATION 34
{
   "Descripción de la localidad 34";
}

La última novedad es el carácter de acento circunflejo "^". Este carácter indica a InPAWS que queremos generar un retorno de carro, de forma que lo que viene a continuación sea mostrado, en nuestra aventura, en una nueva línea. Hay mucho más que decir de estos códigos de control que permiten desde un retorno de carro hasta cambiar el color de los caracteres, el fondo , el juego de caracteres. Consulta el capítulo sobre los códigos de control de InPAWS en el manual para tener todo el detalle sobre su utilización.

Empezamos a trastear con los procesos

Necesitamos que tras mostrar el mensaje de bienvenida, el programa haga una pausa, nos pida pulsar una tecla, y nos lleve a la localidad inicial. Para ello es necesario ampliar el proceso 1, que es el que se llama al finalizar las descripciones en PAW, para que haga estos trabajos.

En PAW todas las entradas de procesos estaban juntas y se definían de forma totalmente independiente de las localidades u objetos a los que afectaran. En InPAWS se ha flexibilizado este procedimiento, y un bloque de procesos no representa a todo el proceso, sino a un trozo del proceso.

Esto nos permite definir las partes de procesos y respuestas que afectan a la localidad u objeto que estamos definiendo, facilitando la depuración y clarificando el código.

Durante el proceso de compilación, InPAWS agrupa todos esos trozos de código en un solo proceso para generar la aventura final. Sin más dilación, así quedaría nuestro código para tratar la presentación a la aventura:

PROCESS 1
{
    _ _ : AT Inicio ANYKEY GOTO Entrada DESC;
}

El trozo de código anterior está metiendo una entrada nueva en la tabla de procesos 1, y esa entrada le está indicando a PAW que cuando el jugador esté en la localidad 0 (Inicio), y tras haber mostrado el mensaje de bienvenida, espere la pulsación de una tecla y lo traslade a la localidad inicial de la aventura: la entrada al templo.

En cada bloque PROCESS o RESPONSE es posible meter tantas entradas como sean necesarias, símplemente separándolas por el carácter de punto y coma. En este caso sólo nos va a hacer falta una, así que el bloque queda muy sencillito.

Como se puede observar, estamos utilizando dentro de los condactos la referencia al nombre de la localidad, no a su código. InPAWS se encargará de casar todo el puzzle de símbolos y códigos al generar la aventura en PAWS, de forma que para el programador sea algo transparente.

El inventario del aventurero

Para poder entrar en el templo, el jugador necesita mover una palanca dentro de un agujero junto a la entrada. Pero este agujero está poblado por ciertas criaturas cuya picadura dará al traste con la operación, así que ni cortos ni perezosos vamos a proporcionar unos guantes antibocado a nuestro sufrido aventurero. La forma de definir los objetos es muy similar a las localidades.

Object Guantes
{
    "Unos guantes";
    INITIALLYAT MochilaLoc;
    WORDS GUANT _;
    WEIGHT 1;
    PROPERTY CLOTHING;
}

El bloque de definición de objetos comienza con la descripción del objeto, que es la cadena con que lo va a identificar en los listados del inventario y en las descripciones de las acciones (ej: Dejas unos guantes").

Seguidamente vienen la localidad inicial del objeto (INITIALLYAT), las palabras, nombre y adjetivo, con las que lo identificamos en los comandos (WORDS), así como su peso (WEIGHT) y las propiedades especiales, si las tiene(PROPERTY). En nuestro caso, los guantes podemos ponérnoslos y quitárnoslos, así que debemos identificarlos como una prenda (PROPERTY CLOTHING)

Para poder interacturar con los guantes, necesitamos también que estén definidas las palabras de vocabulario con las que lo identificamos. En este caso GUANT (recuerda la limitación de cinco caracteres de PAW). Abrimos pues un pequeño bloque de vocabulario para añadir el nombre GUANT a la aventura.

VOCABULARY { Noun: "GUANT"; }

No es necesario asignar un número a las palabras del vocabulario, InPAWS irá asignando progresivamente a medida que las vayas definiendo. Sí puedes, en cambio, forzar a que una palabra tenga un número concreto. Esto es especialmente necesario en el caso de palabras "especiales" de PAW, como son los nombres de dirección, los convertibles, o los nombres propios. En ese caso, se lo indicaríamos de la siguiente manera.

VOCABULARY { Noun 14: "I", "INVEN"; }

Estamos definiendo el comando para hacer el inventario como una palabra convertible (es tanto nombre como verbo), así que forzamos a que InPAWS le asigne el código 14. De paso, también has visto cómo se definen sinónimos: una lista de palabras dentro de la misma definición, separadas por comas.

En la definición de los guantes vimos que su localidad inicial es MochilaLoc. Esta localidad aún no ha sido definida, y es la localidad donde vamos a almacenar los objetos que contiene nuestro siguiente utensilio de campaña: la mochila.

No hay aventurero que se precie sin una buena mochila a la espalda. Este versátil objeto, además de su indudable utilidad en la vida real, nos va a permitir ilustrar la forma de crear un objeto complejo en InPAWS: nos lo podemos poner, y además puede contener otros objetos. Como recordarás, para definir un objeto contenedor en PAW, además de marcarlo como tal en el editor, era necesario definir una localidad con su mismo código para los objetos que almacenara. Vamos a definir el objeto Mochila y su localidad hermana en nuestra aventura:

Object Mochila 1
{
    "Una mochila";
    WORDS MOCHI _;
    INITIALLYAT WORN;
    WEIGHT 2;
    PROPERTY CONTAINER, CLOTHING;
} VOCABULARY { Noun: "MOCHI"; }

Location MochilaLoc 1 { ""; }

Como probablemente hayas adivinado, podemos forzar la asignación de un código concreto a un objeto simplemente indicándolo tras el nombre en su definición (Object mochila 1). En el caso de los contenedores esto es necesario por lo que he comentado antes: el código del contenedor y el de la localidad almacén deben coincir.

Observamos también que podemos indicar ciertas localidades "especiales" como localidades de inicio de los objetos, sin necesidad de haberlas definido. Estas son CARRIED (llevamos el objeto), WORN(lo tenemos puesto) o NOTCREATED (el objeto no está en ninguna localidad). Esas tres palabras es posible utilizarlas al referirnos a una localidad en los condactos que admitan parámetros del tipo LOCNO+.

Finalmente, al ser el objeto tanto una prenda que nos podemos poner como un contenedor, hay que indicar ambas cualidades en la cláusula PROPERTY.

Las primeras respuestas

La mochila no daría mucho juego si no nos permitiera manipularla para meter y sacar objetos. Como estas dos acciones no vienen por defecto en el fichero esqueleto de aventura proporcionado por InPAWS, es necesario definirlas. Para ello ampliamos la tabla de respuestas, al igual que hicimos con el proceso 1. Vamos a definir dos acciones, meter y sacar, que actúen sobre los objetos que contiene la mochila. Además, vamos a permitir el uso de la palabra TODO para interaccionar con todo el contenido de la mochila mediante un sólo comando. Finalmente, vamos a proporcionar al jugador la posibilidad de ver el interior de la mochila tras la descripción que proporciona el comando EXAMINAR. El bloque quedaría así:

RESPONSE
{
    EX MOCHI: PRESENT Mochila MESSAGE "Una mochila de explorador
         la mar de útil. En la mochila hay: " LISTAT MochilaLoc DONE;
    SACA TODO: NOUN2 MOCHI PRESENT Mochila DOALL MochilaLoc;
    SACA _: NOUN2 MOCHI PRESENT Mochila AUTOT MochilaLoc DONE;
    METE TODO: NOUN2 MOCHI PRESENT Mochila DOALL CARRIED;
    METE _: NOUN2 MOCHI PRESENT Mochila AUTOP MochilaLoc DONE;
}

Como decía antes, hemos definido la parte del bloque de respuestas que afectan a la mochila junto a su definición, de forma que de un vistazo a la parte del código de la mochila podemos ver tanto la definición del objeto, su localidad asociada y los comandos para manipularla.

El primer puzzle

Ya tenemos todo lo necesario para meterle mano al primer puzzle de la aventura. Si el jugador intenta mover la palanca con las manos desnudas, recibirá un certero picotazo de vaya usted a saber qué inmunda criatura, y la aventura habrá terminado. Nuestro aventurero, que dicho sea de paso es un poco tonto, tardará un rato en descubrir que si se pone los guantes evitará el daño y podrá mover la palanca sin dificultad.

Manos a la obra pues, y en el lugar más adecuado, que para mí es tras la definición de la localidad de entrada al templo, ponemos el bloque de código que gestiona este puzzle.

Flag entradaAbierta;

PROCESS 1
{
    _ _ : AT Entrada ZERO entradaAbierta
     MESSAGE "Un enorme bloque de piedra bloquea la entrada.";

    _ _ : AT Entrada NOTZERO entradaAbierta
     MESSAGE "Un siniestro pasaje conduce al interior del templo.";
}

VOCABULARY {
    NOUN: "BOQUE", "PALAN";
    NOUN: "TEMPL";
    NOUN: "BLOQU", "PIEDR";
}

RESPONSE
{
  ABRE ENTRA|ABRE BLOQU: AT Entrada ZERO entradaAbierta
	MESSAGE "Ni la fuerza combinada de diez como tú podría mover
	ese mastodonte de piedra." DONE;

  ABRE ENTRA|ABRE BLOQU: AT Entrada
	MESSAGE "Ya no hay bloque que abrir." DONE;

  EX BOQUE: AT Entrada MESSAGE "Un oscuro boquete cuadrado,
	excavado por la mano del hombre, en cuyo interior ves
	una especie de palanca. También crees divisar ojos
	que te observan desde dentro." DONE;

  MUEVE PALAN|
  EMPUJ PALAN|
  TIRA PALAN: AT Entrada ZERO entradaAbierta
    NOTWORN Guantes MESSAGE "Al meter la mano en el boquete
	notas un pichazo agudo. Casi al instante tu vista se
	comienza a nublar y vas perdiendo contacto con la
	realidad.^^       *** ESTAS MUERTO ***" TURNS END;

  MUEVE PALAN|
  EMPUJ PALAN|
  TIRA PALAN: AT Entrada ZERO entradaAbierta
	SET entradaAbierta MESSAGE "Con no poco repelús metes la
	mano enguantada y mueves la palanca. Oyes un chasquido,
	y luego un ruido de correas deslizándose. Al cabo de un
	rato, el enorme bloque cede y se hunde en el suelo como
	tragado por el infierno. La entrada está libre." DONE;

  MUEVE PALAN|EMPUJ PALAN|TIRA PALAN: AT Entrada
   MESSAGE "No necesitas volver a meter la mano en \"eso\"." DONE;

  ENTRA _: AT Entrada NOTZERO EntradaAbierta SET 0 GOTO Interior DESC;
}

Aquí la cosa se complica, por que hemos metido varios elementos nuevos.

Lo primero que nos llama la atención es la definición de un Flag "entradaAbierta". Necesitamos almacenar el estado de la entrada al templo, que dicho sea de paso está bloqueada por un enorme bloque que desaparecerá al activar la palanca. Para definir un flag en InPAWS basta con indicarle un nombre, a partir de lo cual podremos referirnos a él por el nombre dado. InPAWS asigna a este flag un número de los disponibles para el usuario (no reservados). Es posible, al igual que ocurre con las localidades y los objetos, forzar a InPAWS a que asigne un número concreto. Por ejemplo, si nos quisiéramos referir a la localidad actual por locActual en vez de por el número de flag 38,podríamos hacerlo de la siguiente manera:

Flag locActual 38;

Como nuestro flag es nuevo, dejamos a InPAWS el engorro de buscar, asignar y utilizar un número y nos centramos en su nombre. Seguidamente ampliamos el PROCESS 1 con un mensaje extra que queremos que nos muestre la descripción de la localidad en función del estado del flag, o lo que es lo mismo, del bloque de piedra que bloquea la entrada.

En tercer lugar definimos el vocabulario relacionado con la resolución del puzzle:BOQUETE, TEMPLO, PALANCA, etc. No me paro mucho en estos temas de los que ya hemos hablado antes.

Y al fin llegamos al meollo del asunto, la resolución del puzzle. Abrimos un bloque RESPONSE para ampliar la tabla de respuestas y nos encontramos con un elemento nuevo, las entradas sinónimas o alternativas.

Desde la versión 1RC4 de InPAWS, es posible especificar dentro de los procesos entradas alternativas, cuyo cuerpo se repetirá para cada opción especificada. En el ejemplo estamos indicándole a InPAWS que tanto nos da que el jugador teclee MUEVE PALANCA, que EMPUJA PALANCA o TIRA DE LA PALANCA. La respuesta de la aventura en estos casos se traduce en el mismo bloque de código, que es el que va tras los dos puntos (:). InPAWS se encarga de traducir estas alternativas a tantas entradas de respuesta o procesos como sean necesarias al generar la aventura para PAW.

La cosa no queda ahí, y podríamos, si ese fuera el caso, utilizar alternativas dentro del cuerpo de la entrada de procesos, de forma que si, por ejemplo, necesitaramos poder manipular la palanca tanto fuera como dentro del templo podríamos indicarlo de la siguiente manera:

MUEVE PALAN|
EMPUJ PALAN|
TIRA PALAN: AT Entrada|AT Templo ....

Esta es una forma flexible y potente de definir entradas de procesos, pero también costosa por que se puede disparar el número de entradas. Por ejemplo la entrada anterior daría lugar a 6 entradas de respuesta en la aventura de PAW (3 opciones en verbo/nombre X 2 opciones en condactos).

Conclusión

El resto de la aventura, tras la entrada al templo y la consecución del diamante, no presenta muchas más novedades respecto a lo ya explicado. Puedes descargarte la aventura completa aquí.

Hasta otra