Example #1
0
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
Example #2
0
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
Example #3
0
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()
Example #4
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">&lt;</a> </div>''' % js_minimum_arguments
        browse_to_right = '''<div style="float:left"> <a href="javascript:sendInput('%s')" style="font-size:larger">&gt;</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
Example #5
0
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
Example #6
0
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
Example #7
0
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))
Example #8
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">&lt;</a> </div>''' % js_minimum_arguments
        browse_to_right = '''<div style="float:left"> <a href="javascript:sendInput('%s')" style="font-size:larger">&gt;</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
Example #9
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))
Example #10
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
Example #11
0
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()
Example #12
0
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))
Example #13
0
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()
Example #14
0
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
Example #15
0
class Mob(ProtoMob, BehaviourUpdaterSuperclass):
    """
    Istanza di un Mob.
    """
    PRIMARY_KEY = "code"
    VOLATILES = ProtoMob.VOLATILES + ["prototype"]
    MULTILINES = ProtoMob.MULTILINES + []
    SCHEMA = {"specials": ("", "str")}
    SCHEMA.update(ProtoMob.SCHEMA)
    REFERENCES = {"area": ["areas"]}
    REFERENCES.update(ProtoMob.REFERENCES)
    WEAKREFS = {}
    WEAKREFS.update(ProtoMob.WEAKREFS)

    ACCESS_ATTR = "mobs"
    IS_PROTO = False
    CONSTRUCTOR = None  # Classe Mob una volta che viene definita a fine modulo

    # Qui non bisogna passare altri attributi oltre il code, perché altrimenti
    # offuscherebbero gli attributi prototype
    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)

    #- Fine Inizializzazione -

    def get_error_message(self):
        msg = super(Mob, self).get_error_message()
        if msg:
            pass
        elif self.life < 0 or self.life > 9999:
            msg = "life non è tra zero e 9999: %d" % self.life
        elif self.mana < 0 or self.mana > 9999:
            msg = "mana non è tra zero e 9999: %d" % self.mana
        elif self.vigour < 0 or self.vigour > 9999:
            msg = "vigour non è tra zero e 9999: %d" % self.vigour
        elif self.max_life < 0 or self.max_life > 9999:
            msg = "life non è tra zero e 9999: %d" % self.max_life
        elif self.max_mana < 0 or self.max_mana > 9999:
            msg = "mana non è tra zero e 9999: %d" % self.max_mana
        elif self.max_vigour < 0 or self.max_vigour > 9999:
            msg = "vigour non è tra zero e 9999: %d" % self.max_vigour
        elif self.thirst < 0 or self.thirst > MAX_CONDITION:
            msg = "thirst non è tra zero e %s: %d" % (MAX_CONDITION,
                                                      self.thirst)
        elif self.hunger < 0 or self.hunger > MAX_CONDITION:
            msg = "hunger non è tra zero e %s: %d" % (MAX_CONDITION,
                                                      self.hunger)
        elif self.drunkness < 0 or self.drunkness > MAX_CONDITION:
            msg = "drunkness è tra 0 e %d: %d" % (MAX_CONDITION,
                                                  self.drunkness)
        elif self.bloodthirst < 0 or self.bloodthirst > MAX_CONDITION:
            msg = "bloodthirst non è tra zero e %d: %d" % (MAX_CONDITION,
                                                           self.bloodthirst)
        elif self.adrenaline < 0 or self.adrenaline > MAX_CONDITION:
            msg = "adrenaline non è tra zero e %d: %d" % (MAX_CONDITION,
                                                          self.adrenaline)
        elif self.mind < 0 or self.mind > MAX_CONDITION:
            msg = "mind non è tra zero e %d: %d" % (MAX_CONDITION, self.mind)
        elif self.emotion < 0 or self.emotion > MAX_CONDITION:
            msg = "emotion non è tra zero e %d: %d" % (MAX_CONDITION,
                                                       self.emotion)
        elif self.attack < 1:
            msg = "attack minore di 1: %d" % self.attack
        elif self.defense < 1:
            msg = "defense minore di 1: %d" % self.defense
        elif self.speaking.get_error_message(LANGUAGE, "speaking") != "":
            msg = self.speaking.get_error_message(LANGUAGE, "speaking")
        elif self.defeat_from_mob_counter < 0:
            msg = "defeat_from_mob_counter è un contatore, non può essere minore di 0: %d" % self.defeat_from_mob_counter
        elif self.defeat_from_item_counter < 0:
            msg = "defeat_from_item_counter è un contatore, non può essere minore di 0: %d" % self.defeat_from_item_counter
        elif self.defeat_from_player_counter < 0:
            msg = "defeat_from_player_counter è un contatore, non può essere minore di 0: %d" % self.defeat_from_player_counter
        elif self.death_from_player_counter < 0:
            msg = "death_from_player_counter è un contatore, non può essere minore di 0: %d" % self.death_from_player_counter
        elif self.mob_defeated_counter < 0:
            msg = "mob_defeated_counter è un contatore, non può essere minore di 0: %d" % self.mob_defeated_counter
        elif self.item_defeated_counter < 0:
            msg = "item_defeated_counter è un contatore, non può essere minore di 0: %d" % self.item_defeated_counter
        elif self.player_defeated_counter < 0:
            msg = "player_defeated_counter è un contatore, non può essere minore di 0: %d" % self.player_defeated_counter
        elif self.player_killed_counter < 0:
            msg = "player_killed_counter è un contatore, non può essere minore di 0: %d" % self.player_killed_counter
        elif self.style.get_error_message(STYLE, "style") != "":
            msg = self.style.get_error_message(STYLE, "style")
        elif self.mount and self.mount not in database.players and self.mount not in self.mobs:
            msg = "mount non è un player o un mob valido: %s" % self.mount
        elif self.mounted_by and self.mount not in database.players and self.mount not in self.mobs:
            msg = "mounted_by non è un player o un mob valido: %s" % self.mounted_by
        elif self.reply and self.reply not in database.players and self.reply not in database.mobs and self.reply not in database.items:
            msg = "reply non è un entità valida: %s" % self.reply


#       elif self.tracking.get_error_message() != "":
#           msg = self.tracking.get_error_message()
        else:
            return ""

        # Se arriva fino a qui ha trovato un errore
        if type(self) == Mob:
            log.bug("(Mob: code %s) %s" % (self.code, msg))
        return msg

    #- Fine Metodo -

    # -------------------------------------------------------------------------

    def get_strength_way(self):
        """
        Ritorna quale via l'actor sta seguendo, a seconda delle skill che
        conosce.
        """
        # (TD)
        return WAY.GLADIATOR

    #- Fine Metodo -

    def get_weak_way(self):
        """
        Ritorna quale via l'actor non sta seguendo, a seconda delle skill che
        conosce.
        """
        # (TD)
        return WAY.RUNIC

    #- Fine Metodo -

    def has_sight_sense(self):
        """
        Ritorna falso se il mob è cieco, di solito si utilizza questo metodo
        al posto della sintassi normale con l'operatore in per controllare
        un'entità non ci può vedere anche magicamente.
        Concettualmente sarebbe il contrario della funzione is_blind definita
        in molti Diku-like.
        """
        if self.trust >= TRUST.MASTER:
            return True

        if is_affected(self, "truesight"):
            return True

        if is_affected(self, "blind"):
            return False

        return True

    #- Fine Metodo -

    def has_hearing_sense(self):
        """
        Ritorna vero se l'entità è sorda.
        """
        # (TD)
        return True

    #- Fine Metodo -

    def has_smell_sense(self):
        """
        Ritorna vero se l'entità non è il possesso del senso dell'olfatto.
        """
        # (TD)
        return True

    #- Fine Metodo -

    def has_touch_sense(self):
        """
        Ritorna vero se l'entità non è il possesso della sensibilità del tocco.
        """
        # (TD)
        return True

    #- Fine Metodo -

    def has_taste_sense(self):
        """
        Ritorna vero se l'entità non è il possesso del senso del gusto.
        """
        # (TD)
        return True

    #- Fine Metodo -

    def has_sixth_sense(self):
        """
        Ritorna vero se l'entità non è il possesso di intuito, o sesto senso.
        """
        # (TD)
        return True

    #- Fine Metodo -

    # -------------------------------------------------------------------------

    def is_drunk(self, difficulty=1):
        """
        Esegue una specie di tiro di salvezza per vedere se l'entità è ubriaca
        o meno.
        L'argomento difficulty può essere un numero variabile ad indicare la
        difficoltà del controllo, maggiore è difficulty più probabile è che
        l'entità sia considerata ubriaca.
        """
        if difficulty <= 0 or difficulty > 10:
            log.bug("difficulty non è valido: %d" % difficulty)
            return False

        # ---------------------------------------------------------------------

        if random.randint(1, 100) < self.drunkness * difficulty:
            return True

        return False

    #- Fine Metodo -

    def has_drunk_walking(self):
        """
        Ritorna una coppia di valori, il primo indica se il mob ha l'andatura
        da ubriaco, il secondo indica se la propria cavalcatura ha l'andatura
        da ubriaco (sempre che il mob abbia una cavalcatura).
        """
        drunk = False
        mount_drunk = False

        if self.is_drunk(
        ) and self.position != POSITION.SHOVE and self.position != POSITION.DRAG:
            drunk = True
        if (self.mount and self.mount.is_drunk()
                and self.mount.position != POSITION.SHOVE
                and self.mount.position != POSITION.DRAG):
            mount_drunk = True

        return drunk, mount_drunk

    #- Fine Metodo -

    # (TD) skill per guadagnare più punti
    def update_points(self):
        # Recupero dei punti base

        # (bb) attenzione che questo dies potrebbe conflittare con quello del
        # ciclo di loop di fight, da rivedere
        if self.life <= 0:
            self.dies()
        elif self.life < self.max_life:
            self.gain_points("life")

        if self.mana < self.max_mana:
            self.gain_points("mana")

        if self.vigour < self.max_vigour:
            self.gain_points("vigour")

    #- Fine Metodo -

    def gain_points(self, name):
        """
        Aggiorna la quantità dei punti: vita, mana e vigore.
        """
        if not name:
            log.bug("name non è un parametro valido: %r" % name)
            return

        # ---------------------------------------------------------------------

        if self.is_fighting():
            return

        if self.position == POSITION.DEAD:
            gain = 0
        elif self.position == POSITION.MORTAL:
            gain = -random.randint(4, 16)
        elif self.position == POSITION.INCAP:
            gain = -random.randint(0, 4)
        elif self.position == POSITION.STUN:
            gain = random.randint(0, 1)
        elif self.position == POSITION.SLEEP:
            gain = random.randint(5, max(6, math.log(1 + self.level / 3) * 9))
        elif self.position == POSITION.REST:
            gain = random.randint(4, max(5, math.log(1 + self.level / 3) * 8))
        elif self.position == POSITION.SIT:
            gain = random.randint(3, max(4, math.log(1 + self.level / 3) * 7))
        elif self.position == POSITION.KNEE:
            gain = random.randint(2, max(3, math.log(1 + self.level / 3) * 6))
        else:
            # (TD) da pensare se il gain in piedi è da disattivare, tranne
            # che per i troll
            gain = random.randint(1, max(2, math.log(1 + self.level / 3) * 4))

        points = getattr(self, name)
        max_points = getattr(self, "max_" + name)

        # Non si può guadagnare per volta più della metà della rimanenza dei punti
        if points >= 2:
            gain = min(gain, points / 2)
        else:
            # Caso particolare, la disperazione porta a piccole grazie!
            # (TD) aggiungere un messaggio e un check sulla fortuna invece del random.randint
            if gain > 0 and random.randint(1, 10) == 1:
                gain = random.randint(gain, gain * 2)

        # Se si ha fame o sete il guadagno dei punti è compromesso
        if gain > 0:
            if self.hunger >= MAX_CONDITION - SERIOUS_CONDITION: gain = 0
            elif self.hunger >= MAX_CONDITION - MEDIUM_CONDITION: gain /= 2
            elif self.hunger >= MAX_CONDITION - LIGHT_CONDITION: gain /= 4
            if self.thirst >= MAX_CONDITION - SERIOUS_CONDITION: gain = 0
            elif self.thirst >= MAX_CONDITION - MEDIUM_CONDITION: gain /= 2
            elif self.thirst >= MAX_CONDITION - LIGHT_CONDITION: gain /= 4

        # (TD) se si è avvelenati il guadagno della vita è compromesso

        # (TD) se si è sotto effetto di incantesimi o se ci si trova in un
        #  posto con clima ostile l'energia è compromessa

        # (TD) Se si è vampiri il guadagno dei punti cambia a seconda che sia giorno o notte

        # Capita quando si hanno dei punti sovra-restorati
        alternate_gain = max_points - points
        if gain > 0 and alternate_gain < 0 and -alternate_gain > gain * 2:
            alternate_gain /= 2

        setattr(self, name, max(0, points + min(gain, alternate_gain)))

    #- Fine Metodo -

    def update_conditions(self):
        # ---------------------------------------------------------------------
        # Modifica dello stato delle condizioni
        # (TD) probabilmente questo devo farlo una volta ogni minuto reale

        # (TD) (BB) per ora disattivata per via del baco sui reset che non
        # darebbero abbastanza cibo
        return
        is_alive = True
        if self.level > 1 and self.trust == TRUST.PLAYER:
            #if is_alive and self.thirst < MAX_CONDITION:
            #    self.gain_condition("thirst", +1)
            is_alive = self.gain_condition("hunger", +2)
            #if is_alive and self.drunkness > 0:
            #    self.gain_condition("drunkness", -1)
            #if is_alive and self.adrenaline > 0:
            #    self.gain_condition("adrenaline", -1)
            #if is_alive and self.bloodthirst < MAX_CONDITION:
            #    self.gain_condition("bloodthirst", +1)
            # (TD) da rivalutare e finire, magari farla solo come malus per le
            # morti, una delle due o tutte e due
            #self.gain_condition("mind")
            #self.gain_condition("emotion")

        if not is_alive:
            return

    #- Fine Metodo -

    def gain_condition(self, name, value):
        """
        Aggiorna lo stato delle condizioni (fame, sete, sonno...)
        """
        if not name:
            log.bug("name non è un parametro valido: %r" % name)
            return True

        if value < 0 or value > MAX_CONDITION:
            log.bug("name non è un parametro valido: %d" % value)
            return True

        # ---------------------------------------------------------------------

        # (TD) qui tutto cambia molto quando ci saranno le malattie del
        # vampirismo e della licantropia

        # (TD) Inserire anche dei modificato di value razziali

        condition = getattr(self, name)
        if condition < MAX_CONDITION:
            condition = max(0, min(condition + value, MAX_CONDITION))
            setattr(self, name, condition)

        is_alive = True
        if self.IS_PLAYER and name == "hunger":
            if condition >= MAX_CONDITION - SERIOUS_CONDITION:
                self.act("\n" + self.get_hunger_condition(), TO.ENTITY)
                self.act("$n sta languendo per la [orange]fame[close]!",
                         TO.OTHERS)
                is_alive = self.damage(self, int(math.log(self.level) * 2),
                                       DAMAGE.HUNGER)
                self.send_prompt()
            elif condition >= MAX_CONDITION - MEDIUM_CONDITION:
                self.act("\n" + self.get_hunger_condition(), TO.ENTITY)
                self.act(
                    "Avverti lo stomaco di $n che [orange]brontola[close].",
                    TO.OTHERS)
                is_alive = self.damage(self, int(math.log(self.level)),
                                       DAMAGE.HUNGER)
                self.send_prompt()
            elif condition >= MAX_CONDITION - LIGHT_CONDITION:
                self.act("\n" + self.get_hunger_condition(), TO.ENTITY)
                self.send_prompt()
                # Qui nessun messaggio di act per gli altri, per evitare spam

        return is_alive

    #- Fine Metodo -

    def skin_colorize(self, argument):
        if not argument:
            log.bug("argument non è un parametro valido: %r" % argument)
            return ""

        # ---------------------------------------------------------------------

        if self.skin_color == COLOR.NONE:
            return "[pink]%s[close]" % argument
        elif self.skin_color.web_name == config.text_color:
            return argument
        else:
            return "[%s]%s[close]" % (self.skin_color.web_name, argument)

    #- Fine Metodo -

    def eye_colorize(self, argument):
        if not argument:
            log.bug("argument non è un parametro valido: %r" % argument)
            return ""

        # ---------------------------------------------------------------------

        if self.eye_color == COLOR.NONE or self.eye_color.web_name == config.text_color:
            return argument
        else:
            return "[%s]%s[close]" % (self.eye_color.web_name, argument)

    #- Fine Metodo -

    def hair_colorize(self, argument):
        if not argument:
            log.bug("argument non è un parametro valido: %r" % argument)
            return ""

        # ---------------------------------------------------------------------

        if self.hair_color == COLOR.NONE or self.hair_color.web_name == config.text_color:
            return argument
        else:
            return "[%s]%s[close]" % (self.hair_color.web_name, argument)

    #- Fine Metodo -

    # -------------------------------------------------------------------------

    def get_thirst_condition(self):
        # (TD)
        return "Non hai [darkcyan]sete[close]"

    #- Fine Metodo -

    def get_hunger_condition(self):
        if self.hunger >= MAX_CONDITION - SERIOUS_CONDITION:
            return "Stai languendo per la [orange]FAME[close]!"
        elif self.hunger >= MAX_CONDITION - MEDIUM_CONDITION:
            return "Il tuo stomaco brontola per la [orange]fame[close]"
        elif self.hunger >= MAX_CONDITION - LIGHT_CONDITION:
            return "Hai [orange]fame[close]"
        else:
            return "Non hai [orange]fame[close]"

    #- Fine Metodo -

    def get_sleep_condition(self):
        # (TD)
        return "Non hai [blue]sonno[close]"

    #- Fine Metodo -

    def get_drunkness_condition(self):
        # (TD)
        return "Non sei [purple]ubriac$o[close]"

    #- Fine Metodo -

    def get_adrenaline_condition(self):
        # (TD)
        return "La tua [red]adrenalina[close] è sotto controllo"

    #- Fine Metodo -

    def get_mind_condition(self):
        # (TD)
        return ""

    #- Fine Metodo -

    def get_emotion_condition(self):
        # (TD)
        return ""

    #- Fine Metodo -

    def get_bloodthirst_condition(self):
        # (TD)
        return ""

    #- Fine Metodo -

    def dies(self, opponent=None, auto_loot=False, teleport_corpse=False):
        force_return = check_trigger(self, "before_die", self, opponent)
        if force_return:
            return
        if opponent:
            force_return = check_trigger(opponent, "before_dies", self,
                                         opponent)
            if force_return:
                return

        remains, use_repop = self.make_remains(auto_loot)

        # Attenzione che l'utilizzo di tali trigger potrebbero essere pericolosi
        # visto che sotto c'è un'extract
        force_return = check_trigger(self, "after_die", self, opponent)
        if force_return:
            return
        if opponent:
            force_return = check_trigger(opponent, "after_dies", self,
                                         opponent)
            if force_return:
                return

        self.extract(1, use_repop=use_repop)
Example #16
0
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)
Example #17
0
class ProtoMob(ProtoEntity):
    """
    Classe che gestisce il prototipo di un Mob.
    """
    PRIMARY_KEY = "code"
    VOLATILES = ProtoEntity.VOLATILES + []
    MULTILINES = ProtoEntity.MULTILINES + []
    SCHEMA = {
        "behaviour": ("src.behaviour", "MobBehaviour"),
        "height": ("", "measure")
    }
    SCHEMA.update(ProtoEntity.SCHEMA)
    REFERENCES = {}
    REFERENCES.update(ProtoEntity.REFERENCES)
    WEAKREFS = {}
    WEAKREFS.update(ProtoEntity.WEAKREFS)

    IS_AREA = False
    IS_DESCR = True
    IS_ROOM = False
    IS_EXIT = False
    IS_WALL = False
    IS_ACTOR = True
    IS_MOB = True
    IS_ITEM = False
    IS_PLAYER = False
    IS_EXTRA = False
    IS_PROTO = True

    ACCESS_ATTR = "proto_mobs"
    CONSTRUCTOR = None  # Classe Mob una volta che viene definita a fine modulo

    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)

    #- Fine Inizializzazione -

    def get_error_message(self):
        msg = super(ProtoMob, self).get_error_message()
        if msg:
            pass
        elif self.IS_MOB and "_mob_" not in self.code:
            msg = "code di mob senza l'identificativo _mob_ al suo interno"
        elif self.race.get_error_message(RACE, "race", allow_none=False) != "":
            return self.race.get_error_message(RACE, "race", allow_none=False)
        elif self.birth_day <= 0 or self.birth_day > config.days_in_month:
            return "birth_day errato: %d" % self.birth_day
        elif self.birth_month.get_error_message(MONTH, "birth_month") != "":
            return self.birth_month.get_error_message(MONTH, "birth_month")
        elif self.age < 0:
            return "age minore di zero: %d" % self.age
        elif self.height <= 0:
            msg = "altezza minore o uguale a zero: %s" % self.height
        elif self.constellation.get_error_message(CONSTELLATION,
                                                  "constellation") != "":
            msg = self.constellation.get_error_message(CONSTELLATION,
                                                       "constellation")
        elif self.virtue.get_error_message(VIRTUE, "virtue") != "":
            msg = self.virtue.get_error_message(VIRTUE, "virtue")
        elif self.hometown and self.hometown not in database["areas"]:
            msg = "hometown inesistente tra i codici delle aree: %s" % self.hometown
        elif self.group_name and self.group_name not in database["groups"]:
            msg = "group_name inesistente tra i nomi dei gruppi: %s" % self.group_name
        elif self.strength <= 0 or self.strength > config.max_stat_value:
            msg = "strength non è tra zero e %d: %d" % (config.max_stat_value,
                                                        self.strength)
        elif self.endurance <= 0 or self.endurance > config.max_stat_value:
            msg = "endurance non è tra zero e %d: %d" % (config.max_stat_value,
                                                         self.endurance)
        elif self.agility <= 0 or self.agility > config.max_stat_value:
            msg = "agility non è tra zero e %d: %d" % (config.max_stat_value,
                                                       self.agility)
        elif self.speed <= 0 or self.speed > config.max_stat_value:
            msg = "speed non è tra zero e %d: %d" % (config.max_stat_value,
                                                     self.speed)
        elif self.intelligence <= 0 or self.intelligence > config.max_stat_value:
            msg = "intelligence non è tra zero e %d: %d" % (
                config.max_stat_value, self.intelligence)
        elif self.willpower <= 0 or self.willpower > config.max_stat_value:
            msg = "willpower non è tra zero e %d: %d" % (config.max_stat_value,
                                                         self.willpower)
        elif self.personality <= 0 or self.personality > config.max_stat_value:
            msg = "personality non è tra zero e %d: %d" % (
                config.max_stat_value, self.personality)
        elif self.luck <= 0 or self.luck > config.max_stat_value:
            msg = "luck non è tra zero e %d: %d" % (config.max_stat_value,
                                                    self.luck)
        elif self.voice_potence < 0:
            msg = "voice_potence non può essere minore di zero: %s" % self.voice_potence
        # (TD) ricordarsi di aggiungere il controllo alle parts
        else:
            return ""

        if type(self) == ProtoMob:
            log.bug("(ProtoMob: code %s) %s" % (self.code, msg))
        return msg

    #- Fine Metodo -

    def get_area_code(self):
        """
        Ritorna il codice dell'area carpendolo dal proprio codice.
        """
        if "_mob_" in self.code:
            return self.code.split("_mob_", 1)[0]
        else:
            log.bug("Codice errato per l'entità %s: %s" %
                    (self.__class__.__name__, self.code))
            return ""
Example #18
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))
Example #19
0
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()
Example #20
0
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)
Example #21
0
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
Example #22
0
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)
Example #23
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