コード例 #1
0
ファイル: procgen.py プロジェクト: hagukin/Geophyte
def generate_stair(
    dungeon: GameMap,
    rooms: List,
    stair_type: str = "pair", # pair : ascending, descending stair pair / up : ascending stair / down : descending stair
) -> None:
    """Generate a given type of stair."""

    # Log
    print("Generating Staircases...")

    ascend_tile = None
    descend_tile = None

    if stair_type == "pair":
        while True:
            # Select random tile from a random room and check for conditions
            while True:
                ascend_room = random.choice(rooms)
                ascend_tile = random.choice(ascend_room.inner_tiles)
                if dungeon.get_any_entity_at_location(ascend_tile[0], ascend_tile[1]) or not dungeon.tiles[ascend_tile]["walkable"] or not dungeon.tiles[ascend_tile]["safe_to_walk"]:
                    continue
                else:
                    break
            while True:
                descend_room = random.choice(rooms)
                descend_tile = random.choice(descend_room.inner_tiles)
                if dungeon.get_any_entity_at_location(descend_tile[0], descend_tile[1]) or not dungeon.tiles[descend_tile]["walkable"] or not dungeon.tiles[descend_tile]["safe_to_walk"]:
                    continue
                else:
                    break

            # Check if both stairs are connected to one another
            connected = False
            cost = np.array(dungeon.tiles["walkable"], dtype=np.int8) # tunnelmap은 void도 경로에 포함시키기 때문에 tunnelmap대신 새로운 cost 그리드를 생성해 pathfinder에 전달한다.

            # Avoid dangerous tiles
            dangerous_coordinates = zip(*np.where(dungeon.tiles["safe_to_walk"][:,:] == False))
            for cor in dangerous_coordinates:
                cost[cor] = 0
            
            for x, y in path_between(cost, ascend_tile, descend_tile):
                if x != descend_tile[0] or y != descend_tile[1]:
                    continue
                else:
                    connected = True
                    break

            if connected:
                break
            else:
                print("ERROR : Path not found, Regenerating Staircases...") # 새로운 길을 찾는다.
                continue
    elif stair_type == "up": # Generate single stair
        while True:
            ascend_room = random.choice(rooms)
            ascend_tile = random.choice(ascend_room.inner_tiles)
            if dungeon.get_any_entity_at_location(ascend_tile[0], ascend_tile[1]) or not dungeon.tiles[ascend_tile]["walkable"] or not dungeon.tiles[ascend_tile]["safe_to_walk"]:
                continue
            else:
                break
    elif stair_type == "down": # Generate single stair
        while True:
            descend_room = random.choice(rooms)
            descend_tile = random.choice(descend_room.inner_tiles)
            if dungeon.get_any_entity_at_location(descend_tile[0], descend_tile[1]) or not dungeon.tiles[descend_tile]["walkable"] or not dungeon.tiles[descend_tile]["safe_to_walk"]:
                continue
            else:
                break

    if ascend_tile:
        dungeon.tilemap[ascend_tile] = TilemapOrder.ASCEND_STAIR.value
        dungeon.tiles[ascend_tile] = dungeon.tileset["t_ascending_stair"]()
        dungeon.ascend_loc = ascend_tile
    if descend_tile:
        dungeon.tilemap[descend_tile] = TilemapOrder.DESCEND_STAIR.value
        dungeon.tiles[descend_tile] = dungeon.tileset["t_descending_stair"]()
        dungeon.descend_loc = descend_tile
    
    # If depth 1, spawn player
    if dungeon.engine.depth == 1:
        dungeon.engine.player.gamemap = dungeon
        dungeon.engine.player.place(ascend_tile[0], ascend_tile[1])

    return None
