The Battle for Wesnoth  1.15.0-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 "gettext.hpp"
16 #include "log.hpp"
18 #include "terrain/terrain.hpp"
19 
20 #include <set>
21 
22 static lg::log_domain log_config("config");
23 #define ERR_G LOG_STREAM(err, lg::general())
24 #define WRN_G LOG_STREAM(warn, lg::general())
25 #define LOG_G LOG_STREAM(info, lg::general())
26 #define DBG_G LOG_STREAM(debug, lg::general())
27 
29  minimap_image_(),
30  minimap_image_overlay_(),
31  editor_image_(),
32  id_(),
33  name_(),
34  editor_name_(),
35  description_(),
36  help_topic_text_(),
37  number_(t_translation::VOID_TERRAIN),
38  mvt_type_(1, t_translation::VOID_TERRAIN),
39  vision_type_(1, t_translation::VOID_TERRAIN),
40  def_type_(1, t_translation::VOID_TERRAIN),
41  union_type_(1, t_translation::VOID_TERRAIN),
42  height_adjust_(0),
43  height_adjust_set_(false),
44  submerge_(0.0),
45  submerge_set_(false),
46  light_modification_(0),
47  max_light_(0),
48  min_light_(0),
49  heals_(0),
50  income_description_(),
51  income_description_ally_(),
52  income_description_enemy_(),
53  income_description_own_(),
54  editor_group_(),
55  village_(false),
56  castle_(false),
57  keep_(false),
58  overlay_(false),
59  combined_(false),
60  editor_default_base_(t_translation::VOID_TERRAIN),
61  hide_help_(false),
62  hide_in_editor_(false),
63  hide_if_impassable_(false)
64 {}
65 
67  icon_image_(cfg["icon_image"]),
68  minimap_image_(cfg["symbol_image"]),
70  editor_image_(cfg["editor_image"].empty() ? "terrain/" + minimap_image_ + ".png" : "terrain/" + cfg["editor_image"].str() + ".png"),
71  id_(cfg["id"]),
72  name_(cfg["name"].t_str()),
73  editor_name_(cfg["editor_name"].t_str()),
74  description_(cfg["description"].t_str()),
75  help_topic_text_(cfg["help_topic_text"].t_str()),
76  number_(t_translation::read_terrain_code(cfg["string"])),
77  mvt_type_(),
78  vision_type_(),
79  def_type_(),
80  union_type_(),
81  height_adjust_(cfg["unit_height_adjust"]),
82  height_adjust_set_(!cfg["unit_height_adjust"].empty()),
83  submerge_(cfg["submerge"].to_double()),
84  submerge_set_(!cfg["submerge"].empty()),
85  light_modification_(cfg["light"]),
86  max_light_(cfg["max_light"].to_int(light_modification_)),
87  min_light_(cfg["min_light"].to_int(light_modification_)),
88  heals_(cfg["heals"]),
93  editor_group_(cfg["editor_group"]),
94  village_(cfg["gives_income"].to_bool()),
95  castle_(cfg["recruit_onto"].to_bool()),
96  keep_(cfg["recruit_from"].to_bool()),
98  combined_(false),
100  hide_help_(cfg["hide_help"].to_bool(false)),
101  hide_in_editor_(cfg["hidden"].to_bool(false)),
102  hide_if_impassable_(cfg["hide_if_impassable"].to_bool(false))
103 {
104 /**
105  * @todo reenable these validations. The problem is that all MP
106  * scenarios/campaigns share the same namespace and one rogue scenario
107  * can avoid the player to create a MP game. So every scenario/campaign
108  * should get its own namespace to be safe.
109  */
110 #if 0
112  missing_mandatory_wml_key("terrain_type", "string"));
113  VALIDATE(!minimap_image_.empty(),
114  missing_mandatory_wml_key("terrain_type", "symbol_image", "string",
116  VALIDATE(!name_.empty(),
117  missing_mandatory_wml_key("terrain_type", "name", "string",
119 #endif
120 
121  if(editor_image_.empty()) {
122  editor_image_ = "terrain/" + minimap_image_ + ".png";
123  }
124 
125  if(hide_in_editor_) {
126  editor_image_ = "";
127  }
128 
129  mvt_type_.push_back(number_);
130  def_type_.push_back(number_);
131  vision_type_.push_back(number_);
132 
133  const t_translation::ter_list& alias = t_translation::read_list(cfg["aliasof"].str());
134  if(!alias.empty()) {
135  mvt_type_ = alias;
136  vision_type_ = alias;
137  def_type_ = alias;
138  }
139 
140  const t_translation::ter_list& mvt_alias = t_translation::read_list(cfg["mvt_alias"].str());
141  if(!mvt_alias.empty()) {
142  mvt_type_ = mvt_alias;
143  }
144 
145  const t_translation::ter_list& def_alias = t_translation::read_list(cfg["def_alias"].str());
146  if(!def_alias.empty()) {
147  def_type_ = def_alias;
148  }
149 
150  const t_translation::ter_list& vision_alias = t_translation::read_list(cfg["vision_alias"].str());
151  if(!vision_alias.empty()) {
152  vision_type_ = vision_alias;
153  }
154 
156  union_type_.insert( union_type_.end(), def_type_.begin(), def_type_.end() );
157  union_type_.insert( union_type_.end(), vision_type_.begin(), vision_type_.end() );
158 
159  // remove + and -
160  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
162 
163  union_type_.erase(std::remove(union_type_.begin(), union_type_.end(),
165 
166  // remove doubles
167  std::sort(union_type_.begin(),union_type_.end());
168  union_type_.erase(std::unique(union_type_.begin(), union_type_.end()), union_type_.end());
169 
170 
171 
172  //mouse over message are only shown on villages
173  if(village_) {
174  income_description_ = cfg["income_description"];
175  if(income_description_.empty()) {
176  income_description_ = _("Village");
177  }
178 
179  income_description_ally_ = cfg["income_description_ally"];
181  income_description_ally_ = _("Allied village");
182  }
183 
184  income_description_enemy_ = cfg["income_description_enemy"];
186  income_description_enemy_ = _("Enemy village");
187  }
188 
189  income_description_own_ = cfg["income_description_own"];
191  income_description_own_ = _("Owned village");
192  }
193  }
194 }
195 
197  icon_image_(),
200  editor_image_(base.editor_image_ + "~BLIT(" + overlay.editor_image_ +")"),
201  id_(base.id_+"^"+overlay.id_),
202  name_(overlay.name_),
203  editor_name_((base.editor_name_.empty() ? base.name_ : base.editor_name_) + " / " + (overlay.editor_name_.empty() ? overlay.name_ : overlay.editor_name_)),
204  description_(overlay.description()),
206  number_(t_translation::terrain_code(base.number_.base, overlay.number_.overlay)),
207  mvt_type_(overlay.mvt_type_),
208  vision_type_(overlay.vision_type_),
209  def_type_(overlay.def_type_),
210  union_type_(),
213  submerge_(base.submerge_),
216  max_light_(std::max(base.max_light_, overlay.max_light_)),
217  min_light_(std::min(base.min_light_, overlay.min_light_)),
218  heals_(std::max<int>(base.heals_, overlay.heals_)),
223  editor_group_(),
224  village_(base.village_ || overlay.village_),
225  castle_(base.castle_ || overlay.castle_),
226  keep_(base.keep_ || overlay.keep_),
227  overlay_(false),
228  combined_(true),
230  hide_help_(base.hide_help_ || overlay.hide_help_),
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::ter_list& terrain_list,
318  std::map<t_translation::terrain_code, terrain_type>& letter_to_terrain)
319 {
320  for (const config &terrain_data : cfgs)
321  {
322  terrain_type terrain(terrain_data);
323  DBG_G << "create_terrain_maps: " << terrain.number() << " "
324  << terrain.id() << " " << terrain.name() << " : " << terrain.editor_group() << "\n";
325 
327  res = letter_to_terrain.emplace(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::ter_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:117
void remove()
Removes a tip.
Definition: tooltip.cpp:188
std::string minimap_image_overlay_
Definition: terrain.hpp:93
t_translation::terrain_code editor_default_base_
Definition: terrain.hpp:137
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:111
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
t_translation::ter_list def_type_
Definition: terrain.hpp:113
t_string name_
Definition: terrain.hpp:101
std::string id_
Definition: terrain.hpp:100
bool hide_in_editor_
Definition: terrain.hpp:138
t_string income_description_
Definition: terrain.hpp:127
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:99
bool operator==(const terrain_type &other) const
Definition: terrain.cpp:292
bool combined_
Definition: terrain.hpp:136
bool hide_help_
Definition: terrain.hpp:138
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
void create_terrain_maps(const config::const_child_itors &cfgs, t_translation::ter_list &terrain_list, std::map< t_translation::terrain_code, terrain_type > &letter_to_terrain)
Definition: terrain.cpp:316
STL namespace.
const ter_layer NO_LAYER
Definition: translation.hpp:41
#define DBG_G
Definition: terrain.cpp:26
t_string description_
Definition: terrain.hpp:103
t_string income_description_own_
Definition: terrain.hpp:130
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
std::string editor_group_
Definition: terrain.hpp:132
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
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
t_string income_description_ally_
Definition: terrain.hpp:128
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
bool submerge_set_
Definition: terrain.hpp:120
const terrain_code MINUS
const terrain_code PLUS
int max_light_
Definition: terrain.hpp:123
double submerge_
Definition: terrain.hpp:119
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
int height_adjust_
Definition: terrain.hpp:116
static lg::log_domain log_config("config")
boost::iterator_range< const_child_iterator > const_child_itors
Definition: config.hpp:210
t_translation::terrain_code number_
Definition: terrain.hpp:110
t_translation::ter_list union_type_
Definition: terrain.hpp:114
t_translation::ter_list vision_type_
Definition: terrain.hpp:112
const terrain_code BASE
std::size_t i
Definition: function.cpp:933
#define ERR_G
Definition: terrain.cpp:23
t_translation::terrain_code terrain_with_default_base() const
Definition: terrain.cpp:285
t_translation::terrain_code number() const
Definition: terrain.hpp:44
map_location curr
Definition: astarsearch.cpp:64
bool hide_if_impassable_
Definition: terrain.hpp:138
std::string minimap_image_
The image used in the minimap.
Definition: terrain.hpp:92
static int sort(lua_State *L)
Definition: ltablib.cpp:411
bool castle_
Definition: terrain.hpp:134
void merge_alias_lists(t_translation::ter_list &first, const t_translation::ter_list &second)
Definition: terrain.cpp:367
bool village_
Definition: terrain.hpp:134
#define LOG_G
Definition: terrain.cpp:25
const t_string & name() const
Definition: terrain.hpp:33
t_string income_description_enemy_
Definition: terrain.hpp:129
int light_modification_
Definition: terrain.hpp:122
void set_editor_group(const std::string &str)
Definition: terrain.hpp:77
bool empty() const
Definition: tstring.hpp:182
double t
Definition: astarsearch.cpp:63
bool overlay_
Definition: terrain.hpp:136
int min_light_
Definition: terrain.hpp:124
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).
const std::string & id() const
Definition: terrain.hpp:37
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:104
std::string icon_image_
The image used as symbol icon.
Definition: terrain.hpp:89
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
const std::string & editor_group() const
Definition: terrain.hpp:76
terrain_code read_terrain_code(const std::string &str, const ter_layer filler)
Reads a single terrain from a string.
t_string editor_name_
Definition: terrain.hpp:102