The Battle for Wesnoth  1.15.2+dev
type_data.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
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 "terrain/type_data.hpp"
16 
18 
19 #include <map>
20 
21 #include "log.hpp"
22 #define ERR_G LOG_STREAM(err, lg::general())
23 #define LOG_G LOG_STREAM(info, lg::general())
24 #define DBG_G LOG_STREAM(debug, lg::general())
25 
27  : terrainList_()
28  , tcodeToTerrain_()
29  , initialized_(false)
30  , game_config_(game_config)
31 {
32 }
33 
35 {
36  if(initialized_)
37  return;
38 
39  for (const config &terrain_data : game_config_.child_range("terrain_type"))
40  {
41  terrain_type terrain(terrain_data);
42  DBG_G << "create_terrain_maps: " << terrain.number() << " "
43  << terrain.id() << " " << terrain.name() << " : " << terrain.editor_group() << "\n";
44 
46  res = tcodeToTerrain_.emplace(terrain.number(), terrain);
47  if (!res.second) {
48  terrain_type& curr = res.first->second;
49  if(terrain == curr) {
50  LOG_G << "Merging terrain " << terrain.number()
51  << ": " << terrain.id() << " (" << terrain.name() << ")\n";
52  std::vector<std::string> eg1 = utils::split(curr.editor_group());
53  std::vector<std::string> eg2 = utils::split(terrain.editor_group());
54  std::set<std::string> egs;
55  bool clean_merge = true;
56  for (std::string& t : eg1) {
57  clean_merge &= egs.insert(t).second;
58  }
59  for (std::string& t : eg2) {
60  clean_merge &= egs.insert(t).second;
61  }
62  std::string joined = utils::join(egs);
63 
64  if(clean_merge) {
65  LOG_G << "Editor groups merged to: " << joined << "\n";
66  } else {
67  LOG_G << "Merged terrain " << terrain.number()
68  << ": " << terrain.id() << " (" << terrain.name() << ") "
69  << "with duplicate editor groups [" << terrain.editor_group() << "] "
70  << "and [" << curr.editor_group() << "]\n";
71  }
72  curr.set_editor_group(joined);
73  } else {
74  ERR_G << "Duplicate terrain code definition found for " << terrain.number() << "\n"
75  << "Failed to add terrain " << terrain.id() << " (" << terrain.name() << ") "
76  << "[" << terrain.editor_group() << "]" << "\n"
77  << "which conflicts with " << curr.id() << " (" << curr.name() << ") "
78  << "[" << curr.editor_group() << "]" << "\n\n";
79  }
80  } else {
81  terrainList_.push_back(terrain.number());
82  }
83  }
84  initialized_ = true;
85 }
86 
88 {
90  return terrainList_;
91 }
92 
93 
94 const std::map<t_translation::terrain_code, terrain_type> & terrain_type_data::map() const
95 {
97  return tcodeToTerrain_;
98 }
99 
101 {
102  auto i = find_or_create(terrain);
103 
104  if(i != tcodeToTerrain_.end()) {
105  return i->second;
106  } else {
107  static const terrain_type default_terrain;
108  return default_terrain;
109  }
110 }
111 
113 {
114  auto i = find_or_create(terrain);
115 
116  if(i == tcodeToTerrain_.end()) {
117  // TODO: At least in some cases (for example when this is called from lua) it
118  // seems to make more sense to throw an exception here, same goes for get_terrain_info
119  // and underlying_def_terrain
120  static t_translation::ter_list result(1);
121  result[0] = terrain;
122  return result;
123  } else {
124  return i->second.mvt_type();
125  }
126 }
127 
129 {
130  auto i = find_or_create(terrain);
131 
132  if(i == tcodeToTerrain_.end()) {
133  static t_translation::ter_list result(1);
134  result[0] = terrain;
135  return result;
136  } else {
137  return i->second.def_type();
138  }
139 }
140 
142 {
143  auto i = find_or_create(terrain);
144 
145  if(i == tcodeToTerrain_.end()) {
146  static t_translation::ter_list result(1);
147  result[0] = terrain;
148  return result;
149  } else {
150  return i->second.union_type();
151  }
152 }
153 
154 
155 
157 {
158  t_string str =
159  get_terrain_info(terrain).description();
160 
161  str += get_underlying_terrain_string(terrain);
162 
163  return str;
164 }
165 
167 {
168  t_string str =
169  get_terrain_info(terrain).editor_name();
170  const t_string& desc =
171  get_terrain_info(terrain).description();
172 
173  if(str != desc) {
174  str += "/";
175  str += desc;
176  }
177 
178  str += get_underlying_terrain_string(terrain);
179 
180  return str;
181 }
182 
184 {
185  // lazy_initialization() is handled in underlying_union_terrain
186  std::string str;
187 
188  const t_translation::ter_list& underlying = underlying_union_terrain(terrain);
189  assert(!underlying.empty());
190 
191  if(underlying.size() > 1 || underlying[0] != terrain) {
192  str += " (";
193  t_translation::ter_list::const_iterator i = underlying.begin();
194  str += get_terrain_info(*i).name();
195  while (++i != underlying.end()) {
196  str += ", " + get_terrain_info(*i).name();
197  }
198  str += ")";
199  }
200 
201  return str;
202 }
203 
204 terrain_type_data::tcodeToTerrain_t::const_iterator terrain_type_data::find_or_create(t_translation::terrain_code terrain) const
205 {
207  auto i = tcodeToTerrain_.find(terrain);
208  if (i != tcodeToTerrain_.end()) {
209  return i;
210  }
211  else {
212  DBG_G << "find_or_create: creating terrain " << terrain << std::endl;
215 
216  if(base_iter == tcodeToTerrain_.end() || overlay_iter == tcodeToTerrain_.end()) {
217  // This line is easily reachable, after the player has played multiple
218  // campaigns. The code for showing movetypes for discovered terrains in the
219  // sidebar will query every terrain listed in
220  // preferences::encountered_terrains(), even those that are campaign-specific.
221  // ERR_G << "couldn't find base or overlay for " << terrain << std::endl;
222  return tcodeToTerrain_.end();
223  }
224 
225  terrain_type new_terrain(base_iter->second, overlay_iter->second);
226  terrainList_.push_back(new_terrain.number());
227  return tcodeToTerrain_.emplace(new_terrain.number(), std::move(new_terrain)).first;
228  }
229 }
230 
232 {
233  // These can't be combined in to a single line, because find_or_create
234  // can change the value of tcodeToTerrain_.end().
235  const auto t = find_or_create(terrain);
236  return t != tcodeToTerrain_.end();
237 }
238 
241 
242  if(mode == OVERLAY) {
244  if (is_known(t)) {
245  result = t;
246  }
247  }
248  else if(mode == BASE) {
250  if (is_known(t)) {
251  result = t;
252  }
253  }
254  else if(mode == BOTH && new_t.base != t_translation::NO_LAYER) {
255  // We need to merge here, too, because the dest terrain might be a combined one.
256  if (is_known(new_t)) {
257  result = new_t;
258  }
259  }
260 
261  // if merging of overlay and base failed, and replace_if_failed is set,
262  // replace the terrain with the complete new terrain (if given)
263  // or with (default base)^(new overlay)
264  if(result == t_translation::NONE_TERRAIN && replace_if_failed && is_known(new_t)) {
265  if(new_t.base != t_translation::NO_LAYER) {
266  result = new_t;
267  }
268  else if (get_terrain_info(new_t).default_base() != t_translation::NONE_TERRAIN) {
270  }
271  }
272  return result;
273 }
const terrain_code NONE_TERRAIN
Definition: translation.hpp:59
const t_string & description() const
Definition: terrain.hpp:35
#define DBG_G
Definition: type_data.cpp:24
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
t_translation::ter_list terrainList_
Definition: type_data.hpp:39
child_itors child_range(config_key_type key)
Definition: config.cpp:362
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
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Get the corresponding terrain_type information object for a given type of terrain.
Definition: type_data.cpp:100
const ter_layer NO_LAYER
Definition: translation.hpp:41
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.
tcodeToTerrain_t::const_iterator find_or_create(t_translation::terrain_code) const
Definition: type_data.cpp:204
const std::map< t_translation::terrain_code, terrain_type > & map() const
Definition: type_data.cpp:94
const t_translation::ter_list & underlying_mvt_terrain(const t_translation::terrain_code &terrain) const
The underlying movement type of the terrain.
Definition: type_data.cpp:112
const t_string & editor_name() const
Definition: terrain.hpp:34
t_string get_terrain_string(const t_translation::terrain_code &terrain) const
Get a formatted terrain name – terrain (underlying terrains)
Definition: type_data.cpp:156
t_string get_terrain_editor_string(const t_translation::terrain_code &terrain) const
Definition: type_data.cpp:166
t_translation::terrain_code merge_terrains(const t_translation::terrain_code &old_t, const t_translation::terrain_code &new_t, const merge_mode mode, bool replace_if_failed=false) const
Tries to find a new terrain which is the combination of old and new terrain using the merge_settings...
Definition: type_data.cpp:239
const t_translation::ter_list & list() const
Definition: type_data.cpp:87
const t_translation::ter_list & underlying_def_terrain(const t_translation::terrain_code &terrain) const
The underlying defense type of the terrain.
Definition: type_data.cpp:128
std::string default_terrain
Definition: game_config.cpp:70
void lazy_initialization() const
On the first call to this function, parse all of the [terrain_type]s that are defined in WML...
Definition: type_data.cpp:34
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
bool is_known(const t_translation::terrain_code &terrain) const
Returns true if get_terrain_info(terrain) would succeed, or false if get_terrain_info(terrain) would ...
Definition: type_data.cpp:231
std::size_t i
Definition: function.cpp:933
#define ERR_G
Definition: type_data.cpp:22
Game configuration data as global variables.
Definition: build_info.cpp:49
t_translation::terrain_code terrain_with_default_base() const
Definition: terrain.cpp:296
t_translation::terrain_code number() const
Definition: terrain.hpp:44
#define LOG_G
Definition: type_data.cpp:23
map_location curr
Definition: astarsearch.cpp:65
const t_translation::ter_list & underlying_union_terrain(const t_translation::terrain_code &terrain) const
Unordered set of all terrains used in either underlying_mvt_terrain or underlying_def_terrain.
Definition: type_data.cpp:141
const t_string & name() const
Definition: terrain.hpp:33
void set_editor_group(const std::string &str)
Definition: terrain.hpp:132
double t
Definition: astarsearch.cpp:64
Standard logging facilities (interface).
const std::string & id() const
Definition: terrain.hpp:37
std::vector< terrain_code > ter_list
Definition: translation.hpp:78
terrain_type_data(const config &game_config)
Definition: type_data.cpp:26
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
t_string get_underlying_terrain_string(const t_translation::terrain_code &terrain) const
Definition: type_data.cpp:183
tcodeToTerrain_t tcodeToTerrain_
Definition: type_data.hpp:41
const config & game_config_
Definition: type_data.hpp:43
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
const std::string & editor_group() const
Definition: terrain.hpp:131