#!/usr/bin/env python
# encoding: iso-8859-15
#
#Minë. Mundo Interactivo-Narrativo en Español [Tierra-Media]
#Copyright (C) 2002  Pablo Ruiz Múzquiz
#
#
#This program is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 2 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#
#Fichero: PersonajeNoJugador.py

"""Clase PersonajeNoJugador."""

import logging
import os
import random

from utils import *
import Personaje
import Idioma
import Objeto
import Modulo
import xmlutils

log = logging.getLogger("PNJ")

# Version del sistema de descripciones de pnj (se incrementa cada vez que cambia
# el formato de los ficheros de desc_pnjs)
VERSION_DESC_PNJS = '1.0'

DIR_DESC_PNJS = 'desc_pnjs'
EXT_DESC_PNJS = '.xml'

# Contador para ir asignando ids a los pnjs nuevos
__contador_de_ids = 0


class PersonajeNoJugador(Personaje.Personaje):
    """Cualquier personaje no controlado por un jugador.

    Los PNJs siempre tienen un controlador activo, excepto cuando son guardados a disco
    al volcarse junto con una sala. Al ser recuperados, se les vuelve a acoplar
    inmediatamente un controlador.

    Opcionalmente puede guardar el documento xml leido del fichero, esto es válido
    para editores de PNJs.
    
    Invariantes adicionales sobre los atributos de la clase base:
        id tiene formato "id_fichero%clave_unica"
        controlador != None
    """

    # Atributos públicos de la clase

    def __leer_autor(self): return self.__autor

    autor = property(__leer_autor,
                     doc="""(string): nombre del autor del fichero de descripcion.

		         Invariantes:
			     autor != None
		         """)

    def __leer_area(self): return self.__area

    area = property(__leer_area,
                    doc="""(string): id del área por la que se mueve este pnj (si está vacío,
		        puede moverse por cualquier área).

			Invariantes:
			    area != None
			""")

    def __leer_tipo_controlador(self): return self.__tipo_controlador

    tipo_controlador = property(__leer_tipo_controlador,
                                doc="""(string): descripcion del tipo de controlador.

				    Invariantes:
					tipo_controlador in ['estandar', 'hablante']
				    """)

    def __leer_datos_controlador(self): return self.__datos_controlador

    datos_controlador = property(__leer_datos_controlador,
                                 doc="""(string): información para configurar el controlador.

				     Invariantes:
					 datos_controlador != None
				     """)


    def __leer_intocable(self): return self.__intocable

    intocable = property(__leer_intocable,
                         doc="""(string): si vale 'si', al pnj no se le puede matar.

			     Esto no me convence nada, habrá que repensarlo mejor...

			     Invariantes:
				 intocable in ['si', 'no']
			     """)

    def __leer_contadores(self): return self.__contadores

    contadores = property(__leer_contadores,
			  doc="""({string:int}): cada contador es un nombre asociado a
			      un número, que se puede acceder libremente desde guiones.

		              Invariantes:
                                  contadores != None
		              """)

    def __leer_etiquetas(self): return self.__etiquetas

    etiquetas = property(__leer_etiquetas,
			 doc="""({string:string}): cada etiqueta es un nombre asociado a
			     un valor de texto, que se puede acceder libremente desde
			     guiones.

		             Invariantes:
                                 etiquetas != None
		             """)

    # Constructor

    def __init__(self, id, sala, nombre, descripcion, experiencia, nivel, vida,
                 volumen, estado, aura, tipo_controlador, datos_controlador, conversacion,
		 atrib, idiomas, idioma_base, dinero, autor, area, intocable, 
		 contadores, etiquetas):
        """Crea un nuevo personaje no jugador a partir de sus atributos.

        Requiere:
	  Los atributos satisfacen todas las invariantes
        """

	# Atributos privados:
	#
	# __tipo_controlador (string): determina de qué tipo será el controlador automático.
	# __datos_controlador (string): información adicional para crear el controlador.
	# __conversacion (preguntar, decir, especiales): conjunto de módulos que responden a los
	#   sucesos de conversación (cuando un PJ pregunta por un tema, dice un tema o ocurre
	#   un suceso especial). Es una tupla con tres valores, y cada valor es un diccionario
	#   que corresponde el nombre del tema con el módulo a ejecutar.

        Personaje.Personaje.__init__(self, id, sala, nombre, descripcion, experiencia, nivel,
		                     vida, volumen, estado, aura, None, atrib, idiomas,
				     idioma_base, dinero)

	self.__tipo_controlador = tipo_controlador
	self.__datos_controlador = datos_controlador
	self.__conversacion = conversacion
	self.__autor = autor
	self.__area = area
	self.__intocable = intocable
	self.__contadores = contadores
	self.__etiquetas = etiquetas

        self.controlador_automatico()


    # Métodos normales

    def controlador_automatico(self):
        """Instancia un controlador automatico para este PNJ y se lo acopla.
        
        El tipo de controlador vendra determinado por los atributos de este
        PNJ segun se leen del fichero de descripcion.

        Requiere:
           self.controlador == None
        
        Asegura:
           self.controlador != None
        """
	if self.__tipo_controlador == "hablante":
	    import InterfazPNJHablante
            self._Personaje__controlador = \
		    InterfazPNJHablante.InterfazPNJHablante(self.__datos_controlador)
            self._Personaje__controlador.controlar_personaje(self)
        else:
            import InterfazPNJ
            self._Personaje__controlador = InterfazPNJ.InterfazPNJ()
            self._Personaje__controlador.controlar_personaje(self)


    def cambiar_dinero(self, monedas):
	"""Redefinición del método de la clase Personaje.

	De momento vamos a hacer que el PNJ se queda sin dinero, se recarga
	automáticamente. Así no tenemos que andar preocupandonos de cómo se ganan la
	vida los PNJs...
	"""
	super(PersonajeNoJugador, self).cambiar_dinero(monedas)
	if self.dinero <= 0:
	    self._Personaje__dinero = Personaje.DINERO_INICIAL
	

    def contador(self, nombre_contador):
	"""Devuelve el valor del contador con el nombre indicado.

	Es útil para requisitos. Si no existe, devuelve None.

	Requiere:
	    nombre_contador != None
	"""
	try:
	    return self.__contadores[nombre_contador]
	except KeyError:
	    return None


    def cambiar_contador(self, nombre_contador, incr_valor):
	"""Suma la cantidad indicada al contador.

	Si el nombre del contador no existe, no hace nada.

	Requiere:
	    nombre_contador != None
	    incr_valor != None
	"""
	if self.__contadores.has_key(nombre_contador):
	    self.__contadores[nombre_contador] += incr_valor


    def crear_contador(self, nombre_contador, valor):
	"""Crea un contador nuevo, con el valor indicado.

	Si ya existía, es sustituido.

	Requiere:
	    nombre_contador != None
	    valor != None
	"""
	self.__contadores[nombre_contador] = valor


    def borrar_contador(self, nombre_contador):
	"""Destruye un contador.

	Si no existía, no hace nada.

	Requiere:
	    nombre_contador != None
	"""
	try:
	    del self.__contadores[nombre_contador]
	except KeyError:
	    pass
	

    def etiqueta(self, nombre_etiqueta):
	"""Devuelve el valor de la etiqueta con el nombre indicado.

	Es útil para requisitos. Si no existe, devuelve None.

	Requiere:
	    nombre_etiqueta != None
	"""
	try:
	    return self.__etiquetas[nombre_etiqueta]
	except KeyError:
	    return None


    def cambiar_etiqueta(self, nombre_etiqueta, valor):
	"""Asigna el valor textual indicado a la etiqueta.

	Si el nombre de la etiqueta no existe, no hace nada.

	Requiere:
	    nombre_etiqueta != None
	    valor != None
	"""
	if self.__etiquetas.has_key(nombre_etiqueta):
	    self.__etiquetas[nombre_etiqueta] = valor


    def crear_etiqueta(self, nombre_etiqueta, valor):
	"""Crea una etiqueta nueva, con el valor indicado.

	Si ya existía, es sustituida.

	Requiere:
	    nombre_etiqueta != None
	    valor != None
	"""
	self.__etiquetas[nombre_etiqueta] = valor


    def borrar_etiqueta(self, nombre_etiqueta):
	"""Destruye una etiqueta.

	Si no existía, no hace nada.

	Requiere:
	    nombre_etiqueta != None
	"""
	try:
	    del self.__etiquetas[nombre_etiqueta]
	except KeyError:
	    pass


    def personaje_pregunta(self, interlocutor, tema):
	"""Responde al suceso de que un pj pregunta sobre un tema a éste.

	Requiere:
	    interlocutor != None
	"""
	self.__activar_conversacion(self.__conversacion[0], interlocutor, tema)


    def personaje_dice(self, interlocutor, tema):
	"""Responde al suceso de que un pj habla sobre un tema a éste.

	Requiere:
	    interlocutor != None
	"""
	self.__activar_conversacion(self.__conversacion[1], interlocutor, tema)


    def __activar_conversacion(self, conversacion, interlocutor, tema):
	"""Factor común de las dos anteriores."""
	if conversacion.has_key(tema):
	    modulo = conversacion[tema]
	    if modulo.agotado:
		modulo = self.__conversacion[2]["tema_agotado"]
	else:
	    modulo = self.__conversacion[2]["tema_no_encontrado"]

	macros_valores = {"$pj": interlocutor,
			  "$sala": self.sala,
			  "$tema": tema,
			  "$pnj": self}
	modulo.ejecutar(macros_valores)


