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