#include "ap_state.h" #define HAS_STD_FILESYSTEM #define _WEBSOCKETPP_CPP11_STRICT_ #pragma comment(lib, "crypt32") #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "game_data.h" #include "tracker_frame.h" #include "tracker_state.h" constexpr int AP_MAJOR = 0; constexpr int AP_MINOR = 4; constexpr int AP_REVISION = 5; constexpr const char* CERT_STORE_PATH = "cacert.pem"; constexpr int ITEM_HANDLING = 7; // <- all namespace { struct APState { std::unique_ptr apclient; bool initialized = false; TrackerFrame* tracker_frame = nullptr; bool client_active = false; std::mutex client_mutex; bool connected = false; bool has_connection_result = false; std::string data_storage_prefix; std::list tracked_data_storage_keys; std::string victory_data_storage_key; std::map inventory; std::set checked_locations; std::map data_storage; std::optional> player_pos; DoorShuffleMode door_shuffle_mode = kNO_DOORS; bool color_shuffle = false; bool painting_shuffle = false; int mastery_requirement = 21; int level_2_requirement = 223; LocationChecks location_checks = kNORMAL_LOCATIONS; VictoryCondition victory_condition = kTHE_END; bool early_color_hallways = false; bool pilgrimage_enabled = false; bool pilgrimage_allows_roof_access = false; bool pilgrimage_allows_paintings = false; SunwarpAccess sunwarp_access = kSUNWARP_ACCESS_NORMAL; bool sunwarp_shuffle = false; std::map painting_mapping; std::set painting_codomain; std::map sunwarp_mapping; void Connect(std::string server, std::string player, std::string password) { if (!initialized) { wxLogVerbose("Initializing APState..."); std::thread([this]() { for (;;) { { std::lock_guard client_guard(client_mutex); if (apclient) { apclient->poll(); } } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } }).detach(); for (int panel_id : GD_GetAchievementPanels()) { tracked_data_storage_keys.push_back( "Achievement|" + GD_GetPanel(panel_id).achievement_name); } for (const MapArea& map_area : GD_GetMapAreas()) { for (const Location& location : map_area.locations) { tracked_data_storage_keys.push_back( "Hunt|" + std::to_string(location.ap_location_id)); } } tracked_data_storage_keys.push_back("PlayerPos"); tracked_data_storage_keys.push_back("Paintings"); initialized = true; } tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); wxLogStatus("Connecting to Archipelago server (%s)...", server); { wxLogVerbose("Destroying old AP client..."); std::lock_guard client_guard(client_mutex); if (apclient) { DestroyClient(); } std::string cert_store = ""; if (std::filesystem::exists(CERT_STORE_PATH)) { cert_store = CERT_STORE_PATH; } apclient = std::make_unique(ap_get_uuid(""), "Lingo", server, cert_store); } inventory.clear(); checked_locations.clear(); data_storage.clear(); player_pos = std::nullopt; victory_data_storage_key.clear(); door_shuffle_mode = kNO_DOORS; color_shuffle = false; painting_shuffle = false; painting_mapping.clear(); painting_codomain.clear(); mastery_requirement = 21; level_2_requirement = 223; location_checks = kNORMAL_LOCATIONS; victory_condition = kTHE_END; early_color_hallways = false; pilgrimage_enabled = false; pilgrimage_allows_roof_access = false; pilgrimage_allows_paintings = false; sunwarp_access = kSUNWARP_ACCESS_NORMAL; sunwarp_shuffle = false; sunwarp_mapping.clear();
#include "network_set.h"

void NetworkSet::Clear() {
  network_by_item_.clear();
}

void NetworkSet::AddLink(int id1, int id2) {
  if (id2 > id1) {
    // Make sure id1 < id2
    std::swap(id1, id2);
  }

  if (!network_by_item_.count(id1)) {
    network_by_item_[id1] = {};
  }
  if (!network_by_item_.count(id2)) {
    network_by_item_[id2] = {};
  }

  network_by_item_[id1].insert({id1, id2});
  network_by_item_[id2].insert({id1, id2});
}

