diff options
Diffstat (limited to 'src/subway_map.cpp')
-rw-r--r-- | src/subway_map.cpp | 136 |
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 | ||
17 | enum class ItemDrawType { kNone, kBox, kOwl }; | 17 | enum class ItemDrawType { kNone, kBox, kOwl }; |
18 | 18 | ||
19 | namespace { | ||
20 | |||
21 | std::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 | |||
19 | SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) { | 41 | SubwayMap::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() { | |||
162 | void SubwayMap::UpdateSunwarp(SubwaySunwarp from_sunwarp, | 221 | void 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 | ||
168 | void SubwayMap::Zoom(bool in) { | 227 | void 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; |