diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index 1b9636eca3..6b2bdee43c 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -1375,6 +1375,10 @@ file(GLOB MAIN_SOURCES Source/PokemonLA/Resources/PokemonLA_WeatherAndTimeIcons.h Source/PokemonLGPE/Commands/PokemonLGPE_DateSpam.cpp Source/PokemonLGPE/Commands/PokemonLGPE_DateSpam.h + Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.cpp + Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.h + Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.cpp + Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.h Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.cpp Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.h Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp @@ -1385,6 +1389,10 @@ file(GLOB MAIN_SOURCES Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_FossilRevival.h Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.cpp + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.h + Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.cpp + Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.h Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.cpp Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.h Source/PokemonLGPE/PokemonLGPE_Panels.cpp diff --git a/SerialPrograms/SerialPrograms.pro b/SerialPrograms/SerialPrograms.pro index 2208fc3705..9c9db6d84f 100644 --- a/SerialPrograms/SerialPrograms.pro +++ b/SerialPrograms/SerialPrograms.pro @@ -674,11 +674,15 @@ SOURCES += \ Source/PokemonLA/Resources/PokemonLA_PokemonSprites.cpp \ Source/PokemonLA/Resources/PokemonLA_WeatherAndTimeIcons.cpp \ Source/PokemonLGPE/Commands/PokemonLGPE_DateSpam.cpp \ + Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.cpp \ + Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.cpp \ Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.cpp \ Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_FossilRevival.cpp \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp \ + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.cpp \ + Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.cpp \ Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.cpp \ Source/PokemonLGPE/PokemonLGPE_Panels.cpp \ Source/PokemonLGPE/PokemonLGPE_Settings.cpp \ @@ -1869,11 +1873,15 @@ HEADERS += \ Source/PokemonLA/Resources/PokemonLA_PokemonSprites.h \ Source/PokemonLA/Resources/PokemonLA_WeatherAndTimeIcons.h \ Source/PokemonLGPE/Commands/PokemonLGPE_DateSpam.h \ + Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.h \ + Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.h \ Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.h \ Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.h \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_FossilRevival.h \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h \ + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.h \ + Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.h \ Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.h \ Source/PokemonLGPE/PokemonLGPE_Panels.h \ Source/PokemonLGPE/PokemonLGPE_Settings.h \ diff --git a/SerialPrograms/Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.cpp b/SerialPrograms/Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.cpp new file mode 100644 index 0000000000..30f15e801e --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.cpp @@ -0,0 +1,69 @@ +/* Battle Arrow Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "Kernels/Waterfill/Kernels_Waterfill_Session.h" +#include "CommonFramework/Globals.h" +#include "CommonFramework/ImageTypes/ImageViewRGB32.h" +#include "CommonTools/Images/BinaryImage_FilterRgb32.h" +#include "CommonTools/ImageMatch/ExactImageMatcher.h" +#include "PokemonLGPE_BattleArrowDetector.h" + +//#include +//using std::cout; +//using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + +const ImageMatch::ExactImageMatcher& BATTLE_ARROW(){ + static ImageMatch::ExactImageMatcher matcher(RESOURCE_PATH() + "PokemonLGPE/BattleArrow.png"); + return matcher; +} + +BattleArrowDetector::BattleArrowDetector(Color color, const ImageFloatBox& box) + : m_color(color) + , m_box(box) +{} +void BattleArrowDetector::make_overlays(VideoOverlaySet& items) const{ + items.add(m_color, m_box); +} +bool BattleArrowDetector::detect(const ImageViewRGB32& screen) const{ + using namespace Kernels::Waterfill; + + ImageViewRGB32 region = extract_box_reference(screen, m_box); + + const ImageMatch::ExactImageMatcher& matcher = BATTLE_ARROW(); + + auto matrix = compress_rgb32_to_binary_range(region, 0xffc0c0c0, 0xffffffff); + auto session = make_WaterfillSession(matrix); + auto iter = session->make_iterator(100); + WaterfillObject object; + + //static int c = 0; + while (iter->find_next(object, false)){ + double aspect_ratio = object.aspect_ratio(); + if (aspect_ratio < 1.0 || aspect_ratio > 1.3){ + continue; + } + ImageViewRGB32 cropped = extract_box_reference(region, object); + //cropped.save("test-object-" + std::to_string(c++) + ".png"); + double rmsd = matcher.rmsd(cropped); + //cout << rmsd << endl; + if (rmsd < 110){ + return true; + } + } + + return false; +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.h b/SerialPrograms/Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.h new file mode 100644 index 0000000000..5235944b2b --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.h @@ -0,0 +1,53 @@ +/* Battle Arrow Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLGPE_BattleArrowDetector_H +#define PokemonAutomation_PokemonLGPE_BattleArrowDetector_H + +#include +#include +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "Common/Cpp/Color.h" +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include "CommonTools/VisualDetector.h" +#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + +class BattleArrowDetector : public StaticScreenDetector{ +public: + /* + |Fight|Pokemon|Bag|Run| for wild battle + |---|Fight|Pokemon|Bag| for trainer battle + (align right) + Don't know what changes for a double battle. + */ + //Arrow bounces back and forth. + BattleArrowDetector(Color color, const ImageFloatBox& box); + + virtual void make_overlays(VideoOverlaySet& items) const override; + virtual bool detect(const ImageViewRGB32& screen) const override; + +protected: + Color m_color; + ImageFloatBox m_box; +}; +class BattleArrowWatcher : public DetectorToFinder{ +public: + BattleArrowWatcher(Color color = COLOR_RED, ImageFloatBox box = {0.546, 0.863, 0.045, 0.068}) + : DetectorToFinder("BattleArrowWatcher", std::chrono::milliseconds(100), color, box) + {} +}; + + + +} +} +} + +#endif diff --git a/SerialPrograms/Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.cpp b/SerialPrograms/Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.cpp new file mode 100644 index 0000000000..f1d9cdb9c7 --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.cpp @@ -0,0 +1,47 @@ +/* Shiny Sound Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonTools/Audio/AudioTemplateCache.h" +#include "CommonTools/Audio/SpectrogramMatcher.h" +#include "NintendoSwitch/NintendoSwitch_ConsoleHandle.h" +#include "PokemonLGPE/PokemonLGPE_Settings.h" +#include "PokemonLGPE_ShinySoundDetector.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + + +ShinySoundDetector::ShinySoundDetector(Logger& logger, DetectedCallback detected_callback) + // Use a yellow as the detection color because the shiny animation is yellow. + : AudioPerSpectrumDetectorBase( + logger, + "ShinySoundDetector", + "Shiny sound", + COLOR_YELLOW, + detected_callback + ) +{} + + +float ShinySoundDetector::get_score_threshold() const{ + return (float)GameSettings::instance().SHINY_SOUND_THRESHOLD; +} + +std::unique_ptr ShinySoundDetector::build_spectrogram_matcher(size_t sample_rate){ + return std::make_unique( + "Shiny Sound", + AudioTemplateCache::instance().get_throw("PokemonLGPE/ShinySound", sample_rate), + SpectrogramMatcher::Mode::SPIKE_CONV, sample_rate, + GameSettings::instance().SHINY_SOUND_LOW_FREQUENCY + ); +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.h b/SerialPrograms/Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.h new file mode 100644 index 0000000000..cd76bcd059 --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.h @@ -0,0 +1,36 @@ +/* Shiny Sound Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLGPE_ShinySoundDetector_H +#define PokemonAutomation_PokemonLGPE_ShinySoundDetector_H + +#include "CommonTools/Audio/AudioPerSpectrumDetectorBase.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + + +class ShinySoundDetector : public AudioPerSpectrumDetectorBase{ +public: + // Warning: The callback will be called from the audio inference thread. + ShinySoundDetector(Logger& logger, DetectedCallback detected_callback); + + // Implement AudioPerSpectrumDetectorBase::get_score_threshold() + virtual float get_score_threshold() const override; + +protected: + // Implement AudioPerSpectrumDetectorBase::build_spectrogram_matcher() + virtual std::unique_ptr build_spectrogram_matcher(size_t sample_rate) override; +}; + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp index 31fff24aa0..95376aa852 100644 --- a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp +++ b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp @@ -13,6 +13,9 @@ #include "Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h" #include "Programs/ShinyHunting/PokemonLGPE_FossilRevival.h" #include "Programs/ShinyHunting/PokemonLGPE_GiftReset.h" +#include "Programs/ShinyHunting/PokemonLGPE_LegendaryReset.h" + +#include "Programs/TestPrograms/PokemonLGPE_SoundListener.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -35,6 +38,14 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); + if (IS_BETA_VERSION || PreloadSettings::instance().DEVELOPER_MODE) { + ret.emplace_back(make_single_switch_program()); + } + + if (PreloadSettings::instance().DEVELOPER_MODE){ + ret.emplace_back("---- Developer Tools ----"); + ret.emplace_back(make_single_switch_program()); + } return ret; } diff --git a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp index cf99cdc421..db04e2536b 100644 --- a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp +++ b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp @@ -48,6 +48,17 @@ GameSettings::GameSettings() LockMode::LOCK_WHILE_RUNNING, "15 s" ) + , m_shiny_audio_settings("Shiny Audio Settings:") + , SHINY_SOUND_THRESHOLD( + "Shiny Sound Threshold:
Maximum error coefficient to trigger a shiny detection.", + LockMode::LOCK_WHILE_RUNNING, + 0.95, 0, 1.0 + ) + , SHINY_SOUND_LOW_FREQUENCY( + "Shiny Sound Low Frequency (Hz):
High pass filter frequency for shiny sound.", + LockMode::LOCK_WHILE_RUNNING, + 1000, 0, 48000 + ) { PA_ADD_STATIC(m_general); @@ -59,6 +70,10 @@ GameSettings::GameSettings() PA_ADD_OPTION(START_GAME_WAIT1); PA_ADD_OPTION(ENTER_GAME_MASH0); PA_ADD_OPTION(ENTER_GAME_WAIT0); + + PA_ADD_STATIC(m_shiny_audio_settings); + PA_ADD_OPTION(SHINY_SOUND_THRESHOLD); + PA_ADD_OPTION(SHINY_SOUND_LOW_FREQUENCY); } diff --git a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.h b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.h index 792dd6e0a4..cbaa1135e6 100644 --- a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.h +++ b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.h @@ -32,6 +32,10 @@ class GameSettings : public BatchOption{ MillisecondsOption START_GAME_WAIT1; MillisecondsOption ENTER_GAME_MASH0; MillisecondsOption ENTER_GAME_WAIT0; + + SectionDividerOption m_shiny_audio_settings; + FloatingPointOption SHINY_SOUND_THRESHOLD; + FloatingPointOption SHINY_SOUND_LOW_FREQUENCY; }; diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.cpp b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.cpp new file mode 100644 index 0000000000..967f4a4743 --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.cpp @@ -0,0 +1,241 @@ +/* LGPE Legendary Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/StartupChecks/VideoResolutionCheck.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" +#include "Pokemon/Pokemon_Strings.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.h" +#include "PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.h" +#include "PokemonLGPE/Programs/PokemonLGPE_GameEntry.h" +#include "PokemonLGPE_LegendaryReset.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + +LegendaryReset_Descriptor::LegendaryReset_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLGPE:LegendaryReset", + Pokemon::STRING_POKEMON + " LGPE", "Legendary Reset", + "ComputerControl/blob/master/Wiki/Programs/PokemonLGPE/LegendaryReset.md", + "Shiny hunt Legendary Pokemon by resetting the game.", + FeedbackType::VIDEO_AUDIO, + AllowCommandsWhenRunning::DISABLE_COMMANDS, + {ControllerFeature::NintendoSwitch_RightJoycon}, + FasterIfTickPrecise::NOT_FASTER + ) +{} + +struct LegendaryReset_Descriptor::Stats : public StatsTracker{ + Stats() + : resets(m_stats["Resets"]) + , shinies(m_stats["Shinies"]) + { + m_display_order.emplace_back("Resets"); + m_display_order.emplace_back("Shinies"); + } + std::atomic& resets; + std::atomic& shinies; +}; +std::unique_ptr LegendaryReset_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + +LegendaryReset::LegendaryReset() + : TARGET( + "Target:
", + { + {Target::mewtwo, "mewtwo", "Mewtwo, Articuno, Zapdos, Moltres"}, + {Target::snorlax, "snorlax", "Snorlax"}, + //{Target::snorlax2, "snorlax2", "Snorlax (w/Fuji)"}, + }, + LockMode::LOCK_WHILE_RUNNING, + Target::mewtwo + ) + , GO_HOME_WHEN_DONE(true) + , NOTIFICATION_SHINY( + "Shiny Found", + true, true, ImageAttachmentMode::JPG, + {"Notifs", "Showcase"} + ) + , NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600)) + , NOTIFICATIONS({ + &NOTIFICATION_SHINY, + &NOTIFICATION_STATUS_UPDATE, + &NOTIFICATION_PROGRAM_FINISH, + }) +{ + PA_ADD_OPTION(TARGET); + PA_ADD_OPTION(GO_HOME_WHEN_DONE); + PA_ADD_OPTION(NOTIFICATIONS); +} + +bool LegendaryReset::run_encounter(SingleSwitchProgramEnvironment& env, JoyconContext& context){ + float shiny_coefficient = 1.0; + ShinySoundDetector shiny_detector(env.logger(), [&](float error_coefficient) -> bool{ + shiny_coefficient = error_coefficient; + return true; + }); + BattleArrowWatcher battle_started(COLOR_YELLOW, {0.546, 0.863, 0.045, 0.068}); + + env.log("Starting battle."); + switch (TARGET) { + case Target::mewtwo: + pbf_mash_button(context, BUTTON_A, 3000ms); //untested + pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); //also untested + break; + case Target::snorlax: + pbf_mash_button(context, BUTTON_A, 5000ms); + pbf_mash_button(context, BUTTON_B, 10000ms); + break; + } + context.wait_for_all_requests(); + + int res = run_until( + env.console, context, + [&](JoyconContext& context) { + int ret = wait_until( + env.console, context, + std::chrono::seconds(90), + {{battle_started}} + ); + if (ret == 0) { + env.log("HP boxes detected."); + } else { + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "run_battle(): Did not detect battle start.", + env.console + ); + } + context.wait_for_all_requests(); + }, + {{shiny_detector}} + ); + shiny_detector.throw_if_no_sound(); + if (res == 0){ + env.log("Shiny detected!"); + return true; + } + env.log("Shiny not found."); + + return false; +} + +void LegendaryReset::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){ + JoyconContext context(scope, env.console.controller()); + assert_16_9_720p_min(env.logger(), env.console); + LegendaryReset_Descriptor::Stats& stats = env.current_stats(); + + /* + Setup: + Stand in front of encounter. (And save) + Start the program in game. + Your lead must not be shiny. + + Settings: + Text Speed fast + Skip cutscene On + Skip move animation On + + Mewtwo, Articuno, Zapdos, Moltres, Snorlax, Electrode(?) + Don't do it on the first Snorlax, otherwise have to sit through fuji tutorial + */ + + while (true) { + bool encounter_battle = run_encounter(env, context); + if (encounter_battle) { + stats.shinies++; + env.update_stats(); + send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", env.console.video().snapshot(), true); + break; + } + env.log("No shiny found. Resetting game."); + send_program_status_notification( + env, NOTIFICATION_STATUS_UPDATE, + "No shiny found. Resetting game." + ); + + //Reset game + pbf_press_button(context, BUTTON_HOME, 200ms, 2000ms); + reset_game_from_home(env, env.console, context, 3000ms); + context.wait_for_all_requests(); + + stats.resets++; + env.update_stats(); + } + //Shiny found, complete the battle + WallClock start = current_time(); + BattleArrowWatcher catching_started(COLOR_RED, {0.005, 0.662, 0.049, 0.069}); + int res = run_until( + env.console, context, + [&](JoyconContext& context) { + while(true){ + if (current_time() - start > std::chrono::minutes(5)){ + env.log("Timed out during battle after 5 minutes.", COLOR_RED); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Timed out during battle after 5 minutes.", + env.console + ); + } + BattleArrowWatcher battle_menu(COLOR_YELLOW, {0.546, 0.863, 0.045, 0.068}); + context.wait_for_all_requests(); + + int ret = wait_until( + env.console, context, + std::chrono::seconds(30), + { battle_menu } + ); + switch (ret){ + case 0: + env.log("Detected battle menu. Mashing A to attack."); + pbf_mash_button(context, BUTTON_A, 3000ms); + context.wait_for_all_requests(); + break; + default: + env.log("Timed out during battle. Stuck, crashed, or took more than 30 seconds for a turn.", COLOR_RED); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Timed out during battle. Stuck, crashed, or took more than 30 seconds for a turn.", + env.console + ); + } + } + }, + {{catching_started}} + ); + switch (res){ + case 0: + env.log("Catching menu detected."); + break; + default: + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to detect catching menu.", + env.console + ); + break; + } + + if (GO_HOME_WHEN_DONE) { + pbf_press_button(context, BUTTON_HOME, 200ms, 1000ms); + } + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); +} + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.h b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.h new file mode 100644 index 0000000000..e186468887 --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.h @@ -0,0 +1,58 @@ +/* LGPE Legendary Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLGPE_LegendaryReset_H +#define PokemonAutomation_PokemonLGPE_LegendaryReset_H + +#include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "Common/Cpp/Options/SimpleIntegerOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + +class LegendaryReset_Descriptor : public SingleSwitchProgramDescriptor{ +public: + LegendaryReset_Descriptor(); + struct Stats; + virtual std::unique_ptr make_stats() const override; +}; + +class LegendaryReset : public SingleSwitchProgramInstance{ +public: + LegendaryReset(); + virtual void program(SingleSwitchProgramEnvironment& env, CancellableScope& scope) override; + +private: + bool run_encounter(SingleSwitchProgramEnvironment& env, JoyconContext& context); + + enum class Target{ + mewtwo, + snorlax, + //snorlax2, + }; + EnumDropdownOption TARGET; + + GoHomeWhenDoneOption GO_HOME_WHEN_DONE; + + EventNotificationOption NOTIFICATION_SHINY; + EventNotificationOption NOTIFICATION_STATUS_UPDATE; + EventNotificationsOption NOTIFICATIONS; +}; + + + + +} +} +} +#endif + + + diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.cpp b/SerialPrograms/Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.cpp new file mode 100644 index 0000000000..f47c2e6c48 --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.cpp @@ -0,0 +1,100 @@ +/* Sound Listener + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include +#include +#include +#include +#include +#include +#include "Common/Cpp/Exceptions.h" +#include "Common/Cpp/Containers/AlignedVector.tpp" +#include "CommonFramework/AudioPipeline/AudioFeed.h" +#include "CommonFramework/AudioPipeline/AudioTemplate.h" +#include "CommonTools/Audio/AudioTemplateCache.h" +#include "CommonTools/Audio/SpectrogramMatcher.h" +#include "CommonTools/Async/InferenceSession.h" +#include "Pokemon/Pokemon_Strings.h" +#include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h" +#include "PokemonLGPE/Inference/Sounds/PokemonLGPE_ShinySoundDetector.h" +#include "PokemonLGPE_SoundListener.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + using namespace Pokemon; + + +SoundListener_Descriptor::SoundListener_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLGPE:SoundListener", + STRING_POKEMON + " LGPE", "Sound Listener", + "", + "Test sound detectors listening to audio stream.", + FeedbackType::REQUIRED, AllowCommandsWhenRunning::ENABLE_COMMANDS, + {ControllerFeature::NintendoSwitch_RightJoycon}, + FasterIfTickPrecise::NOT_FASTER + ) +{} + + +SoundListener::SoundListener() + : SOUND_TYPE("Which Sound to Detect", + { + {SoundType::SHINY, "shiny", "Shiny Sound"}, + }, + LockMode::LOCK_WHILE_RUNNING, + SoundType::SHINY + ) + , STOP_ON_DETECTED_SOUND( + "Stop on the detected sound
Stop program when the sound is detected.", + LockMode::LOCK_WHILE_RUNNING, + false + ) +{ + PA_ADD_OPTION(SOUND_TYPE); + PA_ADD_OPTION(STOP_ON_DETECTED_SOUND); +} + +void SoundListener::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){ + JoyconContext context(scope, env.console.controller()); + + std::cout << "Running audio test program." << std::endl; + + std::shared_ptr detector; + auto action = [&](float error_coefficient) -> bool{ + // This lambda function will be called when the sound is detected. + // Its return will determine whether to stop the program: + return STOP_ON_DETECTED_SOUND; + }; + + SoundType type = SOUND_TYPE; + switch (type){ + case SoundType::SHINY: + detector = std::make_shared(env.console, action); + break; + default: + throw InternalProgramError( + &env.logger(), PA_CURRENT_FUNCTION, + "No such sound detector as sound type " + std::to_string((size_t)type) + ); + return; + } + + InferenceSession session( + context, env.console, + {{*detector, std::chrono::milliseconds(20)}} + ); + context.wait_until_cancel(); + + std::cout << "Audio test program Sound listener finished." << std::endl; +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.h b/SerialPrograms/Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.h new file mode 100644 index 0000000000..ad31b0add0 --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.h @@ -0,0 +1,53 @@ +/* Sound Listener + * + * From: https://github.com/PokemonAutomation/ + * + * Debug program to test all kinds of sound detectors. + */ + +#ifndef PokemonAutomation_PokemonLGPE_SoundListener_H +#define PokemonAutomation_PokemonLGPE_SoundListener_H + +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/EnumDropdownOption.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +//#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + + +class SoundListener_Descriptor : public SingleSwitchProgramDescriptor{ +public: + SoundListener_Descriptor(); +}; + + +class SoundListener : public SingleSwitchProgramInstance{ +public: + SoundListener(); + virtual void program(SingleSwitchProgramEnvironment& env, CancellableScope& scope) override; + + virtual void start_program_border_check( + CancellableScope& scope, + VideoStream& stream, + FeedbackType feedback_type + ) override{} + +private: + enum class SoundType{ + SHINY, + }; + + EnumDropdownOption SOUND_TYPE; + BooleanCheckBoxOption STOP_ON_DETECTED_SOUND; +}; + + + + +} +} +} +#endif