Puntuación y otras yerbasEl modelo del mundo¿Qué hora es?Iniciar, mover, cambiar y matar al jugador

Iniciar, mover, cambiar y matar al jugador

La única cosa realmente obligatoria que debe hacer la rutina Inicializar es poner en localizacion el lugar en que debe comenzar el juego. Éste lugar normalmente es una habitación (y puede estar a oscuras) pero también podría ser un objeto dentro de una habitación, como una silla o una cama. Si quieres que el jugador comience con algunos objetos en su inventario, debes moverlos también en la rutina Inicializar.

Los juegos que comiencen mostrando gran cantidad de texto (a modo de presentación o "introducción") harían bien en ofrecer al jugador la posibilidad de recuperar una partida guardada antes de empezar con la introducción (para que este pueda saltársela si ya la había visto). Pueden hacerlo si ponen lo siguiente en la rutina Inicializar:

   print "¿Quieres recuperar un juego previo?  >";
   if (SiONo()) <Restaurar>;  

Si quieres que la línea de estado no sea visible durante la fase de introducción, mira la sección sobre el lenguaje ensamblador. La rutina Inicializar normalmente retornará 0 ó 1, y la librería ignora este valor. Pero si retorna 2, entonces la librería no imprimirá el "anuncio" del juego (esto es, el título, autor y copyright). Esto puede ser útil para juegos que no muestran el "anuncio" hasta más adelante en el juego (puedes mostrarlo cuando quieras llamando a la función Anuncio).

Veamos, por ejemplo, la rutina Inicializar del juego Ruinas:

[ Inicializar;
    Portada();
    localizacion=Bosque;
    move racion_de_comida to jugador;
    move lampara to jugador;
    move diccionario to jugador;
    laoscuridad.descripcion = "La oscuridad de los siglos pesa sobre ti,
          y la sientes claustrofóbica";
    "^^^^^Tras días de búsqueda, de sed, de penoso avance a través 
    de la maleza del bosque, al fin tu paciencia se ve recompensada. 
    ¡Has descubierto algo!^";
];

La función Portada será programada más adelante como otra parte del juego. Ruinas es un juego demasiado corto como para merecer una portada, pero no importa. La variable localizacion necesita un poco más de explicación. Normalmente contiene la habitación en la que se halla el jugador (si hay luz bastante para verla), o el valor especial laoscuridad (si no hay luz). En este último caso, pero sólo en este caso, la variable localizacion_real contiene el verdadero lugar en el que se halla el jugador, por si necesitaras conocerlo. Ni localizacion ni localizacion_real tienen que coincidir necesariamente con el objeto padre del jugador (aunque suele ser así). Por ejemplo, si el jugador está en un jeep dentro de un garaje a oscuras, localizacion valdría laoscuridad, localizacion_real sería el Garaje, y en cambio parent(jugador) sería el jeep.

Debido a estas complejidades, el programador no debe intentar mover el jugador "a mano" (mediante algo como move jugador to habitacion). Si es necesario teletransportar "mágicamente" al jugador a otro lugar, deberá usarse la función JugadorA(lugar) (esta función se ocupa también de imprimir la descripción del lugar automáticamente, si hay luz suficiente para ver). También puede usarse JugadorA para mover al jugador a un objeto dentro de una habitación (un vehículo o un recipiente, por ejemplo).

(!) Si usamos la forma JugadorA(lugar,1), el jugador será teleportado a ese lugar, pero no se imprimirá la descripción del nuevo lugar.

Si usamos la forma JugadorA(lugar,2) la descripción que se mostrará tendrá en cuenta si el jugador ya ha estado allí, para mostrar una descripción más breve (sólo el título) si ya había estado (lo mismo que cuando entra caminando a un lugar).

Durante el proceso que llamaremos "puntuar la llegada" la librería comprueba si la habitación en la que acaba de entrar el jugador es visitada por primera vez. De ser así, le activará el atributo visitado y si la habitación tiene el atributo valepuntos aumentará convenientemente la puntuación del jugador.

