The Battle for Wesnoth  1.15.1+dev
terrain.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://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 "deprecation.hpp"
16 #include "game_version.hpp"
17 #include "gettext.hpp"
18 #include "log.hpp"
20 #include "terrain/terrain.hpp"
21 
22 #include <set>
23 
24 static lg::log_domain log_config("config");
25 #define ERR_G LOG_STREAM(err, lg::general())
26 #define WRN_G LOG_STREAM(warn, lg::general())
27 #define LOG_G LOG_STREAM(info, lg::general())
28 #define DBG_G LOG_STREAM(debug, lg::general())
29 
30 /**
31  * Insert second vector into first when the terrain _ref^base is encountered
32  */
34 
36  minimap_image_(),
37  minimap_image_overlay_(),
38  editor_image_(),
39  id_(),
40  name_(),
41  editor_name_(),
42  description_(),
43  help_topic_text_(),
44  number_(t_translation::VOID_TERRAIN),
45  mvt_type_(1, t_translation::VOID_TERRAIN),
46  vision_type_(1, t_translation::VOID_TERRAIN),
47  def_type_(1, t_translation::VOID_TERRAIN),
48  union_type_(1, t_translation::VOID_TERRAIN),
49  height_adjust_(0),
50  height_adjust_set_(false),
51  submerge_(0.0),
52  submerge_set_(false),
53  light_modification_(0),
54  max_light_(0),
55  min_light_(0),
56  heals_(0),
57  income_description_(),
58  income_description_ally_(),
59  income_description_enemy_(),
60  income_description_own_(),
61  editor_group_(),
62  village_(false),
63  castle_(false),
64  keep_(false),
65  overlay_(false),
66  combined_(false),
67  editor_default_base_(t_translation::VOID_TERRAIN),
68  hide_help_(false),
69  hide_in_editor_(false),
70  hide_if_impassable_(false)
71 {}
72 
74  icon_image_(cfg["icon_image"]),
75  minimap_image_(cfg["symbol_image"]),
77  editor_image_(cfg["editor_image"].empty() ? "terrain/" + minimap_image_ + ".png" : "terrain/" + cfg["editor_image"].str() + ".png"),
78  id_(cfg["id"]),
79  name_(cfg["name"].t_str()),
80  editor_name_(cfg["editor_name"].t_str()),
81  description_(cfg["description"].t_str()),
82  help_topic_text_(cfg["help_topic_text"].t_str()),
83  number_(t_translation::read_terrain_code(cfg["string"].str())),
84  mvt_type_(),
85  vision_type_(),
86  def_type_(),
87  union_type_(),
88  height_adjust_(cfg["unit_height_adjust"]),
89  height_adjust_set_(!cfg["unit_height_adjust"].empty()),
90  submerge_(cfg["submerge"].to_double()),
91  submerge_set_(!cfg["submerge"].empty()),
92  light_modification_(cfg["light"]),
93  max_light_(cfg["max_light"].to_int(light_modification_)),
94  min_light_(cfg["min_light"].to_int(light_modification_)),
95  heals_(cfg["heals"]),
100  editor_group_(cfg["editor_group"]),
101  village_(cfg["gives_income"].to_bool()),
102  castle_(cfg["recruit_onto"].to_bool()),
103  keep_(cfg["recruit_from"].to_bool()),
105  combined_(false),
106  editor_default_base_(t_translation::read_terrain_code(cfg["default_base"].str())),
107  hide_help_(cfg["hide_help"].to_bool(false)),
108  hide_in_editor_(cfg["hidden"].to_bool(false)),
109  hide_if_impassable_(cfg["hide_if_impassable"].to_bool(false))
110 {
111 /**
112  * @todo reenable these validations. The problem is that all MP
113  * scenarios/campaigns share the same namespace and one rogue scenario
114  * can avoid the player to create a MP game. So every scenario/campaign
115  * should get its own namespace to be safe.
116  */
117 #if 0
119  missing_mandatory_wml_key("terrain_type", "string"));
120  VALIDATE(!minimap_image_.empty(),
121  missing_mandatory_wml_key("terrain_type", "symbol_image", "string",
123  VALIDATE(!name_.empty(),
124  missing_mandatory_wml_key("terrain_type", "name", "string",
126 #endif
127 
128  if(editor_image_.empty()) {
129  editor_image_ = "terrain/" + minimap_image_ + ".png";
130  }
131 
132  if(hide_in_editor_) {
133  editor_image_ = "";
134  }
135 
136  mvt_type_.push_back(number_);
137  def_type_.push_back(number_);
138  vision_type_.push_back(number_);
139 
140  const t_translation::ter_list& alias = t_translation::read_list(cfg["aliasof"].str());
141  if(!alias.empty()) {
142  mvt_type_ = alias;
143  vision_type_ = alias;
144  def_type_ = alias;
145  }
146 
147  const t_translation::ter_list& mvt_alias = t_translation::read_list(cfg["mvt_alias"].str());
148  if(!mvt_alias.empty()) {
149  mvt_type_ = mvt_alias;
150  }
151 
152  const t_translation::ter_list& def_alias = t_translation::read_list(cfg["def_alias"].str());
153  if(!def_alias.empty()) {
154  def_type_ = def_alias;
155  }
156 
157  const t_translation::ter_list& vision_alias = t_translation::read_list(cfg["vision_alias"].str());
158  if(!vision_alias.empty()) {
159  // Vision costs are calculated in movetype.cpp, but they're calculated based on gamemap::underlying_mvt_terrain().
160  // Having vision costs that are different to movement costs is still supported, but having separate aliases seems
161  // an edge case that shouldn't be introduced until we're ready to test it.
162  deprecated_message("vision_alias", DEP_LEVEL::REMOVED, {1, 15, 2}, "vision_alias was never completely implemented, vision is calculated using mvt_alias instead");
163  vision_type_ = vision_alias;
164  }
165 
167  union_type_.insert( union_type_.end(), def_type_.begin(), def_type_.end() );
168  union_type_.insert( union_type_.end(), vision_type_.begin(), vision_type_.end() );
169 
170  // remove + and -
171  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
173 
174  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
176 
177  // remove doubles
178  std::sort(union_type_.begin(),union_type_.end());
179  union_type_.erase(std::unique(union_type_.begin(), union_type_.end()), union_type_.end());
180 
181 
182 
183  //mouse over message are only shown on villages
184  if(village_) {
185  income_description_ = cfg["income_description"];
186  if(income_description_.empty()) {
187  income_description_ = _("Village");
188  }
189 
190  income_description_ally_ = cfg["income_description_ally"];
192  income_description_ally_ = _("Allied village");
193  }
194 
195  income_description_enemy_ = cfg["income_description_enemy"];
197  income_description_enemy_ = _("Enemy village");
198  }
199 
200  income_description_own_ = cfg["income_description_own"];
202  income_description_own_ = _("Owned village");
203  }
204  }
205 }
206 
208  icon_image_(),
211  editor_image_(base.editor_image_ + "~BLIT(" + overlay.editor_image_ +")"),
212  id_(base.id_+"^"+overlay.id_),
213  name_(overlay.name_),
214  editor_name_((base.editor_name_.empty() ? base.name_ : base.editor_name_) + " / " + (overlay.editor_name_.empty() ? overlay.name_ : overlay.editor_name_)),
215  description_(overlay.description()),
217  number_(t_translation::terrain_code(base.number_.base, overlay.number_.overlay)),
218  mvt_type_(overlay.mvt_type_),
219  vision_type_(overlay.vision_type_),
220  def_type_(overlay.def_type_),
221  union_type_(),
224  submerge_(base.submerge_),
227  max_light_(std::max(base.max_light_, overlay.max_light_)),
228  min_light_(std::min(base.min_light_, overlay.min_light_)),
229  heals_(std::max<int>(base.heals_, overlay.heals_)),
234  editor_group_(),
235  village_(base.village_ || overlay.village_),
236  castle_(base.castle_ || overlay.castle_),
237  keep_(base.keep_ || overlay.keep_),
238  overlay_(false),
239  combined_(true),
241  hide_help_(base.hide_help_ || overlay.hide_help_),
244 {
245  if(description_.empty()) {
246  description_ = base.description();
247  }
248 
249  if(overlay.height_adjust_set_) {
250  height_adjust_set_ = true;
251  height_adjust_ = overlay.height_adjust_;
252  }
253 
254  if(overlay.submerge_set_) {
255  submerge_set_ = true;
256  submerge_ = overlay.submerge_;
257  }
258 
262 
264  union_type_.insert( union_type_.end(), def_type_.begin(), def_type_.end() );
265  union_type_.insert( union_type_.end(), vision_type_.begin(), vision_type_.end() );
266 
267  // remove + and -
268  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
270 
271  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
273 
274  // remove doubles
275  std::sort(union_type_.begin(),union_type_.end());
276  union_type_.erase(std::unique(union_type_.begin(), union_type_.end()), union_type_.end());
277 
278 
279 
280  //mouse over message are only shown on villages
281  if(base.village_) {
286  }
287  else if (overlay.village_) {
292  }
293 
294 }
295 
299  }
300  return number_;
301 }
302 
303 bool terrain_type::operator==(const terrain_type& other) const {
304  return minimap_image_ == other.minimap_image_
306  && editor_image_ == other.editor_image_
307  && id_ == other.id_
308  && name_.base_str() == other.name_.base_str()
310  && number_ == other.number_
311  && mvt_type_ == other.mvt_type_
312  && vision_type_ == other.vision_type_
313  && def_type_ == other.def_type_
314  && union_type_ == other.union_type_
315  && height_adjust_ == other.height_adjust_
317  && submerge_ == other.submerge_
318  && submerge_set_ == other.submerge_set_
320  && max_light_ == other.max_light_
321  && min_light_ == other.min_light_
322  && heals_ == other.heals_
323  && village_ == other.village_
324  && castle_ == other.castle_
325  && keep_ == other.keep_
326  && combined_ == other.combined_
327  && overlay_ == other.overlay_
329  && hide_in_editor_ == other.hide_in_editor_
330  && hide_help_ == other.hide_help_;
331 }
332 
334 {
335  // Insert second vector into first when the terrain _ref^base is encountered
336 
337  bool revert = (first.front() == t_translation::MINUS ? true : false);
339 
340  for(i = first.begin(); i != first.end(); ++i) {
341  if(*i == t_translation::PLUS) {
342  revert = false;
343  continue;
344  } else if(*i == t_translation::MINUS) {
345  revert = true;
346  continue;
347  }
348 
349  // This only works for a subset of the possible cases, and doesn't work for
350  // worst(best(a,b),c,d) terrain. Part of the reason that it doesn't work is that
351  // movetype.cpp starts with a default value of either UNREACHABLE or zero, which
352  // when inverted would drown out the values in best(a,b). Another part of the reason
353  // is that the insertion of a plus or minus before the base terrain is commented out
354  // in this function.
355 
356  if(*i == t_translation::BASE) {
357  t_translation::ter_list::iterator insert_it = first.erase(i);
358  //if we are in reverse mode, insert PLUS before and MINUS after the base list
359  //so calculation of base aliases will work normal
360  if(revert) {
361 // insert_it = first.insert(insert_it, t_translation::PLUS);
362 // insert_it++;
363  insert_it = first.insert(insert_it, t_translation::MINUS);
364  }
365  else {
366  //else insert PLUS after the base aliases to restore previous "reverse state"
367  insert_it = first.insert(insert_it, t_translation::PLUS);
368  }
369 
370  first.insert(insert_it, second.begin(), second.end());
371 
372  break;
373  }
374  }
375 
376 }
bool height_adjust_set_
Definition: terrain.hpp:186
void remove()
Removes a tip.
Definition: tooltip.cpp:189
std::string minimap_image_overlay_
Definition: terrain.hpp:162
t_translation::terrain_code editor_default_base_
Definition: terrain.hpp:206
const terrain_code NONE_TERRAIN
Definition: translation.hpp:59
const t_string & description() const
Definition: terrain.hpp:35
t_translation::ter_list mvt_type_
Definition: terrain.hpp:180
Interfaces for manipulating version numbers of engine, add-ons, etc.
t_translation::ter_list def_type_
Definition: terrain.hpp:182
t_string name_
Definition: terrain.hpp:170
std::string id_
Definition: terrain.hpp:169
bool hide_in_editor_
Definition: terrain.hpp:207
t_string income_description_
Definition: terrain.hpp:196
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:168
bool operator==(const terrain_type &other) const
Returns true if all most of the data matches.
Definition: terrain.cpp:303
bool combined_
Definition: terrain.hpp:205
bool hide_help_
Definition: terrain.hpp:207
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
STL namespace.
const ter_layer NO_LAYER
Definition: translation.hpp:41
t_string description_
Definition: terrain.hpp:172
t_string income_description_own_
Definition: terrain.hpp:199
std::string editor_group_
Definition: terrain.hpp:201
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 terrain_code VOID_TERRAIN
VOID_TERRAIN is used for shrouded hexes.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
t_string income_description_ally_
Definition: terrain.hpp:197
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:29
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
bool submerge_set_
Definition: terrain.hpp:189
const terrain_code MINUS
const terrain_code PLUS
int max_light_
Definition: terrain.hpp:192
double submerge_
Definition: terrain.hpp:188
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
int height_adjust_
Definition: terrain.hpp:185
static lg::log_domain log_config("config")
t_translation::terrain_code number_
Definition: terrain.hpp:179
t_translation::ter_list union_type_
Definition: terrain.hpp:183
t_translation::ter_list vision_type_
Definition: terrain.hpp:181
const terrain_code BASE
std::size_t i
Definition: function.cpp:933
t_translation::terrain_code terrain_with_default_base() const
Definition: terrain.cpp:296
terrain_code read_terrain_code(utils::string_view str, const ter_layer filler)
Reads a single terrain from a string.
bool hide_if_impassable_
Definition: terrain.hpp:207
std::string minimap_image_
The image used in the minimap.
Definition: terrain.hpp:161
static int sort(lua_State *L)
Definition: ltablib.cpp:411
bool castle_
Definition: terrain.hpp:203
void merge_alias_lists(t_translation::ter_list &first, const t_translation::ter_list &second)
Insert second vector into first when the terrain _ref^base is encountered.
Definition: terrain.cpp:333
bool village_
Definition: terrain.hpp:203
t_string income_description_enemy_
Definition: terrain.hpp:198
int light_modification_
Definition: terrain.hpp:191
bool empty() const
Definition: tstring.hpp:182
bool overlay_
Definition: terrain.hpp:205
int min_light_
Definition: terrain.hpp:193
ter_list read_list(utils::string_view str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
Standard logging facilities (interface).
std::vector< terrain_code > ter_list
Definition: translation.hpp:78
std::string base_str() const
Definition: tstring.hpp:190
t_string help_topic_text_
Definition: terrain.hpp:173
std::string icon_image_
The image used as symbol icon.
Definition: terrain.hpp:158
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
t_string editor_name_
Definition: terrain.hpp:171