about summary refs log tree commit diff stats
path: root/src/game_data.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game_data.cpp')
-rw-r--r--src/game_data.cpp184
1 files changed, 123 insertions, 61 deletions
diff --git a/src/game_data.cpp b/src/game_data.cpp index a4a441d..588ffc8 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -12,32 +12,6 @@
12 12
13namespace { 13namespace {
14 14
15LingoColor GetColorForString(const std::string &str) {
16 if (str == "black") {
17 return LingoColor::kBlack;
18 } else if (str == "red") {
19 return LingoColor::kRed;
20 } else if (str == "blue") {
21 return LingoColor::kBlue;
22 } else if (str == "yellow") {
23 return LingoColor::kYellow;
24 } else if (str == "orange") {
25 return LingoColor::kOrange;
26 } else if (str == "green") {
27 return LingoColor::kGreen;
28 } else if (str == "gray") {
29 return LingoColor::kGray;
30 } else if (str == "brown") {
31 return LingoColor::kBrown;
32 } else if (str == "purple") {
33 return LingoColor::kPurple;
34 } else {
35 TrackerLog(fmt::format("Invalid color: {}", str));
36
37 return LingoColor::kNone;
38 }
39}
40
41struct GameData { 15struct GameData {
42 std::vector<Room> rooms_; 16 std::vector<Room> rooms_;
43 std::vector<Door> doors_; 17 std::vector<Door> doors_;
@@ -55,10 +29,10 @@ struct GameData {
55 std::map<std::string, int> painting_by_id_; 29 std::map<std::string, int> painting_by_id_;
56 30
57 std::vector<int> door_definition_order_; 31 std::vector<int> door_definition_order_;
58 std::vector<int> room_definition_order_;
59 32
60 std::map<std::string, int> room_by_painting_; 33 std::map<std::string, int> room_by_painting_;
61 std::map<int, int> room_by_sunwarp_; 34 std::map<int, int> room_by_sunwarp_;
35 std::map<int, int> panel_by_solve_index_;
62 36
63 std::vector<int> achievement_panels_; 37 std::vector<int> achievement_panels_;
64 38
@@ -69,6 +43,8 @@ struct GameData {
69 std::map<std::string, int> subway_item_by_painting_; 43 std::map<std::string, int> subway_item_by_painting_;
70 std::map<SubwaySunwarp, int> subway_item_by_sunwarp_; 44 std::map<SubwaySunwarp, int> subway_item_by_sunwarp_;
71 45
46 std::map<int, std::string> item_by_ap_id_;
47
72 bool loaded_area_data_ = false; 48 bool loaded_area_data_ = false;
73 std::set<std::string> malconfigured_areas_; 49 std::set<std::string> malconfigured_areas_;
74 50
@@ -84,7 +60,7 @@ struct GameData {
84 ids_config["special_items"][color_name]) { 60 ids_config["special_items"][color_name]) {
85 std::string input_name = color_name; 61 std::string input_name = color_name;
86 input_name[0] = std::tolower(input_name[0]); 62 input_name[0] = std::tolower(input_name[0]);
87 ap_id_by_color_[GetColorForString(input_name)] = 63 ap_id_by_color_[GetLingoColorForString(input_name)] =
88 ids_config["special_items"][color_name].as<int>(); 64 ids_config["special_items"][color_name].as<int>();
89 } else { 65 } else {
90 TrackerLog(fmt::format("Missing AP item ID for color {}", color_name)); 66 TrackerLog(fmt::format("Missing AP item ID for color {}", color_name));
@@ -101,11 +77,20 @@ struct GameData {
101 init_color_id("Brown"); 77 init_color_id("Brown");
102 init_color_id("Gray"); 78 init_color_id("Gray");
103 79
80 if (ids_config["special_items"]) {
81 for (const auto& special_item_it : ids_config["special_items"])
82 {
83 item_by_ap_id_[special_item_it.second.as<int>()] =
84 special_item_it.first.as<std::string>();
85 }
86 }
87
104 rooms_.reserve(lingo_config.size() * 2); 88 rooms_.reserve(lingo_config.size() * 2);
105 89
90 std::vector<int> panel_location_ids;
91
106 for (const auto &room_it : lingo_config) { 92 for (const auto &room_it : lingo_config) {
107 int room_id = AddOrGetRoom(room_it.first.as<std::string>()); 93 int room_id = AddOrGetRoom(room_it.first.as<std::string>());
108 room_definition_order_.push_back(room_id);
109 94
110 for (const auto &entrance_it : room_it.second["entrances"]) { 95 for (const auto &entrance_it : room_it.second["entrances"]) {
111 int from_room_id = AddOrGetRoom(entrance_it.first.as<std::string>()); 96 int from_room_id = AddOrGetRoom(entrance_it.first.as<std::string>());
@@ -142,6 +127,10 @@ struct GameData {
142 exit_obj.type = EntranceType::kCrossroadsRoofAccess; 127 exit_obj.type = EntranceType::kCrossroadsRoofAccess;
143 } 128 }
144 129
130 if (option["static_painting"] && option["static_painting"].as<bool>()) {
131 exit_obj.type = EntranceType::kStaticPainting;
132 }
133
145 rooms_[from_room_id].exits.push_back(exit_obj); 134 rooms_[from_room_id].exits.push_back(exit_obj);
146 }; 135 };
147 136
@@ -181,12 +170,12 @@ struct GameData {
181 170
182 if (panel_it.second["colors"]) { 171 if (panel_it.second["colors"]) {
183 if (panel_it.second["colors"].IsScalar()) { 172 if (panel_it.second["colors"].IsScalar()) {
184 panels_[panel_id].colors.push_back(GetColorForString( 173 panels_[panel_id].colors.push_back(GetLingoColorForString(
185 panel_it.second["colors"].as<std::string>())); 174 panel_it.second["colors"].as<std::string>()));
186 } else { 175 } else {
187 for (const auto &color_node : panel_it.second["colors"]) { 176 for (const auto &color_node : panel_it.second["colors"]) {
188 panels_[panel_id].colors.push_back( 177 panels_[panel_id].colors.push_back(
189 GetColorForString(color_node.as<std::string>())); 178 GetLingoColorForString(color_node.as<std::string>()));
190 } 179 }
191 } 180 }
192 } 181 }
@@ -292,10 +281,11 @@ struct GameData {
292 ids_config["panels"][rooms_[room_id].name] && 281 ids_config["panels"][rooms_[room_id].name] &&
293 ids_config["panels"][rooms_[room_id].name] 282 ids_config["panels"][rooms_[room_id].name]
294 [panels_[panel_id].name]) { 283 [panels_[panel_id].name]) {
295 panels_[panel_id].ap_location_id = 284 int location_id = ids_config["panels"][rooms_[room_id].name]
296 ids_config["panels"][rooms_[room_id].name] 285 [panels_[panel_id].name]
297 [panels_[panel_id].name] 286 .as<int>();
298 .as<int>(); 287 panels_[panel_id].ap_location_id = location_id;
288 panel_location_ids.push_back(location_id);
299 } else { 289 } else {
300 TrackerLog(fmt::format("Missing AP location ID for panel {} - {}", 290 TrackerLog(fmt::format("Missing AP location ID for panel {} - {}",
301 rooms_[room_id].name, 291 rooms_[room_id].name,
@@ -361,6 +351,9 @@ struct GameData {
361 ids_config["doors"][rooms_[room_id].name] 351 ids_config["doors"][rooms_[room_id].name]
362 [doors_[door_id].name]["item"] 352 [doors_[door_id].name]["item"]
363 .as<int>(); 353 .as<int>();
354
355 item_by_ap_id_[doors_[door_id].ap_item_id] =
356 doors_[door_id].item_name;
364 } else { 357 } else {
365 TrackerLog(fmt::format("Missing AP item ID for door {} - {}", 358 TrackerLog(fmt::format("Missing AP item ID for door {} - {}",
366 rooms_[room_id].name, 359 rooms_[room_id].name,
@@ -377,6 +370,9 @@ struct GameData {
377 doors_[door_id].group_ap_item_id = 370 doors_[door_id].group_ap_item_id =
378 ids_config["door_groups"][doors_[door_id].group_name] 371 ids_config["door_groups"][doors_[door_id].group_name]
379 .as<int>(); 372 .as<int>();
373
374 item_by_ap_id_[doors_[door_id].group_ap_item_id] =
375 doors_[door_id].group_name;
380 } else { 376 } else {
381 TrackerLog(fmt::format("Missing AP item ID for door group {}", 377 TrackerLog(fmt::format("Missing AP item ID for door group {}",
382 doors_[door_id].group_name)); 378 doors_[door_id].group_name));
@@ -440,21 +436,50 @@ struct GameData {
440 int panel_door_id = 436 int panel_door_id =
441 AddOrGetPanelDoor(rooms_[room_id].name, panel_door_name); 437 AddOrGetPanelDoor(rooms_[room_id].name, panel_door_name);
442 438
439 std::map<std::string, std::vector<std::string>> panel_per_room;
440 int num_panels = 0;
443 for (const auto &panel_node : panel_door_it.second["panels"]) { 441 for (const auto &panel_node : panel_door_it.second["panels"]) {
442 num_panels++;
443
444 int panel_id = -1; 444 int panel_id = -1;
445 445
446 if (panel_node.IsScalar()) { 446 if (panel_node.IsScalar()) {
447 panel_id = AddOrGetPanel(rooms_[room_id].name, 447 panel_id = AddOrGetPanel(rooms_[room_id].name,
448 panel_node.as<std::string>()); 448 panel_node.as<std::string>());
449
450 panel_per_room[rooms_[room_id].name].push_back(
451 panel_node.as<std::string>());
449 } else { 452 } else {
450 panel_id = AddOrGetPanel(panel_node["room"].as<std::string>(), 453 panel_id = AddOrGetPanel(panel_node["room"].as<std::string>(),
451 panel_node["panel"].as<std::string>()); 454 panel_node["panel"].as<std::string>());
455
456 panel_per_room[panel_node["room"].as<std::string>()].push_back(
457 panel_node["panel"].as<std::string>());
452 } 458 }
453 459
454 Panel &panel = panels_[panel_id]; 460 Panel &panel = panels_[panel_id];
455 panel.panel_door = panel_door_id; 461 panel.panel_door = panel_door_id;
456 } 462 }
457 463
464 if (panel_door_it.second["item_name"]) {
465 panel_doors_[panel_door_id].item_name =
466 panel_door_it.second["item_name"].as<std::string>();
467 } else {
468 std::vector<std::string> room_strs;
469 for (const auto &[room_str, panels_str] : panel_per_room) {
470 room_strs.push_back(fmt::format(
471 "{} - {}", room_str, hatkirby::implode(panels_str, ", ")));
472 }
473
474 if (num_panels == 1) {
475 panel_doors_[panel_door_id].item_name =
476 fmt::format("{} (Panel)", room_strs[0]);
477 } else {
478 panel_doors_[panel_door_id].item_name = fmt::format(
479 "{} (Panels)", hatkirby::implode(room_strs, " and "));
480 }
481 }
482
458 if (ids_config["panel_doors"] && 483 if (ids_config["panel_doors"] &&
459 ids_config["panel_doors"][rooms_[room_id].name] && 484 ids_config["panel_doors"][rooms_[room_id].name] &&
460 ids_config["panel_doors"][rooms_[room_id].name] 485 ids_config["panel_doors"][rooms_[room_id].name]
@@ -462,6 +487,9 @@ struct GameData {
462 panel_doors_[panel_door_id].ap_item_id = 487 panel_doors_[panel_door_id].ap_item_id =
463 ids_config["panel_doors"][rooms_[room_id].name][panel_door_name] 488 ids_config["panel_doors"][rooms_[room_id].name][panel_door_name]
464 .as<int>(); 489 .as<int>();
490
491 item_by_ap_id_[panel_doors_[panel_door_id].ap_item_id] =
492 panel_doors_[panel_door_id].item_name;
465 } else { 493 } else {
466 TrackerLog(fmt::format("Missing AP item ID for panel door {} - {}", 494 TrackerLog(fmt::format("Missing AP item ID for panel door {} - {}",
467 rooms_[room_id].name, panel_door_name)); 495 rooms_[room_id].name, panel_door_name));
@@ -475,6 +503,9 @@ struct GameData {
475 ids_config["panel_groups"][panel_group]) { 503 ids_config["panel_groups"][panel_group]) {
476 panel_doors_[panel_door_id].group_ap_item_id = 504 panel_doors_[panel_door_id].group_ap_item_id =
477 ids_config["panel_groups"][panel_group].as<int>(); 505 ids_config["panel_groups"][panel_group].as<int>();
506
507 item_by_ap_id_[panel_doors_[panel_door_id].group_ap_item_id] =
508 panel_group;
478 } else { 509 } else {
479 TrackerLog(fmt::format( 510 TrackerLog(fmt::format(
480 "Missing AP item ID for panel door group {}", panel_group)); 511 "Missing AP item ID for panel door group {}", panel_group));
@@ -538,6 +569,8 @@ struct GameData {
538 ids_config["progression"][progressive_item_name]) { 569 ids_config["progression"][progressive_item_name]) {
539 progressive_item_id = 570 progressive_item_id =
540 ids_config["progression"][progressive_item_name].as<int>(); 571 ids_config["progression"][progressive_item_name].as<int>();
572
573 item_by_ap_id_[progressive_item_id] = progressive_item_name;
541 } else { 574 } else {
542 TrackerLog(fmt::format("Missing AP item ID for progressive item {}", 575 TrackerLog(fmt::format("Missing AP item ID for progressive item {}",
543 progressive_item_name)); 576 progressive_item_name));
@@ -589,6 +622,21 @@ struct GameData {
589 } 622 }
590 } 623 }
591 624
625 // Determine the panel solve indices from the sorted location IDs.
626 std::sort(panel_location_ids.begin(), panel_location_ids.end());
627
628 std::map<int, int> solve_index_by_location_id;
629 for (int i = 0; i < panel_location_ids.size(); i++) {
630 solve_index_by_location_id[panel_location_ids[i]] = i;
631 }
632
633 for (Panel &panel : panels_) {
634 if (panel.ap_location_id != -1) {
635 panel.solve_index = solve_index_by_location_id[panel.ap_location_id];
636 panel_by_solve_index_[panel.solve_index] = panel.id;
637 }
638 }
639
592 map_areas_.reserve(areas_config.size()); 640 map_areas_.reserve(areas_config.size());
593 641
594 std::map<std::string, int> fold_areas; 642 std::map<std::string, int> fold_areas;
@@ -734,31 +782,6 @@ struct GameData {
734 } 782 }
735 } 783 }
736 784
737 // As a workaround for a generator bug in 0.5.1, we are going to remove the
738 // panel door requirement on panels that are defined earlier in the file than
739 // the panel door is. This results in logic that matches the generator, even
740 // if it is not true to how the game should work. This will be reverted once
741 // the logic bug is fixed and released.
742 // See: https://github.com/ArchipelagoMW/Archipelago/pull/4342
743 for (Panel& panel : panels_) {
744 if (panel.panel_door == -1) {
745 continue;
746 }
747 const PanelDoor &panel_door = panel_doors_[panel.panel_door];
748 for (int room_id : room_definition_order_) {
749 if (room_id == panel_door.room) {
750 // The panel door was defined first (or at the same time as the panel),
751 // so we're good.
752 break;
753 } else if (room_id == panel.room) {
754 // The panel was defined first, so we have to pretend the panel door is
755 // not required for this panel.
756 panel.panel_door = -1;
757 break;
758 }
759 }
760 }
761
762 // Report errors. 785 // Report errors.
763 for (const std::string &area : malconfigured_areas_) { 786 for (const std::string &area : malconfigured_areas_) {
764 TrackerLog(fmt::format("Area data not found for: {}", area)); 787 TrackerLog(fmt::format("Area data not found for: {}", area));
@@ -891,7 +914,7 @@ struct GameData {
891 if (!panel_doors_by_id_.count(full_name)) { 914 if (!panel_doors_by_id_.count(full_name)) {
892 int panel_door_id = panel_doors_.size(); 915 int panel_door_id = panel_doors_.size();
893 panel_doors_by_id_[full_name] = panel_door_id; 916 panel_doors_by_id_[full_name] = panel_door_id;
894 panel_doors_.push_back({.room = AddOrGetRoom(room)}); 917 panel_doors_.push_back({});
895 } 918 }
896 919
897 return panel_doors_by_id_[full_name]; 920 return panel_doors_by_id_[full_name];
@@ -964,6 +987,10 @@ const Panel &GD_GetPanel(int panel_id) {
964 return GetState().panels_.at(panel_id); 987 return GetState().panels_.at(panel_id);
965} 988}
966 989
990int GD_GetPanelBySolveIndex(int solve_index) {
991 return GetState().panel_by_solve_index_.at(solve_index);
992}
993
967const std::vector<PaintingExit> &GD_GetPaintings() { 994const std::vector<PaintingExit> &GD_GetPaintings() {
968 return GetState().paintings_; 995 return GetState().paintings_;
969} 996}
@@ -1010,3 +1037,38 @@ std::optional<int> GD_GetSubwayItemForPainting(const std::string &painting_id) {
1010int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) { 1037int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) {
1011 return GetState().subway_item_by_sunwarp_.at(sunwarp); 1038 return GetState().subway_item_by_sunwarp_.at(sunwarp);
1012} 1039}
1040
1041std::string GD_GetItemName(int id) {
1042 auto it = GetState().item_by_ap_id_.find(id);
1043 if (it != GetState().item_by_ap_id_.end()) {
1044 return it->second;
1045 } else {
1046 return "Unknown";
1047 }
1048}
1049
1050LingoColor GetLingoColorForString(const std::string &str) {
1051 if (str == "black") {
1052 return LingoColor::kBlack;
1053 } else if (str == "red") {
1054 return LingoColor::kRed;
1055 } else if (str == "blue") {
1056 return LingoColor::kBlue;
1057 } else if (str == "yellow") {
1058 return LingoColor::kYellow;
1059 } else if (str == "orange") {
1060 return LingoColor::kOrange;
1061 } else if (str == "green") {
1062 return LingoColor::kGreen;
1063 } else if (str == "gray") {
1064 return LingoColor::kGray;
1065 } else if (str == "brown") {
1066 return LingoColor::kBrown;
1067 } else if (str == "purple") {
1068 return LingoColor::kPurple;
1069 } else {
1070 TrackerLog(fmt::format("Invalid color: {}", str));
1071
1072 return LingoColor::kNone;
1073 }
1074}