about summary refs log tree commit diff stats
path: root/src/game_data.cpp
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2024-06-09 22:43:20 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2024-06-09 22:43:20 -0400
commit475b7a38f66071ad5713f6f00a49c4e1399e0613 (patch)
tree4dcb76d5bb9e1dbabe19dcbd0cc9676c31f715e6 /src/game_data.cpp
parent829bb6ba7fdbef5c4e6fb9e4eabc0c2f962325ae (diff)
parent14d075e02007aeb53dbadd6c629564ee467cd7b2 (diff)
downloadlingo-ap-tracker-475b7a38f66071ad5713f6f00a49c4e1399e0613.tar.gz
lingo-ap-tracker-475b7a38f66071ad5713f6f00a49c4e1399e0613.tar.bz2
lingo-ap-tracker-475b7a38f66071ad5713f6f00a49c4e1399e0613.zip
Merge branch 'main' into panels
Diffstat (limited to 'src/game_data.cpp')
-rw-r--r--src/game_data.cpp257
1 files changed, 202 insertions, 55 deletions
diff --git a/src/game_data.cpp b/src/game_data.cpp index 0567623..1ccf511 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -1,5 +1,11 @@
1#include "game_data.h" 1#include "game_data.h"
2 2
3#include <wx/wxprec.h>
4
5#ifndef WX_PRECOMP
6#include <wx/wx.h>
7#endif
8
3#include <hkutil/string.h> 9#include <hkutil/string.h>
4#include <yaml-cpp/yaml.h> 10#include <yaml-cpp/yaml.h>
5 11
@@ -7,7 +13,6 @@
7#include <sstream> 13#include <sstream>
8 14
9#include "global.h" 15#include "global.h"
10#include "logger.h"
11 16
12namespace { 17namespace {
13 18
@@ -31,9 +36,7 @@ LingoColor GetColorForString(const std::string &str) {
31 } else if (str == "purple") { 36 } else if (str == "purple") {
32 return LingoColor::kPurple; 37 return LingoColor::kPurple;
33 } else { 38 } else {
34 std::ostringstream errmsg; 39 wxLogError("Invalid color: %s", str);
35 errmsg << "Invalid color: " << str;
36 TrackerLog(errmsg.str());
37 40
38 return LingoColor::kNone; 41 return LingoColor::kNone;
39 } 42 }
@@ -45,12 +48,15 @@ struct GameData {
45 std::vector<Panel> panels_; 48 std::vector<Panel> panels_;
46 std::vector<PanelDoor> panel_doors_; 49 std::vector<PanelDoor> panel_doors_;
47 std::vector<MapArea> map_areas_; 50 std::vector<MapArea> map_areas_;
51 std::vector<SubwayItem> subway_items_;
52 std::vector<PaintingExit> paintings_;
48 53
49 std::map<std::string, int> room_by_id_; 54 std::map<std::string, int> room_by_id_;
50 std::map<std::string, int> door_by_id_; 55 std::map<std::string, int> door_by_id_;
51 std::map<std::string, int> panel_by_id_; 56 std::map<std::string, int> panel_by_id_;
52 std::map<std::string, int> panel_doors_by_id_; 57 std::map<std::string, int> panel_doors_by_id_;
53 std::map<std::string, int> area_by_id_; 58 std::map<std::string, int> area_by_id_;
59 std::map<std::string, int> painting_by_id_;
54 60
55 std::vector<int> door_definition_order_; 61 std::vector<int> door_definition_order_;
56 62
@@ -63,6 +69,9 @@ struct GameData {
63 69
64 std::vector<int> sunwarp_doors_; 70 std::vector<int> sunwarp_doors_;
65 71
72 std::map<std::string, int> subway_item_by_painting_;
73 std::map<SubwaySunwarp, int> subway_item_by_sunwarp_;
74
66 bool loaded_area_data_ = false; 75 bool loaded_area_data_ = false;
67 std::set<std::string> malconfigured_areas_; 76 std::set<std::string> malconfigured_areas_;
68 77
@@ -81,9 +90,7 @@ struct GameData {
81 ap_id_by_color_[GetColorForString(input_name)] = 90 ap_id_by_color_[GetColorForString(input_name)] =
82 ids_config["special_items"][color_name].as<int>(); 91 ids_config["special_items"][color_name].as<int>();
83 } else { 92 } else {
84 std::ostringstream errmsg; 93 wxLogError("Missing AP item ID for color %s", color_name);
85 errmsg << "Missing AP item ID for color " << color_name;
86 TrackerLog(errmsg.str());
87 } 94 }
88 }; 95 };
89 96
@@ -158,8 +165,9 @@ struct GameData {
158 } 165 }
159 default: { 166 default: {
160 // This shouldn't happen. 167 // This shouldn't happen.
161 std::cout << "Error reading game data: " << entrance_it 168 std::ostringstream formatted;
162 << std::endl; 169 formatted << entrance_it;
170 wxLogError("Error reading game data: %s", formatted.str());
163 break; 171 break;
164 } 172 }
165 } 173 }
@@ -256,6 +264,11 @@ struct GameData {
256 achievement_panels_.push_back(panel_id); 264 achievement_panels_.push_back(panel_id);
257 } 265 }
258 266
267 if (panel_it.second["location_name"]) {
268 panels_[panel_id].location_name =
269 panel_it.second["location_name"].as<std::string>();
270 }
271
259 if (panel_it.second["hunt"]) { 272 if (panel_it.second["hunt"]) {
260 panels_[panel_id].hunt = panel_it.second["hunt"].as<bool>(); 273 panels_[panel_id].hunt = panel_it.second["hunt"].as<bool>();
261 } 274 }
@@ -279,10 +292,8 @@ struct GameData {
279 [panels_[panel_id].name] 292 [panels_[panel_id].name]
280 .as<int>(); 293 .as<int>();
281 } else { 294 } else {
282 std::ostringstream errmsg; 295 wxLogError("Missing AP location ID for panel %s - %s",
283 errmsg << "Missing AP location ID for panel " 296 rooms_[room_id].name, panels_[panel_id].name);
284 << rooms_[room_id].name << " - " << panels_[panel_id].name;
285 TrackerLog(errmsg.str());
286 } 297 }
287 } 298 }
288 } 299 }
@@ -345,10 +356,8 @@ struct GameData {
345 [doors_[door_id].name]["item"] 356 [doors_[door_id].name]["item"]
346 .as<int>(); 357 .as<int>();
347 } else { 358 } else {
348 std::ostringstream errmsg; 359 wxLogError("Missing AP item ID for door %s - %s",
349 errmsg << "Missing AP item ID for door " << rooms_[room_id].name 360 rooms_[room_id].name, doors_[door_id].name);
350 << " - " << doors_[door_id].name;
351 TrackerLog(errmsg.str());
352 } 361 }
353 } 362 }
354 363
@@ -362,10 +371,8 @@ struct GameData {
362 ids_config["door_groups"][doors_[door_id].group_name] 371 ids_config["door_groups"][doors_[door_id].group_name]
363 .as<int>(); 372 .as<int>();
364 } else { 373 } else {
365 std::ostringstream errmsg; 374 wxLogError("Missing AP item ID for door group %s",
366 errmsg << "Missing AP item ID for door group " 375 doors_[door_id].group_name);
367 << doors_[door_id].group_name;
368 TrackerLog(errmsg.str());
369 } 376 }
370 } 377 }
371 378
@@ -375,13 +382,11 @@ struct GameData {
375 } else if (!door_it.second["skip_location"] && 382 } else if (!door_it.second["skip_location"] &&
376 !door_it.second["event"]) { 383 !door_it.second["event"]) {
377 if (has_external_panels) { 384 if (has_external_panels) {
378 std::ostringstream errmsg; 385 wxLogError(
379 errmsg 386 "%s - %s has panels from other rooms but does not have an "
380 << rooms_[room_id].name << " - " << doors_[door_id].name 387 "explicit location name and is not marked skip_location or "
381 << " has panels from other rooms but does not have an " 388 "event",
382 "explicit " 389 rooms_[room_id].name, doors_[door_id].name);
383 "location name and is not marked skip_location or event";
384 TrackerLog(errmsg.str());
385 } 390 }
386 391
387 doors_[door_id].location_name = 392 doors_[door_id].location_name =
@@ -401,10 +406,8 @@ struct GameData {
401 [doors_[door_id].name]["location"] 406 [doors_[door_id].name]["location"]
402 .as<int>(); 407 .as<int>();
403 } else { 408 } else {
404 std::ostringstream errmsg; 409 wxLogError("Missing AP location ID for door %s - %s",
405 errmsg << "Missing AP location ID for door " 410 rooms_[room_id].name, doors_[door_id].name);
406 << rooms_[room_id].name << " - " << doors_[door_id].name;
407 TrackerLog(errmsg.str());
408 } 411 }
409 } 412 }
410 413
@@ -478,12 +481,14 @@ struct GameData {
478 481
479 if (room_it.second["paintings"]) { 482 if (room_it.second["paintings"]) {
480 for (const auto &painting : room_it.second["paintings"]) { 483 for (const auto &painting : room_it.second["paintings"]) {
481 std::string painting_id = painting["id"].as<std::string>(); 484 std::string internal_id = painting["id"].as<std::string>();
482 room_by_painting_[painting_id] = room_id; 485 int painting_id = AddOrGetPainting(internal_id);
486 PaintingExit &painting_exit = paintings_[painting_id];
487 painting_exit.room = room_id;
483 488
484 if (!painting["exit_only"] || !painting["exit_only"].as<bool>()) { 489 if ((!painting["exit_only"] || !painting["exit_only"].as<bool>()) &&
485 PaintingExit painting_exit; 490 (!painting["disable"] || !painting["disable"].as<bool>())) {
486 painting_exit.id = painting_id; 491 painting_exit.entrance = true;
487 492
488 if (painting["required_door"]) { 493 if (painting["required_door"]) {
489 std::string rd_room = rooms_[room_id].name; 494 std::string rd_room = rooms_[room_id].name;
@@ -494,9 +499,9 @@ struct GameData {
494 painting_exit.door = AddOrGetDoor( 499 painting_exit.door = AddOrGetDoor(
495 rd_room, painting["required_door"]["door"].as<std::string>()); 500 rd_room, painting["required_door"]["door"].as<std::string>());
496 } 501 }
497
498 rooms_[room_id].paintings.push_back(painting_exit);
499 } 502 }
503
504 rooms_[room_id].paintings.push_back(painting_exit.id);
500 } 505 }
501 } 506 }
502 507
@@ -523,10 +528,8 @@ struct GameData {
523 progressive_item_id = 528 progressive_item_id =
524 ids_config["progression"][progressive_item_name].as<int>(); 529 ids_config["progression"][progressive_item_name].as<int>();
525 } else { 530 } else {
526 std::ostringstream errmsg; 531 wxLogError("Missing AP item ID for progressive item %s",
527 errmsg << "Missing AP item ID for progressive item " 532 progressive_item_name);
528 << progressive_item_name;
529 TrackerLog(errmsg.str());
530 } 533 }
531 534
532 if (progression_it.second["doors"]) { 535 if (progression_it.second["doors"]) {
@@ -600,8 +603,21 @@ struct GameData {
600 std::string room_name = rooms_[room_id].name; 603 std::string room_name = rooms_[room_id].name;
601 604
602 std::string area_name = room_name; 605 std::string area_name = room_name;
603 if (fold_areas.count(room_name)) { 606 std::string section_name = panel.name;
604 int fold_area_id = fold_areas[room_name]; 607 std::string location_name = room_name + " - " + panel.name;
608
609 if (!panel.location_name.empty()) {
610 location_name = panel.location_name;
611
612 size_t divider_pos = location_name.find(" - ");
613 if (divider_pos != std::string::npos) {
614 area_name = location_name.substr(0, divider_pos);
615 section_name = location_name.substr(divider_pos + 3);
616 }
617 }
618
619 if (fold_areas.count(area_name)) {
620 int fold_area_id = fold_areas[area_name];
605 area_name = map_areas_[fold_area_id].name; 621 area_name = map_areas_[fold_area_id].name;
606 } 622 }
607 623
@@ -617,15 +633,15 @@ struct GameData {
617 MapArea &map_area = map_areas_[area_id]; 633 MapArea &map_area = map_areas_[area_id];
618 // room field should be the original room ID 634 // room field should be the original room ID
619 map_area.locations.push_back( 635 map_area.locations.push_back(
620 {.name = panel.name, 636 {.name = section_name,
621 .ap_location_name = room_name + " - " + panel.name, 637 .ap_location_name = location_name,
622 .ap_location_id = panel.ap_location_id, 638 .ap_location_id = panel.ap_location_id,
623 .room = panel.room, 639 .room = panel.room,
624 .panels = {panel.id}, 640 .panels = {panel.id},
625 .classification = classification, 641 .classification = classification,
626 .hunt = panel.hunt}); 642 .hunt = panel.hunt});
627 locations_by_name[map_area.locations.back().ap_location_name] = { 643 locations_by_name[location_name] = {area_id,
628 area_id, map_area.locations.size() - 1}; 644 map_area.locations.size() - 1};
629 } 645 }
630 646
631 for (int door_id : door_definition_order_) { 647 for (int door_id : door_definition_order_) {
@@ -679,11 +695,101 @@ struct GameData {
679 } 695 }
680 } 696 }
681 697
698 for (const Room &room : rooms_) {
699 std::string area_name = room.name;
700 if (fold_areas.count(room.name)) {
701 int fold_area_id = fold_areas[room.name];
702 area_name = map_areas_[fold_area_id].name;
703 }
704
705 if (!room.paintings.empty()) {
706 int area_id = AddOrGetArea(area_name);
707 MapArea &map_area = map_areas_[area_id];
708
709 for (int painting_id : room.paintings) {
710 const PaintingExit &painting_obj = paintings_.at(painting_id);
711 if (painting_obj.entrance) {
712 map_area.paintings.push_back(painting_id);
713 }
714 }
715 }
716 }
717
682 // Report errors. 718 // Report errors.
683 for (const std::string &area : malconfigured_areas_) { 719 for (const std::string &area : malconfigured_areas_) {
684 std::ostringstream errstr; 720 wxLogError("Area data not found for: %s", area);
685 errstr << "Area data not found for: " << area; 721 }
686 TrackerLog(errstr.str()); 722
723 // Read in subway items.
724 YAML::Node subway_config =
725 YAML::LoadFile(GetAbsolutePath("assets/subway.yaml"));
726 for (const auto &subway_it : subway_config) {
727 SubwayItem subway_item;
728 subway_item.id = subway_items_.size();
729 subway_item.x = subway_it["pos"][0].as<int>();
730 subway_item.y = subway_it["pos"][1].as<int>();
731
732 if (subway_it["door"]) {
733 subway_item.door = AddOrGetDoor(subway_it["room"].as<std::string>(),
734 subway_it["door"].as<std::string>());
735 }
736
737 if (subway_it["paintings"]) {
738 for (const auto &painting_it : subway_it["paintings"]) {
739 std::string painting_id = painting_it.as<std::string>();
740
741 subway_item.paintings.push_back(painting_id);
742 subway_item_by_painting_[painting_id] = subway_item.id;
743 }
744 }
745
746 if (subway_it["tags"]) {
747 for (const auto &tag_it : subway_it["tags"]) {
748 subway_item.tags.push_back(tag_it.as<std::string>());
749 }
750 }
751
752 if (subway_it["sunwarp"]) {
753 SubwaySunwarp sunwarp;
754 sunwarp.dots = subway_it["sunwarp"]["dots"].as<int>();
755
756 std::string sunwarp_type =
757 subway_it["sunwarp"]["type"].as<std::string>();
758 if (sunwarp_type == "final") {
759 sunwarp.type = SubwaySunwarpType::kFinal;
760 } else if (sunwarp_type == "exit") {
761 sunwarp.type = SubwaySunwarpType::kExit;
762 } else {
763 sunwarp.type = SubwaySunwarpType::kEnter;
764 }
765
766 subway_item.sunwarp = sunwarp;
767
768 subway_item_by_sunwarp_[sunwarp] = subway_item.id;
769
770 subway_item.door =
771 AddOrGetDoor("Sunwarps", std::to_string(sunwarp.dots) + " Sunwarp");
772 }
773
774 if (subway_it["special"]) {
775 subway_item.special = subway_it["special"].as<std::string>();
776 }
777
778 subway_items_.push_back(subway_item);
779 }
780
781 // Find singleton subway tags.
782 std::map<std::string, std::set<int>> subway_tags;
783 for (const SubwayItem &subway_item : subway_items_) {
784 for (const std::string &tag : subway_item.tags) {
785 subway_tags[tag].insert(subway_item.id);
786 }
787 }
788
789 for (const auto &[tag, items] : subway_tags) {
790 if (items.size() == 1) {
791 wxLogWarning("Singleton subway item tag: %s", tag);
792 }
687 } 793 }
688 } 794 }
689 795
@@ -700,8 +806,10 @@ struct GameData {
700 std::string full_name = room + " - " + door; 806 std::string full_name = room + " - " + door;
701 807
702 if (!door_by_id_.count(full_name)) { 808 if (!door_by_id_.count(full_name)) {
809 int door_id = doors_.size();
703 door_by_id_[full_name] = doors_.size(); 810 door_by_id_[full_name] = doors_.size();
704 doors_.push_back({.room = AddOrGetRoom(room), .name = door}); 811 doors_.push_back(
812 {.id = door_id, .room = AddOrGetRoom(room), .name = door});
705 } 813 }
706 814
707 return door_by_id_[full_name]; 815 return door_by_id_[full_name];
@@ -745,6 +853,16 @@ struct GameData {
745 853
746 return area_by_id_[area]; 854 return area_by_id_[area];
747 } 855 }
856
857 int AddOrGetPainting(std::string internal_id) {
858 if (!painting_by_id_.count(internal_id)) {
859 int painting_id = paintings_.size();
860 painting_by_id_[internal_id] = painting_id;
861 paintings_.push_back({.id = painting_id, .internal_id = internal_id});
862 }
863
864 return painting_by_id_[internal_id];
865 }
748}; 866};
749 867
750GameData &GetState() { 868GameData &GetState() {
@@ -754,6 +872,10 @@ GameData &GetState() {
754 872
755} // namespace 873} // namespace
756 874
875bool SubwaySunwarp::operator<(const SubwaySunwarp &rhs) const {
876 return std::tie(dots, type) < std::tie(rhs.dots, rhs.type);
877}
878
757const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; } 879const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; }
758 880
759const MapArea &GD_GetMapArea(int id) { return GetState().map_areas_.at(id); } 881const MapArea &GD_GetMapArea(int id) { return GetState().map_areas_.at(id); }
@@ -780,8 +902,12 @@ const Panel &GD_GetPanel(int panel_id) {
780 return GetState().panels_.at(panel_id); 902 return GetState().panels_.at(panel_id);
781} 903}
782 904
783int GD_GetRoomForPainting(const std::string &painting_id) { 905const PaintingExit &GD_GetPaintingExit(int painting_id) {
784 return GetState().room_by_painting_.at(painting_id); 906 return GetState().paintings_.at(painting_id);
907}
908
909int GD_GetPaintingByName(const std::string &name) {
910 return GetState().painting_by_id_.at(name);
785} 911}
786 912
787const std::vector<int> &GD_GetAchievementPanels() { 913const std::vector<int> &GD_GetAchievementPanels() {
@@ -799,3 +925,24 @@ const std::vector<int> &GD_GetSunwarpDoors() {
799int GD_GetRoomForSunwarp(int index) { 925int GD_GetRoomForSunwarp(int index) {
800 return GetState().room_by_sunwarp_.at(index); 926 return GetState().room_by_sunwarp_.at(index);
801} 927}
928
929const std::vector<SubwayItem> &GD_GetSubwayItems() {
930 return GetState().subway_items_;
931}
932
933const SubwayItem &GD_GetSubwayItem(int id) {
934 return GetState().subway_items_.at(id);
935}
936
937int GD_GetSubwayItemForPainting(const std::string &painting_id) {
938#ifndef NDEBUG
939 if (!GetState().subway_item_by_painting_.count(painting_id)) {
940 wxLogError("No subway item for painting %s", painting_id);
941 }
942#endif
943 return GetState().subway_item_by_painting_.at(painting_id);
944}
945
946int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) {
947 return GetState().subway_item_by_sunwarp_.at(sunwarp);
948}