/[ambar]/ambar/personajenojugador.py
ViewVC logotype

Diff of /ambar/personajenojugador.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2.5 by pabloruiz, Sun Sep 15 15:25:41 2002 UTC revision 2.6 by amoyav, Sun Nov 10 13:48:16 2002 UTC
# Line 23  Line 23 
23    
24  """Clase PersonajeNoJugador."""  """Clase PersonajeNoJugador."""
25    
26  from os import path  from xml.dom import minidom
27  from personaje import *  import os
28    import random
   
 DIR_DESC_PNJS = 'desc_pnjs'  
29    
30    from personaje import *
31    from utils import *
32    from objeto import *
33    
34  class PersonajeNoJugador(Personaje):  class PersonajeNoJugador(Personaje):
35      """Cualquier personaje no controlado por un jugador.      """Cualquier personaje no controlado por un jugador.
# Line 36  class PersonajeNoJugador(Personaje): Line 37  class PersonajeNoJugador(Personaje):
37      Los PNJs siempre tienen un controlador activo, excepto cuando son guardados a disco      Los PNJs siempre tienen un controlador activo, excepto cuando son guardados a disco
38      al volcarse junto con una sala. Al ser recuperados, se les vuelve a acoplar      al volcarse junto con una sala. Al ser recuperados, se les vuelve a acoplar
39      inmediatamente un controlador.      inmediatamente un controlador.
40    
41        Opcionalmente puede guardar el documento xml leido del fichero, esto es válido
42        para editores de PNJs.
43            
44      Contiene los atributos comunes de un personaje, y ademas:      Contiene los atributos comunes de un personaje, y ademas:
45       - posesion (string): nombre del objeto que guarda este personaje       - __autor (string): nombre del autor del fichero de descripcion
46         - __area (string): id del área por la que se mueve este pnj (si está vacío, puede
47                            moverse por cualquier área)
48         - __tipo_controlador (string): descripcion del tipo de controlador
49         - __datos_controlador (string): información para configurar el controlador
50         - __arbol_xml (minidom.Document, opcional): arbol XML leido del fichero de descripcion
51            
52      Invariantes:      Invariantes:
53          id tiene formato "id_fichero%clave_unica"          id tiene formato "id_fichero%clave_unica"
         posesion != None  
54          controlador != None          controlador != None
55            __autor != None
56            __area != None
57            __tipo_controlador in ['estandar', 'hablante']
58            __datos_controlador != None
59      """      """
60    
61        # Version del sistema de descripciones de pnj (se incrementa cada vez que cambia
62        # el formato de los ficheros de desc_pnjs)
63        VERSION_DESC_PNJS = '1.0'
64    
65        DIR_DESC_PNJS = 'desc_pnjs'
66        EXT_DESC_PNJS = '.xml'
67    
68        # Contador para ir asignando ids a los pnjs nuevos
69        contador_de_ids = 0
70    
71      def __init__(self, id, sala):      def __init__(self, id, sala, conservar_arbol_xml = 0):
72          """Método para crear un nuevo personaje no jugador.          """Método para crear un nuevo personaje no jugador.
73    
74          Al crearlo se le debe pasar un id unico, que no se repita dentro del juego          Al crearlo se le debe pasar un id unico, que no se repita dentro del juego
75          en ninguna otra instancia. Para ello, se añade al id que identifica el fichero          en ninguna otra instancia. Para ello, se añade al id que identifica el fichero
76          un simbolo % y un numero obtenido con PersonajeNoJugador_nuevo_id().          un simbolo % y un numero obtenido con PersonajeNoJugador_nuevo_id().
77    
78            Parametros:
79              id: el id del PNJ
80              sala: la sala en la que aparece el pnj
81              conservar_arbol_xml: si vale true, el arbol no se borra una vez leido
82    
83          Requiere:          Requiere:
84            id tiene formato "id_fichero%clave_unica"            id tiene formato "id_fichero%clave_unica"
85            sala != None            sala != None
86          """          """
87          Personaje.__init__(self, id, sala)          Personaje.__init__(self, id, sala)
         print "el ID de este personaje es",id  
         # DUMMY: de momento rellenamos los atributos a piñon.  
         if id.lower() == "tutora":  
             self.__dict__["nombre"] = "La Tutora"  
             self.__dict__["descripcion"] = [{"dificultad":0, "texto":"Una anciana mujer, de aspecto respetable. Va vestida con una túnica encapuchada."}]  
         elif id.split('%')[0].lower() == "posadero":  
             self.__dict__["nombre"] = "Posadero"  
             self.__dict__["descripcion"] = [{"dificultad":0, "texto":"Un hombre rechoncho y ciertamente grasiento que habla siempre como si le costase respirar. El mandil está muy sucio y le limpia constantemente las manos en los viejos pantalones.."}]  
         else:  
             self.__dict__["nombre"] = id.split('%')[0]  
             self.__dict__["descripcion"] = [{"dificultad":0, "texto":"Este personaje no tiene descripción por ahora.."}]  
         self.__dict__["experiencia"] = 0  
         self.__dict__["nivel"] = 0  
         self.__dict__["vida"] = 1  
         self.__dict__["volumen"] = 1  
         self.__dict__["estado"] = "vivo"  
         self.__dict__["controlador"] = None  
         self.__dict__["atrib"] = { "fuerza":10,  
                                    "destreza":10,  
                                    "constitucion":10,  
                                    "inteligencia":10,  
                                    "sabiduria":10,  
                                    "carisma":10 }  
         self.__dict__["idiomas"] = { Idioma_oestron:5,  
                                      Idioma_enano:3,  
                                      Idioma_quenya:3,  
                                      Idioma_orco:3 }  
         self.__dict__["idioma_base"] = Idioma_oestron  
