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