next up previous contents
Next: About this document ... Up: Esquema general de Minë Previous: Contribuir con código   Contents

Subsections

4 Apéndices

Descripción del sistema de conversaciones con los PNJ

Los Personajes No Jugadores tienen su importancia dentro de la ambientación del mundo de la Tierra Media. Son sus residentes naturales, los vecinos con los que puedes mantener una conversación formal pero agradable, y que te pueden revelar algún secreto de la región que estás visitando. A continuación se describe el mecanismo que se incluirá en Minë para hablar con ellos.

El sistema de conversación con los PNJ está ideado para facilitar a los jugadores las tareas de:

Otro objetivo importante es el permitir que los PNJs ayuden a crear un entorno de juego creíble y una historia interesante. La conversación que se puede sostener con un PNJ la creará un Maestro de Lugares, con un mecanismo similar al que se usa para crear habitaciones.

Cada conversación estará centrada en "temas" que tienen asociado un fragmento de diálogo. El jugador, en función de cómo transcurra el diálogo, escoge el siguiente tema por el que quiere preguntar. Normalmente escogerá alguno que se acabe de mencionar, aunque puede preguntar por alguno del que se haya hablado un rato antes, o que no haya salido en la conversación.

Los jugadores dispondrán de los comandos "+decir" y "+preguntar por". Con el comando +decir se supone que el PJ ofrece información que el PNJ no conoce, y con +preguntar (más frecuente) intenta sonsacarle. El estilo literario del texto puede hacer que se consiga un diálogo bastante bueno. Este tipo de conversación se podría adornar con verbos adicionales, sobre todo de comunicación no verbal (+tocar, +abrazar, +pellizcar, +carraspear, incluso +besar!) que pueden ayudar a cambiar el humor del PNJ.

Como muestra, éste es un fragmento del diálogo que se puede mantener con el "Tutor", un PNJ que aparecerá a la entrada del juego para enseñar a los jugadores nuevos los comandos de Minë:

? +decir hola

- Saludos, buen mentor.

- Bienvenido, mi joven aprendiz. ¿Estás preparado para comenzar tu instrucción sobre habilidades de supervivencia en el mundo de la Tierra Media?

- Asientes con admiración y respeto.

- Para hablar conmigo, escribe "+preguntar por", seguido por el tema del que quieras hablar. Con este comando puedes preguntarme sobre cualquier duda que tengas. También puedes escribir "+?" para obtener una ayuda, con un resumen de todo lo que puedes hacer. ¿Has entendido bien?

- Sí, maestro.

- De acuerdo, vamos allá. Pregúntame sobre lo primero que quieras aprender.

? +preguntar por habilidades de supervivencia

- Maestro, ¿qué es lo mas importante para sobrevivir en el mundo de la Tierra Media?

- Lo primero que debes dominar es el funcionamiento de la línea de comandos. No irás muy lejos si no sabes siquiera cómo desplazarte, ¿verdad? También es importante que sepas cómo combatir, y por cierto que deberás aprender el arte de una buena conversación si quieres llegar a alguna parte.

? +preguntar por linea de comandos

- Si escribes texto directamente, dirás en voz alta lo que has escrito, en idioma oestron. Puedes escoger en qué idioma quieres hablar, de todos modos. En cambio, para realizar cualquier acción, primero debes conocer el comando adecuado. Ya conoces "+preguntar por" y "+?". Los comandos empiezan por el signo "+". Todo lo que escribas detrás de este signo es un comando que intentarás realizar.

? +preguntar por ejemplo

- ¿Podrías darme algún ejemplo de manejo de la línea de comandos, mi buen mentor?

El tutor se rasca la cabeza unos instantes, meditando la respuesta.

- Si escribes: "Estoy de buen humor, ¿tú no?", dirás ese texto y te podrán oír todos los que estén en la misma habitación. También puedes escribir el comando: "+preguntar por supervivencia" para comenzar una conversación sobre ese tema.

? +preguntar por combate

- Para atacar a un personaje, escribe "+atacar" y el nombre del personaje. Esto comenzará una pelea. No te recomiendo que empieces un combate a muerte, sin embargo, hasta que llegues a ser un gran guerrero.

? +preguntar por personaje

- Maestro, ¿qué tipo de criaturas me puedo encontrar en mis viajes?

- Es pronto para que te preocupes por eso. Más adelante podrás estudiar este asunto, si te interesa.

? +preguntar por mundo

El tutor parece un poco desorientado por tu pregunta.

- ¿Por qué este mundo se llama Tierra Media, por cierto?

- ¡Ah! Se llenaría un tratado entero para responder con propiedad esa pregunta. ¿Por qué no me pides que te lo explique... en otra ocasión?

Creación de conversaciones

Una conversación estará repartida en varios ficheros de "contexto"; en cada fichero estarán incluidos varios temas fuertemente relacionados. Puedes pensar que un contexto es como una habitación: mientras hables de temas parecidos permaneces en el mismo contexto, y si preguntas por algo no directamente relacionado, te mueves a otro contexto. El diálogo se debe diseñar como un edificio, lleno de habitaciones y recovecos por explorar. Un diálogo puede ser pequeño y confortable como la sala de estar de un hobbit, o profundo y extenso como el palacio de un Señor Enano.

Lo más importante a destacar es que un mismo tema puede aparecer en distintos contextos. Si el jugador pregunta por ese tema, obtendrá primero la respuesta contenida en el contexto actual, o la del contexto más cercano. También se puede partir el texto asociado a un tema en varios fragmentos sucesivos. De esta forma se consigue que se pueda preguntar varias veces por un mismo tema y obtener respuestas diferentes en cada ocasión, haciendo avanzar el diálogo.

Para que el escritor tenga control sobre qué texto se va a mostrar en un momento dado, dispondrá de al menos estos 2 mecanismos:

  1. Aislamiento de los temas. Los temas estarán agrupados en contextos. Si el jugador cambia bruscamente de contexto, se activará la respuesta por defecto del tema solicitado; pero si se mantiene preguntando por tópicos del mismo contexto, se pueden ir activando respuestas preparadas más sutilmente, que formen una línea argumental de diálogo. El atributo de inteligencia del PJ debería permitir detectar, como si fuesen objetos ocultos, los temas de conversación más relacionados con el que se está diciendo ahora mismo. Esto representa que los personajes más inteligentes pueden encontrar más fácilmente los matices en la conversación con el PNJ, y aprenden qué es de lo que más le interesa hablar. Así, un jugador con un PJ inteligente podrá mantener mejores diálogos con los PNJs que uno tonto.
  2. Estado previo del diálogo: memoria, humor del PNJ, y requisitos. No se debería repetir dos veces un mismo fragmento de texto. Se debe registrar si de este tema se hablado ya, y en ese caso mostrar un texto alternativo de entre varios. Al acceder a ciertos items de texto se pueden definir hitos en el diálogo, indicando que el jugador ha descubierto algo de información. Puede haber items ocultos que sólo se presenten si se ha alcanzado un hito concreto, o items que dependan de requisitos (características del jugador, presencia de algún objeto en la sala...). Algunos de estos hitos pueden representar distintos estados de ánimo del PNJ (alegre, miedoso, enfadado...) y estar almacenados en una variable que se cambie cuando el escritor quiera.
