Ejemplo n.º 1
0
    def play_all(self):
        """Play the entire animation once.

        That method plays the entire animation only once, there is no auto
        replay as it blocks the game (for the moment).

        If the the state is PAUSED or STOPPED, the animation does not play and
        the method return False.

        If parent is not a sub class of
        :class:`~gamelib.BoardItem.BoardItem` an exception is raised.

        If screen_refresh is not defined or is not a function an exception
        is raised.

        :raise: :class:`~gamelib.HacExceptions.HacInvalidTypeException`

        Example::

            item.animation.play_all()
        """
        if self.state == PAUSED or self.state == STOPPED:
            return False
        if self.refresh_screen is None or not callable(self.refresh_screen):
            raise HacInvalidTypeException(
                "The refresh_screen parameter needs to be a callback "
                "function reference.")
        if not isinstance(self.parent, BoardItem):
            raise HacInvalidTypeException(
                "The parent needs to be a sub class of BoardItem.")
        for f in self.frames:
            self.parent.model = f
            self.refresh_screen()
            time.sleep(self.display_time)
        return True
Ejemplo n.º 2
0
    def add_board(self, level_number, board):
        """Add a board for the level number.

        This method associate a Board (:class:`gamelib.Board.Board`) to a level number.

        Example::

            game.add_board(1,myboard)

        :param level_number: the level number to associate the board to.
        :type level_number: int
        :param board: a Board object corresponding to the level number.
        :type board: gamelib.Board.Board

        :raises HacInvalidTypeException: If either of these parameters are not of the correct type.
        """
        if type(level_number) is int:
            if isinstance(board, Board):
                self._boards[level_number] = {'board': board, 'npcs': []}
            else:
                raise HacInvalidTypeException(
                    "The board paramater must be a gamelib.Board.Board() object."
                )
        else:
            raise HacInvalidTypeException("The level number must be an int.")
Ejemplo n.º 3
0
    def add_waypoint(self, row, column):
        """Add a waypoint to the list of waypoints.

        Waypoints are used one after the other on a FIFO basis
        (First In, First Out).

        :param row: The "row" part of the waypoint's coordinate.
        :type row: int
        :param column: The "column" part of the waypoint's coordinate.
        :type row: int
        :raise HacInvalidTypeException: If any of the parameters is not an int.

        Example::

            pf = PathFinder(game=mygame, actuated_object=npc1)
            pf.add_waypoint(3,5)
            pf.add_waypoint(12,15)

        """
        if type(row) is not int:
            raise HacInvalidTypeException(
                '"row" is not an integer. It must be.')
        if type(column) is not int:
            raise HacInvalidTypeException('"column" is not an integer.\
                                         It must be.')
        self.waypoints.append((row, column))
Ejemplo n.º 4
0
    def remove_waypoint(self, row, column):
        """ Remove a waypoint from the stack.

        This method removes the first occurrence of a waypoint in the stack.

        If the waypoint cannot be found, it raises a ValueError exception.
        If the row and column parameters are not int, an
        HacInvalidTypeException is raised.

        :param row: The "row" part of the waypoint's coordinate.
        :type row: int
        :param column: The "column" part of the waypoint's coordinate.
        :type row: int
        :raise HacInvalidTypeException: If any of the parameters is not an int.
        :raise ValueError: If the waypoint is not found in the stack.

        Example::

            method()
        """
        if type(row) is not int:
            raise HacInvalidTypeException(
                '"row" is not an integer. It must be.')
        if type(column) is not int:
            raise HacInvalidTypeException('"column" is not an integer.\
                                         It must be.')
        try:
            idx = self.waypoints.index((row, column))
            self.waypoints.pop(idx)
        except ValueError as e:
            print(e)