# Funciones públicas

def nuevo_id():
    """Devuelve un número único para usarlo en el id de un nuevo pnj."""
    global __contador_de_ids
    __contador_de_ids += 1
    return str(__contador_de_ids)


def nuevo_xml(id, sala):
    """Crea un nuevo personaje no jugador a partir de un fichero XML de descripción.

    Al crearlo se le debe pasar un id unico, que no se repita dentro del juego
    en ninguna otra instancia. Para ello, se añade al id que identifica el fichero
    un simbolo % y un numero obtenido con PersonajeNoJugador.nuevo_id().

    Parametros:
      id: el id del PNJ
      sala: la sala en la que aparece el pnj

    Requiere:
      id tiene formato "id_fichero%clave_unica"
      sala != None
    """
    (id, nombre, descripcion, experiencia, nivel, vida, volumen, estado, aura,
        tipo_controlador, datos_controlador, conversacion, atrib, idiomas, idioma_base,
	dinero, autor, area, intocable, contadores, etiquetas, objetos) = \
		_parsear_fichero(id)

    pnj = PersonajeNoJugador(id, sala, nombre, descripcion, experiencia, nivel,
	                     vida, volumen, estado, aura, tipo_controlador,
			     datos_controlador, conversacion, atrib, idiomas,
			     idioma_base, dinero, autor, area, intocable,
			     contadores, etiquetas)

    for objeto in objetos:
	pnj.meter_en_mochila(objeto)

    return pnj