El siguiente es un ejemplo de cómo crear un contexto de conversación:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>

<!DOCTYPE contextodeconversacion SYSTEM "mine_conversacion.dtd">

<contexto version="1.0" autor="Hizgael" pnj="tutor" id="tutor-cortesia">

<tema nombre="saludos" accion="decir">

   <sinonimo>hola</sinonimo>

   <sinonimo>buenos días</sinonimo>

   <item>

     <pregunta>Saludos, buen mentor. </pregunta>

     <respuesta>Bienvenido, mi joven aprendiz. ¿Estás preparado para comenzar tu instrucción sobre habilidades de supervivencia en el mundo de la Tierra Media? </respuesta>

     <entorno><tu>Asientes</tu><otros><pj/> asiente</otros> con admiración y respeto. </entorno>

     <respuesta>Para hablar conmigo, escribe "+preguntar por", seguido por el tema del que quieras hablar. Con este comando puedes preguntarme sobre cualquier duda que tengas. También puedes escribir "+?" para obtener una ayuda, con un resumen de todo lo que puedes hacer. ¿Has entendido bien? </respuesta>

     <pregunta>Sí, maestro. </pregunta>

     <respuesta>De acuerdo, vamos allá. Pregúntame sobre lo primero que quieras aprender. </respuesta>

     <relacionado contexto="tutor-topicos" nombre="supervivencia"/>

     <relacionado contexto="tutor-comandos" nombre="linea de comandos"/>

   </item>

   <item>

     <pregunta>¡Hola de nuevo!</pregunta>

     <respuesta>¿Cuántas veces me piensas saludar hoy, jovenzuelo?</respuesta> </item>

</tema>

</contexto> 

Este contexto contiene un sólo tema, con dos items de texto. El segundo ítem sólo aparecerá si vuelves a preguntar por el mismo tema, en este caso el tema "saludos". Se pueden definir sinónimos para detectar las distintas palabras que el jugador puede usar para referirse al tema.

Cada ítem puede tener asociado un conjunto de temas relacionados, que a pesar de estar en otro contexto tienen relación con lo que se dice en el texto. Si el personaje pregunta por un tema que no está en el mismo contexto ni está relacionado con los items utilizados, la pregunta está "fuera de contexto" y el personaje no jugador se extrañará por el cambio brusco del diálogo.

Confianza entre el PNJ y los PJs

Otra idea importante es la de que la conversación dependa del grado de confianza del PNJ con cada uno de los personajes de la sala. El PNJ tendrá un humor (o 'ánimo') base, que al inicializarse depende de los personajes presentes en la sala. Por ejemplo, el posadero puede empezar la conversación de mal humor porque la taberna se le ha llenado de enanos (este posadero, ha salido un poco racista).

El humor cambiará a mejor o peor, como efectos por activar items de texto específicos. También bajará (¡mostrando mensajes de ambientación como efecto secundario!) si el PJ cambia constantemente entre temas no relacionados; esto favorece que los jugadores procuren mantenerse "dentro de contexto" y mejora mucho la apariencia de realidad del diálogo.

Además, si un PJ hace subir el humor, la confianza del PNJ en él aumenta, o si le estorba o dice algo raro, disminuye. La confianza inicial en cada personaje estará en proporción con su atributo de Carisma. Ciertos contextos o items de la conversación sólo serán accesibles si la confianza en el PJ está por encima de un umbral.

Salas llenas de gente

¿Cómo se comporta el sistema de conversaciones con varios jugadores acosando a preguntas al PNJ desde varios frentes? Los diálogos hacen mejor efecto cuando un solo jugador habla con el PNJ.

El efecto confianza puede ayudar a resolver este problema. El PNJ sólo tocará los textos más delicados (es decir, que requieren una secuenciación correcta), si los PJ hablan de uno en uno. Además, sólo se dirigirá en este caso al PJ con el que tenga más confianza. Esto aproxima la conversación a un diálogo entre dos personajes.

Otra idea para mejorar esto es que, si varios jugadores hablan a la vez, el PNJ sólo responda a aquél con el que ya estaba hablando, o bien con el que tenga más confianza. Esto último refuerza la ambientación de la característica Carisma: los PNJs tenderán a hablar con los PJ más carismáticos.

Iniciativa de los PNJ

El personaje no jugador puede tener su propia agenda de intereses. Al tocar un cierto tema, se puede despertar su curiosidad por algún otro relacionado. Si el jugador no pregunta por este otro tema posteriormente, el PNJ tomará la iniciativa y lo introducirá en la conversación ('¿Te he dicho ya que maté 80 orcos en la Batalla de los 5 Ejércitos?'), en cuanto el diálogo decaiga.

Además, el incluir temas con la iniciativa del PNJ puede valer para que reaccione a palabras clave de los diálogos entre los PJ, sin que resulte demasiado forzado. Por ejemplo, si el grupo de jugadores se pone a discutir a voz en grito sobre el Nigromante en medio de la posada, seguro que alguno de los aldeanos intervendrá en la conversación para recriminarles. Para hacer esto, no hace falta que el sistema sea capaz de entender el lenguaje natural de los mensajes entre jugadores; basta que reaccione a la palabra clave "Nigromante".

Este sistema puede forzar a que los jugadores hablen con el PNJ más interesante de la sala, si antes les había pasado desapercibido.

Efectos especiales durante la conversación

Los diálogos entre PJ y PNJ deberían estar plagados de 'frases de ambientación' que reflejen la actitud que presentan los personajes frente a cómo se está desarrollando el diálogo; o que refuercen el efecto dramático de los pasajes más importantes. Por ejemplo, cuando Gandalf lee en el Concilio de Elrond el texto inscrito en el Único en Lengua Negra, todos los presentes en la sala se estremecen, y un velo de oscuridad parece cubrir el sol.

Estos 'trucos de ambientación' son especialmente efectivos si se refieren a posturas y expresiones de los personajes. Si aparecen frecuentemente durante el diálogo, se evita el efecto de bustos parlantes, personajes entre los cuales sólo se intercambia texto. Al describir su actitud corporal, la ambientación se enriquece y la credibilidad aumenta.

Las frases de ambientación no necesariamente deben estar ligadas a un ítem de texto concreto; habrá un mecanismo para que la frase se pueda activar automáticamente en momentos claves del diálogo, por ejemplo cada vez que el humor del PNJ cambia, o bien cuando desciende por debajo de un cierto umbral.

En realidad, este mecanismo de efectos especiales debería estar disponible para ser utilizado fácilmente en todos los comandos del juego: uso de objetos, magia, movimiento, combate... La diferencia entre Petria y Minë puede estar en que, en el combate, en vez de 'El monstruo de la cueva te pega un zurriagazo. Estás malherido' el mensaje que se muestre sea de tipo: 'El Trasgo Maloliente hace girar su bastón nudoso sobre su cabeza. Intentas esquivarlo echándote a un lado, pero dada la estrechez de la sala no consigues apartarte lo bastante rápido y el garrotazo te alcanza en el cuerpo. ¡Aï! ¡Ese último golpe parece haberte dejado sin respiración!'

Cómo construir una sala

Abrimos un editor de textos cualquiera del que podamos estar seguros que será capaz de guardar en formato TXT simple. Nosotros recomendamos siempre el uso de software libre.

