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

Diff of /ambar/interfazpj.py

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

revision 2.4 by amoyav, Sun Oct 27 10:16:28 2002 UTC revision 2.5 by pabloruiz, Tue Nov 5 22:58:22 2002 UTC
# Line 1  Line 1 
1  #!/usr/bin/env python  #!/usr/bin/env python
2  #  #
3  #Minë. Mundo Interactivo-Narrativo en Español [Tierra-Media]  #Minë. Mundo Interactivo-Narrativo en Español [Tierra-Media]
4  #Copyright (C) 2002  Pablo Ruiz Múzquiz  #Copyright (C) 2002  Pablo Ruiz Múzquiz
5  #  #
6  #  #
7  #This program is free software; you can redistribute it and/or modify  #This program is free software; you can redistribute it and/or modify
8  #it under the terms of the GNU General Public License as published by  #it under the terms of the GNU General Public License as published by
9  #the Free Software Foundation; either version 2 of the License, or  #the Free Software Foundation; either version 2 of the License, or
10  #(at your option) any later version.  #(at your option) any later version.
11  #  #
12  #This program is distributed in the hope that it will be useful,  #This program is distributed in the hope that it will be useful,
13  #but WITHOUT ANY WARRANTY; without even the implied warranty of  #but WITHOUT ANY WARRANTY; without even the implied warranty of
14  #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  #GNU General Public License for more details.  #GNU General Public License for more details.
16  #  #
17  #You should have received a copy of the GNU General Public License  #You should have received a copy of the GNU General Public License
18  #along with this program; if not, write to the Free Software  #along with this program; if not, write to the Free Software
19  #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  #  #
21  #  #
22  #Fichero: interfazpj.py  #Fichero: interfazpj.py
23    
24  """Clase InterfazPJ."""  """Clase InterfazPJ."""
25    
26  from controlador import *  from controlador import *
27  from connection import *  from connection import *
28  from dialogo import *  from dialogo import *
29  from dialogoinicial import *  from dialogoinicial import *
30  from mundo import *  from mundo import *
31  from utils import *  from utils import *
32    
33    
34  class InterfazPJ(Controlador):  class InterfazPJ(Controlador):
35      """Interfaz que interactúa con el jugador a través de una conexion socket.      """Interfaz que interactúa con el jugador a través de una conexion socket.
36    
37      Controla directamente a una instancia de clase PersonajeJugador. Por ello,      Controla directamente a una instancia de clase PersonajeJugador. Por ello,
38      implementa el interfaz Controlador y recibe todos los eventos generados      implementa el interfaz Controlador y recibe todos los eventos generados
39      por los personajes. También recibe los eventos del socket.      por los personajes. También recibe los eventos del socket.
40                    
41      Una vez inicializada, crea un dialogo con el jugador y le pasa el control.      Una vez inicializada, crea un dialogo con el jugador y le pasa el control.
42      Todos los eventos recibidos se los pasa al dialogo actual, y éste responde a      Todos los eventos recibidos se los pasa al dialogo actual, y éste responde a
43      los mismos. La respuesta puede incluir cambiar a otro dialogo distinto.      los mismos. La respuesta puede incluir cambiar a otro dialogo distinto.
44    
45      También se encarga de recibir los ticks del reloj global de Mundo, y pasárselos      También se encarga de recibir los ticks del reloj global de Mundo, y pasárselos
46      al diálogo si éste los acepta.      al diálogo si éste los acepta.
47            
48      Contiene los siguientes atributos:      Contiene los siguientes atributos:
49            
50       - __conn (Connection): la conexion por la cual se comunica       - __conn (Connection): la conexion por la cual se comunica
51       - __personaje (Personaje): el personaje que controlamos       - __personaje (Personaje): el personaje que controlamos
52       - __dialogo (Dialogo): el dialogo actual con el jugador       - __dialogo (Dialogo): el dialogo actual con el jugador
53            
54       Invariantes:       Invariantes:
55         __conn != None         __conn != None
56         __dialogo != None         __dialogo != None
57         __personaje != None -> __personaje.controlador == self         __personaje != None -> __personaje.controlador == self
58      """      """
59    
60      def __init__(self, conn):      def __init__(self, conn):
61          """Crea un interfaz nuevo para una conexión de socket.          """Crea un interfaz nuevo para una conexión de socket.
62    
63          Requiere:          Requiere:
64            conn != None            conn != None
65          """          """
66          self.__conn = conn          self.__conn = conn
67          self.__conn.receive_callback = self.comando_recibido          self.__conn.receive_callback = self.comando_recibido
68          self.__conn.error_callback = self.error_de_conexion          self.__conn.error_callback = self.error_de_conexion
69          self.__personaje = None          self.__personaje = None
70          self.__dialogo = DialogoInicial(self, self.__conn)          self.__dialogo = DialogoInicial(self, self.__conn)
71    
72          Mundo_suscribirse_al_tick(self.tick_recibido)          Mundo_suscribirse_al_tick(self.tick_recibido)
73    
74    
75      def __del__(self):      def __del__(self):
76          """Realiza ajustes automáticos al ser destruido."""          """Realiza ajustes automáticos al ser destruido."""
77          self.desconectar()          self.desconectar()
78          Mundo_borrarse_del_tick(self.tick_recibido)          Mundo_borrarse_del_tick(self.tick_recibido)
79    
80            
81      def conn(self):      def conn(self):
82          return self.__conn          return self.__conn
83    
84    
85      def personaje(self):      def personaje(self):
86          return self.__personaje          return self.__personaje
87    
88    
89      def controlar_personaje(self, personaje):      def controlar_personaje(self, personaje):
90          """Pasar a estar controlando un personaje.          """Pasar a estar controlando un personaje.
91                    
92          Requiere:          Requiere:
93            self.__personaje == None            self.__personaje == None
94            personaje != None            personaje != None
95          """          """
96          self.__personaje = personaje          self.__personaje = personaje
97          self.__personaje.controlar(self)          self.__personaje.controlar(self)
98    
99    
100      def liberar_personaje(self):      def liberar_personaje(self):
101          """Soltar al personaje actual y dejarlo libre.          """Soltar al personaje actual y dejarlo libre.
102    
103          Requiere:          Requiere:
104            self.__personaje != None            self.__personaje != None
105          """          """
106          escribir("La conexión desde " + self.__conn.ip + " ha liberado al personaje " + self.__personaje.id)          escribir("La conexión desde " + self.__conn.ip + " ha liberado al personaje " + self.__personaje.id)
107          self.__personaje.liberar()          self.__personaje.liberar()
108          self.__personaje = None          self.__personaje = None
109                    
110    
111      def terminar(self):      def terminar(self):
112          """Soltar al personaje y volver al estado inicial."""          """Soltar al personaje y volver al estado inicial."""
113          if self.__personaje != None:          if self.__personaje != None:
114              self.liberar_personaje()              self.liberar_personaje()
115    
116          if not isinstance(self.__dialogo, DialogoInicial):          if not isinstance(self.__dialogo, DialogoInicial):
117              self.__dialogo = DialogoInicial(self, self.__conn)              self.__dialogo = DialogoInicial(self, self.__conn)
118    
119    
120      def desconectar(self):      def desconectar(self):
121          """Soltar al personaje, desconectar la conexión y destruir el interfaz."""          """Soltar al personaje, desconectar la conexión y destruir el interfaz."""
122          if self.__personaje != None:          if self.__personaje != None:
123              self.liberar_personaje()              self.liberar_personaje()
124    
125          if self.__dialogo != None:          if self.__dialogo != None:
126              self.__dialogo = None              self.__dialogo = None
127            
128          if self.__conn.is_open:          if self.__conn.is_open:
129              # Desconectar ordenadamente.              # Desconectar ordenadamente.
130              self.__conn.send("Adiós, vuelve pronto...")              self.__conn.send("Adiós, vuelve pronto...")
131              sleep(1)              sleep(1)
132              self.__conn.close()              self.__conn.close()
133              escribir("Se ha cerrado normalmente la conexión desde " + self.__conn.ip)              escribir("Se ha cerrado normalmente la conexión desde " + self.__conn.ip)
134    
135          # En este punto la conexión por socket está cerrada, y el handler          # En este punto la conexión por socket está cerrada, y el handler
136          # se ocupa de destruir el InterfazPJ.          # se ocupa de destruir el InterfazPJ.
137    
138    
139                    
140      # ---------------------------------------      # ---------------------------------------
141      # Eventos del controlador de un personaje      # Eventos del controlador de un personaje
142      # ---------------------------------------      # ---------------------------------------
143            
144      def entra_personaje(self, personaje):      def entra_personaje(self, personaje):
145          self.__dialogo.entra_personaje(personaje)          self.__dialogo.entra_personaje(personaje)
146                                                    
147                                                    
148      def sale_personaje(self, personaje, nombre_sala_destino):      def sale_personaje(self, personaje, nombre_sala_destino):
149          self.__dialogo.sale_personaje(personaje, nombre_sala_destino)          self.__dialogo.sale_personaje(personaje, nombre_sala_destino)
150                                                    
151                                                    
152      def habla_personaje(self, personaje, mensaje):      def habla_personaje(self, personaje, mensaje):
153          self.__dialogo.habla_personaje(personaje, mensaje)          self.__dialogo.habla_personaje(personaje, mensaje)
154    
155                    
156      def susurra_personaje(self, personaje, mensaje):      def susurra_personaje(self, personaje, mensaje):
157          self.__dialogo.susurra_personaje(personaje, mensaje)          self.__dialogo.susurra_personaje(personaje, mensaje)
158    
159                    
160      def grita_personaje(self, personaje, mensaje):      def grita_personaje(self, personaje, mensaje):
161          self.__dialogo.grita_personaje(personaje, mensaje)          self.__dialogo.grita_personaje(personaje, mensaje)
162    
163    
164      def actua_personaje(self, personaje, accion):      def actua_personaje(self, personaje, accion):
165          self.__dialogo.actua_personaje(personaje, accion)          self.__dialogo.actua_personaje(personaje, accion)
166    
167    
168      def actua_individual_personaje(self, personaje, accion):      def actua_individual_personaje(self, personaje, accion):
169          self.__dialogo.actua_individual_personaje(personaje, accion)          self.__dialogo.actua_individual_personaje(personaje, accion)
170                                                    
171                                                    
172      def actua_uno_mismo(self, accion):      def actua_uno_mismo(self, accion):
173          self.__dialogo.actua_uno_mismo(accion)          self.__dialogo.actua_uno_mismo(accion)
174                                                    
175    
176      def actua_global_personaje(self, personaje, accion):      def actua_global_personaje(self, personaje, accion):
177          self.__dialogo.actua_global_personaje(personaje, accion)          self.__dialogo.actua_global_personaje(personaje, accion)
178                                                        
179                                                    
180      def suceso_entorno(self, mensaje):      def suceso_entorno(self, mensaje):
181          self.__dialogo.suceso_entorno(mensaje)          self.__dialogo.suceso_entorno(mensaje)
182                
183    
184      def ataca_personaje(self, personaje, result):      def ataca_personaje(self, personaje, result):
185          self.__dialogo.ataca_personaje(personaje, result)          self.__dialogo.ataca_personaje(personaje, result)
186                    
187            
188      def movimiento_automatico(self):      def movimiento_automatico(self):
189          self.__dialogo.movimiento_automatico()          self.__dialogo.movimiento_automatico()
190    
191    
192      # ------------------------------      # ------------------------------
193      # Tick del reloj global de Mundo      # Tick del reloj global de Mundo
194      # ------------------------------      # ------------------------------
195                
196      def tick_recibido(self, tick_ahora, tick_anterior):      def tick_recibido(self, tick_ahora, tick_anterior):
197          """Responde al tick llamando al diálogo si éste implementa la función."""          """Responde al tick llamando al diálogo si éste implementa la función."""
198    
199          try:          try:
200    
201              # Luego llamamos a la funcion correspondiente segun estado              # Luego llamamos a la funcion correspondiente segun estado
202              nombre_func = "tick_" + str(self.__dialogo.estado())              nombre_func = "tick_" + str(self.__dialogo.estado())
203              func = getattr(self.__dialogo, nombre_func, None)              func = getattr(self.__dialogo, nombre_func, None)
204              if func != None:              if func != None:
205                  nuevo_dialogo = func(tick_ahora, tick_anterior)                  nuevo_dialogo = func(tick_ahora, tick_anterior)
206    
207                  # Si hay que cambiar de dialogo, hacerlo                  # Si hay que cambiar de dialogo, hacerlo
208                  if nuevo_dialogo != None:                  if nuevo_dialogo != None:
209                      self.__dialogo = nuevo_dialogo                      self.__dialogo = nuevo_dialogo
210    
211          except:          except:
212                    
213              # No deben ocurrir excepciones no tratadas salvo por un bug del              # No deben ocurrir excepciones no tratadas salvo por un bug del
214              # programa. Aquí se interceptan para que un bug afecte, si es posible,              # programa. Aquí se interceptan para que un bug afecte, si es posible,
215              # sólo a la conexión que lo ha hecho saltar, pero no se caiga el              # sólo a la conexión que lo ha hecho saltar, pero no se caiga el
216              # servidor entero.              # servidor entero.
217              #              #
218              # Si ocurre esto, desconectamos al jugador de su personaje, pero              # Si ocurre esto, desconectamos al jugador de su personaje, pero
219              # mantenemos la conexión abierta por si quiere volverlo a intentar.              # mantenemos la conexión abierta por si quiere volverlo a intentar.
220    
221              escribir("Excepción imprevista durante el tick del reloj global.")              escribir("Excepción imprevista durante el tick del reloj global.")
222              escribir(" -> conexión desde " + self.__conn.ip)              escribir(" -> conexión desde " + self.__conn.ip)
223              escribir(" -> tick ahora " + str(tick_ahora))              escribir(" -> tick ahora " + str(tick_ahora))
224              escribir(" -> tick anterior " + str(tick_anterior))              escribir(" -> tick anterior " + str(tick_anterior))
225              escribir(" -> dialogo " + str(self.__dialogo.__class__))              escribir(" -> dialogo " + str(self.__dialogo.__class__))
226              if self.__personaje != None:              if self.__personaje != None:
227                  escribir(" -> personaje " + self.__personaje.id)                  escribir(" -> personaje " + self.__personaje.id)
228              escribir_excepcion()              escribir_excepcion()
229    
230              try:              try:
231    
232                  self.__conn.send("\n\nHa ocurrido un error imprevisto en Mine, probablemente se trate")                  self.__conn.send("\n\nHa ocurrido un error imprevisto en Mine, probablemente se trate")
233                  self.__conn.send("de un fallo en el programa. Por favor, ponte en contacto con los")                  self.__conn.send("de un fallo en el programa. Por favor, ponte en contacto con los")
234                  self.__conn.send("administadores del juego y explicales, si es posible, toda la")                  self.__conn.send("administadores del juego y explicales, si es posible, toda la")
235                  self.__conn.send("información que tengas sobre lo que estabas haciendo en el momento")                  self.__conn.send("información que tengas sobre lo que estabas haciendo en el momento")
236                  self.__conn.send("del error. Gracias, y disculpa por las molestias.")                  self.__conn.send("del error. Gracias, y disculpa por las molestias.")
237    
238                  self.terminar()                  self.terminar()
239    
240              except:              except:
241                                    
242                  # Si no se puede salir del personaje normalmente, tiramos la                  # Si no se puede salir del personaje normalmente, tiramos la
243                  # conexión del todo.                  # conexión del todo.
244                  escribir("Problema gordo: no se puede mantener la conexión. La tiramos...")                  escribir("Problema gordo: no se puede mantener la conexión. La tiramos...")
245                  self.desconectar()                  self.desconectar()
246    
247                    
248      # ------------------      # ------------------
249      # Eventos del socket      # Eventos del socket
250      # ------------------      # ------------------
251    
252      def comando_recibido(self, conn):      def comando_recibido(self, conn):
253          """Responde a la recepcion de un mensaje del usuario."""          """Responde a la recepcion de un mensaje del usuario."""
254    
255          cmd_list = []          cmd_list = []
256    
257          try:          try:
258    
259              # Primero lo convertimos en una lista para manejar las palabras              # Primero lo convertimos en una lista para manejar las palabras
260              # mas comodamente. De paso, nos cargamos el \n del final.              # mas comodamente. De paso, nos cargamos el \n del final.
261              cmd_list = conn.receive().split()              cmd_list = conn.receive().split()
262    
263              # Luego llamamos a la funcion correspondiente segun estado              # Luego llamamos a la funcion correspondiente segun estado
264              nombre_func = "comando_" + str(self.__dialogo.estado())              nombre_func = "comando_" + str(self.__dialogo.estado())
265              func = getattr(self.__dialogo, nombre_func)              func = getattr(self.__dialogo, nombre_func)
266              nuevo_dialogo = func(cmd_list)              nuevo_dialogo = func(cmd_list)
267    
268              # Si hay que cambiar de dialogo, hacerlo              # Si hay que cambiar de dialogo, hacerlo
269              if nuevo_dialogo != None:              if nuevo_dialogo != None:
270                  self.__dialogo = nuevo_dialogo                  self.__dialogo = nuevo_dialogo
271    
272          except:          except:
273                    
274              # No deben ocurrir excepciones no tratadas salvo por un bug del              # No deben ocurrir excepciones no tratadas salvo por un bug del
275              # programa. Aquí se interceptan para que un bug afecte, si es posible,              # programa. Aquí se interceptan para que un bug afecte, si es posible,
276              # sólo a la conexión que lo ha hecho saltar, pero no se caiga el              # sólo a la conexión que lo ha hecho saltar, pero no se caiga el
277              # servidor entero.              # servidor entero.
278              #              #
279              # Si ocurre esto, desconectamos al jugador de su personaje, pero              # Si ocurre esto, desconectamos al jugador de su personaje, pero
280              # mantenemos la conexión abierta por si quiere volverlo a intentar.              # mantenemos la conexión abierta por si quiere volverlo a intentar.
281    
282              escribir("Excepción imprevista durante la ejecución de un comando.")              escribir("Excepción imprevista durante la ejecución de un comando.")
283              escribir(" -> conexión desde " + self.__conn.ip)              escribir(" -> conexión desde " + self.__conn.ip)
284              escribir(" -> comando " + " ".join(cmd_list))              escribir(" -> comando " + " ".join(cmd_list))
285              escribir(" -> dialogo " + str(self.__dialogo.__class__))              escribir(" -> dialogo " + str(self.__dialogo.__class__))
286              if self.__personaje != None:              if self.__personaje != None:
287                  escribir(" -> personaje " + self.__personaje.id)                  escribir(" -> personaje " + self.__personaje.id)
288              escribir_excepcion()              escribir_excepcion()
289    
290              try:              try:
291    
292                  self.__conn.send("\n\nHa ocurrido un error imprevisto en Mine, probablemente se trate")                  self.__conn.send("\n\nHa ocurrido un error imprevisto en Mine, probablemente se trate")
293                  self.__conn.send("de un fallo en el programa. Por favor, ponte en contacto con los")                  self.__conn.send("de un fallo en el programa. Por favor, ponte en contacto con los")
294                  self.__conn.send("administadores del juego y explicales, si es posible, toda la")                  self.__conn.send("administadores del juego y explicales, si es posible, toda la")
295                  self.__conn.send("información que tengas sobre lo que estabas haciendo en el momento")                  self.__conn.send("información que tengas sobre lo que estabas haciendo en el momento")
296                  self.__conn.send("del error. Gracias, y disculpa por las molestias.")                  self.__conn.send("del error. Gracias, y disculpa por las molestias.")
297    
298                  self.terminar()                  self.terminar()
299    
300              except:              except:
301                                    
302                  # Si no se puede salir del personaje normalmente, tiramos la                  # Si no se puede salir del personaje normalmente, tiramos la
303                  # conexión del todo.                  # conexión del todo.
304                  escribir("Problema gordo: no se puede mantener la conexión. La tiramos...")                  escribir("Problema gordo: no se puede mantener la conexión. La tiramos...")
305                  self.desconectar()                  self.desconectar()
306    
307    
308      def error_de_conexion(self, conn):      def error_de_conexion(self, conn):
309          """Responde al evento de perdida de conexion por el socket."""          """Responde al evento de perdida de conexion por el socket."""
310          escribir("Se ha caido bruscamente la conexion con " + self.__conn.ip)          escribir("Se ha caido bruscamente la conexion con " + self.__conn.ip)
311          self.desconectar()          self.desconectar()
312    
313    
314  # Código para pruebas unitarias del módulo.  # Código para pruebas unitarias del módulo.
315    
316  if (__name__ == '__main__'):  if (__name__ == '__main__'):
317      print "No hay código para pruebas unitarias del módulo."      print "No hay código para pruebas unitarias del módulo."
318      print "Para probar, ejecutar mine.py y conectarse via telnet."      print "Para probar, ejecutar mine.py y conectarse via telnet."
319    

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

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