![]() | ![]() | ![]() | Programando la antorcha (¡por fin!) |
Object antorcha "antorcha" EscaleraCaracol2 with name 'antorcha', before [; Take: print "La antorcha está incrustada en la pared.^"; rtrue; ], has female; |
Ahora, el print
y el rtrue
sólo se ejecutarán si la acción era
Take
(¡cuidado! Hablamos de acciones, no de verbos, recuerda).
Cualquier otra acción es ignorada por la antorcha, y por tanto causará
la acción por defecto.
Si queremos que la antorcha reaccione de la misma forma ante dos o más acciones diferentes, basta poner éstas separadas por comas, por ejemplo:
Object antorcha "antorcha" EscaleraCaracol2 with name 'antorcha', before [; Take, Turn: print "La antorcha está incrustada en la pared.^"; rtrue; ], has female; |
Ahora el print
y el rtrue
se ejecutarán para las acciones
Take
y Turn
, las restantes acciones seguirán siendo tratadas por la
librería.
Si queremos diferentes mensajes de respuesta ante diferentes acciones, basta ir repitiendo una estructura similar a la anterior, por ejemplo ¿qué pasa si el jugador pone SOPLA LA ANTORCHA? Intentémoslo (con el listado de acciones activado para ver qué acción se genera):
>sopla antorcha [ Action Blow with noun 31 (antorcha) ] Tu soplido no produce ningún efecto. |
¡Vaya! Inform tenía prevista una acción Blow (Soplar)
, y la respuesta
por defecto no parece del todo mala, pero cambiémosla por otra más
apropiada:
Object antorcha "antorcha" EscaleraCaracol2 with name 'antorcha', before [; Take, Turn: print "La antorcha está incrustada en la pared.^"; rtrue; Blow: print "Iluso, el fuego que arde en esta antorcha no es de este mundo.^"; rtrue; ], has female; |
¡Acuerdate de poner el rtrue
! (¿Qué pasaría si no lo pones?) La
verdad es que repetir rtrue
después de cada print
es un poco
pesado. Por eso Inform nos proporciona una abreviatura: el comando
print_ret
imprime una cadena e inmediatamente retorna con rtrue
.
Además, imprime una "linea nueva" al final del texto, por lo que nos
evita tener que poner el ^
en cada mensaje. Usando esta abreviatura,
la cosa quedaría así:
Object antorcha "antorcha" EscaleraCaracol2 with name 'antorcha', before [; Take, Turn: print_ret "La antorcha está incrustada en la pared."; Blow: print_ret "Iluso, el fuego que arde en esta antorcha no es de este mundo."; ], has female; |
Aún es posible abreviar más. ¿No te suena esto de "imprimir, añadir salto de linea y retornar inmediatamente"? Todo ello podía abreviarse sin más que poner el mensaje entre comillas. Así:
Object antorcha "antorcha" EscaleraCaracol2 with name 'antorcha', before [; Take, Turn: print_ret "La antorcha está incrustada en la pared."; Blow: "Iluso, el fuego que arde en esta antorcha no es de este mundo."; ], has female; |
Esta forma es muy habitual, porque resulta muy cómoda. Sin embargo es
un poco "rara" para el principiante, ya que en realidad se trata de
una orden print
, pero el print
no se escribe. Además retorna
inmediatamente (con rtrue
), y eso tampoco se ve claramente en el
código. Con todo, si sabes esto, no deberías tener problemas con su
uso.
Como ves, añadir mensajes específicos para la antorcha resulta muy sencillo. ¡Añade tú mismo alguno! Por ejemplo, ¿tendrá Inform previsto HUELE ANTORCHA? ¿COME ANTORCHA? ¿QUEMA ANTORCHA? ¿TOCA ANTORCHA? Pruebalo, verás que todos ellos están previstos, pero el mensaje de respuesta estándar puede no encajar muy bien. Averigua qué acciones genera cada una de las frases anteriores y modifica la antorcha para que imprima mensajes más apropiados.
EscaleraCaracol2
. Recuerda que las
salidas de una localidad son propiedades de esa
localidad. Ahora tenemos un pequeño problema:
![]() | Una vez que el juego ha comenzado, no se pueden añadir o quitar propiedades a los objetos, pero sí que es posible cambiar el valor de cualquier propiedad de cualquier objeto. |
Por tanto no podemos hacer que EscaleraCaracol2
empieze sin su
propiedad w_to
, y más adelante en el juego de pronto adquiera esta
propiedad. Sin embargo, lo que si podemos hacer es que
EscaleraCaracol2
, inicialmente tenga la propiedad w_to
, pero esta
propiedad tome el valor cero (que es lo mismo que decir que esa salida
no lleva a ningún lugar). Más adelante, cuando se empuje la antorcha,
cambiamos el valor de esta propiedad para que sea igual a Mazmorra
.
Es decir, edita el juego y añade de nuevo la salida w_to
en la
escalera, pero en lugar de hacer que lleve a Mazmorra
, haz que
"lleve a 0", así:
Object EscaleraCaracol2 "Escalera de caracol" with description "Los desgastados peldaños de piedra resbalan en ocasiones. A mitad de la escalera una antorcha en la pared impide que la oscuridad sea completa.", d_to EscaleraCaracol1, w_to 0, u_to AltoTorre, has light; |
Cuando una salida "lleva a 0 (cero)", el jugador no podrá pasar por ella. Es como si no existiera. Pero el declararla de este modo nos permitirá cambiar su valor más adelante en el juego, mediante una instrucción como esta:
EscaleraCaracol2.w_to = Mazmorra; |
Que puedes leer así: "Cambia la propiedad w_to
del objeto
EscaleraCaracol2
, y haz que sea igual a Mazmorra
". Si quisieramos
eliminar esa salida, basta hacerla igual a cero de nuevo:
EscaleraCaracol2.w_to = 0; |
¿Cuándo debe ejecutarse este código? Evidentemente cuando el jugador empuje o tire de la antorcha. Cuando empuja la conexión se crea, cuando tira, la conexión desaparece. Es decir:
Object antorcha "antorcha" EscaleraCaracol2 with name 'antorcha', before [; Take, Turn: "La antorcha está incrustada en la pared."; Blow: "Iluso, el fuego que arde en esta antorcha no es de este mundo."; Push: EscaleraCaracol2.w_to = Mazmorra; "Al empujar la antorcha una porción de pared se abre al oeste dando acceso a una estancia."; Pull: EscaleraCaracol2.w_to = 0; "Al tirar la antorcha, la puerta secreta se cierra de nuevo."; ], has female; |
¿Por qué he puesto la asignación antes del mensaje? ¿Daría igual hacerlo al revés?
Intenta probar si la cosa funciona. Empuja la antorcha, se abre la conexión, tira de ella, se cierra. ¡Bien! Empuja de nuevo, se abre otra vez. Y ahora que está abierta ¡empuja otra vez! ¿qué ocurre? Hum, esto no queda muy bien, el mensaje diciendo que la pared se mueve aparece de nuevo.
Deberíamos comprobar si la conexión existe antes de mostrar ese mensaje. Un poco más de programación:
Object antorcha "antorcha" EscaleraCaracol2 with name 'antorcha', before [; Take, Turn: "La antorcha está incrustada en la pared."; Blow: "Iluso, el fuego que arde en esta antorcha no es de este mundo."; Push: if (EscaleraCaracol2.w_to==0) { EscaleraCaracol2.w_to = Mazmorra; "Al empujar la antorcha una porción de pared se abre al oeste dando acceso a una estancia."; } else "La antorcha no cede más."; Pull: if (EscaleraCaracol2.w_to == Mazmorra) { EscaleraCaracol2.w_to = 0; "Al tirar la antorcha, la puerta secreta se cierra de nuevo."; } else "La antorcha no cede más."; ], has female; |
Hemos usado aqui una estructura condicional, es decir, una
forma de decirle a Inform que cierto código sólo debe ejecutarse si se
cumple cierta condición. La estructura if...else
tiene la siguiente
sintaxis:
if (condicion) { ! Secuencia de instrucciones que deben ejecutarse ! si la condición se cumple } else { ! Secuencia de instrucciones que deben ejecutarse ! si la condición no se cumple } |
Observaciones:
;
) como delimitador de
instrucciones.
{
, }
a su alrededor. Sin
embargo, si tiene más de una instrucción es obligatorio poner esas
llaves.
else
es opcional. Si no la ponemos, entonces no se
ejecutará nada en caso de que la condición no se cumpla.
![]() |
¡Cuidado! Una pifia típica es olvidar las llaves cuando hay más de una
instrucción. Considera el ejemplo siguiente:
Parece que el programador pretendía aquí que la fuerza del jugador
aumente si lleva un talismán consigo (la condición La respuesta es que no habrá mensaje de error, pero en cambio el juego
no funcionará de la forma prevista. Seguramente lo verás más claro si
elimino un par de espacios delante de
¿Vés ahora mejor lo que ocurre? Al no poner llaves, Inform entiende
que la "secuencia de instrucciones a ejecutar en caso de que la
condición sea cierta", se compone de una sola instrucción: la llamada
a la rutina |
Una vez explicado if
, podemos ver con mayor claridad qué ocurre
cuando el jugador empuja la antorcha. El código que se ejecutará
entonces será el siguiente (un extracto de la rutina before
de la
antorcha):
Push: if (EscaleraCaracol2.w_to==0) { EscaleraCaracol2.w_to = Mazmorra; "Al empujar la antorcha una porción de pared se abre al oeste dando acceso a una estancia."; } else "La antorcha no cede más." |
La condición que comprobamos es EscaleraCaracol2.w_to==0
. El doble
signo ==
significa que se intenta comprobar la igualdad, y no debe
ser confundido con un solo =
que sería una asignación como ya hemos
visto. Por tanto la condición evaluada es "¿el valor de la propiedad w_to
del objeto EscaleraCaracol2
es igual a cero?" Si esta
condición es cierta, se ejecutará lo que viene entre llaves a
continuación. Si es falsa se ejecutará lo que va tras el else
. Date
cuenta de que si es cierta, esto implica que hacia el oeste la salida
aún no existe, y por tanto lo que hacemos es crearla y emitir el
mensaje. Y si es falsa, es que la salida hacia el oeste ya había sido
creada, y por tanto emitimos un mensaje indicando que no ocurre nada
más.
El código para el caso de la acción Pull (Tirar)
es totalmente análogo.
Inform puede comprobar muchos tipos de condiciones diferentes. Ya
hemos visto uno de ellos: la igualdad. Las comparaciones numéricas
tienen una sintaxis bastante lógica: >
significa "mayor que", <
es "menor que", >=
significa "mayor o igual" y <=
sería
"menor o igual".
Además de estos casos sencillos, hay otras comprobaciones interesantes que necesitarás usar para programar juegos:
~=
~
que aparece delante del igual se
obtiene en la mayoría de los ordenadores pulsando AltGr y el 4. Si
estás acostumbrado a programar en C, ten cuidado de no confundirte y
usar !=
ya que en Inform el carácter !
es el comentario como ya
hemos dicho.
in
true
(verdad) si el objeto que nombras a la izquierda del in
está dentro
del que nombras a su derecha. Por ejemplo antorcha in
EscaleraCaracol2
es cierto, y sin embargo antorcha in player
es
falso (¡a menos que el jugador haya cogido la antorcha de alguna
forma!)
Ten en cuenta que en Inform los objetos pueden estar dentro de otros y
estos a su vez dentro de otros. Si el jugador llevara consigo una caja
dentro de la cual hay una moneda, sería cierto caja in player
y
moneda in caja
, pero no sería cierto moneda in player
(la
condición in
se limita a comprobar la inclusión en un solo nivel).
has
cierto
si el objeto que nombras a la izquierda de has
tiene
activado el atributo que nombras a su derecha. Por ejemplo
antorcha has female
sería cierto (puesto que en la declaración del
objeto antorcha
le hemos puesto el atributo female
), o
EscaleraCaracol2 has light
también sería cierto (pues esta localidad
tiene el atributo light
). En cambio, antorcha has luz
es falso pues
no le hemos dado este atributo a la antorcha (pensandolo bien, parece
que deberíamos haberselo dado, ¿no? De todas formas en este juego es
intrascendente porque la antorcha nunca se mueve de su localidad)Observa que has
se limita a evaluar si el objeto dado tiene ese
atributo, pero no tiene inteligencia alguna para hacer
deducciones. Por ejemplo, si llevas una linterna que tiene el atributo light
y con ella entras en una cueva que no tiene el atributo
light
,
será cierto linterna has light
pero falso que cueva has light
. Es
decir, has
no es capaz de deducir que hay luz en la cueva
(suministrada por la linterna). Para comprobar si hay luz en una
localidad deberías comprobar si la localidad "has light
" o si alguno
de los objetos que tiene dentro "has light
". Por suerte no tienes
que molestarte en comprobar esto. La librería lo hace automáticamente en cada turno (de hecho hace algo mucho más complejo, pues tiene en
cuenta si los objetos están dentro de otros. Así, si llevas la
linterna dentro de una caja opaca, la librería deduciría que no hay
luz visible, pero si la llevas dentro de una caja transparente sí la
habría).
hasnt
has
. La condición
objeto hasnt atributo
es cierta si el objeto tiene ese atributo
desactivado. Por tanto, Cueva hasnt light
será cierto si la cueva
no tiene luz.
Hay más condiciones, pero estas son las más importantes y las más
usadas. Puedes combinar varias condiciones en una sola. Por ejemplo,
si quieres que algo se ejecute sólo si el jugador lleva un talismán, y
además el talismán tiene light
, puedes combinar ambas
condiciones usando el operador &&
, en la forma siguiente:
if ((talisman in player) && (talisman has light)) ... |
Observa cómo hay que encerrar cada condición entre paréntesis, y
colocar el operador &&
entre ambas.
Si lo que quieres es ejecutar algo cuando es cierta una condición
cualquiera entre varias, por ejemplo, si el jugador lleva el talismán
o si lleva el anillo, entonces el operador es ||
(con algunos
teclados el símbolo |
se
obtiene pulsando AltGr y 1):
if ((talisman in player) || (anillo in player)) ... |
Puedes poner tantas condiciones como quieras combinadas con estos
operadores, e incluso mezclar operadores. Piensa por ejemplo cómo
harías para escribir una condición que sea "si el jugador (player) lleva el
talismán con luz, o bien si lleva el anillo puesto" (para verificar
si lleva el anillo puesto debes mirar si anillo has worn
, además
de comprobar que está en el jugador).
Inform tiene también una abreviatura muy cómoda para el caso de que
estés comprobando varias igualdades alternativas. Por ejemplo, imagina
que quieres emitir un mensaje si el jugador está en la localidad
llamada Mazmorra
, o en la localidad Pasadizo
o en la localidad
Sotano
. En principio puede hacerse usando el operador ||
para
diferentes comparaciones con la variable localizacion
, así:
if ((location==Mazmorra) || (location==Pasadizo) || (location==Sotano)) print "¡Qué frio!^" |
Pero también es posible usar la siguiente forma abreviada:
if (location== Mazmorra or Pasadizo or Sotano) print "¡Qué frio!^"; |
Esta abreviatura (or
) sólo puede aplicarse para comparaciones de
igualdad, en las que el elemento a la izquierda de la comparación es
siempre el mismo, y queremos compararlo contra diferentes valores.
![]() | ![]() | ![]() | Programando la antorcha (¡por fin!) |