Diseñando una aventura conversacional - Parte 3

Por Spellcaster

Traducido por DCG

Mirar una localidad

Veamos, una de las primeras cosas que tu conversacional debe hacer es el 'mirar' la localidad inicial… Por 'mirar una localidad' quiero decir 'describir la habitación actual'. Al describir una localidad, lo que se hace es sacar por pantalla tanto la descripción de la misma, como los objetos, monstruos y PSI's que puedan haber. Como de momento no trataremos ni monstruos, ni objetos, ni tampoco PSI's, nos limitaremos a escribir la descripción de la habitación, la cual la tenemos almacenada en el array Localizaciones[].Desc… Construyamos el procedimiento 'mirar' (look).

        Procedure Mirar(NumeroLoc:Word);
        Var A:Byte;
        Begin
                Writeln;
                A:=1;
                While (A<11) And (Localizaciones[NumeroLoc].Desc[A]<>'*') Do
                Begin
                        Writeln(Localizaciones[NumeroLoc].Desc[A]);
                        Inc(A);
                End;
                Writeln;
        End;
      

Quizá te preguntes porque no hacemos simplemente un bucle for para escribir la descripción de 10 líneas. La razón es que la descripción podría tener menos de 10 líneas, y que de ser así, la última línea tendrá un único carácter (un '*').

Ooopsss… Casi me olvido de describir las salidas… Para hacerlo, añade las siguientes líneas:

        Writeln('Salidas visibles:');
        If Rooms[NumeroLoc].Norte<>0 Then Write('Norte');
        If Rooms[NumeroLoc].Sur<>0 Then Write('Sur');
        If Rooms[NumeroLoc].Este<>0 Then Write('Este');
        If Rooms[NumeroLoc].Oeste<>0 Then Write('Oeste');
        Writeln;
      

Si quieres añadirle un poco de colorido, usa otro color diferente. Prueba a añadir lo siguiente antes de describir la localidad:

        TextColor(White);
      

Y antes de dar las salidas:

        TextColor(Yellow);
      

Y quedará mucho mejor… :)

Si queremos usarlo, tendrás que implementar la procedure 'Jugar', que constituirá el cuerpo principal del juego… De momento, 'Jugar' se limitará a describir la localidad…

        Procedure Jugar;
        Var Fin:Boolean;
        Begin
                Fin:=False;
                Mirar(LocalidadActual);
                Repeat
                Until Fin;
        End;
      

El booleano Fin controla el final del juego… cuando se ponga a cierto (true), la partida se dará por terminada. Ésto deberá ocurrir cuando por ejemplo el jugador desee abandonar o finalice con éxito la aventura…

Así pues, tendrás que añadir al programa principal una llamada a esta rutina, y también definir e inicializar la variable LocalidadActual… En LocalidadActual guardaremos la posición actual del jugador en el juego, yo la declaro de tipo Word… Y la inicializo al valor 22, porque esta es precisamente la localidad de comienzo en Fanglore… Házlo en la rutina Init.



La Entrada de comandos y el parser

Ha llegado la hora de recibir las ordenes del usuario… Es aquí donde muchos juegos fallan… Y por qué? Pues porque su parser la caga.

¿Qué se entiende por parser? Pues no es más que una rutina (más bien un montón de ellas) que cogen la entrada del usuario, la procesan (separando comandos y nombres) y ejecuta las instrucciones que correspondan… Bien, creo que esto es algo complicado para el principiante, así que intentaré explicarlo bien.

Antes de nada tienes que recoger la entrada (o input) del usuario… Lo haremos llamando a Readln (la mayoría de las aventuras tienes sus propias rutinas para leer la entrada del jugador, pero es algo un tanto complejo como para explicarlo aquí).

        ReadLn(Comando);
      

Pónlo en el la rutina Play, a continuación de la llamada a Mirar. Define además la variable Comando como un string…

En el programa Fanglore.Pas le añado color:

        TextColor(LightRed);
      

Y también le he puesto un mensaje (el prompt), para que el que juegue sepa que el juego está a la espera de comandos:

        TextColor(White);
        Writeln('¿Cuál es la oferta, maestro?');
      

El siguiente paso es el dividir el string en sus componentes. Dado un string como 'Coger la máscara', obtendríamos solamente las palabras 'coger' y 'máscara'… El artículo 'la', al igual que todos los artículos que pudieran haber, desaparecería.

