SPAC
Portada > Webzine > Sección objetiva > A. técnicos > Cursillo práctico de Inform 7 (II)

Cursillo práctico de Inform 7 (II)

Complicando las cosas: sobre las acciones - Nivel: Novato

Viernes 8 de febrero de 2008, por Sarganar


Algo de programación

Hasta aquí nuestra versión del mundo del juego ha sido meramente descriptiva. No hemos necesitado programar mucho todavía, porque las respuestas por defecto de la librería nos parecen adecuadas. Naturalmente esto impide cualquier tipo de rompecabezas ya que la librería no trae ninguno pre-programado (salvo quizás, ocultar un objeto dentro de otro y esperar a que el jugador abra el objeto para descubrirlo).

Ha llegado el momento de cambiar alguna de las respuestas por defecto de la librería. Por ejemplo, es bastante probable que el jugador intente el comando ROMPE EL PAPEL, recibiendo la respuesta estándar "La violencia no es la solución.", no muy adecuada en este caso.

Inform asocia cada verbo que puedas escribir en el juego con una acción (en inglés action). Así, en tu código te referirás siempre a la acción y no al verbo que la genera.

La librería comprende el verbo ROMPER (acción attacking), pero responde siempre la misma frase, independientemente del objeto sobre el que se use. En Inform, por defecto, los objetos no pueden romperse. Bien, el papel parece una excepción lícita. ¿Cómo hacer que el papel sea "rompible"? Aunque existe el atributo openable, no existe el atributo breakable y esto se debe a que, si bien podemos suponer qué pasará en general al abrir un objeto (simplemente cambia de estar cerrado a estar abierto), ya no es posible suponer qué pasará en el caso general al romper un objeto. ¿Qué debería hacer la librería con el papel si dejara romperlo? ¿desaparecería el papel del juego? ¿Cambiaría el papel una bandera que indique que está "roto"? ¿deberán aparecer en su lugar unos cuantos trocitos de papel? (esto podría ser la solución a un rompecabezas en el que el jugador necesitase obtener confetti). Por supuesto la librería no puede (o no quiere) traer programado qué ocurrirá en general al romper un objeto, de modo que por defecto impide que se rompan y si queremos un objeto rompible debemos programar nosotros qué pasará cuando se rompa.

Empecemos por lo fácil: si el jugador pone ROMPE PAPEL, el papel debe desaparecer del juego, mostrando un mensaje apropiado. Bien, esto se trata como una excepción a la regla general para la acción attacking , pero sólo cuando el objeto sea el Papel. En los demás casos queremos mantener la regla original (es decir, el boli y la caja no se pueden romper). Aquí es dónde entran en juego las rules de I7, y en especial las rules relacionadas con las acciones. La rule Instead of… se ejecutará -si existe- en lugar de la acción por defecto.

Hay que decir que toda accion en I7 está regida por reglas específicas (que vienen de fábrica). Las puedes ver en Index>>Actions. Pero son modificables o pueden ser ‘ignoradas’ usando otras reglas, como la Instead of…

Ahora, averigüemos qué acción corresponde a ROMPER.

En el juego usa el comando de depuración ACTIONS:


>actions
Actions listing on.

>rompe papel
[attacking el papel]
La violencia no es la solución.
[attacking el papel - failed the block attacking rule]

Perfecto! Tienes el nombre de la acción (attacking), el sujeto (el papel) y la regla estándar que aplica (aquí se llama ‘the block attacking rule’). Veremos más sobre reglas luego.

Otra forma es buscar dicho verbo (en realidad, su imperativo ‘rompe’) en la lista de Index>>Actions.

La búsqueda se activa con CTRL+F. Encontrarás en la lista:


"rompe [something]" [E1] – Attacking

Bingo! Attacking! También tienes un link a la definición completa de la acción y las reglas que la gobiernan. Con estos métodos podrás saber si I7 ya tiene soporte para los verbos que necesites en el juego.

Entonces, la forma de programar esto es la siguiente:


 Instead of attacking the papel:
        remove the papel from play;
        say "Rompes el papel en trocitos minúsculos, que
                 desaparecen al tocar el suelo."

No importa dónde lo agregues, mejor cerca del código del papel lo cual hace más simple la programación y modificación del juego. Compila y prueba romper el papel. Ahora la regla Instead of attacking the papel…. se encarga de la acción. ¿Entiendes? Y puedes ser aun más específico:

Instead of attacking the papel while the papel is in the caja:

Solo funcionará si el papel está en la caja.

