about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md16
-rw-r--r--VERSION2
-rw-r--r--assets/subway.yaml2
-rw-r--r--src/area_popup.cpp14
-rw-r--r--src/game_data.cpp4
-rw-r--r--src/game_data.h4
-rw-r--r--src/network_set.cpp13
-rw-r--r--src/network_set.h2
-rw-r--r--src/subway_map.cpp25
-rw-r--r--src/tracker_panel.cpp20
-rw-r--r--src/tracker_state.cpp13
-rw-r--r--src/tracker_state.h2
-rw-r--r--src/version.h2
13 files changed, 93 insertions, 26 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a9ce76d..a78c24c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
1# lingo-ap-tracker Releases 1# lingo-ap-tracker Releases
2 2
3## v0.11.1 - 2024-07-25
4
5- The Pilgrim Antechamber sunwarp on the subway map now shows all sunwarp
6 connections, and is red if a pilgrimage is not possible.
7- The save analysis panel now uses the remote location status for non-counting
8 panels.
9- Fixed positioning of Outside The Undeterred - Number Hunt door on subway map.
10- Fixed subway map issue when sunwarp shuffle and individual/progressive sunwarp
11 access were combined where the icons on the map would show unshuffled access.
12- Map area indicators now correctly treat unreachable pre-checked paintings as
13 unchecked.
14
15Download:
16[lingo-ap-tracker-v0.11.1-win64.zip](https://files.fourisland.com/releases/lingo-ap-tracker/lingo-ap-tracker-v0.11.1-win64.zip)<br/>
17Source: [v0.11.1](https://code.fourisland.com/lingo-ap-tracker/tag/?h=v0.11.1)
18
3## v0.11.0 - 2024-07-19 19## v0.11.0 - 2024-07-19
4 20
5- Added a savedata analyzer. When connected to a world, the user can open up the 21- Added a savedata analyzer. When connected to a world, the user can open up the
diff --git a/VERSION b/VERSION index e88c34f..a5de145 100644 --- a/VERSION +++ b/VERSION
@@ -1 +1 @@
v0.11.0 \ No newline at end of file v0.11.1 \ No newline at end of file
diff --git a/assets/subway.yaml b/assets/subway.yaml index ede704c..dcc58b2 100644 --- a/assets/subway.yaml +++ b/assets/subway.yaml
@@ -701,7 +701,7 @@
701- pos: [719, 1039] 701- pos: [719, 1039]
702 room: Outside The Undeterred 702 room: Outside The Undeterred
703 door: Challenge Entrance 703 door: Challenge Entrance
704- pos: [438, 1039] 704- pos: [483, 1039]
705 room: Outside The Undeterred 705 room: Outside The Undeterred
706 door: Number Hunt 706 door: Number Hunt
707- pos: [563, 1071] 707- pos: [563, 1071]
diff --git a/src/area_popup.cpp b/src/area_popup.cpp index b18ba62..8d6487e 100644 --- a/src/area_popup.cpp +++ b/src/area_popup.cpp
@@ -55,7 +55,7 @@ void AreaPopup::UpdateIndicators() {
55 const Location& location = map_area.locations.at(section_id); 55 const Location& location = map_area.locations.at(section_id);
56 56
57 if (tracker_panel->IsPanelsMode()) { 57 if (tracker_panel->IsPanelsMode()) {
58 if (!location.panel) { 58 if (!location.single_panel) {
59 continue; 59 continue;
60 } 60 }
61 } else { 61 } else {
@@ -117,12 +117,12 @@ void AreaPopup::UpdateIndicators() {
117 if (IsLocationWinCondition(location)) { 117 if (IsLocationWinCondition(location)) {
118 checked = AP_HasReachedGoal(); 118 checked = AP_HasReachedGoal();
119 } else if (tracker_panel->IsPanelsMode()) { 119 } else if (tracker_panel->IsPanelsMode()) {
120 checked = location.panel && std::any_of( 120 const Panel& panel = GD_GetPanel(*location.single_panel);
121 location.panels.begin(), location.panels.end(), 121 if (panel.non_counting) {
122 [tracker_panel](int panel_id) { 122 checked = AP_HasCheckedGameLocation(location.ap_location_id);
123 const Panel& panel = GD_GetPanel(panel_id); 123 } else {
124 return tracker_panel->GetSolvedPanels().contains(panel.nodepath); 124 checked = tracker_panel->GetSolvedPanels().contains(panel.nodepath);
125 }); 125 }
126 } else { 126 } else {
127 checked = 127 checked =
128 AP_HasCheckedGameLocation(location.ap_location_id) || 128 AP_HasCheckedGameLocation(location.ap_location_id) ||
diff --git a/src/game_data.cpp b/src/game_data.cpp index 0786edb..4d448d3 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -645,7 +645,7 @@ struct GameData {
645 .panels = {panel.id}, 645 .panels = {panel.id},
646 .classification = classification, 646 .classification = classification,
647 .hunt = panel.hunt, 647 .hunt = panel.hunt,
648 .panel = true}); 648 .single_panel = panel.id});
649 locations_by_name[location_name] = {area_id, 649 locations_by_name[location_name] = {area_id,
650 map_area.locations.size() - 1}; 650 map_area.locations.size() - 1};
651 } 651 }
@@ -698,7 +698,7 @@ struct GameData {
698 for (const Location &location : map_area.locations) { 698 for (const Location &location : map_area.locations) {
699 map_area.classification |= location.classification; 699 map_area.classification |= location.classification;
700 map_area.hunt |= location.hunt; 700 map_area.hunt |= location.hunt;
701 map_area.panel |= location.panel; 701 map_area.has_single_panel |= location.single_panel.has_value();
702 } 702 }
703 } 703 }
704 704
diff --git a/src/game_data.h b/src/game_data.h index 6f287cf..9b6f3b2 100644 --- a/src/game_data.h +++ b/src/game_data.h
@@ -121,7 +121,7 @@ struct Location {
121 std::vector<int> panels; 121 std::vector<int> panels;
122 int classification = 0; 122 int classification = 0;
123 bool hunt = false; 123 bool hunt = false;
124 bool panel = false; 124 std::optional<int> single_panel;
125}; 125};
126 126
127struct MapArea { 127struct MapArea {
@@ -133,7 +133,7 @@ struct MapArea {
133 int map_y; 133 int map_y;
134 int classification = 0; 134 int classification = 0;
135 bool hunt = false; 135 bool hunt = false;
136 bool panel = false; 136 bool has_single_panel = false;
137}; 137};
138 138
139enum class SubwaySunwarpType { 139enum class SubwaySunwarpType {
diff --git a/src/network_set.cpp b/src/network_set.cpp index 6d2a098..2a9e12c 100644 --- a/src/network_set.cpp +++ b/src/network_set.cpp
@@ -21,6 +21,19 @@ void NetworkSet::AddLink(int id1, int id2) {
21 network_by_item_[id2].insert({id1, id2}); 21 network_by_item_[id2].insert({id1, id2});
22} 22}
23 23
24void NetworkSet::AddLinkToNetwork(int network_id, int id1, int id2) {
25 if (id2 > id1) {
26 // Make sure id1 < id2
27 std::swap(id1, id2);
28 }
29
30 if (!network_by_item_.count(network_id)) {
31 network_by_item_[network_id] = {};
32 }
33
34 network_by_item_[network_id].insert({id1, id2});
35}
36
24bool NetworkSet::IsItemInNetwork(int id) const { 37bool NetworkSet::IsItemInNetwork(int id) const {
25 return network_by_item_.count(id); 38 return network_by_item_.count(id);
26} 39}
diff --git a/src/network_set.h b/src/network_set.h index e6f0c07..cec3f39 100644 --- a/src/network_set.h +++ b/src/network_set.h
@@ -13,6 +13,8 @@ class NetworkSet {
13 13
14 void AddLink(int id1, int id2); 14 void AddLink(int id1, int id2);
15 15
16 void AddLinkToNetwork(int network_id, int id1, int id2);
17
16 bool IsItemInNetwork(int id) const; 18 bool IsItemInNetwork(int id) const;
17 19
18 const std::set<std::pair<int, int>>& GetNetworkGraph(int id) const; 20 const std::set<std::pair<int, int>>& GetNetworkGraph(int id) const;
diff --git a/src/subway_map.cpp b/src/subway_map.cpp index 9bfedf9..5b3ff5f 100644 --- a/src/subway_map.cpp +++ b/src/subway_map.cpp
@@ -107,7 +107,7 @@ void SubwayMap::OnConnect() {
107 107
108 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp && 108 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp &&
109 subway_item.sunwarp->type != SubwaySunwarpType::kFinal) { 109 subway_item.sunwarp->type != SubwaySunwarpType::kFinal) {
110 std::string tag = fmt::format("subway{}", subway_item.sunwarp->dots); 110 std::string tag = fmt::format("sunwarp{}", subway_item.sunwarp->dots);
111 tagged[tag].push_back(subway_item.id); 111 tagged[tag].push_back(subway_item.id);
112 } 112 }
113 113
@@ -119,6 +119,9 @@ void SubwayMap::OnConnect() {
119 } 119 }
120 120
121 if (AP_IsSunwarpShuffle()) { 121 if (AP_IsSunwarpShuffle()) {
122 SubwaySunwarp final_sunwarp{.dots = 6, .type = SubwaySunwarpType::kFinal};
123 int final_sunwarp_item = GD_GetSubwayItemForSunwarp(final_sunwarp);
124
122 for (const auto &[index, mapping] : AP_GetSunwarpMapping()) { 125 for (const auto &[index, mapping] : AP_GetSunwarpMapping()) {
123 std::string tag = fmt::format("sunwarp{}", mapping.dots); 126 std::string tag = fmt::format("sunwarp{}", mapping.dots);
124 127
@@ -142,6 +145,11 @@ void SubwayMap::OnConnect() {
142 145
143 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp)); 146 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp));
144 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp)); 147 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp));
148
149 networks_.AddLinkToNetwork(
150 final_sunwarp_item, GD_GetSubwayItemForSunwarp(fromWarp),
151 mapping.dots == 6 ? final_sunwarp_item
152 : GD_GetSubwayItemForSunwarp(toWarp));
145 } 153 }
146 } 154 }
147 155
@@ -555,6 +563,7 @@ void SubwayMap::Redraw() {
555 ItemDrawType draw_type = ItemDrawType::kNone; 563 ItemDrawType draw_type = ItemDrawType::kNone;
556 const wxBrush *brush_color = wxGREY_BRUSH; 564 const wxBrush *brush_color = wxGREY_BRUSH;
557 std::optional<wxColour> shade_color; 565 std::optional<wxColour> shade_color;
566 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
558 567
559 if (AP_HasEarlyColorHallways() && 568 if (AP_HasEarlyColorHallways() &&
560 subway_item.special == "starting_room_paintings") { 569 subway_item.special == "starting_room_paintings") {
@@ -570,6 +579,16 @@ void SubwayMap::Redraw() {
570 brush_color = wxRED_BRUSH; 579 brush_color = wxRED_BRUSH;
571 } 580 }
572 } 581 }
582 } else if (subway_item.sunwarp &&
583 subway_item.sunwarp->type == SubwaySunwarpType::kFinal &&
584 AP_IsPilgrimageEnabled()) {
585 draw_type = ItemDrawType::kBox;
586
587 if (IsPilgrimageDoable()) {
588 brush_color = wxGREEN_BRUSH;
589 } else {
590 brush_color = wxRED_BRUSH;
591 }
573 } else if (!subway_item.paintings.empty()) { 592 } else if (!subway_item.paintings.empty()) {
574 if (AP_IsPaintingShuffle()) { 593 if (AP_IsPaintingShuffle()) {
575 bool has_checked_painting = false; 594 bool has_checked_painting = false;
@@ -606,10 +625,10 @@ void SubwayMap::Redraw() {
606 } else if (!subway_item.tags.empty()) { 625 } else if (!subway_item.tags.empty()) {
607 draw_type = ItemDrawType::kOwl; 626 draw_type = ItemDrawType::kOwl;
608 } 627 }
609 } else if (subway_item.door) { 628 } else if (subway_door) {
610 draw_type = ItemDrawType::kBox; 629 draw_type = ItemDrawType::kBox;
611 630
612 if (IsDoorOpen(*subway_item.door)) { 631 if (IsDoorOpen(*subway_door)) {
613 brush_color = wxGREEN_BRUSH; 632 brush_color = wxGREEN_BRUSH;
614 } else { 633 } else {
615 brush_color = wxRED_BRUSH; 634 brush_color = wxRED_BRUSH;
diff --git a/src/tracker_panel.cpp b/src/tracker_panel.cpp index 2e1497b..27e825a 100644 --- a/src/tracker_panel.cpp +++ b/src/tracker_panel.cpp
@@ -180,7 +180,7 @@ void TrackerPanel::Redraw() {
180 for (AreaIndicator &area : areas_) { 180 for (AreaIndicator &area : areas_) {
181 const MapArea &map_area = GD_GetMapArea(area.area_id); 181 const MapArea &map_area = GD_GetMapArea(area.area_id);
182 if (panels_mode_) { 182 if (panels_mode_) {
183 area.active = map_area.panel; 183 area.active = map_area.has_single_panel;
184 } else if (!AP_IsLocationVisible(map_area.classification) && 184 } else if (!AP_IsLocationVisible(map_area.classification) &&
185 !(map_area.hunt && GetTrackerConfig().show_hunt_panels) && 185 !(map_area.hunt && GetTrackerConfig().show_hunt_panels) &&
186 !(AP_IsPaintingShuffle() && !map_area.paintings.empty())) { 186 !(AP_IsPaintingShuffle() && !map_area.paintings.empty())) {
@@ -200,11 +200,14 @@ void TrackerPanel::Redraw() {
200 if (IsLocationWinCondition(section)) { 200 if (IsLocationWinCondition(section)) {
201 has_unchecked = !AP_HasReachedGoal(); 201 has_unchecked = !AP_HasReachedGoal();
202 } else if (panels_mode_) { 202 } else if (panels_mode_) {
203 has_unchecked = section.panel && std::any_of( 203 if (section.single_panel) {
204 section.panels.begin(), section.panels.end(), [this](int panel_id) { 204 const Panel &panel = GD_GetPanel(*section.single_panel);
205 const Panel &panel = GD_GetPanel(panel_id); 205 if (panel.non_counting) {
206 return !solved_panels_.contains(panel.nodepath); 206 has_unchecked = !AP_HasCheckedGameLocation(section.ap_location_id);
207 }); 207 } else {
208 has_unchecked = !solved_panels_.contains(panel.nodepath);
209 }
210 }
208 } else if (AP_IsLocationVisible(section.classification)) { 211 } else if (AP_IsLocationVisible(section.classification)) {
209 has_unchecked = !AP_HasCheckedGameLocation(section.ap_location_id); 212 has_unchecked = !AP_HasCheckedGameLocation(section.ap_location_id);
210 } else if (section.hunt && GetTrackerConfig().show_hunt_panels) { 213 } else if (section.hunt && GetTrackerConfig().show_hunt_panels) {
@@ -223,9 +226,8 @@ void TrackerPanel::Redraw() {
223 if (AP_IsPaintingShuffle() && !panels_mode_) { 226 if (AP_IsPaintingShuffle() && !panels_mode_) {
224 for (int painting_id : map_area.paintings) { 227 for (int painting_id : map_area.paintings) {
225 const PaintingExit &painting = GD_GetPaintingExit(painting_id); 228 const PaintingExit &painting = GD_GetPaintingExit(painting_id);
226 if (!AP_IsPaintingChecked(painting.internal_id)) { 229 bool reachable = IsPaintingReachable(painting_id);
227 bool reachable = IsPaintingReachable(painting_id); 230 if (!reachable || !AP_IsPaintingChecked(painting.internal_id)) {
228
229 if (reachable) { 231 if (reachable) {
230 has_reachable_unchecked = true; 232 has_reachable_unchecked = true;
231 } else { 233 } else {
diff --git a/src/tracker_state.cpp b/src/tracker_state.cpp index 18bb499..4a49fac 100644 --- a/src/tracker_state.cpp +++ b/src/tracker_state.cpp
@@ -166,6 +166,7 @@ struct TrackerState {
166 std::mutex reachability_mutex; 166 std::mutex reachability_mutex;
167 RequirementCalculator requirements; 167 RequirementCalculator requirements;
168 std::map<int, std::map<std::string, bool>> door_reports; 168 std::map<int, std::map<std::string, bool>> door_reports;
169 bool pilgrimage_doable = false;
169}; 170};
170 171
171enum Decision { kYes, kNo, kMaybe }; 172enum Decision { kYes, kNo, kMaybe };
@@ -375,6 +376,8 @@ class StateCalculator {
375 return door_report_; 376 return door_report_;
376 } 377 }
377 378
379 bool IsPilgrimageDoable() const { return pilgrimage_doable_; }
380
378 std::string GetPathToRoom(int room_id) const { 381 std::string GetPathToRoom(int room_id) const {
379 if (!paths_.count(room_id)) { 382 if (!paths_.count(room_id)) {
380 return ""; 383 return "";
@@ -601,6 +604,8 @@ class StateCalculator {
601 } 604 }
602 } 605 }
603 606
607 pilgrimage_doable_ = true;
608
604 return kYes; 609 return kYes;
605 } 610 }
606 611
@@ -641,6 +646,7 @@ class StateCalculator {
641 std::set<int> solveable_panels_; 646 std::set<int> solveable_panels_;
642 std::set<int> reachable_paintings_; 647 std::set<int> reachable_paintings_;
643 std::map<int, std::map<std::string, bool>> door_report_; 648 std::map<int, std::map<std::string, bool>> door_report_;
649 bool pilgrimage_doable_ = false;
644 650
645 std::map<int, std::list<int>> paths_; 651 std::map<int, std::list<int>> paths_;
646}; 652};
@@ -692,6 +698,7 @@ void RecalculateReachability() {
692 std::swap(GetState().reachable_doors, new_reachable_doors); 698 std::swap(GetState().reachable_doors, new_reachable_doors);
693 std::swap(GetState().reachable_paintings, reachable_paintings); 699 std::swap(GetState().reachable_paintings, reachable_paintings);
694 std::swap(GetState().door_reports, door_reports); 700 std::swap(GetState().door_reports, door_reports);
701 GetState().pilgrimage_doable = state_calculator.IsPilgrimageDoable();
695} 702}
696 703
697bool IsLocationReachable(int location_id) { 704bool IsLocationReachable(int location_id) {
@@ -721,3 +728,9 @@ const std::map<std::string, bool>& GetDoorRequirements(int door_id) {
721 728
722 return GetState().door_reports[door_id]; 729 return GetState().door_reports[door_id];
723} 730}
731
732bool IsPilgrimageDoable() {
733 std::lock_guard reachability_guard(GetState().reachability_mutex);
734
735 return GetState().pilgrimage_doable;
736}
diff --git a/src/tracker_state.h b/src/tracker_state.h index c7857a0..a8f155d 100644 --- a/src/tracker_state.h +++ b/src/tracker_state.h
@@ -16,4 +16,6 @@ bool IsPaintingReachable(int painting_id);
16 16
17const std::map<std::string, bool>& GetDoorRequirements(int door_id); 17const std::map<std::string, bool>& GetDoorRequirements(int door_id);
18 18
19bool IsPilgrimageDoable();
20
19#endif /* end of include guard: TRACKER_STATE_H_8639BC90 */ 21#endif /* end of include guard: TRACKER_STATE_H_8639BC90 */
diff --git a/src/version.h b/src/version.h index ed5e97c..24c04b4 100644 --- a/src/version.h +++ b/src/version.h
@@ -36,6 +36,6 @@ struct Version {
36 } 36 }
37}; 37};
38 38
39constexpr const Version kTrackerVersion = Version(0, 11, 0); 39constexpr const Version kTrackerVersion = Version(0, 11, 1);
40 40
41#endif /* end of include guard: VERSION_H_C757E53C */ \ No newline at end of file 41#endif /* end of include guard: VERSION_H_C757E53C */ \ No newline at end of file