00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019 #include "gettext.hpp"
00020 #include "log.hpp"
00021 #include "terrain_translation.hpp"
00022 #include "serialization/string_utils.hpp"
00023 #include "wml_exception.hpp"
00024
00025 #include <iostream>
00026
00027 #define ERR_G LOG_STREAM(err, general)
00028 #define WRN_G LOG_STREAM(warn, general)
00029
00030 namespace t_translation {
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 static t_layer get_layer_mask_(t_layer terrain);
00047
00048
00049
00050
00051
00052
00053
00054
00055 static t_terrain get_mask_(const t_terrain& terrain);
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 static t_layer string_to_layer_(const std::string& str);
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 static t_terrain string_to_number_(std::string str, int& start_position, const t_layer filler);
00078 static t_terrain string_to_number_(const std::string& str, const t_layer filler = NO_LAYER);
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 static std::string number_to_string_(t_terrain terrain, const int start_position, const size_t min_size);
00092 static std::string number_to_string_(t_terrain terrain, const int start_position = -1);
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 static t_terrain string_to_builder_number_(std::string str);
00103
00104
00105
00106 const t_terrain OFF_MAP_USER = string_to_number_("_off^_usr");
00107
00108 const t_terrain VOID_TERRAIN = string_to_number_("_s");
00109 const t_terrain FOGGED = string_to_number_("_f");
00110
00111 const t_terrain HUMAN_CASTLE = string_to_number_("Ch");
00112 const t_terrain HUMAN_KEEP = string_to_number_("Kh");
00113 const t_terrain SHALLOW_WATER = string_to_number_("Ww");
00114 const t_terrain DEEP_WATER = string_to_number_("Wo");
00115 const t_terrain GRASS_LAND = string_to_number_("Gg");
00116 const t_terrain FOREST = string_to_number_("Gg^Ff");
00117 const t_terrain MOUNTAIN = string_to_number_("Mm");
00118 const t_terrain HILL = string_to_number_("Hh");
00119
00120 const t_terrain CAVE_WALL = string_to_number_("Xu");
00121 const t_terrain CAVE = string_to_number_("Uu");
00122 const t_terrain UNDERGROUND_VILLAGE = string_to_number_("Uu^Vu");
00123 const t_terrain DWARVEN_CASTLE = string_to_number_("Cud");
00124 const t_terrain DWARVEN_KEEP = string_to_number_("Kud");
00125
00126 const t_terrain PLUS = string_to_number_("+");
00127 const t_terrain MINUS = string_to_number_("-");
00128 const t_terrain NOT = string_to_number_("!");
00129 const t_terrain STAR = string_to_number_("*");
00130 const t_terrain BASE = string_to_number_("_bas");
00131
00132
00133
00134 t_terrain::t_terrain(const std::string& b) :
00135 base(string_to_layer_(b)), overlay(NO_LAYER)
00136 {}
00137
00138 t_terrain::t_terrain(const std::string& b, const t_layer o) :
00139 base(string_to_layer_(b)), overlay(o)
00140 {}
00141
00142 t_terrain::t_terrain(const std::string& b, const std::string& o) :
00143 base(string_to_layer_(b)), overlay(string_to_layer_(o))
00144 {}
00145
00146 t_match::t_match() :
00147 terrain(),
00148 mask(),
00149 masked_terrain(),
00150 has_wildcard(false),
00151 is_empty(true)
00152 {}
00153
00154 t_match::t_match(const std::string& str, const t_layer filler) :
00155 terrain(t_translation::read_list(str, filler)),
00156 mask(),
00157 masked_terrain(),
00158 has_wildcard(t_translation::has_wildcard(terrain)),
00159 is_empty(terrain.empty())
00160
00161 {
00162 mask.resize(terrain.size());
00163 masked_terrain.resize(terrain.size());
00164
00165 for(size_t i = 0; i < terrain.size(); i++) {
00166 mask[i] = t_translation::get_mask_(terrain[i]);
00167 masked_terrain[i] = mask[i] & terrain[i];
00168 }
00169 }
00170
00171 t_match::t_match(const t_terrain& tcode):
00172 terrain(t_list(1, tcode)),
00173 mask(),
00174 masked_terrain(),
00175 has_wildcard(t_translation::has_wildcard(terrain)),
00176 is_empty(terrain.empty())
00177 {
00178 mask.resize(terrain.size());
00179 masked_terrain.resize(terrain.size());
00180
00181 for(size_t i = 0; i < terrain.size(); i++) {
00182 mask[i] = t_translation::get_mask_(terrain[i]);
00183 masked_terrain[i] = mask[i] & terrain[i];
00184 }
00185 }
00186
00187 t_terrain read_terrain_code(const std::string& str, const t_layer filler)
00188 {
00189 return string_to_number_(str, filler);
00190 }
00191
00192 std::string write_terrain_code(const t_terrain& tcode)
00193 {
00194 return number_to_string_(tcode);
00195 }
00196
00197 t_list read_list(const std::string& str, const t_layer filler)
00198 {
00199
00200 t_list result;
00201
00202 if(str.empty()) {
00203 return result;
00204 }
00205
00206 size_t offset = 0;
00207 while(offset < str.length()) {
00208
00209
00210 const std::string separators = ",";
00211 const size_t pos_separator = str.find_first_of(separators, offset);
00212 const std::string terrain = str.substr(offset, pos_separator - offset);
00213
00214
00215 const t_terrain tile = string_to_number_(terrain, filler);
00216
00217
00218 result.push_back(tile);
00219
00220
00221 if(pos_separator == std::string::npos) {
00222 offset = str.length();
00223 } else {
00224 offset = pos_separator + 1;
00225 }
00226 }
00227
00228 return result;
00229 }
00230
00231 std::string write_list(const t_list& list)
00232 {
00233 std::stringstream result;
00234
00235 t_list::const_iterator itor = list.begin();
00236 for( ; itor != list.end(); ++itor) {
00237 if(itor == list.begin()) {
00238 result << number_to_string_(*itor);
00239 } else {
00240 result << ", " << number_to_string_(*itor);
00241 }
00242 }
00243
00244 return result.str();
00245 }
00246
00247 t_map read_game_map(const std::string& str, std::map<int, coordinate>& starting_positions)
00248 {
00249 t_map result;
00250
00251 size_t offset = 0;
00252 size_t x = 0, y = 0, width = 0;
00253
00254
00255 while(offset < str.length() && utils::isnewline(str[offset])) {
00256 ++offset;
00257 }
00258
00259
00260 if((offset + 1) >= str.length()) {
00261 return result;
00262 }
00263
00264 while(offset < str.length()) {
00265
00266
00267 const std::string separators = ",\n\r";
00268 const size_t pos_separator = str.find_first_of(separators, offset);
00269 const std::string terrain = str.substr(offset, pos_separator - offset);
00270
00271
00272 int starting_position = -1;
00273
00274 const t_terrain tile = string_to_number_(terrain, starting_position, NO_LAYER);
00275
00276
00277 if(starting_position != -1) {
00278 if(starting_positions.find(starting_position) != starting_positions.end()) {
00279
00280 WRN_G << "Starting position " << starting_position << " is redefined.\n";
00281 starting_positions[starting_position].x = x;
00282 starting_positions[starting_position].y = y;
00283 } else {
00284
00285 const struct coordinate coord = {x, y};
00286 starting_positions.insert(std::pair<int, coordinate>(starting_position, coord));
00287 }
00288 }
00289
00290
00291
00292
00293
00294
00295 if(result.size() <= x) {
00296 result.resize(x + 1);
00297 }
00298 if(result[x].size() <= y) {
00299 result[x].resize(y + 1);
00300 }
00301
00302
00303 result[x][y] = tile;
00304
00305
00306 if(utils::isnewline(str[pos_separator]) || pos_separator == std::string::npos) {
00307
00308 if(y == 0) {
00309
00310 width = x + 1;
00311 } else {
00312 if((x + 1) != width ) {
00313 ERR_G << "Map not a rectangle error occured at line offset " << y << " position offset " << x << "\n";
00314 throw error("Map not a rectangle.");
00315 }
00316 }
00317
00318
00319 ++y;
00320 x = 0;
00321
00322
00323 if(pos_separator == std::string::npos) {
00324 offset = str.length();
00325
00326 } else {
00327
00328 offset = pos_separator + 1;
00329
00330 while(offset < str.length() && utils::isnewline(str[offset])) {
00331 ++offset;
00332 }
00333 }
00334
00335 } else {
00336 ++x;
00337 offset = pos_separator + 1;
00338 }
00339
00340 }
00341
00342 if(x != 0 && (x + 1) != width) {
00343 ERR_G << "Map not a rectangle error occured at the end\n";
00344 throw error("Map not a rectangle.");
00345 }
00346
00347 return result;
00348 }
00349
00350 std::string write_game_map(const t_map& map, std::map<int, coordinate> starting_positions)
00351 {
00352 std::stringstream str;
00353
00354 for(size_t y = 0; y < map[0].size(); ++y) {
00355 for(size_t x = 0; x < map.size(); ++x) {
00356
00357
00358
00359
00360
00361 std::map<int, coordinate>::iterator itor = starting_positions.begin();
00362 int starting_position = -1;
00363 for(; itor != starting_positions.end(); ++itor) {
00364 if(itor->second.x == x && itor->second.y == y) {
00365 starting_position = itor->first;
00366 starting_positions.erase(itor);
00367 break;
00368 }
00369 }
00370
00371
00372 if(x != 0) {
00373 str << ", ";
00374 }
00375 str << number_to_string_(map[x][y], starting_position, 12);
00376 }
00377
00378 str << "\n";
00379 }
00380
00381 return str.str();
00382 }
00383
00384 bool terrain_matches(const t_terrain& src, const t_terrain& dest)
00385 {
00386 return terrain_matches(src, t_list(1, dest));
00387 }
00388
00389 bool terrain_matches(const t_terrain& src, const t_list& dest)
00390 {
00391
00392
00393
00394
00395
00396 if(dest.empty()) {
00397 return false;
00398 }
00399
00400 #if 0
00401 std::cerr << std::hex << "src = " << src.base << "^" << src.overlay << "\t"
00402 << src_mask.base << "^" << src_mask.overlay << "\t"
00403 << masked_src.base << "^" << masked_src.overlay << "\t"
00404 << src_has_wildcard << "\n";
00405 #endif
00406
00407 bool result = true;
00408 t_list::const_iterator itor = dest.begin();
00409
00410
00411 for(; itor != dest.end(); ++itor) {
00412
00413
00414 if(*itor == STAR) {
00415 return result;
00416 }
00417
00418
00419 if(*itor == NOT) {
00420 result = !result;
00421 continue;
00422 }
00423
00424
00425 if(src == *itor) {
00426 return result;
00427 }
00428
00429
00430 const t_terrain dest_mask = get_mask_(*itor);
00431 const t_terrain masked_dest = (*itor & dest_mask);
00432 const bool dest_has_wildcard = has_wildcard(*itor);
00433 #if 0
00434 std::cerr << std::hex << "dest= "
00435 << itor->base << "^" << itor->overlay << "\t"
00436 << dest_mask.base << "^" << dest_mask.overlay << "\t"
00437 << masked_dest.base << "^" << masked_dest.overlay << "\t"
00438 << dest_has_wildcard << "\n";
00439 #endif
00440 if(dest_has_wildcard &&
00441 (src.base & dest_mask.base) == masked_dest.base &&
00442 (src.overlay & dest_mask.overlay) == masked_dest.overlay) {
00443 return result;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 }
00464
00465
00466 return !result;
00467 }
00468
00469
00470
00471
00472 bool terrain_matches(const t_terrain& src, const t_match& dest)
00473 {
00474 if(dest.is_empty) {
00475 return false;
00476 }
00477
00478 bool result = true;
00479
00480
00481
00482
00483
00484
00485 size_t i = 0;
00486 t_list::const_iterator end = dest.terrain.end();
00487 for(t_list::const_iterator terrain_itor = dest.terrain.begin();
00488 terrain_itor != end;
00489 ++i, ++terrain_itor) {
00490
00491
00492 if(*terrain_itor == STAR) {
00493 return result;
00494 }
00495
00496
00497 if(*terrain_itor == NOT) {
00498 result = !result;
00499 continue;
00500 }
00501
00502
00503 if(*terrain_itor == src) {
00504 return result;
00505 }
00506
00507
00508 if(dest.has_wildcard &&
00509 (src.base & dest.mask[i].base) == dest.masked_terrain[i].base &&
00510 (src.overlay & dest.mask[i].overlay) == dest.masked_terrain[i].overlay) {
00511 return result;
00512 }
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 }
00532
00533
00534 return !result;
00535 }
00536
00537 bool has_wildcard(const t_terrain& tcode)
00538 {
00539 if(tcode.overlay == NO_LAYER) {
00540 return get_layer_mask_(tcode.base) != NO_LAYER;
00541 } else {
00542 return get_layer_mask_(tcode.base) != NO_LAYER || get_layer_mask_(tcode.overlay) != NO_LAYER;
00543 }
00544 }
00545
00546 bool has_wildcard(const t_list& list)
00547 {
00548 if(list.empty()) {
00549 return false;
00550 }
00551
00552
00553 t_list::const_iterator itor = list.begin();
00554 for(; itor != list.end(); ++itor) {
00555 if(has_wildcard(*itor)) {
00556 return true;
00557 }
00558 }
00559
00560
00561 return false;
00562 }
00563
00564 t_map read_builder_map(const std::string& str)
00565 {
00566 size_t offset = 0;
00567 t_map result;
00568
00569
00570 while(offset < str.length() && utils::isnewline(str[offset])) {
00571 ++offset;
00572 }
00573
00574
00575 if((offset + 1) >= str.length()) {
00576 return result;
00577 }
00578
00579 size_t x = 0, y = 0;
00580 while(offset < str.length()) {
00581
00582
00583 const std::string separators = ",\n\r";
00584 const size_t pos_separator = str.find_first_of(separators, offset);
00585
00586 std::string terrain = "";
00587
00588
00589 if(pos_separator != offset) {
00590 terrain = str.substr(offset, pos_separator - offset);
00591 }
00592
00593
00594 const t_terrain tile = string_to_builder_number_(terrain);
00595
00596
00597 if(result.size() <= y) {
00598 result.resize(y + 1);
00599 }
00600 if(result[y].size() <= x) {
00601 result[y].resize(x + 1);
00602 }
00603
00604
00605 result[y][x] = tile;
00606
00607
00608 if(pos_separator == std::string::npos) {
00609
00610
00611
00612
00613
00614 offset = str.length();
00615 } else if(utils::isnewline(str[pos_separator])) {
00616
00617 ++y;
00618 x = 0;
00619
00620 offset = pos_separator + 1;
00621
00622 while(offset < str.length() && utils::isnewline(str[offset])) {
00623 ++offset;
00624 }
00625
00626 } else {
00627 ++x;
00628 offset = pos_separator + 1;
00629 }
00630
00631 }
00632
00633 return result;
00634 }
00635
00636
00637
00638
00639 inline t_layer get_layer_mask_(t_layer terrain)
00640 {
00641
00642
00643
00644
00645
00646
00647 if((terrain & 0xFF000000) == 0x2A000000) return 0x00000000;
00648 if((terrain & 0x00FF0000) == 0x002A0000) return 0xFF000000;
00649 if((terrain & 0x0000FF00) == 0x00002A00) return 0xFFFF0000;
00650 if((terrain & 0x000000FF) == 0x0000002A) return 0xFFFFFF00;
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 return 0xFFFFFFFF;
00662 }
00663
00664 static t_terrain get_mask_(const t_terrain& terrain)
00665 {
00666 if(terrain.overlay == NO_LAYER) {
00667 return t_terrain(get_layer_mask_(terrain.base), 0xFFFFFFFF);
00668 } else {
00669 return t_terrain(get_layer_mask_(terrain.base), get_layer_mask_(terrain.overlay));
00670 }
00671 }
00672
00673 static t_layer string_to_layer_(const std::string& str)
00674 {
00675 if (str.size() == 0)
00676 return NO_LAYER;
00677
00678 t_layer result = 0;
00679
00680
00681
00682 VALIDATE(str.size() <= 4, _("A terrain with a string with more "
00683 "than 4 characters has been found, the affected terrain is :") + str);
00684
00685
00686
00687
00688
00689 for(size_t i = 0; i < 4; ++i) {
00690 const unsigned char c = (i < str.length()) ? str[i] : 0;
00691
00692
00693
00694 result <<= 8;
00695
00696
00697 result += c;
00698 }
00699
00700 return result;
00701 }
00702
00703 static t_terrain string_to_number_(const std::string& str, const t_layer filler) {
00704 int dummy = -1;
00705 return string_to_number_(str, dummy, filler);
00706 }
00707
00708 static t_terrain string_to_number_(std::string str, int& start_position, const t_layer filler)
00709 {
00710 t_terrain result;
00711
00712
00713
00714
00715 const std::string input(str);
00716
00717
00718 const std::string& whitespace = " \t";
00719 str.erase(0, str.find_first_not_of(whitespace));
00720 str.erase(str.find_last_not_of(whitespace) + 1);
00721 if(str.empty()) {
00722 return result;
00723 }
00724
00725
00726 size_t offset = str.find(' ', 0);
00727 if(offset != std::string::npos) {
00728 try {
00729 start_position = lexical_cast<int>(str.substr(0, offset));
00730 } catch(bad_lexical_cast&) {
00731 goto terrain_error;
00732 }
00733 str.erase(0, offset + 1);
00734 }
00735
00736 offset = str.find('^', 0);
00737 if(offset != std::string::npos) {
00738
00739 if(offset > 4 || (str.size() - offset) > 5) {
00740 goto terrain_error;
00741 }
00742 const std::string base_str(str, 0, offset);
00743 const std::string overlay_str(str, offset + 1, str.size());
00744 result = t_terrain(base_str, overlay_str);
00745 } else {
00746
00747 if(str.size() > 4) {
00748 goto terrain_error;
00749 }
00750 result = t_terrain(str, filler);
00751
00752
00753 if(filler == WILDCARD && (result.base == NOT.base ||
00754 result.base == STAR.base)) {
00755
00756 result.overlay = NO_LAYER;
00757 }
00758 }
00759
00760 return result;
00761
00762 terrain_error:
00763
00764
00765
00766 lg::wml_error << _("Invalid terrain found probably an 1.2 terrain format, "
00767 "terrain = ") << input << '\n';
00768 return VOID_TERRAIN;
00769 }
00770
00771 static std::string number_to_string_(t_terrain terrain, const int start_position)
00772 {
00773 std::string result = "";
00774
00775
00776 if(start_position > 0) {
00777 result = str_cast(start_position) + " ";
00778 }
00779
00780
00781 unsigned char tcode[9];
00782 tcode[0] = ((terrain.base & 0xFF000000) >> 24);
00783 tcode[1] = ((terrain.base & 0x00FF0000) >> 16);
00784 tcode[2] = ((terrain.base & 0x0000FF00) >> 8);
00785 tcode[3] = (terrain.base & 0x000000FF);
00786
00787 if(terrain.overlay != NO_LAYER) {
00788 tcode[4] = '^';
00789 tcode[5] = ((terrain.overlay & 0xFF000000) >> 24);
00790 tcode[6] = ((terrain.overlay & 0x00FF0000) >> 16);
00791 tcode[7] = ((terrain.overlay & 0x0000FF00) >> 8);
00792 tcode[8] = (terrain.overlay & 0x000000FF);
00793 } else {
00794
00795
00796 tcode[4] = 0;
00797 }
00798
00799 for(int i = 0; i < 9; ++i) {
00800 if(tcode[i] != 0 && tcode[i] != 0xFF) {
00801 result += tcode[i];
00802 }
00803 if(i == 4 && tcode[i] == 0) {
00804
00805 break;
00806 }
00807 }
00808
00809 return result;
00810 }
00811
00812 static std::string number_to_string_(t_terrain terrain, const int start_position, const size_t min_size)
00813 {
00814 std::string result = number_to_string_(terrain, start_position);
00815 if(result.size() < min_size) {
00816 result.resize(min_size, ' ');
00817 }
00818
00819 return result;
00820 }
00821
00822 static t_terrain string_to_builder_number_(std::string str)
00823 {
00824
00825 const std::string& whitespace = " \t";
00826 str.erase(0, str.find_first_not_of(whitespace));
00827 if(! str.empty()) {
00828 str.erase(str.find_last_not_of(whitespace) + 1);
00829 }
00830
00831
00832 if(str.empty()) {
00833 return t_terrain();
00834 }
00835
00836 const int number = lexical_cast_default(str, -1);
00837 if(number == -1) {
00838
00839
00840
00841 return t_terrain(str[0] << 24, 0);
00842 } else {
00843 return t_terrain(0, number);
00844 }
00845 }
00846
00847 }
00848
00849 #if 0
00850
00851
00852
00853 int main(int argc, char** argv)
00854 {
00855 if(argc > 1) {
00856
00857 if(std::string(argv[1]) == "match" && argc == 4) {
00858 t_translation::t_terrain src = t_translation::read_terrain_code(std::string(argv[2]));
00859
00860 t_translation::t_list dest = t_translation::read_list(std::string(argv[3]));
00861
00862 if(t_translation::terrain_matches(src, dest)) {
00863 std::cout << "Match\n" ;
00864 } else {
00865 std::cout << "No match\n";
00866 }
00867 }
00868 }
00869 }
00870
00871 #endif
00872