summary refs log tree commit diff stats
path: root/data/maps/the_hive/doors.txtpb
blob: 4d86e13fc1b957b5d2f9b307b06ea8c6742c6e05 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
doors {
  name: "Room 8 Door"
  type: LOCATION_ONLY
  panels { room: "Main Area" name: "STEM" }
  panels { room: "Main Area" name: "PETAL" }
  panels { room: "Main Area" name: "SOIL" }
  panels { room: "Main Area" name: "PLANTS" }
  location_room: "Main Area"
}
doors {
  name: "Mastery Door"
  type: EVENT
  panels { room: "Main Area" name: "ASP" }
  panels { room: "Main Area" name: "HORN" }
  panels { room: "Main Area" name: "NET" }
  panels { room: "Main Area" name: "WAS" }
  panels { room: "Main Area" name: "HONE" }
  panels { room: "Main Area" name: "MOO" }
  panels { room: "Main Area" name: "QUIT" }
  panels { room: "Main Area" name: "EYE" }
  panels { room: "Main Area" name: "YELL" }
  panels { room: "Main Area" name: "AT" }
  panels { room: "Main Area" name: "LOW (1)" }
  panels { room: "Main Area" name: "JACK" }
  panels { room: "Main Area" name: "LOW (2)" }
  panels { room: "Main Area" name: "OWE" }
  panels { room: "Main Area" name: "DEN" }
  panels { room: "Main Area" name: "AD" }
  panels { room: "Main Area" name: "SITE" }
  panels { room: "Main Area" name: "ATE" }
  panels { room: "Main Area" name: "CURE" }
  panels { room: "Main Area" name: "PAR" }
  panels { room: "Main Area" name: "EEL" }
  panels { room: "Main Area" name: "SIR" }
  panels { room: "Main Area" name: "PER" }
  panels { room: "Main Area" name: "BEE" }
  panels { room: "Main Area" name: "STEM" }
  panels { room: "Main Area" name: "PETAL" }
  panels { room: "Main Area" name: "SOIL" }
  panels { room: "Main Area" name: "PLANTS" }
  panels { room: "Room 8" name: "BUMBLE" }
  panels { room: "Room 8" name: "CARPENTER" }
  panels { room: "Room 8" name: "CLOVER" }
  panels { room: "Room 8" name: "WILDFLOWER" }
  panels { room: "Main Area" name: "COWARDLY" }
  panels { room: "Main Area" name: "COAT" }
  panels { room: "Main Area" name: "FLAXEN" }
  panels { room: "Main Area" name: "CASE" }
  panels { room: "Main Area" name: "LEGS" }
  panels { room: "Main Area" name: "EYES" }
  panels { room: "Main Area" name: "WINGS" }
  panels { room: "Main Area" name: "ANTENNA" }
  panels { room: "Main Area" name: "COFFEE" }
  panels { room: "Main Area" name: "BEEF" }
}
8'>328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
#include "tracker_frame.h"

#include <fmt/core.h>
#include <wx/aboutdlg.h>
#include <wx/choicebk.h>
#include <wx/filedlg.h>
#include <wx/notebook.h>
#include <wx/stdpaths.h>
#include <wx/webrequest.h>

#include <nlohmann/json.hpp>
#include <sstream>

#include "achievements_pane.h"
#include "ap_state.h"
#include "connection_dialog.h"
#include "ipc_dialog.h"
#include "ipc_state.h"
#include "settings_dialog.h"
#include "subway_map.h"
#include "tracker_config.h"
#include "tracker_panel.h"
#include "version.h"

namespace {

std::string GetStatusMessage() {
  std::string msg = AP_GetStatusMessage();

  std::optional<std::string> ipc_msg = IPC_GetStatusMessage();
  if (ipc_msg) {
    msg += " ";
    msg += *ipc_msg;
  }

  return msg;
}

}  // namespace

enum TrackerFrameIds {
  ID_AP_CONNECT = 1,
  ID_CHECK_FOR_UPDATES = 2,
  ID_SETTINGS = 3,
  ID_ZOOM_IN = 4,
  ID_ZOOM_OUT = 5,
  ID_OPEN_SAVE_FILE = 6,
  ID_IPC_CONNECT = 7,
};

wxDEFINE_EVENT(STATE_RESET, wxCommandEvent);
wxDEFINE_EVENT(STATE_CHANGED, wxCommandEvent);
wxDEFINE_EVENT(STATUS_CHANGED, wxCommandEvent);
wxDEFINE_EVENT(REDRAW_POSITION, wxCommandEvent);
wxDEFINE_EVENT(CONNECT_TO_AP, ApConnectEvent);

