def __init__(self, size): """Construct a square TetrisGrid with the given size.""" # Initialise grid squares grid_squares = [] for column_index in range(0, size): column = [] for row_index in range(0, size): column.append(GridSquare()) grid_squares.append(column) super(TetrisGrid, self).__init__( attrs_dict={ "_size": size, "x_bounds": (0, size - 1), "y_bounds": (0, size - 1), "grid_squares": grid_squares }) # Populate grid with fixed elements for row_num in range(*self.y_bounds): # Left Wall self._get_grid_square(Position(self.x_bounds[0], row_num)).fill_with( Element(ElementType.WALL)) # Right wall self._get_grid_square(Position(self.y_bounds[-1], row_num)).fill_with( Element(ElementType.WALL)) # Floor for col_num in range(*self.y_bounds): self._get_grid_square(Position(col_num, self.y_bounds[0])).fill_with( Element(ElementType.WALL))
def __init__(self, name=""): self.comment = "" self.created_time = datetime.datetime.now() # Data di creazione del'account self.name = name # Nome di login self.password = "" # Password self.email = "" # Indirizzo e-mail (opzionale) self.options = Flags(OPTION.NONE) self.show_logs = Flags(LOG.NONE) self.aliases = {} # Dizionario relativo agli alias self.macros = {} # Dizionario relativo alle macro # (TD) provare a convertire questi datetime in None e caricarli tramite schema self.last_bug_sended_at = None self.last_comment_sended_at = None self.last_typo_sended_at = None self.last_idea_sended_at = None self.sended_bugs = 0 # Bug totali inviati self.sended_comments = 0 # Typo totali inviati self.sended_ideas = 0 # Idee totali inviati self.sended_typos = 0 # Typo totali inviati self.user_agents = [] # Informazioni relative ai client browser utilizzati dal giocatore per entrare nel Mud self.resolution_width = 0 # Risoluzione in pixel del monitor del client in larghezza self.resolution_height = 0 # Risoluzione in pixel del monitor del client in altezza # Al primo account creato in assoluto dà poteri di Implementor, dando # per scontato che il primo giocatore che utilizza questo Mud sia il # futuro amministratore, ai successivi account dona la trust di player if not database["accounts"]: self.trust = Element(TRUST.IMPLEMENTOR) else: self.trust = Element(TRUST.PLAYER) # Attributi volatili self.players = {} # Dizionario dei giocatori creati dall'account self.player = None # Personaggio che si sta creando o utilizzando
def __init__(self, code=""): super(Mob, self).__init__() BehaviourUpdaterSuperclass.__init__(self) self.code = "" self.prototype = None if code: self.reinit_code(code) copy_existing_attributes(self.prototype, self, except_these_attrs=["code"]) self.after_copy_existing_attributes() # Eventuale inizializzazione dei punti if self.max_life == 0: self.max_life = config.starting_points if self.max_mana == 0: self.max_mana = config.starting_points if self.max_vigour == 0: self.max_vigour = config.starting_points if self.life == 0: self.life = self.max_life if self.mana == 0: self.mana = self.max_mana if self.vigour == 0: self.vigour = self.max_vigour if self.hand == HAND.NONE: self.hand = self.hand.randomize() # Variabili proprie di una istanza di mob: self.area = None self.attack = 1 self.defense = 1 self.speaking = Element( LANGUAGE.COMMON ) # Indica con quale linguaggio sta attualmente parlando il mob self.style = Element( STYLE.NONE) # Style di combattimento che sta utilizzando self.experience = 0 # Esperienza accumulata prima di poter livellare self.mount = None # Indica quale mob o pg sta cavalcando self.mounted_by = None # Indica da quali mob o pg è cavalcato self.specials = { } # E' una lista di variabili speciali, possono essere utilizzate come delle flags, vengono aggiunte di solito nei gamescript self.reply = None # Entità a cui si può replicare # self.tracking = Track() # Serve quando il mob inizia a tracciare e cacciare una preda fuggita self.last_fight_time = None self.last_death_time = None # Contatori di statistica self.defeat_from_mob_counter = 0 # Conteggio delle sconfitte self.defeat_from_item_counter = 0 # Conteggio delle sconfitte self.defeat_from_player_counter = 0 # Conteggio delle sconfitte self.death_from_player_counter = 0 # Conteggio delle sconfitte self.mob_defeated_counter = 0 # Conteggio delle vittorie sui mob self.item_defeated_counter = 0 # Conteggio degli oggetti distrutti self.player_defeated_counter = 0 # Conteggio delle vittorie sui giocatori self.player_killed_counter = 0 # Conteggio delle volte che viene ucciso un giocatore check_trigger(self, "on_init", self)
def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- try: entitype, percent, buyback_percent = line.split(None, 2) except ValueError: log.bug( "Errore nella lettura di un Sellable nel file <%s> per la linea <%s> e l'attributo <%s>" % (file.name, line, attr)) return self.entitype = Element(entitype) self.percent = fread_percent(file, percent, attr) self.buyback_percent = fread_percent(file, buyback_percent, attr)
def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- if "," in line: material, percent = line.split(",", 1) else: material, percent = line.split(None, 1) material = material.strip() percent = percent.strip() self.material = Element(material) self.percent = fread_percent(file, percent, attr)
def __init__(self): self.comment = "" self.fun_name = "" # Nome della funzione del comando legato al social self.intention = Element(INTENTION.NONE) # Tipologia di intenzione self.smiles = "" # Elenco degli smile supportati dal social self.expression = "" # Espressione relativa al'utilizzo degli smile self.racial_messages = EnumElementDict()
def render_POST(self, request, conn): #if conn.new_player and conn.new_player.code in database["players"]: # return "\nImpossibile creare il personaggio %s perché già esistente.\n" % conn.new_player.name page = self.check_number_of_players(request, conn) if page: return page # Ricava gli argomenti del form dalla richiesta race = "" if "race" in request.args: race = Element(request.args["race"][0]) sex = "" if "sex" in request.args: sex = Element(request.args["sex"][0]) constellation = "" if "constellation" in request.args: constellation = Element(request.args["constellation"][0]) # Controlla la validità degli argomenti inseriti nel form err_msg_race = "" if not race: err_msg_race = "Scegli la razza che vuoi interpretare" race = RACE.NONE else: # (TD) per ora gestisce la sessualità unica delle Frijen in maniera forzata if race == RACE.FRIJEN: sex = SEX.FEMALE err_msg_sex = "" if not sex: err_msg_sex = "Scegli la sessualità che vuoi interpretare" sex = SEX.NONE err_msg_constellation = "" if not constellation: err_msg_constellation = "Scegli la costellazione sotto cui il tuo personaggio è nato" constellation = CONSTELLATION.NONE # Se tutti gli argomenti del form sono validi crea il personaggio e # passa alla pagina di creazione successiva if not err_msg_race and not err_msg_sex and not err_msg_constellation: new_player = Player() new_player.race = race new_player.sex = sex new_player.constellation = constellation conn.new_player = new_player request.redirect("create_player2.html") request.finish() return server.NOT_DONE_YET return self.create_page(request, conn, race, sex, constellation, err_msg_race, err_msg_sex, err_msg_constellation)
def load(self): filepath = "persistence/calendar.rpg" try: file = open(filepath, "r") except IOError: log.bug("Impossibile aprire il file %s in lettura" % filepath) return for line in file: if not line.strip(): continue if line[0] == "#": continue break else: log.bug("Non è stato trovato nessuna riga valida al file %s" % filepath) file.close() return file.close() values = line.split() if len(values) != 5: log.bug( "E' stato trovato un numero inatteso di valori al file %s: %d" % (filepath, len(values))) return if is_number(values[0]): self.minute = int(values[0]) else: log.bug("minute del file %s non sono un numero valido: %s" % values[0]) if is_number(values[1]): self.hour = int(values[1]) else: log.bug("hour del file %s non sono un numero valido: %s" % values[1]) if is_number(values[2]): self.day = int(values[2]) else: log.bug("day del file %s non sono un numero valido: %s" % values[2]) self.month = Element(values[3]) if is_number(values[4]): self.year = int(values[4]) else: log.bug("year del file %s non sono un numero valido: %s" % values[4]) self.get_error_message()
class Weapon(object): PRIMARY_KEY = "" VOLATILES = [] MULTILINES = ["comment"] SCHEMA = {} REFERENCES = {} WEAKREFS = {} def __init__(self): self.comment = "" self.category = Element(WEAPON.NONE) # Tipo di arma self.flags = Flags(WEAPONFLAG.NONE) # Flag di arma self.damage = "" # Danno dell'arma, se vuoto viene ricavato automaticamente tramite una tabella #- Fine Inizializzazione - def __str__(self): return "%r: %s" % (self, sorted(self.__dict__)) #- Fine Metodo - def get_error_message(self, entity): if self.category.get_error_message(WEAPON, "category") != "": return self.category.get_error_message(WEAPON, "category") elif self.flags.get_error_message(WEAPONFLAG, "flags") != "": return self.category.get_error_message(WEAPONFLAG, "flags") return "" #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Weapon() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, weapon2): if not weapon2: return False if self.comment != weapon2.comment: return False if self.category != weapon2.category: return False if self.flags != weapon2.flags: return False if self.damage != weapon2.damage: return False return True
def __init__(self, code=""): self.comment = "" self.code = code # Codice identificativo dell'area self.name = "" # Nome esteso self.short = "" # Descrizioni breve dell'area self.short_night = "" # Descrizioni breve notturna dell'area self.descr = "" # Descrizione dell'area per la pagina web della lista delle aree self.creators = "" # Lista dei creatori, vale il codice dell'account (TD) in futuro sarà una lista per poter ricavare il riferimento self.level = 1 # Livello base per tutte le entità dell'area, se viene modificato questo anche tutte le entità aumentano o diminuiscono di livello in proporzione self.flags = Flags(AREA.NONE) # self.races = Flags(RACE.NONE) # Razze che si possono incontrare principalmente nell'area (TD) self.color = Element(COLOR.NONE) # Colore dell'area self.music = "" # File mid avviato quando uno entra nell'area self.music_wild = "" # File mid avviato quando uno esce dall'area ed entra nella wild self.climates = {} # Informazioni climatiche dell'area relativamente alle stagioni self.maze = None # Informazioni relative al labirinto self.wumpus = None # Informazioni relative alle aree wumpus self.wild = None # Struttura relativa alla wilderness self.landfill_code = "" # Codice della stanza prototipo in cui verranno inseriti gli oggetti "da buttare" self.repop_time = 0 # Minuti reali tra un repop di un'entità ed un'altro self.room_resets = [] # Lista dei reset dell'area # Attributi relativi alle liste dei messaggi di echo self.echoes_dawn = [] self.echoes_dawn_no_sun = [] self.echoes_sunrise = [] self.echoes_sunrise_no_sun = [] self.echoes_noon = [] self.echoes_noon_no_sun = [] self.echoes_sunset = [] self.echoes_sunset_no_sun = [] self.echoes_dusk = [] self.echoes_dusk_no_moon = [] self.echoes_dusk_full_moon = [] self.echoes_midnight = [] self.echoes_midnight_no_moon = [] self.echoes_midnight_full_moon = [] # Attributi volatili: self.max_players = 0 # Numero massimo di giocatori che sono stati presenti contemporaneamente nell'area nella sessione di gioco self.upper_limit = 0 # Limite di coordinata Z verso l'alto oltre la quale si esce dall'area self.lower_limit = 0 # Limite di coordinata Z verso il basso oltre la quale si esce dall'area self.rooms = {} # Stanze in-game nelle rispettive coordinate self.players = [] # Giocatori in-game che si trovano nelll'area self.mobs = [] # Mob in-game che si trovano nell'area self.items = [] # Oggetti in-game che si trovano nell'area self.meteo = Meteo() # Informazioni meteo in-game dell'area self.gamescripts = {} # Gamescript a livello di area # Liste relative ai dati modello dell'area, i prototipi self.proto_rooms = {} self.proto_mobs = {} self.proto_items = {}
class Weapon(object): PRIMARY_KEY = "" VOLATILES = [] MULTILINES = ["comment"] SCHEMA = {} REFERENCES = {} WEAKREFS = {} def __init__(self): self.comment = "" self.category = Element(WEAPON.NONE) # Tipo di arma self.flags = Flags(WEAPONFLAG.NONE) # Flag di arma self.damage = "" # Danno dell'arma, se vuoto viene ricavato automaticamente tramite una tabella #- Fine Inizializzazione - def __str__(self): return "%r: %s" % (self, sorted(self.__dict__)) #- Fine Metodo - def get_error_message(self, entity): if self.category.get_error_message(WEAPON, "category") != "": return self.category.get_error_message(WEAPON, "category") elif self.flags.get_error_message(WEAPONFLAG, "flags") != "": return self.category.get_error_message(WEAPONFLAG, "flags") return "" #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Weapon() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, weapon2): if not weapon2: return False if self.comment != weapon2.comment: return False if self.category != weapon2.category: return False if self.flags != weapon2.flags: return False if self.damage != weapon2.damage: return False return True
def __init__(self, columns=0, rows=0, code_prefix=""): self.columns = columns # Numero di colonne totali del labirinto self.rows = rows # Numero di righe totali del labirinto self.code_prefix = code_prefix # Prefisso del codice delle room utilizzate per il reset self.remake_hour = -1 # In quale ora il maze viene ricreato self.remake_weekday = Element(WEEKDAY.NONE) self.remake_message = "" # Messaggio di act a tutte le entità nel labirinto durante il relativo remake self.passages = [ ] # Elenco dei passaggi: entrate, uscite o altre nicchie, collegate al labirinto attorno al suo bordo self.dead_ends = [ ] # Elenco dei vicoli ciechi casualmente da inserire al posto di quelli standard # Variabili volatili self.cells = [] self.track_counter = 0 # Numero di room tracciate dall'algoritmo di creazione del maze
def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- try: entitype, percent, buyback_percent = line.split(None, 2) except ValueError: log.bug("Errore nella lettura di un Sellable nel file <%s> per la linea <%s> e l'attributo <%s>" % ( file.name, line, attr)) return self.entitype = Element(entitype) self.percent = fread_percent(file, percent, attr) self.buyback_percent = fread_percent(file, buyback_percent, attr)
def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- if "," in line: material, percent = line.split(",", 1) else: material, percent = line.split(None, 1) material = material.strip() percent = percent.strip() self.material = Element(material) self.percent = fread_percent(file, percent, attr)
def __init__(self, direction=DIR.NONE): if not direction: log.bug("direction non è un parametro valido: %r" % direction) return # --------------------------------------------------------------------- self.comment = "" # Eventuale commento al muro self.direction = Element(direction) # Tipologia della direzione self.maked_by = None # Oggetto di base utilizzato nella costruzione del muro (di solito un mattone o una pietra) self.depth = 0 # Profondità della parete, assieme al tipo di materiale in quella direzione ne fanno la forza, che serve nel caso si voglia romperlo, picconarlo, sfondarlo o farlo saltare in aria! self.height = 0 # Altezza del muro, se differente dall'altezza della stanza self.descr = "" # Descrizione dell'uscita che viene a formarsi quando il muro viene sfondato self.descr_night = "" # Descrizione notturna dell'uscita che viene a formarsi quando il muro viene sfondato self.descr_hearing = "" # Descrizione uditiva self.descr_hearing_night = "" # Descrizione uditiva notturna self.descr_smell = "" # Descrizione odorosa self.descr_smell_night = "" # Descrizione odorosa notturna self.descr_touch = "" # Descrizione tattile self.descr_touch_night = "" # Descrizione tattile notturna self.descr_taste = "" # Descrizione del sapore self.descr_taste_night = "" # Descrizione del sapore notturna self.descr_sixth = "" # Descrizione del sesto senso self.descr_sixth_night = "" # Descrizione del sesto senso notturna self.extras = Extras() # Elenco delle extra che si possono guardare o leggere sul muro
def __init__(self, fun_name=""): self.comment = "" self.fun_name = fun_name or "" # Nome della funzione self.type = Element(CMDTYPE.INFORMATION) # Tipologia del comando self.trust = Element(TRUST.PLAYER) # Fiducia minima per digitarlo self.position = Element(POSITION.REST) # Posizione minima per utilizzarlo self.flags = Flags(CMDFLAG.NONE) # Flag dei comandi self.no_races = Flags(RACE.NONE) # Razze che NON possono usarlo (RACE.NONE significa che tutti lo possono utilizzare) self.mini_help = "" # Piccola descrizione dell'utilizzo del comando self.timer = 0.0 # Tempo totale di esecuzione del comando (anche se nelle pagine d'amministrazione visualizza il tempo medio) # Variabili volatili self.module = None # Riferimento al modulo che contiene la funzione self.function = None # Riferimento alla funzione if self.fun_name: self.import_module_and_function()
def __init__(self, direction=DIR.NONE): if not direction: log.bug("direction non è un parametro valido: %r" % direction) return # --------------------------------------------------------------------- self.comment = "" # Eventuale commento all'uscita self.direction = Element(direction) # Tipologia della direzione self.descr = "" # Descrizione di quello che si vede guardando la direzione self.descr_night = "" # Descrizione notturna di quello che si vede guardando la direzione self.descr_hearing = "" # Descrizione uditiva self.descr_hearing_night = "" # Descrizione uditiva notturna self.descr_smell = "" # Descrizione odorosa self.descr_smell_night = "" # Descrizione odorosa notturna self.descr_touch = "" # Descrizione tattile self.descr_touch_night = "" # Descrizione tattile notturna self.descr_taste = "" # Descrizione del sapore self.descr_taste_night = "" # Descrizione del sapore notturna self.descr_sixth = "" # Descrizione del sesto senso self.descr_sixth_night = "" # Descrizione del sesto senso notturna self.icon = "" # Icona rappresentante l'uscita di giorno self.icon_night = "" # Icona rappresentante l'uscita di notte self.extras = Extras() # Descrizioni extra dell'uscita self.flags = Flags(EXIT.NONE) # Flags dell'uscita self.destination = None # Stanza a cui l'uscita porta se questa differente rispetto alla direzione presa self.door = None # Oggetto porta se serve aprirla (se non viene indicata questa viene caricata dal limbo una porta di default) (TD) qui vorrei aggiungere anche una variabile finestra.. ma poi come gestire finestre e porte multiple? e il key_code nel qual caso una finestra sia chiudibile (cmq per ora continuo così.. in effetti potrei considerare il fatto di voler inserire più porte o finestre in una uscita come una eccezione e gestirla tramite gamescripts) self.entity_message = "" # Messaggio di movimento per colui che si sta spostando self.others_in_message = "" # Messaggio di movimento per gli altri della stanza di partenza self.others_out_message = "" # Messaggio di movimento per gli altri della stanza di arrivo
def test_should_fill_with_element(self): # noqa: D102 grid_square = GridSquare() element = Element(ElementType.WALL) grid_square.fill_with(element) self.assertFalse(grid_square.is_empty())
def test_should_clear(self): # noqa: D102 grid_square = GridSquare() element = Element(ElementType.WALL) grid_square.fill_with(element) grid_square.clear() self.assertTrue(grid_square.is_empty())
def _wait_for_element(self): self._element = Element(self._driver, self._locator, self._position) WebDriverWait(self._driver, self._timeout).until( EC.visibility_of_element_located( (By.XPATH, self._element.locator)), "{} is not visible after {} seconds".format( self._element.name, self._timeout)) self._position = 0
def __init__(self): self.comment = "" # Commento per gli area builder relativo all'entità leggibile self.title = "" # Titolo del libro self.author = "" # Autore o gli autori di questo libro self.summary = "" # Riassunto del libro che il giocatore carpisce esaminandolo self.language = Element(LANGUAGE.COMMON) # (TD) Lingua di questo libro self.flags = Flags( READABLE.NONE) # Flag relative alle entità leggibili self.visual_width = "" # Larghezza in pixel del libro sullo schermo self.visual_height = "" # Larghezza in pixel del libro sullo schermo self.padding = "" # Larghezza in pixel del padding della cornice del libro self.border_top = "" # Bordo css decorante il libro in alto self.border_right = "" # Bordo css decorante il libro a destra self.border_bottom = "" # Bordo css decorante il libro in basso self.border_left = "" # Bordo css decorante il libro a sinistra self.border_inside = "" # Bordo css decorante il libro tra le due pagine self.number_decoration_left = "" # Decorazione della pagina sinistra per i numeri di pagina self.number_decoration_right = "" # Decorazione della pagina sinistra per i numeri di pagina self.pages = [] # Lista delle pagine e relativo contenuto
def __init__(self): self.comment = "" self.code = "" # Codice identificativo dell'help self.italian_keywords = "" # Parole di ricerca italiane self.english_keywords = "" # Parole di ricerca inglesi self.type = Element(HELP.NONE) # Tipologia dell'help self.text = "" # Testo visualizzato da tutti self.admin_text = "" # Testo visualizzato solo dagli Admin self.see_also = "" # Voci degli help simili a questo self.counter_use = 0 # Contatore dell'utilizzo dell'help self.syntax_function = None # Eventuale funzione che fa visualizzare la sintassi del comando
def __init__(self, code=""): super(ProtoMob, self).__init__() self.code = code or "" self.height = 0 self.constellation = Element( CONSTELLATION.NONE) # Costellazione sotto cui è nato il mob self.virtue = Element( VIRTUE.NONE) # Virtù che il mob segue principalmente self.hand = Element( HAND.NONE) # Indica quale mano utilizza preferibilmente self.hometown = "" # Area che il mob o il pg considera come propria casa self.group_name = "" # Nome del gruppo in cui fa parte, fanno parte tutti i mob che lo hanno uguale self.voice_emote = "" # Stringa che ne descrive la voce nel canale rpg_channel() self.voice_potence = 50 # Potenza della voce, 0 o meno significa aver perso la voce, per razze umanoidi i valori sono da 40 a 80, per razze 'minori' o 'maggiori' i valori possono variare e superare anche il 100 self.parts = { } # Forma, materiale, vita, flags delle parti sono già di default a seconda delle razza, però si possono cambiare anche a livello di file di area self.morph = None # Tipo di morph sotto cui il personaggio è affetto self.skill_messages = { } # Dizionario dei messaggi personalizzati riguardanti le skill # Attributi self.strength = 0 self.endurance = 0 self.agility = 0 self.speed = 0 self.intelligence = 0 self.willpower = 0 self.personality = 0 self.luck = 0 # Condizioni self.thirst = 0 self.hunger = 0 self.sleep = 0 self.drunkness = 0 self.adrenaline = 0 self.mind = 0 # Tale quale a quello dello smaug self.emotion = 0 # Tale quale a quello dello smaug self.bloodthirst = 0 self.eye_color = Element(COLOR.NONE) self.hair_color = Element(COLOR.NONE) self.hair_length = 0 self.hair_type = Element(HAIRTYPE.NONE) self.skin_color = Element(COLOR.NONE)
def __init__(self, columns=0, rows=0, code_prefix=""): self.columns = columns # Numero di colonne totali del labirinto self.rows = rows # Numero di righe totali del labirinto self.code_prefix = code_prefix # Prefisso del codice delle room utilizzate per il reset self.remake_hour = -1 # In quale ora il maze viene ricreato self.remake_weekday = Element(WEEKDAY.NONE) self.remake_message = "" # Messaggio di act a tutte le entità nel labirinto durante il relativo remake self.passages = [] # Elenco dei passaggi: entrate, uscite o altre nicchie, collegate al labirinto attorno al suo bordo self.dead_ends = [] # Elenco dei vicoli ciechi casualmente da inserire al posto di quelli standard # Variabili volatili self.cells = [] self.track_counter = 0 # Numero di room tracciate dall'algoritmo di creazione del maze
def __init__(self, layout, position): """Construct a TetrisPiece using the given Layout located at the given Position.""" super(TetrisPiece, self).__init__( attrs_dict={ 'layout': layout, 'position': position, 'elements': [ Element(ElementType.PIECE, position.add(elem_position)) for elem_position in layout.positions ] })
def __init__(self, name=""): self.comment = "" self.created_time = datetime.datetime.now( ) # Data di creazione del'account self.name = name # Nome di login self.password = "" # Password self.email = "" # Indirizzo e-mail (opzionale) self.options = Flags(OPTION.NONE) self.show_logs = Flags(LOG.NONE) self.aliases = {} # Dizionario relativo agli alias self.macros = {} # Dizionario relativo alle macro # (TD) provare a convertire questi datetime in None e caricarli tramite schema self.last_bug_sended_at = None self.last_comment_sended_at = None self.last_typo_sended_at = None self.last_idea_sended_at = None self.sended_bugs = 0 # Bug totali inviati self.sended_comments = 0 # Typo totali inviati self.sended_ideas = 0 # Idee totali inviati self.sended_typos = 0 # Typo totali inviati self.user_agents = [ ] # Informazioni relative ai client browser utilizzati dal giocatore per entrare nel Mud self.resolution_width = 0 # Risoluzione in pixel del monitor del client in larghezza self.resolution_height = 0 # Risoluzione in pixel del monitor del client in altezza # Al primo account creato in assoluto dà poteri di Implementor, dando # per scontato che il primo giocatore che utilizza questo Mud sia il # futuro amministratore, ai successivi account dona la trust di player if not database["accounts"]: self.trust = Element(TRUST.IMPLEMENTOR) else: self.trust = Element(TRUST.PLAYER) # Attributi volatili self.players = {} # Dizionario dei giocatori creati dall'account self.player = None # Personaggio che si sta creando o utilizzando
def load(self): filepath = "persistence/calendar.rpg" try: file = open(filepath, "r") except IOError: log.bug("Impossibile aprire il file %s in lettura" % filepath) return for line in file: if not line.strip(): continue if line[0] == "#": continue break else: log.bug("Non è stato trovato nessuna riga valida al file %s" % filepath) file.close() return file.close() values = line.split() if len(values) != 5: log.bug("E' stato trovato un numero inatteso di valori al file %s: %d" % (filepath, len(values))) return if is_number(values[0]): self.minute = int(values[0]) else: log.bug("minute del file %s non sono un numero valido: %s" % values[0]) if is_number(values[1]): self.hour = int(values[1]) else: log.bug("hour del file %s non sono un numero valido: %s" % values[1]) if is_number(values[2]): self.day = int(values[2]) else: log.bug("day del file %s non sono un numero valido: %s" % values[2]) self.month = Element(values[3]) if is_number(values[4]): self.year = int(values[4]) else: log.bug("year del file %s non sono un numero valido: %s" % values[4]) self.get_error_message()
def __init__(self, season=SEASON.NONE): self.season = Element(season) self.temperature = 17 # In gradi centigradi self.wind_direction = Element(DIR.NONE) # Direzione del vento self.cloud_color = Element(COLOR.NONE) # Colore delle nuvole self.cloud = 25 # Densità delle nuvole del cielo: 0 è limpido, 100 è completamente coperto self.humidity = 20 # Umidità nell'aria: 0 deserto secco, 100 foresta pluviale self.fog = 10 # Probabilità che vi sia la nebbia, da 0 a 100 self.rain = 15 # Probabilità che piova, da 0 a 100 (se la temperatura è bassa si tramuta in neve) self.hail = 2 # Probabilità che grandini, da 0 a 100 self.snow = 3 # Probabilità che nevichi self.lightning = 5 # Probabilità che tuoni e fulmini, da 0 a 100
def __init__(self): self.comment = "" # Commento per gli area builder relativo all'entità leggibile self.title = "" # Titolo del libro self.author = "" # Autore o gli autori di questo libro self.summary = "" # Riassunto del libro che il giocatore carpisce esaminandolo self.language = Element(LANGUAGE.COMMON) # (TD) Lingua di questo libro self.flags = Flags(READABLE.NONE) # Flag relative alle entità leggibili self.visual_width = "" # Larghezza in pixel del libro sullo schermo self.visual_height = "" # Larghezza in pixel del libro sullo schermo self.padding = "" # Larghezza in pixel del padding della cornice del libro self.border_top = "" # Bordo css decorante il libro in alto self.border_right = "" # Bordo css decorante il libro a destra self.border_bottom = "" # Bordo css decorante il libro in basso self.border_left = "" # Bordo css decorante il libro a sinistra self.border_inside = "" # Bordo css decorante il libro tra le due pagine self.number_decoration_left = "" # Decorazione della pagina sinistra per i numeri di pagina self.number_decoration_right = "" # Decorazione della pagina sinistra per i numeri di pagina self.pages = [] # Lista delle pagine e relativo contenuto
def __init__(self, fun_name=""): self.comment = "" self.fun_name = fun_name or "" # Nome della funzione self.type = Element(CMDTYPE.INFORMATION) # Tipologia del comando self.trust = Element(TRUST.PLAYER) # Fiducia minima per digitarlo self.position = Element( POSITION.REST) # Posizione minima per utilizzarlo self.flags = Flags(CMDFLAG.NONE) # Flag dei comandi self.no_races = Flags( RACE.NONE ) # Razze che NON possono usarlo (RACE.NONE significa che tutti lo possono utilizzare) self.mini_help = "" # Piccola descrizione dell'utilizzo del comando self.timer = 0.0 # Tempo totale di esecuzione del comando (anche se nelle pagine d'amministrazione visualizza il tempo medio) # Variabili volatili self.module = None # Riferimento al modulo che contiene la funzione self.function = None # Riferimento alla funzione if self.fun_name: self.import_module_and_function()
class Maze(object): """ Classe relativa ad un labirinto. """ PRIMARY_KEY = "" VOLATILES = ["cells", "track_counter"] MULTILINES = [] SCHEMA = {"passages" : ("src.games.maze", "MazePassage"), "dead_ends" : ("src.games.maze", "MazeDeadEnd")} REFERENCES = {} WEAKREFS = {} def __init__(self, columns=0, rows=0, code_prefix=""): self.columns = columns # Numero di colonne totali del labirinto self.rows = rows # Numero di righe totali del labirinto self.code_prefix = code_prefix # Prefisso del codice delle room utilizzate per il reset self.remake_hour = -1 # In quale ora il maze viene ricreato self.remake_weekday = Element(WEEKDAY.NONE) self.remake_message = "" # Messaggio di act a tutte le entità nel labirinto durante il relativo remake self.passages = [] # Elenco dei passaggi: entrate, uscite o altre nicchie, collegate al labirinto attorno al suo bordo self.dead_ends = [] # Elenco dei vicoli ciechi casualmente da inserire al posto di quelli standard # Variabili volatili self.cells = [] self.track_counter = 0 # Numero di room tracciate dall'algoritmo di creazione del maze #- Fine Inizializzazione - def get_error_message(self): if self.columns <= 1: return "colums non è valido: %d" % self.columns elif self.rows <= 1: return "rows non è valido: %d" % self.rows elif self.remake_hour < -1 and self.remake_hour > config.hours_in_day - 1: return "remake_hour non è un'ora rpg valida: %d (inserire da -1 a %d)" % (self.remake_hour, config.hours_in_day - 1) elif self.remake_weekday.get_error_message(WEEKDAY, "remake_weekday") != "": return self.remake_weekday.get_error_message(WEEKDAY, "remake_weekday") elif self.get_error_message_passages() != "": return self.get_error_message_passages() elif self.get_error_message_dead_ends() != "": return self.get_error_message_dead_ends() else: return "" #- Fine Metodo - def get_error_message_passages(self): for passage in self.passages: message = passage.get_error_message(self) if message: return message return "" #- Fine Metodo - def get_error_message_dead_ends(self): for dead_end in self.dead_ends: message = dead_end.get_error_message(self) if message: return message return "" #- Fine Metodo - def create(self, area): if not area: log.bug("area non è un parametro valido: %r" % area) return # --------------------------------------------------------------------- # Mette il token(none), wall(4 * True) e visited(false) a tutte le room self.cells = [[MazeCell() for r in xrange(self.rows)] for c in xrange(self.columns)] self.track_counter = 0 # A stack containing coordinates of the current cell and a scrambled # list of the direction to its neighbors shuffled = list(DIRS) random.shuffle(shuffled) # inizialmente contiene solo dati per una room: coordinate e la sequenza delle vicine scramblate stack = [StackElement(math.floor(random.random() * self.columns), math.floor(random.random() * self.rows), shuffled)] # Il loop deve iterare fino a che ha visitato tutte le celle, ma poiché # il depth first può anche tornare sui propri passi non basta farlo # iterare (self.rows * self.columns) volte while self.track_counter < (self.rows * self.columns): self.depth_first_search(stack) # Toglie i muri relativi ai vari passaggi fuori dai limiti della griglia # aprendo dei passi in questa maniera vengono correttamente caricate # le stanze a seconda delle uscite attorno for passage in self.passages: if passage.z != 0: continue coords = "%d %d %d" % (passage.x, passage.y, passage.z) if coords not in area.rooms: log.bug("Non esistono le coordinate %s nell'area %s (nel ciclo dei passages attorno)" % (coords, area.code)) continue passage_room = area.rooms[coords] if passage.y == -1: self.cells[passage.x][0].wall[SOUTH] = False; if DIR.NORTH not in passage_room.exits: passage_room.exits[DIR.NORTH] = Exit(DIR.NORTH) if passage.y == self.rows: self.cells[passage.x][self.rows - 1].wall[NORTH] = False; if DIR.SOUTH not in passage_room.exits: passage_room.exits[DIR.SOUTH] = Exit(DIR.SOUTH) if passage.x == -1: self.cells[0][passage.y].wall[WEST] = False; if DIR.EAST not in passage_room.exits: passage_room.exits[DIR.EAST] = Exit(DIR.EAST) if passage.x == self.columns: self.cells[self.columns - 1][passage.y].wall[EAST] = False; if DIR.WEST not in passage_room.exits: passage_room.exits[DIR.WEST] = Exit(DIR.WEST) # Crea ed avvia i reset per l'area del labirinto self.create_resets(area) # Crea le aperture in alto e in basso per eventuali altri passaggi # Non esistendo delle descrizioni di stanze con uscite verso il basso # e verso l'alto è dato al giocatore fare attenzione a queste uscite # verso l'inizio o la fine del labirinto o altre nicchie. # Stesso discorso per l'aggiunta delle uscite diagonali per i 4 angoli # esterni. # Se la room relativa al passaggio non possiede l'uscita per arrivare # alla stanza del labirinto viene creata automaticamente. for passage in self.passages: if passage.z == 0: maze_coords = "" if passage.x == -1 and passage.y == -1: maze_coords = "0 0 0" maze_dir = DIR.SOUTHWEST elif passage.x == -1 and passage.y == self.rows: maze_coords = "0 %d 0" % self.rows - 1 maze_dir = DIR.NORTHEAST elif passage.x == self.columns and passage.y == -1: maze_coords = "%d 0 0" % self.columns - 1 maze_dir = DIR.SOUTHEAST elif passage.x == self.columns and passage.y == self.rows: maze_coords = "%d %d 0" % (self.columns - 1, self.rows - 1) maze_dir = DIR.NORTHEAST if maze_coords: maze_room = area.rooms[maze_coords] maze_room.exits[maze_dir] = Exit(maze_dir) passage_coords = "%d %d %d" % (passage.x, passage.y, passage.z) if passage_coords not in area.rooms: log.bug("Non esistono le coordinate %s nell'area %s (nel ciclo dei passages negli angoli)" % (passage_coords, area.code)) continue passage_room = area.rooms[passage_coords] if maze_dir.reverse_dir not in passage_room.exits: passage_room.exits[maze_dir.reverse_dir] = Exit(maze_dir.reverse_dir) else: passage_coords = "%d %d %d" % (passage.x, passage.y, passage.z) if passage_coords not in area.rooms: log.bug("Non esistono le coordinate %s nell'area %s (nel ciclo dei passages nell'up & down)" % (passage_coords, area.code)) continue passage_room = area.rooms[passage_coords] maze_room = area.rooms["%d %d 0" % (passage.x, passage.y)] if passage.z == 1: maze_room.exits[DIR.UP] = Exit(DIR.UP) if DIR.DOWN not in passage_room.exits: passage_room.exits[DIR.DOWN] = Exit(DIR.DOWN) else: maze_room.exits[DIR.DOWN] = Exit(DIR.DOWN) if DIR.UP not in passage_room.exits: passage_room.exits[DIR.UP] = Exit(DIR.UP) # (TD) Ora provvede ad inserire casualmente i DeadEnds evitando # che questi tangino eventuali Passagges pass # Rimuove le informazioni delle MazeCell per pulizia self.cells = [] #- Fine Metodo - def depth_first_search(self, stack): tail_element = stack[-1] x = tail_element.x y = tail_element.y neighbors = tail_element.neighbors # When all cells have been visited at least once, it's done if not self.cells[x][y].visited: self.cells[x][y].visited = True self.track_counter = self.track_counter +1 # Stampa le coordinate della via seguita per la generazione del maze per # verificare che non restino celle non tracciate # When all cells have been visited at least once, it's done #print "(", x, ",", y, ")", "- room tracciate", self.track_counter # Look for a neighbor that is in the maze and hasn't been visited yet while len(neighbors) > 0: direction = neighbors.pop() if len(neighbors) == 0: stack.pop() # All neighbors checked, done with this one dx = x + DELTA["x"][direction] dy = y + DELTA["y"][direction] if dx >= 0 and dy >= 0 and dx < self.columns and dy < self.rows: if self.cells[dx][dy].visited == False: # Break down the wall between them. The new neighbor is # added onto the stack and becomes the new current cell self.cells[x][y].wall[direction] = False self.cells[dx][dy].wall[UNDIRS[direction]] = False shuffled = list(DIRS) random.shuffle(shuffled) new_element = StackElement(dx, dy, shuffled) stack.append(new_element); break; #- Fine Metodo - def create_resets(self, area): """ Esegue il reset del labirinto con le stanze appositamente create per l'area. """ for x in xrange(self.columns): for y in xrange(self.rows): wall = self.cells[x][y].wall # [NORTH, SOUTH, WEST, EAST ] #print "x:%d y:%d NORTH:%s SOUTH:%s WEST:%s EAST:%s" % (x, y, wall[NORTH], wall[SOUTH], wall[WEST], wall[EAST]) if wall == [True, False, True, True ]: code = "_sud" # switch 1 elif wall == [False, True, True, True ]: code = "_nord" # switch 1 elif wall == [True, True, False, True ]: code = "_ovest" elif wall == [True, True, True, False]: code = "_est" elif wall == [False, False, True, True ]: code = "_nord-sud" elif wall == [True, True, False, False]: code = "_est-ovest" elif wall == [False, False, False, False]: code = "_incrocio" elif wall == [True, False, True, False]: code = "_sud-est" # switch 2 elif wall == [True, False, False, True ]: code = "_sud-ovest" # switch 3 elif wall == [False, True, True, False]: code = "_nord-est" # switch 2 elif wall == [False, True, False, True ]: code = "_nord-ovest" # switch 3 elif wall == [False, False, False, True ]: code = "_3no-est" elif wall == [False, True, False, False]: code = "_3no-sud" # switch 4 elif wall == [False, False, True, False]: code = "_3no-ovest" elif wall == [True, False, False, False]: code = "_3no-nord" # switch 4 elif wall == [True, True, True, True ]: code = "_no" #; print wall else: log.bug("Qui non dovrebbe mai passare: %s", wall) continue room_reset = RoomReset() room_reset.proto_room = database["proto_rooms"][self.code_prefix + code] room_reset.destination = Destination(x, y, 0, area) area.room_resets.append(room_reset) # Una volta creati i reset li avvia area.defer_reset_events() #- Fine Metodo - def destroy(self, area): if not area: log.bug("area non è un parametro valido: %r" % area) return # --------------------------------------------------------------------- room_codes = [] for passage in self.passages: room_codes.append(passage.proto_room.code) area.stop_reset_events(except_these=room_codes) area.room_resets = [] area.extract_rooms(except_these=room_codes) #- Fine Metodo - def remake(self, area): # Ricava le entità da salvarsi e trasportare nel nuovo labirinto players = [] for player in area.players: self.send_remake_message(player) player = player.from_location(1, use_repop=False) players.append(player) entities = [] for entity in area.iter_contains(use_reversed=True): if not entity.location: log.bug("location dell'entità %s non è valido: %r" % (entity.code, entity.location)) continue if not entity.IS_PLAYER and entity.location.IS_ROOM: self.send_remake_message(entity) entity = entity.from_location(entity.quantity, use_repop=False) entities.append(entity) # Distrugge il vecchio labirinto e ne crea uno nuovo self.destroy(area) self.create(area) # Sposta le entità salvate precedentemente nel nuovo labirinto for entity in players + entities: if entity.previous_location() and entity.previous_location().IS_ROOM: coords = "%d %d %d" % (entity.previous_location().x, entity.previous_location().y, entity.previous_location().z) if coords in area.rooms: room = area.rooms[coords] else: room = random.choice(area.rooms.values()) else: room = random.choice(area.rooms.values()) entity.to_location(room) #- Fine Metodo - def send_remake_message(self, entity): if self.remake_message == "no_send": return if self.remake_message: message = "\n" + self.remake_message else: message = "\nD'improvviso le aperture e i corridoi attorno a te si muovono come mischiandosi e ti ritrovi smarrit$o." entity.send_output(message) entity.send_prompt()
def __init__(self): self.material = Element(MATERIAL.NONE) self.percent = 0
class MaterialPercentage(object): PRIMARY_KEY = "" VOLATILES = [] MULTILINES = [] SCHEMA = {} REFERENCES = {} WEAKREFS = {} def __init__(self): self.material = Element(MATERIAL.NONE) self.percent = 0 #- Fine Inizializzazione - def __repr__(self): return "%s %s %s%%" % (super( MaterialPercentage, self).__repr__(), self.material, self.percent) #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = MaterialPercentage() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Funzione - def equals(self, material2): if not material2: return False if self.material != material2.material: return False if self.percent != material2.percent: return False return True #- Fine Metodo - def get_error_message(self): if self.material.get_error_message( MATERIAL, "material", allow_none=False) != "": return self.material.get_error_message(MATERIAL, "material", allow_none=False) elif self.percent < 1 or self.percent > 100: return "percent dev'essere tra 1 e 100 e non %d" % self.percent return "" #- Fine Metodo - def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- if "," in line: material, percent = line.split(",", 1) else: material, percent = line.split(None, 1) material = material.strip() percent = percent.strip() self.material = Element(material) self.percent = fread_percent(file, percent, attr) #- Fine Metodo - def fwrite_the_line(self, file, label, indentation=""): """ Scrive su file un elemento sinonimo. """ if not file: log.bug("file non è un parametro valido: %r" % file) return if not label: log.bug("label non è un parametro valido: %r" % label) return # ------------------------------------------------------------------------- file.write("%s%s%s %s%%\n" % (indentation, label, self.material.code, self.percent))
def __init__(self): self.minute = 0 # Minuto rpg self.hour = 0 # Ora rpg self.day = 1 # Giorno rpg self.month = Element(MONTH.NONE) # Mese rpg self.year = 0 # Anno rpg
class Calendar(object): def __init__(self): self.minute = 0 # Minuto rpg self.hour = 0 # Ora rpg self.day = 1 # Giorno rpg self.month = Element(MONTH.NONE) # Mese rpg self.year = 0 # Anno rpg #- Fine Inizializzazione - def get_error_message(self): # L'anno non ha bisogno di check perché può avere qualsiasi valore if self.minute < 0 or self.minute > config.minutes_in_hour - 1: msg = "minute non è un valore valido: %d (dev'essere tra -1 e %d)" % (self.minute, config.minutes_in_hour - 1) elif self.hour < 0 or self.hour > config.hours_in_day - 1: msg = "hour non è un valore valido: %d (dev'essere tra 0 e %d)" % (self.hour, config.hours_in_day) elif self.day <= 0 or self.day > config.days_in_month: msg = "day non è un valore valido: %s (dev'essere tra -1 e %s)" % (self.day, config.days_in_month) elif self.month.get_error_message(MONTH, "month") != "": msg = self.month.get_error_message(MONTH, "month") else: return "" # Se arriva fino a qui ha un messaggio di errore da inviare log.bug("(Calendar) %s" % msg) return msg #- Fine Metodo - def __str__(self): return "%d-%02d-%02d %02d:%02d" % ( self.year, self.month.index, self.day, self.hour, self.minute) #- Fine Metodo - def load(self): filepath = "persistence/calendar.rpg" try: file = open(filepath, "r") except IOError: log.bug("Impossibile aprire il file %s in lettura" % filepath) return for line in file: if not line.strip(): continue if line[0] == "#": continue break else: log.bug("Non è stato trovato nessuna riga valida al file %s" % filepath) file.close() return file.close() values = line.split() if len(values) != 5: log.bug("E' stato trovato un numero inatteso di valori al file %s: %d" % (filepath, len(values))) return if is_number(values[0]): self.minute = int(values[0]) else: log.bug("minute del file %s non sono un numero valido: %s" % values[0]) if is_number(values[1]): self.hour = int(values[1]) else: log.bug("hour del file %s non sono un numero valido: %s" % values[1]) if is_number(values[2]): self.day = int(values[2]) else: log.bug("day del file %s non sono un numero valido: %s" % values[2]) self.month = Element(values[3]) if is_number(values[4]): self.year = int(values[4]) else: log.bug("year del file %s non sono un numero valido: %s" % values[4]) self.get_error_message() #- Fine Metodo - def save(self): filepath = "persistence/calendar.rpg" try: file = open(filepath, "w") except IOError: log.bug("Impossibile aprire il file %s in scrittura" % filepath) return file.write("# minute hour day month year\n") file.write("%d %d %d %s %d\n" % (self.minute, self.hour, self.day, self.month.code, self.year)) file.close() #- Fine Metodo - # ------------------------------------------------------------------------- def is_day(self): if self.hour >= config.sunrise_hour and self.hour <= config.sunset_hour: return True return False #- Fine Metodo - def is_night(self): if self.hour < config.sunrise_hour or self.hour > config.sunset_hour: return True return False #- Fine Metodo - def get_weekday(self): """ Ritorna il giorno corrente della settimana. """ # (bb) (TD) Per ora ogni anno il calendario si resetta al primo giorno # della settimana anche se l'ultimo giorno dell'anno rpg precedente # non era l'ultimo giorno della settimana day_number = (self.month.index + 1) * config.days_in_month day_number += self.day day_number %= len(WEEKDAY.elements) - 1 return WEEKDAY.elements[day_number] #- Fine Metodo - def get_season(self): """ Ritorna la stagione corrente. Le stagioni di "passaggio" durano 3 mesi, le altre 2 mesi. """ if self.month == MONTH.TEN or self.month == MONTH.ONE: return SEASON.WINTER elif self.month == MONTH.TWO or self.month == MONTH.THREE or self.month == MONTH.FOUR: return SEASON.SPRING elif self.month == MONTH.FIVE or self.month == MONTH.SIX: return SEASON.SUMMER elif self.month == MONTH.SEVEN or self.month == MONTH.EIGHT or self.month == MONTH.NINE: return SEASON.AUTUMN log.bug("self.month non è valido: %r" % self.month) return SEASON.NONE #- Fine Metodo - def get_first_month_of_season(self, season=None): if not season: season = self.get_season() if season == SEASON.WINTER: return MONTH.TEN elif season == SEASON.SPRING: return MONTH.TWO elif season == SEASON.SUMMER: return MONTH.FIVE elif season == SEASON.AUTUMN: return MONTH.SEVEN log.bug("Stagione mancante o errata: %r" % season) return MONTH.NONE #- Fine Metodo - def get_real_seconds_to(self, minute=-1, hour=-1, day=-1, month=MONTH.NONE, year=-1, force_advance=False): if minute < -1 or minute > config.minutes_in_hour: log.bug("minute non è un parametro valido: %d" % minute) return -1 if hour < -1 or hour > config.hours_in_day: log.bug("hour non è un parametro valido: %d" % hour) return -1 if day < -1 or day > config.days_in_month: log.bug("day non è un parametro valido: %d" % day) return -1 if not month: log.bug("month non è un parametro valido: %r" % month) return -1 if year < -1: log.bug("year non è un parametro valido: %d" % year) return -1 # force_advance ha valore di verità # --------------------------------------------------------------------- if minute == -1: #minute_is_defined = False minute = self.minute else: #minute_is_defined = True pass if hour == -1: hour_is_defined = False hour = self.hour else: hour_is_defined = True if day == -1: day_is_defined = False day = self.day else: day_is_defined = True if month == MONTH.NONE: month_is_defined = False month = self.month else: month_is_defined = True if year == -1: #year_is_defined = False year = self.year else: #year_is_defined = True pass # --------------------------------------------------------------------- advance_a_day = False if not hour_is_defined and minute > self.minute: hour += 1 # Le ore vanno da 0 al suo massimo escluso if hour >= config.hours_in_day: hour = 0 advance_a_day = True advance_a_month = False if advance_a_day: day += 1 # I giorni vanno da 1 al suo massimo incluso if day > config.days_in_month: day = 1 advance_a_month = True if advance_a_month: month += 1 # Se in una enumerazione sfora il massimo dei mesi rinizi dal # primo automaticamente (vedi cycle_on_last nel file element.py) if month == MONTH.ONE: year += 1 # year non ha limite superiore per cui non c'è bisogno di controllarlo # --------------------------------------------------------------------- #print minute, hour, day, month.index, year, "-->", # (TD) Brrrr... lo so che fa schifo, ma per ora si tiene così fino a # che non si trova un po' di tempo per trovare una struttura smart if force_advance: if month < self.month: #print "A1", year += 1 elif day < self.day and month <= self.month: if month_is_defined and month == self.month: #print "B1", year += 1 else: #print "B2", month += 1 if month == MONTH.ONE: #print "B3", year += 1 elif hour < self.hour and day <= self.day and month <= self.month: if day_is_defined and day == self.day: if month_is_defined and month == self.month: #print "C1", year += 1 else: #print "C2", month += 1 if month == MONTH.ONE: #print "C3", year += 1 else: #print "C4", day += 1 if day > config.days_in_month: #print "C5", day = 1 if month_is_defined and month == self.month: #print "C6", year += 1 else: #print "C7", month += 1 if month == MONTH.ONE: #print "C8", year += 1 elif minute < self.minute and hour <= self.hour and day <= self.day and month <= self.month: if hour_is_defined and hour == self.hour: if day_is_defined and day == self.day: if month_is_defined and month == self.month: #print "D1", year += 1 else: #print "D2", month += 1 if month == MONTH.ONE: #print "D3", year += 1 else: #print "D4", day += 1 if day > config.days_in_month: #print "D5", day = 1 if month_is_defined and month == self.month: #print "D6", year += 1 else: #print "D7", month += 1 if month == MONTH.ONE: #print "D8", year += 1 else: #print "D9", hour += 1 if hour >= config.hours_in_day: #print "D10", hour = 0 if day_is_defined and day == self.day: if month_is_defined and month == self.month: #print "D11", year += 1 else: #print "D12", month += 1 if month == MONTH.ONE: #print "D13", year += 1 else: #print "D14", day += 1 if day > config.days_in_month: #print "D15", day = 1 if month_is_defined and month == self.month: #print "D16", year += 1 else: #print "D17", month += 1 if month == MONTH.ONE: #print "D18", year += 1 # --------------------------------------------------------------------- minutes = (minute - self.minute) minutes += (hour - self.hour) * config.minutes_in_hour minutes += (day - self.day) * (config.minutes_in_hour * config.hours_in_day) minutes += (month.index - self.month.index) * (config.minutes_in_hour * config.hours_in_day * config.days_in_month) minutes += (year - self.year) * (config.minutes_in_hour * config.hours_in_day * config.days_in_month * config.months_in_year) #print "PROSSIMO RESET:%ss attuale:%d %d %d %d %d reset:%d %d %d %d %d %s %s %s" % ( # minutes * config.seconds_in_minute, # self.minute, self.hour, self.day, self.month.index, self.year, # minute, hour, day, month.index, year, # hour_is_defined, day_is_defined, month_is_defined) return minutes * config.seconds_in_minute #- Fine Metodo - def update(self): first_day_of_month = False first_day_of_year = False moment_type = "" if self.minute < config.minutes_in_hour - 1: self.minute += 1 else: self.minute = 0 # Controlla il cambio dell'ora if self.hour < config.hours_in_day - 1: self.hour += 1 else: self.hour = 0 # Controlla il cambio del giorno if self.day < config.days_in_month: self.day += 1 else: first_day_of_month = True self.day = 1 # Controlla il cambio del mese if self.month.index < len(MONTH.elements): self.month += 1 else: first_day_of_year = True self.month = MONTH.ONE self.year += 1 if self.hour == config.dawn_hour: moment_type = "dawn" elif self.hour == config.sunrise_hour: moment_type = "sunrise" elif self.hour == config.noon_hour: moment_type = "noon" elif self.hour == config.sunset_hour: moment_type = "sunset" elif self.hour == config.dusk_hour: moment_type = "dusk" elif self.hour == config.midnight_hour: moment_type = "midnight" from src.database import database if moment_type: for area in database["areas"].itervalues(): echoes = globals()["ECHOES_%s" % moment_type.upper()] # (TD) a seconda che nell'area vi sia bello o brutto tempo fa # vedere o meno il sole o la luna con messaggi appositi # E anche il sistema della luna piena area_echoes = getattr(area, "echoes_%s" % moment_type) if area_echoes: echoes = area_echoes # Poiché esistono anche gli echoes personalizzabili per stanza # allora esegue una ricerca stanza per stanza for room in reversed(area.rooms.values()): room_echoes = getattr(room, "echoes_%s" % moment_type) if room_echoes: echoes = room_echoes # Se la stanza è interna allora non fa visualizzare i # messaggi di echo di default, a meno che appunto non # siano stati inseriti ad uopo per la stanza if ROOM.INSIDE in room.flags and not room_echoes: pass elif echoes: # Non esegue il random pg per pg per poter avere un # messaggio unico almeno stanza per stanza room.echo(random.choice(echoes)) # I check sui trigger force_return = check_trigger(room, "on_" + moment_type, room) if force_return: continue for content in room.iter_all_entities(use_reversed=True): force_return = check_trigger(content, "on_" + moment_type, content) if force_return: break # A tutti fa visualizzare se il giorno è il primo dell'anno o del mese # (TD) in futuro anche il nome della settimana for player in database["players"].itervalues(): if not player.game_request: continue if first_day_of_year: player.send_output("\nOggi è il [white]primo giorno[close] dell'anno %d!" % self.year) player.send_prompt() elif first_day_of_month: player.send_output("\nOggi è il [white]primo giorno[close] del mese %s." % self.month.description) player.send_prompt()
def __init__(self): self.comment = "" self.category = Element(WEAPON.NONE) # Tipo di arma self.flags = Flags(WEAPONFLAG.NONE) # Flag di arma self.damage = "" # Danno dell'arma, se vuoto viene ricavato automaticamente tramite una tabella
class Climate(object): """ Gestisce le informazioni climatiche di un'area. """ PRIMARY_KEY = "" VOLATILES = [] MULTILINES = [] SCHEMA = { "temperature": ("", "temperature"), "cloud": ("", "percent"), "humidity": ("", "percent"), "fog": ("", "percent"), "rain": ("", "percent"), "hail": ("", "percent"), "snow": ("", "percent"), "lightning": ("", "percent") } REFERENCES = {} WEAKREFS = {} def __init__(self, season=SEASON.NONE): self.season = Element(season) self.temperature = 17 # In gradi centigradi self.wind_direction = Element(DIR.NONE) # Direzione del vento self.cloud_color = Element(COLOR.NONE) # Colore delle nuvole self.cloud = 25 # Densità delle nuvole del cielo: 0 è limpido, 100 è completamente coperto self.humidity = 20 # Umidità nell'aria: 0 deserto secco, 100 foresta pluviale self.fog = 10 # Probabilità che vi sia la nebbia, da 0 a 100 self.rain = 15 # Probabilità che piova, da 0 a 100 (se la temperatura è bassa si tramuta in neve) self.hail = 2 # Probabilità che grandini, da 0 a 100 self.snow = 3 # Probabilità che nevichi self.lightning = 5 # Probabilità che tuoni e fulmini, da 0 a 100 #- Fine Inizializzazione - def __repr__(self): return "%s: %s" % (super(Climate, self).__repr__, self.climate) #- Fine Metodo - def get_error_message(self): """ Controlla l'integrità degli attributi della istanza. """ if self.season.get_error_message(SEASON, "season") != "": msg = self.season.get_error_message(SEASON, "season") elif self.temperature < -273 or self.temperature > 10000: msg = "temperatura del clima errata: %d" % self.temperature elif self.wind_direction.get_error_message(DIR, "wind_direction") != "": msg = self.wind_direction.get_error_message(DIR, "wind_direction") elif self.cloud_color.get_error_message(COLOR, "cloud_color") != "": msg = self.cloud_color.get_error_message(COLOR, "cloud_color") elif self.cloud < 0 or self.cloud > 100: msg = "probabilità di nuvolosità errata: %d" % self.cloud elif self.humidity < 0 or self.humidity > 100: msg = "probabilità di umidità errata: %d" % self.humidity elif self.fog < 0 or self.fog > 100: msg = "probabilità di nebbia errata: %d" % self.fog elif self.rain < 0 or self.rain > 100: msg = "probabilità di pioggia errata: %d" % self.rain elif self.hail < 0 or self.hail > 100: msg = "probabilità di grandine errata: %d" % self.hail elif self.snow < 0 or self.snow > 100: msg = "probabilità di nevicate errata: %d" % self.snow elif self.lightning < 0 or self.lightning > 100: msg = "probabilità dei tempeste con fulmini errata: %d" % self.lightning else: return "" log.error("(Meteo: repr %s) %s" % (repr(self), msg)) return msg
class Maze(object): """ Classe relativa ad un labirinto. """ PRIMARY_KEY = "" VOLATILES = ["cells", "track_counter"] MULTILINES = [] SCHEMA = { "passages": ("src.games.maze", "MazePassage"), "dead_ends": ("src.games.maze", "MazeDeadEnd") } REFERENCES = {} WEAKREFS = {} def __init__(self, columns=0, rows=0, code_prefix=""): self.columns = columns # Numero di colonne totali del labirinto self.rows = rows # Numero di righe totali del labirinto self.code_prefix = code_prefix # Prefisso del codice delle room utilizzate per il reset self.remake_hour = -1 # In quale ora il maze viene ricreato self.remake_weekday = Element(WEEKDAY.NONE) self.remake_message = "" # Messaggio di act a tutte le entità nel labirinto durante il relativo remake self.passages = [ ] # Elenco dei passaggi: entrate, uscite o altre nicchie, collegate al labirinto attorno al suo bordo self.dead_ends = [ ] # Elenco dei vicoli ciechi casualmente da inserire al posto di quelli standard # Variabili volatili self.cells = [] self.track_counter = 0 # Numero di room tracciate dall'algoritmo di creazione del maze #- Fine Inizializzazione - def get_error_message(self): if self.columns <= 1: return "colums non è valido: %d" % self.columns elif self.rows <= 1: return "rows non è valido: %d" % self.rows elif self.remake_hour < -1 and self.remake_hour > config.hours_in_day - 1: return "remake_hour non è un'ora rpg valida: %d (inserire da -1 a %d)" % ( self.remake_hour, config.hours_in_day - 1) elif self.remake_weekday.get_error_message(WEEKDAY, "remake_weekday") != "": return self.remake_weekday.get_error_message( WEEKDAY, "remake_weekday") elif self.get_error_message_passages() != "": return self.get_error_message_passages() elif self.get_error_message_dead_ends() != "": return self.get_error_message_dead_ends() else: return "" #- Fine Metodo - def get_error_message_passages(self): for passage in self.passages: message = passage.get_error_message(self) if message: return message return "" #- Fine Metodo - def get_error_message_dead_ends(self): for dead_end in self.dead_ends: message = dead_end.get_error_message(self) if message: return message return "" #- Fine Metodo - def create(self, area): if not area: log.bug("area non è un parametro valido: %r" % area) return # --------------------------------------------------------------------- # Mette il token(none), wall(4 * True) e visited(false) a tutte le room self.cells = [[MazeCell() for r in xrange(self.rows)] for c in xrange(self.columns)] self.track_counter = 0 # A stack containing coordinates of the current cell and a scrambled # list of the direction to its neighbors shuffled = list(DIRS) random.shuffle(shuffled) # inizialmente contiene solo dati per una room: coordinate e la sequenza delle vicine scramblate stack = [ StackElement(math.floor(random.random() * self.columns), math.floor(random.random() * self.rows), shuffled) ] # Il loop deve iterare fino a che ha visitato tutte le celle, ma poiché # il depth first può anche tornare sui propri passi non basta farlo # iterare (self.rows * self.columns) volte while self.track_counter < (self.rows * self.columns): self.depth_first_search(stack) # Toglie i muri relativi ai vari passaggi fuori dai limiti della griglia # aprendo dei passi in questa maniera vengono correttamente caricate # le stanze a seconda delle uscite attorno for passage in self.passages: if passage.z != 0: continue coords = "%d %d %d" % (passage.x, passage.y, passage.z) if coords not in area.rooms: log.bug( "Non esistono le coordinate %s nell'area %s (nel ciclo dei passages attorno)" % (coords, area.code)) continue passage_room = area.rooms[coords] if passage.y == -1: self.cells[passage.x][0].wall[SOUTH] = False if DIR.NORTH not in passage_room.exits: passage_room.exits[DIR.NORTH] = Exit(DIR.NORTH) if passage.y == self.rows: self.cells[passage.x][self.rows - 1].wall[NORTH] = False if DIR.SOUTH not in passage_room.exits: passage_room.exits[DIR.SOUTH] = Exit(DIR.SOUTH) if passage.x == -1: self.cells[0][passage.y].wall[WEST] = False if DIR.EAST not in passage_room.exits: passage_room.exits[DIR.EAST] = Exit(DIR.EAST) if passage.x == self.columns: self.cells[self.columns - 1][passage.y].wall[EAST] = False if DIR.WEST not in passage_room.exits: passage_room.exits[DIR.WEST] = Exit(DIR.WEST) # Crea ed avvia i reset per l'area del labirinto self.create_resets(area) # Crea le aperture in alto e in basso per eventuali altri passaggi # Non esistendo delle descrizioni di stanze con uscite verso il basso # e verso l'alto è dato al giocatore fare attenzione a queste uscite # verso l'inizio o la fine del labirinto o altre nicchie. # Stesso discorso per l'aggiunta delle uscite diagonali per i 4 angoli # esterni. # Se la room relativa al passaggio non possiede l'uscita per arrivare # alla stanza del labirinto viene creata automaticamente. for passage in self.passages: if passage.z == 0: maze_coords = "" if passage.x == -1 and passage.y == -1: maze_coords = "0 0 0" maze_dir = DIR.SOUTHWEST elif passage.x == -1 and passage.y == self.rows: maze_coords = "0 %d 0" % self.rows - 1 maze_dir = DIR.NORTHEAST elif passage.x == self.columns and passage.y == -1: maze_coords = "%d 0 0" % self.columns - 1 maze_dir = DIR.SOUTHEAST elif passage.x == self.columns and passage.y == self.rows: maze_coords = "%d %d 0" % (self.columns - 1, self.rows - 1) maze_dir = DIR.NORTHEAST if maze_coords: maze_room = area.rooms[maze_coords] maze_room.exits[maze_dir] = Exit(maze_dir) passage_coords = "%d %d %d" % (passage.x, passage.y, passage.z) if passage_coords not in area.rooms: log.bug( "Non esistono le coordinate %s nell'area %s (nel ciclo dei passages negli angoli)" % (passage_coords, area.code)) continue passage_room = area.rooms[passage_coords] if maze_dir.reverse_dir not in passage_room.exits: passage_room.exits[maze_dir.reverse_dir] = Exit( maze_dir.reverse_dir) else: passage_coords = "%d %d %d" % (passage.x, passage.y, passage.z) if passage_coords not in area.rooms: log.bug( "Non esistono le coordinate %s nell'area %s (nel ciclo dei passages nell'up & down)" % (passage_coords, area.code)) continue passage_room = area.rooms[passage_coords] maze_room = area.rooms["%d %d 0" % (passage.x, passage.y)] if passage.z == 1: maze_room.exits[DIR.UP] = Exit(DIR.UP) if DIR.DOWN not in passage_room.exits: passage_room.exits[DIR.DOWN] = Exit(DIR.DOWN) else: maze_room.exits[DIR.DOWN] = Exit(DIR.DOWN) if DIR.UP not in passage_room.exits: passage_room.exits[DIR.UP] = Exit(DIR.UP) # (TD) Ora provvede ad inserire casualmente i DeadEnds evitando # che questi tangino eventuali Passagges pass # Rimuove le informazioni delle MazeCell per pulizia self.cells = [] #- Fine Metodo - def depth_first_search(self, stack): tail_element = stack[-1] x = tail_element.x y = tail_element.y neighbors = tail_element.neighbors # When all cells have been visited at least once, it's done if not self.cells[x][y].visited: self.cells[x][y].visited = True self.track_counter = self.track_counter + 1 # Stampa le coordinate della via seguita per la generazione del maze per # verificare che non restino celle non tracciate # When all cells have been visited at least once, it's done #print "(", x, ",", y, ")", "- room tracciate", self.track_counter # Look for a neighbor that is in the maze and hasn't been visited yet while len(neighbors) > 0: direction = neighbors.pop() if len(neighbors) == 0: stack.pop() # All neighbors checked, done with this one dx = x + DELTA["x"][direction] dy = y + DELTA["y"][direction] if dx >= 0 and dy >= 0 and dx < self.columns and dy < self.rows: if self.cells[dx][dy].visited == False: # Break down the wall between them. The new neighbor is # added onto the stack and becomes the new current cell self.cells[x][y].wall[direction] = False self.cells[dx][dy].wall[UNDIRS[direction]] = False shuffled = list(DIRS) random.shuffle(shuffled) new_element = StackElement(dx, dy, shuffled) stack.append(new_element) break #- Fine Metodo - def create_resets(self, area): """ Esegue il reset del labirinto con le stanze appositamente create per l'area. """ for x in xrange(self.columns): for y in xrange(self.rows): wall = self.cells[x][y].wall # [NORTH, SOUTH, WEST, EAST ] #print "x:%d y:%d NORTH:%s SOUTH:%s WEST:%s EAST:%s" % (x, y, wall[NORTH], wall[SOUTH], wall[WEST], wall[EAST]) if wall == [True, False, True, True]: code = "_sud" # switch 1 elif wall == [False, True, True, True]: code = "_nord" # switch 1 elif wall == [True, True, False, True]: code = "_ovest" elif wall == [True, True, True, False]: code = "_est" elif wall == [False, False, True, True]: code = "_nord-sud" elif wall == [True, True, False, False]: code = "_est-ovest" elif wall == [False, False, False, False]: code = "_incrocio" elif wall == [True, False, True, False]: code = "_sud-est" # switch 2 elif wall == [True, False, False, True]: code = "_sud-ovest" # switch 3 elif wall == [False, True, True, False]: code = "_nord-est" # switch 2 elif wall == [False, True, False, True]: code = "_nord-ovest" # switch 3 elif wall == [False, False, False, True]: code = "_3no-est" elif wall == [False, True, False, False]: code = "_3no-sud" # switch 4 elif wall == [False, False, True, False]: code = "_3no-ovest" elif wall == [True, False, False, False]: code = "_3no-nord" # switch 4 elif wall == [True, True, True, True]: code = "_no" #; print wall else: log.bug("Qui non dovrebbe mai passare: %s", wall) continue room_reset = RoomReset() room_reset.proto_room = database["proto_rooms"][ self.code_prefix + code] room_reset.destination = Destination(x, y, 0, area) area.room_resets.append(room_reset) # Una volta creati i reset li avvia area.defer_reset_events() #- Fine Metodo - def destroy(self, area): if not area: log.bug("area non è un parametro valido: %r" % area) return # --------------------------------------------------------------------- room_codes = [] for passage in self.passages: room_codes.append(passage.proto_room.code) area.stop_reset_events(except_these=room_codes) area.room_resets = [] area.extract_rooms(except_these=room_codes) #- Fine Metodo - def remake(self, area): # Ricava le entità da salvarsi e trasportare nel nuovo labirinto players = [] for player in area.players: self.send_remake_message(player) player = player.from_location(1, use_repop=False) players.append(player) entities = [] for entity in area.iter_contains(use_reversed=True): if not entity.location: log.bug("location dell'entità %s non è valido: %r" % (entity.code, entity.location)) continue if not entity.IS_PLAYER and entity.location.IS_ROOM: self.send_remake_message(entity) entity = entity.from_location(entity.quantity, use_repop=False) entities.append(entity) # Distrugge il vecchio labirinto e ne crea uno nuovo self.destroy(area) self.create(area) # Sposta le entità salvate precedentemente nel nuovo labirinto for entity in players + entities: if entity.previous_location() and entity.previous_location( ).IS_ROOM: coords = "%d %d %d" % (entity.previous_location().x, entity.previous_location().y, entity.previous_location().z) if coords in area.rooms: room = area.rooms[coords] else: room = random.choice(area.rooms.values()) else: room = random.choice(area.rooms.values()) entity.to_location(room) #- Fine Metodo - def send_remake_message(self, entity): if self.remake_message == "no_send": return if self.remake_message: message = "\n" + self.remake_message else: message = "\nD'improvviso le aperture e i corridoi attorno a te si muovono come mischiandosi e ti ritrovi smarrit$o." entity.send_output(message) entity.send_prompt()
def __init__(self): self.material = Element(MATERIAL.NONE) self.percent = 0
class Account(Data): """ Contiene tutte le informazioni e le opzioni di un Account di gioco, in esso c'è anche la lista dei personaggi creati e giocabili dal giocatore dell'account. """ PRIMARY_KEY = "name" VOLATILES = ["player", "players"] MULTILINES = [] SCHEMA = {"players" : ("src.player", "Player"), "player" : ("src.player", "Player"), "aliases" : ("src.account", "Alias"), "macros" : ("src.account", "Macro"), "user_agents" : ("", "str"), "created_time" : ("", "datetime"), "last_bug_sended_at" : ("", "datetime"), "last_comment_sended_at" : ("", "datetime"), "last_typo_sended_at" : ("", "datetime"), "last_idea_sended_at" : ("", "datetime")} REFERENCES = {} WEAKREFS = {} def __init__(self, name=""): self.comment = "" self.created_time = datetime.datetime.now() # Data di creazione del'account self.name = name # Nome di login self.password = "" # Password self.email = "" # Indirizzo e-mail (opzionale) self.options = Flags(OPTION.NONE) self.show_logs = Flags(LOG.NONE) self.aliases = {} # Dizionario relativo agli alias self.macros = {} # Dizionario relativo alle macro # (TD) provare a convertire questi datetime in None e caricarli tramite schema self.last_bug_sended_at = None self.last_comment_sended_at = None self.last_typo_sended_at = None self.last_idea_sended_at = None self.sended_bugs = 0 # Bug totali inviati self.sended_comments = 0 # Typo totali inviati self.sended_ideas = 0 # Idee totali inviati self.sended_typos = 0 # Typo totali inviati self.user_agents = [] # Informazioni relative ai client browser utilizzati dal giocatore per entrare nel Mud self.resolution_width = 0 # Risoluzione in pixel del monitor del client in larghezza self.resolution_height = 0 # Risoluzione in pixel del monitor del client in altezza # Al primo account creato in assoluto dà poteri di Implementor, dando # per scontato che il primo giocatore che utilizza questo Mud sia il # futuro amministratore, ai successivi account dona la trust di player if not database["accounts"]: self.trust = Element(TRUST.IMPLEMENTOR) else: self.trust = Element(TRUST.PLAYER) # Attributi volatili self.players = {} # Dizionario dei giocatori creati dall'account self.player = None # Personaggio che si sta creando o utilizzando #- Fine Inizializzazione - def __repr__(self): return "%s %s" % (super(Account, self).__repr__, self.name) #- Fine Metodo - def get_error_message(self, already_in_database=True): """ Ritorna una stringa vuota se l'account non ha errori, altrimenti il messaggio d'errore. Bisogna passare l'argomento already_in_database uguale a False quando si controlla l'integrità di un account appena creato e che non si è ancora aggiunto al database degli account. """ msg = "" if already_in_database != True and already_in_database != False: msg = "L'argomento already_in_database non è un booleano valido: %s" % already_in_database # --------------------------------------------------------------------- # self.player è lecito che sia anche None se l'account non sta giocando if msg: pass elif get_error_message_name(self.name, already_in_database) != "": msg = "%s: %s" % (get_error_message_name(self.name, already_in_database), self.name) elif get_error_message_password(self.password) != "": msg = "%s: %s" % (get_error_message_password(self.password), self.password) elif get_error_message_email(self.email, already_in_database) != "": msg = "%s: %s" % (get_error_message_email(self.email, already_in_database), self.email) elif self.trust.get_error_message(TRUST, "trust") != "": msg = self.trust.get_error_message(TRUST, "trust") elif self.options.get_error_message(OPTION, "options") != "": msg = self.options.get_error_message(OPTION, "options") elif self.show_logs.get_error_message(LOG, "logs") != "": msg = self.show_logs.get_error_message(LOG, "logs") elif len(self.players) > config.max_account_players: msg = "Numero di personaggi superiore a %s" % config.max_account_players elif self._get_error_message_only_one_player() != "": msg = self._get_error_message_only_one_player() elif len(self.aliases) > config.max_aliases: msg = "Numero degli alias superiore al massimo (%d): %d" % (config.max_aliases, len(self.aliases)) elif len(self.macros) > config.max_macros: msg = "Numero delle macro superiore al massimo (%d): %d" % (config.max_macros, len(self.macros)) elif self.resolution_width < 0: msg = "Risoluzione del client in larghezza errato: %d" % self.resolution_width elif self.resolution_height < 0: msg = "Risoluzione del client in altezza errato: %d" % self.resolution_height else: return "" # Se ha trovato un errore invia il relativo messaggio log.bug("(Account: name %s) %s" % (self.name, msg)) return msg #- Fine Metodo - def _get_error_message_only_one_player(self): """ Controlla che due o più account non utilizzino lo stesso player. """ for player in self.players.itervalues(): for account in database["accounts"].itervalues(): if account.name == self.name: continue if player.code in account.players: return "Personaggio %s già esistente nell'account %s" % (player.code, account.name) return "" #- Fine Metodo - # ------------------------------------------------------------------------- def get_id(self): """ Ritorna una o tutte tra le seguenti informazioni: il nome dell'account e il nome del personaggio. Molto utile da utilizzare nei messaggi di log. Questo metodo fa a coppia con quello nella classe Connection. """ player_name = "None" if self.player: player_name = self.player.code return "%s.%s" % (self.name, player_name) #- Fine Metodo - def check_alias(self, arg, argument): """ Controlla se argument sia un alias di un pg, se sì lo ritorna. """ if not arg: log.bug("arg non è un parametro valido: %r" % arg) return # --------------------------------------------------------------------- if arg not in self.aliases: return False alias = self.aliases[arg] argument = argument or "" interpret(self.player, "%s %s" % (alias.action, argument), use_check_alias=False) return True
class Area(Data, AreaResetsSuperclass): """ Contiene tutte le informazioni di un'area e i metodi per gestirla. """ PRIMARY_KEY = "code" VOLATILES = ["max_players", "upper_limit", "lower_limit", "rooms", "players", "mobs", "items", "room_scripts", "mob_scripts", "item_scripts", "player_scripts", "meteo", "proto_rooms", "proto_mobs", "proto_items"] MULTILINES = ["descr"] SCHEMA = {"climates" : ("src.climate", "Climate"), "maze" : ("src.games.maze", "Maze"), "wumpus" : ("src.games.wumpus", "Wumpus"), "wild" : ("src.wild", "Wild"), "room_resets" : ("src.reset", "RoomReset"), "echoes_dawn" : ("", "str"), "echoes_dawn_no_sun" : ("", "str"), "echoes_sunrise" : ("", "str"), "echoes_sunrise_no_sun" : ("", "str"), "echoes_noon" : ("", "str"), "echoes_noon_no_sun" : ("", "str"), "echoes_sunset" : ("", "str"), "echoes_sunset_no_sun" : ("", "str"), "echoes_dusk" : ("", "str"), "echoes_dusk_no_moon" : ("", "str"), "echoes_dusk_full_moon" : ("", "str"), "echoes_midnight" : ("", "str"), "echoes_midnight_no_moon" : ("", "str"), "echoes_midnight_full_moon" : ("", "str")} REFERENCES = {} WEAKREFS = {} IS_AREA = True IS_DESCR = False IS_ROOM = False IS_EXIT = False IS_WALL = False IS_ACTOR = False IS_MOB = False IS_ITEM = False IS_PLAYER = False IS_EXTRA = False IS_PROTO = False def __init__(self, code=""): self.comment = "" self.code = code # Codice identificativo dell'area self.name = "" # Nome esteso self.short = "" # Descrizioni breve dell'area self.short_night = "" # Descrizioni breve notturna dell'area self.descr = "" # Descrizione dell'area per la pagina web della lista delle aree self.creators = "" # Lista dei creatori, vale il codice dell'account (TD) in futuro sarà una lista per poter ricavare il riferimento self.level = 1 # Livello base per tutte le entità dell'area, se viene modificato questo anche tutte le entità aumentano o diminuiscono di livello in proporzione self.flags = Flags(AREA.NONE) # self.races = Flags(RACE.NONE) # Razze che si possono incontrare principalmente nell'area (TD) self.color = Element(COLOR.NONE) # Colore dell'area self.music = "" # File mid avviato quando uno entra nell'area self.music_wild = "" # File mid avviato quando uno esce dall'area ed entra nella wild self.climates = {} # Informazioni climatiche dell'area relativamente alle stagioni self.maze = None # Informazioni relative al labirinto self.wumpus = None # Informazioni relative alle aree wumpus self.wild = None # Struttura relativa alla wilderness self.landfill_code = "" # Codice della stanza prototipo in cui verranno inseriti gli oggetti "da buttare" self.repop_time = 0 # Minuti reali tra un repop di un'entità ed un'altro self.room_resets = [] # Lista dei reset dell'area # Attributi relativi alle liste dei messaggi di echo self.echoes_dawn = [] self.echoes_dawn_no_sun = [] self.echoes_sunrise = [] self.echoes_sunrise_no_sun = [] self.echoes_noon = [] self.echoes_noon_no_sun = [] self.echoes_sunset = [] self.echoes_sunset_no_sun = [] self.echoes_dusk = [] self.echoes_dusk_no_moon = [] self.echoes_dusk_full_moon = [] self.echoes_midnight = [] self.echoes_midnight_no_moon = [] self.echoes_midnight_full_moon = [] # Attributi volatili: self.max_players = 0 # Numero massimo di giocatori che sono stati presenti contemporaneamente nell'area nella sessione di gioco self.upper_limit = 0 # Limite di coordinata Z verso l'alto oltre la quale si esce dall'area self.lower_limit = 0 # Limite di coordinata Z verso il basso oltre la quale si esce dall'area self.rooms = {} # Stanze in-game nelle rispettive coordinate self.players = [] # Giocatori in-game che si trovano nelll'area self.mobs = [] # Mob in-game che si trovano nell'area self.items = [] # Oggetti in-game che si trovano nell'area self.meteo = Meteo() # Informazioni meteo in-game dell'area self.gamescripts = {} # Gamescript a livello di area # Liste relative ai dati modello dell'area, i prototipi self.proto_rooms = {} self.proto_mobs = {} self.proto_items = {} #- Fine Inizializzazione - def __repr__(self): return "%s %s" % (super(Area, self).__repr__, self.code) #- Fine Metodo - def get_error_message(self): """ Ritorna un messaggio di errore se la struttura dell'area contiene delle anomalie, altrimenti se tutto è corretto ritorna una stringa vuota. """ if not self.code: msg = "code dell'area non valido" elif not self.code.islower(): msg = "code dell'area per convenzione deve essere scritto in minuscolo: %s" % self.code elif not self.short: msg = "short dell'area non valido: %r" % self.short elif not self.name: msg = "name dell'area non valido: %r" % self.name elif not self.descr: msg = "descr dell'area non valida: %r" % self.descr elif self.get_error_message_creators() != "": msg = self.get_error_message_creators() elif self.level <= 0: msg = "Il livello di un'area non può essere uguale a 0 o negativo: %d" % self.level # elif self.races.get_error_message(RACE, "races") != "": # msg = self.races.get_error_message(RACE, "races") elif self.flags.get_error_message(AREA, "flags") != "": msg = self.flags.get_error_message(AREA, "flags") elif self.color.get_error_message(COLOR, "color") != "": msg = self.color.get_error_message(COLOR, "color") elif self.get_error_message_climates() != "": msg = self.get_error_message_climates() elif self.maze and self.maze.get_error_message() != "": msg = self.maze.get_error_message() elif self.wumpus and self.wumpus.get_error_message() != "": msg = self.wumpus.get_error_message() elif self.repop_time < config.min_repop_time or self.repop_time > config.max_repop_time: msg = "il repop time deve essere compreso tra %d e %d minuti invece è: %d" % ( config.min_repop_time, config.max_repop_time, self.repop_time) elif not self.landfill_code and not self.wild: msg = "landfill_code dell'area non valido: %r" % self.landfill_code elif self.get_error_message_resets() != "": msg = self.get_error_message_resets() else: return "" # Se arriva qui c'è un messaggio d'errore da inviare log.error("(Area: %s) %s" % (self.code, msg)) return msg #- Fine Metodo - def get_error_message_creators(self): if self.creators: from src.database import database hint = "controllare di aver inserito il nome con la maiuscola" for name in self.creators.split(): if name not in database["accounts"]: #return "area %s non ha trovato nell'etichetta Creators un nome tra quelli degli account: %s (%s)" % ( # self.code, name, hint) continue return "" #- Fine Metodo - def get_error_message_climates(self): for climate in self.climates: if climate.get_error_message() != "": return climate.get_error_message() return "" #- Fine Metodo - # (TD) def get_pedantic_messages(self): messages = [] if not self.short_night and "@empty_short_night" not in self.comment: messages.append("short_night non è stata scritta, da ignorare nel qual caso nell'area non sussistano grossi cambiamenti di luce o altro, tra giorno e notte. (@empty_short_night)") length = len(remove_colors(getattr(self, "descr"))) if length > config.max_google_translate * 2 and "@descr_too_long" not in self.comment: messages.append("descr è più lunga di %d caratteri: %d (@descr_too_long)" % (config.max_google_translate * 2, length)) for i, message in enumerate(messages): messages[i] = "(Area: code %s) %s" % (self.code, message) return messages #- Fine Metodo - def get_name(self, looker=None): # (TD) fare il sistema di self.name if calendar.is_night() and self.short_night: return self.short_night else: return self.short #- Fine Metodo - def extract_rooms(self, except_these=None): if except_these is None: except_these = [] for room in reversed(self.rooms.values()): if room.prototype.code not in except_these: room.extract(1) # (TD) L'estrazione del resto delle altre entità non dovrebbe servire, # tuttavia in futuro sarebbe il caso di aggiungere un check per # controllare i riferimenti #- Fine Metodo - # (TT) Questo metodo è uguale a quello in entity.py, possibilità di accorpare? def iter_contains(self, entity_tables=None, use_reversed=False): """ È curioso come a volte questo metodo possa essere utilizzato per iterare i codici dell entità prototipo passando un entity_tables uguale a questo: ("proto_items", "proto_mobs", "proto_rooms"); per avere i valori di prototipo invece basta utilizzare il metodo iter_protos. """ if not entity_tables: entity_tables = ["items", "mobs", "players"] if use_reversed: for type in entity_tables: for content in reversed(getattr(self, type)): yield content else: for type in entity_tables: for content in getattr(self, type): yield content #- Fine Metodo - def iter_protos(self, entity_tables=None, use_reversed=False): if not entity_tables: entity_tables = ["proto_items", "proto_mobs", "proto_rooms"] if use_reversed: for type in entity_tables: for content in reversed(getattr(self, type).values()): yield content else: for type in entity_tables: for content in getattr(self, type).values(): yield content #- Fine Metodo - def get_list_of_entities(looker, include_looker="dummy-parameter", avoid_inventory="dummy-parameter", avoid_equipment="dummy-parameter", admin_descrs="dummy-parameter"): return getattr(self, entity_type) #- Fine Metodo - def get_min_coord(self, axis): if axis not in ("x", "y", "z"): log.bug("axis non è una asse cartesiano valido: %s" % axis) return 0 #---------------------------------------------------------------------- coords = [] for room_reset in self.room_resets: coords.append(getattr(room_reset.destination, axis)) if coords: return min(coords) else: return 0 #- Fine Metodo - def get_max_coord(self, axis): if axis not in ("x", "y", "z"): log.bug("axis non è una asse cartesiano valido: %s" % axis) return 0 #---------------------------------------------------------------------- coords = [] for room_reset in self.room_resets: coords.append(getattr(room_reset.destination, axis)) if coords: return max(coords) else: return 0
class Readable(object): PRIMARY_KEY = "" VOLATILES = [] MULTILINES = ["comment", "pages", "summary"] SCHEMA = { "visual_width": ("", "css_measure"), "visual_height": ("", "css_measure"), "padding": ("", "css_measure"), "border_top": ("", "css_border"), "border_right": ("", "css_border"), "border_bottom": ("", "css_border"), "border_left": ("", "css_border"), "border_inside": ("", "css_border"), "pages": ("", "str") } REFERENCES = {} WEAKREFS = {} def __init__(self): self.comment = "" # Commento per gli area builder relativo all'entità leggibile self.title = "" # Titolo del libro self.author = "" # Autore o gli autori di questo libro self.summary = "" # Riassunto del libro che il giocatore carpisce esaminandolo self.language = Element(LANGUAGE.COMMON) # (TD) Lingua di questo libro self.flags = Flags( READABLE.NONE) # Flag relative alle entità leggibili self.visual_width = "" # Larghezza in pixel del libro sullo schermo self.visual_height = "" # Larghezza in pixel del libro sullo schermo self.padding = "" # Larghezza in pixel del padding della cornice del libro self.border_top = "" # Bordo css decorante il libro in alto self.border_right = "" # Bordo css decorante il libro a destra self.border_bottom = "" # Bordo css decorante il libro in basso self.border_left = "" # Bordo css decorante il libro a sinistra self.border_inside = "" # Bordo css decorante il libro tra le due pagine self.number_decoration_left = "" # Decorazione della pagina sinistra per i numeri di pagina self.number_decoration_right = "" # Decorazione della pagina sinistra per i numeri di pagina self.pages = [] # Lista delle pagine e relativo contenuto #- Fine Inizializzazione - def get_error_message(self, entity): if not self.title: return "title è una stringa non valida: %r" % self.title elif not self.author: return "author è una stringa non valida: %r" % self.author elif not self.summary: return "summary è una stringa non valida: %r" % self.summary elif self.language.get_error_message(LANGUAGE, "language") != "": return self.language.get_error_message(LANGUAGE, "language") elif self.flags.get_error_message(READABLE, "flags") != "": return self.flags.get_error_message(READABLE, "flags") elif READABLE.CENTER in self.flags and READABLE.RIGHT in self.flags: return "Non possono convivere le flag READABLE.CENTER e READABLE.RIGHT assieme." elif (self.number_decoration_left or self.number_decoration_right ) and READABLE.NUMBERS not in self.flags: return "Nonostante sia stata definita una decorazione per i numeri non esiste la flag READABLE.NUMBERS che la mostrerebbe." elif not self.visual_width: return "visual_width è una stringa non valida: %r" % self.visual_width elif not self.visual_height: return "visual_height è una stringa non valida: %r" % self.visual_height elif not self.pages: return "dev'esservi almeno una pagina: %r" % self.pages return "" #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Readable() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, readable2): if not readable2: return False if self.comment != readable2.comment: return False if self.title != readable2.title: return False if self.author != readable2.author: return False if self.summary != readable2.summary: return False if self.language != readable2.language: return False if self.flags != readable2.flags: return False if self.visual_width != readable2.visual_width: return False if self.visual_height != readable2.visual_height: return False if self.padding != readable2.padding: return False if self.border_top != readable2.border_top: return False if self.border_right != readable2.border_right: return False if self.border_bottom != readable2.border_bottom: return False if self.border_left != readable2.border_left: return False if self.border_inside != readable2.border_inside: return False if self.number_decoration_left != readable2.number_decoration_left: return False if self.number_decoration_right != readable2.number_decoration_right: return False if len(self.pages) != len(readable2.pages): return False for page in self.pages: for page2 in readable2.pages: if page == page2: break else: return False return True #- Fine Metodo - # ------------------------------------------------------------------------- # (TD) entity e target serviranno in futuro per scramblerare la lingua del # libro se sconosciuta def get_pages(self, entity, target, page_number, from_location=None): if not entity: log.bug("entity non è un parametro valido: %r" % entity) return "" if not target: log.bug("target non è un parametro valido: %r" % target) return "" if page_number < 0 or page_number >= len(self.pages): log.bug("page_number non è un parametro valido: %r" % page_number) return "" # --------------------------------------------------------------------- # Prepara i bordi border_top = "" border_right = "" border_bottom = "" border_left = "" border_inside = "" if self.border_top: border_top = "border-top:%s;" % self.border_top if self.border_right: border_right = "border-right:%s;" % self.border_right if self.border_bottom: border_bottom = "border-bottom:%s;" % self.border_bottom if self.border_left: border_left = "border-left:%s;" % self.border_left if self.border_inside: border_inside = "border-right:%s;" % self.border_inside # Prepara il padding se esistente padding_style = "" if self.padding: padding_style = "padding:%s;" % self.padding # Prepara lo style css per l'output scritto della pagina alignment = "" if READABLE.CENTER in self.flags: alignment = '''text-align:center;''' if READABLE.RIGHT in self.flags: alignment = '''text-align:right;''' visual_style = ''' style="min-width:%s; max-width:%s; min-height:%s; max-height:%s; %s %s"''' % ( self.visual_width, self.visual_width, self.visual_height, self.visual_height, padding_style, alignment) # Ricava informazioni che servono a sfogliare il libro tramite click translated_input = translate_input(entity, "read", "en") if not translated_input: log.bug("Non è stato possibile tradurre l'input read per %s: %r" % (target.code, translated_input)) return False numbered_keyword = target.get_numbered_keyword(looker=entity) if page_number % 2 == 0 and page_number != len(self.pages) - 1: minimum_page = max([0, page_number - 2]) maximum_page = min([len(self.pages) - 1, page_number + 1]) else: minimum_page = max([0, page_number - 1]) maximum_page = min([len(self.pages) - 1, page_number + 2]) if from_location: js_minimum_arguments = "%s %s %s %d" % ( translated_input, numbered_keyword, from_location.get_numbered_keyword(looker=entity), minimum_page) js_maximum_arguments = "%s %s %s %d" % ( translated_input, numbered_keyword, from_location.get_numbered_keyword(looker=entity), maximum_page) else: js_minimum_arguments = "%s %s %d" % ( translated_input, numbered_keyword, minimum_page) js_maximum_arguments = "%s %s %d" % ( translated_input, numbered_keyword, maximum_page) browse_to_left = '''<div style="float:left"><a href="javascript:sendInput('%s')" style="font-size:larger"><</a> </div>''' % js_minimum_arguments browse_to_right = '''<div style="float:left"> <a href="javascript:sendInput('%s')" style="font-size:larger">></a></div>''' % js_maximum_arguments # Gestisce la copertina e la retrocopertina o altre tipologie di entità # leggibili differenti da dei libri, ovvero con al massimo il fronte # e il retro if page_number == 0 or page_number == len(self.pages) - 1: style = "" if border_top or border_right or border_bottom or border_left: style = ''' style="float:left; %s%s%s%s"''' % ( border_top, border_right, border_bottom, border_left) output = "" if page_number == len(self.pages) - 1: output += browse_to_left output += '''<div%s><div%s>%s</div></div>''' % ( style, visual_style, self.pages[page_number]) if page_number == 0: output += browse_to_right output += '''<div style="clear:both;" />''' return output # A seconda che si voglia visualizzare una pagina a destra o a sinistra # sceglie il numero corretto di pagina da far visualizzare nell'altra if page_number % 2 == 0: left_page_number = page_number - 1 right_page_number = page_number else: left_page_number = page_number right_page_number = page_number + 1 # Prepara lo stile dei bordi preparati in precedenza, se ve n'erano left_style = '''style="float:left;%s%s%s%s"''' % ( border_top, border_inside, border_bottom, border_left) right_style = '''style="float:left;%s%s%s"''' % ( border_top, border_right, border_bottom) # Prepara il contenuto scritto delle pagine aggiungendo una pagina # vuota prima della retrocopertina se necessario left_output = self.pages[left_page_number] if len(self.pages) % 2 == 0 and page_number == len(self.pages) - 1: right_output = "" elif len(self.pages) % 2 == 1 and page_number == len(self.pages) - 2: right_output = "" else: right_output = self.pages[right_page_number] if MIML_SEPARATOR in left_output: left_output = target.parse_miml(left_output, looker=entity) if MIML_SEPARATOR in right_output: right_output = target.parse_miml(right_output, looker=entity) # Prepara l'output per i numeri di pagina left_page_number_output = "" right_page_number_output = "" if READABLE.NUMBERS in self.flags: if len(self.number_decoration_left) == 0: left_page_number_output = '''<center>%d</center>''' % left_page_number elif len(self.number_decoration_left) == 1: left_page_number_output = '''<center>%s%d</center>''' % ( self.number_decoration_left, left_page_number) else: middle = int(math.ceil(len(self.number_decoration_left) / 2.0)) left_page_number_output = '''<center>%s%d%s</center>''' % ( self.number_decoration_left[:middle], left_page_number, self.number_decoration_left[middle:]) if len(self.number_decoration_right) == 0: right_page_number_output = '''<center>%d</center>''' % right_page_number elif len(self.number_decoration_right) == 1: right_page_number_output = '''<center>%d%s</center>''' % ( right_page_number, self.number_decoration_right) else: middle = int(math.floor( len(self.number_decoration_left) / 2.0)) right_page_number_output = '''<center>%s%d%s</center>''' % ( self.number_decoration_right[:middle], right_page_number, self.number_decoration_right[middle:]) # Ecco l'output del libro in tutto il suo splendore output = browse_to_left output += '''<div %s><div%s>%s</div>%s</div>''' % ( left_style, visual_style, left_output, left_page_number_output) output += '''<div %s><div%s>%s</div>%s</div>''' % ( right_style, visual_style, right_output, right_page_number_output) output += browse_to_right output += '''<div style="clear:both;" />''' return output
class Wall(Describable): """ Classe per la gestione di un muro di stanza. """ PRIMARY_KEY = "direction" VOLATILES = [] MULTILINES = ["comment"] SCHEMA = {"extras" : ("src.extra", "ExtraDescription")} REFERENCES = {"maked_by" : ["proto_items", "proto_mobs"]} WEAKREFS = {} IS_AREA = False IS_DESCR = True IS_ROOM = False IS_EXIT = False IS_WALL = True IS_ACTOR = False IS_MOB = False IS_ITEM = False IS_PLAYER = False IS_EXTRA = False IS_PROTO = False def __init__(self, direction=DIR.NONE): if not direction: log.bug("direction non è un parametro valido: %r" % direction) return # --------------------------------------------------------------------- self.comment = "" # Eventuale commento al muro self.direction = Element(direction) # Tipologia della direzione self.maked_by = None # Oggetto di base utilizzato nella costruzione del muro (di solito un mattone o una pietra) self.depth = 0 # Profondità della parete, assieme al tipo di materiale in quella direzione ne fanno la forza, che serve nel caso si voglia romperlo, picconarlo, sfondarlo o farlo saltare in aria! self.height = 0 # Altezza del muro, se differente dall'altezza della stanza self.descr = "" # Descrizione dell'uscita che viene a formarsi quando il muro viene sfondato self.descr_night = "" # Descrizione notturna dell'uscita che viene a formarsi quando il muro viene sfondato self.descr_hearing = "" # Descrizione uditiva self.descr_hearing_night = "" # Descrizione uditiva notturna self.descr_smell = "" # Descrizione odorosa self.descr_smell_night = "" # Descrizione odorosa notturna self.descr_touch = "" # Descrizione tattile self.descr_touch_night = "" # Descrizione tattile notturna self.descr_taste = "" # Descrizione del sapore self.descr_taste_night = "" # Descrizione del sapore notturna self.descr_sixth = "" # Descrizione del sesto senso self.descr_sixth_night = "" # Descrizione del sesto senso notturna self.extras = Extras() # Elenco delle extra che si possono guardare o leggere sul muro #- Fine Inizializzazione - def get_error_message(self): """ Se nell'instanza del muro c'è un errore ritorna il relativo messaggio. """ if self.direction.get_error_message(DIR, "direction", allow_none=False) != "": msg = self.direction.get_error_message(DIR, "direction", allow_none=False) elif not self.maked_by: msg = "non esiste nessuna entità legata a maked_by" elif self.maked_by and self.maked_by.code not in database["proto_items"]: msg = "non esiste nessun oggetto prototipo dal codice %s" % self.maked_by.code elif self.depth <= 0: msg = "depth è una lunghezza e quindi non deve essere minore e uguale a 0: %d" % self.depth elif self.height <= 0: msg = "height è una lunghezza e quindi non deve essere minore e uguale a 0: %d" % self.height elif self.extras.get_error_message(): msg = self.extras.get_error_message() else: return "" return "(wall %s): %s" % (self.direction, msg) #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Wall() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, wall2): # Non dovrebbe servire implementarli, ma inserisco questo "avviso" al caso raise NotImplementedError #- Fine Metodo - # ------------------------------------------------------------------------- def get_descr(self, type="", looker=None): """ Ritorna la descrizione del muro. """ if type: type = "_" + type descr = "" if calendar.is_night(): descr = getattr(self, "descr%s_night" % type) if not descr: descr = getattr(self, "descr%s" % type) # Normale che possa accadere per qualsiasi tipologia di descrizione if not descr: return "" if self.ASCIIART_TAG_OPEN in descr: descr = self.convert_asciiart_linefeeds(descr) else: descr = put_final_dot(descr) if ".\n" in descr: descr = descr.replace(".\n", ".<br>") if "!\n" in descr: descr = descr.replace("!\n", "!<br>") if "?\n" in descr: descr = descr.replace("?\n", "?<br>") if "\n" in descr: descr = descr.replace("\n", " ") return descr
def __init__(self): self.entitype = Element( ENTITYPE.NONE ) # Tipologia di entità che possono essere venduta al negoziante self.percent = 50 # Percentuale sul costo per le entità vendute al negoziante self.buyback_percent = 100 # Percentuale sul costo per le entità comprate dal negoziante e precedentemente vendutegli
def __init__(self): self.entitype = Element(ENTITYPE.NONE) # Tipologia di entità che possono essere venduta al negoziante self.percent = 50 # Percentuale sul costo per le entità vendute al negoziante self.buyback_percent = 100 # Percentuale sul costo per le entità comprate dal negoziante e precedentemente vendutegli
class Social(Data): """ Gestisce un social. """ PRIMARY_KEY = "fun_name" VOLATILES = [] MULTILINES = [] SCHEMA = {"racial_messages" : ("src.social", "SocialRacialMessage")} REFERENCES = {} WEAKREFS = {} def __init__(self): self.comment = "" self.fun_name = "" # Nome della funzione del comando legato al social self.intention = Element(INTENTION.NONE) # Tipologia di intenzione self.smiles = "" # Elenco degli smile supportati dal social self.expression = "" # Espressione relativa al'utilizzo degli smile self.racial_messages = EnumElementDict() #- Fine Inizializzazione - def get_error_message(self): if not self.fun_name: msg = "fun_name non valida: %r" % self.fun_name elif " " in self.fun_name: msg = "fun_name contiene degli spazi: <%s>" % self.fun_name elif self.intention.get_error_message(INTENTION, "intention") != "": msg = self.intention.get_error_message(INTENTION, "intention") elif (( self.smiles and not self.expression) or (not self.smiles and self.expression)): msg = "smiles ed expression devono essere tutti e due vuoti oppure non vuoti" elif not self.racial_messages: msg = "Deve esistere almeno un messaggio razziale di social, di solito umano" elif RACE.HUMAN not in self.racial_messages: msg = "Deve esistere sempre il messaggio razziale di social degli umani" elif self._get_message_error_racial_message() != "": msg = self._get_message_error_racial_message() else: return "" log.bug("(Social: fun_name %s) %s" % (self.fun_name, msg)) return msg #- Fine Metodo - def get_input_argument(self): return self.fun_name.split("_")[1] #- Fine Metodo - def _get_message_error_racial_message(self): """ Controlla tutti i messaggi di social razziali """ for racial_message in self.racial_messages.itervalues(): msg = racial_message.get_error_message() if msg: return msg return "" #- Fine Metodo - def get_racial_message(self, entity, attr, target=None, possessive="", use_human=True): """ Ricava il messaggio social razziale corretto. """ if not entity: log.bug("entity non è un parametro valido: %r" % entity) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return if not target and target is not None: log.bug("entity non è un parametro valido: %r" % target) return if possessive not in ("", "mio", "tuo", "suo"): log.bug("possessive non è un parametro valido: %r" % possessive) return # use_human ha valore di verità # ------------------------------------------------------------------------- if entity.race in self.racial_messages: message = getattr(self.racial_messages[entity.race], attr) elif use_human: # I messaggi di social razziali degli umani devono esistere per forza message = getattr(self.racial_messages[RACE.HUMAN], attr) else: return "" if target and target.location == entity: message = message.replace("$N,", "$N, nel %s inventario," % possessive) message = message.replace("$N ", "$N, nel %s inventario, " % possessive) message = message.replace("$N.", "$N, nel %s inventario." % possessive) return message #- Fine Metodo - def send_to(self, sender, receiver=None): """ Se receiver non è valido allora invia il social senza argomento. """ # E' possibile che non siano valide per via della defer che # chiama questo metodo if not sender: return if not receiver: return modifier = 0 if sender.position > POSITION.SLEEP and not is_affected(sender, "charm") and sender.is_original(): # Modificatore comportamentale per i mob, un valore tra -10 e 10 if receiver and sender.race in receiver.reputations: modifier = receiver.reputations[sender.race] / 10 # (TD) if self.intention == INTENTION.FRIENDLY: modifier += 5 elif self.intention == INTENTION.AGGRESSIVE: modifier -= 5 # Caso peggiorativo if receiver and modifier <= -10: if random.randint(0, 5) == 0: interpret(sender, "say a %s Te la sei proprio [red]andata a cercare[close]!" % receiver.get_numbered_keyword(looker=sender)) start_fight(receiver, sender) # Casi non buoni elif modifier <= -5 and self.intention == INTENTION.AGGRESSIVE: self.send_with_same_intention(sender, receiver) # Casi neutrali elif -5 < modifier < 5 and self.intention == INTENTION.NEUTRAL: # Qui è voluto che capitino casi buffi, come ad esempio se si # annuisce potrebbe darsi che di risposti ci si becchi una vomitata. # Se si vuole un mud full-rpg forse è bene ritornare al posto di # questa riga sottostante self.send_with_same_intention(sender, receiver) # Casi migliorativi elif modifier >= 5 and self.intention == INTENTION.FRIENDLY: self.send_with_same_intention(sender, receiver) #- Fine Funzione - def send_with_same_intention(self, sender, receiver=None): """ Invia un social a caso con la stessa intenzione. Se receiver non è valido allora invia il social senza argomento. """ if not sender: log.bug("sender non è un parametro valido: %r" % sender) return # ------------------------------------------------------------------------- # Il più delle volte invia lo stesso social in questione, altrimenti ne # cerca uno con intenzione simile if random.randint(0, 5) != 0: social_input = self.get_input_argument() if receiver: receiver_numbered_keyword = receiver.get_numbered_keyword(looker=sender) argument = "%s %s" % (social_input, receiver_numbered_keyword) else: argument = social_input interpret(sender, argument) return # Se il mud è stato appena creato potrebbe non avere ancora i social if not database["socials"]: return # Crea una lista con tutti i social con l'intenzione voluta socials = [] for social in database["socials"].itervalues(): if social.intention == self.intention: socials.append(social) # Potrebbe benissimo essere che non esistano ancora abbastanza social # per averne uno con quell'intenzione if not socials: return # Invia un social scelto a caso tra quelli voluti social = random.choice(socials) argument = social.fun_name.split("_")[1] if receiver: argument += " %s" % receiver.get_numbered_keyword(looker=sender) interpret(sender, argument)
class Command(Data): """ Gestisce tutte le caratteristiche di un comando. Se tra gli attributi cercate quelli che servono per chiamare il comando tramite il testo inviato dai giocatori qui non li troverete, per quel compito ci pensa la classe Input(). """ PRIMARY_KEY = "fun_name" VOLATILES = [ "timer", "module", "function", ] MULTILINES = ["mini_help"] SCHEMA = {} REFERENCES = {} WEAKREFS = {} def __init__(self, fun_name=""): self.comment = "" self.fun_name = fun_name or "" # Nome della funzione self.type = Element(CMDTYPE.INFORMATION) # Tipologia del comando self.trust = Element(TRUST.PLAYER) # Fiducia minima per digitarlo self.position = Element( POSITION.REST) # Posizione minima per utilizzarlo self.flags = Flags(CMDFLAG.NONE) # Flag dei comandi self.no_races = Flags( RACE.NONE ) # Razze che NON possono usarlo (RACE.NONE significa che tutti lo possono utilizzare) self.mini_help = "" # Piccola descrizione dell'utilizzo del comando self.timer = 0.0 # Tempo totale di esecuzione del comando (anche se nelle pagine d'amministrazione visualizza il tempo medio) # Variabili volatili self.module = None # Riferimento al modulo che contiene la funzione self.function = None # Riferimento alla funzione if self.fun_name: self.import_module_and_function() #- Fine Inizializzazione - def get_error_message(self): """ Ritorna un messaggio di errore se qualcosa nel comando è sbagliata, altrimenti se tutto è a posto ritorna una stringa vuota. """ if not self.fun_name: msg = "il nome della funzione non è valido" elif (not self.fun_name.startswith("command_") and not self.fun_name.startswith("skill_") and not self.fun_name.startswith("social_")): msg = "il nome della funzione non inizia per command_, skill_ o social_" elif self.type.get_error_message(CMDTYPE, "type") != "": msg = self.type.get_error_message(CMDTYPE, "type") elif self.trust.get_error_message(TRUST, "trust") != "": msg = self.trust.get_error_message(TRUST, "trust") elif self.position.get_error_message(POSITION, "position") != "": msg = self.position.get_error_message(POSITION, "position") elif self.flags.get_error_message(CMDFLAG, "flags") != "": msg = self.flags.get_error_message(CMDFLAG, "flags") elif self.no_races.get_error_message(RACE, "no_races") != "": msg = self.no_races.get_error_message(RACE, "no_races") # Ignora i minihelp vuoti relativi ai comandi-social elif not self.mini_help and not self.fun_name.startswith("social_"): msg = "la stringa di mini help è vuota" elif self.timer < 0.0: msg = "il timer non può essere negativo: %f" % self.timer elif not self.module: msg = "modulo non importato" elif not self.function: msg = "funzione non importata" else: return "" # Se arriva qui significa che ha un messaggio da inviare log.bug("(Command: fun_name %s) %s" % (self.fun_name, msg)) return msg #- Fine Metodo - def get_total_use_count(self): """ Ritorna l'utilizzo totale della funzione di comando tra tutti gli input. """ total_use_count = 0 for inputs_name, inputs in yield_inputs_items(): for input in inputs: if input.command == self: total_use_count += input.counter_use return total_use_count #- Fine Metodo - def import_module_and_function(self): """ Importa il modulo che contiene la funzione del comando. """ if self.fun_name.startswith("command_"): package = "src.commands." elif self.fun_name.startswith("skill_"): package = "src.skills." elif self.fun_name.startswith("social_"): package = "src.socials." else: log.bug("la fun_name del comando è errata: %s" % self.fun_name) return None import_path = package + self.fun_name self.module = __import__(import_path, globals(), locals(), [""]) self.function = getattr(self.module, self.fun_name)
class Exit(Describable): """ Gestisce una singola uscita di una stanza. """ PRIMARY_KEY = "direction" VOLATILES = [] MULTILINES = ["comment"] SCHEMA = {"extras" : ("src.extra", "ExtraDescription"), "height" : ("", "measure"), "depth" : ("", "measure"), "destination" : ("src.room", "Destination")} REFERENCES = {} WEAKREFS = {} IS_AREA = False IS_DESCR = True IS_ROOM = False IS_EXIT = True IS_WALL = False IS_ACTOR = False IS_MOB = False IS_ITEM = False IS_PLAYER = False IS_EXTRA = False IS_PROTO = False def __init__(self, direction=DIR.NONE): if not direction: log.bug("direction non è un parametro valido: %r" % direction) return # --------------------------------------------------------------------- self.comment = "" # Eventuale commento all'uscita self.direction = Element(direction) # Tipologia della direzione self.descr = "" # Descrizione di quello che si vede guardando la direzione self.descr_night = "" # Descrizione notturna di quello che si vede guardando la direzione self.descr_hearing = "" # Descrizione uditiva self.descr_hearing_night = "" # Descrizione uditiva notturna self.descr_smell = "" # Descrizione odorosa self.descr_smell_night = "" # Descrizione odorosa notturna self.descr_touch = "" # Descrizione tattile self.descr_touch_night = "" # Descrizione tattile notturna self.descr_taste = "" # Descrizione del sapore self.descr_taste_night = "" # Descrizione del sapore notturna self.descr_sixth = "" # Descrizione del sesto senso self.descr_sixth_night = "" # Descrizione del sesto senso notturna self.icon = "" # Icona rappresentante l'uscita di giorno self.icon_night = "" # Icona rappresentante l'uscita di notte self.extras = Extras() # Descrizioni extra dell'uscita self.flags = Flags(EXIT.NONE) # Flags dell'uscita self.destination = None # Stanza a cui l'uscita porta se questa differente rispetto alla direzione presa self.door = None # Oggetto porta se serve aprirla (se non viene indicata questa viene caricata dal limbo una porta di default) (TD) qui vorrei aggiungere anche una variabile finestra.. ma poi come gestire finestre e porte multiple? e il key_code nel qual caso una finestra sia chiudibile (cmq per ora continuo così.. in effetti potrei considerare il fatto di voler inserire più porte o finestre in una uscita come una eccezione e gestirla tramite gamescripts) self.entity_message = "" # Messaggio di movimento per colui che si sta spostando self.others_in_message = "" # Messaggio di movimento per gli altri della stanza di partenza self.others_out_message = "" # Messaggio di movimento per gli altri della stanza di arrivo #- Fine Inizializzazione - def get_error_message(self): """ Se c'è un errore nell'uscita ne ritorna il messaggio appropriato. """ if self.direction.get_error_message(DIR, "direction", allow_none=False) != "": msg = self.direction.get_error_message(DIR, "direction", allow_none=False) elif self.flags.get_error_message(EXIT, "flags") != "": msg = self.flags.get_error_message(EXIT, "flags") # elif (self.door and self.door.code not in database["items"] # and self.door and self.door.code not in database["mobs"]): # msg = "door dell'uscita non è un oggetto valido: %s" % self.door.code elif self.destination and self.destination.get_error_message() != "": msg = self.destination.get_error_message() elif self.extras.get_error_message(): msg = self.extras.get_error_message() else: return "" return "(exit %r): %s" % (self.direction, msg) #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Exit() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, exit2): # Non dovrebbe servire implementarli, ma inserisco questo "avviso" al caso raise NotImplementedError #- Fine Metodo - # ------------------------------------------------------------------------- def get_icon(self, room=None): if room: door = room.get_door(self.direction) else: door = None icon = "" if door and door.door_type and DOOR.CLOSED in door.door_type.flags and DOOR.SECRET not in door.door_type.flags: # L'icone dell'entità porta è intesa come chiusa icon = door.get_icon() if not icon: icon = "icons/door/default-door.png" elif door and door.door_type and DOOR.CLOSED not in door.door_type.flags: # Icona della porta aperta icon = door.door_type.get_icon() if not icon: icon = "icons/door/default-door-open.png" elif not door or (door.door_type and DOOR.SECRET not in door.door_type.flags): if calendar.is_night() and self.icon_night: # icona dell'uscita di notte icon = self.icon_night elif self.icon: # icona dell'uscita di giorno icon = self.icon # Inserisce di default dei simboli di una rosa dei venti if not icon: icon = "icons/compass/%s.png" % repr(self.direction).split(".")[1].lower() return icon #- Fine Metodo - def get_descr(self, type="", looker=None): """ Ritorna la descrizione dell'uscita. """ if type: type = "_" + type descr = "" if calendar.is_night(): descr = getattr(self, "descr%s_night" % type) if not descr: descr = getattr(self, "descr%s" % type) # Normale che possa accadere per qualsiasi tipologia di descrizione if not descr: return "" if self.ASCIIART_TAG_OPEN in descr: descr = self.convert_asciiart_linefeeds(descr) else: descr = put_final_dot(descr) if ".\n" in descr: descr = descr.replace(".\n", ".<br>") if "!\n" in descr: descr = descr.replace("!\n", "!<br>") if "?\n" in descr: descr = descr.replace("?\n", "?<br>") if "\n" in descr: descr = descr.replace("\n", " ") return descr
class Sellable(object): """ Classe che gestisce le differenti tipologie di entità vendute e comprate dal negoziante. """ PRIMARY_KEY = "" VOLATILES = [] MULTILINES = [] SCHEMA = {"percent": ("", "percent"), "buyback_percent": ("", "percent")} REFERENCES = {} WEAKREFS = {} def __init__(self): self.entitype = Element( ENTITYPE.NONE ) # Tipologia di entità che possono essere venduta al negoziante self.percent = 50 # Percentuale sul costo per le entità vendute al negoziante self.buyback_percent = 100 # Percentuale sul costo per le entità comprate dal negoziante e precedentemente vendutegli #- Fine Metodo - def get_error_message(self): if self.entitype.get_error_message(ENTITYPE, "entitype") != "": return self.entitypes.get_error_message(ENTITYPE, "entitype") elif self.buyback_percent < 10 and self.buyback_percent > 1000: return "buyback_percent dev'essere un valore tra 10 e 1000: %d" % self.buyback_percent elif self.percent < 10 and self.percent > 1000: return "percent dev'essere un valore tra 10 e 1000: %d" % self.percent return "" #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Sellable() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, sellable2): if not sellable2: return False if self.entitype != sellable2.entitype: return False if self.percent != sellable2.percent: return False if self.buyback_percent != sellable2.buyback_percent: return False return True #- Fine Metodo - def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- try: entitype, percent, buyback_percent = line.split(None, 2) except ValueError: log.bug( "Errore nella lettura di un Sellable nel file <%s> per la linea <%s> e l'attributo <%s>" % (file.name, line, attr)) return self.entitype = Element(entitype) self.percent = fread_percent(file, percent, attr) self.buyback_percent = fread_percent(file, buyback_percent, attr) #- Fine Metodo - def fwrite_the_line(self, file, label, indentation=""): if not file: log.bug("file non è un parametro valido: %r" % file) return if not label: log.bug("label non è un parametro valido: %r" % label) return # ------------------------------------------------------------------------- file.write("%s%s %r %d%% %d%%\n" % (indentation, label, self.entitype, self.percent, self.buyback_percent))
class Command(Data): """ Gestisce tutte le caratteristiche di un comando. Se tra gli attributi cercate quelli che servono per chiamare il comando tramite il testo inviato dai giocatori qui non li troverete, per quel compito ci pensa la classe Input(). """ PRIMARY_KEY = "fun_name" VOLATILES = ["timer", "module", "function",] MULTILINES = ["mini_help"] SCHEMA = {} REFERENCES = {} WEAKREFS = {} def __init__(self, fun_name=""): self.comment = "" self.fun_name = fun_name or "" # Nome della funzione self.type = Element(CMDTYPE.INFORMATION) # Tipologia del comando self.trust = Element(TRUST.PLAYER) # Fiducia minima per digitarlo self.position = Element(POSITION.REST) # Posizione minima per utilizzarlo self.flags = Flags(CMDFLAG.NONE) # Flag dei comandi self.no_races = Flags(RACE.NONE) # Razze che NON possono usarlo (RACE.NONE significa che tutti lo possono utilizzare) self.mini_help = "" # Piccola descrizione dell'utilizzo del comando self.timer = 0.0 # Tempo totale di esecuzione del comando (anche se nelle pagine d'amministrazione visualizza il tempo medio) # Variabili volatili self.module = None # Riferimento al modulo che contiene la funzione self.function = None # Riferimento alla funzione if self.fun_name: self.import_module_and_function() #- Fine Inizializzazione - def get_error_message(self): """ Ritorna un messaggio di errore se qualcosa nel comando è sbagliata, altrimenti se tutto è a posto ritorna una stringa vuota. """ if not self.fun_name: msg = "il nome della funzione non è valido" elif (not self.fun_name.startswith("command_") and not self.fun_name.startswith("skill_") and not self.fun_name.startswith("social_")): msg = "il nome della funzione non inizia per command_, skill_ o social_" elif self.type.get_error_message(CMDTYPE, "type") != "": msg = self.type.get_error_message(CMDTYPE, "type") elif self.trust.get_error_message(TRUST, "trust") != "": msg = self.trust.get_error_message(TRUST, "trust") elif self.position.get_error_message(POSITION, "position") != "": msg = self.position.get_error_message(POSITION, "position") elif self.flags.get_error_message(CMDFLAG, "flags") != "": msg = self.flags.get_error_message(CMDFLAG, "flags") elif self.no_races.get_error_message(RACE, "no_races") != "": msg = self.no_races.get_error_message(RACE, "no_races") # Ignora i minihelp vuoti relativi ai comandi-social elif not self.mini_help and not self.fun_name.startswith("social_"): msg = "la stringa di mini help è vuota" elif self.timer < 0.0: msg = "il timer non può essere negativo: %f" % self.timer elif not self.module: msg = "modulo non importato" elif not self.function: msg = "funzione non importata" else: return "" # Se arriva qui significa che ha un messaggio da inviare log.bug("(Command: fun_name %s) %s" % (self.fun_name, msg)) return msg #- Fine Metodo - def get_total_use_count(self): """ Ritorna l'utilizzo totale della funzione di comando tra tutti gli input. """ total_use_count = 0 for inputs_name, inputs in yield_inputs_items(): for input in inputs: if input.command == self: total_use_count += input.counter_use return total_use_count #- Fine Metodo - def import_module_and_function(self): """ Importa il modulo che contiene la funzione del comando. """ if self.fun_name.startswith("command_"): package = "src.commands." elif self.fun_name.startswith("skill_"): package = "src.skills." elif self.fun_name.startswith("social_"): package = "src.socials." else: log.bug("la fun_name del comando è errata: %s" % self.fun_name) return None import_path = package + self.fun_name self.module = __import__(import_path, globals(), locals(), [""]) self.function = getattr(self.module, self.fun_name)
class Sellable(object): """ Classe che gestisce le differenti tipologie di entità vendute e comprate dal negoziante. """ PRIMARY_KEY = "" VOLATILES = [] MULTILINES = [] SCHEMA = {"percent" : ("", "percent"), "buyback_percent" : ("", "percent")} REFERENCES = {} WEAKREFS = {} def __init__(self): self.entitype = Element(ENTITYPE.NONE) # Tipologia di entità che possono essere venduta al negoziante self.percent = 50 # Percentuale sul costo per le entità vendute al negoziante self.buyback_percent = 100 # Percentuale sul costo per le entità comprate dal negoziante e precedentemente vendutegli #- Fine Metodo - def get_error_message(self): if self.entitype.get_error_message(ENTITYPE, "entitype") != "": return self.entitypes.get_error_message(ENTITYPE, "entitype") elif self.buyback_percent < 10 and self.buyback_percent > 1000: return "buyback_percent dev'essere un valore tra 10 e 1000: %d" % self.buyback_percent elif self.percent < 10 and self.percent > 1000: return "percent dev'essere un valore tra 10 e 1000: %d" % self.percent return "" #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Sellable() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, sellable2): if not sellable2: return False if self.entitype != sellable2.entitype: return False if self.percent != sellable2.percent: return False if self.buyback_percent != sellable2.buyback_percent: return False return True #- Fine Metodo - def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- try: entitype, percent, buyback_percent = line.split(None, 2) except ValueError: log.bug("Errore nella lettura di un Sellable nel file <%s> per la linea <%s> e l'attributo <%s>" % ( file.name, line, attr)) return self.entitype = Element(entitype) self.percent = fread_percent(file, percent, attr) self.buyback_percent = fread_percent(file, buyback_percent, attr) #- Fine Metodo - def fwrite_the_line(self, file, label, indentation=""): if not file: log.bug("file non è un parametro valido: %r" % file) return if not label: log.bug("label non è un parametro valido: %r" % label) return # ------------------------------------------------------------------------- file.write("%s%s %r %d%% %d%%\n" % (indentation, label, self.entitype, self.percent, self.buyback_percent))
class MaterialPercentage(object): PRIMARY_KEY = "" VOLATILES = [] MULTILINES = [] SCHEMA = {} REFERENCES = {} WEAKREFS = {} def __init__(self): self.material = Element(MATERIAL.NONE) self.percent = 0 #- Fine Inizializzazione - def __repr__(self): return "%s %s %s%%" % (super(MaterialPercentage, self).__repr__(), self.material, self.percent) #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = MaterialPercentage() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Funzione - def equals(self, material2): if not material2: return False if self.material != material2.material: return False if self.percent != material2.percent: return False return True #- Fine Metodo - def get_error_message(self): if self.material.get_error_message(MATERIAL, "material", allow_none=False) != "": return self.material.get_error_message(MATERIAL, "material", allow_none=False) elif self.percent < 1 or self.percent > 100: return "percent dev'essere tra 1 e 100 e non %d" % self.percent return "" #- Fine Metodo - def fread_the_line(self, file, line, attr): if not file: log.bug("file non è un parametro valido: %r" % file) return if not line: log.bug("line non è un parametro valido: %r" % line) return if not attr: log.bug("attr non è un parametro valido: %r" % attr) return # --------------------------------------------------------------------- if "," in line: material, percent = line.split(",", 1) else: material, percent = line.split(None, 1) material = material.strip() percent = percent.strip() self.material = Element(material) self.percent = fread_percent(file, percent, attr) #- Fine Metodo - def fwrite_the_line(self, file, label, indentation=""): """ Scrive su file un elemento sinonimo. """ if not file: log.bug("file non è un parametro valido: %r" % file) return if not label: log.bug("label non è un parametro valido: %r" % label) return # ------------------------------------------------------------------------- file.write("%s%s%s %s%%\n" % (indentation, label, self.material.code, self.percent))
class Readable(object): PRIMARY_KEY = "" VOLATILES = [] MULTILINES = ["comment", "pages", "summary"] SCHEMA = {"visual_width" : ("", "css_measure"), "visual_height" : ("", "css_measure"), "padding" : ("", "css_measure"), "border_top" : ("", "css_border"), "border_right" : ("", "css_border"), "border_bottom" : ("", "css_border"), "border_left" : ("", "css_border"), "border_inside" : ("", "css_border"), "pages" : ("", "str")} REFERENCES = {} WEAKREFS = {} def __init__(self): self.comment = "" # Commento per gli area builder relativo all'entità leggibile self.title = "" # Titolo del libro self.author = "" # Autore o gli autori di questo libro self.summary = "" # Riassunto del libro che il giocatore carpisce esaminandolo self.language = Element(LANGUAGE.COMMON) # (TD) Lingua di questo libro self.flags = Flags(READABLE.NONE) # Flag relative alle entità leggibili self.visual_width = "" # Larghezza in pixel del libro sullo schermo self.visual_height = "" # Larghezza in pixel del libro sullo schermo self.padding = "" # Larghezza in pixel del padding della cornice del libro self.border_top = "" # Bordo css decorante il libro in alto self.border_right = "" # Bordo css decorante il libro a destra self.border_bottom = "" # Bordo css decorante il libro in basso self.border_left = "" # Bordo css decorante il libro a sinistra self.border_inside = "" # Bordo css decorante il libro tra le due pagine self.number_decoration_left = "" # Decorazione della pagina sinistra per i numeri di pagina self.number_decoration_right = "" # Decorazione della pagina sinistra per i numeri di pagina self.pages = [] # Lista delle pagine e relativo contenuto #- Fine Inizializzazione - def get_error_message(self, entity): if not self.title: return "title è una stringa non valida: %r" % self.title elif not self.author: return "author è una stringa non valida: %r" % self.author elif not self.summary: return "summary è una stringa non valida: %r" % self.summary elif self.language.get_error_message(LANGUAGE, "language") != "": return self.language.get_error_message(LANGUAGE, "language") elif self.flags.get_error_message(READABLE, "flags") != "": return self.flags.get_error_message(READABLE, "flags") elif READABLE.CENTER in self.flags and READABLE.RIGHT in self.flags: return "Non possono convivere le flag READABLE.CENTER e READABLE.RIGHT assieme." elif (self.number_decoration_left or self.number_decoration_right) and READABLE.NUMBERS not in self.flags: return "Nonostante sia stata definita una decorazione per i numeri non esiste la flag READABLE.NUMBERS che la mostrerebbe." elif not self.visual_width: return "visual_width è una stringa non valida: %r" % self.visual_width elif not self.visual_height: return "visual_height è una stringa non valida: %r" % self.visual_height elif not self.pages: return "dev'esservi almeno una pagina: %r" % self.pages return "" #- Fine Metodo - def copy(self, to_obj=None, avoid_volatiles=False): if not to_obj: to_obj = Readable() copy_existing_attributes(self, to_obj, avoid_volatiles=avoid_volatiles) return to_obj #- Fine Metodo - def equals(self, readable2): if not readable2: return False if self.comment != readable2.comment: return False if self.title != readable2.title: return False if self.author != readable2.author: return False if self.summary != readable2.summary: return False if self.language != readable2.language: return False if self.flags != readable2.flags: return False if self.visual_width != readable2.visual_width: return False if self.visual_height != readable2.visual_height: return False if self.padding != readable2.padding: return False if self.border_top != readable2.border_top: return False if self.border_right != readable2.border_right: return False if self.border_bottom != readable2.border_bottom: return False if self.border_left != readable2.border_left: return False if self.border_inside != readable2.border_inside: return False if self.number_decoration_left != readable2.number_decoration_left: return False if self.number_decoration_right != readable2.number_decoration_right: return False if len(self.pages) != len(readable2.pages): return False for page in self.pages: for page2 in readable2.pages: if page == page2: break else: return False return True #- Fine Metodo - # ------------------------------------------------------------------------- # (TD) entity e target serviranno in futuro per scramblerare la lingua del # libro se sconosciuta def get_pages(self, entity, target, page_number, from_location=None): if not entity: log.bug("entity non è un parametro valido: %r" % entity) return "" if not target: log.bug("target non è un parametro valido: %r" % target) return "" if page_number < 0 or page_number >= len(self.pages): log.bug("page_number non è un parametro valido: %r" % page_number) return "" # --------------------------------------------------------------------- # Prepara i bordi border_top = "" border_right = "" border_bottom = "" border_left = "" border_inside = "" if self.border_top: border_top = "border-top:%s;" % self.border_top if self.border_right: border_right = "border-right:%s;" % self.border_right if self.border_bottom: border_bottom = "border-bottom:%s;" % self.border_bottom if self.border_left: border_left = "border-left:%s;" % self.border_left if self.border_inside: border_inside = "border-right:%s;" % self.border_inside # Prepara il padding se esistente padding_style = "" if self.padding: padding_style = "padding:%s;" % self.padding # Prepara lo style css per l'output scritto della pagina alignment = "" if READABLE.CENTER in self.flags: alignment = '''text-align:center;''' if READABLE.RIGHT in self.flags: alignment = '''text-align:right;''' visual_style = ''' style="min-width:%s; max-width:%s; min-height:%s; max-height:%s; %s %s"''' % ( self.visual_width, self.visual_width, self.visual_height, self.visual_height, padding_style, alignment) # Ricava informazioni che servono a sfogliare il libro tramite click translated_input = translate_input(entity, "read", "en") if not translated_input: log.bug("Non è stato possibile tradurre l'input read per %s: %r" % (target.code, translated_input)) return False numbered_keyword = target.get_numbered_keyword(looker=entity) if page_number % 2 == 0 and page_number != len(self.pages)-1: minimum_page = max([0, page_number-2]) maximum_page = min([len(self.pages)-1, page_number+1]) else: minimum_page = max([0, page_number-1]) maximum_page = min([len(self.pages)-1, page_number+2]) if from_location: js_minimum_arguments = "%s %s %s %d" % (translated_input, numbered_keyword, from_location.get_numbered_keyword(looker=entity), minimum_page) js_maximum_arguments = "%s %s %s %d" % (translated_input, numbered_keyword, from_location.get_numbered_keyword(looker=entity), maximum_page) else: js_minimum_arguments = "%s %s %d" % (translated_input, numbered_keyword, minimum_page) js_maximum_arguments = "%s %s %d" % (translated_input, numbered_keyword, maximum_page) browse_to_left = '''<div style="float:left"><a href="javascript:sendInput('%s')" style="font-size:larger"><</a> </div>''' % js_minimum_arguments browse_to_right = '''<div style="float:left"> <a href="javascript:sendInput('%s')" style="font-size:larger">></a></div>''' % js_maximum_arguments # Gestisce la copertina e la retrocopertina o altre tipologie di entità # leggibili differenti da dei libri, ovvero con al massimo il fronte # e il retro if page_number == 0 or page_number == len(self.pages) - 1: style = "" if border_top or border_right or border_bottom or border_left: style = ''' style="float:left; %s%s%s%s"''' % (border_top, border_right, border_bottom, border_left) output = "" if page_number == len(self.pages) - 1: output += browse_to_left output += '''<div%s><div%s>%s</div></div>''' % (style, visual_style, self.pages[page_number]) if page_number == 0: output += browse_to_right output += '''<div style="clear:both;" />''' return output # A seconda che si voglia visualizzare una pagina a destra o a sinistra # sceglie il numero corretto di pagina da far visualizzare nell'altra if page_number % 2 == 0: left_page_number = page_number - 1 right_page_number = page_number else: left_page_number = page_number right_page_number = page_number + 1 # Prepara lo stile dei bordi preparati in precedenza, se ve n'erano left_style = '''style="float:left;%s%s%s%s"''' % (border_top, border_inside, border_bottom, border_left) right_style = '''style="float:left;%s%s%s"''' % (border_top, border_right, border_bottom) # Prepara il contenuto scritto delle pagine aggiungendo una pagina # vuota prima della retrocopertina se necessario left_output = self.pages[left_page_number] if len(self.pages) % 2 == 0 and page_number == len(self.pages) - 1: right_output = "" elif len(self.pages) % 2 == 1 and page_number == len(self.pages) - 2: right_output = "" else: right_output = self.pages[right_page_number] if MIML_SEPARATOR in left_output: left_output = target.parse_miml(left_output, looker=entity) if MIML_SEPARATOR in right_output: right_output = target.parse_miml(right_output, looker=entity) # Prepara l'output per i numeri di pagina left_page_number_output = "" right_page_number_output = "" if READABLE.NUMBERS in self.flags: if len(self.number_decoration_left) == 0: left_page_number_output = '''<center>%d</center>''' % left_page_number elif len(self.number_decoration_left) == 1: left_page_number_output = '''<center>%s%d</center>''' % (self.number_decoration_left, left_page_number) else: middle = int(math.ceil(len(self.number_decoration_left) / 2.0)) left_page_number_output = '''<center>%s%d%s</center>''' % (self.number_decoration_left[ : middle], left_page_number, self.number_decoration_left[middle : ]) if len(self.number_decoration_right) == 0: right_page_number_output = '''<center>%d</center>''' % right_page_number elif len(self.number_decoration_right) == 1: right_page_number_output = '''<center>%d%s</center>''' % (right_page_number, self.number_decoration_right) else: middle = int(math.floor(len(self.number_decoration_left) / 2.0)) right_page_number_output = '''<center>%s%d%s</center>''' % (self.number_decoration_right[ : middle], right_page_number, self.number_decoration_right[middle : ]) # Ecco l'output del libro in tutto il suo splendore output = browse_to_left output += '''<div %s><div%s>%s</div>%s</div>''' % (left_style, visual_style, left_output, left_page_number_output) output += '''<div %s><div%s>%s</div>%s</div>''' % (right_style, visual_style, right_output, right_page_number_output) output += browse_to_right output += '''<div style="clear:both;" />''' return output
def parse_miml_check(self, check, looker=None): if not check: log.bug("check non è un parametro valido: %r" % check) return False # --------------------------------------------------------------------- check_parts = check.split() if check_parts[0][0:4] == "self": check_entity = self elif check_parts[0][0:8] == "location": if self.IS_ROOM: check_entity = self else: check_entity = self.location elif check_parts[0][0:17] == "previous_location": if self.IS_ROOM: check_entity = self else: check_entity = self.previous_location elif check_parts[0][0:6] == "looker": if not looker: log.bug( "looker non valido (%r) anche se il check lo necessita: %s" % (looker, check)) return False check_entity = looker elif check_parts[0][0:6] == "season": if check_parts[1] == "is": if calendar.season == Element(check_parts[2]): return True else: return False elif check_parts[1] == "is not": if calendar.season != Element(check_parts[2]): return True else: return False else: log.bug( "Operatore di check sconosciuto: %s per l'elemento con codice %s" % (check_parts[1], check_parts[2])) return False else: log.bug("entità da utilizzare per i check è sconosciuta: %s" % check_parts[0]) return False # (TD) no, dovrò splittare con or o and ed utilizzare le builtin any o all #for element_code in check_parts[2].split("|"): # pass # Miml relativo alla razza dell'entità controllata if check_parts[2][0:5] == "RACE.": if check_entity.IS_ROOM: return False if check_parts[1] == "is": if check_entity.race == Element(check_parts[2]): return True else: return False elif check_parts[1] == "is not": if check_entity.race != Element(check_parts[2]): return True else: return False else: log.bug( "Operatore di check sconosciuto: %s per l'elemento con codice %s" % (check_parts[1], check_parts[2])) return False # Miml relativo alla sessualità dell'entità controllata elif check_parts[2][0:4] == "SEX.": if check_entity.IS_ROOM: return False if check_parts[1] == "is": if check_entity.sex == Element(check_parts[2]): return True else: return False elif check_parts[1] == "is not": if check_entity.sex != Element(check_parts[2]): return True else: return False else: log.bug( "Operatore di check sconosciuto: %s per l'elemento con codice %s" % (check_parts[1], check_parts[2])) return False # Miml relativo ai contenitori elif check_parts[2][0:10] == "CONTAINER.": if check_entity.IS_ROOM or not check_entity.container_type: return False if check_parts[1] == "is": if Element( check_parts[2]) in check_entity.container_type.flags: return True else: return False elif check_parts[1] == "is not": if Element(check_parts[2] ) not in check_entity.container_type.flags: return True else: return False else: log.bug( "Operatore di check sconosciuto: %s per l'elemento con codice %s" % (check_parts[1], check_parts[2])) return False # Miml relativo al settore di una stanza elif check_parts[2][0:7] == "SECTOR.": if not check_entity.IS_ROOM: return False if check_parts[1] == "is": if check_entity.sector == Element(check_parts[2]): return True else: return False elif check_parts[1] == "is not": if check_entity.sector != Element(check_parts[2]): return True else: return False else: log.bug( "Operatore di check sconosciuto: %s per l'elemento con codice %s" % (check_parts[1], check_parts[2])) return False # Miml relativo alle flags di una stanza elif check_parts[2][0:5] == "ROOM.": if not check_entity.IS_ROOM: return False if check_parts[1] == "is": if Element(check_parts[2]) in check_entity.flags: return True else: return False elif check_parts[1] == "is not": if Element(check_parts[2]) not in check_entity.flags: return True else: return False else: log.bug( "Operatore di check sconosciuto: %s per l'elemento con codice %s" % (check_parts[1], check_parts[2])) return False # Miml relativo all'inventario portato elif check_parts[0][-14:] == ".inventory_qty": check_qty = 0 if is_number(check_parts[2]): check_qty = int(check_parts[2]) else: log.bug( "la parte destra dell'opeartore del check miml %s non è un numbero valido" % (check)) qty = 0 for content in check_entity.iter_contains(): if len(content.wear_mode ) == 0 and FLAG.INGESTED not in content.flags: qty += 1 if check_parts[1] == "==" and qty == check_qty: return True elif check_parts[1] == "!=" and qty != check_qty: return True elif check_parts[1] == ">" and qty > check_qty: return True elif check_parts[1] == ">=" and qty >= check_qty: return True elif check_parts[1] == "<" and qty < check_qty: return True elif check_parts[1] == "<=" and qty <= check_qty: return True else: return False # Miml relativo all'equipaggiamento portato elif check_parts[0][-14:] == ".equipment_qty": check_qty = 0 if is_number(check_parts[2]): check_qty = int(check_parts[2]) else: log.bug( "la parte destra dell'opeartore del check miml %s non è un numbero valido" % check) qty = 0 for content in check_entity.iter_contains(): if len(content.wear_mode ) != 0 and FLAG.INGESTED not in content.flags: qty += 1 if check_parts[1] == "==" and qty == check_qty: return True elif check_parts[1] == "!=" and qty != check_qty: return True elif check_parts[1] == ">" and qty > check_qty: return True elif check_parts[1] == ">=" and qty >= check_qty: return True elif check_parts[1] == "<" and qty < check_qty: return True elif check_parts[1] == "<=" and qty <= check_qty: return True else: return False # Miml relativo alle exits, wall e direzioni elif get_direction_miml(check_parts[0]) != DIR.NONE: if not check_entity.IS_ROOM: return False direction = get_direction_miml(check_parts[0]) if direction in check_entity.exits: if check_parts[1] == "is": if check_parts[2] == "Exit": return True elif check_parts[2] == "Wall": # Il check qui ci vuole comunque perché una direzione può # avere sia uscita che muro, idem per il ramo 'is not' if direction in check_entity.walls: return True else: return False elif check_parts[2] == "Door": if check_entity.exits[ direction].door and check_entity.exits[ direction].door.door_type: return True else: return False elif check_parts[2][:5] == "EXIT.": if Element(check_parts[2] ) in check_entity.exits[direction].flags: return True else: return False elif check_parts[2][:5] == "DOOR.": if check_entity.exits[ direction].door and check_entity.exits[ direction].door.door_type and Element( check_parts[2]) in check_entity.exits[ direction].door.door_type.flags: return True else: return False elif check_parts[1] == "is not": if check_parts[2] == "Exit": return False elif check_parts[2] == "Wall": if direction in check_entity.walls: return False else: return True elif check_parts[2] == "Door": if check_entity.exits[ direction].door and check_entity.exits[ direction].door.door_type: return False else: return True elif check_parts[2][:5] == "EXIT.": if Element(check_parts[2] ) in check_entity.exits[direction].flags: return False else: return True elif check_parts[2][:5] == "DOOR.": if check_entity.exits[ direction].door and check_entity.exits[ direction].door.door_type and Element( check_parts[2]) in check_entity.exits[ direction].door.door_type.flags: return False else: return True else: log.bug( "Operatore di check sconosciuto: %s per il check %s" % (check_parts[1], check)) return False if direction in check_entity.walls: if check_parts[1] == "is": if check_parts[2] == "Wall": if direction in check_entity.walls: return True else: return False elif check_parts[1] == "is not": if check_parts[2] == "Wall": if direction in check_entity.walls: return False else: return True return False # Tutti gli altri casi vengono gestiti come errore di sintassi log.bug("check del miml dalla sintassi errata: %s" % check) return False