diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2023-05-02 20:14:43 -0400 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2023-05-02 20:14:43 -0400 |
commit | 70f1c629a6e08e0f9c58707f0470e08c6ffeca34 (patch) | |
tree | a2262b898f02c551d3de298ffbd61505cdd384d2 | |
parent | 09d67fbad9df92caf2251d36b4abd7979fd27126 (diff) | |
download | lingo-ap-tracker-70f1c629a6e08e0f9c58707f0470e08c6ffeca34.tar.gz lingo-ap-tracker-70f1c629a6e08e0f9c58707f0470e08c6ffeca34.tar.bz2 lingo-ap-tracker-70f1c629a6e08e0f9c58707f0470e08c6ffeca34.zip |
Added reachability checking (only no doors rn)
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | ap_state.cpp | 41 | ||||
-rw-r--r-- | ap_state.h | 13 | ||||
-rw-r--r-- | area_popup.cpp | 5 | ||||
-rw-r--r-- | area_window.cpp | 16 | ||||
-rw-r--r-- | game_data.h | 10 | ||||
-rw-r--r-- | tracker_frame.cpp | 22 | ||||
-rw-r--r-- | tracker_frame.h | 5 | ||||
-rw-r--r-- | tracker_state.cpp | 143 | ||||
-rw-r--r-- | tracker_state.h | 19 |
10 files changed, 267 insertions, 8 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c346a9..399060b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -33,6 +33,7 @@ add_executable(lingo_ap_tracker | |||
33 | ap_state.cpp | 33 | ap_state.cpp |
34 | connection_dialog.cpp | 34 | connection_dialog.cpp |
35 | eye_indicator.cpp | 35 | eye_indicator.cpp |
36 | tracker_state.cpp | ||
36 | ) | 37 | ) |
37 | set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 17) | 38 | set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 17) |
38 | set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD_REQUIRED ON) | 39 | set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD_REQUIRED ON) |
diff --git a/ap_state.cpp b/ap_state.cpp index 4d7ddb7..9df487f 100644 --- a/ap_state.cpp +++ b/ap_state.cpp | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <thread> | 9 | #include <thread> |
10 | 10 | ||
11 | #include "game_data.h" | 11 | #include "game_data.h" |
12 | #include "tracker_state.h" | ||
12 | 13 | ||
13 | constexpr int AP_MAJOR = 0; | 14 | constexpr int AP_MAJOR = 0; |
14 | constexpr int AP_MINOR = 4; | 15 | constexpr int AP_MINOR = 4; |
@@ -16,6 +17,11 @@ constexpr int AP_REVISION = 0; | |||
16 | 17 | ||
17 | constexpr int ITEM_HANDLING = 7; // <- all | 18 | constexpr int ITEM_HANDLING = 7; // <- all |
18 | 19 | ||
20 | NLOHMANN_JSON_SERIALIZE_ENUM(DoorShuffleMode, | ||
21 | {{DoorShuffleMode::kNone, "none"}, | ||
22 | {DoorShuffleMode::kSimple, "simple"}, | ||
23 | {DoorShuffleMode::kComplex, "complex"}}); | ||
24 | |||
19 | APState::APState() { | 25 | APState::APState() { |
20 | std::thread([this]() { | 26 | std::thread([this]() { |
21 | for (;;) { | 27 | for (;;) { |
@@ -92,6 +98,9 @@ void APState::Connect(std::string server, std::string player, | |||
92 | apclient_->set_slot_connected_handler([&](const nlohmann::json& slot_data) { | 98 | apclient_->set_slot_connected_handler([&](const nlohmann::json& slot_data) { |
93 | tracker_frame_->SetStatusMessage("Connected to Archipelago!"); | 99 | tracker_frame_->SetStatusMessage("Connected to Archipelago!"); |
94 | 100 | ||
101 | door_shuffle_mode_ = slot_data["shuffle_doors"].get<DoorShuffleMode>(); | ||
102 | color_shuffle_ = slot_data["shuffle_colors"].get<bool>(); | ||
103 | |||
95 | connected = true; | 104 | connected = true; |
96 | has_connection_result = true; | 105 | has_connection_result = true; |
97 | }); | 106 | }); |
@@ -169,6 +178,16 @@ void APState::Connect(std::string server, std::string player, | |||
169 | } | 178 | } |
170 | } | 179 | } |
171 | 180 | ||
181 | ap_id_by_color_[LingoColor::kBlack] = GetItemId("Black"); | ||
182 | ap_id_by_color_[LingoColor::kRed] = GetItemId("Red"); | ||
183 | ap_id_by_color_[LingoColor::kBlue] = GetItemId("Blue"); | ||
184 | ap_id_by_color_[LingoColor::kYellow] = GetItemId("Yellow"); | ||
185 | ap_id_by_color_[LingoColor::kPurple] = GetItemId("Purple"); | ||
186 | ap_id_by_color_[LingoColor::kOrange] = GetItemId("Orange"); | ||
187 | ap_id_by_color_[LingoColor::kGreen] = GetItemId("Green"); | ||
188 | ap_id_by_color_[LingoColor::kBrown] = GetItemId("Brown"); | ||
189 | ap_id_by_color_[LingoColor::kGray] = GetItemId("Gray"); | ||
190 | |||
172 | RefreshTracker(); | 191 | RefreshTracker(); |
173 | } else { | 192 | } else { |
174 | client_active_ = false; | 193 | client_active_ = false; |
@@ -185,7 +204,27 @@ bool APState::HasCheckedGameLocation(int area_id, int section_id) const { | |||
185 | } | 204 | } |
186 | } | 205 | } |
187 | 206 | ||
188 | void APState::RefreshTracker() { tracker_frame_->UpdateIndicators(); } | 207 | bool APState::HasColorItem(LingoColor color) const { |
208 | if (ap_id_by_color_.count(color)) { | ||
209 | return inventory_.count(ap_id_by_color_.at(color)); | ||
210 | } else { | ||
211 | return false; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | void APState::RefreshTracker() { | ||
216 | GetTrackerState().CalculateState(); | ||
217 | tracker_frame_->UpdateIndicators(); | ||
218 | } | ||
219 | |||
220 | int64_t APState::GetItemId(const std::string& item_name) { | ||
221 | int64_t ap_id = apclient_->get_item_id(item_name); | ||
222 | if (ap_id == APClient::INVALID_NAME_ID) { | ||
223 | std::cout << "Could not find AP item ID for " << item_name << std::endl; | ||
224 | } | ||
225 | |||
226 | return ap_id; | ||
227 | } | ||
189 | 228 | ||
190 | APState& GetAPState() { | 229 | APState& GetAPState() { |
191 | static APState* instance = new APState(); | 230 | static APState* instance = new APState(); |
diff --git a/ap_state.h b/ap_state.h index b5a94e3..d818b40 100644 --- a/ap_state.h +++ b/ap_state.h | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "game_data.h" | 11 | #include "game_data.h" |
12 | #include "tracker_frame.h" | 12 | #include "tracker_frame.h" |
13 | 13 | ||
14 | enum class DoorShuffleMode { kNone, kSimple, kComplex }; | ||
15 | |||
14 | class APState { | 16 | class APState { |
15 | public: | 17 | public: |
16 | APState(); | 18 | APState(); |
@@ -23,9 +25,17 @@ class APState { | |||
23 | 25 | ||
24 | bool HasCheckedGameLocation(int area_id, int section_id) const; | 26 | bool HasCheckedGameLocation(int area_id, int section_id) const; |
25 | 27 | ||
28 | bool HasColorItem(LingoColor color) const; | ||
29 | |||
30 | DoorShuffleMode GetDoorShuffleMode() const { return door_shuffle_mode_; } | ||
31 | |||
32 | bool IsColorShuffle() const { return color_shuffle_; } | ||
33 | |||
26 | private: | 34 | private: |
27 | void RefreshTracker(); | 35 | void RefreshTracker(); |
28 | 36 | ||
37 | int64_t GetItemId(const std::string& item_name); | ||
38 | |||
29 | TrackerFrame* tracker_frame_; | 39 | TrackerFrame* tracker_frame_; |
30 | 40 | ||
31 | std::unique_ptr<APClient> apclient_; | 41 | std::unique_ptr<APClient> apclient_; |
@@ -39,6 +49,9 @@ class APState { | |||
39 | std::map<int, int64_t> ap_id_by_door_id_; | 49 | std::map<int, int64_t> ap_id_by_door_id_; |
40 | std::map<int, int64_t> ap_id_by_door_group_id_; | 50 | std::map<int, int64_t> ap_id_by_door_group_id_; |
41 | std::map<LingoColor, int64_t> ap_id_by_color_; | 51 | std::map<LingoColor, int64_t> ap_id_by_color_; |
52 | |||
53 | DoorShuffleMode door_shuffle_mode_ = DoorShuffleMode::kNone; | ||
54 | bool color_shuffle_ = false; | ||
42 | }; | 55 | }; |
43 | 56 | ||
44 | APState& GetAPState(); | 57 | APState& GetAPState(); |
diff --git a/area_popup.cpp b/area_popup.cpp index e46e4ec..4cc3c63 100644 --- a/area_popup.cpp +++ b/area_popup.cpp | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | #include "ap_state.h" | 3 | #include "ap_state.h" |
4 | #include "game_data.h" | 4 | #include "game_data.h" |
5 | #include "tracker_state.h" | ||
5 | 6 | ||
6 | AreaPopup::AreaPopup(wxWindow* parent, int area_id) | 7 | AreaPopup::AreaPopup(wxWindow* parent, int area_id) |
7 | : wxPanel(parent, wxID_ANY), area_id_(area_id) { | 8 | : wxPanel(parent, wxID_ANY), area_id_(area_id) { |
@@ -43,7 +44,9 @@ void AreaPopup::UpdateIndicators() { | |||
43 | for (int section_id = 0; section_id < map_area.locations.size(); | 44 | for (int section_id = 0; section_id < map_area.locations.size(); |
44 | section_id++) { | 45 | section_id++) { |
45 | bool checked = GetAPState().HasCheckedGameLocation(area_id_, section_id); | 46 | bool checked = GetAPState().HasCheckedGameLocation(area_id_, section_id); |
46 | const wxColour* text_color = checked ? wxWHITE : wxGREEN; | 47 | bool reachable = |
48 | GetTrackerState().IsLocationReachable(area_id_, section_id); | ||
49 | const wxColour* text_color = reachable ? wxWHITE : wxRED; | ||
47 | 50 | ||
48 | section_labels_[section_id]->SetForegroundColour(*text_color); | 51 | section_labels_[section_id]->SetForegroundColour(*text_color); |
49 | eye_indicators_[section_id]->SetChecked(checked); | 52 | eye_indicators_[section_id]->SetChecked(checked); |
diff --git a/area_window.cpp b/area_window.cpp index ca327b8..fded223 100644 --- a/area_window.cpp +++ b/area_window.cpp | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include "ap_state.h" | 5 | #include "ap_state.h" |
6 | #include "game_data.h" | 6 | #include "game_data.h" |
7 | #include "tracker_state.h" | ||
7 | 8 | ||
8 | AreaWindow::AreaWindow(wxWindow* parent, int area_id, AreaPopup* popup) | 9 | AreaWindow::AreaWindow(wxWindow* parent, int area_id, AreaPopup* popup) |
9 | : wxWindow(parent, wxID_ANY), area_id_(area_id), popup_(popup) { | 10 | : wxWindow(parent, wxID_ANY), area_id_(area_id), popup_(popup) { |
@@ -35,16 +36,25 @@ void AreaWindow::Redraw() { | |||
35 | const wxBrush* brush_color = wxGREY_BRUSH; | 36 | const wxBrush* brush_color = wxGREY_BRUSH; |
36 | 37 | ||
37 | const MapArea& map_area = GetGameData().GetMapArea(area_id_); | 38 | const MapArea& map_area = GetGameData().GetMapArea(area_id_); |
38 | int unchecked_sections = 0; | 39 | bool has_reachable_unchecked = false; |
40 | bool has_unreachable_unchecked = false; | ||
39 | for (int section_id = 0; section_id < map_area.locations.size(); | 41 | for (int section_id = 0; section_id < map_area.locations.size(); |
40 | section_id++) { | 42 | section_id++) { |
41 | if (!GetAPState().HasCheckedGameLocation(area_id_, section_id)) { | 43 | if (!GetAPState().HasCheckedGameLocation(area_id_, section_id)) { |
42 | unchecked_sections++; | 44 | if (GetTrackerState().IsLocationReachable(area_id_, section_id)) { |
45 | has_reachable_unchecked = true; | ||
46 | } else { | ||
47 | has_unreachable_unchecked = true; | ||
48 | } | ||
43 | } | 49 | } |
44 | } | 50 | } |
45 | 51 | ||
46 | if (unchecked_sections > 0) { | 52 | if (has_reachable_unchecked && has_unreachable_unchecked) { |
53 | brush_color = wxYELLOW_BRUSH; | ||
54 | } else if (has_reachable_unchecked) { | ||
47 | brush_color = wxGREEN_BRUSH; | 55 | brush_color = wxGREEN_BRUSH; |
56 | } else if (has_unreachable_unchecked) { | ||
57 | brush_color = wxRED_BRUSH; | ||
48 | } | 58 | } |
49 | 59 | ||
50 | int actual_border_size = GetSize().GetWidth() * BORDER_SIZE / EFFECTIVE_SIZE; | 60 | int actual_border_size = GetSize().GetWidth() * BORDER_SIZE / EFFECTIVE_SIZE; |
diff --git a/game_data.h b/game_data.h index 4f93d92..ec3e94d 100644 --- a/game_data.h +++ b/game_data.h | |||
@@ -73,6 +73,16 @@ class GameData { | |||
73 | 73 | ||
74 | const MapArea& GetMapArea(int id) const { return map_areas_.at(id); } | 74 | const MapArea& GetMapArea(int id) const { return map_areas_.at(id); } |
75 | 75 | ||
76 | int GetRoomByName(const std::string& name) const { | ||
77 | return room_by_id_.at(name); | ||
78 | } | ||
79 | |||
80 | const Room& GetRoom(int room_id) const { return rooms_.at(room_id); } | ||
81 | |||
82 | const Door& GetDoor(int door_id) const { return doors_.at(door_id); } | ||
83 | |||
84 | const Panel& GetPanel(int panel_id) const { return panels_.at(panel_id); } | ||
85 | |||
76 | private: | 86 | private: |
77 | int AddOrGetRoom(std::string room); | 87 | int AddOrGetRoom(std::string room); |
78 | int AddOrGetDoor(std::string room, std::string door); | 88 | int AddOrGetDoor(std::string room, std::string door); |
diff --git a/tracker_frame.cpp b/tracker_frame.cpp index cd2060c..237433a 100644 --- a/tracker_frame.cpp +++ b/tracker_frame.cpp | |||
@@ -6,6 +6,9 @@ | |||
6 | 6 | ||
7 | enum TrackerFrameIds { ID_CONNECT = 1 }; | 7 | enum TrackerFrameIds { ID_CONNECT = 1 }; |
8 | 8 | ||
9 | wxDEFINE_EVENT(STATE_CHANGED, wxCommandEvent); | ||
10 | wxDEFINE_EVENT(STATUS_CHANGED, wxCommandEvent); | ||
11 | |||
9 | TrackerFrame::TrackerFrame() | 12 | TrackerFrame::TrackerFrame() |
10 | : wxFrame(nullptr, wxID_ANY, "Lingo Archipelago Tracker") { | 13 | : wxFrame(nullptr, wxID_ANY, "Lingo Archipelago Tracker") { |
11 | ::wxInitAllImageHandlers(); | 14 | ::wxInitAllImageHandlers(); |
@@ -33,17 +36,21 @@ TrackerFrame::TrackerFrame() | |||
33 | Bind(wxEVT_MENU, &TrackerFrame::OnAbout, this, wxID_ABOUT); | 36 | Bind(wxEVT_MENU, &TrackerFrame::OnAbout, this, wxID_ABOUT); |
34 | Bind(wxEVT_MENU, &TrackerFrame::OnExit, this, wxID_EXIT); | 37 | Bind(wxEVT_MENU, &TrackerFrame::OnExit, this, wxID_EXIT); |
35 | Bind(wxEVT_MENU, &TrackerFrame::OnConnect, this, ID_CONNECT); | 38 | Bind(wxEVT_MENU, &TrackerFrame::OnConnect, this, ID_CONNECT); |
39 | Bind(STATE_CHANGED, &TrackerFrame::OnStateChanged, this); | ||
40 | Bind(STATUS_CHANGED, &TrackerFrame::OnStatusChanged, this); | ||
36 | 41 | ||
37 | tracker_panel_ = new TrackerPanel(this); | 42 | tracker_panel_ = new TrackerPanel(this); |
38 | } | 43 | } |
39 | 44 | ||
40 | void TrackerFrame::SetStatusMessage(std::string message) { | 45 | void TrackerFrame::SetStatusMessage(std::string message) { |
41 | SetStatusText(message); | 46 | wxCommandEvent *event = new wxCommandEvent(STATUS_CHANGED); |
47 | event->SetString(message.c_str()); | ||
48 | |||
49 | QueueEvent(event); | ||
42 | } | 50 | } |
43 | 51 | ||
44 | void TrackerFrame::UpdateIndicators() { | 52 | void TrackerFrame::UpdateIndicators() { |
45 | tracker_panel_->UpdateIndicators(); | 53 | QueueEvent(new wxCommandEvent(STATE_CHANGED)); |
46 | Refresh(); | ||
47 | } | 54 | } |
48 | 55 | ||
49 | void TrackerFrame::OnAbout(wxCommandEvent &event) { | 56 | void TrackerFrame::OnAbout(wxCommandEvent &event) { |
@@ -61,3 +68,12 @@ void TrackerFrame::OnConnect(wxCommandEvent &event) { | |||
61 | dlg.GetPasswordValue()); | 68 | dlg.GetPasswordValue()); |
62 | } | 69 | } |
63 | } | 70 | } |
71 | |||
72 | void TrackerFrame::OnStateChanged(wxCommandEvent &event) { | ||
73 | tracker_panel_->UpdateIndicators(); | ||
74 | Refresh(); | ||
75 | } | ||
76 | |||
77 | void TrackerFrame::OnStatusChanged(wxCommandEvent &event) { | ||
78 | SetStatusText(event.GetString()); | ||
79 | } | ||
diff --git a/tracker_frame.h b/tracker_frame.h index 082c12c..6f4e4fc 100644 --- a/tracker_frame.h +++ b/tracker_frame.h | |||
@@ -9,6 +9,9 @@ | |||
9 | 9 | ||
10 | class TrackerPanel; | 10 | class TrackerPanel; |
11 | 11 | ||
12 | wxDECLARE_EVENT(STATE_CHANGED, wxCommandEvent); | ||
13 | wxDECLARE_EVENT(STATUS_CHANGED, wxCommandEvent); | ||
14 | |||
12 | class TrackerFrame : public wxFrame { | 15 | class TrackerFrame : public wxFrame { |
13 | public: | 16 | public: |
14 | TrackerFrame(); | 17 | TrackerFrame(); |
@@ -21,6 +24,8 @@ class TrackerFrame : public wxFrame { | |||
21 | void OnExit(wxCommandEvent &event); | 24 | void OnExit(wxCommandEvent &event); |
22 | void OnAbout(wxCommandEvent &event); | 25 | void OnAbout(wxCommandEvent &event); |
23 | void OnConnect(wxCommandEvent &event); | 26 | void OnConnect(wxCommandEvent &event); |
27 | void OnStateChanged(wxCommandEvent &event); | ||
28 | void OnStatusChanged(wxCommandEvent &event); | ||
24 | 29 | ||
25 | TrackerPanel *tracker_panel_; | 30 | TrackerPanel *tracker_panel_; |
26 | }; | 31 | }; |
diff --git a/tracker_state.cpp b/tracker_state.cpp new file mode 100644 index 0000000..62e4612 --- /dev/null +++ b/tracker_state.cpp | |||
@@ -0,0 +1,143 @@ | |||
1 | #include "tracker_state.h" | ||
2 | |||
3 | #include <list> | ||
4 | #include <set> | ||
5 | |||
6 | #include "ap_state.h" | ||
7 | #include "game_data.h" | ||
8 | |||
9 | bool IsDoorReachable_Helper(int door_id, const std::set<int>& reachable_rooms); | ||
10 | |||
11 | bool IsPanelReachable_Helper(int panel_id, | ||
12 | const std::set<int>& reachable_rooms) { | ||
13 | const Panel& panel_obj = GetGameData().GetPanel(panel_id); | ||
14 | |||
15 | if (!reachable_rooms.count(panel_obj.room)) { | ||
16 | return false; | ||
17 | } | ||
18 | |||
19 | for (int room_id : panel_obj.required_rooms) { | ||
20 | if (!reachable_rooms.count(room_id)) { | ||
21 | return false; | ||
22 | } | ||
23 | } | ||
24 | |||
25 | for (int door_id : panel_obj.required_doors) { | ||
26 | if (!IsDoorReachable_Helper(door_id, reachable_rooms)) { | ||
27 | return false; | ||
28 | } | ||
29 | } | ||
30 | |||
31 | if (GetAPState().IsColorShuffle()) { | ||
32 | for (LingoColor color : panel_obj.colors) { | ||
33 | if (!GetAPState().HasColorItem(color)) { | ||
34 | return false; | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | return true; | ||
40 | } | ||
41 | |||
42 | bool IsDoorReachable_Helper(int door_id, const std::set<int>& reachable_rooms) { | ||
43 | const Door& door_obj = GetGameData().GetDoor(door_id); | ||
44 | |||
45 | switch (GetAPState().GetDoorShuffleMode()) { | ||
46 | case DoorShuffleMode::kNone: { | ||
47 | if (!reachable_rooms.count(door_obj.room)) { | ||
48 | return false; | ||
49 | } | ||
50 | |||
51 | for (int panel_id : door_obj.panels) { | ||
52 | if (!IsPanelReachable_Helper(panel_id, reachable_rooms)) { | ||
53 | return false; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | return true; | ||
58 | } | ||
59 | case DoorShuffleMode::kSimple: { | ||
60 | break; | ||
61 | } | ||
62 | case DoorShuffleMode::kComplex: { | ||
63 | break; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | void TrackerState::CalculateState() { | ||
69 | reachability_.clear(); | ||
70 | |||
71 | std::set<int> reachable_rooms; | ||
72 | |||
73 | std::list<Exit> flood_boundary; | ||
74 | flood_boundary.push_back( | ||
75 | {.destination_room = GetGameData().GetRoomByName("Menu")}); | ||
76 | |||
77 | bool reachable_changed = true; | ||
78 | while (reachable_changed) { | ||
79 | reachable_changed = false; | ||
80 | |||
81 | std::list<Exit> new_boundary; | ||
82 | for (const Exit& room_exit : flood_boundary) { | ||
83 | if (reachable_rooms.count(room_exit.destination_room)) { | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | bool valid_transition = false; | ||
88 | if (room_exit.door.has_value()) { | ||
89 | if (IsDoorReachable_Helper(*room_exit.door, reachable_rooms)) { | ||
90 | valid_transition = true; | ||
91 | } else if (GetAPState().GetDoorShuffleMode() == | ||
92 | DoorShuffleMode::kNone) { | ||
93 | new_boundary.push_back(room_exit); | ||
94 | } | ||
95 | } else { | ||
96 | valid_transition = true; | ||
97 | } | ||
98 | |||
99 | if (valid_transition) { | ||
100 | reachable_rooms.insert(room_exit.destination_room); | ||
101 | reachable_changed = true; | ||
102 | |||
103 | const Room& room_obj = | ||
104 | GetGameData().GetRoom(room_exit.destination_room); | ||
105 | for (const Exit& out_edge : room_obj.exits) { | ||
106 | new_boundary.push_back(out_edge); | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | flood_boundary = new_boundary; | ||
112 | } | ||
113 | |||
114 | for (const MapArea& map_area : GetGameData().GetMapAreas()) { | ||
115 | for (int section_id = 0; section_id < map_area.locations.size(); | ||
116 | section_id++) { | ||
117 | const Location& location_section = map_area.locations.at(section_id); | ||
118 | bool reachable = reachable_rooms.count(location_section.room); | ||
119 | if (reachable) { | ||
120 | for (int panel_id : location_section.panels) { | ||
121 | reachable &= IsPanelReachable_Helper(panel_id, reachable_rooms); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | reachability_[{map_area.id, section_id}] = reachable; | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
130 | bool TrackerState::IsLocationReachable(int area_id, int section_id) { | ||
131 | std::tuple<int, int> key = {area_id, section_id}; | ||
132 | |||
133 | if (reachability_.count(key)) { | ||
134 | return reachability_.at(key); | ||
135 | } else { | ||
136 | return false; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | TrackerState& GetTrackerState() { | ||
141 | static TrackerState* instance = new TrackerState(); | ||
142 | return *instance; | ||
143 | } | ||
diff --git a/tracker_state.h b/tracker_state.h new file mode 100644 index 0000000..879e6f2 --- /dev/null +++ b/tracker_state.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef TRACKER_STATE_H_8639BC90 | ||
2 | #define TRACKER_STATE_H_8639BC90 | ||
3 | |||
4 | #include <map> | ||
5 | #include <tuple> | ||
6 | |||
7 | class TrackerState { | ||
8 | public: | ||
9 | void CalculateState(); | ||
10 | |||
11 | bool IsLocationReachable(int area_id, int section_id); | ||
12 | |||
13 | private: | ||
14 | std::map<std::tuple<int, int>, bool> reachability_; | ||
15 | }; | ||
16 | |||
17 | TrackerState& GetTrackerState(); | ||
18 | |||
19 | #endif /* end of include guard: TRACKER_STATE_H_8639BC90 */ | ||