about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-03-13 12:47:54 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-03-13 12:47:54 -0400
commitdfddd07b8b5cbff7c09103a694aed40bda254a2d (patch)
tree220364fa26eff54d9a3fd49f1b52a8afce2bf907 /src
parentdacbe8e3fbda85f7c2e7e7b660795f2a080a9d25 (diff)
downloadlingo-ap-tracker-dfddd07b8b5cbff7c09103a694aed40bda254a2d.tar.gz
lingo-ap-tracker-dfddd07b8b5cbff7c09103a694aed40bda254a2d.tar.bz2
lingo-ap-tracker-dfddd07b8b5cbff7c09103a694aed40bda254a2d.zip
Obsolete savefile reader + IPC solves
Now, panel solve state is all read from the sync fields in datastorage. The "show hunt panels" field in settings is now a radio box, and you can choose to show all panels.
Diffstat (limited to 'src')
-rw-r--r--src/area_popup.cpp26
-rw-r--r--src/godot_variant.cpp84
-rw-r--r--src/godot_variant.h28
-rw-r--r--src/ipc_state.cpp21
-rw-r--r--src/ipc_state.h2
-rw-r--r--src/settings_dialog.cpp48
-rw-r--r--src/settings_dialog.h11
-rw-r--r--src/tracker_config.cpp8
-rw-r--r--src/tracker_config.h8
-rw-r--r--src/tracker_frame.cpp54
-rw-r--r--src/tracker_frame.h3
-rw-r--r--src/tracker_panel.cpp75
-rw-r--r--src/tracker_panel.h21
13 files changed, 72 insertions, 317 deletions
diff --git a/src/area_popup.cpp b/src/area_popup.cpp index 2c9d18d..8ec4dd1 100644 --- a/src/area_popup.cpp +++ b/src/area_popup.cpp
@@ -54,15 +54,12 @@ void AreaPopup::ResetIndicators() {
54 continue; 54 continue;
55 } 55 }
56 56
57 if (tracker_panel->IsPanelsMode()) { 57 if (!AP_IsLocationVisible(location.classification) &&
58 if (!location.single_panel) { 58 !(location.hunt &&
59 continue; 59 GetTrackerConfig().visible_panels == TrackerConfig::kHUNT_PANELS) &&
60 } 60 !(location.single_panel &&
61 } else { 61 GetTrackerConfig().visible_panels == TrackerConfig::kALL_PANELS)) {
62 if (!AP_IsLocationVisible(location.classification) && 62 continue;
63 !(location.hunt && GetTrackerConfig().show_hunt_panels)) {
64 continue;
65 }
66 } 63 }
67 64
68 indicators_.emplace_back(section_id, kLOCATION, acc_height); 65 indicators_.emplace_back(section_id, kLOCATION, acc_height);
@@ -77,7 +74,7 @@ void AreaPopup::ResetIndicators() {
77 } 74 }
78 } 75 }
79 76
80 if (AP_IsPaintingShuffle() && !tracker_panel->IsPanelsMode()) { 77 if (AP_IsPaintingShuffle()) {
81 for (int painting_id : map_area.paintings) { 78 for (int painting_id : map_area.paintings) {
82 if (IsPaintingPostgame(painting_id)) { 79 if (IsPaintingPostgame(painting_id)) {
83 continue; 80 continue;
@@ -135,16 +132,9 @@ void AreaPopup::UpdateIndicators() {
135 bool checked = false; 132 bool checked = false;
136 if (IsLocationWinCondition(location)) { 133 if (IsLocationWinCondition(location)) {
137 checked = AP_HasReachedGoal(); 134 checked = AP_HasReachedGoal();
138 } else if (tracker_panel->IsPanelsMode()) {
139 const Panel& panel = GD_GetPanel(*location.single_panel);
140 if (panel.non_counting) {
141 checked = AP_HasCheckedGameLocation(location.ap_location_id);
142 } else {
143 checked = tracker_panel->GetSolvedPanels().contains(panel.nodepath);
144 }
145 } else { 135 } else {
146 checked = AP_HasCheckedGameLocation(location.ap_location_id) || 136 checked = AP_HasCheckedGameLocation(location.ap_location_id) ||
147 (location.hunt && 137 (location.single_panel &&
148 AP_IsPanelSolved( 138 AP_IsPanelSolved(
149 GD_GetPanel(*location.single_panel).solve_index)); 139 GD_GetPanel(*location.single_panel).solve_index));
150 } 140 }
diff --git a/src/godot_variant.cpp b/src/godot_variant.cpp deleted file mode 100644 index 152b9ef..0000000 --- a/src/godot_variant.cpp +++ /dev/null
@@ -1,84 +0,0 @@
1// Godot save decoder algorithm by Chris Souvey.
2
3#include "godot_variant.h"
4
5#include <algorithm>
6#include <charconv>
7#include <cstddef>
8#include <cstdint>
9#include <fstream>
10#include <string>
11#include <tuple>
12#include <variant>
13#include <vector>
14
15namespace {
16
17uint16_t ReadUint16(std::basic_istream<char>& stream) {
18 uint16_t result;
19 stream.read(reinterpret_cast<char*>(&result), 2);
20 return result;
21}
22
23uint32_t ReadUint32(std::basic_istream<char>& stream) {
24 uint32_t result;
25 stream.read(reinterpret_cast<char*>(&result), 4);
26 return result;
27}
28
29GodotVariant ParseVariant(std::basic_istream<char>& stream) {
30 uint16_t type = ReadUint16(stream);
31 stream.ignore(2);
32
33 switch (type) {
34 case 1: {
35 // bool
36 bool boolval = (ReadUint32(stream) == 1);
37 return {boolval};
38 }
39 case 15: {
40 // nodepath
41 uint32_t name_length = ReadUint32(stream) & 0x7fffffff;
42 uint32_t subname_length = ReadUint32(stream) & 0x7fffffff;
43 uint32_t flags = ReadUint32(stream);
44
45 std::vector<std::string> result;
46 for (size_t i = 0; i < name_length + subname_length; i++) {
47 uint32_t char_length = ReadUint32(stream);
48 uint32_t padded_length = (char_length % 4 == 0)
49 ? char_length
50 : (char_length + 4 - (char_length % 4));
51 std::vector<char> next_bytes(padded_length);
52 stream.read(next_bytes.data(), padded_length);
53 std::string next_piece;
54 std::copy(next_bytes.begin(),
55 std::next(next_bytes.begin(), char_length),
56 std::back_inserter(next_piece));
57 result.push_back(next_piece);
58 }
59
60 return {result};
61 }
62 case 19: {
63 // array
64 uint32_t length = ReadUint32(stream) & 0x7fffffff;
65 std::vector<GodotVariant> result;
66 for (size_t i = 0; i < length; i++) {
67 result.push_back(ParseVariant(stream));
68 }
69 return {result};
70 }
71 default: {
72 // eh
73 return {std::monostate{}};
74 }
75 }
76}
77
78} // namespace
79
80GodotVariant ParseGodotFile(std::string filename) {
81 std::ifstream file_stream(filename, std::ios_base::binary);
82 file_stream.ignore(4);
83 return ParseVariant(file_stream);
84}
diff --git a/src/godot_variant.h b/src/godot_variant.h deleted file mode 100644 index 620e569..0000000 --- a/src/godot_variant.h +++ /dev/null
@@ -1,28 +0,0 @@
1#ifndef GODOT_VARIANT_H_ED7F2EB6
2#define GODOT_VARIANT_H_ED7F2EB6
3
4#include <string>
5#include <variant>
6#include <vector>
7
8struct GodotVariant {
9 using value_type = std::variant<std::monostate, bool, std::vector<std::string>, std::vector<GodotVariant>>;
10
11 value_type value;
12
13 GodotVariant(value_type v) : value(v) {}
14
15 bool AsBool() const { return std::get<bool>(value); }
16
17 const std::vector<std::string>& AsNodePath() const {
18 return std::get<std::vector<std::string>>(value);
19 }
20
21 const std::vector<GodotVariant>& AsArray() const {
22 return std::get<std::vector<GodotVariant>>(value);
23 }
24};
25
26GodotVariant ParseGodotFile(std::string filename);
27
28#endif /* end of include guard: GODOT_VARIANT_H_ED7F2EB6 */
diff --git a/src/ipc_state.cpp b/src/ipc_state.cpp index a99fa89..6e2a440 100644 --- a/src/ipc_state.cpp +++ b/src/ipc_state.cpp
@@ -39,7 +39,6 @@ struct IPCState {
39 std::string game_ap_user; 39 std::string game_ap_user;
40 40
41 std::optional<std::tuple<int, int>> player_position; 41 std::optional<std::tuple<int, int>> player_position;
42 std::set<std::string> solved_panels;
43 42
44 // Thread state 43 // Thread state
45 std::unique_ptr<wswrap::WS> ws; 44 std::unique_ptr<wswrap::WS> ws;
@@ -103,12 +102,6 @@ struct IPCState {
103 return player_position; 102 return player_position;
104 } 103 }
105 104
106 std::set<std::string> GetSolvedPanels() {
107 std::lock_guard state_guard(state_mutex);
108
109 return solved_panels;
110 }
111
112 private: 105 private:
113 void Thread() { 106 void Thread() {
114 for (;;) { 107 for (;;) {
@@ -134,7 +127,6 @@ struct IPCState {
134 game_ap_user.clear(); 127 game_ap_user.clear();
135 128
136 player_position = std::nullopt; 129 player_position = std::nullopt;
137 solved_panels.clear();
138 130
139 if (address.empty()) { 131 if (address.empty()) {
140 initialized = false; 132 initialized = false;
@@ -273,7 +265,6 @@ struct IPCState {
273 265
274 slot_matches = false; 266 slot_matches = false;
275 player_position = std::nullopt; 267 player_position = std::nullopt;
276 solved_panels.clear();
277 } 268 }
278 } 269 }
279 270
@@ -314,14 +305,6 @@ struct IPCState {
314 std::make_tuple<int, int>(msg["position"]["x"], msg["position"]["z"]); 305 std::make_tuple<int, int>(msg["position"]["x"], msg["position"]["z"]);
315 306
316 tracker_frame->UpdateIndicators(StateUpdate{.player_position = true}); 307 tracker_frame->UpdateIndicators(StateUpdate{.player_position = true});
317 } else if (msg["cmd"] == "SolvePanels") {
318 std::lock_guard state_guard(state_mutex);
319
320 for (std::string panel : msg["panels"]) {
321 solved_panels.insert(std::move(panel));
322 }
323
324 tracker_frame->UpdateIndicators(StateUpdate{.open_panels_tab = true});
325 } 308 }
326 } 309 }
327 310
@@ -382,7 +365,3 @@ bool IPC_IsConnected() { return GetState().IsConnected(); }
382std::optional<std::tuple<int, int>> IPC_GetPlayerPosition() { 365std::optional<std::tuple<int, int>> IPC_GetPlayerPosition() {
383 return GetState().GetPlayerPosition(); 366 return GetState().GetPlayerPosition();
384} 367}
385
386std::set<std::string> IPC_GetSolvedPanels() {
387 return GetState().GetSolvedPanels();
388}
diff --git a/src/ipc_state.h b/src/ipc_state.h index 7c9d68d..0e6fa51 100644 --- a/src/ipc_state.h +++ b/src/ipc_state.h
@@ -20,6 +20,4 @@ bool IPC_IsConnected();
20 20
21std::optional<std::tuple<int, int>> IPC_GetPlayerPosition(); 21std::optional<std::tuple<int, int>> IPC_GetPlayerPosition();
22 22
23std::set<std::string> IPC_GetSolvedPanels();
24
25#endif /* end of include guard: IPC_STATE_H_6B3B0958 */ 23#endif /* end of include guard: IPC_STATE_H_6B3B0958 */
diff --git a/src/settings_dialog.cpp b/src/settings_dialog.cpp index fa7a82f..95df577 100644 --- a/src/settings_dialog.cpp +++ b/src/settings_dialog.cpp
@@ -3,35 +3,43 @@
3#include "tracker_config.h" 3#include "tracker_config.h"
4 4
5SettingsDialog::SettingsDialog() : wxDialog(nullptr, wxID_ANY, "Settings") { 5SettingsDialog::SettingsDialog() : wxDialog(nullptr, wxID_ANY, "Settings") {
6 should_check_for_updates_box_ = new wxCheckBox( 6 wxStaticBoxSizer* main_box =
7 this, wxID_ANY, "Check for updates when the tracker opens"); 7 new wxStaticBoxSizer(wxVERTICAL, this, "General settings");
8
9 should_check_for_updates_box_ =
10 new wxCheckBox(main_box->GetStaticBox(), wxID_ANY,
11 "Check for updates when the tracker opens");
8 hybrid_areas_box_ = new wxCheckBox( 12 hybrid_areas_box_ = new wxCheckBox(
9 this, wxID_ANY, 13 main_box->GetStaticBox(), wxID_ANY,
10 "Use two colors to show that an area has partial availability"); 14 "Use two colors to show that an area has partial availability");
11 show_hunt_panels_box_ = new wxCheckBox(this, wxID_ANY, "Show hunt panels"); 15 track_position_box_ = new wxCheckBox(main_box->GetStaticBox(), wxID_ANY,
12 track_position_box_ = new wxCheckBox(this, wxID_ANY, "Track player position"); 16 "Track player position");
13 17
14 should_check_for_updates_box_->SetValue( 18 should_check_for_updates_box_->SetValue(
15 GetTrackerConfig().should_check_for_updates); 19 GetTrackerConfig().should_check_for_updates);
16 hybrid_areas_box_->SetValue(GetTrackerConfig().hybrid_areas); 20 hybrid_areas_box_->SetValue(GetTrackerConfig().hybrid_areas);
17 show_hunt_panels_box_->SetValue(GetTrackerConfig().show_hunt_panels);
18 track_position_box_->SetValue(GetTrackerConfig().track_position); 21 track_position_box_->SetValue(GetTrackerConfig().track_position);
19 22
20 wxBoxSizer* form_sizer = new wxBoxSizer(wxVERTICAL); 23 main_box->Add(should_check_for_updates_box_, wxSizerFlags().Border());
21 24 main_box->AddSpacer(2);
22 form_sizer->Add(should_check_for_updates_box_, wxSizerFlags().HorzBorder()); 25 main_box->Add(hybrid_areas_box_, wxSizerFlags().Border());
23 form_sizer->AddSpacer(2); 26 main_box->AddSpacer(2);
24 27 main_box->Add(track_position_box_, wxSizerFlags().Border());
25 form_sizer->Add(hybrid_areas_box_, wxSizerFlags().HorzBorder()); 28
26 form_sizer->AddSpacer(2); 29 const wxString visible_panels_choices[] = {"Only show locations",
30 "Show locations and hunt panels",
31 "Show all panels"};
32 visible_panels_box_ =
33 new wxRadioBox(this, wxID_ANY, "Visible panels", wxDefaultPosition,
34 wxDefaultSize, 3, visible_panels_choices, 1);
35 visible_panels_box_->SetSelection(
36 static_cast<int>(GetTrackerConfig().visible_panels));
27 37
28 form_sizer->Add(show_hunt_panels_box_, wxSizerFlags().HorzBorder()); 38 wxBoxSizer* form_sizer = new wxBoxSizer(wxVERTICAL);
29 form_sizer->AddSpacer(2); 39 form_sizer->Add(main_box, wxSizerFlags().Border().Expand());
30 40 form_sizer->Add(visible_panels_box_, wxSizerFlags().Border().Expand());
31 form_sizer->Add(track_position_box_, wxSizerFlags().HorzBorder()); 41 form_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL),
32 form_sizer->AddSpacer(2); 42 wxSizerFlags().Center().Border());
33
34 form_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Center());
35 43
36 SetSizerAndFit(form_sizer); 44 SetSizerAndFit(form_sizer);
37 45
diff --git a/src/settings_dialog.h b/src/settings_dialog.h index 12f2439..c4dacfa 100644 --- a/src/settings_dialog.h +++ b/src/settings_dialog.h
@@ -7,6 +7,10 @@
7#include <wx/wx.h> 7#include <wx/wx.h>
8#endif 8#endif
9 9
10#include <wx/radiobox.h>
11
12#include "tracker_config.h"
13
10class SettingsDialog : public wxDialog { 14class SettingsDialog : public wxDialog {
11 public: 15 public:
12 SettingsDialog(); 16 SettingsDialog();
@@ -15,13 +19,16 @@ class SettingsDialog : public wxDialog {
15 return should_check_for_updates_box_->GetValue(); 19 return should_check_for_updates_box_->GetValue();
16 } 20 }
17 bool GetHybridAreas() const { return hybrid_areas_box_->GetValue(); } 21 bool GetHybridAreas() const { return hybrid_areas_box_->GetValue(); }
18 bool GetShowHuntPanels() const { return show_hunt_panels_box_->GetValue(); } 22 TrackerConfig::VisiblePanels GetVisiblePanels() const {
23 return static_cast<TrackerConfig::VisiblePanels>(
24 visible_panels_box_->GetSelection());
25 }
19 bool GetTrackPosition() const { return track_position_box_->GetValue(); } 26 bool GetTrackPosition() const { return track_position_box_->GetValue(); }
20 27
21 private: 28 private:
22 wxCheckBox* should_check_for_updates_box_; 29 wxCheckBox* should_check_for_updates_box_;
23 wxCheckBox* hybrid_areas_box_; 30 wxCheckBox* hybrid_areas_box_;
24 wxCheckBox* show_hunt_panels_box_; 31 wxRadioBox* visible_panels_box_;
25 wxCheckBox* track_position_box_; 32 wxCheckBox* track_position_box_;
26}; 33};
27 34
diff --git a/src/tracker_config.cpp b/src/tracker_config.cpp index aeff669..da5d60a 100644 --- a/src/tracker_config.cpp +++ b/src/tracker_config.cpp
@@ -16,7 +16,9 @@ void TrackerConfig::Load() {
16 asked_to_check_for_updates = file["asked_to_check_for_updates"].as<bool>(); 16 asked_to_check_for_updates = file["asked_to_check_for_updates"].as<bool>();
17 should_check_for_updates = file["should_check_for_updates"].as<bool>(); 17 should_check_for_updates = file["should_check_for_updates"].as<bool>();
18 hybrid_areas = file["hybrid_areas"].as<bool>(); 18 hybrid_areas = file["hybrid_areas"].as<bool>();
19 show_hunt_panels = file["show_hunt_panels"].as<bool>(); 19 if (file["show_hunt_panels"] && file["show_hunt_panels"].as<bool>()) {
20 visible_panels = kHUNT_PANELS;
21 }
20 22
21 if (file["connection_history"]) { 23 if (file["connection_history"]) {
22 for (const auto& connection : file["connection_history"]) { 24 for (const auto& connection : file["connection_history"]) {
@@ -30,6 +32,8 @@ void TrackerConfig::Load() {
30 32
31 ipc_address = file["ipc_address"].as<std::string>(); 33 ipc_address = file["ipc_address"].as<std::string>();
32 track_position = file["track_position"].as<bool>(); 34 track_position = file["track_position"].as<bool>();
35 visible_panels =
36 static_cast<VisiblePanels>(file["visible_panels"].as<int>());
33 } catch (const std::exception&) { 37 } catch (const std::exception&) {
34 // It's fine if the file can't be loaded. 38 // It's fine if the file can't be loaded.
35 } 39 }
@@ -43,7 +47,6 @@ void TrackerConfig::Save() {
43 output["asked_to_check_for_updates"] = asked_to_check_for_updates; 47 output["asked_to_check_for_updates"] = asked_to_check_for_updates;
44 output["should_check_for_updates"] = should_check_for_updates; 48 output["should_check_for_updates"] = should_check_for_updates;
45 output["hybrid_areas"] = hybrid_areas; 49 output["hybrid_areas"] = hybrid_areas;
46 output["show_hunt_panels"] = show_hunt_panels;
47 50
48 output.remove("connection_history"); 51 output.remove("connection_history");
49 for (const ConnectionDetails& details : connection_history) { 52 for (const ConnectionDetails& details : connection_history) {
@@ -57,6 +60,7 @@ void TrackerConfig::Save() {
57 60
58 output["ipc_address"] = ipc_address; 61 output["ipc_address"] = ipc_address;
59 output["track_position"] = track_position; 62 output["track_position"] = track_position;
63 output["visible_panels"] = static_cast<int>(visible_panels);
60 64
61 std::ofstream filewriter(filename_); 65 std::ofstream filewriter(filename_);
62 filewriter << output; 66 filewriter << output;
diff --git a/src/tracker_config.h b/src/tracker_config.h index 4e851dc..df4105d 100644 --- a/src/tracker_config.h +++ b/src/tracker_config.h
@@ -23,14 +23,20 @@ class TrackerConfig {
23 23
24 void Save(); 24 void Save();
25 25
26 enum VisiblePanels {
27 kLOCATIONS_ONLY,
28 kHUNT_PANELS,
29 kALL_PANELS,
30 };
31
26 ConnectionDetails connection_details; 32 ConnectionDetails connection_details;
27 bool asked_to_check_for_updates = false; 33 bool asked_to_check_for_updates = false;
28 bool should_check_for_updates = false; 34 bool should_check_for_updates = false;
29 bool hybrid_areas = false; 35 bool hybrid_areas = false;
30 bool show_hunt_panels = false;
31 std::deque<ConnectionDetails> connection_history; 36 std::deque<ConnectionDetails> connection_history;
32 std::string ipc_address; 37 std::string ipc_address;
33 bool track_position = true; 38 bool track_position = true;
39 VisiblePanels visible_panels = kLOCATIONS_ONLY;
34 40
35 private: 41 private:
36 std::string filename_; 42 std::string filename_;
diff --git a/src/tracker_frame.cpp b/src/tracker_frame.cpp index 84017a3..c0b070b 100644 --- a/src/tracker_frame.cpp +++ b/src/tracker_frame.cpp
@@ -51,7 +51,6 @@ enum TrackerFrameIds {
51 ID_SETTINGS = 3, 51 ID_SETTINGS = 3,
52 ID_ZOOM_IN = 4, 52 ID_ZOOM_IN = 4,
53 ID_ZOOM_OUT = 5, 53 ID_ZOOM_OUT = 5,
54 ID_OPEN_SAVE_FILE = 6,
55 ID_IPC_CONNECT = 7, 54 ID_IPC_CONNECT = 7,
56 ID_LOG_DIALOG = 8, 55 ID_LOG_DIALOG = 8,
57}; 56};
@@ -77,7 +76,6 @@ TrackerFrame::TrackerFrame()
77 wxMenu *menuFile = new wxMenu(); 76 wxMenu *menuFile = new wxMenu();
78 menuFile->Append(ID_AP_CONNECT, "&Connect to Archipelago"); 77 menuFile->Append(ID_AP_CONNECT, "&Connect to Archipelago");
79 menuFile->Append(ID_IPC_CONNECT, "&Connect to Lingo"); 78 menuFile->Append(ID_IPC_CONNECT, "&Connect to Lingo");
80 menuFile->Append(ID_OPEN_SAVE_FILE, "&Open Save Data\tCtrl-O");
81 menuFile->Append(ID_SETTINGS, "&Settings"); 79 menuFile->Append(ID_SETTINGS, "&Settings");
82 menuFile->Append(wxID_EXIT); 80 menuFile->Append(wxID_EXIT);
83 81
@@ -114,7 +112,6 @@ TrackerFrame::TrackerFrame()
114 Bind(wxEVT_MENU, &TrackerFrame::OnZoomOut, this, ID_ZOOM_OUT); 112 Bind(wxEVT_MENU, &TrackerFrame::OnZoomOut, this, ID_ZOOM_OUT);
115 Bind(wxEVT_MENU, &TrackerFrame::OnOpenLogWindow, this, ID_LOG_DIALOG); 113 Bind(wxEVT_MENU, &TrackerFrame::OnOpenLogWindow, this, ID_LOG_DIALOG);
116 Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &TrackerFrame::OnChangePage, this); 114 Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &TrackerFrame::OnChangePage, this);
117 Bind(wxEVT_MENU, &TrackerFrame::OnOpenFile, this, ID_OPEN_SAVE_FILE);
118 Bind(wxEVT_SPLITTER_SASH_POS_CHANGED, &TrackerFrame::OnSashPositionChanged, 115 Bind(wxEVT_SPLITTER_SASH_POS_CHANGED, &TrackerFrame::OnSashPositionChanged,
119 this); 116 this);
120 Bind(STATE_RESET, &TrackerFrame::OnStateReset, this); 117 Bind(STATE_RESET, &TrackerFrame::OnStateReset, this);
@@ -252,7 +249,7 @@ void TrackerFrame::OnSettings(wxCommandEvent &event) {
252 GetTrackerConfig().should_check_for_updates = 249 GetTrackerConfig().should_check_for_updates =
253 dlg.GetShouldCheckForUpdates(); 250 dlg.GetShouldCheckForUpdates();
254 GetTrackerConfig().hybrid_areas = dlg.GetHybridAreas(); 251 GetTrackerConfig().hybrid_areas = dlg.GetHybridAreas();
255 GetTrackerConfig().show_hunt_panels = dlg.GetShowHuntPanels(); 252 GetTrackerConfig().visible_panels = dlg.GetVisiblePanels();
256 GetTrackerConfig().track_position = dlg.GetTrackPosition(); 253 GetTrackerConfig().track_position = dlg.GetTrackPosition();
257 GetTrackerConfig().Save(); 254 GetTrackerConfig().Save();
258 255
@@ -303,28 +300,6 @@ void TrackerFrame::OnChangePage(wxBookCtrlEvent &event) {
303 zoom_out_menu_item_->Enable(event.GetSelection() == 1); 300 zoom_out_menu_item_->Enable(event.GetSelection() == 1);
304} 301}
305 302
306void TrackerFrame::OnOpenFile(wxCommandEvent &event) {
307 wxFileDialog open_file_dialog(
308 this, "Open Lingo Save File",
309 fmt::format("{}\\Godot\\app_userdata\\Lingo\\level1_stable",
310 wxStandardPaths::Get().GetUserConfigDir().ToStdString()),
311 AP_GetSaveName(), "Lingo save file (*.save)|*.save",
312 wxFD_OPEN | wxFD_FILE_MUST_EXIST);
313 if (open_file_dialog.ShowModal() == wxID_CANCEL) {
314 return;
315 }
316
317 std::string savedata_path = open_file_dialog.GetPath().ToStdString();
318
319 if (panels_panel_ == nullptr) {
320 panels_panel_ = new TrackerPanel(notebook_);
321 notebook_->AddPage(panels_panel_, "Panels");
322 }
323
324 notebook_->SetSelection(notebook_->FindPage(panels_panel_));
325 panels_panel_->SetSavedataPath(savedata_path);
326}
327
328void TrackerFrame::OnSashPositionChanged(wxSplitterEvent& event) { 303void TrackerFrame::OnSashPositionChanged(wxSplitterEvent& event) {
329 notebook_->Refresh(); 304 notebook_->Refresh();
330} 305}
@@ -336,36 +311,20 @@ void TrackerFrame::OnStateReset(wxCommandEvent &event) {
336 options_pane_->OnConnect(); 311 options_pane_->OnConnect();
337 paintings_pane_->ResetIndicators(); 312 paintings_pane_->ResetIndicators();
338 subway_map_->OnConnect(); 313 subway_map_->OnConnect();
339 if (panels_panel_ != nullptr) {
340 notebook_->DeletePage(notebook_->FindPage(panels_panel_));
341 panels_panel_ = nullptr;
342 }
343 Refresh(); 314 Refresh();
344} 315}
345 316
346void TrackerFrame::OnStateChanged(StateChangedEvent &event) { 317void TrackerFrame::OnStateChanged(StateChangedEvent &event) {
347 const StateUpdate &state = event.GetState(); 318 const StateUpdate &state = event.GetState();
348 319
349 if (state.open_panels_tab) {
350 if (panels_panel_ == nullptr) {
351 panels_panel_ = new TrackerPanel(notebook_);
352 panels_panel_->SetPanelsMode();
353 notebook_->AddPage(panels_panel_, "Panels");
354 }
355 panels_panel_->UpdateIndicators(/*reset=*/false);
356 if (notebook_->GetSelection() == 2) {
357 Refresh();
358 }
359
360 return;
361 }
362
363 bool hunt_panels = false; 320 bool hunt_panels = false;
364 if (GetTrackerConfig().show_hunt_panels) { 321 if (GetTrackerConfig().visible_panels == TrackerConfig::kHUNT_PANELS) {
365 hunt_panels = std::any_of( 322 hunt_panels = std::any_of(
366 state.panels.begin(), state.panels.end(), [](int solve_index) { 323 state.panels.begin(), state.panels.end(), [](int solve_index) {
367 return GD_GetPanel(GD_GetPanelBySolveIndex(solve_index)).hunt; 324 return GD_GetPanel(GD_GetPanelBySolveIndex(solve_index)).hunt;
368 }); 325 });
326 } else if (GetTrackerConfig().visible_panels == TrackerConfig::kALL_PANELS) {
327 hunt_panels = true;
369 } 328 }
370 329
371 if (!state.items.empty() || !state.paintings.empty() || 330 if (!state.items.empty() || !state.paintings.empty() ||
@@ -375,15 +334,10 @@ void TrackerFrame::OnStateChanged(StateChangedEvent &event) {
375 // panels later, we can get rid of this. 334 // panels later, we can get rid of this.
376 tracker_panel_->UpdateIndicators(/*reset=*/state.changed_settings); 335 tracker_panel_->UpdateIndicators(/*reset=*/state.changed_settings);
377 subway_map_->UpdateIndicators(); 336 subway_map_->UpdateIndicators();
378 if (panels_panel_ != nullptr) {
379 panels_panel_->UpdateIndicators(/*reset=*/false);
380 }
381 Refresh(); 337 Refresh();
382 } else if (state.player_position && GetTrackerConfig().track_position) { 338 } else if (state.player_position && GetTrackerConfig().track_position) {
383 if (notebook_->GetSelection() == 0) { 339 if (notebook_->GetSelection() == 0) {
384 tracker_panel_->Refresh(); 340 tracker_panel_->Refresh();
385 } else if (notebook_->GetSelection() == 2) {
386 panels_panel_->Refresh();
387 } 341 }
388 } 342 }
389 343
diff --git a/src/tracker_frame.h b/src/tracker_frame.h index 8eb4465..2167852 100644 --- a/src/tracker_frame.h +++ b/src/tracker_frame.h
@@ -54,7 +54,6 @@ struct StateUpdate {
54 bool progression_items = false; 54 bool progression_items = false;
55 std::vector<std::string> paintings; 55 std::vector<std::string> paintings;
56 bool achievements = false; 56 bool achievements = false;
57 bool open_panels_tab = false;
58 bool cleared_locations = false; 57 bool cleared_locations = false;
59 std::set<int> panels; 58 std::set<int> panels;
60 bool player_position = false; 59 bool player_position = false;
@@ -101,7 +100,6 @@ class TrackerFrame : public wxFrame {
101 void OnOpenLogWindow(wxCommandEvent &event); 100 void OnOpenLogWindow(wxCommandEvent &event);
102 void OnCloseLogWindow(wxCloseEvent &event); 101 void OnCloseLogWindow(wxCloseEvent &event);
103 void OnChangePage(wxBookCtrlEvent &event); 102 void OnChangePage(wxBookCtrlEvent &event);
104 void OnOpenFile(wxCommandEvent &event);
105 void OnSashPositionChanged(wxSplitterEvent &event); 103 void OnSashPositionChanged(wxSplitterEvent &event);
106 104
107 void OnStateReset(wxCommandEvent &event); 105 void OnStateReset(wxCommandEvent &event);
@@ -119,7 +117,6 @@ class TrackerFrame : public wxFrame {
119 OptionsPane *options_pane_; 117 OptionsPane *options_pane_;
120 PaintingsPane *paintings_pane_; 118 PaintingsPane *paintings_pane_;
121 SubwayMap *subway_map_; 119 SubwayMap *subway_map_;
122 TrackerPanel *panels_panel_ = nullptr;
123 LogDialog *log_dialog_ = nullptr; 120 LogDialog *log_dialog_ = nullptr;
124 121
125 wxMenuItem *zoom_in_menu_item_; 122 wxMenuItem *zoom_in_menu_item_;
diff --git a/src/tracker_panel.cpp b/src/tracker_panel.cpp index d8ba054..0a756e6 100644 --- a/src/tracker_panel.cpp +++ b/src/tracker_panel.cpp
@@ -9,7 +9,6 @@
9#include "area_popup.h" 9#include "area_popup.h"
10#include "game_data.h" 10#include "game_data.h"
11#include "global.h" 11#include "global.h"
12#include "godot_variant.h"
13#include "ipc_state.h" 12#include "ipc_state.h"
14#include "tracker_config.h" 13#include "tracker_config.h"
15#include "tracker_state.h" 14#include "tracker_state.h"
@@ -52,20 +51,18 @@ TrackerPanel::TrackerPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY) {
52} 51}
53 52
54void TrackerPanel::UpdateIndicators(bool reset) { 53void TrackerPanel::UpdateIndicators(bool reset) {
55 if (panels_mode_ && !savedata_path_) {
56 solved_panels_ = IPC_GetSolvedPanels();
57 }
58
59 if (reset) { 54 if (reset) {
60 for (AreaIndicator &area : areas_) { 55 for (AreaIndicator &area : areas_) {
61 const MapArea &map_area = GD_GetMapArea(area.area_id); 56 const MapArea &map_area = GD_GetMapArea(area.area_id);
62 57
63 if (IsAreaPostgame(area.area_id)) { 58 if (IsAreaPostgame(area.area_id)) {
64 area.active = false; 59 area.active = false;
65 } else if (panels_mode_) {
66 area.active = map_area.has_single_panel;
67 } else if (!AP_IsLocationVisible(map_area.classification) && 60 } else if (!AP_IsLocationVisible(map_area.classification) &&
68 !(map_area.hunt && GetTrackerConfig().show_hunt_panels) && 61 !(map_area.hunt && GetTrackerConfig().visible_panels ==
62 TrackerConfig::kHUNT_PANELS) &&
63 !(map_area.has_single_panel &&
64 GetTrackerConfig().visible_panels ==
65 TrackerConfig::kALL_PANELS) &&
69 !(AP_IsPaintingShuffle() && !map_area.paintings.empty())) { 66 !(AP_IsPaintingShuffle() && !map_area.paintings.empty())) {
70 area.active = false; 67 area.active = false;
71 } else { 68 } else {
@@ -85,47 +82,10 @@ void TrackerPanel::UpdateIndicators(bool reset) {
85 Redraw(); 82 Redraw();
86} 83}
87 84
88void TrackerPanel::SetPanelsMode() { panels_mode_ = true; }
89
90void TrackerPanel::SetSavedataPath(std::string savedata_path) {
91 if (!savedata_path_) {
92 refresh_button_ = new wxButton(this, wxID_ANY, "Refresh");
93 refresh_button_->Bind(wxEVT_BUTTON, &TrackerPanel::OnRefreshSavedata, this);
94 SetUpRefreshButton();
95 }
96
97 savedata_path_ = savedata_path;
98 panels_mode_ = true;
99
100 UpdateIndicators(/*reset=*/true);
101 RefreshSavedata();
102}
103
104void TrackerPanel::RefreshSavedata() {
105 solved_panels_.clear();
106
107 GodotVariant godot_variant = ParseGodotFile(*savedata_path_);
108 for (const GodotVariant &panel_node : godot_variant.AsArray()) {
109 const std::vector<GodotVariant> &fields = panel_node.AsArray();
110 if (fields[1].AsBool()) {
111 const std::vector<std::string> &nodepath = fields[0].AsNodePath();
112 std::string key = fmt::format("{}/{}", nodepath[3], nodepath[4]);
113 solved_panels_.insert(key);
114 }
115 }
116
117 UpdateIndicators(/*reset=*/false);
118 Refresh();
119}
120
121void TrackerPanel::OnPaint(wxPaintEvent &event) { 85void TrackerPanel::OnPaint(wxPaintEvent &event) {
122 if (GetSize() != rendered_.GetSize()) { 86 if (GetSize() != rendered_.GetSize()) {
123 Resize(); 87 Resize();
124 Redraw(); 88 Redraw();
125
126 if (refresh_button_ != nullptr) {
127 SetUpRefreshButton();
128 }
129 } 89 }
130 90
131 wxBufferedPaintDC dc(this); 91 wxBufferedPaintDC dc(this);
@@ -174,10 +134,6 @@ void TrackerPanel::OnMouseMove(wxMouseEvent &event) {
174 event.Skip(); 134 event.Skip();
175} 135}
176 136
177void TrackerPanel::OnRefreshSavedata(wxCommandEvent &event) {
178 RefreshSavedata();
179}
180
181void TrackerPanel::Resize() { 137void TrackerPanel::Resize() {
182 wxSize panel_size = GetClientSize(); 138 wxSize panel_size = GetClientSize();
183 wxSize image_size = map_image_.GetSize(); 139 wxSize image_size = map_image_.GetSize();
@@ -281,18 +237,12 @@ void TrackerPanel::Redraw() {
281 // Nope. 237 // Nope.
282 } else if (IsLocationWinCondition(section)) { 238 } else if (IsLocationWinCondition(section)) {
283 has_unchecked = !AP_HasReachedGoal(); 239 has_unchecked = !AP_HasReachedGoal();
284 } else if (panels_mode_) {
285 if (section.single_panel) {
286 const Panel &panel = GD_GetPanel(*section.single_panel);
287 if (panel.non_counting) {
288 has_unchecked = !AP_HasCheckedGameLocation(section.ap_location_id);
289 } else {
290 has_unchecked = !GetSolvedPanels().contains(panel.nodepath);
291 }
292 }
293 } else if (AP_IsLocationVisible(section.classification)) { 240 } else if (AP_IsLocationVisible(section.classification)) {
294 has_unchecked = !AP_HasCheckedGameLocation(section.ap_location_id); 241 has_unchecked = !AP_HasCheckedGameLocation(section.ap_location_id);
295 } else if (section.hunt && GetTrackerConfig().show_hunt_panels) { 242 } else if ((section.hunt && GetTrackerConfig().visible_panels ==
243 TrackerConfig::kHUNT_PANELS) ||
244 (section.single_panel && GetTrackerConfig().visible_panels ==
245 TrackerConfig::kALL_PANELS)) {
296 has_unchecked = 246 has_unchecked =
297 !AP_IsPanelSolved(GD_GetPanel(*section.single_panel).solve_index); 247 !AP_IsPanelSolved(GD_GetPanel(*section.single_panel).solve_index);
298 } 248 }
@@ -306,7 +256,7 @@ void TrackerPanel::Redraw() {
306 } 256 }
307 } 257 }
308 258
309 if (AP_IsPaintingShuffle() && !panels_mode_) { 259 if (AP_IsPaintingShuffle()) {
310 for (int painting_id : map_area.paintings) { 260 for (int painting_id : map_area.paintings) {
311 if (IsPaintingPostgame(painting_id)) { 261 if (IsPaintingPostgame(painting_id)) {
312 continue; 262 continue;
@@ -358,8 +308,3 @@ void TrackerPanel::Redraw() {
358 } 308 }
359 } 309 }
360} 310}
361
362void TrackerPanel::SetUpRefreshButton() {
363 refresh_button_->SetSize(FromDIP(15), FromDIP(15), wxDefaultCoord,
364 wxDefaultCoord, wxSIZE_AUTO);
365}
diff --git a/src/tracker_panel.h b/src/tracker_panel.h index abab1bf..6825843 100644 --- a/src/tracker_panel.h +++ b/src/tracker_panel.h
@@ -19,16 +19,6 @@ class TrackerPanel : public wxPanel {
19 19
20 void UpdateIndicators(bool reset); 20 void UpdateIndicators(bool reset);
21 21
22 void SetPanelsMode();
23
24 void SetSavedataPath(std::string savedata_path);
25
26 bool IsPanelsMode() const { return panels_mode_; }
27
28 const std::set<std::string> &GetSolvedPanels() const {
29 return solved_panels_;
30 }
31
32 private: 22 private:
33 struct AreaIndicator { 23 struct AreaIndicator {
34 int area_id = -1; 24 int area_id = -1;
@@ -42,23 +32,16 @@ class TrackerPanel : public wxPanel {
42 32
43 void OnPaint(wxPaintEvent &event); 33 void OnPaint(wxPaintEvent &event);
44 void OnMouseMove(wxMouseEvent &event); 34 void OnMouseMove(wxMouseEvent &event);
45 void OnRefreshSavedata(wxCommandEvent &event);
46 35
47 void Resize(); 36 void Resize();
48 void Redraw(); 37 void Redraw();
49 38
50 void RefreshSavedata();
51
52 void SetUpRefreshButton();
53
54 wxImage map_image_; 39 wxImage map_image_;
55 wxImage player_image_; 40 wxImage player_image_;
56 wxBitmap scaled_map_; 41 wxBitmap scaled_map_;
57 wxBitmap rendered_; 42 wxBitmap rendered_;
58 wxBitmap scaled_player_; 43 wxBitmap scaled_player_;
59 44
60 wxButton *refresh_button_ = nullptr;
61
62 int offset_x_ = 0; 45 int offset_x_ = 0;
63 int offset_y_ = 0; 46 int offset_y_ = 0;
64 double scale_x_ = 0; 47 double scale_x_ = 0;
@@ -66,10 +49,6 @@ class TrackerPanel : public wxPanel {
66 int real_area_size_ = 0; 49 int real_area_size_ = 0;
67 50
68 std::vector<AreaIndicator> areas_; 51 std::vector<AreaIndicator> areas_;
69
70 bool panels_mode_ = false;
71 std::optional<std::string> savedata_path_;
72 std::set<std::string> solved_panels_;
73}; 52};
74 53
75#endif /* end of include guard: TRACKER_PANEL_H_D675A54D */ 54#endif /* end of include guard: TRACKER_PANEL_H_D675A54D */