mapgen_dialog.cpp

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

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