Пример #1
0
    def _generate_world(self):
        """
        Private method that handles the procedural generation of the world.
        It will generate several levels and the levels will be populated with Actors.
        :return: None
        """
        # Generate a town level
        level_name = "Town"
        level_difficulty = 1
        Utilities.message(
            "Creating level: " + level_name + '(difficulty:' +
            str(level_difficulty) + ')', "GENERATION")
        town = TownLevel(self, level_difficulty, level_name)
        self._levels.append(town)
        self._currentLevel = town

        # Add some dungeon levels underneath the town
        # Dungeon levels are connected sequentially
        prev_level = None
        for i in range(1, WORLD.DUNGEON_LEVELS + 1):
            prev_level = self.levels[i - 1]
            self._add_dungeon_level(i, [prev_level])

        # Add some cave levels
        # Caves are connected to town and to some other random level
        for i in range(1, WORLD.CAVE_LEVELS + 1):
            random_level = random.choice(self.levels)
            self._add_cave_level(2, [town, random_level])
Пример #2
0
 def _add_dungeon_level(self, difficulty, connected_levels):
     """
     Private method to add a dungeon level to the world.
     :param difficulty: Difficulty for the new dungeon level
     :param connected_levels: Levels to which the new dungeon level will be connected
     :return : None
     """
     level_name = 'Dungeon level ' + str(difficulty)
     Utilities.message(
         "Creating level: " + level_name + '(difficulty:' +
         str(difficulty) + ')', "GENERATION")
     dungeon_level = DungeonLevel(self, difficulty, level_name)
     self._levels.append(dungeon_level)
     for lvl in connected_levels:
         # Add portal in previous level to current level
         down_portal = Portal(
             '>', 'stairs down',
             'You follow the stairs down, looking for more adventure.')
         down_portal.sprite_id = SPRITES.STAIRS_DOWN
         down_portal.moveToLevel(lvl, lvl.getRandomEmptyTile())
         # Add portal in current level to previous level
         up_portal = Portal(
             '<', 'stairs up',
             'You follow the stairs up, hoping to find the exit.')
         up_portal.sprite_id = SPRITES.STAIRS_UP
         up_portal.moveToLevel(dungeon_level,
                               dungeon_level.getRandomEmptyTile())
         # Connect the two portals
         down_portal.connectTo(up_portal)
Пример #3
0
    def _add_cave_level(self, difficulty, connected_levels):
        """
        Private method to add a cave level to the world.
        :param difficulty: Difficulty for the new cave level
        :param connected_levels: Levels to which the new cave level will be connected
        :return : None
        """
        level_name = 'Cave of the Cannibal'
        Utilities.message(
            "Creating level: " + level_name + '(difficulty:' +
            str(difficulty) + ')', "GENERATION")
        cave_level = CaveLevel(self, difficulty, level_name)
        self._levels.append(cave_level)

        # For each connected level
        for lvl in connected_levels:
            # create a portal in the connected level that leads to the new cave
            pit_message = 'You jump into the pit. As you fall deeper and deeper, you realize you didn\'t ' \
                      'think about how to get back out afterward...'
            down_portal = Portal('>', 'Pit', pit_message)
            down_portal.moveToLevel(lvl, lvl.getRandomEmptyTile())
            # create a portal in the new cave that leads back
            up_portal = Portal(
                '<', 'Opening above',
                'After great difficulties you manage to get out of the pit.')
            up_portal.moveToLevel(cave_level, cave_level.getRandomEmptyTile())
            # connect the two portals
            down_portal.connectTo(up_portal)
Пример #4
0
 def __getattr__(self, attribute):
     """
     Generic getter that serves up the json attributes as if it were attributes of this object.
     :param attribute: attribute name
     :return: attribute value from json definition.
     """
     try:
         return self.json[attribute]
     except KeyError as e:
         Utilities.message("ERROR: Requested attribute " + attribute + "is not present in json.", "NETWORK")
         raise e
Пример #5
0
 def receive_from_server(self):
     message = self.receive()
     if message is not None:
         Utilities.message("Received: " + str(message), "NETWORK")
         for header, json in message.items():
             if header == "Player":
                 self._player = Proxy(json)
             elif header == "Level":
                 self._current_level = Proxy(json)
             elif header == "Message":
                 # Write directly to messageBuffer, using message() would bounce loop the message back to server.
                 Utilities.messageBuffer.append(json["text"])
             else:
                 Utilities.message("WARNING: Missing implementation for header " + header, "NETWORK")
