def _link_up_stairs(new_map, old_map, old_quarry_stairs): old_quarry_stairs[1].dest_position = algebra.Location( new_map.width / 2, new_map.height / 2) old_quarry_stairs[ 0].dest_position = old_quarry_stairs[1].dest_position + MINE_SCALE * ( old_quarry_stairs[0].pos - old_quarry_stairs[1].pos) old_quarry_stairs[ 2].dest_position = old_quarry_stairs[1].dest_position + MINE_SCALE * ( old_quarry_stairs[2].pos - old_quarry_stairs[1].pos) map_inset = algebra.Rect(10, 10, new_map.width - 20, new_map.height - 20) old_quarry_stairs[0].dest_position.bound(map_inset) old_quarry_stairs[2].dest_position.bound(map_inset) # print('Map is ' + str(new_map.width) + ' x ' + str(new_map.height)) # print('Stairs come from ', [i.pos for i in old_quarry_stairs]) # print('Stairs to mines connect to ', [i.dest_position for i in old_quarry_stairs]) for i in range(3): old_quarry_stairs[i].destination = new_map stairs = Object(old_quarry_stairs[i].dest_position, '>', 'mine exit', libtcod.white, always_visible=True) stairs.destination = old_map stairs.dest_position = old_quarry_stairs[i].pos new_map.objects.insert(0, stairs) new_map.portals.insert(0, stairs)
def _build_map(new_map): new_map.rng = libtcod.random_new_from_seed(new_map.random_seed) new_map.spare_terrain = copy.deepcopy( new_map.terrain ) # [[0 for y in range(new_map.height)] for x in range(new_map.width)] dig_ca_region(new_map, algebra.Rect(0, 0, new_map.width, new_map.height), 4, 3) center = algebra.Location(new_map.width / 2, new_map.height / 2) stair_loc = _probe_for_stair(new_map, range(new_map.width - 2, center.x, -1), center.y) if not stair_loc: # Uh-oh; no guarantee of completion print('Recursing with unenterable map:') # _dump(new_map) new_map.random_seed = libtcod.random_save(new_map.rng) return _build_map(new_map) pool_x = new_map.width / 4 for x in range(pool_x - 6, pool_x + 7): for y in range(center.y - 6, center.y + 7): dx = x - pool_x dy = y - center.y if math.sqrt(dx**2 + dy**2) > 6: continue if new_map.terrain[x][y] == map.TERRAIN_WALL: new_map.terrain[x][y] = map.TERRAIN_GROUND new_map.pool_x = pool_x _scatter_ponds(new_map) # Can we reach from the stairs to the center of the pool? _floodfill(new_map, stair_loc.x, stair_loc.y, map.TERRAIN_GROUND, map.TERRAIN_FLOOR) if new_map.terrain[pool_x][center.y] != map.TERRAIN_FLOOR: # Uh-oh; no guarantee of completion print('Recursing with disconnected map:') # _dump(new_map) new_map.random_seed = libtcod.random_save(new_map.rng) return _build_map(new_map) # Close up any unconnected subcaves; flood any western bits for x in range(1, new_map.width - 1): for y in range(1, new_map.height - 1): if new_map.terrain[x][y] == map.TERRAIN_GROUND: new_map.terrain[x][y] = map.TERRAIN_WALL elif x < pool_x and new_map.terrain[x][y] == map.TERRAIN_FLOOR: new_map.terrain[x][y] = map.TERRAIN_WATER #for x in range(0, new_map.width): # new_map.terrain[x][0] = map.TERRAIN_WALL # new_map.terrain[x][new_map.height-1] = map.TERRAIN_WALL #for y in range(0, new_map.height): # new_map.terrain[0][y] = map.TERRAIN_WALL # new_map.terrain[new_map.width-1][y] = map.TERRAIN_WALL return stair_loc
def _dig_some_caves(new_map, old_quarry_stairs): new_map.spare_terrain = copy.deepcopy( new_map.terrain ) # [[0 for y in range(new_map.height)] for x in range(new_map.width)] new_map.cave_zones = [] x = new_map.rnd(3, old_quarry_stairs[1].dest_position.x / 2) w = new_map.rnd(20, old_quarry_stairs[1].dest_position.x - x - 3) if old_quarry_stairs[0].dest_position.y < old_quarry_stairs[ 1].dest_position.y: # staircase 0 in top left quadrant, put caves in bottom left quadrant y = new_map.rnd(old_quarry_stairs[1].dest_position.y + 3, old_quarry_stairs[1].dest_position.y * 3 / 2) h = new_map.rnd(20, new_map.height - y - 3) else: # staircase 0 in bottom left quadrant, put caves in top left quadrant y = new_map.rnd(3, old_quarry_stairs[1].dest_position.y / 2) h = new_map.rnd(20, old_quarry_stairs[1].dest_position.y - y - 3) target_zone = algebra.Rect(x, y, w, h) target_zone.x2 = min(target_zone.x2, new_map.width - 2) target_zone.y2 = min(target_zone.y2, new_map.height - 2) # print("Target zone 0 ", target_zone) ca_cartographer.dig_ca_region(new_map, target_zone, 4, 3) new_map.cave_zones.append(target_zone) x = new_map.rnd(old_quarry_stairs[1].dest_position.x + 3, old_quarry_stairs[1].dest_position.x * 3 / 2) w = new_map.rnd(20, new_map.width - x - 3) if old_quarry_stairs[2].dest_position.y < old_quarry_stairs[ 1].dest_position.y: y = new_map.rnd(old_quarry_stairs[1].dest_position.y + 3, old_quarry_stairs[1].dest_position.y * 3 / 2) h = new_map.rnd(20, new_map.height - y - 3) else: y = new_map.rnd(3, old_quarry_stairs[1].dest_position.y / 2) h = new_map.rnd(20, old_quarry_stairs[1].dest_position.y - y - 3) target_zone = algebra.Rect(x, y, w, h) target_zone.x2 = min(target_zone.x2, new_map.width - 2) target_zone.y2 = min(target_zone.y2, new_map.height - 2) # print("Target zone 1 ", target_zone) ca_cartographer.dig_ca_region(new_map, target_zone, 4, 3) new_map.cave_zones.append(target_zone)
def _consider_terminal_room(new_map, x, y): new_room = algebra.Rect(x - 2, y - 2, 4, 4) _create_room(new_map, new_room) count = len(new_map.rooms) new_map.rooms.append(new_room) new_map.room_entered.append(False) for ii in range(x - 2, x + 3): for jj in range(y - 2, y + 3): if (ii >= 0 and jj >= 0 and ii < new_map.width and jj < new_map.height): new_map.room[ii][jj] = count
def _place_random_creatures(new_map, player): start_region = new_map.region[player.pos.x][player.pos.y] terrain_chances = { 'lake': { None: 10 }, 'marsh': { None: 10, bestiary.swamp_goblin: 10 }, 'desert': { None: 20, bestiary.hyena_pair: 5, bestiary.gazelle: 10 }, 'scrub': { None: 20, bestiary.hyena: 2, bestiary.gazelle: 4, bestiary.deer: 4, bestiary.wolf: 2 }, 'forest': { None: 20, bestiary.deer: 10, bestiary.wolf_pair: 5, bestiary.bear: 3 }, 'rock': { None: 10, bestiary.snow_leopard: 1 }, 'ice': { None: 10, bestiary.snow_leopard: 1 } } for r in range(len(new_map.region_seeds)): if (r == start_region or (new_map.quarry_regions and r in new_map.quarry_regions)): continue fn = _random_choice(terrain_chances[new_map.region_terrain[r]]) if fn is not None: pos = algebra.Location(new_map.region_seeds[r][0], new_map.region_seeds[r][1]) while new_map.is_blocked_at(pos): pos += actions.random_direction() pos.bound( algebra.Rect(0, 0, new_map.width - 1, new_map.height - 1)) if new_map.caravanserai and new_map.caravanserai.bounds.contains( pos): continue # print('Creature in region ' + str(r) + ' at ' + str(pos.x) + ' ' + str(pos.y)) fn(new_map, pos, player)
def update_camera(player): """ Makes sure the player is roughly centered and that we're not trying to draw off screen. Basic implementation is stateless. """ newPos = player.pos - _console_center # Make sure the camera doesn't see outside the map. newPos.bound(algebra.Rect(0, 0, player.current_map.width - config.MAP_PANEL_WIDTH, player.current_map.height - config.MAP_PANEL_HEIGHT)) if newPos != player.camera_position: player.current_map.fov_needs_recompute = True player.camera_position = newPos
def _create_entries(new_map, old_quarry_stairs): for i in range(3): w = libtcod.random_get_int(new_map.rng, 1, 3) * 2 + 3 h = libtcod.random_get_int(new_map.rng, 1, 3) * 2 + 3 x = old_quarry_stairs[i].dest_position.x - w / 2 y = old_quarry_stairs[i].dest_position.y - h / 2 new_room = algebra.Rect(x, y, w, h) _create_room(new_map, new_room) # print('Room #' + str(i) + ' at ' + str(new_room)) new_map.rooms.append(new_room) new_map.room_entered.append(False) new_ctr = new_room.center() assert (new_ctr == old_quarry_stairs[i].dest_position)
def __init__(self, width, height, default_terrain): self.width = width self.height = height self.loc_bound = algebra.Rect(0, 0, width - 1, height - 1) self.objects = [] self.portals = [] self.random_seed = None self.rng = None self.fov_map = None self.fov_needs_recompute = True self.terrain = [[default_terrain for y in range(height)] for x in range(width)] self._explored = [[False for y in range(height)] for x in range(width)] self.xp_visit = None
def make_map(player, dungeon_level): """ Creates a new simple map at the given dungeon level. Sets player.current_map to the new map, and adds the player as the first object. """ new_map = map.OutdoorMap(config.OUTDOOR_MAP_WIDTH, config.OUTDOOR_MAP_HEIGHT, dungeon_level) new_map.objects.append(player) player.current_map = new_map player.camera_position = algebra.Location(0, 0) new_map.random_seed = libtcod.random_save(0) _build_map(new_map) # Might want to change this later, but this is required in creature placement # routines so we know what region the player starts in so there isn't a # wandering monster jumping down their throat. Unless, of course, this # start point is on a *region border* and there's a monster in the next # region over... player.pos = algebra.Location(config.OUTDOOR_MAP_WIDTH - 8, 12) _place_random_creatures(new_map, player) _inhabit_rotunda(new_map, new_map.peak) if new_map.caravanserai: compound_cartographer.inhabit_caravanserai(new_map, player) if new_map.quarry_regions: _inhabit_quarry(new_map, player) # make sure we're not starting on top of an object or terrain feature while (new_map.terrain_at(player.pos).name != 'ground'): # subtle bug? doesn't use the map-building random number generator player.pos = player.pos + actions.random_direction() player.pos.bound( algebra.Rect(0, 0, new_map.width - 1, new_map.height - 1)) new_map.initialize_fov() # setting an instancemethod breaks shelve save games # new_map.xp_visit = type(map.BaseMap.xp_visit)(_mountain_exploration, new_map, map.BaseMap) new_map.xp_visit = _mountain_exploration return True
def make_map(player, dungeon_level): """ """ old_map = player.current_map new_map = map.DungeonMap(MINE_SIZE, MINE_SIZE, dungeon_level) new_map.objects.append(player) player.current_map = new_map player.camera_position = algebra.Location(0, 0) new_map.random_seed = libtcod.random_save(0) new_map.rng = libtcod.random_new_from_seed(new_map.random_seed) old_quarry_stairs = old_map.quarry_stairs _link_up_stairs(new_map, old_map, old_quarry_stairs) _create_entries(new_map, old_quarry_stairs) _descend_stairs(new_map, player, old_quarry_stairs) _dig_some_caves(new_map, old_quarry_stairs) _dig_mine_tunnels(new_map) map_bounds = algebra.Rect(1, 1, new_map.width - 1, new_map.height - 1) for x in range(1, new_map.width - 1): for y in range(1, new_map.height - 1): if libtcod.random_get_float(new_map.rng, 0., 1.) < 0.2: new_map.terrain[x][y] = map.TERRAIN_GROUND ca_cartographer._generation(new_map, map_bounds, 7, 1) ca_cartographer._generation(new_map, map_bounds, 5, 1) # Redig the initial rooms because the CA can fill in the stairs for i in range(3): _create_room(new_map, new_map.rooms[i]) for i in range(3): stair_pos = old_quarry_stairs[i].dest_position ca_cartographer._floodfill(new_map, stair_pos.x, stair_pos.y, map.TERRAIN_GROUND, map.TERRAIN_FLOOR) for x in range(1, new_map.width - 1): for y in range(1, new_map.height - 1): if new_map.terrain[x][y] == map.TERRAIN_GROUND: new_map.terrain[x][y] = map.TERRAIN_WALL #for x in range(0, new_map.width): # new_map.terrain[x][0] = map.TERRAIN_WALL # new_map.terrain[x][new_map.height-1] = map.TERRAIN_WALL #for y in range(0, new_map.height): # new_map.terrain[0][y] = map.TERRAIN_WALL # new_map.terrain[new_map.width-1][y] = map.TERRAIN_WALL zone_divisor = MINE_SIZE / 3 slime_zone = new_map.rnd(0, 2) while True: undead_zone = new_map.rnd(0, 2) if undead_zone != slime_zone: break for r in range(3, len(new_map.rooms)): if new_map.rnd(1, 4) < 3: room = new_map.rooms[r] zone = room.center().x / zone_divisor if zone == slime_zone: if new_map.rnd(1, 2) == 1: bestiary.slime(new_map, _find_floor_near_room(new_map, room), player) bestiary.slime(new_map, _find_floor_near_room(new_map, room), player) else: bestiary.jelly(new_map, _find_floor_near_room(new_map, room), player) elif zone == undead_zone: bestiary.ghul(new_map, _find_floor_near_room(new_map, room), player) else: bestiary.worm(new_map, _find_floor_near_room(new_map, room), player) r = new_map.rnd(3, len(new_map.rooms) - 1) pos = new_map.rooms[r].center() while new_map.is_blocked_at(pos): pos += actions.random_direction() new_map.objects.insert(0, Object(pos, '%', "hero's corpse", libtcod.dark_red)) sword = miscellany.the_black_sword() sword.pos = pos new_map.objects.insert(0, sword) new_map.initialize_fov() new_map.xp_visit = _dungeon_exploration return False # Don't need to generate stairs in caller thanks to _link_up_stairs()
def make_caravanserai(new_map): size = 3 (found_x, found_y) = _place_caravanserai(new_map, size) if found_x < 0 or found_y < 0: # Better undersized than none at all? size = 2 (found_x, found_y) = _place_caravanserai(new_map, size) if found_x < 0 or found_y < 0: print("Couldn't fit caravanserai anywhere; sorry!") new_map.caravanserai = None return tl = new_map.region_seeds[found_x * 20 + found_y] br = new_map.region_seeds[found_x * 20 + found_y + (size - 1) * 20 + (size - 1)] print('Caravanserai stretches from ', tl, ' to ', br, ' or so') bounds = algebra.Rect( tl[0], tl[1], max(min(br[0] - tl[0] + 1, MAX_CARAVANSERAI_SIZE), MIN_CARAVANSERAI_SIZE), max(min(br[1] - tl[1] + 1, MAX_CARAVANSERAI_SIZE), MIN_CARAVANSERAI_SIZE)) for x in range(bounds.x1, bounds.x2 + 1): for y in range(bounds.y1, bounds.y2 + 1): if (x == bounds.x1 or x == bounds.x2 or y == bounds.y1 or y == bounds.y2): new_map.terrain[x][y] = map.TERRAIN_WALL else: new_map.terrain[x][y] = map.TERRAIN_FLOOR _clear_outside_walls(new_map, bounds) # Cut gates in it facing east and south center = bounds.center() new_map.caravanserai = Caravanserai(bounds) if (bounds.width > bounds.height): new_map.terrain[center.x][bounds.y2] = map.TERRAIN_GROUND new_map.terrain[bounds.x2][center.y + 2] = map.TERRAIN_GROUND # Rooms in west half wall_offset = new_map.rnd(2, (center.x - bounds.x1) / 3) for y in range(bounds.y1, bounds.y2 + 1): new_map.terrain[center.x - wall_offset][y] = map.TERRAIN_WALL north_door = new_map.rnd(bounds.y1 + 1, center.y - 2) _place_door(new_map, algebra.Location(center.x - wall_offset, north_door)) south_door = new_map.rnd(center.y + 1, bounds.y2 - 1) _place_door(new_map, algebra.Location(center.x - wall_offset, south_door)) wall_y = (north_door + south_door) / 2 for x in range(bounds.x1, center.x - wall_offset): new_map.terrain[x][wall_y] = map.TERRAIN_WALL new_map.caravanserai.rooms.append( algebra.Rect(bounds.x1, bounds.y1, center.x - wall_offset - bounds.x1, wall_y - bounds.y1)) new_map.caravanserai.rooms.append( algebra.Rect(bounds.x1, wall_y, center.x - wall_offset - bounds.x1, bounds.y2 - wall_y)) # outer rooms courtyard_mid_x = (center.x - wall_offset + bounds.x2) / 2 outer_wall_y = (bounds.y1 + center.y + 2) / 2 if outer_wall_y < north_door: outer_wall_y = north_door + 1 for x in range(center.x - wall_offset, bounds.x2): new_map.terrain[x][outer_wall_y] = map.TERRAIN_WALL west_door = new_map.rnd(center.x - wall_offset + 2, courtyard_mid_x - 2) _place_door(new_map, algebra.Location(west_door, outer_wall_y)) east_door = new_map.rnd(courtyard_mid_x + 2, bounds.x2 - 2) _place_door(new_map, algebra.Location(west_door, outer_wall_y)) wall_x = (east_door + west_door) / 2 for y in range(bounds.y1, outer_wall_y): new_map.terrain[wall_x][y] = map.TERRAIN_WALL new_map.caravanserai.rooms.append( algebra.Rect(center.x - wall_offset, bounds.y1, wall_x - center.x + wall_offset, wall_y - bounds.y1)) new_map.caravanserai.rooms.append( algebra.Rect(wall_x, bounds.y1, center.x - wall_offset - bounds.x1, bounds.x2 - wall_x)) courtyard_bounds = algebra.Rect(center.x - wall_offset + 1, outer_wall_y + 1, bounds.x2 - center.x + wall_offset - 1, bounds.y2 - outer_wall_y - 1) else: new_map.terrain[center.x + 2][bounds.y2] = map.TERRAIN_GROUND new_map.terrain[bounds.x2][center.y] = map.TERRAIN_GROUND # Rooms in north half wall_offset = new_map.rnd(2, (center.y - bounds.y1) / 3) for x in range(bounds.x1, bounds.x2 + 1): new_map.terrain[x][center.y - wall_offset] = map.TERRAIN_WALL west_door = new_map.rnd(bounds.x1 + 1, center.x - 2) _place_door(new_map, algebra.Location(west_door, center.y - wall_offset)) east_door = new_map.rnd(center.x + 1, bounds.x2 - 1) _place_door(new_map, algebra.Location(east_door, center.y - wall_offset)) wall_x = (east_door + west_door) / 2 for y in range(bounds.y1, center.y - wall_offset): new_map.terrain[wall_x][y] = map.TERRAIN_WALL new_map.caravanserai.rooms.append( algebra.Rect(bounds.x1, bounds.y1, wall_x - bounds.x1, center.y - wall_offset - bounds.y1)) new_map.caravanserai.rooms.append( algebra.Rect(wall_x, bounds.y1, bounds.x2 - center.x + wall_offset, center.y - wall_offset - bounds.y1)) # outer rooms courtyard_mid_y = (center.y - wall_offset + bounds.y2) / 2 outer_wall_x = (bounds.x1 + center.x + 2) / 2 if outer_wall_x < west_door: outer_wall_x = west_door + 1 for y in range(center.y - wall_offset, bounds.y2): new_map.terrain[outer_wall_x][y] = map.TERRAIN_WALL north_door = new_map.rnd(center.y - wall_offset + 2, courtyard_mid_y - 2) _place_door(new_map, algebra.Location(outer_wall_x, north_door)) south_door = new_map.rnd(courtyard_mid_y + 2, bounds.y2 - 2) _place_door(new_map, algebra.Location(outer_wall_x, south_door)) wall_y = (south_door + north_door) / 2 for x in range(bounds.x1, outer_wall_x): new_map.terrain[x][wall_y] = map.TERRAIN_WALL new_map.caravanserai.rooms.append( algebra.Rect(bounds.x1, center.y - wall_offset, center.x - wall_offset - bounds.x1, wall_y - center.y + wall_offset)) new_map.caravanserai.rooms.append( algebra.Rect(bounds.x1, wall_y, center.x - wall_offset - bounds.x1, bounds.x2 - wall_y)) courtyard_bounds = algebra.Rect(outer_wall_x + 1, center.y - wall_offset + 1, bounds.x2 - outer_wall_x - 1, bounds.y2 - center.y + wall_offset - 1) print('Caravanserai court ', courtyard_bounds) print('Caravanserai rooms ', new_map.caravanserai.rooms[0], new_map.caravanserai.rooms[1], new_map.caravanserai.rooms[2], new_map.caravanserai.rooms[3]) new_map.caravanserai.courtyard = courtyard_bounds _clear_courtyard(new_map, courtyard_bounds) # TODO: create an upstairs and a cellar _add_loot(new_map, miscellany.leather_armor, 1) _add_loot(new_map, miscellany.bandage, 3) _add_loot(new_map, miscellany.bandage, 3) _add_loot(new_map, miscellany.kumiss, 4) _add_loot(new_map, miscellany.arrow, 6)