def _parsear_fichero(id):
    """Analiza un fichero XML y devuelve toda su información.

    La estructura del fichero XML es:

      <pnj version="xxx" autor="xxx" area="xxx">
        <id>xxx</id>
	<nombre>xxx</nombre>
	<descripcion>
	  <item>xxx
	    <NOMBRE_SUCESO>
	      ...guion...
	    </NOMBRE_SUCESO>
	    ...
	  </item>
	  ...
	</descripcion>
	<propiedades experiencia="xxx" nivel="xxx" vida="xxx" volumen="xxx" aura="xxx"
	             intocable="xxx", dinero="xxx">
	  <contador nombre="xxx" valor="xxx"/>
	  ...
	  <etiqueta nombre="xxx" valor="xxx"/>
	  ...
	</propiedades>
	<atributos fuerza="xxx" destreza="xxx" constitucion="xxx" inteligencia="xxx"
	           sabiduria="xxx" carisma="xxx"/>
	<idiomas NOMBRE_IDIOMA="xxx".../>
	<controlador tipo="xxx" datos="xxx"/>
	<conversacion nombre="xxx"/>
	<objetos>
	  <objeto id="xxx" cantidad="xxx" probabilidad="xxx"/>
	  ...
	</objetos>
      </pnj>

    Requiere:
      id != None
      id corresponde con un fichero existente
    """
    archivo = os.path.join(DIR_DESC_PNJS, id.split('%')[0] + EXT_DESC_PNJS)

    elem_pnj = xmlutils.parsear_fichero(archivo)
    (version, autor, area) = _parsear_pnj(id, elem_pnj)

    elem_id = xmlutils.subelemento(elem_pnj, 'id')
    id_fichero = _parsear_id(id, elem_id)

    elem_nombre = xmlutils.subelemento(elem_pnj, 'nombre')
    nombre = _parsear_nombre(id, elem_nombre)

    elem_descripcion = xmlutils.subelemento(elem_pnj, 'descripcion')
    descripcion = _parsear_descripcion(id, elem_descripcion)
    
    elem_propiedades = xmlutils.subelemento(elem_pnj, 'propiedades')
    (experiencia, nivel, vida, volumen, aura, intocable, dinero, contadores, etiquetas) = \
        _parsear_propiedades(id, elem_propiedades)

    estado = "vivo"
    
    elem_atributos = xmlutils.subelemento(elem_pnj, 'atributos')
    atrib = _parsear_atributos(id, elem_atributos)
    
    elem_idiomas = xmlutils.subelemento(elem_pnj, 'idiomas')
    idiomas = _parsear_idiomas(id, elem_idiomas)

    idioma_base = Idioma.oestron
    
    elem_controlador = xmlutils.subelemento(elem_pnj, 'controlador')
    (tipo_controlador, datos_controlador) = \
	    _parsear_controlador(id, elem_controlador)

    elems_conversacion = xmlutils.subelementos(elem_pnj, 'conversacion')
    if len(elems_conversacion) == 0:
	macros_tipos = [("$pj", "Personaje"),
			("$sala", "Sala"),
			("$tema", "string"),
			("$pnj", "Personaje")]
	conversacion = Modulo.conversacion_nula(macros_tipos)
    else:
	conversacion = _parsear_conversacion(id, elems_conversacion[0])
    
    elem_objetos = xmlutils.subelemento(elem_pnj, 'objetos')
    objetos = _parsear_objetos(id, elem_objetos)

    return (id, nombre, descripcion, experiencia, nivel, vida, volumen, estado, aura,
	    tipo_controlador, datos_controlador, conversacion, atrib, idiomas, idioma_base,
	    dinero, autor, area, intocable, contadores, etiquetas, objetos)


