diff options
| -rw-r--r-- | CHANGELOG.md | 34 | ||||
| -rw-r--r-- | VERSION | 2 | ||||
| -rw-r--r-- | assets/player.png | bin | 0 -> 1457 bytes | |||
| -rw-r--r-- | src/ap_state.cpp | 60 | ||||
| -rw-r--r-- | src/ap_state.h | 4 | ||||
| -rw-r--r-- | src/game_data.cpp | 4 | ||||
| -rw-r--r-- | src/tracker_panel.cpp | 32 | ||||
| -rw-r--r-- | src/tracker_panel.h | 7 | ||||
| -rw-r--r-- | src/version.h | 2 |
9 files changed, 121 insertions, 24 deletions
| diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bbde7d..8a2eff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
| @@ -1,5 +1,39 @@ | |||
| 1 | # lingo-ap-tracker Releases | 1 | # lingo-ap-tracker Releases |
| 2 | 2 | ||
| 3 | ## v0.8.0 - 2024-04-03 | ||
| 4 | |||
| 5 | - Added ability to display the player's position on the map (requires v2.1.0 of | ||
| 6 | the client). | ||
| 7 | |||
| 8 | Download: | ||
| 9 | [lingo-ap-tracker-v0.8.0-win64.zip](https://files.fourisland.com/releases/lingo-ap-tracker/lingo-ap-tracker-v0.8.0-win64.zip)<br/> | ||
| 10 | Source: [v0.8.0](https://code.fourisland.com/lingo-ap-tracker/tag/?h=v0.8.0) | ||
| 11 | |||
| 12 | ## v0.7.1 - 2024-04-01 | ||
| 13 | |||
| 14 | - Fixed an issue where door groups in simple doors mode would be ignored. | ||
| 15 | |||
| 16 | Download: | ||
| 17 | [lingo-ap-tracker-v0.7.1-win64.zip](https://files.fourisland.com/releases/lingo-ap-tracker/lingo-ap-tracker-v0.7.1-win64.zip)<br/> | ||
| 18 | Source: [v0.7.1](https://code.fourisland.com/lingo-ap-tracker/tag/?h=v0.7.1) | ||
| 19 | |||
| 20 | ## v0.7.0 - 2024-04-01 | ||
| 21 | |||
| 22 | - Compatibility update for Archipelago 0.4.5 | ||
| 23 | |||
| 24 | Download: | ||
| 25 | [lingo-ap-tracker-v0.7.0-win64.zip](https://files.fourisland.com/releases/lingo-ap-tracker/lingo-ap-tracker-v0.7.0-win64.zip)<br/> | ||
| 26 | Source: [v0.7.0](https://code.fourisland.com/lingo-ap-tracker/tag/?h=v0.7.0) | ||
| 27 | |||
| 28 | ## Initial Testing: v0.6.6 - 2024-03-07 | ||
| 29 | |||
| 30 | - The last five connections are now saved in a list so that you can easily | ||
| 31 | switch between concurrent multiworlds. | ||
| 32 | |||
| 33 | Download: | ||
| 34 | [lingo-ap-tracker-v0.6.6-win64.zip](https://files.fourisland.com/releases/lingo-ap-tracker/lingo-ap-tracker-v0.6.6-win64.zip)<br/> | ||
| 35 | Source: [v0.6.6](https://code.fourisland.com/lingo-ap-tracker/tag/?h=v0.6.6) | ||
| 36 | |||
| 3 | ## Initial Testing: v0.6.5 - 2024-02-18 | 37 | ## Initial Testing: v0.6.5 - 2024-02-18 |
| 4 | 38 | ||
| 5 | - Victory condition will now be checked off when the player reaches the goal. | 39 | - Victory condition will now be checked off when the player reaches the goal. |
| diff --git a/VERSION b/VERSION index bc21b44..4ea5caf 100644 --- a/VERSION +++ b/VERSION | |||
| @@ -1 +1 @@ | |||
| v0.6.5 \ No newline at end of file | v0.8.0 \ No newline at end of file | ||
| diff --git a/assets/player.png b/assets/player.png new file mode 100644 index 0000000..6e0cba4 --- /dev/null +++ b/assets/player.png | |||
| Binary files differ | |||
| diff --git a/src/ap_state.cpp b/src/ap_state.cpp index 1ac6575..aeed914 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | constexpr int AP_MAJOR = 0; | 28 | constexpr int AP_MAJOR = 0; |
| 29 | constexpr int AP_MINOR = 4; | 29 | constexpr int AP_MINOR = 4; |
| 30 | constexpr int AP_REVISION = 0; | 30 | constexpr int AP_REVISION = 5; |
| 31 | 31 | ||
| 32 | constexpr const char* CERT_STORE_PATH = "cacert.pem"; | 32 | constexpr const char* CERT_STORE_PATH = "cacert.pem"; |
| 33 | constexpr int ITEM_HANDLING = 7; // <- all | 33 | constexpr int ITEM_HANDLING = 7; // <- all |
| @@ -54,6 +54,7 @@ struct APState { | |||
| 54 | std::map<int64_t, int> inventory; | 54 | std::map<int64_t, int> inventory; |
| 55 | std::set<int64_t> checked_locations; | 55 | std::set<int64_t> checked_locations; |
| 56 | std::map<std::string, std::any> data_storage; | 56 | std::map<std::string, std::any> data_storage; |
| 57 | std::optional<std::tuple<int, int>> player_pos; | ||
| 57 | 58 | ||
| 58 | DoorShuffleMode door_shuffle_mode = kNO_DOORS; | 59 | DoorShuffleMode door_shuffle_mode = kNO_DOORS; |
| 59 | bool color_shuffle = false; | 60 | bool color_shuffle = false; |
| @@ -101,6 +102,8 @@ struct APState { | |||
| 101 | } | 102 | } |
| 102 | } | 103 | } |
| 103 | 104 | ||
| 105 | tracked_data_storage_keys.push_back("PlayerPos"); | ||
| 106 | |||
| 104 | initialized = true; | 107 | initialized = true; |
| 105 | } | 108 | } |
| 106 | 109 | ||
| @@ -128,6 +131,7 @@ struct APState { | |||
| 128 | inventory.clear(); | 131 | inventory.clear(); |
| 129 | checked_locations.clear(); | 132 | checked_locations.clear(); |
| 130 | data_storage.clear(); | 133 | data_storage.clear(); |
| 134 | player_pos = std::nullopt; | ||
| 131 | victory_data_storage_key.clear(); | 135 | victory_data_storage_key.clear(); |
| 132 | door_shuffle_mode = kNO_DOORS; | 136 | door_shuffle_mode = kNO_DOORS; |
| 133 | color_shuffle = false; | 137 | color_shuffle = false; |
| @@ -199,15 +203,7 @@ struct APState { | |||
| 199 | apclient->set_retrieved_handler( | 203 | apclient->set_retrieved_handler( |
| 200 | [this](const std::map<std::string, nlohmann::json>& data) { | 204 | [this](const std::map<std::string, nlohmann::json>& data) { |
| 201 | for (const auto& [key, value] : data) { | 205 | for (const auto& [key, value] : data) { |
| 202 | if (value.is_boolean()) { | 206 | HandleDataStorage(key, value); |
| 203 | data_storage[key] = value.get<bool>(); | ||
| 204 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 205 | (value.get<bool>() ? "true" : "false")); | ||
| 206 | } else if (value.is_number()) { | ||
| 207 | data_storage[key] = value.get<int>(); | ||
| 208 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 209 | std::to_string(value.get<int>())); | ||
| 210 | } | ||
| 211 | } | 207 | } |
| 212 | 208 | ||
| 213 | RefreshTracker(); | 209 | RefreshTracker(); |
| @@ -216,16 +212,7 @@ struct APState { | |||
| 216 | apclient->set_set_reply_handler([this](const std::string& key, | 212 | apclient->set_set_reply_handler([this](const std::string& key, |
| 217 | const nlohmann::json& value, | 213 | const nlohmann::json& value, |
| 218 | const nlohmann::json&) { | 214 | const nlohmann::json&) { |
| 219 | if (value.is_boolean()) { | 215 | HandleDataStorage(key, value); |
| 220 | data_storage[key] = value.get<bool>(); | ||
| 221 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 222 | (value.get<bool>() ? "true" : "false")); | ||
| 223 | } else if (value.is_number()) { | ||
| 224 | data_storage[key] = value.get<int>(); | ||
| 225 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 226 | std::to_string(value.get<int>())); | ||
| 227 | } | ||
| 228 | |||
| 229 | RefreshTracker(); | 216 | RefreshTracker(); |
| 230 | }); | 217 | }); |
| 231 | 218 | ||
| @@ -369,6 +356,35 @@ struct APState { | |||
| 369 | } | 356 | } |
| 370 | } | 357 | } |
| 371 | 358 | ||
| 359 | void HandleDataStorage(const std::string& key, const nlohmann::json& value) { | ||
| 360 | if (value.is_boolean()) { | ||
| 361 | data_storage[key] = value.get<bool>(); | ||
| 362 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 363 | (value.get<bool>() ? "true" : "false")); | ||
| 364 | } else if (value.is_number()) { | ||
| 365 | data_storage[key] = value.get<int>(); | ||
| 366 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 367 | std::to_string(value.get<int>())); | ||
| 368 | } else if (value.is_object()) { | ||
| 369 | if (key.ends_with("PlayerPos")) { | ||
| 370 | auto map_value = value.get<std::map<std::string, int>>(); | ||
| 371 | player_pos = std::tuple<int, int>(map_value["x"], map_value["z"]); | ||
| 372 | } else { | ||
| 373 | data_storage[key] = value.get<std::map<std::string, int>>(); | ||
| 374 | } | ||
| 375 | |||
| 376 | TrackerLog("Data storage " + key + " retrieved as dictionary"); | ||
| 377 | } else if (value.is_null()) { | ||
| 378 | if (key.ends_with("PlayerPos")) { | ||
| 379 | player_pos = std::nullopt; | ||
| 380 | } else { | ||
| 381 | data_storage.erase(key); | ||
| 382 | } | ||
| 383 | |||
| 384 | TrackerLog("Data storage " + key + " retrieved as null"); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 372 | bool HasCheckedGameLocation(int location_id) { | 388 | bool HasCheckedGameLocation(int location_id) { |
| 373 | return checked_locations.count(location_id); | 389 | return checked_locations.count(location_id); |
| 374 | } | 390 | } |
| @@ -498,3 +514,7 @@ const std::map<int, SunwarpMapping>& AP_GetSunwarpMapping() { | |||
| 498 | } | 514 | } |
| 499 | 515 | ||
| 500 | bool AP_HasReachedGoal() { return GetState().HasReachedGoal(); } | 516 | bool AP_HasReachedGoal() { return GetState().HasReachedGoal(); } |
| 517 | |||
| 518 | std::optional<std::tuple<int, int>> AP_GetPlayerPosition() { | ||
| 519 | return GetState().player_pos; | ||
| 520 | } | ||
| diff --git a/src/ap_state.h b/src/ap_state.h index 36694b2..6667e0d 100644 --- a/src/ap_state.h +++ b/src/ap_state.h | |||
| @@ -2,7 +2,9 @@ | |||
| 2 | #define AP_STATE_H_664A4180 | 2 | #define AP_STATE_H_664A4180 |
| 3 | 3 | ||
| 4 | #include <map> | 4 | #include <map> |
| 5 | #include <optional> | ||
| 5 | #include <string> | 6 | #include <string> |
| 7 | #include <tuple> | ||
| 6 | 8 | ||
| 7 | #include "game_data.h" | 9 | #include "game_data.h" |
| 8 | 10 | ||
| @@ -80,4 +82,6 @@ const std::map<int, SunwarpMapping>& AP_GetSunwarpMapping(); | |||
| 80 | 82 | ||
| 81 | bool AP_HasReachedGoal(); | 83 | bool AP_HasReachedGoal(); |
| 82 | 84 | ||
| 85 | std::optional<std::tuple<int, int>> AP_GetPlayerPosition(); | ||
| 86 | |||
| 83 | #endif /* end of include guard: AP_STATE_H_664A4180 */ | 87 | #endif /* end of include guard: AP_STATE_H_664A4180 */ |
| diff --git a/src/game_data.cpp b/src/game_data.cpp index d354854..c98f532 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp | |||
| @@ -350,9 +350,9 @@ struct GameData { | |||
| 350 | } | 350 | } |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | if (door_it.second["group"]) { | 353 | if (door_it.second["door_group"]) { |
| 354 | doors_[door_id].group_name = | 354 | doors_[door_id].group_name = |
| 355 | door_it.second["group"].as<std::string>(); | 355 | door_it.second["door_group"].as<std::string>(); |
| 356 | 356 | ||
| 357 | if (ids_config["door_groups"] && | 357 | if (ids_config["door_groups"] && |
| 358 | ids_config["door_groups"][doors_[door_id].group_name]) { | 358 | ids_config["door_groups"][doors_[door_id].group_name]) { |
| diff --git a/src/tracker_panel.cpp b/src/tracker_panel.cpp index daaeff7..5f9f8ea 100644 --- a/src/tracker_panel.cpp +++ b/src/tracker_panel.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | constexpr int AREA_ACTUAL_SIZE = 64; | 10 | constexpr int AREA_ACTUAL_SIZE = 64; |
| 11 | constexpr int AREA_BORDER_SIZE = 5; | 11 | constexpr int AREA_BORDER_SIZE = 5; |
| 12 | constexpr int AREA_EFFECTIVE_SIZE = AREA_ACTUAL_SIZE + AREA_BORDER_SIZE * 2; | 12 | constexpr int AREA_EFFECTIVE_SIZE = AREA_ACTUAL_SIZE + AREA_BORDER_SIZE * 2; |
| 13 | constexpr int PLAYER_SIZE = 96; | ||
| 13 | 14 | ||
| 14 | TrackerPanel::TrackerPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY) { | 15 | TrackerPanel::TrackerPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY) { |
| 15 | map_image_ = wxImage(GetAbsolutePath("assets/lingo_map.png").c_str(), | 16 | map_image_ = wxImage(GetAbsolutePath("assets/lingo_map.png").c_str(), |
| @@ -18,6 +19,12 @@ TrackerPanel::TrackerPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY) { | |||
| 18 | return; | 19 | return; |
| 19 | } | 20 | } |
| 20 | 21 | ||
| 22 | player_image_ = | ||
| 23 | wxImage(GetAbsolutePath("assets/player.png").c_str(), wxBITMAP_TYPE_PNG); | ||
| 24 | if (!player_image_.IsOk()) { | ||
| 25 | return; | ||
| 26 | } | ||
| 27 | |||
| 21 | for (const MapArea &map_area : GD_GetMapAreas()) { | 28 | for (const MapArea &map_area : GD_GetMapAreas()) { |
| 22 | AreaIndicator area; | 29 | AreaIndicator area; |
| 23 | area.area_id = map_area.id; | 30 | area.area_id = map_area.id; |
| @@ -50,6 +57,20 @@ void TrackerPanel::OnPaint(wxPaintEvent &event) { | |||
| 50 | wxPaintDC dc(this); | 57 | wxPaintDC dc(this); |
| 51 | dc.DrawBitmap(rendered_, 0, 0); | 58 | dc.DrawBitmap(rendered_, 0, 0); |
| 52 | 59 | ||
| 60 | if (AP_GetPlayerPosition().has_value()) { | ||
| 61 | // 1588, 1194 | ||
| 62 | // 14x14 -> 154x154 | ||
| 63 | double intended_x = | ||
| 64 | 1588.0 + (std::get<0>(*AP_GetPlayerPosition()) * (154.0 / 14.0)); | ||
| 65 | double intended_y = | ||
| 66 | 1194.0 + (std::get<1>(*AP_GetPlayerPosition()) * (154.0 / 14.0)); | ||
| 67 | |||
| 68 | int real_x = offset_x_ + scale_x_ * intended_x - scaled_player_.GetWidth() / 2; | ||
| 69 | int real_y = offset_y_ + scale_y_ * intended_y - scaled_player_.GetHeight() / 2; | ||
| 70 | |||
| 71 | dc.DrawBitmap(scaled_player_, real_x, real_y); | ||
| 72 | } | ||
| 73 | |||
| 53 | event.Skip(); | 74 | event.Skip(); |
| 54 | } | 75 | } |
| 55 | 76 | ||
| @@ -91,6 +112,17 @@ void TrackerPanel::Redraw() { | |||
| 91 | map_image_.Scale(final_width, final_height, wxIMAGE_QUALITY_NORMAL) | 112 | map_image_.Scale(final_width, final_height, wxIMAGE_QUALITY_NORMAL) |
| 92 | .Size(panel_size, {final_x, final_y}, 0, 0, 0)); | 113 | .Size(panel_size, {final_x, final_y}, 0, 0, 0)); |
| 93 | 114 | ||
| 115 | offset_x_ = final_x; | ||
| 116 | offset_y_ = final_y; | ||
| 117 | scale_x_ = static_cast<double>(final_width) / image_size.GetWidth(); | ||
| 118 | scale_y_ = static_cast<double>(final_height) / image_size.GetHeight(); | ||
| 119 | |||
| 120 | int player_width = PLAYER_SIZE * scale_x_; | ||
| 121 | int player_height = PLAYER_SIZE * scale_y_; | ||
| 122 | scaled_player_ = | ||
| 123 | wxBitmap(player_image_.Scale(player_width > 0 ? player_width : 1, | ||
| 124 | player_height > 0 ? player_height : 1)); | ||
| 125 | |||
| 94 | wxMemoryDC dc; | 126 | wxMemoryDC dc; |
| 95 | dc.SelectObject(rendered_); | 127 | dc.SelectObject(rendered_); |
| 96 | 128 | ||
| diff --git a/src/tracker_panel.h b/src/tracker_panel.h index 2dc034c..06ec7a0 100644 --- a/src/tracker_panel.h +++ b/src/tracker_panel.h | |||
| @@ -32,7 +32,14 @@ class TrackerPanel : public wxPanel { | |||
| 32 | void Redraw(); | 32 | void Redraw(); |
| 33 | 33 | ||
| 34 | wxImage map_image_; | 34 | wxImage map_image_; |
| 35 | wxImage player_image_; | ||
| 35 | wxBitmap rendered_; | 36 | wxBitmap rendered_; |
| 37 | wxBitmap scaled_player_; | ||
| 38 | |||
| 39 | int offset_x_ = 0; | ||
| 40 | int offset_y_ = 0; | ||
| 41 | double scale_x_ = 0; | ||
| 42 | double scale_y_ = 0; | ||
| 36 | 43 | ||
| 37 | std::vector<AreaIndicator> areas_; | 44 | std::vector<AreaIndicator> areas_; |
| 38 | }; | 45 | }; |
| diff --git a/src/version.h b/src/version.h index 62a4cd1..8c567e9 100644 --- a/src/version.h +++ b/src/version.h | |||
| @@ -35,6 +35,6 @@ std::ostream& operator<<(std::ostream& out, const Version& ver) { | |||
| 35 | return out << "v" << ver.major << "." << ver.minor << "." << ver.revision; | 35 | return out << "v" << ver.major << "." << ver.minor << "." << ver.revision; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | constexpr const Version kTrackerVersion = Version(0, 6, 5); | 38 | constexpr const Version kTrackerVersion = Version(0, 8, 0); |
| 39 | 39 | ||
| 40 | #endif /* end of include guard: VERSION_H_C757E53C */ \ No newline at end of file | 40 | #endif /* end of include guard: VERSION_H_C757E53C */ \ No newline at end of file |