Ejemplo n.º 5
0
    def add_npc(self,level_number,npc,row=None,column=None):
        """
        Add a NPC to the game. It will be placed on the board corresponding to the level_number.
        If row and column are not None, the NPC is placed at these coordinates. Else, it's randomly placed in an empty cell.

        Example::
 
            game.add_npc(1,my_evil_npc,5,2)

        :param level_number: the level number of the board.
        :type level_number: int
        :param npc: the NPC to place.
        :type npc: gamelib.Characters.NPC
        :param row: the row coordinate to place the NPC at.
        :type row: int
        :param column: the column coordinate to place the NPC at.
        :type column: int

        If either of these parameters are not of the correct type, a HacInvalidTypeException exception is raised.

        .. Important:: If the NPC does not have an actuator, this method is going to affect a gamelib.Actuators.SimpleActuators.RandomActuator() to npc.actuator. And if npc.step == None, this method sets it to 1
        """
        if type(level_number) is int:
            if isinstance(npc, NPC):
                if row == None or column == None:
                    retry = 0
                    while True :
                        if row == None:
                            row = random.randint(0,self._boards[level_number]['board'].size[1]-1)
                        if column == None:
                            column = random.randint(0,self._boards[level_number]['board'].size[0]-1)
                        # print(f"Game.add_npc() finding a position for NPC {npc.name} trying ({x},{y})")
                        if isinstance(self._boards[level_number]['board'].item(row,column), BoardItemVoid):
                            break
                        else:
                            row = None
                            column = None
                            retry += 1
                if type(row) is int:
                    if type(column) is int:
                        if npc.actuator == None:
                            npc.actuator = RandomActuator(moveset=[Constants.UP,Constants.DOWN,Constants.LEFT,Constants.RIGHT])
                        if npc.step == None:
                            npc.step = 1
                        self._boards[level_number]['board'].place_item(npc,row,column)
                        self._boards[level_number]['npcs'].append(npc)
                    else:
                        raise HacInvalidTypeException("column must be an int.")
                else:
                    raise HacInvalidTypeException("row must be an int.")
            else:
                raise HacInvalidTypeException("The npc paramater must be a gamelib.Characters.NPC() object.")
        else:
            raise HacInvalidTypeException("The level number must be an int.")
Ejemplo n.º 6
0
    def next_frame(self):
        """Update the parent.model with the next frame of the animation.

        That method takes care of automatically replaying the animation if the
        last frame is reached if the state is RUNNING.

        If the the state is PAUSED it still update the parent.model
        and returning the current frame. It does NOT actually go to next frame.

        If parent is not a sub class of
        :class:`~gamelib.BoardItem.BoardItem` an exception is raised.

        :raise: :class:`~gamelib.HacExceptions.HacInvalidTypeException`

        Example::

            item.animation.next_frame()
        """
        if not isinstance(self.parent, BoardItem):
            raise HacInvalidTypeException(
                "The parent needs to be a sub class of BoardItem.")
        if self.state == RUNNING:
            self._frame_index += 1
            if self._frame_index >= len(self.frames):
                if self.auto_replay:
                    self.reset()
                else:
                    self._frame_index = len(self.frames) - 1
            self.parent.model = self.frames[self._frame_index]
            return self.frames[self._frame_index]
        elif self.state == PAUSED:
            self.parent.model = self.frames[self._frame_index]
            return self.frames[self._frame_index]
Ejemplo n.º 7
0
    def remove_frame(self, index):
        """Remove a frame from the animation.

        That method remove the frame at the specified index and return it
        if it exists.

        If the index is out of bound an exception is raised.
        If the index is not an int an exception is raised.

        :param index: The index of the frame to remove.
        :type index: int
        :rtype: str
        :raise: IndexError, HacInvalidTypeException

        Example::

            item.animation.remove_frame( item.animation.search_frame(
                Sprite.ALIEN_MONSTER)
            )

        """
        if type(index) is not int:
            raise HacInvalidTypeException(
                'The "index" parameter must be an int.')
        if index <= self._frame_index and self._frame_index > 0:
            self._frame_index -= 1
        return self.frames.pop(index)
Ejemplo n.º 8
0
    def animate_items(self, level_number):
        """That method goes through all the BoardItems of a given map and call
        Animation.next_frame()
        :param level_number: The number of the level to animate items in.
        :type level_number: int

        :raise: :class:`gamelib.HacExceptions.HacInvalidLevelException`
            class:`gamelib.HacExceptions.HacInvalidTypeException`

        Example::

            mygame.animate_items(1)
        """
        if self.state == Constants.RUNNING:
            if type(level_number) is int:
                if level_number in self._boards.keys():
                    for item in self._boards[level_number][
                            "board"].get_immovables():
                        if item.animation is not None:
                            item.animation.next_frame()
                    for item in self._boards[level_number][
                            "board"].get_movables():
                        if item.animation is not None:
                            item.animation.next_frame()
                else:
                    raise HacInvalidLevelException(
                        f"Impossible to animate items for this level (level number "
                        "{level_number} is not associated with any board).")
            else:
                raise HacInvalidTypeException(
                    "In animate_items(level_number) the level_number must be an int."
                )
