about summary refs log tree commit diff stats
path: root/src/tracker_state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tracker_state.cpp')
-rw-r--r--src/tracker_state.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp new file mode 100644 index 0000000..858ec3e --- /dev/null +++ b/src/tracker_state.cpp
@@ -0,0 +1,181 @@
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 if (panel_obj.name == "THE MASTER") {
20 int achievements_accessible = 0;
21
22 for (int achieve_id : GetGameData().GetAchievementPanels()) {
23 if (IsPanelReachable_Helper(achieve_id, reachable_rooms)) {
24 achievements_accessible++;
25
26 if (achievements_accessible >= AP_GetMasteryRequirement()) {
27 break;
28 }
29 }
30 }
31
32 return (achievements_accessible >= AP_GetMasteryRequirement());
33 }
34
35 for (int room_id : panel_obj.required_rooms) {
36 if (!reachable_rooms.count(room_id)) {
37 return false;
38 }
39 }
40
41 for (int door_id : panel_obj.required_doors) {
42 if (!IsDoorReachable_Helper(door_id, reachable_rooms)) {
43 return false;
44 }
45 }
46
47 if (AP_IsColorShuffle()) {
48 for (LingoColor color : panel_obj.colors) {
49 if (!AP_HasColorItem(color)) {
50 return false;
51 }
52 }
53 }
54
55 return true;
56}
57
58bool IsDoorReachable_Helper(int door_id, const std::set<int>& reachable_rooms) {
59 const Door& door_obj = GetGameData().GetDoor(door_id);
60
61 if (AP_GetDoorShuffleMode() == kNO_DOORS || door_obj.skip_item) {
62 if (!reachable_rooms.count(door_obj.room)) {
63 return false;
64 }
65
66 for (int panel_id : door_obj.panels) {
67 if (!IsPanelReachable_Helper(panel_id, reachable_rooms)) {
68 return false;
69 }
70 }
71
72 return true;
73 } else if (AP_GetDoorShuffleMode() == kSIMPLE_DOORS &&
74 !door_obj.group_name.empty()) {
75 return AP_HasItem(door_obj.group_name);
76 } else {
77 bool has_item = AP_HasItem(door_obj.item_name);
78
79 if (!has_item) {
80 for (const ProgressiveRequirement& prog_req : door_obj.progressives) {
81 if (AP_HasItem(prog_req.item_name, prog_req.quantity)) {
82 has_item = true;
83 break;
84 }
85 }
86 }
87
88 return has_item;
89 }
90}
91
92void TrackerState::CalculateState() {
93 reachability_.clear();
94
95 std::set<int> reachable_rooms;
96
97 std::list<Exit> flood_boundary;
98 flood_boundary.push_back(
99 {.destination_room = GetGameData().GetRoomByName("Menu")});
100
101 bool reachable_changed = true;
102 while (reachable_changed) {
103 reachable_changed = false;
104
105 std::list<Exit> new_boundary;
106 for (const Exit& room_exit : flood_boundary) {
107 if (reachable_rooms.count(room_exit.destination_room)) {
108 continue;
109 }
110
111 bool valid_transition = false;
112 if (room_exit.door.has_value()) {
113 if (IsDoorReachable_Helper(*room_exit.door, reachable_rooms)) {
114 valid_transition = true;
115 } else if (AP_GetDoorShuffleMode() == kNO_DOORS) {
116 new_boundary.push_back(room_exit);
117 }
118 } else {
119 valid_transition = true;
120 }
121
122 if (valid_transition) {
123 reachable_rooms.insert(room_exit.destination_room);
124 reachable_changed = true;
125
126 const Room& room_obj =
127 GetGameData().GetRoom(room_exit.destination_room);
128 for (const Exit& out_edge : room_obj.exits) {
129 if (!out_edge.painting || !AP_IsPaintingShuffle()) {
130 new_boundary.push_back(out_edge);
131 }
132 }
133
134 if (AP_IsPaintingShuffle()) {
135 for (const PaintingExit& out_edge : room_obj.paintings) {
136 if (AP_GetPaintingMapping().count(out_edge.id)) {
137 Exit painting_exit;
138 painting_exit.destination_room = GetGameData().GetRoomForPainting(
139 AP_GetPaintingMapping().at(out_edge.id));
140 painting_exit.door = out_edge.door;
141
142 new_boundary.push_back(painting_exit);
143 }
144 }
145 }
146 }
147 }
148
149 flood_boundary = new_boundary;
150 }
151
152 for (const MapArea& map_area : GetGameData().GetMapAreas()) {
153 for (int section_id = 0; section_id < map_area.locations.size();
154 section_id++) {
155 const Location& location_section = map_area.locations.at(section_id);
156 bool reachable = reachable_rooms.count(location_section.room);
157 if (reachable) {
158 for (int panel_id : location_section.panels) {
159 reachable &= IsPanelReachable_Helper(panel_id, reachable_rooms);
160 }
161 }
162
163 reachability_[{map_area.id, section_id}] = reachable;
164 }
165 }
166}
167
168bool TrackerState::IsLocationReachable(int area_id, int section_id) {
169 std::tuple<int, int> key = {area_id, section_id};
170
171 if (reachability_.count(key)) {
172 return reachability_.at(key);
173 } else {
174 return false;
175 }
176}
177
178TrackerState& GetTrackerState() {
179 static TrackerState* instance = new TrackerState();
180 return *instance;
181}