TrackerFrame::TrackerFrame()
    : wxFrame(nullptr, wxID_ANY, "Lingo Archipelago Tracker", wxDefaultPosition,
              wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxFULL_REPAINT_ON_RESIZE) {
  ::wxInitAllImageHandlers();

  AP_SetTrackerFrame(this);
  IPC_SetTrackerFrame(this);

  wxMenu *menuFile = new wxMenu();
  menuFile->Append(ID_AP_CONNECT, "&Connect to Archipelago");
  menuFile->Append(ID_IPC_CONNECT, "&Connect to Lingo");
  menuFile->Append(ID_OPEN_SAVE_FILE, "&Open Save Data\tCtrl-O");
  menuFile->Append(ID_SETTINGS, "&Settings");
  menuFile->Append(wxID_EXIT);

  wxMenu *menuView = new wxMenu();
  zoom_in_menu_item_ = menuView->Append(ID_ZOOM_IN, "Zoom In\tCtrl-+");
  zoom_out_menu_item_ = menuView->Append(ID_ZOOM_OUT, "Zoom Out\tCtrl--");

  zoom_in_menu_item_->Enable(false);
  zoom_out_menu_item_->Enable(false);

  wxMenu *menuHelp = new wxMenu();
  menuHelp->Append(wxID_ABOUT);
  menuHelp->Append(ID_CHECK_FOR_UPDATES, "Check for Updates");

  wxMenuBar *menuBar = new wxMenuBar();
  menuBar->Append(menuFile, "&File");
  menuBar->Append(menuView, "&View");
  menuBar->Append(menuHelp, "&Help");

  SetMenuBar(menuBar);

  CreateStatusBar();

  Bind(wxEVT_MENU, &TrackerFrame::OnAbout, this, wxID_ABOUT);
  Bind(wxEVT_MENU, &TrackerFrame::OnExit, this, wxID_EXIT);
  Bind(wxEVT_MENU, &TrackerFrame::OnApConnect, this, ID_AP_CONNECT);
  Bind(wxEVT_MENU, &TrackerFrame::OnIpcConnect, this, ID_IPC_CONNECT);
  Bind(wxEVT_MENU, &TrackerFrame::OnSettings, this, ID_SETTINGS);
  Bind(wxEVT_MENU, &TrackerFrame::OnCheckForUpdates, this,
       ID_CHECK_FOR_UPDATES);
  Bind(wxEVT_MENU, &TrackerFrame::OnZoomIn, this, ID_ZOOM_IN);
  Bind(wxEVT_MENU, &TrackerFrame::OnZoomOut, this, ID_ZOOM_OUT);
  Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &TrackerFrame::OnChangePage, this);
  Bind(wxEVT_MENU, &TrackerFrame::OnOpenFile, this, ID_OPEN_SAVE_FILE);
  Bind(STATE_RESET, &TrackerFrame::OnStateReset, this);
  Bind(STATE_CHANGED, &TrackerFrame::OnStateChanged, this);
  Bind(STATUS_CHANGED, &TrackerFrame::OnStatusChanged, this);
  Bind(REDRAW_POSITION, &TrackerFrame::OnRedrawPosition, this);
  Bind(CONNECT_TO_AP, &TrackerFrame::OnConnectToAp, this);

  wxChoicebook *choicebook = new wxChoicebook(this, wxID_ANY);
  achievements_pane_ = new AchievementsPane(choicebook);
  choicebook->AddPage(achievements_pane_, "Achievements");

  notebook_ = new wxNotebook(this, wxID_ANY);
  tracker_panel_ = new TrackerPanel(notebook_);
  subway_map_ = new SubwayMap(notebook_);
  notebook_->AddPage(tracker_panel_, "Map");
  notebook_->AddPage(subway_map_, "Subway");

  wxBoxSizer *top_sizer = new wxBoxSizer(wxHORIZONTAL);
  top_sizer->Add(choicebook, wxSizerFlags().Expand().Proportion(1));
  top_sizer->Add(notebook_, wxSizerFlags().Expand().Proportion(3));

  SetSizerAndFit(top_sizer);
  SetSize(1280, 728);

  if (!GetTrackerConfig().asked_to_check_for_updates) {
    GetTrackerConfig().asked_to_check_for_updates = true;

    if (wxMessageBox(
            "Check for updates automatically when the tracker is opened?",
            "Lingo AP Tracker", wxYES_NO) == wxYES) {
      GetTrackerConfig().should_check_for_updates = true;
    } else {
      GetTrackerConfig().should_check_for_updates = false;
    }

    GetTrackerConfig().Save();
  }

  if (GetTrackerConfig().should_check_for_updates) {
    CheckForUpdates(/*manual=*/false);
  }

  SetStatusText(GetStatusMessage());
}

