From 004fb711a86d91985d8e94e1b87089db2ac2cadc Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Tue, 16 Apr 2024 11:34:49 -0400 Subject: Support panels mode door shuffle --- CMakeLists.txt | 1 + src/ap_state.cpp | 17 ++++++- src/ap_state.h | 4 +- src/game_data.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++++------ src/game_data.h | 8 ++++ src/tracker_state.cpp | 26 ++++++++++- src/version.cpp | 5 ++ src/version.h | 4 +- 8 files changed, 167 insertions(+), 21 deletions(-) create mode 100644 src/version.cpp 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 "src/achievements_pane.cpp" "src/settings_dialog.cpp" "src/global.cpp" + "src/version.cpp" "vendor/whereami/whereami.c" ) set_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 { std::optional> player_pos; DoorShuffleMode door_shuffle_mode = kNO_DOORS; + bool group_doors = false; bool color_shuffle = false; bool painting_shuffle = false; int mastery_requirement = 21; @@ -128,6 +129,7 @@ struct APState { player_pos = std::nullopt; victory_data_storage_key.clear(); door_shuffle_mode = kNO_DOORS; + group_doors = false; color_shuffle = false; painting_shuffle = false; painting_mapping.clear(); @@ -212,6 +214,17 @@ struct APState { data_storage_prefix = "Lingo_" + std::to_string(apclient->get_player_number()) + "_"; door_shuffle_mode = slot_data["shuffle_doors"].get(); + if (slot_data.contains("group_doors")) { + group_doors = slot_data.contains("group_doors") && + slot_data["group_doors"].get() == 1; + } else { + // If group_doors doesn't exist yet, that means kPANELS_MODE is actually + // kSIMPLE_DOORS. + if (door_shuffle_mode == kPANELS_MODE) { + door_shuffle_mode = kDOORS_MODE; + group_doors = true; + } + } color_shuffle = slot_data["shuffle_colors"].get() == 1; painting_shuffle = slot_data["shuffle_paintings"].get() == 1; mastery_requirement = slot_data["mastery_achievements"].get(); @@ -346,7 +359,7 @@ struct APState { } else { data_storage.erase(key); } - + TrackerLog("Data storage " + key + " retrieved as null"); } } @@ -426,6 +439,8 @@ bool AP_HasItem(int item_id, int quantity) { DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; } +bool AP_AreDoorsGrouped() { return GetState().group_doors; } + bool AP_IsColorShuffle() { return GetState().color_shuffle; } bool 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 @@ class TrackerFrame; -enum DoorShuffleMode { kNO_DOORS = 0, kSIMPLE_DOORS = 1, kCOMPLEX_DOORS = 2 }; +enum DoorShuffleMode { kNO_DOORS = 0, kPANELS_MODE = 1, kDOORS_MODE = 2 }; enum VictoryCondition { kTHE_END = 0, kTHE_MASTER = 1, kLEVEL_2 = 2 }; @@ -28,6 +28,8 @@ bool AP_HasItem(int item_id, int quantity = 1); DoorShuffleMode AP_GetDoorShuffleMode(); +bool AP_AreDoorsGrouped(); + bool AP_IsColorShuffle(); bool 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 { std::vector rooms_; std::vector doors_; std::vector panels_; + std::vector panel_doors_; std::vector map_areas_; std::map room_by_id_; std::map door_by_id_; std::map panel_by_id_; + std::map panel_doors_by_id_; std::map area_by_id_; std::vector door_definition_order_; @@ -408,6 +410,59 @@ struct GameData { } } + if (room_it.second["panel_doors"]) { + for (const auto &panel_door_it : room_it.second["panel_doors"]) { + std::string panel_door_name = panel_door_it.first.as(); + int panel_door_id = + AddOrGetPanelDoor(rooms_[room_id].name, panel_door_name); + + for (const auto &panel_node : panel_door_it.second["panels"]) { + int panel_id = -1; + + if (panel_node.IsScalar()) { + panel_id = AddOrGetPanel(rooms_[room_id].name, + panel_node.as()); + } else { + panel_id = AddOrGetPanel(panel_node["room"].as(), + panel_node["panel"].as()); + } + + Panel &panel = panels_[panel_id]; + panel.panel_door = panel_door_id; + } + + if (ids_config["panel_doors"] && + ids_config["panel_doors"][rooms_[room_id].name] && + ids_config["panel_doors"][rooms_[room_id].name] + [panel_door_name]) { + panel_doors_[panel_door_id].ap_item_id = + ids_config["panel_doors"][rooms_[room_id].name][panel_door_name] + .as(); + } else { + std::ostringstream errmsg; + errmsg << "Missing AP item ID for panel door " + << rooms_[room_id].name << " - " << panel_door_name; + TrackerLog(errmsg.str()); + } + + if (panel_door_it.second["panel_group"]) { + std::string panel_group = + panel_door_it.second["panel_group"].as(); + + if (ids_config["panel_groups"] && + ids_config["panel_groups"][panel_group]) { + panel_doors_[panel_door_id].group_ap_item_id = + ids_config["panel_groups"][panel_group].as(); + } else { + std::ostringstream errmsg; + errmsg << "Missing AP item ID for panel door group " + << panel_group; + TrackerLog(errmsg.str()); + } + } + } + } + if (room_it.second["paintings"]) { for (const auto &painting : room_it.second["paintings"]) { std::string painting_id = painting["id"].as(); @@ -449,23 +504,47 @@ struct GameData { TrackerLog(errmsg.str()); } - int index = 1; - for (const auto &stage : progression_it.second) { - int door_id = -1; + if (progression_it.second["doors"]) { + int index = 1; + for (const auto &stage : progression_it.second["doors"]) { + int door_id = -1; + + if (stage.IsScalar()) { + door_id = + AddOrGetDoor(rooms_[room_id].name, stage.as()); + } else { + door_id = AddOrGetDoor(stage["room"].as(), + stage["door"].as()); + } - if (stage.IsScalar()) { - door_id = - AddOrGetDoor(rooms_[room_id].name, stage.as()); - } else { - door_id = AddOrGetDoor(stage["room"].as(), - stage["door"].as()); + doors_[door_id].progressives.push_back( + {.item_name = progressive_item_name, + .ap_item_id = progressive_item_id, + .quantity = index}); + index++; } + } + + if (progression_it.second["panel_doors"]) { + int index = 1; + for (const auto &stage : progression_it.second["panel_doors"]) { + int panel_door_id = -1; + + if (stage.IsScalar()) { + panel_door_id = AddOrGetPanelDoor(rooms_[room_id].name, + stage.as()); + } else { + panel_door_id = + AddOrGetPanelDoor(stage["room"].as(), + stage["panel_door"].as()); + } - doors_[door_id].progressives.push_back( - {.item_name = progressive_item_name, - .ap_item_id = progressive_item_id, - .quantity = index}); - index++; + panel_doors_[panel_door_id].progressives.push_back( + {.item_name = progressive_item_name, + .ap_item_id = progressive_item_id, + .quantity = index}); + index++; + } } } } @@ -643,6 +722,18 @@ struct GameData { return panel_by_id_[full_name]; } + int AddOrGetPanelDoor(std::string room, std::string panel) { + std::string full_name = room + " - " + panel; + + if (!panel_doors_by_id_.count(full_name)) { + int panel_door_id = panel_doors_.size(); + panel_doors_by_id_[full_name] = panel_door_id; + panel_doors_.push_back({}); + } + + return panel_doors_by_id_[full_name]; + } + int AddOrGetArea(std::string area) { if (!area_by_id_.count(area)) { if (loaded_area_data_) { @@ -679,6 +770,10 @@ const std::vector &GD_GetDoors() { return GetState().doors_; } const Door &GD_GetDoor(int door_id) { return GetState().doors_.at(door_id); } +const PanelDoor &GD_GetPanelDoor(int panel_door_id) { + return GetState().panel_doors_.at(panel_door_id); +} + const Panel &GD_GetPanel(int panel_id) { return GetState().panels_.at(panel_id); } 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 { bool non_counting = false; int ap_location_id = -1; bool hunt = false; + int panel_door = -1; }; struct ProgressiveRequirement { @@ -63,6 +64,12 @@ struct Door { int ap_location_id = -1; }; +struct PanelDoor { + int ap_item_id = -1; + int group_ap_item_id = -1; + std::vector progressives; +}; + struct Exit { int destination_room; std::optional door; @@ -108,6 +115,7 @@ const Room& GD_GetRoom(int room_id); const std::vector& GD_GetDoors(); const Door& GD_GetDoor(int door_id); const Panel& GD_GetPanel(int panel_id); +const PanelDoor& GD_GetPanelDoor(int panel_door_id); int GD_GetRoomForPainting(const std::string& painting_id); const std::vector& GD_GetAchievementPanels(); int 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, const std::set& solveable_panels) { const Door& door_obj = GD_GetDoor(door_id); - if (AP_GetDoorShuffleMode() == kNO_DOORS || door_obj.skip_item) { + if (AP_GetDoorShuffleMode() != kDOORS_MODE || door_obj.skip_item) { if (!reachable_rooms.count(door_obj.room)) { return kMaybe; } @@ -41,7 +41,7 @@ Decision IsDoorReachable_Helper(int door_id, } return kYes; - } else if (AP_GetDoorShuffleMode() == kSIMPLE_DOORS && + } else if (AP_GetDoorShuffleMode() == kDOORS_MODE && AP_AreDoorsGrouped() && !door_obj.group_name.empty()) { return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo; } else { @@ -136,6 +136,28 @@ Decision IsPanelReachable_Helper(int panel_id, } } + if (panel_obj.panel_door != -1 && AP_GetDoorShuffleMode() == kPANELS_MODE) { + const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_obj.panel_door); + + if (AP_AreDoorsGrouped() && panel_door_obj.group_ap_item_id != -1) { + return AP_HasItem(panel_door_obj.group_ap_item_id) ? kYes : kNo; + } else { + bool has_item = AP_HasItem(panel_door_obj.ap_item_id); + + if (!has_item) { + for (const ProgressiveRequirement& prog_req : + panel_door_obj.progressives) { + if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) { + has_item = true; + break; + } + } + } + + return has_item ? kYes : kNo; + } + } + return kYes; } 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 @@ +#include "version.h" + +std::ostream& operator<<(std::ostream& out, const Version& ver) { + return out << "v" << ver.major << "." << ver.minor << "." << ver.revision; +} 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 { } }; -std::ostream& operator<<(std::ostream& out, const Version& ver) { - return out << "v" << ver.major << "." << ver.minor << "." << ver.revision; -} +std::ostream& operator<<(std::ostream& out, const Version& ver); constexpr const Version kTrackerVersion = Version(0, 8, 0); -- cgit 1.4.1 From 37f78b958c98d6707d84eaf0e3854282a37b6644 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sat, 27 Apr 2024 12:49:51 -0400 Subject: Fixed merge errors --- src/tracker_state.cpp | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index d3dde0d..0d9a9cd 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp @@ -212,7 +212,7 @@ class StateCalculator { } return kYes; - } else if ((AP_GetDoorShuffleMode() == kDOORS_MODE && AP_AreDoorsGrouped() && + } else if (AP_GetDoorShuffleMode() == kDOORS_MODE && AP_AreDoorsGrouped() && !door_obj.group_name.empty()) { return AP_HasItem(door_obj.group_ap_item_id) ? kYes : kNo; } else { @@ -302,33 +302,34 @@ class StateCalculator { } } - if (AP_IsColorShuffle()) { - for (LingoColor color : panel_obj.colors) { - if (!AP_HasItem(GD_GetItemIdForColor(color))) { - return kNo; + if (AP_IsColorShuffle()) { + for (LingoColor color : panel_obj.colors) { + if (!AP_HasItem(GD_GetItemIdForColor(color))) { + return kNo; + } } } - } - if (panel_obj.panel_door != -1 && AP_GetDoorShuffleMode() == kPANELS_MODE) { - const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_obj.panel_door); + if (panel_obj.panel_door != -1 && AP_GetDoorShuffleMode() == kPANELS_MODE) { + const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_obj.panel_door); - if (AP_AreDoorsGrouped() && panel_door_obj.group_ap_item_id != -1) { - return AP_HasItem(panel_door_obj.group_ap_item_id) ? kYes : kNo; - } else { - bool has_item = AP_HasItem(panel_door_obj.ap_item_id); + if (AP_AreDoorsGrouped() && panel_door_obj.group_ap_item_id != -1) { + return AP_HasItem(panel_door_obj.group_ap_item_id) ? kYes : kNo; + } else { + bool has_item = AP_HasItem(panel_door_obj.ap_item_id); - if (!has_item) { - for (const ProgressiveRequirement& prog_req : - panel_door_obj.progressives) { - if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) { - has_item = true; - break; + if (!has_item) { + for (const ProgressiveRequirement& prog_req : + panel_door_obj.progressives) { + if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) { + has_item = true; + break; + } } } - } - return has_item ? kYes : kNo; + return has_item ? kYes : kNo; + } } return kYes; -- cgit 1.4.1 From 63d11be5961c0a5647af8f2c411aa2f3ca58e5b6 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sun, 9 Jun 2024 23:50:35 -0400 Subject: Revert subway map crashing on hover before connect --- src/tracker_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index c475fb7..fb143f8 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp @@ -672,5 +672,5 @@ bool IsPaintingReachable(int painting_id) { const std::map& GetDoorRequirements(int door_id) { std::lock_guard reachability_guard(GetState().reachability_mutex); - return GetState().door_reports.at(door_id); + return GetState().door_reports[door_id]; } -- cgit 1.4.1 From 6676e8fda6c58a93ae9d5cea0c4ad622a77305be Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sun, 9 Jun 2024 23:50:54 -0400 Subject: Fix panels game data error reporting --- src/game_data.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/game_data.cpp b/src/game_data.cpp index 1ccf511..759eb0c 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp @@ -455,10 +455,8 @@ struct GameData { ids_config["panel_doors"][rooms_[room_id].name][panel_door_name] .as(); } else { - std::ostringstream errmsg; - errmsg << "Missing AP item ID for panel door " - << rooms_[room_id].name << " - " << panel_door_name; - TrackerLog(errmsg.str()); + wxLogError("Missing AP item ID for panel door %s - %s", + rooms_[room_id].name, panel_door_name); } if (panel_door_it.second["panel_group"]) { @@ -470,10 +468,8 @@ struct GameData { panel_doors_[panel_door_id].group_ap_item_id = ids_config["panel_groups"][panel_group].as(); } else { - std::ostringstream errmsg; - errmsg << "Missing AP item ID for panel door group " - << panel_group; - TrackerLog(errmsg.str()); + wxLogError("Missing AP item ID for panel door group %s", + panel_group); } } } -- cgit 1.4.1 From 2944687cbbaa53d0815fea9f5f2506500e2e1db3 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sun, 9 Jun 2024 23:52:14 -0400 Subject: Fix panel door reachability calculation --- src/tracker_state.cpp | 69 ++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index fb143f8..eaf3e6b 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp @@ -15,11 +15,12 @@ namespace { struct Requirements { bool disabled = false; - std::set doors; // non-grouped, handles progressive - std::set items; // all other items - std::set rooms; // maybe - bool mastery = false; // maybe - bool panel_hunt = false; // maybe + std::set doors; // non-grouped, handles progressive + std::set panel_doors; // non-grouped, handles progressive + std::set items; // all other items + std::set rooms; // maybe + bool mastery = false; // maybe + bool panel_hunt = false; // maybe void Merge(const Requirements& rhs) { if (rhs.disabled) { @@ -29,6 +30,9 @@ struct Requirements { for (int id : rhs.doors) { doors.insert(id); } + for (int id : rhs.panel_doors) { + panel_doors.insert(id); + } for (int id : rhs.items) { items.insert(id); } @@ -74,15 +78,14 @@ class RequirementCalculator { requirements.doors.insert(door_obj.id); break; } - } else if (AP_GetDoorShuffleMode() == kNO_DOORS || door_obj.skip_item) { + } else if (AP_GetDoorShuffleMode() != kDOORS_MODE || door_obj.skip_item) { requirements.rooms.insert(door_obj.room); for (int panel_id : door_obj.panels) { const Requirements& panel_reqs = GetPanel(panel_id); requirements.Merge(panel_reqs); } - } else if (AP_GetDoorShuffleMode() == kSIMPLE_DOORS && - !door_obj.group_name.empty()) { + } else if (AP_AreDoorsGrouped() && !door_obj.group_name.empty()) { requirements.items.insert(door_obj.group_ap_item_id); } else { requirements.doors.insert(door_obj.id); @@ -129,6 +132,17 @@ class RequirementCalculator { requirements.items.insert(GD_GetItemIdForColor(color)); } } + + if (panel_obj.panel_door != -1 && + AP_GetDoorShuffleMode() == kPANELS_MODE) { + const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_obj.panel_door); + + if (panel_door_obj.group_ap_item_id != -1 && AP_AreDoorsGrouped()) { + requirements.items.insert(panel_door_obj.group_ap_item_id); + } else { + requirements.panel_doors.insert(panel_obj.panel_door); + } + } panels_[panel_id] = requirements; } @@ -337,7 +351,8 @@ class StateCalculator { } private: - Decision IsNonGroupedDoorReachable(const Door& door_obj) { + template + Decision IsNonGroupedDoorReachable(const T& door_obj) { bool has_item = AP_HasItem(door_obj.ap_item_id); if (!has_item) { @@ -373,6 +388,20 @@ class StateCalculator { } } + for (int panel_door_id : reqs.panel_doors) { + const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_door_id); + Decision decision = IsNonGroupedDoorReachable(panel_door_obj); + + if (report) { + (*report)[AP_GetItemName(panel_door_obj.ap_item_id)] = + (decision == kYes); + } + + if (decision != kYes) { + final_decision = decision; + } + } + for (int item_id : reqs.items) { bool has_item = AP_HasItem(item_id); if (report) { @@ -486,28 +515,6 @@ class StateCalculator { return IsDoorReachable(*painting.door); } - if (panel_obj.panel_door != -1 && AP_GetDoorShuffleMode() == kPANELS_MODE) { - const PanelDoor& panel_door_obj = GD_GetPanelDoor(panel_obj.panel_door); - - if (AP_AreDoorsGrouped() && panel_door_obj.group_ap_item_id != -1) { - return AP_HasItem(panel_door_obj.group_ap_item_id) ? kYes : kNo; - } else { - bool has_item = AP_HasItem(panel_door_obj.ap_item_id); - - if (!has_item) { - for (const ProgressiveRequirement& prog_req : - panel_door_obj.progressives) { - if (AP_HasItem(prog_req.ap_item_id, prog_req.quantity)) { - has_item = true; - break; - } - } - } - - return has_item ? kYes : kNo; - } - } - return kYes; } -- cgit 1.4.1 From 378766bcee3cad04256ada937f96b232aba85cf3 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Wed, 24 Jul 2024 09:40:06 -0400 Subject: TrackerLog usage --- src/game_data.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game_data.cpp b/src/game_data.cpp index 39ea360..ec8d8f5 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp @@ -456,8 +456,8 @@ struct GameData { ids_config["panel_doors"][rooms_[room_id].name][panel_door_name] .as(); } else { - wxLogError("Missing AP item ID for panel door %s - %s", - rooms_[room_id].name, panel_door_name); + TrackerLog(fmt::format("Missing AP item ID for panel door {} - {}", + rooms_[room_id].name, panel_door_name)); } if (panel_door_it.second["panel_group"]) { @@ -469,8 +469,8 @@ struct GameData { panel_doors_[panel_door_id].group_ap_item_id = ids_config["panel_groups"][panel_group].as(); } else { - wxLogError("Missing AP item ID for panel door group %s", - panel_group); + TrackerLog(fmt::format( + "Missing AP item ID for panel door group {}", panel_group)); } } } -- cgit 1.4.1