The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
terrain.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 #include "gettext.hpp"
18 #include "log.hpp"
20 #include "terrain/terrain.hpp"
21 #include "util.hpp"
22 
23 #include <set>
24 
25 static lg::log_domain log_config("config");
26 #define ERR_G LOG_STREAM(err, lg::general())
27 #define WRN_G LOG_STREAM(warn, lg::general())
28 #define LOG_G LOG_STREAM(info, lg::general())
29 #define DBG_G LOG_STREAM(debug, lg::general())
30 
32  minimap_image_(),
33  minimap_image_overlay_(),
34  editor_image_(),
35  id_(),
36  name_(),
37  editor_name_(),
38  description_(),
39  help_topic_text_(),
40  number_(t_translation::VOID_TERRAIN),
41  mvt_type_(1, t_translation::VOID_TERRAIN),
42  vision_type_(1, t_translation::VOID_TERRAIN),
43  def_type_(1, t_translation::VOID_TERRAIN),
44  union_type_(1, t_translation::VOID_TERRAIN),
45  height_adjust_(0),
46  height_adjust_set_(false),
47  submerge_(0.0),
48  submerge_set_(false),
49  light_modification_(0),
50  max_light_(0),
51  min_light_(0),
52  heals_(0),
53  income_description_(),
54  income_description_ally_(),
55  income_description_enemy_(),
56  income_description_own_(),
57  editor_group_(),
58  village_(false),
59  castle_(false),
60  keep_(false),
61  overlay_(false),
62  combined_(false),
63  editor_default_base_(t_translation::VOID_TERRAIN),
64  hide_help_(false),
65  hide_in_editor_(false)
66 {}
67 
69  icon_image_(cfg["icon_image"]),
70  minimap_image_(cfg["symbol_image"]),
71  minimap_image_overlay_(),
72  editor_image_(cfg["editor_image"].empty() ? "terrain/" + minimap_image_ + ".png" : "terrain/" + cfg["editor_image"].str() + ".png"),
73  id_(cfg["id"]),
74  name_(cfg["name"].t_str()),
75  editor_name_(cfg["editor_name"].t_str()),
76  description_(cfg["description"].t_str()),
77  help_topic_text_(cfg["help_topic_text"].t_str()),
78  number_(t_translation::read_terrain_code(cfg["string"])),
79  mvt_type_(),
80  vision_type_(),
81  def_type_(),
82  union_type_(),
83  height_adjust_(cfg["unit_height_adjust"]),
84  height_adjust_set_(!cfg["unit_height_adjust"].empty()),
85  submerge_(cfg["submerge"].to_double()),
86  submerge_set_(!cfg["submerge"].empty()),
87  light_modification_(cfg["light"]),
88  max_light_(cfg["max_light"].to_int(light_modification_)),
89  min_light_(cfg["min_light"].to_int(light_modification_)),
90  heals_(cfg["heals"]),
91  income_description_(),
92  income_description_ally_(),
93  income_description_enemy_(),
94  income_description_own_(),
95  editor_group_(cfg["editor_group"]),
96  village_(cfg["gives_income"].to_bool()),
97  castle_(cfg["recruit_onto"].to_bool()),
98  keep_(cfg["recruit_from"].to_bool()),
99  overlay_(number_.base == t_translation::NO_LAYER),
100  combined_(false),
101  editor_default_base_(t_translation::read_terrain_code(cfg["default_base"])),
102  hide_help_(cfg["hide_help"].to_bool(false)),
103  hide_in_editor_(cfg["hidden"].to_bool(false))
104 {
105 /**
106  * @todo reenable these validations. The problem is that all MP
107  * scenarios/campaigns share the same namespace and one rogue scenario
108  * can avoid the player to create a MP game. So every scenario/campaign
109  * should get its own namespace to be safe.
110  */
111 #if 0
113  missing_mandatory_wml_key("terrain_type", "string"));
114  VALIDATE(!minimap_image_.empty(),
115  missing_mandatory_wml_key("terrain_type", "symbol_image", "string",
117  VALIDATE(!name_.empty(),
118  missing_mandatory_wml_key("terrain_type", "name", "string",
120 #endif
121 
122  if(editor_image_.empty()) {
123  editor_image_ = "terrain/" + minimap_image_ + ".png";
124  }
125 
126  if(hide_in_editor_) {
127  editor_image_ = "";
128  }
129 
130  mvt_type_.push_back(number_);
131  def_type_.push_back(number_);
132  vision_type_.push_back(number_);
133 
134  const t_translation::t_list& alias = t_translation::read_list(cfg["aliasof"]);
135  if(!alias.empty()) {
136  mvt_type_ = alias;
137  vision_type_ = alias;
138  def_type_ = alias;
139  }
140 
141  const t_translation::t_list& mvt_alias = t_translation::read_list(cfg["mvt_alias"]);
142  if(!mvt_alias.empty()) {
143  mvt_type_ = mvt_alias;
144  }
145 
146  const t_translation::t_list& def_alias = t_translation::read_list(cfg["def_alias"]);
147  if(!def_alias.empty()) {
148  def_type_ = def_alias;
149  }
150 
151  const t_translation::t_list& vision_alias = t_translation::read_list(cfg["vision_alias"]);
152  if(!vision_alias.empty()) {
153  vision_type_ = vision_alias;
154  }
155 
157  union_type_.insert( union_type_.end(), def_type_.begin(), def_type_.end() );
158  union_type_.insert( union_type_.end(), vision_type_.begin(), vision_type_.end() );
159 
160  // remove + and -
161  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
163 
164  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
166 
167  // remove doubles
168  std::sort(union_type_.begin(),union_type_.end());
169  union_type_.erase(std::unique(union_type_.begin(), union_type_.end()), union_type_.end());
170 
171 
172 
173  //mouse over message are only shown on villages
174  if(village_) {
175  income_description_ = cfg["income_description"];
176  if(income_description_ == "") {
177  income_description_ = _("Village");
178  }
179 
180  income_description_ally_ = cfg["income_description_ally"];
181  if(income_description_ally_ == "") {
182  income_description_ally_ = _("Allied village");
183  }
184 
185  income_description_enemy_ = cfg["income_description_enemy"];
186  if(income_description_enemy_ == "") {
187  income_description_enemy_ = _("Enemy village");
188  }
189 
190  income_description_own_ = cfg["income_description_own"];
191  if(income_description_own_ == "") {
192  income_description_own_ = _("Owned village");
193  }
194  }
195 }
196 
198  icon_image_(),
199  minimap_image_(base.minimap_image_),
200  minimap_image_overlay_(overlay.minimap_image_),
201  editor_image_(base.editor_image_ + "~BLIT(" + overlay.editor_image_ +")"),
202  id_(base.id_+"^"+overlay.id_),
203  name_(overlay.name_),
204  editor_name_((base.editor_name_.empty() ? base.name_ : base.editor_name_) + " / " + (overlay.editor_name_.empty() ? overlay.name_ : overlay.editor_name_)),
205  description_(overlay.description()),
206  help_topic_text_(),
207  number_(t_translation::t_terrain(base.number_.base, overlay.number_.overlay)),
208  mvt_type_(overlay.mvt_type_),
209  vision_type_(overlay.vision_type_),
210  def_type_(overlay.def_type_),
211  union_type_(),
212  height_adjust_(base.height_adjust_),
213  height_adjust_set_(base.height_adjust_set_),
214  submerge_(base.submerge_),
215  submerge_set_(base.submerge_set_),
216  light_modification_(base.light_modification_ + overlay.light_modification_),
217  max_light_(std::max(base.max_light_, overlay.max_light_)),
218  min_light_(std::min(base.min_light_, overlay.min_light_)),
219  heals_(std::max<int>(base.heals_, overlay.heals_)),
220  income_description_(),
221  income_description_ally_(),
222  income_description_enemy_(),
223  income_description_own_(),
224  editor_group_(),
225  village_(base.village_ || overlay.village_),
226  castle_(base.castle_ || overlay.castle_),
227  keep_(base.keep_ || overlay.keep_),
228  overlay_(false),
229  combined_(true),
230  editor_default_base_(),
231  hide_help_(base.hide_help_ || overlay.hide_help_),
232  hide_in_editor_(base.hide_in_editor_ || overlay.hide_in_editor_)
233 {
234  if(description_.empty()) {
235  description_ = base.description();
236  }
237 
238  if(overlay.height_adjust_set_) {
239  height_adjust_set_ = true;
240  height_adjust_ = overlay.height_adjust_;
241  }
242 
243  if(overlay.submerge_set_) {
244  submerge_set_ = true;
245  submerge_ = overlay.submerge_;
246  }
247 
251 
253  union_type_.insert( union_type_.end(), def_type_.begin(), def_type_.end() );
254  union_type_.insert( union_type_.end(), vision_type_.begin(), vision_type_.end() );
255 
256  // remove + and -
257  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
259 
260  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
262 
263  // remove doubles
264  std::sort(union_type_.begin(),union_type_.end());
265  union_type_.erase(std::unique(union_type_.begin(), union_type_.end()), union_type_.end());
266 
267 
268 
269  //mouse over message are only shown on villages
270  if(base.village_) {
275  }
276  else if (overlay.village_) {
281  }
282 
283 }
284 
288  }
289  return number_;
290 }
291 
292 bool terrain_type::operator==(const terrain_type& other) const {
293  return minimap_image_ == other.minimap_image_
295  && editor_image_ == other.editor_image_
296  && id_ == other.id_
297  && name_.base_str() == other.name_.base_str()
299  && number_ == other.number_
300  && height_adjust_ == other.height_adjust_
302  && submerge_ == other.submerge_
303  && submerge_set_ == other.submerge_set_
305  && max_light_ == other.max_light_
306  && min_light_ == other.min_light_
307  && heals_ == other.heals_
308  && village_ == other.village_
309  && castle_ == other.castle_
310  && keep_ == other.keep_
312  && hide_in_editor_ == other.hide_in_editor_
313  && hide_help_ == other.hide_help_;
314 }
315 
317  t_translation::t_list& terrain_list,
318  std::map<t_translation::t_terrain, terrain_type>& letter_to_terrain)
319 {
320  for (const config &t : cfgs)
321  {
323  DBG_G << "create_terrain_maps: " << terrain.number() << " "
324  << terrain.id() << " " << terrain.name() << " : " << terrain.editor_group() << "\n";
325 
327  res = letter_to_terrain.insert(std::make_pair(terrain.number(), terrain));
328  if (!res.second) {
329  terrain_type& curr = res.first->second;
330  if(terrain == curr) {
331  LOG_G << "Merging terrain " << terrain.number()
332  << ": " << terrain.id() << " (" << terrain.name() << ")\n";
333  std::vector<std::string> eg1 = utils::split(curr.editor_group());
334  std::vector<std::string> eg2 = utils::split(terrain.editor_group());
335  std::set<std::string> egs;
336  bool clean_merge = true;
337  for (std::string& t : eg1) {
338  clean_merge &= egs.insert(t).second;
339  }
340  for (std::string& t : eg2) {
341  clean_merge &= egs.insert(t).second;
342  }
343 
344  std::string joined = utils::join(egs);
345  curr.set_editor_group(joined);
346  if(clean_merge) {
347  LOG_G << "Editor groups merged to: " << joined << "\n";
348  } else {
349  LOG_G << "Merged terrain " << terrain.number()
350  << ": " << terrain.id() << " (" << terrain.name() << ") "
351  << "with duplicate editor groups [" << terrain.editor_group() << "] "
352  << "and [" << curr.editor_group() << "]\n";
353  }
354  } else {
355  ERR_G << "Duplicate terrain code definition found for " << terrain.number() << "\n"
356  << "Failed to add terrain " << terrain.id() << " (" << terrain.name() << ") "
357  << "[" << terrain.editor_group() << "]" << "\n"
358  << "which conflicts with " << curr.id() << " (" << curr.name() << ") "
359  << "[" << curr.editor_group() << "]" << "\n\n";
360  }
361  } else {
362  terrain_list.push_back(terrain.number());
363  }
364  }
365 }
366 
368 {
369  // Insert second vector into first when the terrain _ref^base is encountered
370 
371  bool revert = (first.front() == t_translation::MINUS ? true : false);
373 
374  for(i = first.begin(); i != first.end(); ++i) {
375  if(*i == t_translation::PLUS) {
376  revert = false;
377  continue;
378  } else if(*i == t_translation::MINUS) {
379  revert = true;
380  continue;
381  }
382 
383  if(*i == t_translation::BASE) {
384  t_translation::t_list::iterator insert_it = first.erase(i);
385  //if we are in reverse mode, insert PLUS before and MINUS after the base list
386  //so calculation of base aliases will work normal
387  if(revert) {
388 // insert_it = first.insert(insert_it, t_translation::PLUS);
389 // insert_it++;
390  insert_it = first.insert(insert_it, t_translation::MINUS);
391  }
392  else {
393  //else insert PLUS after the base aliases to restore previous "reverse state"
394  insert_it = first.insert(insert_it, t_translation::PLUS);
395  }
396 
397  first.insert(insert_it, second.begin(), second.end());
398 
399  break;
400  }
401  }
402 
403 }
bool height_adjust_set_
Definition: terrain.hpp:114
std::string minimap_image_overlay_
Definition: terrain.hpp:90
bool operator==(const terrain_type &other) const
Definition: terrain.cpp:292
std::string id_
Definition: formula.cpp:636
t_list read_list(const std::string &str, const t_layer filler)
Reads a list of terrains from a string, when reading the.
t_translation::t_terrain number_
Definition: terrain.hpp:107
t_string name_
Definition: terrain.hpp:98
const t_terrain NONE_TERRAIN
Definition: translation.hpp:56
std::string id_
Definition: terrain.hpp:97
bool hide_in_editor_
Definition: terrain.hpp:135
t_translation::t_list mvt_type_
Definition: terrain.hpp:108
t_string income_description_
Definition: terrain.hpp:124
std::string editor_image_
The image used in the editor palette if not defined in WML it will be initialized with the value of m...
Definition: terrain.hpp:96
const t_terrain MINUS
bool hide_help_
Definition: terrain.hpp:135
const t_string & name() const
Definition: terrain.hpp:33
const std::string & id() const
Definition: terrain.hpp:37
STL namespace.
const std::string & editor_group() const
Definition: terrain.hpp:73
GLdouble GLdouble t
Definition: glew.h:1366
#define DBG_G
Definition: terrain.cpp:29
t_terrain read_terrain_code(const std::string &str, const t_layer filler)
Reads a single terrain from a string.
t_string description_
Definition: terrain.hpp:100
t_string income_description_own_
Definition: terrain.hpp:127
std::pair< const_child_iterator, const_child_iterator > const_child_itors
Definition: config.hpp:214
std::string missing_mandatory_wml_key(const std::string &section, const std::string &key, const std::string &primary_key, const std::string &primary_value)
Returns a standard message for a missing wml key.
const t_terrain BASE
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
const t_terrain PLUS
t_string income_description_ally_
Definition: terrain.hpp:125
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
bool submerge_set_
Definition: terrain.hpp:117
t_translation::t_terrain number() const
Definition: terrain.hpp:43
t_translation::t_terrain editor_default_base_
Definition: terrain.hpp:134
int max_light_
Definition: terrain.hpp:120
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:135
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
Templates and utility-routines for strings and numbers.
double submerge_
Definition: terrain.hpp:116
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:47
int height_adjust_
Definition: terrain.hpp:113
std::string join(T const &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::string base_str() const
Definition: tstring.hpp:174
static lg::log_domain log_config("config")
GLuint res
Definition: glew.h:9258
void merge_alias_lists(t_translation::t_list &first, const t_translation::t_list &second)
Definition: terrain.cpp:367
#define ERR_G
Definition: terrain.cpp:26
map_location curr
Definition: astarsearch.cpp:67
size_t i
Definition: function.cpp:1057
t_translation::t_terrain terrain_with_default_base() const
Definition: terrain.cpp:285
t_translation::t_list vision_type_
Definition: terrain.hpp:109
std::string minimap_image_
The image used in the minimap.
Definition: terrain.hpp:89
static int sort(lua_State *L)
Definition: ltablib.cpp:246
bool castle_
Definition: terrain.hpp:131
bool village_
Definition: terrain.hpp:131
std::string write_terrain_code(const t_terrain &tcode)
Writes a single terrain code to a string.
const t_layer NO_LAYER
Definition: translation.hpp:38
#define LOG_G
Definition: terrain.cpp:28
const t_terrain VOID_TERRAIN
t_string income_description_enemy_
Definition: terrain.hpp:126
int light_modification_
Definition: terrain.hpp:119
void set_editor_group(const std::string &str)
Definition: terrain.hpp:74
t_translation::t_list def_type_
Definition: terrain.hpp:110
bool overlay_
Definition: terrain.hpp:133
int min_light_
Definition: terrain.hpp:121
void create_terrain_maps(const config::const_child_itors &cfgs, t_translation::t_list &terrain_list, std::map< t_translation::t_terrain, terrain_type > &letter_to_terrain)
Definition: terrain.cpp:316
Standard logging facilities (interface).
GLint * first
Definition: glew.h:1496
const std::string remove
remove directive
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
t_translation::t_list union_type_
Definition: terrain.hpp:111
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
const t_string & description() const
Definition: terrain.hpp:35
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool empty() const
Definition: tstring.hpp:166
std::vector< t_terrain > t_list
Definition: translation.hpp:75
t_string editor_name_
Definition: terrain.hpp:99