Para los que deseen saber qué es lo que escribirán exactamente, podemos decir que se trata de un fichero XML. Un fichero XML es un documento con un lenguaje interno que nos permite conocer luego los elementos que lo conforman. La sintaxis puede resultar algo extraña para un profano pero no es necesario entenderla para escribir correctamente un fichero de éstos correctamente.

Datos generales en toda sala

Nada más comenzar a escribir colocamos 'de regalo' estas dos líneas:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>

<!DOCTYPE saladeMine SYSTEM "mine_sala.dtd">  

No importa qué sala vayas a hacer, estas dos líneas aseguran que nuestro programa pueda dar por válido o no tu fichero.

Una vez escritas esas dos líneas, ponemos:

<sala version="1.0" autor="Aranarth" area="moria" comentario="una sala de prueba">  

en donde cada uno puede cambiar tanto el autor como el área pero no la version (¡ojo! NO poner tildes en area="loquesea"). Lo de version="1.0" dejadlo así, es una manera de que el programa no se haga líos según vayamos evolucionando el formato de este fichero. Cada vez que se haga un cambio aumentaremos el número de versión, y el programa se negará a cargar ficheros con una versión distinta a la que él entiende. Para no desaprovechar el trabajo realizado, normalmente proporcionaremos un script para convertir automáticamente los ficheros a las nuevas versiones (si es posible hacerlo). Esto lo decimos para que la gente no se lleve a engaño y crea que version="1.0" se refiere a la versión de su sala... Si deseáis realizar algún comentario, hacedlo en el campo -opcional- de comentario="" (ej: comentario="Sala de pruebas, intento de tener una sala con personajes no jugadores"). No confundir tampoco con la version del lenguaje XML de la primera línea del fichero.

Bien. Lo siguiente es bastante sencillo.

<id>moria-entrada01</id>  

dentro de <id></id> habréis de poner un texto que no contenga espacios y que identifique de forma unívoca al fichero en donde se guarda la sala. Para ello, la regla es que escribáis

nombre_de_area-nombre_de_sala.  

Es decir, dos partes separadas por un guión ''-'', la primera coincide con el nombre del área que hemos puesto arriba, y la segunda es un nombre que no se repite dentro de ese área. En cada nombre se pueden usar únicamente letras, números y el signo ''_'' para separar palabras.

Importante: el nombre del fichero que estáis editando será SIEMPRE el id de la sala + la coletilla '.xml'. Éste puede ser un buen momento para guardar el archivo con el nombre indicado.

Si existe un área llamada "poblado" y creéis que la posada del poblado se merece un área para ella sola, indicadlo escribiendo poblado_posada en el campo área de todas las salas que pertenezcan a la posada del poblado. La parte del id de una sala que se refiere a la sala en sí también puede contener más de dos palabras pero siempre separadas por guiones bajos (a modo de espacios), como por ejemplo; piso01_cuarto02. Con lo que el id completo resultaría ser:

<id>poblado_posada-piso01_cuarto02</id>  

Al principio puede costar un poco acostumbrarse pero con el tiempo veréis que es mucho más inteligente para llevar buena cuenta de las áreas y las salas.

Un área puede ser una construcción grande (+20 salas) o un pueblo, o una sección de un camino muy largo, etc. En general se apela al sentido común de la gente. No puede haber áreas de 5 salas porque sería fragmentar demasiado todo. Recomendamos que las áreas tengan un mínimo de 30 salas aunque hay casos particulares en donde podemos bajar a 20.

Ahora viene algo bastante fácil, el nombre 'normal' de la sala, lo que aparecerá como título del lugar a los visitantes.

<nombre>la entrada a Moria</nombre>  

Intentad que se quede en menos de 6 palabras pero que sirva de referencia. El nombre debe contener un artículo y empezar por minúscula, ya que será mostrado de la forma "Estás en la entrada a Moria".

La descripción de la sala

Ahora nos encontramos algo más largo pero que es a la vez lo más importante, sin duda. La descripción de la estancia en sí.

<descripcion>

   <item>Una gran sala se aparece ante ti. Tanto el techo como las paredes son de color rojizo oscuro y notas que la atmósfera es bastante húmeda debido, sin duda, a las filtraciones de agua del cercano lago. Tres columnas impiden que la estancia se derrumbe.</item>

   <item dificultad='12'>Hace tiempo que nadie limpia por aquí.</item>

</descripcion>  

Vayamos por partes. Lo primero que has de notar es que hemos escrito <descripcion>. Exacto, nos hemos metido en el 'modo descripción'. Es aquí donde se demuestra la habilidad descriptiva del Maestro de lugares porque ha de tener en cuenta los siguientes elementos.

  1. La descripción ha de estar comprendida entre 3 y 10 líneas a ser posible.
  2. Esta descripción ha de ser intemporal y no depender de ninguna futura circunstancia. Nada de 'un enorme orco de da la bienvenida' porque no sabemos cuánto tiempo va a durar ese pobre orco ahí (poco, lo más probable) y quedaría muy mal que la gente leyese algo que no es verdad. Tampoco alusiones a objetos que se puedan coger son bienvenidas por el mismo motivo. Quizá en versiones posteriores de Minë esto pueda modificarse pero de momento no es posible. Entended que hemos de ir por partes.
  3. Ha de provocar al viajante una sensación global del lugar.
Si leéis los dos 'items' dentro de <descripcion></descripcion> veréis que uno lleva un dificultad='12' y el otro no. ¿Por qué? Digamos que una sala siempre tiene un <item> sin dificultad que se le aparecerá a cualquier jugador que entre ahí mientras que aquellos <item> con dificultad aparecerán impresos sólo a aquellos personajes que superen una tirada interna de percepción del programa. Para que os hagáis una idea de a qué equivalen ciertos valores en la dificultad ahí va una tabla resumen orientativa.

Dificultad de los items descriptivos en una sala:

0 Para eso no pongas dificultad. Lo ve todo el mundo por muy cegato que esté.
10 Hombre, con un poco que se fije uno aparece.
20 Se podría decir que uno debe tener buen ojo para ver esto
30 La cosa se complica pero con mucha atención se acaba descubriendo.
40 Aquí aparece una barrera natural. Mucha gente no superará esta dificultad hasta que sume bastante experiencia.
50 Difícil aunque un elfo no tendría muchos problemas.
60 Aquí el humano corriente puede abandonar porque se dejaría los ojos antes que descubrir la descripción extra.
70 Aquí los elfos tienen ya problemas serios para ver algo.
80 Esta descripción se reserva para Istari en la práctica.
90 Gandalf tendría serios problemas.
100 Reservado a Maiar de alto linaje.

Para que os hagáis más idea aún, diremos que en igualdad de tiempo jugado, de un grupo de humano, elfo, orco, hobbit o enano en los primeros niveles tendríamos que un humano apenas pasaría del 30, el elfo lograría quizá llegar al 50 en contadas ocasiones, el orco como el humano o un poco más, el hobbit como el humano y el enano se queda en el 40.

Podéis poner tantos items descriptivos como queráis, con o sin dificultad pero intentad que el resultado final no sea excesivo o inundaréis de letras la pantalla del jugador (con la consiguiente desgana lectora de éste)

