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
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