Cuando tiene lugar la acción Mirar, o bien cuando ha sido llamada la función JugadorA(lugar,1), la librería, además de "puntuar la llegada", realizará lo que llamaremos "anotar la llegada". Esto consiste en comprobar si la variable localizacion ha cambiado desde la última vez (es decir, el jugador se ha movido a otra habitación, o bien se ha quedado a oscuras si no lo estaba, o bien ha obtenido luz si estaba a oscuras). Si se encuentra que localizacion ha cambiado, se llevarán a cabo las siguientes acciones:

  1. Si la nueva localizacion tiene la propiedad inicial, se imprimirá ésta (si es una cadena) o se ejecutará (si es una rutina).
  2. Se llama a la rutina global LugarNuevo, si existe. Por defecto no existe, pero el programador puede crear una.
  3. Todos los objetos "flotantes" (esto es, los que tienen la propiedad esta_en) se mueven a la nueva localización (si su propiedad esta_en indica que deben aparecer en ella).

El comportamiento del jugador puede cambiarse fácilmente, ya que el objeto jugador puede tener una rutina ordenes como cualquier otro personaje del juego. Para cambiar la rutina ordenes del jugador basta hacer algo como:

  jugador.ordenes=MiReglaNueva;  

donde MiReglaNueva será una nueva rutina ordenes. Observar que esta nueva regla se aplicará a cualquier acción que intente el jugador, y también a todos los comandos que el jugador de a otros personajes. La variable actor contendrá el personaje que está recibiendo la orden (normalmente será el propio jugador) y las variables accion, uno y otro se inicializan en la forma usual. Por ejemplo, si un cañón se dispara cerca del jugador podría ocasionarle una sordera momentánea (el verbo "escucha" dejaría de funcionar), lo cual puede lograrse con una rutina como esta:

[ MiReglaNueva;
  if (actor~=jugador) rfalse;
  Escuchar: "No oyes muy bien todavía debido a ese cañonazo.";
];  

El if que hay al principio garantiza que el sordo es el jugador, y no otro personaje, de modo que un comando como "Helena, escucha", aún seguirá funcionando.

(?) EJERCICIO 42  Podría haberse logrado un efecto parecido usando la rutina reaccionar_antes del jugador, pero hay ocasiones en las que esta rutina no sería lo mejor. ¿Puedes imaginar en cuáles?
(Solución)

(?) EJERCICIO 43  Escribir otra MiReglaNueva que impida al jugador hablar mientras lleva puesta una máscara de gas (por tanto también le impedirá dar órdenes a otros personajes). Este efecto aparece en el juego "Curses"
(Solución)

(!) De hecho se puede hacer un truco mucho más potente: el jugador puede convertirse en otro personaje diferente durante el juego, permitiendo al jugador "auténtico" (el de carne y hueso que está ante el teclado) actuar a través de otro personaje (piensa en juegos multi-personaje como Maniac Mansion). Llamando a la rutina CambiarJugador(objeto) el jugador será transformado en objeto. No es necesario darle al objeto nombres como 'yo' o 'mi' en la propiedad nombres (el parser entiende 'mi' y 'me' como formas de referirse al jugador actual, sea este el objeto que sea). Sin embargo tiene que tener una propiedad llamada numero, no importa qué valor se le de (la librería usa esta propiedad para sus cálculos). También se le puede dar la propiedad capacidad (para indicar el máximo número de objetos que puede transportar).

CambiarJugador no imprime nada especial, así que probablemente debas poner detrás un comando <<Mirar>>.

CambiarJugador tiene muchas aplicaciones posibles. El jugador que ande trasteando con la máquina de transmitir mentes del doctor Frankenstein puede encontrarse súbitamente convertido en el monstruo atado a la mesa. Un jugador que ha bebido demasiado vino puede ser convertido en un objeto jugador_borracho, al que se apliquen diferentes reglas. El jugador puede ser transformado en animal mediante algún conjuro (como en el juego "Spellbreaker"). Más ambicioso: un juego puede tener un almacén de doce o más personajes principales y el foco puede ir cambiando de uno a otro. Por ejemplo el jugador podría tener un equipo de exploradores para recorrer un laberinto y tecleando el nombre de cada miembro puede cambiar el foco entre ellos. En este caso puede ser necesario que la función MasAlla cambie el foco a un miembro vivo de la expedición cuando muere el que tiene el foco.

