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.cpp238
1 files changed, 182 insertions, 56 deletions
diff --git a/src/game_data.cpp b/src/game_data.cpp index bc4f41b..e75170e 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -1,5 +1,6 @@
1#include "game_data.h" 1#include "game_data.h"
2 2
3#include <fmt/core.h>
3#include <hkutil/string.h> 4#include <hkutil/string.h>
4#include <yaml-cpp/yaml.h> 5#include <yaml-cpp/yaml.h>
5 6
@@ -31,9 +32,7 @@ LingoColor GetColorForString(const std::string &str) {
31 } else if (str == "purple") { 32 } else if (str == "purple") {
32 return LingoColor::kPurple; 33 return LingoColor::kPurple;
33 } else { 34 } else {
34 std::ostringstream errmsg; 35 TrackerLog(fmt::format("Invalid color: {}", str));
35 errmsg << "Invalid color: " << str;
36 TrackerLog(errmsg.str());
37 36
38 return LingoColor::kNone; 37 return LingoColor::kNone;
39 } 38 }
@@ -44,11 +43,14 @@ struct GameData {
44 std::vector<Door> doors_; 43 std::vector<Door> doors_;
45 std::vector<Panel> panels_; 44 std::vector<Panel> panels_;
46 std::vector<MapArea> map_areas_; 45 std::vector<MapArea> map_areas_;
46 std::vector<SubwayItem> subway_items_;
47 std::vector<PaintingExit> paintings_;
47 48
48 std::map<std::string, int> room_by_id_; 49 std::map<std::string, int> room_by_id_;
49 std::map<std::string, int> door_by_id_; 50 std::map<std::string, int> door_by_id_;
50 std::map<std::string, int> panel_by_id_; 51 std::map<std::string, int> panel_by_id_;
51 std::map<std::string, int> area_by_id_; 52 std::map<std::string, int> area_by_id_;
53 std::map<std::string, int> painting_by_id_;
52 54
53 std::vector<int> door_definition_order_; 55 std::vector<int> door_definition_order_;
54 56
@@ -61,6 +63,9 @@ struct GameData {
61 63
62 std::vector<int> sunwarp_doors_; 64 std::vector<int> sunwarp_doors_;
63 65
66 std::map<std::string, int> subway_item_by_painting_;
67 std::map<SubwaySunwarp, int> subway_item_by_sunwarp_;
68
64 bool loaded_area_data_ = false; 69 bool loaded_area_data_ = false;
65 std::set<std::string> malconfigured_areas_; 70 std::set<std::string> malconfigured_areas_;
66 71
@@ -79,9 +84,7 @@ struct GameData {
79 ap_id_by_color_[GetColorForString(input_name)] = 84 ap_id_by_color_[GetColorForString(input_name)] =
80 ids_config["special_items"][color_name].as<int>(); 85 ids_config["special_items"][color_name].as<int>();
81 } else { 86 } else {
82 std::ostringstream errmsg; 87 TrackerLog(fmt::format("Missing AP item ID for color {}", color_name));
83 errmsg << "Missing AP item ID for color " << color_name;
84 TrackerLog(errmsg.str());
85 } 88 }
86 }; 89 };
87 90
@@ -156,8 +159,10 @@ struct GameData {
156 } 159 }
157 default: { 160 default: {
158 // This shouldn't happen. 161 // This shouldn't happen.
159 std::cout << "Error reading game data: " << entrance_it 162 std::ostringstream formatted;
160 << std::endl; 163 formatted << entrance_it;
164 TrackerLog(
165 fmt::format("Error reading game data: {}", formatted.str()));
161 break; 166 break;
162 } 167 }
163 } 168 }
@@ -282,10 +287,9 @@ struct GameData {
282 [panels_[panel_id].name] 287 [panels_[panel_id].name]
283 .as<int>(); 288 .as<int>();
284 } else { 289 } else {
285 std::ostringstream errmsg; 290 TrackerLog(fmt::format("Missing AP location ID for panel {} - {}",
286 errmsg << "Missing AP location ID for panel " 291 rooms_[room_id].name,
287 << rooms_[room_id].name << " - " << panels_[panel_id].name; 292 panels_[panel_id].name));
288 TrackerLog(errmsg.str());
289 } 293 }
290 } 294 }
291 } 295 }
@@ -348,10 +352,9 @@ struct GameData {
348 [doors_[door_id].name]["item"] 352 [doors_[door_id].name]["item"]
349 .as<int>(); 353 .as<int>();
350 } else { 354 } else {
351 std::ostringstream errmsg; 355 TrackerLog(fmt::format("Missing AP item ID for door {} - {}",
352 errmsg << "Missing AP item ID for door " << rooms_[room_id].name 356 rooms_[room_id].name,
353 << " - " << doors_[door_id].name; 357 doors_[door_id].name));
354 TrackerLog(errmsg.str());
355 } 358 }
356 } 359 }
357 360
@@ -365,10 +368,8 @@ struct GameData {
365 ids_config["door_groups"][doors_[door_id].group_name] 368 ids_config["door_groups"][doors_[door_id].group_name]
366 .as<int>(); 369 .as<int>();
367 } else { 370 } else {
368 std::ostringstream errmsg; 371 TrackerLog(fmt::format("Missing AP item ID for door group {}",
369 errmsg << "Missing AP item ID for door group " 372 doors_[door_id].group_name));
370 << doors_[door_id].group_name;
371 TrackerLog(errmsg.str());
372 } 373 }
373 } 374 }
374 375
@@ -378,13 +379,11 @@ struct GameData {
378 } else if (!door_it.second["skip_location"] && 379 } else if (!door_it.second["skip_location"] &&
379 !door_it.second["event"]) { 380 !door_it.second["event"]) {
380 if (has_external_panels) { 381 if (has_external_panels) {
381 std::ostringstream errmsg; 382 TrackerLog(fmt::format(
382 errmsg 383 "{} - {} has panels from other rooms but does not have an "
383 << rooms_[room_id].name << " - " << doors_[door_id].name 384 "explicit location name and is not marked skip_location or "
384 << " has panels from other rooms but does not have an " 385 "event",
385 "explicit " 386 rooms_[room_id].name, doors_[door_id].name));
386 "location name and is not marked skip_location or event";
387 TrackerLog(errmsg.str());
388 } 387 }
389 388
390 doors_[door_id].location_name = 389 doors_[door_id].location_name =
@@ -404,10 +403,9 @@ struct GameData {
404 [doors_[door_id].name]["location"] 403 [doors_[door_id].name]["location"]
405 .as<int>(); 404 .as<int>();
406 } else { 405 } else {
407 std::ostringstream errmsg; 406 TrackerLog(fmt::format("Missing AP location ID for door {} - {}",
408 errmsg << "Missing AP location ID for door " 407 rooms_[room_id].name,
409 << rooms_[room_id].name << " - " << doors_[door_id].name; 408 doors_[door_id].name));
410 TrackerLog(errmsg.str());
411 } 409 }
412 } 410 }
413 411
@@ -428,12 +426,14 @@ 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; 430 int painting_id = AddOrGetPainting(internal_id);
431 PaintingExit &painting_exit = paintings_[painting_id];
432 painting_exit.room = room_id;
433 433
434 if (!painting["exit_only"] || !painting["exit_only"].as<bool>()) { 434 if ((!painting["exit_only"] || !painting["exit_only"].as<bool>()) &&
435 PaintingExit painting_exit; 435 (!painting["disable"] || !painting["disable"].as<bool>())) {
436 painting_exit.id = painting_id; 436 painting_exit.entrance = true;
437 437
438 if (painting["required_door"]) { 438 if (painting["required_door"]) {
439 std::string rd_room = rooms_[room_id].name; 439 std::string rd_room = rooms_[room_id].name;
@@ -444,9 +444,9 @@ struct GameData {
444 painting_exit.door = AddOrGetDoor( 444 painting_exit.door = AddOrGetDoor(
445 rd_room, painting["required_door"]["door"].as<std::string>()); 445 rd_room, painting["required_door"]["door"].as<std::string>());
446 } 446 }
447
448 rooms_[room_id].paintings.push_back(painting_exit);
449 } 447 }
448
449 rooms_[room_id].paintings.push_back(painting_exit.id);
450 } 450 }
451 } 451 }
452 452
@@ -473,10 +473,8 @@ struct GameData {
473 progressive_item_id = 473 progressive_item_id =
474 ids_config["progression"][progressive_item_name].as<int>(); 474 ids_config["progression"][progressive_item_name].as<int>();
475 } else { 475 } else {
476 std::ostringstream errmsg; 476 TrackerLog(fmt::format("Missing AP item ID for progressive item {}",
477 errmsg << "Missing AP item ID for progressive item " 477 progressive_item_name));
478 << progressive_item_name;
479 TrackerLog(errmsg.str());
480 } 478 }
481 479
482 int index = 1; 480 int index = 1;
@@ -559,14 +557,13 @@ struct GameData {
559 int area_id = AddOrGetArea(area_name); 557 int area_id = AddOrGetArea(area_name);
560 MapArea &map_area = map_areas_[area_id]; 558 MapArea &map_area = map_areas_[area_id];
561 // room field should be the original room ID 559 // room field should be the original room ID
562 map_area.locations.push_back( 560 map_area.locations.push_back({.name = section_name,
563 {.name = section_name, 561 .ap_location_name = location_name,
564 .ap_location_name = location_name, 562 .ap_location_id = panel.ap_location_id,
565 .ap_location_id = panel.ap_location_id, 563 .room = panel.room,
566 .room = panel.room, 564 .panels = {panel.id},
567 .panels = {panel.id}, 565 .classification = classification,
568 .classification = classification, 566 .hunt = panel.hunt});
569 .hunt = panel.hunt});
570 locations_by_name[location_name] = {area_id, 567 locations_by_name[location_name] = {area_id,
571 map_area.locations.size() - 1}; 568 map_area.locations.size() - 1};
572 } 569 }
@@ -622,11 +619,101 @@ struct GameData {
622 } 619 }
623 } 620 }
624 621
622 for (const Room &room : rooms_) {
623 std::string area_name = room.name;
624 if (fold_areas.count(room.name)) {
625 int fold_area_id = fold_areas[room.name];
626 area_name = map_areas_[fold_area_id].name;
627 }
628
629 if (!room.paintings.empty()) {
630 int area_id = AddOrGetArea(area_name);
631 MapArea &map_area = map_areas_[area_id];
632
633 for (int painting_id : room.paintings) {
634 const PaintingExit &painting_obj = paintings_.at(painting_id);
635 if (painting_obj.entrance) {
636 map_area.paintings.push_back(painting_id);
637 }
638 }
639 }
640 }
641
625 // Report errors. 642 // Report errors.
626 for (const std::string &area : malconfigured_areas_) { 643 for (const std::string &area : malconfigured_areas_) {
627 std::ostringstream errstr; 644 TrackerLog(fmt::format("Area data not found for: {}", area));
628 errstr << "Area data not found for: " << area; 645 }
629 TrackerLog(errstr.str()); 646
647 // Read in subway items.
648 YAML::Node subway_config =
649 YAML::LoadFile(GetAbsolutePath("assets/subway.yaml"));
650 for (const auto &subway_it : subway_config) {
651 SubwayItem subway_item;
652 subway_item.id = subway_items_.size();
653 subway_item.x = subway_it["pos"][0].as<int>();
654 subway_item.y = subway_it["pos"][1].as<int>();
655
656 if (subway_it["door"]) {
657 subway_item.door = AddOrGetDoor(subway_it["room"].as<std::string>(),
658 subway_it["door"].as<std::string>());
659 }
660
661 if (subway_it["paintings"]) {
662 for (const auto &painting_it : subway_it["paintings"]) {
663 std::string painting_id = painting_it.as<std::string>();
664
665 subway_item.paintings.push_back(painting_id);
666 subway_item_by_painting_[painting_id] = subway_item.id;
667 }
668 }
669
670 if (subway_it["tags"]) {
671 for (const auto &tag_it : subway_it["tags"]) {
672 subway_item.tags.push_back(tag_it.as<std::string>());
673 }
674 }
675
676 if (subway_it["sunwarp"]) {
677 SubwaySunwarp sunwarp;
678 sunwarp.dots = subway_it["sunwarp"]["dots"].as<int>();
679
680 std::string sunwarp_type =
681 subway_it["sunwarp"]["type"].as<std::string>();
682 if (sunwarp_type == "final") {
683 sunwarp.type = SubwaySunwarpType::kFinal;
684 } else if (sunwarp_type == "exit") {
685 sunwarp.type = SubwaySunwarpType::kExit;
686 } else {
687 sunwarp.type = SubwaySunwarpType::kEnter;
688 }
689
690 subway_item.sunwarp = sunwarp;
691
692 subway_item_by_sunwarp_[sunwarp] = subway_item.id;
693
694 subway_item.door =
695 AddOrGetDoor("Sunwarps", std::to_string(sunwarp.dots) + " Sunwarp");
696 }
697
698 if (subway_it["special"]) {
699 subway_item.special = subway_it["special"].as<std::string>();
700 }
701
702 subway_items_.push_back(subway_item);
703 }
704
705 // Find singleton subway tags.
706 std::map<std::string, std::set<int>> subway_tags;
707 for (const SubwayItem &subway_item : subway_items_) {
708 for (const std::string &tag : subway_item.tags) {
709 subway_tags[tag].insert(subway_item.id);
710 }
711 }
712
713 for (const auto &[tag, items] : subway_tags) {
714 if (items.size() == 1) {
715 TrackerLog(fmt::format("Singleton subway item tag: {}", tag));
716 }
630 } 717 }
631 } 718 }
632 719
@@ -643,8 +730,10 @@ struct GameData {
643 std::string full_name = room + " - " + door; 730 std::string full_name = room + " - " + door;
644 731
645 if (!door_by_id_.count(full_name)) { 732 if (!door_by_id_.count(full_name)) {
733 int door_id = doors_.size();
646 door_by_id_[full_name] = doors_.size(); 734 door_by_id_[full_name] = doors_.size();
647 doors_.push_back({.room = AddOrGetRoom(room), .name = door}); 735 doors_.push_back(
736 {.id = door_id, .room = AddOrGetRoom(room), .name = door});
648 } 737 }
649 738
650 return door_by_id_[full_name]; 739 return door_by_id_[full_name];
@@ -676,6 +765,16 @@ struct GameData {
676 765
677 return area_by_id_[area]; 766 return area_by_id_[area];
678 } 767 }
768
769 int AddOrGetPainting(std::string internal_id) {
770 if (!painting_by_id_.count(internal_id)) {
771 int painting_id = paintings_.size();
772 painting_by_id_[internal_id] = painting_id;
773 paintings_.push_back({.id = painting_id, .internal_id = internal_id});
774 }
775
776 return painting_by_id_[internal_id];
777 }
679}; 778};
680 779
681GameData &GetState() { 780GameData &GetState() {
@@ -685,6 +784,10 @@ GameData &GetState() {
685 784
686} // namespace 785} // namespace
687 786
787bool SubwaySunwarp::operator<(const SubwaySunwarp &rhs) const {
788 return std::tie(dots, type) < std::tie(rhs.dots, rhs.type);
789}
790
688const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; } 791const std::vector<MapArea> &GD_GetMapAreas() { return GetState().map_areas_; }
689 792
690const MapArea &GD_GetMapArea(int id) { return GetState().map_areas_.at(id); } 793const MapArea &GD_GetMapArea(int id) { return GetState().map_areas_.at(id); }
@@ -707,8 +810,12 @@ const Panel &GD_GetPanel(int panel_id) {
707 return GetState().panels_.at(panel_id); 810 return GetState().panels_.at(panel_id);
708} 811}
709 812
710int GD_GetRoomForPainting(const std::string &painting_id) { 813const PaintingExit &GD_GetPaintingExit(int painting_id) {
711 return GetState().room_by_painting_.at(painting_id); 814 return GetState().paintings_.at(painting_id);
815}
816
817int GD_GetPaintingByName(const std::string &name) {
818 return GetState().painting_by_id_.at(name);
712} 819}
713 820
714const std::vector<int> &GD_GetAchievementPanels() { 821const std::vector<int> &GD_GetAchievementPanels() {
@@ -726,3 +833,22 @@ const std::vector<int> &GD_GetSunwarpDoors() {
726int GD_GetRoomForSunwarp(int index) { 833int GD_GetRoomForSunwarp(int index) {
727 return GetState().room_by_sunwarp_.at(index); 834 return GetState().room_by_sunwarp_.at(index);
728} 835}
836
837const std::vector<SubwayItem> &GD_GetSubwayItems() {
838 return GetState().subway_items_;
839}
840
841const SubwayItem &GD_GetSubwayItem(int id) {
842 return GetState().subway_items_.at(id);
843}
844
845std::optional<int> GD_GetSubwayItemForPainting(const std::string &painting_id) {
846 if (GetState().subway_item_by_painting_.count(painting_id)) {
847 return GetState().subway_item_by_painting_.at(painting_id);
848 }
849 return std::nullopt;
850}
851
852int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) {
853 return GetState().subway_item_by_sunwarp_.at(sunwarp);
854}