Las salidas en una sala

Importante: los siguientes datos se refieren a las posibles salidas. se recomienda que se relacionen items de descripción con alguna salida. De vez en cuando colocad el mismo valor de dificultad en aquellos <item> y salidas relacionados. Luego pondremos un ejemplo.

Esto es bastante simple pero hay que entenderlo bien porque es lo que relaciona esta sala con el resto de ellas.

<salidas>

   <oeste id="moria-cocina01">la cocina</oeste>

   <este dificultad='12' id="moria-salon01">el salon</este>

   <norte id="moria-cuartucho08">un cuartucho oscuro</norte>

   <sur id="moria-entrada01">la entrada</sur>

   <arriba id="moria-bano01">el baño</arriba>

   <abajo></abajo>

   <otro id="moria-tunel01" tipo_cierre="cerradura" datos_cierre="moria-llave_de_tunel01"

       mensaje_cerrado="una reja con un candado bloquea el paso"> un estrecho [tunel]</otro>

</salidas>  

Importante: También son válidas las salidas 'noreste, noroeste, sureste y suroeste'.

Analicemos esto detenidamente.

lo primero es escribir <salidas> (y lo último </salidas>). Entremedias, y en este caso, tenemos 7 -siete- posibles direcciones a las que ir. Escribe tan sólo aquellas que de verdad existan o déjalas vacías.

Por ej: <abajo></abajo> quiere decir que no hay nada hacia abajo. Para eso, simplemente no lo escribas.

Cojamos la primera salida de nuestro ejemplo:

<oeste id="moria-cocina01">la cocina</oeste>  

<oeste <- esto indica que se refiere a la sala a la que entraremos si nos dirigimos al oeste (a la izquierda en un mapa) ¡Haced un dibujo antes!

<oeste id="moria-cocina01" <- el id es el identificador de la sala que hay en esa dirección. Coincide con el nombre del fichero (sin el .xml) que contiene la información, y con el párrafo <id>...</id> de dicho fichero.

<oeste id="moria-cocina01">la cocina</oeste> <- Escribid en medio algo descriptivo que pudiese dar una idea al personaje de lo que hay en esa dirección. Puede coincidir exactamente con el verdadero nombre de la sala al oeste o puede que no. Por ejemplo, si Kloin el enano está vagando por los túneles de Moria y llega a una bifurcación del camino oeste-este puede que el este aparezca como "Al este divisas un pasadizo oscuro"

<este id="moria-pasadizo87">un pasadizo oscuro</este>

y el oeste como "Al oeste divisas un pasadizo con [restos] humanos"

<oeste id="moria-pasadizo88">un pasadizo con [restos] humanos</oeste>

Si Kloin el enano decide ir hacia el oeste se encontrará con que ha entrado en "La Antesala de Mazarbul" que, desde lejos, parecía un simple 'pasadizo con restos humanos'.

Los jugadores también pueden usar la primera palabra de la descripción para moverse (exceptuando artículos: el, la, los, las, un, uno, una, unos, unas). En el ejemplo anterior es lo mismo decir "+sur" que "+entrada". Si no interesa la primera palabra, o hay varias salidas que repiten, se puede indicar otra rodeándola entre corchetes. En el caso que tenemos aquí, "+pasadizo" seria igual que "+este", y "+restos" seria "+oeste". Ojo, solo puede haber una palabra entre corchetes, sin espacios. Esto es imprescindible si se usan salidas con dirección <otro>.

Bien. también está la dificultad. Si creéis que una de las salidas no es visible a simple vista podéis poner un dificultad="37" que se aplicará de la misma forma que los items de la descripción de antes.

Un personaje que sea capaz de ver un ítem de descripción de dificultad='35' podrá ver cualquier salida con dificultad igual o menor a 35. Así que un combo descripción-salida puede ser el siguiente:

<item dificultad="26">Arriba alcanzas a ver una trampilla</item>

...

<arriba id="tharbad-herrero_cuartito03" dificultad="26">una trampilla</arriba>  

cada uno en su respectivo sitio dentro del fichero, claro. No abuséis mucho de las dificultad=' '. Usadlo con mesura. Se trata de la Tierra Media, no de un laberinto oscuro. Una salida con dificultad por sala es una auténtica burrada. Una por cada diez salas, aceptable, una por cada 20, correcto. Por otro lado, un personaje incapaz de ver una salida, podrá cruzarla si sigue a otro que pueda.

Finalmente, tenemos los cierres. Las salidas normalmente se pueden transitar libremente, pero a veces nos podemos encontrar puertas con candado o algún otro tipo de obstáculo. De ello trata el tipo_cierre, que por el momento puede tener los siguientes valores:

Si ponemos un tipo de cierre distinto de "ninguno", pondremos también datos_cierre, que sera:

Y no nos queda más que mensaje_cerrado, con el texto que le aparecerá al jugador si intenta pasar y no puede.

Ejemplos de cierre podrían ser:

<norte id="xxxx" tipo_cierre="horario" datos_cierre="10-20" mensaje_cerrado="el guardia te dice 'el puente está cerrado, no se puede entrar en la ciudad hasta las 10'">  

<norte id="xxxx" tipo_cierre="magia" estado="cerrado" datos_cierre="bloquear_portal"

     mensaje_cerrado="hay una puerta fuertemente cerrada, no parece que haya medios de abrirla">  

Propiedades globales de la sala

Ahora pasamos a una de las partes más sencillas, más rápidas y que más vida le dan al juego.

<propiedades tipo='caverna' subtipo ='entrada' volumen='25' luz='06' aura='56' combate="si"

       ocultabilidad='30'/>  

A simple vista parece sencillo rellenar este campo. Y lo es, para qué negarlo.

Estas 'propiedades' se refieren a atributos muy específicos de la sala en la que estamos y la elección de los valores determinará mucho de lo que pueda acontecer en ella.

Vayamos uno por uno.

Objetos en la sala

Y llegamos a los objetos, otra de las partes más interesantes de una sala. En principio un objeto o lo tiene un personaje o lo tiene una sala. Cada <objeto> tiene un id="identificativo", una cantidad mayor que 1 (si no se especifica se sobreentiende que es 1) y una dificultad de encontrarlo (se aplica el mismo criterio que arriba) aparte, naturalmente, de un breve texto o una palabra que haga referencia a él.

<objetos>

<objeto id="pocion01" cantidad="3">una poción recuperadora</objeto>

<objeto id="espada02" probabilidad="15" maximo="3">una espada brillante</objeto>

<objeto id="pocion02" cantidad="2" dificultad="14">una poción curativa</objeto>

</objetos>  

El texto o palabra descriptivo (lo que se encuentra dentro de los signos > y < ) no ha de ser necesariamente el texto 'verdadero' del objeto aunque sí tiene que ver algo con él.

