00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "global.hpp"
00022
00023 #include "foreach.hpp"
00024 #include "gettext.hpp"
00025 #include "language.hpp"
00026 #include "log.hpp"
00027 #include "map.hpp"
00028 #include "mapgen.hpp"
00029 #include "pathfind/pathfind.hpp"
00030 #include "pathutils.hpp"
00031 #include "race.hpp"
00032 #include "util.hpp"
00033 #include "wml_exception.hpp"
00034 #include "formula_string_utils.hpp"
00035 #include "SDL.h"
00036
00037
00038 static lg::log_domain log_engine("engine");
00039 #define ERR_NG LOG_STREAM(err, log_engine)
00040 #define LOG_NG LOG_STREAM(info, log_engine)
00041
00042 config map_generator::create_scenario(const std::vector<std::string>& args)
00043 {
00044 config res;
00045 res["data"] = create_map(args);
00046 return res;
00047 }
00048
00049 typedef std::vector<std::vector<int> > height_map;
00050 typedef t_translation::t_map terrain_map;
00051
00052 typedef map_location location;
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 static height_map generate_height_map(size_t width, size_t height,
00068 size_t iterations, size_t hill_size,
00069 size_t island_size, size_t island_off_center)
00070 {
00071 height_map res(width,std::vector<int>(height,0));
00072
00073 size_t center_x = width/2;
00074 size_t center_y = height/2;
00075
00076 LOG_NG << "off-centering...\n";
00077
00078 if(island_off_center != 0) {
00079 switch(rand()%4) {
00080 case 0:
00081 center_x += island_off_center;
00082 break;
00083 case 1:
00084 center_y += island_off_center;
00085 break;
00086 case 2:
00087 if(center_x < island_off_center)
00088 center_x = 0;
00089 else
00090 center_x -= island_off_center;
00091 break;
00092 case 3:
00093 if(center_y < island_off_center)
00094 center_y = 0;
00095 else
00096 center_y -= island_off_center;
00097 break;
00098 }
00099 }
00100
00101 for(size_t i = 0; i != iterations; ++i) {
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 bool is_valley = false;
00115
00116 int x1 = island_size > 0 ? center_x - island_size + (rand()%(island_size*2)) :
00117 int(rand()%width);
00118 int y1 = island_size > 0 ? center_y - island_size + (rand()%(island_size*2)) :
00119 int(rand()%height);
00120
00121
00122 if(island_size != 0) {
00123 const size_t diffx = abs(x1 - int(center_x));
00124 const size_t diffy = abs(y1 - int(center_y));
00125 const size_t dist = size_t(std::sqrt(double(diffx*diffx + diffy*diffy)));
00126 is_valley = dist > island_size;
00127 }
00128
00129 const int radius = rand()%hill_size + 1;
00130
00131 const int min_x = x1 - radius > 0 ? x1 - radius : 0;
00132 const int max_x = x1 + radius < static_cast<long>(res.size()) ? x1 + radius : res.size();
00133 const int min_y = y1 - radius > 0 ? y1 - radius : 0;
00134 const int max_y = y1 + radius < static_cast<long>(res.front().size()) ? y1 + radius : res.front().size();
00135
00136 for(int x2 = min_x; x2 < max_x; ++x2) {
00137 for(int y2 = min_y; y2 < max_y; ++y2) {
00138 const int xdiff = (x2-x1);
00139 const int ydiff = (y2-y1);
00140
00141 const int height = radius - int(std::sqrt(double(xdiff*xdiff + ydiff*ydiff)));
00142
00143 if(height > 0) {
00144 if(is_valley) {
00145 if(height > res[x2][y2]) {
00146 res[x2][y2] = 0;
00147 } else {
00148 res[x2][y2] -= height;
00149 }
00150 } else {
00151 res[x2][y2] += height;
00152 }
00153 }
00154 }
00155 }
00156 }
00157
00158
00159 int heighest = 0, lowest = 100000, x;
00160 for(x = 0; size_t(x) != res.size(); ++x) {
00161 for(int y = 0; size_t(y) != res[x].size(); ++y) {
00162 if(res[x][y] > heighest)
00163 heighest = res[x][y];
00164
00165 if(res[x][y] < lowest)
00166 lowest = res[x][y];
00167 }
00168 }
00169
00170
00171 heighest -= lowest;
00172 for(x = 0; size_t(x) != res.size(); ++x) {
00173 for(int y = 0; size_t(y) != res[x].size(); ++y) {
00174 res[x][y] -= lowest;
00175 res[x][y] *= 1000;
00176 if(heighest != 0)
00177 res[x][y] /= heighest;
00178 }
00179 }
00180
00181 return res;
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 static bool generate_lake(terrain_map& terrain, int x, int y, int lake_fall_off, std::set<location>& locs_touched)
00194 {
00195 if(x < 0 || y < 0 || size_t(x) >= terrain.size() || size_t(y) >= terrain.front().size()) {
00196 return false;
00197 }
00198
00199 terrain[x][y] = t_translation::SHALLOW_WATER;
00200 locs_touched.insert(location(x,y));
00201
00202 if((rand()%100) < lake_fall_off) {
00203 generate_lake(terrain,x+1,y,lake_fall_off/2,locs_touched);
00204 }
00205
00206 if((rand()%100) < lake_fall_off) {
00207 generate_lake(terrain,x-1,y,lake_fall_off/2,locs_touched);
00208 }
00209
00210 if((rand()%100) < lake_fall_off) {
00211 generate_lake(terrain,x,y+1,lake_fall_off/2,locs_touched);
00212 }
00213
00214 if((rand()%100) < lake_fall_off) {
00215 generate_lake(terrain,x,y-1,lake_fall_off/2,locs_touched);
00216 }
00217
00218 return true;
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 static bool generate_river_internal(const height_map& heights,
00239 terrain_map& terrain, int x, int y, std::vector<location>& river,
00240 std::set<location>& seen_locations, int river_uphill)
00241 {
00242 const bool on_map = x >= 0 && y >= 0 &&
00243 x < static_cast<long>(heights.size()) &&
00244 y < static_cast<long>(heights.back().size());
00245
00246 if(on_map && !river.empty() && heights[x][y] >
00247 heights[river.back().x][river.back().y] + river_uphill) {
00248
00249 return false;
00250 }
00251
00252
00253 if(!on_map || terrain[x][y] == t_translation::SHALLOW_WATER ||
00254 terrain[x][y] == t_translation::DEEP_WATER) {
00255
00256 LOG_NG << "generating river...\n";
00257
00258
00259 for(std::vector<location>::const_iterator i = river.begin();
00260 i != river.end(); ++i) {
00261 terrain[i->x][i->y] = t_translation::SHALLOW_WATER;
00262 }
00263
00264 LOG_NG << "done generating river\n";
00265
00266 return true;
00267 }
00268
00269 location current_loc(x,y);
00270 location adj[6];
00271 get_adjacent_tiles(current_loc,adj);
00272 static int items[6] = {0,1,2,3,4,5};
00273 std::random_shuffle(items,items+4);
00274
00275
00276 seen_locations.insert(current_loc);
00277 river.push_back(current_loc);
00278 for(int a = 0; a != 6; ++a) {
00279 const location& loc = adj[items[a]];
00280 if(seen_locations.count(loc) == 0) {
00281 const bool res = generate_river_internal(heights,terrain,loc.x,loc.y,river,seen_locations,river_uphill);
00282 if(res) {
00283 return true;
00284 }
00285
00286 }
00287 }
00288
00289 river.pop_back();
00290
00291 return false;
00292 }
00293
00294 static std::vector<location> generate_river(const height_map& heights, terrain_map& terrain, int x, int y, int river_uphill)
00295 {
00296 std::vector<location> river;
00297 std::set<location> seen_locations;
00298 const bool res = generate_river_internal(heights,terrain,x,y,river,seen_locations,river_uphill);
00299 if(!res) {
00300 river.clear();
00301 }
00302
00303 return river;
00304 }
00305
00306
00307
00308
00309
00310 static location random_point_at_side(size_t width, size_t height)
00311 {
00312 const int side = rand()%4;
00313 if(side < 2) {
00314 const int x = rand()%width;
00315 const int y = side == 0 ? 0 : height-1;
00316 return location(x,y);
00317 } else {
00318 const int y = rand()%height;
00319 const int x = side == 2 ? 0 : width-1;
00320 return location(x,y);
00321 }
00322 }
00323
00324
00325 static std::string output_map(const terrain_map& terrain,
00326 std::map<int, t_translation::coordinate> starting_positions)
00327 {
00328
00329
00330
00331
00332 const size_t begin_x = terrain.size() / 3 - gamemap::default_border ;
00333 const size_t end_x = terrain.size() * 2 / 3 + gamemap::default_border;
00334 const size_t begin_y = terrain.front().size() / 3 - gamemap::default_border;
00335 const size_t end_y = terrain.front().size() * 2 / 3 + gamemap::default_border;
00336
00337 terrain_map map;
00338 map.resize(end_x - begin_x);
00339 for(size_t y = begin_y; y != end_y; ++y) {
00340 for(size_t x = begin_x; x != end_x; ++x) {
00341 if((y - begin_y) == 0){
00342 map[x - begin_x].resize(end_y - begin_y);
00343 }
00344 map[x - begin_x][y - begin_y] = terrain[x][y];
00345 }
00346 }
00347
00348
00349
00350 std::map<int, t_translation::coordinate>::iterator itor = starting_positions.begin();
00351 for(; itor != starting_positions.end(); ++itor) {
00352 itor->second.x -= begin_x;
00353 itor->second.y -= begin_y;
00354 }
00355
00356 return t_translation::write_game_map(map, starting_positions);
00357 }
00358
00359 namespace {
00360
00361
00362
00363
00364
00365 struct road_path_calculator : pathfind::cost_calculator
00366 {
00367 road_path_calculator(const terrain_map& terrain, const config& cfg) :
00368 calls(0),
00369 map_(terrain),
00370 cfg_(cfg),
00371
00372 windiness_(std::max<int>(1, cfg["road_windiness"].to_int())),
00373 seed_(rand()),
00374 cache_()
00375 {
00376 }
00377
00378 virtual double cost(const location& loc, const double so_far) const;
00379
00380 mutable int calls;
00381 private:
00382 const terrain_map& map_;
00383 const config& cfg_;
00384 int windiness_;
00385 int seed_;
00386 mutable std::map<t_translation::t_terrain, double> cache_;
00387 };
00388
00389 double road_path_calculator::cost(const location& loc,
00390 const double ) const
00391 {
00392 ++calls;
00393 if (loc.x < 0 || loc.y < 0 || loc.x >= static_cast<long>(map_.size()) ||
00394 loc.y >= static_cast<long>(map_.front().size())) {
00395
00396 return (pathfind::cost_calculator::getNoPathValue());
00397 }
00398
00399
00400
00401
00402
00403
00404
00405
00406 double windiness = 1.0;
00407
00408 if (windiness_ > 1) {
00409
00410 unsigned int a = (loc.x + 92872973) ^ 918273;
00411 unsigned int b = (loc.y + 1672517) ^ 128123;
00412 unsigned int c = a*b + a + b + seed_;
00413 unsigned int random = c*c;
00414
00415
00416
00417 int noise = random % (windiness_ * 137) / 137;
00418 windiness += noise;
00419 }
00420
00421 const t_translation::t_terrain c = map_[loc.x][loc.y];
00422 const std::map<t_translation::t_terrain, double>::const_iterator itor = cache_.find(c);
00423 if(itor != cache_.end()) {
00424 return itor->second*windiness;
00425 }
00426
00427 static std::string terrain;
00428 terrain = t_translation::write_terrain_code(c);
00429 double res = getNoPathValue();
00430 if (const config &child = cfg_.find_child("road_cost", "terrain", terrain)) {
00431 res = child["cost"].to_double();
00432 }
00433
00434 cache_.insert(std::pair<t_translation::t_terrain, double>(c,res));
00435 return windiness*res;
00436 }
00437
00438 struct is_valid_terrain
00439 {
00440 is_valid_terrain(const t_translation::t_map& map,
00441 const t_translation::t_list& terrain_list);
00442 bool operator()(int x, int y) const;
00443 private:
00444 t_translation::t_map map_;
00445 const t_translation::t_list& terrain_;
00446 };
00447
00448 is_valid_terrain::is_valid_terrain(const t_translation::t_map& map,
00449 const t_translation::t_list& terrain_list)
00450 : map_(map), terrain_(terrain_list)
00451 {}
00452
00453 bool is_valid_terrain::operator()(int x, int y) const
00454 {
00455 if(x < 0 || x >= static_cast<long>(map_.size()) ||
00456 y < 0 || y >= static_cast<long>(map_[x].size())) {
00457
00458 return false;
00459 }
00460
00461 return std::find(terrain_.begin(),terrain_.end(),map_[x][y]) != terrain_.end();
00462 }
00463
00464 }
00465
00466 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,
00467 size_t min_distance, const std::vector<map_location>& other_castles, int highest_ranking)
00468 {
00469 const map_location loc(x,y);
00470
00471 size_t avg_distance = 0, lowest_distance = 1000;
00472
00473 for(std::vector<map_location>::const_iterator c = other_castles.begin(); c != other_castles.end(); ++c) {
00474 const size_t distance = distance_between(loc,*c);
00475 if(distance < 6) {
00476 return 0;
00477 }
00478
00479 if(distance < lowest_distance) {
00480 lowest_distance = distance;
00481 }
00482
00483 if(distance < min_distance) {
00484 avg_distance = 0;
00485 return -1;
00486 }
00487
00488 avg_distance += distance;
00489 }
00490
00491 if(other_castles.empty() == false) {
00492 avg_distance /= other_castles.size();
00493 }
00494
00495 for(int i = x-1; i <= x+1; ++i) {
00496 for(int j = y-1; j <= y+1; ++j) {
00497 if(!valid_terrain(i,j)) {
00498 return 0;
00499 }
00500 }
00501 }
00502
00503 const int x_from_border = std::min<int>(x - min_x,max_x - x);
00504 const int y_from_border = std::min<int>(y - min_y,max_y - y);
00505
00506 const int border_ranking = min_distance - std::min<int>(x_from_border,y_from_border) +
00507 min_distance - x_from_border - y_from_border;
00508
00509 int current_ranking = border_ranking*2 + avg_distance*10 + lowest_distance*10;
00510 static const int num_nearby_locations = 11*11;
00511
00512 const int max_possible_ranking = current_ranking + num_nearby_locations;
00513
00514 if(max_possible_ranking < highest_ranking) {
00515 return current_ranking;
00516 }
00517
00518 int surrounding_ranking = 0;
00519
00520 for(int xpos = x-5; xpos <= x+5; ++xpos) {
00521 for(int ypos = y-5; ypos <= y+5; ++ypos) {
00522 if(valid_terrain(xpos,ypos)) {
00523 ++surrounding_ranking;
00524 }
00525 }
00526 }
00527
00528 return surrounding_ranking + current_ranking;
00529 }
00530
00531 typedef std::map<t_translation::t_terrain, t_translation::t_list> tcode_list_cache;
00532
00533 static map_location place_village(const t_translation::t_map& map,
00534 const size_t x, const size_t y, const size_t radius, const config& cfg,
00535 tcode_list_cache &adj_liked_cache)
00536 {
00537 const map_location loc(x,y);
00538 std::set<map_location> locs;
00539 get_tiles_radius(loc,radius,locs);
00540 map_location best_loc;
00541 int best_rating = 0;
00542 for(std::set<map_location>::const_iterator i = locs.begin();
00543 i != locs.end(); ++i) {
00544
00545 if(i->x < 0 || i->y < 0 || i->x >= static_cast<long>(map.size()) ||
00546 i->y >= static_cast<long>(map[i->x].size())) {
00547
00548 continue;
00549 }
00550
00551 const t_translation::t_terrain t = map[i->x][i->y];
00552 const std::string str = t_translation::write_terrain_code(t);
00553 if (const config &child = cfg.find_child("village", "terrain", str)) {
00554 tcode_list_cache::iterator l = adj_liked_cache.find(t);
00555 t_translation::t_list *adjacent_liked;
00556 if (l != adj_liked_cache.end()) {
00557 adjacent_liked = &(l->second);
00558 } else {
00559 adj_liked_cache[t] = t_translation::read_list(child["adjacent_liked"]);
00560 adjacent_liked = &(adj_liked_cache[t]);
00561 }
00562
00563 int rating = child["rating"];
00564 map_location adj[6];
00565 get_adjacent_tiles(map_location(i->x,i->y),adj);
00566 for(size_t n = 0; n != 6; ++n) {
00567 if(adj[n].x < 0 || adj[n].y < 0 ||
00568 adj[n].x >= static_cast<long>(map.size()) ||
00569 adj[n].y >= static_cast<long>(map[adj[n].x].size())) {
00570
00571 continue;
00572 }
00573
00574 const t_translation::t_terrain t2 = map[adj[n].x][adj[n].y];
00575 rating += std::count(adjacent_liked->begin(),adjacent_liked->end(),t2);
00576 }
00577
00578 if(rating > best_rating) {
00579 best_loc = map_location(i->x,i->y);
00580 best_rating = rating;
00581 }
00582 }
00583 }
00584
00585 return best_loc;
00586 }
00587
00588 static std::string generate_name(const unit_race& name_generator, const std::string& id,
00589 std::string* base_name=NULL,
00590 utils::string_map* additional_symbols=NULL)
00591 {
00592 const std::vector<std::string>& options = utils::split(string_table[id].str());
00593 if(options.empty() == false) {
00594 const size_t choice = rand()%options.size();
00595 LOG_NG << "calling name generator...\n";
00596 const std::string& name = name_generator.generate_name(unit_race::MALE);
00597 LOG_NG << "name generator returned '" << name << "'\n";
00598 if(base_name != NULL) {
00599 *base_name = name;
00600 }
00601
00602 LOG_NG << "assigned base name..\n";
00603 utils::string_map table;
00604 if(additional_symbols == NULL) {
00605 additional_symbols = &table;
00606 }
00607
00608 LOG_NG << "got additional symbols\n";
00609
00610 (*additional_symbols)["name"] = name;
00611 LOG_NG << "interpolation variables into '" << options[choice] << "'\n";
00612 return utils::interpolate_variables_into_string(options[choice], additional_symbols);
00613 }
00614
00615 return "";
00616 }
00617
00618
00619 static void flood_name(const map_location& start, const std::string& name, std::map<map_location,std::string>& tile_names,
00620 const t_translation::t_match& tile_types, const terrain_map& terrain,
00621 unsigned width, unsigned height,
00622 size_t label_count, std::map<map_location,std::string>* labels, const std::string& full_name) {
00623 map_location adj[6];
00624 get_adjacent_tiles(start,adj);
00625 size_t n;
00626
00627 for (n = 0; n < 6; n++) {
00628
00629
00630 if (unsigned(adj[n].x) >= width / 3 || unsigned(adj[n].y) >= height / 3) {
00631 continue;
00632 }
00633
00634 const t_translation::t_terrain terr = terrain[adj[n].x + (width / 3)][adj[n].y + (height / 3)];
00635 const location loc(adj[n].x, adj[n].y);
00636 if((t_translation::terrain_matches(terr, tile_types)) && (tile_names.find(loc) == tile_names.end())) {
00637 tile_names.insert(std::pair<location, std::string>(loc, name));
00638
00639 if (label_count % 6 == 0) {
00640 labels->insert(std::pair<map_location, std::string>(loc, full_name));
00641 label_count++;
00642 }
00643 flood_name(adj[n], name, tile_names, tile_types, terrain, width, height, label_count++, labels, full_name);
00644 }
00645 }
00646 }
00647
00648 namespace {
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 class terrain_height_mapper
00659 {
00660 public:
00661 explicit terrain_height_mapper(const config& cfg);
00662
00663 bool convert_terrain(const int height) const;
00664 t_translation::t_terrain convert_to() const;
00665
00666 private:
00667 int terrain_height;
00668 t_translation::t_terrain to;
00669 };
00670
00671 terrain_height_mapper::terrain_height_mapper(const config& cfg) :
00672 terrain_height(cfg["height"]),
00673 to(t_translation::GRASS_LAND)
00674 {
00675 const std::string& terrain = cfg["terrain"];
00676 if(terrain != "") {
00677 to = t_translation::read_terrain_code(terrain);
00678 }
00679 }
00680
00681 bool terrain_height_mapper::convert_terrain(const int height) const
00682 {
00683 return height >= terrain_height;
00684 }
00685
00686 t_translation::t_terrain terrain_height_mapper::convert_to() const
00687 {
00688 return to;
00689 }
00690
00691 class terrain_converter
00692 {
00693 public:
00694 explicit terrain_converter(const config& cfg);
00695
00696 bool convert_terrain(const t_translation::t_terrain terrain, const int height, const int temperature) const;
00697 t_translation::t_terrain convert_to() const;
00698
00699 private:
00700 int min_temp, max_temp, min_height, max_height;
00701 t_translation::t_list from;
00702 t_translation::t_terrain to;
00703 };
00704
00705 terrain_converter::terrain_converter(const config& cfg) : min_temp(-1),
00706 max_temp(-1), min_height(-1), max_height(-1),
00707 from(t_translation::read_list(cfg["from"])),
00708 to(t_translation::NONE_TERRAIN)
00709 {
00710 min_temp = cfg["min_temperature"].to_int(-100000);
00711 max_temp = cfg["max_temperature"].to_int(100000);
00712 min_height = cfg["min_height"].to_int(-100000);
00713 max_height = cfg["max_height"].to_int(100000);
00714
00715 const std::string& to_str = cfg["to"];
00716 if(to_str != "") {
00717 to = t_translation::read_terrain_code(to_str);
00718 }
00719 }
00720
00721 bool terrain_converter::convert_terrain(const t_translation::t_terrain terrain,
00722 const int height, const int temperature) const
00723 {
00724 return std::find(from.begin(),from.end(),terrain) != from.end() && height >= min_height && height <= max_height &&
00725 temperature >= min_temp && temperature <= max_temp && to != t_translation::NONE_TERRAIN;
00726 }
00727
00728 t_translation::t_terrain terrain_converter::convert_to() const
00729 {
00730 return to;
00731 }
00732
00733 }
00734
00735 std::string default_generate_map(size_t width, size_t height, size_t island_size, size_t island_off_center,
00736 size_t iterations, size_t hill_size,
00737 size_t max_lakes, size_t nvillages, size_t castle_size, size_t nplayers, bool roads_between_castles,
00738 std::map<map_location,std::string>* labels, const config& cfg)
00739 {
00740 log_scope("map generation");
00741
00742
00743 VALIDATE(is_even(width), _("Random maps with an odd width aren't supported."));
00744
00745 int ticks = SDL_GetTicks();
00746
00747
00748 std::string flatland = cfg["default_flatland"];
00749 if(flatland == "") {
00750 flatland = t_translation::write_terrain_code(t_translation::GRASS_LAND);
00751 }
00752
00753 const t_translation::t_terrain grassland = t_translation::read_terrain_code(flatland);
00754
00755
00756
00757
00758
00759
00760
00761 width *= 3;
00762 height *= 3;
00763
00764 LOG_NG << "generating height map...\n";
00765
00766 const height_map heights = generate_height_map(width,height,iterations,hill_size,island_size,island_off_center);
00767 LOG_NG << "done generating height map...\n";
00768 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
00769
00770 config naming = cfg.child_or_empty("naming");
00771
00772 naming["id"] = "village_naming";
00773 naming["plural_name"] = "villages";
00774
00775
00776 const unit_race name_generator(naming);
00777
00778 std::vector<terrain_height_mapper> height_conversion;
00779
00780 foreach (const config &h, cfg.child_range("height")) {
00781 height_conversion.push_back(terrain_height_mapper(h));
00782 }
00783
00784 terrain_map terrain(width, t_translation::t_list(height, grassland));
00785 size_t x, y;
00786 for(x = 0; x != heights.size(); ++x) {
00787 for(y = 0; y != heights[x].size(); ++y) {
00788 for(std::vector<terrain_height_mapper>::const_iterator i = height_conversion.begin();
00789 i != height_conversion.end(); ++i) {
00790 if(i->convert_terrain(heights[x][y])) {
00791 terrain[x][y] = i->convert_to();
00792 break;
00793 }
00794 }
00795 }
00796 }
00797
00798 std::map<int, t_translation::coordinate> starting_positions;
00799 LOG_NG << output_map(terrain, starting_positions);
00800 LOG_NG << "placed land forms\n";
00801 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816 std::set<location> lake_locs;
00817
00818 std::map<location, std::string> river_names, lake_names, road_names, bridge_names, mountain_names, forest_names, swamp_names;
00819
00820 const size_t nlakes = max_lakes > 0 ? (rand()%max_lakes) : 0;
00821 for(size_t lake = 0; lake != nlakes; ++lake) {
00822 for(int tries = 0; tries != 100; ++tries) {
00823 const int x = rand()%width;
00824 const int y = rand()%height;
00825 if (heights[x][y] > cfg["min_lake_height"].to_int()) {
00826 std::vector<location> river = generate_river(heights,
00827 terrain, x, y, cfg["river_frequency"]);
00828
00829 if(river.empty() == false && labels != NULL) {
00830 std::string base_name;
00831 LOG_NG << "generating name for river...\n";
00832 const std::string& name = generate_name(name_generator,"river_name",&base_name);
00833 LOG_NG << "named river '" << name << "'\n";
00834 size_t name_frequency = 20;
00835 for(std::vector<location>::const_iterator r = river.begin(); r != river.end(); ++r) {
00836
00837 const map_location loc(r->x-width/3,r->y-height/3);
00838
00839 if(((r - river.begin())%name_frequency) == name_frequency/2) {
00840 labels->insert(std::pair<map_location,std::string>(loc,name));
00841 }
00842
00843 river_names.insert(std::pair<location,std::string>(loc,base_name));
00844 }
00845
00846 LOG_NG << "put down river name...\n";
00847 }
00848
00849 LOG_NG << "generating lake...\n";
00850 std::set<location> locs;
00851 bool res = generate_lake(terrain, x, y, cfg["lake_size"], locs);
00852 if(res && labels != NULL) {
00853 bool touches_other_lake = false;
00854
00855 std::string base_name;
00856 const std::string& name = generate_name(name_generator,"lake_name",&base_name);
00857
00858 std::set<location>::const_iterator i;
00859
00860
00861
00862 for(i = locs.begin(); i != locs.end(); ++i) {
00863 if(lake_locs.count(*i) != 0) {
00864 touches_other_lake = true;
00865
00866
00867 const location loc(i->x-width/3,i->y-height/3);
00868 const std::map<location,std::string>::const_iterator other_name = lake_names.find(loc);
00869 if(other_name != lake_names.end()) {
00870 base_name = other_name->second;
00871 }
00872 }
00873
00874 lake_locs.insert(*i);
00875 }
00876
00877 if(!touches_other_lake) {
00878 const map_location loc(x-width/3,y-height/3);
00879 labels->erase(loc);
00880 labels->insert(std::pair<map_location,std::string>(loc,name));
00881 }
00882
00883 for(i = locs.begin(); i != locs.end(); ++i) {
00884 const location loc(i->x-width/3,i->y-height/3);
00885 lake_names.insert(std::pair<location, std::string>(loc, base_name));
00886 }
00887 }
00888
00889 break;
00890 }
00891 }
00892 }
00893
00894 LOG_NG << "done generating rivers...\n";
00895 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
00896
00897 const size_t default_dimensions = 40*40*9;
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907 const height_map temperature_map = generate_height_map(width,height,
00908 cfg["temperature_iterations"].to_int() * width * height / default_dimensions,
00909 cfg["temperature_size"], 0, 0);
00910
00911 LOG_NG << "generated temperature map...\n";
00912 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
00913
00914 std::vector<terrain_converter> converters;
00915 foreach (const config &cv, cfg.child_range("convert")) {
00916 converters.push_back(terrain_converter(cv));
00917 }
00918
00919 LOG_NG << "created terrain converters\n";
00920 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
00921
00922
00923
00924
00925 for(x = 0; x != width; ++x) {
00926 for(y = 0; y != height; ++y) {
00927 for(std::vector<terrain_converter>::const_iterator i = converters.begin(); i != converters.end(); ++i) {
00928 if(i->convert_terrain(terrain[x][y],heights[x][y],temperature_map[x][y])) {
00929 terrain[x][y] = i->convert_to();
00930 break;
00931 }
00932 }
00933 }
00934 }
00935
00936 LOG_NG << "placing villages...\n";
00937 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
00938
00939
00940
00941
00942
00943
00944 std::set<location> villages;
00945
00946 LOG_NG << "placing castles...\n";
00947
00948
00949 const config &castle_config = cfg.child("castle");
00950 if (!castle_config) {
00951 LOG_NG << "Could not find castle configuration\n";
00952 return std::string();
00953 }
00954
00955
00956
00957
00958
00959 const t_translation::t_list list =
00960 t_translation::read_list(castle_config["valid_terrain"]);
00961
00962 const is_valid_terrain terrain_tester(terrain, list);
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973 std::vector<location> castles;
00974 std::set<location> failed_locs;
00975
00976 for(size_t player = 0; player != nplayers; ++player) {
00977 LOG_NG << "placing castle for " << player << "\n";
00978 log_scope("placing castle");
00979 const int min_x = width/3 + 3;
00980 const int min_y = height/3 + 3;
00981 const int max_x = (width/3)*2 - 4;
00982 const int max_y = (height/3)*2 - 4;
00983 int min_distance = castle_config["min_distance"];
00984
00985 location best_loc;
00986 int best_ranking = 0;
00987 for(int x = min_x; x != max_x; ++x) {
00988 for(int y = min_y; y != max_y; ++y) {
00989 const location loc(x,y);
00990 if(failed_locs.count(loc)) {
00991 continue;
00992 }
00993
00994 const int ranking = rank_castle_location(x,y,terrain_tester,min_x,max_x,min_y,max_y,min_distance,castles,best_ranking);
00995 if(ranking <= 0) {
00996 failed_locs.insert(loc);
00997 }
00998
00999 if(ranking > best_ranking) {
01000 best_ranking = ranking;
01001 best_loc = loc;
01002 }
01003 }
01004 }
01005 if(best_ranking == 0) {
01006 ERR_NG << "No castle location found, aborting.\n";
01007 std::string error = _("No valid castle location found. Too many or too few mountain hexes? (please check the 'max hill size' parameter)");
01008 throw mapgen_exception(error);
01009 }
01010 assert(std::find(castles.begin(), castles.end(), best_loc) == castles.end());
01011 castles.push_back(best_loc);
01012
01013 failed_locs.insert(best_loc);
01014 }
01015
01016 LOG_NG << "placing roads...\n";
01017 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
01018
01019
01020
01021
01022 int nroads = cfg["roads"];
01023 if(roads_between_castles) {
01024 nroads += castles.size()*castles.size();
01025 }
01026
01027 std::set<location> bridges;
01028
01029 road_path_calculator calc(terrain,cfg);
01030 for (int road = 0; road != nroads; ++road) {
01031 log_scope("creating road");
01032
01033
01034
01035
01036
01037
01038 location src = random_point_at_side(width/3 + 2,height/3 + 2);
01039 location dst = random_point_at_side(width/3 + 2,height/3 + 2);
01040
01041 src.x += width/3 - 1;
01042 src.y += height/3 - 1;
01043 dst.x += width/3 - 1;
01044 dst.y += height/3 - 1;
01045
01046 if (roads_between_castles && road < int(castles.size() * castles.size())) {
01047 const size_t src_castle = road/castles.size();
01048 const size_t dst_castle = road%castles.size();
01049 if(src_castle >= dst_castle) {
01050 continue;
01051 }
01052
01053 src = castles[src_castle];
01054 dst = castles[dst_castle];
01055 }
01056
01057
01058 else if(src.x == dst.x || src.y == dst.y) {
01059 continue;
01060 }
01061
01062 if (calc.cost(src, 0.0) >= 1000.0 || calc.cost(dst, 0.0) >= 1000.0) {
01063 continue;
01064 }
01065
01066
01067 pathfind::plain_route rt = pathfind::a_star_search(src, dst, 10000.0, &calc, width, height);
01068
01069 std::string road_base_name;
01070 const std::string& name = generate_name(name_generator, "road_name", &road_base_name);
01071 const int name_frequency = 20;
01072 int name_count = 0;
01073
01074 bool on_bridge = false;
01075
01076
01077
01078 for(std::vector<location>::const_iterator step = rt.steps.begin();
01079 step != rt.steps.end(); ++step) {
01080
01081 const int x = step->x;
01082 const int y = step->y;
01083
01084 if(x < 0 || y < 0 || x >= static_cast<long>(width) ||
01085 y >= static_cast<long>(height)) {
01086
01087 continue;
01088 }
01089
01090
01091
01092 if (const config &child = cfg.find_child("road_cost", "terrain",
01093 t_translation::write_terrain_code(terrain[x][y])))
01094 {
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104 const std::string &convert_to_bridge = child["convert_to_bridge"];
01105 if(convert_to_bridge.empty() == false) {
01106 if(step == rt.steps.begin() || step+1 == rt.steps.end())
01107 continue;
01108
01109 const location& last = *(step-1);
01110 const location& next = *(step+1);
01111
01112 location adj[6];
01113 get_adjacent_tiles(*step,adj);
01114
01115 int direction = -1;
01116
01117
01118 if((last == adj[0] && next == adj[3]) || (last == adj[3] && next == adj[0])) {
01119 direction = 0;
01120 }
01121
01122
01123 else if((last == adj[1] && next == adj[4]) || (last == adj[4] && next == adj[1])) {
01124 direction = 1;
01125 }
01126
01127
01128 else if((last == adj[2] && next == adj[5]) || (last == adj[5] && next == adj[2])) {
01129 direction = 2;
01130 }
01131
01132 if(labels != NULL && on_bridge == false) {
01133 on_bridge = true;
01134 std::string bridge_base_name;
01135 const std::string& name = generate_name(name_generator, "bridge_name", &bridge_base_name);
01136 const location loc(x - width / 3, y-height/3);
01137 labels->insert(std::pair<map_location,std::string>(loc,name));
01138 bridge_names.insert(std::pair<location,std::string>(loc, bridge_base_name));
01139 bridges.insert(loc);
01140 }
01141
01142 if(direction != -1) {
01143 const std::vector<std::string> items = utils::split(convert_to_bridge);
01144 if(size_t(direction) < items.size() && items[direction].empty() == false) {
01145 terrain[x][y] = t_translation::read_terrain_code(items[direction]);
01146 }
01147
01148 continue;
01149 }
01150 } else {
01151 on_bridge = false;
01152 }
01153
01154
01155 const std::string &convert_to = child["convert_to"];
01156 if(convert_to.empty() == false) {
01157 const t_translation::t_terrain letter =
01158 t_translation::read_terrain_code(convert_to);
01159 if(labels != NULL && terrain[x][y] != letter && name_count++ == name_frequency && on_bridge == false) {
01160 labels->insert(std::pair<map_location,std::string>(map_location(x-width/3,y-height/3),name));
01161 name_count = 0;
01162 }
01163
01164 terrain[x][y] = letter;
01165 const location loc(x - width / 3, y - height / 3);
01166 road_names.insert(std::pair<location,std::string>(loc, road_base_name));
01167 }
01168 }
01169 }
01170
01171 LOG_NG << "looked at " << calc.calls << " locations\n";
01172 }
01173
01174
01175
01176 for(std::vector<location>::const_iterator c = castles.begin(); c != castles.end(); ++c) {
01177 if(c->valid() == false) {
01178 continue;
01179 }
01180
01181 const int x = c->x;
01182 const int y = c->y;
01183 const int player = c - castles.begin() + 1;
01184 const struct t_translation::coordinate coord(x, y);
01185 starting_positions.insert(std::pair<int, t_translation::coordinate>(player, coord));
01186 terrain[x][y] = t_translation::HUMAN_KEEP;
01187
01188 const int castles[13][2] = {
01189 {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {0, 1}, {-1, 1},
01190 {-2, 1}, {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, {1, -2}
01191 };
01192
01193 for (size_t i = 0; i < castle_size - 1; i++) {
01194 terrain[x+castles[i][0]][y+castles[i][1]] = t_translation::HUMAN_CASTLE;
01195 }
01196
01197
01198 if(labels != NULL) {
01199 labels->erase(location(x-width/3,y-height/3));
01200 for (size_t i = 0; i < castle_size - 1; i++) {
01201 labels->erase(location(x+castles[i][0]-width/3,
01202 y+castles[i][1]-height/3));
01203 }
01204
01205 }
01206
01207 }
01208
01209 LOG_NG << "placed castles\n";
01210 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
01211
01212
01213
01214
01215
01216 for (x = width / 3; x < (width / 3)*2; x++) {
01217 for (y = height / 3; y < (height / 3) * 2;y++) {
01218
01219 const location loc(x - width / 3, y - height / 3);
01220 const t_translation::t_terrain terr = terrain[x][y];
01221 std::string name, base_name;
01222 std::set<std::string> used_names;
01223 if (t_translation::terrain_matches(terr, t_translation::ALL_MOUNTAINS)) {
01224
01225 if ((rand()%15) == 0) {
01226 for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
01227 name = generate_name(name_generator, "mountain_name", &base_name);
01228 }
01229 labels->insert(std::pair<map_location, std::string>(loc, name));
01230 mountain_names.insert(std::pair<location, std::string>(loc, base_name));
01231 }
01232 }
01233 else if (t_translation::terrain_matches(terr, t_translation::ALL_FORESTS)) {
01234
01235 const std::map<location, std::string>::const_iterator forest_name = forest_names.find(loc);
01236 if(forest_name == forest_names.end()) {
01237 for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
01238 name = generate_name(name_generator, "forest_name", &base_name);
01239 }
01240 forest_names.insert(std::pair<location, std::string>(loc, base_name));
01241
01242 flood_name(loc, base_name, forest_names, t_translation::ALL_FORESTS, terrain, width, height, 0, labels, name);
01243 }
01244 }
01245 else if (t_translation::terrain_matches(terr, t_translation::ALL_SWAMPS)) {
01246
01247 const std::map<location, std::string>::const_iterator swamp_name = swamp_names.find(loc);
01248 if(swamp_name == swamp_names.end()) {
01249 for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
01250 name = generate_name(name_generator, "swamp_name", &base_name);
01251 }
01252 swamp_names.insert(std::pair<location, std::string>(loc, base_name));
01253
01254 flood_name(loc, base_name, swamp_names, t_translation::ALL_SWAMPS, terrain, width, height, 0, labels, name);
01255 }
01256 }
01257
01258 }
01259 }
01260
01261 if (nvillages > 0)
01262 {
01263 config naming_cfg = cfg.child_or_empty("village_naming");
01264
01265 naming_cfg["id"] = "village_naming";
01266 naming_cfg["plural_name"] = "villages";
01267
01268 const unit_race village_names_generator(naming_cfg);
01269
01270
01271 const size_t tiles_per_village = ((width*height)/9)/nvillages;
01272 size_t village_x = 1, village_y = 1;
01273
01274
01275
01276
01277 while(village_x*village_y < tiles_per_village) {
01278 if(village_x < village_y) {
01279 ++village_x;
01280 } else {
01281 ++village_y;
01282 }
01283 }
01284
01285 std::set<std::string> used_names;
01286 tcode_list_cache adj_liked_cache;
01287
01288 for(size_t vx = 0; vx < width; vx += village_x) {
01289 LOG_NG << "village at " << vx << "\n";
01290 for(size_t vy = rand()%village_y; vy < height; vy += village_y) {
01291
01292 const size_t add_x = rand()%3;
01293 const size_t add_y = rand()%3;
01294 const size_t x = (vx + add_x) - 1;
01295 const size_t y = (vy + add_y) - 1;
01296
01297 const map_location res = place_village(terrain,x,y,2,cfg,adj_liked_cache);
01298
01299 if(res.x >= static_cast<long>(width) / 3 &&
01300 res.x < static_cast<long>(width * 2) / 3 &&
01301 res.y >= static_cast<long>(height) / 3 &&
01302 res.y < static_cast<long>(height * 2) / 3) {
01303
01304 const std::string str =
01305 t_translation::write_terrain_code(terrain[res.x][res.y]);
01306 if (const config &child = cfg.find_child("village", "terrain", str))
01307 {
01308 const std::string &convert_to = child["convert_to"];
01309 if(convert_to != "") {
01310 terrain[res.x][res.y] =
01311 t_translation::read_terrain_code(convert_to);
01312
01313 villages.insert(res);
01314
01315 if(labels != NULL && naming_cfg.empty() == false) {
01316 const map_location loc(res.x-width/3,res.y-height/3);
01317
01318 map_location adj[6];
01319 get_adjacent_tiles(loc,adj);
01320
01321 std::string name_type = "village_name";
01322 const t_translation::t_list
01323 field = t_translation::t_list(1, t_translation::GRASS_LAND),
01324 forest = t_translation::t_list(1, t_translation::FOREST),
01325 mountain = t_translation::t_list(1, t_translation::MOUNTAIN),
01326 hill = t_translation::t_list(1, t_translation::HILL);
01327
01328 size_t field_count = 0, forest_count = 0, mountain_count = 0, hill_count = 0;
01329
01330 utils::string_map symbols;
01331
01332 size_t n;
01333 for(n = 0; n != 6; ++n) {
01334 const std::map<location,std::string>::const_iterator road_name = road_names.find(adj[n]);
01335 if(road_name != road_names.end()) {
01336 symbols["road"] = road_name->second;
01337 name_type = "village_name_road";
01338 break;
01339 }
01340
01341 const std::map<location,std::string>::const_iterator river_name = river_names.find(adj[n]);
01342 if(river_name != river_names.end()) {
01343 symbols["river"] = river_name->second;
01344 name_type = "village_name_river";
01345
01346 const std::map<location,std::string>::const_iterator bridge_name = bridge_names.find(adj[n]);
01347 if(bridge_name != bridge_names.end()) {
01348
01349 symbols["bridge"] = bridge_name->second;
01350 name_type = "village_name_river_bridge";
01351 }
01352
01353 break;
01354 }
01355
01356 const std::map<location,std::string>::const_iterator forest_name = forest_names.find(adj[n]);
01357 if(forest_name != forest_names.end()) {
01358 symbols["forest"] = forest_name->second;
01359 name_type = "village_name_forest";
01360 break;
01361 }
01362
01363 const std::map<location,std::string>::const_iterator lake_name = lake_names.find(adj[n]);
01364 if(lake_name != lake_names.end()) {
01365 symbols["lake"] = lake_name->second;
01366 name_type = "village_name_lake";
01367 break;
01368 }
01369
01370 const std::map<location,std::string>::const_iterator mountain_name = mountain_names.find(adj[n]);
01371 if(mountain_name != mountain_names.end()) {
01372 symbols["mountain"] = mountain_name->second;
01373 name_type = "village_name_mountain";
01374 break;
01375 }
01376
01377 const std::map<location,std::string>::const_iterator swamp_name = swamp_names.find(adj[n]);
01378 if(swamp_name != swamp_names.end()) {
01379 symbols["swamp"] = swamp_name->second;
01380 name_type = "village_name_swamp";
01381 break;
01382 }
01383
01384 const t_translation::t_terrain terr =
01385 terrain[adj[n].x+width/3][adj[n].y+height/3];
01386
01387 if(std::count(field.begin(),field.end(),terr) > 0) {
01388 ++field_count;
01389 } else if(std::count(forest.begin(),forest.end(),terr) > 0) {
01390 ++forest_count;
01391 } else if(std::count(hill.begin(),hill.end(),terr) > 0) {
01392 ++hill_count;
01393 } else if(std::count(mountain.begin(),mountain.end(),terr) > 0) {
01394 ++mountain_count;
01395 }
01396 }
01397
01398 if(n == 6) {
01399 if(field_count == 6) {
01400 name_type = "village_name_grassland";
01401 } else if(forest_count >= 2) {
01402 name_type = "village_name_forest";
01403 } else if(mountain_count >= 1) {
01404 name_type = "village_name_mountain_anonymous";
01405 } else if(hill_count >= 2) {
01406 name_type = "village_name_hill";
01407 }
01408 }
01409
01410 std::string name;
01411 for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
01412 name = generate_name(village_names_generator,name_type,NULL,&symbols);
01413 }
01414
01415 used_names.insert(name);
01416 labels->insert(std::pair<map_location,std::string>(loc,name));
01417 }
01418 }
01419 }
01420 }
01421 }
01422 }
01423 }
01424
01425 LOG_NG << "placed villages\n";
01426 LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
01427
01428 return output_map(terrain, starting_positions);
01429 }
01430
01431 namespace {
01432
01433 typedef std::map<std::string,map_generator*> generator_map;
01434 generator_map generators;
01435
01436 }
01437
01438 #ifdef TEST_MAPGEN
01439
01440
01441 int main(int argc, char** argv)
01442 {
01443 int x = 50, y = 50, iterations = 50,
01444 hill_size = 50, lakes=3,
01445 nvillages = 25, nplayers = 2;
01446 if(argc >= 2) {
01447 x = atoi(argv[1]);
01448 }
01449
01450 if(argc >= 3) {
01451 y = atoi(argv[2]);
01452 }
01453
01454 if(argc >= 4) {
01455 iterations = atoi(argv[3]);
01456 }
01457
01458 if(argc >= 5) {
01459 hill_size = atoi(argv[4]);
01460 }
01461
01462 if(argc >= 6) {
01463 lakes = atoi(argv[5]);
01464 }
01465
01466 if(argc >= 7) {
01467 nvillages = atoi(argv[6]);
01468 }
01469
01470 if(argc >= 8) {
01471 nplayers = atoi(argv[7]);
01472 }
01473
01474 srand(time(NULL));
01475 std::cout << generate_map(x,y,iterations,hill_size,lakes,nvillages,nplayers) << "\n";
01476 }
01477
01478 #endif