From 08ffb400114029569b4043b4f4c5a3f2af9b37b8 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Wed, 3 May 2023 17:25:41 -0400 Subject: Added progressive items --- ap_state.cpp | 94 ++++++++++++++++++++++++++++++------------------------- ap_state.h | 5 +-- game_data.cpp | 33 ++++++++++++++----- game_data.h | 6 ++++ tracker_state.cpp | 13 +++++++- 5 files changed, 98 insertions(+), 53 deletions(-) diff --git a/ap_state.cpp b/ap_state.cpp index c901dce..8b7339a 100644 --- a/ap_state.cpp +++ b/ap_state.cpp @@ -4,9 +4,10 @@ #define _WEBSOCKETPP_CPP11_STRICT_ #pragma comment(lib, "crypt32") +#include + #include #include -#include #include #include #include @@ -63,11 +64,13 @@ void APState::Connect(std::string server, std::string player, has_connection_result_ = false; apclient->set_room_info_handler([this, player, password]() { + inventory_.clear(); + tracker_frame_->SetStatusMessage( "Connected to Archipelago server. Authenticating..."); apclient->ConnectSlot(player, password, ITEM_HANDLING, {"Tracker"}, - {AP_MAJOR, AP_MINOR, AP_REVISION}); + {AP_MAJOR, AP_MINOR, AP_REVISION}); }); apclient->set_location_checked_handler( @@ -81,19 +84,19 @@ void APState::Connect(std::string server, std::string player, }); apclient->set_slot_disconnected_handler([this]() { - tracker_frame_->SetStatusMessage("Disconnected from Archipelago. Attempting to reconnect..."); + tracker_frame_->SetStatusMessage( + "Disconnected from Archipelago. Attempting to reconnect..."); }); apclient->set_socket_disconnected_handler([this]() { - tracker_frame_->SetStatusMessage("Disconnected from Archipelago. Attempting to reconnect..."); + tracker_frame_->SetStatusMessage( + "Disconnected from Archipelago. Attempting to reconnect..."); }); apclient->set_items_received_handler( [this](const std::list& items) { for (const APClient::NetworkItem& item : items) { - // TODO: Progressive items. - - inventory_.insert(item.item); + inventory_[item.item]++; std::cout << "Item: " << item.item << std::endl; } @@ -110,7 +113,8 @@ void APState::Connect(std::string server, std::string player, if (painting_shuffle_ && slot_data.contains("painting_entrance_to_exit")) { painting_mapping_.clear(); - for (const auto& mapping_it : slot_data["painting_entrance_to_exit"].items()) { + for (const auto& mapping_it : + slot_data["painting_entrance_to_exit"].items()) { painting_mapping_[mapping_it.key()] = mapping_it.value(); } } @@ -119,41 +123,40 @@ void APState::Connect(std::string server, std::string player, has_connection_result_ = true; }); - apclient->set_slot_refused_handler( - [this](const std::list& errors) { - connected_ = false; - has_connection_result_ = true; - - tracker_frame_->SetStatusMessage("Disconnected from Archipelago."); - - std::vector error_messages; - error_messages.push_back("Could not connect to Archipelago."); - - for (const std::string& error : errors) { - if (error == "InvalidSlot") { - error_messages.push_back("Invalid player name."); - } else if (error == "InvalidGame") { - error_messages.push_back( - "The specified player is not playing Lingo."); - } else if (error == "IncompatibleVersion") { - error_messages.push_back( - "The Archipelago server is not the correct version for this " - "client."); - } else if (error == "InvalidPassword") { - error_messages.push_back("Incorrect password."); - } else if (error == "InvalidItemsHandling") { - error_messages.push_back( - "Invalid item handling flag. This is a bug with the tracker. " - "Please report it to the lingo-ap-tracker GitHub."); - } else { - error_messages.push_back("Unknown error."); - } - } + apclient->set_slot_refused_handler([this]( + const std::list& errors) { + connected_ = false; + has_connection_result_ = true; - std::string full_message = hatkirby::implode(error_messages, " "); + tracker_frame_->SetStatusMessage("Disconnected from Archipelago."); + + std::vector error_messages; + error_messages.push_back("Could not connect to Archipelago."); + + for (const std::string& error : errors) { + if (error == "InvalidSlot") { + error_messages.push_back("Invalid player name."); + } else if (error == "InvalidGame") { + error_messages.push_back("The specified player is not playing Lingo."); + } else if (error == "IncompatibleVersion") { + error_messages.push_back( + "The Archipelago server is not the correct version for this " + "client."); + } else if (error == "InvalidPassword") { + error_messages.push_back("Incorrect password."); + } else if (error == "InvalidItemsHandling") { + error_messages.push_back( + "Invalid item handling flag. This is a bug with the tracker. " + "Please report it to the lingo-ap-tracker GitHub."); + } else { + error_messages.push_back("Unknown error."); + } + } - wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); - }); + std::string full_message = hatkirby::implode(error_messages, " "); + + wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); + }); client_active_ = true; @@ -202,6 +205,10 @@ void APState::Connect(std::string server, std::string player, !ap_id_by_item_name_.count(door.group_name)) { ap_id_by_item_name_[door.group_name] = GetItemId(door.group_name); } + + for (const ProgressiveRequirement& prog_req : door.progressives) { + ap_id_by_item_name_[prog_req.item_name] = GetItemId(prog_req.item_name); + } } } @@ -239,9 +246,10 @@ bool APState::HasColorItem(LingoColor color) const { } } -bool APState::HasItem(const std::string& item) const { +bool APState::HasItem(const std::string& item, int quantity) const { if (ap_id_by_item_name_.count(item)) { - return inventory_.count(ap_id_by_item_name_.at(item)); + int64_t ap_id = ap_id_by_item_name_.at(item); + return inventory_.count(ap_id) && inventory_.at(ap_id) >= quantity; } else { return false; } diff --git a/ap_state.h b/ap_state.h index ce7bafc..ce73528 100644 --- a/ap_state.h +++ b/ap_state.h @@ -26,7 +26,7 @@ class APState { bool HasColorItem(LingoColor color) const; - bool HasItem(const std::string& item) const; + bool HasItem(const std::string& item, int quantity = 1) const; DoorShuffleMode GetDoorShuffleMode() const { return door_shuffle_mode_; } @@ -53,12 +53,13 @@ class APState { bool connected_ = false; bool has_connection_result_ = false; - std::set inventory_; + std::map inventory_; std::set checked_locations_; std::map, int64_t> ap_id_by_location_id_; std::map ap_id_by_item_name_; std::map ap_id_by_color_; + std::map progressive_item_by_ap_id_; DoorShuffleMode door_shuffle_mode_ = kNO_DOORS; bool color_shuffle_ = false; diff --git a/game_data.cpp b/game_data.cpp index 2f8f505..9b31f89 100644 --- a/game_data.cpp +++ b/game_data.cpp @@ -235,7 +235,7 @@ GameData::GameData() { } if (room_it.second["paintings"]) { - for (const auto& painting : room_it.second["paintings"]) { + for (const auto &painting : room_it.second["paintings"]) { std::string painting_id = painting["id"].as(); room_by_painting_[painting_id] = room_id; @@ -250,14 +250,36 @@ GameData::GameData() { } painting_exit.door = AddOrGetDoor( - rd_room, - painting["required_door"]["door"].as()); + rd_room, painting["required_door"]["door"].as()); } room_obj.paintings.push_back(painting_exit); } } } + + if (room_it.second["progression"]) { + for (const auto &progression_it : room_it.second["progression"]) { + std::string progressive_item_name = + progression_it.first.as(); + + int index = 1; + for (const auto &stage : progression_it.second) { + int door_id = -1; + + if (stage.IsScalar()) { + door_id = AddOrGetDoor(room_obj.name, stage.as()); + } else { + door_id = AddOrGetDoor(stage["room"].as(), + stage["door"].as()); + } + + doors_[door_id].progressives.push_back( + {.item_name = progressive_item_name, .quantity = index}); + index++; + } + } + } } map_areas_.reserve(areas_config.size()); @@ -341,10 +363,7 @@ int GameData::AddOrGetDoor(std::string room, std::string door) { if (!door_by_id_.count(full_name)) { door_by_id_[full_name] = doors_.size(); - doors_.push_back({ - .room = AddOrGetRoom(room), - .name = door - }); + doors_.push_back({.room = AddOrGetRoom(room), .name = door}); } return door_by_id_[full_name]; diff --git a/game_data.h b/game_data.h index 981f56f..2df8bc5 100644 --- a/game_data.h +++ b/game_data.h @@ -30,6 +30,11 @@ struct Panel { bool exclude_reduce = false; }; +struct ProgressiveRequirement { + std::string item_name; + int quantity = 0; +}; + struct Door { int room; std::string name; @@ -40,6 +45,7 @@ struct Door { bool skip_item = false; std::vector panels; bool exclude_reduce = true; + std::vector progressives; }; struct Exit { diff --git a/tracker_state.cpp b/tracker_state.cpp index 169d301..4921d3f 100644 --- a/tracker_state.cpp +++ b/tracker_state.cpp @@ -58,7 +58,18 @@ bool IsDoorReachable_Helper(int door_id, const std::set& reachable_rooms) { !door_obj.group_name.empty()) { return GetAPState().HasItem(door_obj.group_name); } else { - return GetAPState().HasItem(door_obj.item_name); + bool has_item = GetAPState().HasItem(door_obj.item_name); + + if (!has_item) { + for (const ProgressiveRequirement& prog_req : door_obj.progressives) { + if (GetAPState().HasItem(prog_req.item_name, prog_req.quantity)) { + has_item = true; + break; + } + } + } + + return has_item; } } -- cgit 1.4.1