Una espada herrumbrosa no debería hacer referencia al fichero id="vino34", por ejemplo. Pero una poción élfica reconstituyente sí podría verse a simple vista como una 'poción vitalizante' que hace referencia oculta al fichero con id="pocion_elfica02". Es decir, el personaje verá sólo aquellos objetos con una dificultad aceptable (si un objeto no dispone de dificultad se sobreentiende que se ve a simple vista) y de éstos, sólo la descripción y la cantidad. Si un personaje decide recoger un objeto, automáticamente descubrirá su nombre verdadero pero no sus efectos hasta que no lo examine (a no ser que ya lo sepa porque haya tenido previamente uno de ellos) , y aún así podría no conocerlo todo sobre el objeto en cuestión hasta que no se decida a usarlo. Además, la probabilidad marca la facilidad (de 1 a 100) de que aparezca espontáneamente ese objeto en la sala cuando entra un personaje). Esto sirve para lugares en donde de vez en cuando aparecen hierbas curativas o pequeños trozos de pan, etc. Hay que usar esto con mucho cuidado. Recordad que la cantidad marca el número inicial de regalo de esos objetos, una vez que se acaben se comenzará a aplicar la probabilidad que será 0 si no pusiste tal atributo. El maximo indica el tope de número de ese objeto que puede generarse en esa sala. Tened en cuenta que si hay una probabilidad alta de que aparezca un objeto al entrar un personaje, al cabo de unos días aquello podría ser imposible de transitar. Si colocamos un maximo="3" nos aseguramos que nunca se superará esa cantidad para ese objeto en particular y esa sala. Si no colocas un máximo, se sobreentiende el valor inicial que aparece en la sala. Si el máximo es 0, no hay límite y la cantidad puede crecer indefinidamente ¡cuidado!.

En cualquier caso, cada objeto tiene un fichero y tendrás que leerte el apéndice Cómo fabricar un objeto para entender del todo cómo funcionan.

La descripción del objeto sigue las mismas normas que el <nombre> de un objeto, tal como se explica en el apéndice mencionado.

Personajes no jugadores (en construcción)

Y por último nos encontramos con los encuentros de personajes no jugadores.

<encuentros>

<encuentro id="unicornio" probabilidad="20" dificultad="30">un unicornio</encuentro>

<encuentro id="orco" probabilidad="15" cantidad="2" maximo="4">un orco</encuentro>

</encuentros>  

Un encuentro se compone de -id-, que es el fichero en donde residen sus datos, una -probabilidad- que indica la facilidad con la que puede aparecer 'mágicamente' en el lugar (de 0 a 100 siendo 0 imposible y 100 todo el rato que alguien entre en la sala), una -dificultad- que marca la fácil o difícil que es descubrir al encuentro en la sala y -cantidad- que indica el valor inicial del número de ese tipo de encuentros y el posterior número de unicornios u orcos que mágicamente pueden aparecer cuando entre un personaje en la sala. Si se omite la probabilidad, se sobreentiende 0 y si se omite la cantidad se sobreentiende 1. El máximo funciona igual que en los objetos. Luego está la descripción genérica para que sepáis cómo hacer referencia a ellos en vuestras acciones de compra-venta, charla o combate.

Finalmente...

Y por último.

</sala>  

Guardad este fichero como uno de tipo xml.

ejemplo: moria-entrada01.xml

Bien, un texto completo quedaría tal que así:

-----------

<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>

<!DOCTYPE saladeMinë SYSTEM "mine_sala.dtd">

<sala version="1.1" autor="Hirunatan" area="moria" comentario="pruebas">

<id>moria-entrada01</id>

<nombre>la sala nueva</nombre>

<descripcion>

   <item>Una sala nueva se aparece ante ti. Tanto el techo como las paredes son de color rojizo oscuro y notas que la atmósfera es bastante húmeda debido, sin duda, a las filtraciones de agua del cercano lago. Tres columnas impiden que la estancia se derrumbe.</item>

   <item dificultad='12'>Hace tiempo que nadie limpia por aquí.</item>

</descripcion>

<salidas>

   <oeste id="moria-cocina01">la cocina</oeste>

   <este dificultad='12' id="moria-salon01">el salon</este>

   <norte id="moria-cuartucho01">un cuartucho oscuro</norte>

   <sur id="moria-entrada02">la entrada</sur>

   <arriba id="moria-bano01">el baño</arriba>

   <otro id="moria-tunel01" tipo_cierre="cerradura" datos_cierre="moria-llave_de_tunel01"

          mensaje_cerrado="una reja con un candado bloquea el paso"> un estrecho [tunel]</otro>

</salidas>

<propiedades tipo='caverna' subtipo ='entrada' volumen='25' luz='56' aura='56' combate="si"

    ocultabilidad='30'/>

<objetos>

   <objeto id="pocion01" cantidad="3">una pocion recuperadora</objeto>

   <objeto id="espada02" probabilidad="20" maximo="3">una espada brillante</objeto>

   <objeto id="pocion02" cantidad="2" dificultad="14">una pocion curativa</objeto>

</objetos>

<encuentros>

   <encuentro id="unicornio" probabilidad="20">un unicornio</encuentro>

   <encuentro id="orco" probabilidad="15" dificultad="36" cantidad="3" maximo="4">un orco</encuentro>

</encuentros>

</sala>

-----------

Lo que un personaje estándar vería, por ejemplo, sería algo como:

Estás en la sala nueva:

*********

Una sala nueva se aparece ante ti. Tanto el techo como las paredes son de color rojizo oscuro y notas que la atmósfera es bastante húmeda debido, sin duda, a las filtraciones de agua del cercano lago. Tres columnas impiden que la estancia se derrumbe.

Hace tiempo que nadie limpia por aquí.

*********

Al oeste ves la cocina

Al este ves el salón

Al norte ves un cuartucho oscuro

Al sur ves la entrada

Hacia arriba ves el baño

También ves un estrecho [tunel]

Aquí se encuentran:

un unicornio

un orco

Galran el elfo

Aquí hay:

una pocion recuperadora (3)

una espada brillante

una pocion curativa (2)

?

------------

Consejos

  1. Sé coherente. primero escribe la descripción general, luego las especiales y luego las propiedades, asegúrate que el sentido común impera. Un baúl en un sitio con luz="75" y ocultabilidad="2" no puede tener dificultad="70" porque es que se ve a simple vista.
  2. No hagas lugares generadores de monstruos. hacer algo como <encuentro id="orco03" probabilidad="95" cantidad="10">orco enorme</encuentro> sólo tiene sentido en mitad de Mordor.
  3. Para los caminos o lugares cuya descripción es muy repetitiva no te comas la cabeza, copia varias veces el mismo fichero, retoca el nombre de ese trozo del camino y hacia adonde apuntan las salidas y poco más.

    ejemplo:

    Estás en un lugar del camino de Bree:

    *******

    Un trozo de camino igual que tantos otros. Algo de vegetación y surcos de ruedas en la blanda tierra.

    *******

    Al norte ves que el camino sigue.

    Al sur ves que el camino sigue.

    No encuentras nada.

    Aquí no hay nadie.

    ?

    ---

    cuyo fichero sería algo como:

    -------------

    <?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>

    <!DOCTYPE saladeMinë SYSTEM "mine_sala.dtd">

    <sala version="1.0" autor="Aranarth" area="camino_bree">

    <id>camino_bree-camino34</id>

    <nombre>un lugar del camino de Bree</nombre>

    <descripcion>

       <item>Un trozo de camino igual que tantos otros. Algo de vegetación y surcos de

       ruedas en la blanda tierra.</item>

    </descripcion>

    <salidas>

       <norte id="bree-camino35">que el camino sigue</norte>

       <sur id="bree-camino33">que el camino sigue</sur>

    </salidas>

    <propiedades tipo='campo' subtipo ='llanura' volumen='30' luz='66' aura='58' combate="si"

         ocultabilidad='13'/>

    <objetos> </objetos>

    <encuentros> </encuentros>

    </sala>

    ---------

  4. Intenta no forzar a que la gente escriba con tildes porque si bien los creadores de este juego defendemos la ortografía creemos que dificultaría el disfrute de gente con teclados americanos. Por lo tanto los objetos o cualquier encuentro o lo que sea que haya que escribir su nombre no debe tener ni tildes ni nuestra preciada eñe. En lugar de la eñe, escribid una simple 'n'.
  5. Todos los atributos que sean dificultad="3" o atributo="constitucion" DEBEN tener comillas en los valores. Serán no válidos cosas como aura=3 ó volumen=34, cuidad que las comillas son las mismas y no se os escapa una mezcla como ocultabilidad='3", por ejemplo.
  6. Ningún <id> debe contener '.xml' al final. sólo el fichero en donde se guardan esos datos.