Veamos. Toda regla tiene esta sintaxis y es esta:


Regla:
  frase1;
  frase2;
  ….
  última frase.

Y en nuestro caso, hemos usado dos frases:


remove the papel from play;
        que traslada al objeto a un especie de ‘limbo’ inaccesible desde el juego.

say "Rompes el papel en trocitos minúsculos, que
                 desaparecen al tocar el suelo."
        que es la típica orden PRINT en I7.

Ahora ve a Index>>Accions.Attacking

snapshot de accion attaking

Podrás ver tu regla Instead en la lista. Estrictamente hablando tu regla Instead será una regla más del RuleBook llamado Instead. Los rulebooks agrupan las reglas del mismo tipo (Instead, Check, Report, etc). Pero dejémonos de purismos esta vez.

Usando el mismo rulebook Instead, podemos programar excepciones a otras acciones (por ejemplo podemos cambiar la respuesta por defecto ante el verbo/acción ABRIR/opening). Para ello basta repetir el esquema visto para el verbo ROMPER, es decir:

   
   Instead of opening the papel:
        say "El papel no está doblado. No necesitas abrirlo."

Como solo hay una frase, también puedes usar directamente comillas:


   Instead of opening the papel, say "El papel no está doblado. No necesitas abrirlo."

Las acciones que no se mencionan en Instead seguirán funcionando "por defecto" (por ejemplo, CERRAR PAPEL produciría la respuesta estándar "No es algo que pueda cerrarse"). Para variar esta respuesta para el caso del papel habría que programar CERRAR (acción closing) con otra regla Instead.

Al programar algo con Instead, la mayoría de las veces nos limitaremos a poner un mensaje (que aparecerá cuando el jugador intente ese verbo sobre ese objeto), y no hará nada más. Así que en realidad se trata de impedir al jugador que lleve a cabo esa acción mostrando un mensaje que explica por qué no puede llevarla a cabo (mira por ejemplo la acción opening del ejemplo anterior). Para eso usaremos (normalmente) las Instead rules.

En otras ocasiones sí se puede llevar a cabo la acción, pero entonces debemos programar "a mano" las consecuencias de la misma. Por ejemplo hemos visto cómo hacer desaparecer el papel ante la acción attacking the papel.

Pensemos ahora otro caso posible (y bastante frecuente). Queremos que como consecuencia de una acción del jugador, algo ocurra en el juego. Por ejemplo, imaginemos un diamante dentro de una cúpula transparente, sobre un cojín de terciopelo que tiene un sensor de peso, de modo que puede detectar cuando el diamante está encima.

El jugador puede EXAMINAR DIAMANTE sin problema, ya que la cúpula es transparente. Sin embargo no puede COGER DIAMANTE, porque la cúpula se lo impide. Si el jugador consigue desembarazarse de la cúpula (la rompe, o la levanta o lo que sea), entonces ya podría coger el diamante. Pero queremos que en ese caso suene una alarma (ya que el cojín de terciopelo detecta la ausencia de peso).

Ante la acción taking (COGER), la librería se ocupa por defecto de comprobar si el diamante está dentro de otro objeto, impidiendo cogerlo si está dentro de un objeto cerrado (obvio, no?). Sin embargo, en el momento que la cúpula deja de ser un impedimento, la librería dejará ya libre acceso al diamante, es decir COGER DIAMANTE, produciría la acción por defecto "Cogido." Todo esto sin que nosotros programemos una sola línea.

Como queremos que salte una alarma al coger el diamante, parece un caso de "excepción a la regla general", para el caso particular del diamante. No obstante, intentar programárla en una regla Instead complicaría la cosa, ya que se ejecutaría eso en vez de las comprobaciones generales para la accion taking. En particular, la librería no ha comprobado aún si hay cúpula u otro impedimento para coger el diamante. Esto significa que deberíamos comprobarlo nosotros mediante la programación adecuada dentro de la regla Instead. (Imagina que en el juego aparecen otros muchos recipientes que puedan estar abiertos o cerrados y el diamante podría estar en cualquiera de ellos, ya que el jugador pudo haberlo metido allí. Olvídalo Joe!).

No va por allí los tiros. Para ello existe el rulebook After. La diferencia con Instead es que I7 lo aplica después de que la librería ha comprobado si la acción es posible y después de haberla llevado a cabo. En nuestro ejemplo, eso sería una vez que la acción taking ha tenido éxito y por tanto el diamante está en poder del jugador y la cúpula queda vacía. En ese momento, podremos imprimir el mensaje adecuado, indicando que una alarma ha empezado a sonar (y podremos modificar otros objetos del juego, u otras variables para indicar que la alarma está sonando).

