20 |
# |
# |
21 |
|
|
22 |
|
|
23 |
#Fichero: interfazpnjhablante.py |
#Fichero: interfazpnjhablante.py |
24 |
|
|
25 |
"""Clase InterfazPNJHablante.""" |
"""Clase InterfazPNJHablante.""" |
26 |
|
|
27 |
from controlador import * |
from interfazpnj import * |
28 |
from personaje import * |
from conversacion import * |
29 |
from personajejugador import * |
from visita import * |
30 |
from personajenojugador import * |
import copy |
31 |
from sala import * |
|
32 |
from utils import * |
class InterfazPNJHablante(InterfazPNJ): |
33 |
from timer import * |
"""Interfaz controla directamente a una instancia de clase PersonajeNoJugador con capacidad de dialogar. |
34 |
from conversacion import * |
|
35 |
from visita import * |
El control es automático, no necesita intervención de ningún jugador. |
36 |
from idioma import * |
|
37 |
from dialogonormal import * |
La clase funciona como una maquina de estados, que acepta los eventos de |
38 |
import copy |
Controlador, y reacciona apropiadamente en cada caso. |
39 |
|
|
40 |
class InterfazPNJHablante(InterfazPNJ): |
Contiene los siguientes atributos: |
41 |
"""Interfaz controla directamente a una instancia de clase PersonajeNoJugador con capacidad de dialogar. |
|
42 |
|
- _conversacion (Conversacion): la conversacion que es capaz de mantener el PNJ |
43 |
El control es automátic, no necesita intervención de ningún jugador. |
- _visitas ([Visita]): los estados de conversacion que mantiene con distintos grupos de PJs. |
44 |
|
- __personaje (Personaje): el personaje que controlamos |
45 |
La clase funciona como una maquina de estados, que reacciona frente a los siguientes |
- estado (string): el estado en el que se encuentra el interfaz |
46 |
eventos: |
- sub_estado (int): algunos estados tienen fases intermedias. Si no, None. |
47 |
|
- timer (Timer): temporizador usado opcionalmente |
48 |
* - comando_recibido: el jugador ha enviado un comando por el socket |
- oponente (Personaje): otro personaje con quien el nuestro está combatiendo |
49 |
- entra_personaje: otro personaje ha entrado en la sala |
- _fragmentos: lista de fragmentos que falta por decir |
50 |
- sale_personaje: otro personaje sale de la sala |
- timers: temporizadores para mostrar los fragmentos restantes |
51 |
- actua_pesonaje: otro personaje hace algo y lo ven los que están en la misma sala |
|
52 |
* - habla_pesonaje: otro personaje dice algo a los que están en la misma sala |
Los siguientes atributos provocan ajustes automáticos al ser modificados: |
53 |
* - susurra_pesonaje: otro personaje susurra algo a éste. |
|
54 |
- grita_personaje: otro personaje dice algo a todos los personajes del mundo |
- personaje: se modifica también al personaje para que tenga a este interfaz como |
55 |
- ataca_personaje: otro personaje ataca a este |
controlador |
56 |
|
|
57 |
Contiene los siguientes atributos: |
Invariantes: |
58 |
|
_conversacion != None |
59 |
- _conversacion (Conversacion): la conversacion que es capaz de mantener el PNJ |
__personaje != None |
60 |
- _visitas ([Visita]): los estados de conversacion que mantiene con distintos grupos de PJs. |
len(_visitas) >= 0 |
61 |
- __personaje (Personaje): el personaje que controlamos |
len(timers) >= 0 |
62 |
- estado (string): el estado en el que se encuentra el interfaz |
len(_fragmentos) >= 0 |
63 |
- sub_estado (int): algunos estados tienen fases intermedias. Si no, None. |
self.visita[i].activo <--> len(self._fragmentos) > 0 |
64 |
- timer (Timer): temporizador usado opcionalmente |
""" |
65 |
- oponente (Personaje): otro personaje con quien el nuestro está combatiendo
|
|
66 |
- _fragmentos: lista de fragmentos que falta por decir |
|
67 |
- timers: temporizadores para mostrar los fragmentos restantes |
def __init__(self, id): |
68 |
|
InterfazPNJ.__init__(self) |
69 |
Los siguientes atributos provocan ajustes automáticos al ser modificados: |
idconversacion = id.split("%")[0] |
70 |
|
self._conversacion = Conversacion(idconversacion) |
71 |
- personaje: se modifica también al personaje para que tenga a este interfaz como |
self._visitas = [Visita(self._conversacion, None)] |
72 |
controlador |
self._fragmentos = [] |
73 |
|
|
74 |
Invariantes: |
|
75 |
_conversacion != None |
|
76 |
__personaje != None |
def __setattr__(self, name, value): |
77 |
len(_visitas) >= 0 |
"""Realiza ajustes automáticos al modificar cualquier parámetro""" |
78 |
len(timers) >= 0 |
|
79 |
len(_fragmentos) >= 0 |
if name == "personaje": |
80 |
self.visita[i].activo <--> len(self._fragmentos) > 0 |
# Si es personaje, liberar al anterior y controlar al nuevo. |
81 |
""" |
if (self.personaje != None): self.personaje.controlador = None |
82 |
|
self.__dict__["personaje"] = value |
83 |
|
if (self.personaje != None): self.personaje.controlador = self |
84 |
def __init__(self, id): |
# Y borrar las visitas que ha mantenido hasta ahora |
85 |
InterfazPNJ.__init__(self) |
# self._visitas = [] |
86 |
idconversacion = id.split("%")[0] |
else: |
87 |
self._conversacion = Conversacion(idconversacion) |
# En otro caso, asignar y ya esta |
88 |
self._visitas = [Visita(self._conversacion, None)] |
self.__dict__[name] = value |
89 |
self._fragmentos = [] |
|
90 |
|
def controlar_personaje(self, personaje): |
91 |
|
"""Pasar a estar controlando un personaje. |
92 |
|
|
93 |
def __setattr__(self, name, value): |
Requiere: |
94 |
"""Realiza ajustes automáticos al modificar cualquier parámetro""" |
self.__personaje == None |
95 |
|
personaje != None |
96 |
if name == "personaje": |
""" |
97 |
# Si es personaje, liberar al anterior y controlar al nuevo. |
self.__personaje = personaje |
98 |
if (self.personaje != None): self.personaje.controlador = None |
self.__personaje.controlar(self) |
99 |
self.__dict__["personaje"] = value |
self._visitas[0].pnj = self.__personaje |
100 |
if (self.personaje != None): self.personaje.controlador = self |
|
101 |
# Y borrar las visitas que ha mantenido hasta ahora |
# ---------------------------- |
102 |
# self._visitas = [] |
# Metodos de manejo de eventos |
103 |
else: |
# ---------------------------- |
104 |
# En otro caso, asignar y ya esta |
|
105 |
self.__dict__[name] = value |
def conversa_personaje(self, personaje, comando, nombretema): |
106 |
|
"""Metodo llamado cuando otro personaje habla con este PNJ""" |
107 |
def controlar_personaje(self, personaje): |
visita = self._visitas[0] |
108 |
"""Pasar a estar controlando un personaje. |
if visita.activo: |
109 |
|
if visita.pj_activo.atrib["carisma"] > personaje.atrib["carisma"] : #visita.pj_activo.aura > personaje.controlador._DialogoNormal__personaje.aura: |
110 |
Requiere: |
personaje.controlador.conn().send(visita.pnj.nombre +" está hablando con " + visita.pj_activo.nombre) |
111 |
self.__personaje == None |
return |
112 |
personaje != None |
else: |
113 |
""" |
self.anular_conversacion() |
114 |
self.__personaje = personaje |
respuesta = visita.responder(personaje, comando, nombretema.lower()) |
115 |
self.__personaje.controlar(self) |
escribir("Tema " + visita.estado()) |
116 |
self._visitas[0].pnj = self.__personaje |
#print respuesta[len(respuesta)-1] |
117 |
|
if visita.estado() == Visita.ENCONTRADO or visita.estado() == Visita.OFFTOPIC: |
118 |
# ---------------------------- |
visita.activar(respuesta) |
119 |
# Metodos de manejo de eventos |
|
120 |
# ---------------------------- |
nombre = visita.pnj.nombre[0].lower() + visita.pnj.nombre[1:] |
121 |
|
if comando == "decir": |
122 |
def conversa_personaje(self, personaje, comando, nombretema): |
visita.pj_activo.actuar("dice a " + nombre + " algo acerca de '" + nombretema + "'") |
123 |
"""Metodo llamado cuando otro personaje habla con este PNJ""" |
personaje.controlador.conn().send("Dices a " + nombre + " algo sobre '" + nombretema + "'") |
124 |
visita = self._visitas[0] |
else: |
125 |
if visita.activo: |
visita.pj_activo.actuar("pregunta a " + nombre + " acerca de '" + nombretema + "'") |
126 |
if visita.pj_activo.atrib["carisma"] > personaje.atrib["carisma"] : #visita.pj_activo.aura > personaje.controlador._DialogoNormal__personaje.aura: |
personaje.controlador.conn().send("Preguntas a " + nombre + " sobre '" + nombretema + "'") |
127 |
personaje.controlador.conn().send(visita.pnj.nombre +" está hablando con " + visita.pj_activo.nombre) |
|
128 |
return |
fragmentos = [] |
129 |
else: |
|
130 |
self.anular_conversacion() |
|
131 |
respuesta = visita.responder(personaje, comando, nombretema.lower()) |
for item in respuesta["especiales"]: |
132 |
escribir("Tema " + visita.estado()) |
fragmentos = fragmentos + item._fragmentos |
133 |
#print respuesta[len(respuesta)-1] |
# if type(item) == type(""): |
134 |
if visita.estado() == Visita.ENCONTRADO or visita.estado() == Visita.OFFTOPIC: |
# escribir(str(item)) |
135 |
visita.activar(respuesta) |
# else: |
136 |
|
# self._fragmentos = self._fragmentos + copy.copy(item._fragmentos) |
137 |
nombre = visita.pnj.nombre[0].lower() + visita.pnj.nombre[1:] |
if respuesta["tema"]: |
138 |
if comando == "decir": |
fragmentos = fragmentos + respuesta["tema"]._fragmentos |
139 |
visita.pj_activo.actuar("dice a " + nombre + " algo acerca de '" + nombretema + "'") |
|
140 |
personaje.controlador.conn().send("Dices a " + nombre + " algo sobre '" + nombretema + "'") |
self.temporizar(fragmentos) |
141 |
else: |
# self._fragmentos = self._fragmentos + copy.copy(respuesta["tema"]._fragmentos) |
142 |
visita.pj_activo.actuar("pregunta a " + nombre + " acerca de '" + nombretema + "'") |
|
143 |
personaje.controlador.conn().send("Preguntas a " + nombre + " sobre '" + nombretema + "'") |
def temporizar(self, fragmentos): |
144 |
|
"""Programa la temporización del diálogo contenido en la lista de fragmentos.""" |
145 |
fragmentos = [] |
|
146 |
|
self.timers=[] |
147 |
|
self._fragmentos = [] |
148 |
for item in respuesta["especiales"]: |
timeout = 0 |
149 |
fragmentos = fragmentos + item._fragmentos |
|
150 |
# if type(item) == type(""): |
visita = self._visitas[0] |
151 |
# escribir(str(item)) |
for fragmento in fragmentos: |
152 |
# else: |
# Comprueba requisitos de fragmento |
153 |
# self._fragmentos = self._fragmentos + copy.copy(item._fragmentos) |
if fragmento.__dict__.has_key("_texto_unico"): |
154 |
if respuesta["tema"]: |
hito = fragmento._texto_unico |
155 |
fragmentos = fragmentos + respuesta["tema"]._fragmentos |
print hito + " " + visita.hito(hito) |
156 |
|
if visita.hito(hito): |
157 |
self.temporizar(fragmentos) |
continue # Fragmento repetido |
158 |
# self._fragmentos =
self._fragmentos + copy.copy(respuesta["tema"]._fragmentos) |
else: |
159 |
|
self.timers.append(Timer(Mundo.timer_handler, timeout, lambda timer: visita.asignar_hito(hito))) |
160 |
def temporizar(self, fragmentos): |
|
161 |
"""Programa la temporización del diálogo contenido en la lista de fragmentos.""" |
# Asigna temporizador para el fragmento |
162 |
|
self._fragmentos.append(copy.copy(fragmento)) |
163 |
self.timers=[] |
print "temporizado " + str(timeout) + " segundos: " + str(fragmento) |
164 |
self._fragmentos = [] |
self.timers.append(Timer(Mundo.timer_handler, timeout, lambda timer: self.show())) |
165 |
timeout = 0 |
timeout = timeout + fragmento.retardo() |
166 |
|
self.timers.append(Timer(Mundo.timer_handler, timeout, lambda timer: self.anular_conversacion())) |
167 |
visita = self._visitas[0] |
|
168 |
for fragmento in fragmentos: |
def show(self): |
169 |
# Comprueba requisitos de fragmento |
try: |
170 |
if fragmento.__dict__.has_key("_texto_unico"): |
if not self._visitas[0].activo or len(self._fragmentos)==0: return |
171 |
hito = fragmento._texto_unico |
# Actualiza el estado parcial del dialogo (consumiendo el siguiente fragmento) |
172 |
print hito + " " + visita.hito(hito) |
pj = self._visitas[0].pj_activo |
173 |
if visita.hito(hito): |
fragmento = self._fragmentos[0] |
174 |
continue # Fragmento repetido |
visita = self._visitas[0] |
175 |
else: |
del self._fragmentos[0] |
176 |
self.timers.append(Timer(Mundo.timer_handler, timeout, lambda timer: visita.asignar_hito(hito))) |
del self.timers[0] |
177 |
|
# if not self._fragmentos: |
178 |
# Asigna temporizador para el fragmento |
# self.anular_conversacion() |
179 |
self._fragmentos.append(copy.copy(fragmento)) |
|
180 |
print "temporizado " + str(timeout) + " segundos: " + str(fragmento) |
if fragmento.clase() == "pregunta": |
181 |
self.timers.append(Timer(Mundo.timer_handler, timeout, lambda timer: self.show())) |
escribir(pj.nombre + " dice: " + fragmento.mensaje_formateado(visita, "otros")) |
182 |
timeout = timeout + fragmento.retardo() |
pj.hablar(fragmento.mensaje_formateado(visita, "otros"), Idioma_oestron) |
183 |
self.timers.append(Timer(Mundo.timer_handler, timeout, lambda timer: self.anular_conversacion())) |
pj.controlador.conn().send("Dices: " + pj.color_texto() + fragmento.mensaje_formateado(visita, "tu") + finl) |
184 |
|
elif fragmento.clase() == "respuesta": |
185 |
def show(self): |
escribir(self.__personaje.nombre + " dice: " + fragmento.mensaje_formateado(visita, "otros") + finl) |
186 |
try: |
self.__personaje.hablar(fragmento.mensaje_formateado(visita, "otros")) |
187 |
if not self._visitas[0].activo or len(self._fragmentos)==0: return |
elif fragmento.clase() == "hito": |
188 |
# Actualiza el estado parcial del dialogo (consumiendo el siguiente fragmento) |
visita.asignar_hito(fragmento._nombre, fragmento.mensaje_formateado(self, "otros")) |
189 |
pj = self._visitas[0].pj_activo |
elif fragmento.clase() == "redireccion": |
190 |
fragmento = self._fragmentos[0] |
self.anular_conversacion() |
191 |
visita = self._visitas[0] |
tema = fragmento.texto_xml().getAttribute("nombre").encode('ISO-8859-1') |
192 |
del self._fragmentos[0] |
respuesta = visita.responder(pj, "preguntar",tema.lower()) |
193 |
del self.timers[0] |
if respuesta["tema"]: |
194 |
# if not self._fragmentos: |
# La redirección no dispara mensajes de offtopic |
195 |
# self.anular_conversacion() |
self.temporizar(respuesta["tema"]._fragmentos) |
196 |
|
else: |
197 |
if fragmento.clase() == "pregunta": |
# Muestra mensajes de tema agotado o no encontrado |
198 |
escribir(pj.nombre + " dice: " + fragmento.mensaje_formateado(visita, "otros")) |
fragmentos = [] |
199 |
pj.hablar(fragmento.mensaje_formateado(visita, "otros"), Idioma_oestron) |
for item in respuesta["especiales"]: |
200 |
pj.controlador.conn().send("Dices: " + pj.color_texto() + fragmento.mensaje_formateado(visita, "tu") + finl) |
fragmentos = fragmentos + item._fragmentos |
201 |
elif fragmento.clase() == "respuesta": |
self.temporizar(fragmentos) |
202 |
escribir(self.__personaje.nombre + " dice: " + fragmento.mensaje_formateado(visita, "otros") + finl) |
else: |
203 |
self.__personaje.hablar(fragmento.mensaje_formateado(visita, "otros")) |
escribir("efecto especial de conversación: " + fragmento.mensaje_formateado(visita, "otros")) |
204 |
elif fragmento.clase() == "hito": |
self.__personaje.describir(fragmento.mensaje_formateado(visita, "otros")) |
205 |
visita.asignar_hito(fragmento._nombre, fragmento.mensaje_formateado(self, "otros")) |
except Exception: |
206 |
elif fragmento.clase() == "redireccion": |
# Conviene protegerse contra errores en carga de salas. No es bueno que por |
207 |
self.anular_conversacion() |
# un fichero de sala mal escrito pete el servidor entero o te eche de la |
208 |
tema = fragmento.texto_xml().getAttribute("nombre").encode('ISO-8859-1') |
# conexión. |
209 |
respuesta = visita.responder(pj, "preguntar",tema.lower()) |
escribir( "Ha saltado una excepcion al intentar mostrar un fragmento de conversación") |
210 |
if respuesta["tema"]: |
escribir_excepcion() |
211 |
# La redirección no dispara mensajes de offtopic |
|
212 |
self.temporizar(respuesta["tema"]._fragmentos) |
def anular_conversacion(self): |
213 |
else: |
self._fragmentos = [] |
214 |
# Muestra mensajes de tema agotado o no encontrado |
self._visitas[0].activo = None |
215 |
fragmentos = [] |
for timer in self.timers: |
216 |
for item in respuesta["especiales"]: |
# Anula los timers que no se han ejecutado aún, asignandoles la función nula |
217 |
fragmentos = fragmentos + item._fragmentos |
timer.timeout_func = lambda x: None |
218 |
self.temporizar(fragmentos) |
|
219 |
else: |
def sale_personaje(self, personaje, nombre_sala_destino): |
220 |
escribir("efecto especial de conversación: " + fragmento.mensaje_formateado(visita, "otros")) |
"""Metodo llamado cuando otro personaje sale de la misma sala. |
221 |
self.__personaje.describir(fragmento.mensaje_formateado(visita, "otros")) |
|
222 |
except Exception: |
personaje -- el personaje que sale. |
223 |
# Conviene protegerse contra errores en carga de salas. No es bueno que por |
nombre_sala_destino -- el nombre de la sala a donde va |
224 |
# un fichero de sala mal escrito pete el servidor entero o te eche de la |
""" |
225 |
# conexión. |
visita = self._visitas[0] |
226 |
escribir( "Ha saltado una excepcion al intentar mostrar un fragmento de conversación") |
if personaje == visita.pj_activo: |
227 |
escribir_excepcion() |
escribir("Conversacion anulada por abandono del hablante") |
228 |
|
self.anular_conversacion() |
229 |
def anular_conversacion(self): |
|
230 |
self._fragmentos = [] |
def old_conversa_personaje(self, dialogo, comando, nombretema): |
231 |
self._visitas[0].activo = None |
"""Metodo llamado cuando otro personaje habla con este PNJ""" |
232 |
for timer in self.timers: |
visita = self._visitas[0] |
233 |
# Anula los timers que no se han ejecutado aún, asignandoles la función nula |
respuesta = visita.responder(dialogo._DialogoNormal__personaje, comando, nombretema) |
234 |
timer.timeout_func = lambda x: None |
for item in respuesta: |
235 |
|
if type(item) == type(""): |
236 |
def sale_personaje(self, personaje, nombre_sala_destino): |
escribir(str(item)) |
237 |
"""Metodo llamado cuando otro personaje sale de la misma sala. |
else: |
238 |
|
for fragmento in item._fragmentos: |
239 |
personaje -- el personaje que sale. |
if fragmento.clase() == "pregunta": |
240 |
nombre_sala_destino -- el nombre de la sala a donde va |
dialogo._DialogoNormal__personaje.hablar(fragmento.mensaje_formateado(visita, "otros"), Idioma_oestron) |
241 |
""" |
dialogo.conn().send("Dices: " + fragmento.mensaje_formateado(visita, "tu")) |
242 |
visita = self._visitas[0] |
elif fragmento.clase() == "respuesta": |
243 |
if personaje == visita.pj_activo: |
self.personaje.hablar(fragmento.mensaje_formateado(visita, "otros"), Idioma_oestron) |
244 |
escribir("Conversacion anulada por abandono del hablante") |
else: |
245 |
self.anular_conversacion() |
self.personaje.describir(fragmento.mensaje_formateado(visita, "otros")) |
246 |
|
|
247 |
def old_conversa_personaje(self, dialogo, comando, nombretema): |
|
248 |
"""Metodo llamado cuando otro personaje habla con este PNJ""" |
|
249 |
visita = self._visitas[0] |
# Código para pruebas unitarias del módulo. |
250 |
respuesta = visita.responder(dialogo._DialogoNormal__personaje, comando, nombretema) |
|
251 |
for item in respuesta: |
if (__name__ == '__main__'): |
252 |
if type(item) == type(""): |
print "No hay código para pruebas unitarias del módulo. Para probar, ejecutar ambar.py" |
253 |
escribir(str(item)) |
print "y conectarse via telnet." |
|
else: |
|
|
for fragmento in item._fragmentos: |
|
|
if fragmento.clase() == "pregunta": |
|
|
dialogo._DialogoNormal__personaje.hablar(fragmento.mensaje_formateado(visita, "otros"), Idioma_oestron) |
|
|
dialogo.conn().send("Dices: " + fragmento.mensaje_formateado(visita, "tu")) |
|
|
elif fragmento.clase() == "respuesta": |
|
|
self.personaje.hablar(fragmento.mensaje_formateado(visita, "otros"), Idioma_oestron) |
|
|
else: |
|
|
self.personaje.describir(fragmento.mensaje_formateado(visita, "otros")) |
|
|
|
|
|
|
|
|
|
|
|
# Código para pruebas unitarias del módulo.
|
|
|
|
|
|
if (__name__ == '__main__'): |
|
|
print "No hay código para pruebas unitarias del módulo. Para probar, ejecutar ambar.py" |
|
|
print "y conectarse via telnet." |
|