Пример #6
0
 def updateFieldOfView(self, x, y):
     """
     Update the map tiles with what is in field of view, marking
     those as explored.
     """
     view_range = self.range_of_view
     for tx, ty in self.each_map_position:
         tile = self.tiles[tx][ty]
         dist = Utilities.distance_between_points(x, y, tx, ty)
         visible = dist <= view_range
         line_of_sight = Utilities.line_of_sight(
             self.solidTileMatrix, x, y, tx, ty)
         if visible and line_of_sight:
             tile.inView = True
             tile.explored = True
         else:
             tile.inView = False
         # set all actors as in view too
         for actor in tile.actors:
             actor.inView = visible and line_of_sight
Пример #7
0
    def __init__(self):
        """
        Constructor to create a new world
        :return : World object
        """
        # Initialize class variables
        self._players = []
        self._levels = []
        self._world_time = 0  # Running total of game time (in milliseconds)
        self._tick_time = 0  # Time spent in the current tick (in milliseconds)
        self._tick_speed = GAME.SPEED  # Speed of game ticks in milliseconds (how fast the game moves)

        # Initialize libraries
        self._monsterLibrary = MonsterLibrary()
        self._itemLibrary = ItemLibrary()

        # Clean up
        Utilities.reset_utility_queues()

        # Procedural generation of the world
        self._generate_world()
Пример #8
0
    def new_player(self):
        """
        Adds a new player to the world.
        :return : Player
        """
        player = Player()
        self.players.append(player)
        first_level = self.levels[0]
        player.moveToLevel(first_level, first_level.getRandomEmptyTile())

        # Starting gear
        potion = self.item_library.create_item("healingpotion")
        player.addItem(potion)
        potion = self.item_library.create_item("healingpotion")
        player.addItem(potion)

        # TODO: multiplayer - move FOV code into player (it will be different for every player)
        first_level.map.updateFieldOfView(player.tile.x, player.tile.y)

        # Quick start
        if GAME.QUICK_START:
            town = self.levels[0]
            # Group portals together
            i = 1
            for portal in town.portals:
                if portal.destinationPortal.level not in town.subLevels:
                    tile = town.map.tiles[1][i]
                    i += 1
                    portal.moveToTile(tile)
            # Move player close to portals
            tile = town.map.tiles[len(self.players) + 1][1]
            player.moveToTile(tile)
            # Provide more starting gear
            scroll = self.item_library.create_item("firenova", "double")
            player.addItem(scroll)
            scroll = self.item_library.create_item("tremor")
            player.addItem(scroll)
            potion = self.item_library.create_item("healingvial", "exquisite")
            player.addItem(potion)
            cloak = self.item_library.create_item("cloak")
            player.addItem(cloak)
            scroll = self.item_library.create_item("fireball")
            player.addItem(scroll)
            scroll = self.item_library.create_item("confuse")
            player.addItem(scroll)
            scroll = self.item_library.create_item("lightning")
            player.addItem(scroll)
            # Add a chest with extra gear
            chest = Chest()
            tile = town.map.tiles[len(self.players) + 1][2]
            chest.moveToTile(tile)
            for i in range(1, 9):
                item = self.item_library.get_random_item(i)
                chest.inventory.add(item)

        # Send welcome message to the player
        Utilities.message(
            'You are ' + player.name +
            ', a young and fearless adventurer. It is time to begin your ' +
            'legendary and without doubt heroic expedition into the ' +
            'unknown. Good luck!', "GAME")
        return player
