¡¡En este capítulo nos meteremos de lleno en el alucinante y esencial mundo de los objetos!! Ninguna aventura conversacional sería realista al 100% sin 100000 objetos, pero para Fanglore seremos más modestos, y tan solo tendremos cuatro... Estos serán:
Para crearlos, podemos utilizar el programa OBJGEN.PAS. Es muy parecido al ROOMGEN.PAS que venía con el SQ 1, excepto que en vez de crear localidades, crea objetos.
Bien, veamos qué es lo que necesitamos guardar para cada objeto:
su nombre, su posición (podemos mover objetos de una localidad a
otra o llevarlo en el inventario) y su descripción. Explicaré
la parte de la descripción más adelante. Definiremos un record
como este:
Definamos el número de objetos que habrán en el juego:
Type TipoObj=Record
Nombre:String[80];
Pos:Byte;
Desc:Array[1..5] Of String[80];
End;
Y, finalmente, definamos el vector (array) que guardará los
objetos:
Const NumeroObjs=6;
Esto, después de haber definido estas estructuras y haber obtenido
el fichero OBJ.DAT (con el OBJGEN), tendremos
todos los datos en el mismo, con lo cual sólo habrá que
leer estos, con una rutina muy similar a LeerDatosLocalizaciones
que ya vimos en nuestra segunda entrega:
Var Objetos:Array[1..NumeroObjs] of TipoObj;
Procedure LeerDatosObjetos;
{ Leemos del disco los datos de los objetos }
Var F:Text;
A,B:Byte;
Flag:Boolean;
Begin
{ Preparamos el fichero de texto para el acceso }
Assign(F,'Obj.Dat');
Reset(F);
{ Para cada objeto del juego }
For A:=1 To NumeroObjs Do
Begin
{ Leemos el nombre del objeto }
ReadLn(F,Objetos[A].Nombre);
{ Leemos la posición inicial }
ReadLn(F,Objetos[A].Pos);
{ Limpiamos la descripción del objeto }
For B:=1 To 5 Do Objetos[A].Desc[B]:='';
{ Leemos la descrición }
Flag:=True;
B:=1;
While Flag Do
Begin
ReadLn(F,Objetos[A].Desc[B]);
If (B=5) Or (Objetos[A].Desc[B]='*') Then Flag:=False;
Inc(B);
End;
End;
Close(F);
End;
Un apunte más... Si el campo POS de un objeto es 0, significará que estamos llevando el objeto, y si es 255, que el objeto está escondido (en el caso de la máscara de gas, ésta sólo aparece si el horno está abierto).
Un objeto es inútil, a menos que se pueda usar... Y sólo lo puedes usar si se ve, o si sabes que está allí... Así que hay dos clases de objetos que uno puede ver: objetos que llevas y objetos que ruedan por el escenario... Un buen juego tiene diferentes descripciones para cada una de estas dos clases, pero Fanglore se limita a tratarlos de la misma forma, soltando la descripción.
Bien, has de saber que hay un comando básico que es igual en TODAS las aventuras: ¡EXAMINAR!
Al comando examinar le sigue un parámetro, esto es, acepta (y requiere)
que teclees otra cosa... Esta cosa es precisamente lo que deseas examinar...
Por ejemplo, si quieres examinar la espada, uno teclearía:
Procedure Examinar(Param:String);
Var Flag:Boolean;
A,B:Byte;
Begin
Flag:=True;
{ ***************************************************** }
{ Aquí vendría el código para cosas como el horno, etc. }
{ ***************************************************** }
{ Buscamos el objeto en la lista de objetos }
A:=0;
Repeat
Inc(A);
If Objetos[A].Nombre=Param Then Flag:=True;
Until Flag Or (A>NumeroObjs);
If Flag Then
Begin
{ El objeto existe }
{ Comprobamos que esté en localidad o bajo tu poder }
If (Objetos[A].Pos=0) Or (Objetos[A].Pos=LocalidadActual) Then
Begin
{ El objeto es 'visible'... Sacamos descripción }
Writeln;
B:=1;
TextColor(Yellow);
While (B<6) And (Objetos[A].Desc[B]<>'*') Do
Begin
Writeln(Objetos[A].Desc[B]);
Inc(B);
End;
Writeln;
End
Else
Begin
{ El objeto existe, pero no está visible }
Writeln;
TextColor(Yellow);
WriteLn('No veo el ',Param,' por aquí...');
WriteLn;
End;
End
Else
Begin
{ El parámetro especificado no representa ningún objeto }
{ existente... }
WriteLn;
TextColor(Yellow);
WriteLn('Lo siento, pero no sé qué es un ',Param);
WriteLn;
End;
End;
Por supuesto tienes que completar la rutina que llama a esta procedure...
Debes ponerlo todo (al igual que el resto de comandos) en Play. La
rutina quedaría así:
If Parsed[1]='EXAMINAR' Then
Begin
Valid:=True;
Examinar(Parsed[2]);
End;
¿Verdad que es fácil...? Pero aún no hemos acabado... Si
te acuerdas de lo que dije a propósito del parseo, sabrás que
las entradas se dividen en palabras... Pero resulta que la máscara
de gas tiene 2 palabras como nombre (Gas Mask)... Tal como lo tenemos ahora
el programa es incapaz de detectar los objetos con varias palabras.
¿Cómo podríamos arreglarlo? Bien, hay que volver a unir las
palabras otra vez... Observa:
If Parsed[1]='EXAMINAR' Then
Begin
Valid:=True;
{ Juntamos las palabras otra vez }
D:=3;
E:=Parsed[2];
While Parsed[D]<>'' Do
Begin
E:=E+' '+Parsed[D];
Inc(D);
End;
Examinar(E);
End;
En cuanto a la definición de tipos, define E como string y D como
un Byte. A pesar de que esto funciona con comandos de sólo un
parametro, la cosa falla cuando hay comandos que requieren múltiples
parametros... La regla es no utilizar objetos con nombres que llevan
espacios...
Aún no hemos acabado la sección... Todavía nos queda ver que objetos hay en la localidad, y que objetos llevas... Pero esto lo dejaré para mañana, ya que ayer sólo dormí 2 horas... Y estoy MUY cansado...
Buenas noches... Zzzzzzzzzzzzzzzzzzzzzzzz..........
Ok... ¡He vuelto! :) Preparado para continuar... Ya... Nuestro problema es saber los objetos con los que podemos interactuar. Es fácil. Cuando entremos en una localidad, haremos que el programa saque una lista de los objetos visibles. Para conseguirlo, añadimos el siguiente código a la rutina de Mirar:
TextColor(LightCyan);
Writeln('Objetos visibles:');
Flag:=False;
For A:=1 To NumeroObjs Do If Objetos[A].Pos=NumeroLoc Then
Begin
Writeln(' ',Objects[A].Nombre);
Flag:=True;
End;
If Flag=False Then Writeln(' Nada');
No olvides definir la variable Flag como un Boolean. Se usa para
saber si hay algún objeto en la habitación... Si al salir
del bucle For fuera falso, significará que no hay objetos en la
localidad, y el programa notificará que no hay ningún objeto...
Para saber qué objetos estás llevando, usamos el segundo comando más conocido en las aventuras solo-texto... ¡El comando de INVENTARIO! Para implementarlo, sólo hace falta chequear todos los objetos del juego. Si su localización (campo POS) es cero, entonces es que lo estás llevando... Codificando:
Procedure Inventario;
Var A:Byte;
Flag:Boolean;
Begin
Flag:=False;
TextColor(LightBlue);
WriteLn;
WriteLn('Inventario:');
For A:=1 To NumeroObjs Do If Objetos[A].Pos=0 Then
Begin
WriteLn(' ',Objetos[A].Nombre);
Flag:=True;
End;
If Flag=False Then Writeln(' Nada');
WriteLn;
End;
Como ya es habitual, debes añadir unas líneas a la rutina
Play, para que llame a esta última:
If Parsed[1]='INVENTARIO' Then
Begin
Valid:=True;
Inventario;
End;
Ahora ya podemos mirar los objetos... Pero nos queda la interacción,
que dejaremos para el siguiente capítulo...
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 no os será nada complicado el pasarlo.