about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/ap_state.cpp15
-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, 166 insertions, 20 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 8feb78b..4fd241a 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;
@@ -134,6 +135,7 @@ struct APState {
134 player_pos = std::nullopt; 135 player_pos = std::nullopt;
135 victory_data_storage_key.clear(); 136 victory_data_storage_key.clear();
136 door_shuffle_mode = kNO_DOORS; 137 door_shuffle_mode = kNO_DOORS;
138 group_doors = false;
137 color_shuffle = false; 139 color_shuffle = false;
138 painting_shuffle = false; 140 painting_shuffle = false;
139 painting_mapping.clear(); 141 painting_mapping.clear();
@@ -224,6 +226,17 @@ struct APState {
224 data_storage_prefix = 226 data_storage_prefix =
225 "Lingo_" + std::to_string(apclient->get_player_number()) + "_"; 227 "Lingo_" + std::to_string(apclient->get_player_number()) + "_";
226 door_shuffle_mode = slot_data["shuffle_doors"].get<DoorShuffleMode>(); 228 door_shuffle_mode = slot_data["shuffle_doors"].get<DoorShuffleMode>();
229 if (slot_data.contains("group_doors")) {
230 group_doors = slot_data.contains("group_doors") &&
231 slot_data["group_doors"].get<int>() == 1;
232 } else {
233 // If group_doors doesn't exist yet, that means kPANELS_MODE is actually
234 // kSIMPLE_DOORS.
235 if (door_shuffle_mode == kPANELS_MODE) {
236 door_shuffle_mode = kDOORS_MODE;
237 group_doors = true;
238 }
239 }
227 color_shuffle = slot_data["shuffle_colors"].get<int>() == 1; 240 color_shuffle = slot_data["shuffle_colors"].get<int>() == 1;
228 painting_shuffle = slot_data["shuffle_paintings"].get<int>() == 1; 241 painting_shuffle = slot_data["shuffle_paintings"].get<int>() == 1;
229 mastery_requirement = slot_data["mastery_achievements"].get<int>(); 242 mastery_requirement = slot_data["mastery_achievements"].get<int>();
@@ -463,6 +476,8 @@ bool AP_HasItem(int item_id, int quantity) {
463 476
464DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; } 477DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; }
465 478
479bool AP_AreDoorsGrouped() { return GetState().group_doors; }
480
466bool AP_IsColorShuffle() { return GetState().color_shuffle; } 481bool AP_IsColorShuffle() { return GetState().color_shuffle; }
467 482
468bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; } 483bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; }
diff --git a/src/ap_state.h b/src/ap_state.h index 6667e0d..c514489 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 { 15enum VictoryCondition {
16 kTHE_END = 0, 16 kTHE_END = 0,
@@ -50,6 +50,8 @@ bool AP_HasItem(int item_id, int quantity = 1);
50 50
51DoorShuffleMode AP_GetDoorShuffleMode(); 51DoorShuffleMode AP_GetDoorShuffleMode();
52 52
53bool AP_AreDoorsGrouped();
54
53bool AP_IsColorShuffle(); 55bool AP_IsColorShuffle();
54 56
55bool AP_IsPaintingShuffle(); 57bool AP_IsPaintingShuffle();
diff --git a/src/game_data.cpp b/src/game_data.cpp index c98f532..0567623 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_;
@@ -421,6 +423,59 @@ struct GameData {
421 } 423 }
422 } 424 }
423 425
426 if (room_it.second["panel_doors"]) {
427 for (const auto &panel_door_it : room_it.second["panel_doors"]) {
428 std::string panel_door_name = panel_door_it.first.as<std::string>();
429 int panel_door_id =
430 AddOrGetPanelDoor(rooms_[room_id].name, panel_door_name);
431
432 for (const auto &panel_node : panel_door_it.second["panels"]) {
433 int panel_id = -1;
434
435 if (panel_node.IsScalar()) {
436 panel_id = AddOrGetPanel(rooms_[room_id].name,
437 panel_node.as<std::string>());
438 } else {
439 panel_id = AddOrGetPanel(panel_node["room"].as<std::string>(),
440 panel_node["panel"].as<std::string>());
441 }
442
443 Panel &panel = panels_[panel_id];
444 panel.panel_door = panel_door_id;
445 }
446
447 if (ids_config["panel_doors"] &&
448 ids_config["panel_doors"][rooms_[room_id].name] &&
449 ids_config["panel_doors"][rooms_[room_id].name]
450 [panel_door_name]) {
451 panel_doors_[panel_door_id].ap_item_id =
452 ids_config["panel_doors"][rooms_[room_id].name][panel_door_name]
453 .as<int>();
454 } else {
455 std::ostringstream errmsg;
456 errmsg << "Missing AP item ID for panel door "
457 << rooms_[room_id].name << " - " << panel_door_name;
458 TrackerLog(errmsg.str());
459 }
460
461 if (panel_door_it.second["panel_group"]) {
462 std::string panel_group =
463 panel_door_it.second["panel_group"].as<std::string>();
464
465 if (ids_config["panel_groups"] &&
466 ids_config["panel_groups"][panel_group]) {
467 panel_doors_[panel_door_id].group_ap_item_id =
468 ids_config["panel_groups"][panel_group].as<int>();
469 } else {
470 std::ostringstream errmsg;
471 errmsg << "Missing AP item ID for panel door group "
472 << panel_group;
473 TrackerLog(errmsg.str());
474 }
475 }
476 }
477 }
478
424 if (room_it.second["paintings"]) { 479 if (room_it.second["paintings"]) {
425 for (const auto &painting : room_it.second["paintings"]) { 480 for (const auto &painting : room_it.second["paintings"]) {
426 std::string painting_id = painting["id"].as<std::string>(); 481 std::string painting_id = painting["id"].as<std::string>();
@@ -474,23 +529,47 @@ struct GameData {
474 TrackerLog(errmsg.str()); 529 TrackerLog(errmsg.str());
475 } 530 }
476 531
477 int index = 1; 532 if (progression_it.second["doors"]) {
478 for (const auto &stage : progression_it.second) { 533 int index = 1;
479 int door_id = -1; 534 for (const auto &stage : progression_it.second["doors"]) {
535 int door_id = -1;
536
537 if (stage.IsScalar()) {
538 door_id =
539 AddOrGetDoor(rooms_[room_id].name, stage.as<std::string>());
540 } else {
541 door_id = AddOrGetDoor(stage["room"].as<std::string>(),
542 stage["door"].as<std::string>());
543 }
480 544
481 if (stage.IsScalar()) { 545 doors_[door_id].progressives.push_back(
482 door_id = 546 {.item_name = progressive_item_name,
483 AddOrGetDoor(rooms_[room_id].name, stage.as<std::string>()); 547 .ap_item_id = progressive_item_id,
484 } else { 548 .quantity = index});
485 door_id = AddOrGetDoor(stage["room"].as<std::string>(), 549 index++;
486 stage["door"].as<std::string>());
487 } 550 }
551 }
552
553 if (progression_it.second["panel_doors"]) {
554 int index = 1;
555 for (const auto &stage : progression_it.second["panel_doors"]) {
556 int panel_door_id = -1;
557
558 if (stage.IsScalar()) {
559 panel_door_id = AddOrGetPanelDoor(rooms_[room_id].name,
560 stage.as<std::string>());
561 } else {
562 panel_door_id =
563 AddOrGetPanelDoor(stage["room"].as<std::string>(),
564 stage["panel_door"].as<std::string>());
565 }
488 566
489 doors_[door_id].progressives.push_back( 567 panel_doors_[panel_door_id].progressives.push_back(
490 {.item_name = progressive_item_name, 568 {.item_name = progressive_item_name,
491 .ap_item_id = progressive_item_id, 569 .ap_item_id = progressive_item_id,
492 .quantity = index}); 570 .quantity = index});
493 index++; 571 index++;
572 }
494 } 573 }
495 } 574 }
496 } 575 }
@@ -641,6 +720,18 @@ struct GameData {
641 return panel_by_id_[full_name]; 720 return panel_by_id_[full_name];
642 } 721 }
643 722
723 int AddOrGetPanelDoor(std::string room, std::string panel) {
724 std::string full_name = room + " - " + panel;
725
726 if (!panel_doors_by_id_.count(full_name)) {
727 int panel_door_id = panel_doors_.size();
728 panel_doors_by_id_[full_name] = panel_door_id;
729 panel_doors_.push_back({});
730 }
731
732 return panel_doors_by_id_[full_name];
733 }
734
644 int AddOrGetArea(std::string area) { 735 int AddOrGetArea(std::string area) {
645 if (!area_by_id_.count(area)) { 736 if (!area_by_id_.count(area)) {
646 if (loaded_area_data_) { 737 if (loaded_area_data_) {
@@ -677,6 +768,10 @@ const std::vector<Door> &GD_GetDoors() { return GetState().doors_; }
677 768
678const Door &GD_GetDoor(int door_id) { return GetState().doors_.at(door_id); } 769const Door &GD_GetDoor(int door_id) { return GetState().doors_.at(door_id); }
679 770
771const PanelDoor &GD_GetPanelDoor(int panel_door_id) {
772 return GetState().panel_doors_.at(panel_door_id);
773}
774
680int GD_GetDoorByName(const std::string &name) { 775int GD_GetDoorByName(const std::string &name) {
681 return GetState().door_by_id_.at(name); 776 return GetState().door_by_id_.at(name);
682} 777}
diff --git a/src/game_data.h b/src/game_data.h index cd09627..09824d7 100644 --- a/src/game_data.h +++ b/src/game_data.h
@@ -53,6 +53,7 @@ struct Panel {
53 bool non_counting = false; 53 bool non_counting = false;
54 int ap_location_id = -1; 54 int ap_location_id = -1;
55 bool hunt = false; 55 bool hunt = false;
56 int panel_door = -1;
56}; 57};
57 58
58struct ProgressiveRequirement { 59struct ProgressiveRequirement {
@@ -79,6 +80,12 @@ struct Door {
79 DoorType type = DoorType::kNormal; 80 DoorType type = DoorType::kNormal;
80}; 81};
81 82
83struct PanelDoor {
84 int ap_item_id = -1;
85 int group_ap_item_id = -1;
86 std::vector<ProgressiveRequirement> progressives;
87};
88
82struct Exit { 89struct Exit {
83 int destination_room; 90 int destination_room;
84 std::optional<int> door; 91 std::optional<int> door;
@@ -126,6 +133,7 @@ const std::vector<Door>& GD_GetDoors();
126const Door& GD_GetDoor(int door_id); 133const Door& GD_GetDoor(int door_id);
127int GD_GetDoorByName(const std::string& name); 134int GD_GetDoorByName(const std::string& name);
128const Panel& GD_GetPanel(int panel_id); 135const Panel& GD_GetPanel(int panel_id);
136const PanelDoor& GD_GetPanelDoor(int panel_door_id);
129int GD_GetRoomForPainting(const std::string& painting_id); 137int GD_GetRoomForPainting(const std::string& painting_id);
130const std::vector<int>& GD_GetAchievementPanels(); 138const std::vector<int>& GD_GetAchievementPanels();
131int GD_GetItemIdForColor(LingoColor color); 139int GD_GetItemIdForColor(LingoColor color);
diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index 640a159..1881513 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp
@@ -199,7 +199,7 @@ class StateCalculator {
199 case kSUNWARP_ACCESS_PROGRESSIVE: 199 case kSUNWARP_ACCESS_PROGRESSIVE:
200 return IsNonGroupedDoorReachable(door_obj); 200 return IsNonGroupedDoorReachable(door_obj);
201 } 201 }
202 } else if (AP_GetDoorShuffleMode() == kNO_DOORS || door_obj.skip_item) { 202 } else if (AP_GetDoorShuffleMode() != kDOORS_MODE || door_obj.skip_item) {
203 if (!reachable_rooms_.count(door_obj.room)) { 203 if (!reachable_rooms_.count(door_obj.room)) {
204 return kMaybe; 204 return kMaybe;
205 } 205 }
@@ -211,7 +211,7 @@ class StateCalculator {
211 } 211 }
212 212
213 return kYes; 213 return kYes;
214 } else if (AP_GetDoorShuffleMode() == kSIMPLE_DOORS && 214 } else if (AP_GetDoorShuffleMode() == kDOORS_MODE && AP_AreDoorsGrouped() &&
215 !door_obj.group_name.empty()) { 215 !door_obj.group_name.empty()) {
216 return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo; 216 return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo;
217 } else { 217 } else {
@@ -309,6 +309,28 @@ class StateCalculator {
309 } 309 }
310 } 310 }
311 311
312 if (panel_obj.panel_door != -1 && AP_GetDoorShuffleMode() == kPANELS_MODE) {
313 const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_obj.panel_door);
314
315 if (AP_AreDoorsGrouped() && panel_door_obj.group_ap_item_id != -1) {
316 return AP_HasItem(panel_door_obj.group_ap_item_id) ? kYes : kNo;
317 } else {
318 bool has_item = AP_HasItem(panel_door_obj.ap_item_id);
319
320 if (!has_item) {
321 for (const ProgressiveRequirement& prog_req :
322 panel_door_obj.progressives) {
323 if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) {
324 has_item = true;
325 break;
326 }
327 }
328 }
329
330 return has_item ? kYes : kNo;
331 }
332 }
333
312 return kYes; 334 return kYes;
313 } 335 }
314 336
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 805dc2d..db75351 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, 9, 0); 36constexpr const Version kTrackerVersion = Version(0, 9, 0);
39 37