88    
89          self.posesion = ""          archivo = os.path.join(PersonajeNoJugador.DIR_DESC_PNJS,
90                                   self.id.split('%')[0] + PersonajeNoJugador.EXT_DESC_PNJS)
91    
92            arbol_xml = minidom.parse(archivo)
93    
94            elem_pnj = arbol_xml.documentElement
95            self.__parsear_pnj(elem_pnj)
96    
97            elem_id = elem_pnj.getElementsByTagName('id')[0]
98            self.__parsear_id(elem_id)
99    
100            elem_nombre = elem_pnj.getElementsByTagName('nombre')[0]
101            self.__parsear_nombre(elem_nombre)
102    
103            elem_descripcion = elem_pnj.getElementsByTagName('descripcion')[0]
104            self.__parsear_descripcion(elem_descripcion)
105            
106            elem_propiedades = elem_pnj.getElementsByTagName('propiedades')[0]
107            self.__parsear_propiedades(elem_propiedades)
108            
109            elem_atributos = elem_pnj.getElementsByTagName('atributos')[0]
110            self.__parsear_atributos(elem_atributos)
111            
112            elem_idiomas = elem_pnj.getElementsByTagName('idiomas')[0]
113            self.__parsear_idiomas(elem_idiomas)
114            
115            elem_controlador = elem_pnj.getElementsByTagName('controlador')[0]
116            self.__parsear_controlador(elem_controlador)
117            
118            elem_objetos = elem_pnj.getElementsByTagName('objetos')[0]
119            self.__parsear_objetos(elem_objetos)
120    
121            if conservar_arbol_xml:
122                self.__arbol_xml = arbol_xml
123    
124          self.controlador_automatico()          self.controlador_automatico()
125    
126    
127        def __parsear_pnj(self, elem_pnj):
128            """Extrae la información del elemento pnj:
129                - version
130                - autor
131                - area
132            """
133            version_desc_pnj = extraer_atributo_xml(elem_pnj, 'version')
134    
135            if version_desc_pnj != PersonajeNoJugador.VERSION_DESC_PNJS:
136                raise ValueError("Version incorrecta del fichero descriptor de pnj " + self.id.split('%')[0] + ": " +
137                                 version_desc_pnj + " cuando se esperaba " + Sala.VERSION_DESC_PNJS)
138            
139            self.__autor = extraer_atributo_xml(elem_pnj, 'autor')
140            if elem_pnj.hasAttribute('area'):
141                self.__area = extraer_atributo_xml(elem_pnj, 'area')
142            else:
143                self.__area = ""
144    
145    
146        def __parsear_id(self, elem_id):
147            """Extrae el id del pnj"""
148            id_fichero = extraer_contenido_xml(elem_id)
149            if id_fichero != self.id.split('%')[0]:
150                raise ValueError("El id no coincide con el nombre del fichero")
151            
152    
153        def __parsear_nombre(self, elem_nombre):
154            """Extrae el nombre del pnj"""
155            self.nombre = extraer_contenido_xml(elem_nombre)
156    
157    
158        def __parsear_descripcion(self, elem_descripcion):
159            """Extrae el texto y la dificultad de todos los items de descripcion del pnj."""
160            self.descripcion = []
161    
162            elems_item = elem_descripcion.getElementsByTagName('item')
163            for elem_item in elems_item:
164    
165                texto_item = extraer_contenido_xml(elem_item)
166                texto_item = " ".join(texto_item.split()) # elimina todos los espacios redundantes
167    
168                if elem_item.hasAttribute('dificultad'):
169                    try:
170                        dif_item = int(extraer_atributo_xml(elem_item, 'dificultad'))
171                    except ValueError:
172                        raise ValueError("Error en pnj " + self.id.split('%')[0] +
173                                         ". La dificultad en la descripción tiene que ser un número.")
174                    if not dif_item in range(0, 101):
175                        raise ValueError("Error en pnj " + self.id.split('%')[0] +
176                                         ". La dificultad en la descripción tiene que ser de 0 a 100.")
177                else:
178                    dif_item = 0
179    
180                self.descripcion.append({"dificultad": dif_item, "texto": texto_item})
181    
182    
183        def __parsear_propiedades(self, elem_propiedades):
184            """Extrae la información del elemento propiedades:
185                - experiencia
186                - nivel
187                - vida
188                - volumen
189                - aura
190                - intocable
191            """
192            try:
193                self.experiencia = int(extraer_atributo_xml(elem_propiedades, 'experiencia'))
194            except ValueError:
195                raise ValueError("Error en pnj " + self.id.split('%')[0] +
196                                 ". La experiencia tiene que ser un número.")
197            if self.experiencia < 0:
198                raise ValueError("Error en pnj " + self.id.split('%')[0] +
199                                 ". La experiencia tiene que ser mayor que cero.")
200    
201            try:
202                self.nivel = int(extraer_atributo_xml(elem_propiedades, 'nivel'))
203            except ValueError:
204                raise ValueError("Error en pnj " + self.id.split('%')[0] +
205                                 ". El nivel tiene que ser un número.")
206            if self.nivel < 1:
207                raise ValueError("Error en pnj " + self.id.split('%')[0] +
208                                 ". El nivel tiene que ser mayor o igual que uno.")
209    
210            try:
211                self.vida = int(extraer_atributo_xml(elem_propiedades, 'vida'))
212            except ValueError:
213                raise ValueError("Error en pnj " + self.id.split('%')[0] +
214                                 ". La vida tiene que ser un número.")
215            if self.vida < 0:
216                raise ValueError("Error en pnj " + self.id.split('%')[0] +
217                                 ". La vida tiene que ser mayor que cero.")
218    
219            try:
220                self.volumen = float(extraer_atributo_xml(elem_propiedades, 'volumen'))
221            except ValueError:
222                raise ValueError("Error en pnj " + self.id.split('%')[0] +
223                                 ". El volumen tiene que ser un número.")
224            if self.volumen < 0:
225                raise ValueError("Error en pnj " + self.id.split('%')[0] +
226                                 ". El volumen tiene que ser mayor que cero.")
227    
228            self.estado = "vivo"
229    
230            try:
231                self.aura = int(extraer_atributo_xml(elem_propiedades, 'aura'))
232            except ValueError:
233                raise ValueError("Error en pnj " + self.id.split('%')[0] +
234                                 ". El aura tiene que ser un número.")
235            if not self.aura in range(1, 101):
236                raise ValueError("Error en pnj " + self.id.split('%')[0] +
237                                 ". El aura tiene que ser de 1 a 100.")
238    
239            if elem_propiedades.hasAttribute('intocable'):
240                self.intocable = extraer_atributo_xml(elem_propiedades, 'intocable')
241                if not self.intocable in ["si", "no"]:
242                    raise ValueError('Error en pnj ' + self.id.split('%')[0] +
243                                     '. El atributo intocable tiene que valer "si" o "no".')
244            else:
245                self.intocable = "no"
246    
247    
248        def __parsear_atributos(self, elem_atributos):
249            """Extrae la información del elemento atributos:
250                - fuerza
251                - destreza
252                - constitucion
253                - inteligencia
254                - sabiduria
255                - carisma
256            """
257            self.atrib = {}
258            for atrib in elem_atributos.attributes.values():
259                if not atrib.name in ["fuerza", "destreza", "constitucion",
260                                      "inteligencia", "sabiduria", "carisma"]:
261                    raise ValueError("Error en pnj " + self.id.split('%')[0] +
262                                     ". El atributo " + atrib.name + " no existe.")
263                try:
264                    nivel = int(atrib.value)
265                except ValueError:
266                    raise ValueError("Error en pnj " + self.id.split('%')[0] +
267                                     ". El nivel del atributo " + atrib.name + " tiene que ser un número.")
268                if nivel < 1:
269                    raise ValueError("Error en pnj " + self.id.split('%')[0] +
270                                     ". El nivel del atributo " + atrib.name + " tiene que ser mayor o igual que uno.")
271    
272                self.atrib[atrib.name] = nivel
273    
274    
275        def __parsear_idiomas(self, elem_idiomas):
276            """Extrae la información del elemento idiomas."""
277            self.idiomas = {}
278            for atrib in elem_idiomas.attributes.values():
279                idioma = Idioma_buscar(atrib.name)
280                if idioma == None:
281                    raise ValueError("Error en pnj " + self.id.split('%')[0] +
282                                     ". El idioma " + atrib.name + " no existe.")
283                try:
284                    nivel = int(atrib.value)
285                except ValueError:
286                    raise ValueError("Error en pnj " + self.id.split('%')[0] +
287                                     ". El nivel del idioma " + atrib.name + " tiene que ser un número.")
288                if not nivel in range(0, 6):
289                    raise ValueError("Error en pnj " + self.id.split('%')[0] +
290                                     ". El nivel del idioma " + atrib.name + " tiene que ser de 0 a 5.")
291    
292                self.idiomas[idioma] = nivel
293    
294            self.idioma_base = Idioma_oestron
295    
296    
297        def __parsear_controlador(self, elem_controlador):
298            """Extrae la información del elemento controlador:
299                - tipo
300                - datos
301            """
302            self.__tipo_controlador = extraer_atributo_xml(elem_controlador, 'tipo')
303            if not self.__tipo_controlador in ["estandar", "hablante"]:
304                raise ValueError('Error en pnj ' + self.id.split('%')[0] +
305                                 '. El tipo de controlador tiene que valer "estandar" o "hablante".')
306            if elem_controlador.hasAttribute('datos'):
307                self.__datos_controlador = extraer_atributo_xml(elem_controlador, 'datos')
308            else:
309                self.__datos_controlador = ""
310    
311    
312        def __parsear_objetos(self, elem_objetos):
313            """Extrae el texto y la dificultad de todos los items de objetos del pnj."""
314            self.objetos = []
315    
316            lista_elem_objeto = elem_objetos.getElementsByTagName('objeto')
317            for elem_objeto in lista_elem_objeto:
318    
319                id_objeto = extraer_atributo_xml(elem_objeto, 'id')
320                if elem_objeto.hasAttribute('cantidad'):
321                    try:
322                        cantidad_objeto = int(extraer_atributo_xml(elem_objeto, 'cantidad'))
323                    except ValueError:
324                        raise ValueError("Error en pnj " + self.id.split('%')[0] +
325                                         ". La cantidad del objeto " + id_objeto + " tiene que ser un número.")
326                    if cantidad_objeto < 0:
327                        raise ValueError("Error en pnj " + self.id.split('%')[0] +
328                                         ". La cantidad del objeto " + id_objeto + " tiene que ser mayor que cero.")
329                else:
330                    cantidad_objeto = 1
331                if elem_objeto.hasAttribute('probabilidad'):
332                    probabilidad_objeto = int(extraer_atributo_xml(elem_objeto, 'probabilidad'))
333                else:
334                    probabilidad_objeto = 100
335    
336                if tirar_porcentaje() <= probabilidad_objeto:
337                    for i in range(1, cantidad_objeto+1):
338                        self.meter_en_mochila(Objeto(id_objeto))
339    
340    
341        def autor(self):
342            return self.__autor
343    
344    
345        def area(self):
346            return self.__area
347    
348    
349      def controlador_automatico(self):      def controlador_automatico(self):
350          """Instancia un controlador automatico para este PNJ y se lo acopla.          """Instancia un controlador automatico para este PNJ y se lo acopla.
351                    
# Line 104  class PersonajeNoJugador(Personaje): Line 358  class PersonajeNoJugador(Personaje):
358          Asegura:          Asegura:
359             self.controlador != None             self.controlador != None
360          """          """
361          # De momento, a piñon tambien.          if self.__tipo_controlador == "hablante":
362          if self.id.split('%')[0].lower() == "tutora":              from interfazpnjhablante import InterfazPNJHablante
363              from interfazpnjhablante import InterfazPNJHablante              self.controlador = InterfazPNJHablante(self.__datos_controlador)
             self.controlador = InterfazPNJHablante(self.id)  
             self.controlador.controlar_personaje(self)  
         elif self.id.split('%')[0].lower() == "posadero":  
             from interfazpnjhablante import InterfazPNJHablante  
             self.controlador = InterfazPNJHablante(self.id)  