Cómo fabricar un objeto

Lo primero es abrir un editor de textos simple con un nombre del estilo de abrigo03.xml o pocion_elfica11.xml, etc.

Inicialmente

Escribimos estas dos líneas tal cual.

<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>

<!DOCTYPE objetodeMine SYSTEM "mine_objeto.dtd">  

luego escribimos esta línea modificando en cada caso el autor. El comentario y el área son opcionales (el área raras veces se escribe ya que los objetos son móviles y no parece que tengan que pertenecer a un área concreta).

<objeto version="1.0" autor="Hirunatan" comentario="una prueba que se me ha ocurrido" area="poblado">

Datos generales

Ponemos <id></id> y entremedias el nombre del fichero que estamos editando y que corresponde al identificador del objeto SIN .xml.

<id>pocion01</id>  

luego ponemos entre <nombre> y </nombre> una par o tres de palabras por el que queremos que se conozca nuestro objeto (es mucho mejor sin tildes)

<nombre>una pocion recuperadora</nombre>  

El nombre del objeto normalmente empezará por un artículo, ya que en las listas de objetos aparecerá algo así: ''Aquí hay una pocion recuperadora''.

La primera palabra (que no sea artículo) del nombre servirá para que los jugadores se refieran a ese objeto cuando esté dentro de una lista. Por ejemplo, un jugador puede escribir +beber pocion para usar el objeto del ejemplo.

Si queremos usar otra palabra que no sea la primera, o varias palabras, las rodearemos por un par de corchetes [ ]. En el caso anterior, si queremos que el usuario tenga que escribir +beber recuperadora, escribiremos:

<nombre>una pocion [recuperadora]</nombre>

Descripción

Llega la descripción. ponemos <descripcion> y luego tantos <item>'s como queramos (mínimo 1). No hay que poner muchos, con uno basta, aunque si queremos poner algún ítem secreto podemos hacerlo especificando una dificultad='nn' como aparece en el ejemplo de abajo.

<descripcion>

<item>Se trata de un elixir fabricado a partir de hojas frescas de diversas plantas y que devuelve un poco de vitalidad a la persona que la ingiere.</item>

<item dificultad="40">Devuelve hasta 15 pv. si se conoce Hierbas</item>

</descripcion>  

Propiedades generales

Y llegamos a las propiedades generales. Para aura consúltese el Apéndice Cómo construir una sala. volumen: lo que ocupa. desde 0 (despreciable) hasta infinito. Una caja de zapatos ocupa volumen='0.2'. volumen='1' es como un humano adulto así que con esa referencia debería valer.

<propiedades tipo="metal" categoria="recipiente" aura="65" volumen="0" peso="0.05" cargas="1" valor="10" estado="100"/>  

Usos

Llamamos uso a una forma concreta de utilizar el objeto. Una espada puede empuñarse o arrojarse (dos usos), una botella puede beberse, arrojarse o empuñarse (tres usos) y así con muchos objetos.

La sintaxis de los usos va como sigue:

<usos>

   <uso tipo=''xxx'' posicion=''yyy'' gasto=''zzz'' msg=''descripción del uso'' duracion=''nnn''>

      <requisito atributo=''xxx'' valor=''nnn'' msg=''mensaje de error si el requisito no se satisface''/>

      ...

      <efecto atributo=''xxx'' valor=''+/- nnn'' duracion=''nnn'' msg=''Descripción del efecto''/>

      ...

   </uso>

   ...

</usos>

Como puede apreciarse, un objeto puede tener varios usos y cada uso puede tener ninguno o varios requisitos y ninguno o varios efectos. Los tipos posibles para el uso son: comer, beber, poner (ponerse una pieza de ropa, un collar, un anillo, etc), lanzar (algo que se arroja y golpea, causando daño) y usar (uso genérico, como en un artefacto mecánico). El uso ``lanzar'' puede ser obviado ya que todo objeto es lanzable. Minë calculará unos requisitos y efectos genéricos para el objeto cuando se desee lanzar. Sin embargo, Minë no realizará estos cálculos automáticos si encuentra un uso de tipo 'lanzar' explícito en el fichero descriptivo del objeto.

Las diferentes posiciones en las que un objeto se puede poner son: cabeza, cuello, tronco, brazo-izq, mano-izq, brazo-der, mano-der, dos-manos, pierna-izq, pierna-der, pie-izq, pie-der (para los otros usos no es necesario indicar posición). Naturalmente, un arma puede empuñarse tanto con la mano derecha como con la izquierda así que pondremos dos usos diferentes para las dos manos. Suponiendo que los PJs son todos diestros (aunque esto es fácilmente cambiable) tendremos que los requisitos de destreza con la mano izquierda serán mayores y el efecto en el combate será menor.

El gasto es el número de cargas que gasta este uso. 0 = no gasta. * = gasta todas las que resten. Si se cumplen los requisitos pero no hay suficientes cargas para un uso concreto Minë avisará al jugador.

La duración en el efecto se refiere al número de segundos que dura el efecto (pon 0 si es definitivo, o no pongas duración=''). El tiempo lo lleva el servidor de Minë así que será independiente de los ordenadores de los jugadores. En el momento en el que un uso activa una cuenta atrás, Minë se hace cargo del tiempo y avisará cuando el efecto haya pasado (si es menester). La duración en el uso se refiere al tiempo que existe ese uso con ese objeto. Esto permite añadir usos a objetos durante el juego mediante habilidades especiales (encender una antorcha, por ejemplo).

Los requisitos pueden pedir ciertos valores mínimos a los atributos: Fuerza, Destreza, Constitución, Inteligencia, Sabiduría, Carisma, luz y Aura. Los efectos incluyen estos atributos y añaden: Vida, Ataque y Defensa.

En nuestro ejemplo particular:

<usos>

   <uso tipo=''beber'' gasto=''1'' msg=''Bebes un elixir revitalizante''>

      <requisito atributo=''destreza'' valor=''3'' msg=''Eres demasiado torpe para beber la poción''/>

      <requisito atributo=''aura'' valor=''47'' msg=''Te quema la lengua. No puedes beberla''/>

      

      <efecto atributo=''vida'' valor=''+15'' msg=''Te sientes mucho mejor. Has recobrado parte de tu vitalidad''/>

      

   </uso>