Ejemplo n.º 9
0
    def place_item(self,item,row,column):
        """
        Place an item at coordinates row and column.

        If row or column are our of the board boundaries, an HacOutOfBoardBoundException is raised.

        If the item is not a subclass of BoardItem, an HacInvalidTypeException

        .. warning:: Nothing prevents you from placing an object on top of another. Be sure to check that. This method will check for items that are both overlappable **and** restorable to save them, but that's the extend of it.
        """
        if row < self.size[1] and column < self.size[0]:
            if isinstance(item, BoardItem):
                # If we are about to place the item on a overlappable and restorable we store it to be restored when the Movable will move.
                if isinstance(self._matrix[row][column], Immovable) and self._matrix[row][column].restorable() and self._matrix[row][column].overlappable():
                    item._overlapping = self._matrix[row][column]
                self._matrix[row][column] = item
                item.store_position(row,column)
                if isinstance(item, Movable) and item not in self._movables:
                    self._movables.append(item)
                elif isinstance(item, Immovable) and item not in self._immovables:
                    self._immovables.append(item)
            else:
                raise HacInvalidTypeException("The item passed in argument is not a subclass of BoardItem")
        else:
            raise HacOutOfBoardBoundException(f"There is no item at coordinates [{row},{column}] because it's out of the board boundaries ({self.size[0]}x{self.size[1]}).")
Ejemplo n.º 10
0
    def change_level(self, level_number):
        """
        Change the current level, load the board and place the player to the right place.

        Example::

            game.change_level(1)

        :param level_number: the level number to change to.
        :type level_number: int

        :raises HacInvalidTypeException: If parameter is not an int.
        """
        if type(level_number) is int:
            if self.player == None:
                raise HacException(
                    'undefined_player',
                    'Game.player is undefined. We cannot change level without a player. Please set player in your Game object: mygame.player = Player()'
                )
            if level_number in self._boards.keys():
                if self.player.pos[0] != None or self.player.pos[1] != None:
                    self._boards[self.current_level]['board'].clear_cell(
                        self.player.pos[0], self.player.pos[1])
                self.current_level = level_number
                b = self._boards[self.current_level]['board']
                b.place_item(self.player, b.player_starting_position[0],
                             b.player_starting_position[1])
            else:
                raise HacInvalidLevelException(
                    f"Impossible to change level to an unassociated level (level number {level_number} is not associated with any board).\nHave you called:\ngame.add_board({level_number},Board()) ?"
                )
        else:
            raise HacInvalidTypeException(
                'level_number needs to be an int in change_level(level_number).'
            )
Ejemplo n.º 11
0
    def actuate_npcs(self, level_number):
        """Actuate all NPCs on a given level

        This method actuate all NPCs on a board associated with a level. At the moment it means moving the NPCs but as the Actuators become more capable this method will evolve to allow more choice (like attack use objects, etc.)

        :param level_number: The number of the level to actuate NPCs in.
        :type int:

        Example::

            mygame.actuate_npcs(1)
        
        .. note:: This method only move NPCs when their actuator state is RUNNING. If it is PAUSED or STOPPED, theNPC is not moved.
        """
        if self.state == Constants.RUNNING:
            if type(level_number) is int:
                if level_number in self._boards.keys():
                    for npc in self._boards[level_number]['npcs']:
                        if npc.actuator.state == Constants.RUNNING:
                            self._boards[level_number]['board'].move(
                                npc, npc.actuator.next_move(), npc.step)
                else:
                    raise HacInvalidLevelException(
                        f"Impossible to actuate NPCs for this level (level number {level_number} is not associated with any board)."
                    )
            else:
                raise HacInvalidTypeException(
                    'In actuate_npcs(level_number) the level_number must be an int.'
                )