Vamos a programar todas estas ideas en forma de dos objetos: una cúpula (que será un recipiente transparente dentro del cual está el diamante) y un diamante (y que al ser cogido sonará una alarma). La cúpula tiene una tapita que el jugador puede abrir para acceder al diamante. La cúpula no puede ser cogida por el jugador.

Una primera versión del código puede ser:


A cupula de cristal is here. The printed name is "cúpula de cristal". [nota el acento]
   The description is "Examinando con detenimiento la cúpula descubres una
       especie de juntura. Parece una tapa que podría abrirse."
   It is container, openable, closed and female.
   It is fixed in place and transparent.

A diamante is in the cupula.
   The description is "El diamante reposa sobre un cojín de terciopelo."
   After taking the diamante, say "Al coger el diamante una alarma empieza a sonar."

printed name, es la propiedad que I7 usa cuando tiene que referirse al objeto en cualquier texto de salida de la aventura. Por defecto usaría el nombre ‘cupula’ sin acento pero se lo cambiamos a ‘cúpula de cristal’. Si bien definimos el objeto como ‘cupula de cristal’, luego podemos usar solo cupula en el código. I7 no tiene problemas con esto, ni en el código ni el juego.

Agrégalo a tu código del Cursillo y compílalo:


Puedes ver una caja (cerrada) y una cúpula de cristal (cerrada) (en la que ves un diamante).

Esto aparece como parte de la descripción de la habitación . Menciona al diamante porque la cúpula es transparente. En cambio no menciona el papel que hay dentro de la caja porque la caja no es transparente. Así que podemos ver el diamante. Intentemos hacer cosas con él:


>examina diamante
El diamante reposa sobre un cojín de terciopelo.

>coge diamante
La cúpula de cristal no está abierta.

>saca diamante de la cupula
La cúpula de cristal no está abierta.

¡Funciona! Podemos ver el diamante, pero no hacer cosas con él. Intentemos ahora manipular la cúpula:


>coge cupula
La cúpula de cristal está fija en el sitio.

>rompe cupula
La violencia no es la solución.

>empuja cupula
Está firmemente sujeta.

>examina cupula
Examinando con detenimiento la cúpula descubres una especie de juntura. Parece una tapa que podría abrirse.

>abre cupula
Abres la cúpula de cristal.

Qué bien! Todo parece funcionar. Ahora se supone que ya tenemos acceso al diamante (pero esto debería hacer saltar la alarma). Probemos:


>coge diamante
Al coger el diamante una alarma empieza a sonar.

>inventario
Llevas:
 un diamante
 un boligrafo

Bueno, no ha sido tan difícil ¿verdad?

Algo más de programación

Todo funciona bien ¿no? Eso crees tú... la verdad es que no todo es tan perfecto como parece. Ahora que el jugador tiene el diamante en su poder su descripción debería cambiar (ya no está sobre el cojín). Además, si se deja el diamante (en el suelo) al recogerlo de nuevo no debe sonar la alarma otra vez, sin embargo tal y como lo hemos hecho cada vez que se recoja el diamante saldrá el mensajito de la alarma. Pruébalo:


>coge diamante
Ya tienes el diamante.

>examina diamante
El diamante reposa sobre un cojín de terciopelo.

>deja diamante
Dejado.

>coge diamante
Al coger el diamante una alarma empieza a sonar.

Esto no es correcto. Una forma de evitarlo consiste en usar una regla Instead para el caso especifico del diamante fuera de la cúpula. La acción sobre la cual trabajar es la acción que utiliza la propiedad description del diamante, o sea la acción examinig the diamante:


A diamante is in the cupula.
   The description is "El diamante reposa sobre un cojín de terciopelo."
   After taking the diamante, say "Al coger el diamante una alarma empieza a sonar."
   Instead of examining the diamante while the noun is not in the cupula, say "Tiene un brillo casi cegador, que no parece explicable por las leyes de la óptica."

Con la palabra ‘while’ estás introduciendo más detalles a la regla, haciéndola más específica (también puedes usar ‘when’ aquí), ya que ahora tiene una condición que cumplir.

the noun hace referencia al objeto de la acción: nuestro diamante (en este caso).

is not in hace el chekeo en sí: SI NO ESTÁ EN. A estos conectores I7 los llama whereabouts y los puedes usar en porciones while o if… Hay muchos más (is in, contains, is carried by, does not have, support, is inside, is part of, etc). Son muy útiles. [1]

