En la sección sobre temporización vimos cómo funcionaba el modelo de tiempo de AGE, basado en unidades de tiempo y en propiedades cuyo método update
se activa cuando su contador de tiempo llega a cero. En esa sección, vimos algunos ejemplos de cómo usar ese mecanismo para definir entidades con comportamientos que dependieran del tiempo. Pero, además de los que nosotros añadamos, en AGE ya existen comportamientos definidos por defecto que dependen del tiempo, que son los asociados a las acciones de las criatura, como coger un objeto o moverse en una dirección. Todas las acciones que llevan a cabo las criaturas consumen un tiempo, y la cuenta de este tiempo se lleva en el temporizador de una propiedad llamada “state”.
Por ejemplo, como jugadores, cuando AGE nos acepta una orden de entrada, es porque ha llegado a cero el temporizador de “state” de nuestro personaje jugador. Si tecleamos “ir norte”, AGE cambiará el valor de “state” a un valor de estado (que se verá más adelante) que indica que nos estamos moviendo, y fijará el temporizador al número de unidades de tiempo que nos consuma ir hacia el norte. Una vez llegado el temporizador a cero, esto significa que ya hemos terminado de ir hacia el norte y AGE esperará otra orden de entrada, que de nuevo cambiará el valor y temporizador de “state”, y así sucesivamente.
Por lo tanto, el método update
que define AGE por defecto para la propiedad “state” de los jugadores es muy importante, porque es nada menos que el que consigue que al ejecutar una aventura monojugador, ésta nos vaya pidiendo órdenes y ejecutándolas una por una. En una aventura multijugador o que cuente con personajes complejos que realicen acciones, el temporizador de esta propiedad será el que se encargue de entrelazar correctamente las acciones: por ejemplo, si ir al norte desde una localidad a otra consume tres unidades de tiempo y coger un objeto consume una unidad de tiempo, el jugador A podrá coger tres objetos en el tiempo en el que el jugador B va al norte (la manera concreta en la que los jugadores perciben esto en los modos síncrono y de tiempo real se trató en la sección de temporización).
En la presente sección veremos en detalle cómo funciona esta propiedad especial “state” (y otra asociada, llamada “target”) y qué podemos hacer con ellas.
Las criaturas (objetos de la clase Mobile
) tienen una propiedad especialmente importante llamada “state” (estado). La importancia de la propiedad “state” radica en que esta propiedad es la que define qué cosa está haciendo una criatura en cada momento, y su temporizador es el que indica cuánto tiempo tardará en hacerlo.
Asociada a la propiedad “state” aparece a veces otra propiedad, llamada “target”, que nos proporciona información extendida sobre el estado. Así, por ejemplo, si en un instante dado del juego la criatura Pepito está yendo de la sala sur a la sala norte, su propiedad “state” en ese momento valdrá Mobile.MOVING
(valor que indica que se está moviendo) y su propiedad “target” contendrá un identificador de la sala norte. 1)
El manejo de las propiedades “state” y “target” ha de considerarse un tema avanzado, pues en la mayoría de los juegos no hace falta manipularlas. Sólo debería ser necesario en aventuras en las que se quiera tener un control fino del combate o de la temporización de eventos.
En la siguiente tabla se muestran los valores que puede tomar, para cualquier criatura, la propiedad “state”, así como su significado y el uso de la propiedad “target” para ese estado. Nótese que gran parte de los estados, aunque no todos, están relacionados con el combate y se tratarán en más detalle en la sección Combate y armas de esta documentación.
Valor de “state” | Significado de “state” | Significado de “target” |
---|---|---|
Mobile.IDLE | Estado por defecto. Ojo: el nombre (IDLE, ocioso) está mal puesto, pues no tiene por qué significar que la criatura esté ociosa. Se puede utilizar para denotar que la criatura está llevando a cabo cualquier acción no contemplada en los otros estados. Por ejemplo, es el estado que tiene una criatura que está cogiendo o dejando un objeto. | |
Mobile.MOVING | La criatura está moviendose de una habitación a otra. El temporizador de “state” indica cuántas unidades de tiempo quedan hasta que se complete el movimiento. En el momento en que se completa es cuando la criatura cambia realmente de habitación, y se imprimen los mensajes como “Fulano se va al norte” o “Fulano llega desde el sur”. | Habitación destino |
Mobile.ATTACKING | La criatura está lanzando un ataque contra otra criatura. Cuando el temporizador llegue a cero, el ataque impactará al enemigo (si no ha sucedido antes algo que lo impida, como que la criatura reciba un golpe). | Criatura que recibirá el ataque |
Mobile.BLOCKING | La criatura está preparando un bloqueo. Cuando el temporizador llegue a cero, la criatura pasará a estar “en guardia” (Mobile.READY_TO_BLOCK ) y si le llega un ataque, será bloqueado. | |
Mobile.READY_TO_BLOCK | La criatura está bloqueándose, con un escudo o arma alzada para parar un ataque enemigo. | |
Mobile.DODGING | La criatura está echándose a un lado para intentar esquivar un ataque. Si el temporizador llega a cero antes de que se reciba el ataque, se considerará que le ha dado tiempo a esquivar. | |
Mobile.READY_TO_DODGE | La criatura está echándose a un lado para intentar esquivar un ataque, y ha pasado el tiempo suficiente para considerar que le da tiempo a esquivar, sin que el ataque haya llegado. | |
Mobile.ATTACK_RECOVER | La criatura está recuperándose después de haber lanzado una estocada o golpe. Hasta que el temporizador del “state” llegue a cero, no podrá emprender otra acción. | |
Mobile.BLOCK_RECOVER | La criatura está recuperándose después de haber parado un golpe. Hasta que el temporizador del “state” llegue a cero, no podrá emprender otra acción. | |
Mobile.DAMAGE_RECOVER | La criatura está recuperándose después de haber recibido un golpe. Hasta que el temporizador del “state” llegue a cero, no podrá emprender otra acción. | |
Mobile.DODGE_RECOVER | La criatura está recuperándose después de haber llevado a cabo una esquivada con éxito. Hasta que el temporizador del “state” llegue a cero, no podrá emprender otra acción. | |
Mobile.DYING | La criatura está cayendo muerta. Este estado siempre dura una unidad de tiempo nada más, y luego se pasa al estado Mobile.DEAD . | |
Mobile.DEAD | La criatura está muerta. | |
Mobile.SURPRISE_RECOVER | La criatura está recuperándose de una sorpresa o interrupción. | |
Mobile.DISABLED | La criatura está desactivada y no reaccionará ante nada, ni recibirá entradas si es un jugador. Este estado se usa, por ejemplo, cuando el jugador que controlaba un personaje en una aventura multijugador se ha caído o desconectado. | |
Mobile.CASTING | La criatura está lanzando un conjuro. | Entidad a la que se le lanza el hechizo, si la hay |
He aquí lo que sucede por defecto en AGE cuando el temporizador del estado de una criatura llega a cero, a no ser que nosotros como programadores redefinamos el método update
para que haga algo distinto con la propiedad “state”:
Valor de “state” | Reacción de las criaturas | |
---|---|---|
Mobile.IDLE | Tomar decisión | |
Mobile.MOVING | Tomar decisión | |
Mobile.ATTACKING | Se lleva a cabo el ataque y se pasa a Mobile.ATTACK_RECOVER | |
Mobile.BLOCKING | Se pasa a Mobile.READY_TO_BLOCK | |
Mobile.READY_TO_BLOCK | Se refresca el estado hasta que llegue el ataque enemigo, y en ese momento se pasa a BLOCK_RECOVER o DAMAGE_RECOVER según el resultado | |
Mobile.DODGING | Se pasa a Mobile.READY_TO_DODGE | |
Mobile.READY_TO_DODGE | Se refresca el estado hasta que llegue el ataque enemigo, y en ese momento se pasa a DODGE_RECOVER o DAMAGE_RECOVER según el resultado | |
Mobile.ATTACK_RECOVER | Tomar decisión | |
Mobile.BLOCK_RECOVER | Tomar decisión | |
Mobile.DAMAGE_RECOVER | Tomar decisión | |
Mobile.DODGE_RECOVER | Tomar decisión | |
Mobile.DYING | Se pasa a Mobile.DEAD | |
Mobile.DEAD | Se mantiene el estado (salvo para jugadores, que se pasa a Mobile.IDLE, para que puedan teclear comandos desde el limbo si la aventura lo soporta) | |
Mobile.SURPRISE_RECOVER | Tomar decisión | |
Mobile.DISABLED | Se mantiene el estado | |
Mobile.CASTING | Se pasa a IDLE |
Los casos en los que esta tabla dice “Tomar decisión” quiere decir que la criatura tiene la iniciativa y puede en ese momento emprender una nueva acción. Esto tiene un significado distinto según si la criatura es un jugador o no:
Mobile.IDLE
.Por supuesto, podemos sobreescribir el método update de los personajes no jugadores definiendo comportamientos más complejos, y así obtener criaturas que se muevan, sigan rutas, cojan objetos, desempeñen tareas, etc.
Como programadores de aventuras, el uso más evidente de la propiedad “state” es el de comprobar lo que está haciendo una criatura. Por ejemplo, si queremos saber si un personaje llamado Manolo que está en nuestra habitación ha empezado a irse hacia otra, podríamos hacer algo como:
if ( equals ( get(mobile("Manolo"),"state") , Mobile.MOVING ) ) { self.say("¡No te vayas aún, Manolo, que todavía me quedan cosas que contarte!\n"); }
Además, con room(get(mobile(“Manolo”),“target”))
podemos obtener la habitación a la que se está moviendo Manolo, y con getTime(mobile(“Manolo”),“state”)
tendremos el número de unidades de tiempo que le faltan para llegar a ella (véase la sección sobre temporización).
Aparte de utilizar la propiedad “state” para comprobar el estado de una criatura, los programadores más osados pueden querer redefinir lo que sucede en el método update
para la propiedad “state” y de ese modo cambiar la manera en la que se comporta una criatura en los cambios de estado. Estos cambios pueden potencialmente ir desde modificaciones puntuales hasta cambios radicales que, por ejemplo, modifiquen totalmente la manera en la que se resuelven los cambios de estado tipo “Tomar decisión” cambiando todo el sistema de parseado de AGE por otro sistema totalmente distinto. Por supuesto, sólo los programadores avanzados o con mucha práctica en AGE y con interés en personalizarlo deberían utilizar estas características, que no son para nada necesarias para hacer un buen juego con AGE.
room(fulano.get(“target”)
). Probablemente la propiedad “target” pase a contener nombres únicos, en lugar de dichos identifiadores enteros, en futuras versiones de AGE.