From d8b771eac3b6f655ec142881e2c71d68bb85a7ab Mon Sep 17 00:00:00 2001 From: Butters Date: Mon, 13 Apr 2026 20:47:18 -0500 Subject: [PATCH 1/7] Added day night and weather detection to benchsit Created a day/night detection program that looks for the crecent moon on the minimap. added logic to bench sit to allow the user to only run forward during specifically day/night and specific weather patterns. --- .../PokemonLZA_DayNightStateDetector.cpp | 127 ++++++ .../PokemonLZA_DayNightStateDetector.h | 68 +++ .../PokemonLZA_ShinyHunt_BenchSit.cpp | 406 ++++++++++++++---- .../PokemonLZA_ShinyHunt_BenchSit.h | 15 + .../Resources/crescent_moon_template_v2.png | Bin 0 -> 9153 bytes SerialPrograms/cmake/SourceFiles.cmake | 2 + 6 files changed, 528 insertions(+), 90 deletions(-) create mode 100644 SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp create mode 100644 SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h create mode 100644 SerialPrograms/Source/PokemonLZA/Resources/crescent_moon_template_v2.png diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp new file mode 100644 index 0000000000..8b935f4eb6 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -0,0 +1,127 @@ +#include "CommonFramework/ImageTools/ImageBoxes.h" + +#include "CommonTools/Images/BinaryImage_FilterRgb32.h" + +#include "PokemonLZA_DayNightStateDetector.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +namespace{ + +// minimap crescent icon region (screen relative) +const ImageFloatBox MOON_BOX( + 0.075, + 0.025, + 0.040, + 0.050 + ); + + +// color range of moon icon +const uint32_t MOON_COLOR_MIN = 0xffc0c0c0; +const uint32_t MOON_COLOR_MAX = 0xffffffff; + + +// ratio thresholds (resolution independent) +const double MIN_MOON_RATIO = 0.03; +const double MAX_MOON_RATIO = 0.40; + + +} + + + +DayNightStateDetector::DayNightStateDetector( + Color color, + VideoOverlay* overlay + ) + : StaticScreenDetector() + , m_state(DayNightState::UNKNOWN) +{} + + +void DayNightStateDetector::make_overlays( + VideoOverlaySet& items + ) const{ + + items.add(COLOR_RED, MOON_BOX); + +} + + + +bool DayNightStateDetector::detect( + const ImageViewRGB32& screen + ){ + + ImageViewRGB32 roi = + extract_box_reference( + screen, + MOON_BOX + ); + + + if (!roi){ + + m_state = DayNightState::UNKNOWN; + + return false; + } + + + PackedBinaryMatrix matrix = + compress_rgb32_to_binary_range( + roi, + MOON_COLOR_MIN, + MOON_COLOR_MAX + ); + + + size_t matching_pixels = 0; + + for (size_t y = 0; y < matrix.height(); y++){ + for (size_t x = 0; x < matrix.width(); x++){ + + if (matrix.get(x,y)){ + matching_pixels++; + } + + } + } + + + const double moon_ratio = + (double)matching_pixels / + (double)(matrix.width() * matrix.height()); + + + const bool moon_detected = + moon_ratio >= MIN_MOON_RATIO && + moon_ratio <= MAX_MOON_RATIO; + + + m_state = + moon_detected + ? DayNightState::NIGHT + : DayNightState::DAY; + + + return true; +} + + + +void DayNightStateDetector::reset_state(){ + + m_state = DayNightState::UNKNOWN; + +} + + + +} +} +} \ No newline at end of file diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h new file mode 100644 index 0000000000..5b4de6c042 --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -0,0 +1,68 @@ +/* Day Night State Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLZA_DayNightStateDetector_H +#define PokemonAutomation_PokemonLZA_DayNightStateDetector_H + +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonTools/VisualDetector.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLZA{ + + +enum class DayNightState{ + DAY, + NIGHT, + UNKNOWN +}; + + +// Detect current day/night state by analyzing the minimap +// Returns NIGHT if moon icon is detected at top of minimap +// Returns DAY if minimap is visible but no moon detected +// Returns UNKNOWN if unable to determine +class DayNightStateDetector : public StaticScreenDetector{ +public: + DayNightStateDetector(Color color = COLOR_RED, VideoOverlay* overlay = nullptr); + + virtual void make_overlays(VideoOverlaySet& items) const override; + + // This is not const so that detector can save/cache state. + virtual bool detect(const ImageViewRGB32& screen) override; + + // Get the detected day/night state from the last frame processed + DayNightState get_state() const { return m_state; } + + void reset_state() override; + +private: + DayNightState m_state; +}; + + +class DayNightStateWatcher : public DetectorToFinder{ +public: + DayNightStateWatcher( + Color color = COLOR_RED, + VideoOverlay* overlay = nullptr, + std::chrono::milliseconds hold_duration = std::chrono::milliseconds(100) + ) + : DetectorToFinder("DayNightStateWatcher", hold_duration, color, overlay) + {} + + // Get the detected day/night state + DayNightState get_state() const { return static_cast(this)->get_state(); } +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index aae4ecf654..f6efbb5a44 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -8,6 +8,8 @@ #include "CommonFramework/GlobalSettingsPanel.h" #include "CommonFramework/ProgramStats/StatsTracking.h" #include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/Tools/VideoStream.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" #include "CommonTools/Async/InferenceRoutines.h" #include "CommonTools/StartupChecks/VideoResolutionCheck.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" @@ -16,6 +18,8 @@ #include "Pokemon/Pokemon_Strings.h" #include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" #include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_WeatherDetector.h" #include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" #include "PokemonLZA_ShinyHunt_BenchSit.h" @@ -27,18 +31,16 @@ using namespace Pokemon; - - ShinyHunt_BenchSit_Descriptor::ShinyHunt_BenchSit_Descriptor() : SingleSwitchProgramDescriptor( - "PokemonLZA:ShinyHunt-BenchSit", - STRING_POKEMON + " LZA", "Bench Sit", - "Programs/PokemonLZA/ShinyHunt-BenchSit.html", - "Shiny hunt by repeatedly sitting on a bench to reset spawns.", - ProgramControllerClass::StandardController_NoRestrictions, - FeedbackType::REQUIRED, - AllowCommandsWhenRunning::DISABLE_COMMANDS - ) + "PokemonLZA:ShinyHunt-BenchSit", + STRING_POKEMON + " LZA", "Bench Sit", + "Programs/PokemonLZA/ShinyHunt-BenchSit.html", + "Shiny hunt by repeatedly sitting on a bench to reset spawns.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS + ) {} class ShinyHunt_BenchSit_Descriptor::Stats : public StatsTracker{ public: @@ -65,46 +67,86 @@ std::unique_ptr ShinyHunt_BenchSit_Descriptor::make_stats() const{ - - ShinyHunt_BenchSit::ShinyHunt_BenchSit() : WALK_DIRECTION( - "Run Direction:
The direction of running after each day change to increase the spawn radius.", - { - {0, "forward", "Forward"}, - {1, "left", "Turn Left"}, - {2, "right", "Turn Right"}, - }, - LockMode::UNLOCK_WHILE_RUNNING, - 0 - ) + "Run Direction:
The direction of running after each day change to increase the spawn radius.", + { + {0, "forward", "Forward"}, + {1, "left", "Turn Left"}, + {2, "right", "Turn Right"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + 0 + ) , WALK_FORWARD_DURATION( - "Run Forward Duration
" - "Run forward and backward for this long after each day change to " - "increase the spawn radius. Set to zero to disable this.", - LockMode::UNLOCK_WHILE_RUNNING, - "2000 ms" - ) + "Run Forward Duration
" + "Run forward and backward for this long after each day change to " + "increase the spawn radius. Set to zero to disable this.", + LockMode::UNLOCK_WHILE_RUNNING, + "2000 ms" + ) , PERIODIC_SAVE( - "Periodically Save:
" - "Save the game every this many bench sits. This reduces the loss to game crashes. Set to zero to disable. Saving will be unsuccessful if you are under attack", - LockMode::UNLOCK_WHILE_RUNNING, - 100, - 0 - ) + "Periodically Save:
" + "Save the game every this many bench sits. This reduces the loss to game crashes. Set to zero to disable. Saving will be unsuccessful if you are under attack", + LockMode::UNLOCK_WHILE_RUNNING, + 100, + 0 + ) + , DAY_NIGHT_FILTER( + "Run Only During Day/Night:", + LockMode::UNLOCK_WHILE_RUNNING, + GroupOption::EnableMode::DEFAULT_DISABLED + ) + , FILTER_ENABLED( + "Enable day/night filter", + LockMode::UNLOCK_WHILE_RUNNING, + false + ) + , FILTER_MODE( + "Time filter", + { + {0, "day", "Day"}, + {1, "night", "Night"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + 0 + ) + , WEATHER_FILTER( + "Run Only During Specific Weather:", + LockMode::UNLOCK_WHILE_RUNNING, + GroupOption::EnableMode::DEFAULT_DISABLED + ) + , WEATHER_FILTER_ENABLED( + "Enable weather filter", + LockMode::UNLOCK_WHILE_RUNNING, + false + ) + , WEATHER_FILTER_MODE( + "Weather filter", + { + {0, "clear", "Clear"}, + {1, "sunny", "Sunny"}, + {2, "rain", "Rain"}, + {3, "cloudy", "Cloudy"}, + {4, "foggy", "Foggy"}, + {5, "rainbow", "Rainbow"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + 0 + ) , SHINY_DETECTED( - "Shiny Detected", "", - "2000 ms", - ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY - ) + "Shiny Detected", "", + "2000 ms", + ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY + ) , 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, - }) + &NOTIFICATION_STATUS, + &SHINY_DETECTED.NOTIFICATIONS, + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_RECOVERABLE, + &NOTIFICATION_ERROR_FATAL, + }) { PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); if (PreloadSettings::instance().DEVELOPER_MODE){ @@ -112,6 +154,12 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() } PA_ADD_OPTION(WALK_FORWARD_DURATION); PA_ADD_OPTION(PERIODIC_SAVE); + PA_ADD_OPTION(DAY_NIGHT_FILTER); + DAY_NIGHT_FILTER.add_option(FILTER_ENABLED, "FilterEnabled"); + DAY_NIGHT_FILTER.add_option(FILTER_MODE, "FilterMode"); + PA_ADD_OPTION(WEATHER_FILTER); + WEATHER_FILTER.add_option(WEATHER_FILTER_ENABLED, "WeatherFilterEnabled"); + WEATHER_FILTER.add_option(WEATHER_FILTER_MODE, "WeatherFilterMode"); PA_ADD_OPTION(SHINY_DETECTED); PA_ADD_OPTION(NOTIFICATIONS); } @@ -119,13 +167,13 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() void run_back_until_found_bench( SingleSwitchProgramEnvironment& env, ProControllerContext& context -){ + ){ ButtonWatcher buttonA( COLOR_RED, ButtonType::ButtonA, {0.486, 0.477, 0.115, 0.5}, &env.console.overlay() - ); + ); int ret = run_until( env.console, context, @@ -134,7 +182,6 @@ void run_back_until_found_bench( pbf_move_left_joystick(context, {0, -1}, 800ms, 200ms); pbf_press_button(context, BUTTON_L, 160ms, 160ms); - // Can't just hold it down since sometimes it doesn't register. for (int c = 0; c < 10; c++){ pbf_move_right_joystick(context, {-1, 0}, 800ms, 200ms); pbf_press_button(context, BUTTON_L, 160ms, 0ms); @@ -142,7 +189,7 @@ void run_back_until_found_bench( } }, {buttonA} - ); + ); switch (ret){ case 0: @@ -153,108 +200,287 @@ void run_back_until_found_bench( ErrorReport::SEND_ERROR_REPORT, "run_back_until_found_bench(): Unable to detect bench after multiple attempts.", env.console - ); + ); } } -void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + +bool ShinyHunt_BenchSit::should_run_based_on_day_night(const ImageViewRGB32& frame){ + + if (!DAY_NIGHT_FILTER.enabled() || !FILTER_ENABLED){ + return true; + } + + DayNightStateDetector detector(COLOR_RED); + + if (!detector.detect(frame)){ + return true; + } + + DayNightState current_state = + detector.get_state(); + + int filter_mode = + FILTER_MODE.current_value(); + + if (filter_mode == 0){ + return current_state == DayNightState::DAY; + } + else if (filter_mode == 1){ + return current_state == DayNightState::NIGHT; + } + + return true; +} + + +bool ShinyHunt_BenchSit::should_run_based_on_weather(const ImageViewRGB32& frame){ + + if (!WEATHER_FILTER_ENABLED){ + return true; + } + + int weather_mode = WEATHER_FILTER_MODE.current_value(); + + WeatherIconType weather_type; + + switch (weather_mode){ + case 0: + weather_type = WeatherIconType::Clear; + break; + case 1: + weather_type = WeatherIconType::Sunny; + break; + case 2: + weather_type = WeatherIconType::Rain; + break; + case 3: + weather_type = WeatherIconType::Cloudy; + break; + case 4: + weather_type = WeatherIconType::Foggy; + break; + case 5: + weather_type = WeatherIconType::Rainbow; + break; + default: + return true; + } + + WeatherIconDetector detector(weather_type, nullptr); + + return detector.detect(frame); +} + + +void ShinyHunt_BenchSit::program( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context + ){ assert_16_9_720p_min(env.logger(), env.console); - ShinyHunt_BenchSit_Descriptor::Stats& stats = env.current_stats(); + ShinyHunt_BenchSit_Descriptor::Stats& stats = + env.current_stats(); ShinySoundHandler shiny_sound_handler(SHINY_DETECTED); - PokemonLA::ShinySoundDetector shiny_detector(env.console, [&](float error_coefficient) -> bool{ - // Warning: This callback will be run from a different thread than this function. - stats.shinies++; - env.update_stats(); - env.console.overlay().add_log("Shiny Sound Detected!", COLOR_YELLOW); - return shiny_sound_handler.on_shiny_sound( - env, env.console, - stats.shinies, - error_coefficient + PokemonLA::ShinySoundDetector shiny_detector( + env.console, + [&](float error_coefficient) -> bool{ + + stats.shinies++; + env.update_stats(); + + env.console.overlay().add_log( + "Shiny Sound Detected!", + COLOR_YELLOW + ); + + return shiny_sound_handler.on_shiny_sound( + env, + env.console, + stats.shinies, + error_coefficient + ); + } ); - }); + run_until( - env.console, context, + env.console, + context, + [&](ProControllerContext& context){ + for (uint32_t rounds_since_last_save = 0;; rounds_since_last_save++){ + send_program_status_notification(env, NOTIFICATION_STATUS); + sit_on_bench(env.console, context); + shiny_sound_handler.process_pending(context); + stats.resets++; env.update_stats(); + uint32_t periodic_save = PERIODIC_SAVE; - if (periodic_save != 0 && rounds_since_last_save >= periodic_save){ - bool save_successful = save_game_to_menu(env.console, context); + + if (periodic_save != 0 && + rounds_since_last_save >= periodic_save){ + + bool save_successful = + save_game_to_menu(env.console, context); + pbf_mash_button(context, BUTTON_B, 2000ms); + if (save_successful){ - env.console.overlay().add_log("Game Saved Successfully", COLOR_BLUE); + + env.console.overlay().add_log( + "Game Saved Successfully", + COLOR_BLUE + ); + rounds_since_last_save = 0; + }else{ - env.console.overlay().add_log("Game Save Failed. Will attempt to save after the next reset.", COLOR_RED); + + env.console.overlay().add_log( + "Game Save Failed. Will retry later.", + COLOR_RED + ); } } + + Milliseconds duration = WALK_FORWARD_DURATION; + if (duration > Milliseconds::zero()){ - if (WALK_DIRECTION.current_value() == 0){ // forward + + auto frame = + env.console.video().snapshot(); + + + if (!should_run_based_on_day_night(frame)){ + + env.console.overlay().add_log( + "Skipping move (wrong day/night)", + COLOR_ORANGE + ); + + run_back_until_found_bench(env, context); + + shiny_sound_handler.process_pending(context); + + continue; + } + + + + if (!should_run_based_on_weather(frame)){ + + env.console.overlay().add_log( + "Skipping move (wrong weather)", + COLOR_ORANGE + ); + + run_back_until_found_bench(env, context); + + shiny_sound_handler.process_pending(context); + + continue; + } + + + + if (WALK_DIRECTION.current_value() == 0){ + env.console.overlay().add_log("Move Forward"); - ssf_press_button(context, BUTTON_B, 0ms, 2*duration, 0ms); - pbf_move_left_joystick(context, {0, +1}, duration, 0ms); - // run back - pbf_move_left_joystick(context, {0, -1}, duration + 750ms, 0ms); + + ssf_press_button( + context, + BUTTON_B, + 0ms, + 2*duration, + 0ms + ); + + pbf_move_left_joystick( + context, + {0, +1}, + duration, + 0ms + ); + + pbf_move_left_joystick( + context, + {0, -1}, + duration + 750ms, + 0ms + ); + run_back_until_found_bench(env, context); - }else if (WALK_DIRECTION.current_value() == 1){ // left + } + else if (WALK_DIRECTION.current_value() == 1){ + env.console.overlay().add_log("Move Left"); + ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); - pbf_move_left_joystick(context, {-1, 0}, duration, 0ms); + + pbf_move_left_joystick(context, {-1, 0}, duration, 0ms); + pbf_press_button(context, BUTTON_L, 100ms, 400ms); + ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); + pbf_move_left_joystick(context, {0, -1}, duration, 0ms); - pbf_move_left_joystick(context, {-1, 0}, 100ms, 0ms); - }else if (WALK_DIRECTION.current_value() == 2){ // right + + pbf_move_left_joystick(context, {-1, 0}, 100ms, 0ms); + } + else if (WALK_DIRECTION.current_value() == 2){ + env.console.overlay().add_log("Move Right"); + ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); + pbf_move_left_joystick(context, {+1, 0}, duration, 0ms); + pbf_press_button(context, BUTTON_L, 100ms, 400ms); + ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); + pbf_move_left_joystick(context, {0, -1}, duration, 0ms); + pbf_move_left_joystick(context, {+1, 0}, 100ms, 0ms); } + }else{ + run_back_until_found_bench(env, context); } + shiny_sound_handler.process_pending(context); } + }, {shiny_detector} - ); + ); + - // Shiny sound detected and user requested stopping the program when - // detected shiny sound. shiny_sound_handler.process_pending(context); go_home(env.console, context); - send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); -} - - - - - - - - - - + send_program_finished_notification( + env, + NOTIFICATION_PROGRAM_FINISH + ); +} } } -} +} \ No newline at end of file diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h index 700d1e435b..59a4248b3e 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h @@ -10,10 +10,15 @@ #include "Common/Cpp/Options/EnumDropdownOption.h" #include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/TimeDurationOption.h" +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/GroupOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "CommonFramework/ImageTools/ImageBoxes.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" #include "PokemonLA/Options/PokemonLA_ShinyDetectedAction.h" #include "PokemonLZA/Options/PokemonLZA_ShinyDetectedAction.h" +#include "PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_WeatherDetector.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -38,12 +43,22 @@ class ShinyHunt_BenchSit : public SingleSwitchProgramInstance{ virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; private: + bool should_run_based_on_day_night(const ImageViewRGB32& frame); + bool should_run_based_on_weather(const ImageViewRGB32& frame); PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; IntegerEnumDropdownOption WALK_DIRECTION; MillisecondsOption WALK_FORWARD_DURATION; SimpleIntegerOption PERIODIC_SAVE; + GroupOption DAY_NIGHT_FILTER; + BooleanCheckBoxOption FILTER_ENABLED; + IntegerEnumDropdownOption FILTER_MODE; + + GroupOption WEATHER_FILTER; + BooleanCheckBoxOption WEATHER_FILTER_ENABLED; + IntegerEnumDropdownOption WEATHER_FILTER_MODE; + ShinySoundDetectedActionOption SHINY_DETECTED; EventNotificationOption NOTIFICATION_STATUS; diff --git a/SerialPrograms/Source/PokemonLZA/Resources/crescent_moon_template_v2.png b/SerialPrograms/Source/PokemonLZA/Resources/crescent_moon_template_v2.png new file mode 100644 index 0000000000000000000000000000000000000000..36c7bc7d5d2b41c4fbc884063bb97d0ccfb4c4c4 GIT binary patch literal 9153 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