コード例 #2
0
ファイル: procgen.py プロジェクト: hagukin/Geophyte
def generate_rooms(
    dungeon: GameMap,
    rooms: List,
    max_rooms: int,
    engine: Engine,
) -> None:
    """Generate rooms, stairs, and doors."""
    # Log
    print("Generating Dungeon Rooms...")

    # Generate rooms
    for r in range(max_rooms):
        # Choose the terrain of the room
        room_terrain = choose_terrain(terrain_lists=terrain_factories.terrain_lists)

        # Choose the size of the room
        room_width = random.randint(room_terrain.min_width, room_terrain.max_width)
        room_height = random.randint(room_terrain.min_height, room_terrain.max_height)

        # Choose the location of the room
        # NOTE: There should be at least 4 tiles of free space each sides, so that every room can be connected.
        # It is recommeded to keep the free space as minimum as possible.
        x = random.randint(3, dungeon.width - room_width - 4)
        y = random.randint(3, dungeon.height - room_height - 4)

        # Choose the shape of the room
        shape = list(room_terrain.shape.keys())
        shape_weights = list(room_terrain.shape.values())
        room_shape = random.choices(population=shape, weights=shape_weights, cum_weights=None, k=1)[0]
        
        # Actual generation of the room
        if room_shape == "rectangular":
            new_room = RectangularRoom(x, y, room_width, room_height, parent=dungeon, terrain=room_terrain)
        elif room_shape == "circular":
            new_room = CircularRoom(x, y, room_width, room_height, parent=dungeon, terrain=room_terrain)
        elif room_shape == "perpendicular":
            new_room = PerpendicularRoom(x, y, room_width, room_height, parent=dungeon, terrain=room_terrain)
        else:
            new_room = RectangularRoom(x, y, room_width, room_height, parent=dungeon, terrain=room_terrain)
            print("ERROR : PROCGEN - GENERATE_ROOMS - FAILED TO SET THE ROOM SHAPE")

        # Run through the other rooms and see if they intersect with this one.
        if any(new_room.intersects(other_room) for other_room in rooms):
            continue  # This room intersects, so go to the next attempt.
        # If there are no intersections then the room is valid.

        # Fill room's outer area on tilemap.
        for outer_slice in new_room.outer:
            dungeon.tilemap[outer_slice] = TilemapOrder.ROOM_WALL.value
            dungeon.tunnelmap[outer_slice] = False

        # Dig out this rooms inner area.
        for inner_slice in new_room.inner:
            dungeon.tiles[inner_slice] = dungeon.tileset["t_floor"]()
            dungeon.tilemap[inner_slice] = TilemapOrder.ROOM_INNER.value
            dungeon.tunnelmap[inner_slice] = True

        # choose the direction of the door
        doordir = []
        tempdir = ["u","d","l","r"]
        random.shuffle(tempdir)
        door_num = random.choices(new_room.terrain.door_num_range, new_room.terrain.door_num_weight, k=1)[0]
        for i in range(door_num):
            doordir.append(tempdir[i%4]) # udlr 1234

        # generate doors and door convexes
        if new_room.terrain.has_door:
            for direction in doordir:
                if direction == "u":
                    for door_up_slice in new_room.door_up:
                        # generate door convex
                        dungeon.tilemap[door_up_slice] = TilemapOrder.DOOR_CONVEX.value
                        dungeon.tunnelmap[door_up_slice] = True
                        dungeon.tiles[door_up_slice] = dungeon.tileset["t_floor"]()
                        # generate door
                        door_loc = door_up_slice[0].start, door_up_slice[1].start + 1
                        new_room.doors.append(door_loc)
                        dungeon.tilemap[door_loc] = TilemapOrder.DOOR.value
                        dungeon.tunnelmap[door_loc] = True
                        dungeon.tiles[door_loc] = dungeon.tileset["t_floor"]()
                        dungeon.tiles[door_up_slice] = dungeon.tileset["t_floor"]()
                        # spawn door unless there is nothing on the location
                        if not dungeon.get_any_entity_at_location(door_loc[0], door_loc[1]):
                            semiactor_factories.closed_door.spawn(gamemap=dungeon, x=door_loc[0], y=door_loc[1], lifetime=-1)
                elif direction == "d":
                    for door_down_slice in new_room.door_down:
                        # generate door convex
                        dungeon.tilemap[door_down_slice] = TilemapOrder.DOOR_CONVEX.value
                        dungeon.tunnelmap[door_down_slice] = True
                        dungeon.tiles[door_down_slice] = dungeon.tileset["t_floor"]()
                        # generate door
                        door_loc = door_down_slice[0].start, door_down_slice[1].start - 1
                        new_room.doors.append(door_loc)
                        dungeon.tilemap[door_loc] = TilemapOrder.DOOR.value
                        dungeon.tunnelmap[door_loc] = True
                        dungeon.tiles[door_loc] = dungeon.tileset["t_floor"]()
                        dungeon.tiles[door_down_slice] = dungeon.tileset["t_floor"]()
                        # spawn door unless there is nothing on the location
                        if not dungeon.get_any_entity_at_location(door_loc[0], door_loc[1]):
                            semiactor_factories.closed_door.spawn(gamemap=dungeon, x=door_loc[0], y=door_loc[1], lifetime=-1)
                elif direction == "l":
                    for door_left_slice in new_room.door_left:
                        # generate door convex
                        dungeon.tilemap[door_left_slice] = TilemapOrder.DOOR_CONVEX.value
                        dungeon.tunnelmap[door_left_slice] = True
                        dungeon.tiles[door_left_slice] = dungeon.tileset["t_floor"]()
                        # generate door
                        door_loc = door_left_slice[0].start + 1, door_left_slice[1].start
                        new_room.doors.append(door_loc)
                        dungeon.tilemap[door_loc] = TilemapOrder.DOOR.value
                        dungeon.tunnelmap[door_loc] = True
                        dungeon.tiles[door_loc] = dungeon.tileset["t_floor"]()
                        dungeon.tiles[door_left_slice] = dungeon.tileset["t_floor"]()
                        # spawn door unless there is nothing on the location
                        if not dungeon.get_any_entity_at_location(door_loc[0], door_loc[1]):
                            semiactor_factories.closed_door.spawn(gamemap=dungeon, x=door_loc[0], y=door_loc[1], lifetime=-1)
                elif direction == "r":
                    for door_right_slice in new_room.door_right:
                        # generate door convex
                        dungeon.tilemap[door_right_slice] = TilemapOrder.DOOR_CONVEX.value
                        dungeon.tunnelmap[door_right_slice] = True
                        dungeon.tiles[door_right_slice] = dungeon.tileset["t_floor"]()
                        # generate door
                        door_loc = door_right_slice[0].start - 1, door_right_slice[1].start
                        new_room.doors.append(door_loc)
                        dungeon.tilemap[door_loc] = TilemapOrder.DOOR.value
                        dungeon.tunnelmap[door_loc] = True
                        dungeon.tiles[door_loc] = dungeon.tileset["t_floor"]()
                        dungeon.tiles[door_right_slice] = dungeon.tileset["t_floor"]()
                        # spawn door unless there is nothing on the location
                        if not dungeon.get_any_entity_at_location(door_loc[0], door_loc[1]):
                            semiactor_factories.closed_door.spawn(gamemap=dungeon, x=door_loc[0], y=door_loc[1], lifetime=-1)

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

    # NOTE: You can save the room data on GameMap by adding something here like "dungeon.rooms = rooms"
    
    return dungeon, rooms