about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/ap_state.cpp17
-rw-r--r--src/ap_state.h4
-rw-r--r--src/game_data.cpp123
-rw-r--r--src/game_data.h8
-rw-r--r--src/tracker_state.cpp26
-rw-r--r--src/version.cpp5
-rw-r--r--src/version.h4
8 files changed, 167 insertions, 21 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index a6f6342..f857096 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -43,6 +43,7 @@ add_executable(lingo_ap_tracker
43 "src/achievements_pane.cpp" 43 "src/achievements_pane.cpp"
44 "src/settings_dialog.cpp" 44 "src/settings_dialog.cpp"
45 "src/global.cpp" 45 "src/global.cpp"
46 "src/version.cpp"
46 "vendor/whereami/whereami.c" 47 "vendor/whereami/whereami.c"
47) 48)
48set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 20) 49set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 20)
diff --git a/src/ap_state.cpp b/src/ap_state.cpp index 58670e6..62c9f3f 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp
@@ -57,6 +57,7 @@ struct APState {
57 std::optional<std::tuple<int, int>> player_pos; 57 std::optional<std::tuple<int, int>> player_pos;
58 58
59 DoorShuffleMode door_shuffle_mode = kNO_DOORS; 59 DoorShuffleMode door_shuffle_mode = kNO_DOORS;
60 bool group_doors = false;
60 bool color_shuffle = false; 61 bool color_shuffle = false;
61 bool painting_shuffle = false; 62 bool painting_shuffle = false;
62 int mastery_requirement = 21; 63 int mastery_requirement = 21;
@@ -128,6 +129,7 @@ struct APState {
128 player_pos = std::nullopt; 129 player_pos = std::nullopt;
129 victory_data_storage_key.clear(); 130 victory_data_storage_key.clear();
130 door_shuffle_mode = kNO_DOORS; 131 door_shuffle_mode = kNO_DOORS;
132 group_doors = false;
131 color_shuffle = false; 133 color_shuffle = false;
132 painting_shuffle = false; 134 painting_shuffle = false;
133 painting_mapping.clear(); 135 painting_mapping.clear();
@@ -212,6 +214,17 @@ struct APState {
212 data_storage_prefix = 214 data_storage_prefix =
213 "Lingo_" + std::to_string(apclient->get_player_number()) + "_"; 215 "Lingo_" + std::to_string(apclient->get_player_number()) + "_";
214 door_shuffle_mode = slot_data["shuffle_doors"].get<DoorShuffleMode>(); 216 door_shuffle_mode = slot_data["shuffle_doors"].get<DoorShuffleMode>();
217 if (slot_data.contains("group_doors")) {
218 group_doors = slot_data.contains("group_doors") &&
219 slot_data["group_doors"].get<int>() == 1;
220 } else {
221 // If group_doors doesn't exist yet, that means kPANELS_MODE is actually
222 // kSIMPLE_DOORS.
223 if (door_shuffle_mode == kPANELS_MODE) {
224 door_shuffle_mode = kDOORS_MODE;
225 group_doors = true;
226 }
227 }
215 color_shuffle = slot_data["shuffle_colors"].get<int>() == 1; 228 color_shuffle = slot_data["shuffle_colors"].get<int>() == 1;
216 painting_shuffle = slot_data["shuffle_paintings"].get<int>() == 1; 229 painting_shuffle = slot_data["shuffle_paintings"].get<int>() == 1;
217 mastery_requirement = slot_data["mastery_achievements"].get<int>(); 230 mastery_requirement = slot_data["mastery_achievements"].get<int>();
@@ -346,7 +359,7 @@ struct APState {
346 } else { 359 } else {
347 data_storage.erase(key); 360 data_storage.erase(key);
348 } 361 }
349 362
350 TrackerLog("Data storage " + key + " retrieved as null"); 363 TrackerLog("Data storage " + key + " retrieved as null");
351 } 364 }
352 } 365 }
@@ -426,6 +439,8 @@ bool AP_HasItem(int item_id, int quantity) {
426 439
427DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; } 440DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; }
428 441
442bool AP_AreDoorsGrouped() { return GetState().group_doors; }
443
429bool AP_IsColorShuffle() { return GetState().color_shuffle; } 444bool AP_IsColorShuffle() { return GetState().color_shuffle; }
430 445
431bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; } 446bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; }
diff --git a/src/ap_state.h b/src/ap_state.h index 420a032..5c37b56 100644 --- a/src/ap_state.h +++ b/src/ap_state.h
@@ -10,7 +10,7 @@
10 10
11class TrackerFrame; 11class TrackerFrame;
12 12
13enum DoorShuffleMode { kNO_DOORS = 0, kSIMPLE_DOORS = 1, kCOMPLEX_DOORS = 2 }; 13enum DoorShuffleMode { kNO_DOORS = 0, kPANELS_MODE = 1, kDOORS_MODE = 2 };
14 14
15enum VictoryCondition { kTHE_END = 0, kTHE_MASTER = 1, kLEVEL_2 = 2 }; 15enum VictoryCondition { kTHE_END = 0, kTHE_MASTER = 1, kLEVEL_2 = 2 };
16 16
@@ -28,6 +28,8 @@ bool AP_HasItem(int item_id, int quantity = 1);
28 28
29DoorShuffleMode AP_GetDoorShuffleMode(); 29DoorShuffleMode AP_GetDoorShuffleMode();
30 30
31bool AP_AreDoorsGrouped();
32
31bool AP_IsColorShuffle(); 33bool AP_IsColorShuffle();
32 34
33bool AP_IsPaintingShuffle(); 35bool AP_IsPaintingShuffle();
diff --git a/src/game_data.cpp b/src/game_data.cpp index ee818c4..eece8d7 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -43,11 +43,13 @@ struct GameData {
43 std::vector<Room> rooms_; 43 std::vector<Room> rooms_;
44 std::vector<Door> doors_; 44 std::vector<Door> doors_;
45 std::vector<Panel> panels_; 45 std::vector<Panel> panels_;
46 std::vector<PanelDoor> panel_doors_;
46 std::vector<MapArea> map_areas_; 47 std::vector<MapArea> map_areas_;
47 48
48 std::map<std::string, int> room_by_id_; 49 std::map<std::string, int> room_by_id_;
49 std::map<std::string, int> door_by_id_; 50 std::map<std::string, int> door_by_id_;
50 std::map<std::string, int> panel_by_id_; 51 std::map<std::string, int> panel_by_id_;
52 std::map<std::string, int> panel_doors_by_id_;
51 std::map<std::string, int> area_by_id_; 53 std::map<std::string, int> area_by_id_;
52 54
53 std::vector<int> door_definition_order_; 55 std::vector<int> door_definition_order_;
@@ -408,6 +410,59 @@ struct GameData {
408 } 410 }
409 } 411 }
410 412
413 if (room_it.second["panel_doors"]) {
414 for (const auto &panel_door_it : room_it.second["panel_doors"]) {
415 std::string panel_door_name = panel_door_it.first.as<std::string>();
416 int panel_door_id =
417 AddOrGetPanelDoor(rooms_[room_id].name, panel_door_name);
418
419 for (const auto &panel_node : panel_door_it.second["panels"]) {
420 int panel_id = -1;
421
422 if (panel_node.IsScalar()) {
423 panel_id = AddOrGetPanel(rooms_[room_id].name,
424 panel_node.as<std::string>());
425 } else {
426 panel_id = AddOrGetPanel(panel_node["room"].as<std::string>(),
427 panel_node["panel"].as<std::string>());
428 }
429
430 Panel &panel = panels_[panel_id];
431 panel.panel_door = panel_door_id;
432 }
433
434 if (ids_config["panel_doors"] &&
435 ids_config["panel_doors"][rooms_[room_id].name] &&
436 ids_config["panel_doors"][rooms_[room_id].name]
437 [panel_door_name]) {
438 panel_doors_[panel_door_id].ap_item_id =
439 ids_config["panel_doors"][rooms_[room_id].name][panel_door_name]
440 .as<int>();
441 } else {
442 std::ostringstream errmsg;
443 errmsg << "Missing AP item ID for panel door "
444 << rooms_[room_id].name << " - " << panel_door_name;
445 TrackerLog(errmsg.str());
446 }
447
448 if (panel_door_it.second["panel_group"]) {
449 std::string panel_group =
450 panel_door_it.second["panel_group"].as<std::string>();
451
452 if (ids_config["panel_groups"] &&
453 ids_config["panel_groups"][panel_group]) {
454 panel_doors_[panel_door_id].group_ap_item_id =
455 ids_config["panel_groups"][panel_group].as<int>();
456 } else {
457 std::ostringstream errmsg;
458 errmsg << "Missing AP item ID for panel door group "
459 << panel_group;
460 TrackerLog(errmsg.str());
461 }
462 }
463 }
464 }
465
411 if (room_it.second["paintings"]) { 466 if (room_it.second["paintings"]) {
412 for (const auto &painting : room_it.second["paintings"]) { 467 for (const auto &painting : room_it.second["paintings"]) {
413 std::string painting_id = painting["id"].as<std::string>(); 468 std::string painting_id = painting["id"].as<std::string>();
@@ -449,23 +504,47 @@ struct GameData {
449 TrackerLog(errmsg.str()); 504 TrackerLog(errmsg.str());
450 } 505 }
451 506
452 int index = 1; 507 if (progression_it.second["doors"]) {
453 for (const auto &stage : progression_it.second) { 508 int index = 1;
454 int door_id = -1; 509 for (const auto &stage : progression_it.second["doors"]) {
510 int door_id = -1;
511
512 if (stage.IsScalar()) {
513 door_id =
514 AddOrGetDoor(rooms_[room_id].name, stage.as<std::string>());
515 } else {
516 door_id = AddOrGetDoor(stage["room"].as<std::string>(),
517 stage["door"].as<std::string>());
518 }
455 519
456 if (stage.IsScalar()) { 520 doors_[door_id].progressives.push_back(
457 door_id = 521 {.item_name = progressive_item_name,
458 AddOrGetDoor(rooms_[room_id].name, stage.as<std::string>()); 522 .ap_item_id = progressive_item_id,
459 } else { 523 .quantity = index});
460 door_id = AddOrGetDoor(stage["room"].as<std::string>(), 524 index++;
461 stage["door"].as<std::string>());
462 } 525 }
526 }
527
528 if (progression_it.second["panel_doors"]) {
529 int index = 1;
530 for (const auto &stage : progression_it.second["panel_doors"]) {
531 int panel_door_id = -1;
532
533 if (stage.IsScalar()) {
534 panel_door_id = AddOrGetPanelDoor(rooms_[room_id].name,
535 stage.as<std::string>());
536 } else {
537 panel_door_id =
538 AddOrGetPanelDoor(stage["room"].as<std::string>(),
539 stage["panel_door"].as<std::string>());
540 }
463 541
464 doors_[door_id].progressives.push_back( 542 panel_doors_[panel_door_id].progressives.push_back(
465 {.item_name = progressive_item_name, 543 {.item_name = progressive_item_name,
466 .ap_item_id = progressive_item_id, 544 .ap_item_id = progressive_item_id,
467 .quantity = index}); 545 .quantity = index});
468 index++; 546 index++;
547 }
469 } 548 }
470 } 549 }
471 } 550 }
@@ -643,6 +722,18 @@ struct GameData {
643 return panel_by_id_[full_name]; 722 return panel_by_id_[full_name];
644 } 723 }
645 724
725 int AddOrGetPanelDoor(std::string room, std::string panel) {
726 std::string full_name = room + " - " + panel;
727
728 if (!panel_doors_by_id_.count(full_name)) {
729 int panel_door_id = panel_doors_.size();
730 panel_doors_by_id_[full_name] = panel_door_id;
731 panel_doors_.push_back({});
732 }
733
734 return panel_doors_by_id_[full_name];
735 }
736
646 int AddOrGetArea(std::string area) { 737 int AddOrGetArea(std::string area) {
647 if (!area_by_id_.count(area)) { 738 if (!area_by_id_.count(area)) {
648 if (loaded_area_data_) { 739 if (loaded_area_data_) {
@@ -679,6 +770,10 @@ const std::vector<Door> &GD_GetDoors() { return GetState().doors_; }
679 770
680const Door &GD_GetDoor(int door_id) { return GetState().doors_.at(door_id); } 771const Door &GD_GetDoor(int door_id) { return GetState().doors_.at(door_id); }
681 772
773const PanelDoor &GD_GetPanelDoor(int panel_door_id) {
774 return GetState().panel_doors_.at(panel_door_id);
775}
776
682const Panel &GD_GetPanel(int panel_id) { 777const Panel &GD_GetPanel(int panel_id) {
683 return GetState().panels_.at(panel_id); 778 return GetState().panels_.at(panel_id);
684} 779}
diff --git a/src/game_data.h b/src/game_data.h index 8a38264..aa5ac19 100644 --- a/src/game_data.h +++ b/src/game_data.h
@@ -38,6 +38,7 @@ struct Panel {
38 bool non_counting = false; 38 bool non_counting = false;
39 int ap_location_id = -1; 39 int ap_location_id = -1;
40 bool hunt = false; 40 bool hunt = false;
41 int panel_door = -1;
41}; 42};
42 43
43struct ProgressiveRequirement { 44struct ProgressiveRequirement {
@@ -63,6 +64,12 @@ struct Door {
63 int ap_location_id = -1; 64 int ap_location_id = -1;
64}; 65};
65 66
67struct PanelDoor {
68 int ap_item_id = -1;
69 int group_ap_item_id = -1;
70 std::vector<ProgressiveRequirement> progressives;
71};
72
66struct Exit { 73struct Exit {
67 int destination_room; 74 int destination_room;
68 std::optional<int> door; 75 std::optional<int> door;
@@ -108,6 +115,7 @@ const Room& GD_GetRoom(int room_id);
108const std::vector<Door>& GD_GetDoors(); 115const std::vector<Door>& GD_GetDoors();
109const Door& GD_GetDoor(int door_id); 116const Door& GD_GetDoor(int door_id);
110const Panel& GD_GetPanel(int panel_id); 117const Panel& GD_GetPanel(int panel_id);
118const PanelDoor& GD_GetPanelDoor(int panel_door_id);
111int GD_GetRoomForPainting(const std::string& painting_id); 119int GD_GetRoomForPainting(const std::string& painting_id);
112const std::vector<int>& GD_GetAchievementPanels(); 120const std::vector<int>& GD_GetAchievementPanels();
113int GD_GetItemIdForColor(LingoColor color); 121int GD_GetItemIdForColor(LingoColor color);
diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index e02ee14..9d2c6d1 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp
@@ -29,7 +29,7 @@ Decision IsDoorReachable_Helper(int door_id,
29 const std::set<int>& solveable_panels) { 29 const std::set<int>& solveable_panels) {
30 const Door& door_obj = GD_GetDoor(door_id); 30 const Door& door_obj = GD_GetDoor(door_id);
31 31
32 if (AP_GetDoorShuffleMode() == kNO_DOORS || door_obj.skip_item) { 32 if (AP_GetDoorShuffleMode() != kDOORS_MODE || door_obj.skip_item) {
33 if (!reachable_rooms.count(door_obj.room)) { 33 if (!reachable_rooms.count(door_obj.room)) {
34 return kMaybe; 34 return kMaybe;
35 } 35 }
@@ -41,7 +41,7 @@ Decision IsDoorReachable_Helper(int door_id,
41 } 41 }
42 42
43 return kYes; 43 return kYes;
44 } else if (AP_GetDoorShuffleMode() == kSIMPLE_DOORS && 44 } else if (AP_GetDoorShuffleMode() == kDOORS_MODE && AP_AreDoorsGrouped() &&
45 !door_obj.group_name.empty()) { 45 !door_obj.group_name.empty()) {
46 return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo; 46 return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo;
47 } else { 47 } else {
@@ -136,6 +136,28 @@ Decision IsPanelReachable_Helper(int panel_id,
136 } 136 }
137 } 137 }
138 138
139 if (panel_obj.panel_door != -1 && AP_GetDoorShuffleMode() == kPANELS_MODE) {
140 const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_obj.panel_door);
141
142 if (AP_AreDoorsGrouped() && panel_door_obj.group_ap_item_id != -1) {
143 return AP_HasItem(panel_door_obj.group_ap_item_id) ? kYes : kNo;
144 } else {
145 bool has_item = AP_HasItem(panel_door_obj.ap_item_id);
146
147 if (!has_item) {
148 for (const ProgressiveRequirement& prog_req :
149 panel_door_obj.progressives) {
150 if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) {
151 has_item = true;
152 break;
153 }
154 }
155 }
156
157 return has_item ? kYes : kNo;
158 }
159 }
160
139 return kYes; 161 return kYes;
140} 162}
141 163
diff --git a/src/version.cpp b/src/version.cpp new file mode 100644 index 0000000..3b4d5f3 --- /dev/null +++ b/src/version.cpp
@@ -0,0 +1,5 @@
1#include "version.h"
2
3std::ostream& operator<<(std::ostream& out, const Version& ver) {
4 return out << "v" << ver.major << "." << ver.minor << "." << ver.revision;
5}
diff --git a/src/version.h b/src/version.h index 8c567e9..859fc69 100644 --- a/src/version.h +++ b/src/version.h
@@ -31,9 +31,7 @@ struct Version {
31 } 31 }
32}; 32};
33 33
34std::ostream& operator<<(std::ostream& out, const Version& ver) { 34std::ostream& operator<<(std::ostream& out, const Version& ver);
35 return out << "v" << ver.major << "." << ver.minor << "." << ver.revision;
36}
37 35
38constexpr const Version kTrackerVersion = Version(0, 8, 0); 36constexpr const Version kTrackerVersion = Version(0, 8, 0);
39 37