about summary refs log tree commit diff stats
path: root/src/subway_map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/subway_map.cpp')
-rw-r--r--src/subway_map.cpp136
1 files changed, 111 insertions, 25 deletions
diff --git a/src/subway_map.cpp b/src/subway_map.cpp index e3b844d..f896693 100644 --- a/src/subway_map.cpp +++ b/src/subway_map.cpp
@@ -16,6 +16,28 @@ constexpr int OWL_ACTUAL_SIZE = 32;
16 16
17enum class ItemDrawType { kNone, kBox, kOwl }; 17enum class ItemDrawType { kNone, kBox, kOwl };
18 18
19namespace {
20
21std::optional<int> GetRealSubwayDoor(const SubwayItem subway_item) {
22 if (AP_IsSunwarpShuffle() && subway_item.sunwarp &&
23 subway_item.sunwarp->type != SubwaySunwarpType::kFinal) {
24 int sunwarp_index = subway_item.sunwarp->dots - 1;
25 if (subway_item.sunwarp->type == SubwaySunwarpType::kExit) {
26 sunwarp_index += 6;
27 }
28
29 for (const auto &[start_index, mapping] : AP_GetSunwarpMapping()) {
30 if (start_index == sunwarp_index || mapping.exit_index == sunwarp_index) {
31 return GD_GetSunwarpDoors().at(mapping.dots - 1);
32 }
33 }
34 }
35
36 return subway_item.door;
37}
38
39} // namespace
40
19SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) { 41SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) {
20 SetBackgroundStyle(wxBG_STYLE_PAINT); 42 SetBackgroundStyle(wxBG_STYLE_PAINT);
21 43
@@ -69,10 +91,12 @@ void SubwayMap::OnConnect() {
69 networks_.Clear(); 91 networks_.Clear();
70 92
71 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;
72 for (const SubwayItem &subway_item : GD_GetSubwayItems()) { 96 for (const SubwayItem &subway_item : GD_GetSubwayItems()) {
73 if (AP_HasEarlyColorHallways() && 97 if (AP_HasEarlyColorHallways() &&
74 subway_item.special == "starting_room_paintings") { 98 subway_item.special == "starting_room_paintings") {
75 tagged["early_ch"].push_back(subway_item.id); 99 entrances["early_ch"].push_back(subway_item.id);
76 } 100 }
77 101
78 if (AP_IsPaintingShuffle() && !subway_item.paintings.empty()) { 102 if (AP_IsPaintingShuffle() && !subway_item.paintings.empty()) {
@@ -82,21 +106,40 @@ void SubwayMap::OnConnect() {
82 for (const std::string &tag : subway_item.tags) { 106 for (const std::string &tag : subway_item.tags) {
83 tagged[tag].push_back(subway_item.id); 107 tagged[tag].push_back(subway_item.id);
84 } 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 }
85 115
86 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp && 116 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp) {
87 subway_item.sunwarp->type != SubwaySunwarpType::kFinal) { 117 std::string tag = fmt::format("sunwarp{}", subway_item.sunwarp->dots);
88 std::string tag = fmt::format("subway{}", subway_item.sunwarp->dots); 118 switch (subway_item.sunwarp->type) {
89 tagged[tag].push_back(subway_item.id); 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 }
90 } 128 }
91 129
92 if (!AP_IsPilgrimageEnabled() && 130 if (!AP_IsPilgrimageEnabled()) {
93 (subway_item.special == "sun_painting" || 131 if (subway_item.special == "sun_painting") {
94 subway_item.special == "sun_painting_exit")) { 132 entrances["sun_painting"].push_back(subway_item.id);
95 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 }
96 } 136 }
97 } 137 }
98 138
99 if (AP_IsSunwarpShuffle()) { 139 if (AP_IsSunwarpShuffle()) {
140 SubwaySunwarp final_sunwarp{.dots = 6, .type = SubwaySunwarpType::kFinal};
141 int final_sunwarp_item = GD_GetSubwayItemForSunwarp(final_sunwarp);
142
100 for (const auto &[index, mapping] : AP_GetSunwarpMapping()) { 143 for (const auto &[index, mapping] : AP_GetSunwarpMapping()) {
101 std::string tag = fmt::format("sunwarp{}", mapping.dots); 144 std::string tag = fmt::format("sunwarp{}", mapping.dots);
102 145
@@ -118,8 +161,14 @@ void SubwayMap::OnConnect() {
118 toWarp.type = SubwaySunwarpType::kExit; 161 toWarp.type = SubwaySunwarpType::kExit;
119 } 162 }
120 163
121 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp)); 164 entrances[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp));
122 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp)); 165 exits[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp));
166
167 networks_.AddLinkToNetwork(
168 final_sunwarp_item, GD_GetSubwayItemForSunwarp(fromWarp),
169 mapping.dots == 6 ? final_sunwarp_item
170 : GD_GetSubwayItemForSunwarp(toWarp),
171 false);
123 } 172 }
124 } 173 }
125 174
@@ -129,7 +178,17 @@ void SubwayMap::OnConnect() {
129 tag_it1++) { 178 tag_it1++) {
130 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();
131 tag_it2++) { 180 tag_it2++) {
132 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);
133 } 192 }
134 } 193 }
135 } 194 }
@@ -149,7 +208,7 @@ void SubwayMap::UpdateIndicators() {
149 AP_GetPaintingMapping().at(painting_id)); 208 AP_GetPaintingMapping().at(painting_id));
150 209
151 if (from_id && to_id) { 210 if (from_id && to_id) {
152 networks_.AddLink(*from_id, *to_id); 211 networks_.AddLink(*from_id, *to_id, false);
153 } 212 }
154 } 213 }
155 } 214 }
@@ -162,7 +221,7 @@ void SubwayMap::UpdateIndicators() {
162void SubwayMap::UpdateSunwarp(SubwaySunwarp from_sunwarp, 221void SubwayMap::UpdateSunwarp(SubwaySunwarp from_sunwarp,
163 SubwaySunwarp to_sunwarp) { 222 SubwaySunwarp to_sunwarp) {
164 networks_.AddLink(GD_GetSubwayItemForSunwarp(from_sunwarp), 223 networks_.AddLink(GD_GetSubwayItemForSunwarp(from_sunwarp),
165 GD_GetSubwayItemForSunwarp(to_sunwarp)); 224 GD_GetSubwayItemForSunwarp(to_sunwarp), false);
166} 225}
167 226
168void SubwayMap::Zoom(bool in) { 227void SubwayMap::Zoom(bool in) {
@@ -267,9 +326,11 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
267 // Note that these requirements are duplicated on OnMouseClick so that it 326 // Note that these requirements are duplicated on OnMouseClick so that it
268 // knows when an item has a hover effect. 327 // knows when an item has a hover effect.
269 const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_); 328 const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_);
270 if (subway_item.door && !GetDoorRequirements(*subway_item.door).empty()) { 329 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
330
331 if (subway_door && !GetDoorRequirements(*subway_door).empty()) {
271 const std::map<std::string, bool> &report = 332 const std::map<std::string, bool> &report =
272 GetDoorRequirements(*subway_item.door); 333 GetDoorRequirements(*subway_door);
273 334
274 int acc_height = 10; 335 int acc_height = 10;
275 int col_width = 0; 336 int col_width = 0;
@@ -326,10 +387,9 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
326 if (networks_.IsItemInNetwork(*hovered_item_)) { 387 if (networks_.IsItemInNetwork(*hovered_item_)) {
327 dc.SetBrush(*wxTRANSPARENT_BRUSH); 388 dc.SetBrush(*wxTRANSPARENT_BRUSH);
328 389
329 for (const auto &[item_id1, item_id2] : 390 for (const auto node : networks_.GetNetworkGraph(*hovered_item_)) {
330 networks_.GetNetworkGraph(*hovered_item_)) { 391 const SubwayItem &item1 = GD_GetSubwayItem(node.entry);
331 const SubwayItem &item1 = GD_GetSubwayItem(item_id1); 392 const SubwayItem &item2 = GD_GetSubwayItem(node.exit);
332 const SubwayItem &item2 = GD_GetSubwayItem(item_id2);
333 393
334 wxPoint item1_pos = MapPosToRenderPos( 394 wxPoint item1_pos = MapPosToRenderPos(
335 {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});
@@ -349,6 +409,12 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
349 dc.DrawLine(item1_pos, item2_pos); 409 dc.DrawLine(item1_pos, item2_pos);
350 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2)); 410 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2));
351 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 }
352 } else { 418 } else {
353 int ellipse_x; 419 int ellipse_x;
354 int ellipse_y; 420 int ellipse_y;
@@ -391,6 +457,12 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
391 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2)); 457 dc.SetPen(*wxThePenList->FindOrCreatePen(*wxCYAN, 2));
392 dc.DrawEllipticArc(ellipse_x, ellipse_y, halfwidth * 2, 458 dc.DrawEllipticArc(ellipse_x, ellipse_y, halfwidth * 2,
393 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 }
394 } 466 }
395 } 467 }
396 } 468 }
@@ -450,7 +522,9 @@ void SubwayMap::OnMouseClick(wxMouseEvent &event) {
450 522
451 if (actual_hover_) { 523 if (actual_hover_) {
452 const SubwayItem &subway_item = GD_GetSubwayItem(*actual_hover_); 524 const SubwayItem &subway_item = GD_GetSubwayItem(*actual_hover_);
453 if ((subway_item.door && !GetDoorRequirements(*subway_item.door).empty()) || 525 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
526
527 if ((subway_door && !GetDoorRequirements(*subway_door).empty()) ||
454 networks_.IsItemInNetwork(*hovered_item_)) { 528 networks_.IsItemInNetwork(*hovered_item_)) {
455 if (actual_hover_ != hovered_item_) { 529 if (actual_hover_ != hovered_item_) {
456 hovered_item_ = actual_hover_; 530 hovered_item_ = actual_hover_;
@@ -509,7 +583,8 @@ void SubwayMap::OnClickHelp(wxCommandEvent &event) {
509 "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 "
510 "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 "
511 "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 "
512 "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 "
513 "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 "
514 "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 "
515 "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 "
@@ -529,6 +604,7 @@ void SubwayMap::Redraw() {
529 ItemDrawType draw_type = ItemDrawType::kNone; 604 ItemDrawType draw_type = ItemDrawType::kNone;
530 const wxBrush *brush_color = wxGREY_BRUSH; 605 const wxBrush *brush_color = wxGREY_BRUSH;
531 std::optional<wxColour> shade_color; 606 std::optional<wxColour> shade_color;
607 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
532 608
533 if (AP_HasEarlyColorHallways() && 609 if (AP_HasEarlyColorHallways() &&
534 subway_item.special == "starting_room_paintings") { 610 subway_item.special == "starting_room_paintings") {
@@ -544,6 +620,16 @@ void SubwayMap::Redraw() {
544 brush_color = wxRED_BRUSH; 620 brush_color = wxRED_BRUSH;
545 } 621 }
546 } 622 }
623 } else if (subway_item.sunwarp &&
624 subway_item.sunwarp->type == SubwaySunwarpType::kFinal &&
625 AP_IsPilgrimageEnabled()) {
626 draw_type = ItemDrawType::kBox;
627
628 if (IsPilgrimageDoable()) {
629 brush_color = wxGREEN_BRUSH;
630 } else {
631 brush_color = wxRED_BRUSH;
632 }
547 } else if (!subway_item.paintings.empty()) { 633 } else if (!subway_item.paintings.empty()) {
548 if (AP_IsPaintingShuffle()) { 634 if (AP_IsPaintingShuffle()) {
549 bool has_checked_painting = false; 635 bool has_checked_painting = false;
@@ -577,13 +663,13 @@ void SubwayMap::Redraw() {
577 } 663 }
578 } 664 }
579 } 665 }
580 } else if (!subway_item.tags.empty()) { 666 } else if (subway_item.HasWarps()) {
581 draw_type = ItemDrawType::kOwl; 667 draw_type = ItemDrawType::kOwl;
582 } 668 }
583 } else if (subway_item.door) { 669 } else if (subway_door) {
584 draw_type = ItemDrawType::kBox; 670 draw_type = ItemDrawType::kBox;
585 671
586 if (IsDoorOpen(*subway_item.door)) { 672 if (IsDoorOpen(*subway_door)) {
587 brush_color = wxGREEN_BRUSH; 673 brush_color = wxGREEN_BRUSH;
588 } else { 674 } else {
589 brush_color = wxRED_BRUSH; 675 brush_color = wxRED_BRUSH;