/** * River generation. * * Rivers have a source, and then keep on flowing until they meet another body * of water, which they flow into, or until they reach the edge of the map. * Rivers will always flow downhill, except that they can flow a maximum of * 'river_uphill' uphill. This is to represent the water eroding the higher * ground lower. * * Every possible path for a river will be attempted, in random order, and the * first river path that can be found that makes the river flow into another * body of water or off the map will be used. * * If no path can be found, then the river's generation will be aborted, and * false will be returned. true is returned if the river is generated * successfully. */ static bool generate_river_internal(const height_map& heights, terrain_map& terrain, int x, int y, std::vector<location>& river, std::set<location>& seen_locations, int river_uphill) { const bool on_map = x >= 0 && y >= 0 && x < static_cast<long>(heights.size()) && y < static_cast<long>(heights.back().size()); if(on_map && !river.empty() && heights[x][y] > heights[river.back().x][river.back().y] + river_uphill) { return false; } // If we're at the end of the river if(!on_map || terrain[x][y] == t_translation::SHALLOW_WATER || terrain[x][y] == t_translation::DEEP_WATER) { LOG_NG << "generating river...\n"; // Generate the river for(std::vector<location>::const_iterator i = river.begin(); i != river.end(); ++i) { terrain[i->x][i->y] = t_translation::SHALLOW_WATER; } LOG_NG << "done generating river\n"; return true; } location current_loc(x,y); location adj[6]; get_adjacent_tiles(current_loc,adj); static int items[6] = {0,1,2,3,4,5}; std::random_shuffle(items,items+4); // Mark that we have attempted from this location seen_locations.insert(current_loc); river.push_back(current_loc); for(int a = 0; a != 6; ++a) { const location& loc = adj[items[a]]; if(seen_locations.count(loc) == 0) { const bool res = generate_river_internal(heights,terrain,loc.x,loc.y,river,seen_locations,river_uphill); if(res) { return true; } } } river.pop_back(); return false; }
bool default_map_generator_job::generate_river_internal(const height_map& heights, terrain_map& terrain, int x, int y, std::vector<map_location>& river, std::set<map_location>& seen_locations, int river_uphill) { const bool on_map = x >= 0 && y >= 0 && x < static_cast<long>(heights.size()) && y < static_cast<long>(heights.back().size()); if(on_map && !river.empty() && heights[x][y] > heights[river.back().x][river.back().y] + river_uphill) { return false; } // If we're at the end of the river if(!on_map || terrain[x][y] == t_translation::SHALLOW_WATER || terrain[x][y] == t_translation::DEEP_WATER) { LOG_NG << "generating river...\n"; // Generate the river for(auto i : river) { terrain[i.x][i.y] = t_translation::SHALLOW_WATER; } LOG_NG << "done generating river\n"; return true; } map_location current_loc(x,y); map_location adj[6]; get_adjacent_tiles(current_loc,adj); std::shuffle(std::begin(adj), std::end(adj), rng_); // Mark that we have attempted from this map_location seen_locations.insert(current_loc); river.push_back(current_loc); for(const map_location& loc : adj) { if(seen_locations.count(loc) == 0) { const bool res = generate_river_internal(heights,terrain,loc.x,loc.y,river,seen_locations,river_uphill); if(res) { return true; } } } river.pop_back(); return false; }