Hágamos una rutina que dado un string, nos devuelva un array con las palabras separadas:

        Procedure Parse(S:String;Var Parsed:Array[1..10] Of String);
      

Usamos una rutina con un parámetro Var en vez de una función, porque una función no puede devolver un array… Y de hecho tampoco sería posible hacer lo de más arriba, sino que deberás definir un tipo:

        Type ParsedTipo:Array[1..10] Of String;
      

De esta manera podrás definir la rutina así:

        Procedure Parse(S:String;Var Parsed:ParsedType);
      

Ahora, lo primero que tenemos que hacer es dividir la entrada en sus componentes… Lo haremos buscando el primer espacio, y cogiendo todo lo que estuviera desde el comienzo hasta el espacio, y guardándolo en el array, y así sucesivamente…

La rutina sería algo como:

        Procedure Parse(S:String;Var Parsed:TipoParsed);
        Var IndiceArray:Byte;
            IndiceString:Byte;
            SiguienteEspacio:Byte;
        Begin
                IndiceArray:=1;
                IndiceString:=0;
                SiguienteEspacio:=EncuentraEspacio(S,IndiceString);
                While (IndiceString<=Length(S)) And (IndiceArray<11) Do
                Begin
                        NextSpace:=EncuentraEspacio(S,IndiceString);
                        Parsed[IndiceArray]:=ObtieneString(S,IndiceString,SiguienteEspacio);
                        IndiceString:=SiguienteEspacio;
                        Inc(IndiceArray);
                End;
        End;

Esto parseará el string… Usa dos funciones, EncuentraEspacio y ObtieneString, cuyo código viene a continuación… La primera función se encarga de buscar el siguiente espacio dada una posición de comienzo, mientras que la segunda copia una parte del string.

        Function EncuentraEspacio(S:String;Inicio:Byte):Byte;
        Begin
                While (S[Inicio+1]<>' ') And (Inicio<Length(S)) Do Inc(Inicio);
                EncuentraEspacio:=Inicio;
        End;
        

Function ObtieneString(S:String;Inicio,Final:Byte):String; Var A:Byte; Tmp:String; Begin Tmp:=''; For A:=Inicio+1 To Final Do Tmp:=Tmp+S[A]; ObtieneString:=Tmp; End;

No te olvides de llamar a la rutina Parse después de leer el comando:

        Parse(Comando,Parsed);
      

Y acuérdate de declarar también el array Parsed:

        Var Parsed:TipoParsed;
      

Ahora lo que tenemos es un array con la entrada parseada… Lo que hay que hacer es pasarlo todo a mayúsculas… ¿Por qué? Pues bien, porque lo que no querrás es que el programa te mande a paseo si alguien escribe 'coger' o 'Coger' en lugar de 'COGER'. Ten en cuenta que para el ordenador resultan muy diferentes las mayúsculas de las minúsculas…

Usaremos la rutina PasarAMayusculas para tal fin:

        Function PasarAMayusculas(S:String):String;
        Var Tmp:String;
            A:Byte;
        Begin
                Tmp:='';
                For A:=1 To Length(S) Do Tmp:=Tmp+UpCase(S[A]);
                Upper:=Tmp;
        End;
      
La función Upcase es una función estándar de Pascal que convierte una minúscula en mayúscula, sin afectar a los simbolos especiales, ni tampoco a las mayúsculas… Llama a la rutina PasarAMayusculas por cada elemento del array Parsed, después de parsear la entrada.


Próxima Entrega: En nuestro próximo capítulo continuaremos con el desarrollo del parser, y abordaremos el movimiento del jugador.

Nota de Spanish Quest: En los primeros números de 'The Mag' se realizó un cursillo de Pascal la mar de majo. Como comprenderéis no es cuestión de que lo reproduzcamos aquí, después de todo esto es una revista sobre aventuras, y no de programación. A los que no conozcáis Pascal y sepáis inglés os remito directamente a 'The Mag'. A los demás buscaos un buen tutorial en castellano, que seguro que los habrá perdidos en algún rincón de la red o miraros alguno de esos CD-ROMS que regalan las revistas, que puede que venga algún tutorial o cursillo interactivo de Pascal. Si el Pascal no os va, o simplemente conocéis algún otro lenguaje (BASIC, no gracias) no os será nada complicado el pasarlo.


Indice