diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp index 3acc9d7e8..6b948a8d2 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp @@ -105,6 +105,26 @@ class DialogTealArrowMatcher : public ImageMatch::WaterfillTemplateMatcher{ } }; +class DialogBlueArrowMatcher : public ImageMatch::WaterfillTemplateMatcher{ +public: + DialogBlueArrowMatcher() + : WaterfillTemplateMatcher( + "PokemonLZA/DialogBox/DialogBoxBlueArrow-Template.png", + Color(0xff005460), Color(0xff6BBEC9), 50 + ) + { + m_aspect_ratio_lower = 0.9; + m_aspect_ratio_upper = 1.1; + m_area_ratio_lower = 0.8; + m_area_ratio_upper = 1.1; + } + + static const ImageMatch::WaterfillTemplateMatcher& instance() { + static DialogBlueArrowMatcher matcher; + return matcher; + } +}; + namespace { @@ -143,6 +163,33 @@ bool detect_white_arrow(const ImageViewRGB32& screen, PokemonAutomation::ImageFl return found; } +bool detect_blue_arrow(const ImageViewRGB32& screen, PokemonAutomation::ImageFloatBox& found_box){ + double screen_rel_size = (screen.height() / 1080.0); + double screen_rel_size_2 = screen_rel_size * screen_rel_size; + + double min_area_1080p = 150.0; + double rmsd_threshold = 120.0; + size_t min_area = size_t(screen_rel_size_2 * min_area_1080p); + + const std::vector> FILTERS = { + {0x005460, 0xff7FC0C9}, + }; + + bool found = match_template_by_waterfill( + screen.size(), + extract_box_reference(screen, DIALOG_ARROW_BOX), + DialogBlueArrowMatcher::instance(), + FILTERS, + {min_area, SIZE_MAX}, + rmsd_threshold, + [&](Kernels::Waterfill::WaterfillObject& object) -> bool { + found_box = translate_to_parent(screen, DIALOG_ARROW_BOX, object); + return true; + } + ); + return found; +} + } // end anonymous namespace @@ -486,6 +533,43 @@ bool TransparentBattleDialogDetector::detect(const ImageViewRGB32& screen){ } +LightBlueDialogDetector::LightBlueDialogDetector(Color color, VideoOverlay* overlay) + : m_color(color) + , m_overlay(overlay) + , m_corner(0.765093, 0.933594, 0.006586, 0.013672) +{} +void LightBlueDialogDetector::make_overlays(VideoOverlaySet& items) const{ + items.add(m_color, m_corner); + items.add(m_color, DIALOG_ARROW_BOX); +} +bool LightBlueDialogDetector::detect(const ImageViewRGB32& screen){ + do{ + if (is_solid( + extract_box_reference(screen, m_corner), + {0.108317, 0.462282, 0.429400}, + 0.25 + )){ + break; + } + m_last_detected_box_scope.reset(); +// cout << "not solid" << endl; + return false; + }while (false); + + const bool found = detect_blue_arrow(screen, m_last_detected_box); + + if (m_overlay){ + if (found){ + m_last_detected_box_scope.emplace(*m_overlay, m_last_detected_box, COLOR_GREEN); + }else{ + m_last_detected_box_scope.reset(); + } + } + + return found; +} + + } } diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h index 762fed850..d10f622bc 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h @@ -206,6 +206,37 @@ class TransparentBattleDialogWatcher : public DetectorToFinder m_last_detected_box_scope; +}; +class LightBlueDialogWatcher : public DetectorToFinder{ +public: + LightBlueDialogWatcher( + Color color = COLOR_RED, + VideoOverlay* overlay = nullptr, + std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250) + ) + : DetectorToFinder("BlueDialogWatcher", hold_duration, color, overlay) + {} +}; + } } diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.cpp new file mode 100644 index 000000000..eeba02352 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.cpp @@ -0,0 +1,39 @@ +/* Hyperspace Reward Name Reader + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonTools/OCR/OCR_RawOCR.h" +#include "PokemonLZA_HyperspaceRewardNameReader.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +HyperspaceRewardNameReader& HyperspaceRewardNameReader::instance(){ + static HyperspaceRewardNameReader reader; + return reader; +} + + +HyperspaceRewardNameReader::HyperspaceRewardNameReader() + : SmallDictionaryMatcher("PokemonLZA/HyperBattle/HyperspaceRewardNameOCR.json") +{} + +OCR::StringMatchResult HyperspaceRewardNameReader::read_substring( + Logger& logger, + Language language, + const ImageViewRGB32& image, + const std::vector& text_color_ranges, + double min_text_ratio, double max_text_ratio +) const{ + return match_substring_from_image_multifiltered( + &logger, language, image, text_color_ranges, + MAX_LOG10P, MAX_LOG10P_SPREAD, min_text_ratio, max_text_ratio + ); +} + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.h new file mode 100644 index 000000000..53a8041e1 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.h @@ -0,0 +1,38 @@ +/* Hyperspace Reward Name Reader + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_HyperspaceRewardNameReader_H +#define PokemonAutomation_PokemonLZA_HyperspaceRewardNameReader_H + +#include "CommonTools/OCR/OCR_SmallDictionaryMatcher.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +class HyperspaceRewardNameReader : public OCR::SmallDictionaryMatcher{ +public: + static constexpr double MAX_LOG10P = -1.40; + static constexpr double MAX_LOG10P_SPREAD = 0.50; + +public: + HyperspaceRewardNameReader(); + + static HyperspaceRewardNameReader& instance(); + + OCR::StringMatchResult read_substring( + Logger& logger, + Language language, + const ImageViewRGB32& image, + const std::vector& text_color_ranges, + double min_text_ratio = 0.01, double max_text_ratio = 0.50 + ) const; + +}; +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.cpp b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.cpp new file mode 100644 index 000000000..79c33f84a --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.cpp @@ -0,0 +1,42 @@ +/* Hyperspace Reward Option + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Logging/Logger.h" +#include "PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.h" +#include "PokemonLZA_HyperspaceRewardOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +StringSelectDatabase make_hyperspace_reward_database(){ + StringSelectDatabase ret; + for (const auto& slug : HYPERSPACE_REWARD_SLUGS()){ + const HyperspaceRewardNames& data = get_hyperspace_reward_name(slug); + ret.add_entry(StringSelectEntry(slug, data.display_name())); + } + return ret; +} +const StringSelectDatabase& HYPERSPACE_REWARD_DATABASE(){ + static StringSelectDatabase database = make_hyperspace_reward_database(); + return database; +} + + +HyperspaceRewardCell::HyperspaceRewardCell( + const std::string& default_slug +) + : StringSelectCell( + HYPERSPACE_REWARD_DATABASE(), + LockMode::LOCK_WHILE_RUNNING, + default_slug + ) +{} + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.h b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.h new file mode 100644 index 000000000..5fa7ff5bd --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.h @@ -0,0 +1,24 @@ +/* Hyperspace Reward Option + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_HyperspaceRewardOption_H +#define PokemonAutomation_PokemonLZA_HyperspaceRewardOption_H + +#include "CommonTools/Options/StringSelectOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +class HyperspaceRewardCell : public StringSelectCell{ +public: + HyperspaceRewardCell(const std::string& default_slug); +}; + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.cpp b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.cpp new file mode 100644 index 000000000..90c17e343 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.cpp @@ -0,0 +1,73 @@ +/* Hyperspace Reward Table + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.h" +#include "PokemonLZA_HyperspaceRewardTable.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +HyperspaceRewardRow::HyperspaceRewardRow(EditableTableOption& parent_table) + : EditableTableRow(parent_table) + , item("bottle-cap") +{ + PA_ADD_OPTION(item); +} +std::unique_ptr HyperspaceRewardRow::clone() const{ + std::unique_ptr ret(new HyperspaceRewardRow(parent())); + ret->item.set_by_index(item.index()); + return ret; +} + +HyperspaceRewardTable::HyperspaceRewardTable(std::string label) + : EditableTableOption_t( + std::move(label), + LockMode::LOCK_WHILE_RUNNING, + make_defaults() + ) +{} + +bool HyperspaceRewardTable::find_item(const std::string& item_slug) const{ + std::vector> table = copy_snapshot(); + for (const std::unique_ptr& row : table){ + if (row->item.slug() == item_slug){ + return true; + } + } + return false; +} + +std::vector HyperspaceRewardTable::selected_items() const{ + std::vector> table = copy_snapshot(); + std::vector slugs; + for (const std::unique_ptr& row : table){ + slugs.emplace_back(row->item.slug()); + } + return slugs; +} + + +std::vector HyperspaceRewardTable::make_header() const{ + return std::vector{ + "Item", + }; +} + +std::vector> HyperspaceRewardTable::make_defaults(){ + std::vector> ret; + ret.emplace_back(std::make_unique(*this)); + return ret; +} + + + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.h b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.h new file mode 100644 index 000000000..72e4ba7f6 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.h @@ -0,0 +1,51 @@ +/* Hyperspace Reward Table + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_HyperspaceRewardTable_H +#define PokemonAutomation_PokemonLZA_HyperspaceRewardTable_H + +#include "Common/Cpp/Options/EditableTableOption.h" +#include "PokemonLZA_HyperspaceRewardOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + + +class HyperspaceRewardRow : public EditableTableRow{ +public: + HyperspaceRewardRow(EditableTableOption& parent_table); + virtual std::unique_ptr clone() const override; + +public: + HyperspaceRewardCell item; +}; + + + +class HyperspaceRewardTable : public EditableTableOption_t{ +public: + HyperspaceRewardTable(std::string label); + + + // Whether item_slug is among the selected items. + bool find_item(const std::string& item_slug) const; + std::vector selected_items() const; + + virtual std::vector make_header() const override; + + std::vector> make_defaults(); +}; + + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp index ab648cf64..e9fac21df 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp @@ -24,6 +24,7 @@ #include "Programs/Farming/PokemonLZA_JacintheInfiniteFarmer.h" #include "Programs/Farming/PokemonLZA_FriendshipFarmer.h" #include "Programs/Farming/PokemonLZA_InPlaceCatcher.h" +#include "Programs/Farming/PokemonLZA_HyperspaceRewardReset.h" // Shiny Hunting #include "Programs/ShinyHunting/PokemonLZA_AutoFossil.h" @@ -78,6 +79,7 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); if (IS_BETA_VERSION){ + ret.emplace_back(make_single_switch_program()); } ret.emplace_back("---- Shiny Hunting ----"); diff --git a/SerialPrograms/Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.cpp new file mode 100644 index 000000000..043583add --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.cpp @@ -0,0 +1,233 @@ +/* Hyperspace Reward Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Logging/Logger.h" +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "CommonTools/Images/ImageFilter.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "CommonTools/StartupChecks/VideoResolutionCheck.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonLZA/Programs/PokemonLZA_GameEntry.h" +#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.h" +#include "PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.h" +#include "PokemonLZA_HyperspaceRewardReset.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +using namespace Pokemon; + +HyperspaceRewardReset_Descriptor::HyperspaceRewardReset_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLZA:HyperspaceRewardReset", + STRING_POKEMON + " LZA", "Hyperspace Reward Reset", + "Programs/PokemonLZA/HyperspaceRewardReset.html", + "Reset in front of a Hyperspace Battle Zone trainer to receive a specific reward.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS + ) +{} + +struct HyperspaceRewardReset_Descriptor::Stats : public StatsTracker{ + Stats() + : matches(m_stats["Items matched"]) + , resets(m_stats["Resets"]) + , errors(m_stats["Errors"]) + { + m_display_order.emplace_back("Items matched"); + m_display_order.emplace_back("Resets"); + m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); + } + std::atomic& matches; + std::atomic& resets; + std::atomic& errors; +}; +std::unique_ptr HyperspaceRewardReset_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + +HyperspaceRewardReset::HyperspaceRewardReset() + : LANGUAGE( + "Game Language:
The language is needed to read the rewards.", + HyperspaceRewardNameReader::instance().languages(), + LockMode::LOCK_WHILE_RUNNING, + true + ) + , TARGET_ITEMS("Items:") + , GO_HOME_WHEN_DONE(true) + , NOTIFICATION_REWARD_MATCH("Matching Reward", true, false, ImageAttachmentMode::JPG, { "Notifs" }) + , NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600)) + , NOTIFICATIONS({ + &NOTIFICATION_REWARD_MATCH, + &NOTIFICATION_STATUS_UPDATE, + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_FATAL, + }) +{ + PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(TARGET_ITEMS); + PA_ADD_OPTION(GO_HOME_WHEN_DONE); + PA_ADD_OPTION(NOTIFICATIONS); +} + +void HyperspaceRewardReset::talk_to_trainer(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + HyperspaceRewardReset_Descriptor::Stats& stats = env.current_stats(); + + bool exit = false; + while (!exit){ + context.wait_for_all_requests(); + + ButtonWatcher buttonA_watcher( + COLOR_WHITE, + ButtonType::ButtonA, + {0.1, 0.1, 0.8, 0.8}, + &env.console.overlay() + ); + //First dialog box varies by trainer (hologram, regular, etc.) + BlueDialogWatcher blue_dialog_watcher(COLOR_BLUE, &env.console.overlay()); //Item received (not the big box) + FlatWhiteDialogWatcher white_dialog_watcher(COLOR_WHITE, &env.console.overlay()); //Non-hologram + LightBlueDialogWatcher light_blue_dialog_watcher(COLOR_WHITE, &env.console.overlay()); //hologram + + int ret = wait_until( + env.console, context, + 10s, + { + buttonA_watcher, + blue_dialog_watcher, + white_dialog_watcher, + light_blue_dialog_watcher, + } + ); + context.wait_for(100ms); + + switch (ret){ + case 0: + env.log("Detected A button."); + pbf_press_button(context, BUTTON_A, 80ms, 40ms); + continue; + case 1: + env.log("Detected item received dialog."); + exit = true; + break; + case 2: + env.log("Detected white dialog."); + pbf_press_button(context, BUTTON_A, 80ms, 40ms); + continue; + case 3: + env.log("Detected light blue dialog."); + pbf_press_button(context, BUTTON_A, 80ms, 40ms); + continue; + default: + stats.errors++; + env.update_stats(); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "talk_to_trainer(): Failed to detect blue item received dialog.", + env.console + ); + } + } +} + +//Check reward and notify if it matches filters +bool HyperspaceRewardReset::check_reward(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + HyperspaceRewardReset_Descriptor::Stats& stats = env.current_stats(); + + VideoSnapshot screen = env.console.video().snapshot(); + ImageFloatBox dialog_box(0.248, 0.792, 0.483, 0.147); + ImageViewRGB32 dialog_image = extract_box_reference(screen, dialog_box); + + /* + bool replace_color_within_range = false; + ImageRGB32 dialog_filtered = filter_rgb32_range( + extract_box_reference(screen, dialog_box), + combine_rgb(50, 135, 162), combine_rgb(167, 244, 255), Color(0), replace_color_within_range + ); + dialog_filtered.save("./dialog_image.png"); + */ + + const double LOG10P_THRESHOLD = -1.5; + OCR::StringMatchResult result = PokemonLZA::HyperspaceRewardNameReader::instance().read_substring( + env.console, LANGUAGE, dialog_image, + OCR::BLUE_TEXT_FILTERS() + ); + result.clear_beyond_log10p(LOG10P_THRESHOLD); + if (result.results.empty()){ + env.log("No matching reward name found in dialog box."); + send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE); + } + for (const auto& r : result.results){ + env.console.log("Found reward: " + r.second.token); + if (TARGET_ITEMS.find_item(r.second.token)){ + env.log("Reward matched"); + + stats.matches++; + env.update_stats(); + + send_program_notification( + env, NOTIFICATION_REWARD_MATCH, + COLOR_GREEN, "Reward matched", + { + { "Item:", get_hyperspace_reward_name(r.second.token).display_name() }, + } + , "", screen); + return true; + break; + } + } + return false; +} + +void HyperspaceRewardReset::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + assert_16_9_720p_min(env.logger(), env.console); + HyperspaceRewardReset_Descriptor::Stats& stats = env.current_stats(); + + /* + * In a Hyperspace Battle Zone: + * Win a battle with a trainer that gives a prize. + * Save the game and reset. Do not talk to the trainer. + * (Reset is required because trainer position will move.) + * Re-enter the game and then save again, this time in front of the trainer. + * Start the program. + * + * Make sure you won't be spotted by another trainer. + */ + + bool item_found = false; + while (!item_found){ + send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE); + + talk_to_trainer(env, context); + item_found = check_reward(env, context); + + if (item_found) { + break; + } + + go_home(env.console, context); + reset_game_from_home(env, env.console, context); + stats.resets++; + env.update_stats(); + } + + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); + GO_HOME_WHEN_DONE.run_end_of_program(context); +} + +} +} +} + diff --git a/SerialPrograms/Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.h b/SerialPrograms/Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.h new file mode 100644 index 000000000..861d2220a --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.h @@ -0,0 +1,54 @@ +/* Hyperspace Reward Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_HyperspaceRewardReset_H +#define PokemonAutomation_PokemonLZA_HyperspaceRewardReset_H + +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/SimpleIntegerOption.h" +#include "Common/Cpp/Options/ButtonOption.h" +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "CommonTools/Options/LanguageOCROption.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" +#include "PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +class HyperspaceRewardReset_Descriptor : public SingleSwitchProgramDescriptor{ +public: + HyperspaceRewardReset_Descriptor(); + struct Stats; + virtual std::unique_ptr make_stats() const override; +}; + +class HyperspaceRewardReset : public SingleSwitchProgramInstance{ +public: + HyperspaceRewardReset(); + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + OCR::LanguageOCROption LANGUAGE; + HyperspaceRewardTable TARGET_ITEMS; + GoHomeWhenDoneOption GO_HOME_WHEN_DONE; + + EventNotificationOption NOTIFICATION_REWARD_MATCH; + EventNotificationOption NOTIFICATION_STATUS_UPDATE; + EventNotificationsOption NOTIFICATIONS; + + void talk_to_trainer(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + bool check_reward(SingleSwitchProgramEnvironment& env, ProControllerContext& context); +}; + +} +} +} +#endif + + + diff --git a/SerialPrograms/Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.cpp b/SerialPrograms/Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.cpp new file mode 100644 index 000000000..a63fbec8d --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.cpp @@ -0,0 +1,109 @@ +/* Hyperspace Reward Names + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include +#include "Common/Cpp/Json/JsonValue.h" +#include "Common/Cpp/Json/JsonArray.h" +#include "Common/Cpp/Json/JsonObject.h" +#include "CommonFramework/Globals.h" +#include "PokemonLZA_HyperspaceRewardNames.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +struct HyperspaceRewardNamesDatabase{ + HyperspaceRewardNamesDatabase(); + + static const HyperspaceRewardNamesDatabase& instance(){ + static HyperspaceRewardNamesDatabase database; + return database; + } + + static const std::string NULL_SLUG; + std::vector ordered_list; + std::map database; + std::map reverse_lookup; +}; +const std::string HyperspaceRewardNamesDatabase::NULL_SLUG; + +HyperspaceRewardNamesDatabase::HyperspaceRewardNamesDatabase() +{ + // Load a list of tournament prize slugs in the desired order: + // ["potion", "fresh-water", ... ] + std::string path_slugs = RESOURCE_PATH() + "PokemonLZA/HyperBattle/HyperspaceRewardList.json"; + JsonValue json_slugs = load_json_file(path_slugs); + JsonArray& slugs = json_slugs.to_array_throw(path_slugs); + + // Load a map of tournament prize slugs to item names in all languages, e.g.: + // { + // "potion": { + // "eng": "Potion", + // "deu": "Trank", + // ... + // }, + // .... + // } + std::string path_disp = RESOURCE_PATH() + "PokemonLZA/HyperBattle/HyperspaceRewardNameDisplay.json"; + JsonValue json_disp = load_json_file(path_disp); + JsonObject& item_disp = json_disp.to_object_throw(path_disp); + + for (auto& item : slugs){ + std::string& slug = item.to_string_throw(path_slugs); + + JsonObject& auction_item_name_dict = item_disp.get_object_throw(slug, path_disp); + std::string& display_name = auction_item_name_dict.get_string_throw("eng", path_disp); + + ordered_list.push_back(slug); + database[std::move(slug)].m_display_name = std::move(display_name); + } + + for (const auto& item : database){ + reverse_lookup[item.second.m_display_name] = item.first; + } +} + +const HyperspaceRewardNames& get_hyperspace_reward_name(const std::string& slug){ + const std::map& database = HyperspaceRewardNamesDatabase::instance().database; + auto iter = database.find(slug); + if (iter == database.end()){ + throw InternalProgramError( + nullptr, PA_CURRENT_FUNCTION, + "Hyperspace reward slug not found in database: " + slug + ); + } + return iter->second; +} +const std::string& parse_hyperspace_reward_name(const std::string& display_name){ + const std::map& database = HyperspaceRewardNamesDatabase::instance().reverse_lookup; + auto iter = database.find(display_name); + if (iter == database.end()){ + throw InternalProgramError( + nullptr, PA_CURRENT_FUNCTION, + "Hyperspace reward name not found in database: " + display_name + ); + } + return iter->second; +} +const std::string& parse_hyperspace_reward_name_nothrow(const std::string& display_name){ + const std::map& database = HyperspaceRewardNamesDatabase::instance().reverse_lookup; + auto iter = database.find(display_name); + if (iter == database.end()){ + return HyperspaceRewardNamesDatabase::NULL_SLUG; + } + return iter->second; +} + + +const std::vector& HYPERSPACE_REWARD_SLUGS(){ + return HyperspaceRewardNamesDatabase::instance().ordered_list; +} + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.h b/SerialPrograms/Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.h new file mode 100644 index 000000000..107f44c94 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.h @@ -0,0 +1,39 @@ +/* Hyperspace Reward Names + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_HyperspaceRewardNames_H +#define PokemonAutomation_PokemonLZA_HyperspaceRewardNames_H + +#include +#include + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +class HyperspaceRewardNames{ +public: + const std::string& display_name() const { return m_display_name; } + +private: + friend struct HyperspaceRewardNamesDatabase; + + std::string m_display_name; +}; + + +const HyperspaceRewardNames& get_hyperspace_reward_name(const std::string& slug); +const std::string& parse_hyperspace_reward_name(const std::string& display_name); +const std::string& parse_hyperspace_reward_name_nothrow(const std::string& display_name); + +const std::vector& HYPERSPACE_REWARD_SLUGS(); + + +} +} +} +#endif diff --git a/SerialPrograms/SourceFiles.cmake b/SerialPrograms/SourceFiles.cmake index 5c92733bd..8962a430f 100644 --- a/SerialPrograms/SourceFiles.cmake +++ b/SerialPrograms/SourceFiles.cmake @@ -1607,6 +1607,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Inference/PokemonLZA_DayNightChangeDetector.h Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h + Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.cpp + Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.h Source/PokemonLZA/Inference/PokemonLZA_MainMenuDetector.cpp Source/PokemonLZA/Inference/PokemonLZA_MainMenuDetector.h Source/PokemonLZA/Inference/PokemonLZA_OverworldPartySelectionDetector.cpp @@ -1619,6 +1621,10 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/InferenceTraining/PokemonLZA_GenerateLocationNameOCR.h Source/PokemonLZA/Options/PokemonLZA_BattleAIOption.cpp Source/PokemonLZA/Options/PokemonLZA_BattleAIOption.h + Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.cpp + Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardOption.h + Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.cpp + Source/PokemonLZA/Options/PokemonLZA_HyperspaceRewardTable.h Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h Source/PokemonLZA/PokemonLZA_Panels.cpp @@ -1627,6 +1633,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/PokemonLZA_Settings.h Source/PokemonLZA/Programs/Farming/PokemonLZA_FriendshipFarmer.cpp Source/PokemonLZA/Programs/Farming/PokemonLZA_FriendshipFarmer.h + Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.cpp + Source/PokemonLZA/Programs/Farming/PokemonLZA_HyperspaceRewardReset.h Source/PokemonLZA/Programs/Farming/PokemonLZA_InPlaceCatcher.cpp Source/PokemonLZA/Programs/Farming/PokemonLZA_InPlaceCatcher.h Source/PokemonLZA/Programs/Farming/PokemonLZA_JacintheInfiniteFarmer.cpp @@ -1686,6 +1694,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Programs/Trading/PokemonLZA_SelfBoxTrade.h Source/PokemonLZA/Programs/Trading/PokemonLZA_TradeRoutines.cpp Source/PokemonLZA/Programs/Trading/PokemonLZA_TradeRoutines.h + Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.cpp + Source/PokemonLZA/Resources/PokemonLZA_HyperspaceRewardNames.h Source/PokemonRSE/Inference/Dialogs/PokemonRSE_DialogDetector.cpp Source/PokemonRSE/Inference/Dialogs/PokemonRSE_DialogDetector.h Source/PokemonRSE/Inference/PokemonRSE_ShinyNumberDetector.cpp