The Battle for Wesnoth  1.17.8+dev
translation.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2022
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);
52  terrain_code(ter_layer b, ter_layer o) : base(b), overlay(o) {}
53  terrain_code() : base(0), overlay(NO_LAYER) {}
54 
55  ter_layer base;
56  ter_layer overlay;
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(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 = x * h + y; return data.at(index); }
90  const terrain_code& get(int x, int y) const { std::size_t index = 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() + h * x; }
96  std::vector<terrain_code>::const_iterator operator[](int x) const { return data.begin() + 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 
109  ter_list terrain;
110  ter_list mask;
111  ter_list masked_terrain;
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 new format of a terrain code
168  * is 2 to 4 characters in the set
169  *@verbatim
170  * [a-Z][A-Z]/|\_
171  *@endverbatim
172  * The underscore is intended for internal use.
173  * Other letters and characters are not validated but
174  * users of these letters can get nasty surprises.
175  * The * is used as wildcard in some cases.
176  * The terrain code can be two groups separated by a caret,
177  * the first group is the base terrain,
178  * the second the overlay terrain.
179  *
180  * @param filler if there's no layer this value will be used as the second layer
181  *
182  * @return A single terrain code
183  */
184  terrain_code read_terrain_code(std::string_view str, const ter_layer filler = NO_LAYER);
185 
186  /**
187  * Writes a single terrain code to a string.
188  * The writers only support the new format.
189  *
190  * @param tcode The terrain code to convert to a string
191  *
192  * @return A string containing the terrain code
193  */
194  std::string write_terrain_code(const terrain_code& tcode);
195  inline std::ostream &operator<<(std::ostream &s, const terrain_code &a)
196  { s << write_terrain_code(a); return s; }
197 
198  /**
199  * Reads a list of terrains from a string, when reading the
200  *
201  * @param str A string with one or more terrain codes (see read_terrain_code)
202  * @param filler If there's no layer, this value will be used as the second layer
203  *
204  * @returns A vector which contains the terrain codes found in the string
205  */
206  ter_list read_list(std::string_view str, const ter_layer filler = NO_LAYER);
207 
208  /**
209  * Writes a list of terrains to a string, only writes the new format.
210  *
211  * @param list A vector with one or more terrain codes
212  *
213  * @returns A string with the terrain codes, comma separated
214  * and a space behind the commas. Not padded.
215  */
216  std::string write_list(const ter_list& list);
217 
218  using starting_positions = boost::bimaps::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::multiset_of<coordinate>>;
219  /**
220  * Reads a gamemap string into a 2D vector
221  *
222  * @param str A string containing the gamemap, the following rules
223  * are stated for a gamemap:
224  * * The map is square
225  * * The map can be prefixed with one or more empty lines,
226  * these lines are ignored
227  * * The map can be postfixed with one or more empty lines,
228  * these lines are ignored
229  * * Every end of line can be followed by one or more empty
230  * lines, these lines are ignored.
231  * @deprecated NOTE it's deprecated to use this feature.
232  * * Terrain strings are separated by comma's or an end of line
233  * symbol, for the last terrain string in the row. For
234  * readability it's allowed to pad strings with either spaces
235  * or tab, however the tab is deprecated.
236  * * A terrain string contains either a terrain or a terrain and
237  * starting location. The following format is used
238  * [S ]T
239  * S = starting location a positive non-zero number
240  * T = terrain code (see read_terrain_code)
241  * @param positions This parameter will be filled with the starting
242  * locations found. Starting locations can only occur once
243  * if multiple definitions occur of the same position only
244  * the last is stored. The returned value is a map:
245  * * first the starting locations
246  * * second a coordinate structure where the location was found
247  * @param border_offset
248  *
249  * @returns A 2D vector with the terrains found the vector data is stored
250  * like result[x][y] where x the column number is and y the row number.
251  */
252  ter_map read_game_map(std::string_view str, starting_positions& positions, coordinate border_offset = coordinate{ 0, 0 });
253 
254  /**
255  * Write a gamemap in to a vector string.
256  *
257  * @param map A terrain vector, as returned from read_game_map
258  * @param positions A starting positions map, as returned from read_game_map
259  * @param border_offset
260  *
261  * @returns A terrain string which can be read with read_game_map.
262  * For readability the map is padded to groups of 12 chars,
263  * followed by a comma and space.
264  */
265  std::string write_game_map(const ter_map& map, const starting_positions& positions = starting_positions(), coordinate border_offset = coordinate{ 0, 0 });
266 
267  /**
268  * Tests whether a specific terrain matches a list of expressions.
269  * The list can use wildcard matching with *.
270  * It also has an inversion function.
271  * When a ! is found the result of the match is inverted.
272  * The matching stops at the first match (regardless of the ! found)
273  * the data is match from start to end.
274  *
275  * Example:
276  * Ww, W* does match and returns true
277  * Ww, {!, W*} does match and returns false (due to the !)
278  * WW, Ww doesn't match and return false
279  *
280  * Multilayer rules:
281  * If a terrain has multiple layers, each layer will be matched separately,
282  * returning true only if both layers match.
283  *
284  * Example:
285  * A*^* matches Abcd but also Abcd^Abcd
286  * A*^ matches Abcd but *not* Abcd^Abcd
287  * A*^Abcd does not match Abcd but matches Abcd^Abcd
288  *
289  * Note: If an expression doesn't specify a second layer (i.e. it contains
290  * no caret) the second layer will be filled in with a default value
291  * (See read_terrain_code and read_list).
292  *
293  * In the terrain building code, the second layer will default to the wildcard,
294  * so both A* and A*^* will match Abcd^Abcd
295  *
296  * @param src the value to match (may not contain wildcards)
297  * @param dest the list of expressions to match against
298  *
299  * @returns the result of the match (depending on the !'s)
300  */
301  bool terrain_matches(const terrain_code& src, const ter_list& dest);
302 
303  /**
304  * Tests whether a specific terrain matches an expression,
305  * for matching rules see above.
306  *
307  * @param src the value to match (may not contain wildcards)
308  * @param dest the expression to match against
309  *
310  * @returns the result of the match (depending on the !'s)
311  */
312  bool terrain_matches(const terrain_code& src, const terrain_code& dest);
313 
314  /**
315  * Tests whether a certain terrain matches a list of expressions, for matching
316  * rules see above. The matching requires some bit mask which impose a
317  * certain overhead. This version uses a cache to cache the masks so if
318  * a list needs to be matched often this version is preferred.
319  *
320  * @param src the value to match (may not contain wildcards)
321  * @param dest the cached list of expressions to match against
322  *
323  * @returns the result of the match (depending on the !'s)
324  */
325  bool terrain_matches(const terrain_code& src, const ter_match& dest);
326 
327  /**
328  * Tests whether a terrain code contains a wildcard
329  *
330  * @param tcode the terrain code to test for a wildcard
331  *
332  * @returns true if wildcard found, else false
333  */
334  bool has_wildcard(const terrain_code& tcode);
335 
336  /**
337  * Tests whether a terrain-code list contains at least
338  * one item with a wildcard
339  *
340  * @param list the list to test for a wildcard
341  *
342  * @returns true if a wildcard found, else false
343  */
344  bool has_wildcard(const ter_list& list);
345 
346  // These terrain letters are in the builder format,
347  // and not usable in other parts of the engine
348  const ter_layer TB_STAR = '*' << 24; // It can be assumed this is the equivalent of STAR
349  const ter_layer TB_DOT = '.' << 24;
350 
351  /**
352  * Reads a builder map.
353  * A builder map differs a great deal from a normal map,
354  * hence the different functions.
355  *
356  * @param str The map data, a terrain letter is either a * or a . or a number as
357  * anchor. The star or dot are stored in the base part of the terrain
358  * and the anchor in the overlay part. If more letters are allowed as
359  * special case they will be stored in the base part.
360  * Anchor 0 is no anchor.
361  *
362  * @returns A 2D vector with the data found the vector data is stored
363  * like result[y][x] where x the column number is and y the row number.
364  */
365  ter_map read_builder_map(const std::string& str);
366 
367 } // end namespace t_translation
const terrain_code CAVE
ter_map(int w, int h, terrain_code fill=terrain_code())
Definition: translation.hpp:84
const terrain_code NONE_TERRAIN
Definition: translation.hpp:58
const terrain_code FOREST
boost::bimaps::bimap< boost::bimaps::set_of< std::string >, boost::bimaps::multiset_of< coordinate > > starting_positions
const terrain_code DWARVEN_KEEP
error(const std::string &message)
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
#define a
uint32_t ter_layer
Definition: translation.hpp:38
std::string_view data
Definition: picture.cpp:208
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
std::vector< terrain_code > data
Definition: translation.hpp:92
const ter_layer NO_LAYER
Definition: translation.hpp:40
#define h
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 HUMAN_KEEP
const terrain_code HILL
const ter_match ALL_MOUNTAINS("!,*^V*,!,M*")
terrain_code read_terrain_code(std::string_view str, const ter_layer filler)
Reads a single terrain from a string.
terrain_code(ter_layer b, ter_layer o)
Definition: translation.hpp:52
const terrain_code VOID_TERRAIN
VOID_TERRAIN is used for shrouded hexes.
#define b
std::vector< terrain_code >::const_iterator operator[](int x) const
Definition: translation.hpp:96
int max_map_size()
Return the maximum allowed map size (in either dimension), the maximum map area is, therefore, this value squared.
Definition: translation.cpp:37
const terrain_code MOUNTAIN
std::ostream & operator<<(std::ostream &s, const terrain_code &a)
bool operator<(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:60
const terrain_code FOGGED
const terrain_code STAR
const terrain_code DWARVEN_CASTLE
const terrain_code MINUS
const ter_layer TB_STAR
const terrain_code PLUS
const terrain_code NOT
const ter_layer TB_DOT
const ter_match ALL_HILLS("!,*^V*,!,H*")
const terrain_code OFF_MAP_USER
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
const terrain_code HUMAN_CASTLE
terrain_code operator &(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:69
Encapsulates the map of the game.
Definition: location.hpp:38
std::vector< terrain_code >::iterator operator[](int x)
Definition: translation.hpp:95
const terrain_code BASE
const ter_match ALL_SWAMPS("!,*^V*,*^B*,!,S*")
bool operator==(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:63
terrain_code operator|(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:72
static map_location::DIRECTION s
ter_map read_builder_map(const std::string &str)
Reads a builder map.
bool operator!=(const terrain_code &a, const terrain_code &b)
Definition: translation.hpp:66
std::string write_list(const ter_list &list)
Writes a list of terrains to a string, only writes the new format.
int w
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:72
const terrain_code CAVE_WALL
bool has_wildcard(const terrain_code &tcode)
Tests whether a terrain code contains a wildcard.
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 terrain_code DEEP_WATER
const ter_match ALL_OFF_MAP
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:28
const terrain_code UNDERGROUND_VILLAGE
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
const ter_layer WILDCARD
Definition: translation.hpp:39
const terrain_code SHALLOW_WATER
This structure can be used for matching terrain strings.
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:41
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
const terrain_code GRASS_LAND
ter_list read_list(std::string_view str, const ter_layer filler)
Reads a list of terrains from a string, when reading the.
const ter_match ALL_FORESTS