The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
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
33
35 : terrainList_()
36 , tcodeToTerrain_()
37 , initialized_(false)
38 , game_config_(game_config)
39{
41 singleton_ = this;
42}
43
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 {
65 DBG_G << "create_terrain_maps: " << terrain.number() << " "
66 << terrain.id() << " " << terrain.name() << " : " << terrain.editor_group();
67
68 std::pair<std::map<t_translation::terrain_code, terrain_type>::iterator, bool> res;
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
115
116
117const 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
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
182terrain_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;
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)
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
double t
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
t_string get_terrain_string(const t_translation::terrain_code &terrain) const
Get a formatted terrain name – terrain (underlying terrains)
static terrain_type_data * singleton_
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 ...
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.
static terrain_type_data * get()
Definition type_data.cpp:28
const std::map< t_translation::terrain_code, terrain_type > & map() const
tcodeToTerrain_t::const_iterator find_or_create(t_translation::terrain_code) const
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.
t_string get_terrain_editor_string(const t_translation::terrain_code &terrain) const
terrain_type_data(const game_config_view &game_config)
Definition type_data.cpp:34
const t_translation::ter_list & list() const
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 & name() const
Definition terrain.hpp:48
const std::string & editor_group() const
Definition terrain.hpp:162
const t_translation::ter_list & union_type() const
Definition terrain.hpp:87
t_translation::terrain_code number() const
Definition terrain.hpp:66
const t_string & description() const
Definition terrain.hpp:50
const t_string & editor_name() const
Definition terrain.hpp:49
#define ERR_G
Definition gettext.cpp:39
#define DBG_G
Definition gettext.cpp:36
Standard logging facilities (interface).
Game configuration data as global variables.
constexpr terrain_code NONE_TERRAIN
std::vector< terrain_code > ter_list
constexpr ter_layer NO_LAYER
std::string join(const Range &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)
#define LOG_G
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
#define i