From 88e83884ba4893a4d748818b68225756bff8abcc Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Wed, 22 Oct 2025 01:43:49 -0700 Subject: [PATCH 01/22] Add PLZA button detectors. Refactor waterfill routine to take input resolution for size normalization. Add bench reset routine. --- .../Source/CommonFramework/Globals.cpp | 4 +- .../ImageTypes/ImageViewPlanar32.h | 2 + .../ImageMatch/WaterfillTemplateMatcher.cpp | 23 ++- .../ImageMatch/WaterfillTemplateMatcher.h | 17 +- .../CommonTools/Images/WaterfillUtilities.cpp | 12 +- .../CommonTools/Images/WaterfillUtilities.h | 8 +- .../DevPrograms/TestProgramSwitch.cpp | 10 +- .../Objects/PokemonLA_ArcDetector.cpp | 6 +- .../Inference/Objects/PokemonLA_ArcDetector.h | 6 +- .../Objects/PokemonLA_ArcPhoneDetector.cpp | 8 +- .../Objects/PokemonLA_ArcPhoneDetector.h | 6 +- .../PokemonLA_BattleSpriteArrowDetector.cpp | 12 +- .../PokemonLA_BattleSpriteArrowDetector.h | 6 +- .../Objects/PokemonLA_BubbleDetector.cpp | 6 +- .../Objects/PokemonLA_BubbleDetector.h | 6 +- .../Objects/PokemonLA_ButtonDetector.cpp | 27 ++- .../Objects/PokemonLA_ButtonDetector.h | 10 +- .../PokemonLA_DialogueEllipseDetector.cpp | 8 +- .../PokemonLA_DialogueEllipseDetector.h | 6 +- .../PokemonLA_DialogueYellowArrowDetector.cpp | 1 + .../Objects/PokemonLA_FlagDetector.cpp | 16 +- .../Objects/PokemonLA_FlagDetector.h | 6 +- .../PokemonLA_MMOQuestionMarkDetector.cpp | 5 +- .../Objects/PokemonLA_QuestMarkDetector.cpp | 6 +- .../Objects/PokemonLA_QuestMarkDetector.h | 6 +- .../Objects/PokemonLA_WhiteObjectDetector.cpp | 9 +- .../Objects/PokemonLA_WhiteObjectDetector.h | 7 +- .../Inference/PokemonLA_MountDetector.cpp | 52 ++--- .../Inference/PokemonLZA_ButtonDetector.cpp | 189 ++++++++++++++++++ .../Inference/PokemonLZA_ButtonDetector.h | 126 ++++++++++++ .../Inference/PokemonLZA_DialogDetector.cpp | 15 +- .../PokemonLZA_SelectionArrowDetector.cpp | 1 + .../Programs/PokemonLZA_BasicNavigation.cpp | 126 ++++++++++++ .../Programs/PokemonLZA_BasicNavigation.h | 27 +++ .../Programs/PokemonLZA_RestaurantFarmer.h | 1 - .../PokemonLZA_OverworldWatcher.cpp | 3 + .../Boxes/PokemonSV_BoxEggDetector.cpp | 1 + .../Dialogs/PokemonSV_DialogArrowDetector.cpp | 1 + .../PokemonSV_DestinationMarkerDetector.cpp | 2 + .../Map/PokemonSV_FastTravelDetector.cpp | 1 + .../Inference/Map/PokemonSV_MapDetector.cpp | 2 + .../PokemonSV_MapPokeCenterIconDetector.cpp | 1 + .../Overworld/PokemonSV_DirectionDetector.cpp | 1 + .../Overworld/PokemonSV_OliveDetector.cpp | 8 +- .../Overworld/PokemonSV_OverworldDetector.cpp | 1 + .../PokemonSV_SandwichHandDetector.cpp | 1 + .../PokemonSV_SandwichIngredientDetector.cpp | 2 + .../PokemonSV_WhiteButtonDetector.cpp | 2 +- .../Inference/PokemonSV_WhiteButtonDetector.h | 2 +- .../PokemonSV_WhiteTriangleDetector.cpp | 1 + .../Tera/PokemonSV_TeraRaidSearchDetector.cpp | 2 +- .../PokemonSwSh_DialogTriangleDetector.cpp | 1 + .../Inference/PokemonSwSh_YCommDetector.cpp | 1 + SerialPrograms/SourceFiles.cmake | 4 + 54 files changed, 721 insertions(+), 92 deletions(-) create mode 100644 SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.cpp create mode 100644 SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.h create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.h diff --git a/SerialPrograms/Source/CommonFramework/Globals.cpp b/SerialPrograms/Source/CommonFramework/Globals.cpp index a705e5d631..497078d7ea 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.cpp +++ b/SerialPrograms/Source/CommonFramework/Globals.cpp @@ -25,8 +25,8 @@ namespace PokemonAutomation{ const bool IS_BETA_VERSION = true; const int PROGRAM_VERSION_MAJOR = 0; -const int PROGRAM_VERSION_MINOR = 58; -const int PROGRAM_VERSION_PATCH = 3; +const int PROGRAM_VERSION_MINOR = 59; +const int PROGRAM_VERSION_PATCH = 1; const std::string PROGRAM_VERSION_BASE = "v" + std::to_string(PROGRAM_VERSION_MAJOR) + diff --git a/SerialPrograms/Source/CommonFramework/ImageTypes/ImageViewPlanar32.h b/SerialPrograms/Source/CommonFramework/ImageTypes/ImageViewPlanar32.h index 3c03c9c6e8..1ae09f6733 100644 --- a/SerialPrograms/Source/CommonFramework/ImageTypes/ImageViewPlanar32.h +++ b/SerialPrograms/Source/CommonFramework/ImageTypes/ImageViewPlanar32.h @@ -9,6 +9,7 @@ #include #include "Common/Compiler.h" +#include "Common/Cpp/ImageResolution.h" namespace PokemonAutomation{ @@ -35,6 +36,7 @@ class ImageViewPlanar32{ PA_FORCE_INLINE size_t bytes_per_row () const{ return m_bytes_per_row; } PA_FORCE_INLINE size_t width () const{ return m_width; } PA_FORCE_INLINE size_t height () const{ return m_height; } + PA_FORCE_INLINE Resolution size () const{ return Resolution(m_width, m_height); } PA_FORCE_INLINE size_t total_pixels () const{ return m_width * m_height; } // Direct Pixel Access diff --git a/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.cpp b/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.cpp index fa87444d7b..966fe83988 100644 --- a/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.cpp +++ b/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.cpp @@ -77,8 +77,8 @@ WaterfillTemplateMatcher::WaterfillTemplateMatcher( } } -double WaterfillTemplateMatcher::rmsd(const ImageViewRGB32& image) const{ - if (!image || !check_image(image)){ +double WaterfillTemplateMatcher::rmsd(Resolution input_resolution, const ImageViewRGB32& image) const{ + if (!image || !check_image(input_resolution, image)){ return 99999.; } return m_matcher->rmsd(image); @@ -125,7 +125,11 @@ bool WaterfillTemplateMatcher::check_area_ratio(double candidate_area_ratio) con return pass; } -double WaterfillTemplateMatcher::rmsd_precropped(const ImageViewRGB32& cropped_image, const WaterfillObject& object) const{ +double WaterfillTemplateMatcher::rmsd_precropped( + Resolution input_resolution, + const ImageViewRGB32& cropped_image, + const WaterfillObject& object +) const{ // XXX // dump_debug_image(global_logger_command_line(), "CommonFramework/WaterfillTemplateMatcher", "rmsd_precropped_input", cropped_image); @@ -142,7 +146,7 @@ double WaterfillTemplateMatcher::rmsd_precropped(const ImageViewRGB32& cropped_i // static int c = 0; // cout << c << endl; - double rmsd = this->rmsd(cropped_image); + double rmsd = this->rmsd(input_resolution, cropped_image); // cout << "rmsd = " << rmsd << endl; @@ -153,7 +157,11 @@ double WaterfillTemplateMatcher::rmsd_precropped(const ImageViewRGB32& cropped_i return rmsd; } -double WaterfillTemplateMatcher::rmsd_original(const ImageViewRGB32& original_image, const WaterfillObject& object) const{ +double WaterfillTemplateMatcher::rmsd_original( + Resolution input_resolution, + const ImageViewRGB32& original_image, + const WaterfillObject& object +) const{ if (PreloadSettings::debug().IMAGE_TEMPLATE_MATCHING){ cout << "rmsd_original()" << endl; @@ -172,7 +180,10 @@ double WaterfillTemplateMatcher::rmsd_original(const ImageViewRGB32& original_im return 99999.; } - double rmsd = this->rmsd(extract_box_reference(original_image, object)); + double rmsd = this->rmsd( + input_resolution, + extract_box_reference(original_image, object) + ); if (PreloadSettings::debug().IMAGE_TEMPLATE_MATCHING){ cout << "Passed aspect and area ratio check, rmsd = " << rmsd << endl; } diff --git a/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.h b/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.h index 120e652989..742cf51c73 100644 --- a/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.h +++ b/SerialPrograms/Source/CommonTools/ImageMatch/WaterfillTemplateMatcher.h @@ -9,6 +9,7 @@ #include #include "Common/Cpp/Color.h" +#include "Common/Cpp/ImageResolution.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonTools/ImageMatch/ExactImageMatcher.h" @@ -51,7 +52,7 @@ class WaterfillTemplateMatcher{ // In case the image is invalid, return a large value. // It also calls the virtual function `check_image()` on the image. // If the function returns false, then return a large value. - double rmsd(const ImageViewRGB32& image) const; + double rmsd(Resolution input_resolution, const ImageViewRGB32& image) const; // Compute RMSD of the object on the image against the template. // The input `cropped_image` is already cropped from a full image using the bounding box of the input waterfill `object`. @@ -59,7 +60,11 @@ class WaterfillTemplateMatcher{ // The waterfill object's aspect ratio and area ratio are checked against template's. Return a large value // if the check fails. // See `double rmsd(const ImageViewRGB32& image) const` on the details of comparing the image against the template. - virtual double rmsd_precropped(const ImageViewRGB32& cropped_image, const WaterfillObject& object) const; + virtual double rmsd_precropped( + Resolution input_resolution, + const ImageViewRGB32& cropped_image, + const WaterfillObject& object + ) const; // Compute RMSD of the object on the image against the template. // It will crop the original image using the bounding box of the waterfill object, then compare the cropped @@ -67,13 +72,17 @@ class WaterfillTemplateMatcher{ // The waterfill object's aspect ratio and area ratio are checked against template's. Return a large value // if the check fails. // See `double rmsd(const ImageViewRGB32& image) const` on the details of comparing the image against the template. - virtual double rmsd_original(const ImageViewRGB32& original_image, const WaterfillObject& object) const; + virtual double rmsd_original( + Resolution input_resolution, + const ImageViewRGB32& original_image, + const WaterfillObject& object + ) const; // Return the image template mesh const ImageRGB32& image_template() const { return m_matcher->image_template(); } protected: - virtual bool check_image(const ImageViewRGB32& image) const{ return true; }; + virtual bool check_image(Resolution input_resolution, const ImageViewRGB32& image) const{ return true; }; bool check_aspect_ratio(size_t candidate_width, size_t candidate_height) const; bool check_area_ratio(double candidate_area_ratio) const; diff --git a/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp b/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp index fffb14ad68..4c4fe09912 100644 --- a/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp +++ b/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp @@ -74,10 +74,11 @@ std::pair remove_center_pixels( } bool match_template_by_waterfill( - const ImageViewRGB32 &image, - const ImageMatch::WaterfillTemplateMatcher &matcher, - const std::vector> &filters, - const std::pair &area_thresholds, + Resolution input_resolution, + const ImageViewRGB32& image, + const ImageMatch::WaterfillTemplateMatcher& matcher, + const std::vector>& filters, + const std::pair& area_thresholds, double rmsd_threshold, std::function check_matched_object) { @@ -133,12 +134,13 @@ bool match_template_by_waterfill( if (object.area > area_thresholds.second){ continue; } - double rmsd = matcher.rmsd_original(image, object); + double rmsd = matcher.rmsd_original(input_resolution, image, object); if (PreloadSettings::debug().IMAGE_TEMPLATE_MATCHING){ std::cout << "Object rmsd: " << rmsd << std::endl; } if (rmsd < rmsd_threshold){ +// std::cout << "Object rmsd: " << rmsd << std::endl; detected = true; if (check_matched_object(object)){ diff --git a/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.h b/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.h index 40c05bc048..5020c7dba5 100644 --- a/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.h +++ b/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.h @@ -10,6 +10,7 @@ #include #include +#include "Common/Cpp/ImageResolution.h" #include "CommonFramework/ImageTypes/BinaryImage.h" namespace PokemonAutomation{ @@ -54,10 +55,11 @@ std::pair remove_center_pixels( // check_matched_object: if a matcher is found, pass the matched object to this function. If the function returns true, stop the // entire template matching operation. bool match_template_by_waterfill( - const ImageViewRGB32 &image, - const ImageMatch::WaterfillTemplateMatcher &matcher, + Resolution input_resolution, + const ImageViewRGB32& image, + const ImageMatch::WaterfillTemplateMatcher& matcher, const std::vector> &filters, - const std::pair &area_thresholds, + const std::pair& area_thresholds, double rmsd_threshold, std::function check_matched_object); diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index 54e8dfcd69..31e566f23e 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -146,6 +146,7 @@ #include "PokemonLGPE/Inference/Battles/PokemonLGPE_BattleArrowDetector.h" #include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h" #include "PokemonLZA/Programs/PokemonLZA_GameEntry.h" +#include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" @@ -274,6 +275,7 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& // using namespace PokemonBDSP; // using namespace PokemonLA; // using namespace PokemonSV; + using namespace PokemonLZA; [[maybe_unused]] Logger& logger = env.logger(); [[maybe_unused]] ConsoleHandle& console = env.consoles[0]; @@ -284,7 +286,13 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& VideoOverlaySet overlays(overlay); + while (true){ + sit_on_bench(console, context); + } + + +#if 0 while (true){ ssf_press_button(context, BUTTON_ZL, 160ms, 800ms, 200ms); ssf_press_button(context, BUTTON_PLUS, 320ms, 840ms); @@ -293,7 +301,7 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& pbf_press_button(context, BUTTON_X, 80ms, 24ms); pbf_press_button(context, BUTTON_B, 80ms, 24ms); } - +#endif #if 0 diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.cpp index 57f32cf7d6..142330c97f 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.cpp @@ -69,7 +69,11 @@ ArcDetector::ArcDetector() } ) {} -void ArcDetector::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ +void ArcDetector::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ ImagePixelBox object_box; if (ArcMatcher::left().matches(object_box, image, object)){ m_left.emplace_back(object_box); diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.h index b38b66a07b..a8b8a58ad7 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcDetector.h @@ -18,7 +18,11 @@ namespace PokemonLA{ class ArcDetector : public WhiteObjectDetector{ public: ArcDetector(); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; virtual void finish(const ImageViewRGB32& image) override; private: diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.cpp index 963c0c42ae..acb98277ff 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.cpp @@ -45,7 +45,11 @@ ArcPhoneTracker::ArcPhoneTracker() ) {} -void ArcPhoneTracker::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ +void ArcPhoneTracker::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ // cout << "asdf" << endl; // static int c = 0; // cout << "c = " << c << endl; @@ -60,7 +64,7 @@ void ArcPhoneTracker::process_object(const ImageViewRGB32& image, const Waterfil // cout << (double)object.width() / image.width() << endl; - double rmsd = ArcPhoneMatcher::instance().rmsd_original(image, object); + double rmsd = ArcPhoneMatcher::instance().rmsd_original(input_resolution, image, object); // cout << "rmsd = " << rmsd << endl; if (rmsd < 80){ // cout << "rmsd = " << rmsd << endl; diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.h index e46c714033..a3c97ed86c 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ArcPhoneDetector.h @@ -31,7 +31,11 @@ class ArcPhoneTracker : public WhiteObjectDetector{ public: ArcPhoneTracker(); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; virtual void finish(const ImageViewRGB32& image) override; }; diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.cpp index e779bdf70f..690a7afe01 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.cpp @@ -42,8 +42,16 @@ BattleSpriteArrowTracker::BattleSpriteArrowTracker() ) {} -void BattleSpriteArrowTracker::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ - double rmsd = BattleSpriteArrowMatcher::instance().rmsd_original(image, object); +void BattleSpriteArrowTracker::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ + double rmsd = BattleSpriteArrowMatcher::instance().rmsd_original( + input_resolution, + image, + object + ); if (rmsd < 80){ m_detections.emplace_back(object); } diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.h index 1512bfce42..6a14332d26 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BattleSpriteArrowDetector.h @@ -32,7 +32,11 @@ class BattleSpriteArrowTracker : public WhiteObjectDetector{ public: BattleSpriteArrowTracker(); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; virtual void finish(const ImageViewRGB32& image) override; }; diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.cpp index e19c7661b5..b7132522fb 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.cpp @@ -56,7 +56,11 @@ class BubbleMatcher : public ImageMatch::SubObjectTemplateMatcher{ BubbleDetector::BubbleDetector() : WhiteObjectDetector(COLOR_GREEN, {Color(0xffb0b0b0)}) {} -void BubbleDetector::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ +void BubbleDetector::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ if (object.area < 200){ return; } diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.h index 6f0d3d41fa..77b6881a3e 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_BubbleDetector.h @@ -18,7 +18,11 @@ namespace PokemonLA{ class BubbleDetector : public WhiteObjectDetector{ public: BubbleDetector(); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; virtual void finish(const ImageViewRGB32& image) override; }; diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.cpp index 632d2b2bf7..d69efec3b4 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.cpp @@ -17,7 +17,7 @@ namespace PokemonLA{ namespace{ -const char* templatePath(ButtonType type){ +const char* template_path(ButtonType type){ switch (type){ case ButtonType::ButtonA: return "PokemonLA/Buttons/ButtonA-Template.png"; @@ -55,7 +55,7 @@ const char* button_name(ButtonType type){ } } -const ButtonMatcher& getButtonMatcher(ButtonType type){ +const ButtonMatcher& get_button_matcher(ButtonType type){ switch (type){ case ButtonType::ButtonA: return ButtonMatcher::A(); @@ -76,12 +76,15 @@ const ButtonMatcher& getButtonMatcher(ButtonType type){ } -ButtonMatcher::ButtonMatcher(ButtonType type, size_t min_width, size_t max_width, double max_rmsd) +ButtonMatcher::ButtonMatcher(ButtonType type, size_t min_width, size_t min_height, double max_rmsd) : WaterfillTemplateMatcher( - templatePath(type), Color(0xff808008), Color(0xffffffff), 100 + template_path(type), + Color(0xff808008), + Color(0xffffffff), + 100 ) , m_min_width(min_width) - , m_min_height(max_width) + , m_min_height(min_height) , m_max_rmsd(max_rmsd) {} const ButtonMatcher& ButtonMatcher::A(){ @@ -125,17 +128,25 @@ ButtonTracker::ButtonTracker(ButtonType type) Color(0xffd0d0d0), } ) - , m_matcher(getButtonMatcher(type)) + , m_matcher(get_button_matcher(type)) {} -void ButtonTracker::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ +void ButtonTracker::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ // cout << "asdf" << endl; // static int c = 0; // extract_box(image, object).save("test-" + std::to_string(c++) + ".png"); // image.save("test-" + std::to_string(c++) + "-A.png"); // extract_box(image, object).save("test-" + std::to_string(c++) + "-B.png"); - double rmsd = m_matcher.rmsd_precropped(extract_box_reference(image, object), object); + double rmsd = m_matcher.rmsd_precropped( + input_resolution, + extract_box_reference(image, object), + object + ); // cout << "rmsd = " << rmsd << endl; // cout << "max = " << m_matcher.m_max_rmsd << endl; if (rmsd < m_matcher.m_max_rmsd){ diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.h index 024297e215..fdd9a52e31 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_ButtonDetector.h @@ -31,7 +31,7 @@ enum class ButtonType{ class ButtonMatcher : public ImageMatch::WaterfillTemplateMatcher{ public: - ButtonMatcher(ButtonType type, size_t min_width, size_t max_width, double max_rmsd); + ButtonMatcher(ButtonType type, size_t min_width, size_t min_height, double max_rmsd); static const ButtonMatcher& A(); static const ButtonMatcher& B(); static const ButtonMatcher& Plus(); @@ -39,7 +39,7 @@ class ButtonMatcher : public ImageMatch::WaterfillTemplateMatcher{ static const ButtonMatcher& ArrowLeft(); static const ButtonMatcher& ArrowRight(); - virtual bool check_image(const ImageViewRGB32& image) const override{ + virtual bool check_image(Resolution input_resolution, const ImageViewRGB32& image) const override{ return image.width() >= m_min_width && image.height() >= m_min_height; }; @@ -55,7 +55,11 @@ class ButtonTracker : public WhiteObjectDetector{ public: ButtonTracker(ButtonType type); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; virtual void finish(const ImageViewRGB32& image) override; private: diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.cpp index d25f55f81b..92f75488dd 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.cpp @@ -42,8 +42,12 @@ DialogueEllipseTracker::DialogueEllipseTracker() ) {} -void DialogueEllipseTracker::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ - double rmsd = DialogueEllipseMatcher::instance().rmsd_original(image, object); +void DialogueEllipseTracker::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ + double rmsd = DialogueEllipseMatcher::instance().rmsd_original(input_resolution, image, object); if (rmsd < 80){ m_detections.emplace_back(object); } diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.h index 3f72aba30c..985d065bb4 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueEllipseDetector.h @@ -33,7 +33,11 @@ class DialogueEllipseTracker : public WhiteObjectDetector{ public: DialogueEllipseTracker(); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; virtual void finish(const ImageViewRGB32& image) override; }; diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueYellowArrowDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueYellowArrowDetector.cpp index 3a4392508a..d824e613a8 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueYellowArrowDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_DialogueYellowArrowDetector.cpp @@ -77,6 +77,7 @@ bool DialogueYellowArrowDetector::process_frame(const ImageViewRGB32& frame, Wal const size_t min_size = size_t(200 * screen_scale * screen_scale); const bool detected = match_template_by_waterfill( + frame.size(), extract_box_reference(frame, YELLOW_ARROW_BOX), DialogueYellowArrowMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.cpp index ddfefb848c..9e69063369 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.cpp @@ -105,7 +105,11 @@ FlagDetector::FlagDetector() } ) {} -void FlagDetector::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ +void FlagDetector::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ // cout << "FlagDetector::process_object()" << endl; if (object.area < 50){ return; @@ -234,13 +238,17 @@ std::vector> make_digit_matchers(){ } -std::pair read_digit(const ImageViewRGB32& image, const WaterfillObject& object){ +std::pair read_digit( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ static const std::vector> MATCHERS = make_digit_matchers(); double best_rmsd = 99999; int best_digit = -1; for (const auto& item : MATCHERS){ // cout << item.first << " : " << << endl; - double rmsd = item.second.rmsd_original(image, object); + double rmsd = item.second.rmsd_original(input_resolution, image, object); if (best_rmsd > rmsd){ best_rmsd = rmsd; best_digit = item.first; @@ -307,7 +315,7 @@ int read_flag_distance(const ImageViewRGB32& screen, double flag_x, double flag_ // static int c = 0; // extract_box_reference(image, object).save("image-" + std::to_string(c++) + ".png"); - std::pair digit = read_digit(image, object); + std::pair digit = read_digit(screen.size(), image, object); if (digit.second >= 0){ hits.emplace( object.min_x, diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.h index a9c17b2f0b..0e99befafd 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_FlagDetector.h @@ -18,7 +18,11 @@ namespace PokemonLA{ class FlagDetector : public WhiteObjectDetector{ public: FlagDetector(); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; virtual void finish(const ImageViewRGB32& image) override; private: diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_MMOQuestionMarkDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_MMOQuestionMarkDetector.cpp index ac72a3f917..d60a56a677 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_MMOQuestionMarkDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_MMOQuestionMarkDetector.cpp @@ -85,7 +85,7 @@ const std::array hisui_map_boxes{{ }}; -bool detect_MMO_question_mark(const PokemonAutomation::ImageViewRGB32 &frame, const ImageFloatBox& box){ +bool detect_MMO_question_mark(const PokemonAutomation::ImageViewRGB32& frame, const ImageFloatBox& box){ auto image = extract_box_reference(frame, box); const double screen_rel_size = (frame.height() / 1080.0); @@ -99,6 +99,7 @@ bool detect_MMO_question_mark(const PokemonAutomation::ImageViewRGB32 &frame, co }; bool detected = match_template_by_waterfill( + frame.size(), image, MMOQuestionMarkBackgroundMatcher::instance(), { @@ -116,6 +117,7 @@ bool detect_MMO_question_mark(const PokemonAutomation::ImageViewRGB32 &frame, co const size_t min_curve_size = 250; const size_t max_curve_size = 450; detected = match_template_by_waterfill( + frame.size(), image, MMOQuestionMarkCurveMatcher::instance(), {{combine_rgb(180, 180, 180), combine_rgb(255, 255, 255)}}, {scale(min_curve_size), scale(max_curve_size)}, 100, @@ -181,6 +183,7 @@ std::vector MMOQuestionMarkDetector::detect_MMOs_on_region_map(co }; match_template_by_waterfill( + frame.size(), map_image, MMOQuestionMarkBackgroundMatcher::instance(), {{combine_rgb(0, 5, 30), combine_rgb(100, 130, 130)}}, {scale(min_bg_size), scale(max_bg_size)}, 110, diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.cpp index ddcfa54a2a..6cc4e68ac1 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.cpp @@ -63,7 +63,11 @@ QuestMarkDetector::QuestMarkDetector() } ) {} -void QuestMarkDetector::process_object(const ImageViewRGB32& image, const WaterfillObject& object){ +void QuestMarkDetector::process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object +){ ImagePixelBox object_box; if (QuestMarkMatcher::instance().matches(object_box, image, object)){ m_detections.emplace_back(object_box); diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.h index 2301f3f6af..dbb1e8541f 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_QuestMarkDetector.h @@ -18,7 +18,11 @@ namespace PokemonLA{ class QuestMarkDetector : public WhiteObjectDetector{ public: QuestMarkDetector(); - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) override; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) override; }; diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.cpp index 739cd7def6..2ffa5aa5b5 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.cpp @@ -22,6 +22,7 @@ using namespace Kernels::Waterfill; void find_overworld_white_objects( + Resolution input_resolution, const std::vector>& detectors, const ImageViewRGB32& image ){ @@ -62,7 +63,7 @@ void find_overworld_white_objects( for (const auto& detector : detectors){ const std::set& thresholds = detector.first.thresholds(); if (thresholds.find((Color)filters[c].first) != thresholds.end()){ - detector.first.process_object(image, object); + detector.first.process_object(input_resolution, image, object); } } } @@ -132,7 +133,11 @@ bool WhiteObjectWatcher::process_frame(const ImageViewRGB32& frame, WallClock ti detector.first.clear(); } - find_overworld_white_objects(m_detectors, extract_box_reference(frame, m_box)); + find_overworld_white_objects( + frame.size(), + m_detectors, + extract_box_reference(frame, m_box) + ); m_overlays.clear(); for (auto& detector : m_detectors){ diff --git a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.h b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.h index aa19a31a83..b5de188476 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.h +++ b/SerialPrograms/Source/PokemonLA/Inference/Objects/PokemonLA_WhiteObjectDetector.h @@ -48,7 +48,11 @@ class WhiteObjectDetector{ const std::vector& detections() const{ return m_detections; } void clear(){ m_detections.clear(); } - virtual void process_object(const ImageViewRGB32& image, const WaterfillObject& object) = 0; + virtual void process_object( + Resolution input_resolution, + const ImageViewRGB32& image, + const WaterfillObject& object + ) = 0; virtual void finish(const ImageViewRGB32& image){} protected: @@ -66,6 +70,7 @@ class WhiteObjectDetector{ void find_overworld_white_objects( + Resolution input_resolution, const std::vector>& detectors, const ImageViewRGB32& screen ); diff --git a/SerialPrograms/Source/PokemonLA/Inference/PokemonLA_MountDetector.cpp b/SerialPrograms/Source/PokemonLA/Inference/PokemonLA_MountDetector.cpp index b56ac640d4..f2e0eda279 100644 --- a/SerialPrograms/Source/PokemonLA/Inference/PokemonLA_MountDetector.cpp +++ b/SerialPrograms/Source/PokemonLA/Inference/PokemonLA_MountDetector.cpp @@ -58,17 +58,17 @@ ImageRGB32 make_MountMatcher2Image(const char* path){ ImageViewRGB32 cropped = extract_box_reference(image, object); // cropped.save("test-" + std::to_string(c++) + ".png"); - double current_rmsd_plus = ButtonMatcher::Plus().rmsd_precropped(cropped, object); + double current_rmsd_plus = ButtonMatcher::Plus().rmsd_precropped(image.size(), cropped, object); if (rmsd_plus > current_rmsd_plus){ rmsd_plus = current_rmsd_plus; plus = object; } - double current_rmsd_arrowL = ButtonMatcher::ArrowLeft().rmsd_precropped(cropped, object); + double current_rmsd_arrowL = ButtonMatcher::ArrowLeft().rmsd_precropped(image.size(), cropped, object); if (rmsd_arrowL > current_rmsd_arrowL){ rmsd_arrowL = current_rmsd_arrowL; arrowL = object; } - double current_rmsd_arrowR = ButtonMatcher::ArrowRight().rmsd_precropped(cropped, object); + double current_rmsd_arrowR = ButtonMatcher::ArrowRight().rmsd_precropped(image.size(), cropped, object); if (rmsd_arrowR > current_rmsd_arrowR){ rmsd_arrowR = current_rmsd_arrowR; arrowR = object; @@ -430,19 +430,19 @@ MountState MountDetector::detect(const ImageViewRGB32& screen) const{ // Read the buttons. - double current_rmsd_plus = ButtonMatcher::Plus().rmsd_precropped(cropped, object); + double current_rmsd_plus = ButtonMatcher::Plus().rmsd_precropped(screen.size(), cropped, object); if (rmsd_plus > current_rmsd_plus){ rmsd_plus = current_rmsd_plus; plus = object; } // cout << "Arrow (left)" << endl; - double current_rmsd_arrowL = ButtonMatcher::ArrowLeft().rmsd_precropped(cropped, object); + double current_rmsd_arrowL = ButtonMatcher::ArrowLeft().rmsd_precropped(screen.size(), cropped, object); if (rmsd_arrowL > current_rmsd_arrowL){ rmsd_arrowL = current_rmsd_arrowL; arrowL = object; } // cout << "Arrow (right)" << endl; - double current_rmsd_arrowR = ButtonMatcher::ArrowRight().rmsd_precropped(cropped, object); + double current_rmsd_arrowR = ButtonMatcher::ArrowRight().rmsd_precropped(screen.size(), cropped, object); // cout << "rmsd_arrowR = " << rmsd_arrowR << endl; if (rmsd_arrowR > current_rmsd_arrowR){ rmsd_arrowR = current_rmsd_arrowR; @@ -459,16 +459,16 @@ MountState MountDetector::detect(const ImageViewRGB32& screen) const{ ImageViewRGB32 filtered_cropped = extract_box_reference(filtered.image, object); #if 1 - candidates.add_filtered(MountWyrdeerMatcher ::off().rmsd_precropped(filtered_cropped, object), MountState::WYRDEER_OFF); - candidates.add_direct (MountWyrdeerMatcher ::off().rmsd_precropped(cropped , object), MountState::WYRDEER_OFF); - candidates.add_filtered(MountUrsalunaMatcher ::off().rmsd_precropped(filtered_cropped, object), MountState::URSALUNA_OFF); - candidates.add_direct (MountUrsalunaMatcher ::off().rmsd_precropped(cropped , object), MountState::URSALUNA_OFF); - candidates.add_filtered(MountBasculegionMatcher ::off().rmsd_precropped(filtered_cropped, object), MountState::BASCULEGION_OFF); - candidates.add_direct (MountBasculegionMatcher ::off().rmsd_precropped(cropped , object), MountState::BASCULEGION_OFF); - candidates.add_filtered(MountSneaslerMatcher ::off().rmsd_precropped(filtered_cropped, object), MountState::SNEASLER_OFF); - candidates.add_direct (MountSneaslerMatcher ::off().rmsd_precropped(cropped , object), MountState::SNEASLER_OFF); - candidates.add_filtered(MountBraviaryMatcher ::off().rmsd_precropped(filtered_cropped, object), MountState::BRAVIARY_OFF); - candidates.add_direct (MountBraviaryMatcher ::off().rmsd_precropped(cropped , object), MountState::BRAVIARY_OFF); + candidates.add_filtered(MountWyrdeerMatcher ::off().rmsd_precropped(screen.size(), filtered_cropped, object), MountState::WYRDEER_OFF); + candidates.add_direct (MountWyrdeerMatcher ::off().rmsd_precropped(screen.size(), cropped , object), MountState::WYRDEER_OFF); + candidates.add_filtered(MountUrsalunaMatcher ::off().rmsd_precropped(screen.size(), filtered_cropped, object), MountState::URSALUNA_OFF); + candidates.add_direct (MountUrsalunaMatcher ::off().rmsd_precropped(screen.size(), cropped , object), MountState::URSALUNA_OFF); + candidates.add_filtered(MountBasculegionMatcher ::off().rmsd_precropped(screen.size(), filtered_cropped, object), MountState::BASCULEGION_OFF); + candidates.add_direct (MountBasculegionMatcher ::off().rmsd_precropped(screen.size(), cropped , object), MountState::BASCULEGION_OFF); + candidates.add_filtered(MountSneaslerMatcher ::off().rmsd_precropped(screen.size(), filtered_cropped, object), MountState::SNEASLER_OFF); + candidates.add_direct (MountSneaslerMatcher ::off().rmsd_precropped(screen.size(), cropped , object), MountState::SNEASLER_OFF); + candidates.add_filtered(MountBraviaryMatcher ::off().rmsd_precropped(screen.size(), filtered_cropped, object), MountState::BRAVIARY_OFF); + candidates.add_direct (MountBraviaryMatcher ::off().rmsd_precropped(screen.size(), cropped , object), MountState::BRAVIARY_OFF); #endif } @@ -548,16 +548,16 @@ MountState MountDetector::detect(const ImageViewRGB32& screen) const{ ImageViewRGB32 cropped = extract_box_reference(image, object); ImageViewRGB32 filtered_cropped = extract_box_reference(filtered.image, object); #if 1 - candidates.add_filtered(MountWyrdeerMatcher ::on().rmsd(filtered_cropped), MountState::WYRDEER_ON); - candidates.add_direct (MountWyrdeerMatcher ::on().rmsd(cropped ), MountState::WYRDEER_ON); - candidates.add_filtered(MountUrsalunaMatcher ::on().rmsd(filtered_cropped), MountState::URSALUNA_ON); - candidates.add_direct (MountUrsalunaMatcher ::on().rmsd(cropped ), MountState::URSALUNA_ON); - candidates.add_filtered(MountBasculegionMatcher ::on().rmsd(filtered_cropped), MountState::BASCULEGION_ON); - candidates.add_direct (MountBasculegionMatcher ::on().rmsd(cropped ), MountState::BASCULEGION_ON); - candidates.add_filtered(MountSneaslerMatcher ::on().rmsd(filtered_cropped), MountState::SNEASLER_ON); - candidates.add_direct (MountSneaslerMatcher ::on().rmsd(cropped ), MountState::SNEASLER_ON); - candidates.add_filtered(MountBraviaryMatcher ::on().rmsd(filtered_cropped), MountState::BRAVIARY_ON); - candidates.add_direct (MountBraviaryMatcher ::on().rmsd(cropped ), MountState::BRAVIARY_ON); + candidates.add_filtered(MountWyrdeerMatcher ::on().rmsd(screen.size(), filtered_cropped), MountState::WYRDEER_ON); + candidates.add_direct (MountWyrdeerMatcher ::on().rmsd(screen.size(), cropped ), MountState::WYRDEER_ON); + candidates.add_filtered(MountUrsalunaMatcher ::on().rmsd(screen.size(), filtered_cropped), MountState::URSALUNA_ON); + candidates.add_direct (MountUrsalunaMatcher ::on().rmsd(screen.size(), cropped ), MountState::URSALUNA_ON); + candidates.add_filtered(MountBasculegionMatcher ::on().rmsd(screen.size(), filtered_cropped), MountState::BASCULEGION_ON); + candidates.add_direct (MountBasculegionMatcher ::on().rmsd(screen.size(), cropped ), MountState::BASCULEGION_ON); + candidates.add_filtered(MountSneaslerMatcher ::on().rmsd(screen.size(), filtered_cropped), MountState::SNEASLER_ON); + candidates.add_direct (MountSneaslerMatcher ::on().rmsd(screen.size(), cropped ), MountState::SNEASLER_ON); + candidates.add_filtered(MountBraviaryMatcher ::on().rmsd(screen.size(), filtered_cropped), MountState::BRAVIARY_ON); + candidates.add_direct (MountBraviaryMatcher ::on().rmsd(screen.size(), cropped ), MountState::BRAVIARY_ON); #endif // extract_box(image, object).save("test-" + std::to_string(i) + ".png"); // i++; diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.cpp new file mode 100644 index 0000000000..31a9e9f2f9 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.cpp @@ -0,0 +1,189 @@ +/* Button Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "Kernels/Waterfill/Kernels_Waterfill_Types.h" +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonTools/Images/WaterfillUtilities.h" +#include "PokemonLZA_ButtonDetector.h" + +//#include +//using std::cout; +//using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +const char* template_path(ButtonType type){ + switch (type){ + case ButtonType::ButtonA: + return "PokemonLZA/Buttons/ButtonA.png"; + case ButtonType::ButtonB: + return "PokemonLZA/Buttons/ButtonB.png"; + case ButtonType::ButtonX: + return "PokemonLZA/Buttons/ButtonX.png"; + case ButtonType::ButtonY: + return "PokemonLZA/Buttons/ButtonY.png"; + case ButtonType::ButtonL: + return "PokemonLZA/Buttons/ButtonL.png"; + case ButtonType::ButtonR: + return "PokemonLZA/Buttons/ButtonR.png"; + case ButtonType::ButtonPlus: + return "PokemonLZA/Buttons/ButtonPlus.png"; + case ButtonType::ButtonMinus: + return "PokemonLZA/Buttons/ButtonMinus.png"; + case ButtonType::ButtonRight: + return "PokemonLZA/Buttons/ButtonRight.png"; + default: + return ""; + } +} + +const char* button_name(ButtonType type){ + switch (type){ + case ButtonType::ButtonA: + return "A"; + case ButtonType::ButtonB: + return "B"; + case ButtonType::ButtonX: + return "X"; + case ButtonType::ButtonY: + return "Y"; + case ButtonType::ButtonL: + return "L"; + case ButtonType::ButtonR: + return "R"; + case ButtonType::ButtonPlus: + return "+"; + case ButtonType::ButtonMinus: + return "-"; + case ButtonType::ButtonRight: + return ">"; + default: + return ""; + } +} + +const ButtonMatcher& get_button_matcher(ButtonType type){ + switch (type){ + case ButtonType::ButtonA: + return ButtonMatcher::A(); + case ButtonType::ButtonB: + return ButtonMatcher::B(); + case ButtonType::ButtonX: + return ButtonMatcher::X(); + case ButtonType::ButtonY: + return ButtonMatcher::Y(); + case ButtonType::ButtonL: + return ButtonMatcher::L(); + case ButtonType::ButtonR: + return ButtonMatcher::R(); + case ButtonType::ButtonPlus: + return ButtonMatcher::Plus(); + case ButtonType::ButtonMinus: + return ButtonMatcher::Minus(); + case ButtonType::ButtonRight: + return ButtonMatcher::Right(); + default: + throw std::runtime_error("No corresponding ButtonMatcher for ButtonType"); + } +} + + +ButtonMatcher::ButtonMatcher(ButtonType type, size_t min_width, size_t min_height, double max_rmsd) + : WaterfillTemplateMatcher( + template_path(type), + Color(0xff808008), + Color(0xffffffff), + 100 + ) + , m_min_width(min_width) + , m_min_height(min_height) + , m_max_rmsd(max_rmsd) +{} + + + +ButtonDetector::ButtonDetector( + Color color, + ButtonType button_type, + const ImageFloatBox& box, + VideoOverlay* overlay +) + : m_color(color) + , m_matcher(get_button_matcher(button_type)) + , m_box(box) + , m_overlay(overlay) +{ + +} +void ButtonDetector::make_overlays(VideoOverlaySet& items) const{ + items.add(m_color, m_box); +} +bool ButtonDetector::detect(const ImageViewRGB32& screen){ + + double screen_rel_size = (screen.height() / 2160.0); + double screen_rel_size_2 = screen_rel_size * screen_rel_size; + + double min_area_3840p = 1000.0; +// double rmsd_threshold = 120.0; + size_t min_area = size_t(screen_rel_size_2 * min_area_3840p); + + const std::vector> FILTERS = { + {0xffc0c0c0, 0xffffffff}, + {0xffb0b0b0, 0xffffffff}, + {0xffa0a0a0, 0xffffffff}, + {0xff909090, 0xffffffff}, + {0xff808080, 0xffffffff}, + }; + + bool found = match_template_by_waterfill( + screen.size(), + extract_box_reference(screen, m_box), + m_matcher, + FILTERS, + {min_area, SIZE_MAX}, + m_matcher.m_max_rmsd, + [&](Kernels::Waterfill::WaterfillObject& object) -> bool { +// cout << "width = " << object.width() << ", height = " << object.height() << endl; + m_last_detected = translate_to_parent(screen, m_box, object); + return true; + } + ); + + if (m_overlay){ + if (found){ + m_last_detected_box.emplace(*m_overlay, m_last_detected, COLOR_GREEN); + }else{ + m_last_detected_box.reset(); + } + } + + return found; +} + + + + + + + + + + + + + + + + + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.h new file mode 100644 index 0000000000..f9bbf53547 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.h @@ -0,0 +1,126 @@ +/* Button Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_ButtonDetector_H +#define PokemonAutomation_PokemonLZA_ButtonDetector_H + +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h" +#include "CommonTools/VisualDetector.h" +#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h" + +namespace PokemonAutomation{ + class Logger; +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +enum class ButtonType{ + ButtonA, + ButtonB, + ButtonX, + ButtonY, + ButtonL, + ButtonR, + ButtonPlus, + ButtonMinus, + ButtonRight, +}; + + +class ButtonMatcher : public ImageMatch::WaterfillTemplateMatcher{ +public: + ButtonMatcher(ButtonType type, size_t min_width, size_t min_height, double max_rmsd); + static const ButtonMatcher& A(){ + static ButtonMatcher matcher(ButtonType::ButtonA, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& B(){ + static ButtonMatcher matcher(ButtonType::ButtonB, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& X(){ + static ButtonMatcher matcher(ButtonType::ButtonX, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& Y(){ + static ButtonMatcher matcher(ButtonType::ButtonY, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& L(){ + static ButtonMatcher matcher(ButtonType::ButtonL, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& R(){ + static ButtonMatcher matcher(ButtonType::ButtonR, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& Plus(){ + static ButtonMatcher matcher(ButtonType::ButtonPlus, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& Minus(){ + static ButtonMatcher matcher(ButtonType::ButtonMinus, 60, 60, 70); + return matcher; + } + static const ButtonMatcher& Right(){ + static ButtonMatcher matcher(ButtonType::ButtonRight, 60, 60, 70); + return matcher; + } + + virtual bool check_image(Resolution input_resolution, const ImageViewRGB32& image) const override{ + size_t min_width = m_min_width * input_resolution.width / 3840; + size_t min_height = m_min_height * input_resolution.height / 2160; + return image.width() >= min_width && image.height() >= min_height; + }; + + size_t m_min_width; + size_t m_min_height; + double m_max_rmsd; +}; + + +class ButtonDetector : public StaticScreenDetector{ +public: + ButtonDetector( + Color color, + ButtonType button_type, + const ImageFloatBox& box, + VideoOverlay* overlay = nullptr + ); + virtual void make_overlays(VideoOverlaySet& items) const override; + virtual bool detect(const ImageViewRGB32& screen) override; + +private: + Color m_color; + const ButtonMatcher& m_matcher; + ImageFloatBox m_box; + VideoOverlay* m_overlay; + + ImageFloatBox m_last_detected; + std::optional m_last_detected_box; +}; +class ButtonWatcher : public DetectorToFinder{ +public: + ButtonWatcher( + Color color, + ButtonType button_type, + const ImageFloatBox& box, + VideoOverlay* overlay = nullptr, + std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250) + ) + : DetectorToFinder("ButtonWatcher", hold_duration, color, button_type, box, overlay) + {} +}; + + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp index 7b12a35690..6d07228099 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp @@ -9,15 +9,14 @@ //#include "CommonTools/Images/SolidColorTest.h" #include "PokemonLZA_DialogDetector.h" #include "CommonTools/Images/SolidColorTest.h" -#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h" #include "CommonTools/Images/WaterfillUtilities.h" +#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h" #include "CommonFramework/VideoPipeline/VideoOverlay.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" -// REMOVE -#include -using std::cout; -using std::endl; +//#include +//using std::cout; +//using std::endl; namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -138,6 +137,7 @@ bool NormalDialogDetector::process_frame(const ImageViewRGB32& frame, WallClock const double green_line_rmsd_threshold = 50.0; const size_t min_green_line_size = size_t(screen_rel_size_2 * min_green_line_size_1080P); match_template_by_waterfill( + frame.size(), extract_box_reference(frame, m_title_green_line_box), DialogTitleGreenLineMatcher::instance(), green_line_filters, @@ -160,6 +160,7 @@ bool NormalDialogDetector::process_frame(const ImageViewRGB32& frame, WallClock const double black_arrow_rmsd_threshold = 120.0; const size_t min_black_arrow_size = size_t(screen_rel_size_2 * min_black_arrow_size_1080P); match_template_by_waterfill( + frame.size(), extract_box_reference(frame, m_black_arrow_box), DialogBlackArrowMatcher::instance(), black_arrow_filters, @@ -235,6 +236,7 @@ bool FlatWhiteDialogDetector::detect(const ImageViewRGB32& screen){ }; bool found = match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_arrow_box), DialogBlackArrowMatcher::instance(), FILTERS, @@ -296,6 +298,7 @@ bool BlueDialogDetector::detect(const ImageViewRGB32& screen){ }; bool found = match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_arrow_box), DialogWhiteArrowMatcher::instance(), FILTERS, @@ -345,6 +348,7 @@ bool ItemReceiveDetector::detect(const ImageViewRGB32& screen){ }; bool found = match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_arrow_box), DialogWhiteArrowMatcher::instance(), FILTERS, @@ -390,6 +394,7 @@ bool TealDialogDetector::detect(const ImageViewRGB32& screen){ }; bool found = match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_arrow_box), DialogTealArrowMatcher::instance(), FILTERS, diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp index e208807b4c..8beb63c03f 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp @@ -82,6 +82,7 @@ bool SelectionArrowDetector::detect(const ImageViewRGB32& screen){ }; bool found = match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_arrow_box), SelectionArrowMatcher::matcher(m_type), FILTERS, diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp new file mode 100644 index 0000000000..322e83cf39 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp @@ -0,0 +1,126 @@ +/* Basic Navigation + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h" +#include "PokemonLZA_BasicNavigation.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + + +void sit_on_bench( + ConsoleHandle& console, ProControllerContext& context +){ +#if 0 + while (true){ + ButtonWatcher buttonA(COLOR_RED, ButtonType::ButtonA, {0, 0, 1, 1}, &console.overlay()); + BlueDialogWatcher dialog(COLOR_YELLOW, &console.overlay()); + SelectionArrowWatcher arrow(COLOR_BLUE, &console.overlay(), SelectionArrowType::RIGHT, {0.5, 0.4, 0.3, 0.3}); + BlackScreenOverWatcher black_screen(COLOR_BLUE); + + int ret = wait_until( + console, context, + 10000ms, + { + buttonA, + dialog, + arrow, + black_screen, + } + ); + context.wait_for(100ms); + + switch (ret){ + case 0: + console.log("Detected floating A button..."); + pbf_press_button(context, BUTTON_A, 200ms, 200ms); + continue; + case 1: + console.log("Detected dialog..."); + pbf_press_button(context, BUTTON_B, 200ms, 200ms); + continue; + case 2: + console.log("Detected selection arrow..."); + pbf_press_button(context, BUTTON_A, 200ms, 200ms); + continue; + case 3: + console.log("Detected day change."); + break; + default: + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "sit_on_bench(): No recognized state after 10 seconds.", + console + ); + } + } +#endif + + { + BlackScreenOverWatcher black_screen(COLOR_BLUE); + + int ret = run_until( + console, context, + [](ProControllerContext& context){ + pbf_mash_button(context, BUTTON_A, 30000ms); + }, + {black_screen} + ); + + switch (ret){ + case 0: + console.log("Detected day change."); + break; + default: + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "sit_on_bench(): No transition deteted after 30 seconds of mashing A.", + console + ); + } + } + { + ButtonWatcher buttonA(COLOR_RED, ButtonType::ButtonA, {0, 0, 1, 1}, &console.overlay()); + + int ret = run_until( + console, context, + [](ProControllerContext& context){ + // Can't just hold it down since sometimes it doesn't register. + for (int c = 0; c < 60; c++){ + pbf_move_left_joystick(context, 128, 255, 800ms, 200ms); + } + }, + {buttonA} + ); + + switch (ret){ + case 0: + console.log("Detected floating A button..."); + break; + default: + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "sit_on_bench(): Unable to detect bench after 60 seconds.", + console + ); + } + } + +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.h new file mode 100644 index 0000000000..d1c1e85e4b --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.h @@ -0,0 +1,27 @@ +/* Basic Navigation + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_BasicNavigation_H +#define PokemonAutomation_PokemonLZA_BasicNavigation_H + +#include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" +#include "NintendoSwitch/NintendoSwitch_ConsoleHandle.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +void sit_on_bench( + ConsoleHandle& console, ProControllerContext& context +); + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.h index cbef2aeaee..b9cedc0833 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.h @@ -7,7 +7,6 @@ #ifndef PokemonAutomation_PokemonLZA_RestaurantFarmer_H #define PokemonAutomation_PokemonLZA_RestaurantFarmer_H -#include "CommonFramework/ImageTypes/ImageRGB32.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" namespace PokemonAutomation{ diff --git a/SerialPrograms/Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.cpp b/SerialPrograms/Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.cpp index 7d6f67f4bb..d5f8fb52eb 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.cpp @@ -8,6 +8,7 @@ #include "Pokemon/Pokemon_Strings.h" #include "PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h" #include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" #include "PokemonLZA_OverworldWatcher.h" namespace PokemonAutomation{ @@ -44,6 +45,7 @@ void OverworldWatcher::program(SingleSwitchProgramEnvironment& env, ProControlle TealDialogWatcher dialog_teal(COLOR_RED, &overlay); SelectionArrowWatcher selection_arrow_right(COLOR_RED, &overlay, SelectionArrowType::RIGHT, {0, 0, 1, 1}); SelectionArrowWatcher selection_arrow_down(COLOR_RED, &overlay, SelectionArrowType::DOWN, {0, 0, 1, 1}); + ButtonWatcher buttonA(COLOR_RED, ButtonType::ButtonA, {0, 0, 1, 1}, &overlay); CancellableHolder scope(*context.scope()); InferenceSession session( @@ -54,6 +56,7 @@ void OverworldWatcher::program(SingleSwitchProgramEnvironment& env, ProControlle dialog_teal, selection_arrow_right, selection_arrow_down, + buttonA, } ); context.wait_until_cancel(); diff --git a/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxEggDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxEggDetector.cpp index d54d3d4a0a..4834a6329d 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxEggDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Boxes/PokemonSV_BoxEggDetector.cpp @@ -86,6 +86,7 @@ bool BoxEggDetector::detect(const ImageViewRGB32& frame){ const size_t min_size = size_t(screen_rel_size * screen_rel_size * 700); return match_template_by_waterfill( + frame.size(), extract_box_reference(frame, m_box), EggMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Dialogs/PokemonSV_DialogArrowDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Dialogs/PokemonSV_DialogArrowDetector.cpp index 8322006a48..58b91819f6 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Dialogs/PokemonSV_DialogArrowDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Dialogs/PokemonSV_DialogArrowDetector.cpp @@ -144,6 +144,7 @@ std::pair DialogArrowDetector::locate_dialog_arrow(const ImageVi ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_box); match_template_by_waterfill( + screen.size(), cropped, DialogArrowMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_DestinationMarkerDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_DestinationMarkerDetector.cpp index 3db683ede7..b13b2c3cf3 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_DestinationMarkerDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_DestinationMarkerDetector.cpp @@ -97,6 +97,7 @@ std::vector DestinationMarkerDetector::detect_all(const ImageView ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_box); match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_box), DestinationMarkerMatcher::instance(), filters, @@ -136,6 +137,7 @@ std::vector DestinationMarkerDetector::detect_all_yellow(const Im ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_box); match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_box), DestinationMarkerYellowMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp index b226e9a1c3..31589ef349 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp @@ -90,6 +90,7 @@ std::vector FastTravelDetector::detect_all(const ImageViewRGB32& ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_box); match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_box), FastTravelMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapDetector.cpp index 423f4faafd..971d107bb6 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapDetector.cpp @@ -78,6 +78,7 @@ bool MapFixedViewDetector::detect(const ImageViewRGB32& frame){ const size_t min_size = size_t(screen_rel_size * screen_rel_size * 150.0); const bool detected = match_template_by_waterfill( + frame.size(), extract_box_reference(frame, m_arrow_box), MapOrangleFixedViewArrowMatcher::instance(), filters, @@ -106,6 +107,7 @@ bool MapRotatedViewDetector::detect(const ImageViewRGB32& frame){ const size_t min_size = size_t(screen_rel_size * screen_rel_size * 450.0); const bool detected = match_template_by_waterfill( + frame.size(), extract_box_reference(frame, m_arrow_box), MapOrangleRotatedViewArrowMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapPokeCenterIconDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapPokeCenterIconDetector.cpp index b83300695c..e25963a64b 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapPokeCenterIconDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_MapPokeCenterIconDetector.cpp @@ -70,6 +70,7 @@ std::vector MapPokeCenterIconDetector::detect_all(const ImageView ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_box); match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_box), MapPokeCenterIconMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.cpp index d2f56f3dec..56d5cfb670 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.cpp @@ -88,6 +88,7 @@ std::pair DirectionDetector::locate_north(Logger& logger, const ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_minimap_box); match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_minimap_box), DirectionMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OliveDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OliveDetector.cpp index 196ab42bf1..4b90cd35d8 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OliveDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OliveDetector.cpp @@ -67,7 +67,12 @@ std::pair box_center(ImageFloatBox& box){ return std::make_pair(x, y); } -ImageFloatBox OliveDetector::get_olive_floatbox(const ImageViewRGB32& screen, ProControllerContext& context, uint8_t rgb_gap, ImageFloatBox box){ +ImageFloatBox OliveDetector::get_olive_floatbox( + const ImageViewRGB32& screen, + ProControllerContext& context, + uint8_t rgb_gap, + ImageFloatBox box +){ const std::vector> filters = { {combine_rgb(0, 10, 0), combine_rgb(255, 255, 255)}, }; @@ -85,6 +90,7 @@ ImageFloatBox OliveDetector::get_olive_floatbox(const ImageViewRGB32& screen, Pr ImageViewRGB32 cropped = extract_box_reference(green_only, box); ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), box); match_template_by_waterfill( + screen.size(), cropped, OliveMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OverworldDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OverworldDetector.cpp index 56c04af2d5..458d1817c3 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OverworldDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Overworld/PokemonSV_OverworldDetector.cpp @@ -103,6 +103,7 @@ std::pair OverworldDetector::locate_ball(const ImageViewRGB32& s ImageViewRGB32 cropped = extract_box_reference(screen, m_ball); ImagePixelBox pixel_box = floatbox_to_pixelbox(screen.width(), screen.height(), m_ball); match_template_by_waterfill( + screen.size(), cropped, RadarBallMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichHandDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichHandDetector.cpp index c888e21d0d..9f8c7780bd 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichHandDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichHandDetector.cpp @@ -104,6 +104,7 @@ std::pair SandwichHandLocator::locate_sandwich_hand(const ImageV ImagePixelBox pixel_box = floatbox_to_pixelbox(frame.width(), frame.height(), area_to_search); match_template_by_waterfill( + frame.size(), extract_box_reference(frame, area_to_search), ((m_type == HandType::FREE) ? SandwichFreeHandMatcher::instance() : SandwichGrabbingHandMatcher::instance()), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichIngredientDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichIngredientDetector.cpp index ba3eafd039..401ccae150 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichIngredientDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Picnics/PokemonSV_SandwichIngredientDetector.cpp @@ -119,6 +119,7 @@ bool SandwichCondimentsPageDetector::detect(const ImageViewRGB32& screen){ const size_t min_size = size_t(screen_rel_size * screen_rel_size * 700); return match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_box), SandwichCondimentsPageMatcher::instance(), filters, @@ -146,6 +147,7 @@ bool SandwichPicksPageDetector::detect(const ImageViewRGB32& screen){ const size_t min_size = size_t(screen_rel_size * screen_rel_size * 300); return match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_box), SandwichPicksPageMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.cpp index 024fc02ffd..2e106badb4 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.cpp @@ -162,7 +162,7 @@ std::vector WhiteButtonDetector::detect_all(const ImageViewRGB32& ){ continue; } - double rmsd = m_matcher.rmsd_original(region, object); + double rmsd = m_matcher.rmsd_original(screen.size(), region, object); // cout << "rmsd = " << rmsd << endl; if (rmsd < m_matcher.m_max_rmsd){ hits.emplace_back(translate_to_parent(screen, m_box, object)); diff --git a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.h b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.h index 95b62650b8..9e7f38c939 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.h +++ b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.h @@ -50,7 +50,7 @@ class WhiteButtonMatcher : public ImageMatch::WaterfillTemplateMatcher{ static const WhiteButtonMatcher& ArrowRight(); static const WhiteButtonMatcher& LStick(); - virtual bool check_image(const ImageViewRGB32& image) const override{ + virtual bool check_image(Resolution input_resolution, const ImageViewRGB32& image) const override{ return image.width() >= m_min_width && image.height() >= m_min_height; }; diff --git a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp index dbea2213b9..25f21cc471 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp @@ -71,6 +71,7 @@ bool WhiteTriangleDetector::detect(const ImageViewRGB32& screen) { bool is_found = false; match_template_by_waterfill( + screen.size(), extract_box_reference(screen, m_box), WhiteTriangleMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSV/Inference/Tera/PokemonSV_TeraRaidSearchDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Tera/PokemonSV_TeraRaidSearchDetector.cpp index 33c224fb4f..149c1a09c3 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Tera/PokemonSV_TeraRaidSearchDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Tera/PokemonSV_TeraRaidSearchDetector.cpp @@ -64,7 +64,7 @@ bool TeraRaidSearchDetector::detect_search_location(ImageFloatBox& box, const Im // cout << "yellow = " << object.area << endl; // extract_box_reference(screen, object).save("object-" + std::to_string(c++) + ".png"); // yellows.emplace_back(std::move(object)); - double rmsd = MATCHER.rmsd(extract_box_reference(screen, object)); + double rmsd = MATCHER.rmsd(screen.size(), extract_box_reference(screen, object)); // cout << "rmsd = " << rmsd << endl; if (rmsd < 100){ diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogTriangleDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogTriangleDetector.cpp index fa6b7ef28b..cbb4cf7f5a 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogTriangleDetector.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_DialogTriangleDetector.cpp @@ -75,6 +75,7 @@ bool DialogTriangleDetector::process_frame(const ImageViewRGB32& frame, WallCloc const size_t min_size = size_t(screen_rel_size * screen_rel_size * 500.0); const bool detected = match_template_by_waterfill( + frame.size(), extract_box_reference(frame, BLACK_TRIANGLE_BOX), DialogTriangleMatcher::instance(), filters, diff --git a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_YCommDetector.cpp b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_YCommDetector.cpp index a167a0ca7f..314c7cec19 100644 --- a/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_YCommDetector.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Inference/PokemonSwSh_YCommDetector.cpp @@ -105,6 +105,7 @@ bool YCommIconDetector::process_frame(const ImageViewRGB32& frame, WallClock tim const size_t min_size = (size_t)(350. * frame.total_pixels() / (1920 * 1080.)); const bool detected = match_template_by_waterfill( + frame.size(), extract_box_reference(frame, YCOMM_ICON_BOX), YCommIconMatcher::instance(), filters, diff --git a/SerialPrograms/SourceFiles.cmake b/SerialPrograms/SourceFiles.cmake index 062f821efd..d53949f3e9 100644 --- a/SerialPrograms/SourceFiles.cmake +++ b/SerialPrograms/SourceFiles.cmake @@ -1539,6 +1539,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_LegendaryReset.h Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.cpp Source/PokemonLGPE/Programs/TestPrograms/PokemonLGPE_SoundListener.h + Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.cpp + Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.h Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp @@ -1547,6 +1549,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/PokemonLZA_Panels.h Source/PokemonLZA/PokemonLZA_Settings.cpp Source/PokemonLZA/PokemonLZA_Settings.h + Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp + Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.h Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.h Source/PokemonLZA/Programs/PokemonLZA_GameEntry.cpp From a82ceef8d367b8d70877afac7f356f0954450af0 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Wed, 22 Oct 2025 09:20:33 -0700 Subject: [PATCH 02/22] Add WIP bench shiny hunt. --- SerialPrograms/Source/PanelLists.cpp | 4 +- .../PokemonBDSP/PokemonBDSP_Settings.cpp | 6 +- .../Source/PokemonLA/PokemonLA_Settings.cpp | 6 +- .../PokemonLGPE/PokemonLGPE_Settings.cpp | 6 +- .../PokemonLZA_ShinyDetectedAction.cpp | 162 ++++++++++++++++++ .../Options/PokemonLZA_ShinyDetectedAction.h | 68 ++++++++ .../Source/PokemonLZA/PokemonLZA_Panels.cpp | 10 +- .../Source/PokemonLZA/PokemonLZA_Settings.cpp | 6 +- .../Programs/PokemonLZA_ShinyHunt_Bench.cpp | 142 +++++++++++++++ .../Programs/PokemonLZA_ShinyHunt_Bench.h | 53 ++++++ .../Source/PokemonSV/PokemonSV_Settings.cpp | 6 +- .../PokemonSwSh/PokemonSwSh_Settings.cpp | 6 +- .../Source/ZeldaTotK/ZeldaTotK_Settings.cpp | 6 +- 13 files changed, 457 insertions(+), 24 deletions(-) create mode 100644 SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp create mode 100644 SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h diff --git a/SerialPrograms/Source/PanelLists.cpp b/SerialPrograms/Source/PanelLists.cpp index 57f4d04a3c..d9d186a643 100644 --- a/SerialPrograms/Source/PanelLists.cpp +++ b/SerialPrograms/Source/PanelLists.cpp @@ -54,7 +54,9 @@ ProgramSelect::ProgramSelect(QWidget& parent, PanelHolder& holder) add(std::make_unique()); add(std::make_unique()); - add(std::make_unique()); + if (PreloadSettings::instance().DEVELOPER_MODE){ + add(std::make_unique()); + } add(std::make_unique()); diff --git a/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Settings.cpp b/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Settings.cpp index 8f66de723e..718f19a741 100644 --- a/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Settings.cpp +++ b/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Settings.cpp @@ -39,17 +39,17 @@ GameSettings::GameSettings() ) , m_start_game_timings("Start Game Timings:") , START_GAME_WAIT0( - "2. Start Game Wait:
Wait this long for the game to load.", + "Start Game Wait:
Wait this long for the game to load.", LockMode::LOCK_WHILE_RUNNING, "300 s" ) , ENTER_GAME_MASH0( - "3. Enter Game Mash:
Mash A for this long to enter the game.", + "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, "5000 ms" ) , ENTER_GAME_WAIT0( - "4. Enter Game Wait:
Wait this long for the game to enter the overworld.", + "Enter Game Wait:
Wait this long for the game to enter the overworld.", LockMode::LOCK_WHILE_RUNNING, "300 s" ) diff --git a/SerialPrograms/Source/PokemonLA/PokemonLA_Settings.cpp b/SerialPrograms/Source/PokemonLA/PokemonLA_Settings.cpp index bf12f0db7b..c5618aa52c 100644 --- a/SerialPrograms/Source/PokemonLA/PokemonLA_Settings.cpp +++ b/SerialPrograms/Source/PokemonLA/PokemonLA_Settings.cpp @@ -40,17 +40,17 @@ GameSettings::GameSettings() ) , m_start_game_timings("Start Game Timings:") , START_GAME_WAIT1( - "2. Start Game Wait:
Wait this long for the game to load.", + "Start Game Wait:
Wait this long for the game to load.", LockMode::LOCK_WHILE_RUNNING, "40 s" ) , ENTER_GAME_MASH0( - "3. Enter Game Mash:
Mash A for this long to enter the game.", + "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, "5000 ms" ) , ENTER_GAME_WAIT0( - "4. Enter Game Wait:
Wait this long for the game to enter the overworld.", + "Enter Game Wait:
Wait this long for the game to enter the overworld.", LockMode::LOCK_WHILE_RUNNING, "15 s" ) diff --git a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp index 844cc33bdc..d1554c0638 100644 --- a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp +++ b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Settings.cpp @@ -29,17 +29,17 @@ GameSettings::GameSettings() ) , m_start_game_timings("Start Game Timings:") , START_GAME_WAIT1( - "2. Start Game Wait:
Wait this long for the game to load.", + "Start Game Wait:
Wait this long for the game to load.", LockMode::LOCK_WHILE_RUNNING, "20 s" ) , ENTER_GAME_MASH0( - "3. Enter Game Mash:
Mash A for this long to enter the game.", + "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, "5 s" ) , ENTER_GAME_WAIT0( - "4. Enter Game Wait:
Wait this long for the opening animations to finish.", + "Enter Game Wait:
Wait this long for the opening animations to finish.", LockMode::LOCK_WHILE_RUNNING, "15 s" ) diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp new file mode 100644 index 0000000000..89b97ebc11 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp @@ -0,0 +1,162 @@ +/* Shiny Detected Action + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "Common/Cpp/Exceptions.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "Pokemon/Pokemon_Notification.h" +#include "PokemonLZA_ShinyDetectedAction.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + + +ShinyDetectedActionOption::ShinyDetectedActionOption( + std::string label, std::string description, + std::string default_delay, + ShinyDetectedActionType default_action +) + : GroupOption(std::move(label), LockMode::UNLOCK_WHILE_RUNNING) + , DESCRIPTION(std::move(description)) + , ACTION( + "Action:", + { + {ShinyDetectedActionType::IGNORE, "ignore", "Ignore the shiny. Do not stop the program."}, + {ShinyDetectedActionType::STOP_PROGRAM, "stop", "Stop program and go Home."}, + {ShinyDetectedActionType::STOP_AFTER_COUNT, "stop-count", "Stop program only after X shinies are found."}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + default_action + ) + , MAX_COUNT( + "Max Detections:
" + "Stop the program after this many shinies are detected.", + LockMode::UNLOCK_WHILE_RUNNING, + 10 + ) + , TAKE_VIDEO( + "Take Video:", + LockMode::UNLOCK_WHILE_RUNNING, + true + ) + , SCREENSHOT_DELAY( + "Screenshot Delay:
" + "Wait this long before taking a screenshot + video of the shiny.
" + "Set to zero to skip this. Don't set this too large or the shiny may run away!", + LockMode::UNLOCK_WHILE_RUNNING, + std::move(default_delay) + ) + , NOTIFICATIONS( + this->label(), + true, true, + ImageAttachmentMode::JPG, + {"Notifs", "Showcase"} + ) +{ + if (!DESCRIPTION.text().empty()){ + PA_ADD_OPTION(DESCRIPTION); + } + PA_ADD_OPTION(ACTION); + PA_ADD_OPTION(MAX_COUNT); + PA_ADD_OPTION(TAKE_VIDEO); + PA_ADD_OPTION(SCREENSHOT_DELAY); + + on_config_value_changed(this); + + ACTION.add_listener(*this); +} +ShinyDetectedActionOption::~ShinyDetectedActionOption(){ + ACTION.remove_listener(*this); +} +void ShinyDetectedActionOption::on_config_value_changed(void* object){ + MAX_COUNT.set_visibility( + ACTION == ShinyDetectedActionType::STOP_AFTER_COUNT + ? ConfigOptionState::ENABLED + : ConfigOptionState::HIDDEN + ); +} + +bool ShinyDetectedActionOption::stop_on_shiny(uint8_t current_count) const{ + switch (ACTION){ + case ShinyDetectedActionType::IGNORE: + return false; + case ShinyDetectedActionType::STOP_PROGRAM: + return true; + case ShinyDetectedActionType::STOP_AFTER_COUNT: + return current_count >= MAX_COUNT; + default: + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid shiny action enum type."); + } +} + + + + + + + + +bool on_shiny_sound( + ProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, + ShinyDetectedActionOption& options, + uint8_t current_count, + float error_coefficient +){ + { + std::ostringstream ss; + ss << "Detected Shiny Sound! (error coefficient = " << error_coefficient << ")"; + stream.log(ss.str(), COLOR_BLUE); + } + + if (options.TAKE_VIDEO){ + context.wait_for(options.SCREENSHOT_DELAY); + pbf_press_button(context, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 0); + } + + std::vector> embeds; + + { + std::ostringstream ss; + ss << "Error Coefficient: "; + ss << error_coefficient; + ss << "\n(Shiny may not be visible on the screen.)"; + embeds.emplace_back("Detection Results:", ss.str()); + } + + send_program_notification( + env, options.NOTIFICATIONS, + Pokemon::COLOR_STAR_SHINY, + "Detected Shiny Sound", + embeds, "", + stream.video().snapshot(), true + ); + + return options.stop_on_shiny(current_count); +} + + + + + + + + + + + + + + + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h new file mode 100644 index 0000000000..58014597e7 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h @@ -0,0 +1,68 @@ +/* Shiny Detected Action + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_ShinyDetectedAction_H +#define PokemonAutomation_PokemonLZA_ShinyDetectedAction_H + +#include "Common/Cpp/Options/GroupOption.h" +#include "Common/Cpp/Options/StaticTextOption.h" +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options//TimeDurationOption.h" +#include "Common/Cpp/Options/SimpleIntegerOption.h" +#include "CommonFramework/Notifications/EventNotificationOption.h" +#include "CommonFramework/Tools/VideoStream.h" +#include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" + +namespace PokemonAutomation{ + class ProgramEnvironment; +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +enum class ShinyDetectedActionType{ + IGNORE, + STOP_PROGRAM, + STOP_AFTER_COUNT, +}; + + +class ShinyDetectedActionOption : public GroupOption, public ConfigOption::Listener{ +public: + ~ShinyDetectedActionOption(); + ShinyDetectedActionOption( + std::string label, std::string description, + std::string default_delay, + ShinyDetectedActionType default_action = ShinyDetectedActionType::STOP_AFTER_COUNT + ); + + bool stop_on_shiny(uint8_t current_count) const; + + virtual void on_config_value_changed(void* object) override; + + StaticTextOption DESCRIPTION; + EnumDropdownOption ACTION; + SimpleIntegerOption MAX_COUNT; + BooleanCheckBoxOption TAKE_VIDEO; + MillisecondsOption SCREENSHOT_DELAY; + EventNotificationOption NOTIFICATIONS; +}; + + + +bool on_shiny_sound( + ProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, + ShinyDetectedActionOption& options, + uint8_t current_count, + float error_coefficient +); + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp index 8991d91676..fca234ed97 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp @@ -10,8 +10,9 @@ #include "PokemonLZA_Settings.h" -#include "Programs/PokemonLZA_RestaurantFarmer.h" #include "Programs/PokemonLZA_ClothingBuyer.h" +#include "Programs/PokemonLZA_RestaurantFarmer.h" +#include "Programs/PokemonLZA_ShinyHunt_Bench.h" #include "Programs/TestPrograms/PokemonLZA_OverworldWatcher.h" namespace PokemonAutomation{ @@ -31,8 +32,13 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back(make_settings()); ret.emplace_back("---- General ----"); - ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); + + if (PreloadSettings::instance().DEVELOPER_MODE){ + ret.emplace_back("---- Shiny Hunting ----"); + ret.emplace_back(make_single_switch_program()); + } if (PreloadSettings::instance().DEVELOPER_MODE){ diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp index b68ea9db7f..f37681a28a 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp @@ -24,17 +24,17 @@ GameSettings::GameSettings() , m_general("General Settings:") , m_start_game_timings("Start Game Timings:") , START_GAME_WAIT( - "2. Start Game Wait:
Wait this long for the game to load.", + "Start Game Wait:
Wait this long for the game to load.", LockMode::LOCK_WHILE_RUNNING, "40 s" ) , ENTER_GAME_MASH( - "3. Enter Game Mash:
Mash A for this long to enter the game.", + "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, "5000 ms" ) , ENTER_GAME_WAIT( - "4. Enter Game Wait:
Wait this long for the game to enter the overworld.", + "Enter Game Wait:
Wait this long for the game to enter the overworld.", LockMode::LOCK_WHILE_RUNNING, "15 s" ) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp new file mode 100644 index 0000000000..5fea851ec6 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp @@ -0,0 +1,142 @@ +/* Shiny Hunt - Bench + * + * From: https://github.com/PokemonAutomation/ + * + */ + +//#include +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" +#include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" +#include "PokemonLZA_ShinyHunt_Bench.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +using namespace Pokemon; + + + + + +ShinyHunt_Bench_Descriptor::ShinyHunt_Bench_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLZA:ShinyHunt-Bench", + STRING_POKEMON + " LZA", "Shiny Hunt - Bench", + "Programs/PokemonLZA/ShinyHunt-Bench.html", + "Shiny hunt by repeatedly sitting on a bench to reset spawns.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS, + {} + ) +{} +class ShinyHunt_Bench_Descriptor::Stats : public StatsTracker{ +public: + Stats() + : resets(m_stats["Bench Sits"]) + , shinies(m_stats["Shinies"]) + , errors(m_stats["Errors"]) + { + m_display_order.emplace_back("Bench Sits"); + m_display_order.emplace_back("Shinies"); + m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); + } + + std::atomic& resets; + std::atomic& shinies; + std::atomic& errors; +}; +std::unique_ptr ShinyHunt_Bench_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + + + + +ShinyHunt_Bench::ShinyHunt_Bench() + : SHINY_DETECTED("Shiny Detected", "", "2000ms") + , NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)) + , NOTIFICATIONS({ + &NOTIFICATION_STATUS, + &SHINY_DETECTED.NOTIFICATIONS, + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_RECOVERABLE, + &NOTIFICATION_ERROR_FATAL, + }) +{ + PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); + PA_ADD_STATIC(SHINY_DETECTED); + PA_ADD_OPTION(NOTIFICATIONS); +} + +void ShinyHunt_Bench::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + ShinyHunt_Bench_Descriptor::Stats& stats = env.current_stats(); + + uint8_t shiny_count = 0; + + while (true){ + float shiny_coefficient = 1.0; + PokemonLA::ShinySoundDetector shiny_detector(env.console, [&](float error_coefficient) -> bool{ + // Warning: This callback will be run from a different thread than this function. + shiny_count++; + stats.shinies++; + env.update_stats(); + shiny_coefficient = error_coefficient; + return true; + }); + + int ret = run_until( + env.console, context, + [&](ProControllerContext& context){ + while (true){ + send_program_status_notification(env, NOTIFICATION_STATUS); + sit_on_bench(env.console, context); + stats.resets++; + env.update_stats(); + } + }, + {{shiny_detector}} + ); + + // This should never happen. + if (ret != 0){ + continue; + } + + shiny_count++; + if (on_shiny_sound( + env, env.console, context, + SHINY_DETECTED, + shiny_count, + shiny_coefficient + )){ + break; + } + } + + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); + +} + + + + + + + + + + + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h new file mode 100644 index 0000000000..9d4720331a --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h @@ -0,0 +1,53 @@ +/* Shiny Hunt - Bench + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_ShinyHunt_Bench_H +#define PokemonAutomation_PokemonLZA_ShinyHunt_Bench_H + +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "PokemonLA/Options/PokemonLA_ShinyDetectedAction.h" +#include "PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + + + +class ShinyHunt_Bench_Descriptor : public SingleSwitchProgramDescriptor{ +public: + ShinyHunt_Bench_Descriptor(); + + class Stats; + virtual std::unique_ptr make_stats() const override; +}; + + +class ShinyHunt_Bench : public SingleSwitchProgramInstance{ +public: + ShinyHunt_Bench(); + + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; + + ShinyDetectedActionOption SHINY_DETECTED; + + EventNotificationOption NOTIFICATION_STATUS; + EventNotificationsOption NOTIFICATIONS; +}; + + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSV/PokemonSV_Settings.cpp b/SerialPrograms/Source/PokemonSV/PokemonSV_Settings.cpp index d8e081f68a..d7cea5c984 100644 --- a/SerialPrograms/Source/PokemonSV/PokemonSV_Settings.cpp +++ b/SerialPrograms/Source/PokemonSV/PokemonSV_Settings.cpp @@ -30,17 +30,17 @@ GameSettings::GameSettings() ) , m_start_game_timings("Start Game Timings:") , START_GAME_WAIT0( - "2. Start Game Wait:
Wait this long for the game to load.", + "Start Game Wait:
Wait this long for the game to load.", LockMode::LOCK_WHILE_RUNNING, "60 s" ) , ENTER_GAME_MASH0( - "3. Enter Game Mash:
Mash A for this long to enter the game.", + "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, "5000 ms" ) , ENTER_GAME_WAIT0( - "4. Enter Game Wait:
Wait this long for the game to enter the overworld.", + "Enter Game Wait:
Wait this long for the game to enter the overworld.", LockMode::LOCK_WHILE_RUNNING, "60 s" ) diff --git a/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_Settings.cpp b/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_Settings.cpp index 1674c46268..6ba90e0a88 100644 --- a/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_Settings.cpp +++ b/SerialPrograms/Source/PokemonSwSh/PokemonSwSh_Settings.cpp @@ -90,17 +90,17 @@ GameSettings::GameSettings() ) , m_start_game_timings("Start Game Timings:") , START_GAME_WAIT0( - "2. Start Game Wait:
Wait this long for the game to load.", + "Start Game Wait:
Wait this long for the game to load.", LockMode::LOCK_WHILE_RUNNING, "20000 ms" ) , ENTER_GAME_MASH0( - "3. Enter Game Mash:
Mash A for this long to enter the game.", + "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, "3000 ms" ) , ENTER_GAME_WAIT0( - "4. Enter Game Wait:
Wait this long for the game to enter the overworld.", + "Enter Game Wait:
Wait this long for the game to enter the overworld.", LockMode::LOCK_WHILE_RUNNING, "11000 ms" ) diff --git a/SerialPrograms/Source/ZeldaTotK/ZeldaTotK_Settings.cpp b/SerialPrograms/Source/ZeldaTotK/ZeldaTotK_Settings.cpp index fe0ad09736..0bd8e002a9 100644 --- a/SerialPrograms/Source/ZeldaTotK/ZeldaTotK_Settings.cpp +++ b/SerialPrograms/Source/ZeldaTotK/ZeldaTotK_Settings.cpp @@ -31,17 +31,17 @@ GameSettings::GameSettings() "2000 ms" ) , START_GAME_WAIT0( - "2. Start Game Wait:
Wait this long for the game to load.", + "Start Game Wait:
Wait this long for the game to load.", LockMode::LOCK_WHILE_RUNNING, "60 s" ) , ENTER_GAME_MASH0( - "3. Enter Game Mash:
Mash A for this long to enter the game.", + "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, "5000 ms" ) , ENTER_GAME_WAIT0( - "4. Enter Game Wait:
Wait this long for the game to enter the overworld.", + "Enter Game Wait:
Wait this long for the game to enter the overworld.", LockMode::LOCK_WHILE_RUNNING, "60 s" ) From 7c3527dff5c9b3abef717004b8c6d60d6b51af14 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Wed, 22 Oct 2025 09:49:07 -0700 Subject: [PATCH 03/22] missed a file --- SerialPrograms/SourceFiles.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SerialPrograms/SourceFiles.cmake b/SerialPrograms/SourceFiles.cmake index d53949f3e9..70970f9aac 100644 --- a/SerialPrograms/SourceFiles.cmake +++ b/SerialPrograms/SourceFiles.cmake @@ -1545,6 +1545,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h + Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp + Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h Source/PokemonLZA/PokemonLZA_Panels.cpp Source/PokemonLZA/PokemonLZA_Panels.h Source/PokemonLZA/PokemonLZA_Settings.cpp @@ -1557,6 +1559,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Programs/PokemonLZA_GameEntry.h Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.h + Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp + Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.cpp Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.h Source/PokemonRSE/Inference/Dialogs/PokemonRSE_DialogDetector.cpp From ed89b98f8b78d59bb3e6e50d5784c556052f4499 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Wed, 22 Oct 2025 10:00:11 -0700 Subject: [PATCH 04/22] Add note about shiny sound radius being smaller than spawn radius. --- .../PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp index 5fea851ec6..cc648eda05 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp @@ -60,7 +60,13 @@ std::unique_ptr ShinyHunt_Bench_Descriptor::make_stats() const{ ShinyHunt_Bench::ShinyHunt_Bench() - : SHINY_DETECTED("Shiny Detected", "", "2000ms") + : SHINY_DETECTED( + "Shiny Detected", + "The shiny sound plays on a smaller radius than the shiny spawn radius. " + "Therefore some (if not most) of the shinies will be inaudible and will not be detected by this program. " + "You will still need to manually run around to see if any shinies spawned out-of-range.<\font>", + "2000ms" + ) , NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)) , NOTIFICATIONS({ &NOTIFICATION_STATUS, From fdffc79f8f7117ce913e7fdc5a5fb181baca71bc Mon Sep 17 00:00:00 2001 From: kichithewolf Date: Tue, 21 Oct 2025 22:13:23 -0400 Subject: [PATCH 05/22] lza beldum hunter --- .../Source/PokemonLZA/PokemonLZA_Panels.cpp | 2 + .../Programs/PokemonLZA_BeldumHunter.cpp | 191 ++++++++++++++++++ .../Programs/PokemonLZA_BeldumHunter.h | 48 +++++ SerialPrograms/SourceFiles.cmake | 2 + 4 files changed, 243 insertions(+) create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp index fca234ed97..c52b918b2d 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp @@ -10,6 +10,7 @@ #include "PokemonLZA_Settings.h" +#include "Programs/PokemonLZA_BeldumHunter.h" #include "Programs/PokemonLZA_ClothingBuyer.h" #include "Programs/PokemonLZA_RestaurantFarmer.h" #include "Programs/PokemonLZA_ShinyHunt_Bench.h" @@ -38,6 +39,7 @@ std::vector PanelListFactory::make_panels() const{ if (PreloadSettings::instance().DEVELOPER_MODE){ ret.emplace_back("---- Shiny Hunting ----"); ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); } diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp new file mode 100644 index 0000000000..c316130db7 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp @@ -0,0 +1,191 @@ +/* Beldum Hunter + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/Notifications/ProgramNotifications.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/Commands/NintendoSwitch_Commands_Superscalar.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonLZA/PokemonLZA_Settings.h" +#include "PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h" +#include "PokemonLZA/Programs/PokemonLZA_GameEntry.h" +#include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" +#include "PokemonLZA_BeldumHunter.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +using namespace Pokemon; + +BeldumHunter_Descriptor::BeldumHunter_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLZA:BeldumHunter", + STRING_POKEMON + " LZA", "Beldum Hunter", + "Programs/PokemonLZA/BeldumHunter.html", + "Reset in Lysandre Labs to shiny hunt Beldum.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::VIDEO_AUDIO, + AllowCommandsWhenRunning::DISABLE_COMMANDS + ) +{} +class BeldumHunter_Descriptor::Stats : public StatsTracker, public PokemonLA::ShinyStatIncrementer{ +public: + Stats() + : attempts(m_stats["Attempts"]) + , errors(m_stats["Errors"]) + , shinies(m_stats["Shinies"]) + { + m_display_order.emplace_back("Attempts"); + m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); + m_display_order.emplace_back("Shinies"); + } + virtual void add_shiny() override{ + shinies++; + } + + std::atomic& attempts; + std::atomic& errors; + std::atomic& shinies; +}; +std::unique_ptr BeldumHunter_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + +BeldumHunter::BeldumHunter() + : NOTIFICATION_SHINY( + "Shiny Found", + true, true, ImageAttachmentMode::JPG, + {"Notifs", "Showcase"} + ) + , NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)) + , NOTIFICATIONS({ + &NOTIFICATION_SHINY, + &NOTIFICATION_STATUS, + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_RECOVERABLE, + &NOTIFICATION_ERROR_FATAL, + }) +{ + PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); + PA_ADD_OPTION(NOTIFICATIONS); +} + +bool BeldumHunter::run_iteration(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + BeldumHunter_Descriptor::Stats& stats = env.current_stats(); + stats.attempts++; + + float shiny_coefficient = 1.0; + PokemonLA::ShinySoundDetector shiny_detector(env.logger(), [&](float error_coefficient) -> bool{ + shiny_coefficient = error_coefficient; + return true; + }); + + int res = run_until( + env.console, context, + [&](ProControllerContext& context) { + BlackScreenOverWatcher warped(COLOR_RED, {0.2, 0.2, 0.6, 0.6}); + + env.log("Using warp panel."); + pbf_press_button(context, BUTTON_A, 40ms, 40ms); + context.wait_for_all_requests(); + int ret = wait_until( + env.console, context, + 8000ms, + {{warped}} + ); + if (ret == 0){ + env.log("Successful warp."); + }else{ + env.log("Failed to warp."); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to warp.", + env.console + ); + } + pbf_wait(context, 1000ms); + context.wait_for_all_requests(); + + env.log("Into the Houndoom room."); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 255, 128, 128, 128, 80); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 255, 128, 128, 60); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 255, 128, 128, 128, 140); + + env.log("Through the room and down the hallway."); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 255, 128, 128, 210); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 340); + + env.log("Final hallway to Beldum room."); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 255, 128, 128, 350); + + }, + {{shiny_detector}} + ); + shiny_detector.throw_if_no_sound(); + + if (res == 0){ + env.log("Shiny detected!"); + return true; + } + + env.console.log("No shiny detected. Resetting."); + + pbf_press_button(context, BUTTON_HOME, 160ms, 3000ms); + reset_game_from_home(env, env.console, context, false); + + return false; +} + + +void BeldumHunter::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + BeldumHunter_Descriptor::Stats& stats = env.current_stats(); + + /* + * Setup: Clear out the Noivern, Houndour, and Houndoom spawns. + * Use the warp panel near the Noivern and save the game. + * + * Program will use the warp panel and then run to the Beldum room. + * No shiny, reset the game. Repeat. + * On warp the Beldum will reroll. We reset the game instead of running back to the panel + * to prevent the wild Pokemon from respawning. + */ + + while (true){ + env.update_stats(); + send_program_status_notification(env, NOTIFICATION_STATUS); + try{ + bool shiny_found = run_iteration(env, context); + if (shiny_found) { + stats.shinies++; + env.update_stats(); + send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", env.console.video().snapshot(), true); + break; + } + }catch (OperationFailedException& e){ + stats.errors++; + e.send_notification(env, NOTIFICATION_ERROR_RECOVERABLE); + + pbf_press_button(context, BUTTON_HOME, 160ms, 3000ms); + reset_game_from_home(env, env.console, context, false); + } + } + + env.update_stats(); + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h new file mode 100644 index 0000000000..7c91a4dcbf --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h @@ -0,0 +1,48 @@ +/* Beldum Hunter + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_BeldumHunter_H +#define PokemonAutomation_PokemonLZA_BeldumHunter_H + +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "PokemonLA/Options/PokemonLA_ShinyDetectedAction.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +class BeldumHunter_Descriptor : public SingleSwitchProgramDescriptor{ +public: + BeldumHunter_Descriptor(); + + class Stats; + virtual std::unique_ptr make_stats() const override; +}; + + +class BeldumHunter : public SingleSwitchProgramInstance{ +public: + BeldumHunter(); + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + bool run_iteration(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + +private: + PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; + + EventNotificationOption NOTIFICATION_SHINY; + EventNotificationOption NOTIFICATION_STATUS; + EventNotificationsOption NOTIFICATIONS; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/SourceFiles.cmake b/SerialPrograms/SourceFiles.cmake index 70970f9aac..bff02c3609 100644 --- a/SerialPrograms/SourceFiles.cmake +++ b/SerialPrograms/SourceFiles.cmake @@ -1553,6 +1553,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/PokemonLZA_Settings.h Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.h + Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp + Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.h Source/PokemonLZA/Programs/PokemonLZA_GameEntry.cpp From c74cc363d7f4c3e6bc083626dabd9b41de540486 Mon Sep 17 00:00:00 2001 From: kichithewolf Date: Wed, 22 Oct 2025 09:29:14 -0400 Subject: [PATCH 06/22] adjust path to go from door instead of warp --- .../Programs/PokemonLZA_BeldumHunter.cpp | 103 ++++++++++-------- .../Programs/PokemonLZA_BeldumHunter.h | 3 + 2 files changed, 62 insertions(+), 44 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp index c316130db7..d179fe01a7 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp @@ -62,7 +62,8 @@ std::unique_ptr BeldumHunter_Descriptor::make_stats() const{ BeldumHunter::BeldumHunter() - : NOTIFICATION_SHINY( + : TAKE_VIDEO("Take Video:", LockMode::UNLOCK_WHILE_RUNNING, true) + , NOTIFICATION_SHINY( "Shiny Found", true, true, ImageAttachmentMode::JPG, {"Notifs", "Showcase"} @@ -77,36 +78,36 @@ BeldumHunter::BeldumHunter() }) { PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); + PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(NOTIFICATIONS); } bool BeldumHunter::run_iteration(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ BeldumHunter_Descriptor::Stats& stats = env.current_stats(); stats.attempts++; + { + float shiny_coefficient = 1.0; + PokemonLA::ShinySoundDetector shiny_detector(env.logger(), [&](float error_coefficient) -> bool { + shiny_coefficient = error_coefficient; + return true; + }); - float shiny_coefficient = 1.0; - PokemonLA::ShinySoundDetector shiny_detector(env.logger(), [&](float error_coefficient) -> bool{ - shiny_coefficient = error_coefficient; - return true; - }); - - int res = run_until( - env.console, context, - [&](ProControllerContext& context) { - BlackScreenOverWatcher warped(COLOR_RED, {0.2, 0.2, 0.6, 0.6}); + BlackScreenOverWatcher entered(COLOR_RED, { 0.074, 0.044, 0.826, 0.278 }); - env.log("Using warp panel."); - pbf_press_button(context, BUTTON_A, 40ms, 40ms); + env.log("Entering the lab."); context.wait_for_all_requests(); - int ret = wait_until( + int ret = run_until( env.console, context, - 8000ms, - {{warped}} - ); - if (ret == 0){ - env.log("Successful warp."); - }else{ - env.log("Failed to warp."); + [&](ProControllerContext& context) { + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 0, 128, 128, 100); + pbf_wait(context, 5000ms); + }, + { {entered} } + ); + if (ret == 0) { + env.log("Entered the lab."); + } else { + env.log("Failed to enter the lab."); OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, "Failed to warp.", @@ -116,28 +117,40 @@ bool BeldumHunter::run_iteration(SingleSwitchProgramEnvironment& env, ProControl pbf_wait(context, 1000ms); context.wait_for_all_requests(); - env.log("Into the Houndoom room."); - pbf_controller_state(context, BUTTON_B, DPAD_NONE, 255, 128, 128, 128, 80); - pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 255, 128, 128, 60); - pbf_controller_state(context, BUTTON_B, DPAD_NONE, 255, 128, 128, 128, 140); + int res = run_until( + env.console, context, + [&](ProControllerContext& context) { - env.log("Through the room and down the hallway."); - pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 255, 128, 128, 210); - pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 340); + env.log("Go straight toward the elevator."); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 0, 128, 128, 460); - env.log("Final hallway to Beldum room."); - pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 255, 128, 128, 350); + env.log("Go left to where the Noivern spawns, then forward and then left."); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 300); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 0, 128, 128, 80); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 180); - }, - {{shiny_detector}} - ); - shiny_detector.throw_if_no_sound(); + env.log("Through the Houndoom room and down the hallway."); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 255, 128, 128, 140); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 200); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 0, 128, 128, 340); - if (res == 0){ - env.log("Shiny detected!"); - return true; - } + env.log("Final hallway to Beldum room."); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 350); + }, + { {shiny_detector} } + ); + shiny_detector.throw_if_no_sound(); + + if (res == 0) { + env.log("Shiny detected!"); + if (TAKE_VIDEO) { + pbf_press_button(context, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 0); + } + + return true; + } + } env.console.log("No shiny detected. Resetting."); pbf_press_button(context, BUTTON_HOME, 160ms, 3000ms); @@ -151,13 +164,13 @@ void BeldumHunter::program(SingleSwitchProgramEnvironment& env, ProControllerCon BeldumHunter_Descriptor::Stats& stats = env.current_stats(); /* - * Setup: Clear out the Noivern, Houndour, and Houndoom spawns. - * Use the warp panel near the Noivern and save the game. + * Setup: Face the opening to the labs. Save the game. * - * Program will use the warp panel and then run to the Beldum room. + * Program will enter the Labs and then run to the Beldum room. * No shiny, reset the game. Repeat. - * On warp the Beldum will reroll. We reset the game instead of running back to the panel - * to prevent the wild Pokemon from respawning. + * Every time we enter the Beldum will reroll. We reset the game instead of running back + * due to the wild Pokemon spawns. + * This can also hunt Noivern, Houndour, and Houndoom. */ while (true){ @@ -168,7 +181,9 @@ void BeldumHunter::program(SingleSwitchProgramEnvironment& env, ProControllerCon if (shiny_found) { stats.shinies++; env.update_stats(); - send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", env.console.video().snapshot(), true); + send_program_notification(env, NOTIFICATION_SHINY, + COLOR_YELLOW, "Shiny sound detected!", {}, + "", env.console.video().snapshot(), true); break; } }catch (OperationFailedException& e){ diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h index 7c91a4dcbf..efb7e61482 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.h @@ -8,6 +8,7 @@ #define PokemonAutomation_PokemonLZA_BeldumHunter_H #include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" #include "PokemonLA/Options/PokemonLA_ShinyDetectedAction.h" @@ -36,6 +37,8 @@ class BeldumHunter : public SingleSwitchProgramInstance{ private: PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; + BooleanCheckBoxOption TAKE_VIDEO; + EventNotificationOption NOTIFICATION_SHINY; EventNotificationOption NOTIFICATION_STATUS; EventNotificationsOption NOTIFICATIONS; From 0c6f9e5a2c4b3aa3f2584f7548dae1b2d556bae9 Mon Sep 17 00:00:00 2001 From: kichithewolf Date: Wed, 22 Oct 2025 14:41:33 -0400 Subject: [PATCH 07/22] copy LA game entry to LZA to fix resets lowered start game mash default --- .../Source/PokemonLZA/PokemonLZA_Settings.cpp | 6 +- .../Source/PokemonLZA/PokemonLZA_Settings.h | 2 +- .../Programs/PokemonLZA_GameEntry.cpp | 75 ++++++++++++++++++- .../Programs/PokemonLZA_GameEntry.h | 15 ++-- 4 files changed, 87 insertions(+), 11 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp index f37681a28a..74e6345838 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.cpp @@ -28,10 +28,10 @@ GameSettings::GameSettings() LockMode::LOCK_WHILE_RUNNING, "40 s" ) - , ENTER_GAME_MASH( + , ENTER_GAME_MASH0( "Enter Game Mash:
Mash A for this long to enter the game.", LockMode::LOCK_WHILE_RUNNING, - "5000 ms" + "3000 ms" ) , ENTER_GAME_WAIT( "Enter Game Wait:
Wait this long for the game to enter the overworld.", @@ -46,7 +46,7 @@ GameSettings::GameSettings() PA_ADD_STATIC(m_start_game_timings); PA_ADD_OPTION(START_GAME_WAIT); - PA_ADD_OPTION(ENTER_GAME_MASH); + PA_ADD_OPTION(ENTER_GAME_MASH0); PA_ADD_OPTION(ENTER_GAME_WAIT); PA_ADD_STATIC(m_advanced_options); diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.h b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.h index 29817d5198..dac97374d5 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.h +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Settings.h @@ -26,7 +26,7 @@ class GameSettings : public BatchOption{ SectionDividerOption m_start_game_timings; MillisecondsOption START_GAME_WAIT; - MillisecondsOption ENTER_GAME_MASH; + MillisecondsOption ENTER_GAME_MASH0; MillisecondsOption ENTER_GAME_WAIT; SectionDividerOption m_advanced_options; diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.cpp index 330f1d522b..2f338a9945 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.cpp @@ -4,7 +4,13 @@ * */ +#include "CommonFramework/Tools/ErrorDumper.h" +#include "CommonFramework/Tools/ProgramEnvironment.h" #include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" #include "PokemonLZA/PokemonLZA_Settings.h" #include "PokemonLZA_GameEntry.h" @@ -12,16 +18,81 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonLZA{ +bool reset_game_to_gamemenu( + ConsoleHandle& console, ProControllerContext& context +){ + from_home_close_and_reopen_game(console, context, true); + + // Now the game has opened: + return openedgame_to_gamemenu(console, context, GameSettings::instance().START_GAME_WAIT); +} + +// From the game menu screen (where "Press A" is displayed to enter the game), +// mash A to enter the game and wait until the black screen is gone. +bool gamemenu_to_ingame( + VideoStream& stream, ProControllerContext& context, + Milliseconds mash_duration, Milliseconds enter_game_timeout +){ + stream.log("Mashing A to enter game..."); + BlackScreenOverWatcher detector(COLOR_RED, {0.074, 0.044, 0.826, 0.278}); + pbf_mash_button(context, BUTTON_A, mash_duration); + context.wait_for_all_requests(); + stream.log("Waiting to enter game..."); + int ret = wait_until( + stream, context, + std::chrono::milliseconds(enter_game_timeout), + {{detector}} + ); + if (ret == 0){ + stream.log("Entered game!"); + return true; + }else{ + stream.log("Timed out waiting to enter game.", COLOR_RED); + return false; + } +} + +bool reset_game_from_home( + ProgramEnvironment& env, + ConsoleHandle& console, ProControllerContext& context, + bool backup_save, + Milliseconds enter_game_mash, + Milliseconds enter_game_timeout, + Milliseconds post_wait_time +){ + bool ok = true; + ok &= reset_game_to_gamemenu(console, context); + + if (backup_save){ + console.log("Loading backup save!"); + pbf_wait(context, 1000ms); + ssf_press_dpad(context, DPAD_UP, 0ms, 200ms); + ssf_press_button(context, BUTTON_B | BUTTON_X, 1000ms, 200ms); + } + + ok &= gamemenu_to_ingame( + console, context, + enter_game_mash, + enter_game_timeout + ); + if (!ok){ + dump_image(console.logger(), env.program_info(), console.video(), "StartGame"); + } + console.log("Entered game! Waiting out grace period."); + pbf_wait(context, post_wait_time); + context.wait_for_all_requests(); + return ok; +} bool reset_game_from_home( ProgramEnvironment& env, ConsoleHandle& console, ProControllerContext& context, bool backup_save, Milliseconds post_wait_time ){ - return PokemonLA::reset_game_from_home( + return reset_game_from_home( env, console, context, backup_save, - GameSettings::instance().ENTER_GAME_MASH, + GameSettings::instance().ENTER_GAME_MASH0, GameSettings::instance().ENTER_GAME_WAIT, post_wait_time ); diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.h index e0eecf635a..cb4bad6196 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_GameEntry.h @@ -9,7 +9,6 @@ #include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" #include "NintendoSwitch/NintendoSwitch_ConsoleHandle.h" -#include "PokemonLA/Programs/PokemonLA_GameEntry.h" namespace PokemonAutomation{ class ProgramEnvironment; @@ -22,11 +21,9 @@ using namespace std::chrono_literals; // From Switch Home menu, reset game and wait until the game menu screen (where // "Press A" is displayed to enter the game) is shown. -inline bool reset_game_to_gamemenu( +bool reset_game_to_gamemenu( ConsoleHandle& console, ProControllerContext& context -){ - return PokemonLA::reset_game_to_gamemenu(console, context); -} +); // From Switch Home menu, start game and wait until the player character // appears in game. @@ -36,6 +33,14 @@ bool reset_game_from_home( ProgramEnvironment& env, ConsoleHandle& console, ProControllerContext& context, bool backup_save, + Milliseconds enter_game_mash, + Milliseconds enter_game_timeout, + Milliseconds post_wait_time +); +bool reset_game_from_home( + ProgramEnvironment& env, + ConsoleHandle& console, ProControllerContext& context, + bool backup_save = false, Milliseconds post_wait_time = 1000ms ); From 188f79835126a4eae77056df00cc3b45fea9262d Mon Sep 17 00:00:00 2001 From: kichithewolf Date: Wed, 22 Oct 2025 11:01:51 -0400 Subject: [PATCH 08/22] go to home on shiny detection --- .../Programs/PokemonLZA_BeldumHunter.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp index d179fe01a7..2f71c7542d 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BeldumHunter.cpp @@ -28,10 +28,10 @@ using namespace Pokemon; BeldumHunter_Descriptor::BeldumHunter_Descriptor() : SingleSwitchProgramDescriptor( - "PokemonLZA:BeldumHunter", - STRING_POKEMON + " LZA", "Beldum Hunter", + "PokemonLZA:ShinyHunt-Beldum", + STRING_POKEMON + " LZA", "Shiny Hunt - Beldum", "Programs/PokemonLZA/BeldumHunter.html", - "Reset in Lysandre Labs to shiny hunt Beldum.", + "Repeatedly enter Lysandre Labs to shiny hunt Beldum.", ProgramControllerClass::StandardController_NoRestrictions, FeedbackType::VIDEO_AUDIO, AllowCommandsWhenRunning::DISABLE_COMMANDS @@ -135,8 +135,9 @@ bool BeldumHunter::run_iteration(SingleSwitchProgramEnvironment& env, ProControl pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 0, 128, 128, 340); env.log("Final hallway to Beldum room."); - pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 350); - + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 0, 128, 128, 128, 400); + pbf_press_button(context, BUTTON_L, 40ms, 40ms); + context.wait_for_all_requests(); }, { {shiny_detector} } ); @@ -181,6 +182,9 @@ void BeldumHunter::program(SingleSwitchProgramEnvironment& env, ProControllerCon if (shiny_found) { stats.shinies++; env.update_stats(); + + pbf_press_button(context, BUTTON_HOME, 160ms, 3000ms); + send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny sound detected!", {}, "", env.console.video().snapshot(), true); From 7d98b062900ee677424d888e99d41ee4d5ca5de3 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Wed, 22 Oct 2025 20:54:10 -0700 Subject: [PATCH 09/22] fixes --- .../Source/CommonFramework/Globals.cpp | 2 +- .../PokemonLZA_SelectionArrowDetector.cpp | 4 ++ .../Programs/PokemonLZA_RestaurantFarmer.cpp | 41 +++++++++++++++---- .../Programs/PokemonLZA_ShinyHunt_Bench.cpp | 8 ++-- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/Globals.cpp b/SerialPrograms/Source/CommonFramework/Globals.cpp index 497078d7ea..b2b91a664e 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.cpp +++ b/SerialPrograms/Source/CommonFramework/Globals.cpp @@ -26,7 +26,7 @@ namespace PokemonAutomation{ const bool IS_BETA_VERSION = true; const int PROGRAM_VERSION_MAJOR = 0; const int PROGRAM_VERSION_MINOR = 59; -const int PROGRAM_VERSION_PATCH = 1; +const int PROGRAM_VERSION_PATCH = 2; const std::string PROGRAM_VERSION_BASE = "v" + std::to_string(PROGRAM_VERSION_MAJOR) + diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp index 8beb63c03f..264ff90ec6 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp @@ -77,6 +77,10 @@ bool SelectionArrowDetector::detect(const ImageViewRGB32& screen){ size_t min_area = size_t(screen_rel_size_2 * min_area_1080p); const std::vector> FILTERS = { + {0xff808000, 0xffffff7f}, + {0xff808000, 0xffdfff7f}, + {0xff80a000, 0xffffff7f}, + {0xff80a000, 0xffdfff7f}, {0xff80c000, 0xffffff7f}, {0xff80c000, 0xffdfff7f}, }; diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp index 1b959b515e..4f59ac5843 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp @@ -14,6 +14,7 @@ #include "Pokemon/Pokemon_Strings.h" #include "PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h" #include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" #include "PokemonLZA_RestaurantFarmer.h" namespace PokemonAutomation{ @@ -57,11 +58,17 @@ RestaurantFarmer::RestaurantFarmer(){} void RestaurantFarmer::run_lobby(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ -// RestaurantFarmer_Descriptor::Stats& stats = env.current_stats(); + RestaurantFarmer_Descriptor::Stats& stats = env.current_stats(); while (true){ context.wait_for_all_requests(); + ButtonWatcher buttonA( + COLOR_RED, + ButtonType::ButtonA, + {0.1, 0.1, 0.8, 0.8}, + &env.console.overlay() + ); SelectionArrowWatcher arrow( COLOR_YELLOW, &env.console.overlay(), SelectionArrowType::RIGHT, @@ -69,37 +76,55 @@ void RestaurantFarmer::run_lobby(SingleSwitchProgramEnvironment& env, ProControl ); FlatWhiteDialogWatcher dialog0(COLOR_RED, &env.console.overlay()); BlueDialogWatcher dialog1(COLOR_RED, &env.console.overlay()); + ItemReceiveWatcher item_receive(COLOR_RED, &env.console.overlay()); int ret = wait_until( env.console, context, - 1000ms, + 10000ms, { + buttonA, arrow, dialog0, dialog1, + item_receive, } ); context.wait_for(100ms); switch (ret){ case 0: + env.log("Detected A button."); + pbf_press_button(context, BUTTON_A, 160ms, 80ms); + continue; + + case 1: env.log("Detected selection arrow."); pbf_mash_button(context, BUTTON_A, 5000ms); return; - case 1: + case 2: env.log("Detected white dialog."); pbf_press_button(context, BUTTON_B, 160ms, 80ms); continue; - case 2: + case 3: env.log("Detected blue dialog."); pbf_press_button(context, BUTTON_B, 160ms, 80ms); continue; - default: - env.log("Detected nothing."); + case 4: + env.log("Detected item receive."); pbf_press_button(context, BUTTON_A, 160ms, 80ms); + continue; + + default: + stats.errors++; + env.update_stats(); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Battle took longer than 30 minutes.", + env.console + ); } } } @@ -114,7 +139,7 @@ void RestaurantFarmer::run_battle(SingleSwitchProgramEnvironment& env, ProContro SelectionArrowType::RIGHT, {0.654308, 0.481553, 0.295529, 0.312621} ); - ItemReceiveWatcher dialog0(COLOR_RED, &env.console.overlay(), 1000ms); + ItemReceiveWatcher item_receive(COLOR_RED, &env.console.overlay(), 1000ms); BlueDialogWatcher dialog1(COLOR_RED, &env.console.overlay()); @@ -132,7 +157,7 @@ void RestaurantFarmer::run_battle(SingleSwitchProgramEnvironment& env, ProContro }, { arrow, - dialog0, + item_receive, dialog1, } ); diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp index cc648eda05..409212a74b 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp @@ -39,12 +39,14 @@ class ShinyHunt_Bench_Descriptor::Stats : public StatsTracker{ public: Stats() : resets(m_stats["Bench Sits"]) - , shinies(m_stats["Shinies"]) + , shinies(m_stats["Shinies Detected"]) , errors(m_stats["Errors"]) { m_display_order.emplace_back("Bench Sits"); - m_display_order.emplace_back("Shinies"); + m_display_order.emplace_back("Shinies Detected"); m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); + + m_aliases["Shinies"] = "Shinies Detected"; } std::atomic& resets; @@ -63,7 +65,7 @@ ShinyHunt_Bench::ShinyHunt_Bench() : SHINY_DETECTED( "Shiny Detected", "The shiny sound plays on a smaller radius than the shiny spawn radius. " - "Therefore some (if not most) of the shinies will be inaudible and will not be detected by this program. " + "Therefore most shinies will be inaudible and will not be detected by this program. " "You will still need to manually run around to see if any shinies spawned out-of-range.<\font>", "2000ms" ) From bb95cfbde028ab1d62f0d94ff0bed660bdba75c9 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Thu, 23 Oct 2025 01:45:53 -0700 Subject: [PATCH 10/22] Tighten selection arrow threshold. --- .../Source/CommonTools/Images/WaterfillUtilities.cpp | 7 ++++++- .../Inference/PokemonLZA_SelectionArrowDetector.cpp | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp b/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp index 4c4fe09912..0482162799 100644 --- a/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp +++ b/SerialPrograms/Source/CommonTools/Images/WaterfillUtilities.cpp @@ -140,7 +140,12 @@ bool match_template_by_waterfill( } if (rmsd < rmsd_threshold){ -// std::cout << "Object rmsd: " << rmsd << std::endl; +#if 0 + std::cout << "Object rmsd: " << rmsd << std::endl; +// static int c = 0; +// extract_box_reference(image, object).save("match-" + std::to_string(c++) + ".png"); +#endif + detected = true; if (check_matched_object(object)){ diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp index 264ff90ec6..6d3bd71918 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.cpp @@ -72,8 +72,8 @@ bool SelectionArrowDetector::detect(const ImageViewRGB32& screen){ double screen_rel_size = (screen.height() / 1080.0); double screen_rel_size_2 = screen_rel_size * screen_rel_size; - double min_area_1080p = 700.0; - double rmsd_threshold = 120.0; + double min_area_1080p = 700; + double rmsd_threshold = 80; size_t min_area = size_t(screen_rel_size_2 * min_area_1080p); const std::vector> FILTERS = { From c357ae80f63d246da95347feb2bdc6886b4a9ad9 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Thu, 23 Oct 2025 01:46:56 -0700 Subject: [PATCH 11/22] Shiny sound can play multiple times. --- .../Options/PokemonLZA_ShinyDetectedAction.cpp | 13 +++++++++++-- .../Options/PokemonLZA_ShinyDetectedAction.h | 4 +++- .../Programs/PokemonLZA_ShinyHunt_Bench.cpp | 10 ++-------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp index 89b97ebc11..1ac2d63763 100644 --- a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp @@ -58,16 +58,25 @@ ShinyDetectedActionOption::ShinyDetectedActionOption( ImageAttachmentMode::JPG, {"Notifs", "Showcase"} ) + , NOTES( + "" + "The shiny sound is not a reliable measure of shinies encountered. " + "First, the sound only plays on a smaller radius than the spawn radius, so the vast majority of shinies are inaudible. " + "Secondly, it may play multiple times for the same shiny, so it may overcount. " + "You will still need to manually run around to see if any shinies spawned out-of-range.<\font>" + ) { if (!DESCRIPTION.text().empty()){ - PA_ADD_OPTION(DESCRIPTION); + PA_ADD_STATIC(DESCRIPTION); } PA_ADD_OPTION(ACTION); PA_ADD_OPTION(MAX_COUNT); PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(SCREENSHOT_DELAY); - on_config_value_changed(this); + PA_ADD_STATIC(NOTES); + + ShinyDetectedActionOption::on_config_value_changed(this); ACTION.add_listener(*this); } diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h index 58014597e7..052f44b7e9 100644 --- a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h @@ -35,7 +35,7 @@ class ShinyDetectedActionOption : public GroupOption, public ConfigOption::Liste ShinyDetectedActionOption( std::string label, std::string description, std::string default_delay, - ShinyDetectedActionType default_action = ShinyDetectedActionType::STOP_AFTER_COUNT + ShinyDetectedActionType default_action = ShinyDetectedActionType::IGNORE ); bool stop_on_shiny(uint8_t current_count) const; @@ -48,6 +48,8 @@ class ShinyDetectedActionOption : public GroupOption, public ConfigOption::Liste BooleanCheckBoxOption TAKE_VIDEO; MillisecondsOption SCREENSHOT_DELAY; EventNotificationOption NOTIFICATIONS; + + StaticTextOption NOTES; }; diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp index 409212a74b..738737a381 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp @@ -62,13 +62,7 @@ std::unique_ptr ShinyHunt_Bench_Descriptor::make_stats() const{ ShinyHunt_Bench::ShinyHunt_Bench() - : SHINY_DETECTED( - "Shiny Detected", - "The shiny sound plays on a smaller radius than the shiny spawn radius. " - "Therefore most shinies will be inaudible and will not be detected by this program. " - "You will still need to manually run around to see if any shinies spawned out-of-range.<\font>", - "2000ms" - ) + : SHINY_DETECTED("Shiny Detected", "", "2000ms") , NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)) , NOTIFICATIONS({ &NOTIFICATION_STATUS, @@ -79,7 +73,7 @@ ShinyHunt_Bench::ShinyHunt_Bench() }) { PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); - PA_ADD_STATIC(SHINY_DETECTED); + PA_ADD_OPTION(SHINY_DETECTED); PA_ADD_OPTION(NOTIFICATIONS); } From 368005d4bcd664fcc3a70101420801ffc161c005 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Thu, 23 Oct 2025 01:47:08 -0700 Subject: [PATCH 12/22] Try to fix bench reset interruptions. --- SerialPrograms/Source/CommonFramework/Globals.cpp | 2 +- .../PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/Globals.cpp b/SerialPrograms/Source/CommonFramework/Globals.cpp index b2b91a664e..5b4305a9a6 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.cpp +++ b/SerialPrograms/Source/CommonFramework/Globals.cpp @@ -26,7 +26,7 @@ namespace PokemonAutomation{ const bool IS_BETA_VERSION = true; const int PROGRAM_VERSION_MAJOR = 0; const int PROGRAM_VERSION_MINOR = 59; -const int PROGRAM_VERSION_PATCH = 2; +const int PROGRAM_VERSION_PATCH = 3; const std::string PROGRAM_VERSION_BASE = "v" + std::to_string(PROGRAM_VERSION_MAJOR) + diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp index 322e83cf39..63edff2330 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_BasicNavigation.cpp @@ -8,6 +8,7 @@ #include "CommonTools/Async/InferenceRoutines.h" #include "CommonTools/VisualDetectors/BlackScreenDetector.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" #include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" #include "PokemonLZA/Inference/PokemonLZA_SelectionArrowDetector.h" #include "PokemonLZA/Inference/PokemonLZA_DialogDetector.h" @@ -73,7 +74,12 @@ void sit_on_bench( int ret = run_until( console, context, [](ProControllerContext& context){ - pbf_mash_button(context, BUTTON_A, 30000ms); + pbf_mash_button(context, BUTTON_A, 5000ms); + for (int c = 0; c < 3; c++){ + pbf_move_left_joystick(context, 128, 255, 1000ms, 0ms); + pbf_mash_button(context, BUTTON_B, 1000ms); + pbf_mash_button(context, BUTTON_A, 5000ms); + } }, {black_screen} ); @@ -85,7 +91,7 @@ void sit_on_bench( default: OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "sit_on_bench(): No transition deteted after 30 seconds of mashing A.", + "sit_on_bench(): No transition detected after 4 attempts.", console ); } From a17c9ef817b4dc43a0c4d0c5420d1ad7d9c0fcce Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Thu, 23 Oct 2025 01:49:59 -0700 Subject: [PATCH 13/22] Fix incorrect error message. --- .../Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp index 4f59ac5843..6ab41f5885 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp @@ -122,7 +122,7 @@ void RestaurantFarmer::run_lobby(SingleSwitchProgramEnvironment& env, ProControl env.update_stats(); OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Battle took longer than 30 minutes.", + "run_lobby(): No recognized state after 60 seconds.", env.console ); } From 1033be9c3395dee2048b50e00ed542b1d6bb8499 Mon Sep 17 00:00:00 2001 From: EZ <52121058+Ericzklm@users.noreply.github.com> Date: Thu, 23 Oct 2025 14:48:20 -0700 Subject: [PATCH 14/22] constexpr compile fix (#743) --- .../AutoStory/PokemonSV_AutoStory_Segment_34.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_34.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_34.h index fb4c227761..b2d6149b6e 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_34.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_34.h @@ -26,24 +26,22 @@ class AutoStory_Segment_34 : public AutoStory_Segment{ ) const override; }; -static constexpr std::string segment_num = "34"; +static constexpr const char* segment_num = "34"; - - -inline std::string checkpoint90_start(){ return segment_num + ": Beat Geeta. At Pokemon League Pokecenter.";} -inline std::string checkpoint90_end(){ return segment_num + ": Beat Nemona. At dormitory room, next to bed.";} +inline std::string checkpoint90_start(){ return std::string(segment_num) + ": Beat Geeta. At Pokemon League Pokecenter.";} +inline std::string checkpoint90_end(){ return std::string(segment_num) + ": Beat Nemona. At dormitory room, next to bed.";} // start: Beat Geeta. At Pokemon League Pokecenter. // end: Beat Nemona. At dormitory room, next to bed. void checkpoint_90(SingleSwitchProgramEnvironment& env, ProControllerContext& context, EventNotificationOption& notif_status_update, AutoStoryStats& stats); inline std::string checkpoint91_start(){ return checkpoint90_end();} -inline std::string checkpoint91_end(){ return segment_num + ": Beat Penny. At Academy fly point.";} +inline std::string checkpoint91_end(){ return std::string(segment_num) + ": Beat Penny. At Academy fly point.";} // start: Beat Nemona. At dormitory room, next to bed." // end: Beat Penny. At Academy fly point. void checkpoint_91(SingleSwitchProgramEnvironment& env, ProControllerContext& context, EventNotificationOption& notif_status_update, AutoStoryStats& stats); inline std::string checkpoint92_start(){ return checkpoint91_end();} -inline std::string checkpoint92_end(){ return segment_num + ": Beat Arven. At Los Platos Pokecenter.";} +inline std::string checkpoint92_end(){ return std::string(segment_num) + ": Beat Arven. At Los Platos Pokecenter.";} // start: Beat Penny. At Academy fly point. // end: Beat Arven. At Los Platos Pokecenter. void checkpoint_92(SingleSwitchProgramEnvironment& env, ProControllerContext& context, EventNotificationOption& notif_status_update, AutoStoryStats& stats); From f30d29da559c659840bd6f7b9a2b2360d0d18d48 Mon Sep 17 00:00:00 2001 From: Dalton <59972310+Dalton-V@users.noreply.github.com> Date: Thu, 23 Oct 2025 17:03:17 -0500 Subject: [PATCH 15/22] Update Ut Installer Url (#742) --- .../Build-Windows-Qt6.8.3.md | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/SerialPrograms/BuildInstructions/Build-Windows-Qt6.8.3.md b/SerialPrograms/BuildInstructions/Build-Windows-Qt6.8.3.md index 21165e9ff4..e54cf6386d 100644 --- a/SerialPrograms/BuildInstructions/Build-Windows-Qt6.8.3.md +++ b/SerialPrograms/BuildInstructions/Build-Windows-Qt6.8.3.md @@ -7,13 +7,13 @@ The installation order here is important. While other orderings may work, this is the specific order that we have tested. And the Qt installation must be the last thing installed. 1. Install Visual Studio 2022: - 1. [Download Page](https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes) - 2. Make sure you select the C++ development tools. + 1. [Download Page](https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes) + 2. Make sure you select the C++ development tools. 2. Install Windows Development SDK: - 1. [Download Page](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) + 1. [Download Page](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) 3. Install CMake: - 1. [Download Page](https://cmake.org/download/) - 2. When prompted select, "Add CMake to the system PATH for all users". + 1. [Download Page](https://cmake.org/download/) + 2. When prompted select, "Add CMake to the system PATH for all users". ## Install Qt 6.8.3: @@ -23,16 +23,16 @@ Unlike with Qt 5.12, there is no offline installer for it. So you have two optio If you are ok with creating an account with Qt and using their online installer, then use this method. -1. Download the online installer from here: https://www.qt.io/download-qt-Images/ -3. Select the following options: - - Qt 6.8.3 - - MSVC 2022 64-bit - - Sources - - Additional Libraries - - Qt Image Formats - - Qt Multimedia - - Qt Serial Port - - Qt Debug Information Files +1. Download the online installer from here: https://www.qt.io/download-qt-installer-oss/ +2. Select the following options: + - Qt 6.8.3 + - MSVC 2022 64-bit + - Sources + - Additional Libraries + - Qt Image Formats + - Qt Multimedia + - Qt Serial Port + - Qt Debug Information Files ![](Images/Windows-Install-Qt6.8.3-Custom.png) ![](Images/Windows-Install-Qt6.8.3-Components.png) @@ -43,12 +43,12 @@ If you repeatedly run into an error involving "SSL handshake failed", you will n If you are unable or unwilling to use the online installer, the alternative is to copy an installation directly into your system. To do this, you will need to download the installation from us, and copy it into your C drive. -1. Join our [Discord server](https://discord.gg/cQ4gWxN) and ask for the link to the Qt6 standalone. Someone will DM you with a link*. +1. Join our [Discord server](https://discord.gg/cQ4gWxN) and ask for the link to the Qt6 standalone. Someone will DM you with a link\*. 2. Download `Qt6.8.3.7z` and decompress it. You can use [7-zip](https://www.7-zip.org/) to decompress it. This will create a folder with the same name. 3. Move this folder to `C:\`. It will probably ask you for permissions to do it. 4. Navigate to: `C:\Qt6.8.3\Tools\QtCreator\bin\` and create a shortcut to `qtcreator.exe`. Copy this shortcut to somewhere convenient. (By default this shortcut is named, `Qt Creator 16.0.0 (Community)`) -*This Qt6 standalone file is 3GB in size and is being hosted by our staff for our own developers. We don't want the entire world converging here and overrunning the server. +\*This Qt6 standalone file is 3GB in size and is being hosted by our staff for our own developers. We don't want the entire world converging here and overrunning the server. ## Setup: @@ -62,8 +62,8 @@ If you are unable or unwilling to use the online installer, the alternative is t 5. Click on `File` -> `Open File or Project`. 6. Navigate to `SerialPrograms` and select `CMakeLists.txt`. 7. It will then ask you to configure the project. Ensure `Desktop Qt 6.8.3 MSVC2022 64bit` and `Release with Debug Information` are selected. - - Ensure the build directory for `Desktop_Qt_6_8_2_MSVC2022_64bit-RelWithDebInfo` is located in the root of the `Arduino-Source` repo, and not buried in subfolders (e.g. `build` or `SerialPrograms`). - - Click `Configure Project`. + - Ensure the build directory for `Desktop_Qt_6_8_2_MSVC2022_64bit-RelWithDebInfo` is located in the root of the `Arduino-Source` repo, and not buried in subfolders (e.g. `build` or `SerialPrograms`). + - Click `Configure Project`. ![](Images/Windows-configure-project-qt-creator-13.png) @@ -79,13 +79,13 @@ If you are unable or unwilling to use the online installer, the alternative is t - Click `Projects` on the left sidebar. - In `Build directory`, ensure the build directory for `Desktop_Qt_6_8_3_MSVC2022_64bit-RelWithDebInfo` is located in the root of the `Arduino-Source` repo, and not buried in subfolders (e.g. `build` or `SerialPrograms`). - - e.g. change the default build directory from: `Arduino-Source/SerialPrograms/build/Desktop_Qt_6_8_3_MSVC2022_64bit-RelWithDebInfo` + - e.g. change the default build directory from: `Arduino-Source/SerialPrograms/build/Desktop_Qt_6_8_3_MSVC2022_64bit-RelWithDebInfo` - to: `Arduino-Source/build-SerialPrograms-Desktop_Qt_6_8_3_MSVC2022_64bit-RelWithDebInfo` - ## Upgrading Qt components ### Installing newer Qt version + If you have already have older versions of Qt installed, but need to upgrade Qt components, you can use the Maintenance tool, which comes pre-instaled with Qt (C:\Qt\MaintenanceTool.exe). - When prompted, in `Maintenance Actions`, choose `Add or remove components`. @@ -93,15 +93,16 @@ If you have already have older versions of Qt installed, but need to upgrade Qt - Optional: In `Maintenance Actions`, you may also choose `Update components` as well. To update Qt Creator, and other components. ### Building with the newer Qt version + - Open the `SerialPrograms` project in Qt, as outlined in the "Setup" section above. - In the toolbar, click `Edit` -> `Preferences` - Under `Kits` tab, choose the newer Qt version (e.g. Desktop Qt 6.8.3) - + - Under `Compiler`, set it to Microsoft Visual C++ Compiler or Visual Studio, if not already set. - Click `Ok`, to save Kits preferences. - Click the Monitor symbol at the bottom left - + - Under `Kit`: choose the desired Qt version. - Under `Build`: choose `Release with Debug Information` @@ -109,18 +110,17 @@ If you have already have older versions of Qt installed, but need to upgrade Qt - Optional: Move the `UserSettings` folder from the old build folder to the new build folder, to keep your old settings, such as the dev key. ### Upgrade compiler + - Upgrade the compiler by installing a new version of Visual Studio. Ensure `Desktop development with C++` is checked, so the latest MSVC compiler is also installed. - Open the `SerialPrograms` project in Qt, as outlined in the "Setup" section above. - In the toolbar, click `Edit` -> `Preferences` -- Click the `Kits` tab on the left. Then click the `Compilers` tab, click `Re-detect` to refresh the list of compilers. Then click `Apply` in the bottom right. +- Click the `Kits` tab on the left. Then click the `Compilers` tab, click `Re-detect` to refresh the list of compilers. Then click `Apply` in the bottom right. - Back in the `Kits` tab, your newly installed compilers should now show up in the list of compilers. When building, if you get the error `yvals_core.h:931: error: STL1001: Unexpected compiler version, expected MSVC 19.42 or newer` (or something similar), consider deleting the old build folder, and rebuilding from scratch.
-**Discord Server:** - +**Discord Server:** [](https://discord.gg/cQ4gWxN) - From d140a86a5c85acefc6df14fa1d2afadbdb8815e6 Mon Sep 17 00:00:00 2001 From: Nymphea <87930564+NympheaR@users.noreply.github.com> Date: Fri, 24 Oct 2025 07:04:49 +0900 Subject: [PATCH 16/22] Extend purchase arrow detection wait time for languages with longer text (#741) * Extend purchase arrow detection wait time for languages with longer text * Further increase wait time until throwing error --- .../Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp index 89a029689c..eee5335b1d 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ClothingBuyer.cpp @@ -80,7 +80,7 @@ void ClothingBuyer::program(SingleSwitchProgramEnvironment& env, ProControllerCo FlatWhiteDialogWatcher already_bought(COLOR_RED, &env.console.overlay()); int ret = wait_until( env.console, context, - std::chrono::seconds(2), + std::chrono::seconds(30), { buy_yes_no, already_bought } ); switch (ret) { From 231ac634e101be806c28fe0cfe81fdad4308c6a9 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Fri, 24 Oct 2025 01:45:37 -0700 Subject: [PATCH 17/22] Change shiny sound notification system. --- .../PokemonLZA_ShinyDetectedAction.cpp | 86 ++++++------------- .../Options/PokemonLZA_ShinyDetectedAction.h | 34 +++----- .../Programs/PokemonLZA_ShinyHunt_Bench.cpp | 22 +++-- .../Programs/PokemonLZA_ShinyHunt_Bench.h | 2 +- 4 files changed, 58 insertions(+), 86 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp index 1ac2d63763..67791c80c2 100644 --- a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp @@ -4,7 +4,7 @@ * */ -#include "Common/Cpp/Exceptions.h" +//#include "Common/Cpp/Exceptions.h" #include "CommonFramework/Notifications/ProgramNotifications.h" #include "CommonFramework/VideoPipeline/VideoFeed.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" @@ -17,29 +17,23 @@ namespace PokemonLZA{ -ShinyDetectedActionOption::ShinyDetectedActionOption( +ShinySoundDetectedActionOption::ShinySoundDetectedActionOption( std::string label, std::string description, std::string default_delay, - ShinyDetectedActionType default_action + ShinySoundDetectedAction default_action ) : GroupOption(std::move(label), LockMode::UNLOCK_WHILE_RUNNING) , DESCRIPTION(std::move(description)) , ACTION( "Action:", { - {ShinyDetectedActionType::IGNORE, "ignore", "Ignore the shiny. Do not stop the program."}, - {ShinyDetectedActionType::STOP_PROGRAM, "stop", "Stop program and go Home."}, - {ShinyDetectedActionType::STOP_AFTER_COUNT, "stop-count", "Stop program only after X shinies are found."}, + {ShinySoundDetectedAction::STOP_PROGRAM, "stop", "Stop program and go Home. Send notification."}, + {ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY, "notify-first", "Keep running. Notify on first shiny sound only."}, + {ShinySoundDetectedAction::NOTIFY_ON_ALL, "notify-all", "Keep running. Notify on all shiny sounds."}, }, LockMode::UNLOCK_WHILE_RUNNING, default_action ) - , MAX_COUNT( - "Max Detections:
" - "Stop the program after this many shinies are detected.", - LockMode::UNLOCK_WHILE_RUNNING, - 10 - ) , TAKE_VIDEO( "Take Video:", LockMode::UNLOCK_WHILE_RUNNING, @@ -60,71 +54,43 @@ ShinyDetectedActionOption::ShinyDetectedActionOption( ) , NOTES( "" - "The shiny sound is not a reliable measure of shinies encountered. " - "First, the sound only plays on a smaller radius than the spawn radius, so the vast majority of shinies are inaudible. " - "Secondly, it may play multiple times for the same shiny, so it may overcount. " - "You will still need to manually run around to see if any shinies spawned out-of-range.<\font>" + "The shiny sound is not a reliable measure of shinies encountered:
" + "1. The sound only plays on a smaller radius than the spawn radius, so the vast majority of shinies are inaudible. " + "You will still need to manually run around to see if any shinies spawned out-of-range. " + "
" + "2. Secondly, it may play multiple times for the same shiny, so it may overcount. " + "If a shiny spawns next to you, it may play the sound on every reset afterwards. <\font>" ) { if (!DESCRIPTION.text().empty()){ PA_ADD_STATIC(DESCRIPTION); } PA_ADD_OPTION(ACTION); - PA_ADD_OPTION(MAX_COUNT); PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(SCREENSHOT_DELAY); PA_ADD_STATIC(NOTES); - - ShinyDetectedActionOption::on_config_value_changed(this); - - ACTION.add_listener(*this); -} -ShinyDetectedActionOption::~ShinyDetectedActionOption(){ - ACTION.remove_listener(*this); -} -void ShinyDetectedActionOption::on_config_value_changed(void* object){ - MAX_COUNT.set_visibility( - ACTION == ShinyDetectedActionType::STOP_AFTER_COUNT - ? ConfigOptionState::ENABLED - : ConfigOptionState::HIDDEN - ); } -bool ShinyDetectedActionOption::stop_on_shiny(uint8_t current_count) const{ - switch (ACTION){ - case ShinyDetectedActionType::IGNORE: - return false; - case ShinyDetectedActionType::STOP_PROGRAM: - return true; - case ShinyDetectedActionType::STOP_AFTER_COUNT: - return current_count >= MAX_COUNT; - default: - throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid shiny action enum type."); - } -} - - - - - - - - -bool on_shiny_sound( +bool ShinySoundDetectedActionOption::on_shiny_sound( ProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, - ShinyDetectedActionOption& options, - uint8_t current_count, + size_t current_count, float error_coefficient ){ + ShinySoundDetectedAction action = ACTION; + + if (action == ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY && current_count > 0){ + return false; + } + { std::ostringstream ss; ss << "Detected Shiny Sound! (error coefficient = " << error_coefficient << ")"; stream.log(ss.str(), COLOR_BLUE); } - if (options.TAKE_VIDEO){ - context.wait_for(options.SCREENSHOT_DELAY); + if (TAKE_VIDEO){ + context.wait_for(SCREENSHOT_DELAY); pbf_press_button(context, BUTTON_CAPTURE, 2 * TICKS_PER_SECOND, 0); } @@ -139,14 +105,14 @@ bool on_shiny_sound( } send_program_notification( - env, options.NOTIFICATIONS, + env, NOTIFICATIONS, Pokemon::COLOR_STAR_SHINY, "Detected Shiny Sound", embeds, "", stream.video().snapshot(), true ); - return options.stop_on_shiny(current_count); + return action == ShinySoundDetectedAction::STOP_PROGRAM; } @@ -164,6 +130,10 @@ bool on_shiny_sound( + + + + } diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h index 052f44b7e9..6db0a5c538 100644 --- a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h @@ -11,7 +11,7 @@ #include "Common/Cpp/Options/StaticTextOption.h" #include "Common/Cpp/Options/BooleanCheckBoxOption.h" #include "Common/Cpp/Options//TimeDurationOption.h" -#include "Common/Cpp/Options/SimpleIntegerOption.h" +//#include "Common/Cpp/Options/SimpleIntegerOption.h" #include "CommonFramework/Notifications/EventNotificationOption.h" #include "CommonFramework/Tools/VideoStream.h" #include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" @@ -22,29 +22,29 @@ namespace NintendoSwitch{ namespace PokemonLZA{ -enum class ShinyDetectedActionType{ - IGNORE, +enum class ShinySoundDetectedAction{ STOP_PROGRAM, - STOP_AFTER_COUNT, + NOTIFY_ON_FIRST_ONLY, + NOTIFY_ON_ALL, }; -class ShinyDetectedActionOption : public GroupOption, public ConfigOption::Listener{ +class ShinySoundDetectedActionOption : public GroupOption, public ConfigOption::Listener{ public: - ~ShinyDetectedActionOption(); - ShinyDetectedActionOption( + ShinySoundDetectedActionOption( std::string label, std::string description, std::string default_delay, - ShinyDetectedActionType default_action = ShinyDetectedActionType::IGNORE + ShinySoundDetectedAction default_action ); - bool stop_on_shiny(uint8_t current_count) const; - - virtual void on_config_value_changed(void* object) override; + bool on_shiny_sound( + ProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, + size_t current_count, + float error_coefficient + ); StaticTextOption DESCRIPTION; - EnumDropdownOption ACTION; - SimpleIntegerOption MAX_COUNT; + EnumDropdownOption ACTION; BooleanCheckBoxOption TAKE_VIDEO; MillisecondsOption SCREENSHOT_DELAY; EventNotificationOption NOTIFICATIONS; @@ -54,14 +54,6 @@ class ShinyDetectedActionOption : public GroupOption, public ConfigOption::Liste -bool on_shiny_sound( - ProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, - ShinyDetectedActionOption& options, - uint8_t current_count, - float error_coefficient -); - - } diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp index 738737a381..490a325102 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp @@ -8,6 +8,7 @@ #include "CommonFramework/ProgramStats/StatsTracking.h" #include "CommonFramework/Notifications/ProgramNotifications.h" #include "CommonTools/Async/InferenceRoutines.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" #include "Pokemon/Pokemon_Strings.h" #include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" #include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" @@ -39,14 +40,15 @@ class ShinyHunt_Bench_Descriptor::Stats : public StatsTracker{ public: Stats() : resets(m_stats["Bench Sits"]) - , shinies(m_stats["Shinies Detected"]) + , shinies(m_stats["Shiny Sounds"]) , errors(m_stats["Errors"]) { m_display_order.emplace_back("Bench Sits"); - m_display_order.emplace_back("Shinies Detected"); + m_display_order.emplace_back("Shiny Sounds"); m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); - m_aliases["Shinies"] = "Shinies Detected"; + m_aliases["Shinies"] = "Shiny Sounds"; + m_aliases["Shinies Detected"] = "Shiny Sounds"; } std::atomic& resets; @@ -62,7 +64,11 @@ std::unique_ptr ShinyHunt_Bench_Descriptor::make_stats() const{ ShinyHunt_Bench::ShinyHunt_Bench() - : SHINY_DETECTED("Shiny Detected", "", "2000ms") + : SHINY_DETECTED( + "Shiny Detected", "", + "2000ms", + ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY + ) , NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)) , NOTIFICATIONS({ &NOTIFICATION_STATUS, @@ -112,9 +118,12 @@ void ShinyHunt_Bench::program(SingleSwitchProgramEnvironment& env, ProController } shiny_count++; - if (on_shiny_sound( + + // Wait for the day/night transition to finish. + context.wait_for(std::chrono::milliseconds(2000)); + + if (SHINY_DETECTED.on_shiny_sound( env, env.console, context, - SHINY_DETECTED, shiny_count, shiny_coefficient )){ @@ -122,6 +131,7 @@ void ShinyHunt_Bench::program(SingleSwitchProgramEnvironment& env, ProController } } + go_home(env.console, context); send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); } diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h index 9d4720331a..4331694f48 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h @@ -37,7 +37,7 @@ class ShinyHunt_Bench : public SingleSwitchProgramInstance{ private: PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; - ShinyDetectedActionOption SHINY_DETECTED; + ShinySoundDetectedActionOption SHINY_DETECTED; EventNotificationOption NOTIFICATION_STATUS; EventNotificationsOption NOTIFICATIONS; From 8adcbafa52fce02066d078866e91f0a99c0e680f Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Fri, 24 Oct 2025 03:06:18 -0700 Subject: [PATCH 18/22] Rename bench-sit. Add overworld SR, --- .../ProgramStats/StatsDatabase.cpp | 1 + .../PokemonLZA_ShinyDetectedAction.cpp | 1 + .../Source/PokemonLZA/PokemonLZA_Panels.cpp | 6 +- ....cpp => PokemonLZA_ShinyHunt_BenchSit.cpp} | 27 ++- ...ench.h => PokemonLZA_ShinyHunt_BenchSit.h} | 14 +- .../PokemonLZA_ShinyHunt_OverworldReset.cpp | 160 ++++++++++++++++++ .../PokemonLZA_ShinyHunt_OverworldReset.h | 58 +++++++ SerialPrograms/SourceFiles.cmake | 6 +- 8 files changed, 247 insertions(+), 26 deletions(-) rename SerialPrograms/Source/PokemonLZA/Programs/{PokemonLZA_ShinyHunt_Bench.cpp => PokemonLZA_ShinyHunt_BenchSit.cpp} (79%) rename SerialPrograms/Source/PokemonLZA/Programs/{PokemonLZA_ShinyHunt_Bench.h => PokemonLZA_ShinyHunt_BenchSit.h} (68%) create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp create mode 100644 SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.h diff --git a/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp b/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp index b7c44799a5..394a4c48c9 100644 --- a/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp +++ b/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp @@ -35,6 +35,7 @@ const std::map STATS_DATABASE_ALIASES{ {"Shiny Hunt Autonomous - Fishing", "PokemonSwSh:ShinyHuntAutonomousFishing"}, {"Shiny Hunt Autonomous - Overworld", "PokemonSwSh:ShinyHuntAutonomousOverworld"}, {"PokemonSV:StatsResetBloodmoon", "PokemonSV:StatsResetEventBattle"}, + {"PokemonLZA:ShinyHunt-Bench", "PokemonLZA:ShinyHunt-BenchSit"}, }; diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp index 67791c80c2..78ac6a7a5a 100644 --- a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp @@ -4,6 +4,7 @@ * */ +#include //#include "Common/Cpp/Exceptions.h" #include "CommonFramework/Notifications/ProgramNotifications.h" #include "CommonFramework/VideoPipeline/VideoFeed.h" diff --git a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp index c52b918b2d..56a3634f1d 100644 --- a/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp +++ b/SerialPrograms/Source/PokemonLZA/PokemonLZA_Panels.cpp @@ -13,7 +13,8 @@ #include "Programs/PokemonLZA_BeldumHunter.h" #include "Programs/PokemonLZA_ClothingBuyer.h" #include "Programs/PokemonLZA_RestaurantFarmer.h" -#include "Programs/PokemonLZA_ShinyHunt_Bench.h" +#include "Programs/PokemonLZA_ShinyHunt_BenchSit.h" +#include "Programs/PokemonLZA_ShinyHunt_OverworldReset.h" #include "Programs/TestPrograms/PokemonLZA_OverworldWatcher.h" namespace PokemonAutomation{ @@ -38,7 +39,8 @@ std::vector PanelListFactory::make_panels() const{ if (PreloadSettings::instance().DEVELOPER_MODE){ ret.emplace_back("---- Shiny Hunting ----"); - ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); } diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.cpp similarity index 79% rename from SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp rename to SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.cpp index 490a325102..4bafcaee56 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -1,10 +1,9 @@ -/* Shiny Hunt - Bench +/* Shiny Hunt - Bench Sit * * From: https://github.com/PokemonAutomation/ * */ -//#include #include "CommonFramework/ProgramStats/StatsTracking.h" #include "CommonFramework/Notifications/ProgramNotifications.h" #include "CommonTools/Async/InferenceRoutines.h" @@ -12,7 +11,7 @@ #include "Pokemon/Pokemon_Strings.h" #include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" #include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" -#include "PokemonLZA_ShinyHunt_Bench.h" +#include "PokemonLZA_ShinyHunt_BenchSit.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -24,11 +23,11 @@ using namespace Pokemon; -ShinyHunt_Bench_Descriptor::ShinyHunt_Bench_Descriptor() +ShinyHunt_BenchSit_Descriptor::ShinyHunt_BenchSit_Descriptor() : SingleSwitchProgramDescriptor( - "PokemonLZA:ShinyHunt-Bench", - STRING_POKEMON + " LZA", "Shiny Hunt - Bench", - "Programs/PokemonLZA/ShinyHunt-Bench.html", + "PokemonLZA:ShinyHunt-BenchSit", + STRING_POKEMON + " LZA", "Shiny Hunt - Bench Sit", + "Programs/PokemonLZA/ShinyHunt-BenchSit.html", "Shiny hunt by repeatedly sitting on a bench to reset spawns.", ProgramControllerClass::StandardController_NoRestrictions, FeedbackType::REQUIRED, @@ -36,7 +35,7 @@ ShinyHunt_Bench_Descriptor::ShinyHunt_Bench_Descriptor() {} ) {} -class ShinyHunt_Bench_Descriptor::Stats : public StatsTracker{ +class ShinyHunt_BenchSit_Descriptor::Stats : public StatsTracker{ public: Stats() : resets(m_stats["Bench Sits"]) @@ -55,7 +54,7 @@ class ShinyHunt_Bench_Descriptor::Stats : public StatsTracker{ std::atomic& shinies; std::atomic& errors; }; -std::unique_ptr ShinyHunt_Bench_Descriptor::make_stats() const{ +std::unique_ptr ShinyHunt_BenchSit_Descriptor::make_stats() const{ return std::unique_ptr(new Stats()); } @@ -63,10 +62,10 @@ std::unique_ptr ShinyHunt_Bench_Descriptor::make_stats() const{ -ShinyHunt_Bench::ShinyHunt_Bench() +ShinyHunt_BenchSit::ShinyHunt_BenchSit() : SHINY_DETECTED( "Shiny Detected", "", - "2000ms", + "2000 ms", ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY ) , NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)) @@ -83,8 +82,8 @@ ShinyHunt_Bench::ShinyHunt_Bench() PA_ADD_OPTION(NOTIFICATIONS); } -void ShinyHunt_Bench::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ - ShinyHunt_Bench_Descriptor::Stats& stats = env.current_stats(); +void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + ShinyHunt_BenchSit_Descriptor::Stats& stats = env.current_stats(); uint8_t shiny_count = 0; @@ -117,8 +116,6 @@ void ShinyHunt_Bench::program(SingleSwitchProgramEnvironment& env, ProController continue; } - shiny_count++; - // Wait for the day/night transition to finish. context.wait_for(std::chrono::milliseconds(2000)); diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.h similarity index 68% rename from SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h rename to SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.h index 4331694f48..9c05a50d5e 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.h @@ -1,11 +1,11 @@ -/* Shiny Hunt - Bench +/* Shiny Hunt - Bench Sit * * From: https://github.com/PokemonAutomation/ * */ -#ifndef PokemonAutomation_PokemonLZA_ShinyHunt_Bench_H -#define PokemonAutomation_PokemonLZA_ShinyHunt_Bench_H +#ifndef PokemonAutomation_PokemonLZA_ShinyHunt_BenchSit_H +#define PokemonAutomation_PokemonLZA_ShinyHunt_BenchSit_H #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" @@ -19,18 +19,18 @@ namespace PokemonLZA{ -class ShinyHunt_Bench_Descriptor : public SingleSwitchProgramDescriptor{ +class ShinyHunt_BenchSit_Descriptor : public SingleSwitchProgramDescriptor{ public: - ShinyHunt_Bench_Descriptor(); + ShinyHunt_BenchSit_Descriptor(); class Stats; virtual std::unique_ptr make_stats() const override; }; -class ShinyHunt_Bench : public SingleSwitchProgramInstance{ +class ShinyHunt_BenchSit : public SingleSwitchProgramInstance{ public: - ShinyHunt_Bench(); + ShinyHunt_BenchSit(); virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp new file mode 100644 index 0000000000..11cdbde020 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp @@ -0,0 +1,160 @@ +/* Shiny Hunt - Overworld Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" +#include "PokemonLZA/Programs/PokemonLZA_GameEntry.h" +#include "PokemonLZA_ShinyHunt_OverworldReset.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + +using namespace Pokemon; + + + + + +ShinyHunt_OverworldReset_Descriptor::ShinyHunt_OverworldReset_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLZA:ShinyHunt-OverworldReset", + STRING_POKEMON + " LZA", "Shiny Hunt - Overworld Reset", + "Programs/PokemonLZA/ShinyHunt-OverworldReset.html", + "Shiny hunt by repeatedly sitting on a bench to reset spawns.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS, + {} + ) +{} +class ShinyHunt_OverworldReset_Descriptor::Stats : public StatsTracker{ +public: + Stats() + : resets(m_stats["Resets"]) + , shinies(m_stats["Shinies"]) + , errors(m_stats["Errors"]) + { + m_display_order.emplace_back("Resets"); + m_display_order.emplace_back("Shinies"); + m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); + } + + std::atomic& resets; + std::atomic& shinies; + std::atomic& errors; +}; +std::unique_ptr ShinyHunt_OverworldReset_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + + + + +ShinyHunt_OverworldReset::ShinyHunt_OverworldReset() + : RESET_DELAY( + "Reset Delay:
Wait this long after the game loads before resetting.", + LockMode::UNLOCK_WHILE_RUNNING, + "5000 ms" + ) + , ROTATE_CAMERA( + "Rotate Camera:
Rotate camera upon entering the game.", + LockMode::UNLOCK_WHILE_RUNNING, + false + ) + , SHINY_DETECTED( + "Shiny Detected", "", + "5000 ms", + ShinySoundDetectedAction::STOP_PROGRAM + ) + , NOTIFICATION_STATUS("Status Update", true, false, std::chrono::seconds(3600)) + , NOTIFICATIONS({ + &NOTIFICATION_STATUS, + &SHINY_DETECTED.NOTIFICATIONS, + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_RECOVERABLE, + &NOTIFICATION_ERROR_FATAL, + }) +{ + PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); + PA_ADD_OPTION(RESET_DELAY); + PA_ADD_OPTION(ROTATE_CAMERA); + PA_ADD_OPTION(SHINY_DETECTED); + PA_ADD_OPTION(NOTIFICATIONS); +} + +void ShinyHunt_OverworldReset::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + ShinyHunt_OverworldReset_Descriptor::Stats& stats = env.current_stats(); + + uint8_t shiny_count = 0; + + while (true){ + go_home(env.console, context); + send_program_status_notification(env, NOTIFICATION_STATUS); + + + float shiny_coefficient = 1.0; + PokemonLA::ShinySoundDetector shiny_detector(env.console, [&](float error_coefficient) -> bool{ + // Warning: This callback will be run from a different thread than this function. + shiny_count++; + stats.shinies++; + env.update_stats(); + shiny_coefficient = error_coefficient; + return true; + }); + + int ret = run_until( + env.console, context, + [&](ProControllerContext& context){ + reset_game_from_home(env, env.console, context); + + if (ROTATE_CAMERA){ + pbf_move_right_joystick(context, 255, 128, RESET_DELAY, 0ms); + }else{ + pbf_wait(context, RESET_DELAY); + } + + stats.resets++; + env.update_stats(); + }, + {{shiny_detector}} + ); + + if (ret < 0){ + continue; + } + + if (SHINY_DETECTED.on_shiny_sound( + env, env.console, context, + shiny_count, + shiny_coefficient + )){ + break; + } + } + + go_home(env.console, context); + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); +} + + + + + + + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.h b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.h new file mode 100644 index 0000000000..c601651dfb --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.h @@ -0,0 +1,58 @@ +/* Shiny Hunt - Overworld Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_ShinyHunt_OverworldReset_H +#define PokemonAutomation_PokemonLZA_ShinyHunt_OverworldReset_H + +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/TimeDurationOption.h" +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "PokemonLA/Options/PokemonLA_ShinyDetectedAction.h" +#include "PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + + + +class ShinyHunt_OverworldReset_Descriptor : public SingleSwitchProgramDescriptor{ +public: + ShinyHunt_OverworldReset_Descriptor(); + + class Stats; + virtual std::unique_ptr make_stats() const override; +}; + + +class ShinyHunt_OverworldReset : public SingleSwitchProgramInstance{ +public: + ShinyHunt_OverworldReset(); + + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; + + MillisecondsOption RESET_DELAY; + BooleanCheckBoxOption ROTATE_CAMERA; + + ShinySoundDetectedActionOption SHINY_DETECTED; + + EventNotificationOption NOTIFICATION_STATUS; + EventNotificationsOption NOTIFICATIONS; +}; + + + + + +} +} +} +#endif diff --git a/SerialPrograms/SourceFiles.cmake b/SerialPrograms/SourceFiles.cmake index bff02c3609..9c023e5981 100644 --- a/SerialPrograms/SourceFiles.cmake +++ b/SerialPrograms/SourceFiles.cmake @@ -1561,8 +1561,10 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Programs/PokemonLZA_GameEntry.h Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.cpp Source/PokemonLZA/Programs/PokemonLZA_RestaurantFarmer.h - Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.cpp - Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_Bench.h + Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.cpp + Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_BenchSit.h + Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp + Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.h Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.cpp Source/PokemonLZA/Programs/TestPrograms/PokemonLZA_OverworldWatcher.h Source/PokemonRSE/Inference/Dialogs/PokemonRSE_DialogDetector.cpp From 960bd80c4fe035d12a51070da1e6d01541b75a95 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Fri, 24 Oct 2025 03:11:40 -0700 Subject: [PATCH 19/22] assert sound --- .../PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp index 11cdbde020..890b5967d1 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/PokemonLZA_ShinyHunt_OverworldReset.cpp @@ -128,6 +128,7 @@ void ShinyHunt_OverworldReset::program(SingleSwitchProgramEnvironment& env, ProC }, {{shiny_detector}} ); + shiny_detector.throw_if_no_sound(); if (ret < 0){ continue; From bbd37df8e12344391c6cf5155f51d9cdd6022f75 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Fri, 24 Oct 2025 09:38:43 -0700 Subject: [PATCH 20/22] Increase duration of key button presses to reduce drop chance. --- .../Program/PokemonSwSh_MaxLair_Run_Battle.cpp | 15 ++++++++------- .../PokemonSwSh_MaxLair_Run_EnterLobby.cpp | 12 ++++++------ .../Program/PokemonSwSh_MaxLair_Run_Entrance.cpp | 6 +++--- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Battle.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Battle.cpp index 678a2ddba1..3675b7963c 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Battle.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Battle.cpp @@ -255,10 +255,10 @@ StateMachineAction run_move_select( // If we had trouble selecting a move, then we're probably stuck in a self-target loop. // Force target the opponent. stream.log("Force targeting opponent due to inability to select a move after multiple attempts...", COLOR_RED); - pbf_press_button(context, BUTTON_A, 20, 2 * TICKS_PER_SECOND); - pbf_press_dpad(context, DPAD_UP, 2 * TICKS_PER_SECOND, 0); + pbf_press_button(context, BUTTON_A, 160ms, 2000ms); + pbf_press_dpad(context, DPAD_UP, 2000ms, 0ms); } - pbf_mash_button(context, BUTTON_A, 2 * TICKS_PER_SECOND); + pbf_mash_button(context, BUTTON_A, 2000ms); context.wait_for_all_requests(); // inference.stop(); @@ -268,7 +268,7 @@ StateMachineAction run_move_select( int result = run_until( stream, context, [](ProControllerContext& context){ - pbf_mash_button(context, BUTTON_B, 5 * TICKS_PER_SECOND); + pbf_mash_button(context, BUTTON_B, 5000ms); }, {{detector}}, INFERENCE_RATE @@ -300,9 +300,10 @@ StateMachineAction run_move_select( state_tracker.push_update(console_index); // Reset position. - pbf_press_button(context, BUTTON_A, 10, TICKS_PER_SECOND); - pbf_press_dpad(context, DPAD_RIGHT, 2 * TICKS_PER_SECOND, 0); - pbf_press_dpad(context, DPAD_UP, 2 * TICKS_PER_SECOND, 0); + pbf_mash_button(context, BUTTON_B, 2000ms); + pbf_press_button(context, BUTTON_A, 160ms, 1000ms); + pbf_press_dpad(context, DPAD_RIGHT, 2000ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 2000ms, 0ms); state.move_slot = 0; inferred = state_tracker.infer_actual_state(console_index); diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_EnterLobby.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_EnterLobby.cpp index cc56e4d16e..005d389481 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_EnterLobby.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_EnterLobby.cpp @@ -68,7 +68,7 @@ std::shared_ptr enter_lobby( size_t boss_slot, bool connect_to_internet, ReadableQuantity999& ore ){ - pbf_mash_button(context, BUTTON_B, 2 * TICKS_PER_SECOND); + pbf_mash_button(context, BUTTON_B, 2000ms); if (connect_to_internet){ connect_to_internet_with_inference(info, stream, context); @@ -89,7 +89,7 @@ std::shared_ptr enter_lobby( size_t ore_dialog_count = 0; while (presses < 50){ presses++; - pbf_press_button(context, BUTTON_A, 10, TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_A, 160ms, 1000ms); context.wait_for_all_requests(); VideoSnapshot screen = stream.video().snapshot(); @@ -141,7 +141,7 @@ std::shared_ptr enter_lobby( stream.log("Detected save dialog."); context.wait_for_all_requests(); VideoSnapshot entrance = stream.video().snapshot(); - pbf_press_button(context, BUTTON_A, 10, 5 * TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_A, 160ms, 5000ms); context.wait_for_all_requests(); return std::move(entrance.frame); } @@ -151,11 +151,11 @@ std::shared_ptr enter_lobby( stream.log("Detected boss selection."); if (boss_slot > 0){ for (size_t c = 1; c < boss_slot; c++){ - pbf_press_dpad(context, DPAD_DOWN, 10, 50); + pbf_press_dpad(context, DPAD_DOWN, 160ms, 400ms); } - pbf_press_button(context, BUTTON_A, 10, TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_A, 160ms, 1000ms); }else{ - pbf_press_button(context, BUTTON_B, 10, TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_B, 160ms, 1000ms); } } } diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Entrance.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Entrance.cpp index eb3a6bdc9e..a86a977f62 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Entrance.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_Entrance.cpp @@ -39,12 +39,12 @@ void run_entrance( OverlayBoxScope box(stream.overlay(), {0.782, 0.850, 0.030, 0.050}); - pbf_wait(context, 2 * TICKS_PER_SECOND); + pbf_wait(context, 2000ms); while (true){ if (save_path){ - pbf_press_button(context, BUTTON_A, 10, TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_A, 160ms, 1000ms); }else{ - pbf_press_button(context, BUTTON_B, 10, TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_B, 160ms, 1000ms); } context.wait_for_all_requests(); From 248b6b46a9130a2c93751b7daefd9cfce0c1d3b9 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Fri, 24 Oct 2025 19:12:10 -0700 Subject: [PATCH 21/22] Fix off by one. --- .../PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp index 78ac6a7a5a..9609eea57b 100644 --- a/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp +++ b/SerialPrograms/Source/PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.cpp @@ -80,7 +80,7 @@ bool ShinySoundDetectedActionOption::on_shiny_sound( ){ ShinySoundDetectedAction action = ACTION; - if (action == ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY && current_count > 0){ + if (action == ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY && current_count > 1){ return false; } From 2f2134286498ead6de4311f0c236c46ef4bfea56 Mon Sep 17 00:00:00 2001 From: Gin <> Date: Fri, 24 Oct 2025 23:57:35 -0700 Subject: [PATCH 22/22] fix typo --- SerialPrograms/cmake/MacOSXBundleInfo.plist.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SerialPrograms/cmake/MacOSXBundleInfo.plist.in b/SerialPrograms/cmake/MacOSXBundleInfo.plist.in index 3cd45dde73..b23642e29e 100644 --- a/SerialPrograms/cmake/MacOSXBundleInfo.plist.in +++ b/SerialPrograms/cmake/MacOSXBundleInfo.plist.in @@ -31,10 +31,10 @@ NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} NSCameraUsageDescription - The cameras are listed to choose the Switch video stream from the captrue card. + The cameras are listed to choose the Switch video stream from the capture card. NSCameraUseContinuityCameraDeviceType NSMicrophoneUsageDescription - The microphones are listed to choose the Switch audio stream from the captrue card. + The microphones are listed to choose the Switch audio stream from the capture card.