00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "global.hpp"
00022
00023 #include "cavegen.hpp"
00024 #include "foreach.hpp"
00025 #include "log.hpp"
00026 #include "map.hpp"
00027 #include "pathfind/pathfind.hpp"
00028 #include "serialization/string_utils.hpp"
00029 #include "util.hpp"
00030
00031 static lg::log_domain log_engine("engine");
00032 #define LOG_NG LOG_STREAM(info, log_engine)
00033
00034 cave_map_generator::cave_map_generator(const config &cfg) :
00035 wall_(t_translation::CAVE_WALL),
00036 clear_(t_translation::CAVE),
00037 village_(t_translation::UNDERGROUND_VILLAGE),
00038 castle_(t_translation::DWARVEN_CASTLE),
00039 keep_(t_translation::DWARVEN_KEEP),
00040 map_(),
00041 starting_positions_(),
00042 chamber_ids_(),
00043 chambers_(),
00044 passages_(),
00045 res_(),
00046 cfg_(cfg ? cfg : config()),
00047 width_(50),
00048 height_(50),
00049 village_density_(0),
00050 flipx_(false),
00051 flipy_(false)
00052 {
00053 width_ = cfg_["map_width"];
00054 height_ = cfg_["map_height"];
00055
00056 village_density_ = cfg_["village_density"];
00057
00058 int r = rand() % 100;
00059 int chance = cfg_["flipx_chance"];
00060
00061 flipx_ = r < chance;
00062
00063 LOG_NG << "flipx: " << r << " < " << chance << " = " << (flipx_ ? "true" : "false") << "\n";
00064 flipy_ = rand() % 100 < cfg_["flipy_chance"];
00065 }
00066
00067 std::string cave_map_generator::config_name() const
00068 {
00069 return "";
00070 }
00071
00072 size_t cave_map_generator::translate_x(size_t x) const
00073 {
00074 if(flipx_) {
00075 x = width_ - x - 1;
00076 }
00077
00078 return x;
00079 }
00080
00081 size_t cave_map_generator::translate_y(size_t y) const
00082 {
00083 if(flipy_) {
00084 y = height_ - y - 1;
00085 }
00086
00087 return y;
00088 }
00089
00090 std::string cave_map_generator::create_map(const std::vector<std::string>& args)
00091 {
00092 const config res = create_scenario(args);
00093 return res["data"];
00094 }
00095
00096 config cave_map_generator::create_scenario(const std::vector<std::string>& )
00097 {
00098 map_ = t_translation::t_map(width_ + 2 * gamemap::default_border,
00099 t_translation::t_list(height_ + 2 * gamemap::default_border, wall_));
00100 chambers_.clear();
00101 passages_.clear();
00102
00103 res_.clear();
00104 if (const config &settings = cfg_.child("settings")) {
00105 res_ = settings;
00106 }
00107
00108 LOG_NG << "creating scenario....\n";
00109 generate_chambers();
00110
00111 LOG_NG << "placing chambers...\n";
00112 for(std::vector<chamber>::const_iterator c = chambers_.begin(); c != chambers_.end(); ++c) {
00113 place_chamber(*c);
00114 }
00115
00116 LOG_NG << "placing passages...\n";
00117
00118 for(std::vector<passage>::const_iterator p = passages_.begin(); p != passages_.end(); ++p) {
00119 place_passage(*p);
00120 }
00121
00122 LOG_NG << "outputting map....\n";
00123
00124 config& map = res_.add_child("map");
00125 map["data"] = t_translation::write_game_map(map_, starting_positions_);
00126 map["usage"] = "map";
00127 map["border_size"] = gamemap::default_border;
00128
00129 LOG_NG << "returning result...\n";
00130
00131 return res_;
00132 }
00133
00134 void cave_map_generator::build_chamber(map_location loc, std::set<map_location>& locs, size_t size, size_t jagged)
00135 {
00136 if(size == 0 || locs.count(loc) != 0 || !on_board(loc))
00137 return;
00138
00139 locs.insert(loc);
00140
00141 map_location adj[6];
00142 get_adjacent_tiles(loc,adj);
00143 for(size_t n = 0; n != 6; ++n) {
00144 if((rand() % 100) < (100l - static_cast<long>(jagged))) {
00145 build_chamber(adj[n],locs,size-1,jagged);
00146 }
00147 }
00148 }
00149
00150 void cave_map_generator::generate_chambers()
00151 {
00152 foreach (const config &ch, cfg_.child_range("chamber"))
00153 {
00154
00155 if (ch.has_attribute("chance") && (rand() % 100) < ch["chance"].to_int()) {
00156 continue;
00157 }
00158
00159 const std::string &xpos = ch["x"];
00160 const std::string &ypos = ch["y"];
00161
00162 size_t min_xpos = 0, min_ypos = 0, max_xpos = width_, max_ypos = height_;
00163
00164 if (!xpos.empty()) {
00165 const std::vector<std::string>& items = utils::split(xpos, '-');
00166 if(items.empty() == false) {
00167 min_xpos = atoi(items.front().c_str()) - 1;
00168 max_xpos = atoi(items.back().c_str());
00169 }
00170 }
00171
00172 if (!ypos.empty()) {
00173 const std::vector<std::string>& items = utils::split(ypos, '-');
00174 if(items.empty() == false) {
00175 min_ypos = atoi(items.front().c_str()) - 1;
00176 max_ypos = atoi(items.back().c_str());
00177 }
00178 }
00179
00180 const size_t x = translate_x(min_xpos + (rand()%(max_xpos-min_xpos)));
00181 const size_t y = translate_y(min_ypos + (rand()%(max_ypos-min_ypos)));
00182
00183 int chamber_size = ch["size"].to_int(3);
00184 int jagged_edges = ch["jagged"];
00185
00186 chamber new_chamber;
00187 new_chamber.center = map_location(x,y);
00188 build_chamber(new_chamber.center,new_chamber.locs,chamber_size,jagged_edges);
00189
00190 const config &items = ch.child("items");
00191 new_chamber.items = items ? &items : NULL;
00192
00193 const std::string &id = ch["id"];
00194 if (!id.empty()) {
00195 chamber_ids_[id] = chambers_.size();
00196 }
00197
00198 chambers_.push_back(new_chamber);
00199
00200 foreach (const config &p, ch.child_range("passage"))
00201 {
00202 const std::string &dst = p["destination"];
00203
00204
00205 const std::map<std::string,size_t>::const_iterator itor = chamber_ids_.find(dst);
00206 if(itor == chamber_ids_.end())
00207 continue;
00208
00209 assert(itor->second < chambers_.size());
00210
00211 passages_.push_back(passage(new_chamber.center, chambers_[itor->second].center, p));
00212 }
00213 }
00214 }
00215
00216 void cave_map_generator::place_chamber(const chamber& c)
00217 {
00218 for(std::set<map_location>::const_iterator i = c.locs.begin(); i != c.locs.end(); ++i) {
00219 set_terrain(*i,clear_);
00220 }
00221
00222 if (c.items == NULL || c.locs.empty()) return;
00223
00224 size_t index = 0;
00225 foreach (const config::any_child &it, c.items->all_children_range())
00226 {
00227 config cfg = it.cfg;
00228 config &filter = cfg.child("filter");
00229 config* object_filter = NULL;
00230 if (config &object = cfg.child("object")) {
00231 if (config &of = object.child("filter"))
00232 object_filter = &of;
00233 }
00234
00235 if (!it.cfg["same_location_as_previous"].to_bool()) {
00236 index = rand()%c.locs.size();
00237 }
00238 std::string loc_var = it.cfg["store_location_as"];
00239
00240 std::set<map_location>::const_iterator loc = c.locs.begin();
00241 std::advance(loc,index);
00242
00243 cfg["x"] = loc->x + 1;
00244 cfg["y"] = loc->y + 1;
00245
00246 if (filter) {
00247 filter["x"] = loc->x + 1;
00248 filter["y"] = loc->y + 1;
00249 }
00250
00251 if (object_filter) {
00252 (*object_filter)["x"] = loc->x + 1;
00253 (*object_filter)["y"] = loc->y + 1;
00254 }
00255
00256
00257 if (it.key == "side" && !it.cfg["no_castle"].to_bool()) {
00258 place_castle(it.cfg["side"].to_int(-1), *loc);
00259 }
00260
00261 res_.add_child(it.key, cfg);
00262
00263 if(!loc_var.empty()) {
00264 config &temp = res_.add_child("event");
00265 temp["name"] = "prestart";
00266 config &xcfg = temp.add_child("set_variable");
00267 xcfg["name"] = loc_var + "_x";
00268 xcfg["value"] = loc->x + 1;
00269 config &ycfg = temp.add_child("set_variable");
00270 ycfg["name"] = loc_var + "_y";
00271 ycfg["value"] = loc->y + 1;
00272 }
00273 }
00274 }
00275
00276 struct passage_path_calculator : pathfind::cost_calculator
00277 {
00278 passage_path_calculator(const t_translation::t_map& mapdata,
00279 t_translation::t_terrain wall, double laziness, size_t windiness):
00280 map_(mapdata), wall_(wall), laziness_(laziness), windiness_(windiness)
00281 {}
00282
00283 virtual double cost(const map_location& loc, const double so_far) const;
00284 private:
00285 const t_translation::t_map& map_;
00286 t_translation::t_terrain wall_;
00287 double laziness_;
00288 size_t windiness_;
00289 };
00290
00291 double passage_path_calculator::cost(const map_location& loc, const double) const
00292 {
00293 double res = 1.0;
00294 if (map_[loc.x + gamemap::default_border][loc.y + gamemap::default_border] == wall_) {
00295 res = laziness_;
00296 }
00297
00298 if(windiness_ > 1) {
00299 res *= double(rand()%windiness_);
00300 }
00301
00302 return res;
00303 }
00304
00305 void cave_map_generator::place_passage(const passage& p)
00306 {
00307 const std::string& chance = p.cfg["chance"];
00308 if(chance != "" && (rand()%100) < atoi(chance.c_str())) {
00309 return;
00310 }
00311
00312
00313 int windiness = p.cfg["windiness"];
00314 double laziness = std::max<double>(1.0, p.cfg["laziness"].to_double());
00315
00316 passage_path_calculator calc(map_,wall_,laziness,windiness);
00317
00318 pathfind::plain_route rt = a_star_search(p.src, p.dst, 10000.0, &calc, width_, height_);
00319
00320 int width = std::max<int>(1, p.cfg["width"].to_int());
00321 int jagged = p.cfg["jagged"];
00322
00323 for(std::vector<map_location>::const_iterator i = rt.steps.begin(); i != rt.steps.end(); ++i) {
00324 std::set<map_location> locs;
00325 build_chamber(*i,locs,width,jagged);
00326 for(std::set<map_location>::const_iterator j = locs.begin(); j != locs.end(); ++j) {
00327 set_terrain(*j,clear_);
00328 }
00329 }
00330 }
00331
00332 void cave_map_generator::set_terrain(map_location loc, t_translation::t_terrain t)
00333 {
00334 if (on_board(loc)) {
00335 if (t == clear_ && (rand() % 1000) < village_density_) {
00336 t = village_;
00337 }
00338
00339 t_translation::t_terrain& c = map_[loc.x + gamemap::default_border][loc.y + gamemap::default_border];
00340 if(c == clear_ || c == wall_ || c == village_) {
00341 c = t;
00342 }
00343 }
00344 }
00345
00346 void cave_map_generator::place_castle(int starting_position, const map_location &loc)
00347 {
00348 if (starting_position != -1) {
00349 set_terrain(loc, keep_);
00350
00351 t_translation::coordinate coord(
00352 loc.x + gamemap::default_border
00353 , loc.y + gamemap::default_border);
00354 starting_positions_[starting_position] = coord;
00355 }
00356
00357 map_location adj[6];
00358 get_adjacent_tiles(loc,adj);
00359 for(size_t n = 0; n != 6; ++n) {
00360 set_terrain(adj[n],castle_);
00361 }
00362 }
00363