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.cpp180
1 files changed, 119 insertions, 61 deletions
diff --git a/src/game_data.cpp b/src/game_data.cpp index a4a441d..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));
@@ -538,6 +565,8 @@ struct GameData {
538 ids_config["progression"][progressive_item_name]) { 565 ids_config["progression"][progressive_item_name]) {
539 progressive_item_id = 566 progressive_item_id =
540 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;
541 } else { 570 } else {
542 TrackerLog(fmt::format("Missing AP item ID for progressive item {}", 571 TrackerLog(fmt::format("Missing AP item ID for progressive item {}",
543 progressive_item_name)); 572 progressive_item_name));
@@ -589,6 +618,21 @@ struct GameData {
589 } 618 }
590 } 619 }
591 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
592 map_areas_.reserve(areas_config.size()); 636 map_areas_.reserve(areas_config.size());
593 637
594 std::map<std::string, int> fold_areas; 638 std::map<std::string, int> fold_areas;
@@ -734,31 +778,6 @@ struct GameData {
734 } 778 }
735 } 779 }
736 780
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. 781 // Report errors.
763 for (const std::string &area : malconfigured_areas_) { 782 for (const std::string &area : malconfigured_areas_) {
764 TrackerLog(fmt::format("Area data not found for: {}", area)); 783 TrackerLog(fmt::format("Area data not found for: {}", area));
@@ -891,7 +910,7 @@ struct GameData {
891 if (!panel_doors_by_id_.count(full_name)) { 910 if (!panel_doors_by_id_.count(full_name)) {
892 int panel_door_id = panel_doors_.size(); 911 int panel_door_id = panel_doors_.size();
893 panel_doors_by_id_[full_name] = panel_door_id; 912 panel_doors_by_id_[full_name] = panel_door_id;
894 panel_doors_.push_back({.room = AddOrGetRoom(room)}); 913 panel_doors_.push_back({});
895 } 914 }
896 915
897 return panel_doors_by_id_[full_name]; 916 return panel_doors_by_id_[full_name];
@@ -964,6 +983,10 @@ const Panel &GD_GetPanel(int panel_id) {
964 return GetState().panels_.at(panel_id); 983 return GetState().panels_.at(panel_id);
965} 984}
966 985
986int GD_GetPanelBySolveIndex(int solve_index) {
987 return GetState().panel_by_solve_index_.at(solve_index);
988}
989
967const std::vector<PaintingExit> &GD_GetPaintings() { 990const std::vector<PaintingExit> &GD_GetPaintings() {
968 return GetState().paintings_; 991 return GetState().paintings_;
969} 992}
@@ -1010,3 +1033,38 @@ std::optional<int> GD_GetSubwayItemForPainting(const std::string &painting_id) {
1010int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) { 1033int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) {
1011 return GetState().subway_item_by_sunwarp_.at(sunwarp); 1034 return GetState().subway_item_by_sunwarp_.at(sunwarp);
1012} 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}