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 |