![]() | ![]() | ![]() | Cómo extender o redefinir la librería |
Para hacer esto, tu juego necesitará crear una "clase" para los amuletos. Llamemosla por ejemplo Amuleto. Entonces, la forma de comprobar si un objeto dado (por ejemplo, el indicado en la variable uno) es un amuleto sería:
if (uno ofclass Amuleto) ... |
El hechizo concreto asociado con el amuleto (es decir, lo que ocurrirá al usar el amuleto) podría estar almacenado en la propiedad efecto_amuleto. Posibles valores de esta propiedad serían:
efecto_amuleto "El amuleto se desintegra con un puf.",
efecto_amuleto [;
if (localizacion == laoscuridad)
{
give localizacion_real luz;
"La estancia se ilumina con una luz sobrenatural.";
}
],
efecto_amuleto HabitacionOculta,
efecto_amuleto [;
return random(HabitacionDePlomo, HabitacionDePlata,
HabitacionDeOro);
],
|
El proceso de activar el amuleto X y desencadenar los efectos oportunos se reduce tan solo a enviarle el mensaje
X.efecto_amuleto(); |
y esta activación puede retornar el valor false si no ha ocurrido nada, true si ha ocurrido algo, o bien retornar un objeto que sería la habitación a la cual debe ser teletransportado el jugador. A continuación un ejemplo de cómo se manejaría todo esto:
[ UsarAmuletoSub destino;
if (uno ofclass Amuleto)
{
if (~~(uno provides efecto_amuleto))
"[¡Hey! Olvidaste programar el efecto de este amuleto.]";
destino=uno.efecto_amuleto();
switch(destino)
{
false: "No ocurre nada.";
true: ; ! No hacemos nada especial
default: print "Eres teletransportado mágicamente hasta...^";
JugadorA(destino);
}
}
else "Sólo puedes utilizar el verbo ~USA~ con un amuleto.";
];
|
Una extensión elaborada de la librería definirá muchas nuevas clases, gramáticas, acciones y definiciones de verbos. Todo esto podría ser empaquetado en un fichero de apellido .h y almacenarse con los demás ficheros de la librería, para ser incluido con Include en los juegos que lo necesiten.
![]() ![]() | Si dentro de ese fichero usas la directiva System_file; entonces sería posible incluso que los juegos que incluyan esta extensión puedan reemplazar (usando Replace) algunas de las rutinas proporcionadas en ella. Ver más adelante. |
![]() |
Las propiedades definidas en la librería (como descripcion
o al_e), se llaman "Propiedades comunes". Son especiales
por la siguiente razón: si un objeto O no da ningún valor
a la propiedad común P, la propiedad O.P puede ser
examinada de todas formas sin que ocurran errores, si bien no se le
puede dar ningún valor. Esto no podría hacerse con las propiedades
inventadas para tu juego (como efecto_amuleto, es decir,
si intentas ver lo que vale efecto_amuleto para un objeto
en el cual no se haya escrito esta propiedad, el juego generará un
error al ser jugado. En las propiedades comunes, todos los objetos
tienen la propiedad definida a un valor por defecto (por ejemplo, la
propiedad no_puedes_ir tiene como valor por defecto la
cadena de texto "No puedes ir por ahí.", para todos los objetos
que no den valor a esta propiedad.
Los valores por defecto de las propiedades pueden ser cambiados durante el juego, usando la rutina CambiarDefecto. Por ejemplo, en un estadio más avanzado del juego podrías poner:
Por supuesto no puedes cambiar los valores por defecto de las propiedades "inventadas", ya que éstas no tienen valor por defecto. |
![]() ![]() |
Las propiedades comunes también son ligeramente más rápidas a la
hora de hacer operaciones con ellas. El único inconveniente de las
propiedades comunes es que su número está limitado. 63 en total, de
las cuales la librería ya usa más de la mitad. Para indicar que una
propiedad es una "propiedad común", debes usar la directiva
Property. Por ejemplo:
En los dos últimos casos estás dando además su valor por defecto. En el primer caso el valor por defecto será 0. |
Normalmente no se necesita hacer grandes cambios en la librería. Es mucho más frecuente que simplemente quieras cambiar los mensajes por defecto, como por ejemplo el mensaje "No hay nada en venta" que se genera para la acción Comprar, o el mensaje "Cogido." que aparece ante la acción Coger.
Esto es muy fácil de hacer, como se describe a continuación. Debes crear un objeto llamado MensajesLibreria, y su definición hay que ponerla entre la línea Include "EParser"; y la línea Include "Acciones";. Este objeto no necesita tener nombre ni descripción ni nada de esto. Tan sólo debe tener la propiedad antes y en ella se especifican los mensajes por defecto para cada acción. Por ejemplo:
Object MensajesLibreria
with antes [;
Saltar: "Saltas, y por unos instantes flotas inútilmente en
la gravedad cero de la Estación Espacial Alfa.";
Encender:
if (ml_n==3)
{
print "Conectas la alimentación ", (del) ml_o, ".";
}
];
|
Este objeto nunca aparecerá físicamente en el juego, por supuesto. La idea es que su regla antes es consultada por la librería antes de imprimir ningún mensaje. Si el objeto MensajesLibreria retorna false, entonces la librería mostrará su mensaje estándar. Si retorna true, no imprimirá nada, suponiendo que el objeto ya ha impreso un mensaje apropiado.
Observando el ejemplo anterior, vemos que la acción Saltar simplemente imprime un mensaje, pero otras acciones (como Encender) necesitan imprimir un mensaje diferente según la situación particular (el caso extremo es la acción Coger, que puede generar hasta 13 mensajes diferentes, según el caso). La variable ml_n contiene un número que indica el mensaje concreto. Los posibles valores de ml_n y el mensaje estándar asociado a cada caso se muestra en un apéndice. Es posible que futuras ampliaciones de la librería añadan más números, pero se respetará la numeración de los que ya existían.
Un mensaje de la librería especialmente útil es el "prompt", cuyo
valor habitual es "^>" (es decir, retorno de carro seguido de
>). Ese texto es impreso ante la acción Prompt (es
una acción ficticia que existe sólo con este propósito). De esta forma
el prompt del juego puede hacerse sensible al contexto, o bien
puede quitarse la línea en blanco que se genera tras cada turno.
![]() | La acción Prompt se genera sólo durante el transcurso normal del juego, pero no en la lectura directa del teclado ni en preguntas de tipo si/no o en la elección REINICIAR/RESTAURAR/ABANDONAR. |
EJERCICIO 47 |
El juego "The Witness" de Infocom tenía un prompt que decía:
"¿Qué harás ahora, detective?" en el primer turno, pero sólo
"¿Ahora qué?" en los siguientes. Programa esto. (Solución) |
![]() ![]() |
Una forma divertida de ver en acción el sistema de mensajes es
escribir:
en tu juego (nota ocultista: la variable sw__var, "variable switch", contiene en este caso el número de acción). Otro efecto divertido es simplemente retornar true, dando lugar a un juego alarmantemente silencioso. |
![]() ![]() |
Observar que MensajesLibreria puede usarse como una forma
retorcida de añadir reglas extra al final del proceso de las
acciones, ya que nada te impide hacer procesamiento real dentro de
ella (esto es usado por ejemplo para implementar habitaciones en
penumbra). Más comúnmente lo usarás para hacer que los mensajes del
juego sean más sensibles al contexto, de forma que el mensaje "No
hay nada en venta" puede convertirse en "Ese no es un artículo en
venta", mientras el jugador esté dentro de una tienda.
|
La propia librería está escrita en el lenguaje Inform, por lo que en teoría es posible modificarla. Y en la práctica no es tan complicado, con un poco de experiencia. Pero modificar los ficheros de la librería no es muy elegante y puede ser difícil después recordar dónde hicimos los cambios. Así que aquí tienes el último recurso: averigua qué rutina de la librería es la que te da los problemas (la que querrías cambiar) y reemplázala con otra usando la directiva Replace. Por ejemplo, si ponemos la directiva:
Replace QuemarSub; |
en tu fichero, antes de incluir los ficheros de la librería, entonces Inform ignorará la definición de QuemarSub cuando la encuentre en ficheros de librería (ficheros que lleven la directiva System_file). Así que podrás definir tu propia QuemarSub. Lo habitual será que copies la definición que estaba en la librería (en este caso estaría en el fichero accionm.h, que es donde están todas las rutinas de manejo de acciones), la "pegues" en tu juego, y hagas las modificaciones deseadas sobre la versión "pegada".
La rutina más frecuentemente reemplazada es DibujarLineaEstado. En la sección sección sobre ensamblador tienes varios ejemplos.
![]() ![]() | Inform te deja incluso reemplazar mediante Replace algunas funciones "hardware", como random, que normalmente serían convertidas directamente en código Z. Obviamente reemplazar algo como child por una rutina software causaría una ralentización notable de la ejecución, y un ligero aumento en el tamaño del código. Reemplazar random, sin embargo, puede ser útil para fijar el generador de números aleatorios, de cara a probar el juego. |
![]() | ![]() | ![]() | Cómo extender o redefinir la librería |