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