Ejemplo n.º 12
0
    def neighbors(self, radius=1, object=None):
        """Get a list of neighbors (non void item) around an object.

        This method returns a list of objects that are all around an object between the position of an object and all the cells at **radius**.

        :param radius: The radius in which non void item should be included
        :type radius: int
        :param object: The central object. The neighbors are calculated for that object. If None, the player is the object.
        :type object: gamelib.BoardItem.BoardItem
        :return: A list of BoardItem. No BoardItemVoid is included.
        :raises HacInvalidTypeException: If radius is not an int.
        
        Example::
        
            for item in game.neighbors(2):
                print(f'{item.name} is around player at coordinates ({item.pos[0]},{item.pos[1]})')
        """
        if type(radius) is not int:
            raise HacInvalidTypeException(
                'In Game.neighbors(radius), radius must be an integer.')
        if object == None:
            object = self.player
        return_array = []
        for x in range(-radius, radius + 1, 1):
            for y in range(-radius, radius + 1, 1):
                if x == 0 and y == 0:
                    continue
                true_x = object.pos[0] + x
                true_y = object.pos[1] + y
                if not isinstance(self.current_board().item(true_x, true_y),
                                  BoardItemVoid):
                    return_array.append(self.current_board().item(
                        true_x, true_y))
        return return_array
Ejemplo n.º 13
0
    def delete_menu_category(self, category=None):
        """Delete an entire category from the menu.

        That function removes the entire list of messages that are attached to the
        category.

        :param category: The category tp delete.
        :type category: str
        :raise HacInvalidTypeException: If the category is not a string

        .. important:: If the entry have no shortcut it's advised not to try to update
            unless you have only one NoneType as a shortcut.

        Example::

            game.add_menu_entry('main_menu','d','Go right')
            game.update_menu_entry('main_menu','d','Go LEFT',Constants.LEFT)

        """
        if type(category) is str and category in self._menu:
            del self._menu[category]
        else:
            raise HacInvalidTypeException(
                "in Game.delete_menu_entry(): category cannot be anything else but a"
                "string.")
Ejemplo n.º 14
0
    def add_item(self, item):
        """Add an item to the inventory.

        This method will add an item to the inventory unless:

         * it is not an instance of :class:`~gamelib.BoardItem.BoardItem`,
         * you try to add an item that is not pickable,
         * there is no more space left in the inventory (i.e: the cumulated size of the
           inventory + your item.size is greater than the inventory max_size)

        :param item: the item you want to add
        :type item: :class:`~gamelib.BoardItem.BoardItem`
        :raises: HacInventoryException, HacInvalidTypeException

        Example::

            item = Treasure(model=Sprites.MONEY_BAG,size=2,name='Money bag')
            try:
                mygame.player.inventory.add_item(item)
            expect HacInventoryException as e:
                if e.error == 'not_enough_space':
                    print(f"Impossible to add {item.name} to the inventory, there is no"
                    "space left in it!")
                    print(e.message)
                elif e.error == 'not_pickable':
                    print(e.message)

        .. warning:: if you try to add more than one item with the same name (or if the
            name is empty), this function will automatically change the name of the item
            by adding a UUID to it.

        """
        if isinstance(item, BoardItem):
            if item.pickable():
                if (item.name is None or item.name == ""
                        or item.name in self.__items.keys()):
                    item.name += "_" + uuid.uuid4().hex
                if (hasattr(item, "_size")
                        and self.max_size >= self.size() + item.size()):
                    self.__items[item.name] = item
                else:
                    raise HacInventoryException(
                        "not_enough_space",
                        "There is not enough space left in the inventory. Max. size: "
                        + str(self.max_size) + ", current inventory size: " +
                        str(self.size()) + " and item size: " +
                        str(item.size()),
                    )
            else:
                raise HacInventoryException(
                    "not_pickable",
                    f"The item (name='{item.name}') is not pickable. Make sure to only "
                    "add pickable objects to the inventory.",
                )
        else:
            raise HacInvalidTypeException(
                "The item is not an instance of BoardItem. The item is of type: "
                + type(item))
Ejemplo n.º 15
0
    def add_directional_model(self, direction, model):
        """Add an model for a specific direction.

        :param direction: A direction from the Constants module.
        :type direction: int
        :param model: The model for the direction
        :type model: str

        Example::

            fireball.add_directional_animation(Constants.UP, updward_animation)
        """
        if type(direction) is not int:
            raise HacInvalidTypeException(
                "Projectile.add_directional_model "
                "requires an int from the Constants module as"
                "direction.")
        if type(model) is not str:
            raise HacInvalidTypeException("Projectile.add_directional_model "
                                          "requires a string as model.")
        self._directional_models[direction] = model
