doxygen, comments
This commit is contained in:
parent
cb1114a5b3
commit
ca39286028
2 changed files with 176 additions and 140 deletions
295
src/mapgen.cpp
295
src/mapgen.cpp
|
@ -12,6 +12,9 @@
|
|||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
//! @file mapgen.cpp
|
||||
//! Map-generator, with standalone testprogram.
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -50,15 +53,19 @@ typedef t_translation::t_map terrain_map;
|
|||
|
||||
typedef gamemap::location location;
|
||||
|
||||
//basically we generate alot of hills, each hill being centered at a certain point, with a certain radius - being a half sphere.
|
||||
//Hills are combined additively to form a bumpy surface
|
||||
//The size of each hill varies randomly from 1-hill_size.
|
||||
//we generate 'iterations' hills in total.
|
||||
//the range of heights is normalized to 0-1000
|
||||
//'island_size' controls whether or not the map should tend toward an island shape, and if
|
||||
//so, how large the island should be. Hills with centers that are more than 'island_size'
|
||||
//away from the center of the map will be inverted (i.e. be valleys).
|
||||
//'island_size' as 0 indicates no island
|
||||
//! Generate a height-map.
|
||||
//! Basically we generate alot of hills,
|
||||
//! each hill being centered at a certain point,
|
||||
//! with a certain radius - being a half sphere.
|
||||
//! Hills are combined additively to form a bumpy surface.
|
||||
//! The size of each hill varies randomly from 1-hill_size.
|
||||
//! We generate 'iterations' hills in total.
|
||||
//! The range of heights is normalized to 0-1000.
|
||||
//! 'island_size' controls whether or not the map should tend toward an island shape,
|
||||
//! and if so, how large the island should be.
|
||||
//! Hills with centers that are more than 'island_size' away from
|
||||
//! the center of the map will be inverted (i.e. be valleys).
|
||||
//! 'island_size' as 0 indicates no island.
|
||||
static height_map generate_height_map(size_t width, size_t height,
|
||||
size_t iterations, size_t hill_size,
|
||||
size_t island_size, size_t island_off_center)
|
||||
|
@ -95,16 +102,17 @@ static height_map generate_height_map(size_t width, size_t height,
|
|||
|
||||
for(size_t i = 0; i != iterations; ++i) {
|
||||
|
||||
//(x1,y1) is the location of the hill, and 'radius' is the radius of the hill.
|
||||
//we iterate over all points, (x2,y2). The formula for the amount the height
|
||||
//is increased by is radius - sqrt((x2-x1)^2 + (y2-y1)^2) with negative values
|
||||
//ignored.
|
||||
// (x1,y1) is the location of the hill,
|
||||
// and 'radius' is the radius of the hill.
|
||||
// We iterate over all points, (x2,y2).
|
||||
// The formula for the amount the height is increased by is:
|
||||
// radius - sqrt((x2-x1)^2 + (y2-y1)^2) with negative values ignored.
|
||||
//
|
||||
//rather than iterate over every single point, we can reduce the points to
|
||||
//a rectangle that contains all the positive values for this formula --
|
||||
//the rectangle is given by min_x,max_x,min_y,max_y
|
||||
// Rather than iterate over every single point, we can reduce the points
|
||||
// to a rectangle that contains all the positive values for this formula --
|
||||
// the rectangle is given by min_x,max_x,min_y,max_y.
|
||||
|
||||
//is this a negative hill? (i.e. a valley)
|
||||
// Is this a negative hill? (i.e. a valley)
|
||||
bool is_valley = false;
|
||||
|
||||
int x1 = island_size > 0 ? center_x - island_size + (rand()%(island_size*2)) :
|
||||
|
@ -112,7 +120,7 @@ static height_map generate_height_map(size_t width, size_t height,
|
|||
int y1 = island_size > 0 ? center_y - island_size + (rand()%(island_size*2)) :
|
||||
int(rand()%height);
|
||||
|
||||
//we have to check whether this is actually a valley
|
||||
// We have to check whether this is actually a valley
|
||||
if(island_size != 0) {
|
||||
const size_t diffx = abs(x1 - int(center_x));
|
||||
const size_t diffy = abs(y1 - int(center_y));
|
||||
|
@ -149,7 +157,7 @@ static height_map generate_height_map(size_t width, size_t height,
|
|||
}
|
||||
}
|
||||
|
||||
//find the heighest and lowest points on the map for normalization
|
||||
// Find the highest and lowest points on the map for normalization:
|
||||
int heighest = 0, lowest = 100000, x;
|
||||
for(x = 0; size_t(x) != res.size(); ++x) {
|
||||
for(int y = 0; size_t(y) != res[x].size(); ++y) {
|
||||
|
@ -161,7 +169,7 @@ static height_map generate_height_map(size_t width, size_t height,
|
|||
}
|
||||
}
|
||||
|
||||
//normalize the heights to the range 0-1000
|
||||
// Normalize the heights to the range 0-1000:
|
||||
heighest -= lowest;
|
||||
for(x = 0; size_t(x) != res.size(); ++x) {
|
||||
for(int y = 0; size_t(y) != res[x].size(); ++y) {
|
||||
|
@ -175,10 +183,12 @@ static height_map generate_height_map(size_t width, size_t height,
|
|||
return res;
|
||||
}
|
||||
|
||||
//function to generate a lake. It will create water at (x,y), and then have
|
||||
//'lake_fall_off' % chance to make another water tile in each of the directions n,s,e,w.
|
||||
//In each of the directions it does make another water tile, it will have 'lake_fall_off'/2 %
|
||||
//chance to make another water tile in each of the directions. This will continue recursively.
|
||||
//! Generate a lake.
|
||||
//! It will create water at (x,y), and then have 'lake_fall_off' % chance
|
||||
//! to make another water tile in each of the directions n,s,e,w.
|
||||
//! In each of the directions it does make another water tile,
|
||||
//! it will have 'lake_fall_off'/2 % chance to make another water tile
|
||||
//! in each of the directions. This will continue recursively.
|
||||
static bool generate_lake(terrain_map& terrain, int x, int y, int lake_fall_off, std::set<location>& locs_touched)
|
||||
{
|
||||
if(x < 0 || y < 0 || size_t(x) >= terrain.size() || size_t(y) >= terrain.front().size()) {
|
||||
|
@ -209,16 +219,21 @@ static bool generate_lake(terrain_map& terrain, int x, int y, int lake_fall_off,
|
|||
|
||||
typedef gamemap::location location;
|
||||
|
||||
//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.
|
||||
//! 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)
|
||||
|
@ -233,13 +248,13 @@ static bool generate_river_internal(const height_map& heights,
|
|||
return false;
|
||||
}
|
||||
|
||||
//if we're at the end of the river
|
||||
// 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
|
||||
// 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;
|
||||
|
@ -256,7 +271,7 @@ static bool generate_river_internal(const height_map& heights,
|
|||
static int items[6] = {0,1,2,3,4,5};
|
||||
std::random_shuffle(items,items+4);
|
||||
|
||||
//mark that we have attempted from this location
|
||||
// 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) {
|
||||
|
@ -287,8 +302,8 @@ static std::vector<location> generate_river(const height_map& heights, terrain_m
|
|||
return river;
|
||||
}
|
||||
|
||||
//function to return a random tile at one of the borders of a map that is
|
||||
//of the given dimensions.
|
||||
//! Return a random tile at one of the borders of a map
|
||||
//! that is of the given dimensions.
|
||||
static location random_point_at_side(size_t width, size_t height)
|
||||
{
|
||||
const int side = rand()%4;
|
||||
|
@ -303,13 +318,13 @@ static location random_point_at_side(size_t width, size_t height)
|
|||
}
|
||||
}
|
||||
|
||||
//function which, given the map will output it in a valid format.
|
||||
//! Function which, given the map will output it in a valid format.
|
||||
static std::string output_map(const terrain_map& terrain,
|
||||
std::map<int, t_translation::coordinate> starting_positions)
|
||||
{
|
||||
//remember that we only want the middle 1/9th of the map. All other
|
||||
//segments of the map are there only to give the important middle part
|
||||
//some context.
|
||||
// Remember that we only want the middle 1/9th of the map.
|
||||
// All other segments of the map are there only to give
|
||||
// the important middle part some context.
|
||||
const size_t begin_x = terrain.size()/3;
|
||||
const size_t end_x = begin_x*2;
|
||||
const size_t begin_y = terrain.front().size()/3;
|
||||
|
@ -326,8 +341,8 @@ static std::string output_map(const terrain_map& terrain,
|
|||
}
|
||||
}
|
||||
|
||||
// Since the map has been resize the starting
|
||||
// locations also need to be fixed
|
||||
// Since the map has been resized,
|
||||
// the starting locations also need to be fixed
|
||||
std::map<int, t_translation::coordinate>::iterator itor = starting_positions.begin();
|
||||
for(; itor != starting_positions.end(); ++itor) {
|
||||
itor->second.x -= begin_x;
|
||||
|
@ -339,14 +354,14 @@ static std::string output_map(const terrain_map& terrain,
|
|||
|
||||
namespace {
|
||||
|
||||
//an object that will calculate the cost of building a road over terrain
|
||||
//for use in the a_star_search algorithm.
|
||||
//! Calculate the cost of building a road over terrain.
|
||||
//! For use in the a_star_search algorithm.
|
||||
struct road_path_calculator : cost_calculator
|
||||
{
|
||||
road_path_calculator(const terrain_map& terrain, const config& cfg)
|
||||
: calls(0), map_(terrain), cfg_(cfg),
|
||||
|
||||
//find out how windy roads should be.
|
||||
// Find out how windy roads should be.
|
||||
windiness_(maximum<int>(1,atoi(cfg["road_windiness"].c_str()))) {}
|
||||
virtual double cost(const location& src, const location& loc, const double so_far, const bool isDst) const;
|
||||
|
||||
|
@ -375,10 +390,12 @@ double road_path_calculator::cost(const location& /*src*/, const location& loc,
|
|||
return val->second;
|
||||
}
|
||||
|
||||
//we multiply the cost by a random amount depending upon how 'windy' the road should
|
||||
//be. If windiness is 1, that will mean that the cost is always genuine, and so
|
||||
//the road always takes the shortest path. If windiness is greater than 1, we sometimes
|
||||
//over-report costs for some segments, to make the road wind a little.
|
||||
// We multiply the cost by a random amount,
|
||||
// depending upon how 'windy' the road should be.
|
||||
// If windiness is 1, that will mean that the cost is always genuine,
|
||||
// and so the road always takes the shortest path.
|
||||
// If windiness is greater than 1, we sometimes over-report costs
|
||||
// for some segments, to make the road wind a little.
|
||||
const double windiness = windiness_ > 0 ? (double(rand()%windiness_) + 1.0) : 1.0;
|
||||
|
||||
const t_translation::t_letter c = map_[loc.x][loc.y];
|
||||
|
@ -400,6 +417,7 @@ double road_path_calculator::cost(const location& /*src*/, const location& loc,
|
|||
return windiness*res;
|
||||
}
|
||||
|
||||
//!
|
||||
struct is_valid_terrain
|
||||
{
|
||||
is_valid_terrain(const t_translation::t_map& map,
|
||||
|
@ -428,6 +446,7 @@ bool is_valid_terrain::operator()(int x, int y) const
|
|||
|
||||
}
|
||||
|
||||
//!
|
||||
static int rank_castle_location(int x, int y, const is_valid_terrain& valid_terrain, int min_x, int max_x, int min_y, int max_y,
|
||||
size_t min_distance, const std::vector<gamemap::location>& other_castles, int highest_ranking)
|
||||
{
|
||||
|
@ -493,6 +512,7 @@ static int rank_castle_location(int x, int y, const is_valid_terrain& valid_terr
|
|||
return surrounding_ranking + current_ranking;
|
||||
}
|
||||
|
||||
//!
|
||||
static gamemap::location place_village(const t_translation::t_map& map,
|
||||
const size_t x, const size_t y, const size_t radius, const config& cfg)
|
||||
{
|
||||
|
@ -541,6 +561,7 @@ static gamemap::location place_village(const t_translation::t_map& map,
|
|||
return best_loc;
|
||||
}
|
||||
|
||||
//!
|
||||
static std::string generate_name(const unit_race& name_generator, const std::string& id,
|
||||
std::string* base_name=NULL,
|
||||
utils::string_map* additional_symbols=NULL)
|
||||
|
@ -573,13 +594,14 @@ static std::string generate_name(const unit_race& name_generator, const std::str
|
|||
|
||||
namespace {
|
||||
|
||||
//the configuration file should contain a number of [height] tags:
|
||||
//[height]
|
||||
//height=n
|
||||
//terrain=x
|
||||
//[/height]
|
||||
//these should be in descending order of n. They are checked sequentially, and if
|
||||
//height is greater than n for that tile, then the tile is set to terrain type x.
|
||||
// the configuration file should contain a number of [height] tags:
|
||||
// [height]
|
||||
// height=n
|
||||
// terrain=x
|
||||
// [/height]
|
||||
// These should be in descending order of n.
|
||||
// They are checked sequentially, and if height is greater than n for that tile,
|
||||
// then the tile is set to terrain type x.
|
||||
class terrain_height_mapper
|
||||
{
|
||||
public:
|
||||
|
@ -655,9 +677,9 @@ t_translation::t_letter terrain_converter::convert_to() const
|
|||
return to;
|
||||
}
|
||||
|
||||
}
|
||||
} // end anon namespace
|
||||
|
||||
//function to generate the map.
|
||||
//! Generate the map.
|
||||
std::string default_generate_map(size_t width, size_t height, size_t island_size, size_t island_off_center,
|
||||
size_t iterations, size_t hill_size,
|
||||
size_t max_lakes, size_t nvillages, size_t castle_size, size_t nplayers, bool roads_between_castles,
|
||||
|
@ -665,12 +687,12 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
{
|
||||
log_scope("map generation");
|
||||
|
||||
//odd widths are nasty
|
||||
// Odd widths are nasty
|
||||
wassert(is_even(width));
|
||||
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
//find out what the 'flatland' on this map is. i.e. grassland.
|
||||
// Find out what the 'flatland' on this map is, i.e. grassland.
|
||||
std::string flatland = cfg["default_flatland"];
|
||||
if(flatland == "") {
|
||||
flatland = t_translation::write_letter(t_translation::GRASS_LAND);
|
||||
|
@ -678,16 +700,17 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
const t_translation::t_letter grassland = t_translation::read_letter(flatland);
|
||||
|
||||
//we want to generate a map that is 9 times bigger than the
|
||||
//actual size desired. Only the middle part of the map will be
|
||||
//used, but the rest is so that the map we end up using can
|
||||
//have a context (e.g. rivers flowing from out of the map into
|
||||
//the map, same for roads, etc etc)
|
||||
// We want to generate a map that is 9 times bigger
|
||||
// than the actual size desired.
|
||||
// Only the middle part of the map will be used,
|
||||
// but the rest is so that the map we end up using
|
||||
// can have a context (e.g. rivers flowing from
|
||||
// out of the map into the map, same for roads, etc.)
|
||||
width *= 3;
|
||||
height *= 3;
|
||||
|
||||
LOG_NG << "generating height map...\n";
|
||||
//generate the height of everything.
|
||||
// Generate the height of everything.
|
||||
const height_map heights = generate_height_map(width,height,iterations,hill_size,island_size,island_off_center);
|
||||
LOG_NG << "done generating height map...\n";
|
||||
LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
|
||||
|
@ -698,7 +721,7 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
naming = *names_info;
|
||||
}
|
||||
|
||||
//make a dummy race for generating names
|
||||
// Make a dummy race for generating names
|
||||
unit_race name_generator(naming);
|
||||
|
||||
std::vector<terrain_height_mapper> height_conversion;
|
||||
|
@ -725,15 +748,19 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
LOG_NG << "placed land forms\n";
|
||||
LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
|
||||
|
||||
//now that we have our basic set of flatland/hills/mountains/water, we can place lakes
|
||||
//and rivers on the map. All rivers are sourced at a lake. Lakes must be in high land -
|
||||
//at least 'min_lake_height'. (Note that terrain below a certain altitude may be made
|
||||
//into bodies of water in the code above - i.e. 'sea', but these are not considered 'lakes' because
|
||||
//they are not sources of rivers).
|
||||
// Now that we have our basic set of flatland/hills/mountains/water,
|
||||
// we can place lakes and rivers on the map.
|
||||
// All rivers are sourced at a lake.
|
||||
// Lakes must be in high land - at least 'min_lake_height'.
|
||||
// (Note that terrain below a certain altitude may be made
|
||||
// into bodies of water in the code above - i.e. 'sea',
|
||||
// but these are not considered 'lakes', because
|
||||
// they are not sources of rivers).
|
||||
//
|
||||
//we attempt to place 'max_lakes' lakes. Each lake will be placed at a random location,
|
||||
//if that random location meets the minimum terrain requirements for a lake.
|
||||
//We will also attempt to source a river from each lake.
|
||||
// We attempt to place 'max_lakes' lakes.
|
||||
// Each lake will be placed at a random location,
|
||||
// if that random location meets the minimum terrain requirements for a lake.
|
||||
// We will also attempt to source a river from each lake.
|
||||
std::set<location> lake_locs;
|
||||
|
||||
std::map<location,std::string> river_names, lake_names;
|
||||
|
@ -777,13 +804,13 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
std::set<location>::const_iterator i;
|
||||
|
||||
//only generate a name if the lake hasn't touched any other lakes, so that we
|
||||
//don't end up with one big lake with multiple names
|
||||
// Only generate a name if the lake hasn't touched any other lakes,
|
||||
// so that we don't end up with one big lake with multiple names.
|
||||
for(i = locs.begin(); i != locs.end(); ++i) {
|
||||
if(lake_locs.count(*i) != 0) {
|
||||
touches_other_lake = true;
|
||||
|
||||
//reassign the name of this lake to be the same as the other lake
|
||||
// Reassign the name of this lake to be the same as the other lake
|
||||
const location loc(i->x-width/3,i->y-height/3);
|
||||
const std::map<location,std::string>::const_iterator other_name = lake_names.find(loc);
|
||||
if(other_name != lake_names.end()) {
|
||||
|
@ -816,10 +843,11 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
const size_t default_dimensions = 40*40*9;
|
||||
|
||||
//convert grassland terrain to other types of flat terrain.
|
||||
//we generate a 'temperature map' which uses the height generation algorithm to
|
||||
//generate the temperature levels all over the map. Then we can use a combination
|
||||
//of height and terrain to divide terrain up into more interesting types than the default
|
||||
//! Convert grassland terrain to other types of flat terrain.
|
||||
//! We generate a 'temperature map' which uses the height generation algorithm
|
||||
//! to generate the temperature levels all over the map.
|
||||
//! Then we can use a combination of height and terrain
|
||||
//! to divide terrain up into more interesting types than the default.
|
||||
const height_map temperature_map = generate_height_map(width,height,
|
||||
(atoi(cfg["temperature_iterations"].c_str())*width*height)/default_dimensions,
|
||||
atoi(cfg["temperature_size"].c_str()),0,0);
|
||||
|
@ -837,8 +865,8 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
|
||||
|
||||
|
||||
//iterate over every flatland tile, and determine what type of flatland it is,
|
||||
//based on our [convert] tags.
|
||||
// Iterate over every flatland tile, and determine
|
||||
// what type of flatland it is, based on our [convert] tags.
|
||||
for(x = 0; x != width; ++x) {
|
||||
for(y = 0; y != height; ++y) {
|
||||
for(std::vector<terrain_converter>::const_iterator i = converters.begin(); i != converters.end(); ++i) {
|
||||
|
@ -853,33 +881,34 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
LOG_NG << "placing villages...\n";
|
||||
LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
|
||||
|
||||
//place villages in a 'grid', to make placing fair, but with villages
|
||||
//displaced from their position according to terrain and randomness, to
|
||||
//add some variety.
|
||||
|
||||
//! Place villages in a 'grid', to make placing fair,
|
||||
//! but with villages displaced from their position
|
||||
//! according to terrain and randomness, to add some variety.
|
||||
std::set<location> villages;
|
||||
|
||||
LOG_NG << "placing castles...\n";
|
||||
|
||||
//try to find configuration for castles.
|
||||
//! Try to find configuration for castles.
|
||||
const config* const castle_config = cfg.child("castle");
|
||||
if(castle_config == NULL) {
|
||||
LOG_NG << "Could not find castle configuration\n";
|
||||
return "";
|
||||
}
|
||||
|
||||
//castle configuration tag contains a 'valid_terrain' attribute which is a list of
|
||||
//terrains that the castle may appear on.
|
||||
//! Castle configuration tag contains a 'valid_terrain' attribute
|
||||
//! which is a list of terrains that the castle may appear on.
|
||||
const t_translation::t_list list =
|
||||
t_translation::read_list((*castle_config)["valid_terrain"]);
|
||||
|
||||
const is_valid_terrain terrain_tester(terrain, list);
|
||||
|
||||
//attempt to place castles at random. Once we have placed castles, we run a sanity
|
||||
//check to make sure that the castles are well-placed. If the castles are not well-placed,
|
||||
//we try again. Definition of 'well-placed' is if no two castles are closer than
|
||||
//'min_distance' hexes from each other, and the castles appear on a terrain listed
|
||||
//in 'valid_terrain'.
|
||||
//! Attempt to place castles at random.
|
||||
//! Once we have placed castles, we run a sanity check
|
||||
//! to make sure that the castles are well-placed.
|
||||
//! If the castles are not well-placed, we try again.
|
||||
//! Definition of 'well-placed' is if no two castles
|
||||
//! are closer than 'min_distance' hexes from each other,
|
||||
//! and the castles appear on a terrain listed in 'valid_terrain'.
|
||||
std::vector<location> castles;
|
||||
std::set<location> failed_locs;
|
||||
|
||||
|
@ -919,8 +948,9 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
LOG_NG << "placing roads...\n";
|
||||
LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
|
||||
|
||||
//place roads. We select two tiles at random locations on the borders of the map,
|
||||
//and try to build roads between them.
|
||||
// Place roads.
|
||||
// We select two tiles at random locations on the borders
|
||||
// of the map, and try to build roads between them.
|
||||
size_t nroads = atoi(cfg["roads"].c_str());
|
||||
if(roads_between_castles) {
|
||||
nroads += castles.size()*castles.size();
|
||||
|
@ -932,9 +962,9 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
for(size_t road = 0; road != nroads; ++road) {
|
||||
log_scope("creating road");
|
||||
|
||||
//we want the locations to be on the portion of the map we're actually going
|
||||
//to use, since roads on other parts of the map won't have any influence,
|
||||
//and doing it like this will be quicker.
|
||||
//! We want the locations to be on the portion of the map
|
||||
//! we're actually going to use, since roads on other parts of the map
|
||||
//! won't have any influence, and doing it like this will be quicker.
|
||||
location src = random_point_at_side(width/3 + 2,height/3 + 2);
|
||||
location dst = random_point_at_side(width/3 + 2,height/3 + 2);
|
||||
|
||||
|
@ -954,7 +984,7 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
dst = castles[dst_castle];
|
||||
}
|
||||
|
||||
//if the road isn't very interesting (on the same border), don't draw it
|
||||
// If the road isn't very interesting (on the same border), don't draw it.
|
||||
else if(src.x == dst.x || src.y == dst.y) {
|
||||
continue;
|
||||
}
|
||||
|
@ -963,7 +993,7 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
continue;
|
||||
}
|
||||
|
||||
//search a path out for the road
|
||||
// Search a path out for the road
|
||||
const paths::route rt = a_star_search(src, dst, 10000.0, &calc, width, height);
|
||||
|
||||
const std::string& name = generate_name(name_generator,"road_name");
|
||||
|
@ -972,7 +1002,8 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
bool on_bridge = false;
|
||||
|
||||
//draw the road. If the search failed, rt.steps will simply be empty
|
||||
// Draw the road.
|
||||
// If the search failed, rt.steps will simply be empty.
|
||||
for(std::vector<location>::const_iterator step = rt.steps.begin();
|
||||
step != rt.steps.end(); ++step) {
|
||||
|
||||
|
@ -987,20 +1018,20 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
calc.terrain_changed(*step);
|
||||
|
||||
//find the configuration which tells us what to convert this tile to
|
||||
//to make it into a road.
|
||||
// Find the configuration which tells us
|
||||
// what to convert this tile to, to make it into a road.
|
||||
const config* const child = cfg.find_child("road_cost", "terrain",
|
||||
t_translation::write_letter(terrain[x][y]));
|
||||
if(child != NULL) {
|
||||
//convert to bridge means that we want to convert depending
|
||||
//upon the direction the road is going.
|
||||
//typically it will be in a format like,
|
||||
//convert_to_bridge=\,|,/
|
||||
// Convert to bridge means that we want to convert
|
||||
// depending upon the direction the road is going.
|
||||
// Typically it will be in a format like,
|
||||
// convert_to_bridge=\,|,/
|
||||
// '|' will be used if the road is going north-south
|
||||
// '/' will be used if the road is going south west-north east
|
||||
// '\' will be used if the road is going south east-north west
|
||||
//the terrain will be left unchanged otherwise (if there is no clear
|
||||
//direction)
|
||||
// The terrain will be left unchanged otherwise
|
||||
// (if there is no clear direction).
|
||||
const std::string& convert_to_bridge = (*child)["convert_to_bridge"];
|
||||
if(convert_to_bridge.empty() == false) {
|
||||
if(step == rt.steps.begin() || step+1 == rt.steps.end())
|
||||
|
@ -1014,17 +1045,17 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
int direction = -1;
|
||||
|
||||
//if we are going north-south
|
||||
// If we are going north-south
|
||||
if(last == adj[0] && next == adj[3] || last == adj[3] && next == adj[0]) {
|
||||
direction = 0;
|
||||
}
|
||||
|
||||
//if we are going south west-north east
|
||||
// If we are going south west-north east
|
||||
else if(last == adj[1] && next == adj[4] || last == adj[4] && next == adj[1]) {
|
||||
direction = 1;
|
||||
}
|
||||
|
||||
//if we are going south east-north west
|
||||
// If we are going south east-north west
|
||||
else if(last == adj[2] && next == adj[5] || last == adj[5] && next == adj[2]) {
|
||||
direction = 2;
|
||||
}
|
||||
|
@ -1049,7 +1080,7 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
on_bridge = false;
|
||||
}
|
||||
|
||||
//just a plain terrain substitution for a road
|
||||
// Just a plain terrain substitution for a road
|
||||
const std::string& convert_to = (*child)["convert_to"];
|
||||
if(convert_to.empty() == false) {
|
||||
const t_translation::t_letter letter =
|
||||
|
@ -1068,7 +1099,7 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
}
|
||||
|
||||
|
||||
//now that road drawing is done, we can plonk down the castles.
|
||||
// Now that road drawing is done, we can plonk down the castles.
|
||||
std::map<int, t_translation::coordinate> starting_positions;
|
||||
for(std::vector<location>::const_iterator c = castles.begin(); c != castles.end(); ++c) {
|
||||
if(c->valid() == false) {
|
||||
|
@ -1091,7 +1122,7 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
terrain[x+castles[i][0]][y+castles[i][1]] = t_translation::HUMAN_CASTLE;
|
||||
}
|
||||
|
||||
//remove all labels under the castle tiles
|
||||
// Remove all labels under the castle tiles
|
||||
if(labels != NULL) {
|
||||
labels->erase(location(x-width/3,y-height/3));
|
||||
for (size_t i = 0; i < castle_size - 1; i++) {
|
||||
|
@ -1115,13 +1146,13 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
const unit_race village_names_generator(naming_cfg);
|
||||
|
||||
//first we work out the size of the x and y distance between villages
|
||||
// First we work out the size of the x and y distance between villages
|
||||
const size_t tiles_per_village = ((width*height)/9)/nvillages;
|
||||
size_t village_x = 1, village_y = 1;
|
||||
|
||||
//alternate between incrementing the x and y value. When they are high enough
|
||||
//to equal or exceed the tiles_per_village, then we have them to the value
|
||||
//we want them at.
|
||||
// Alternate between incrementing the x and y value.
|
||||
// When they are high enough to equal or exceed the tiles_per_village,
|
||||
// then we have them to the value we want them at.
|
||||
while(village_x*village_y < tiles_per_village) {
|
||||
if(village_x < village_y) {
|
||||
++village_x;
|
||||
|
@ -1144,9 +1175,9 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
const gamemap::location res = place_village(terrain,x,y,2,cfg);
|
||||
|
||||
if(res.x >= static_cast<long>(width) / 3 &&
|
||||
res.x < static_cast<long>(width * 2) / 3 &&
|
||||
res.x < static_cast<long>(width * 2) / 3 &&
|
||||
res.y >= static_cast<long>(height) / 3 &&
|
||||
res.y < static_cast<long>(height * 2) / 3) {
|
||||
res.y < static_cast<long>(height * 2) / 3) {
|
||||
|
||||
const std::string str =
|
||||
t_translation::write_letter(terrain[res.x][res.y]);
|
||||
|
@ -1168,10 +1199,10 @@ std::string default_generate_map(size_t width, size_t height, size_t island_size
|
|||
|
||||
std::string name_type = "village_name";
|
||||
const t_translation::t_list
|
||||
field = t_translation::t_list(1, t_translation::GRASS_LAND),
|
||||
forest = t_translation::t_list(1, t_translation::FOREST),
|
||||
field = t_translation::t_list(1, t_translation::GRASS_LAND),
|
||||
forest = t_translation::t_list(1, t_translation::FOREST),
|
||||
mountain = t_translation::t_list(1, t_translation::MOUNTAIN),
|
||||
hill = t_translation::t_list(1, t_translation::HILL);
|
||||
hill = t_translation::t_list(1, t_translation::HILL);
|
||||
|
||||
size_t field_count = 0, forest_count = 0, mountain_count = 0, hill_count = 0;
|
||||
|
||||
|
@ -1255,9 +1286,11 @@ generator_map generators;
|
|||
|
||||
#ifdef TEST_MAPGEN
|
||||
|
||||
//! Standalone testprogram for the mapgenerator.
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int x = 50, y = 50, iterations = 50, hill_size = 50, lakes=3,
|
||||
int x = 50, y = 50, iterations = 50,
|
||||
hill_size = 50, lakes=3,
|
||||
nvillages = 25, nplayers = 2;
|
||||
if(argc >= 2) {
|
||||
x = atoi(argv[1]);
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
//! @file mapgen.hpp
|
||||
//!
|
||||
|
||||
#ifndef MAP_GEN_HPP_INCLUDED
|
||||
#define MAP_GEN_HPP_INCLUDED
|
||||
|
||||
|
@ -29,21 +32,21 @@ class map_generator
|
|||
public:
|
||||
virtual ~map_generator() {}
|
||||
|
||||
//returns true iff the map generator has an interactive screen
|
||||
//which allows the user to modify how the generator behaves
|
||||
//! Returns true iff the map generator has an interactive screen,
|
||||
//! which allows the user to modify how the generator behaves.
|
||||
virtual bool allow_user_config() const = 0;
|
||||
|
||||
//display the interactive screen which allows the user to
|
||||
//modify how the generator behaves. (This function will not
|
||||
//be called if allow_user_config() returns false)
|
||||
//! Display the interactive screen, which allows the user
|
||||
//! to modify how the generator behaves.
|
||||
//! (This function will not be called if allow_user_config() returns false).
|
||||
virtual void user_config(display& disp) = 0;
|
||||
|
||||
//returns a string identifying the generator by name. The name should
|
||||
//not contain spaces.
|
||||
//! Returns a string identifying the generator by name.
|
||||
//! The name should not contain spaces.
|
||||
virtual std::string name() const = 0;
|
||||
|
||||
//creates a new map and returns it. args may contain arguments to
|
||||
//the map generator
|
||||
//! Creates a new map and returns it.
|
||||
//! args may contain arguments to the map generator.
|
||||
virtual std::string create_map(const std::vector<std::string>& args) = 0;
|
||||
|
||||
virtual config create_scenario(const std::vector<std::string>& args);
|
||||
|
|
Loading…
Add table
Reference in a new issue