Пример #9
0
    def generate_map(self):
        """
        generate a randomized dungeon map with a minimum of two rooms
        """
        # Clear existing rooms
        self.clear_rooms()

        # Constants used to generate map
        room_max_size = DUNGEON.ROOM_MAX_SIZE
        room_min_size = DUNGEON.ROOM_MIN_SIZE
        max_rooms = DUNGEON.MAX_ROOMS

        if self.width < room_max_size or self.height < room_max_size:
            raise Utilities.GameError("Requested size is too small, can't generate dungeon.")

        # Create a new map with empty tiles
        self._tiles = [[Tile(self, x, y) for y in range(self. height)] for x in range(self. width)]

        # Block all tiles
        for y in range(self.height):
            for x in range(self.width):
                t = self.tiles[x][y]
                t.blocked = True
                t.blockSight = True
                t.color = DUNGEON.COLOR_WALL
                t.material = MaterialType.STONE

        # Cut out rooms (minimum 2)
        rooms_to_generate = random.randint(2, max_rooms)
        while len(self.rooms) < rooms_to_generate:
            # Random width and height
            w = random.randrange(room_min_size, room_max_size)
            h = random.randrange(room_min_size, room_max_size)
            # Random position without going out of the boundaries of the map
            x = random.randrange(0, self.width - w - 1)
            y = random.randrange(0, self.height - h - 1)
            # Create a new room
            new_room = Room(self, x, y, w, h)

            # Abort if room intersects with existing room
            intersects = False
            for other_room in self.rooms:
                if new_room.intersect(other_room):
                    intersects = True
                    break
            if intersects is True:
                break

            # Cut it out of the map, go through the tiles in the room and make them passable
            for x in range(new_room.x1 + 1, new_room.x2):
                for y in range(new_room.y1 + 1, new_room.y2):
                    self.tiles[x][y].blocked = False
                    self.tiles[x][y].blockSight = False
                    self.tiles[x][y].color = DUNGEON.COLOR_FLOOR
                    self.tiles[x][y].material = MaterialType.DIRT

            # Create corridor towards previous room
            (new_x, new_y) = new_room.center
            # All rooms, after the first room, connect to the previous room
            if len(self.rooms) > 0:
                # Center coordinates of previous room
                prev_room = self.rooms[len(self.rooms) - 1]
                (prev_x, prev_y) = prev_room.center
                # Create a corridor: First move horizontally, then vertically
                self._create_horizontal_tunnel(prev_x, new_x, new_y)
                self._create_vertical_tunnel(prev_y, new_y, prev_x)

            # Finally, append the new room to the list
            self.rooms.append(new_room)

        # Set entry and exit tiles
        (entryX, entryY) = self.rooms[0].center
        self._entryTile = self._tiles[entryX][entryY]
        (exitX, exitY) = self.rooms[len(self.rooms) - 1].center
        self._exitTile = self._tiles[exitX][exitY]

        # Assign texture ID based on texture hash
        # The assignments below are calculated using a helper spreadsheet
        for x in range(self.width):
            for y in range(self.height):
                t = self.tiles[x][y]
                h = t.texture_hash
                # Map hash to a tileset ID
                if not self.tiles[x][y].blockSight:
                    t.texture_id = SPRITES.TILE_EMPTY
                    if random.random() < 0.05:
                        t.texture_id = SPRITES.TILE_SUBTILES
                    if random.random() < 0.05:
                        t.texture_id = SPRITES.TILE_LINED
                    if random.random() < 0.05:
                        t.texture_id = SPRITES.TILE_CRACKED
                elif h in [16, 511]:
                    t.texture_id = SPRITES.PILLAR
                elif h in [24, 25, 88, 89]:
                    t.texture_id = SPRITES.NS_WALL_W_CAP
                elif h in [56, 57, 60, 63, 120, 121, 124, 125, 127, 312, 313, 316, 317, 319, 377, 380, 381, 383, 504,
                           505, 508, 509]:
                    t.texture_id = SPRITES.NS_WALL
                elif h in [48, 52, 304, 308]:
                    t.texture_id = SPRITES.NS_WALL_E_CAP
                elif h in [18, 19, 22, 23]:
                    t.texture_id = SPRITES.EW_WALL_N_CAP
                elif h in [146, 147, 150, 151, 210, 214, 215, 219, 223, 402, 403, 407, 438, 439, 466, 467, 470, 471,
                           475, 479, 502, 503]:
                    t.texture_id = SPRITES.EW_WALL
                elif h in [144, 208, 400, 464]:
                    t.texture_id = SPRITES.EW_WALL_S_CAP
                elif h in [26, 27, 30, 31, 90, 91, 94, 95, 283, 510]:
                    t.texture_id = SPRITES.NW_CORNER
                elif h in [50, 51, 54, 55, 118, 306, 307, 310, 311, 507]:
                    t.texture_id = SPRITES.NE_CORNER
                elif h in [152, 153, 216, 217, 220, 408, 409, 447, 472, 473]:
                    t.texture_id = SPRITES.SW_CORNER
                elif h in [176, 180, 240, 244, 255, 432, 433, 436, 496, 500]:
                    t.texture_id = SPRITES.SE_CORNER
                elif h in [186, 187, 190, 250, 254, 442, 443]:
                    t.texture_id = SPRITES.CROSS
                elif h in [58, 59, 62, 122, 123, 126, 314, 315, 318, 378, 379, 382, 506]:
                    t.texture_id = SPRITES.T_SOUTH
                elif h in [178, 179, 182, 183, 242, 243, 246, 247, 251, 434, 435, 498, 499]:
                    t.texture_id = SPRITES.T_WEST
                elif h in [154, 155, 158, 159, 218, 222, 410, 411, 414, 415, 446, 474, 478]:
                    t.texture_id = SPRITES.T_EAST
                elif h in [184, 185, 188, 189, 191, 248, 249, 252, 253, 440, 441, 444, 445]:
                    t.texture_id = SPRITES.T_NORTH
                else:
                    print("WARNING: Unknown hash " + str(h) + ", can't assign tileset ID.")
Пример #10
0
 def generate_map(self):
     """
     Place holder function, subclass must provide actual implementation.
     """
     raise Utilities.GameError("Can't use Map class directly, use a subclass!")