def make_corridor(dungeon, start_coords, end_coords): """ Modifies the dungeon given to construct a corridor. """ # Identify the dimension over which most of the travel is happening, and # allow the rest of the code to work in a dimension-agnostic manner. if (abs(end_coords[0] - start_coords[0]) > abs(end_coords[1] - start_coords[1])): major_dimension = 0 minor_dimension = 1 else: major_dimension = 1 minor_dimension = 0 if end_coords[major_dimension] - start_coords[major_dimension] >= 0: first_coords = start_coords last_coords = end_coords else: first_coords = end_coords last_coords = start_coords # The kink is the major dimension coordinate at which the corridor starts # moving on the minor dimension, not the major dimension. kink_major_coordinate = rng.randInt(first_coords[major_dimension], last_coords[major_dimension]) for major_coordinate in range(first_coords[major_dimension], kink_major_coordinate + 1): current_coords = [0, 0] current_coords[major_dimension] = major_coordinate current_coords[minor_dimension] = first_coords[minor_dimension] current_coords = tuple(current_coords) if dungeon[current_coords] == config.TRANSPARENT_GLYPH: dungeon[current_coords] = level.CORRIDOR_GLYPH if first_coords[minor_dimension] <= last_coords[minor_dimension]: minor_coordinate_range = range(first_coords[minor_dimension], last_coords[minor_dimension] + 1) else: minor_coordinate_range = range(last_coords[minor_dimension], first_coords[minor_dimension] + 1) for minor_coordinate in minor_coordinate_range: current_coords = [0, 0] current_coords[major_dimension] = kink_major_coordinate current_coords[minor_dimension] = minor_coordinate current_coords = tuple(current_coords) if dungeon[current_coords] == config.TRANSPARENT_GLYPH: dungeon[current_coords] = level.CORRIDOR_GLYPH for major_coordinate in range(kink_major_coordinate, last_coords[major_dimension] + 1): current_coords = [0, 0] current_coords[major_dimension] = major_coordinate current_coords[minor_dimension] = last_coords[minor_dimension] current_coords = tuple(current_coords) if dungeon[current_coords] == config.TRANSPARENT_GLYPH: dungeon[current_coords] = level.CORRIDOR_GLYPH
def choose_room_corners(possible_nw, possible_se): """ Generate possible northwest and southeast corners for a room. possible_nw: the upper-left-most possible square in which the room can be. possible_se: the lower-right-most possible square in which the room can be. """ if (possible_nw[0] + MIN_ROOM_SIZE > possible_se[0] or possible_nw[1] + MIN_ROOM_SIZE > possible_se[1]): raise ValueError("Not enough room for a room in %s, %s." % (possible_nw, possible_se)) while True: room_nw = (rng.randInt(possible_nw[0], possible_se[0]), rng.randInt(possible_nw[1], possible_se[1])) room_se = (room_nw[0] + rng.randInt(MIN_ROOM_SIZE, MAX_ROOM_SIZE), (room_nw[1] + rng.randInt(MIN_ROOM_SIZE, MAX_ROOM_SIZE))) # check validity of room dimensions if room_se[0] <= possible_se[0] and room_se[1] <= possible_se[1]: return (room_nw, room_se)
def getRandomMonster(self): """ Return a random monster created on this floor. """ if self.total == 0 or len(self.rarities) == 0: return self.monster_factory.getBuggyMonster() random_number = rng.randInt(0, self.total - 1) for r in self.rarities: random_number -= r[0] if random_number < 0: return self.monster_factory.create(r[1])
def getRandomMonster(self, dlvl): """ Get a duplicate of a random monster in the MonsterFactory. """ monster_selection_container, total = self.getMonsterSelection(dlvl) if total == 0 or len(monster_selection_container) == 0: return self.getBuggyMonster() random_number = rng.randInt(0, total - 1) for i in monster_selection_container: random_number -= i[0] if random_number < 0: return duplicate(i[1])
def randomDungeon(): """ Gets a random dungeon, using a very simple room/corridor model. The room/corridor model used is similar to that of Rogue; the map is divided into nine sectors, each of which is randomly called a room, a corridor, or empty. Once this is done, rooms and corridors are connected to adjacent rooms and corridors. This is coded terribly because it will be replaced someday. """ map_dimensions = (60, 60) map_nwcorner = (10, 10) sector_size = (12, 12) sector_nwcorners = {} for x in range(0, 3): for y in range(0, 3): sector_nwcorners[(x, y)] = ( map_nwcorner[0] + sector_size[0] * x, map_nwcorner[1] + sector_size[1] * y ) sector_types = {} for x in range(0, 3): for y in range(0, 3): percent = rng.randInt(1, 100) if percent <= 60: sector_types[(x, y)] = 1 # it's a room! elif percent <= 75: sector_types[(x, y)] = 2 # it's a corridor! else: sector_types[(x, y)] = 0 # it's empty! room_nwcoords = {} room_secoords = {} for sector_coords in sector_types.keys(): if sector_types[sector_coords] == 1: room_created = False sector_nw = sector_nwcorners[sector_coords] sector_se = (sector_nw[0] + sector_size[0] - 1, sector_nw[1] + sector_size[1] - 1) while not room_created: room_nw = (rng.randInt(sector_nw[0], sector_se[0]), rng.randInt(sector_nw[1], sector_se[1])) room_se = (room_nw[0] + rng.randInt(3, 8), room_nw[1] + rng.randInt(3, 8)) # check validity of room dimensions if room_se[0] <= sector_se[0] and room_se[1] <= sector_se[1]: room_nwcoords[sector_coords] = room_nw room_secoords[sector_coords] = room_se room_created = True elif sector_types[sector_coords] == 2: # A corridor is currently implemented as just a 1-space room. corridor_coords = (rng.randInt(sector_nwcorners[sector_coords][0], sector_nwcorners[sector_coords][0] + sector_size[0] - 1,), rng.randInt(sector_nwcorners[sector_coords][1], sector_nwcorners[sector_coords][1] + sector_size[1] - 1,)) room_nwcoords[sector_coords] = corridor_coords room_secoords[sector_coords] = corridor_coords # Check whether everywhere is accessible; if not, do a redo. sector_is_accessible = {} for x in range(3): for y in range(3): sector_is_accessible[(x, y)] = False for coord in ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)): if True not in sector_is_accessible.values() and sector_types[coord] != 0: sector_is_accessible[coord] = True if sector_is_accessible[coord] == True and sector_types[coord] != 0: for coord_adjustment in ((1, 0), (0, 1), (-1, 0), (0, -1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] >= 0 and adjacent_coord[0] < 3 and adjacent_coord[1] >= 0 and adjacent_coord[1] < 3): sector_is_accessible[adjacent_coord] = True for accessible in sector_is_accessible.items(): if sector_types[accessible[0]] != 0 and not accessible[1]: # Oops. Give up and try again. return randomDungeon() entrance_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] == 1]) exit_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] == 1]) entrance_coords = rng.randomPointInRect(room_nwcoords[entrance_sector], room_secoords[entrance_sector]) exit_coords = rng.randomPointInRect(room_nwcoords[exit_sector], room_secoords[exit_sector]) ret_dungeon = level.empty_dungeon(map_dimensions) for coord in ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)): if sector_types[coord] != 0: for x in range(room_nwcoords[coord][0], room_secoords[coord][0] + 1): for y in range(room_nwcoords[coord][1], room_secoords[coord][1] + 1): if sector_types[coord] == 1: ret_dungeon[(x, y)] = level.ROOM_INTERIOR_GLYPH else: ret_dungeon[(x, y)] = level.CORRIDOR_GLYPH for coord_adjustment in ((1, 0), (0, 1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] < 3 and adjacent_coord[1] < 3 and sector_types[adjacent_coord] != 0): make_corridor(ret_dungeon, rng.randomPointInRect(room_nwcoords[coord], room_secoords[coord]), rng.randomPointInRect(room_nwcoords[adjacent_coord], room_secoords[adjacent_coord])) ret_dungeon[entrance_coords] = level.UPSTAIRS_GLYPH ret_dungeon[exit_coords] = level.DOWNSTAIRS_GLYPH return ret_dungeon
def randomDungeon(): """ Gets a random dungeon, using a very simple room/corridor model. The room/corridor model used is similar to that of Rogue; the map is divided into nine sectors, each of which is randomly called a room, a corridor, or empty. Once this is done, rooms and corridors are connected to adjacent rooms and corridors. This is coded terribly because it will be replaced someday. """ map_dimensions = (MAX_SIZE_X, MAX_SIZE_Y) map_nwcorner = (NW_CORNER_X, NW_CORNER_Y) sector_size = (SECTOR_SIZE_X, SECTOR_SIZE_Y) sector_list = [(x, y) for x in range(NUM_SECTORS_X) for y in range(NUM_SECTORS_Y)] sector_nwcorners = {} for x in range(NUM_SECTORS_X): for y in range(NUM_SECTORS_Y): sector_nwcorners[(x, y)] = ( map_nwcorner[0] + sector_size[0] * x, map_nwcorner[1] + sector_size[1] * y ) sector_types = {} for x in range(NUM_SECTORS_X): for y in range(NUM_SECTORS_Y): percent = rng.randInt(1, 100) if percent <= 25: sector_types[(x, y)] = st.ROOM elif percent <= 60: sector_types[(x, y)] = st.DOUBLE_ROOM elif percent <= 75: sector_types[(x, y)] = st.CORRIDOR else: sector_types[(x, y)] = st.EMPTY room_nwcoords = {} room_secoords = {} for sector_coords in sector_types.keys(): sector_nw = sector_nwcorners[sector_coords] sector_se = (sector_nw[0] + sector_size[0] - 1, sector_nw[1] + sector_size[1] - 1) if sector_types[sector_coords] in (st.ROOM, st.DOUBLE_ROOM): (room_nwcoords[sector_coords], room_secoords[sector_coords]) \ = choose_room_corners(sector_nw, sector_se) elif sector_types[sector_coords] == st.CORRIDOR: # A corridor is currently implemented as just a 1-space room. corridor_coords = (rng.randInt(sector_nw[0], sector_se[0]), rng.randInt(sector_nw[1], sector_se[1])) room_nwcoords[sector_coords] = corridor_coords room_secoords[sector_coords] = corridor_coords # Check whether everywhere is accessible; if not, do a redo. sector_is_accessible = {} for x in range(NUM_SECTORS_X): for y in range(NUM_SECTORS_Y): sector_is_accessible[(x, y)] = False for coord in sector_list: if True not in sector_is_accessible.values() \ and sector_types[coord] != 0: sector_is_accessible[coord] = True if sector_is_accessible[coord] == True \ and sector_types[coord] != st.EMPTY: for coord_adjustment in ((1, 0), (0, 1), (-1, 0), (0, -1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] >= 0 and adjacent_coord[0] < NUM_SECTORS_X and adjacent_coord[1] >= 0 and adjacent_coord[1] < NUM_SECTORS_Y): sector_is_accessible[adjacent_coord] = True for accessible in sector_is_accessible.items(): if sector_types[accessible[0]] != 0 and not accessible[1]: # Oops. Give up and try again. return randomDungeon() entrance_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] in (st.ROOM, st.DOUBLE_ROOM)]) exit_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] in (st.ROOM, st.DOUBLE_ROOM)]) entrance_coords = rng.randomPointInRect(room_nwcoords[entrance_sector], room_secoords[entrance_sector]) exit_coords = rng.randomPointInRect(room_nwcoords[exit_sector], room_secoords[exit_sector]) ret_dungeon = level.empty_dungeon(map_dimensions) for coord in sector_list: if sector_types[coord] != st.EMPTY: if sector_types[coord] == st.CORRIDOR: fill_glyph = level.CORRIDOR_GLYPH else: fill_glyph = level.ROOM_INTERIOR_GLYPH arrays.fill_rect(ret_dungeon, room_nwcoords[coord], room_secoords[coord], fill_glyph) # If there is another room to the south or east, make a corridor from this room # to it. for coord_adjustment in ((1, 0), (0, 1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] < NUM_SECTORS_X and adjacent_coord[1] < NUM_SECTORS_Y and sector_types[adjacent_coord] != 0): make_corridor(ret_dungeon, rng.randomPointInRect(room_nwcoords[coord], room_secoords[coord]), rng.randomPointInRect(room_nwcoords[adjacent_coord], room_secoords[adjacent_coord])) # If the room type is DOUBLE_ROOM, bolt on a second room to the first. # This room can overflow! That is intentional. if sector_types[coord] == st.DOUBLE_ROOM: max_second_se = (room_secoords[coord][0] + MIN_ROOM_SIZE, room_secoords[coord][1] + MIN_ROOM_SIZE) (second_nw, second_se) = choose_room_corners( room_nwcoords[coord], max_second_se) arrays.fill_rect(ret_dungeon, second_nw, second_se, level.ROOM_INTERIOR_GLYPH) ret_dungeon[entrance_coords] = level.UPSTAIRS_GLYPH ret_dungeon[exit_coords] = level.DOWNSTAIRS_GLYPH return ret_dungeon