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.cpp293
1 files changed, 157 insertions, 136 deletions
diff --git a/src/subway_map.cpp b/src/subway_map.cpp index 0a250fb..55ac411 100644 --- a/src/subway_map.cpp +++ b/src/subway_map.cpp
@@ -9,12 +9,28 @@
9#include "ap_state.h" 9#include "ap_state.h"
10#include "game_data.h" 10#include "game_data.h"
11#include "global.h" 11#include "global.h"
12#include "report_popup.h"
12#include "tracker_state.h" 13#include "tracker_state.h"
13 14
14constexpr int AREA_ACTUAL_SIZE = 21; 15constexpr int AREA_ACTUAL_SIZE = 21;
15constexpr int OWL_ACTUAL_SIZE = 32; 16constexpr int OWL_ACTUAL_SIZE = 32;
17constexpr int PAINTING_RADIUS = 9; // the actual circles on the map are radius 11
18constexpr int PAINTING_EXIT_RADIUS = 6;
16 19
17enum class ItemDrawType { kNone, kBox, kOwl }; 20enum class ItemDrawType { kNone, kBox, kOwl, kOwlExit };
21
22namespace {
23
24wxPoint GetSubwayItemMapCenter(const SubwayItem &subway_item) {
25 if (subway_item.painting) {
26 return {subway_item.x, subway_item.y};
27 } else {
28 return {subway_item.x + AREA_ACTUAL_SIZE / 2,
29 subway_item.y + AREA_ACTUAL_SIZE / 2};
30 }
31}
32
33} // namespace
18 34
19SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) { 35SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) {
20 SetBackgroundStyle(wxBG_STYLE_PAINT); 36 SetBackgroundStyle(wxBG_STYLE_PAINT);
@@ -31,14 +47,6 @@ SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) {
31 return; 47 return;
32 } 48 }
33 49
34 unchecked_eye_ =
35 wxBitmap(wxImage(GetAbsolutePath("assets/unchecked.png").c_str(),
36 wxBITMAP_TYPE_PNG)
37 .Scale(32, 32));
38 checked_eye_ = wxBitmap(
39 wxImage(GetAbsolutePath("assets/checked.png").c_str(), wxBITMAP_TYPE_PNG)
40 .Scale(32, 32));
41
42 tree_ = std::make_unique<quadtree::Quadtree<int, GetItemBox>>( 50 tree_ = std::make_unique<quadtree::Quadtree<int, GetItemBox>>(
43 quadtree::Box<float>{0, 0, static_cast<float>(map_image_.GetWidth()), 51 quadtree::Box<float>{0, 0, static_cast<float>(map_image_.GetWidth()),
44 static_cast<float>(map_image_.GetHeight())}); 52 static_cast<float>(map_image_.GetHeight())});
@@ -57,12 +65,14 @@ SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) {
57 Bind(wxEVT_LEFT_DOWN, &SubwayMap::OnMouseClick, this); 65 Bind(wxEVT_LEFT_DOWN, &SubwayMap::OnMouseClick, this);
58 Bind(wxEVT_TIMER, &SubwayMap::OnTimer, this); 66 Bind(wxEVT_TIMER, &SubwayMap::OnTimer, this);
59 67
60 zoom_slider_ = new wxSlider(this, wxID_ANY, 0, 0, 8, {15, 15}); 68 zoom_slider_ = new wxSlider(this, wxID_ANY, 0, 0, 8, FromDIP(wxPoint{15, 15}));
61 zoom_slider_->Bind(wxEVT_SLIDER, &SubwayMap::OnZoomSlide, this); 69 zoom_slider_->Bind(wxEVT_SLIDER, &SubwayMap::OnZoomSlide, this);
62 70
63 help_button_ = new wxButton(this, wxID_ANY, "Help"); 71 help_button_ = new wxButton(this, wxID_ANY, "Help");
64 help_button_->Bind(wxEVT_BUTTON, &SubwayMap::OnClickHelp, this); 72 help_button_->Bind(wxEVT_BUTTON, &SubwayMap::OnClickHelp, this);
65 SetUpHelpButton(); 73 SetUpHelpButton();
74
75 report_popup_ = new ReportPopup(this);
66} 76}
67 77
68void SubwayMap::OnConnect() { 78void SubwayMap::OnConnect() {
@@ -73,11 +83,11 @@ void SubwayMap::OnConnect() {
73 std::map<std::string, std::vector<int>> exits; 83 std::map<std::string, std::vector<int>> exits;
74 for (const SubwayItem &subway_item : GD_GetSubwayItems()) { 84 for (const SubwayItem &subway_item : GD_GetSubwayItems()) {
75 if (AP_HasEarlyColorHallways() && 85 if (AP_HasEarlyColorHallways() &&
76 subway_item.special == "starting_room_paintings") { 86 subway_item.special == "early_color_hallways") {
77 entrances["early_ch"].push_back(subway_item.id); 87 entrances["early_ch"].push_back(subway_item.id);
78 } 88 }
79 89
80 if (AP_IsPaintingShuffle() && !subway_item.paintings.empty()) { 90 if (AP_IsPaintingShuffle() && subway_item.painting) {
81 continue; 91 continue;
82 } 92 }
83 93
@@ -174,6 +184,8 @@ void SubwayMap::OnConnect() {
174 } 184 }
175 185
176 checked_paintings_.clear(); 186 checked_paintings_.clear();
187
188 UpdateIndicators();
177} 189}
178 190
179void SubwayMap::UpdateIndicators() { 191void SubwayMap::UpdateIndicators() {
@@ -202,6 +214,8 @@ void SubwayMap::UpdateIndicators() {
202 } 214 }
203 } 215 }
204 216
217 report_popup_->UpdateIndicators();
218
205 Redraw(); 219 Redraw();
206} 220}
207 221
@@ -255,6 +269,9 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
255 SetZoomPos({zoom_x_, zoom_y_}); 269 SetZoomPos({zoom_x_, zoom_y_});
256 270
257 SetUpHelpButton(); 271 SetUpHelpButton();
272
273 zoom_slider_->SetSize(FromDIP(15), FromDIP(15), wxDefaultCoord,
274 wxDefaultCoord, wxSIZE_AUTO);
258 } 275 }
259 276
260 wxBufferedPaintDC dc(this); 277 wxBufferedPaintDC dc(this);
@@ -310,67 +327,6 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
310 } 327 }
311 328
312 if (hovered_item_) { 329 if (hovered_item_) {
313 // Note that these requirements are duplicated on OnMouseClick so that it
314 // knows when an item has a hover effect.
315 const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_);
316 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
317
318 if (subway_door && !GetDoorRequirements(*subway_door).empty()) {
319 const std::map<std::string, bool> &report =
320 GetDoorRequirements(*subway_door);
321
322 int acc_height = 10;
323 int col_width = 0;
324
325 for (const auto &[text, obtained] : report) {
326 wxSize item_extent = dc.GetTextExtent(text);
327 int item_height = std::max(32, item_extent.GetHeight()) + 10;
328 acc_height += item_height;
329
330 if (item_extent.GetWidth() > col_width) {
331 col_width = item_extent.GetWidth();
332 }
333 }
334
335 int item_width = col_width + 10 + 32;
336 int full_width = item_width + 20;
337
338 wxPoint popup_pos =
339 MapPosToRenderPos({subway_item.x + AREA_ACTUAL_SIZE / 2,
340 subway_item.y + AREA_ACTUAL_SIZE / 2});
341
342 if (popup_pos.x + full_width > GetSize().GetWidth()) {
343 popup_pos.x = GetSize().GetWidth() - full_width;
344 }
345 if (popup_pos.y + acc_height > GetSize().GetHeight()) {
346 popup_pos.y = GetSize().GetHeight() - acc_height;
347 }
348
349 dc.SetPen(*wxTRANSPARENT_PEN);
350 dc.SetBrush(*wxBLACK_BRUSH);
351 dc.DrawRectangle(popup_pos, {full_width, acc_height});
352
353 dc.SetFont(GetFont());
354
355 int cur_height = 10;
356
357 for (const auto &[text, obtained] : report) {
358 wxBitmap *eye_ptr = obtained ? &checked_eye_ : &unchecked_eye_;
359
360 dc.DrawBitmap(*eye_ptr, popup_pos + wxPoint{10, cur_height});
361
362 dc.SetTextForeground(obtained ? *wxWHITE : *wxRED);
363 wxSize item_extent = dc.GetTextExtent(text);
364 dc.DrawText(
365 text,
366 popup_pos +
367 wxPoint{10 + 32 + 10,
368 cur_height + (32 - dc.GetFontMetrics().height) / 2});
369
370 cur_height += 10 + 32;
371 }
372 }
373
374 if (networks_.IsItemInNetwork(*hovered_item_)) { 330 if (networks_.IsItemInNetwork(*hovered_item_)) {
375 dc.SetBrush(*wxTRANSPARENT_BRUSH); 331 dc.SetBrush(*wxTRANSPARENT_BRUSH);
376 332
@@ -378,10 +334,8 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
378 const SubwayItem &item1 = GD_GetSubwayItem(node.entry); 334 const SubwayItem &item1 = GD_GetSubwayItem(node.entry);
379 const SubwayItem &item2 = GD_GetSubwayItem(node.exit); 335 const SubwayItem &item2 = GD_GetSubwayItem(node.exit);
380 336
381 wxPoint item1_pos = MapPosToRenderPos( 337 wxPoint item1_pos = MapPosToRenderPos(GetSubwayItemMapCenter(item1));
382 {item1.x + AREA_ACTUAL_SIZE / 2, item1.y + AREA_ACTUAL_SIZE / 2}); 338 wxPoint item2_pos = MapPosToRenderPos(GetSubwayItemMapCenter(item2));
383 wxPoint item2_pos = MapPosToRenderPos(
384 {item2.x + AREA_ACTUAL_SIZE / 2, item2.y + AREA_ACTUAL_SIZE / 2});
385 339
386 int left = std::min(item1_pos.x, item2_pos.x); 340 int left = std::min(item1_pos.x, item2_pos.x);
387 int top = std::min(item1_pos.y, item2_pos.y); 341 int top = std::min(item1_pos.y, item2_pos.y);
@@ -470,9 +424,7 @@ void SubwayMap::OnMouseMove(wxMouseEvent &event) {
470 } 424 }
471 425
472 if (!sticky_hover_ && actual_hover_ != hovered_item_) { 426 if (!sticky_hover_ && actual_hover_ != hovered_item_) {
473 hovered_item_ = actual_hover_; 427 EvaluateHover();
474
475 Refresh();
476 } 428 }
477 429
478 if (scroll_mode_) { 430 if (scroll_mode_) {
@@ -514,13 +466,11 @@ void SubwayMap::OnMouseClick(wxMouseEvent &event) {
514 if ((subway_door && !GetDoorRequirements(*subway_door).empty()) || 466 if ((subway_door && !GetDoorRequirements(*subway_door).empty()) ||
515 networks_.IsItemInNetwork(*hovered_item_)) { 467 networks_.IsItemInNetwork(*hovered_item_)) {
516 if (actual_hover_ != hovered_item_) { 468 if (actual_hover_ != hovered_item_) {
517 hovered_item_ = actual_hover_; 469 EvaluateHover();
518 470
519 if (!hovered_item_) { 471 if (!hovered_item_) {
520 sticky_hover_ = false; 472 sticky_hover_ = false;
521 } 473 }
522
523 Refresh();
524 } else { 474 } else {
525 sticky_hover_ = !sticky_hover_; 475 sticky_hover_ = !sticky_hover_;
526 } 476 }
@@ -571,11 +521,12 @@ void SubwayMap::OnClickHelp(wxCommandEvent &event) {
571 "your mouse. Click again to stop.\nHover over a door to see the " 521 "your mouse. Click again to stop.\nHover over a door to see the "
572 "requirements to open it.\nHover over a warp or active painting to see " 522 "requirements to open it.\nHover over a warp or active painting to see "
573 "what it is connected to.\nFor one-way connections, there will be a " 523 "what it is connected to.\nFor one-way connections, there will be a "
574 "circle at the exit.\nIn painting shuffle, paintings that have not " 524 "circle at the exit.\nCircles represent paintings.\nA red circle means "
575 "yet been checked will not show their connections.\nA green shaded owl " 525 "that the painting is locked by a door.\nA blue circle means painting "
576 "means that there is a painting entrance there.\nA red shaded owl means " 526 "shuffle is enabled and the painting has not been checked yet.\nA black "
577 "that there are only painting exits there.\nClick on a door or " 527 "circle means the painting is not a warp.\nA green circle means that the "
578 "warp to make the popup stick until you click again.", 528 "painting is a warp.\nPainting exits will be indicated with an X.\nClick "
529 "on a door or warp to make the popup stick until you click again.",
579 "Subway Map Help"); 530 "Subway Map Help");
580} 531}
581 532
@@ -592,20 +543,32 @@ void SubwayMap::Redraw() {
592 for (const SubwayItem &subway_item : GD_GetSubwayItems()) { 543 for (const SubwayItem &subway_item : GD_GetSubwayItems()) {
593 ItemDrawType draw_type = ItemDrawType::kNone; 544 ItemDrawType draw_type = ItemDrawType::kNone;
594 const wxBrush *brush_color = wxGREY_BRUSH; 545 const wxBrush *brush_color = wxGREY_BRUSH;
595 std::optional<wxColour> shade_color;
596 std::optional<int> subway_door = GetRealSubwayDoor(subway_item); 546 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
597 547
598 if (AP_HasEarlyColorHallways() && 548 if (AP_HasEarlyColorHallways() &&
599 subway_item.special == "starting_room_paintings") { 549 subway_item.special == "early_color_hallways") {
600 draw_type = ItemDrawType::kOwl; 550 draw_type = ItemDrawType::kOwl;
601 shade_color = wxColour(0, 255, 0, 128); 551 brush_color = wxGREEN_BRUSH;
552 } else if (subway_item.special == "starting_room_overhead") {
553 // Do not draw.
554 } else if (AP_IsColorShuffle() && subway_item.special &&
555 subway_item.special->starts_with("color_")) {
556 std::string color_name = subway_item.special->substr(6);
557 LingoColor lingo_color = GetLingoColorForString(color_name);
558 int color_item_id = GD_GetItemIdForColor(lingo_color);
559
560 draw_type = ItemDrawType::kBox;
561 if (AP_HasItemSafe(color_item_id)) {
562 brush_color = wxGREEN_BRUSH;
563 } else {
564 brush_color = wxRED_BRUSH;
565 }
602 } else if (subway_item.special == "sun_painting") { 566 } else if (subway_item.special == "sun_painting") {
603 if (!AP_IsPilgrimageEnabled()) { 567 if (!AP_IsPilgrimageEnabled()) {
568 draw_type = ItemDrawType::kOwl;
604 if (IsDoorOpen(*subway_item.door)) { 569 if (IsDoorOpen(*subway_item.door)) {
605 draw_type = ItemDrawType::kOwl; 570 brush_color = wxGREEN_BRUSH;
606 shade_color = wxColour(0, 255, 0, 128);
607 } else { 571 } else {
608 draw_type = ItemDrawType::kBox;
609 brush_color = wxRED_BRUSH; 572 brush_color = wxRED_BRUSH;
610 } 573 }
611 } 574 }
@@ -619,41 +582,28 @@ void SubwayMap::Redraw() {
619 } else { 582 } else {
620 brush_color = wxRED_BRUSH; 583 brush_color = wxRED_BRUSH;
621 } 584 }
622 } else if (!subway_item.paintings.empty()) { 585 } else if (subway_item.painting) {
623 if (AP_IsPaintingShuffle()) { 586 if (subway_door && !IsDoorOpen(*subway_door)) {
624 bool has_checked_painting = false; 587 draw_type = ItemDrawType::kOwl;
625 bool has_unchecked_painting = false; 588 brush_color = wxRED_BRUSH;
626 bool has_mapped_painting = false; 589 } else if (AP_IsPaintingShuffle()) {
627 bool has_codomain_painting = false; 590 if (!checked_paintings_.count(*subway_item.painting)) {
628
629 for (const std::string &painting_id : subway_item.paintings) {
630 if (checked_paintings_.count(painting_id)) {
631 has_checked_painting = true;
632
633 if (painting_mapping.count(painting_id)) {
634 has_mapped_painting = true;
635 } else if (AP_IsPaintingMappedTo(painting_id)) {
636 has_codomain_painting = true;
637 }
638 } else {
639 has_unchecked_painting = true;
640 }
641 }
642
643 if (has_unchecked_painting || has_mapped_painting ||
644 has_codomain_painting) {
645 draw_type = ItemDrawType::kOwl; 591 draw_type = ItemDrawType::kOwl;
646 592 brush_color = wxBLUE_BRUSH;
647 if (has_checked_painting) { 593 } else if (painting_mapping.count(*subway_item.painting)) {
648 if (has_mapped_painting) { 594 draw_type = ItemDrawType::kOwl;
649 shade_color = wxColour(0, 255, 0, 128); 595 brush_color = wxGREEN_BRUSH;
650 } else { 596 } else if (AP_IsPaintingMappedTo(*subway_item.painting)) {
651 shade_color = wxColour(255, 0, 0, 128); 597 draw_type = ItemDrawType::kOwlExit;
652 } 598 brush_color = wxGREEN_BRUSH;
653 }
654 } 599 }
655 } else if (subway_item.HasWarps()) { 600 } else if (subway_item.HasWarps()) {
656 draw_type = ItemDrawType::kOwl; 601 brush_color = wxGREEN_BRUSH;
602 if (!subway_item.exits.empty()) {
603 draw_type = ItemDrawType::kOwlExit;
604 } else {
605 draw_type = ItemDrawType::kOwl;
606 }
657 } 607 }
658 } else if (subway_door) { 608 } else if (subway_door) {
659 draw_type = ItemDrawType::kBox; 609 draw_type = ItemDrawType::kBox;
@@ -673,21 +623,40 @@ void SubwayMap::Redraw() {
673 if (draw_type == ItemDrawType::kBox) { 623 if (draw_type == ItemDrawType::kBox) {
674 gcdc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 1)); 624 gcdc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 1));
675 gcdc.SetBrush(*brush_color); 625 gcdc.SetBrush(*brush_color);
676 gcdc.DrawRectangle(real_area_pos, {real_area_size, real_area_size}); 626
677 } else if (draw_type == ItemDrawType::kOwl) { 627 if (subway_item.tilted) {
678 wxBitmap owl_bitmap = wxBitmap(owl_image_.Scale( 628 constexpr int AREA_TILTED_SIDE =
679 real_area_size, real_area_size, wxIMAGE_QUALITY_BILINEAR)); 629 static_cast<int>(AREA_ACTUAL_SIZE / 1.41421356237);
680 gcdc.DrawBitmap(owl_bitmap, real_area_pos); 630 const wxPoint poly_points[] = {{AREA_TILTED_SIDE, 0},
681 631 {2 * AREA_TILTED_SIDE, AREA_TILTED_SIDE},
682 if (shade_color) { 632 {AREA_TILTED_SIDE, 2 * AREA_TILTED_SIDE},
683 gcdc.SetBrush(wxBrush(*shade_color)); 633 {0, AREA_TILTED_SIDE}};
634 gcdc.DrawPolygon(4, poly_points, subway_item.x, subway_item.y);
635 } else {
684 gcdc.DrawRectangle(real_area_pos, {real_area_size, real_area_size}); 636 gcdc.DrawRectangle(real_area_pos, {real_area_size, real_area_size});
685 } 637 }
638 } else if (draw_type == ItemDrawType::kOwl || draw_type == ItemDrawType::kOwlExit) {
639 gcdc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 1));
640 gcdc.SetBrush(*brush_color);
641 gcdc.DrawCircle(real_area_pos, PAINTING_RADIUS);
642
643 if (draw_type == ItemDrawType::kOwlExit) {
644 gcdc.DrawLine(subway_item.x - PAINTING_EXIT_RADIUS,
645 subway_item.y - PAINTING_EXIT_RADIUS,
646 subway_item.x + PAINTING_EXIT_RADIUS,
647 subway_item.y + PAINTING_EXIT_RADIUS);
648 gcdc.DrawLine(subway_item.x + PAINTING_EXIT_RADIUS,
649 subway_item.y - PAINTING_EXIT_RADIUS,
650 subway_item.x - PAINTING_EXIT_RADIUS,
651 subway_item.y + PAINTING_EXIT_RADIUS);
652 }
686 } 653 }
687 } 654 }
688} 655}
689 656
690void SubwayMap::SetUpHelpButton() { 657void SubwayMap::SetUpHelpButton() {
658 help_button_->SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord,
659 wxDefaultCoord, wxSIZE_AUTO);
691 help_button_->SetPosition({ 660 help_button_->SetPosition({
692 GetSize().GetWidth() - help_button_->GetSize().GetWidth() - 15, 661 GetSize().GetWidth() - help_button_->GetSize().GetWidth() - 15,
693 15, 662 15,
@@ -723,6 +692,51 @@ void SubwayMap::EvaluateScroll(wxPoint pos) {
723 SetScrollSpeed(scroll_x, scroll_y); 692 SetScrollSpeed(scroll_x, scroll_y);
724} 693}
725 694
695void SubwayMap::EvaluateHover() {
696 hovered_item_ = actual_hover_;
697
698 if (hovered_item_) {
699 // Note that these requirements are duplicated on OnMouseClick so that it
700 // knows when an item has a hover effect.
701 const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_);
702 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
703
704 if (subway_door && !GetDoorRequirements(*subway_door).empty()) {
705 report_popup_->SetDoorId(*subway_door);
706
707 wxPoint popupPos =
708 MapPosToRenderPos({subway_item.x + AREA_ACTUAL_SIZE / 2,
709 subway_item.y + AREA_ACTUAL_SIZE / 2});
710
711 report_popup_->SetClientSize(
712 report_popup_->GetVirtualSize().GetWidth(),
713 std::min(GetSize().GetHeight(),
714 report_popup_->GetVirtualSize().GetHeight()));
715
716 if (popupPos.x + report_popup_->GetSize().GetWidth() >
717 GetSize().GetWidth()) {
718 popupPos.x = GetSize().GetWidth() - report_popup_->GetSize().GetWidth();
719 }
720 if (popupPos.y + report_popup_->GetSize().GetHeight() >
721 GetSize().GetHeight()) {
722 popupPos.y =
723 GetSize().GetHeight() - report_popup_->GetSize().GetHeight();
724 }
725 report_popup_->SetPosition(popupPos);
726
727 report_popup_->Show();
728 } else {
729 report_popup_->Reset();
730 report_popup_->Hide();
731 }
732 } else {
733 report_popup_->Reset();
734 report_popup_->Hide();
735 }
736
737 Refresh();
738}
739
726wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const { 740wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const {
727 return {static_cast<int>(pos.x * render_width_ * zoom_ / 741 return {static_cast<int>(pos.x * render_width_ * zoom_ /
728 map_image_.GetSize().GetWidth() + 742 map_image_.GetSize().GetWidth() +
@@ -812,6 +826,13 @@ std::optional<int> SubwayMap::GetRealSubwayDoor(const SubwayItem subway_item) {
812 826
813quadtree::Box<float> SubwayMap::GetItemBox::operator()(const int &id) const { 827quadtree::Box<float> SubwayMap::GetItemBox::operator()(const int &id) const {
814 const SubwayItem &subway_item = GD_GetSubwayItem(id); 828 const SubwayItem &subway_item = GD_GetSubwayItem(id);
815 return {static_cast<float>(subway_item.x), static_cast<float>(subway_item.y), 829 if (subway_item.painting) {
816 AREA_ACTUAL_SIZE, AREA_ACTUAL_SIZE}; 830 return {static_cast<float>(subway_item.x) - PAINTING_RADIUS,
831 static_cast<float>(subway_item.y) - PAINTING_RADIUS,
832 PAINTING_RADIUS * 2, PAINTING_RADIUS * 2};
833 } else {
834 return {static_cast<float>(subway_item.x),
835 static_cast<float>(subway_item.y), AREA_ACTUAL_SIZE,
836 AREA_ACTUAL_SIZE};
837 }
817} 838}