Ejemplo n.º 16
0
    def add_directional_animation(self, direction, animation):
        """Add an animation for a specific direction.

        :param direction: A direction from the Constants module.
        :type direction: int
        :param animation: The animation for the direction
        :type animation: :class:`~gamelib.Animation.Animation`

        Example::

            fireball.add_directional_animation(Constants.UP, updward_animation)
        """
        if type(direction) is not int:
            raise HacInvalidTypeException(
                "Projectile.add_directional_animation "
                "requires an int from the Constants module as"
                "direction.")
        if not isinstance(animation, Animation):
            raise HacInvalidTypeException(
                "Projectile.add_directional_animation "
                "requires a gamelib.Animation.Animation as "
                "animation")
        self._directional_animations[direction] = animation
Ejemplo n.º 17
0
    def set_restorable(self,val):
        """Make the structure restorable or not.

        :param val: True or False depending on the restorability of the structure.
        :type val: bool
        
        Example::
        
            myneatstructure.set_restorable(True)
        """
        if type(val) is bool:
            self.__is_restorable = val
        else:
            raise HacInvalidTypeException('set_restorable(bool) takes a boolean as paramater.')
Ejemplo n.º 18
0
    def remove_directional_model(self, direction):
        """Remove the model for a specific direction.

        :param direction: A direction from the Constants module.
        :type direction: int

        Example::

            fireball.directional_model(Constants.UP)
        """
        if type(direction) is not int:
            raise HacInvalidTypeException(
                "Projectile.add_directional_model "
                "requires an int from the Constants module as"
                "direction.")
        del self._directional_models[direction]
Ejemplo n.º 19
0
    def set_destination(self,row=0,column=0):
        """Set the targeted destination.

        :param row: "row" coordinate on the board grid
        :type row: int
        :param column: "column" coordinate on the board grid
        :type column: int
        :raises HacInvalidTypeException: if row or column are not int.
        
        Example::
        
            mykillernpc.actuator.set_destination( mygame.player.pos[0], mygame.player.pos[1] )
        """
        if type(row) is not int or type(column) is not int:
            raise HacInvalidTypeException("In Actuator.PathFinder.set_destination(x,y) both x and y must be integer.")
        self.destination = (row,column)
Ejemplo n.º 20
0
    def add_frame(self, frame):
        """Add a frame to the animation.

        The frame has to be a string (that includes sprites from the Sprite module and squares from the Utils module).

        Raise an exception if frame is not a string.

        :param frame: The frame to add to the animation.
        :type frame: str
        :raise: :class:`gamelib.HacExceptions.HacInvalidTypeException`
        
        Example::

            item.animation.add_frame(Sprite.ALIEN)
            item.animation.add_frame(Sprite.ALIEN_MONSTER)
        """
        if type(frame) is not str:
            raise HacInvalidTypeException(
                'The "frame" parameter must be a string.')
        self.frames.append(frame)
Ejemplo n.º 21
0
    def search_frame(self, frame):
        """Search a frame in the animation.

        That method is returning the index of the first occurrence of "frame".

        Raise an exception if frame is not a string.

        :param frame: The frame to find.
        :type frame: str
        :rtype: int
        :raise: :class:`gamelib.HacExceptions.HacInvalidTypeException`
        
        Example::

            item.animation.remove_frame( item.animation.search_frame(Sprite.ALIEN_MONSTER) )
            
        """
        if type(frame) is not str:
            raise HacInvalidTypeException(
                'The "frame" parameter must be a string.')
        return self.frames.index(frame)
Ejemplo n.º 22
0
    def directional_animation(self, direction):
        """Return the animation for a specific direction.

        :param direction: A direction from the Constants module.
        :type direction: int
        :rtype: :class:`~gamelib.Animation.Animation`

        Example::

            # No more animation for the UP direction
            fireball.directional_animation(Constants.UP)
        """
        if type(direction) is not int:
            raise HacInvalidTypeException(
                "Projectile.add_directional_animation "
                "requires an int from the Constants module as"
                "direction.")
        if direction in self._directional_animations:
            return self._directional_animations[direction]
        elif self.movement_animation is not None:
            return self.movement_animation
        else:
            return self.animation