void TrackerFrame::ConnectToAp(std::string server, std::string user,
                               std::string pass) {
  QueueEvent(new ApConnectEvent(CONNECT_TO_AP, GetId(), std::move(server),
                                std::move(user), std::move(pass)));
}

void TrackerFrame::UpdateStatusMessage() {
  QueueEvent(new wxCommandEvent(STATUS_CHANGED));
}

void TrackerFrame::ResetIndicators() {
  QueueEvent(new wxCommandEvent(STATE_RESET));
}

void TrackerFrame::UpdateIndicators(UpdateIndicatorsMode mode) {
  auto evt = new wxCommandEvent(STATE_CHANGED);
  evt->SetInt(static_cast<int>(mode));

  QueueEvent(evt);
}

void TrackerFrame::RedrawPosition() {
  QueueEvent(new wxCommandEvent(REDRAW_POSITION));
}

void TrackerFrame::OnAbout(wxCommandEvent &event) {
  wxAboutDialogInfo about_info;
  about_info.SetName("Lingo Archipelago Tracker");
  about_info.SetVersion(kTrackerVersion.ToString());
  about_info.AddDeveloper("hatkirby");
  about_info.AddDeveloper("art0007i");
  about_info.AddArtist("Brenton Wildes");
  about_info.AddArtist("kinrah");

  wxAboutBox(about_info);
}

void TrackerFrame::OnExit(wxCommandEvent &event) { Close(true); }

void TrackerFrame::OnApConnect(wxCommandEvent &event) {
  ConnectionDialog dlg;

  if (dlg.ShowModal() == wxID_OK) {
    GetTrackerConfig().connection_details.ap_server = dlg.GetServerValue();
    GetTrackerConfig().connection_details.ap_player = dlg.GetPlayerValue();
    GetTrackerConfig().connection_details.ap_password = dlg.GetPasswordValue();

    std::deque<ConnectionDetails> new_history;
    new_history.push_back(GetTrackerConfig().connection_details);

    for (const ConnectionDetails &details :
         GetTrackerConfig().connection_history) {
      if (details != GetTrackerConfig().connection_details) {
        new_history.push_back(details);
      }
    }

    while (new_history.size() > 10) {
      new_history.pop_back();
    }

    GetTrackerConfig().connection_history = std::move(new_history);
    GetTrackerConfig().Save();

    AP_Connect(dlg.GetServerValue(), dlg.GetPlayerValue(),
               dlg.GetPasswordValue());
  }
}

void TrackerFrame::OnIpcConnect(wxCommandEvent &event) {
  IpcDialog dlg;

  if (dlg.ShowModal() == wxID_OK) {
    GetTrackerConfig().ipc_address = dlg.GetIpcAddress();
    GetTrackerConfig().Save();

    IPC_Connect(dlg.GetIpcAddress());
  }
}

void TrackerFrame::OnSettings(wxCommandEvent &event) {
  SettingsDialog dlg;

  if (dlg.ShowModal() == wxID_OK) {
    GetTrackerConfig().should_check_for_updates =
        dlg.GetShouldCheckForUpdates();
    GetTrackerConfig().hybrid_areas = dlg.GetHybridAreas();
    GetTrackerConfig().show_hunt_panels = dlg.GetShowHuntPanels();
    GetTrackerConfig().Save();

    UpdateIndicators();
  }
}

void TrackerFrame::OnCheckForUpdates(wxCommandEvent &event) {
  CheckForUpdates(/*manual=*/true);
}

void TrackerFrame::OnZoomIn(wxCommandEvent &event) {
  if (notebook_->GetSelection() == 1) {
    subway_map_->Zoom(true);
  }
}

void TrackerFrame::OnZoomOut(wxCommandEvent &event) {
  if (notebook_->GetSelection() == 1) {
    subway_map_->Zoom(false);
  }
}

void TrackerFrame::OnChangePage(wxBookCtrlEvent &event) {
  zoom_in_menu_item_->Enable(event.GetSelection() == 1);
  zoom_out_menu_item_->Enable(event.GetSelection() == 1);
}

