The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
default_map_generator.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "global.hpp"
16 
17 #define GETTEXT_DOMAIN "wesnoth-lib"
18 
20 
22 #include "gettext.hpp"
23 #include "log.hpp"
24 #include "map/map.hpp"
25 #include "marked-up_text.hpp"
26 #include "show_dialog.hpp"
27 #include "seed_rng.hpp"
28 #include "widgets/slider.hpp"
29 #include "sdl/rect.hpp"
30 
31 static lg::log_domain log_engine("engine");
32 #define DBG_NG LOG_STREAM(debug, log_engine)
33 
34 namespace {
35  const size_t max_island = 10;
36  const size_t max_coastal = 5;
37 }
38 
40  default_width_(40),
41  default_height_(40),
42  width_(40),
43  height_(40),
44  island_size_(0),
45  iterations_(1000),
46  hill_size_(10),
47  max_lakes_(20),
48  nvillages_(25),
49  castle_size_(9),
50  nplayers_(2),
51  link_castles_(true),
52  show_labels_(true),
53  cfg_(cfg ? cfg : config())
54 {
55  if (!cfg) return;
56 
57  int width = cfg["map_width"];
58  if (width > 0)
59  width_ = width;
60 
61  int height = cfg["map_height"];
62  if (height > 0)
63  height_ = height;
64 
67 
68  int iterations = cfg["iterations"];
69  if (iterations > 0)
70  iterations_ = iterations;
71 
72  int hill_size = cfg["hill_size"];
73  if (hill_size > 0)
74  hill_size_ = hill_size;
75 
76  int max_lakes = cfg["max_lakes"];
77  if (max_lakes > 0)
78  max_lakes_ = max_lakes;
79 
80  int nvillages = cfg["villages"];
81  if (nvillages > 0)
82  nvillages_ = nvillages;
83 
84  int castle_size = cfg["castle_size"];
85  if (castle_size > 0)
86  castle_size_ = castle_size;
87 
88  int nplayers = cfg["players"];
89  if (nplayers > 0)
90  nplayers_ = nplayers;
91 
92  int island_size = cfg["island_size"];
93  if (island_size > 0)
94  island_size_ = island_size;
95 }
96 
97 bool default_map_generator::allow_user_config() const { return true; }
98 
100 {
101  const events::event_context dialog_events_context;
102 
103  CVideo& screen = v;
104 
105  const int width = 600;
106  const int height = 400;
107  const int xpos = screen.getx()/2 - width/2;
108  int ypos = screen.gety()/2 - height/2;
109 
110  gui::button close_button(screen,_("Close"));
111  std::vector<gui::button*> buttons(1,&close_button);
112 
113  gui::dialog_frame f(screen,_("Map Generator"),gui::dialog_frame::default_style,true,&buttons);
114  f.layout(xpos,ypos,width,height);
115  f.draw();
116 
117  SDL_Rect dialog_rect = sdl::create_rect(xpos, ypos, width, height);
118  surface_restorer dialog_restorer(&screen,dialog_rect);
119 
120  const std::string& players_label = _("Players:");
121  const std::string& width_label = _("Width:");
122  const std::string& height_label = _("Height:");
123  const std::string& iterations_label = _("Number of hills:");
124  const std::string& hillsize_label = _("Max hill size:");
125  const std::string& villages_label = _("Villages:");
126  const std::string& castlesize_label = _("Castle size:");
127  const std::string& landform_label = _("Landform:");
128 
129  SDL_Rect players_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,players_label,0,0);
130  SDL_Rect width_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,width_label,0,0);
131  SDL_Rect height_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,height_label,0,0);
132  SDL_Rect iterations_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,iterations_label,0,0);
133  SDL_Rect hillsize_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,hillsize_label,0,0);
134  SDL_Rect villages_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,villages_label,0,0);
135  SDL_Rect castlesize_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,castlesize_label,0,0);
136  SDL_Rect landform_rect = font::draw_text(nullptr,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,landform_label,0,0);
137 
138  const int horz_margin = 15;
139  const int text_right = xpos + horz_margin +
140  std::max<int>(std::max<int>(std::max<int>(std::max<int>(std::max<int>(std::max<int>(
141  players_rect.w,width_rect.w),height_rect.w),iterations_rect.w),hillsize_rect.w),villages_rect.w),castlesize_rect.w);
142 
143  players_rect.x = text_right - players_rect.w;
144  width_rect.x = text_right - width_rect.w;
145  height_rect.x = text_right - height_rect.w;
146  iterations_rect.x = text_right - iterations_rect.w;
147  hillsize_rect.x = text_right - hillsize_rect.w;
148  villages_rect.x = text_right - villages_rect.w;
149  castlesize_rect.x = text_right - castlesize_rect.w;
150  landform_rect.x = text_right - landform_rect.w;
151 
152  const int vertical_margin = 20;
153  players_rect.y = ypos + vertical_margin*2;
154  width_rect.y = players_rect.y + players_rect.h + vertical_margin;
155  height_rect.y = width_rect.y + width_rect.h + vertical_margin;
156  iterations_rect.y = height_rect.y + height_rect.h + vertical_margin;
157  hillsize_rect.y = iterations_rect.y + iterations_rect.h + vertical_margin;
158  villages_rect.y = hillsize_rect.y + hillsize_rect.h + vertical_margin;
159  castlesize_rect.y = villages_rect.y + iterations_rect.h + vertical_margin;
160  landform_rect.y = castlesize_rect.y + villages_rect.h + vertical_margin;
161 
162  const int right_space = 150;
163 
164  const int slider_left = text_right + 10;
165  const int slider_right = xpos + width - horz_margin - right_space;
166  SDL_Rect slider_rect = sdl::create_rect(slider_left
167  , players_rect.y
168  , slider_right - slider_left
169  , players_rect.h);
170 
171  gui::slider players_slider(screen);
172  players_slider.set_location(slider_rect);
173  players_slider.set_min(2);
174  players_slider.set_max(gamemap::MAX_PLAYERS);
175  players_slider.set_value(nplayers_);
176 
177  const int min_width = 20;
178  const int max_width = 100;
179  const int max_height = 100;
180  const int extra_size_per_player = 2;
181 
182  slider_rect.y = width_rect.y;
183  gui::slider width_slider(screen);
184  width_slider.set_location(slider_rect);
185  width_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
186  width_slider.set_max(max_width);
187  width_slider.set_value(width_);
188 
189  slider_rect.y = height_rect.y;
190  gui::slider height_slider(screen);
191  height_slider.set_location(slider_rect);
192  height_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
193  height_slider.set_max(max_height);
194  height_slider.set_value(height_);
195 
196  const int min_iterations = 10;
197  const int max_iterations = 3000;
198 
199  slider_rect.y = iterations_rect.y;
200  gui::slider iterations_slider(screen);
201  iterations_slider.set_location(slider_rect);
202  iterations_slider.set_min(min_iterations);
203  iterations_slider.set_max(max_iterations);
204  iterations_slider.set_value(iterations_);
205 
206  const int min_hillsize = 1;
207  const int max_hillsize = 50;
208 
209  slider_rect.y = hillsize_rect.y;
210  gui::slider hillsize_slider(screen);
211  hillsize_slider.set_location(slider_rect);
212  hillsize_slider.set_min(min_hillsize);
213  hillsize_slider.set_max(max_hillsize);
214  hillsize_slider.set_value(hill_size_);
215 
216  const int min_villages = 0;
217  const int max_villages = 50;
218 
219  slider_rect.y = villages_rect.y;
220  gui::slider villages_slider(screen);
221  villages_slider.set_location(slider_rect);
222  villages_slider.set_min(min_villages);
223  villages_slider.set_max(max_villages);
224  villages_slider.set_value(nvillages_);
225 
226  const int min_castlesize = 2;
227  const int max_castlesize = 14;
228 
229  slider_rect.y = castlesize_rect.y;
230  gui::slider castlesize_slider(screen);
231  castlesize_slider.set_location(slider_rect);
232  castlesize_slider.set_min(min_castlesize);
233  castlesize_slider.set_max(max_castlesize);
234  castlesize_slider.set_value(castle_size_);
235 
236 
237  const int min_landform = 0;
238  const int max_landform = int(max_island);
239  slider_rect.y = landform_rect.y;
240  gui::slider landform_slider(screen);
241  landform_slider.set_location(slider_rect);
242  landform_slider.set_min(min_landform);
243  landform_slider.set_max(max_landform);
244  landform_slider.set_value(island_size_);
245 
246  SDL_Rect link_rect = slider_rect;
247  link_rect.y = link_rect.y + link_rect.h + vertical_margin;
248 
249  gui::button link_castles(screen,_("Roads between castles"),gui::button::TYPE_CHECK);
250  link_castles.set_check(link_castles_);
251  link_castles.set_location(link_rect);
252 
253  SDL_Rect labels_rect = link_rect;
254  labels_rect.y = labels_rect.y + labels_rect.h + vertical_margin;
255 
256  gui::button show_labels(screen,_("Show labels"),gui::button::TYPE_CHECK);
257  show_labels.set_check(show_labels_);
258  show_labels.set_location(labels_rect);
259 
260  while(true) {
261  nplayers_ = players_slider.value();
262  width_ = width_slider.value();
263  height_ = height_slider.value();
264  iterations_ = iterations_slider.value();
265  hill_size_ = hillsize_slider.value();
266  nvillages_ = villages_slider.value();
267  castle_size_ = castlesize_slider.value();
268  island_size_ = landform_slider.value();
269 
270  dialog_restorer.restore();
271  close_button.set_dirty(true);
272  if (close_button.pressed())
273  break;
274 
275  players_slider.set_dirty();
276  width_slider.set_dirty();
277  height_slider.set_dirty();
278  iterations_slider.set_dirty();
279  hillsize_slider.set_dirty();
280  villages_slider.set_dirty();
281  castlesize_slider.set_dirty();
282  landform_slider.set_dirty();
283  link_castles.set_dirty();
284  show_labels.set_dirty();
285 
286  width_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
287  height_slider.set_min(min_width+(players_slider.value()-2)*extra_size_per_player);
288 
289  f.draw();
292 
293  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,players_label,players_rect.x,players_rect.y);
294  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,width_label,width_rect.x,width_rect.y);
295  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,height_label,height_rect.x,height_rect.y);
296  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,iterations_label,iterations_rect.x,iterations_rect.y);
297  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,hillsize_label,hillsize_rect.x,hillsize_rect.y);
298  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,villages_label,villages_rect.x,villages_rect.y);
299  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,castlesize_label,castlesize_rect.x,castlesize_rect.y);
300  font::draw_text(&screen,screen_area(),font::SIZE_NORMAL,font::NORMAL_COLOR,landform_label,landform_rect.x,landform_rect.y);
301 
303  font::NORMAL_COLOR, std::to_string(nplayers_),
304  slider_right + horz_margin, players_rect.y);
305 
307  font::NORMAL_COLOR, std::to_string(width_),
308  slider_right + horz_margin, width_rect.y);
309 
311  font::NORMAL_COLOR, std::to_string(height_),
312  slider_right+horz_margin,height_rect.y);
313 
314  std::stringstream villages_str;
315  villages_str << nvillages_ << _("/1000 tiles");
317  slider_right+horz_margin,villages_rect.y);
318 
320  font::NORMAL_COLOR, std::to_string(castle_size_),
321  slider_right + horz_margin, castlesize_rect.y);
322 
323  std::stringstream landform_str;
324  landform_str << translation::gettext(island_size_ == 0 ? N_("Inland") : (island_size_ < max_coastal ? N_("Coastal") : N_("Island")));
326  slider_right+horz_margin,landform_rect.y);
327 
328  update_rect(xpos,ypos,width,height);
329 
330  v.flip();
331  CVideo::delay(100);
332  events::pump();
333  }
334 
335  link_castles_ = link_castles.checked();
336  show_labels_ = show_labels.checked();
337 }
338 
339 std::string default_map_generator::name() const { return "default"; }
340 
342 {
343  if (const config &c = cfg_.child("scenario"))
344  return c["name"];
345 
346  return std::string();
347 }
348 
349 std::string default_map_generator::create_map(boost::optional<boost::uint32_t> randomseed)
350 {
351  return generate_map(nullptr, randomseed);
352 }
353 
354 std::string default_map_generator::generate_map(std::map<map_location,std::string>* labels, boost::optional<boost::uint32_t> randomseed)
355 {
356  boost::uint32_t seed;
357  if(const boost::uint32_t* pseed = randomseed.get_ptr()) {
358  seed = *pseed;
359  }
360  else {
361  seed = seed_rng::next_seed();
362  }
363 
364  // Suppress labels?
365  if ( !show_labels_ )
366  labels = nullptr;
367 
368  // the random generator thinks odd widths are nasty, so make them even
369  if (is_odd(width_))
370  ++width_;
371 
372  size_t iterations = (iterations_*width_*height_)/(default_width_*default_height_);
373  size_t island_size = 0;
374  size_t island_off_center = 0;
375  size_t max_lakes = max_lakes_;
376 
377  if(island_size_ >= max_coastal) {
378 
379  //islands look good with much fewer iterations than normal, and fewer lake
380  iterations /= 10;
381  max_lakes /= 9;
382 
383  //the radius of the island should be up to half the width of the map
384  const size_t island_radius = 50 + ((max_island - island_size_)*50)/(max_island - max_coastal);
385  island_size = (island_radius*(width_/2))/100;
386  } else if(island_size_ > 0) {
387  DBG_NG << "coastal...\n";
388  //the radius of the island should be up to twice the width of the map
389  const size_t island_radius = 40 + ((max_coastal - island_size_)*40)/max_coastal;
390  island_size = (island_radius*width_*2)/100;
391  island_off_center = std::min<size_t>(width_,height_);
392  DBG_NG << "calculated coastal params...\n";
393  }
394 
395  // A map generator can fail so try a few times to get a map before aborting.
396  std::string map;
397  // Keep a copy of labels as it can be written to by the map generator func
398  std::map<map_location,std::string> labels_copy;
399  std::map<map_location,std::string> * labels_ptr = labels ? &labels_copy : nullptr;
400  std::string error_message;
401  //initilize the job outside the loop so that we really get a different result everytime we run the loop.
402  default_map_generator_job job(seed);
403  int tries = 10;
404  do {
405  if (labels) {
406  // Reset the labels.
407  labels_copy = *labels;
408  }
409  try{
410  map = job.default_generate_map(width_, height_, island_size, island_off_center,
411  iterations, hill_size_, max_lakes, (nvillages_ * width_ * height_) / 1000,
412  castle_size_, nplayers_, link_castles_, labels_ptr, cfg_);
413  error_message = "";
414  }
415  catch (mapgen_exception& exc){
416  error_message = exc.message;
417  }
418  --tries;
419  } while (tries && map.empty());
420  if (labels) {
421  labels->swap(labels_copy);
422  }
423 
424  if (error_message != "")
425  throw mapgen_exception(error_message);
426 
427  return map;
428 }
429 
430 config default_map_generator::create_scenario(boost::optional<boost::uint32_t> randomseed)
431 {
432  DBG_NG << "creating scenario...\n";
433 
434  config res = cfg_.child_or_empty("scenario");
435 
436  DBG_NG << "got scenario data...\n";
437 
438  std::map<map_location,std::string> labels;
439  DBG_NG << "generating map...\n";
440 
441  try{
442  res["map_data"] = generate_map(&labels, randomseed);
443  }
444  catch (mapgen_exception& exc){
445  res["map_data"] = "";
446  res["error_message"] = exc.message;
447  }
448  DBG_NG << "done generating map..\n";
449 
450  for(std::map<map_location,std::string>::const_iterator i =
451  labels.begin(); i != labels.end(); ++i) {
452 
453  if(i->first.x >= 0 && i->first.y >= 0 &&
454  i->first.x < static_cast<long>(width_) &&
455  i->first.y < static_cast<long>(height_)) {
456 
457  config& label = res.add_child("label");
458  label["text"] = i->second;
459  label["category"] = "villages";
460  i->first.write(label);
461  }
462  }
463 
464  return res;
465 }
std::string generate_map(std::map< map_location, std::string > *labels, boost::optional< boost::uint32_t > randomseed)
void set_check(bool check)
Definition: button.cpp:352
std::string default_generate_map(size_t width, size_t height, size_t island_size, size_t island_off_center, size_t iterations, size_t hill_size, size_t max_lakes, size_t nvillages, size_t castle_size, size_t nplayers, bool roads_between_castles, std::map< map_location, std::string > *labels, const config &cfg)
Generate the map.
static const style default_style
Definition: show_dialog.hpp:69
const GLfloat * c
Definition: glew.h:12741
void set_value(int value)
Definition: slider.cpp:87
int value() const
Definition: slider.cpp:112
boost::uint32_t uint32_t
Definition: xbrz.hpp:45
void set_max(int value)
Definition: slider.cpp:77
Definition: video.hpp:58
game_display * screen
Definition: resources.cpp:27
void flip()
Definition: video.cpp:496
bool is_odd(T num)
Definition: util.hpp:37
config create_scenario(boost::optional< boost::uint32_t > randomseed)
std::string config_name() const
Return a friendly name for the generator used to differentiate between different configs of the same ...
const config & child_or_empty(const std::string &key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:722
static lg::log_domain log_engine("engine")
const SDL_Color NORMAL_COLOR
Definition: font.cpp:564
void set_location(int x, int y)
Definition: slider.hpp:47
const int SIZE_NORMAL
Definition: font.hpp:58
SDL_Rect screen_area()
Definition: video.cpp:135
dimension_measurements layout(int x, int y, int w, int h)
void set_dirty(bool dirty=true)
Definition: widget.cpp:217
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
void restore() const
Definition: utils.cpp:2496
int gety() const
Definition: video.cpp:481
std::string create_map(boost::optional< boost::uint32_t > randomseed)
Creates a new map and returns it.
const GLdouble * v
Definition: glew.h:1359
config & add_child(const std::string &key)
Definition: config.cpp:743
#define DBG_NG
bool pressed()
Definition: button.cpp:770
static UNUSEDNOWARN std::string gettext(const char *str)
Definition: gettext.hpp:64
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
void raise_draw_event()
Definition: events.cpp:565
void pump()
Definition: events.cpp:336
SDL_Rect draw_text(surface &dst, const SDL_Rect &area, int size, const SDL_Color &color, const std::string &txt, int x, int y, bool use_tooltips, int style)
Function to draw text on a surface.
GLuint res
Definition: glew.h:9258
bool allow_user_config() const
Returns true if the map generator has an interactive screen, which allows the user to modify how the ...
void raise_process_event()
Definition: events.cpp:539
int getx() const
Definition: video.cpp:472
default_map_generator(const config &game_config)
size_t i
Definition: function.cpp:1057
void user_config(CVideo &v)
Display the interactive screen, which allows the user to modify how the generator behaves...
#define N_(String)
Definition: gettext.hpp:90
GLint GLint GLint GLint GLint GLint GLsizei GLsizei height
Definition: glew.h:1220
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
Definition: rect.cpp:28
uint32_t next_seed()
Definition: seed_rng.cpp:52
Contains the SDL_Rect helper code.
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:658
bool checked() const
Definition: button.cpp:381
Standard logging facilities (interface).
void set_min(int value)
Definition: slider.cpp:67
std::string message
Definition: exceptions.hpp:29
static void delay(unsigned int milliseconds)
Definition: video.cpp:490
std::string name() const
Returns a string identifying the generator by name.
virtual void set_location(SDL_Rect const &rect)
Definition: widget.cpp:85
GLint GLint GLint GLint GLint GLint GLsizei width
Definition: glew.h:1220
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
void update_rect(const SDL_Rect &)
Definition: dummy_video.cpp:27
GLsizei const GLcharARB ** string
Definition: glew.h:4503
GLclampf f
Definition: glew.h:3024