about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game_data.cpp17
-rw-r--r--src/game_data.h6
-rw-r--r--src/network_set.cpp29
-rw-r--r--src/network_set.h16
-rw-r--r--src/subway_map.cpp83
-rw-r--r--src/tracker_frame.cpp1
-rw-r--r--src/version.h2
7 files changed, 117 insertions, 37 deletions
diff --git a/src/game_data.cpp b/src/game_data.cpp index 4d448d3..828808f 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -756,6 +756,18 @@ struct GameData {
756 } 756 }
757 } 757 }
758 758
759 if (subway_it["entrances"]) {
760 for (const auto &entrance_it : subway_it["entrances"]) {
761 subway_item.entrances.push_back(entrance_it.as<std::string>());
762 }
763 }
764
765 if (subway_it["exits"]) {
766 for (const auto &exit_it : subway_it["exits"]) {
767 subway_item.exits.push_back(exit_it.as<std::string>());
768 }
769 }
770
759 if (subway_it["sunwarp"]) { 771 if (subway_it["sunwarp"]) {
760 SubwaySunwarp sunwarp; 772 SubwaySunwarp sunwarp;
761 sunwarp.dots = subway_it["sunwarp"]["dots"].as<int>(); 773 sunwarp.dots = subway_it["sunwarp"]["dots"].as<int>();
@@ -879,6 +891,11 @@ GameData &GetState() {
879 891
880} // namespace 892} // namespace
881 893
894bool SubwayItem::HasWarps() const {
895 return !(this->tags.empty() && this->entrances.empty() &&
896 this->exits.empty());
897}
898
882bool SubwaySunwarp::operator<(const SubwaySunwarp &rhs) const { 899bool SubwaySunwarp::operator<(const SubwaySunwarp &rhs) const {
883 return std::tie(dots, type) < std::tie(rhs.dots, rhs.type); 900 return std::tie(dots, type) < std::tie(rhs.dots, rhs.type);
884} 901}
diff --git a/src/game_data.h b/src/game_data.h index 9b6f3b2..b00bac9 100644 --- a/src/game_data.h +++ b/src/game_data.h
@@ -155,9 +155,13 @@ struct SubwayItem {
155 int y; 155 int y;
156 std::optional<int> door; 156 std::optional<int> door;
157 std::vector<std::string> paintings; 157 std::vector<std::string> paintings;
158 std::vector<std::string> tags; 158 std::vector<std::string> tags; // 2-way teleports
159 std::vector<std::string> entrances; // teleport entrances
160 std::vector<std::string> exits; // teleport exits
159 std::optional<SubwaySunwarp> sunwarp; 161 std::optional<SubwaySunwarp> sunwarp;
160 std::optional<std::string> special; 162 std::optional<std::string> special;
163
164 bool HasWarps() const;
161}; 165};
162 166
163const std::vector<MapArea>& GD_GetMapAreas(); 167const std::vector<MapArea>& GD_GetMapAreas();
diff --git a/src/network_set.cpp b/src/network_set.cpp index 2a9e12c..45911e3 100644 --- a/src/network_set.cpp +++ b/src/network_set.cpp
@@ -4,9 +4,8 @@ void NetworkSet::Clear() {
4 network_by_item_.clear(); 4 network_by_item_.clear();
5} 5}
6 6
7void NetworkSet::AddLink(int id1, int id2) { 7void NetworkSet::AddLink(int id1, int id2, bool two_way) {
8 if (id2 > id1) { 8 if (two_way && id2 > id1) {
9 // Make sure id1 < id2
10 std::swap(id1, id2); 9 std::swap(id1, id2);
11 } 10 }
12 11
@@ -17,13 +16,14 @@ void NetworkSet::AddLink(int id1, int id2) {
17 network_by_item_[id2] = {}; 16 network_by_item_[id2] = {};
18 } 17 }
19 18
20 network_by_item_[id1].insert({id1, id2}); 19 NetworkNode node = {id1, id2, two_way};
21 network_by_item_[id2].insert({id1, id2}); 20
21 network_by_item_[id1].insert(node);
22 network_by_item_[id2].insert(node);
22} 23}
23 24
24void NetworkSet::AddLinkToNetwork(int network_id, int id1, int id2) { 25void NetworkSet::AddLinkToNetwork(int network_id, int id1, int id2, bool two_way) {
25 if (id2 > id1) { 26 if (two_way && id2 > id1) {
26 // Make sure id1 < id2
27 std::swap(id1, id2); 27 std::swap(id1, id2);
28 } 28 }
29 29
@@ -31,13 +31,22 @@ void NetworkSet::AddLinkToNetwork(int network_id, int id1, int id2) {
31 network_by_item_[network_id] = {}; 31 network_by_item_[network_id] = {};
32 } 32 }
33 33
34 network_by_item_[network_id].insert({id1, id2}); 34 NetworkNode node = {id1, id2, two_way};
35
36 network_by_item_[network_id].insert(node);
35} 37}
36 38
37bool NetworkSet::IsItemInNetwork(int id) const { 39bool NetworkSet::IsItemInNetwork(int id) const {
38 return network_by_item_.count(id); 40 return network_by_item_.count(id);
39} 41}
40 42
41const std::set<std::pair<int, int>>& NetworkSet::GetNetworkGraph(int id) const { 43const std::set<NetworkNode>& NetworkSet::GetNetworkGraph(int id) const {
42 return network_by_item_.at(id); 44 return network_by_item_.at(id);
43} 45}
46
47bool NetworkNode::operator<(const NetworkNode& rhs) const {
48 if (entry != rhs.entry) return entry < rhs.entry;
49 if (exit != rhs.exit) return exit < rhs.exit;
50 if (two_way != rhs.two_way) return two_way < rhs.two_way;
51 return false;
52}
diff --git a/src/network_set.h b/src/network_set.h index cec3f39..0f72052 100644 --- a/src/network_set.h +++ b/src/network_set.h
@@ -7,21 +7,29 @@
7#include <utility> 7#include <utility>
8#include <vector> 8#include <vector>
9 9
10struct NetworkNode {
11 int entry;
12 int exit;
13 bool two_way;
14
15 bool operator<(const NetworkNode& rhs) const;
16};
17
10class NetworkSet { 18class NetworkSet {
11 public: 19 public:
12 void Clear(); 20 void Clear();
13 21
14 void AddLink(int id1, int id2); 22 void AddLink(int id1, int id2, bool two_way);
15 23
16 void AddLinkToNetwork(int network_id, int id1, int id2); 24 void AddLinkToNetwork(int network_id, int id1, int id2, bool two_way);
17 25
18 bool IsItemInNetwork(int id) const; 26 bool IsItemInNetwork(int id) const;
19 27
20 const std::set<std::pair<int, int>>& GetNetworkGraph(int id) const; 28 const std::set<NetworkNode>& GetNetworkGraph(int id) const;
21 29
22 private: 30 private:
23 31
24 std::map<int, std::set<std::pair<int, int>>> network_by_item_; 32 std::map<int, std::set<NetworkNode>> network_by_item_;
25}; 33};
26 34
27#endif /* end of include guard: NETWORK_SET_H_3036B8E3 */ 35#endif /* end of include guard: NETWORK_SET_H_3036B8E3 */
diff --git a/src/subway_map.cpp b/src/subway_map.cpp index 5b3ff5f..f896693 100644 --- a/src/subway_map.cpp +++ b/src/subway_map.cpp
@@ -91,10 +91,12 @@ void SubwayMap::OnConnect() {
91 networks_.Clear(); 91 networks_.Clear();
92 92
93 std::map<std::string, std::vector<int>> tagged; 93 std::map<std::string, std::vector<int>> tagged;
94 std::map<std::string, std::vector<int>> entrances;
95 std::map<std::string, std::vector<int>> exits;
94 for (const SubwayItem &subway_item : GD_GetSubwayItems()) { 96 for (const SubwayItem &subway_item : GD_GetSubwayItems()) {
95 if (AP_HasEarlyColorHallways() && 97 if (AP_HasEarlyColorHallways() &&
96 subway_item.special == "starting_room_paintings") { 98 subway_item.special == "starting_room_paintings") {
97 tagged["early_ch"].push_back(subway_item.id); 99 entrances["early_ch"].push_back(subway_item.id);
98 } 100 }
99 101
100 if (AP_IsPaintingShuffle() && !subway_item.paintings.empty()) { 102 if (AP_IsPaintingShuffle() && !subway_item.paintings.empty()) {
@@ -104,17 +106,33 @@ void SubwayMap::OnConnect() {
104 for (const std::string &tag : subway_item.tags) { 106 for (const std::string &tag : subway_item.tags) {
105 tagged[tag].push_back(subway_item.id); 107 tagged[tag].push_back(subway_item.id);
106 } 108 }
109 for (const std::string &tag : subway_item.entrances) {
110 entrances[tag].push_back(subway_item.id);
111 }
112 for (const std::string &tag : subway_item.exits) {
113 exits[tag].push_back(subway_item.id);
114 }
107 115
108 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp && 116 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp) {
109 subway_item.sunwarp->type != SubwaySunwarpType::kFinal) {
110 std::string tag = fmt::format("sunwarp{}", subway_item.sunwarp->dots); 117 std::string tag = fmt::format("sunwarp{}", subway_item.sunwarp->dots);
111 tagged[tag].push_back(subway_item.id); 118 switch (subway_item.sunwarp->type) {
119 case SubwaySunwarpType::kEnter:
120 entrances[tag].push_back(subway_item.id);
121 break;
122 case SubwaySunwarpType::kExit:
123 exits[tag].push_back(subway_item.id);
124 break;
125 default:
126 break;
127 }
112 } 128 }
113 129
114 if (!AP_IsPilgrimageEnabled() && 130 if (!AP_IsPilgrimageEnabled()) {
115 (subway_item.special == "sun_painting" || 131 if (subway_item.special == "sun_painting") {
116 subway_item.special == "sun_painting_exit")) { 132 entrances["sun_painting"].push_back(subway_item.id);
117 tagged["sun_painting"].push_back(subway_item.id); 133 } else if (subway_item.special == "sun_painting_exit") {
134 exits["sun_painting"].push_back(subway_item.id);
135 }
118 } 136 }
119 } 137 }
120 138
@@ -143,13 +161,14 @@ void SubwayMap::OnConnect() {
143 toWarp.type = SubwaySunwarpType::kExit; 161 toWarp.type = SubwaySunwarpType::kExit;
144 } 162 }
145 163
146 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp)); 164 entrances[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp));
147 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp)); 165 exits[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp));
148 166
149 networks_.AddLinkToNetwork( 167 networks_.AddLinkToNetwork(
150 final_sunwarp_item, GD_GetSubwayItemForSunwarp(fromWarp), 168 final_sunwarp_item, GD_GetSubwayItemForSunwarp(fromWarp),
151 mapping.dots == 6 ? final_sunwarp_item 169 mapping.dots == 6 ? final_sunwarp_item
152 : GD_GetSubwayItemForSunwarp(toWarp)); 170 : GD_GetSubwayItemForSunwarp(toWarp),
171 false);
153 } 172 }
154 } 173 }
155 174
@@ -159,7 +178,17 @@ void SubwayMap::OnConnect() {
159 tag_it1++) { 178 tag_it1++) {
160 for (auto tag_it2 = std::next(tag_it1); tag_it2 != items.end(); 179 for (auto tag_it2 = std::next(tag_it1); tag_it2 != items.end();
161 tag_it2++) { 180 tag_it2++) {
162 networks_.AddLink(*tag_it1, *tag_it2); 181 // two links because tags are bi-directional
182 networks_.AddLink(*tag_it1, *tag_it2, true);
183 }
184 }
185 }
186
187 for (const auto &[tag, items] : entrances) {
188 if (!exits.contains(tag)) continue;
189 for (auto exit : exits[tag]) {
190 for (auto entrance : items) {
191 networks_.AddLink(entrance, exit, false);
163 } 192 }
164 } 193 }
165 } 194 }
@@ -179,7 +208,7 @@ void SubwayMap::UpdateIndicators() {
179 AP_GetPaintingMapping().at(painting_id)); 208 AP_GetPaintingMapping().at(painting_id));
180 209
181 if (from_id && to_id) { 210 if (from_id && to_id) {
182 networks_.AddLink(*from_id, *to_id); 211 networks_.AddLink(*from_id, *to_id, false);
183 } 212 }
184 } 213 }
185 } 214 }
@@ -192,7 +221,7 @@ void SubwayMap::UpdateIndicators() {
192void SubwayMap::UpdateSunwarp(SubwaySunwarp from_sunwarp, 221void SubwayMap::UpdateSunwarp(SubwaySunwarp from_sunwarp,
193 SubwaySunwarp to_sunwarp) { 222 SubwaySunwarp to_sunwarp) {
194 networks_.AddLink(GD_GetSubwayItemForSunwarp(from_sunwarp), 223 networks_.AddLink(GD_GetSubwayItemForSunwarp(from_sunwarp),
195 GD_GetSubwayItemForSunwarp(to_sunwarp)); 224 GD_GetSubwayItemForSunwarp(to_sunwarp), false);
196} 225}
197 226
198void SubwayMap::Zoom(bool in) { 227void SubwayMap::Zoom(bool in) {
@@ -358,10 +387,9 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
358 if (networks_.IsItemInNetwork(*hovered_item_)) { 387 if (networks_.IsItemInNetwork(*hovered_item_)) {
359 dc.SetBrush(*wxTRANSPARENT_BRUSH); 388 dc.SetBrush(*wxTRANSPARENT_BRUSH);
360 389
361 for (const auto &[item_id1, item_id2] : 390 for (const auto node : networks_.GetNetworkGraph(*hovered_item_)) {
362 networks_.GetNetworkGraph(*hovered_item_)) { 391 const SubwayItem &item1 = GD_GetSubwayItem(node.entry);
363 const SubwayItem &item1 = GD_GetSubwayItem(item_id1); 392 const SubwayItem &item2 = GD_GetSubwayItem(node.exit);
364 const SubwayItem &item2 = GD_GetSubwayItem(item_id2);
365 393
366 wxPoint item1_pos = MapPosToRenderPos( 394 wxPoint item1_pos = MapPosToRenderPos(
367 {item1.x + AREA_ACTUAL_SIZE / 2, item1.y + AREA_ACTUAL_SIZE / 2}); 395 {item1.x + AREA_ACTUAL_SIZE / 2, item1.y + AREA_ACTUAL_SIZE / 2});
@@ -381,6 +409,12 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
381 dc.DrawLine(item1_pos, item2_pos); 409 dc.DrawLine(item1_pos, item2_pos);
382 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2)); 410 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2));
383 dc.DrawLine(item1_pos, item2_pos); 411 dc.DrawLine(item1_pos, item2_pos);
412 if (!node.two_way) {
413 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 2));
414 dc.SetBrush(*wxCYAN_BRUSH);
415 dc.DrawCircle(item2_pos, 4);
416 dc.SetBrush(*wxTRANSPARENT_BRUSH);
417 }
384 } else { 418 } else {
385 int ellipse_x; 419 int ellipse_x;
386 int ellipse_y; 420 int ellipse_y;
@@ -423,6 +457,12 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
423 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2)); 457 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2));
424 dc.DrawEllipticArc(ellipse_x, ellipse_y, halfwidth * 2, 458 dc.DrawEllipticArc(ellipse_x, ellipse_y, halfwidth * 2,
425 halfheight * 2, start, end); 459 halfheight * 2, start, end);
460 if (!node.two_way) {
461 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 2));
462 dc.SetBrush(*wxCYAN_BRUSH);
463 dc.DrawCircle(item2_pos, 4);
464 dc.SetBrush(*wxTRANSPARENT_BRUSH);
465 }
426 } 466 }
427 } 467 }
428 } 468 }
@@ -543,7 +583,8 @@ void SubwayMap::OnClickHelp(wxCommandEvent &event) {
543 "corner.\nClick on a side of the screen to start panning. It will follow " 583 "corner.\nClick on a side of the screen to start panning. It will follow "
544 "your mouse. Click again to stop.\nHover over a door to see the " 584 "your mouse. Click again to stop.\nHover over a door to see the "
545 "requirements to open it.\nHover over a warp or active painting to see " 585 "requirements to open it.\nHover over a warp or active painting to see "
546 "what it is connected to.\nIn painting shuffle, paintings that have not " 586 "what it is connected to.\nFor one-way connections, there will be a "
587 "circle at the exit.\nIn painting shuffle, paintings that have not "
547 "yet been checked will not show their connections.\nA green shaded owl " 588 "yet been checked will not show their connections.\nA green shaded owl "
548 "means that there is a painting entrance there.\nA red shaded owl means " 589 "means that there is a painting entrance there.\nA red shaded owl means "
549 "that there are only painting exits there.\nClick on a door or " 590 "that there are only painting exits there.\nClick on a door or "
@@ -622,7 +663,7 @@ void SubwayMap::Redraw() {
622 } 663 }
623 } 664 }
624 } 665 }
625 } else if (!subway_item.tags.empty()) { 666 } else if (subway_item.HasWarps()) {
626 draw_type = ItemDrawType::kOwl; 667 draw_type = ItemDrawType::kOwl;
627 } 668 }
628 } else if (subway_door) { 669 } else if (subway_door) {
diff --git a/src/tracker_frame.cpp b/src/tracker_frame.cpp index 3b6beda..b9282f5 100644 --- a/src/tracker_frame.cpp +++ b/src/tracker_frame.cpp
@@ -137,6 +137,7 @@ void TrackerFrame::OnAbout(wxCommandEvent &event) {
137 about_info.SetName("Lingo Archipelago Tracker"); 137 about_info.SetName("Lingo Archipelago Tracker");
138 about_info.SetVersion(kTrackerVersion.ToString()); 138 about_info.SetVersion(kTrackerVersion.ToString());
139 about_info.AddDeveloper("hatkirby"); 139 about_info.AddDeveloper("hatkirby");
140 about_info.AddDeveloper("art0007i");
140 about_info.AddArtist("Brenton Wildes"); 141 about_info.AddArtist("Brenton Wildes");
141 about_info.AddArtist("kinrah"); 142 about_info.AddArtist("kinrah");
142 143
diff --git a/src/version.h b/src/version.h index 24c04b4..ec52f44 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, 1); 39constexpr const Version kTrackerVersion = Version(0, 11, 2);
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