mapgen.cpp

Go to the documentation of this file.
00001 /* $Id: mapgen.cpp 24925 2008-03-21 04:54:52Z alink $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 //! @file mapgen.cpp
00016 //! Map-generator, with standalone testprogram.
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 //! Generate a height-map.
00060 //! Basically we generate alot of hills,
00061 //! each hill being centered at a certain point,
00062 //! with a certain radius - being a half sphere.
00063 //! Hills are combined additively to form a bumpy surface.
00064 //! The size of each hill varies randomly from 1-hill_size.
00065 //! We generate 'iterations' hills in total.
00066 //! The range of heights is normalized to 0-1000.
00067 //! 'island_size' controls whether or not the map should tend toward an island shape,
00068 //! and if so, how large the island should be.
00069 //! Hills with centers that are more than 'island_size' away from
00070 //! the center of the map will be inverted (i.e. be valleys).
00071 //! 'island_size' as 0 indicates no island.
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         // (x1,y1) is the location of the hill,
00109         // and 'radius' is the radius of the hill.
00110         // We iterate over all points, (x2,y2).
00111         // The formula for the amount the height is increased by is:
00112         // radius - sqrt((x2-x1)^2 + (y2-y1)^2) with negative values ignored.
00113         //
00114         // Rather than iterate over every single point, we can reduce the points
00115         // to a rectangle that contains all the positive values for this formula --
00116         // the rectangle is given by min_x,max_x,min_y,max_y.
00117 
00118         // Is this a negative hill? (i.e. a valley)
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         // We have to check whether this is actually a valley
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     // Find the highest and lowest points on the map for normalization:
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     // Normalize the heights to the range 0-1000:
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 //! Generate a lake.
00190 //! It will create water at (x,y), and then have 'lake_fall_off' % chance
00191 //! to make another water tile in each of the directions n,s,e,w.
00192 //! In each of the directions it does make another water tile,
00193 //! it will have 'lake_fall_off'/2 % chance to make another water tile
00194 //! in each of the directions. This will continue recursively.
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 //! River generation.
00224 //! Rivers have a source, and then keep on flowing
00225 //! until they meet another body of water, which they flow into,
00226 //! or until they reach the edge of the map.
00227 //! Rivers will always flow downhill, except that they can flow
00228 //! a maximum of 'river_uphill' uphill.
00229 //! This is to represent the water eroding the higher ground lower.
00230 //!
00231 //! Every possible path for a river will be attempted, in random order,
00232 //! and the first river path that can be found that makes the river flow
00233 //! into another body of water or off the map will be used.
00234 //!
00235 //! If no path can be found, then the river's generation will be aborted,
00236 //! and false will be returned.
00237 //! true is returned if the river is generated successfully.
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     // If we're at the end of the river
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         // Generate the river
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     // Mark that we have attempted from this location
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 //! Return a random tile at one of the borders of a map
00307 //! that is of the given dimensions.
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 //! Function which, given the map will output it in a valid format.
00323 static std::string output_map(const terrain_map& terrain,
00324         std::map<int, t_translation::coordinate> starting_positions)
00325 {
00326     // Remember that we only want the middle 1/9th of the map.
00327     // All other segments of the map are there only to give
00328     // the important middle part some context.
00329     // We also have a border so also adjust for that.
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     // Since the map has been resized,
00347     // the starting locations also need to be fixed
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 //! Calculate the cost of building a road over terrain.
00360 //! For use in the a_star_search algorithm.
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                   // Find out how windy roads should be.
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& /*src*/, const location& loc,
00381     const double /*so_far*/) 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     // We multiply the cost by a random amount,
00391     // depending upon how 'windy' the road should be.
00392     // If windiness is 1, that will mean that the cost is always genuine,
00393     // and so the road always takes the shortest path.
00394     // If windiness is greater than 1, we sometimes over-report costs
00395     // for some segments, to make the road wind a little.
00396 
00397     double windiness = 1.0;
00398 
00399     if (windiness_ > 1) {
00400         // modified pseudo_random taken from builder.cpp
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         // this is just "big random number modulo windiness_"
00406         // but avoid the "modulo by a low number (like 2)"
00407         // because it can increase arithmetic patterns
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 // the configuration file should contain a number of [height] tags:
00618 //   [height]
00619 //     height=n
00620 //     terrain=x
00621 //   [/height]
00622 // These should be in descending order of n.
00623 // They are checked sequentially, and if height is greater than n for that tile,
00624 // then the tile is set to terrain type x.
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 } // end anon namespace
00701 
00702 //! Generate the map.
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     // Odd widths are nasty
00711     VALIDATE(is_even(width), _("Random maps with an odd width aren't supported."));
00712 
00713     int ticks = SDL_GetTicks();
00714 
00715     // Find out what the 'flatland' on this map is, i.e. grassland.
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     // We want to generate a map that is 9 times bigger
00724     // than the actual size desired.
00725     // Only the middle part of the map will be used,
00726     // but the rest is so that the map we end up using
00727     // can have a context (e.g. rivers flowing from
00728     // out of the map into the map, same for roads, etc.)
00729     width *= 3;
00730     height *= 3;
00731 
00732     LOG_NG << "generating height map...\n";
00733     // Generate the height of everything.
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     // Make a dummy race for generating names
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     // Now that we have our basic set of flatland/hills/mountains/water,
00772     // we can place lakes and rivers on the map.
00773     // All rivers are sourced at a lake.
00774     // Lakes must be in high land - at least 'min_lake_height'.
00775     // (Note that terrain below a certain altitude may be made
00776     // into bodies of water in the code above - i.e. 'sea',
00777     // but these are not considered 'lakes', because
00778     // they are not sources of rivers).
00779     //
00780     // We attempt to place 'max_lakes' lakes.
00781     // Each lake will be placed at a random location,
00782     // if that random location meets the minimum terrain requirements for a lake.
00783     // We will also attempt to source a river from each lake.
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                     // Only generate a name if the lake hasn't touched any other lakes,
00828                     // so that we don't end up with one big lake with multiple names.
00829                     for(i = locs.begin(); i != locs.end(); ++i) {
00830                         if(lake_locs.count(*i) != 0) {
00831                             touches_other_lake = true;
00832 
00833                             // Reassign the name of this lake to be the same as the other lake
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     //! Convert grassland terrain to other types of flat terrain.
00867     //! We generate a 'temperature map' which uses the height generation algorithm
00868     //! to generate the temperature levels all over the map.
00869     //! Then we can use a combination of height and terrain
00870     //! to divide terrain up into more interesting types than the default.
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     // Iterate over every flatland tile, and determine
00889     // what type of flatland it is, based on our [convert] tags.
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     //! Place villages in a 'grid', to make placing fair,
00905     //! but with villages displaced from their position
00906     //! according to terrain and randomness, to add some variety.
00907     std::set<location> villages;
00908 
00909     LOG_NG << "placing castles...\n";
00910 
00911     //! Try to find configuration for castles.
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     //! Castle configuration tag contains a 'valid_terrain' attribute
00919     //! which is a list of terrains that the castle may appear on.
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     //! Attempt to place castles at random.
00926     //! Once we have placed castles, we run a sanity check
00927     //! to make sure that the castles are well-placed.
00928     //! If the castles are not well-placed, we try again.
00929     //! Definition of 'well-placed' is if no two castles
00930     //! are closer than 'min_distance' hexes from each other,
00931     //! and the castles appear on a terrain listed in 'valid_terrain'.
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         // Make sure the location can't get a second castle.
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     // Place roads.
00978     // We select two tiles at random locations on the borders
00979     // of the map, and try to build roads between them.
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         //! We want the locations to be on the portion of the map
00992         //! we're actually going to use, since roads on other parts of the map
00993         //! won't have any influence, and doing it like this will be quicker.
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         // If the road isn't very interesting (on the same border), don't draw it.
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         // Search a path out for the road
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         // Draw the road.
01032         // If the search failed, rt.steps will simply be empty.
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             // Find the configuration which tells us
01046             // what to convert this tile to, to make it into a road.
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                 // Convert to bridge means that we want to convert
01051                 // depending upon the direction the road is going.
01052                 // Typically it will be in a format like,
01053                 // convert_to_bridge=\,|,/
01054                 // '|' will be used if the road is going north-south
01055                 // '/' will be used if the road is going south west-north east
01056                 // '\' will be used if the road is going south east-north west
01057                 // The terrain will be left unchanged otherwise
01058                 // (if there is no clear direction).
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                     // If we are going north-south
01073                     if((last == adj[0] && next == adj[3]) || (last == adj[3] && next == adj[0])) {
01074                         direction = 0;
01075                     }
01076 
01077                     // If we are going south west-north east
01078                     else if((last == adj[1] && next == adj[4]) || (last == adj[4] && next == adj[1])) {
01079                         direction = 1;
01080                     }
01081 
01082                     // If we are going south east-north west
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                 // Just a plain terrain substitution for a road
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     // Now that road drawing is done, we can plonk down the castles.
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         // Remove all labels under the castle tiles
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         // First we work out the size of the x and y distance between villages
01174         const size_t tiles_per_village = ((width*height)/9)/nvillages;
01175         size_t village_x = 1, village_y = 1;
01176 
01177         // Alternate between incrementing the x and y value.
01178         // When they are high enough to equal or exceed the tiles_per_village,
01179         // then we have them to the value we want them at.
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 //! Standalone testprogram for the mapgenerator.
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

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs