#include "subway_map.h" #include #include #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(); scroll_timer_ = new wxTimer(this); Bind(wxEVT_PAINT, &SubwayMap::OnPaint, this); Bind(wxEVT_MOTION, &SubwayMap::OnMouseMove, this); Bind(wxEVT_MOUSEWHEEL, &SubwayMap::OnMouseScroll, this); Bind(wxEVT_LEAVE_WINDOW, &SubwayMap::OnMouseLeave, this); Bind(wxEVT_LEFT_DOWN, &SubwayMap::OnMouseClick, this); Bind(wxEVT_TIMER, &SubwayMap::OnTimer, this); zoom_slider_ = new wxSlider(this, wxID_ANY, 0, 0, 8, {15, 15}); zoom_slider_->Bind(wxEVT_SLIDER, &SubwayMap::OnZoomSlide, this); help_button_ = new wxButton(this, wxID_ANY, "Help"); help_button_->Bind(wxEVT_BUTTON, &SubwayMap::OnClickHelp, this); SetUpHelpButton(); } void SubwayMap::OnConnect() { networks_.Clear(); std::map> tagged; for (const SubwayItem &subway_item : GD_GetSubwayItems()) { if (AP_HasEarlyColorHallways() && subway_item.special == "starting_room_paintings") { tagged["early_ch"].push_back(subway_item.id); } 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::string tag = fmt::format("subway{}", subway_item.sunwarp->dots); tagged[tag].push_back(subway_item.id); } if (!AP_IsPilgrimageEnabled() && (subway_item.special == "sun_painting" || subway_item.special == "sun_painting_exit")) { tagged["sun_painting"].push_back(subway_item.id); } } if (AP_IsSunwarpShuffle()) { for (const auto &[index, mapping] : AP_GetSunwarpMapping()) { std::string tag = fmt::format("sunwarp{}", mapping.dots); SubwaySunwarp fromWarp; if (index < 6) { fromWarp.dots = index + 1; fromWarp.type = SubwaySunwarpType::kEnter; } else { fromWarp.dots = index - 5; fromWarp.type = SubwaySunwarpType::kExit; } SubwaySunwarp toWarp; if (mapping.exit_index < 6) { toWarp.dots = mapping.exit_index + 1; toWarp.type = SubwaySunwarpType::kEnter; } else { toWarp.dots = mapping.exit_index - 5; toWarp.type = SubwaySunwarpType::kExit; } tagged[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp)); tagged[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp)); } } 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_GetCheckedPainti
#include "achievements_pane.h"

#include "ap_state.h"
#include "game_data.h"

AchievementsPane::AchievementsPane(wxWindow* parent)
    : wxListView(parent, wxID_ANY) {
  AppendColumn("Achievement");

  for (int panel_id : GD_GetAchievementPanels()) {
    achievement_names_.push_back(GD_GetPanel(panel_id).achievement_name);
  }

  std::sort(std::begin(achievement_names_), std::end(achievement_names_));

  for (int i = 0; i < achievement_names_.size(); i++) {
    InsertItem(i, achievement_names_.at(i));
  }

  SetColumnWidth(0, wxLIST_AUTOSIZE);

  UpdateIndicators();
}