bool NetworkSet::IsItemInNetwork(int id) const {
  return network_by_item_.count(id);
}

const std::set<std::pair<int, int>>& NetworkSet::GetNetworkGraph(int id) const {
  return network_by_item_.at(id);
}
checked_paintings.count(painting_mapping.at(painting_id))); } void RefreshTracker(bool reset) { wxLogVerbose("Refreshing display..."); RecalculateReachability(); if (reset) { tracker_frame->ResetIndicators(); } else { tracker_frame->UpdateIndicators(); } } int64_t GetItemId(const std::string& item_name) { int64_t ap_id = apclient->get_item_id(item_name); if (ap_id == APClient::INVALID_NAME_ID) { wxLogError("Could not find AP item ID for %s", item_name); } return ap_id; } std::string GetItemName(int id) { return apclient->get_item_name(id); } bool HasReachedGoal() { return data_storage.count(victory_data_storage_key) && std::any_cast(data_storage.at(victory_data_storage_key)) == 30; // CLIENT_GOAL } void DestroyClient() { client_active = false; apclient->reset(); apclient.reset(); } }; APState& GetState() { static APState* instance = new APState(); return *instance; } } // namespace void AP_SetTrackerFrame(TrackerFrame* arg) { GetState().tracker_frame = arg; } void AP_Connect(std::string server, std::string player, std::string password) { GetState().Connect(server, player, password); } bool AP_HasCheckedGameLocation(int location_id) { return GetState().HasCheckedGameLocation(location_id); } bool AP_HasCheckedHuntPanel(int location_id) { return GetState().HasCheckedHuntPanel(location_id); } bool AP_HasItem(int item_id, int quantity) { return GetState().HasItem(item_id, quantity); } std::string AP_GetItemName(int item_id) { return GetState().GetItemName(item_id); } DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; } bool AP_IsColorShuffle() { return GetState().color_shuffle; } bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; } const std::map& AP_GetPaintingMapping() { return GetState().painting_mapping; } bool AP_IsPaintingMappedTo(const std::string& painting_id) { return GetState().painting_codomain.count(painting_id); } const std::set& AP_GetCheckedPaintings() { return GetState().GetCheckedPaintings(); } bool AP_IsPaintingChecked(const std::string& painting_id) { return GetState().IsPaintingChecked(painting_id); } int AP_GetMasteryRequirement() { return GetState().mastery_requirement; } int AP_GetLevel2Requirement() { return GetState().level_2_requirement; } bool AP_IsLocationVisible(int classification) { switch (GetState().location_checks) { case kNORMAL_LOCATIONS: return classification & kLOCATION_NORMAL; case kREDUCED_LOCATIONS: return classification & kLOCATION_REDUCED; case kPANELSANITY: return classification & kLOCATION_INSANITY; default: return false; } } VictoryCondition AP_GetVictoryCondition() { return GetState().victory_condition; } bool AP_HasAchievement(const std::string& achievement_name) { return GetState().HasAchievement(achievement_name); } bool AP_HasEarlyColorHallways() { return GetState().early_color_hallways; } bool AP_IsPilgrimageEnabled() { return GetState().pilgrimage_enabled; } bool AP_DoesPilgrimageAllowRoofAccess() { return GetState().pilgrimage_allows_roof_access; } bool AP_DoesPilgrimageAllowPaintings() { return GetState().pilgrimage_allows_paintings; } SunwarpAccess AP_GetSunwarpAccess() { return GetState().sunwarp_access; } bool AP_IsSunwarpShuffle() { return GetState().sunwarp_shuffle; } const std::map& AP_GetSunwarpMapping() { return GetState().sunwarp_mapping; } bool AP_HasReachedGoal() { return GetState().HasReachedGoal(); } std::optional> AP_GetPlayerPosition() { return GetState().player_pos; }