diff options
Diffstat (limited to 'src/tracker_state.cpp')
| -rw-r--r-- | src/tracker_state.cpp | 75 |
1 files changed, 64 insertions, 11 deletions
| diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index 1a2d116..8d5d904 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | #include "tracker_state.h" | 1 | #include "tracker_state.h" |
| 2 | 2 | ||
| 3 | #include <fmt/core.h> | ||
| 4 | #include <hkutil/string.h> | ||
| 5 | |||
| 3 | #include <list> | 6 | #include <list> |
| 4 | #include <map> | 7 | #include <map> |
| 5 | #include <mutex> | 8 | #include <mutex> |
| @@ -9,6 +12,7 @@ | |||
| 9 | 12 | ||
| 10 | #include "ap_state.h" | 13 | #include "ap_state.h" |
| 11 | #include "game_data.h" | 14 | #include "game_data.h" |
| 15 | #include "logger.h" | ||
| 12 | 16 | ||
| 13 | namespace { | 17 | namespace { |
| 14 | 18 | ||
| @@ -148,6 +152,7 @@ struct TrackerState { | |||
| 148 | std::mutex reachability_mutex; | 152 | std::mutex reachability_mutex; |
| 149 | RequirementCalculator requirements; | 153 | RequirementCalculator requirements; |
| 150 | std::map<int, std::map<std::string, bool>> door_reports; | 154 | std::map<int, std::map<std::string, bool>> door_reports; |
| 155 | bool pilgrimage_doable = false; | ||
| 151 | }; | 156 | }; |
| 152 | 157 | ||
| 153 | enum Decision { kYes, kNo, kMaybe }; | 158 | enum Decision { kYes, kNo, kMaybe }; |
| @@ -176,7 +181,8 @@ class StateCalculator { | |||
| 176 | std::list<int> panel_boundary; | 181 | std::list<int> panel_boundary; |
| 177 | std::list<int> painting_boundary; | 182 | std::list<int> painting_boundary; |
| 178 | std::list<Exit> flood_boundary; | 183 | std::list<Exit> flood_boundary; |
| 179 | flood_boundary.push_back({.destination_room = options_.start}); | 184 | flood_boundary.push_back( |
| 185 | {.source_room = -1, .destination_room = options_.start}); | ||
| 180 | 186 | ||
| 181 | bool reachable_changed = true; | 187 | bool reachable_changed = true; |
| 182 | while (reachable_changed) { | 188 | while (reachable_changed) { |
| @@ -217,7 +223,9 @@ class StateCalculator { | |||
| 217 | PaintingExit target_painting = | 223 | PaintingExit target_painting = |
| 218 | GD_GetPaintingExit(GD_GetPaintingByName( | 224 | GD_GetPaintingExit(GD_GetPaintingByName( |
| 219 | AP_GetPaintingMapping().at(cur_painting.internal_id))); | 225 | AP_GetPaintingMapping().at(cur_painting.internal_id))); |
| 226 | painting_exit.source_room = cur_painting.room; | ||
| 220 | painting_exit.destination_room = target_painting.room; | 227 | painting_exit.destination_room = target_painting.room; |
| 228 | painting_exit.type = EntranceType::kPainting; | ||
| 221 | 229 | ||
| 222 | new_boundary.push_back(painting_exit); | 230 | new_boundary.push_back(painting_exit); |
| 223 | } | 231 | } |
| @@ -244,6 +252,12 @@ class StateCalculator { | |||
| 244 | reachable_rooms_.insert(room_exit.destination_room); | 252 | reachable_rooms_.insert(room_exit.destination_room); |
| 245 | reachable_changed = true; | 253 | reachable_changed = true; |
| 246 | 254 | ||
| 255 | #ifndef NDEBUG | ||
| 256 | std::list<int> room_path = paths_[room_exit.source_room]; | ||
| 257 | room_path.push_back(room_exit.destination_room); | ||
| 258 | paths_[room_exit.destination_room] = room_path; | ||
| 259 | #endif | ||
| 260 | |||
| 247 | const Room& room_obj = GD_GetRoom(room_exit.destination_room); | 261 | const Room& room_obj = GD_GetRoom(room_exit.destination_room); |
| 248 | for (const Exit& out_edge : room_obj.exits) { | 262 | for (const Exit& out_edge : room_obj.exits) { |
| 249 | if (out_edge.type == EntranceType::kPainting && | 263 | if (out_edge.type == EntranceType::kPainting && |
| @@ -270,32 +284,44 @@ class StateCalculator { | |||
| 270 | if (AP_GetSunwarpMapping().count(index)) { | 284 | if (AP_GetSunwarpMapping().count(index)) { |
| 271 | const SunwarpMapping& sm = AP_GetSunwarpMapping().at(index); | 285 | const SunwarpMapping& sm = AP_GetSunwarpMapping().at(index); |
| 272 | 286 | ||
| 273 | Exit sunwarp_exit; | 287 | new_boundary.push_back( |
| 274 | sunwarp_exit.destination_room = | 288 | {.source_room = room_exit.destination_room, |
| 275 | GD_GetRoomForSunwarp(sm.exit_index); | 289 | .destination_room = GD_GetRoomForSunwarp(sm.exit_index), |
| 276 | sunwarp_exit.door = GD_GetSunwarpDoors().at(sm.dots - 1); | 290 | .door = GD_GetSunwarpDoors().at(sm.dots - 1), |
| 277 | 291 | .type = EntranceType::kSunwarp}); | |
| 278 | new_boundary.push_back(sunwarp_exit); | ||
| 279 | } | 292 | } |
| 280 | } | 293 | } |
| 281 | } | 294 | } |
| 282 | 295 | ||
| 283 | if (AP_HasEarlyColorHallways() && room_obj.name == "Starting Room") { | 296 | if (AP_HasEarlyColorHallways() && room_obj.name == "Starting Room") { |
| 284 | new_boundary.push_back( | 297 | new_boundary.push_back( |
| 285 | {.destination_room = GD_GetRoomByName("Color Hallways"), | 298 | {.source_room = room_exit.destination_room, |
| 299 | .destination_room = GD_GetRoomByName("Color Hallways"), | ||
| 286 | .type = EntranceType::kPainting}); | 300 | .type = EntranceType::kPainting}); |
| 287 | } | 301 | } |
| 288 | 302 | ||
| 289 | if (AP_IsPilgrimageEnabled()) { | 303 | if (AP_IsPilgrimageEnabled()) { |
| 290 | if (room_obj.name == "Hub Room") { | 304 | int pilgrimage_start_id = GD_GetRoomByName("Hub Room"); |
| 305 | if (AP_IsSunwarpShuffle()) { | ||
| 306 | for (const auto& [start_index, mapping] : | ||
| 307 | AP_GetSunwarpMapping()) { | ||
| 308 | if (mapping.dots == 1) { | ||
| 309 | pilgrimage_start_id = GD_GetRoomForSunwarp(start_index); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | if (room_exit.destination_room == pilgrimage_start_id) { | ||
| 291 | new_boundary.push_back( | 315 | new_boundary.push_back( |
| 292 | {.destination_room = GD_GetRoomByName("Pilgrim Antechamber"), | 316 | {.source_room = room_exit.destination_room, |
| 317 | .destination_room = GD_GetRoomByName("Pilgrim Antechamber"), | ||
| 293 | .type = EntranceType::kPilgrimage}); | 318 | .type = EntranceType::kPilgrimage}); |
| 294 | } | 319 | } |
| 295 | } else { | 320 | } else { |
| 296 | if (room_obj.name == "Starting Room") { | 321 | if (room_obj.name == "Starting Room") { |
| 297 | new_boundary.push_back( | 322 | new_boundary.push_back( |
| 298 | {.destination_room = GD_GetRoomByName("Pilgrim Antechamber"), | 323 | {.source_room = room_exit.destination_room, |
| 324 | .destination_room = GD_GetRoomByName("Pilgrim Antechamber"), | ||
| 299 | .door = | 325 | .door = |
| 300 | GD_GetDoorByName("Pilgrim Antechamber - Sun Painting"), | 326 | GD_GetDoorByName("Pilgrim Antechamber - Sun Painting"), |
| 301 | .type = EntranceType::kPainting}); | 327 | .type = EntranceType::kPainting}); |
| @@ -336,6 +362,21 @@ class StateCalculator { | |||
| 336 | return door_report_; | 362 | return door_report_; |
| 337 | } | 363 | } |
| 338 | 364 | ||
| 365 | bool IsPilgrimageDoable() const { return pilgrimage_doable_; } | ||
| 366 | |||
| 367 | std::string GetPathToRoom(int room_id) const { | ||
| 368 | if (!paths_.count(room_id)) { | ||
| 369 | return ""; | ||
| 370 | } | ||
| 371 | |||
| 372 | const std::list<int>& path = paths_.at(room_id); | ||
| 373 | std::vector<std::string> room_names; | ||
| 374 | for (int room_id : path) { | ||
| 375 | room_names.push_back(GD_GetRoom(room_id).name); | ||
| 376 | } | ||
| 377 | return hatkirby::implode(room_names, " -> "); | ||
| 378 | } | ||
| 379 | |||
| 339 | private: | 380 | private: |
| 340 | Decision IsNonGroupedDoorReachable(const Door& door_obj) { | 381 | Decision IsNonGroupedDoorReachable(const Door& door_obj) { |
| 341 | bool has_item = AP_HasItem(door_obj.ap_item_id); | 382 | bool has_item = AP_HasItem(door_obj.ap_item_id); |
| @@ -534,6 +575,8 @@ class StateCalculator { | |||
| 534 | } | 575 | } |
| 535 | } | 576 | } |
| 536 | 577 | ||
| 578 | pilgrimage_doable_ = true; | ||
| 579 | |||
| 537 | return kYes; | 580 | return kYes; |
| 538 | } | 581 | } |
| 539 | 582 | ||
| @@ -574,6 +617,9 @@ class StateCalculator { | |||
| 574 | std::set<int> solveable_panels_; | 617 | std::set<int> solveable_panels_; |
| 575 | std::set<int> reachable_paintings_; | 618 | std::set<int> reachable_paintings_; |
| 576 | std::map<int, std::map<std::string, bool>> door_report_; | 619 | std::map<int, std::map<std::string, bool>> door_report_; |
| 620 | bool pilgrimage_doable_ = false; | ||
| 621 | |||
| 622 | std::map<int, std::list<int>> paths_; | ||
| 577 | }; | 623 | }; |
| 578 | 624 | ||
| 579 | } // namespace | 625 | } // namespace |
| @@ -623,6 +669,7 @@ void RecalculateReachability() { | |||
| 623 | std::swap(GetState().reachable_doors, new_reachable_doors); | 669 | std::swap(GetState().reachable_doors, new_reachable_doors); |
| 624 | std::swap(GetState().reachable_paintings, reachable_paintings); | 670 | std::swap(GetState().reachable_paintings, reachable_paintings); |
| 625 | std::swap(GetState().door_reports, door_reports); | 671 | std::swap(GetState().door_reports, door_reports); |
| 672 | GetState().pilgrimage_doable = state_calculator.IsPilgrimageDoable(); | ||
| 626 | } | 673 | } |
| 627 | 674 | ||
| 628 | bool IsLocationReachable(int location_id) { | 675 | bool IsLocationReachable(int location_id) { |
| @@ -652,3 +699,9 @@ const std::map<std::string, bool>& GetDoorRequirements(int door_id) { | |||
| 652 | 699 | ||
| 653 | return GetState().door_reports[door_id]; | 700 | return GetState().door_reports[door_id]; |
| 654 | } | 701 | } |
| 702 | |||
| 703 | bool IsPilgrimageDoable() { | ||
| 704 | std::lock_guard reachability_guard(GetState().reachability_mutex); | ||
| 705 | |||
| 706 | return GetState().pilgrimage_doable; | ||
| 707 | } | ||