def _parsear_pnj(id, elem_pnj):
    """Analiza el elemento <pnj>. Devuelve:
	- version
	- autor
	- area
    """
    version_desc_pnj = xmlutils.atributo(elem_pnj, 'version')
    if version_desc_pnj != VERSION_DESC_PNJS:
	raise ValueError("Version incorrecta del fichero descriptor de pnj " + 
			 self._Personaje__id.split('%')[0] + ": " + version_desc_pnj +
			 " cuando se esperaba " + VERSION_DESC_PNJS)
    
    version = VERSION_DESC_PNJS
    autor = xmlutils.atributo(elem_pnj, 'autor')
    area = xmlutils.atributo_def(elem_pnj, 'area', '')

    return (version, autor, area)


def _parsear_id(id, elem_id):
    """Analiza el elemento <id>. Devuelve:
        - id_fichero
    """
    id_fichero = xmlutils.contenido(elem_id)
    if id_fichero != id.split('%')[0]:
	raise ValueError("El id %s no coincide con el nombre del fichero %s." % (id, id_fichero))

    return id_fichero


def _parsear_nombre(id, elem_nombre):
    """Analiza el elemento <nombre>. Devuelve:
        - nombre
    """
    nombre = xmlutils.contenido(elem_nombre)
    return nombre


def _parsear_descripcion(id, elem_descripcion):
    """Analiza el elemento <descripcion> y todos sus subelementos. Devuelve:
        - descripcion
    """
    descripcion = []

    for elem_item in xmlutils.subelementos(elem_descripcion, 'item'):

	texto_item = xmlutils.contenido(elem_item)
	texto_item = " ".join(texto_item.split()) # elimina todos los espacios redundantes	    
	
	dif_item = xmlutils.atributo_int_def(elem_item, 'dificultad', 0,
		                             "Error en pnj %s. La dificultad de la descripción "
				             "tiene que ser un número." % id)
	if not dif_item in range(0, 101):
	    raise ValueError("Error en pnj %s. La dificultad de la descripción "
	                     "tiene que ser de 0 a 100." % id)

	modulo = None
	for elem_suceso in xmlutils.subelementos(elem_item):
	    suceso = xmlutils.nombre_elemento(elem_suceso)
	    if suceso == "personaje_mira":
		modulo = Modulo.nuevo_xml(elem_suceso,
					  macros_tipos = [ ("$observador", "Personaje"),
							   ("$sala", "Sala") ])

	descripcion.append({"dificultad": dif_item, 
		            "texto": texto_item,
			    "personaje_mira": modulo})

    return descripcion