Ejemplo n.º 23
0
    def set_direction(self, direction):
        """Set the direction of a projectile

        This method will set a UnidirectionalActuator with the direction.
        It will also take care of updating the model and animation for the given
        direction if they are specified.

        :param direction: A direction from the Constants module.
        :type direction: int

        Example::

            fireball.set_direction(Constants.UP)
        """
        if type(direction) is not int:
            raise HacInvalidTypeException(
                "Projectile.set_direction "
                "requires an int from the Constants module as"
                "direction.")
        self.model = self.directional_model(direction)
        self.animation = self.directional_animation(direction)
        self.direction = direction
        self.actuator = UnidirectionalActuator(direction=direction)
Ejemplo n.º 24
0
    def save_board(self, lvl_number, filename):
        """Save a board to a JSON file

        This method saves a Board and everything in it but the BoardItemVoid.

        Not check are done on the filename, if anything happen you get the exceptions from open().

        :param lvl_number: The level number to get the board from.
        :type lvl_number: int
        :param filename: The path to the file to save the data to.
        :type filename: str

        :raises HacInvalidTypeException: If any parameter is not of the right type
        :raises HacInvalidLevelException: If the level is not associated with a Board.
        
        Example::
        
            game.save_board( 1, 'hac-maps/level1.json')
        
        If Game.object_library is not an empty array, it will be saved also.
        """
        if type(lvl_number) is not int:
            raise HacInvalidTypeException(
                "lvl_number must be an int in Game.save_board()")
        if type(filename) is not str:
            raise HacInvalidTypeException(
                "filename must be a str in Game.save_board()")
        if lvl_number not in self._boards:
            raise HacInvalidLevelException(
                'lvl_number ' + lvl_number +
                ' does not correspond to any level associated with a board in Game.save_board()'
            )

        data = {}
        local_board = self._boards[lvl_number]['board']
        data['name'] = local_board.name
        data['player_starting_position'] = local_board.player_starting_position
        data['ui_border_left'] = local_board.ui_border_left
        data['ui_border_right'] = local_board.ui_border_right
        data['ui_border_top'] = local_board.ui_border_top
        data['ui_border_bottom'] = local_board.ui_border_bottom
        data['ui_board_void_cell'] = local_board.ui_board_void_cell
        data['size'] = local_board.size
        data['map_data'] = {}

        def _obj2ref(obj):
            ref = {
                "object": str(obj.__class__),
                "name": obj.name,
                "pos": obj.pos,
                "model": obj.model,
                "type": obj.type
            }

            if isinstance(obj, Structures.Wall):
                ref['size'] = obj.size()
            elif isinstance(obj, Structures.Treasure):
                ref['value'] = obj.value
                ref['size'] = obj.size()
            elif isinstance(
                    obj, Structures.GenericActionableStructure) or isinstance(
                        obj, Structures.GenericStructure):
                ref['value'] = obj.value
                ref['size'] = obj.size()
                ref['overlappable'] = obj.overlappable()
                ref['pickable'] = obj.pickable()
                ref['restorable'] = obj.restorable()
            elif isinstance(obj, Structures.Door):
                ref['value'] = obj.value
                ref['size'] = obj.size()
                ref['overlappable'] = obj.overlappable()
                ref['pickable'] = obj.pickable()
                ref['restorable'] = obj.restorable()
            elif isinstance(obj, NPC):
                ref['hp'] = obj.hp
                ref['max_hp'] = obj.max_hp
                ref['step'] = obj.step
                ref['remaining_lives'] = obj.remaining_lives
                ref['attack_power'] = obj.attack_power
                if obj.actuator != None:
                    if isinstance(obj.actuator, RandomActuator):
                        ref['actuator'] = {
                            'type': 'RandomActuator',
                            'moveset': obj.actuator.moveset
                        }
                    elif isinstance(obj.actuator, PathActuator):
                        ref['actuator'] = {
                            'type': 'PathActuator',
                            'path': obj.actuator.path
                        }
            return ref

        if len(self.object_library) > 0:
            data['library'] = []
            for o in self.object_library:
                data['library'].append(_obj2ref(o))

        # Now we need to run through all the cells to store anything that is not a BoardItemVoid
        for x in self.current_board()._matrix:
            for y in x:
                if not isinstance(y, BoardItemVoid) and not isinstance(
                        y, Player):
                    # print(f"Item: name={y.name} pos={y.pos} type={y.type}")
                    if str(y.pos[0]) not in data['map_data'].keys():
                        data['map_data'][str(y.pos[0])] = {}

                    data['map_data'][str(y.pos[0])][str(
                        y.pos[1])] = _obj2ref(y)
        with open(filename, 'w') as f:
            json.dump(data, f)
