diff options
| author | Star Rauchenberger <fefferburbia@gmail.com> | 2024-04-03 14:33:30 -0400 |
|---|---|---|
| committer | Star Rauchenberger <fefferburbia@gmail.com> | 2024-04-03 14:33:30 -0400 |
| commit | 3037b9305b10b58e01055c21bbce223d7b2c673f (patch) | |
| tree | ebe7d5c88906c45b0b494955aef21e0a7756fa49 | |
| parent | e57195bfd9d84a571e8fa11998af5065848b4360 (diff) | |
| download | lingo-ap-tracker-3037b9305b10b58e01055c21bbce223d7b2c673f.tar.gz lingo-ap-tracker-3037b9305b10b58e01055c21bbce223d7b2c673f.tar.bz2 lingo-ap-tracker-3037b9305b10b58e01055c21bbce223d7b2c673f.zip | |
Added player position tracking
| -rw-r--r-- | assets/player.png | bin | 0 -> 1457 bytes | |||
| -rw-r--r-- | src/ap_state.cpp | 58 | ||||
| -rw-r--r-- | src/ap_state.h | 4 | ||||
| -rw-r--r-- | src/tracker_panel.cpp | 32 | ||||
| -rw-r--r-- | src/tracker_panel.h | 7 |
5 files changed, 82 insertions, 19 deletions
| 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 8134cdb..58670e6 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp | |||
| @@ -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; |
| @@ -95,6 +96,8 @@ struct APState { | |||
| 95 | } | 96 | } |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 99 | tracked_data_storage_keys.push_back("PlayerPos"); | ||
| 100 | |||
| 98 | initialized = true; | 101 | initialized = true; |
| 99 | } | 102 | } |
| 100 | 103 | ||
| @@ -122,6 +125,7 @@ struct APState { | |||
| 122 | inventory.clear(); | 125 | inventory.clear(); |
| 123 | checked_locations.clear(); | 126 | checked_locations.clear(); |
| 124 | data_storage.clear(); | 127 | data_storage.clear(); |
| 128 | player_pos = std::nullopt; | ||
| 125 | victory_data_storage_key.clear(); | 129 | victory_data_storage_key.clear(); |
| 126 | door_shuffle_mode = kNO_DOORS; | 130 | door_shuffle_mode = kNO_DOORS; |
| 127 | color_shuffle = false; | 131 | color_shuffle = false; |
| @@ -187,15 +191,7 @@ struct APState { | |||
| 187 | apclient->set_retrieved_handler( | 191 | apclient->set_retrieved_handler( |
| 188 | [this](const std::map<std::string, nlohmann::json>& data) { | 192 | [this](const std::map<std::string, nlohmann::json>& data) { |
| 189 | for (const auto& [key, value] : data) { | 193 | for (const auto& [key, value] : data) { |
| 190 | if (value.is_boolean()) { | 194 | HandleDataStorage(key, value); |
| 191 | data_storage[key] = value.get<bool>(); | ||
| 192 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 193 | (value.get<bool>() ? "true" : "false")); | ||
| 194 | } else if (value.is_number()) { | ||
| 195 | data_storage[key] = value.get<int>(); | ||
| 196 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 197 | std::to_string(value.get<int>())); | ||
| 198 | } | ||
| 199 | } | 195 | } |
| 200 | 196 | ||
| 201 | RefreshTracker(); | 197 | RefreshTracker(); |
| @@ -204,16 +200,7 @@ struct APState { | |||
| 204 | apclient->set_set_reply_handler([this](const std::string& key, | 200 | apclient->set_set_reply_handler([this](const std::string& key, |
| 205 | const nlohmann::json& value, | 201 | const nlohmann::json& value, |
| 206 | const nlohmann::json&) { | 202 | const nlohmann::json&) { |
| 207 | if (value.is_boolean()) { | 203 | HandleDataStorage(key, value); |
| 208 | data_storage[key] = value.get<bool>(); | ||
| 209 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 210 | (value.get<bool>() ? "true" : "false")); | ||
| 211 | } else if (value.is_number()) { | ||
| 212 | data_storage[key] = value.get<int>(); | ||
| 213 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 214 | std::to_string(value.get<int>())); | ||
| 215 | } | ||
| 216 | |||
| 217 | RefreshTracker(); | 204 | RefreshTracker(); |
| 218 | }); | 205 | }); |
| 219 | 206 | ||
| @@ -335,6 +322,35 @@ struct APState { | |||
| 335 | } | 322 | } |
| 336 | } | 323 | } |
| 337 | 324 | ||
| 325 | void HandleDataStorage(const std::string& key, const nlohmann::json& value) { | ||
| 326 | if (value.is_boolean()) { | ||
| 327 | data_storage[key] = value.get<bool>(); | ||
| 328 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 329 | (value.get<bool>() ? "true" : "false")); | ||
| 330 | } else if (value.is_number()) { | ||
| 331 | data_storage[key] = value.get<int>(); | ||
| 332 | TrackerLog("Data storage " + key + " retrieved as " + | ||
| 333 | std::to_string(value.get<int>())); | ||
| 334 | } else if (value.is_object()) { | ||
| 335 | if (key.ends_with("PlayerPos")) { | ||
| 336 | auto map_value = value.get<std::map<std::string, int>>(); | ||
| 337 | player_pos = std::tuple<int, int>(map_value["x"], map_value["z"]); | ||
| 338 | } else { | ||
| 339 | data_storage[key] = value.get<std::map<std::string, int>>(); | ||
| 340 | } | ||
| 341 | |||
| 342 | TrackerLog("Data storage " + key + " retrieved as dictionary"); | ||
| 343 | } else if (value.is_null()) { | ||
| 344 | if (key.ends_with("PlayerPos")) { | ||
| 345 | player_pos = std::nullopt; | ||
| 346 | } else { | ||
| 347 | data_storage.erase(key); | ||
| 348 | } | ||
| 349 | |||
| 350 | TrackerLog("Data storage " + key + " retrieved as null"); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 338 | bool HasCheckedGameLocation(int location_id) { | 354 | bool HasCheckedGameLocation(int location_id) { |
| 339 | return checked_locations.count(location_id); | 355 | return checked_locations.count(location_id); |
| 340 | } | 356 | } |
| @@ -446,3 +462,7 @@ bool AP_HasAchievement(const std::string& achievement_name) { | |||
| 446 | bool AP_HasEarlyColorHallways() { return GetState().early_color_hallways; } | 462 | bool AP_HasEarlyColorHallways() { return GetState().early_color_hallways; } |
| 447 | 463 | ||
| 448 | bool AP_HasReachedGoal() { return GetState().HasReachedGoal(); } | 464 | bool AP_HasReachedGoal() { return GetState().HasReachedGoal(); } |
| 465 | |||
| 466 | std::optional<std::tuple<int, int>> AP_GetPlayerPosition() { | ||
| 467 | return GetState().player_pos; | ||
| 468 | } | ||
| diff --git a/src/ap_state.h b/src/ap_state.h index cc51a78..420a032 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 | ||
| @@ -46,4 +48,6 @@ bool AP_HasEarlyColorHallways(); | |||
| 46 | 48 | ||
| 47 | bool AP_HasReachedGoal(); | 49 | bool AP_HasReachedGoal(); |
| 48 | 50 | ||
| 51 | std::optional<std::tuple<int, int>> AP_GetPlayerPosition(); | ||
| 52 | |||
| 49 | #endif /* end of include guard: AP_STATE_H_664A4180 */ | 53 | #endif /* end of include guard: AP_STATE_H_664A4180 */ |
| 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 cb4f082..b26d971 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 | }; |
