about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/ap_state.cpp18
-rw-r--r--src/ap_state.h29
-rw-r--r--src/game_data.cpp19
-rw-r--r--src/game_data.h9
-rw-r--r--src/tracker_state.cpp83
5 files changed, 139 insertions, 19 deletions
diff --git a/src/ap_state.cpp b/src/ap_state.cpp index 1937597..bdd9cb2 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp
@@ -64,6 +64,8 @@ struct APState {
64 VictoryCondition victory_condition = kTHE_END; 64 VictoryCondition victory_condition = kTHE_END;
65 bool early_color_hallways = false; 65 bool early_color_hallways = false;
66 bool pilgrimage_enabled = false; 66 bool pilgrimage_enabled = false;
67 bool pilgrimage_allows_roof_access = false;
68 bool pilgrimage_allows_paintings = false;
67 SunwarpAccess sunwarp_access = kSUNWARP_ACCESS_NORMAL; 69 SunwarpAccess sunwarp_access = kSUNWARP_ACCESS_NORMAL;
68 70
69 std::map<std::string, std::string> painting_mapping; 71 std::map<std::string, std::string> painting_mapping;
@@ -135,6 +137,8 @@ struct APState {
135 victory_condition = kTHE_END; 137 victory_condition = kTHE_END;
136 early_color_hallways = false; 138 early_color_hallways = false;
137 pilgrimage_enabled = false; 139 pilgrimage_enabled = false;
140 pilgrimage_allows_roof_access = false;
141 pilgrimage_allows_paintings = false;
138 sunwarp_access = kSUNWARP_ACCESS_NORMAL; 142 sunwarp_access = kSUNWARP_ACCESS_NORMAL;
139 143
140 connected = false; 144 connected = false;
@@ -240,6 +244,12 @@ struct APState {
240 slot_data["early_color_hallways"].get<int>() == 1; 244 slot_data["early_color_hallways"].get<int>() == 1;
241 pilgrimage_enabled = slot_data.contains("enable_pilgrimage") && 245 pilgrimage_enabled = slot_data.contains("enable_pilgrimage") &&
242 slot_data["enable_pilgrimage"].get<int>() == 1; 246 slot_data["enable_pilgrimage"].get<int>() == 1;
247 pilgrimage_allows_roof_access =
248 slot_data.contains("pilgrimage_allows_roof_access") &&
249 slot_data["pilgrimage_allows_roof_access"].get<int>() == 1;
250 pilgrimage_allows_paintings =
251 slot_data.contains("pilgrimage_allows_paintings") &&
252 slot_data["pilgrimage_allows_paintings"].get<int>() == 1;
243 sunwarp_access = slot_data["sunwarp_access"].get<SunwarpAccess>(); 253 sunwarp_access = slot_data["sunwarp_access"].get<SunwarpAccess>();
244 254
245 if (painting_shuffle && slot_data.contains("painting_entrance_to_exit")) { 255 if (painting_shuffle && slot_data.contains("painting_entrance_to_exit")) {
@@ -454,6 +464,14 @@ bool AP_HasEarlyColorHallways() { return GetState().early_color_hallways; }
454 464
455bool AP_IsPilgrimageEnabled() { return GetState().pilgrimage_enabled; } 465bool AP_IsPilgrimageEnabled() { return GetState().pilgrimage_enabled; }
456 466
467bool AP_DoesPilgrimageAllowRoofAccess() {
468 return GetState().pilgrimage_allows_roof_access;
469}
470
471bool AP_DoesPilgrimageAllowPaintings() {
472 return GetState().pilgrimage_allows_paintings;
473}
474
457SunwarpAccess AP_GetSunwarpAccess() { return GetState().sunwarp_access; } 475SunwarpAccess AP_GetSunwarpAccess() { return GetState().sunwarp_access; }
458 476
459bool AP_HasReachedGoal() { return GetState().HasReachedGoal(); } 477bool AP_HasReachedGoal() { return GetState().HasReachedGoal(); }
diff --git a/src/ap_state.h b/src/ap_state.h index e3c2d7f..e1f34c7 100644 --- a/src/ap_state.h +++ b/src/ap_state.h
@@ -10,11 +10,26 @@ class TrackerFrame;
10 10
11enum DoorShuffleMode { kNO_DOORS = 0, kSIMPLE_DOORS = 1, kCOMPLEX_DOORS = 2 }; 11enum DoorShuffleMode { kNO_DOORS = 0, kSIMPLE_DOORS = 1, kCOMPLEX_DOORS = 2 };
12 12
13enum VictoryCondition { kTHE_END = 0, kTHE_MASTER = 1, kLEVEL_2 = 2, kPILGRIMAGE = 3 }; 13enum VictoryCondition {
14 14 kTHE_END = 0,
15enum LocationChecks { kNORMAL_LOCATIONS = 0, kREDUCED_LOCATIONS = 1, kPANELSANITY = 2 }; 15 kTHE_MASTER = 1,
16 16 kLEVEL_2 = 2,
17enum SunwarpAccess { kSUNWARP_ACCESS_NORMAL = 0, kSUNWARP_ACCESS_DISABLED = 1, kSUNWARP_ACCESS_UNLOCK = 2, kSUNWARP_ACCESS_PROGRESSIVE = 3 }; 17 kPILGRIMAGE = 3
18};
19
20enum LocationChecks {
21 kNORMAL_LOCATIONS = 0,
22 kREDUCED_LOCATIONS = 1,
23 kPANELSANITY = 2
24};
25
26enum SunwarpAccess {
27 kSUNWARP_ACCESS_NORMAL = 0,
28 kSUNWARP_ACCESS_DISABLED = 1,
29 kSUNWARP_ACCESS_UNLOCK = 2,
30 kSUNWARP_ACCESS_INDIVIDUAL = 3,
31 kSUNWARP_ACCESS_PROGRESSIVE = 4
32};
18 33
19void AP_SetTrackerFrame(TrackerFrame* tracker_frame); 34void AP_SetTrackerFrame(TrackerFrame* tracker_frame);
20 35
@@ -48,6 +63,10 @@ bool AP_HasEarlyColorHallways();
48 63
49bool AP_IsPilgrimageEnabled(); 64bool AP_IsPilgrimageEnabled();
50 65
66bool AP_DoesPilgrimageAllowRoofAccess();
67
68bool AP_DoesPilgrimageAllowPaintings();
69
51SunwarpAccess AP_GetSunwarpAccess(); 70SunwarpAccess AP_GetSunwarpAccess();
52 71
53bool AP_HasReachedGoal(); 72bool AP_HasReachedGoal();
diff --git a/src/game_data.cpp b/src/game_data.cpp index 28ca598..75c5b7e 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -58,6 +58,8 @@ struct GameData {
58 58
59 std::map<LingoColor, int> ap_id_by_color_; 59 std::map<LingoColor, int> ap_id_by_color_;
60 60
61 std::vector<int> sunwarp_doors_;
62
61 bool loaded_area_data_ = false; 63 bool loaded_area_data_ = false;
62 std::set<std::string> malconfigured_areas_; 64 std::set<std::string> malconfigured_areas_;
63 65
@@ -125,6 +127,11 @@ struct GameData {
125 exit_obj.type = EntranceType::kWarp; 127 exit_obj.type = EntranceType::kWarp;
126 } 128 }
127 129
130 if (rooms_[from_room_id].name == "Crossroads" &&
131 rooms_[room_id].name == "Roof") {
132 exit_obj.type == EntranceType::kCrossroadsRoofAccess;
133 }
134
128 rooms_[from_room_id].exits.push_back(exit_obj); 135 rooms_[from_room_id].exits.push_back(exit_obj);
129 }; 136 };
130 137
@@ -401,6 +408,14 @@ struct GameData {
401 doors_[door_id].exclude_reduce = 408 doors_[door_id].exclude_reduce =
402 !door_it.second["include_reduce"].as<bool>(); 409 !door_it.second["include_reduce"].as<bool>();
403 } 410 }
411
412 if (doors_[door_id].name.ends_with(" Sunwarp")) {
413 sunwarp_doors_.push_back(door_id);
414 doors_[door_id].type = DoorType::kSunwarp;
415 } else if (doors_[door_id].item_name ==
416 "Pilgrim Room - Sun Painting") {
417 doors_[door_id].type = DoorType::kSunPainting;
418 }
404 } 419 }
405 } 420 }
406 421
@@ -667,3 +682,7 @@ const std::vector<int> &GD_GetAchievementPanels() {
667int GD_GetItemIdForColor(LingoColor color) { 682int GD_GetItemIdForColor(LingoColor color) {
668 return GetState().ap_id_by_color_.at(color); 683 return GetState().ap_id_by_color_.at(color);
669} 684}
685
686const std::vector<int> &GD_GetSunwarpDoors() {
687 return GetState().sunwarp_doors_;
688}
diff --git a/src/game_data.h b/src/game_data.h index 2c18588..16d006c 100644 --- a/src/game_data.h +++ b/src/game_data.h
@@ -29,6 +29,13 @@ enum class EntranceType {
29 kSunwarp, 29 kSunwarp,
30 kWarp, 30 kWarp,
31 kPilgrimage, 31 kPilgrimage,
32 kCrossroadsRoofAccess,
33};
34
35enum class DoorType {
36 kNormal,
37 kSunwarp,
38 kSunPainting,
32}; 39};
33 40
34struct Panel { 41struct Panel {
@@ -69,6 +76,7 @@ struct Door {
69 int ap_item_id = -1; 76 int ap_item_id = -1;
70 int group_ap_item_id = -1; 77 int group_ap_item_id = -1;
71 int ap_location_id = -1; 78 int ap_location_id = -1;
79 DoorType type = DoorType::kNormal;
72}; 80};
73 81
74struct Exit { 82struct Exit {
@@ -120,5 +128,6 @@ const Panel& GD_GetPanel(int panel_id);
120int GD_GetRoomForPainting(const std::string& painting_id); 128int GD_GetRoomForPainting(const std::string& painting_id);
121const std::vector<int>& GD_GetAchievementPanels(); 129const std::vector<int>& GD_GetAchievementPanels();
122int GD_GetItemIdForColor(LingoColor color); 130int GD_GetItemIdForColor(LingoColor color);
131const std::vector<int>& GD_GetSunwarpDoors();
123 132
124#endif /* end of include guard: GAME_DATA_H_9C42AC51 */ 133#endif /* end of include guard: GAME_DATA_H_9C42AC51 */
diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index cc941ef..5a99254 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp
@@ -24,9 +24,12 @@ TrackerState& GetState() {
24 return *instance; 24 return *instance;
25} 25}
26 26
27class StateCalculator;
28
27struct StateCalculatorOptions { 29struct StateCalculatorOptions {
28 std::string start = "Menu"; 30 std::string start = "Menu";
29 bool pilgrimage = false; 31 bool pilgrimage = false;
32 StateCalculator* parent = nullptr;
30}; 33};
31 34
32class StateCalculator { 35class StateCalculator {
@@ -136,15 +139,43 @@ class StateCalculator {
136 139
137 const std::set<int>& GetReachableRooms() const { return reachable_rooms_; } 140 const std::set<int>& GetReachableRooms() const { return reachable_rooms_; }
138 141
142 const std::map<int, Decision>& GetDoorDecisions() const { return door_decisions_; }
143
139 const std::set<int>& GetSolveablePanels() const { return solveable_panels_; } 144 const std::set<int>& GetSolveablePanels() const { return solveable_panels_; }
140 145
141 private: 146 private:
142 Decision IsDoorReachable(int door_id) { 147 Decision IsNonGroupedDoorReachable(const Door& door_obj) {
148 bool has_item = AP_HasItem(door_obj.ap_item_id);
149
150 if (!has_item) {
151 for (const ProgressiveRequirement& prog_req : door_obj.progressives) {
152 if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) {
153 has_item = true;
154 break;
155 }
156 }
157 }
158
159 return has_item ? kYes : kNo;
160 }
161
162 Decision IsDoorReachable_Helper(int door_id) {
143 const Door& door_obj = GD_GetDoor(door_id); 163 const Door& door_obj = GD_GetDoor(door_id);
144 164
145 if (!AP_IsPilgrimageEnabled() && 165 if (!AP_IsPilgrimageEnabled() && door_obj.type == DoorType::kSunPainting) {
146 door_obj.item_name == "Pilgrim Room - Sun Painting") {
147 return AP_HasItem(door_obj.ap_item_id) ? kYes : kNo; 166 return AP_HasItem(door_obj.ap_item_id) ? kYes : kNo;
167 } else if (door_obj.type == DoorType::kSunwarp) {
168 switch (AP_GetSunwarpAccess()) {
169 case kSUNWARP_ACCESS_NORMAL:
170 return kYes;
171 case kSUNWARP_ACCESS_DISABLED:
172 return kNo;
173 case kSUNWARP_ACCESS_UNLOCK:
174 return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo;
175 case kSUNWARP_ACCESS_INDIVIDUAL:
176 case kSUNWARP_ACCESS_PROGRESSIVE:
177 return IsNonGroupedDoorReachable(door_obj);
178 }
148 } else if (AP_GetDoorShuffleMode() == kNO_DOORS || door_obj.skip_item) { 179 } else if (AP_GetDoorShuffleMode() == kNO_DOORS || door_obj.skip_item) {
149 if (!reachable_rooms_.count(door_obj.room)) { 180 if (!reachable_rooms_.count(door_obj.room)) {
150 return kMaybe; 181 return kMaybe;
@@ -161,19 +192,25 @@ class StateCalculator {
161 !door_obj.group_name.empty()) { 192 !door_obj.group_name.empty()) {
162 return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo; 193 return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo;
163 } else { 194 } else {
164 bool has_item = AP_HasItem(door_obj.ap_item_id); 195 return IsNonGroupedDoorReachable(door_obj);
196 }
197 }
165 198
166 if (!has_item) { 199 Decision IsDoorReachable(int door_id) {
167 for (const ProgressiveRequirement& prog_req : door_obj.progressives) { 200 if (options_.parent) {
168 if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) { 201 return options_.parent->IsDoorReachable(door_id);
169 has_item = true; 202 }
170 break;
171 }
172 }
173 }
174 203
175 return has_item ? kYes : kNo; 204 if (door_decisions_.count(door_id)) {
205 return door_decisions_.at(door_id);
176 } 206 }
207
208 Decision result = IsDoorReachable_Helper(door_id);
209 if (result != kMaybe) {
210 door_decisions_[door_id] = result;
211 }
212
213 return result;
177 } 214 }
178 215
179 Decision IsPanelReachable(int panel_id) { 216 Decision IsPanelReachable(int panel_id) {
@@ -258,6 +295,15 @@ class StateCalculator {
258 return kNo; 295 return kNo;
259 } 296 }
260 297
298 if (AP_GetSunwarpAccess() != kSUNWARP_ACCESS_NORMAL) {
299 for (int door_id : GD_GetSunwarpDoors()) {
300 Decision sub_decision = IsDoorReachable(door_id);
301 if (sub_decision != kYes) {
302 return sub_decision;
303 }
304 }
305 }
306
261 static const std::vector<std::tuple<std::string, std::string>> 307 static const std::vector<std::tuple<std::string, std::string>>
262 pilgrimage_pairs = { 308 pilgrimage_pairs = {
263 {"Crossroads", "Hot Crusts Area"}, 309 {"Crossroads", "Hot Crusts Area"},
@@ -268,7 +314,7 @@ class StateCalculator {
268 314
269 for (const auto& [from_room, to_room] : pilgrimage_pairs) { 315 for (const auto& [from_room, to_room] : pilgrimage_pairs) {
270 StateCalculator pilgrimage_calculator( 316 StateCalculator pilgrimage_calculator(
271 {.start = from_room, .pilgrimage = true}); 317 {.start = from_room, .pilgrimage = true, .parent = this});
272 pilgrimage_calculator.Calculate(); 318 pilgrimage_calculator.Calculate();
273 319
274 if (!pilgrimage_calculator.GetReachableRooms().count( 320 if (!pilgrimage_calculator.GetReachableRooms().count(
@@ -285,6 +331,14 @@ class StateCalculator {
285 room_exit.type == EntranceType::kSunwarp) { 331 room_exit.type == EntranceType::kSunwarp) {
286 return kNo; 332 return kNo;
287 } 333 }
334 if (room_exit.type == EntranceType::kCrossroadsRoofAccess &&
335 !AP_DoesPilgrimageAllowRoofAccess()) {
336 return kNo;
337 }
338 if (room_exit.type == EntranceType::kPainting &&
339 !AP_DoesPilgrimageAllowPaintings()) {
340 return kNo;
341 }
288 } 342 }
289 343
290 if (room_exit.type == EntranceType::kSunwarp) { 344 if (room_exit.type == EntranceType::kSunwarp) {
@@ -305,6 +359,7 @@ class StateCalculator {
305 StateCalculatorOptions options_; 359 StateCalculatorOptions options_;
306 360
307 std::set<int> reachable_rooms_; 361 std::set<int> reachable_rooms_;
362 std::map<int, Decision> door_decisions_;
308 std::set<int> solveable_panels_; 363 std::set<int> solveable_panels_;
309}; 364};
310 365