void TrackerFrame::OnOpenFile(wxCommandEvent &event) {
  wxFileDialog open_file_dialog(
      this, "Open Lingo Save File",
      fmt::format("{}\\Godot\\app_userdata\\Lingo\\level1_stable",
                  wxStandardPaths::Get().GetUserConfigDir().ToStdString()),
      AP_GetSaveName(), "Lingo save file (*.save)|*.save",
      wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  if (open_file_dialog.ShowModal() == wxID_CANCEL) {
    return;
  }

  std::string savedata_path = open_file_dialog.GetPath().ToStdString();

  if (panels_panel_ == nullptr) {
    panels_panel_ = new TrackerPanel(notebook_);
    notebook_->AddPage(panels_panel_, "Panels");
  }

  notebook_->SetSelection(notebook_->FindPage(panels_panel_));
  panels_panel_->SetSavedataPath(savedata_path);
}

void TrackerFrame::OnStateReset(wxCommandEvent &event) {
  tracker_panel_->UpdateIndicators();
  achievements_pane_->UpdateIndicators();
  subway_map_->OnConnect();
  if (panels_panel_ != nullptr) {
    notebook_->DeletePage(notebook_->FindPage(panels_panel_));
    panels_panel_ = nullptr;
  }
  Refresh();
}

void TrackerFrame::OnStateChanged(wxCommandEvent &event) {
  UpdateIndicatorsMode mode = static_cast<UpdateIndicatorsMode>(event.GetInt());

  if (mode == kUPDATE_ALL_INDICATORS) {
    tracker_panel_->UpdateIndicators();
    achievements_pane_->UpdateIndicators();
    subway_map_->UpdateIndicators();
    if (panels_panel_ != nullptr) {
      panels_panel_->UpdateIndicators();
    }
    Refresh();
  } else if (mode == kUPDATE_ONLY_PANELS) {
    if (panels_panel_ == nullptr) {
      panels_panel_ = new TrackerPanel(notebook_);
      panels_panel_->SetPanelsMode();
      notebook_->AddPage(panels_panel_, "Panels");
    }
    panels_panel_->UpdateIndicators();
    if (notebook_->GetSelection() == 2) {
      Refresh();
    }
  }
}

void TrackerFrame::OnStatusChanged(wxCommandEvent &event) {
  SetStatusText(GetStatusMessage());
}

void TrackerFrame::OnRedrawPosition(wxCommandEvent &event) {
  if (notebook_->GetSelection() == 0) {
    tracker_panel_->Refresh();
  } else if (notebook_->GetSelection() == 2) {
    panels_panel_->Refresh();
  }
}

void TrackerFrame::OnConnectToAp(ApConnectEvent &event) {
  AP_Connect(event.GetServer(), event.GetUser(), event.GetPass());
}

void TrackerFrame::CheckForUpdates(bool manual) {
  wxWebRequest request = wxWebSession::GetDefault().CreateRequest(
      this, "https://code.fourisland.com/lingo-ap-tracker/plain/VERSION");

  if (!request.IsOk()) {
    if (manual) {
      wxMessageBox("Could not check for updates.", "Error",
                   wxOK | wxICON_ERROR);
    } else {
      SetStatusText("Could not check for updates.");
    }

    return;
  }

  Bind(wxEVT_WEBREQUEST_STATE, [this, manual](wxWebRequestEvent &evt) {
    if (evt.GetState() == wxWebRequest::State_Completed) {
      std::string response = evt.GetResponse().AsString().ToStdString();

      Version latest_version(response);
      if (kTrackerVersion < latest_version) {
        std::ostringstream message_text;
        message_text << "There is a newer version of Lingo AP Tracker "
                        "available. You have "
                     << kTrackerVersion.ToString()
                     << ", and the latest version is "
                     << latest_version.ToString()
                     << ". Would you like to update?";

        if (wxMessageBox(message_text.str(), "Update available", wxYES_NO) ==
            wxYES) {
          wxLaunchDefaultBrowser(
              "https://code.fourisland.com/lingo-ap-tracker/about/"
              "CHANGELOG.md");
        }
      } else if (manual) {
        wxMessageBox("Lingo AP Tracker is up to date!", "Lingo AP Tracker",
                     wxOK);
      }
    } else if (evt.GetState() == wxWebRequest::State_Failed) {
      if (manual) {
        wxMessageBox("Could not check for updates.", "Error",
                     wxOK | wxICON_ERROR);
      } else {
        SetStatusText("Could not check for updates.");
      }
    }
  });

  request.Start();
}