![]() | ![]() | ![]() | La ventana y los barrotes |
¡Vamos con los últimos puzzles del juego! Ahora que el jugador tiene la funda debe descubrir el barrote suelto que hay en la ventana, atar la funda a otro barrote de la misma y salir por la ventana para terminar el juego.
¿Qué objetos participan en todo esto? Evidentemente tenemos una
ventana
, un barrote_suelto
y un barrote_fijo
, más la funda
que
ya teníamos. Y hay una serie de acciones que debemos contemplar para
cada uno de esos objetos. De modo que vayamos por partes. Lo primero
será programar la ventana.
La ventana, de acuerdo con el modelo del mundo que tiene la librería Inform debería ser un conector que lleve de la mazmorra al exterior de la torre. Sin embargo, ya que en este juego el mero hecho de atravesar la ventana da por finalizado el juego, no necesitamos que sea realmente una conexión de esas.
De todas formas, por hacer más interesante este cursillo, crearemos una localidad nueva, el exterior de la torre, y haremos que la ventana sea un conducto que une esta localidad con la mazmorra.
Este tipo de conductos, en Inform se llaman doors (puertas)
, aunque como
vemos no siempre son una puerta real. Son simplemente un objeto que
comunica dos lugares. También podría ser un puente, una cabina de
teletransportación, ...
Las puertas tienen dos propiedades importantes:
door_to
door_dir
Además, debe tener el atributo door
, para indicarle a Inform que es un conector entre dos lugares, y que por tanto debe admitir por
defecto la orden ENTRAR EN o METERSE POR ese objeto.
Vamos a programar una versión inicial de la ventana, sin puzzle alguno, que deje salir al jugador de la mazmorra. En primer lugar hay que añadir a la mazmorra una nueva salida, pero en lugar de indicar a dónde lleva esa salida (llevará al exterior de la torre), ponemos qué "puerta" hay en esa salida, que en nuestro caso sería el ventanuco. La nueva mazmorra quedará así:
Object Mazmorra "Mazmorra" with description "Una silenciosa estancia débilmente alumbrada por los rayos de luna que se filtran a través de un pequeño ventanuco. El suelo está lleno de paja, colgando de unos grilletes en la pared observas un esqueleto humano.", e_to EscaleraCaracol2, out_to ventanuco, has light; |
La dirección es out_to (afuera)
, y por tanto se activará cuando el jugador
escriba "SALIR", o "AFUERA" (esta es una "dirección" adicional a
las clásicas NORTE, SUR, etc..)
Por su parte el ventanuco debe estar localizado en la Mazmorra
, y su
código sería el siguiente:
Object ventanuco "ventanuco" Mazmorra with name 'ventanuco' 'ventana' 'tragaluz', description "A través de los barrotes de este ventanuco puedes ver el exterior de la torre, iluminado por una increíble luna llena.", door_to ExteriorTorre, door_dir out_to, has door open scenery |
Fijate que la propiedad door_to
indica que esta ventana conduce a
la localidad ExteriorTorre
cuando se la atraviese. De modo que si el
jugador está en la Mazmorra y pone "SALIR", esto es lo que ocurrirá:
Go (Ir)
con noun=out_obj
(out_obj
es una forma que tiene Inform de representar la
"dirección exterior", igual que tiene n_obj
para representar la
"dirección norte", etc).
out_to
de la mazmorra, y encontrará que
conduce al ventanuco.
door
,
de donde deducirá que no se trata del destino del viaje, sino de un
mero tránsito. Ya que tiene el atributo open
, el jugador puede
pasar a través de ella.
door_to
del
ventanuco a dónde debe ir a parar. Encontrará allí ExteriorTorre
que ya es una localidad normal, de modo que moverá al jugador allí.
Si queremos impedir que el jugador salga antes de haber reunido
ciertas condiciones, podremos escribir una rutina en la salida out_to
de la localidad. Esta rutina puede imprimir un mensaje y
retornar true para impedir al jugador que salga, o bien retornar
ventanuco
para que todo prosiga normalmente. Por ejemplo, el código
siguiente no dejará salir al jugador mientras no lleve consigo el
carbón (es un ejemplo tonto, un ejemplo más realista lo programaremos
más adelante, donde comprobaremos si el jugador ha aflojado el barrote
y ha atado la funda antes de dejarle salir).
out_to [; if (carbon in jugador) return ventanuco; else "Tienes la sensación de que olvidas algo en esta torre. Decides no irte todavía."; ], |
Pero observa de nuevo el código del ventanuco. Además, de indicar a
qué localidad lleva, es necesario poner en el ventanuco la propiedad
door_dir
, con el valor out_to
. El por qué es necesaria esta
propiedad es un poco rebuscado, y en mi opinión es un error de diseño
de Inform, pero ya que las cosas están así, mejor que estés al
tanto de esto. La razón es que el jugador puede, en lugar de poner
SALIR, poner algo como METERSE POR LA VENTANA. Esto genera una acción Go
, con
noun=ventanuco
, en lugar de generar Go
con noun=out_obj
. Si
Inform se limitara a mirar la dirección door_to
, y llevar al jugador al ExteriorTorre
, entonces la rutina
que hemos programado para impedir que el jugador pueda salir, no sería
ejecutada. Dicho de otro modo, sería diferente lo que ocurre cuando el
jugador pone SALIR que cuando pone METERSE POR EL VENTANUCO. Esto no
estaría bien.
Por mantener una cierta coherencia, Inform quiere asegurar que
siempre que el jugador se mueva de un lugar a otro, se generará una
acción Go
, tanto si pone SALIR, como si pone METERSE POR EL
VENTANUCO. Para ello, lo que hace Inform cuando el jugador intenta
meterse por una puerta, es consultar la propiedad door_dir
de
dicha puerta, y generar una acción Go
que lleve a esa dirección. Así
que en el caso de nuestro ventanuco, si el astuto jugador pone METERSE
POR VENTANUCO, Inform cambiará esa acción en IR AFUERA, por lo que
la rutina out_to
que hemos visto antes se ejecturará y podremos
impedir al jugador que salga si no cumple las condiciones que le hemos
impuesto.
![]() |
Resumen para programar una conexión:
|
![]() | Las conexiones (o puertas) son ciertamente un objeto complicado en Inform. Ten en cuenta que todo lo anterior es necesario para hacer una puerta que lleve de A a B, pero ¡no al revés! Si quieres volver de B a A, ¡necesitas programar otra puerta en sentido contrario! Puede hacerse un solo objeto que lleve en ambas direcciones a la vez, pero esto exige una programación aún más retorcida. Por todo esto se ha desarrollado un módulo de ampliación, llamado "Puertas", que intenta simplificar al máximo la programación de puertas con dos lados. Si estás interesado, puedes descargar este módulo de la zona de modulos de INFSP |
Inicialmente, sólo estará presente el objeto "barrotes". Cuando el jugador lo examine, haremos aparecer el objeto "barrote flojo", para que el jugador pueda retirarlo. Esto planteará un problema de ambigüedad si el jugador intenta despues ROMPER BARROTE o ATAR FUNDA A BARROTE. ¿A cuál se refiere? ¿Al flojo que tiene en la mano, o a uno de los barrotes que han quedado en la ventana?
Por suerte Inform maneja las ambigüedades de forma automática. Sólo tenemos que tener la precaución de dar un nombre corto diferente a cada uno de los objetos que podrían dar lugar a confusión, y que su lista de sinónimos no sea idéntica. Así, por ejemplo, el barrote flojo puede tener como nombre "barra", y en su lista de sinónimos pondremos la palabra 'flojo' y 'floja', mientras que los restantes barrotes los llamaremos "barrotes sólidos" y pondremos las palabras 'solido' y 'fijo' en su lista de sinónimos.
Vamos a programar los barrotes sólidos, para que al ser examinados
hagan aparecer el barrote flojo. Se trata del mismo truco que ya
usamos para hacer aparecer el cuchillo al examinar el esqueleto, es
decir, hacer uso del atributo general
. Además, usamos el atributo
moved
del barrote flojo, para saber si el jugador lo ha retirado ya
o no, y así cambiar la descripción del ventanuco.
Object barrotes "barrotes sólidos" Mazmorra with name 'barrotes' 'barrote' 'solido' 'barra' 'barras' 'solidos' 'fijos' 'fijo', description [; if (barrotes hasnt general) { move barrote_flojo to Mazmorra; give barrotes general; "Al examinar de cerca los barrotes de la ventana, descubres uno que parece estar más flojo."; } if (barrote_flojo has moved) "En la ventana falta un barrote. Parece que podrías pasar por el hueco."; "Entre los barrotes hay uno que parece más flojo."; ], has pluralname scenery |
Fijate que le hemos puesto el atributo scenery
, para impedir que
el jugador pueda coger estos barrotes. En cuanto al barrote_flojo
,
inicalmente estará en el limbo. Usaremos de nuevo su atributo moved
para saber si el jugador lo ha retirado ya de la ventana o no, y así
cambiar su descripción. En este caso no le damos el atributo scenery
, para que el jugador pueda cogerlo. Pero le damos el
atributo concealed
, para que al MIRAR, la descripción de la localidad
no diga "Puedes ver un barrote flojo". Fijate que hemos capturado
algunas acciones obvias que el jugador intentará con el barrote, como
moverlo, empujarlo... Y hemos cambiado tambien el mensaje por defecto
para cuando el jugador lo coja.
Object barrote_flojo "barra" Limbo with name 'barrote' 'flojo' 'barra' 'floja', description [; if (barrote_flojo has moved) "Es el barrote que quitaste del ventanuco de la mazmorra."; "Parece que este barrote podría quitarse con un poco de esfuerzo."; ], before [; Push, Pull, Mover: "Aflojas el barrote."; ], after [; Take: "Con esfuerzo, consigues arrancar el barrote de su sitio."; ], has female concealed; |
Fíjate que le hemos puesto como nombre corto "barra", y eso nos
obliga a ponerle el atributo female
. De ese modo, cuando el
jugador lo coja y mire su inventario, Inform le dirá que lleva
"una barra", y no "un barra".
Sólo queda por resolver la acción de ATAR FUNDA A BARROTE. Inform tiene ya programado el verbo ATA, y genera la acción
Tie (Atar)
. Al igual
que ocurre con Cut
, el jugador puede poner simplemente ATA FUNDA,
o bien ATA FUNDA A BARROTE. En el primer caso la variable second
tomará el valor cero, y en el segundo tomará el valor barrote_flojo
.
Si pone ATA FUNDA A BARROTES, second
tomará el valor barrotes
.
En todos los casos, el objeto
noun
es la funda
, y es quien recibirá
la acción. Por tanto la respuesta a Tie
debemos programarla en la
funda, y no en los barrotes. Por tanto debemos modificar la rutina before
de la funda, para tratar en ella las diferentes ataduras que
se le pueden ocurrir al jugador, y dar un mensaje adecuado en cada
caso. Cuando el second
sean los barrotes, marcaremos el puzzle de la
funda como resuelta, activando la propiedad general
de la funda
.
Observa que no podemos usar la propiedad general
de los barrotes
porque esa ya la hemos usado para marcar si han sido examinados o no.
La nueva rutina
before
de la funda debería cambiar también la
respuesta ante Take
, comprobando si la funda está atada a los
barrotes, ya que en ese caso el jugador no podrá cogerla. También tendriamos que manejar correctamente la acción
Untie (Desatar)
que no se provee en la libreria Inform (más
adelante veremos cómo agregar acciones nuevas a tu juego).
Entonces la rutina
before
que se ocupa de todo esto podría ser la siguiente:
before [; Take: if (correas hasnt general) "La funda está sujeta a la cama por unas correas."; if (funda has general) "La funda está atada a los barrotes."; Tie: if (second==0) "No tiene sentido hacer un nudo en la funda."; if (second==correas or catre or esqueleto or cuchillo) "No tiene sentido atar la funda ahí."; if (second==carbon or antorcha) "¿Estás loco?"; if (second==barrote_flojo) "Mejor atarla a un barrote sólido."; if (second==barrotes or ventanuco) { give funda general; move funda to location; "Atas la funda a uno de los barrotes más sólidos y la dejas colgando por la ventana."; } ], |
Fijate en un detalle. Cuando el jugador ATA con exito la funda a los
barrotes, no sólo le damos el atributo general
para marcar este
hecho. Además, movemos la funda a la localización actual (que será la
mazmorra, ya que de lo contrario los barrotes no estarían presentes y
la acción no se habría generado). Esto lo hacemos para evitar que la
funda siga en poder del jugador despues de haberla atado. Si no lo
hicieramos, el jugador podría salir de la mazmorra y llevarse la funda
consigo ¡mientras aún está atada a los barrotes!
Ya solo queda modificar la salida out_to
de la mazmorra para que
sólo deje salir al jugador cuando este haya resuelto el puzzle de los
barrotes. Vamos allá:
out_to [; if (barrote_flojo hasnt moved) "No puedes salir por el ventanuco, los barrotes no dejan suficiente hueco."; if (funda hasnt general) "No te atreves a saltar desde esta altura. Necesitas algún tipo de cuerda para descolgarte."; print "Contorsionándote, logras hacer pasar tu cuerpo por la estrecha abertura que dejó el barrote, y te descuelgas con cuidado usando la funda a modo de cuerda.^^"; return ventanuco; |
Bueno, si el jugador hace todo bien, conseguirá llegar a la localidad "Exterior de la torre", y se supone que ahí termina el juego. Pero si juegas lo anterior verás que el juego sigue esperando nuevos comandos del jugador, aunque realmente ya nada puede hacerse en esa localidad sin salidas.
La forma de dar por terminado el juego es hacer la asignación siguiente:
deadflag=2; |
Si al final del turno, Inform encuentra que deadflag
vale 2,
entiende que el juego ha terminado con éxito. Si vale 1, entiende que
ha terminado con la muerte del aventurero. En ambos casos ya no le
pide más órdenes, sino que le invita a rejugar la aventura o finalizar
el programa, con un mensaje apropiado a cada caso.
El lugar obvio para hacer esa asignación es el momento en que el
jugador sale por la ventana, esto es, en la rutina afuera
de la
mazmorra, cuando ha impreso el mensaje que explica cómo sale el
jugador por la ventana, y va a retornar el objeto ventanuco
.
La nueva rutina queda entonces así:
out_to [; if (barrote_flojo hasnt moved) "No puedes salir por el ventanuco, los barrotes no dejan suficiente hueco."; if (funda hasnt general) "No te atreves a saltar desde esta altura. Necesitas algún tipo de cuerda para descolgarte."; print "Contorsionándote, logras hacer pasar tu cuerpo por la estrecha abertura que dejó el barrote, y te descuelgas con cuidado usando la funda a modo de cuerda.^^"; deadflag=2; return ventanuco; |
Como de costumbre, aquí tienes la versión completa del juego para que lo estudies, lo modifiques a tu antojo y lo pruebes.
![]() | ![]() | ![]() | La ventana y los barrotes |