</usos> 

Como vemos, este objeto requiere una mínima coordinación cabeza-mano (destreza='3') y un aura aceptable (aura='47'). Si se cumplen estos requisitos, la vida subirá 15 puntos. Es posible que personajes con habilidades especiales puedan sacar más partido a esta poción.

Uniendo todos los pedazos de nuestro fichero descriptor del objeto pocion01, tenemos:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>

<!DOCTYPE objetodeMine SYSTEM "mine_objeto.dtd">

<objeto version="1.0" autor="Aranarth">

 <id>pocion01</id>

 <nombre>una pocion recuperadora</nombre>

 <descripcion>

   <item>Se trata de un elixir fabricado a partir de hojas frescas de diversas plantas y que devuelve un poco de vitalidad a la persona que la ingiere.</item>

   <item dificultad="40">Devuelve hasta 15 pv.</item>

 </descripcion>  
<propiedades aura="65" volumen="0" peso="0.05" cargas="1" valor="10" estado="100"/>

 <usos>

   <uso tipo=''beber'' gasto=''1'' msg=''Bebes un elixir revitalizante''>

      <requisito atributo=''destreza'' valor=''3'' msg=''Eres demasiado torpe para beber la poción''/>

      <requisito atributo=''aura'' valor=''47'' msg=''Te quema la lengua. No puedes beberla''/>

      

      <efecto atributo=''vida'' valor=''+15'' msg=''Te sientes mucho mejor. Has recobrado parte de tu vitalidad''/>

      

   </uso>

 </usos>

</objeto>

Normas de diseño de código fuente en Minë

Diseño por contrato

Tipos Abstractos de Datos

Según esta técnica, cada clase representa un Tipo Abstracto de Datos, en el sentido matemático: es decir, una pieza de información, con propiedades (o atributos), y operaciones que realizan cálculos sobre esas propiedades o cambian el valor de las mismas. El interfaz de la clase debe coincidir con el T.A.D., y el resto de la clase debe ser oculto (privado).

ejemplo
una Sala es una habitación o lugar del juego. Sus propiedades son el id, autor, nombre, volumen, personajes que contiene, etc. Sus operaciones son crear una sala nueva, entrar y salir un personaje, etc.

En Python, el mapa entre T.A.D. y clase no está perfectamente definido, pero grosso modo, las propiedades corresponden a los atributos públicos, y las operaciones a las funciones miembro, públicas también. La parte privada de la clase no tiene reflejo en el T.A.D., y no debe ser conocida por ningún otro trozo de código.

ejemplo
Sala.id, Sala.autor, etc. son atributos, y Sala.__init__(), Sala.entrar_personaje(), etc. son funciones miembro.

Requisitos de las propiedades: dominios e invariantes

Las propiedades deben cumplir una serie de requisitos. Por un lado, el DOMINIO o conjunto de valores que puede tomar (es decir, el tipo: string, int, etc.).

ejemplo
El dominio del id de una Sala son los números enteros (int), el del autor son las cadenas de caracteres (string), etc.

En Python, los tipos existen pero no son declarados (es un lenguaje dinámicamente tipado), e incluso una variable puede adoptar valores de distintos tipos. Esto puede ser cómodo en proyectos pequeños, pero en los medianos o grandes, hay que indicar los tipos en el interfaz, y para ello se pueden usar los strings de documentación. Estoy buscando una forma más o menos estándar de hacerlo, pero de momento lo haremos así (si un atributo puede tener distintos tipos, se comenta también, pero no es algo tan frecuente):

> class Sala:

> """<descripción de la clase, una línea>

>

> <descripción más larga>

>

> Contiene los siguientes atributos:

> - id (string): <descripción>

> - luz (int): <descripción>

> [...]

> """

Por otro, las propiedades tienen restricciones o condiciones que deben cumplirse siempre. A estas condiciones se les denomina INVARIANTES. Una instancia cuyas propiedades cumplen todas las invariantes es una instancia válida. NO SE ADMITEN INSTANCIAS NO VÁLIDAS EN NINGÚN MOMENTO, excepto durante la creación de la instancia o la ejecución de una única de sus funciones miembro públicas. A la salida de cualquier función miembro pública, el código debe asegurar que ninguna invariante se ha roto, en ningún caso (esto no es necesario en las privadas).

ejemplo
son invariantes Sala.area != None, aura in range(0,100), n_jugadores >= 0, n_jugadores <= len(personajes), etc. El __init__() debe dar valores a todos los atributos que satisfagan todas las invariantes. No se admite, por ejemplo, crear una sala con area == None, y luego darle un valor más tarde. Sí se admite que el __init__() la inicialice a None y más tarde llame a una función que lee el área de un fichero y actualice el valor, siempre y cuando todo ello ocurra dentro de la ejecución de __init__().
En Python no hay ningún mecanismo para expresar invariantes, así que lo haremos también en la documentación. También estoy buscando una forma estándar. De momento será como sigue. Durante la depuración, si se quiere verificar algunas invariantes, se puede usar la instrucción assert justo antes del return de todas las funciones (no hacerlo sistemáticamente con todas, porque puede cargar mucho).

> class Sala:

> """[...]

> [...]

> Invariantes:

> id != None

> aura in range(0,100)

> n_jugadores <= len(personajes)

> [...]

> """

>

> def entrar_personaje(self, personaje):

> [...]

> assert self.n_jugadores <= len(self.personajes)

>

> def salir_personaje(self, personaje):

> [...]

> assert self.n_jugadores <= len(self.personajes)

Requisitos de las operaciones: declaración, precondiciones y postcondiciones

Las operaciones también tienen requisitos. Por un lado, está la DECLARACIÓN (el nombre y tipo de los parámetros, y el tipo de valor devuelto).

ejemplo,
la operación "entrar personaje en una sala" tiene un parámetro que es la sala y otro que es el personaje que entra; sus tipos son las clases Sala y Personaje. No devuelve ningún valor.

En Python los parámetros vienen explícitos, y los tipos se pueden poner en el comentario, si no son obvios. Pueden ser obvios en los siguientes casos: si el nombre coincide con el de una clase, el tipo es esa clase; si coincide con el de un atributo de la clase actual, el tipo es el mismo que el del atributo; si el tipo es int o string, en muchos casos queda claro con sólo el nombre. Lo mismo con el valor de retorno.

> def entrar_personaje(self, personaje):

> """[...]

> self(Sala) - obvio, el self siempre está claro

> personaje(Personaje) - obvio, mismo nombre que clase

> """

>

> def mensaje_filtrado(self, mensaje, idioma, oyente):

> """[...]

> mensaje(string) - puede ser obvio, no hay clase mensaje así que

> será un string

> idioma(Idioma) - obvio, nombre de clase

> oyente(Personaje) - en principio no es obvio, pero se sabe

> por la descripción del método

>

> Devuelve string - puede ser obvio también por la descripción

> """