Por ejemplo, lo anterior lo hubiéramos podido hacer así:


A diamante is in the cupula.
   The description is "Tiene un brillo casi cegador, que no parece explicable por las leyes de la óptica."
   After taking the diamante, say "Al coger el diamante una alarma empieza a sonar."
   Instead of examining the diamante while the noun is inside the cupula, say "El diamante reposa sobre un cojín de terciopelo."

Ves? Ahora usamos ‘is inside’. Dependerá un poco de la manera en que tu cerebro organiza la aventura.

Incluso podemos hacerlo usando otra filosofía:


A diamante is in the cupula.
   After taking the diamante, say "Al coger el diamante una alarma empieza a sonar."
   Instead of examining the diamante:
        if the noun is inside the cupula, say "El diamante reposa sobre un cojín de terciopelo.";
        otherwise say "Tiene un brillo casi cegador, que no parece explicable por las leyes de la óptica."

Aquí trabajamos con frases condicionales if…otherwise.

De igual manera, hacemos lo mismo con la alarma, agregando una condición específica:


   After taking the diamante while the noun is inside the cupula, say "Al coger el diamante una alarma empieza a sonar."

Pero espera, al compilar esto, obtengo:


>abre cupula
Abres la cúpula de cristal.

>toma diamante
Cogido.

Nada! Qué sucedió? Piensa, piensa. ¿Qué dijimos sobre After? Que se ejecuta después que la acción sucede, después que el diamante es cogido.

Si te fijas en Index>>Actions.Taking , verás que nuestra regla está situada al fondo. A esa altura, I7 ya movió el diamante de la cupula al jugador (en la carry out rule), por lo que la clausula while the noun is inside the cupula nunca será cierta.

¿Qué hacer entonces?

Pues bien, podemos usar una Check rule:


   Check taking something inside the cupula: say "Al coger el diamante una alarma empieza a sonar."

Que sería una regla que funciona para cualquier cosa que se saque de la cúpula. ¿Y esta de dónde salió? Paso a explicar: las acciones están gobernadas por una serie de reglas, agrupadas en RulesBooks. Y se ejecutan según un orden. Estas son:

esquema rules en I7

Las Check, Carry Out y Report rules son reglas generales aplicadas a la acción. Todas las acciones vienen de fábrica con este trío dinámico. Creo que ya te habrás dado cuenta. Las Checks rules realizan verificaciones y bloquean la acción si no están las condiciones dadas (el objeto es inaccesible, o es escenario, o qué se yo) Las Carry Out rules ejecutan la acción. No imprimen nada. Las Report rules solo imprimen los resultados (Cogido., Abres el armario., etc)

Usamos las Instead rules para bloquear el flujo normal. Cuando se dispara la Instead rule, ya no se ejecutan las siguientes rules. De allí que se usen para situaciones particulares o para reemplazar las respuestas por defecto del juego. Las After rules tiene precedencia a las Report, y pueden usarse para hacer cosas antes de imprimir la consecuencia de la acción o para imprimir respuestas un poco más ‘floridas’ que el insulso “Cogido.” Las Before rules se usan mayormente para intentar lanzar otras acciones, reemplazándolas o ejecutándolas silenciosamente. Son consideradas antes que cualquier otra comprobación. Esto es un esquema con que I7 pretende organizar sus reglas. Puedes respetarlo (sobre todo al hacer extensiones) o resolver tus problemas como te venga en gana.

Volviendo a nuestro juego, resumamos nuestro mini-puzzle: Si el jugador saca el diamante de la cúpula, una alarma empieza a sonar. Si el jugador mete cualquier cosa en la cúpula, la alarma se detiene. De este modo el jugador puede cambiar el diamante por el bolígrafo por ejemplo y así detener la alarma. ¿Y si además hacemos que la alarma acabe por atraer a alguien si no deja de sonar? Esto será el tema del próximo artículo.

Sayonara!

>>Siguiente: El uso del tiempo y escenas

>>Anterior: Manos a la Obra

Notas

[1] Consulta el capítulo sobre Change: Checking on whereabouts del manual

3 Comentarios


Seguir la vida del sitio  RSS 2.0: Artículos, Comentarios | Mapa del sitio | SPIP
CC Some rights reserved El contenido está disponible bajo los términos de Atribuir - Compartir bajo la misma licencia 3.0 ó 2.5 de Creative Commons.