d%TNA$SW{N;P8;KZe1f@-$KSv03 z6rONJ#Gg3o)fen_Vs9CxZ>ffsQd(crVary!zh|Cb|7K>Sl$VmT8TP@*2u_5e1rWS= zyg8&m(CATVGL+z!p=XD8g7~I@*Z1W9U!DAO0*XT)P5{_LQWt5@x7Rv?cSMEYjo<|@ zLJ(=)2-Q(iFVP%jTHXOA&iWsTz_aU5t`t#ZaMw$Itd4T3NOBappE`kpYX za9Ob0&ILZM*8ZMJ|I7LFxcNc|jbtC4(ac&qTAEP>sHIR!!OZBoNcjBkK1a-mArM5+ zs?<_YGeV5`zT^DjDgCO)d;c)Fd$f_(+GbEgSQc&QaskKiw&m4^qE)CxnN#NA61$o? zpaeXlRbJ+M*46X0-|(UHi;;!(=`(y-v!P9|9e^=9@+wfHp*o{E6Y+T3p{Jsy4HvuS zrDpoz1dsHHg>%Y-(e-$ws{;1kW>_<{p?DwY`vDQ5)j-y=I%c8_biQY{M9vxWM)VOx z$#ZFK9bAhHYb_B)TKje}Y)ePS{Pq7upM0}(sSl5Z4?p@C)%uVC&8+b;)h17wayZP~ zT;DScE1sO65~4@7P^{u&V2BZES`jLSi6OH1;gU;;?er{4 z@D6uG5qog52X8c*(jzAC`RA{93*FNbFhRs2;vS4xOKVE0Ru1EVx6__-eMRm(XXhvQ z=%}i#8t_f_H*~3VjvR9_stL6k)m-D9(cy={ijGYe8EAPjx`10f<$Cp+&tG4XeV{)* z<)6fXL4@^U$O(8w;m75Mw};o1>5{?rtbL+$6<-X&(RCgVl-efef?sCg?bzRuB?Z|M zO^>6$L(V+CILCXBsys~iJ+Llm3qBe$U`Q!#wx|le2%V1% z($N!GMz1JN(32H*w&CsTOaA<`AG6(0=(m28Z(ck{L!=GD1SSc*)S0XClB*ezQ=VM} zYH6b;Qfj023*b3DhOayt^1aRfmCF1dW=OQu?Dwzc7+JWT7HuLj0i0(xxVOp;6~l8y(AMrzT(Sw_nhcGCnu5qU{tN7IuR8*BH$MaBbXckhKC~J z*gTVeq&b6k0q+*IMr}EtWDg9iNnwI_j$yS12h+IcezzxFUgCr2$$1NN7SNCff@BYO zq3f__UXWQeb41I@{_wu!ghl`JLR%Y?9znkOz0hDaC~;S;quEp|LNTq@`|bn09eWV( zA0hm84H?_FF*G6|%Z~6+G8)Fv4b)mNt8DvIx}oE6xMz15xw^R}_C04^e5@%RzDMXW zW6V|?@br#=CmlT3x0!K#$Nn1J+_UyisiCReU4+%e3AOi(Z?E~{=7w>9gY{d=Vdiju z&qR-{de$dTxG9M@hc|q#JK{QUZXTBkHDxLhClT{usmz6nP^ATUFxue$lAj(+-+zc9 zJO9f;xER5kVAjM@@eb$1(k_55tT89#l9;P0sHUhc-^(P&{8=%fdA~FI zi#5-;AGKlqt^@Cwbi~Ty3ECQWZUynhmhF>BFGlGj<2q2Bk!mIvLxT{{w`iUC(U&i| zc>015o#3wagx+I0u`5Q5fklW~)GHyFw6g|gge4L)Zb9{5|Mvd^nhZ~<*UC7+00000 LNkvXXu0mjfaLC1l literal 0 HcmV?d00001 diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 2479d90f97..cd2f399246 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1781,6 +1781,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonLZA/Inference/PokemonLZA_ButtonDetector.h Source/PokemonLZA/Inference/PokemonLZA_DayNightChangeDetector.cpp Source/PokemonLZA/Inference/PokemonLZA_DayNightChangeDetector.h + Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp + Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.cpp Source/PokemonLZA/Inference/PokemonLZA_DialogDetector.h Source/PokemonLZA/Inference/PokemonLZA_HyperspaceRewardNameReader.cpp From 5da06eeb1913b888e3363bc5611034b55ce79ae8 Mon Sep 17 00:00:00 2001 From: Butters Date: Mon, 13 Apr 2026 21:32:16 -0500 Subject: [PATCH 2/7] updated formatting and locks updated the window formatting and locked the filters while running because I don't want them to break somehow. --- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 258 +++++++----------- .../PokemonLZA_ShinyHunt_BenchSit.h | 2 - 2 files changed, 92 insertions(+), 168 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index f6efbb5a44..c443962362 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -8,7 +8,6 @@ #include "CommonFramework/GlobalSettingsPanel.h" #include "CommonFramework/ProgramStats/StatsTracking.h" #include "CommonFramework/Notifications/ProgramNotifications.h" -#include "CommonFramework/Tools/VideoStream.h" #include "CommonFramework/VideoPipeline/VideoFeed.h" #include "CommonTools/Async/InferenceRoutines.h" #include "CommonTools/StartupChecks/VideoResolutionCheck.h" @@ -17,9 +16,9 @@ #include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" #include "Pokemon/Pokemon_Strings.h" #include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.h" -#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" #include "PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h" #include "PokemonLZA/Inference/PokemonLZA_WeatherDetector.h" +#include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" #include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" #include "PokemonLZA_ShinyHunt_BenchSit.h" @@ -31,6 +30,8 @@ using namespace Pokemon; + + ShinyHunt_BenchSit_Descriptor::ShinyHunt_BenchSit_Descriptor() : SingleSwitchProgramDescriptor( "PokemonLZA:ShinyHunt-BenchSit", @@ -67,6 +68,8 @@ std::unique_ptr ShinyHunt_BenchSit_Descriptor::make_stats() const{ + + ShinyHunt_BenchSit::ShinyHunt_BenchSit() : WALK_DIRECTION( "Run Direction:
The direction of running after each day change to increase the spawn radius.", @@ -94,33 +97,26 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() ) , DAY_NIGHT_FILTER( "Run Only During Day/Night:", - LockMode::UNLOCK_WHILE_RUNNING, + LockMode::LOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) - , FILTER_ENABLED( - "Enable day/night filter", - LockMode::UNLOCK_WHILE_RUNNING, - false - ) + , FILTER_MODE( "Time filter", { {0, "day", "Day"}, {1, "night", "Night"}, }, - LockMode::UNLOCK_WHILE_RUNNING, + LockMode::LOCK_WHILE_RUNNING, 0 ) + , WEATHER_FILTER( "Run Only During Specific Weather:", - LockMode::UNLOCK_WHILE_RUNNING, + LockMode::LOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) - , WEATHER_FILTER_ENABLED( - "Enable weather filter", - LockMode::UNLOCK_WHILE_RUNNING, - false - ) + , WEATHER_FILTER_MODE( "Weather filter", { @@ -131,9 +127,10 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() {4, "foggy", "Foggy"}, {5, "rainbow", "Rainbow"}, }, - LockMode::UNLOCK_WHILE_RUNNING, + LockMode::LOCK_WHILE_RUNNING, 0 ) + , SHINY_DETECTED( "Shiny Detected", "", "2000 ms", @@ -155,10 +152,9 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() PA_ADD_OPTION(WALK_FORWARD_DURATION); PA_ADD_OPTION(PERIODIC_SAVE); PA_ADD_OPTION(DAY_NIGHT_FILTER); - DAY_NIGHT_FILTER.add_option(FILTER_ENABLED, "FilterEnabled"); DAY_NIGHT_FILTER.add_option(FILTER_MODE, "FilterMode"); + PA_ADD_OPTION(WEATHER_FILTER); - WEATHER_FILTER.add_option(WEATHER_FILTER_ENABLED, "WeatherFilterEnabled"); WEATHER_FILTER.add_option(WEATHER_FILTER_MODE, "WeatherFilterMode"); PA_ADD_OPTION(SHINY_DETECTED); PA_ADD_OPTION(NOTIFICATIONS); @@ -182,6 +178,7 @@ void run_back_until_found_bench( pbf_move_left_joystick(context, {0, -1}, 800ms, 200ms); pbf_press_button(context, BUTTON_L, 160ms, 160ms); + // Can't just hold it down since sometimes it doesn't register. for (int c = 0; c < 10; c++){ pbf_move_right_joystick(context, {-1, 0}, 800ms, 200ms); pbf_press_button(context, BUTTON_L, 160ms, 0ms); @@ -204,14 +201,15 @@ void run_back_until_found_bench( } } +bool ShinyHunt_BenchSit::should_run_based_on_day_night( + const ImageViewRGB32& frame + ){ -bool ShinyHunt_BenchSit::should_run_based_on_day_night(const ImageViewRGB32& frame){ - - if (!DAY_NIGHT_FILTER.enabled() || !FILTER_ENABLED){ + if (!DAY_NIGHT_FILTER.enabled()){ return true; } - DayNightStateDetector detector(COLOR_RED); + DayNightStateDetector detector(COLOR_RED, nullptr); if (!detector.detect(frame)){ return true; @@ -220,7 +218,7 @@ bool ShinyHunt_BenchSit::should_run_based_on_day_night(const ImageViewRGB32& fra DayNightState current_state = detector.get_state(); - int filter_mode = + size_t filter_mode = FILTER_MODE.current_value(); if (filter_mode == 0){ @@ -236,33 +234,41 @@ bool ShinyHunt_BenchSit::should_run_based_on_day_night(const ImageViewRGB32& fra bool ShinyHunt_BenchSit::should_run_based_on_weather(const ImageViewRGB32& frame){ - if (!WEATHER_FILTER_ENABLED){ + if (!WEATHER_FILTER.enabled()){ return true; } - int weather_mode = WEATHER_FILTER_MODE.current_value(); + size_t weather_mode = + WEATHER_FILTER_MODE.current_value(); WeatherIconType weather_type; switch (weather_mode){ + case 0: weather_type = WeatherIconType::Clear; break; + case 1: weather_type = WeatherIconType::Sunny; break; + case 2: weather_type = WeatherIconType::Rain; break; + case 3: weather_type = WeatherIconType::Cloudy; break; + case 4: weather_type = WeatherIconType::Foggy; break; + case 5: weather_type = WeatherIconType::Rainbow; break; + default: return true; } @@ -272,215 +278,135 @@ bool ShinyHunt_BenchSit::should_run_based_on_weather(const ImageViewRGB32& frame return detector.detect(frame); } - -void ShinyHunt_BenchSit::program( - SingleSwitchProgramEnvironment& env, - ProControllerContext& context - ){ +void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ assert_16_9_720p_min(env.logger(), env.console); - ShinyHunt_BenchSit_Descriptor::Stats& stats = - env.current_stats(); + ShinyHunt_BenchSit_Descriptor::Stats& stats = env.current_stats(); ShinySoundHandler shiny_sound_handler(SHINY_DETECTED); - PokemonLA::ShinySoundDetector shiny_detector( - env.console, - [&](float error_coefficient) -> bool{ - - stats.shinies++; - env.update_stats(); - - env.console.overlay().add_log( - "Shiny Sound Detected!", - COLOR_YELLOW - ); - - return shiny_sound_handler.on_shiny_sound( - env, - env.console, - stats.shinies, - error_coefficient - ); - } - ); - + PokemonLA::ShinySoundDetector shiny_detector(env.console, [&](float error_coefficient) -> bool{ + // Warning: This callback will be run from a different thread than this function. + stats.shinies++; + env.update_stats(); + env.console.overlay().add_log("Shiny Sound Detected!", COLOR_YELLOW); + return shiny_sound_handler.on_shiny_sound( + env, env.console, + stats.shinies, + error_coefficient + ); + }); run_until( - env.console, - context, - + env.console, context, [&](ProControllerContext& context){ - for (uint32_t rounds_since_last_save = 0;; rounds_since_last_save++){ - send_program_status_notification(env, NOTIFICATION_STATUS); - sit_on_bench(env.console, context); - shiny_sound_handler.process_pending(context); - stats.resets++; env.update_stats(); - uint32_t periodic_save = PERIODIC_SAVE; - - if (periodic_save != 0 && - rounds_since_last_save >= periodic_save){ - - bool save_successful = - save_game_to_menu(env.console, context); - + if (periodic_save != 0 && rounds_since_last_save >= periodic_save){ + bool save_successful = save_game_to_menu(env.console, context); pbf_mash_button(context, BUTTON_B, 2000ms); - if (save_successful){ - - env.console.overlay().add_log( - "Game Saved Successfully", - COLOR_BLUE - ); - + env.console.overlay().add_log("Game Saved Successfully", COLOR_BLUE); rounds_since_last_save = 0; - }else{ - - env.console.overlay().add_log( - "Game Save Failed. Will retry later.", - COLOR_RED - ); + env.console.overlay().add_log("Game Save Failed. Will attempt to save after the next reset.", COLOR_RED); } } - - Milliseconds duration = WALK_FORWARD_DURATION; + auto frame = env.console.video().snapshot(); - if (duration > Milliseconds::zero()){ - - auto frame = - env.console.video().snapshot(); - - - if (!should_run_based_on_day_night(frame)){ - - env.console.overlay().add_log( - "Skipping move (wrong day/night)", - COLOR_ORANGE - ); - - run_back_until_found_bench(env, context); - - shiny_sound_handler.process_pending(context); - - continue; - } + if (!should_run_based_on_day_night(frame)){ + env.console.overlay().add_log( + "Skipping move (wrong day/night)", + COLOR_ORANGE + ); + run_back_until_found_bench(env, context); - if (!should_run_based_on_weather(frame)){ + shiny_sound_handler.process_pending(context); - env.console.overlay().add_log( - "Skipping move (wrong weather)", - COLOR_ORANGE - ); + continue; + } - run_back_until_found_bench(env, context); - shiny_sound_handler.process_pending(context); + if (!should_run_based_on_weather(frame)){ - continue; - } + env.console.overlay().add_log( + "Skipping move (wrong weather)", + COLOR_ORANGE + ); + run_back_until_found_bench(env, context); + shiny_sound_handler.process_pending(context); - if (WALK_DIRECTION.current_value() == 0){ + continue; + } + if (duration > Milliseconds::zero()){ + if (WALK_DIRECTION.current_value() == 0){ // forward env.console.overlay().add_log("Move Forward"); - - ssf_press_button( - context, - BUTTON_B, - 0ms, - 2*duration, - 0ms - ); - - pbf_move_left_joystick( - context, - {0, +1}, - duration, - 0ms - ); - - pbf_move_left_joystick( - context, - {0, -1}, - duration + 750ms, - 0ms - ); - + ssf_press_button(context, BUTTON_B, 0ms, 2*duration, 0ms); + pbf_move_left_joystick(context, {0, +1}, duration, 0ms); + // run back + pbf_move_left_joystick(context, {0, -1}, duration + 750ms, 0ms); run_back_until_found_bench(env, context); - } - else if (WALK_DIRECTION.current_value() == 1){ - + }else if (WALK_DIRECTION.current_value() == 1){ // left env.console.overlay().add_log("Move Left"); - ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); - - pbf_move_left_joystick(context, {-1, 0}, duration, 0ms); - + pbf_move_left_joystick(context, {-1, 0}, duration, 0ms); pbf_press_button(context, BUTTON_L, 100ms, 400ms); - ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); - pbf_move_left_joystick(context, {0, -1}, duration, 0ms); - - pbf_move_left_joystick(context, {-1, 0}, 100ms, 0ms); - } - else if (WALK_DIRECTION.current_value() == 2){ - + pbf_move_left_joystick(context, {-1, 0}, 100ms, 0ms); + }else if (WALK_DIRECTION.current_value() == 2){ // right env.console.overlay().add_log("Move Right"); - ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); - pbf_move_left_joystick(context, {+1, 0}, duration, 0ms); - pbf_press_button(context, BUTTON_L, 100ms, 400ms); - ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); - pbf_move_left_joystick(context, {0, -1}, duration, 0ms); - pbf_move_left_joystick(context, {+1, 0}, 100ms, 0ms); } - }else{ - run_back_until_found_bench(env, context); } - shiny_sound_handler.process_pending(context); } - }, {shiny_detector} ); - + // Shiny sound detected and user requested stopping the program when + // detected shiny sound. shiny_sound_handler.process_pending(context); go_home(env.console, context); - - send_program_finished_notification( - env, - NOTIFICATION_PROGRAM_FINISH - ); + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); } + + + + + + + + + + + } } } \ No newline at end of file diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h index 59a4248b3e..ebf6fb0dcf 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h @@ -52,11 +52,9 @@ class ShinyHunt_BenchSit : public SingleSwitchProgramInstance{ SimpleIntegerOption PERIODIC_SAVE; GroupOption DAY_NIGHT_FILTER; - BooleanCheckBoxOption FILTER_ENABLED; IntegerEnumDropdownOption FILTER_MODE; GroupOption WEATHER_FILTER; - BooleanCheckBoxOption WEATHER_FILTER_ENABLED; IntegerEnumDropdownOption WEATHER_FILTER_MODE; ShinySoundDetectedActionOption SHINY_DETECTED; From 0753ee80b728e1f267236849be83b59c204bc9b5 Mon Sep 17 00:00:00 2001 From: Butters Date: Tue, 14 Apr 2026 19:46:16 -0500 Subject: [PATCH 3/7] changed the detector updated the detector to detect the color change on the left side of the main map. the color is dependent on the day night cycle. updated bench sit to use both weather and day/night detection to improve shiny farming rates of different pokemon. --- .../PokemonLZA_DayNightStateDetector.cpp | 126 ++++-------------- .../PokemonLZA_DayNightStateDetector.h | 50 ++----- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 65 ++++----- 3 files changed, 65 insertions(+), 176 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp index 8b935f4eb6..e2c2f16736 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -1,127 +1,53 @@ -#include "CommonFramework/ImageTools/ImageBoxes.h" - -#include "CommonTools/Images/BinaryImage_FilterRgb32.h" - #include "PokemonLZA_DayNightStateDetector.h" +#include "CommonFramework/ImageTools/ImageStats.h" + namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonLZA{ - -namespace{ - -// minimap crescent icon region (screen relative) -const ImageFloatBox MOON_BOX( - 0.075, - 0.025, - 0.040, - 0.050 - ); - - -// color range of moon icon -const uint32_t MOON_COLOR_MIN = 0xffc0c0c0; -const uint32_t MOON_COLOR_MAX = 0xffffffff; - - -// ratio thresholds (resolution independent) -const double MIN_MOON_RATIO = 0.03; -const double MAX_MOON_RATIO = 0.40; - - -} - - - -DayNightStateDetector::DayNightStateDetector( - Color color, - VideoOverlay* overlay - ) - : StaticScreenDetector() - , m_state(DayNightState::UNKNOWN) +DayNightStateDetector::DayNightStateDetector() + : + m_box(0.40, 0.80, 0.45, 0.45), + m_state(DayNightState::DAY) {} -void DayNightStateDetector::make_overlays( - VideoOverlaySet& items - ) const{ - - items.add(COLOR_RED, MOON_BOX); - +void DayNightStateDetector::make_overlays(VideoOverlaySet& items) const{ + items.add(COLOR_GREEN, m_box); } +bool DayNightStateDetector::detect(const ImageViewRGB32& screen){ + ImageStats stats = + image_stats(extract_box_reference(screen, m_box)); -bool DayNightStateDetector::detect( - const ImageViewRGB32& screen - ){ + double r = stats.average.r; + double g = stats.average.g; + double b = stats.average.b; - ImageViewRGB32 roi = - extract_box_reference( - screen, - MOON_BOX - ); + double luminance = + 0.299*r + + 0.587*g + + 0.114*b; - if (!roi){ + bool night_color = + r < 120 && + b > 70 && + luminance < 140; - m_state = DayNightState::UNKNOWN; - return false; + if (night_color){ + m_state = DayNightState::NIGHT; } - - - PackedBinaryMatrix matrix = - compress_rgb32_to_binary_range( - roi, - MOON_COLOR_MIN, - MOON_COLOR_MAX - ); - - - size_t matching_pixels = 0; - - for (size_t y = 0; y < matrix.height(); y++){ - for (size_t x = 0; x < matrix.width(); x++){ - - if (matrix.get(x,y)){ - matching_pixels++; - } - - } + else{ + m_state = DayNightState::DAY; } - - const double moon_ratio = - (double)matching_pixels / - (double)(matrix.width() * matrix.height()); - - - const bool moon_detected = - moon_ratio >= MIN_MOON_RATIO && - moon_ratio <= MAX_MOON_RATIO; - - - m_state = - moon_detected - ? DayNightState::NIGHT - : DayNightState::DAY; - - return true; } - - -void DayNightStateDetector::reset_state(){ - - m_state = DayNightState::UNKNOWN; - -} - - - } } } \ No newline at end of file diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h index 5b4de6c042..ce5bdd15fe 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -1,11 +1,6 @@ -/* Day Night State Detector - * - * From: https://github.com/PokemonAutomation/ - * - */ +#pragma once -#ifndef PokemonAutomation_PokemonLZA_DayNightStateDetector_H -#define PokemonAutomation_PokemonLZA_DayNightStateDetector_H +#include #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" @@ -15,54 +10,33 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonLZA{ - enum class DayNightState{ DAY, - NIGHT, - UNKNOWN + NIGHT }; - -// Detect current day/night state by analyzing the minimap -// Returns NIGHT if moon icon is detected at top of minimap -// Returns DAY if minimap is visible but no moon detected -// Returns UNKNOWN if unable to determine class DayNightStateDetector : public StaticScreenDetector{ public: - DayNightStateDetector(Color color = COLOR_RED, VideoOverlay* overlay = nullptr); + DayNightStateDetector(); virtual void make_overlays(VideoOverlaySet& items) const override; - // This is not const so that detector can save/cache state. virtual bool detect(const ImageViewRGB32& screen) override; - // Get the detected day/night state from the last frame processed - DayNightState get_state() const { return m_state; } - - void reset_state() override; + DayNightState state() const{ + return m_state; + } private: - DayNightState m_state; -}; + ImageFloatBox m_box; -class DayNightStateWatcher : public DetectorToFinder{ -public: - DayNightStateWatcher( - Color color = COLOR_RED, - VideoOverlay* overlay = nullptr, - std::chrono::milliseconds hold_duration = std::chrono::milliseconds(100) - ) - : DetectorToFinder("DayNightStateWatcher", hold_duration, color, overlay) - {} + DayNightState m_state; - // Get the detected day/night state - DayNightState get_state() const { return static_cast(this)->get_state(); } + // persistent overlay box (WeatherDetector style) + mutable std::optional m_overlay; }; - - -} } } -#endif +} \ No newline at end of file diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index c443962362..dbc331f7ce 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -96,7 +96,7 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() 0 ) , DAY_NIGHT_FILTER( - "Run Only During Day/Night:", + "Run Forward Only During Day/Night:", LockMode::LOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) @@ -112,7 +112,7 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() ) , WEATHER_FILTER( - "Run Only During Specific Weather:", + "Run Forward Only During Specific Weather:", LockMode::LOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) @@ -204,22 +204,19 @@ void run_back_until_found_bench( bool ShinyHunt_BenchSit::should_run_based_on_day_night( const ImageViewRGB32& frame ){ - if (!DAY_NIGHT_FILTER.enabled()){ return true; } - DayNightStateDetector detector(COLOR_RED, nullptr); + DayNightStateDetector detector; if (!detector.detect(frame)){ return true; } - DayNightState current_state = - detector.get_state(); + DayNightState current_state = detector.state(); - size_t filter_mode = - FILTER_MODE.current_value(); + size_t filter_mode = FILTER_MODE.current_value(); if (filter_mode == 0){ return current_state == DayNightState::DAY; @@ -232,48 +229,31 @@ bool ShinyHunt_BenchSit::should_run_based_on_day_night( } -bool ShinyHunt_BenchSit::should_run_based_on_weather(const ImageViewRGB32& frame){ - +bool ShinyHunt_BenchSit::should_run_based_on_weather( + const ImageViewRGB32& frame + ){ if (!WEATHER_FILTER.enabled()){ return true; } - size_t weather_mode = - WEATHER_FILTER_MODE.current_value(); + size_t weather_mode = WEATHER_FILTER_MODE.current_value(); WeatherIconType weather_type; switch (weather_mode){ - case 0: - weather_type = WeatherIconType::Clear; - break; - - case 1: - weather_type = WeatherIconType::Sunny; - break; - - case 2: - weather_type = WeatherIconType::Rain; - break; - - case 3: - weather_type = WeatherIconType::Cloudy; - break; - - case 4: - weather_type = WeatherIconType::Foggy; - break; - - case 5: - weather_type = WeatherIconType::Rainbow; - break; + case 0: weather_type = WeatherIconType::Clear; break; + case 1: weather_type = WeatherIconType::Sunny; break; + case 2: weather_type = WeatherIconType::Rain; break; + case 3: weather_type = WeatherIconType::Cloudy; break; + case 4: weather_type = WeatherIconType::Foggy; break; + case 5: weather_type = WeatherIconType::Rainbow; break; default: return true; } - WeatherIconDetector detector(weather_type, nullptr); + WeatherIconDetector detector(weather_type); return detector.detect(frame); } @@ -320,7 +300,17 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl } Milliseconds duration = WALK_FORWARD_DURATION; - auto frame = env.console.video().snapshot(); + + + open_map(env.console, context, false, true); + + ImageViewRGB32 frame = + env.console.video().snapshot(); + + context.wait_for_all_requests(); + + pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); + if (!should_run_based_on_day_night(frame)){ @@ -336,7 +326,6 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl continue; } - if (!should_run_based_on_weather(frame)){ env.console.overlay().add_log( From 6e8eb3823e21341557b69132fdf26f2e80975fd0 Mon Sep 17 00:00:00 2001 From: Butters Date: Tue, 14 Apr 2026 22:33:05 -0500 Subject: [PATCH 4/7] memory issue fix my initial commits had a memory issue. these changes fix that. --- .../PokemonLZA_DayNightStateDetector.cpp | 18 ++++++++++++++---- .../PokemonLZA_DayNightStateDetector.h | 15 ++++++++------- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 7 ++++--- .../PokemonLZA_ShinyHunt_BenchSit.h | 2 +- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp index e2c2f16736..5e6309e226 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -6,11 +6,19 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonLZA{ -DayNightStateDetector::DayNightStateDetector() +DayNightStateDetector::DayNightStateDetector(VideoOverlay* overlay) : - m_box(0.40, 0.80, 0.45, 0.45), + m_box(0.10, 0.75, 0.32, 0.22), m_state(DayNightState::DAY) -{} +{ + if (overlay){ + m_overlay.emplace( + *overlay, + m_box, + COLOR_YELLOW + ); + } +} void DayNightStateDetector::make_overlays(VideoOverlaySet& items) const{ @@ -47,7 +55,9 @@ bool DayNightStateDetector::detect(const ImageViewRGB32& screen){ return true; } - +DayNightState DayNightStateDetector::state() const{ + return m_state; +} } } } \ No newline at end of file diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h index ce5bdd15fe..9c9e048f9c 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -1,7 +1,7 @@ #pragma once #include - +#include "Common/Cpp/Color.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" #include "CommonTools/VisualDetector.h" @@ -10,22 +10,23 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonLZA{ + enum class DayNightState{ DAY, NIGHT }; + class DayNightStateDetector : public StaticScreenDetector{ public: - DayNightStateDetector(); + + DayNightStateDetector(VideoOverlay* overlay = nullptr); virtual void make_overlays(VideoOverlaySet& items) const override; virtual bool detect(const ImageViewRGB32& screen) override; - DayNightState state() const{ - return m_state; - } + DayNightState state() const; private: @@ -33,10 +34,10 @@ class DayNightStateDetector : public StaticScreenDetector{ DayNightState m_state; - // persistent overlay box (WeatherDetector style) - mutable std::optional m_overlay; + std::optional m_overlay; }; + } } } \ No newline at end of file diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index dbc331f7ce..29d38a8359 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -202,13 +202,14 @@ void run_back_until_found_bench( } bool ShinyHunt_BenchSit::should_run_based_on_day_night( - const ImageViewRGB32& frame + const ImageViewRGB32& frame, + VideoOverlay& overlay ){ if (!DAY_NIGHT_FILTER.enabled()){ return true; } - DayNightStateDetector detector; + DayNightStateDetector detector(&overlay); if (!detector.detect(frame)){ return true; @@ -312,7 +313,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); - if (!should_run_based_on_day_night(frame)){ + if (!should_run_based_on_day_night(frame, env.console.overlay())){ env.console.overlay().add_log( "Skipping move (wrong day/night)", diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h index ebf6fb0dcf..782248bcba 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h @@ -43,7 +43,7 @@ class ShinyHunt_BenchSit : public SingleSwitchProgramInstance{ virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; private: - bool should_run_based_on_day_night(const ImageViewRGB32& frame); + bool should_run_based_on_day_night(const ImageViewRGB32& frame, VideoOverlay& overlay); bool should_run_based_on_weather(const ImageViewRGB32& frame); PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; From 6118aecc387cb3f7214af90c7193842df28b1541 Mon Sep 17 00:00:00 2001 From: Butters Date: Wed, 15 Apr 2026 16:58:55 -0500 Subject: [PATCH 5/7] deleted a png, updated the detector, and fixed formatting Copied and pasted the original benchsit programs to the local repo to try to fix formatting. will confirm with diff on github. updated the detector to more clearly define day vs night added to the open menu portion of the detection functions a push left all the way so that the detector accurately detects the color of the border and doesn't get a false positive day or night. made the detector square persistent for testing purposes. --- .../PokemonLZA_DayNightStateDetector.cpp | 24 +-- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 148 +++++++----------- .../PokemonLZA_ShinyHunt_BenchSit.h | 1 + .../Resources/crescent_moon_template_v2.png | Bin 9153 -> 0 bytes 4 files changed, 73 insertions(+), 100 deletions(-) delete mode 100644 SerialPrograms/Source/PokemonLZA/Resources/crescent_moon_template_v2.png diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp index 5e6309e226..81fc159cc2 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -1,5 +1,5 @@ #include "PokemonLZA_DayNightStateDetector.h" - +#include "CommonFramework/Globals.h" #include "CommonFramework/ImageTools/ImageStats.h" namespace PokemonAutomation{ @@ -8,15 +8,11 @@ namespace PokemonLZA{ DayNightStateDetector::DayNightStateDetector(VideoOverlay* overlay) : - m_box(0.10, 0.75, 0.32, 0.22), + m_box(0.02, 0.50, 0.08, 0.10), m_state(DayNightState::DAY) { if (overlay){ - m_overlay.emplace( - *overlay, - m_box, - COLOR_YELLOW - ); + m_overlay.emplace(*overlay, m_box, COLOR_YELLOW); } } @@ -42,17 +38,21 @@ bool DayNightStateDetector::detect(const ImageViewRGB32& screen){ bool night_color = r < 120 && - b > 70 && - luminance < 140; + b > 50 && + luminance < 100; + bool day_color = + r > 100 && r < 180 && + g > 140 && + b > 160 && + luminance > 140; - if (night_color){ + if (night_color) { m_state = DayNightState::NIGHT; } - else{ + else if (day_color) { m_state = DayNightState::DAY; } - return true; } DayNightState DayNightStateDetector::state() const{ diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 29d38a8359..76aed09499 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -20,6 +20,8 @@ #include "PokemonLZA/Inference/PokemonLZA_WeatherDetector.h" #include "PokemonLZA/Inference/PokemonLZA_ButtonDetector.h" #include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" +#include "PokemonLZA/Programs/PokemonLZA_FastTravelNavigation.h" +#include "PokemonLZA/Resources/PokemonLZA_Locations.h" #include "PokemonLZA_ShinyHunt_BenchSit.h" namespace PokemonAutomation{ @@ -34,14 +36,14 @@ using namespace Pokemon; ShinyHunt_BenchSit_Descriptor::ShinyHunt_BenchSit_Descriptor() : SingleSwitchProgramDescriptor( - "PokemonLZA:ShinyHunt-BenchSit", - STRING_POKEMON + " LZA", "Bench Sit", - "Programs/PokemonLZA/ShinyHunt-BenchSit.html", - "Shiny hunt by repeatedly sitting on a bench to reset spawns.", - ProgramControllerClass::StandardController_NoRestrictions, - FeedbackType::REQUIRED, - AllowCommandsWhenRunning::DISABLE_COMMANDS - ) + "PokemonLZA:ShinyHunt-BenchSit", + STRING_POKEMON + " LZA", "Bench Sit", + "Programs/PokemonLZA/ShinyHunt-BenchSit.html", + "Shiny hunt by repeatedly sitting on a bench to reset spawns.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS + ) {} class ShinyHunt_BenchSit_Descriptor::Stats : public StatsTracker{ public: @@ -72,35 +74,34 @@ std::unique_ptr ShinyHunt_BenchSit_Descriptor::make_stats() const{ ShinyHunt_BenchSit::ShinyHunt_BenchSit() : WALK_DIRECTION( - "Run Direction:
The direction of running after each day change to increase the spawn radius.", - { - {0, "forward", "Forward"}, - {1, "left", "Turn Left"}, - {2, "right", "Turn Right"}, - }, - LockMode::UNLOCK_WHILE_RUNNING, - 0 - ) + "Run Direction:
The direction of running after each day change to increase the spawn radius.", + { + {0, "forward", "Forward"}, + {1, "left", "Turn Left"}, + {2, "right", "Turn Right"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + 0 + ) , WALK_FORWARD_DURATION( - "Run Forward Duration
" - "Run forward and backward for this long after each day change to " - "increase the spawn radius. Set to zero to disable this.", - LockMode::UNLOCK_WHILE_RUNNING, - "2000 ms" - ) + "Run Forward Duration
" + "Run forward and backward for this long after each day change to " + "increase the spawn radius. Set to zero to disable this.", + LockMode::UNLOCK_WHILE_RUNNING, + "2000 ms" + ) , PERIODIC_SAVE( - "Periodically Save:
" - "Save the game every this many bench sits. This reduces the loss to game crashes. Set to zero to disable. Saving will be unsuccessful if you are under attack", - LockMode::UNLOCK_WHILE_RUNNING, - 100, - 0 - ) + "Periodically Save:
" + "Save the game every this many bench sits. This reduces the loss to game crashes. Set to zero to disable. Saving will be unsuccessful if you are under attack", + LockMode::UNLOCK_WHILE_RUNNING, + 100, + 0 + ) , DAY_NIGHT_FILTER( "Run Forward Only During Day/Night:", LockMode::LOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) - , FILTER_MODE( "Time filter", { @@ -110,13 +111,11 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() LockMode::LOCK_WHILE_RUNNING, 0 ) - , WEATHER_FILTER( "Run Forward Only During Specific Weather:", LockMode::LOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) - , WEATHER_FILTER_MODE( "Weather filter", { @@ -130,20 +129,19 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() LockMode::LOCK_WHILE_RUNNING, 0 ) - , SHINY_DETECTED( - "Shiny Detected", "", - "2000 ms", - ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY - ) + "Shiny Detected", "", + "2000 ms", + ShinySoundDetectedAction::NOTIFY_ON_FIRST_ONLY + ) , 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, - }) + &NOTIFICATION_STATUS, + &SHINY_DETECTED.NOTIFICATIONS, + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_RECOVERABLE, + &NOTIFICATION_ERROR_FATAL, + }) { PA_ADD_STATIC(SHINY_REQUIRES_AUDIO); if (PreloadSettings::instance().DEVELOPER_MODE){ @@ -153,7 +151,6 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() PA_ADD_OPTION(PERIODIC_SAVE); PA_ADD_OPTION(DAY_NIGHT_FILTER); DAY_NIGHT_FILTER.add_option(FILTER_MODE, "FilterMode"); - PA_ADD_OPTION(WEATHER_FILTER); WEATHER_FILTER.add_option(WEATHER_FILTER_MODE, "WeatherFilterMode"); PA_ADD_OPTION(SHINY_DETECTED); @@ -163,13 +160,13 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() void run_back_until_found_bench( SingleSwitchProgramEnvironment& env, ProControllerContext& context - ){ +){ ButtonWatcher buttonA( COLOR_RED, ButtonType::ButtonA, {0.486, 0.477, 0.115, 0.5}, &env.console.overlay() - ); + ); int ret = run_until( env.console, context, @@ -186,7 +183,7 @@ void run_back_until_found_bench( } }, {buttonA} - ); + ); switch (ret){ case 0: @@ -197,28 +194,24 @@ void run_back_until_found_bench( ErrorReport::SEND_ERROR_REPORT, "run_back_until_found_bench(): Unable to detect bench after multiple attempts.", env.console - ); + ); } } - bool ShinyHunt_BenchSit::should_run_based_on_day_night( - const ImageViewRGB32& frame, - VideoOverlay& overlay - ){ + const ImageViewRGB32& frame, VideoOverlay& overlay){ if (!DAY_NIGHT_FILTER.enabled()){ return true; } - - DayNightStateDetector detector(&overlay); - - if (!detector.detect(frame)){ + + if (!m_day_night_detector){ + m_day_night_detector = std::make_unique(&overlay); + } + + if (!m_day_night_detector->detect(frame)){ return true; } - - DayNightState current_state = detector.state(); - + DayNightState current_state = m_day_night_detector->state(); size_t filter_mode = FILTER_MODE.current_value(); - if (filter_mode == 0){ return current_state == DayNightState::DAY; } @@ -229,36 +222,26 @@ bool ShinyHunt_BenchSit::should_run_based_on_day_night( return true; } - bool ShinyHunt_BenchSit::should_run_based_on_weather( - const ImageViewRGB32& frame - ){ + const ImageViewRGB32& frame){ if (!WEATHER_FILTER.enabled()){ return true; } - size_t weather_mode = WEATHER_FILTER_MODE.current_value(); - WeatherIconType weather_type; - switch (weather_mode){ - case 0: weather_type = WeatherIconType::Clear; break; case 1: weather_type = WeatherIconType::Sunny; break; case 2: weather_type = WeatherIconType::Rain; break; case 3: weather_type = WeatherIconType::Cloudy; break; case 4: weather_type = WeatherIconType::Foggy; break; case 5: weather_type = WeatherIconType::Rainbow; break; - default: return true; } - WeatherIconDetector detector(weather_type); - return detector.detect(frame); } - void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ assert_16_9_720p_min(env.logger(), env.console); @@ -301,46 +284,35 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl } Milliseconds duration = WALK_FORWARD_DURATION; + open_map(env.console, context, true, true); + pbf_move_right_joystick(context, { 0, -1 }, 1000ms, 500ms); + pbf_move_left_joystick(context, { -1, 0 }, 1000ms, 500ms); + context.wait_for_all_requests(); - - open_map(env.console, context, false, true); + pbf_press_button(context, BUTTON_MINUS, 500ms, 500ms); ImageViewRGB32 frame = env.console.video().snapshot(); - context.wait_for_all_requests(); - pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); - - if (!should_run_based_on_day_night(frame, env.console.overlay())){ - env.console.overlay().add_log( "Skipping move (wrong day/night)", COLOR_ORANGE ); - run_back_until_found_bench(env, context); - shiny_sound_handler.process_pending(context); - continue; } - if (!should_run_based_on_weather(frame)){ - env.console.overlay().add_log( "Skipping move (wrong weather)", COLOR_ORANGE ); - run_back_until_found_bench(env, context); - shiny_sound_handler.process_pending(context); - continue; } - if (duration > Milliseconds::zero()){ if (WALK_DIRECTION.current_value() == 0){ // forward env.console.overlay().add_log("Move Forward"); @@ -399,4 +371,4 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl } } -} \ No newline at end of file +} diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h index 782248bcba..5aa0f89640 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h @@ -43,6 +43,7 @@ class ShinyHunt_BenchSit : public SingleSwitchProgramInstance{ virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; private: + std::unique_ptr m_day_night_detector; bool should_run_based_on_day_night(const ImageViewRGB32& frame, VideoOverlay& overlay); bool should_run_based_on_weather(const ImageViewRGB32& frame); PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; diff --git a/SerialPrograms/Source/PokemonLZA/Resources/crescent_moon_template_v2.png b/SerialPrograms/Source/PokemonLZA/Resources/crescent_moon_template_v2.png deleted file mode 100644 index 36c7bc7d5d2b41c4fbc884063bb97d0ccfb4c4c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9153 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

d%TNA$SW{N;P8;KZe1f@-$KSv03 z6rONJ#Gg3o)fen_Vs9CxZ>ffsQd(crVary!zh|Cb|7K>Sl$VmT8TP@*2u_5e1rWS= zyg8&m(CATVGL+z!p=XD8g7~I@*Z1W9U!DAO0*XT)P5{_LQWt5@x7Rv?cSMEYjo<|@ zLJ(=)2-Q(iFVP%jTHXOA&iWsTz_aU5t`t#ZaMw$Itd4T3NOBappE`kpYX za9Ob0&ILZM*8ZMJ|I7LFxcNc|jbtC4(ac&qTAEP>sHIR!!OZBoNcjBkK1a-mArM5+ zs?<_YGeV5`zT^DjDgCO)d;c)Fd$f_(+GbEgSQc&QaskKiw&m4^qE)CxnN#NA61$o? zpaeXlRbJ+M*46X0-|(UHi;;!(=`(y-v!P9|9e^=9@+wfHp*o{E6Y+T3p{Jsy4HvuS zrDpoz1dsHHg>%Y-(e-$ws{;1kW>_<{p?DwY`vDQ5)j-y=I%c8_biQY{M9vxWM)VOx z$#ZFK9bAhHYb_B)TKje}Y)ePS{Pq7upM0}(sSl5Z4?p@C)%uVC&8+b;)h17wayZP~ zT;DScE1sO65~4@7P^{u&V2BZES`jLSi6OH1;gU;;?er{4 z@D6uG5qog52X8c*(jzAC`RA{93*FNbFhRs2;vS4xOKVE0Ru1EVx6__-eMRm(XXhvQ z=%}i#8t_f_H*~3VjvR9_stL6k)m-D9(cy={ijGYe8EAPjx`10f<$Cp+&tG4XeV{)* z<)6fXL4@^U$O(8w;m75Mw};o1>5{?rtbL+$6<-X&(RCgVl-efef?sCg?bzRuB?Z|M zO^>6$L(V+CILCXBsys~iJ+Llm3qBe$U`Q!#wx|le2%V1% z($N!GMz1JN(32H*w&CsTOaA<`AG6(0=(m28Z(ck{L!=GD1SSc*)S0XClB*ezQ=VM} zYH6b;Qfj023*b3DhOayt^1aRfmCF1dW=OQu?Dwzc7+JWT7HuLj0i0(xxVOp;6~l8y(AMrzT(Sw_nhcGCnu5qU{tN7IuR8*BH$MaBbXckhKC~J z*gTVeq&b6k0q+*IMr}EtWDg9iNnwI_j$yS12h+IcezzxFUgCr2$$1NN7SNCff@BYO zq3f__UXWQeb41I@{_wu!ghl`JLR%Y?9znkOz0hDaC~;S;quEp|LNTq@`|bn09eWV( zA0hm84H?_FF*G6|%Z~6+G8)Fv4b)mNt8DvIx}oE6xMz15xw^R}_C04^e5@%RzDMXW zW6V|?@br#=CmlT3x0!K#$Nn1J+_UyisiCReU4+%e3AOi(Z?E~{=7w>9gY{d=Vdiju z&qR-{de$dTxG9M@hc|q#JK{QUZXTBkHDxLhClT{usmz6nP^ATUFxue$lAj(+-+zc9 zJO9f;xER5kVAjM@@eb$1(k_55tT89#l9;P0sHUhc-^(P&{8=%fdA~FI zi#5-;AGKlqt^@Cwbi~Ty3ECQWZUynhmhF>BFGlGj<2q2Bk!mIvLxT{{w`iUC(U&i| zc>015o#3wagx+I0u`5Q5fklW~)GHyFw6g|gge4L)Zb9{5|Mvd^nhZ~<*UC7+00000 LNkvXXu0mjfaLC1l From 4b9d92b6dff0a92ba573e92320a11986bc80262b Mon Sep 17 00:00:00 2001 From: Butters Date: Wed, 15 Apr 2026 17:07:42 -0500 Subject: [PATCH 6/7] more formatting corrections --- .../Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 76aed09499..087cf79298 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -258,7 +258,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl env, env.console, stats.shinies, error_coefficient - ); + ); }); run_until( @@ -346,7 +346,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl } }, {shiny_detector} - ); + ); // Shiny sound detected and user requested stopping the program when // detected shiny sound. From f79e51886dc921985c1da1a3834b2e2eefb1bdff Mon Sep 17 00:00:00 2001 From: Butters Date: Wed, 15 Apr 2026 18:55:54 -0500 Subject: [PATCH 7/7] modified detector more refined the detector and removed some debugging tools --- .../PokemonLZA_DayNightStateDetector.cpp | 16 +++++++--------- .../Inference/PokemonLZA_DayNightStateDetector.h | 1 - .../PokemonLZA_ShinyHunt_BenchSit.cpp | 5 +++++ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp index 81fc159cc2..831536dfaa 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -1,6 +1,7 @@ #include "PokemonLZA_DayNightStateDetector.h" #include "CommonFramework/Globals.h" #include "CommonFramework/ImageTools/ImageStats.h" +#include namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -10,11 +11,7 @@ DayNightStateDetector::DayNightStateDetector(VideoOverlay* overlay) : m_box(0.02, 0.50, 0.08, 0.10), m_state(DayNightState::DAY) -{ - if (overlay){ - m_overlay.emplace(*overlay, m_box, COLOR_YELLOW); - } -} +{} void DayNightStateDetector::make_overlays(VideoOverlaySet& items) const{ @@ -34,12 +31,13 @@ bool DayNightStateDetector::detect(const ImageViewRGB32& screen){ 0.299*r + 0.587*g + 0.114*b; - + + std::cout << "RGB: (" << r << ", " << g << ", " << b << ") Luminance: " << luminance << std::endl; bool night_color = - r < 120 && - b > 50 && - luminance < 100; + r < 10 && + b > 20 && + luminance < 20; bool day_color = r > 100 && r < 180 && diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h index 9c9e048f9c..d3190066f5 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -34,7 +34,6 @@ class DayNightStateDetector : public StaticScreenDetector{ DayNightState m_state; - std::optional m_overlay; }; diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 087cf79298..18b4dd35af 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -211,6 +211,11 @@ bool ShinyHunt_BenchSit::should_run_based_on_day_night( return true; } DayNightState current_state = m_day_night_detector->state(); + if (current_state == DayNightState::NIGHT) { + overlay.add_log("Day/Night Detector: NIGHT", COLOR_CYAN); + } else { + overlay.add_log("Day/Night Detector: DAY", COLOR_YELLOW); + } size_t filter_mode = FILTER_MODE.current_value(); if (filter_mode == 0){ return current_state == DayNightState::DAY;