def render_GET(self, request, conn): from_number, to_number, message = self.get_from_to_numbers(request) if from_number == -1 or to_number == -1: return message # Viene creato un semilavorato in maniera tale che si possano eseguire # eventuali sostituzioni anche nel testo delle news semifinished = self.PAGE_TEMPLATE.safe_substitute({"news" : self.create_news(conn, from_number, to_number)}) mapping = {"game_name" : config.game_name, "game_name_nocolor" : remove_colors(config.game_name), "motto_nocolor" : remove_colors(config.motto)} return string.Template(semifinished).safe_substitute(mapping)
def render_POST(self, request, conn): # Ricava gli argomenti del form dalla richiesta email = "" if "email": email = request.args["email"][0].lower() if not email: return self.create_page(request, conn, "", False) # Cerca la mail tra quella degli account for account in database["accounts"].itervalues(): if account.email == email: break else: return self.create_page(request, conn, email, False) preposition = "a" game_name = remove_colors(config.game_name) if is_vowel(game_name[0]): preposition = "ad" subject = "[%s] Richiesta di recupero utente e password." % game_name.upper() message = "Nome utente: %s\n" % account.name message += "Password: %s\n" % account.password message += "Potete eseguire l'accesso %s %s dalla pagina:\n" % (preposition, game_name) message += "%s/login.html\n" % config.site_address mail.send(account.email, subject, message) return self.create_page(request, conn, email, True)
def render_GET(self, request, conn): disabled = "" if engine.test_inputs_mode: disabled = ''' disabled="disabled"''' mapping = {"game_name" : config.game_name, "game_name_nocolor" : remove_colors(config.game_name), "disabled" : disabled} return self.PAGE_TEMPLATE.safe_substitute(mapping)
def talk_channel(entity, channel, argument): """ Gestisce i canali off rpg. """ if not entity: log.bug("entity non è un parametro valido: %r" % entity) return False if not channel: log.bug("channel non è un parametro valido: %r" % channel) return False # argument può essere una stringa vuota # ------------------------------------------------------------------------- if not argument or not remove_colors(argument): entity.send_output("Con che messaggio vorresti %s?" % channel) return False if len(argument) > config.max_google_translate: entity.send_output("Non puoi %s un messaggio più lungo di %d caratteri" % (channel, config.max_google_translate)) return False argument = convert_urls(argument) for player in database["players"].itervalues(): if not player.game_request: continue if player == entity: continue if player.trust < channel.trust: continue message = "<br>%s%s: '%s'" % (entity.name, channel.verb_it, argument) send_channel_message(player, message, False) player.send_prompt() message = "%s: '%s'" % (channel.verb_you, argument) send_channel_message(entity, message, True) if channel == CHANNEL.CHAT: check_for_badwords(entity, argument) log.chat("%s %s: %s\n" % (datetime.datetime.now(), remove_colors(entity.name), remove_colors(argument))) return True
def get_permissions(self): rows = [] for player in sorted(database["players"].values(), key=lambda player: remove_colors(player.name)): if player.permissions: rows.append('''<tr><td>%s</td><td>%s</td><td>%s</td></tr>''' % (player.name, player.permissions, player.account.name)) if rows: return "".join(rows) else: return '''<tr><td colspan="3">Nessuno</td></tr>'''
def render_GET(self, request, conn): race_options = "" for race in RACE.sort_playable_first(): name = remove_colors(race.name.replace("$o", "o")) race_options += '''\t<option value="%s">%s</option>\n''' % (name, name) social_options = "" for social in sorted(database["socials"].values()): social_name = social.fun_name[len("social_") : ] social_options += '''\t<option value="%s">%s</option>\n''' % (social_name, social_name) mapping = {"race_options" : race_options, "social_options" : social_options} return self.PAGE_TEMPLATE.safe_substitute(mapping)
def grammar_cleaner(argument): """ Passato un argomento ne ritorna la prima parola in minuscolo e senza caratteri di colore che potrebbero interferire con le funzioni grammaticali qui sotto. """ if not argument: log.bug("argument non è un parametro valido: %r" % argument) return "" # ------------------------------------------------------------------------- first_word = argument.split()[0] return remove_colors(first_word).lower()
def render_POST(self, request, conn): aliases = {} # Ricava gli argomenti del form dalla richiesta for arg in request.args: if arg.startswith("name_"): alias = Alias() alias.name = request.args["name_%s" % arg[len("name_") : ]][0].lower().strip() alias.action = request.args["action_%s" % arg[len("name_") : ]][0].strip() if alias.name: alias.name = remove_colors(alias.name) if " " in alias.action: input, argument = alias.action.split(None, 1) alias.action = "%s %s" % (remove_colors(input), argument) if alias.name and alias.action: aliases[alias.name] = alias # (TD) unire questa parte alla parte sopra che è praticamente uguale if arg.startswith("new_name_"): alias = Alias() alias.name = request.args["new_name_%s" % arg[len("new_name_") : ]][0].lower().strip() alias.action = request.args["new_action_%s" % arg[len("new_name_") : ]][0].strip() if alias.name: alias.name = remove_colors(alias.name) if " " in alias.action: input, argument = alias.action.split(None, 1) alias.action = "%s %s" % (remove_colors(input), argument) if alias.name and alias.action: aliases[alias.name] = alias # Sostituisce gli aliases vecchi con quelli ricavati dal post conn.account.aliases = aliases return self.create_page(request, conn)
def clean_string(argument): if not argument: log.bug("argument non è un parametro valido: %r" % argument) return "" # ------------------------------------------------------------------------- argument = remove_accents(argument) if "[" in argument: global remove_colors if not remove_colors: from src.color import remove_colors argument = remove_colors(argument) return argument.lower()
def create_random_player(name="", level=0, race=RACE.NONE, sex=SEX.NONE, way=WAY.NONE): """ Crea un personaggio con caratteristiche casuali, serve principalmente per testing, per esempio per creare due personaggi che combattano tra loro. """ if not name and name != "": log.bug("name non è un parametro valido: %r" % name) return if level < 0 or level > config.max_level: log.bug("level non è un parametro valido: %d" % level) return if not race: log.bug("race non è un parametro valido: %r" % race) return if not sex: log.bug("sex non è un parametro valido: %r" % sex) return if not way: log.bug("way non è un parametro valido: %r" % way) return # ------------------------------------------------------------------------- player = Player() player = create_random_mob(player, name, level, race, sex, way) # Ora che player possiede una razza ed un sesso può creare un nome # casuale se questo non è stato passato if not player.name: player.name = create_random_name(player.race, player.sex, is_player_name=True) player.code = remove_colors(player.name.lower()) # Crea il giocatore con i dati di base # (TD) dovrei impostare casualmente tanti altri attributi player.flags.randomize() create_random_reputations(player) return player
def spelling(self, dictionary=None, typos_file=None): if dictionary is None or typos_file is None: from src.database import database if not dictionary: dictionary = database.spelling_dictionary if not typos_file: typos_file = database.load_typos_file() for attr_name in ("descr", "descr_night", "descr_hearing", "descr_hearing_night", "descr_smell", "descr_smell_night", "descr_touch", "descr_touch_night", "descr_taste", "descr_taste_night", "descr_sixth", "descr_sixth_night"): text = getattr(self, attr_name) if not text: continue text = remove_colors(text) if not text: log.bug("testo dell'attributo %s del dato %s con solo il colore" % (attr_name, self.code)) continue if "$o" in text: text = text.replace("$o", "o") if "$O" in text: text = text.replace("$O", "o") words = text.split() for word in reversed(words): if "'" in word and word[0] != "'" and word[-1] != "'": if word.lower() != "po'": words.remove(word) words += word.split("'") for word in words: word = word.rstrip(",;.!?") if not word: log.bug("Punteggiatura isolata per l'attributo %s al dato %s" % (attr_name, self.code)) continue if not word.isalpha(): continue if word not in dictionary: word = word.lower() if word not in dictionary: typos_file.write("%s (%s)\n" % (word, self.code))
def render_GET(self, request, conn): max_help_types = len(HELP.elements) for help_element in HELP.elements: if (conn.player and help_element.trust > conn.player.trust or conn.account and help_element.trust > conn.account.trust or not conn.account and not conn.player and help_element.trust > TRUST.PLAYER): max_help_types -= 1 half_help_types = max_help_types / 2 + max_help_types % 2 help_types = [] help_types.append('''<table class="mud" align="center" width="100%"><tr>''') help_types.append('''<td valign="top"><ul>''') help_types += self._render_help_types_list(0, half_help_types) help_types.append('''</ul></td>''') help_types.append('''<td valign="top"><ul>''') help_types += self._render_help_types_list(half_help_types, max_help_types) help_types.append('''</ul></td>''') help_types.append('''</tr></table>''') mapping = {"game_name" : config.game_name, "game_name_nocolor" : remove_colors(config.game_name), "help_types" : "".join(help_types)} return self.PAGE_TEMPLATE.safe_substitute(mapping)
def put_final_dot(argument, char="."): """ Aggiunge, se ce n'è bisogno, un punto a fine stringa. """ if not argument: log.bug("argument non è un parametro valido: %r" % argument) return "" # ------------------------------------------------------------------------- argument_without_css = argument if "[" in argument: global remove_colors if not remove_colors: from src.color import remove_colors argument_without_css = remove_colors(argument) if not argument_without_css: log.bug("argument_without_css non è valido: %r" % argument_without_css) return "" if argument_without_css[-1].isalnum(): argument += char return argument
def start(self): from src.calendar import calendar from src.config import config from src.database import database from src.log import log starting_time = time.time() self.booting = True log.platform_infos() print "Cancella tutti i file compilati per forzarne la ricompilazione" remove_compiled_files() try: # Dona maggiori informazioni sotto gli OS Linux e simili log.booting("Avvio del gioco sul server %s per l'utente %s al gruppo %s" % (socket.gethostname(), os.geteuid(), os.getgid())) except: log.booting("Avvio del gioco sul server %s" % socket.gethostname()) log.booting("===========================================================================") log.booting("Carica il file di configurazione %s" % self.options.config_filename) config.load(self.options.config_filename) self.check_the_mode() log.booting("Carica la data del calendario gdr") calendar.load() from src.entity import load_little_words log.booting("Carica da file le little words da utilizzare per filtrare le keywords") load_little_words() from src.account import load_forbidden_names log.booting("Carica da file la lista dei nomi proibiti per nuovi account e giocatori") load_forbidden_names() log.booting("Carica tutti gli input nelle differenti lingue") from src.database import fread_list from src.input import Input import src.interpret as interpret_module interpret_module.inputs_command_it = fread_list("data/inputs_command_it.list", Input, "inputs_command_it[%d]") interpret_module.inputs_command_en = fread_list("data/inputs_command_en.list", Input, "inputs_command_en[%d]") interpret_module.inputs_skill_it = fread_list("data/inputs_skill_it.list", Input, "inputs_skill_it[%d]") interpret_module.inputs_skill_en = fread_list("data/inputs_skill_en.list", Input, "inputs_skill_en[%d]") interpret_module.inputs_social_it = fread_list("data/inputs_social_it.list", Input, "inputs_social_it[%d]") interpret_module.inputs_social_en = fread_list("data/inputs_social_en.list", Input, "inputs_social_en[%d]") # (TD) per ora inutilizzato #from grammar import vocabulary, EntryWord #log.booting("Caricamento del vocabolario grammaticale") #vocabulary = fread_list("data/vocabulary.list", EntryWord, "vocabulary[%d]") from src.database import database log.booting("Carica il Database:") database.load(use_spelling=self.options.spelling) from src.gamescript import create_init_files log.booting("Si assicura dell'esistenza dei file __init__ per importare i gamescript") create_init_files("data", ("proto_rooms", "proto_mobs", "proto_items")) create_init_files("persistence", ("rooms", "mobs", "items", "players")) from src.gamescript import import_all_proto_gamescripts log.booting("Aggiunge i riferimenti ai gamescript dei dati prototipo") import_all_proto_gamescripts("data", ("proto_rooms", "proto_mobs", "proto_items")) from src.gamescript import import_all_instance_gamescripts log.booting("Aggiunge i riferimenti ai gamescript dei dati delle istanze") import_all_instance_gamescripts("persistence", ("rooms", "mobs", "items")) import_all_instance_gamescripts("data", ("players", )) from src.gamescript import import_all_area_gamescripts log.booting("Aggiunge i riferimenti ai gamescript delle aree") import_all_area_gamescripts() from src.games.wumpus import import_all_wumpus_gamescripts log.booting("Aggiunge i riferimenti ai gamescript delle aree wumpus") import_all_wumpus_gamescripts() from src.site import site log.booting("Prepara il web server del gioco") reactor.listenTCP(config.http_port, site) from src.forum_db import forum_db log.booting("Carica il Forum") forum_db.load() # (TD) molto in futuro saranno più di una from src.wild import load_wild log.booting("Carica le informazioni sulla Wild") #load_wild() from src.element import create_elements_list_page log.booting("Crea dinamicamente la pagina web della lista degli elementi") create_elements_list_page() from src.fight import create_damages_page log.booting("Crea dinamicamente la pagina web della lista dei danni") create_damages_page() from src.reset import finalize_room_resets log.booting("Inizializza eventuali valori impliciti nella date dei reset.") finalize_room_resets() from src.reset import start_repop_laters log.booting("Prepara le informazioni di repop per tutti i dati caricati dalla persistenza") start_repop_laters() from src.reset import defer_all_reset_events log.booting("Prepara le aree in gioco eseguendo i primi reset.") defer_all_reset_events() from src.entitypes.plant import restart_all_planting log.booting("Rinizia da capo eventuali stadi di crescita lasciati a metà dal precedente shutdown.") restart_all_planting() from src.loops.aggressiveness import aggressiveness_loop from src.loops.blob import blob_loop from src.entitypes.corpse import decomposer_loop from src.loops.digestion import digestion_loop from src.fight import fight_loop from src.game import game_loop from src.maintenance import maintenance_loop from src.behaviour import room_behaviour_loop log.booting("Avvia tutti i loop") aggressiveness_loop.start() blob_loop.start() decomposer_loop.start() digestion_loop.start() fight_loop.start() game_loop.start() maintenance_loop.start() room_behaviour_loop.start() from src.gamescript import triggering_on_booting log.booting("Attivazione dei trigger on_booting") triggering_on_booting() log.booting("Finalizza e controlla la configurazione caricata precedentemente.") config.finalize() config.get_error_message() log.booting("Esegue un controllo al nome dei metodi della singleton log.") log.check_log_methods() # Se sono stati trovati degli errori sui riferimenti, controllati dal # metodo _search_the_reference o altri tipo di errori pesanti o # bloccanti, allora blocca il boot del gioco, a meno che non sia stato # avviato ignorando esplicitamente tale cosa if self.critical_errors > 0: if self.critical_errors > 1: message = "Sono stati riscontrati %d errori critici" % self.critical_errors elif self.critical_errors == 1: message = "E' stato riscontrato 1 errore critico" log.booting("===>> %s al caricamento del Gioco (ignora l'eventuale blocco dell'avvio con l'opzione d'avvio -i) <<===" % message) if self.options.mode == "official" and not self.options.ignore: sys.exit(1) log.booting("allow_web_robots=%s: le pagine %sverranno indicizzate dai motori di ricerca" % ( config.allow_web_robots, "NON " if not config.allow_web_robots else "")) self.boot_seconds = time.time() - starting_time log.booting("Esecuzione del boot in %d secondi" % self.boot_seconds) from src.color import remove_colors log.booting("Il gioco %s è pronto alla porta http %d" % (remove_colors(config.game_name), config.http_port)) if self.options.boot_only: print "Esecuzione del solo boot terminata." sys.exit(0) log.booting("===========================================================================") self.booting = False try: if config.use_profiler: log.booting("%s è stato avviato in modalità di profiling" % remove_colors(config.game_name)) now = datetime.datetime.now() cProfile.run("from twisted.internet import reactor; reactor.run()", "profile_%dy_%dm_%dd_%dh_%dm_%ds.results" % ( now.year, now.month, now.day, now.hour, now.minute, now.second)) else: reactor.run() except (KeyboardInterrupt, SystemExit): # Sono eccezioni accettabili e non comportano il reboot automatico pass except: self.automatic_reboot = True finally: self.stop() # Nel qual caso vi sia stato un'eccezione sconosciuta e che il # gioco sia quello ufficiale (e quindi è sottinteso che debba # sempre rimanere up and running) allora tenta di riavviarlo # con le stesse opzioni utilizzate per questa istanza morente if self.automatic_reboot and self.options.mode == "official": os.system("%s %s" % (sys.executable, " ".join(sys.argv)))
def command_tell(entity, argument=""): """ Permette di parlare con tutti nel Mud, in maniera off-gdr. """ if not entity: log.bug("entity non è un parametro valido: %r" % entity) return False # ------------------------------------------------------------------------- if not argument: entity.send_output("Vuoi %s a qualcuno che cosa?" % CHANNEL.TELL) if entity.IS_PLAYER and OPTION.NEWBIE in entity.account.options: syntax = get_command_syntax(entity, "command_tell") entity.send_output(syntax, break_line=False) return False # Qui per la ricerca di target non viene utilizzata la find_entity perché # deve cercare solo i giocatori online # (TD) oltre alla ricerca di admin che possiedono mob o oggetti arg, argument = one_argument(argument) target = search_for_player(entity, arg) if not target: # (TD) se non è stato tovato allora cerca tra gli identificativi # personali relativi ai personaggi invisibili (implementazione # alternativa del reply) entity.send_output("Non è stato trovato nessun giocatore con argomento [white]%s[close]" % arg) return False # (TD) possibile implementazione di NOTELL, anche se è preferibile punizione # classica di NO_ENTER_IN_GAME per tot giorni if entity == target: entity.send_output("Non puoi comunicare con [white]te stess$o[close]!") return False if not target.game_request: entity.send_output("Il giocatore [white]%s[close] è attualmente [darkslategray]offline[close]." % target.name) return False if not argument: entity.send_output("Che messaggio privato vorresti inviare a [white]%s[close]?" % target.name) return False channel_color = get_first_color(str(CHANNEL.TELL)) afk_status = "" if FLAG.AFK in target.flags: if entity.account and OPTION.ITALIAN in entity.account.options: afk_status = " (LDT)" else: afk_status = " (AFK)" if is_vowel(remove_colors(target.name)[0]): preposition = "ad" else: preposition = "a" entity.send_output("%s %s%s[close] %s: %s'%s'" % ( CHANNEL.TELL.verb_you, channel_color, preposition, target.name, afk_status, argument), avoid_snoop=True) # (TD) inviare anche il soft beep per avvertire che ha ricevuto un messaggio # ed aggiungere l'opzione apposita if target.get_conn().get_browser(): numbered_keyword = entity.get_numbered_keyword(looker=target) javascript = '''javascript:putInput('%s %s ');''' % (translate_input(target, "tell", "en"), numbered_keyword) target.send_output("""\n<a href="%s">%s%s ti[close]%s</a>: '%s'""" % (javascript, entity.name, channel_color, CHANNEL.TELL.verb_it, argument), avoid_snoop=True) else: target.send_output("""\n%s %sti[close]%s: '%s'""" % (entity.name, channel_color, CHANNEL.TELL.verb_it, argument), avoid_snoop=True) target.send_prompt() return True
def __init__(self, code="", who="", where="", when="", text=""): self.code = code self.who = remove_colors(who) if who else "" # Chi ha inviato la nota self.where = where # Da dove l'ha inviata self.when = remove_colors(when) if when else "" # Quando l'ha inviata self.text = text # Testo della nota
def clean_and_add_article(argument, type, genre=GRAMMAR.MASCULINE, number=GRAMMAR.SINGULAR): if not argument: log.bug("argument non è un parametro valido: %r" % argument) return "" if not type: log.bug("type non è un parametro valido: %r" % type) return "" if not genre: log.bug("genre non è un parametro valido: %r" % genre) return "" if not number: log.bug("number non è un parametro valido: %r" % number) return "" # ------------------------------------------------------------------------- colorless = remove_colors(argument) if not colorless: log.bug("la stringa %s è formata solo da colori" % argument) return "" # Ci sono casi particolari in cui non serve convertire aggiungendo un articolo # altrimenti vengono furoi cose come: # Posi un piccone nell'all'interno delle miniere. if type == GRAMMAR.PREPOSITION_IN and colorless[ : 4] in ("all'", "alla", "agli", "alle"): return argument if colorless[ : 6] in ("degli "): old_article = colorless[ : 6] genre = GRAMMAR.MASCULINE number = GRAMMAR.PLURAL elif colorless[ : 6] in ("delle "): old_article = colorless[ : 6] genre = GRAMMAR.FEMININE number = GRAMMAR.PLURAL elif colorless[ : 4] in ("dei "): old_article = colorless[ : 4] genre = GRAMMAR.MASCULINE number = GRAMMAR.PLURAL elif colorless[ : 4] in ("una "): old_article = colorless[ : 4] genre = GRAMMAR.FEMININE number = GRAMMAR.SINGULAR elif colorless[ : 4] in ("gli "): old_article = colorless[ : 4] genre = GRAMMAR.MASCULINE number = GRAMMAR.PLURAL elif colorless[ : 3] in ("il ", "un "): old_article = colorless[ : 3] genre = GRAMMAR.MASCULINE number = GRAMMAR.SINGULAR elif colorless[ : 3] in ("la ", "un'"): old_article = colorless[ : 3] genre = GRAMMAR.FEMININE number = GRAMMAR.SINGULAR elif colorless[ : 3] in ("le "): old_article = colorless[ : 3] genre = GRAMMAR.FEMININE number = GRAMMAR.PLURAL elif colorless[ : 2] in ("i "): old_article = colorless[ : 2] genre = GRAMMAR.MASCULINE number = GRAMMAR.PLURAL elif colorless[ : 2] in ("l'"): old_article = colorless[ : 2] genre = get_grammar_genre(colorless) # (bb) essendo is_masculine non terminato qui potrebbe ritornare baco al momento number = GRAMMAR.SINGULAR else: old_article = "" article = get_article(colorless[len(old_article) : ], genre, number, type) # Eseguendo la replace tenta di mantenere la colorazione originale, # altrimenti ne invia una versione semplicificata senza colori # (bb) sì lo so, non è perfetta perché se l'articolo è formato da più # colori il sistema non regge, ma per ora va bene così if argument.find(old_article) != -1: return argument.replace(old_article, article, 1) else: return colorless.replace(old_article, article, 1)
def interpret(entity, argument, use_check_alias=True, force_position=True, show_input=True, show_prompt=True, behavioured=False): """ Funzione che interpreta gli inputi inviati dalle entità. L'argomento use_check_alias a False viene passato dalla find_alias per evitare chiamate di alias da altri alias e quindi ricorsioni. """ if not entity: log.bug("entity non è un parametro valido: %r" % entity) return if not argument: log.bug("argument non è un parametro valido: %r" % argument) return # ------------------------------------------------------------------------- # Si assicura che colui che esegue l'azione sia un'entità unica e # non un mucchio fisico entity = entity.split_entity(1) if FLAG.CONVERSING in entity.flags and len(argument) == 1 and is_number(argument): # (TD) return arg, argument = one_argument(argument, search_separator=False) arg = arg.lower() input, huh_input, lang = multiple_search_on_inputs(entity, arg, use_check_alias=use_check_alias, argument=argument) # Utilizzo bislacco di lang per indicare che è stato trovato un alias # e che questo verrà processato tramite un'altra chiamata all'interpret if use_check_alias and lang == "alias": return # Resetta l'inattività di un player se ha inviato un comando if entity.IS_PLAYER: entity.inactivity = 0 # Se non ha trovato nulla invia un messaggio apposito if not input: if show_input: entity.send_output(''' <span class="system">%s %s</span>''' % (remove_colors(arg), argument)) entity.send_output("Huh?") # Se l'input non è stato trovato neanche nell'altra lingua allora # esegue il log dell'input, potrebbero esservene alcuni di sensati # da utilizzare in futuro come sinonimi # Scrive anche gli huh input dei mob così da ricavare gamescript o # random_do_inputs errati if not huh_input: log.huh_inputs(entity, arg) # Se serve visualizza il prompt if show_input: entity.send_prompt() return False # Poiché alcune words nello stesso input a volte hanno prefisso differente # tra loro allora cerca quello più simile possibile per farlo visualizzare # all'utente founded_input = input.findable_words[0] for word in input.findable_words: if is_prefix(arg, word): founded_input = word break # Se il giocatore è in stato di wait e l'input è un comando interattivo # allora evita di inviarlo subito ma lo mette in coda if entity.deferred_wait and CMDFLAG.INTERACT in input.command.flags: entity.waiting_inputs.append("%s %s" % (founded_input, argument)) return False else: # Altrimenti scrive anche l'input a fianco del prompt if show_input: entity.send_output(''' <span class="system">%s %s</span>''' % (founded_input, argument)) # Se il pg si è scollegato dalla pagina di gioco non esegue il comando if not entity.location: return False # Vengono salvate le informazioni sull'ultimo input inviato if argument: last_input = "%s %s" % (arg, argument) else: last_input = arg engine.last_input_sender = entity engine.last_input_sended = last_input # Si salva l'ultimo input inviato con successo if show_input and entity.IS_PLAYER and CMDFLAG.NO_LAST_INPUT not in input.command.flags: entity.last_input = last_input if CMDFLAG.GDR in input.command.flags: entity.sended_inputs.append("%s %s" % (founded_input, argument)) if argument: argument = html_escape(argument) # Gestisce i comandi che devono essere digitati per intero command = input.command if CMDFLAG.TYPE_ALL in command.flags and not is_same(arg, input.findable_words): first_words, other_words = one_argument(input.words, search_separator=False) entity.send_output("Se vuoi veramente farlo devi scrivere per intero [limegreen]%s[close]." % first_words) execution_result = False elif not check_position(entity, command.position, force_position): # Se la posizione non è corretta invia il relativo messaggio d'errore vowel_of_genre = grammar_gender(entity) if entity.position == POSITION.DEAD: entity.send_output("Un po' difficile fino a che rimani MORT%s.." % vowel_of_genre.upper()) elif (entity.position == POSITION.MORTAL or entity.position == POSITION.INCAP): entity.send_output("Sei troppo ferit%s per farlo." % vowel_of_genre) elif entity.position == POSITION.STUN: entity.send_output("Sei troppo intontit%s per farlo." % vowel_of_genre) elif entity.position == POSITION.SLEEP: entity.send_output("Nei tuoi sogni, o cosa?") elif entity.position == POSITION.REST: entity.send_output("Nah.. Sei troppo rilassat%s ora.." % vowel_of_genre) elif entity.position == POSITION.KNEE: entity.send_output("Non puoi farlo da inginocchiat%s" % vowel_of_genre) elif entity.position == POSITION.SIT: entity.send_output("Non puoi farlo da sedut%s." % vowel_of_genre) else: log.bug("Manca la posizione %r" % entity.position) execution_result = False else: if command.type == CMDTYPE.SOCIAL: check_social(entity, command, argument=argument, behavioured=behavioured) if CMDFLAG.PRIVATE not in command.flags and (entity.IS_PLAYER or config.print_entity_inputs) and show_input and show_prompt: if entity.IS_PLAYER: write_on_file = True else: write_on_file = False log.input("'%s%s%s' digitato da %s in %s" % ( founded_input, " " if argument else "", argument, entity.code, entity.location.get_name()), write_on_file=write_on_file) # Per comodità di sviluppo ricarica il modulo relativo al comando ogni # volta che lo si digita, così da poter testare le modifiche al codice # dei comandi senza aver bisogno di riavviare il gioco tutte le volte if config.reload_commands: reload(command.module) command.import_module_and_function() # Se si sta eseguendo un'azione che richiede tempo la interrompe if entity.action_in_progress and CMDFLAG.INTERACT in command.flags: if entity.action_in_progress.defer_later: entity.action_in_progress.stop() entity.action_in_progress = None # Esegue la funzione del comando cronometrandola input.counter_use += 1 starting_time = time.time() execution_result = (command.function)(entity, argument) if command.fun_name[ : 8] == "command_" and execution_result != True and execution_result != False: log.bug("execution_result non è valido per il comando %s: %r" % (command.fun_name, execution_result)) if command.fun_name[ : 6] == "skill_" and execution_result != "clumsy" and execution_result != "failure" and execution_result != "success" and execution_result != "magistral": log.bug("execution_result non è valido per la skill %s: %r" % (command.fun_name, execution_result)) execution_time = time.time() - starting_time # Comandi che superano il tempo definito nella max_execution_time # possono portare a bachi creati dalla deferred impostata nel metodo # split_entity (nello stesso metodo c'è un commento con più informazioni) # Quindi devono essere il più possibile da evitare, allo stesso tempo # sarebbe meglio che il max_execution_time sia relativamente basso. if execution_time > config.max_execution_time: log.time("Il comando %s è stato eseguito in troppo tempo: %f secondi" % (command.fun_name, execution_time)) command.timer += execution_time # Gestisce i comandi da loggare if CMDFLAG.LOG in command.flags: log.command("%s %s" % (command.fun_name, argument)) if FLAG.AFK in entity.flags and command.fun_name != "command_afk": command_afk(entity) # Infine visualizza il prompt if show_prompt: entity.send_prompt() # Se la lista di input ancora da inviare non è vuota allora crea un # "falso wait" per forzarne l'invio. In teoria potrei inviarlo da qui, ma # il codice di ritorno execution_result andrebbe perduto, ecco perché # si fa uso della wait(). if not entity.deferred_wait and entity.waiting_inputs: entity.wait(0.001) # Questa parte è da attivare con l'opzione check_references solo nei # server di test perché consuma molta cpu essendo eseguita su migliaia # di dati ad ogni invio di input, è una modalità di diagnostica # che non bada a spese in termini prestazionali if config.check_references and not database.reference_error_found: database.check_all_references() return execution_result
def render_GET(self, request, conn): page = "" page += '''<h3>Elenco dei tuoi Personaggi:</h3>''' page += '''<table rules="rows" width="100%">''' page += ''' <tr align="center"><th>Gioca con</th><th>Razza</th><th>Livello</th><th>Creato il</th><th>Connesso il</th><th>Disconnesso il</th><th>Giocato</th></tr>''' for player in sorted(conn.account.players.values(), key=lambda player: remove_colors(player.name)): if player.login_time: login_time = pretty_date(past=player.login_time) else: login_time = "Mai" if player.logout_time: logout_time = pretty_date(past=player.logout_time) else: logout_time = "Mai" # (TD) pensare se separare il codice e fare una funzione come la pretty_date seconds = (player.seconds_played) % 60 minutes = (player.seconds_played / 60) % 60 hours = (player.seconds_played / 3600) % 24 days = (player.seconds_played / 86400) if days == 0: if hours == 0: if minutes == 0: time_played = "%d second%s" % (seconds, "o" if seconds == 1 else "i") else: time_played = "%d minut%s" % (minutes, "o" if minutes == 1 else "i") else: time_played = "%d or%s e %d minut%s" % (hours, "a" if hours == 1 else "e", minutes, "o" if minutes == 1 else "i") else: time_played = "%d giorn%s e %d or%s" % (days, "o" if days == 1 else "i", hours, "a" if hours == 1 else "e",) # Sotto alcuni browser non funziona la pagina di gioco se non si # inserisce l'url per intero browser = conn.get_browser() server_address = "" if browser.startswith("IE"): server_address = "%s:%s/" % (config.site_address, config.http_port) href = '''href="game_interface.html?pg_code=%s" target="game_page"''' % player.code page += ''' <tr align="center"><td align="left">%s<a %s>%s</a></td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>''' % ( create_icon(player.get_icon()), href, player.name, player.sex_replacer(player.race.name), player.level, pretty_date(past=player.created_time), login_time, logout_time, time_played) if config.max_account_players == 0: page += ''' <tr><td colspan="7">La creazione di nuovi personaggi è disattiva.</td></tr>''' elif len(conn.account.players) < config.max_account_players: page += ''' <tr><td colspan="7"><a href="create_player1.html">Un Nuovo Personaggio</a></td></tr>''' else: page += ''' <tr><td colspan="7">Numero massimo di personaggi creabili raggiunto.</td></tr>''' page += '''</table>''' page += '''%s personaggi creati su %s.<br>''' % (len(conn.account.players), config.max_account_players) page += '''<br>''' page += '''<br>È inevitabile per i personaggi creati durante questa apertura finiscano lentamente con l'acquisire vantaggi, oggetti ed abilità troppo potenti per poter essere conservati quando si passerà dalla beta alla versione definitiva; è altrettanto inevitabile che sia una sofferenza indicibile rinunciarvi... pertanto concerteremo assieme una via che consenta ai partecipanti di mantenere almeno una parte dello status e dei privilegi acquisiti anche come segno virtuale-tangibile della nostra riconoscenza per aver contribuito alla crescita di Aarit.''' page += '''<script>$.post("players.html", {width:screen.width, height:screen.height});</script>''' return page
def rpg_channel(entity, argument, channel, ask=False, exclaim=False, behavioured=False): """ Gestisce i canali rpg, ha le seguenti caratteristiche: - supporto per gli smile - supporto per i modi di esprimersi con esclamativo e punto di domanda - supporto per gli emote - gestione del bersaglio che può essere un'entità, il gruppo o sé stessi - (TD) parlata da ubriaco - (TD) espansione della potenza della voce in altre stanze - (TD) espressioni per le stanze attorno, anche per coloro che riconoscono la voce, pensare anche alla suddivisione tra social gestuali e 'rumorosi' per gli smile-espressioni around - (TD) modulazione della voce a seconda delle dimensioni di chi parla e della sua voice_potence """ if not entity: log.bug("entity non è un parametro valido: %r" % entity) return False if not channel: log.bug("channel non è un parametro valido: %r" % channel) return False # ------------------------------------------------------------------------- if entity.IS_ROOM: return False objective = OBJECTIVE_ROOM # obiettivo del messaggio # Linguaggio utilizzato per dire il messaggio if entity.IS_ITEM: language = LANGUAGE.COMMON else: language = entity.speaking smile = "" # conterrà l'eventuale espressione di uno smile-social emote = "" # conterrà l'eventuale emote inviato con il messaggio tra due asterischi expres_entity = "" # espressione per chi parla expres_room = "" # espressione per chi sta ascoltando nella stanza expres_objective = "" # espressione per chi riceverà il messaggio # Ricava i verbi e il colore relativi al canale # Se si sta parlando normalmente la propria lingua vengono utilizzati # i verbi razziali per descriverne timbro, flessione o pronuncia if channel == CHANNEL.SAY: verb_you, verb_it = entity.race.say_verb_you, entity.race.say_verb_it else: verb_you, verb_it = channel.verb_you, channel.verb_it color = get_first_color(channel.name) # Se non è stato passato nessun messaggio esce if not argument or not remove_colors(argument): entity.send_output("Cosa vorresti %s?" % channel) return False if len(argument) > config.max_google_translate: entity.send_output("Non puoi %s un messaggio così logorroico." % channel) return False # Copia l'argomento originale, in alcuni casi serve recuperarlo poi original_argument = argument # Controlla se si sta parlando a qualcuno, il controllo sulla particella # la esegue in minuscolo, dando per sottinteso che quando uno scrive # maiuscolo voglia iniziare un discorso target = None if argument[0 : 2] == "a ": arg, argument = one_argument(argument) # Se sta parlando a qualcuno cerca di acquisirlo dal nome successivo objective_name, argument = one_argument(argument) target = entity.find_entity_extensively(objective_name) # con me e self esegue un check senza la is_same volutamente, per evitare # ricerche con nome di player che iniziano con Me o Self if target == entity or objective_name in ("me", "self"): objective = OBJECTIVE_SELF # Se si parla da soli lo si fa utilizzando la lingua madre language = entity.race.natural_language elif target: objective = OBJECTIVE_TARGET # Se si parla con qualcuno della stessa razza lo si fa utilizzando # la lingua preferita dalla razza, è un fattore culturale if entity.race == target.race: language = entity.race.natural_language else: # Se non ha trovato nessun 'a <nome bersaglio>' riprende # l'argument originale argument = original_argument # Stessa cosa di sopra ma qui controlla se si stia parlando al gruppo elif argument[0 : 3] == "al ": arg, argument = one_argument(argument) objective_name, argument = one_argument(argument) if is_prefix(objective_name, "gruppo"): if not entity.group: entity.send_output("Non fai parte di nessun gruppo.") return False # Questa variabile verrà utilizza poi nell'invio del messaggio group_members = entity.get_members_here(entity.location) if not group_members: entity.send_output("Non trovi nessun membro del gruppo vicino a te con cui poter parlare.") return False objective = OBJECTIVE_GROUP # Se si parla in un gruppo in cui tutti sono formati dalla stessa # razza si preferirà parlare con la lingua della propria razza for group_member in group_members: if group_member.race != entity.race: break else: language = entity.race.natural_language else: # Se il personaggio non vuole parlare al gruppo recupera # il valore originale inviato argument = original_argument # (TD) Gestisce il caso in cui l'entità si trovi immersa in un liquido #if entity.is_immersed(): # entity.send_output("Tenti di %s qualcosa ma subito l'acqua ti riempie la gola soffocandoti!" % channel) # entity.points.life -= random.randint(entity.level / 6, entity.level / 4) + 1 # return False if not entity.location: log.bug("entity %s non si trova in una locazione valida: %r (original_argument: %s)" % ( entity.code, entity.location, original_argument)) return False # Gestisce le stanze che obbligano al silenzio if entity.location.IS_ROOM: if ROOM.SILENCE in entity.location.flags: entity.send_output("Il silenzio del luogo ti blocca la gola impedendoti di %s." % channel) return False # (TT) Se nella stanza c'è molto casino, tante persone etc etc è difficile # parlare piano if entity.location.mod_noise > 75 and channel <= CHANNEL.SAY: entity.send_output("Non puoi %s con tutta questa confusione!" % channel) return False # Invia l'appropriato messaggio nel caso in cui trovi argument vuoto if not argument: send_not_argument_message(entity, objective, channel) return False # Cerca eventuali smiles nella stringa controllando gli ultimi caratteri for social in database["socials"].itervalues(): if not social.smiles: continue for single_smile in social.smiles.split(): if single_smile in argument[-config.chars_for_smile : ]: break else: # Se non trova nessun smile esce dal ciclo dei social e continua # col prossimo set di smiles trovato continue cut_smile = argument.rfind(single_smile) # Se argument è formato solo dallo smile invia il corrispondente social if cut_smile == 0: social_name = social.fun_name[len("social_") : ] if objective == OBJECTIVE_TARGET: input_to_send = "%s %s" % (social_name, target.name) elif objective == OBJECTIVE_SELF: input_to_send = "%s %s" % (social_name, entity.name) else: input_to_send = social_name send_input(entity, input_to_send, "en", show_input=False, show_prompt=False) return True # Altrimenti ne ricava l'espressione dello smile-social e toglie lo # smile da argument, se il carattere dopo lo smile era un simbolo di # punteggiatura lo attacca alla frase togliendo gli spazi first_part = argument[ : cut_smile] second_part = argument[cut_smile + len(single_smile) : ] if second_part.strip() and second_part.strip()[0] in "!?.,:;": first_part = first_part.rstrip() second_part = second_part.lstrip() argument = first_part.rstrip() + second_part.rstrip() smile = " %s" % social.expression break # Elabora i punti esclamativi e interrogativi per il canale say. # Qui viene utilizzata l'opzione chars_for_smile visto che si sta facendo # una cosa simile a sopra, ovvero considerare solo l'ultima parte # dell'argomento passato. exclamations = argument[-config.chars_for_smile : ].count("!") questions = argument[-config.chars_for_smile : ].count("?") if exclamations > questions: if channel == CHANNEL.SAY: verb_you = "Esclami" verb_it = " esclama" exclaim = True elif exclamations < questions: if channel == CHANNEL.SAY: verb_you = "Domandi" verb_it = " domanda" ask = True # Questo elif sottintende che exclamations e questions siano uguali elif exclamations != 0 and questions != 0: # Con una stessa quantità di ! e di ? l'ultimo che viene trovato # ha maggiore peso rispetto all'altro exclamation_pos = argument.rfind("!") question_pos = argument.rfind("?") if exclamation_pos > question_pos: if channel == CHANNEL.SAY: verb_you = "Esclami" verb_it = " esclama" exclaim = True else: if channel == CHANNEL.SAY: verb_you = "Domandi" verb_it = " domanda" ask = True # Supporto per piccoli emote separati da * ad inizio argument if argument[0] == "*": cut_emote = argument[1 : ].find("*") if cut_emote != -1: emote = " %s" % argument[1 : cut_emote+1].strip() if smile: emote = " e%s" % emote argument = argument[cut_emote+2 : ].strip() # Unisce i vari pezzi per formare l'output expres_entity = verb_you expres_room = verb_it expres_target = "" if objective == OBJECTIVE_TARGET: name = target.get_name(entity) expres_entity += " a %s" % name expres_room += " a %s" % name expres_target += " ti%s" % verb_it elif objective == OBJECTIVE_SELF: expres_entity += " a te stess%s" % grammar_gender(entity) expres_room += " a sé stess%s" % grammar_gender(entity) elif objective == OBJECTIVE_GROUP: members = entity.get_members_here(entity.location) if len(members) == 1: expres_entity += " a %s" % members[0].name expres_room += " a %s" % members[0].name expres_target += " ti%s" % verb_it else: if len(members) > 5: many = "folto " else: many = "" expres_entity += " al gruppo" expres_room += " ad un %sgruppo" % many expres_target += "%s al gruppo" % verb_it # Aggiunge le eventuali espressioni dello smile e dell'emote expres_entity += smile + emote expres_room += smile + emote expres_target += smile + emote if not argument: send_not_argument_message(entity, objective, channel) return False # Prepara il pezzo riguardante la lingua utilizzata language = "" if not entity.IS_ITEM and entity.speaking != LANGUAGE.COMMON: language = " in lingua %s" % entity.speaking # Mischia il testo se si è ubriachi original_argument = argument = color_first_upper(argument) argument = drunk_speech(argument, entity) # Parlando si impara la lingua if not entity.IS_ITEM: learn_language(entity, channel, entity.speaking) # Controlla se vi sono parolacce o parole offrpg e logga i relativi argument if entity.IS_PLAYER: check_for_badwords(entity, argument) # Invia il messaggio a tutti coloro che lo possono sentire for location in expand_voice_around(entity, channel): if not location: log.bug("location per il canale %s e per l'entità %s non è valida: %r" % (channel, entity.code, location)) continue for listener in location.iter_contains(use_reversed=True): if listener.position <= POSITION.SLEEP: continue if listener == entity: force_return = check_trigger(entity, "before_rpg_channel", listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue force_return = check_trigger(entity, "before_" + channel.trigger_suffix, listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue # Invia all'entità il suo stesso messaggio first_part = (close_color(color) + expres_entity).rstrip() message = "%s: '%s'" % (first_part, close_color(argument)) send_channel_message(entity, message, True) force_return = check_trigger(entity, "after_rpg_channel", listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue force_return = check_trigger(entity, "after_" + channel.trigger_suffix, listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue else: # Fa ascoltare solo ad un'entità di un eventuale gruppo fisico listener = listener.split_entity(1) force_return = check_trigger(listener, "before_listen_rpg_channel", listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue force_return = check_trigger(listener, "before_listen_" + channel.trigger_suffix, listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue # Prepara alcune cose a seconda della stanza di provenienza del messaggio if entity.location == listener.location: entity_name = entity.get_name(listener) entity_name = color_first_upper(entity_name) from_direction = "" elif entity.location.IS_ROOM: # (TD) invia qualcuno a meno che non lo si abbia conosciuto # precedentemente con il sistema di presentazione entity_name = "Qualcuno" from_direction = get_from_direction(listener.location.x, listener.location.y, listener.location.z, entity.location.x, entity.location.y, entity.location.z) elif entity.location.IS_ACTOR: if entity.location != listener: entity_name = "Qualcuno" # (TD) come sopra from_direction = " dall'inventario di %s" % entity.location.get_name(listener) else: entity_name = "Qualcuno" # (TD) come sopra from_direction = " da dentro %s" % entity.location.get_name(listener) # Prepara la prima parte, quella senza il messaggio if objective == OBJECTIVE_ROOM: output = "%s%s%s%s" % (entity_name, close_color(color) + expres_room, language, from_direction) elif objective == OBJECTIVE_TARGET or OBJECTIVE_SELF: if listener == target: output = "%s%s%s%s" % (entity_name, close_color(color) + expres_target, language, from_direction) else: output = "%s%s%s%s" % (entity_name, close_color(color) + expres_room, language, from_direction) elif objective == OBJECTIVE_GROUP: if listener in group_members: output = "%s%s%s%s" % (entity_name, close_color(color) + expres_target, language, from_direction) else: output = "%s%s%s%s" % (entity_name, close_color(color) + expres_room, language, from_direction) output = "<br>%s: '%s'" % (close_color(output).rstrip(), close_color(argument)) send_channel_message(listener, output, False) listener.send_prompt() force_return = check_trigger(listener, "after_listen_rpg_channel", listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue force_return = check_trigger(listener, "after_listen_" + channel.trigger_suffix, listener, entity, target, argument, ask, exclaim, behavioured) if force_return: continue return True
def __init__(self, name=""): super(Player, self).__init__(code="") # Il codice non bisogna passarlo come parametro nell'inizializzazione # degli attributi perché viene ricavato dal nome if name: self.code = remove_colors(name) self.name = name # Rimuove o deinizializza gli attributi inutili per i giocatori del(self.behaviour) del(self.keywords_name) del(self.keywords_short) del(self.keywords_short_night) del(self.prototype) self.life = config.starting_points self.mana = config.starting_points self.vigour = config.starting_points self.max_life = self.life self.max_mana = self.mana self.max_vigour = self.vigour self.strength = config.starting_attrs self.endurance = config.starting_attrs self.agility = config.starting_attrs self.speed = config.starting_attrs self.intelligence = config.starting_attrs self.willpower = config.starting_attrs self.personality = config.starting_attrs self.luck = config.starting_attrs # Variabile proprie di un'istanza di Player self.created_time = datetime.datetime.now() # Data di creazione del personaggio self.account = None # Account del giocatore che contiene questo personaggio self.permissions = "" # Permessi aggiunti alla normale trust self.surname = "" # Cognome o simile self.old_names = "" # Tiene traccia dei vecchi nomi in caso di restring del nome self.title = "" # Titolo con cui è conosciuto il personaggio self.target_descr = "" # Descrizione dell'obiettivo che il personaggio vuole perseguire self.login_time = None self.logout_time = None self.inactivity = 0 self.seconds_played = 0 self.login_times = 0 self.last_input = "guarda" # Ultimo input inviato al Mud self.reputations = {} # Reputazione nei confronti delle varie razze self.talents = 0 self.practices = 0 self.gifts = [] self.idle_seconds = 0 self.ban = None self.visited_areas = {} # Indica quali aree sono state visitate e quante volte self.visited_rooms = {} # Indica quali aree e quali room sono state visitate almeno una volta self.readed_books = {} # Indica quali libri sono stati letti almeno una volta self.digged_rooms = {} # Indica quali stanze sono state stavate almeno una volta self.eated_entities = {} # Indica quali entità sono state mangiate almeno una volta self.drinked_entities = {} # Indica quali entità sono state bevute almeno una volta self.possessed_entities = {} # Indica quali entità sono state possedute in inventario almeno una volta self.sensed_entities = {} # Indica quali entità sono state esaminate con un comando sensoriale che non sia il look self.sensed_rooms = {} # Indica quali stanze sono state esaminate con un comando sensoriale che non sia il look self.interred_entities = {} # Indica quali entità sono state interrate tramite il comando plant o il comando seed self.opened_entities = {} # Indica quali entità sono state aperte tramite il comando open self.unlocked_entities = {} # Indica quali entità sono state sbloccate tramite il comando unlock self.unbolted_entities = {} # Indica quali entità sono state svincolate tramite il comando unbolt self.entered_entities = {} # Indica quali entità sono state utilizzate come portali tramite il comando enter self.selled_entities = {} # Indica quali entità sono state vendute tramite il comando sell self.bought_entities = {} # Indica quali entità sono state vendute tramite il comando buy # Variabili volatili self.sended_inputs = collections.deque([], 100) # Lista degl input inviati dal giocatore self.backsteps = collections.deque([], 100) # Lista delle locazioni cui l'entità si è trovata precedentemente
def enter_in_game(self): force_return = check_trigger(self, "before_enter_in_game", self) if force_return: return # Resetta il contatore di idle, è normale che conn non sia valido # durante il test degli inputs conn = self.get_conn() if conn: conn.reinit() elif not engine.test_inputs_mode: log.bug("conn non è valido: %r" % conn) return # Se il pg ha impostato l'incognito ma non è un admin allora gli # viene rimosso if self.incognito and self.trust == TRUST.PLAYER: log.admin("Rimozione automatica dell'incognito al giocatore %s" % self.code) self.incognito = False # Se la stanza in cui il personaggio si trova è ancora impostata # significa che il giocatore si sta riconnettendo (per colpa di un # crash oppure utilizzando un altro browser) if self.location: # Ripulisce qualsiasi precedente istanza di connessione alla pagina # del gioco che non sia quella attuale actual_session = self.game_request.getSession() for session, connection in connections.iteritems(): if session == actual_session: continue if connection.account and OPTION.COMET not in connection.account.options: continue if ("/game_input.html" in repr(connection.request) or "/game_output.html" in repr(connection.request)): # (TT) in realtà qui dovrei ucciderla o unpausarla, # altrimenti mi occupa spazio di memoria, magari aggiungerla # come lista alle precedenti deferrenti di questa connessione connection.defer_exit_from_game.pause() connection.defer_exit_from_game = None del(connection) # Se un pg si riconnette non avvisa via mail send_a_mail = False log_message = "%s si riconnette al gioco" % self.code # Qui dovrebbe passare per tutti i personaggi che sono entrati almeno # una volta in gioco e che non hanno avuto problemi di sorta elif self.previous_location and self.previous_location() and not self.previous_location().IS_PLAYER: location = self.previous_location() self.previous_location = None self.to_location(location, use_iterative_put=False) send_a_mail = True self.login_times += 1 log_message = "%s entra nel gioco per la %d° volta" % (self.code, self.login_times) # Se la stanza in cui se ne era andato il personaggio non è stata # impostata durante il quit allora significa che il giocatore è nuovo # oppure c'è stato un baco che ne ha corrotto il riferimento else: destination_room = config.initial_destination.get_room() if not destination_room: log.bug("destination_room non valida: %r" % destination_room) return self.to_location(destination_room, use_iterative_put=True) send_a_mail = True self.login_times += 1 log_message = "%s entra nel gioco per la %d° volta" % (self.code, self.login_times) if not engine.test_inputs_mode: log.always(log_message) # Controlla se deve donare un'entità all'evento a cui il giocatore # sta partecipando; il regalo può essere sia un oggetto che un mob if config.gift_on_enter and config.gift_on_enter not in self.gifts: gift = config.gift_on_enter.CONSTRUCTOR(config.gift_on_enter.code) if gift: # Si presuppone che i gift non abbiano il max_global_quantity gift.inject(self) self.gifts.append(config.gift_on_enter) else: log.bug("Impossibile creare il dono %s per %s: %r" % ( config.gift_on_enter.code, self.code, gift)) # Avvisa gli admin via mail se un pg è appena entrato nel Mud if self.account and self.account.trust > TRUST.PLAYER: send_a_mail = False for player in self.account.players.itervalues(): if player.trust > TRUST.PLAYER: send_a_mail = False if send_a_mail and config.mail_on_enter_in_game: mail.send_to_admins(log_message, "%s è un %s di livello %s dell'account %s." % ( self.code, self.sex_replacer(remove_colors(self.race.name)), self.level, self.account.name if self.account else "<Errore>")) eyes = self.eye_colorize("occhi") self.act("Ti materializzi poco a poco dal nulla e poi apri gli %s.\n" % eyes, TO.ENTITY) self.act("$n si materializza poco a poco dal nulla e apre gli %s come se si stesse svegliando." % eyes, TO.OTHERS) command_look(self) self.inactivity = 0 log.connections() force_return = check_trigger(self, "after_enter_in_game", self) if force_return: return
def create_quantities_list(self): quantities = [] for table_name in ("proto_mobs", "proto_items"): quantities.append('''<table class="mud">''') for proto_code, prototype in database[table_name].iteritems(): if prototype.max_global_quantity <= 0: continue quantities.append('''<tr><td>''') quantities.append('''<a href="global_quantity.html?proto_code=%s" title="%s">%s</a>''' % (proto_code, remove_colors(prototype.name), proto_code)) quantities.append('''</td><td>''') quantities.append('''<span style="color:%s">%d su %d</span>''' % ( "red" if prototype.current_global_quantity >= prototype.max_global_quantity else "", prototype.current_global_quantity, prototype.max_global_quantity)) quantities.append('''</tr></td>''') quantities.append('''</table><br>''') return quantities
def get_error_message_name(name, already_in_database, table_name="accounts"): """ Controlla che il nome passato sia valido. Questa funzione viene utilizzata sia per i nomi degli account sia per quelli dei personaggi. Ritorna un messaggio vuoto se tutto è a posto, altrimenti il primo messaggio d'errore incontrato. Bisogna passare l'argomento already_in_database uguale a False quando si controlla l'integrità di un nome di Account o di Player appena creati e non ancora aggiunti al relativo database, viceversa bisogna passarlo a True. """ if table_name not in ("players", "accounts"): return "L'argomento table_name non è valido: %s" % table_name # ------------------------------------------------------------------------- name = name or "" # Se è un nome di un personaggio rimuove gli eventuali codici css if table_name == "players": name = remove_colors(name) # Controlla la lunghezza del nome length = len(name) if length < config.min_len_name: return "Nome troppo corto, deve essere almeno di %d caratteri." % config.min_len_name if length > config.max_len_name: return "Nome troppo lungo, può essere al massimo lungo %d caratteri." % config.max_len_name # Controlla che i caratteri del nome siano solo alfabetici o accentati # (BB) c'è ancora il problema degli accenti che non vengono letti da scritte # inviate tramite web, commentate alcune righe in favore di un rimpiazzo # in attesa del python 3.0 per risolvere la faccenda if table_name == "accounts" and not isalnum_accent(name): #return "Il nome può essere formato solo da lettere (accentate o meno) e da numeri." return "Il nome può essere formato solo da lettere e da numeri." if table_name == "players" and not isalpha_accent(name): #return "Il nome può essere formato solo da lettere (accentate o meno)." return "Il nome può essere formato solo da lettere." # Il nome può avere in più un accento per ogni tre caratteri if count_accents(name) > len(name) / 3: return "Il nome, per essere maggiormente leggibile, può avere solo un accento ogni tre caratteri." # Controlla che il nome abbia una determinata varietà di caratteri inseriti # per evitare nomi come Aaa if len(set(name.lower())) < math.floor(math.log(len(name)) * 2): return "Nome troppo poco vario, utilizzare un maggior numero di vocali o consonanti differenti" # Controlla se esiste già il nome nel database passato, bisogna utilizzare # is_same() altrimenti nomi simili, ma uno con vocale semplice e l'altro # con vocale accentanta, vengono visti come differenti for data in database[table_name].itervalues(): if is_same(data.name, name) or (hasattr(data, "code") and is_same(data.code, name)): # Se si sta controllando un nome già esistente nel database # quando lo trova per una volta lo salta if already_in_database: already_in_database = False continue return "Il nome è già utilizzato in un altro account." # Controlla che il nome non sia una parolaccia, una parola off-rpg, un # nome non utilizzabile o una little word, che degenererebbe la creazione # dinamica delle kewywords per i personaggi for swear_word in swearwords: if is_same(swear_word, name): return "Il nome non è valido perché è una parolaccia." if table_name == "players": for offrpg_word in offrpg_words: if is_same(offrpg_word, name): return "Il nome non è valido perché è una parola non GDR." for forbidden_name in forbidden_names: if is_same(forbidden_name, name): return "Il nome non è valido." for little_word in little_words: if is_same(little_word, name): return "Il nome non è valido." # Controlla che la prima lettera sia maiuscola e il resto minuscolo if name != name.capitalize(): return "Il nome non inizia con la maiuscola e il resto minuscolo" # Se tutto è ok ritorna un messaggio vuoto return ""
def command_list(entity, argument="", behavioured=False): """ Permette di comprare entità da un commerciante. """ # Può essere normale se il comando è stato deferrato if not entity: return False entity = entity.split_entity(1) if argument: dealer = entity.find_entity_extensively(argument) if not dealer: entity.act("Non trovi nessun negoziante chiamato [white]%s[close]." % argument, TO.ENTITY) entity.act("$n sembra cercare qualcuno un negoziante.", TO.OTHERS) return False if not dealer.shop: entity.act("$N non sembra essere un negoziante.", TO.ENTITY, dealer) entity.act("$n crede erroneamente che $N sia un negoziante.", TO.OTHERS, dealer) entity.act("$n crede erroneamente che tu sia un negoziante.", TO.TARGET, dealer) return False # Altrimenti cerca il primo negoziante che si trova nella locazione del giocatore else: for dealer in entity.location.iter_contains(): if dealer.shop: break else: entity.act("Qui non trovi nessun [white]negoziante[close].", TO.ENTITY) entity.act("$n non sembra trovare nessun negoziante qui intorno.", TO.OTHERS) return False in_location = dealer.shop.in_location(dealer) if not in_location and SHOP.DISPENSER not in dealer.shop.types: entity.act("$N non ti mostra la merce perché non si trova nel suo negozio.", TO.ENTITY, dealer) entity.act("$N non mostra la merce a $n perché non si trova nel suo negozio.", TO.OTHERS, dealer) entity.act("Non mostri la tua merce a $n perché non ti trovi nel tuo negozio.", TO.TARGET, dealer) return False # Indica che un'entità vuole interagire con il dealer if entity not in dealer.interactions: dealer.interactions.append(entity) storage = dealer.shop.get_storage(dealer) if not storage: if dealer.shop.proto_storages and dealer.shop.proto_storages[0].IS_MOB: from_where = "da chi" else: from_where = "da dove" entity.act("Non puoi avere la lista da $N perché non ha %s prendere la mercanzia!" % from_where, TO.ENTITY, dealer) entity.act("$n non può avere la lista da $N perché non ha %s prendere la mercanzia!" % from_where, TO.OTHERS, dealer) entity.act("$n non può avere la lista perché non hai %s prendere la mercanzia!" % from_where, TO.TARGET, dealer) return False if not dealer.shop.buyables: entity.send_output("%s non possiede nessuna mercanzia" % dealer.get_name(looker=entity)) log.bug("Non è stato trovato nessun buyable impostato per %s" % dealer.code) return False # Controlla se il magazzino contiene almeno un oggetto comprabile dall'utente if dealer.shop.storage_is_empty(storage): entity.act("Ti accorgi che il negozio non possiede mercanzia, meglio tornare più tardi, dopo il rifornimento.", TO.ENTITY, dealer) entity.act("$n si accorge che il negozio non possiede mercanzia.", TO.OTHERS, dealer) entity.act("$n si accorge che il tuo negozio non possiede mercanzia.", TO.TARGET, dealer) return False force_return = check_trigger(entity, "before_list", entity, dealer, behavioured) if force_return: return True force_return = check_trigger(dealer, "before_listed", entity, dealer, behavioured) if force_return: return True if SHOP.DISPENSER in dealer.shop.types: if not in_location: entity.act("Leggi su di una targetta la lista delle mercanzie di $N anche se non si trova nel suo negozio.", TO.OTHERS, dealer) entity.act("$n legge su di una targetta la lista delle mercanzie di $N anche se non si trova nel suo negozio.", TO.OTHERS, dealer) entity.act("$n legge la tua targetta con la lista delle mercanzie anche se non si trova nel suo negozio.", TO.TARGET, dealer) else: entity.act("Leggi su di una targetta la lista delle mercanzie di $N.", TO.OTHERS, dealer) entity.act("$n legge su di una targetta la lista delle mercanzie di $N.", TO.OTHERS, dealer) entity.act("$n legge la tua targetta con la lista delle mercanzie.", TO.TARGET, dealer) else: entity.act("Chiedi la lista delle mercanzie di $N.", TO.OTHERS, dealer) entity.act("$n chiede la lista delle mercanzie di $N.", TO.OTHERS, dealer) entity.act("$n ti chiede la lista delle mercanzie.", TO.TARGET, dealer) discount_exist = False for buyable in dealer.shop.buyables: if buyable.has_discount(): discount_exist = True buy_translation = translate_input(entity, "buy", "en") rows = [] rows.append('''<table class="mud">''') discount_cell = "" if SHOP.DISPENSER in dealer.shop.types: name_cell = "Prodotti" else: name_cell = "Mercanzia" if discount_exist: discount_cell = '''<th>Sconto</th>''' rows.append('''<tr><th></th><th>%s</th><th colspan="4">Prezzo</th><th>Livello</th><th></th><th></th>%s</tr>''' % ( name_cell, discount_cell)) for en in storage.get_list_of_entities(entity): en = en[INSTANCE] for buyable in dealer.shop.buyables: if en.prototype != buyable.proto_entity: continue # Purtroppo però il sistema di mucchio visivo non permetterà di # visualizzare quantità superiori ad 1 per oggetti di long uguali # tra loro, la quantità si deve per forza basare sul mucchio fisico quantity = 10 if buyable.has_discount(): quantity = buyable.discount_quantity if en.quantity < quantity: quantity = en.quantity name = en.get_name(looker=entity) single_price, dummy_discount = buyable.get_price(en, quantity=1) block_price, dummy_discount = buyable.get_price(en, quantity=quantity) mithril, gold, silver, copper = pretty_money_icons(single_price) rows.append('''<tr><td>%s</td>''' % create_icon(en.get_icon(), add_span=False)) rows.append('''<td>%s </td>''' % create_tooltip(entity.get_conn(), en.get_descr(looker=entity), name)) rows.append('''<td align="right">%s</td>''' % mithril) rows.append('''<td align="right">%s</td>''' % gold) rows.append('''<td align="right">%s</td>''' % silver) rows.append('''<td align="right">%s</td>''' % copper) rows.append('''<td align="center">%d</td>''' % en.level) rows.append('''<td><input type="submit" value="%s" onclick="sendInput('%s 1 %s')" title="Comprerai %s per un prezzo di %s"/></td>''' % ( buy_translation.capitalize(), buy_translation, en.get_numbered_keyword(looker=entity), remove_colors(name), remove_colors(pretty_money_value(single_price)))) rows.append('''<td><input type="submit" value="%s x %d" onclick="sendInput('%s %d %s')" title="Comprerai %d unità di %s per un prezzo di %s"/></td>''' % ( buy_translation.capitalize(), quantity, buy_translation, quantity, en.get_numbered_keyword(looker=entity), quantity, remove_colors(name), remove_colors(pretty_money_value(block_price)))) if discount_exist: if buyable.has_discount(): rows.append('''<td align="center">%d%% per quantità maggiori di %d</td>''' % (buyable.discount_percent, buyable.discount_quantity)) else: rows.append('''<td align="center">Nessuno</td>''') rows.append('''</tr>''') rows.append('''</table>''') entity.send_output("".join(rows), break_line=False) force_return = check_trigger(entity, "after_list", entity, dealer, behavioured) if force_return: return True force_return = check_trigger(dealer, "after_listed", entity, dealer, behavioured) if force_return: return True return True
def msg(self, message, log_type=None, log_stack=True, write_on_file=True, send_output=True, use_blink=False): """ Invia un messaggio di log contenente errori o avvisi. """ if not message: print("[log.bug] message non è un parametro valido: %r" % message) return # ------------------------------------------------------------------------- from src.enums import LOG # Questa extract_stack è un collo di bottiglia prestazionale del Mud, # tuttavia la sua utilità è indubbia e quindi fino a che Aarit non sarà # maturissimo è inutile anche evitarla con qualche opzione di config. # Ho deciso tuttavia di saltare il print della last_function relativa # a tutti i messaggi di log reset, che sono quelli maggiormente inviati stack = None last_function = "" last_function = "" if not log_type or log_type.show_last_function: stack = traceback.extract_stack() last_function = str(stack[-3][2]) # Stampa il messaggio alla console e lo scrive sul file if stack: source_name = stack[-3][0].replace(os.getcwd(), "") if "src" in source_name: position = source_name.find("src") source_name = source_name[position : ] elif "data" in source_name: position = source_name.find("data") source_name = source_name[position : ] source_line = stack[-3][1] last_function = " (%s %s %s)" % (last_function, source_name, source_line) # Rimuove i colori dal messaggio per una stampa a video maggiormente amica from src.color import remove_colors message = remove_colors(message) # Invia il messaggio di log agli Admin del Mud if send_output: from src.database import database if "players" in database and log_type.show_on_mud: from src.utility import html_escape for player in database["players"].itervalues(): if not player.game_request: continue if player.trust < log_type.trust and str(log_type.code) not in player.permissions: continue if log_type != LOG.ALWAYS and log_type not in player.account.show_logs and str(log_type.code) not in player.permissions: continue open_span = "" close_span = "" if use_blink: open_span = "<span style='text-decoration: blink;'>" close_span = "</span>" player.send_output("<br>[magenta]%s%s %s%s[close]" % ( open_span, last_function.lstrip(), html_escape(message), close_span), avoid_log=True) player.send_prompt() # Visto che anche gli altri loop sono legati a questo, non c'è bisogno # di controllarle tutti from src.loops.aggressiveness import aggressiveness_loop from src.loops.blob import blob_loop from src.entitypes.corpse import decomposer_loop from src.loops.digestion import digestion_loop from src.fight import fight_loop from src.game import game_loop from src.maintenance import maintenance_loop from src.behaviour import room_behaviour_loop if (game_loop and game_loop.running and maintenance_loop and maintenance_loop.running and room_behaviour_loop and room_behaviour_loop.running and fight_loop and fight_loop.running and decomposer_loop and decomposer_loop.running and aggressiveness_loop and aggressiveness_loop.running and blob_loop and blob_loop.running and digestion_loop and digestion_loop.running): loop_status = "L" else: loop_status = "l" now = datetime.datetime.now() message = "%02d:%02d:%02d [%s] {%s}%s: %s" % ( now.hour, now.minute, now.second, log_type, loop_status, last_function, message) log_file = None if write_on_file and log_type.write_on_file: log_path = "log/%d-%02d-%02d.log" % (now.year, now.month, now.day) try: log_file = open(log_path, "a") except IOError: print "Impossibile aprire il file %s in append" % log_path log_file = None else: log_file.write("%s\n" % message) # Questo viene fatto perché alcune console purtroppo non supportano # i caratteri accentati e simili, viene così convertito l'accento # nel famoso e muddoso accento apostrofato, quindi attenzione che # in tal caso il messaggio nello stdout è falsato da quello originale # nel qual caso si voglia cercarlo nel codice if log_type.print_on_console: from src.config import config if config.ready and config.log_accents: if "à" in message: message = message.replace("à", "a'") if "è" in message: message = message.replace("è", "e'") if "é" in message: message = message.replace("é", "e'") if "ì" in message: message = message.replace("ì", "i'") if "ò" in message: message = message.replace("ò", "o'") if "ù" in message: message = message.replace("ù", "u'") print(message) # Se la tipologia di log non è un bug allora evita le informazioni di stack if log_type != LOG.BUG: log_stack = False if stack and write_on_file and log_type.write_on_file and log_stack: try: traceback.print_stack(file=log_file) traceback.print_stack(file=sys.stdout) except IOError: # (TT) non ho capito bene come mai mi fa così, ma semplicemente # saltandolo mi evita di fare il traceback, cmq il log avviene pass if log_file: log_file.close()
def get_error_message_name(name, already_in_database, table_name="accounts"): """ Controlla che il nome passato sia valido. Questa funzione viene utilizzata sia per i nomi degli account sia per quelli dei personaggi. Ritorna un messaggio vuoto se tutto è a posto, altrimenti il primo messaggio d'errore incontrato. Bisogna passare l'argomento already_in_database uguale a False quando si controlla l'integrità di un nome di Account o di Player appena creati e non ancora aggiunti al relativo database, viceversa bisogna passarlo a True. """ if table_name not in ("players", "accounts"): return "L'argomento table_name non è valido: %s" % table_name # ------------------------------------------------------------------------- name = name or "" # Se è un nome di un personaggio rimuove gli eventuali codici css if table_name == "players": name = remove_colors(name) # Controlla la lunghezza del nome length = len(name) if length < config.min_len_name: return "Nome troppo corto, deve essere almeno di %d caratteri." % config.min_len_name if length > config.max_len_name: return "Nome troppo lungo, può essere al massimo lungo %d caratteri." % config.max_len_name # Controlla che i caratteri del nome siano solo alfabetici o accentati # (BB) c'è ancora il problema degli accenti che non vengono letti da scritte # inviate tramite web, commentate alcune righe in favore di un rimpiazzo # in attesa del python 3.0 per risolvere la faccenda if table_name == "accounts" and not isalnum_accent(name): #return "Il nome può essere formato solo da lettere (accentate o meno) e da numeri." return "Il nome può essere formato solo da lettere e da numeri." if table_name == "players" and not isalpha_accent(name): #return "Il nome può essere formato solo da lettere (accentate o meno)." return "Il nome può essere formato solo da lettere." # Il nome può avere in più un accento per ogni tre caratteri if count_accents(name) > len(name) / 3: return "Il nome, per essere maggiormente leggibile, può avere solo un accento ogni tre caratteri." # Controlla che il nome abbia una determinata varietà di caratteri inseriti # per evitare nomi come Aaa if len(set(name.lower())) < math.floor(math.log(len(name)) * 2): return "Nome troppo poco vario, utilizzare un maggior numero di vocali o consonanti differenti" # Controlla se esiste già il nome nel database passato, bisogna utilizzare # is_same() altrimenti nomi simili, ma uno con vocale semplice e l'altro # con vocale accentanta, vengono visti come differenti for data in database[table_name].itervalues(): if is_same(data.name, name) or (hasattr(data, "code") and is_same(data.code, name)): # Se si sta controllando un nome già esistente nel database # quando lo trova per una volta lo salta if already_in_database: already_in_database = False continue return "Il nome è già utilizzato in un altro account." # Controlla che il nome non sia una parolaccia, una parola off-rpg, un # nome non utilizzabile o una little word, che degenererebbe la creazione # dinamica delle kewywords per i personaggi for swear_word in swearwords: if is_same(swear_word, name): return "Il nome non è valido perché è una parolaccia." if table_name == "players": for offrpg_word in offrpg_words: if is_same(offrpg_word, name): return "Il nome non è valido perché è una parola non GDR." for forbidden_name in forbidden_names: if is_same(forbidden_name, name): return "Il nome non è valido." for little_word in little_words: if is_same(little_word, name): return "Il nome non è valido." # Controlla che la prima lettera sia maiuscola e il resto minuscolo if name != name.capitalize(): return "Il nome non inizia con la maiuscola e il resto minuscolo" # Se tutto è ok ritorna un messaggio vuoto return ""