The Battle for Wesnoth  1.19.18+dev
translation.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2025
3  by Mark de Wever <koraq@xs4all.nl>
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 #pragma once
17 
18 #include <vector>
19 #include <map>
20 #include <cstdint>
21 #include <boost/bimap.hpp>
22 #include <boost/bimap/set_of.hpp>
23 #include <boost/bimap/multiset_of.hpp>
24 
25 #include "exceptions.hpp"
26 #include "map/location.hpp"
27 
28 #include <string_view>
29 
30 namespace t_translation {
31 
32  /**
33  * Return the maximum allowed map size (in either dimension),
34  * the maximum map area is, therefore, this value squared.
35  */
36  int max_map_size();
37 
38  typedef uint32_t ter_layer;
39  constexpr ter_layer WILDCARD = 0x2A000000;
40  constexpr ter_layer NO_LAYER = 0xFFFFFFFF;
41 
42  // The definitions for a terrain
43  /**
44  * A terrain string which is converted to a terrain is a string with 1 or 2 layers
45  * the layers are separated by a caret and each group consists of 2 to 4 characters
46  * if no second layer is defined it is stored as 0xFFFFFFFF, if the second layer
47  * is empty (needed for matching) the layer has the value 0.
48  */
49  struct terrain_code {
50  terrain_code(const std::string& b, const std::string& o);
51  explicit terrain_code(const std::string& b, ter_layer o = NO_LAYER);
52  constexpr terrain_code(ter_layer b, ter_layer o) : base(b), overlay(o) {}
53  constexpr terrain_code() = default;
54 
57  };
59 
60  inline bool operator<(const terrain_code& a, const terrain_code& b)
61  { return std::tie(a.base, a.overlay) < std::tie(b.base, b.overlay); };
62 
63  inline bool operator==(const terrain_code& a, const terrain_code& b)
64  { return a.base == b.base && a.overlay == b.overlay; }
65 
66  inline bool operator!=(const terrain_code& a, const terrain_code& b)
67  { return a.base != b.base || a.overlay != b.overlay; }
68 
70  { return terrain_code(a.base & b.base, a.overlay & b.overlay); }
71 
73  { return terrain_code(a.base | b.base, a.overlay | b.overlay); }
74 
75  // operator<< is defined later
76 
77  typedef std::vector<terrain_code> ter_list;
78  struct ter_map {
79 
80  ter_map() = default;
81  ter_map(int w, int h, terrain_code fill = NONE_TERRAIN) : data(static_cast<std::size_t>(w) * h, fill), w(w), h(h) {}
82 
83  terrain_code& get(int x, int y) { std::size_t index = static_cast<std::size_t>(x) * h + y; return data.at(index); }
84  const terrain_code& get(int x, int y) const { std::size_t index = static_cast<std::size_t>(x) * h + y; return data.at(index); }
85 
86  std::vector<terrain_code> data;
87  int w{0};
88  int h{0};
89  std::vector<terrain_code>::iterator operator[](int x) { return data.begin() + static_cast<std::size_t>(h) * x; }
90  std::vector<terrain_code>::const_iterator operator[](int x) const { return data.begin() + static_cast<std::size_t>(h) * x; }
91  };
92 
93  /**
94  * This structure can be used for matching terrain strings.
95  * It optimized for strings that need to be matched often,
96  * and caches the wildcard info required for matching.
97  */
98  struct ter_match{
99  ter_match() = default;
100  ter_match(std::string_view str, const ter_layer filler = NO_LAYER);
101  ter_match(const terrain_code& tcode);
102 
106  bool has_wildcard = false;
107  bool is_empty = true;
108  };
109 
110  /** Contains an x and y coordinate used for starting positions in maps. */
112 
113  // Exception thrown if there's an error with the terrain.
114  // Note: atm most thrown result in a crash, but I like
115  // an uncatched exception better than an assert.
116  struct error : public game::error {
117  error(const std::string& message) : game::error(message) {}
118  };
119 
120  // Some types of terrain which must be known, and can't just
121  // be loaded in dynamically because they're special.
122  // It's asserted that there will be corresponding entries for
123  // these types of terrain in the terrain configuration file.
124  extern const terrain_code VOID_TERRAIN;
125  extern const terrain_code FOGGED;
126 
127  // On the map the user can use this type to make odd shaped maps look good.
128  extern const terrain_code OFF_MAP_USER;
129 
130  extern const terrain_code HUMAN_CASTLE;
131  extern const terrain_code HUMAN_KEEP;
132  extern const terrain_code SHALLOW_WATER;
133  extern const terrain_code DEEP_WATER;
134  extern const terrain_code GRASS_LAND;
135  extern const terrain_code FOREST;
136  extern const terrain_code MOUNTAIN;
137  extern const terrain_code HILL;
138 
139  extern const terrain_code CAVE_WALL;
140  extern const terrain_code CAVE;
141  extern const terrain_code UNDERGROUND_VILLAGE;
142  extern const terrain_code DWARVEN_CASTLE;
143  extern const terrain_code DWARVEN_KEEP;
144 
145  extern const terrain_code PLUS; // +
146  extern const terrain_code MINUS; // -
147  extern const terrain_code NOT; // !
148  extern const terrain_code STAR; // *
149  extern const terrain_code BASE; // references the base terrain in movement/defense aliases
150 
151  extern const ter_match ALL_OFF_MAP;
152  extern const ter_match ALL_FORESTS;
153  extern const ter_match ALL_HILLS;
154  extern const ter_match ALL_MOUNTAINS; //excluding impassable mountains
155  extern const ter_match ALL_SWAMPS;
156 
157  /**
158  * Reads a single terrain from a string.
159  *
160  * @param str The string which should contain 1 terrain code;
161  * the format of a terrain code
162  * is 2 to 4 characters in the set
163  *@verbatim
164  * [a-zA-Z/|\_]
165  *@endverbatim
166  * The underscore is intended for internal use.
167  * Other characters are reserved for future use.
168  * The * is used as wildcard in some cases.
169  * The terrain code can be two groups separated by a caret,
170  * the first group is the base terrain,
171  * the second the overlay terrain.
172  *
173  * @param filler If no overlay is specified this value will be used.
174  *
175  * @return A single terrain code
176  */
177  terrain_code read_terrain_code(std::string_view str, const ter_layer filler = NO_LAYER);
178 
179  /**
180  * Writes a single terrain code to a string.
181  * The writers only support the new format.
182  *
183  * @param tcode The terrain code to convert to a string
184  *
185  * @return A string containing the terrain code
186  */
187  std::string write_terrain_code(const terrain_code& tcode);
188  inline std::ostream &operator<<(std::ostream &s, const terrain_code &a)
189  { s << write_terrain_code(a); return s; }
190 
191  /**
192  * Reads a list of terrains from a string, when reading the
193  *
194  * @param str A string with one or more terrain codes (see read_terrain_code)
195  * @param filler If no overlay is specified this value will be used.
196  *
197  * @returns A vector which contains the terrain codes found in the string
198  */
199  ter_list read_list(std::string_view str, const ter_layer filler = NO_LAYER);
200 
201  /**
202  * Writes a list of terrains to a string, only writes the new format.
203  *
204  * @param list A vector with one or more terrain codes
205  *
206  * @returns A string with the terrain codes, comma separated
207  * and a space behind the commas. Not padded.
208  */
209  std::string write_list(const ter_list& list);
210 
211  using starting_positions = boost::bimaps::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::multiset_of<coordinate>>;
212  /**
213  * Reads a gamemap string into a 2D vector
214  *
215  * @param str A string containing the gamemap, the following rules
216  * are stated for a gamemap:
217  * * The map is square
218  * * The map can be prefixed with one or more empty lines,
219  * these lines are ignored
220  * * The map can be postfixed with one or more empty lines,
221  * these lines are ignored
222  * * Every end of line can be followed by one or more empty
223  * lines, these lines are ignored.
224  * @deprecated NOTE it's deprecated to use this feature.
225  * * Terrain strings are separated by comma's or an end of line
226  * symbol, for the last terrain string in the row. For
227  * readability it's allowed to pad strings with either spaces
228  * or tab, however the tab is deprecated.
229  * * A terrain string contains either a terrain or a terrain and
230  * starting location. The following format is used
231  * [S ]T
232  * S = starting location a positive non-zero number
233  * T = terrain code (see read_terrain_code)
234  * @param positions This parameter will be filled with the starting
235  * locations found. Starting locations can only occur once
236  * if multiple definitions occur of the same position only
237  * the last is stored. The returned value is a map:
238  * * first the starting locations
239  * * second a coordinate structure where the location was found
240  * @param border_offset
241  *
242  * @returns A 2D vector with the terrains found the vector data is stored
243  * like result[x][y] where x the column number is and y the row number.
244  */
245  ter_map read_game_map(std::string_view str, starting_positions& positions, coordinate border_offset = coordinate{ 0, 0 });
246 
247  /**
248  * Write a gamemap in to a vector string.
249  *
250  * @param map A terrain vector, as returned from read_game_map
251  * @param positions A starting positions map, as returned from read_game_map
252  * @param border_offset
253  *
254  * @returns A terrain string which can be read with read_game_map.
255  * For readability the map is padded to groups of 12 chars,
256  * followed by a comma and space.
257  */
258  std::string write_game_map(const ter_map& map, const starting_positions& positions = starting_positions(), coordinate border_offset = coordinate{ 0, 0 });
259 
260  /**
261  * Tests whether a specific terrain matches a list of expressions.
262  * The list can use wildcard matching with *.
263  * It also has an inversion function.
264  * When a ! is found the result of the match is inverted.
265  * The matching stops at the first match (regardless of the ! found)
266  * the data is match from start to end.
267  *
268  * Example:
269  * Ww, W* does match and returns true
270  * Ww, {!, W*} does match and returns false (due to the !)
271  * WW, Ww doesn't match and return false
272  *
273  * Multilayer rules:
274  * If a terrain has multiple layers, each layer will be matched separately,
275  * returning true only if both layers match.
276  *
277  * Example:
278  * A*^* matches Abcd but also Abcd^Abcd
279  * A*^ matches Abcd but *not* Abcd^Abcd
280  * A*^Abcd does not match Abcd but matches Abcd^Abcd
281  *
282  * Note: If an expression doesn't specify a second layer (i.e. it contains
283  * no caret) the second layer will be filled in with a default value
284  * (See read_terrain_code and read_list).
285  *
286  * In the terrain building code, the second layer will default to the wildcard,
287  * so both A* and A*^* will match Abcd^Abcd
288  *
289  * @param src the value to match (may not contain wildcards)
290  * @param dest the list of expressions to match against
291  *
292  * @returns the result of the match (depending on the !'s)
293  */
294  bool terrain_matches(const terrain_code& src, const ter_list& dest);
295 
296  /**
297  * Tests whether a specific terrain matches an expression,
298  * for matching rules see above.
299  *
300  * @param src the value to match (may not contain wildcards)
301  * @param dest the expression to match against
302  *
303  * @returns the result of the match (depending on the !'s)
304  */
305  bool terrain_matches(const terrain_code& src, const terrain_code& dest);
306 
307  /**
308  * Tests whether a certain terrain matches a list of expressions, for matching
309  * rules see above. The matching requires some bit mask which impose a
310  * certain overhead. This version uses a cache to cache the masks so if
311  * a list needs to be matched often this version is preferred.
312  *
313  * @param src the value to match (may not contain wildcards)
314  * @param dest the cached list of expressions to match against
315  *
316  * @returns the result of the match (depending on the !'s)
317  */
318  bool terrain_matches(const terrain_code& src, const ter_match& dest);
319 
320  /**
321  * Tests whether a terrain code contains a wildcard
322  *
323  * @param tcode the terrain code to test for a wildcard
324  *
325  * @returns true if wildcard found, else false
326  */
327  bool has_wildcard(const terrain_code& tcode);
328 
329  /**
330  * Tests whether a terrain-code list contains at least
331  * one item with a wildcard
332  *
333  * @param list the list to test for a wildcard
334  *
335  * @returns true if a wildcard found, else false
336  */
337  bool has_wildcard(const ter_list& list);
338 
339  // These terrain letters are in the builder format,
340  // and not usable in other parts of the engine
341  const ter_layer TB_STAR = '*' << 24; // It can be assumed this is the equivalent of STAR
342  const ter_layer TB_DOT = '.' << 24;
343 
344  /**
345  * Reads a builder map.
346  * A builder map differs a great deal from a normal map,
347  * hence the different functions.
348  *
349  * @param str The map data, a terrain letter is either a * or a . or a number as
350  * anchor. The star or dot are stored in the base part of the terrain
351  * and the anchor in the overlay part. If more letters are allowed as
352  * special case they will be stored in the base part.
353  * Anchor 0 is no anchor.
354  *
355  * @returns A 2D vector with the data found the vector data is stored
356  * like result[y][x] where x the column number is and y the row number.
357  */
358  ter_map read_builder_map(const std::string& str);
359 
360 } // end namespace t_translation
void fill(const ::rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:52
terrain_code read_terrain_code(std::string_view str, const ter_layer filler)
Reads a single terrain from a string.
ter_map read_game_map(std::string_view str, starting_positions &starting_positions, coordinate border_offset)
Reads a gamemap string into a 2D vector.
const terrain_code CAVE_WALL
constexpr terrain_code NONE_TERRAIN
Definition: translation.hpp:58
const ter_match ALL_FORESTS
std::string write_game_map(const ter_map &map, const starting_positions &starting_positions, coordinate border_offset)
Write a gamemap in to a vector string.
const ter_layer TB_STAR
const terrain_code VOID_TERRAIN
VOID_TERRAIN is used for shrouded hexes.
const terrain_code SHALLOW_WATER
const terrain_code MINUS
const terrain_code DWARVEN_KEEP
const terrain_code UNDERGROUND_VILLAGE
const ter_match ALL_SWAMPS("!,*^V*,*^B*,!,S*")
constexpr ter_layer WILDCARD
Definition: translation.hpp:39
std::ostream & operator<<(std::ostream &s, const terrain_code &a)
const terrain_code HUMAN_CASTLE
const terrain_code NOT
int max_map_size()
Return the maximum allowed map size (in either dimension), the maximum map area is,...
Definition: translation.cpp:35
bool has_wildcard(const terrain_code &tcode)
Tests whether a terrain code contains a wildcard.
terrain_code operator&(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:69
const terrain_code HILL
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
const terrain_code STAR
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
const terrain_code BASE
const terrain_code GRASS_LAND
const ter_match ALL_OFF_MAP
bool operator!=(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:66
const terrain_code DEEP_WATER
boost::bimaps::bimap< boost::bimaps::set_of< std::string >, boost::bimaps::multiset_of< coordinate > > starting_positions
const ter_match ALL_HILLS("!,*^V*,!,H*")
ter_map read_builder_map(const std::string &str)
Reads a builder map.
uint32_t ter_layer
Definition: translation.hpp:38
const terrain_code FOREST
const terrain_code PLUS
ter_list read_list(std::string_view str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
terrain_code operator|(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:72
const ter_match ALL_MOUNTAINS("!,*^V*,!,M*")
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
const terrain_code MOUNTAIN
bool operator<(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:60
const terrain_code DWARVEN_CASTLE
const ter_layer TB_DOT
constexpr ter_layer NO_LAYER
Definition: translation.hpp:40
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
const terrain_code CAVE
const terrain_code FOGGED
const terrain_code OFF_MAP_USER
bool operator==(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:63
std::string write_list(const ter_list &list)
Writes a list of terrains to a string, only writes the new format.
const terrain_code HUMAN_KEEP
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
rect src
Non-transparent portion of the surface to compose.
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
std::string message
Definition: exceptions.hpp:30
Encapsulates the map of the game.
Definition: location.hpp:46
error(const std::string &message)
std::vector< terrain_code >::const_iterator operator[](int x) const
Definition: translation.hpp:90
terrain_code & get(int x, int y)
Definition: translation.hpp:83
std::vector< terrain_code > data
Definition: translation.hpp:86
std::vector< terrain_code >::iterator operator[](int x)
Definition: translation.hpp:89
const terrain_code & get(int x, int y) const
Definition: translation.hpp:84
ter_map(int w, int h, terrain_code fill=NONE_TERRAIN)
Definition: translation.hpp:81
This structure can be used for matching terrain strings.
Definition: translation.hpp:98
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
constexpr terrain_code()=default
constexpr terrain_code(ter_layer b, ter_layer o)
Definition: translation.hpp:52
static map_location::direction s
#define b