Listado automático de salidasEl modelo del mundoRecipientes, superficies y sub-objetosPuertas

Puertas

Una puerta es un tipo de objeto muy interesante y útil. No necesita ser literalmente una puerta, sino un objeto que sirva al jugador para acceder a otro lugar. Por ejemplo, una cuerda o una escalera. Para programar una puerta debes seguir los siguientes pasos:

  1. Dale al objeto el atributo puerta
  2. Dale al objeto la propiedad puerta_a y asignale la habitación a la que lleva.
  3. Dale al objeto la propiedad direcc_puerta y asígnale la dirección en la que caminaría el jugador si atravesara la puerta (por ejemplo, si yendo hacia el norte el jugador pasaría por la puerta, entonces debes poner aquí al_n).
  4. Pon en la habitación en la cual está la puerta una salida en la dirección adecuada (en el ejemplo anterior, sería al_n) de modo que esa salida lleve al objeto puerta.

Por ejemplo, continuando con "Ruinas", habíamos visto que la cámara lleva hacia el sur a un corredor. Programemos ese corredor de modo que en su lado sur tenga una puerta cerrada y bloqueada con llave que impide el paso al sepulcro (recuerda el mapa del juego). Deberás modificar el objeto Corredor que habíamos programado "en blanco" para que sea como sigue:

Object  Corredor "Corredor de Techo Bajo"
with descripcion "Un corredor de sección cuadrada y techo muy bajo se
            extiende en dirección norte-sur, obligándote a caminar
            encorvado.",
        al_n Camara,
        al_s PuertaPiedra,
has luz

Le hemos puesto luz a esta habitación porque el juego todavía no está terminado, y no hemos programado aún ninguna antorcha o algo similar, y si no le hubiéramos dado el atributo luz no podríamos probar lo que llevamos programado, pues al entrar en esta habitación la librería simplemente diría "Está muy oscuro y no puedes ver nada". Por otro lado, como vemos, hacia el sur lleva al objeto llamado PuertaPiedra. La diferencia con otras habitaciones que habíamos programado antes es que PuertaPiedra no es otra habitación, sino una puerta que se programaría así:

Object PuertaPiedra "puerta de piedra" Corredor
 with   nombre 'puerta' 'gran' 'pesada' 'piedra' 'amarilla',
        descripcion "Simplemente es una gran puerta de piedra",
        si_cerrada "El paso hacia el sur está bloqueado por una gran
            puerta de piedra amarilla.",
        si_abierta "La gran puerta de piedra amarilla que se halla al
            sur, está abierta.",
        puerta_a Sepulcro,
        direcc_puerta al_s,
        con_llave LlavePiedra,
 has    femenino estatico puerta abrible cerrojo cerrojoechado;

Para que puedas compilar el programa, necesitas definir todos los objetos que se mencionan. En particular Inform se quejaría de que no has definido el objeto Sepulcro ni LlavePiedra. Vamos a darle una definición mínima simplemente para que pueda compilarlo y así poder probar lo que va de juego:

Object Sepulcro;
Object LlavePiedra;

Observar que es recomendable darle a las puertas el atributo estatico para evitar que el jugador pueda cogerla y llevársela por ahí. Las propiedades si_abierta y si_cerrada contienen texto que la librería mostrará cuando el jugador entre en la habitación que contiene la puerta. Sólo se mostrará una de las cadenas, según la puerta esté abierta o cerrada. Ya que inicialmente no le hemos dado el atributo abierta, esto significa que está cerrada. Si el jugador intenta abrirla mediante "ABRE PUERTA", recibirá el mensaje "Está cerrada con llave" (debido a que tiene el atributo cerrojoechado). Si el jugador intenta "QUITA EL CERROJO A LA PUERTA", la librería admitirá esa orden (porque la puerta tiene el atributo cerrojo), pero no podrá cumplirla porque esta puerta particular necesita una llave concreta para ser abierta. La llave necesaria es el objeto llamado LlavePiedra, tal como se indica en la propiedad con_llave. Así pues, tal como está, la puerta impide el paso al jugador (por otra parte, el objeto LlavePiedra, tal como lo hemos definido no aparece en el juego, ya que no le hemos puesto localización inicial, de modo que el jugador nunca podrá encontrarlo. Y aún si pudiera, no podría cogerlo pues no puede nombrarlo porque no le hemos dado nombres. La puerta nunca podrá ser abierta). Si estuviera abierta, al ser atravesada conduciría al lugar llamado Sepulcro, tal como se indica en la propiedad puerta_a. Por otro lado, la propiedad direcc_puerta vale al_s, lo que significa que la puerta se halla en el lado sur de la habitación.

Habrás observado que la puerta es de una sola dirección. Una vez que el jugador va en dirección sur y llega al Sepulcro, la librería no garantiza que encontrará allí la puerta (de hecho la puerta sólo está en el lugar llamado Corredor). Sólo hemos programado un lado de la puerta. Si crees que queda mejor que la puerta tenga dos lados, la cosa se complica un poco, ya que entonces este objeto debería aparecer en dos habitaciones a la vez. Esto no es difícil, para eso ya conocemos la propiedad esta_en, la parte complicada es que la propiedad puerta_a y puerta_hacia es diferente según desde qué lado se mire la puerta. La forma de lograr esto es hacer que estas propiedades sean en realidad rutinas, que consulten la variable localizacion para saber dónde está el jugador, y retornen el valor adecuado para una puerta vista desde esa localización. Es decir:

Object PuertaPiedra "puerta de piedra" Corredor
 with   nombre 'puerta' 'gran' 'pesada' 'piedra' 'amarilla',
        descripcion "Simplemente es una gran puerta de piedra",
        si_cerrada "El paso está bloqueado por una gran puerta de 
            piedra amarilla.",
        si_abierta "La gran puerta de piedra amarilla está abierta.",
        puerta_a [;
            if (localizacion==Corredor) return Sepulcro;
            else return Corredor;
        ],
        direcc_puerta[;
            if (localizacion==Corredor) return al_s;
            else return al_n;
        ],      
        con_llave LlavePiedra,
        esta_en Corredor Sepulcro,
 has    femenino estatico puerta abrible cerrojo cerrojoechado abierta;

Observa qué ha pasado con las propiedades puerta_a y direcc_puerta. Ahora son rutinas. La librería llamará a estas rutinas cuando sea necesario y éstas deben responder a dónde lleva la puerta (puerta_a o en hacia qué punto cardinal están orientadas (direcc_puerta). Las rutinas pueden hacer internamente las operaciones que deseen antes de responder, pero no deben imprimir nada en pantalla (prohibido usar print o variantes dentro de ellas). Como vemos en el ejemplo anterior, consultan la variable localizacion, que indica dónde está el jugador, para saber qué responder. Observar también cómo hemos modificado el texto de si_abierta y si_cerrada para eliminar las referencias de dirección de modo que la frase sea válida independientemente del lado desde el que se mire la puerta. Podríamos también haber hecho que si_abierta y si_cerrada fueran rutinas que consultaran la localizacion para generar un texto diferente según el caso.

A primera vista no está claro por qué las puertas han detener la propiedad direcc_puerta. ¿Para qué necesita una puerta saber en qué lado de la habitación está? La razón es que existen dos acciones diferentes para atravesar la puerta. Supongamos que la puerta está en el lado sur. El jugador puede escribir "VE HACIA EL SUR" (o simplemente "Sur"), lo que causará la acción Ir obj_s. Pero el jugador también puede poner "ENTRA POR LA PUERTA", o "PASA POR LA PUERTA", lo que causaría la acción Meterse puerta (la acción Meterse se genera cada vez que el jugador intenta entrar en cualquier objeto del juego. No confundir con la acción Entrar, que sólo ocurre cuando el jugador escribe "Entra", a secas, sin especificar objeto). Si la acción a ejecutar es Meterse puerta, lo que hará la librería será averiguar, a través de la propiedad direcc_puerta, que la puerta está en el sur, por lo que generará la acción Ir obj_s. Así que, aunque el jugador intente meterse en la puerta, la acción que finalmente se genera es Ir de todas formas. Esto facilita el trabajo al programador si quiere capturar la acción de ir hacia el sur.

(Esp) A pesar de que el párrafo anterior procede del manual original de Inform, lo cierto es que la librería de Inform no se comportaba de este modo, sino que ante la acción Meterse puerta generaba finalmente la acción Ir puerta en lugar de Ir s_obj. Este bug está corregido en la librería InformATE.

Así que por cualquiera de los caminos nos encontramos finalmente con la acción Ir s_obj ¿Qué hace la librería ahora? Mirará en la habitación la propiedad al_s, para ver a dónde lleva, y encontrará allí el objeto PuertaPiedra. Comprobará que esta puerta está abierta (si no, mostrará un mensaje diciendo que no puedes pasar) y si lo está consultará la propiedad puerta_a de PuertaPiedra para averiguar a qué habitación conduce la puerta, trasladando finalmente al jugador a ese lugar.

Esto tiene una consecuencia importante: Si quieres, por ejemplo, impedir que el jugador cruce la puerta bajo ciertas condiciones (por ejemplo, si lleva cierto objeto) aparentemente deberías escribir una rutina antes en la PuertaPiedra y capturar en ella la acción Meterse ¿no? La verdad es que ese enfoque sólo te funcionará si el jugador escribe "ENTRA POR LA PUERTA" o "VE POR LA PUERTA" o similar, pero no si pone simplemente "SUR" (en este caso la propiedad antes de la puerta no será llamada, ya que la acción generada es Ir s_obj, y la puerta no aparece como objeto directo).

Para casos como este tienes dos opciones:

  1. Capturar la acción Ir en la rutina antes de la habitación (no la de la puerta). En esta rutina podrías comprobar si uno es igual a s_obj, lo cual significaría que el jugador está intentando ir hacia el sur, y actuarías en la forma conveniente. Fíjate que esto funciona también si el jugador escribiera "ENTRA POR LA PUERTA", ya que como hemos dicho esto llevará finalmente a la acción Ir s_obj.
  2. Poner una rutina en la propiedad puerta_a de la puerta. Efectivamente, esta propiedad puede contener simplemente el nombre de otra habitación (como era el ejemplo de PuertaPiedra o una rutina completa, que haga sus cálculos, imprima un mensaje si lo considera necesario y retorne finalmente un valor. El valor retornado puede ser:
    Una habitación
    En cuyo caso el jugador será movido a esa habitación.
    El valor cero
    En cuyo caso se dirá al jugador "Esa puerta no lleva a ningún sitio".
    El valor true
    En cuyo caso la librería no hace nada (no traslada al jugador), asumiendo que ya lo ha hecho esta rutina. Esta última opción es la típica cuando se quiere mostrar un mensaje impidiendo al jugador atravesar la puerta.

(?) EJERCICIO 13  Programa un puente que lleva al otro lado de un abismo, pero que se viene abajo si el jugador lleva cualquier cosa en su inventario. Pistas: el puente lo programarás como una puerta, en la propiedad puerta_a comprobarás si el jugador lleva algo (puedes usar la función children(jugador) que te devuelve cuántos objetos lleva).
(Solución)


Zak McKraken - spinf@geocities.com

Listado automático de salidasEl modelo del mundoRecipientes, superficies y sub-objetosPuertas