#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# MUnDoCAAD MUD Engine
# Copyright (C) 2002-2008, 2021 José Manuel Ferrer Ortiz
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License version
# 3, as published by the Free Software Foundation.
#
# 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
# Affero General Public License version 3 for more details.
#
# You should have received a copy of the GNU Affero General Public
# License version 3 along with this program. If not, see
# <http://www.gnu.org/licenses/>.
import codecs
import locale
import sys
import traceback
import acciones
import archivero
import mensajero
import parsero
import restaurador
import servidor
# Ponemos la codificación del locale del sistema en la salida estándar, para reconocer y trabajar bien
# con las tildes, así como usar la codificación adecuada en la consola
reload (sys) # Necesario para poder ejecutar sys.setdefaultencoding
sys.stdout = codecs.getwriter (locale.getpreferredencoding()) (sys.stdout)
sys.setdefaultencoding ('iso-8859-15') # Nuestras cadenas están en esta codificación, no en ascii
print 'MUnDoCAAD MUD Engine'
print 'Copyright (C) 2002-2008, 2021 José Manuel Ferrer Ortiz\n'
if len (sys.argv) != 4:
print 'Uso: ' + sys.argv[0] + ' dirección puerto rutabbdd\n'
print 'dirección => dirección IP de la interfaz de red'
print 'puerto => número de puerto de escucha'
print 'rutabbdd => ruta al directorio con la base de datos del MUD'
sys.exit()
archivero.dir_datos = sys.argv[3]
mensajero.inicializa()
sirviente = servidor.Servidor ((sys.argv[1], int (sys.argv[2])))
print 'MUD lanzado satisfactoriamente, base de datos: ' + archivero.dir_datos
print 'A la escucha de conexiones en ' + sys.argv[1] + ':' + sys.argv[2]
fin = False
try:
while not fin:
# Dejamos que el sirviente maneje sus eventos
sirviente.ciclo()
# Eliminamos los jugadores que se han desconectado de mala manera
while servidor.saliendo:
personaje = servidor.saliendo.pop()
# Quitamos al personaje del juego
localidad = archivero.evaluaPropiedad (personaje, 'localidad')
acciones.partir (personaje, localidad, 'Red')
# Quitamos el personaje de la lista de jugadores
del mensajero.jugadores[personaje]
# Atendemos a los jugadores que están entrando al MUD
for conexion in frozenset (servidor.entrando):
indice = conexion.buffer_lect.find ('\n')
if indice == -1: # Aún no se ha introducido el nombre de personaje
continue
personaje = 'per_' + conexion.buffer_lect [:indice].strip().lower()
conexion.buffer_lect = '' # Omitimos lo que se hubiera escrito de más
localidad = archivero.evaluaPropiedad (personaje, 'localidad')
# Personaje inexistente o intento remoto de acceso con mi personaje
if (localidad == None) or \
(personaje == 'per_morgul' and conexion.direccion != sys.argv[1]):
conexion.buffer_escr += \
'Personaje inexistente\r\n\r\nNombre de personaje: '
if localidad:
print 'Intento de suplantación del administrador (Morgul) desde ' + \
conexion.direccion
elif (type (localidad) != str) or (localidad[:4] != 'loc_'):
conexion.buffer_escr += \
'Error: Personaje incorrecto\r\n\r\nNombre de personaje: '
print 'El personaje "' + personaje + \
'", no tiene una "localidad" válida'
elif personaje in mensajero.jugadores: # Ya está conectado
conexion.buffer_escr += \
'Ese personaje ya está jugando\r\n\r\nNombre de personaje: '
else: # Todo correcto, el jugador puede jugar con ese personaje
# Ańadimos el jugador a la lista de jugadores
servidor.entrando.remove (conexion)
mensajero.jugadores[personaje] = conexion
conexion.personaje = personaje
print 'El personaje', personaje, 'ha entrado desde', conexion.direccion
# Ańadimos el personaje al juego
acciones.recibir (personaje)
acciones.llegar (personaje, 'Red', localidad)
mensajero.enviaMensaje ([personaje], acciones.mirar (personaje, \
localidad, False), False)
# Procesamos las órdenes introducidas
for personaje, conexion in mensajero.jugadores.items():
indice = conexion.buffer_lect.find ('\n')
if indice == -1: # No se ha introducido ninguna orden
continue
# Sacamos la orden
orden = conexion.buffer_lect[:indice].strip()
conexion.buffer_lect = conexion.buffer_lect [indice + 1:]
# Analizamos y ejecutamos la orden
if orden:
mensaje = parsero.parsea (orden, personaje)
if mensaje == 1: # El jugador quiere apagar el MUD
print 'Cerrando el MUD por petición de ' + personaje
fin = True
elif mensaje == 2: # El jugador quiere terminar
conexion.buffer_escr += 'Esperamos que vuelvas pronto.\r\n'
conexion.cierrate()
del mensajero.jugadores[personaje]
else: # Mandamos el mensaje al jugador
mensajero.enviaMensaje ([personaje], mensaje, False)
# (else) Nada escrito
elif personaje not in mensajero.noprompt:
conexion.buffer_escr += '> '
# Dejamos que el restaurador restaure los módulos modificados
restaurador.restaura()
except:
print '\n' + traceback.format_exc()
# Para terminar siempre lo más limpiamente posible:
# Eliminamos a todos los personajes jugadores de sus localidades
for personaje in mensajero.jugadores:
localidad = archivero.evaluaPropiedad (personaje, 'localidad')
archivero.escribePropiedad (localidad, 'lista_pers', 1, \
archivero.evaluaPropiedad (localidad, 'lista_pers').difference \
([personaje]))
# Borramos a mano la caché de contenidos
# archivero.optimizar = True # De paso optimizamos la base de datos
del archivero.ccache
# Guardamos la configuración de los personajes
mensajero.salvaConfig()
print 'MUD cerrado satisfactoriamente'