Si usamos la forma CambiarJugador(otro, 1) (es decir, un 1 como segundo parámetro), entonces el título de las habitaciones incluirá entre paréntesis el nombre del personaje que está siendo controlado, por ejemplo: "En el calabozo (como Manolo)".

(!)(!) Cuando el jugador cambia a otro personaje que a su vez tiene una rutina ordenes, la cosa empieza a complicarse (ya que la orden puede provenir del jugador "real" tras el teclado, o del objeto jugador, y la reacción puede ser diferente en cada caso). Resultará útil ordenar las cosas en la forma siguiente (imaginemos que lo siguiente pertenece al objeto MANOLO, y que el jugador puede "convertirse" en manolo durante el juego):

  ordenes [;
    if (jugador==self)
    {
       ! Este objeto (MANOLO) es el que tiene el foco, es decir
       ! el que está siendo controlado por el jugador de carne y hueso
       if (actor==self)
       {
          ! Y la orden me está siendo dada a mi, por ejemplo
          ! el jugador ha puesto: ``SALTA'' mientras controla a MANOLO
      }
      else
      {
          ! La orden ha sido dada a otro personaje, desde éste
          ! Por ejemplo el jugador ha puesto ``HELENA, SALTA''
          ! mientras controla a Manolo
      }
   }
   else {
     ! La orden proviene de otro personaje (que está siendo controlado
     ! por el jugador ``real'') y ha sido dirigida a Manolo.
     ! Por ejemplo, el jugador ha puesto MANOLO, SALTA mientras
     ! controla a otro personaje.
   }

(!)
(?) EJERCICIO 44  En la tradición de Centro América, un brujo puede transformarse a sí mismo en un nagual, un familiar como por ejemplo un mono-araña. De hecho, cada persona tiene un animal asociado o wayhel que vive en una tierra volcánica sobre la que reina el jaguar. Convierte al jugador en su wayhel.
(Solución)

(!)
(?) EJERCICIO 45  Escribe la rutina ordenes de un gigante "con escrúpulos", de modo que si el jugador pone "Gigante, mata el ratón", se niegue a hacerlo, pero si el jugador se convierte en el gigante, entonces pueda ser tan cruel como desee.
(Solución)

El jugador estará vivo mientras la variable banderafin sea cero. Si se da a esta variable el valor 1, el jugador muere. Si se le da el valor 2, el juego termina con la victoria. Valores por encima de 2 significan formas más exóticas de morir, y en este caso la librería llama a la función MensajeMuerte (que debe ser escrita por el programador) para que imprima el mensaje adecuado (se supone que esta rutina consultará la variable banderamuerte e imprimirá un mensaje diferente según el valor que allí encuentre.

Algunos juegos permiten la reencarnación (o más propiamente dicho la resurrección). Tú también puedes permitirlo programando una rutina llamada MasAlla. Esta rutina es llamada cuando el jugador muere, pero antes de que se muestre el mensaje "Estás muerto". Dentro de esta rutina puedes hacer lo que quieras, incluyendo el volver a poner a 0 la variable banderafin, lo cual causará que el juego prosiga normalmente, en vez de terminar. No obstante ten presente que una función MasAlla suele ser difícil de escribir, ya que debe poner el juego en una situación que sea consistente con lo que ha ocurrido (el jugador ha muerto y resucitado. ¿Qué pasa con sus pertenencias? ¿Qué pasa con el objeto o habitación que le causó la muerte?)


Zak McKraken - spinf@geocities.com

Puntuación y otras yerbasEl modelo del mundo¿Qué hora es?Iniciar, mover, cambiar y matar al jugador