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