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-06 15:54:41 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2024-06-06 15:54:41 -0400
commit8ddab49cc13d809ca75dcd7f645661a3d3cb05c4 (patch)
treeba1e5f3237dbb7cdc939c35e193f5e6e46845a77 /src/game_data.cpp
parentac38dd0a5c394eefc39b7a8cf7b96762f18c8b31 (diff)
parent6f5287b3921c843a6b322ccbdfcbef00a8f16980 (diff)
downloadlingo-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.cpp221
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
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 }
@@ -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
677GameData &GetState() { 773GameData &GetState() {
@@ -681,6 +777,10 @@ GameData &GetState() {
681 777
682} // namespace 778} // namespace
683 779
780bool SubwaySunwarp::operator<(const SubwaySunwarp &rhs) const {
781 return std::tie(dots, type) < std::tie(rhs.dots, rhs.type);
782}
783
684const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; } 784const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; }
685 785
686const MapArea &GD_GetMapArea(int id) { return GetState().map_areas_.at(id); } 786const 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
706int GD_GetRoomForPainting(const std::string &painting_id) { 806const PaintingExit &GD_GetPaintingExit(int painting_id) {
707 return GetState().room_by_painting_.at(painting_id); 807 return GetState().paintings_.at(painting_id);
808}
809
810int GD_GetPaintingByName(const std::string &name) {
811 return GetState().painting_by_id_.at(name);
708} 812}
709 813
710const std::vector<int> &GD_GetAchievementPanels() { 814const std::vector<int> &GD_GetAchievementPanels() {
@@ -722,3 +826,24 @@ const std::vector<int> &GD_GetSunwarpDoors() {
722int GD_GetRoomForSunwarp(int index) { 826int GD_GetRoomForSunwarp(int index) {
723 return GetState().room_by_sunwarp_.at(index); 827 return GetState().room_by_sunwarp_.at(index);
724} 828}
829
830const std::vector<SubwayItem> &GD_GetSubwayItems() {
831 return GetState().subway_items_;
832}
833
834const SubwayItem &GD_GetSubwayItem(int id) {
835 return GetState().subway_items_.at(id);
836}
837
838int 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
847int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) {
848 return GetState().subway_item_by_sunwarp_.at(sunwarp);
849}