Las PRECONDICIONES son requisitos que hay que cumplir antes de llamar a una operación. Pueden referirse a los parámetros de la operación o a las propiedades de la clase. Su comprobación es responsabilidad del código llamante (lo puede hacer bien explícitamente, con algún if, o bien apoyándose en una invariante o postcondición). La función debe asumir que las precondiciones se cumplen, y no debe volverlas a chequear. Así se asegura que cada chequeo se realiza sólo una vez, y se evitan redundancias.

ejemplo,
la sala tiene una invariante que dice que el aura es mayor que 0. Si el constructor lee los datos de la sala de un fichero, al leer el aura debe comprobar que cumple la invariante, y si no, dar un error y no crear la sala. A partir de ahí, todo el resto del código asume que el aura es mayor que 0, y se puede pasar como parámetro a una función que tenga esto como precondición.
En Python las precondiciones las colocaremos en el texto del comentario, de la

siguiente manera. Durante la depuración, también se puede usar assert para

comprobar algunas precondiciones, justo al principio de la función:

> def salir_personaje(self, personaje):

> """[...]

> Requiere:

> personaje != None

> personaje in self.personajes.values()

> [...]

> """

> assert personaje in self.personajes.values()

Las POSTCONDICIONES son requisitos que una operación se compromete a asegurar que se cumplen una vez que la misma haya terminado con éxito. Pueden referirse a las propiedades de la clase o al valor de retorno, si lo hay. El código llamante no debe volverlos a chequear. En cierta forma, las postcondiciones representan la información semántica de la operación (su utilidad prevista), frente a la información sintáctica de la declaración.

ejemplo,
la operación salir personaje de una sala asegura que si se completa con éxito, el personaje ya no está dentro de la sala.
En Python, se colocan de forma similar a las precondiciones. Si se usa el assert, se puede poner justo antes de volver, o en el código llamante justo después de hacer la llamada:

> def salir_personaje(self, personaje):

> """[...]

> Asegura:

> personaje not in self.personajes.values()

> """

El contrato

El conjunto de requisitos de propiedades y operaciones se conoce como el CONTRATO del T.A.D. Se llama así porque se asemeja a un contrato real: existe un proveedor (la clase), clientes (cualquiera que lea sus propiedades o use sus operaciones) y cláusulas (los requisitos).

Igual que en un contrato real, cada parte se compromete a cumplir su obligación, y hay un sistema para tratar los incumplimientos. El cliente se compromete a asegurar las precondiciones. Si no se puede cumplir alguna de ellas, no debe llamar a la operación en ningún caso. Una función no debe añadir código para protegerse contra precondiciones no cumplidas (puede permitirse incluso dejar el ordenador colgado o matar el programa si quiere), ya que nunca se va a dar el caso cuando el programa esté depurado (durante la depuración se puede usar assert).

El constructor de la clase debe asegurar todas las invariantes. Si no es posible cumplir alguna de ellas, debe lanzar una EXCEPCIÓN y abortar la creación de la instancia. En ese caso el cliente debe tirar la instancia a medias sin usarla.

Finalmente, las operaciones de la clase se comprometen a verificar tanto las invariantes como las postcondiciones. Si no pueden cumplir alguna, se debe lanzar una EXCEPCIÓN. En ese caso, puede que algunas postcondiciones estén cumplidas y otras no (no se puede asegurar), pero al menos la instancia tiene que seguir siendo válida y la operación tiene que restaurar todas las invariantes que puedan estar temporalmente deshabilitadas.

Las excepciones no son un mecanismo de control de flujo. Sólo deberían ocurrir en caso de incumplimiento de invariantes o postcondiciones, y en casos excepcionales (tipo disco duro lleno, datos corruptos, versiones incompatibles, etc.). Para situaciones que puedan ocurrir en una ejecución normal del programa (por ejemplo, el usuario introduce un nombre que no existe, se ha llegado al final de una lista, etc.) es mejor usar condiciones explícitas (con if, while, etc.). Del mismo modo, las excepciones sólo se deben capturar en dos casos: cuando haya que restaurar alguna invariante, y luego seguir pasando la excepción hacia arriba, o cuando se llegue a un punto en el que se pueda volver a intentar la operación. En particular está prohibido capturar una excepción y luego hacer return normal, devolviendo un valor falso o que no cumple las postcondiciones.

Descripción formal de los ficheros de salas y objetos

Un DTD (Document Type Definition) es la plantilla que especifica de manera formal el contenido de un fichero XML, para que un programa lo pueda leer. Si no sabes XML, no es necesario que entiendas estas plantillas, son útiles para los colaboradores que quieran participar en la parte de código que trata los ficheros.

DTD de una sala


<?xml version="1.0" standalone="no"?>

<!ELEMENT sala (id,nombre,descripcion,salidas,propiedades,objetos,encuentros)>
<!ATTLIST version autor area #REQUIRED comentario #IMPLIED>

<!ELEMENT id (#PCDATA)>

<!ELEMENT nombre (#PCDATA)>

<!ELEMENT descripcion (item+)>
<!ELEMENT item (#PCDATA)>
<!ATTLIST dificultad #IMPLIED>

<!ELEMENT salidas (oeste?,este?,norte?,sur?,noroeste?,noreste?,suroeste?,
                   sureste?,arriba?,abajo?,otro?)>
<!ELEMENT oeste (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT este (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT norte (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT sur (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT noroeste (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT noreste (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT suroeste (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT sureste (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT arriba (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT abajo (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>
<!ELEMENT otro (#PCDATA)>
<!ATTLIST id #REQUIRED dificultad tipo_cierre estado datos_cierre
          mensaje_cerrado #IMPLIED>


<!ELEMENT propiedades (#PCDATA)>
<!ATTLIST volumen luz ocultabilidad tipo #REQUIRED aura combate
          subtipo #IMPLIED>

<!ELEMENT objetos (objeto*)>
<!ELEMENT objeto (#PCDATA)>
<!ATTLIST id #REQUIRED cantidad maximo probabilidad dificultad #IMPLIED>

<!ELEMENT encuentros (encuentro*)>
<!ELEMENT encuentro (#PCDATA)>
<!ATTLIST id #REQUIRED cantidad maximo probabilidad dificultad #IMPLIED>

DTD de un objeto


<?xml version="1.0" standalone="no"?>

<!ELEMENT objeto (#PCDATA)>
<!ATTLIST version autor #REQUIRED comentario area #IMPLIED>

<!ELEMENT id (#PCDATA)>

<!ELEMENT nombre (#PCDATA)>

<!ELEMENT descripcion (item+)>
<!ELEMENT item (#PCDATA)>
<!ATTLIST dificultad #IMPLIED>

<!ELEMENT propiedades (#PCDATA)>
<!ATTLIST peso volumen aura valor tipo #REQUIRED estado categoria
          cargas #IMPLIED>

<!ELEMENT usos (uso*)>
<!ELEMENT uso (requisito*,efecto*,#PCDATA)>
<!ATTLIST tipo posicion gasto msg #REQUIRED aplicable #IMPLIED>
<!ELEMENT requisito (#PCDATA)>
<!ATTLIST atributo valor msg #REQUIRED>
<!ELEMENT efecto (#PCDATA)>
<!ATTLIST atributo valor msg #REQUIRED elemento #IMPLIED>

next up previous contents
Next: About this document ... Up: Esquema general de Minë Previous: Contribuir con código   Contents
Pablo Ruiz 2002-08-25