Ejemplo n.º 25
0
    def display_around(self, object, row_radius, column_radius):
        """Display only a part of the board.

        This method behaves like display() but only display a part of the board around
        an object (usually the player).
        Example::

            # This will display only a total of 30 cells vertically and
            # 60 cells horizontally.
            board.display_around(player, 15, 30)

        :param object: an item to center the view on (it has to be a subclass
            of BoardItem)
        :type object: :class:`~gamelib.BoardItem.BoardItem`
        :param row_radius: The radius of display in number of rows showed. Remember that
            it is a radius not a diameter...
        :type row_radius: int
        :param column_radius: The radius of display in number of columns showed.
            Remember that... Well, same thing.
        :type column_radius: int

        It uses the same display algorithm than the regular display() method.
        """
        # First let's take care of the type checking
        if not isinstance(object, BoardItem):
            raise HacInvalidTypeException(
                "Board.display_around: object needs to be a BoardItem.")
        if type(row_radius) is not int or type(column_radius) is not int:
            raise HacInvalidTypeException(
                "Board.display_around: both row_radius and"
                " column_radius needs to be int.")
        # Now if the viewport is greater or equal to the board size, well we just need
        # a regular display()
        if self.size[1] <= 2 * row_radius and self.size[0] <= 2 * column_radius:
            return self.display()
        row_min_bound = 0
        row_max_bound = self.size[1]
        column_min_bound = 0
        column_max_bound = self.size[0]
        # Row
        if object.pos[0] - row_radius >= 0:
            row_min_bound = object.pos[0] - row_radius
        if object.pos[0] + row_radius < row_max_bound:
            row_max_bound = object.pos[0] + row_radius
        # Columns
        if object.pos[1] - column_radius >= 0:
            column_min_bound = object.pos[1] - column_radius
        if object.pos[1] + column_radius < column_max_bound:
            column_max_bound = object.pos[1] + column_radius
        # Now adjust boundaries so it looks fine at min and max
        if column_min_bound <= 0:
            column_min_bound = 0
            column_max_bound = 2 * column_radius
        if column_max_bound >= self.size[0]:
            column_max_bound = self.size[0]
            if (self.size[0] - 2 * column_radius) >= 0:
                column_min_bound = self.size[0] - 2 * column_radius
        if row_min_bound <= 0:
            row_min_bound = 0
            row_max_bound = 2 * row_radius
        if row_max_bound >= self.size[1]:
            row_max_bound = self.size[1]
            if (self.size[1] - 2 * row_radius) >= 0:
                row_min_bound = self.size[1] - 2 * row_radius
        if row_min_bound == 0:
            bt_size = column_radius * 2
            if bt_size >= self.size[0]:
                bt_size = self.size[0]
                if object.pos[1] - column_radius > 0:
                    bt_size = self.size[0] - (object.pos[1] - column_radius)
            print(self.ui_border_top * bt_size, end="")
            if column_min_bound <= 0 and column_max_bound >= self.size[0]:
                print(self.ui_border_top * 2, end="")
            elif column_min_bound <= 0 or column_max_bound >= self.size[0]:
                print(self.ui_border_top, end="")
            print("\r")
        for row in self._matrix[row_min_bound:row_max_bound]:
            if column_min_bound == 0:
                print(self.ui_border_left, end="")
            for y in row[column_min_bound:column_max_bound]:
                if isinstance(
                        y,
                        BoardItemVoid) and y.model != self.ui_board_void_cell:
                    y.model = self.ui_board_void_cell
                print(y, end="")
            if column_max_bound >= self.size[0]:
                print(self.ui_border_right, end="")
            print("\r")
        if row_max_bound >= self.size[1]:
            bb_size = column_radius * 2
            if bb_size >= self.size[0]:
                bb_size = self.size[0]
                if object.pos[1] - column_radius > 0:
                    bb_size = self.size[0] - (object.pos[1] - column_radius)
            print(self.ui_border_bottom * bb_size, end="")
            if column_min_bound <= 0 and column_max_bound >= self.size[0]:
                print(self.ui_border_bottom * 2, end="")
            elif column_min_bound <= 0 or column_max_bound >= self.size[0]:
                print(self.ui_border_bottom, end="")
            print("\r")