#include "subway_map.h" #include #include #include "ap_state.h" #include "game_data.h" #include "global.h" #include "tracker_state.h" constexpr int AREA_ACTUAL_SIZE = 21; constexpr int OWL_ACTUAL_SIZE = 32; enum class ItemDrawType { kNone, kBox, kOwl }; SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) { SetBackgroundStyle(wxBG_STYLE_PAINT); map_image_ = wxImage(GetAbsolutePath("assets/subway.png").c_str(), wxBITMAP_TYPE_PNG); if (!map_image_.IsOk()) { return; } owl_image_ = wxImage(GetAbsolutePath("assets/owl.png").c_str(), wxBITMAP_TYPE_PNG); if (!owl_image_.IsOk()) { return; } unchecked_eye_ = wxBitmap(wxImage(GetAbsolutePath("assets/unchecked.png").c_str(), wxBITMAP_TYPE_PNG) .Scale(32, 32)); checked_eye_ = wxBitmap( wxImage(GetAbsolutePath("assets/checked.png").c_str(), wxBITMAP_TYPE_PNG) .Scale(32, 32)); tree_ = std::make_unique>( quadtree::Box{0, 0, static_cast(map_image_.GetWidth()), static_cast(map_image_.GetHeight())}); for (const SubwayItem &subway_item : GD_GetSubwayItems()) { tree_->add(subway_item.id); } Redraw(); Bind(wxEVT_PAINT, &SubwayMap::OnPaint, this); Bind(wxEVT_MOTION, &SubwayMap::OnMouseMove, this); } void SubwayMap::OnConnect() { networks_.Clear(); std::map> tagged; for (const SubwayItem &subway_item : GD_GetSubwayItems()) { if (AP_IsPaintingShuffle() && !subway_item.paintings.empty()) { continue; } for (const std::string &tag : subway_item.tags) { tagged[tag].push_back(subway_item.id); } if (!AP_IsSunwarpShuffle() && subway_item.sunwarp && subway_item.sunwarp->type != SubwaySunwarpType::kFinal) { std::ostringstream tag; tag << "sunwarp" << subway_item.sunwarp->dots; tagged[tag.str()].push_back(subway_item.id); } } for (const auto &[tag, items] : tagged) { // Pairwise connect all items with the same tag. for (auto tag_it1 = items.begin(); std::next(tag_it1) != items.end(); tag_it1++) { for (auto tag_it2 = std::next(tag_it1); tag_it2 != items.end(); tag_it2++) { networks_.AddLink(*tag_it1, *tag_it2); } } } checked_paintings_.clear(); } void SubwayMap::UpdateIndicators() { if (AP_IsPaintingShuffle()) { for (const std::string &painting_id : AP_GetCheckedPaintings()) { if (!checked_paintings_.count(painting_id)) { checked_paintings_.insert(painting_id); if (AP_GetPaintingMapping().count(painting_id)) { networks_.AddLink(GD_GetSubwayItemForPainting(painting_id), GD_GetSubwayItemForPainting( AP_GetPaintingMapping().at(painting_id))); } } } } Redraw(); } void SubwayMap::UpdateSunwarp(SubwaySunwarp from_sunwarp, SubwaySunwarp to_sunwarp) { networks_.AddLink(GD_GetSubwayItemForSunwarp(from_sunwarp), GD_GetSubwayItemForSunwarp(to_sunwarp)); } void SubwayMap::OnPaint(wxPaintEvent &event) { if (GetSize() != rendered_.GetSize()) { Redraw(); } wxBufferedPaintDC dc(this); dc.DrawBitmap(rendered_, 0, 0); if (hovered_item_) { const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_); if (subway_item.door && !GetDoorRequirements(*subway_item.door).empty()) { const std::map &report = GetDoorRequirements(*subway_item.door); int acc_height = 10; int col_width = 0; for (const auto &[text, obtained] : report) { wxSize item_extent = dc.GetTextExtent(text); int item_height = std::max(32, item_extent.GetHeight()) + 10; acc_height += item_height; if (item_extent.GetWidth() > col_width) { col_width = item_extent.GetWidth(); } } int item_width = col_width + 10 + 32; int full_width = item_width + 20; wxPoint popup_pos = MapPosToRenderPos({subway_item.x + AREA_ACTUAL_SIZE / 2, subway_item.y + AREA_ACTUAL_SIZE / 2}); if (popup_pos.x + full_width > GetSize().GetWidth()) { popup_pos.x = GetSize().GetWidth() - full_width; } if (popup_pos.y + acc_height > GetSize().GetHeight()) { pop
name: "Maze In Area"
panel_display_name: "Courtyard"
panels {
  name: "IN"
  path: "Panels/Maze/maze_3"
  clue: "in"
  answer: "out"
  symbols: SUN
}
r(255, 255, 0, 100); } else { shade_color = wxColour(100, 100, 100, 100); } } } } else if (!subway_item.tags.empty()) { draw_type = ItemDrawType::kOwl; } } wxPoint real_area_pos = MapPosToRenderPos({subway_item.x, subway_item.y}); int real_area_size = render_width_ * (draw_type == ItemDrawType::kOwl ? OWL_ACTUAL_SIZE : AREA_ACTUAL_SIZE) / image_size.GetWidth(); if (real_area_size == 0) { real_area_size = 1; } if (draw_type == ItemDrawType::kBox) { dc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 1)); dc.SetBrush(*brush_color); dc.DrawRectangle(real_area_pos, {real_area_size, real_area_size}); } else if (draw_type == ItemDrawType::kOwl) { wxBitmap owl_bitmap = wxBitmap( owl_image_.Scale(real_area_size, real_area_size, wxIMAGE_QUALITY_BILINEAR)); dc.DrawBitmap(owl_bitmap, real_area_pos); } } } wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const { return {pos.x * render_width_ / map_image_.GetSize().GetWidth() + render_x_, pos.y * render_width_ / map_image_.GetSize().GetWidth() + render_y_}; } wxPoint SubwayMap::RenderPosToMapPos(wxPoint pos) const { return { std::clamp((pos.x - render_x_) * map_image_.GetWidth() / render_width_, 0, map_image_.GetWidth() - 1), std::clamp((pos.y - render_y_) * map_image_.GetWidth() / render_width_, 0, map_image_.GetHeight() - 1)}; } quadtree::Box SubwayMap::GetItemBox::operator()(const int& id) const { const SubwayItem &subway_item = GD_GetSubwayItem(id); return {static_cast(subway_item.x), static_cast(subway_item.y), AREA_ACTUAL_SIZE, AREA_ACTUAL_SIZE}; }