cavegen.cpp

Go to the documentation of this file.
00001 /* $Id: cavegen.cpp 53182 2012-02-23 20:59:48Z fendrin $ */
00002 /*
00003    Copyright (C) 2003 - 2012 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 as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  * @file
00018  * Map-generator for caves.
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>& /*args*/)
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         // If there is only a chance of the chamber appearing, deal with that here.
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             // Find the destination of this passage
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         // If this is a side, place a castle for the side
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Wed May 23 2012 01:02:34 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs