diff --git a/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.cpp b/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.cpp index 6d113a927a..325709a935 100644 --- a/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.cpp +++ b/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.cpp @@ -120,6 +120,14 @@ const std::vector& BLUE_TEXT_FILTERS(){ }; return filters; } +const std::vector& LIME_TEXT_FILTERS(){ + static std::vector filters{ + {0xff6FA60D, 0xffBEEF36}, + {0xff5E9400, 0xffC9F95C}, + {0xff4D8100, 0xffD3FB7E}, + }; + return filters; +} diff --git a/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.h b/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.h index 6023598883..4028673696 100644 --- a/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.h +++ b/SerialPrograms/Source/CommonTools/OCR/OCR_Routines.h @@ -43,6 +43,7 @@ const std::vector& BLACK_TEXT_FILTERS(); const std::vector& WHITE_TEXT_FILTERS(); const std::vector& BLACK_OR_WHITE_TEXT_FILTERS(); const std::vector& BLUE_TEXT_FILTERS(); +const std::vector& LIME_TEXT_FILTERS(); diff --git a/SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.cpp b/SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.cpp new file mode 100644 index 0000000000..137be02a06 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.cpp @@ -0,0 +1,77 @@ +/* IV Judge Reader + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/ImageTypes/ImageViewRGB32.h" +#include "PokemonLZA_IvJudgeReader.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +const IvJudgeReader& IV_READER(){ + const static Pokemon::IvJudgeReader reader("PokemonLZA/IVCheckerOCR.json"); + return reader; +} + + + + +IvJudgeReaderScope::IvJudgeReaderScope(VideoOverlay& overlay, Language language) + : m_language(language) + , m_box0(overlay, {0.765000, 0.255000, 0.085000, 0.045000}) + , m_box1(overlay, {0.850000, 0.335000, 0.085000, 0.045000}) + , m_box2(overlay, {0.855000, 0.435000, 0.085000, 0.045000}) + , m_box3(overlay, {0.675000, 0.335000, 0.085000, 0.045000}) + , m_box4(overlay, {0.675000, 0.435000, 0.085000, 0.045000}) + , m_box5(overlay, {0.765000, 0.510000, 0.085000, 0.045000}) +{} + + + + +IvJudgeValue IvJudgeReaderScope::read(Logger& logger, const ImageViewRGB32& frame, const OverlayBoxScope& box){ + ImageViewRGB32 image = extract_box_reference(frame, box); + OCR::StringMatchResult result = IV_READER().read_substring( + logger, m_language, image, + OCR::LIME_TEXT_FILTERS() + ); + result.clear_beyond_log10p(IvJudgeReader::MAX_LOG10P); + if (result.results.size() != 1){ + return IvJudgeValue::UnableToDetect; + } + return IV_JUDGE_VALUE_STRINGS().get_enum(result.results.begin()->second.token); +} +IvJudgeReader::Results IvJudgeReaderScope::read(Logger& logger, const ImageViewRGB32& frame){ + IvJudgeReader::Results results; + if (m_language != Language::None){ + results.hp = read(logger, frame, m_box0); + results.attack = read(logger, frame, m_box1); + results.defense = read(logger, frame, m_box2); + results.spatk = read(logger, frame, m_box3); + results.spdef = read(logger, frame, m_box4); + results.speed = read(logger, frame, m_box5); + } + return results; +} + +std::vector IvJudgeReaderScope::dump_images(const ImageViewRGB32& frame){ + std::vector images; + images.emplace_back(extract_box_reference(frame, m_box0)); + images.emplace_back(extract_box_reference(frame, m_box1)); + images.emplace_back(extract_box_reference(frame, m_box2)); + images.emplace_back(extract_box_reference(frame, m_box3)); + images.emplace_back(extract_box_reference(frame, m_box4)); + images.emplace_back(extract_box_reference(frame, m_box5)); + return images; +} + + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.h b/SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.h new file mode 100644 index 0000000000..1a351341da --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.h @@ -0,0 +1,48 @@ +/* IV Judge Reader + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_IvJudgeReader_H +#define PokemonAutomation_PokemonLZA_IvJudgeReader_H + +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "Pokemon/Inference/Pokemon_IvJudgeReader.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ +using namespace Pokemon; + + +const IvJudgeReader& IV_READER(); + + +class IvJudgeReaderScope{ +public: + IvJudgeReaderScope(VideoOverlay& overlay, Language language); + + IvJudgeReader::Results read(Logger& logger, const ImageViewRGB32& frame); + + std::vector dump_images(const ImageViewRGB32& frame); + +private: + IvJudgeValue read(Logger& logger, const ImageViewRGB32& frame, const OverlayBoxScope& box); + +private: + Language m_language; + OverlayBoxScope m_box0; + OverlayBoxScope m_box1; + OverlayBoxScope m_box2; + OverlayBoxScope m_box3; + OverlayBoxScope m_box4; + OverlayBoxScope m_box5; +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp index ed8d3e8a0e..5025f47bdd 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp @@ -30,6 +30,9 @@ #include "Programs/ShinyHunting/PokemonLZA_AutoFossil.h" #include "Programs/ShinyHunting/PokemonLZA_WildZoneEntrance.h" +// Non-Shiny Hunting +#include "Programs/NonShinyHunting/PokemonLZA_StatsReset.h" + // Developer #include "Programs/TestPrograms/PokemonLZA_OverworldWatcher.h" #include "Programs/TestPrograms/PokemonLZA_MoveBoxArrow.h" @@ -73,11 +76,14 @@ std::vector PanelListFactory::make_panels() const{ if (IS_BETA_VERSION){ ret.emplace_back(make_single_switch_program()); } - if (PreloadSettings::instance().DEVELOPER_MODE){ ret.emplace_back(make_single_switch_program()); } + if (IS_BETA_VERSION){ + ret.emplace_back("---- Non-Shiny Hunting ----"); + ret.emplace_back(make_single_switch_program()); + } if (PreloadSettings::instance().DEVELOPER_MODE){ ret.emplace_back("---- Developer Tools ----"); diff --git a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp new file mode 100644 index 0000000000..7178da3dcd --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp @@ -0,0 +1,185 @@ +/* Stats Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.h" +#include "PokemonLZA_StatsReset.h" +#include "PokemonLZA/Programs/PokemonLZA_GameEntry.h" +#include "PokemonLZA/Programs/PokemonLZA_MenuNavigation.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +StatsReset_Descriptor::StatsReset_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLZA:StatsReset", + STRING_POKEMON + " LZA", "Stats Reset", + "Programs/PokemonLZA/StatsReset.html", + "Repeatedly receive gift " + STRING_POKEMON + " until you get the stats you want.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS + ) +{} +struct StatsReset_Descriptor::Stats : public StatsTracker{ + Stats() + : attempts(m_stats["Attempts"]) + , errors(m_stats["Errors"]) + , matches(m_stats["Matches"]) + { + m_display_order.emplace_back(Stat("Attempts")); + m_display_order.emplace_back(Stat("Errors")); + m_display_order.emplace_back(Stat("Matches")); + } + + std::atomic& attempts; + std::atomic& errors; + std::atomic& matches; +}; +std::unique_ptr StatsReset_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + + +StatsReset::StatsReset() + : GO_HOME_WHEN_DONE(true) + , LANGUAGE( + "Game Language:", + IV_READER().languages(), + LockMode::LOCK_WHILE_RUNNING + ) + , POKEMON( + "Gift " + STRING_POKEMON + ":", + { + {GiftPokemon::FLOETTE, "floette", "Floette"}, + }, + LockMode::LOCK_WHILE_RUNNING, + GiftPokemon::FLOETTE + ) + , HP("HP:") + , ATTACK("Attack:", IvJudgeFilter::NoGood) + , DEFENSE("Defense:") + , SPATK("Sp. Atk:") + , SPDEF("Sp. Def:") + , SPEED("Speed:") + , NOTIFICATION_PROGRAM_FINISH("Program Finished", true, true, ImageAttachmentMode::JPG) + , NOTIFICATIONS({ + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_FATAL, + }) +{ + PA_ADD_OPTION(GO_HOME_WHEN_DONE); + + PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(POKEMON); + PA_ADD_OPTION(HP); + PA_ADD_OPTION(ATTACK); + PA_ADD_OPTION(DEFENSE); + PA_ADD_OPTION(SPATK); + PA_ADD_OPTION(SPDEF); + PA_ADD_OPTION(SPEED); + + PA_ADD_OPTION(NOTIFICATIONS); +} + + + +void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + + StatsReset_Descriptor::Stats& stats = env.current_stats(); + + VideoSnapshot screen; + while (true){ + env.update_stats(); + context.wait_for_all_requests(); + + overworld_to_main_menu(env.console, context); + pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); + pbf_move_right_joystick(context, 128, 0, 500ms, 500ms); + pbf_move_right_joystick(context, 128, 0, 500ms, 500ms); + pbf_move_left_joystick(context, 50, 128, 100ms, 500ms); + pbf_mash_button(context, BUTTON_A, 5000ms); + + pbf_move_left_joystick(context, 128, 0, 10s, 500ms); + pbf_mash_button(context, BUTTON_A, 30s); + + context.wait_for_all_requests(); + { + BlackScreenOverWatcher detector; + int result = run_until( + env.console, context, + [this](ProControllerContext& context){ + if (POKEMON == GiftPokemon::FLOETTE){ + pbf_mash_button(context, BUTTON_A, 60s); + }else{ + pbf_mash_button(context, BUTTON_A, 30s); + } + }, + {{detector}} + ); + if (result == 0){ + env.log(STRING_POKEMON + " dialog finished.", COLOR_PURPLE); + }else{ + env.log(STRING_POKEMON + " dialog timed out.", COLOR_RED); + } + } + + overworld_to_box_system(env.console, context); + pbf_press_button(context, BUTTON_RCLICK, 500ms, 500ms); + stats.attempts++; + context.wait_for_all_requests(); + + { + IvJudgeReaderScope reader(env.console, LANGUAGE); + screen = env.console.video().snapshot(); + IvJudgeReader::Results results = reader.read(env.console, screen); + bool ok = true; + ok &= HP.matches(stats.errors, results.hp); + ok &= ATTACK.matches(stats.errors, results.attack); + ok &= DEFENSE.matches(stats.errors, results.defense); + ok &= SPATK.matches(stats.errors, results.spatk); + ok &= SPDEF.matches(stats.errors, results.spdef); + ok &= SPEED.matches(stats.errors, results.speed); + if (ok){ + break; + } + } + + pbf_mash_button(context, BUTTON_B, 3s); + go_home(env.console, context); + reset_game_from_home(env, env.console, context, true); + } + + stats.matches++; + env.update_stats(); + env.log("Result Found!", COLOR_BLUE); + + pbf_wait(context, 5000ms); + pbf_press_button(context, BUTTON_CAPTURE, 2000ms, 5000ms); + + send_program_finished_notification( + env, NOTIFICATION_PROGRAM_FINISH, + "Found a match!", + screen, false + ); + GO_HOME_WHEN_DONE.run_end_of_program(context); +} + + +} +} +} + diff --git a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h new file mode 100644 index 0000000000..27fd34c732 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h @@ -0,0 +1,66 @@ +/* Stats Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_StatsReset_H +#define PokemonAutomation_PokemonLZA_StatsReset_H + +#include "Common/Cpp/Options/EnumDropdownOption.h" +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "CommonTools/Options/LanguageOCROption.h" +#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" +#include "NintendoSwitch/Options/NintendoSwitch_StartInGripMenuOption.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "Pokemon/Options/Pokemon_IvJudgeOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +using namespace Pokemon; + + +class StatsReset_Descriptor : public SingleSwitchProgramDescriptor{ +public: + StatsReset_Descriptor(); + + struct Stats; + virtual std::unique_ptr make_stats() const override; +}; + + + +class StatsReset : public SingleSwitchProgramInstance{ +public: + StatsReset(); + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + StartInGripOrGameOption START_LOCATION; + GoHomeWhenDoneOption GO_HOME_WHEN_DONE; + + OCR::LanguageOCROption LANGUAGE; + + enum class GiftPokemon{ + FLOETTE, + }; + EnumDropdownOption POKEMON; + + IVJudgeFilterOption HP; + IVJudgeFilterOption ATTACK; + IVJudgeFilterOption DEFENSE; + IVJudgeFilterOption SPATK; + IVJudgeFilterOption SPDEF; + IVJudgeFilterOption SPEED; + + EventNotificationOption NOTIFICATION_PROGRAM_FINISH; + EventNotificationsOption NOTIFICATIONS; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/SourceFiles.cmake b/SerialPrograms/SourceFiles.cmake index dbe36de3ea..915fa0d073 100644 --- a/SerialPrograms/SourceFiles.cmake +++ b/SerialPrograms/SourceFiles.cmake @@ -1554,6 +1554,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxDetection.h Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.cpp Source/PokemonLZA/Inference/Boxes/PokemonLZA_BoxInfoDetector.h + Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.cpp + Source/PokemonLZA/Inference/Boxes/PokemonLZA_IvJudgeReader.h Source/PokemonLZA/Inference/PokemonLZA_AlertEyeDetector.cpp Source/PokemonLZA/Inference/PokemonLZA_AlertEyeDetector.h Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.cpp @@ -1603,6 +1605,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Programs/PokemonLZA_StallBuyer.h Source/PokemonLZA/Programs/PokemonLZA_TrainerBattle.cpp Source/PokemonLZA/Programs/PokemonLZA_TrainerBattle.h + Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp + Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_AutoFossil.cpp Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_AutoFossil.h Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_BeldumHunter.cpp