cavegen.cpp

Go to the documentation of this file.
00001 /* $Id: cavegen.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 cavegen.cpp 
00016 //! Map-generator for caves.
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>& /*args*/)
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         // If there is only a chance of the chamber appearing, deal with that here.
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             // Find the destination of this passage
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         // If this is a side, place a castle for the side
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& /*src*/,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 

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