void AchievementsPane::UpdateIndicators() {
  for (int i = 0; i < achievement_names_.size(); i++) {
    if (AP_HasAchievement(achievement_names_.at(i))) {
      SetItemTextColour(i, *wxBLACK);
    } else {
      SetItemTextColour(i, *wxRED);
    }
  }
}
brush_color = wxRED_BRUSH; } } } else if (!subway_item.paintings.empty()) { if (AP_IsPaintingShuffle()) { bool has_checked_painting = false; bool has_unchecked_painting = false; bool has_mapped_painting = false; bool has_codomain_painting = false; for (const std::string &painting_id : subway_item.paintings) { if (checked_paintings_.count(painting_id)) { has_checked_painting = true; if (AP_GetPaintingMapping().count(painting_id)) { has_mapped_painting = true; } else if (AP_IsPaintingMappedTo(painting_id)) { has_codomain_painting = true; } } else { has_unchecked_painting = true; } } if (has_unchecked_painting || has_mapped_painting || has_codomain_painting) { draw_type = ItemDrawType::kOwl; if (has_checked_painting) { if (has_mapped_painting) { shade_color = wxColour(0, 255, 0, 128); } else { shade_color = wxColour(255, 0, 0, 128); } } } } else if (!subway_item.tags.empty()) { draw_type = ItemDrawType::kOwl; } } else if (subway_item.door) { draw_type = ItemDrawType::kBox; if (IsDoorOpen(*subway_item.door)) { brush_color = wxGREEN_BRUSH; } else { brush_color = wxRED_BRUSH; } } wxPoint real_area_pos = {subway_item.x, subway_item.y}; int real_area_size = (draw_type == ItemDrawType::kOwl ? OWL_ACTUAL_SIZE : AREA_ACTUAL_SIZE); if (draw_type == ItemDrawType::kBox) { gcdc.SetPen(*wxThePenList->FindOrCreatePen(*wxBLACK, 1)); gcdc.SetBrush(*brush_color); gcdc.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)); gcdc.DrawBitmap(owl_bitmap, real_area_pos); if (shade_color) { gcdc.SetBrush(wxBrush(*shade_color)); gcdc.DrawRectangle(real_area_pos, {real_area_size, real_area_size}); } } } } void SubwayMap::SetUpHelpButton() { help_button_->SetPosition({ GetSize().GetWidth() - help_button_->GetSize().GetWidth() - 15, 15, }); } void SubwayMap::EvaluateScroll(wxPoint pos) { int scroll_x; int scroll_y; if (pos.x < GetSize().GetWidth() / 9) { scroll_x = 20; } else if (pos.x < GetSize().GetWidth() / 6) { scroll_x = 5; } else if (pos.x > 8 * GetSize().GetWidth() / 9) { scroll_x = -20; } else if (pos.x > 5 * GetSize().GetWidth() / 6) { scroll_x = -5; } else { scroll_x = 0; } if (pos.y < GetSize().GetHeight() / 9) { scroll_y = 20; } else if (pos.y < GetSize().GetHeight() / 6) { scroll_y = 5; } else if (pos.y > 8 * GetSize().GetHeight() / 9) { scroll_y = -20; } else if (pos.y > 5 * GetSize().GetHeight() / 6) { scroll_y = -5; } else { scroll_y = 0; } SetScrollSpeed(scroll_x, scroll_y); } wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const { return {static_cast(pos.x * render_width_ * zoom_ / map_image_.GetSize().GetWidth() + zoom_x_), static_cast(pos.y * render_width_ * zoom_ / map_image_.GetSize().GetWidth() + zoom_y_)}; } wxPoint SubwayMap::MapPosToVirtualPos(wxPoint pos) const { return {static_cast(pos.x * render_width_ * zoom_ / map_image_.GetSize().GetWidth()), static_cast(pos.y * render_width_ * zoom_ / map_image_.GetSize().GetWidth())}; } wxPoint SubwayMap::RenderPosToMapPos(wxPoint pos) const { return { std::clamp(static_cast((pos.x - zoom_x_) * map_image_.GetWidth() / render_width_ / zoom_), 0, map_image_.GetWidth() - 1), std::clamp(static_cast((pos.y - zoom_y_) * map_image_.GetWidth() / render_width_ / zoom_), 0, map_image_.GetHeight() - 1)}; } void SubwayMap::SetZoomPos(wxPoint pos) { if (render_width_ * zoom_ <= GetSize().GetWidth()) { zoom_x_ = (GetSize().GetWidth() - render_width_ * zoom_) / 2; } else { zoom_x_ = std::clamp( pos.x, GetSize().GetWidth() - static_cast(render_width_ * zoom_), 0); } if (render_height_ * zoom_ <= GetSize().GetHeight()) { zoom_y_ = (GetSize().GetHeight() - render_height_ * zoom_) / 2; } else { zoom_y_ = std::clamp( pos.y, GetSize().GetHeight() - static_cast(render_height_ * zoom_), 0); } } void SubwayMap::SetScrollSpeed(int scroll_x, int scroll_y) { bool should_timer = (scroll_x != 0 || scroll_y != 0); if (should_timer != scroll_timer_->IsRunning()) { if (should_timer) { scroll_timer_->Start(1000 / 60); } else { scroll_timer_->Stop(); } } scroll_x_ = scroll_x; scroll_y_ = scroll_y; } void SubwayMap::SetZoom(double zoom, wxPoint static_point) { wxPoint map_pos = RenderPosToMapPos(static_point); zoom_ = zoom; wxPoint virtual_pos = MapPosToVirtualPos(map_pos); SetZoomPos(-(virtual_pos - static_point)); Refresh(); zoom_slider_->SetValue((zoom - 1.0) / 0.25); } 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}; }