def _parsear_propiedades(id, elem_propiedades):
    """Analiza el elemento <propiedades> y todos sus subelementos. Devuelve:
	- experiencia
	- nivel
	- vida
	- volumen
	- aura
	- intocable
	- dinero
	- contadores
	- etiquetas
    """
    experiencia = xmlutils.atributo_int(elem_propiedades, 'experiencia',
		    "Error en pnj %s. La experiencia tiene que ser un número." % 
		    id.split('%')[0])
    if experiencia < 0:
	raise ValueError("Error en pnj %s. La experiencia tiene que ser mayor "
	                 "o igual que cero." % id.split('%')[0])

    nivel = xmlutils.atributo_int(elem_propiedades, 'nivel',
		    "Error en pnj %s. El nivel tiene que ser un número." % 
		    id.split('%')[0])
    if nivel < 1:
	raise ValueError("Error en pnj %s. El nivel tiene que ser mayor "
	                 "o igual que uno." % id.split('%')[0])

    vida = xmlutils.atributo_int(elem_propiedades, 'vida',
		    "Error en pnj %s. La vida tiene que ser un número." % 
		    id.split('%')[0])
    if vida < 0:
	raise ValueError("Error en pnj %s. La vida tiene que ser mayor "
	                 "o igual que cero." % id.split('%')[0])

    volumen = xmlutils.atributo_float(elem_propiedades, 'volumen',
		    "Error en pnj %s. El volumen tiene que ser un número." % 
		    id.split('%')[0])
    if volumen < 0:
	raise ValueError("Error en pnj %s. El volumen tiene que ser mayor "
	                 "o igual que cero." % id.split('%')[0])

    aura = xmlutils.atributo_int(elem_propiedades, 'aura',
		    "Error en pnj %s. El aura tiene que ser un número." % 
		    id.split('%')[0])
    if not aura in range(1, 101):
	raise ValueError("Error en pnj %s. El aura tiene que ser de 1 a 100." %
	                 id.split('%')[0])

    intocable = xmlutils.atributo_def(elem_propiedades, 'intocable', 'no')
    if not intocable in ['si', 'no']:
	raise ValueError("Error en pnj %s. El atributo intocable tiene que valer 'si' "
		         "o 'no'" % id.split('%')[0])

    dinero = xmlutils.atributo_int_def(elem_propiedades, 'dinero', Personaje.DINERO_INICIAL,
		    "Error en pnj %s. El dinero tiene que ser un número." % 
		    id.split('%')[0])
    if dinero < 0:
	raise ValueError("Error en pnj %s. El dinero tiene que ser mayor "
	                 "o igual que cero." % id.split('%')[0])
    
    contadores = {}
    for elem_contador in xmlutils.subelementos(elem_propiedades, 'contador'):
	nombre_contador = xmlutils.atributo(elem_contador, 'nombre')
	valor_contador = xmlutils.atributo_float(elem_contador, 'valor', 
		      "Error en pnj %s. El valor del contador %s tiene que ser un número." %
		      (id, nombre_contador))
	contadores[nombre_contador] = valor_contador
    
    etiquetas = {}
    for elem_etiqueta in xmlutils.subelementos(elem_propiedades, 'etiqueta'):
	nombre_etiqueta = xmlutils.atributo(elem_etiqueta, 'nombre')
	valor_etiqueta = xmlutils.atributo(elem_etiqueta, 'valor')
	etiquetas[nombre_etiqueta] = valor_etiqueta

    return (experiencia, nivel, vida, volumen, aura, intocable, dinero,
	    contadores, etiquetas)


def _parsear_atributos(id, elem_atributos):
    """Analiza el elemento <atributos>. Devuelve:
	- atributos
    """
    atrib = {}
    for un_atrib in elem_atributos.attributes.values():
	if not un_atrib.name in ["fuerza", "destreza", "constitucion",
				 "inteligencia", "sabiduria", "carisma"]:
	    raise ValueError("Error en pnj " + id.split('%')[0] +
			     ". El atributo " + un_atrib.name + " no existe.")
	try:
	    nivel = int(un_atrib.value)
	except ValueError:
	    raise ValueError("Error en pnj " + id.split('%')[0] +
			     ". El nivel del atributo " + un_atrib.name + " tiene que ser un número.")
	if nivel < 1:
	    raise ValueError("Error en pnj " + id.split('%')[0] +
			     ". El nivel del atributo " + un_atrib.name + " tiene que ser mayor o igual que uno.")

	atrib[un_atrib.name] = nivel

    return atrib


