diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2024-06-06 15:54:41 -0400 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2024-06-06 15:54:41 -0400 |
commit | 8ddab49cc13d809ca75dcd7f645661a3d3cb05c4 (patch) | |
tree | ba1e5f3237dbb7cdc939c35e193f5e6e46845a77 /src/game_data.cpp | |
parent | ac38dd0a5c394eefc39b7a8cf7b96762f18c8b31 (diff) | |
parent | 6f5287b3921c843a6b322ccbdfcbef00a8f16980 (diff) | |
download | lingo-ap-tracker-8ddab49cc13d809ca75dcd7f645661a3d3cb05c4.tar.gz lingo-ap-tracker-8ddab49cc13d809ca75dcd7f645661a3d3cb05c4.tar.bz2 lingo-ap-tracker-8ddab49cc13d809ca75dcd7f645661a3d3cb05c4.zip |
Merge branch 'subway'
Diffstat (limited to 'src/game_data.cpp')
-rw-r--r-- | src/game_data.cpp | 221 |
1 files changed, 173 insertions, 48 deletions
diff --git a/src/game_data.cpp b/src/game_data.cpp index be31b8f..5776c6c 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 | ||
12 | namespace { | 17 | namespace { |
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 | } |
@@ -44,11 +47,14 @@ struct GameData { | |||
44 | std::vector<Door> doors_; | 47 | std::vector<Door> doors_; |
45 | std::vector<Panel> panels_; | 48 | std::vector<Panel> panels_; |
46 | std::vector<MapArea> map_areas_; | 49 | std::vector<MapArea> map_areas_; |
50 | std::vector<SubwayItem> subway_items_; | ||
51 | std::vector<PaintingExit> paintings_; | ||
47 | 52 | ||
48 | std::map<std::string, int> room_by_id_; | 53 | std::map<std::string, int> room_by_id_; |
49 | std::map<std::string, int> door_by_id_; | 54 | std::map<std::string, int> door_by_id_; |
50 | std::map<std::string, int> panel_by_id_; | 55 | std::map<std::string, int> panel_by_id_; |
51 | std::map<std::string, int> area_by_id_; | 56 | std::map<std::string, int> area_by_id_; |
57 | std::map<std::string, int> painting_by_id_; | ||
52 | 58 | ||
53 | std::vector<int> door_definition_order_; | 59 | std::vector<int> door_definition_order_; |
54 | 60 | ||
@@ -61,6 +67,9 @@ struct GameData { | |||
61 | 67 | ||
62 | std::vector<int> sunwarp_doors_; | 68 | std::vector<int> sunwarp_doors_; |
63 | 69 | ||
70 | std::map<std::string, int> subway_item_by_painting_; | ||
71 | std::map<SubwaySunwarp, int> subway_item_by_sunwarp_; | ||
72 | |||
64 | bool loaded_area_data_ = false; | 73 | bool loaded_area_data_ = false; |
65 | std::set<std::string> malconfigured_areas_; | 74 | std::set<std::string> malconfigured_areas_; |
66 | 75 | ||
@@ -79,9 +88,7 @@ struct GameData { | |||
79 | ap_id_by_color_[GetColorForString(input_name)] = | 88 | ap_id_by_color_[GetColorForString(input_name)] = |
80 | ids_config["special_items"][color_name].as<int>(); | 89 | ids_config["special_items"][color_name].as<int>(); |
81 | } else { | 90 | } else { |
82 | std::ostringstream errmsg; | 91 | wxLogError("Missing AP item ID for color %s", color_name); |
83 | errmsg << "Missing AP item ID for color " << color_name; | ||
84 | TrackerLog(errmsg.str()); | ||
85 | } | 92 | } |
86 | }; | 93 | }; |
87 | 94 | ||
@@ -156,8 +163,9 @@ struct GameData { | |||
156 | } | 163 | } |
157 | default: { | 164 | default: { |
158 | // This shouldn't happen. | 165 | // This shouldn't happen. |
159 | std::cout << "Error reading game data: " << entrance_it | 166 | std::ostringstream formatted; |
160 | << std::endl; | 167 | formatted << entrance_it; |
168 | wxLogError("Error reading game data: %s", formatted.str()); | ||
161 | break; | 169 | break; |
162 | } | 170 | } |
163 | } | 171 | } |
@@ -282,10 +290,8 @@ struct GameData { | |||
282 | [panels_[panel_id].name] | 290 | [panels_[panel_id].name] |
283 | .as<int>(); | 291 | .as<int>(); |
284 | } else { | 292 | } else { |
285 | std::ostringstream errmsg; | 293 | wxLogError("Missing AP location ID for panel %s - %s", |
286 | errmsg << "Missing AP location ID for panel " | 294 | rooms_[room_id].name, panels_[panel_id].name); |
287 | << rooms_[room_id].name << " - " << panels_[panel_id].name; | ||
288 | TrackerLog(errmsg.str()); | ||
289 | } | 295 | } |
290 | } | 296 | } |
291 | } | 297 | } |
@@ -348,10 +354,8 @@ struct GameData { | |||
348 | [doors_[door_id].name]["item"] | 354 | [doors_[door_id].name]["item"] |
349 | .as<int>(); | 355 | .as<int>(); |
350 | } else { | 356 | } else { |
351 | std::ostringstream errmsg; | 357 | wxLogError("Missing AP item ID for door %s - %s", |
352 | errmsg << "Missing AP item ID for door " << rooms_[room_id].name | 358 | rooms_[room_id].name, doors_[door_id].name); |
353 | << " - " << doors_[door_id].name; | ||
354 | TrackerLog(errmsg.str()); | ||
355 | } | 359 | } |
356 | } | 360 | } |
357 | 361 | ||
@@ -365,10 +369,8 @@ struct GameData { | |||
365 | ids_config["door_groups"][doors_[door_id].group_name] | 369 | ids_config["door_groups"][doors_[door_id].group_name] |
366 | .as<int>(); | 370 | .as<int>(); |
367 | } else { | 371 | } else { |
368 | std::ostringstream errmsg; | 372 | wxLogError("Missing AP item ID for door group %s", |
369 | errmsg << "Missing AP item ID for door group " | 373 | doors_[door_id].group_name); |
370 | << doors_[door_id].group_name; | ||
371 | TrackerLog(errmsg.str()); | ||
372 | } | 374 | } |
373 | } | 375 | } |
374 | 376 | ||
@@ -378,13 +380,11 @@ struct GameData { | |||
378 | } else if (!door_it.second["skip_location"] && | 380 | } else if (!door_it.second["skip_location"] && |
379 | !door_it.second["event"]) { | 381 | !door_it.second["event"]) { |
380 | if (has_external_panels) { | 382 | if (has_external_panels) { |
381 | std::ostringstream errmsg; | 383 | wxLogError( |
382 | errmsg | 384 | "%s - %s has panels from other rooms but does not have an " |
383 | << rooms_[room_id].name << " - " << doors_[door_id].name | 385 | "explicit location name and is not marked skip_location or " |
384 | << " has panels from other rooms but does not have an " | 386 | "event", |
385 | "explicit " | 387 | rooms_[room_id].name, doors_[door_id].name); |
386 | "location name and is not marked skip_location or event"; | ||
387 | TrackerLog(errmsg.str()); | ||
388 | } | 388 | } |
389 | 389 | ||
390 | doors_[door_id].location_name = | 390 | doors_[door_id].location_name = |
@@ -404,10 +404,8 @@ struct GameData { | |||
404 | [doors_[door_id].name]["location"] | 404 | [doors_[door_id].name]["location"] |
405 | .as<int>(); | 405 | .as<int>(); |
406 | } else { | 406 | } else { |
407 | std::ostringstream errmsg; | 407 | wxLogError("Missing AP location ID for door %s - %s", |
408 | errmsg << "Missing AP location ID for door " | 408 | rooms_[room_id].name, doors_[door_id].name); |
409 | << rooms_[room_id].name << " - " << doors_[door_id].name; | ||
410 | TrackerLog(errmsg.str()); | ||
411 | } | 409 | } |
412 | } | 410 | } |
413 | 411 | ||
@@ -428,12 +426,13 @@ struct GameData { | |||
428 | 426 | ||
429 | if (room_it.second["paintings"]) { | 427 | if (room_it.second["paintings"]) { |
430 | for (const auto &painting : room_it.second["paintings"]) { | 428 | for (const auto &painting : room_it.second["paintings"]) { |
431 | std::string painting_id = painting["id"].as<std::string>(); | 429 | std::string internal_id = painting["id"].as<std::string>(); |
432 | room_by_painting_[painting_id] = room_id; | ||
433 | 430 | ||
434 | if (!painting["exit_only"] || !painting["exit_only"].as<bool>()) { | 431 | if ((!painting["exit_only"] || !painting["exit_only"].as<bool>()) && |
435 | PaintingExit painting_exit; | 432 | (!painting["disable"] || !painting["disable"].as<bool>())) { |
436 | painting_exit.id = painting_id; | 433 | int painting_id = AddOrGetPainting(internal_id); |
434 | PaintingExit &painting_exit = paintings_[painting_id]; | ||
435 | painting_exit.room = room_id; | ||
437 | 436 | ||
438 | if (painting["required_door"]) { | 437 | if (painting["required_door"]) { |
439 | std::string rd_room = rooms_[room_id].name; | 438 | std::string rd_room = rooms_[room_id].name; |
@@ -445,7 +444,7 @@ struct GameData { | |||
445 | rd_room, painting["required_door"]["door"].as<std::string>()); | 444 | rd_room, painting["required_door"]["door"].as<std::string>()); |
446 | } | 445 | } |
447 | 446 | ||
448 | rooms_[room_id].paintings.push_back(painting_exit); | 447 | rooms_[room_id].paintings.push_back(painting_exit.id); |
449 | } | 448 | } |
450 | } | 449 | } |
451 | } | 450 | } |
@@ -473,10 +472,8 @@ struct GameData { | |||
473 | progressive_item_id = | 472 | progressive_item_id = |
474 | ids_config["progression"][progressive_item_name].as<int>(); | 473 | ids_config["progression"][progressive_item_name].as<int>(); |
475 | } else { | 474 | } else { |
476 | std::ostringstream errmsg; | 475 | wxLogError("Missing AP item ID for progressive item %s", |
477 | errmsg << "Missing AP item ID for progressive item " | 476 | progressive_item_name); |
478 | << progressive_item_name; | ||
479 | TrackerLog(errmsg.str()); | ||
480 | } | 477 | } |
481 | 478 | ||
482 | int index = 1; | 479 | int index = 1; |
@@ -618,11 +615,98 @@ struct GameData { | |||
618 | } | 615 | } |
619 | } | 616 | } |
620 | 617 | ||
618 | for (const Room &room : rooms_) { | ||
619 | std::string area_name = room.name; | ||
620 | if (fold_areas.count(room.name)) { | ||
621 | int fold_area_id = fold_areas[room.name]; | ||
622 | area_name = map_areas_[fold_area_id].name; | ||
623 | } | ||
624 | |||
625 | if (!room.paintings.empty()) { | ||
626 | int area_id = AddOrGetArea(area_name); | ||
627 | MapArea &map_area = map_areas_[area_id]; | ||
628 | |||
629 | for (int painting_id : room.paintings) { | ||
630 | map_area.paintings.push_back(painting_id); | ||
631 | } | ||
632 | } | ||
633 | } | ||
634 | |||
621 | // Report errors. | 635 | // Report errors. |
622 | for (const std::string &area : malconfigured_areas_) { | 636 | for (const std::string &area : malconfigured_areas_) { |
623 | std::ostringstream errstr; | 637 | wxLogError("Area data not found for: %s", area); |
624 | errstr << "Area data not found for: " << area; | 638 | } |
625 | TrackerLog(errstr.str()); | 639 | |
640 | // Read in subway items. | ||
641 | YAML::Node subway_config = | ||
642 | YAML::LoadFile(GetAbsolutePath("assets/subway.yaml")); | ||
643 | for (const auto &subway_it : subway_config) { | ||
644 | SubwayItem subway_item; | ||
645 | subway_item.id = subway_items_.size(); | ||
646 | subway_item.x = subway_it["pos"][0].as<int>(); | ||
647 | subway_item.y = subway_it["pos"][1].as<int>(); | ||
648 | |||
649 | if (subway_it["door"]) { | ||
650 | subway_item.door = AddOrGetDoor(subway_it["room"].as<std::string>(), | ||
651 | subway_it["door"].as<std::string>()); | ||
652 | } | ||
653 | |||
654 | if (subway_it["paintings"]) { | ||
655 | for (const auto &painting_it : subway_it["paintings"]) { | ||
656 | std::string painting_id = painting_it.as<std::string>(); | ||
657 | |||
658 | subway_item.paintings.push_back(painting_id); | ||
659 | subway_item_by_painting_[painting_id] = subway_item.id; | ||
660 | } | ||
661 | } | ||
662 | |||
663 | if (subway_it["tags"]) { | ||
664 | for (const auto &tag_it : subway_it["tags"]) { | ||
665 | subway_item.tags.push_back(tag_it.as<std::string>()); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | if (subway_it["sunwarp"]) { | ||
670 | SubwaySunwarp sunwarp; | ||
671 | sunwarp.dots = subway_it["sunwarp"]["dots"].as<int>(); | ||
672 | |||
673 | std::string sunwarp_type = | ||
674 | subway_it["sunwarp"]["type"].as<std::string>(); | ||
675 | if (sunwarp_type == "final") { | ||
676 | sunwarp.type = SubwaySunwarpType::kFinal; | ||
677 | } else if (sunwarp_type == "exit") { | ||
678 | sunwarp.type = SubwaySunwarpType::kExit; | ||
679 | } else { | ||
680 | sunwarp.type = SubwaySunwarpType::kEnter; | ||
681 | } | ||
682 | |||
683 | subway_item.sunwarp = sunwarp; | ||
684 | |||
685 | subway_item_by_sunwarp_[sunwarp] = subway_item.id; | ||
686 | |||
687 | subway_item.door = | ||
688 | AddOrGetDoor("Sunwarps", std::to_string(sunwarp.dots) + " Sunwarp"); | ||
689 | } | ||
690 | |||
691 | if (subway_it["special"]) { | ||
692 | subway_item.special = subway_it["special"].as<std::string>(); | ||
693 | } | ||
694 | |||
695 | subway_items_.push_back(subway_item); | ||
696 | } | ||
697 | |||
698 | // Find singleton subway tags. | ||
699 | std::map<std::string, std::set<int>> subway_tags; | ||
700 | for (const SubwayItem &subway_item : subway_items_) { | ||
701 | for (const std::string &tag : subway_item.tags) { | ||
702 | subway_tags[tag].insert(subway_item.id); | ||
703 | } | ||
704 | } | ||
705 | |||
706 | for (const auto &[tag, items] : subway_tags) { | ||
707 | if (items.size() == 1) { | ||
708 | wxLogWarning("Singleton subway item tag: %s", tag); | ||
709 | } | ||
626 | } | 710 | } |
627 | } | 711 | } |
628 | 712 | ||
@@ -639,8 +723,10 @@ struct GameData { | |||
639 | std::string full_name = room + " - " + door; | 723 | std::string full_name = room + " - " + door; |
640 | 724 | ||
641 | if (!door_by_id_.count(full_name)) { | 725 | if (!door_by_id_.count(full_name)) { |
726 | int door_id = doors_.size(); | ||
642 | door_by_id_[full_name] = doors_.size(); | 727 | door_by_id_[full_name] = doors_.size(); |
643 | doors_.push_back({.room = AddOrGetRoom(room), .name = door}); | 728 | doors_.push_back( |
729 | {.id = door_id, .room = AddOrGetRoom(room), .name = door}); | ||
644 | } | 730 | } |
645 | 731 | ||
646 | return door_by_id_[full_name]; | 732 | return door_by_id_[full_name]; |
@@ -672,6 +758,16 @@ struct GameData { | |||
672 | 758 | ||
673 | return area_by_id_[area]; | 759 | return area_by_id_[area]; |
674 | } | 760 | } |
761 | |||
762 | int AddOrGetPainting(std::string internal_id) { | ||
763 | if (!painting_by_id_.count(internal_id)) { | ||
764 | int painting_id = paintings_.size(); | ||
765 | painting_by_id_[internal_id] = painting_id; | ||
766 | paintings_.push_back({.id = painting_id, .internal_id = internal_id}); | ||
767 | } | ||
768 | |||
769 | return painting_by_id_[internal_id]; | ||
770 | } | ||
675 | }; | 771 | }; |
676 | 772 | ||
677 | GameData &GetState() { | 773 | GameData &GetState() { |
@@ -681,6 +777,10 @@ GameData &GetState() { | |||
681 | 777 | ||
682 | } // namespace | 778 | } // namespace |
683 | 779 | ||
780 | bool SubwaySunwarp::operator<(const SubwaySunwarp &rhs) const { | ||
781 | return std::tie(dots, type) < std::tie(rhs.dots, rhs.type); | ||
782 | } | ||
783 | |||
684 | const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; } | 784 | const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; } |
685 | 785 | ||
686 | const MapArea &GD_GetMapArea(int id) { return GetState().map_areas_.at(id); } | 786 | const MapArea &GD_GetMapArea(int id) { return GetState().map_areas_.at(id); } |
@@ -703,8 +803,12 @@ const Panel &GD_GetPanel(int panel_id) { | |||
703 | return GetState().panels_.at(panel_id); | 803 | return GetState().panels_.at(panel_id); |
704 | } | 804 | } |
705 | 805 | ||
706 | int GD_GetRoomForPainting(const std::string &painting_id) { | 806 | const PaintingExit &GD_GetPaintingExit(int painting_id) { |
707 | return GetState().room_by_painting_.at(painting_id); | 807 | return GetState().paintings_.at(painting_id); |
808 | } | ||
809 | |||
810 | int GD_GetPaintingByName(const std::string &name) { | ||
811 | return GetState().painting_by_id_.at(name); | ||
708 | } | 812 | } |
709 | 813 | ||
710 | const std::vector<int> &GD_GetAchievementPanels() { | 814 | const std::vector<int> &GD_GetAchievementPanels() { |
@@ -722,3 +826,24 @@ const std::vector<int> &GD_GetSunwarpDoors() { | |||
722 | int GD_GetRoomForSunwarp(int index) { | 826 | int GD_GetRoomForSunwarp(int index) { |
723 | return GetState().room_by_sunwarp_.at(index); | 827 | return GetState().room_by_sunwarp_.at(index); |
724 | } | 828 | } |
829 | |||
830 | const std::vector<SubwayItem> &GD_GetSubwayItems() { | ||
831 | return GetState().subway_items_; | ||
832 | } | ||
833 | |||
834 | const SubwayItem &GD_GetSubwayItem(int id) { | ||
835 | return GetState().subway_items_.at(id); | ||
836 | } | ||
837 | |||
838 | int GD_GetSubwayItemForPainting(const std::string &painting_id) { | ||
839 | #ifndef NDEBUG | ||
840 | if (!GetState().subway_item_by_painting_.count(painting_id)) { | ||
841 | wxLogError("No subway item for painting %s", painting_id); | ||
842 | } | ||
843 | #endif | ||
844 | return GetState().subway_item_by_painting_.at(painting_id); | ||
845 | } | ||
846 | |||
847 | int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) { | ||
848 | return GetState().subway_item_by_sunwarp_.at(sunwarp); | ||
849 | } | ||