The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
translation.cpp
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/**
17 * @file
18 * Routines for terrain-conversion.
19 */
20
21#define GETTEXT_DOMAIN "wesnoth-lib"
22
23#include "gettext.hpp"
24#include "lexical_cast.hpp"
25#include "log.hpp"
28#include "utils/iterable_pair.hpp" //equal_range returns a std:pair instead of sometihng iterable for some reason.
29
30#define ERR_G LOG_STREAM(err, lg::general())
31#define WRN_G LOG_STREAM(warn, lg::general())
32
33namespace t_translation {
34
36 return 1000; //TODO make this overridable by the user without having to rebuild
37 }
38
39/***************************************************************************************/
40// forward declaration of internal functions
41
42 // The low level convertors,
43 // These function are the ones which know about the internal format.
44 // All other functions are unaware of the internal format.
45
46 /**
47 * Get the mask for a single layer.
48 *
49 * @param terrain 1 layer of a terrain, might have a wildcard.
50 *
51 * @return Mask for that layer.
52 */
53 static ter_layer get_layer_mask_(ter_layer terrain); //inlined
54
55 /**
56 * Gets a mask for a terrain, this mask is used for wildcard matching.
57 *
58 * @param terrain The terrain which might have a wildcard.
59 *
60 * @return The mask for this terrain.
61 */
62 static terrain_code get_mask_(const terrain_code& terrain);
63
64 /**
65 * Converts a string to a layer.
66 *
67 * @param str The terrain string to convert, but needs to be
68 * sanitized so no spaces and only the terrain to convert.
69 *
70 * @return The converted layer.
71 */
72 static ter_layer string_to_layer_(std::string_view str);
73
74 /**
75 * Converts a terrain string to a number.
76 * @param str The terrain string with an optional number.
77 * @param start_positions Returns the start_positions, the caller should
78 * set it on -1 and it's only changed it there is
79 * a starting position found.
80 * @param filler If no overlay is specified this value will be used.
81 *
82 * @return The terrain code found in the string if no
83 * valid terrain is found VOID will be returned.
84 */
85 static terrain_code string_to_number_(std::string_view str, std::vector<std::string>& start_positions, const ter_layer filler);
86 static terrain_code string_to_number_(std::string_view str, const ter_layer filler = NO_LAYER);
87
88 /**
89 * Converts a terrain number to a string
90 *
91 * @param terrain The terrain number to convert.
92 * @param start_position The starting position, if smaller than 0
93 * it's ignored else it's written.
94 *
95 * @return The converted string, if no starting
96 * position given it's padded to 4 chars else
97 * padded to 7 chars.
98 */
99 static std::string number_to_string_(terrain_code terrain, const std::vector<std::string>& start_position = std::vector<std::string>());
100
101 /**
102 * Converts a terrain string to a number for the builder.
103 * The translation rules differ from the normal conversion rules
104 *
105 * @param str The terrain string.
106 *
107 * @return Number for the builder map.
108 */
109 static terrain_code string_to_builder_number_(std::string str);
110
111/***************************************************************************************/
112
114
115/**
116 * VOID_TERRAIN is used for shrouded hexes. It's also used by terrain_type's
117 * default constructor, but that's only used as the sentinel value for when
118 * terrain_type_data::get_terrain_info() is asked for an unknown terrain code.
119 */
122
131
137
143
144const ter_match ALL_OFF_MAP("_off^_usr,*^_fme");
145const ter_match ALL_FORESTS("F*,*^F*");
146const ter_match ALL_HILLS("!,*^V*,!,H*");
147const ter_match ALL_MOUNTAINS("!,*^V*,!,M*"); //excluding impassable mountains
148const ter_match ALL_SWAMPS("!,*^V*,*^B*,!,S*"); //excluding swamp villages and bridges
149
150/***************************************************************************************/
151
153 : base(string_to_layer_(b))
154 , overlay(o)
155{
156}
157
158terrain_code::terrain_code(const std::string& b, const std::string& o)
159 : base(string_to_layer_(b))
161{
162}
163
164ter_match::ter_match(std::string_view str, const ter_layer filler)
165 : terrain(t_translation::read_list(str, filler))
166 , mask()
167 , masked_terrain()
169 , is_empty(terrain.empty())
170{
171 mask.resize(terrain.size());
172 masked_terrain.resize(terrain.size());
173
174 for(std::size_t i = 0; i < terrain.size(); i++) {
177 }
178}
179
181 : terrain(ter_list(1, tcode))
182 , mask()
183 , masked_terrain()
185 , is_empty(terrain.empty())
186{
187 mask.resize(terrain.size());
188 masked_terrain.resize(terrain.size());
189
190 for(std::size_t i = 0; i < terrain.size(); i++) {
193 }
194}
195
196terrain_code read_terrain_code(std::string_view str, const ter_layer filler)
197{
198 return string_to_number_(str, filler);
199}
200
201std::string write_terrain_code(const terrain_code& tcode)
202{
203 return number_to_string_(tcode);
204}
205
206ter_list read_list(std::string_view str, const ter_layer filler)
207{
208 // Handle an empty string
209 ter_list result;
210
211 if(str.empty()) {
212 return result;
213 }
214
215 std::size_t offset = 0;
216 while(offset < str.length()) {
217
218 // Get a terrain chunk
219 const std::string separators = ",";
220 const std::size_t pos_separator = str.find_first_of(separators, offset);
221 std::string_view terrain = str.substr(offset, pos_separator - offset);
222
223 // Process the chunk
224 const terrain_code tile = string_to_number_(terrain, filler);
225
226 // Add the resulting terrain number
227 result.push_back(tile);
228
229 // Evaluate the separator
230 if(pos_separator == std::string_view::npos) {
231 offset = str.length();
232 } else {
233 offset = pos_separator + 1;
234 }
235 }
236
237 return result;
238}
239
240std::string write_list(const ter_list& list)
241{
242 std::stringstream result;
243
244 ter_list::const_iterator itor = list.begin();
245 for( ; itor != list.end(); ++itor) {
246 if(itor == list.begin()) {
247 result << number_to_string_(*itor);
248 } else {
249 result << ", " << number_to_string_(*itor);
250 }
251 }
252
253 return result.str();
254}
255
256static std::pair<int, int> get_map_size(const char* begin, const char* end)
257{
258 int w = 1;
259 int h = 0;
260 for (const char* it = begin; it != end;) {
261 int cur_w = 1;
262 ++h;
263
264
265 for (;it != end && (*it != '\n' && *it != '\r'); ++it) {
266 if (*it == ',') {
267 ++cur_w;
268 }
269 }
270 w = std::max(w, cur_w);
271
272 while (it != end && (*it == '\n' || *it == '\r')) {
273 ++it;
274 }
275
276 }
277 return{ w, h };
278}
279
281{
282 std::size_t offset = 0;
283 int x = 0, y = 0, width = 0;
284
285 // Skip the leading newlines
286 while(!str.empty() && utils::isnewline(str.front())) {
287 str.remove_prefix(1);
288 }
289
290 // Did we get an empty map?
291 if(str.length() <= 1) {
292 return ter_map();
293 }
294
295 auto map_size = get_map_size(&str[0], &str[0] + str.size());
296 ter_map result(map_size.first, map_size.second);
297
298 while(offset < str.length()) {
299
300 // Get a terrain chunk
301 const std::string separators = ",\n\r";
302 const std::size_t pos_separator = str.find_first_of(separators, offset);
303 std::string_view terrain = str.substr(offset, pos_separator - offset);
304
305 // Process the chunk
306 std::vector<std::string> sp;
307 // The gamemap never has a wildcard
308 const terrain_code tile = string_to_number_(terrain, sp, NO_LAYER);
309
310 // Add to the resulting starting position
311 for(const auto& starting_position : sp) {
312 if (starting_positions.left.find(starting_position) != starting_positions.left.end()) {
313 WRN_G << "Starting position " << starting_position << " is redefined.";
314 }
315 starting_positions.insert(starting_positions::value_type(starting_position, coordinate(x - border_offset.x, y - border_offset.y)));
316 }
317
318 if(result.w <= x || result.h <= y) {
319 throw error("Map not a rectangle.");
320 }
321
322 // Add the resulting terrain number
323 result.get(x, y) = tile;
324
325 // Evaluate the separator
326 if(pos_separator == std::string::npos || utils::isnewline(str[pos_separator])) {
327 // the first line we set the with the other lines we check the width
328 if(y == 0) {
329 // x contains the offset in the map
330 width = x + 1;
331 } else {
332 if((x + 1) != width ) {
333 ERR_G << "Map not a rectangle error occurred at line offset " << y << " position offset " << x;
334 throw error("Map not a rectangle.");
335 }
336 if (y > max_map_size()) {
337 ERR_G << "Map size exceeds limit (y > " << max_map_size() << ")";
338 throw error("Map height limit exceeded.");
339 }
340 }
341
342 // Prepare next iteration
343 ++y;
344 x = 0;
345
346 // Avoid in infinite loop if the last line ends without an EOL
347 if(pos_separator == std::string::npos) {
348 offset = str.length();
349
350 } else {
351
352 offset = pos_separator + 1;
353 // Skip the following newlines
354 while(offset < str.length() && utils::isnewline(str[offset])) {
355 ++offset;
356 }
357 }
358
359 } else {
360 ++x;
361 offset = pos_separator + 1;
362 if (x > max_map_size()) {
363 ERR_G << "Map size exceeds limit (x > " << max_map_size() << ")";
364 throw error("Map width limit exceeded.");
365 }
366 }
367
368 }
369
370 if(x != 0 && (x + 1) != width) {
371 ERR_G << "Map not a rectangle error occurred at the end";
372 throw error("Map not a rectangle.");
373 }
374
375 return result;
376}
377
378std::string write_game_map(const ter_map& map, const starting_positions& starting_positions, coordinate border_offset)
379{
380 std::stringstream str;
381
382 for(int y = 0; y < map.h; ++y) {
383 for(int x = 0; x < map.w; ++x) {
384
385 // If the current location is a starting position,
386 // it needs to be added to the terrain.
387 // After it's found it can't be found again,
388 // so the location is removed from the map.
389 std::vector<std::string> sp;
390
391 for(const auto& pair : starting_positions.right.equal_range(coordinate(x - border_offset.x, y - border_offset.y))) {
392 sp.push_back(pair.second);
393 }
394 // Add the separator
395 if(x != 0) {
396 str << ", ";
397 }
398 str << number_to_string_(map[x][y], sp);
399 }
400
401 if (y < map.h -1)
402 str << "\n";
403 }
404
405 return str.str();
406}
407
409{
410 return terrain_matches(src, ter_list(1, dest));
411}
412
413bool terrain_matches(const terrain_code& src, const ter_list& dest)
414{
415 // NOTE we impose some code duplication.
416 // It could have been rewritten to get a match structure
417 // and then call the version with the match structure.
418 // IMO that's some extra overhead to this function
419 // which is not required. Hence the two versions
420 if(dest.empty()) {
421 return false;
422 }
423
424#if 0
425 PLAIN_LOG << std::hex << "src = " << src.base << "^" << src.overlay << "\t"
426 << src_mask.base << "^" << src_mask.overlay << "\t"
427 << masked_src.base << "^" << masked_src.overlay << "\t"
428 << src_has_wildcard << "\n";
429#endif
430
431 bool result = true;
432 ter_list::const_iterator itor = dest.begin();
433
434 // Try to match the terrains if matched jump out of the loop.
435 for(; itor != dest.end(); ++itor) {
436
437 // Match wildcard
438 if(*itor == STAR) {
439 return result;
440 }
441
442 // Match inverse symbol
443 if(itor->base == NOT.base) {
444 result = !result;
445 continue;
446 }
447
448 // Full match
449 if(src == *itor) {
450 return result;
451 }
452
453 // Does the destination wildcard match
454 const terrain_code dest_mask = get_mask_(*itor);
455 const terrain_code masked_dest = (*itor & dest_mask);
456 const bool dest_has_wildcard = has_wildcard(*itor);
457#if 0
458 PLAIN_LOG << std::hex << "dest= "
459 << itor->base << "^" << itor->overlay << "\t"
460 << dest_mask.base << "^" << dest_mask.overlay << "\t"
461 << masked_dest.base << "^" << masked_dest.overlay << "\t"
462 << dest_has_wildcard << "\n";
463#endif
464 if(dest_has_wildcard &&
465 (src.base & dest_mask.base) == masked_dest.base &&
466 (src.overlay & dest_mask.overlay) == masked_dest.overlay) {
467 return result;
468 }
469
470/* Test code */ /*
471 if(src_has_wildcard && dest_has_wildcard && (
472 (
473 get_layer_mask_(itor->base) != NO_LAYER &&
474 get_layer_mask_(src.overlay) != NO_LAYER &&
475 (src.base & dest_mask.base) == masked_dest.base &&
476 (itor->overlay & src_mask.overlay) == masked_src.overlay
477 ) || (
478 get_layer_mask_(itor->overlay) != NO_LAYER &&
479 get_layer_mask_(src.base) != NO_LAYER &&
480 (src.overlay & dest_mask.overlay) == masked_dest.overlay &&
481 (itor->base & src_mask.base) == masked_src.base
482 ))) {
483
484 return result;
485 }
486*/
487 }
488
489 // No match, return the inverse of the result
490 return !result;
491}
492
493// This routine is used for the terrain building,
494// so it's one of the delays while loading a map.
495// This routine is optimized a bit at the loss of readability.
496bool terrain_matches(const terrain_code& src, const ter_match& dest)
497{
498 if(dest.is_empty) {
499 return false;
500 }
501
502 bool result = true;
503
504 // Try to match the terrains if matched jump out of the loop.
505 // We loop on the dest.terrain since the iterator is faster than operator[].
506 // The i holds the value for operator[].
507 // Since dest.mask and dest.masked_terrain need to be in sync,
508 // they are less often looked up, so no iterator for them.
509 std::size_t i = 0;
510 ter_list::const_iterator end = dest.terrain.end();
511 for(ter_list::const_iterator terrain_itor = dest.terrain.begin();
512 terrain_itor != end;
513 ++i, ++terrain_itor) {
514
515 // Match wildcard
516 if(*terrain_itor == STAR) {
517 return result;
518 }
519
520 // Match inverse symbol
521 if(terrain_itor->base == NOT.base) {
522 result = !result;
523 continue;
524 }
525
526 // Full match
527 if(*terrain_itor == src) {
528 return result;
529 }
530
531 // Does the destination wildcard match
532 if(dest.has_wildcard &&
533 (src.base & dest.mask[i].base) == dest.masked_terrain[i].base &&
534 (src.overlay & dest.mask[i].overlay) == dest.masked_terrain[i].overlay) {
535 return result;
536 }
537
538/* Test code */ /*
539 if(src_has_wildcard && has_wildcard(*terrain_itor) && (
540 (
541 get_layer_mask_(terrain_itor->base) != NO_LAYER &&
542 get_layer_mask_(src.overlay) != NO_LAYER &&
543 (src.base & dest.mask[i].base) == dest.masked_terrain[i].base &&
544 (terrain_itor->overlay & src_mask.overlay) == masked_src.overlay
545 ) || (
546 get_layer_mask_(terrain_itor->overlay) != NO_LAYER &&
547 get_layer_mask_(src.base) != NO_LAYER &&
548 (src.overlay & dest.mask[i].overlay) == dest.masked_terrain[i].overlay &&
549 (terrain_itor->base & src_mask.base) == masked_src.base
550 ))) {
551
552 return result;
553 }
554*/
555 }
556
557 // No match, return the inverse of the result
558 return !result;
559}
560
561bool has_wildcard(const terrain_code& tcode)
562{
563 if(tcode.overlay == NO_LAYER) {
564 return get_layer_mask_(tcode.base) != NO_LAYER;
565 } else {
566 return get_layer_mask_(tcode.base) != NO_LAYER || get_layer_mask_(tcode.overlay) != NO_LAYER;
567 }
568}
569
570bool has_wildcard(const ter_list& list)
571{
572 if(list.empty()) {
573 return false;
574 }
575
576 // Test all items for a wildcard
577 ter_list::const_iterator itor = list.begin();
578 for(; itor != list.end(); ++itor) {
579 if(has_wildcard(*itor)) {
580 return true;
581 }
582 }
583
584 // No wildcard found
585 return false;
586}
587
588ter_map read_builder_map(const std::string& str)
589{
590 std::size_t offset = 0;
591 // Skip the leading newlines
592 while(offset < str.length() && utils::isnewline(str[offset])) {
593 ++offset;
594 }
595 // Did we get an empty map?
596 if((offset + 1) >= str.length()) {
597 return ter_map();
598 }
599
600 auto map_size = get_map_size(&str[offset], str.c_str() + str.size());
601 ter_map result(map_size.second, map_size.first, terrain_code(t_translation::TB_DOT, ter_layer()));
602
603 int x = 0, y = 0;
604 while(offset < str.length()) {
605
606 // Get a terrain chunk
607 const std::string separators = ",\n\r";
608 const std::size_t pos_separator = str.find_first_of(separators, offset);
609 std::string terrain = "";
610 // Make sure we didn't hit an empty chunk
611 // which is allowed
612 if(pos_separator != offset) {
613 terrain = str.substr(offset, pos_separator - offset);
614 }
615
616 // Process the chunk
617 const terrain_code tile = string_to_builder_number_(terrain);
618
619 // Make space for the new item
620 if (result.h <= x || result.w <= y) {
621 throw error("Map not a rectangle.");
622 }
623
624 // Add the resulting terrain number,
625 result.get(y, x) = tile;
626
627 // evaluate the separator
628 if(pos_separator == std::string::npos) {
629 // Probably not required to change the value,
630 // but be sure the case should be handled at least.
631 // I'm not sure how it is defined in the standard,
632 // but here it's defined at max u32 which with +1 gives 0
633 // and make a nice infinite loop.
634 offset = str.length();
635 } else if(utils::isnewline(str[pos_separator])) {
636 // Prepare next iteration
637 ++y;
638 x = 0;
639
640 offset = pos_separator + 1;
641 // Skip the following newlines
642 while(offset < str.length() && utils::isnewline(str[offset])) {
643 ++offset;
644 }
645
646 } else {
647 ++x;
648 offset = pos_separator + 1;
649 }
650
651 }
652
653 return result;
654}
655
656/***************************************************************************************/
657// Internal
658
660{
661 // Test for the star 0x2A in every position
662 // and return the appropriate mask
663/*
664 * This is what the code intents to do, but in order to gain some more
665 * speed it's changed to the code below, which does the same but faster.
666 * This routine is used often in the builder and the speedup is noticeable. */
667 if((terrain & 0xFF000000) == 0x2A000000) return 0x00000000;
668 if((terrain & 0x00FF0000) == 0x002A0000) return 0xFF000000;
669 if((terrain & 0x0000FF00) == 0x00002A00) return 0xFFFF0000;
670 if((terrain & 0x000000FF) == 0x0000002A) return 0xFFFFFF00;
671
672/*
673 uint8_t *ptr = (uint8_t *) &terrain;
674
675 if(ptr[3] == 0x2A) return 0x00000000;
676 if(ptr[2] == 0x2A) return 0xFF000000;
677 if(ptr[1] == 0x2A) return 0xFFFF0000;
678 if(ptr[0] == 0x2A) return 0xFFFFFF00;
679*/
680 // no star found return the default
681 return 0xFFFFFFFF;
682}
683
684static terrain_code get_mask_(const terrain_code& terrain)
685{
686 if(terrain.overlay == NO_LAYER) {
687 return terrain_code(get_layer_mask_(terrain.base), 0xFFFFFFFF);
688 } else {
689 return terrain_code(get_layer_mask_(terrain.base), get_layer_mask_(terrain.overlay));
690 }
691}
692
693static ter_layer string_to_layer_(std::string_view str)
694{
695 if(str.empty()) {
696 return NO_LAYER;
697 }
698
699 if(str.size() > 4) {
700 throw error("A terrain with a string with more "
701 "than 4 characters has been found, the affected terrain is: " + std::string(str));
702 }
703
704 ter_layer result = 0;
705 // The conversion to int puts the first char
706 // in the highest part of the number.
707 // This will make the wildcard matching
708 // later on a bit easier.
709 for(std::size_t i = 0; i < 4; ++i) {
710 const unsigned char c = (i < str.size()) ? str[i] : 0;
711
712 // Clearing the lower area is a nop on i == 0
713 // so no need for if statement
714 result <<= 8;
715
716 // Add the result
717 result += c;
718 }
719
720 return result;
721}
722
723static terrain_code string_to_number_(std::string_view str, const ter_layer filler) {
724 std::vector<std::string> dummy;
725 return string_to_number_(str, dummy, filler);
726}
727
728static terrain_code string_to_number_(std::string_view str, std::vector<std::string>& start_positions, const ter_layer filler)
729{
730 // Strip the spaces around us
731 // unlike the old implementation this also trims newlines.
732 utils::trim(str);
733 if(str.empty()) {
734 return NONE_TERRAIN;
735 }
736
737 // Split if we have spaces inside
738 std::size_t offset = str.find(' ', 0);
739 while(offset != std::string::npos) {
740 start_positions.emplace_back(str.substr(0, offset));
741 str.remove_prefix(offset + 1);
742 offset = str.find(' ', 0);
743 }
744
745 offset = str.find('^', 0);
746 if(offset != std::string::npos) {
747 return { string_to_layer_(str.substr(0, offset)), string_to_layer_(str.substr(offset + 1)) };
748 } else {
749 return { string_to_layer_(str), filler };
750 }
751}
752
753static std::string number_to_string_(terrain_code terrain, const std::vector<std::string>& start_positions)
754{
755 std::string result = "";
756
757 // Insert the start position
758 for (const std::string& str : start_positions) {
759 result = str + " " + result;
760 }
761
762 /*
763 * The initialization of tcode is done to make gcc-4.7 happy. Otherwise it
764 * some uninitialized fields might be used. Its analysis are wrong, but
765 * Initialize to keep it happy.
766 */
767 unsigned char tcode[9] {0};
768 // Insert the terrain tcode
769 tcode[0] = ((terrain.base & 0xFF000000) >> 24);
770 tcode[1] = ((terrain.base & 0x00FF0000) >> 16);
771 tcode[2] = ((terrain.base & 0x0000FF00) >> 8);
772 tcode[3] = (terrain.base & 0x000000FF);
773
774 if(terrain.overlay != NO_LAYER) {
775 tcode[4] = '^'; //the layer separator
776 tcode[5] = ((terrain.overlay & 0xFF000000) >> 24);
777 tcode[6] = ((terrain.overlay & 0x00FF0000) >> 16);
778 tcode[7] = ((terrain.overlay & 0x0000FF00) >> 8);
779 tcode[8] = (terrain.overlay & 0x000000FF);
780 } else {
781 // If no second layer, the second layer won't be written,
782 // so no need to initialize that part of the array
783 tcode[4] = 0;
784 }
785
786 for(int i = 0; i < 9; ++i) {
787 if(tcode[i] != 0 && tcode[i] != 0xFF) {
788 result += tcode[i];
789 }
790 if(i == 4 && tcode[i] == 0) {
791 // no layer, stop
792 break;
793 }
794 }
795
796 return result;
797}
798
800{
801 // Strip the spaces around us
802 const std::string& whitespace = " \t";
803 str.erase(0, str.find_first_not_of(whitespace));
804 if(! str.empty()) {
805 str.erase(str.find_last_not_of(whitespace) + 1);
806 }
807
808 // Empty string is allowed here, so handle it
809 if(str.empty()) {
810 return NONE_TERRAIN;
811 }
812
813 const int number = lexical_cast_default(str, -1);
814 if(number == -1) {
815 // At this point we have a single char
816 // which should be interpreted by the
817 // map builder, so return this number
818 return terrain_code(str[0] << 24, 0);
819 } else {
820 return terrain_code(0, number);
821 }
822}
823
824} // end namespace t_translation
825
826#if 0
827// small helper rule to test the matching rules
828// building rule
829// make terrain_translation.o && g++ terrain_translation.o libwesnoth-core.a -lSDL -o terrain_translation
830int main(int argc, char** argv)
831{
832 if(argc > 1) {
833
834 if(std::string(argv[1]) == "match" && argc == 4) {
836
837 t_translation::ter_list dest = t_translation::read_list(std::string(argv[3]));
838
840 std::cout << "Match\n" ;
841 } else {
842 std::cout << "No match\n";
843 }
844 }
845 }
846}
847
848#endif
static auto & dummy
#define ERR_G
Definition gettext.cpp:39
#define WRN_G
Definition gettext.cpp:38
New lexcical_cast header.
To lexical_cast_default(From value, To fallback=To())
Lexical cast converts one type to another with a fallback.
Standard logging facilities (interface).
#define PLAIN_LOG
Definition log.hpp:296
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.
static std::pair< int, int > get_map_size(const char *begin, const char *end)
const terrain_code CAVE_WALL
constexpr terrain_code NONE_TERRAIN
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 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
static ter_layer string_to_layer_(std::string_view str)
Converts a string to a layer.
const terrain_code UNDERGROUND_VILLAGE
const ter_match ALL_SWAMPS("!,*^V*,*^B*,!,S*")
static terrain_code string_to_number_(std::string_view str, std::vector< std::string > &start_positions, const ter_layer filler)
Converts a terrain string to a number.
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,...
bool has_wildcard(const terrain_code &tcode)
Tests whether a terrain code contains a wildcard.
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
static std::string number_to_string_(terrain_code terrain, const std::vector< std::string > &start_position=std::vector< std::string >())
Converts a terrain number to a string.
const terrain_code BASE
const terrain_code GRASS_LAND
const ter_match ALL_OFF_MAP
static terrain_code string_to_builder_number_(std::string str)
Converts a terrain string to a number for the builder.
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
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.
static ter_layer get_layer_mask_(ter_layer terrain)
Get the mask for a single layer.
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
const terrain_code DWARVEN_CASTLE
const ter_layer TB_DOT
constexpr ter_layer NO_LAYER
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
static terrain_code get_mask_(const terrain_code &terrain)
Gets a mask for a terrain, this mask is used for wildcard matching.
const terrain_code OFF_MAP_USER
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
void trim(std::string_view &s)
bool isnewline(const char c)
int w
Definition pathfind.cpp:188
int main(int, char **)
Definition sdl3.cpp:25
rect src
Non-transparent portion of the surface to compose.
Encapsulates the map of the game.
Definition location.hpp:46
terrain_code & get(int x, int y)
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...
constexpr terrain_code()=default
#define i
#define h
#define c
#define b