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.cpp213
1 files changed, 143 insertions, 70 deletions
diff --git a/src/game_data.cpp b/src/game_data.cpp index 0ac77af..94b9888 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>());
@@ -181,12 +166,12 @@ struct GameData {
181 166
182 if (panel_it.second["colors"]) { 167 if (panel_it.second["colors"]) {
183 if (panel_it.second["colors"].IsScalar()) { 168 if (panel_it.second["colors"].IsScalar()) {
184 panels_[panel_id].colors.push_back(GetColorForString( 169 panels_[panel_id].colors.push_back(GetLingoColorForString(
185 panel_it.second["colors"].as<std::string>())); 170 panel_it.second["colors"].as<std::string>()));
186 } else { 171 } else {
187 for (const auto &color_node : panel_it.second["colors"]) { 172 for (const auto &color_node : panel_it.second["colors"]) {
188 panels_[panel_id].colors.push_back( 173 panels_[panel_id].colors.push_back(
189 GetColorForString(color_node.as<std::string>())); 174 GetLingoColorForString(color_node.as<std::string>()));
190 } 175 }
191 } 176 }
192 } 177 }
@@ -292,10 +277,11 @@ struct GameData {
292 ids_config["panels"][rooms_[room_id].name] && 277 ids_config["panels"][rooms_[room_id].name] &&
293 ids_config["panels"][rooms_[room_id].name] 278 ids_config["panels"][rooms_[room_id].name]
294 [panels_[panel_id].name]) { 279 [panels_[panel_id].name]) {
295 panels_[panel_id].ap_location_id = 280 int location_id = ids_config["panels"][rooms_[room_id].name]
296 ids_config["panels"][rooms_[room_id].name] 281 [panels_[panel_id].name]
297 [panels_[panel_id].name] 282 .as<int>();
298 .as<int>(); 283 panels_[panel_id].ap_location_id = location_id;
284 panel_location_ids.push_back(location_id);
299 } else { 285 } else {
300 TrackerLog(fmt::format("Missing AP location ID for panel {} - {}", 286 TrackerLog(fmt::format("Missing AP location ID for panel {} - {}",
301 rooms_[room_id].name, 287 rooms_[room_id].name,
@@ -361,6 +347,9 @@ struct GameData {
361 ids_config["doors"][rooms_[room_id].name] 347 ids_config["doors"][rooms_[room_id].name]
362 [doors_[door_id].name]["item"] 348 [doors_[door_id].name]["item"]
363 .as<int>(); 349 .as<int>();
350
351 item_by_ap_id_[doors_[door_id].ap_item_id] =
352 doors_[door_id].item_name;
364 } else { 353 } else {
365 TrackerLog(fmt::format("Missing AP item ID for door {} - {}", 354 TrackerLog(fmt::format("Missing AP item ID for door {} - {}",
366 rooms_[room_id].name, 355 rooms_[room_id].name,
@@ -377,6 +366,9 @@ struct GameData {
377 doors_[door_id].group_ap_item_id = 366 doors_[door_id].group_ap_item_id =
378 ids_config["door_groups"][doors_[door_id].group_name] 367 ids_config["door_groups"][doors_[door_id].group_name]
379 .as<int>(); 368 .as<int>();
369
370 item_by_ap_id_[doors_[door_id].group_ap_item_id] =
371 doors_[door_id].group_name;
380 } else { 372 } else {
381 TrackerLog(fmt::format("Missing AP item ID for door group {}", 373 TrackerLog(fmt::format("Missing AP item ID for door group {}",
382 doors_[door_id].group_name)); 374 doors_[door_id].group_name));
@@ -440,21 +432,50 @@ struct GameData {
440 int panel_door_id = 432 int panel_door_id =
441 AddOrGetPanelDoor(rooms_[room_id].name, panel_door_name); 433 AddOrGetPanelDoor(rooms_[room_id].name, panel_door_name);
442 434
435 std::map<std::string, std::vector<std::string>> panel_per_room;
436 int num_panels = 0;
443 for (const auto &panel_node : panel_door_it.second["panels"]) { 437 for (const auto &panel_node : panel_door_it.second["panels"]) {
438 num_panels++;
439
444 int panel_id = -1; 440 int panel_id = -1;
445 441
446 if (panel_node.IsScalar()) { 442 if (panel_node.IsScalar()) {
447 panel_id = AddOrGetPanel(rooms_[room_id].name, 443 panel_id = AddOrGetPanel(rooms_[room_id].name,
448 panel_node.as<std::string>()); 444 panel_node.as<std::string>());
445
446 panel_per_room[rooms_[room_id].name].push_back(
447 panel_node.as<std::string>());
449 } else { 448 } else {
450 panel_id = AddOrGetPanel(panel_node["room"].as<std::string>(), 449 panel_id = AddOrGetPanel(panel_node["room"].as<std::string>(),
451 panel_node["panel"].as<std::string>()); 450 panel_node["panel"].as<std::string>());
451
452 panel_per_room[panel_node["room"].as<std::string>()].push_back(
453 panel_node["panel"].as<std::string>());
452 } 454 }
453 455
454 Panel &panel = panels_[panel_id]; 456 Panel &panel = panels_[panel_id];
455 panel.panel_door = panel_door_id; 457 panel.panel_door = panel_door_id;
456 } 458 }
457 459
460 if (panel_door_it.second["item_name"]) {
461 panel_doors_[panel_door_id].item_name =
462 panel_door_it.second["item_name"].as<std::string>();
463 } else {
464 std::vector<std::string> room_strs;
465 for (const auto &[room_str, panels_str] : panel_per_room) {
466 room_strs.push_back(fmt::format(
467 "{} - {}", room_str, hatkirby::implode(panels_str, ", ")));
468 }
469
470 if (num_panels == 1) {
471 panel_doors_[panel_door_id].item_name =
472 fmt::format("{} (Panel)", room_strs[0]);
473 } else {
474 panel_doors_[panel_door_id].item_name = fmt::format(
475 "{} (Panels)", hatkirby::implode(room_strs, " and "));
476 }
477 }
478
458 if (ids_config["panel_doors"] && 479 if (ids_config["panel_doors"] &&
459 ids_config["panel_doors"][rooms_[room_id].name] && 480 ids_config["panel_doors"][rooms_[room_id].name] &&
460 ids_config["panel_doors"][rooms_[room_id].name] 481 ids_config["panel_doors"][rooms_[room_id].name]
@@ -462,6 +483,9 @@ struct GameData {
462 panel_doors_[panel_door_id].ap_item_id = 483 panel_doors_[panel_door_id].ap_item_id =
463 ids_config["panel_doors"][rooms_[room_id].name][panel_door_name] 484 ids_config["panel_doors"][rooms_[room_id].name][panel_door_name]
464 .as<int>(); 485 .as<int>();
486
487 item_by_ap_id_[panel_doors_[panel_door_id].ap_item_id] =
488 panel_doors_[panel_door_id].item_name;
465 } else { 489 } else {
466 TrackerLog(fmt::format("Missing AP item ID for panel door {} - {}", 490 TrackerLog(fmt::format("Missing AP item ID for panel door {} - {}",
467 rooms_[room_id].name, panel_door_name)); 491 rooms_[room_id].name, panel_door_name));
@@ -475,6 +499,9 @@ struct GameData {
475 ids_config["panel_groups"][panel_group]) { 499 ids_config["panel_groups"][panel_group]) {
476 panel_doors_[panel_door_id].group_ap_item_id = 500 panel_doors_[panel_door_id].group_ap_item_id =
477 ids_config["panel_groups"][panel_group].as<int>(); 501 ids_config["panel_groups"][panel_group].as<int>();
502
503 item_by_ap_id_[panel_doors_[panel_door_id].group_ap_item_id] =
504 panel_group;
478 } else { 505 } else {
479 TrackerLog(fmt::format( 506 TrackerLog(fmt::format(
480 "Missing AP item ID for panel door group {}", panel_group)); 507 "Missing AP item ID for panel door group {}", panel_group));
@@ -490,6 +517,13 @@ struct GameData {
490 PaintingExit &painting_exit = paintings_[painting_id]; 517 PaintingExit &painting_exit = paintings_[painting_id];
491 painting_exit.room = room_id; 518 painting_exit.room = room_id;
492 519
520 if (painting["display_name"]) {
521 painting_exit.display_name =
522 painting["display_name"].as<std::string>();
523 } else {
524 painting_exit.display_name = painting_exit.internal_id;
525 }
526
493 if ((!painting["exit_only"] || !painting["exit_only"].as<bool>()) && 527 if ((!painting["exit_only"] || !painting["exit_only"].as<bool>()) &&
494 (!painting["disable"] || !painting["disable"].as<bool>())) { 528 (!painting["disable"] || !painting["disable"].as<bool>())) {
495 painting_exit.entrance = true; 529 painting_exit.entrance = true;
@@ -531,6 +565,8 @@ struct GameData {
531 ids_config["progression"][progressive_item_name]) { 565 ids_config["progression"][progressive_item_name]) {
532 progressive_item_id = 566 progressive_item_id =
533 ids_config["progression"][progressive_item_name].as<int>(); 567 ids_config["progression"][progressive_item_name].as<int>();
568
569 item_by_ap_id_[progressive_item_id] = progressive_item_name;
534 } else { 570 } else {
535 TrackerLog(fmt::format("Missing AP item ID for progressive item {}", 571 TrackerLog(fmt::format("Missing AP item ID for progressive item {}",
536 progressive_item_name)); 572 progressive_item_name));
@@ -582,6 +618,21 @@ struct GameData {
582 } 618 }
583 } 619 }
584 620
621 // Determine the panel solve indices from the sorted location IDs.
622 std::sort(panel_location_ids.begin(), panel_location_ids.end());
623
624 std::map<int, int> solve_index_by_location_id;
625 for (int i = 0; i < panel_location_ids.size(); i++) {
626 solve_index_by_location_id[panel_location_ids[i]] = i;
627 }
628
629 for (Panel &panel : panels_) {
630 if (panel.ap_location_id != -1) {
631 panel.solve_index = solve_index_by_location_id[panel.ap_location_id];
632 panel_by_solve_index_[panel.solve_index] = panel.id;
633 }
634 }
635
585 map_areas_.reserve(areas_config.size()); 636 map_areas_.reserve(areas_config.size());
586 637
587 std::map<std::string, int> fold_areas; 638 std::map<std::string, int> fold_areas;
@@ -602,7 +653,7 @@ struct GameData {
602 // Only locations for the panels are kept here. 653 // Only locations for the panels are kept here.
603 std::map<std::string, std::tuple<int, int>> locations_by_name; 654 std::map<std::string, std::tuple<int, int>> locations_by_name;
604 655
605 for (const Panel &panel : panels_) { 656 for (Panel &panel : panels_) {
606 int room_id = panel.room; 657 int room_id = panel.room;
607 std::string room_name = rooms_[room_id].name; 658 std::string room_name = rooms_[room_id].name;
608 659
@@ -618,6 +669,8 @@ struct GameData {
618 area_name = location_name.substr(0, divider_pos); 669 area_name = location_name.substr(0, divider_pos);
619 section_name = location_name.substr(divider_pos + 3); 670 section_name = location_name.substr(divider_pos + 3);
620 } 671 }
672 } else {
673 panel.location_name = location_name;
621 } 674 }
622 675
623 if (fold_areas.count(area_name)) { 676 if (fold_areas.count(area_name)) {
@@ -716,7 +769,8 @@ struct GameData {
716 MapArea &map_area = map_areas_[area_id]; 769 MapArea &map_area = map_areas_[area_id];
717 770
718 for (int painting_id : room.paintings) { 771 for (int painting_id : room.paintings) {
719 const PaintingExit &painting_obj = paintings_.at(painting_id); 772 PaintingExit &painting_obj = paintings_.at(painting_id);
773 painting_obj.map_area = area_id;
720 if (painting_obj.entrance) { 774 if (painting_obj.entrance) {
721 map_area.paintings.push_back(painting_id); 775 map_area.paintings.push_back(painting_id);
722 } 776 }
@@ -724,31 +778,6 @@ struct GameData {
724 } 778 }
725 } 779 }
726 780
727 // As a workaround for a generator bug in 0.5.1, we are going to remove the
728 // panel door requirement on panels that are defined earlier in the file than
729 // the panel door is. This results in logic that matches the generator, even
730 // if it is not true to how the game should work. This will be reverted once
731 // the logic bug is fixed and released.
732 // See: https://github.com/ArchipelagoMW/Archipelago/pull/4342
733 for (Panel& panel : panels_) {
734 if (panel.panel_door == -1) {
735 continue;
736 }
737 const PanelDoor &panel_door = panel_doors_[panel.panel_door];
738 for (int room_id : room_definition_order_) {
739 if (room_id == panel_door.room) {
740 // The panel door was defined first (or at the same time as the panel),
741 // so we're good.
742 break;
743 } else if (room_id == panel.room) {
744 // The panel was defined first, so we have to pretend the panel door is
745 // not required for this panel.
746 panel.panel_door = -1;
747 break;
748 }
749 }
750 }
751
752 // Report errors. 781 // Report errors.
753 for (const std::string &area : malconfigured_areas_) { 782 for (const std::string &area : malconfigured_areas_) {
754 TrackerLog(fmt::format("Area data not found for: {}", area)); 783 TrackerLog(fmt::format("Area data not found for: {}", area));
@@ -768,13 +797,10 @@ struct GameData {
768 subway_it["door"].as<std::string>()); 797 subway_it["door"].as<std::string>());
769 } 798 }
770 799
771 if (subway_it["paintings"]) { 800 if (subway_it["painting"]) {
772 for (const auto &painting_it : subway_it["paintings"]) { 801 std::string painting_id = subway_it["painting"].as<std::string>();
773 std::string painting_id = painting_it.as<std::string>(); 802 subway_item.painting = painting_id;
774 803 subway_item_by_painting_[painting_id] = subway_item.id;
775 subway_item.paintings.push_back(painting_id);
776 subway_item_by_painting_[painting_id] = subway_item.id;
777 }
778 } 804 }
779 805
780 if (subway_it["tags"]) { 806 if (subway_it["tags"]) {
@@ -821,6 +847,10 @@ struct GameData {
821 subway_item.special = subway_it["special"].as<std::string>(); 847 subway_item.special = subway_it["special"].as<std::string>();
822 } 848 }
823 849
850 if (subway_it["tilted"]) {
851 subway_item.tilted = subway_it["tilted"].as<bool>();
852 }
853
824 subway_items_.push_back(subway_item); 854 subway_items_.push_back(subway_item);
825 } 855 }
826 856
@@ -880,7 +910,7 @@ struct GameData {
880 if (!panel_doors_by_id_.count(full_name)) { 910 if (!panel_doors_by_id_.count(full_name)) {
881 int panel_door_id = panel_doors_.size(); 911 int panel_door_id = panel_doors_.size();
882 panel_doors_by_id_[full_name] = panel_door_id; 912 panel_doors_by_id_[full_name] = panel_door_id;
883 panel_doors_.push_back({.room = AddOrGetRoom(room)}); 913 panel_doors_.push_back({});
884 } 914 }
885 915
886 return panel_doors_by_id_[full_name]; 916 return panel_doors_by_id_[full_name];
@@ -953,6 +983,14 @@ const Panel &GD_GetPanel(int panel_id) {
953 return GetState().panels_.at(panel_id); 983 return GetState().panels_.at(panel_id);
954} 984}
955 985
986int GD_GetPanelBySolveIndex(int solve_index) {
987 return GetState().panel_by_solve_index_.at(solve_index);
988}
989
990const std::vector<PaintingExit> &GD_GetPaintings() {
991 return GetState().paintings_;
992}
993
956const PaintingExit &GD_GetPaintingExit(int painting_id) { 994const PaintingExit &GD_GetPaintingExit(int painting_id) {
957 return GetState().paintings_.at(painting_id); 995 return GetState().paintings_.at(painting_id);
958} 996}
@@ -995,3 +1033,38 @@ std::optional<int> GD_GetSubwayItemForPainting(const std::string &painting_id) {
995int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) { 1033int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) {
996 return GetState().subway_item_by_sunwarp_.at(sunwarp); 1034 return GetState().subway_item_by_sunwarp_.at(sunwarp);
997} 1035}
1036
1037std::string GD_GetItemName(int id) {
1038 auto it = GetState().item_by_ap_id_.find(id);
1039 if (it != GetState().item_by_ap_id_.end()) {
1040 return it->second;
1041 } else {
1042 return "Unknown";
1043 }
1044}
1045
1046LingoColor GetLingoColorForString(const std::string &str) {
1047 if (str == "black") {
1048 return LingoColor::kBlack;
1049 } else if (str == "red") {
1050 return LingoColor::kRed;
1051 } else if (str == "blue") {
1052 return LingoColor::kBlue;
1053 } else if (str == "yellow") {
1054 return LingoColor::kYellow;
1055 } else if (str == "orange") {
1056 return LingoColor::kOrange;
1057 } else if (str == "green") {
1058 return LingoColor::kGreen;
1059 } else if (str == "gray") {
1060 return LingoColor::kGray;
1061 } else if (str == "brown") {
1062 return LingoColor::kBrown;
1063 } else if (str == "purple") {
1064 return LingoColor::kPurple;
1065 } else {
1066 TrackerLog(fmt::format("Invalid color: {}", str));
1067
1068 return LingoColor::kNone;
1069 }
1070}