The Battle for Wesnoth  1.13.10+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 - 2017 by David White <dave@whitevine.net>
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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
21 #include "gettext.hpp"
22 #include "log.hpp"
23 #include "map/map.hpp"
24 #include "seed_rng.hpp"
25 #include "video.hpp"
26 
27 static lg::log_domain log_engine("engine");
28 #define DBG_NG LOG_STREAM(debug, log_engine)
29 
30 namespace {
31  const int max_island = 10;
32  const int max_coastal = 5;
33 }
34 
36  : width(std::max(0, cfg["map_width"].to_int(40)))
37  , height(std::max(0, cfg["map_height"].to_int(40)))
38  , default_width(width)
39  , default_height(height)
40  , nplayers(std::max(0, cfg["players"].to_int(2)))
41  , nvillages(std::max(0, cfg["villages"].to_int(25)))
42  , iterations(std::max(0, cfg["iterations"].to_int(1000)))
43  , hill_size(std::max(0, cfg["hill_size"].to_int(10)))
44  , castle_size(std::max(0, cfg["castle_size"].to_int(9)))
45  , island_size(std::max(0, cfg["island_size"].to_int(0)))
46  , island_off_center(0)
47  , max_lakes(std::max(0, cfg["max_lakes"].to_int(20)))
48  , link_castles(true)
49  , show_labels(true)
50 {
51 }
52 
54  : cfg_(cfg)
55  , data_(cfg)
56 {
57 }
58 
59 bool default_map_generator::allow_user_config() const { return true; }
60 
62 {
64 }
65 
66 std::string default_map_generator::name() const { return "default"; }
67 
69 {
70  if (const config &c = cfg_.child("scenario"))
71  return c["name"];
72 
73  return std::string();
74 }
75 
76 std::string default_map_generator::create_map(boost::optional<uint32_t> randomseed)
77 {
78  return generate_map(nullptr, randomseed);
79 }
80 
81 std::string default_map_generator::generate_map(std::map<map_location,std::string>* labels, boost::optional<uint32_t> randomseed)
82 {
83  uint32_t seed;
84  if(const uint32_t* pseed = randomseed.get_ptr()) {
85  seed = *pseed;
86  } else {
87  seed = seed_rng::next_seed();
88  }
89 
90  /* We construct a copy of the generator data and modify it as needed. This ensures every time
91  * this function is called the generator job gets a fresh set of settings, and that the internal
92  * copy of the settings are never touched except by the settings dialog.
93  *
94  * The original data is still used for conditional checks and calculations, but any modifications
95  * should be done on this object.
96  */
97  generator_data job_data = data_;
98 
99  // Suppress labels?
100  if(!data_.show_labels) {
101  labels = nullptr;
102  }
103 
104  // The random generator thinks odd widths are nasty, so make them even
105  if(is_odd(data_.width)) {
106  ++job_data.width;
107  }
108 
110  job_data.island_size = 0;
111  job_data.nvillages = (data_.nvillages * data_.width * data_.height) / 1000;
112  job_data.island_off_center = 0;
113 
114  if(data_.island_size >= max_coastal) {
115  // Islands look good with much fewer iterations than normal, and fewer lakes
116  job_data.iterations /= 10;
117  job_data.max_lakes /= 9;
118 
119  // The radius of the island should be up to half the width of the map
120  const int island_radius = 50 + ((max_island - data_.island_size) * 50)/(max_island - max_coastal);
121  job_data.island_size = (island_radius * (data_.width/2))/100;
122  } else if(data_.island_size > 0) {
123  // The radius of the island should be up to twice the width of the map
124  const int island_radius = 40 + ((max_coastal - data_.island_size) * 40)/max_coastal;
125  job_data.island_size = (island_radius * data_.width * 2)/100;
126  job_data.island_off_center = std::min(data_.width, data_.height);
127  DBG_NG << "calculated coastal params...\n";
128  }
129 
130  // A map generator can fail so try a few times to get a map before aborting.
131  std::string map;
132 
133  // Keep a copy of labels as it can be written to by the map generator func
134  std::map<map_location,std::string> labels_copy;
135  std::map<map_location,std::string>* labels_ptr = labels ? &labels_copy : nullptr;
136 
137  // Iinitilize the job outside the loop so that we really get a different result everytime we run the loop.
138  default_map_generator_job job(seed);
139 
140  int tries = 10;
141  std::string error_message;
142  do {
143  // Reset the labels.
144  if(labels) {
145  labels_copy = *labels;
146  }
147 
148  try {
149  map = job.default_generate_map(job_data, labels_ptr, cfg_);
150  error_message = "";
151  } catch(mapgen_exception& exc) {
152  error_message = exc.message;
153  }
154 
155  --tries;
156  } while(tries && map.empty());
157 
158  if(labels) {
159  labels->swap(labels_copy);
160  }
161 
162  if(!error_message.empty()) {
163  throw mapgen_exception(error_message);
164  }
165 
166  return map;
167 }
168 
169 config default_map_generator::create_scenario(boost::optional<uint32_t> randomseed)
170 {
171  DBG_NG << "creating scenario...\n";
172 
173  config res = cfg_.child_or_empty("scenario");
174 
175  DBG_NG << "got scenario data...\n";
176 
177  std::map<map_location,std::string> labels;
178  DBG_NG << "generating map...\n";
179 
180  try{
181  res["map_data"] = generate_map(&labels, randomseed);
182  }
183  catch (mapgen_exception& exc){
184  res["map_data"] = "";
185  res["error_message"] = exc.message;
186  }
187  DBG_NG << "done generating map..\n";
188 
189  for(std::map<map_location,std::string>::const_iterator i =
190  labels.begin(); i != labels.end(); ++i) {
191 
192  if(i->first.x >= 0 && i->first.y >= 0 &&
193  i->first.x < static_cast<long>(data_.width) &&
194  i->first.y < static_cast<long>(data_.height)) {
195 
196  config& label = res.add_child("label");
197  label["text"] = i->second;
198  label["category"] = "villages";
199  i->first.write(label);
200  }
201  }
202 
203  return res;
204 }
generator_data(const config &cfg)
bool is_odd(T num)
Definition: math.hpp:34
config & child(config_key_type 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:352
std::vector< char_t > string
std::string name() const override
Returns a string identifying the generator by name.
static CVideo & get_singleton()
Definition: video.hpp:50
STL namespace.
static lg::log_domain log_engine("engine")
-file util.hpp
std::string config_name() const override
Return a friendly name for the generator used to differentiate between different configs of the same ...
std::string create_map(boost::optional< uint32_t > randomseed) override
Creates a new map and returns it.
config create_scenario(boost::optional< uint32_t > randomseed) override
#define DBG_NG
void user_config() override
Display the interactive screen, which allows the user to modify how the generator behaves...
static bool execute(generator_data &data, CVideo &video)
The execute function see modal_dialog for more information.
std::string default_generate_map(generator_data data, std::map< map_location, std::string > *labels, const config &cfg)
Generate the map.
bool allow_user_config() const override
Returns true if the map generator has an interactive screen, which allows the user to modify how the ...
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:385
default_map_generator(const config &game_config)
#define i
config & add_child(config_key_type key)
Definition: config.cpp:408
uint32_t next_seed()
Definition: seed_rng.cpp:45
std::string generate_map(std::map< map_location, std::string > *labels, boost::optional< uint32_t > randomseed)
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:31
static int max_coastal
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
mock_char c