Criaturas vivas y cómo conversarEl modelo del mundoObjetos en los que puede entrarse, viajar o empujarObjetos para leer y consultar

Objetos para leer y consultar

Una orden como "Busca la figura 18 en el manual técnico" es muy difícil de entender para Inform, ya que en la primera parte ("la figura 18") puede aparecer prácticamente cualquier cosa. Incluso su formato depende de la segunda parte. En general el jugador puede intentar las siguientes órdenes:


Consulta <cualquier secuencia de palabras> en <objeto>
Consulta <objeto> sobre <cualquier secuencia de palabras>
Lee sobre <cualquier secuencia de palabras> en <objeto>
Lee <cualquier secuencia de palabras> en <objeto>
Busca <cualquier secuencia de palabras> en <objeto>
Busca en <objeto> sobre <cualquier secuencia de palabras>
Busca en <objeto> <cualquier secuencia de palabras>

Todas ellas generarán la misma acción: <Consultar objeto>. Observa que esta acción tiene un objeto en la variable uno, pero no pone nada en la variable otro. Formalmente, la acción consultar sólo recibe un objeto, que es el libro consultado. El tema de la consulta debe averiguarlo el propio objeto consultado, analizando la cadena <cualquier secuencia de palabras> por sí mismo, ya que el parser no intenta analizar esa parte. Esto deberá hacerlo en su rutina antes. Para facilitar este trabajo, existen las siguientes variables y funciones:

consultar_desde
Es una variable que contiene la posición que ocupa la primera palabra de <cualquier...> dentro de la secuencia de palabras escritas por el jugador. Si, por ejemplo, el jugador ha puesto "Busca en la enciclopedia la historia de Oz", el parser habrá generado la acción Consultar enciclopedia y habrá preparado la variable consultar_desde con el valor 5 (que corresponde a la palabra 'la' que aparece tras la enciclopedia. Basta contar palabras empezando por 1='Busca').
consultar_num_palabras
Es una variable que indica cuántas palabras hay en la parte <cualquier secuencia de palabras>. En el ejemplo anterior valdría 4 (ya que hay 4 palabras en "la historia de Oz").
np
Esta variable contiene el número de la palabra que queremos averiguar. El programador debe hacer np = consultar_desde, para así empezar a averiguar desde la primera palabra desconocida.
SiguientePalabra()
Esta función devuelve cuál es la siguiente palabra de las escritas por el jugador. Utiliza np para saber qué palabra toca (y automáticamente incrementa np). De este modo, si la llamamos justo después de haber inicializado np con el valor consultar_desde, nos devolverá la primera palabra ('la'), si inmediatamente la llamamos otra vez nos devolverá la siguiente palabra ('historia') y así sucesivamente.

En realidad, el valor que devuelve es un número, que identifica a una palabra de las que el juego tiene en su diccionario (el diccionario del juego se forma automáticamente con todas las palabras que el programador haya puesto entre 'apostrofes' en cualquier lugar del código). Si el jugador ha escrito algo que no estaba en el diccionario (por ejemplo "asdfg"), entonces el valor retornado sería 0. También retorna 0 si se ha alcanzado el final del texto.

SiguientePalabraParar()
Como la anterior, pero retorna -1 en vez de 0 si ya no queda más texto.

Usando las variables y funciones anteriores, el objeto consultado debe ir analizando una a una las palabras usadas por el jugador, y decidir qué respuesta darle. Si la rutina devuelve false, la librería mostrará el mensaje estándar "No encuentras nada interesante.", y si devuelve true la librería no hará nada, como de costumbre.