364              self.controlador.controlar_personaje(self)              self.controlador.controlar_personaje(self)
   
365          else:          else:
366              from interfazpnj import InterfazPNJ              from interfazpnj import InterfazPNJ
367              self.controlador = InterfazPNJ()              self.controlador = InterfazPNJ()
368              self.controlador.controlar_personaje(self)              self.controlador.controlar_personaje(self)
369    
370    
371  # Metodos que se refieren a la clase pero tienen ambito de clase,  # Metodos que se refieren a la clase pero tienen ambito de clase,
372  # y no de instancia  # y no de instancia
373    
374  def PersonajeNoJugador_nuevo_id():  def PersonajeNoJugador_nuevo_id():
375      global PersonajeNoJugador_contador_de_ids      PersonajeNoJugador.contador_de_ids += 1
376      PersonajeNoJugador_contador_de_ids += 1      return str(PersonajeNoJugador.contador_de_ids)
     return str(PersonajeNoJugador_contador_de_ids)  
   
377    
 PersonajeNoJugador_contador_de_ids = 0  
378    
379  # Código para pruebas unitarias del módulo.  # Código para pruebas unitarias del módulo.
380    
381  if (__name__ == '__main__'):  if (__name__ == '__main__'):
382      print "No hay prueba unitaria de módulo."      from mundo import Mundo
383        from mundo import Mundo_localizar_sala
384        limbo = Mundo_localizar_sala(Mundo.ID_SALA_LIMBO)
385    
386        id = raw_input("Introducir el id de un personaje no jugador: ")
387        id_unico = id + '%' + PersonajeNoJugador_nuevo_id()
388        pnj = PersonajeNoJugador(id_unico, limbo)
389        limbo.entrar_personaje(pnj)
390    
391        print "[%s] [versión %s]: %s" % (pnj.id, pnj.version, pnj.nombre)
392        for item in pnj.descripcion:
393            print "\n[%d] %s" % (item["dificultad"], item["texto"])
394    
395        print "\npropiedades"
396        print "  experiencia: %d" % pnj.experiencia
397        print "  nivel: %d" % pnj.nivel
398        print "  vida: %d" % pnj.vida
399        print "  volumen: %.2f" % pnj.volumen
400        print "  estado: %s" % pnj.estado
401    
402        print "\natributos"
403        for nombre_atrib in pnj.atrib.keys():
404            print "  %s: %d" % (nombre_atrib, pnj.atrib[nombre_atrib])
405    
406        print "\nidiomas"
407        for idioma in pnj.idiomas.keys():
408            print "  %s: %d" % (idioma.nombre, pnj.idiomas[idioma])
409        print "  idioma_base: %s" % pnj.idioma_base.nombre
410    
411        print "\nmochila"
412        if len(pnj.mochila()) == 0:
413            print "  vacía"
414        else:
415            for instancias_objeto in pnj.mochila():
416                print "  %s (%d)" % (instancias_objeto[0].nombre(), len(instancias_objeto))
417    

Legend:
Removed from v.2.5  
changed lines
  Added in v.2.6

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26