diff options
Diffstat (limited to 'src/tracker_state.cpp')
| -rw-r--r-- | src/tracker_state.cpp | 164 |
1 files changed, 137 insertions, 27 deletions
| diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index f7244a7..bcee1d6 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | #include "ap_state.h" | 13 | #include "ap_state.h" |
| 14 | #include "game_data.h" | 14 | #include "game_data.h" |
| 15 | #include "global.h" | ||
| 15 | #include "logger.h" | 16 | #include "logger.h" |
| 16 | 17 | ||
| 17 | namespace { | 18 | namespace { |
| @@ -25,6 +26,7 @@ struct Requirements { | |||
| 25 | std::set<int> rooms; // maybe | 26 | std::set<int> rooms; // maybe |
| 26 | bool mastery = false; // maybe | 27 | bool mastery = false; // maybe |
| 27 | bool panel_hunt = false; // maybe | 28 | bool panel_hunt = false; // maybe |
| 29 | bool postgame = false; | ||
| 28 | 30 | ||
| 29 | void Merge(const Requirements& rhs) { | 31 | void Merge(const Requirements& rhs) { |
| 30 | if (rhs.disabled) { | 32 | if (rhs.disabled) { |
| @@ -45,6 +47,7 @@ struct Requirements { | |||
| 45 | } | 47 | } |
| 46 | mastery = mastery || rhs.mastery; | 48 | mastery = mastery || rhs.mastery; |
| 47 | panel_hunt = panel_hunt || rhs.panel_hunt; | 49 | panel_hunt = panel_hunt || rhs.panel_hunt; |
| 50 | postgame = postgame || rhs.postgame; | ||
| 48 | } | 51 | } |
| 49 | }; | 52 | }; |
| 50 | 53 | ||
| @@ -146,6 +149,10 @@ class RequirementCalculator { | |||
| 146 | } | 149 | } |
| 147 | } | 150 | } |
| 148 | 151 | ||
| 152 | if (panel_obj.location_name == GetWinCondition()) { | ||
| 153 | requirements.postgame = true; | ||
| 154 | } | ||
| 155 | |||
| 149 | panels_[panel_id] = requirements; | 156 | panels_[panel_id] = requirements; |
| 150 | } | 157 | } |
| 151 | 158 | ||
| @@ -165,6 +172,11 @@ struct TrackerState { | |||
| 165 | RequirementCalculator requirements; | 172 | RequirementCalculator requirements; |
| 166 | std::map<int, std::map<std::string, bool>> door_reports; | 173 | std::map<int, std::map<std::string, bool>> door_reports; |
| 167 | bool pilgrimage_doable = false; | 174 | bool pilgrimage_doable = false; |
| 175 | |||
| 176 | // If these are empty, it actually means everything is non-postgame. | ||
| 177 | std::set<int> non_postgame_areas; | ||
| 178 | std::set<int> non_postgame_locations; | ||
| 179 | std::set<int> non_postgame_paintings; | ||
| 168 | }; | 180 | }; |
| 169 | 181 | ||
| 170 | enum Decision { kYes, kNo, kMaybe }; | 182 | enum Decision { kYes, kNo, kMaybe }; |
| @@ -179,6 +191,11 @@ class StateCalculator; | |||
| 179 | struct StateCalculatorOptions { | 191 | struct StateCalculatorOptions { |
| 180 | int start; | 192 | int start; |
| 181 | bool pilgrimage = false; | 193 | bool pilgrimage = false; |
| 194 | |||
| 195 | // Treats all items as collected and all paintings as checked, but postgame | ||
| 196 | // areas cannot be reached. | ||
| 197 | bool postgame_detection = false; | ||
| 198 | |||
| 182 | StateCalculator* parent = nullptr; | 199 | StateCalculator* parent = nullptr; |
| 183 | }; | 200 | }; |
| 184 | 201 | ||
| @@ -234,7 +251,8 @@ class StateCalculator { | |||
| 234 | 251 | ||
| 235 | PaintingExit cur_painting = GD_GetPaintingExit(painting_id); | 252 | PaintingExit cur_painting = GD_GetPaintingExit(painting_id); |
| 236 | if (painting_mapping_.count(cur_painting.internal_id) && | 253 | if (painting_mapping_.count(cur_painting.internal_id) && |
| 237 | checked_paintings_.count(cur_painting.internal_id)) { | 254 | (checked_paintings_.count(cur_painting.internal_id) || |
| 255 | options_.postgame_detection)) { | ||
| 238 | Exit painting_exit; | 256 | Exit painting_exit; |
| 239 | PaintingExit target_painting = | 257 | PaintingExit target_painting = |
| 240 | GD_GetPaintingExit(GD_GetPaintingByName( | 258 | GD_GetPaintingExit(GD_GetPaintingByName( |
| @@ -419,43 +437,49 @@ class StateCalculator { | |||
| 419 | return kNo; | 437 | return kNo; |
| 420 | } | 438 | } |
| 421 | 439 | ||
| 440 | if (reqs.postgame && options_.postgame_detection) { | ||
| 441 | return kNo; | ||
| 442 | } | ||
| 443 | |||
| 422 | Decision final_decision = kYes; | 444 | Decision final_decision = kYes; |
| 423 | 445 | ||
| 424 | for (int door_id : reqs.doors) { | 446 | if (!options_.postgame_detection) { |
| 425 | const Door& door_obj = GD_GetDoor(door_id); | 447 | for (int door_id : reqs.doors) { |
| 426 | Decision decision = IsNonGroupedDoorReachable(door_obj); | 448 | const Door& door_obj = GD_GetDoor(door_id); |
| 449 | Decision decision = IsNonGroupedDoorReachable(door_obj); | ||
| 427 | 450 | ||
| 428 | if (report) { | 451 | if (report) { |
| 429 | (*report)[door_obj.item_name] = (decision == kYes); | 452 | (*report)[door_obj.item_name] = (decision == kYes); |
| 430 | } | 453 | } |
| 431 | 454 | ||
| 432 | if (decision != kYes) { | 455 | if (decision != kYes) { |
| 433 | final_decision = decision; | 456 | final_decision = decision; |
| 457 | } | ||
| 434 | } | 458 | } |
| 435 | } | ||
| 436 | 459 | ||
| 437 | for (int panel_door_id : reqs.panel_doors) { | 460 | for (int panel_door_id : reqs.panel_doors) { |
| 438 | const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_door_id); | 461 | const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_door_id); |
| 439 | Decision decision = IsNonGroupedDoorReachable(panel_door_obj); | 462 | Decision decision = IsNonGroupedDoorReachable(panel_door_obj); |
| 440 | 463 | ||
| 441 | if (report) { | 464 | if (report) { |
| 442 | (*report)[AP_GetItemName(panel_door_obj.ap_item_id)] = | 465 | (*report)[AP_GetItemName(panel_door_obj.ap_item_id)] = |
| 443 | (decision == kYes); | 466 | (decision == kYes); |
| 444 | } | 467 | } |
| 445 | 468 | ||
| 446 | if (decision != kYes) { | 469 | if (decision != kYes) { |
| 447 | final_decision = decision; | 470 | final_decision = decision; |
| 471 | } | ||
| 448 | } | 472 | } |
| 449 | } | ||
| 450 | 473 | ||
| 451 | for (int item_id : reqs.items) { | 474 | for (int item_id : reqs.items) { |
| 452 | bool has_item = AP_HasItem(item_id); | 475 | bool has_item = AP_HasItem(item_id); |
| 453 | if (report) { | 476 | if (report) { |
| 454 | (*report)[AP_GetItemName(item_id)] = has_item; | 477 | (*report)[AP_GetItemName(item_id)] = has_item; |
| 455 | } | 478 | } |
| 456 | 479 | ||
| 457 | if (!has_item) { | 480 | if (!has_item) { |
| 458 | final_decision = kNo; | 481 | final_decision = kNo; |
| 482 | } | ||
| 459 | } | 483 | } |
| 460 | } | 484 | } |
| 461 | 485 | ||
| @@ -658,6 +682,62 @@ class StateCalculator { | |||
| 658 | void ResetReachabilityRequirements() { | 682 | void ResetReachabilityRequirements() { |
| 659 | std::lock_guard reachability_guard(GetState().reachability_mutex); | 683 | std::lock_guard reachability_guard(GetState().reachability_mutex); |
| 660 | GetState().requirements.Reset(); | 684 | GetState().requirements.Reset(); |
| 685 | |||
| 686 | if (AP_IsPostgameShuffle()) { | ||
| 687 | GetState().non_postgame_areas.clear(); | ||
| 688 | GetState().non_postgame_locations.clear(); | ||
| 689 | GetState().non_postgame_paintings.clear(); | ||
| 690 | } else { | ||
| 691 | StateCalculator postgame_calculator( | ||
| 692 | {.start = GD_GetRoomByName("Menu"), .postgame_detection = true}); | ||
| 693 | postgame_calculator.Calculate(); | ||
| 694 | |||
| 695 | std::set<int>& non_postgame_areas = GetState().non_postgame_areas; | ||
| 696 | non_postgame_areas.clear(); | ||
| 697 | |||
| 698 | std::set<int>& non_postgame_locations = GetState().non_postgame_locations; | ||
| 699 | non_postgame_locations.clear(); | ||
| 700 | |||
| 701 | const std::set<int>& reachable_rooms = | ||
| 702 | postgame_calculator.GetReachableRooms(); | ||
| 703 | const std::set<int>& solveable_panels = | ||
| 704 | postgame_calculator.GetSolveablePanels(); | ||
| 705 | |||
| 706 | for (const MapArea& map_area : GD_GetMapAreas()) { | ||
| 707 | bool area_reachable = false; | ||
| 708 | |||
| 709 | for (const Location& location_section : map_area.locations) { | ||
| 710 | bool reachable = reachable_rooms.count(location_section.room); | ||
| 711 | if (reachable) { | ||
| 712 | for (int panel_id : location_section.panels) { | ||
| 713 | reachable &= (solveable_panels.count(panel_id) == 1); | ||
| 714 | } | ||
| 715 | } | ||
| 716 | |||
| 717 | if (!reachable && IsLocationWinCondition(location_section)) { | ||
| 718 | reachable = true; | ||
| 719 | } | ||
| 720 | |||
| 721 | if (reachable) { | ||
| 722 | non_postgame_locations.insert(location_section.ap_location_id); | ||
| 723 | area_reachable = true; | ||
| 724 | } | ||
| 725 | } | ||
| 726 | |||
| 727 | for (int painting_id : map_area.paintings) { | ||
| 728 | if (postgame_calculator.GetReachablePaintings().count(painting_id)) { | ||
| 729 | area_reachable = true; | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | if (area_reachable) { | ||
| 734 | non_postgame_areas.insert(map_area.id); | ||
| 735 | } | ||
| 736 | } | ||
| 737 | |||
| 738 | GetState().non_postgame_paintings = | ||
| 739 | postgame_calculator.GetReachablePaintings(); | ||
| 740 | } | ||
| 661 | } | 741 | } |
| 662 | 742 | ||
| 663 | void RecalculateReachability() { | 743 | void RecalculateReachability() { |
| @@ -736,3 +816,33 @@ bool IsPilgrimageDoable() { | |||
| 736 | 816 | ||
| 737 | return GetState().pilgrimage_doable; | 817 | return GetState().pilgrimage_doable; |
| 738 | } | 818 | } |
| 819 | |||
| 820 | bool IsAreaPostgame(int area_id) { | ||
| 821 | std::lock_guard reachability_guard(GetState().reachability_mutex); | ||
| 822 | |||
| 823 | if (GetState().non_postgame_areas.empty()) { | ||
| 824 | return false; | ||
| 825 | } else { | ||
| 826 | return !GetState().non_postgame_areas.count(area_id); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | bool IsLocationPostgame(int location_id) { | ||
| 831 | std::lock_guard reachability_guard(GetState().reachability_mutex); | ||
| 832 | |||
| 833 | if (GetState().non_postgame_locations.empty()) { | ||
| 834 | return false; | ||
| 835 | } else { | ||
| 836 | return !GetState().non_postgame_locations.count(location_id); | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | bool IsPaintingPostgame(int painting_id) { | ||
| 841 | std::lock_guard reachability_guard(GetState().reachability_mutex); | ||
| 842 | |||
| 843 | if (GetState().non_postgame_paintings.empty()) { | ||
| 844 | return false; | ||
| 845 | } else { | ||
| 846 | return !GetState().non_postgame_paintings.count(painting_id); | ||
| 847 | } | ||
| 848 | } | ||
