mapgen_dialog.cpp

Go to the documentation of this file.
00001 /* $Id: mapgen_dialog.cpp 53169 2012-02-23 02:39:58Z 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 #include "global.hpp"
00017 
00018 #define GETTEXT_DOMAIN "wesnoth-lib"
00019 
00020 #include "mapgen_dialog.hpp"
00021 
00022 #include "display.hpp"
00023 #include "gettext.hpp"
00024 #include "log.hpp"
00025 #include "map.hpp"
00026 #include "marked-up_text.hpp"
00027 #include "show_dialog.hpp"
00028 
00029 #include "widgets/slider.hpp"
00030 
00031 static lg::log_domain log_engine("engine");
00032 #define DBG_NG LOG_STREAM(debug, log_engine)
00033 
00034 namespace {
00035     const size_t max_island = 10;
00036     const size_t max_coastal = 5;
00037 }
00038 
00039 default_map_generator::default_map_generator(const config &cfg) :
00040     default_width_(40),
00041     default_height_(40),
00042     width_(40),
00043     height_(40),
00044     island_size_(0),
00045     iterations_(1000),
00046     hill_size_(10),
00047     max_lakes_(20),
00048     nvillages_(25),
00049     castle_size_(9),
00050     nplayers_(2),
00051     link_castles_(true),
00052     cfg_(cfg ? cfg : config())
00053 {
00054     if (!cfg) return;
00055 
00056     int width = cfg["map_width"];
00057     if (width > 0)
00058         width_ = width;
00059 
00060     int height = cfg["map_height"];
00061     if (height > 0)
00062         height_ = height;
00063 
00064     default_width_ = width_;
00065     default_height_ = height_;
00066 
00067     int iterations = cfg["iterations"];
00068     if (iterations > 0)
00069         iterations_ = iterations;
00070 
00071     int hill_size = cfg["hill_size"];
00072     if (hill_size > 0)
00073         hill_size_ = hill_size;
00074 
00075     int max_lakes = cfg["max_lakes"];
00076     if (max_lakes > 0)
00077         max_lakes_ = max_lakes;
00078 
00079     int nvillages = cfg["villages"];
00080     if (nvillages > 0)
00081         nvillages_ = nvillages;
00082 
00083     int castle_size = cfg["castle_size"];
00084     if (castle_size > 0)
00085         castle_size_ = castle_size;
00086 
00087     int nplayers = cfg["players"];
00088     if (nplayers > 0)
00089         nplayers_ = nplayers;
00090 
00091     int island_size = cfg["island_size"];
00092     if (island_size > 0)
00093         island_size_ = island_size;
00094 }
00095 
00096 bool default_map_generator::allow_user_config() const { return true; }
00097 
00098 void default_map_generator::user_config(display& disp)
00099 {
00100     const resize_lock prevent_resizing;
00101     const events::event_context dialog_events_context;
00102 
00103     CVideo& screen = disp.video();
00104 
00105     const int width = 600;
00106     const int height = 400;
00107     const int xpos = screen.getx()/2 - width/2;
00108     int ypos = screen.gety()/2 - height/2;
00109 
00110     gui::button close_button(screen,_("Close"));
00111     std::vector<gui::button*> buttons(1,&close_button);
00112 
00113     gui::dialog_frame f(screen,_("Map Generator"),gui::dialog_frame::default_style,true,&buttons);
00114     f.layout(xpos,ypos,width,height);
00115     f.draw();
00116 
00117     SDL_Rect dialog_rect = create_rect(xpos, ypos, width, height);
00118     surface_restorer dialog_restorer(&screen,dialog_rect);
00119 
00120     const std::string& players_label = _("Players:");
00121     const std::string& width_label = _("Width:");
00122     const std::string& height_label = _("Height:");
00123     const std::string& iterations_label = _("Number of hills:");
00124     const std::string& hillsize_label = _("Max hill size:");
00125     const std::string& villages_label = _("Villages:");
00126     const std::string& castlesize_label = _("Castle size:");
00127     const std::string& landform_label = _("Landform:");
00128 
00129     SDL_Rect players_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,players_label,0,0);
00130     SDL_Rect width_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,width_label,0,0);
00131     SDL_Rect height_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,height_label,0,0);
00132     SDL_Rect iterations_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,iterations_label,0,0);
00133     SDL_Rect hillsize_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,hillsize_label,0,0);
00134     SDL_Rect villages_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,villages_label,0,0);
00135     SDL_Rect castlesize_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,castlesize_label,0,0);
00136     SDL_Rect landform_rect = font::draw_text(NULL,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,landform_label,0,0);
00137 
00138     const int horz_margin = 15;
00139     const int text_right = xpos + horz_margin +
00140             std::max<int>(std::max<int>(std::max<int>(std::max<int>(std::max<int>(std::max<int>(
00141                  players_rect.w,width_rect.w),height_rect.w),iterations_rect.w),hillsize_rect.w),villages_rect.w),castlesize_rect.w);
00142 
00143     players_rect.x = text_right - players_rect.w;
00144     width_rect.x = text_right - width_rect.w;
00145     height_rect.x = text_right - height_rect.w;
00146     iterations_rect.x = text_right - iterations_rect.w;
00147     hillsize_rect.x = text_right - hillsize_rect.w;
00148     villages_rect.x = text_right - villages_rect.w;
00149     castlesize_rect.x = text_right - castlesize_rect.w;
00150     landform_rect.x = text_right - landform_rect.w;
00151 
00152     const int vertical_margin = 20;
00153     players_rect.y = ypos + vertical_margin*2;
00154     width_rect.y = players_rect.y + players_rect.h + vertical_margin;
00155     height_rect.y = width_rect.y + width_rect.h + vertical_margin;
00156     iterations_rect.y = height_rect.y + height_rect.h + vertical_margin;
00157     hillsize_rect.y = iterations_rect.y + iterations_rect.h + vertical_margin;
00158     villages_rect.y = hillsize_rect.y + hillsize_rect.h + vertical_margin;
00159     castlesize_rect.y = villages_rect.y + iterations_rect.h + vertical_margin;
00160     landform_rect.y = castlesize_rect.y + villages_rect.h + vertical_margin;
00161 
00162     const int right_space = 150;
00163 
00164     const int slider_left = text_right + 10;
00165     const int slider_right = xpos + width - horz_margin - right_space;
00166     SDL_Rect slider_rect = create_rect(slider_left
00167             , players_rect.y
00168             , slider_right - slider_left
00169             , players_rect.h);
00170 
00171     gui::slider players_slider(screen);
00172     players_slider.set_location(slider_rect);
00173     players_slider.set_min(2);
00174     players_slider.set_max(gamemap::MAX_PLAYERS);
00175     players_slider.set_value(nplayers_);
00176 
00177     const int min_width = 20;
00178     const int max_width = 100;
00179     const int max_height = 100;
00180     const int extra_size_per_player = 2;
00181 
00182     slider_rect.y = width_rect.y;
00183     gui::slider width_slider(screen);
00184     width_slider.set_location(slider_rect);
00185     width_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
00186     width_slider.set_max(max_width);
00187     width_slider.set_value(width_);
00188 
00189     slider_rect.y = height_rect.y;
00190     gui::slider height_slider(screen);
00191     height_slider.set_location(slider_rect);
00192     height_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
00193     height_slider.set_max(max_height);
00194     height_slider.set_value(height_);
00195 
00196     const int min_iterations = 10;
00197     const int max_iterations = 3000;
00198 
00199     slider_rect.y = iterations_rect.y;
00200     gui::slider iterations_slider(screen);
00201     iterations_slider.set_location(slider_rect);
00202     iterations_slider.set_min(min_iterations);
00203     iterations_slider.set_max(max_iterations);
00204     iterations_slider.set_value(iterations_);
00205 
00206     const int min_hillsize = 1;
00207     const int max_hillsize = 50;
00208 
00209     slider_rect.y = hillsize_rect.y;
00210     gui::slider hillsize_slider(screen);
00211     hillsize_slider.set_location(slider_rect);
00212     hillsize_slider.set_min(min_hillsize);
00213     hillsize_slider.set_max(max_hillsize);
00214     hillsize_slider.set_value(hill_size_);
00215 
00216     const int min_villages = 0;
00217     const int max_villages = 50;
00218 
00219     slider_rect.y = villages_rect.y;
00220     gui::slider villages_slider(screen);
00221     villages_slider.set_location(slider_rect);
00222     villages_slider.set_min(min_villages);
00223     villages_slider.set_max(max_villages);
00224     villages_slider.set_value(nvillages_);
00225 
00226     const int min_castlesize = 2;
00227     const int max_castlesize = 14;
00228 
00229     slider_rect.y = castlesize_rect.y;
00230     gui::slider castlesize_slider(screen);
00231     castlesize_slider.set_location(slider_rect);
00232     castlesize_slider.set_min(min_castlesize);
00233     castlesize_slider.set_max(max_castlesize);
00234     castlesize_slider.set_value(castle_size_);
00235 
00236 
00237     const int min_landform = 0;
00238     const int max_landform = int(max_island);
00239     slider_rect.y = landform_rect.y;
00240     gui::slider landform_slider(screen);
00241     landform_slider.set_location(slider_rect);
00242     landform_slider.set_min(min_landform);
00243     landform_slider.set_max(max_landform);
00244     landform_slider.set_value(island_size_);
00245 
00246     SDL_Rect link_rect = slider_rect;
00247     link_rect.y = link_rect.y + link_rect.h + vertical_margin;
00248 
00249     gui::button link_castles(screen,_("Roads between castles"),gui::button::TYPE_CHECK);
00250     link_castles.set_check(link_castles_);
00251     link_castles.set_location(link_rect);
00252 
00253     while(true) {
00254         nplayers_ = players_slider.value();
00255         width_ = width_slider.value();
00256         height_ = height_slider.value();
00257         iterations_ = iterations_slider.value();
00258         hill_size_ = hillsize_slider.value();
00259         nvillages_ = villages_slider.value();
00260         castle_size_ = castlesize_slider.value();
00261         island_size_ = landform_slider.value();
00262 
00263         dialog_restorer.restore();
00264         close_button.set_dirty(true);
00265         if (close_button.pressed())
00266             break;
00267 
00268         players_slider.set_dirty();
00269         width_slider.set_dirty();
00270         height_slider.set_dirty();
00271         iterations_slider.set_dirty();
00272         hillsize_slider.set_dirty();
00273         villages_slider.set_dirty();
00274         castlesize_slider.set_dirty();
00275         landform_slider.set_dirty();
00276         link_castles.set_dirty();
00277 
00278         width_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
00279         height_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
00280 
00281         events::raise_process_event();
00282         events::raise_draw_event();
00283 
00284         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,players_label,players_rect.x,players_rect.y);
00285         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,width_label,width_rect.x,width_rect.y);
00286         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,height_label,height_rect.x,height_rect.y);
00287         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,iterations_label,iterations_rect.x,iterations_rect.y);
00288         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,hillsize_label,hillsize_rect.x,hillsize_rect.y);
00289         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,villages_label,villages_rect.x,villages_rect.y);
00290         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,castlesize_label,castlesize_rect.x,castlesize_rect.y);
00291         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,landform_label,landform_rect.x,landform_rect.y);
00292 
00293         font::draw_text(&screen, screen_area(), font::SIZE_NORMAL,
00294             font::NORMAL_COLOR, str_cast(nplayers_),
00295             slider_right + horz_margin, players_rect.y);
00296 
00297         font::draw_text(&screen, screen_area(), font::SIZE_NORMAL,
00298             font::NORMAL_COLOR, str_cast(width_),
00299             slider_right + horz_margin, width_rect.y);
00300 
00301         font::draw_text(&screen, screen_area(), font::SIZE_NORMAL,
00302             font::NORMAL_COLOR, str_cast(height_),
00303             slider_right+horz_margin,height_rect.y);
00304 
00305         std::stringstream villages_str;
00306         villages_str << nvillages_ << _("/1000 tiles");
00307         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,villages_str.str(),
00308                         slider_right+horz_margin,villages_rect.y);
00309 
00310         font::draw_text(&screen, screen_area(), font::SIZE_NORMAL,
00311             font::NORMAL_COLOR, str_cast(castle_size_),
00312             slider_right + horz_margin, castlesize_rect.y);
00313 
00314         std::stringstream landform_str;
00315         landform_str << gettext(island_size_ == 0 ? N_("Inland") : (island_size_ < max_coastal ? N_("Coastal") : N_("Island")));
00316         font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,landform_str.str(),
00317                         slider_right+horz_margin,landform_rect.y);
00318 
00319         update_rect(xpos,ypos,width,height);
00320 
00321         disp.update_display();
00322         disp.delay(100);
00323         events::pump();
00324     }
00325 
00326     link_castles_ = link_castles.checked();
00327 }
00328 
00329 std::string default_map_generator::name() const { return "default"; }
00330 
00331 std::string default_map_generator::config_name() const
00332 {
00333     if (const config &c = cfg_.child("scenario"))
00334         return c["name"];
00335 
00336     return std::string();
00337 }
00338 
00339 std::string default_map_generator::create_map(const std::vector<std::string>& args)
00340 {
00341     return generate_map(args);
00342 }
00343 
00344 std::string default_map_generator::generate_map(const std::vector<std::string>& /*args*/, std::map<map_location,std::string>* labels)
00345 {
00346     // the random generator thinks odd widths are nasty, so make them even
00347     if (is_odd(width_))
00348         ++width_;
00349 
00350     size_t iterations = (iterations_*width_*height_)/(default_width_*default_height_);
00351     size_t island_size = 0;
00352     size_t island_off_center = 0;
00353     size_t max_lakes = max_lakes_;
00354 
00355     if(island_size_ >= max_coastal) {
00356 
00357         //islands look good with much fewer iterations than normal, and fewer lake
00358         iterations /= 10;
00359         max_lakes /= 9;
00360 
00361         //the radius of the island should be up to half the width of the map
00362         const size_t island_radius = 50 + ((max_island - island_size_)*50)/(max_island - max_coastal);
00363         island_size = (island_radius*(width_/2))/100;
00364     } else if(island_size_ > 0) {
00365         DBG_NG << "coastal...\n";
00366         //the radius of the island should be up to twice the width of the map
00367         const size_t island_radius = 40 + ((max_coastal - island_size_)*40)/max_coastal;
00368         island_size = (island_radius*width_*2)/100;
00369         island_off_center = std::min<size_t>(width_,height_);
00370         DBG_NG << "calculated coastal params...\n";
00371     }
00372 
00373     // A map generator can fail so try a few times to get a map before aborting.
00374     std::string map;
00375     // Keep a copy of labels as it can be written to by the map generator func
00376     std::map<map_location,std::string> labels_copy;
00377     std::string error_message;
00378     int tries = 10;
00379     do {
00380         if (labels) {
00381                 labels_copy = *labels;
00382         }
00383         try{
00384             map = default_generate_map(width_, height_, island_size, island_off_center,
00385                 iterations, hill_size_, max_lakes, (nvillages_ * width_ * height_) / 1000,
00386                 castle_size_, nplayers_, link_castles_, &labels_copy, cfg_);
00387             error_message = "";
00388         }
00389         catch (mapgen_exception& exc){
00390             error_message = exc.message;
00391         }
00392         --tries;
00393     } while (tries && map.empty());
00394     if (labels) {
00395         labels->swap(labels_copy);
00396     }
00397 
00398     if (error_message != "")
00399         throw mapgen_exception(error_message);
00400 
00401     return map;
00402 }
00403 
00404 config default_map_generator::create_scenario(const std::vector<std::string>& args)
00405 {
00406     DBG_NG << "creating scenario...\n";
00407 
00408     config res = cfg_.child_or_empty("scenario");
00409 
00410     DBG_NG << "got scenario data...\n";
00411 
00412     std::map<map_location,std::string> labels;
00413     DBG_NG << "generating map...\n";
00414     config& map = res.add_child("map");
00415     try{
00416         map["data"] = generate_map(args,&labels);
00417     }
00418     catch (mapgen_exception& exc){
00419         map["data"] = "";
00420         res["error_message"] = exc.message;
00421     }
00422     DBG_NG << "done generating map..\n";
00423 
00424     for(std::map<map_location,std::string>::const_iterator i =
00425             labels.begin(); i != labels.end(); ++i) {
00426 
00427         if(i->first.x >= 0 && i->first.y >= 0 &&
00428                 i->first.x < static_cast<long>(width_) &&
00429                 i->first.y < static_cast<long>(height_)) {
00430 
00431             config& label = res.add_child("label");
00432             label["text"] = i->second;
00433             i->first.write(label);
00434         }
00435     }
00436 
00437     return res;
00438 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:05 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs