The Battle for Wesnoth  1.19.19+dev
type_data.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2025
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "terrain/type_data.hpp"
17 
19 #include "game_config_view.hpp"
20 
21 #include <map>
22 
23 #include "log.hpp"
24 #define ERR_G LOG_STREAM(err, lg::general())
25 #define LOG_G LOG_STREAM(info, lg::general())
26 #define DBG_G LOG_STREAM(debug, lg::general())
27 
29 {
30  assert(singleton_);
31  return singleton_;
32 }
33 
35  : terrainList_()
36  , tcodeToTerrain_()
37  , initialized_(false)
38  , game_config_(game_config)
39 {
40  assert(!singleton_);
41  singleton_ = this;
42 }
43 
45 {
46  assert(singleton_);
47  singleton_ = nullptr;
48 }
49 
51 {
52  terrainList_.clear();
53  tcodeToTerrain_.clear();
54  initialized_ = false;
55 }
56 
58 {
59  if(initialized_)
60  return;
61 
62  for (const config &terrain_data : game_config_.child_range("terrain_type"))
63  {
64  terrain_type terrain(terrain_data);
65  DBG_G << "create_terrain_maps: " << terrain.number() << " "
66  << terrain.id() << " " << terrain.name() << " : " << terrain.editor_group();
67 
69  res = tcodeToTerrain_.emplace(terrain.number(), terrain);
70  if (!res.second) {
71  terrain_type& curr = res.first->second;
72  if(terrain == curr) {
73  LOG_G << "Merging terrain " << terrain.number()
74  << ": " << terrain.id() << " (" << terrain.name() << ")";
75  std::vector<std::string> eg1 = utils::split(curr.editor_group());
76  std::vector<std::string> eg2 = utils::split(terrain.editor_group());
77  std::set<std::string> egs;
78  bool clean_merge = true;
79  for (std::string& t : eg1) {
80  clean_merge &= egs.insert(t).second;
81  }
82  for (std::string& t : eg2) {
83  clean_merge &= egs.insert(t).second;
84  }
85  std::string joined = utils::join(egs);
86 
87  if(clean_merge) {
88  LOG_G << "Editor groups merged to: " << joined;
89  } else {
90  LOG_G << "Merged terrain " << terrain.number()
91  << ": " << terrain.id() << " (" << terrain.name() << ") "
92  << "with duplicate editor groups [" << terrain.editor_group() << "] "
93  << "and [" << curr.editor_group() << "]";
94  }
95  curr.set_editor_group(joined);
96  } else {
97  ERR_G << "Duplicate terrain code definition found for " << terrain.number() << "\n"
98  << "Failed to add terrain " << terrain.id() << " (" << terrain.name() << ") "
99  << "[" << terrain.editor_group() << "]" << "\n"
100  << "which conflicts with " << curr.id() << " (" << curr.name() << ") "
101  << "[" << curr.editor_group() << "]" << "\n";
102  }
103  } else {
104  terrainList_.push_back(terrain.number());
105  }
106  }
107  initialized_ = true;
108 }
109 
111 {
113  return terrainList_;
114 }
115 
116 
117 const std::map<t_translation::terrain_code, terrain_type> & terrain_type_data::map() const
118 {
120  return tcodeToTerrain_;
121 }
122 
124 {
125  auto i = find_or_create(terrain);
126 
127  if(i != tcodeToTerrain_.end()) {
128  return i->second;
129  } else {
130  static const terrain_type default_terrain;
131  return default_terrain;
132  }
133 }
134 
136 {
137  t_string str =
138  get_terrain_info(terrain).description();
139 
140  str += get_underlying_terrain_string(terrain);
141 
142  return str;
143 }
144 
146 {
147  t_string str =
148  get_terrain_info(terrain).editor_name();
149  const t_string& desc =
150  get_terrain_info(terrain).description();
151 
152  if(str != desc) {
153  str += "/";
154  str += desc;
155  }
156 
157  str += get_underlying_terrain_string(terrain);
158 
159  return str;
160 }
161 
163 {
164  std::string str;
165 
166  const t_translation::ter_list& underlying = get_terrain_info(terrain).union_type();
167  assert(!underlying.empty());
168 
169  if(underlying.size() > 1 || underlying[0] != terrain) {
170  str += " (";
171  t_translation::ter_list::const_iterator i = underlying.begin();
172  str += get_terrain_info(*i).name();
173  while (++i != underlying.end()) {
174  str += ", " + get_terrain_info(*i).name();
175  }
176  str += ")";
177  }
178 
179  return str;
180 }
181 
182 terrain_type_data::tcodeToTerrain_t::const_iterator terrain_type_data::find_or_create(t_translation::terrain_code terrain) const
183 {
185  auto i = tcodeToTerrain_.find(terrain);
186  if (i != tcodeToTerrain_.end()) {
187  return i;
188  }
189  else {
190  DBG_G << "find_or_create: creating terrain " << terrain;
191  auto base_iter = tcodeToTerrain_.find(t_translation::terrain_code(terrain.base, t_translation::NO_LAYER));
192  auto overlay_iter = tcodeToTerrain_.find(t_translation::terrain_code(t_translation::NO_LAYER, terrain.overlay));
193 
194  if(base_iter == tcodeToTerrain_.end() || overlay_iter == tcodeToTerrain_.end()) {
195  // This line is easily reachable, after the player has played multiple
196  // campaigns. The code for showing movetypes for discovered terrains in the
197  // sidebar will query every terrain listed in
198  // prefs::get().encountered_terrains(), even those that are campaign-specific.
199  // ERR_G << "couldn't find base or overlay for " << terrain;
200  return tcodeToTerrain_.end();
201  }
202 
203  terrain_type new_terrain(base_iter->second, overlay_iter->second);
204  terrainList_.push_back(new_terrain.number());
205  return tcodeToTerrain_.emplace(new_terrain.number(), std::move(new_terrain)).first;
206  }
207 }
208 
210 {
211  // These can't be combined in to a single line, because find_or_create
212  // can change the value of tcodeToTerrain_.end().
213  const auto t = find_or_create(terrain);
214  return t != tcodeToTerrain_.end();
215 }
216 
219 
220  if(mode == OVERLAY) {
222  if (is_known(t)) {
223  result = t;
224  }
225  }
226  else if(mode == BASE) {
228  if (is_known(t)) {
229  result = t;
230  }
231  }
232  else if(mode == BOTH && new_t.base != t_translation::NO_LAYER) {
233  // We need to merge here, too, because the dest terrain might be a combined one.
234  if (is_known(new_t)) {
235  result = new_t;
236  }
237  }
238 
239  // if merging of overlay and base failed, and replace_if_failed is set,
240  // replace the terrain with the complete new terrain (if given)
241  // or with (default base)^(new overlay)
242  if(result == t_translation::NONE_TERRAIN && replace_if_failed && is_known(new_t)) {
243  if(new_t.base != t_translation::NO_LAYER) {
244  result = new_t;
245  }
246  else if (get_terrain_info(new_t).has_default_base()) {
248  }
249  }
250  return result;
251 }
map_location curr
Definition: astarsearch.cpp:64
double t
Definition: astarsearch.cpp:63
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
A class grating read only view to a vector of config objects, viewed as one config with all children ...
config_array_view child_range(std::string_view key) const
Contains the database of all known terrain types, both those defined explicitly by WML [terrain_type]...
Definition: type_data.hpp:41
void reset() const
Clears the database and queues reinitialization on the next call to lazy_initialization.
Definition: type_data.cpp:50
t_translation::ter_list terrainList_
Definition: type_data.hpp:43
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:57
t_string get_underlying_terrain_string(const t_translation::terrain_code &terrain) const
Definition: type_data.cpp:162
t_string get_terrain_string(const t_translation::terrain_code &terrain) const
Get a formatted terrain name – terrain (underlying terrains)
Definition: type_data.cpp:135
static terrain_type_data * singleton_
Definition: type_data.hpp:136
tcodeToTerrain_t tcodeToTerrain_
Definition: type_data.hpp:45
const game_config_view & game_config_
Definition: type_data.hpp:47
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:209
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:217
static terrain_type_data * get()
Definition: type_data.cpp:28
const std::map< t_translation::terrain_code, terrain_type > & map() const
Definition: type_data.cpp:117
tcodeToTerrain_t::const_iterator find_or_create(t_translation::terrain_code) const
Definition: type_data.cpp:182
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:123
t_string get_terrain_editor_string(const t_translation::terrain_code &terrain) const
Definition: type_data.cpp:145
terrain_type_data(const game_config_view &game_config)
Definition: type_data.cpp:34
const t_translation::ter_list & list() const
Definition: type_data.cpp:110
const std::string & editor_group() const
Definition: terrain.hpp:162
const t_string & name() const
Definition: terrain.hpp:48
t_translation::terrain_code terrain_with_default_base() const
Return the overlay part of this terrain, on the default_base().
Definition: terrain.cpp:269
const std::string & id() const
Definition: terrain.hpp:52
const t_string & description() const
Definition: terrain.hpp:50
const t_translation::ter_list & union_type() const
Definition: terrain.hpp:87
const t_string & editor_name() const
Definition: terrain.hpp:49
t_translation::terrain_code number() const
Definition: terrain.hpp:66
std::size_t i
Definition: function.cpp:1032
Standard logging facilities (interface).
Game configuration data as global variables.
Definition: build_info.cpp:61
std::string default_terrain
Definition: game_config.cpp:57
constexpr terrain_code NONE_TERRAIN
Definition: translation.hpp:58
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
constexpr ter_layer NO_LAYER
Definition: translation.hpp:40
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::string > split(const config_attribute_value &val)
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
#define ERR_G
Definition: type_data.cpp:24
#define LOG_G
Definition: type_data.cpp:25
#define DBG_G
Definition: type_data.cpp:26