def _parsear_idiomas(id, elem_idiomas):
    """Analiza el elemento <idiomas>. Devuelve:
	- idiomas
    """
    idiomas = {}
    for atrib in elem_idiomas.attributes.values():
	idioma = Idioma.buscar(atrib.name)
	if idioma == None:
	    raise ValueError("Error en pnj " + id.split('%')[0] +
			     ". El idioma " + atrib.name + " no existe.")
	try:
	    nivel = int(atrib.value)
	except ValueError:
	    raise ValueError("Error en pnj " + id.split('%')[0] +
			     ". El nivel del idioma " + atrib.name + " tiene que ser un número.")
	if not nivel in range(0, 6):
	    raise ValueError("Error en pnj " + id.split('%')[0] +
			     ". El nivel del idioma " + atrib.name + " tiene que ser de 0 a 5.")

	idiomas[idioma] = nivel

    return idiomas


def _parsear_controlador(id, elem_controlador):
    """Analiza el elemento <controlador>. Devuelve:
	- tipo_controlador
	- datos_controlador
    """
    tipo_controlador = xmlutils.atributo(elem_controlador, 'tipo')
    if not tipo_controlador in ["estandar", "hablante"]:
	raise ValueError('Error en pnj ' + id.split('%')[0] +
			 '. El tipo de controlador tiene que valer "estandar" o "hablante".')
    datos_controlador = xmlutils.atributo_def(elem_controlador, 'datos', '')

    return (tipo_controlador, datos_controlador)


def _parsear_conversacion(id, elem_conversacion):
    """Analiza el elemento <conversacion> y todos sus subelementos. Devuelve:
        - conversacion
    """
    nombre_conversacion = xmlutils.atributo(elem_conversacion, 'nombre')
    macros_tipos = [("$pj", "Personaje"),
		    ("$sala", "Sala"),
		    ("$tema", "string"),
		    ("$pnj", "Personaje")]
    conversacion = Modulo.nueva_conversacion(nombre_conversacion, macros_tipos)
    return conversacion


def _parsear_objetos(id, elem_objetos):
    """Analiza el elemento <objetos> y todos sus subelementos. Devuelve:
        - objetos
    """
    objetos = []

    for elem_objeto in xmlutils.subelementos(elem_objetos, 'objeto'):

	id_objeto = xmlutils.atributo(elem_objeto, 'id')
	cantidad_objeto = xmlutils.atributo_int_def(elem_objeto, 'cantidad', 1, 
		         "Error en pnj %s. La cantidad del objeto %s tiene que ser un número" %
			 (id, id_objeto))
	if cantidad_objeto < 0:
	    raise ValueError("Error en pnj %s. La cantidad del objeto %s tiene que ser "
	                     "un número mayor o igual que cero." % (id, id_objeto))
	probabilidad_objeto = xmlutils.atributo_int_def(elem_objeto, 'probabilidad', 100, 
		         "Error en pnj %s. La probabilidad del objeto %s tiene que ser "
			 "un número" % (id, id_objeto))

	if tirar_porcentaje() <= probabilidad_objeto:
	    for i in range(1, cantidad_objeto+1):
		objetos.append(Objeto.nuevo_xml(id_objeto))

    return objetos


# Código para pruebas unitarias del módulo.

if (__name__ == '__main__'):
    from mundo import Mundo
    limbo = Mundo.localizar_sala(Mundo.ID_SALA_LIMBO)

    id = raw_input("Introducir el id de un personaje no jugador: ")
    id_unico = id + '%' + nuevo_id()
    pnj = nuevo_xml(id_unico, limbo)
    limbo.entrar_personaje(pnj)

    print "[%s] [versión %s]: %s" % (pnj.id, pnj.version, pnj.nombre)
    for item in pnj.descripcion:
	print "\n[%d] %s" % (item["dificultad"], item["texto"])

    print "\npropiedades"
    print "  experiencia: %d" % pnj.experiencia
    print "  nivel: %d" % pnj.nivel
    print "  vida: %d" % pnj.vida
    print "  volumen: %.2f" % pnj.volumen
    print "  estado: %s" % pnj.estado

    print "\natributos"
    for nombre_atrib in pnj.atrib.keys():
	print "  %s: %d" % (nombre_atrib, pnj.atrib[nombre_atrib])

    print "\nidiomas"
    for idioma in pnj.idiomas.keys():
	print "  %s: %d" % (idioma.nombre, pnj.idiomas[idioma])
    print "  idioma_base: %s" % pnj.idioma_base.nombre

    print "\nmochila"
    if len(pnj.mochila) == 0:
	print "  vacía"
    else:
	for instancias_objeto in pnj.mochila:
	    print "  %s (%d)" % (instancias_objeto[0].nombre, len(instancias_objeto))

