about summary refs log tree commit diff stats
path: root/tracker_state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tracker_state.cpp')
-rw-r--r--tracker_state.cpp143
1 files changed, 143 insertions, 0 deletions
diff --git a/tracker_state.cpp b/tracker_state.cpp new file mode 100644 index 0000000..62e4612 --- /dev/null +++ b/tracker_state.cpp
@@ -0,0 +1,143 @@
1#include "tracker_state.h"
2
3#include <list>
4#include <set>
5
6#include "ap_state.h"
7#include "game_data.h"
8
9bool IsDoorReachable_Helper(int door_id, const std::set<int>& reachable_rooms);
10
11bool IsPanelReachable_Helper(int panel_id,
12 const std::set<int>& reachable_rooms) {
13 const Panel& panel_obj = GetGameData().GetPanel(panel_id);
14
15 if (!reachable_rooms.count(panel_obj.room)) {
16 return false;
17 }
18
19 for (int room_id : panel_obj.required_rooms) {
20 if (!reachable_rooms.count(room_id)) {
21 return false;
22 }
23 }
24
25 for (int door_id : panel_obj.required_doors) {
26 if (!IsDoorReachable_Helper(door_id, reachable_rooms)) {
27 return false;
28 }
29 }
30
31 if (GetAPState().IsColorShuffle()) {
32 for (LingoColor color : panel_obj.colors) {
33 if (!GetAPState().HasColorItem(color)) {
34 return false;
35 }
36 }
37 }
38
39 return true;
40}
41
42bool IsDoorReachable_Helper(int door_id, const std::set<int>& reachable_rooms) {
43 const Door& door_obj = GetGameData().GetDoor(door_id);
44
45 switch (GetAPState().GetDoorShuffleMode()) {
46 case DoorShuffleMode::kNone: {
47 if (!reachable_rooms.count(door_obj.room)) {
48 return false;
49 }
50
51 for (int panel_id : door_obj.panels) {
52 if (!IsPanelReachable_Helper(panel_id, reachable_rooms)) {
53 return false;
54 }
55 }
56
57 return true;
58 }
59 case DoorShuffleMode::kSimple: {
60 break;
61 }
62 case DoorShuffleMode::kComplex: {
63 break;
64 }
65 }
66}
67
68void TrackerState::CalculateState() {
69 reachability_.clear();
70
71 std::set<int> reachable_rooms;
72
73 std::list<Exit> flood_boundary;
74 flood_boundary.push_back(
75 {.destination_room = GetGameData().GetRoomByName("Menu")});
76
77 bool reachable_changed = true;
78 while (reachable_changed) {
79 reachable_changed = false;
80
81 std::list<Exit> new_boundary;
82 for (const Exit& room_exit : flood_boundary) {
83 if (reachable_rooms.count(room_exit.destination_room)) {
84 continue;
85 }
86
87 bool valid_transition = false;
88 if (room_exit.door.has_value()) {
89 if (IsDoorReachable_Helper(*room_exit.door, reachable_rooms)) {
90 valid_transition = true;
91 } else if (GetAPState().GetDoorShuffleMode() ==
92 DoorShuffleMode::kNone) {
93 new_boundary.push_back(room_exit);
94 }
95 } else {
96 valid_transition = true;
97 }
98
99 if (valid_transition) {
100 reachable_rooms.insert(room_exit.destination_room);
101 reachable_changed = true;
102
103 const Room& room_obj =
104 GetGameData().GetRoom(room_exit.destination_room);
105 for (const Exit& out_edge : room_obj.exits) {
106 new_boundary.push_back(out_edge);
107 }
108 }
109 }
110
111 flood_boundary = new_boundary;
112 }
113
114 for (const MapArea& map_area : GetGameData().GetMapAreas()) {
115 for (int section_id = 0; section_id < map_area.locations.size();
116 section_id++) {
117 const Location& location_section = map_area.locations.at(section_id);
118 bool reachable = reachable_rooms.count(location_section.room);
119 if (reachable) {
120 for (int panel_id : location_section.panels) {
121 reachable &= IsPanelReachable_Helper(panel_id, reachable_rooms);
122 }
123 }
124
125 reachability_[{map_area.id, section_id}] = reachable;
126 }
127 }
128}
129
130bool TrackerState::IsLocationReachable(int area_id, int section_id) {
131 std::tuple<int, int> key = {area_id, section_id};
132
133 if (reachability_.count(key)) {
134 return reachability_.at(key);
135 } else {
136 return false;
137 }
138}
139
140TrackerState& GetTrackerState() {
141 static TrackerState* instance = new TrackerState();
142 return *instance;
143}