(Esp) Todo esto es tremendamente tedioso y difícil de programar. Por ello he desarrollado una librería adicional llamada ETemas que puedes usar en tus juegos junto con InformATE que te permite crear una serie de "Temas de consulta", y hace todo el trabajo de parsing por ti, para identificar el tema que el jugador intentaba consultar, de forma bastante flexible como para que el jugador pueda poner variantes y aún así ser comprendido (por ejemplo: "Busca en la enciclopedia la historia de Oz", "Busca en enciclopedia Oz", "Busca en enciclopedia historia Oz", etc.

Puedes encontrar más información sobre ETemas en http://www.geocities.com/TimesSquare/Fortress/9939/informate.

Un ejemplo de cómo hacer esto: un diccionario de símbolos mayas, que podría llevar consigo el jugador de "Ruinas" para interpretar las pequeñas pistas que irá encontrando por el juego.

Object diccionario "Diccionario Maya de Waldeck" objjugador
 with   nombre 'diccionario' 'libro' 'maya' 'waldeck',
        descripcion "Ha sido escrito a partir de las poco fiables
            litografías del legendario explorador y narrador ~Conde~
            Jean Frederic Maximilian Waldeck (1766??-1875), este libro
            contiene lo poco que se sabe de los símbolos usados en el
            antiguo dialecto local.",
        antes [simbolo;
         Consultar:
            if (consultar_num_palabras > 2)
                print_ret (string) diccionario.ayuda;
            np=consultar_desde;
            simbolo=SiguientePalabra();
            if (consultar_num_palabras > 1) 
            {
                if (simbolo=='el' or 'la')
                    simbolo=SiguientePalabra();  ! Saltarse 'el'
                else print_ret (string) diccionario.ayuda;
            }
            switch(simbolo)
            {
             'q1':"(¡Este es el símbolo que has memorizado!)^^
                    Q1: ~lugar sagrado~.";
             'circulo': "Círculo: ~El Sol; también vida, duración de
                la vida~.";

                ! . . .
                
             default: "Ese símbolo no ha sido registrado hasta la
                fecha.";
            }
        ],
        ayuda  "Ponlo así: ~Busca <nombre del símbolo> en el libro.~",
 has    masculino;

Observaciones: este objeto lo hemos puesto dentro de otro llamado objjugador que, como habrás adivinado, es el jugador. Es la forma de que aparezca inicialmente en su inventario. La rutina antes, por primera vez en lo que va de manual, tiene una variable local, llamada simbolo. Para crear variables locales en las rutinas basta ponerlas delante del punto y coma. Esta variable contendrá la palabra que el jugador está intentando consultar, pero es la propia rutina antes la que tiene que ocuparse de averiguar esa palabra. Lo primero que miramos es que el jugador no haya escrito más de dos palabras (aceptaremos por ejemplo "Busca en el libro el circulo", o "Busca en el libro circulo", pero no "Busca en el libro el símbolo del circulo". Si se detecta que consultar_num_palabras es mayor de 2, se imprime una pequeña ayuda y se termina. Si todo va bien, continúa poniendo la variable np igual a consultar_desde y llamando a SiguientePalabra(). Esto devolverá, bien un artículo, bien directamente el nombre del símbolo. Si es un artículo hay que hacer un de nuevo SiguientePalabra() para obtener el nombre del símbolo (si el jugador usó dos palabras pero la primera no era un artículo, se saca el mensaje de ayuda).

Tras esas averiguaciones, simbolo contendrá la palabra de diccionario usada por el jugador. El switch comparará esa palabra con una serie de posibilidades ('q1', 'circulo', etc.) Importante no poner acentos en estas posibilidades (en general, como ya hemos dicho, no deben ponerse acentos en las palabras de diccionario, es decir, todas aquellas encerradas entre apóstrofes en el listado). Si la palabra que usó el jugador no coincide con ninguna de las listadas, se irá al caso default.

Observar cómo hemos puesto el mensaje de ayuda en una propiedad nueva, creada especialmente para este objeto (y cómo para imprimirla hay que poner (string) delante de ella).

(?) EJERCICIO 17  Programa una biblia en la que el jugador pueda efectuar un comando como "Lee san lucas 23 en la biblia". La Biblia debe entender referencias a los cuatro evangelios. La solución es un poco tediosa, porque hay que tener en cuenta que el jugador puede teclear muchas variantes ("Lee lucas en la biblia", "Lee san lucas en la biblia", "Lee lucas 23 en la biblia") y hay que asegurar que se acepta cualquiera de ellas. Necesitarás usar la función IntentarNumero(np) esta función intenta interpretar como un número la palabra señalada por np. Si lo consigue, devuelve el valor de ese número y si no lo consigue devuelve la cantidad -1000. (Esta función entiende también números "de palabra", como por ejemplo: "Lee san lucas once en la biblia". En este caso sólo comprende números entre "uno" y "veinte"). (Solución)

(!)(!) La librería estándar define el verbo "Lee objeto" de forma que provoque la acción Examinar objeto. Si quieres hacer un objeto que pueda ser examinado o leido, dando diferente resultado en cada caso, hay que redefinir este verbo. Esto se haría por ejemplo así (definimos un nuevo atributo legible que habría que dar a los objetos que pueden ser leídos):

Attribute legible;
...
Object libro_texto "libro de texto"
with nombre 'libro' 'texto',
     descripcion "¡Qué bonita es la portada!",
     antes [;
       Consultar, Leer: 
          "Las páginas están llenas de ecuaciones sin sentido.";
    ],
has legible;
...
[ LeerSub; <<Examinar uno>>; ];
Extend 'lee' first 
      * legible            -> Leer;

La clave está en las dos últimas líneas, que redefinen el verbo "lee" que venía en la librería, de modo que añaden a la definición original la línea que dice * legible -> Leer; Esta línea significa que si el verbo "lee" se intenta sobre un objeto legible, entonces la acción generada será Leer en vez de examinar (si no es legible se usará la gramática original, por lo que se generaría la acción Examinar). Necesitamos proporcionar la rutina LeerSub que lleve a cabo la acción "por defecto", y hemos decidido que la acción por defecto sea Examinar objeto. La forma de evitar esta acción por defecto es hacer que los objetos capturen la acción Leer en su rutina Antes, que es lo que hace el ejemplo libro_texto.

(Esp) Otra posibilidad sería que el verbo "lee" siempre genere la acción Leer, independientemente de que el objeto tenga o no el atributo legible, y posteriormente la rutina LeerSub compruebe si es o no legible para proporcionar una respuesta por defecto apropiada. Esto se haría con una rutina LeerSub y una línea gramatical como las siguientes:

[ LeerSub;
  if (uno has legible) "No entiendes lo que pone.";
  else "Eso no tiene nada escrito.";
];

Extend 'lee' first
   * noun            -> Leer;


Zak McKraken - spinf@geocities.com

Criaturas vivas y cómo conversarEl modelo del mundoObjetos en los que puede entrarse, viajar o empujarObjetos para leer y consultar