From d8b771eac3b6f655ec142881e2c71d68bb85a7ab Mon Sep 17 00:00:00 2001 From: Butters Date: Mon, 13 Apr 2026 20:47:18 -0500 Subject: [PATCH 01/16] 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 02/16] 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 03/16] 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 04/16] 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 05/16] 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 06/16] 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 07/16] 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; From bbfd9e92b4071b9ff6267d2b99887d10c3e297d1 Mon Sep 17 00:00:00 2001 From: Butters Date: Sat, 18 Apr 2026 14:18:08 -0500 Subject: [PATCH 08/16] Improve Day/Night detection robustness Switch detection from luminance calibration of dark map edge to color- ratio sampling of zoomed-in terrain with icons hidden. Uses normalized blue-channel ratio for consistent classification across capture cards. Removes calibration logic and improves reliability across map locations. --- .../PokemonLZA_DayNightStateDetector.cpp | 59 +++++----- .../PokemonLZA_DayNightStateDetector.h | 3 +- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 109 +++++++++++++++--- 3 files changed, 124 insertions(+), 47 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp index 831536dfaa..d82af80103 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -1,15 +1,17 @@ #include "PokemonLZA_DayNightStateDetector.h" -#include "CommonFramework/Globals.h" + #include "CommonFramework/ImageTools/ImageStats.h" -#include namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonLZA{ + DayNightStateDetector::DayNightStateDetector(VideoOverlay* overlay) : - m_box(0.02, 0.50, 0.08, 0.10), + // sample terrain area after zooming map fully in and hiding icons + // screen-relative coordinates (0–1) + m_box(0.30, 0.55, 0.15, 0.18), m_state(DayNightState::DAY) {} @@ -18,44 +20,47 @@ 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)); - double r = stats.average.r; - double g = stats.average.g; - double b = stats.average.b; - - double luminance = - 0.299*r + - 0.587*g + - 0.114*b; - - std::cout << "RGB: (" << r << ", " << g << ", " << b << ") Luminance: " << luminance << std::endl; - - bool night_color = - r < 10 && - b > 20 && - luminance < 20; - - bool day_color = - r > 100 && r < 180 && - g > 140 && - b > 160 && - luminance > 140; - - if (night_color) { + + // robust against brightness differences between capture cards + const double blue_ratio = + stats.average.b / + (stats.average.r + stats.average.g + stats.average.b); + + + /* + Empirically stable separation: + + DAY ≈ 0.32 – 0.35 + NIGHT ≈ 0.40 – 0.46 + + Threshold chosen conservatively to survive: + - HDMI color variance + - OBS color space changes + - capture card gamma shifts + */ + + if (blue_ratio > 0.36){ m_state = DayNightState::NIGHT; } - else if (day_color) { + else{ m_state = DayNightState::DAY; } + 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 d3190066f5..d73fc38270 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -1,6 +1,7 @@ #pragma once -#include +#include + #include "Common/Cpp/Color.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 18b4dd35af..5eae3c5bd7 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -289,59 +289,130 @@ 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); + + open_map(env.console, context, false, true); + context.wait_for_all_requests(); + pbf_wait(context, 800ms); + + + // stabilize zoom + pbf_move_right_joystick(context, {0, 1}, 1500ms, 500ms); + + context.wait_for_all_requests(); + pbf_wait(context, 500ms); + + // show icons pbf_press_button(context, BUTTON_MINUS, 500ms, 500ms); - ImageViewRGB32 frame = - env.console.video().snapshot(); context.wait_for_all_requests(); + pbf_wait(context, 400ms); + + + // double snapshot + ImageViewRGB32 frame1 = + env.console.video().snapshot(); + + pbf_wait(context, 200ms); + + ImageViewRGB32 frame2 = + env.console.video().snapshot(); + + + // evaluate using both frames + bool dayNightOk = + should_run_based_on_day_night(frame1, env.console.overlay()) || + should_run_based_on_day_night(frame2, env.console.overlay()); + + bool weatherOk = + should_run_based_on_weather(frame1) || + should_run_based_on_weather(frame2); + + + // close map + pbf_wait(context, 150ms); + pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); - if (!should_run_based_on_day_night(frame, env.console.overlay())){ + + context.wait_for_all_requests(); + pbf_wait(context, 400ms); + + + // filtering + if (!dayNightOk){ + 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)){ + + if (!weatherOk){ + 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; } + + + // movement if (duration > Milliseconds::zero()){ - if (WALK_DIRECTION.current_value() == 0){ // forward + + 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); + + pbf_move_left_joystick(context, {0, -1}, duration + 1000ms, 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_press_button(context, BUTTON_L, 100ms, 400ms); + + pbf_move_left_joystick(context, {-1, 0}, duration, 0ms); + + pbf_press_button(context, BUTTON_L, 130ms, 450ms); + 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, {0, -1}, duration + 150ms, 0ms); + + pbf_move_left_joystick(context, {-1, 0}, 150ms, 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); + + pbf_press_button(context, BUTTON_L, 130ms, 450ms); + 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); + + pbf_move_left_joystick(context, {0, -1}, duration + 150ms, 0ms); + + pbf_move_left_joystick(context, {+1, 0}, 150ms, 0ms); } }else{ run_back_until_found_bench(env, context); From ebecd925bb9495d67fce63a28edbed7fb097767e Mon Sep 17 00:00:00 2001 From: Butters Date: Sat, 18 Apr 2026 14:21:04 -0500 Subject: [PATCH 09/16] wrong .h file corrected .h file from previous commit --- .../PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h index d73fc38270..7eb8a670f2 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -1,7 +1,5 @@ #pragma once -#include - #include "Common/Cpp/Color.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" From 5158749c029621b4411e5ea49767b4953f60751b Mon Sep 17 00:00:00 2001 From: Butters Date: Sat, 18 Apr 2026 14:21:04 -0500 Subject: [PATCH 10/16] Updated to skip map checks if duration set to 0 Skip map checks when Run Forward Duration is 0 or no filters are enabled. --- .../PokemonLZA_DayNightStateDetector.h | 2 - .../PokemonLZA_ShinyHunt_BenchSit.cpp | 71 ++++++++++--------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h index d73fc38270..7eb8a670f2 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -1,7 +1,5 @@ #pragma once -#include - #include "Common/Cpp/Color.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 5eae3c5bd7..73971b8a50 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -199,6 +199,11 @@ void run_back_until_found_bench( } bool ShinyHunt_BenchSit::should_run_based_on_day_night( const ImageViewRGB32& frame, VideoOverlay& overlay){ + + if ((Milliseconds)WALK_FORWARD_DURATION == Milliseconds::zero()){ + return true; + } + if (!DAY_NIGHT_FILTER.enabled()){ return true; } @@ -290,53 +295,55 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl Milliseconds duration = WALK_FORWARD_DURATION; - open_map(env.console, context, false, true); + bool dayNightOk = true; + bool weatherOk = true; - context.wait_for_all_requests(); - pbf_wait(context, 800ms); + // Only open map if movement is enabled AND a filter is active + if (duration > Milliseconds::zero() && + (DAY_NIGHT_FILTER.enabled() || WEATHER_FILTER.enabled())){ + open_map(env.console, context, false, true); - // stabilize zoom - pbf_move_right_joystick(context, {0, 1}, 1500ms, 500ms); + context.wait_for_all_requests(); + pbf_wait(context, 800ms); - context.wait_for_all_requests(); - pbf_wait(context, 500ms); + // zoom fully in + pbf_move_right_joystick(context, {0, 1}, 1500ms, 500ms); + context.wait_for_all_requests(); + pbf_wait(context, 500ms); - // show icons - pbf_press_button(context, BUTTON_MINUS, 500ms, 500ms); + // hide icons + pbf_press_button(context, BUTTON_MINUS, 500ms, 500ms); - context.wait_for_all_requests(); - pbf_wait(context, 400ms); + context.wait_for_all_requests(); + pbf_wait(context, 400ms); + // double snapshot + ImageViewRGB32 frame1 = + env.console.video().snapshot(); - // double snapshot - ImageViewRGB32 frame1 = - env.console.video().snapshot(); + pbf_wait(context, 200ms); - pbf_wait(context, 200ms); + ImageViewRGB32 frame2 = + env.console.video().snapshot(); - ImageViewRGB32 frame2 = - env.console.video().snapshot(); + dayNightOk = + should_run_based_on_day_night(frame1, env.console.overlay()) || + should_run_based_on_day_night(frame2, env.console.overlay()); + weatherOk = + should_run_based_on_weather(frame1) || + should_run_based_on_weather(frame2); - // evaluate using both frames - bool dayNightOk = - should_run_based_on_day_night(frame1, env.console.overlay()) || - should_run_based_on_day_night(frame2, env.console.overlay()); + // close map + pbf_wait(context, 150ms); - bool weatherOk = - should_run_based_on_weather(frame1) || - should_run_based_on_weather(frame2); + pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); - - // close map - pbf_wait(context, 150ms); - - pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); - - context.wait_for_all_requests(); - pbf_wait(context, 400ms); + context.wait_for_all_requests(); + pbf_wait(context, 400ms); + } // filtering From df501736447c34228572544afd1a68cb3629e8bd Mon Sep 17 00:00:00 2001 From: Butters Date: Sun, 19 Apr 2026 15:08:26 -0500 Subject: [PATCH 11/16] Removed weather and adjusted time check Removed the weather checks entirely. Created a caching system for the first day night cycle and let the user define how often to recheck. Adjusted the timings of waits, presses, and joystick holds to reduce the time spent to under 2000ms per check. --- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 232 +++++++----------- .../PokemonLZA_ShinyHunt_BenchSit.h | 9 +- 2 files changed, 89 insertions(+), 152 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 73971b8a50..9b1caa4e6d 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -17,11 +17,8 @@ #include "Pokemon/Pokemon_Strings.h" #include "PokemonLA/Inference/Sounds/PokemonLA_ShinySoundDetector.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/Programs/PokemonLZA_FastTravelNavigation.h" -#include "PokemonLZA/Resources/PokemonLZA_Locations.h" #include "PokemonLZA_ShinyHunt_BenchSit.h" namespace PokemonAutomation{ @@ -97,38 +94,28 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() 100, 0 ) + , PERIODIC_TIME_CHECK( + "Periodically Check Time:
" + "Re-check day/night state every this many bench sits. " + "Set to 0 to check every cycle.", + LockMode::UNLOCK_WHILE_RUNNING, + 10, + 0 + ) , DAY_NIGHT_FILTER( - "Run Forward Only During Day/Night:", - LockMode::LOCK_WHILE_RUNNING, - GroupOption::EnableMode::DEFAULT_DISABLED - ) - , FILTER_MODE( - "Time filter", - { - {0, "day", "Day"}, - {1, "night", "Night"}, - }, - 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", - { - {0, "clear", "Clear"}, - {1, "sunny", "Sunny"}, - {2, "rain", "Rain"}, - {3, "cloudy", "Cloudy"}, - {4, "foggy", "Foggy"}, - {5, "rainbow", "Rainbow"}, - }, - LockMode::LOCK_WHILE_RUNNING, - 0 - ) + "Run Forward Only During Day/Night:", + LockMode::LOCK_WHILE_RUNNING, + GroupOption::EnableMode::DEFAULT_DISABLED + ) + , DAY_FILTER_MODE( + "Time filter", + { + {0, "day", "Day"}, + {1, "night", "Night"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + 0 + ) , SHINY_DETECTED( "Shiny Detected", "", "2000 ms", @@ -149,10 +136,9 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() } PA_ADD_OPTION(WALK_FORWARD_DURATION); PA_ADD_OPTION(PERIODIC_SAVE); + PA_ADD_OPTION(PERIODIC_TIME_CHECK); 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"); + DAY_NIGHT_FILTER.add_option(DAY_FILTER_MODE, "FilterMode"); PA_ADD_OPTION(SHINY_DETECTED); PA_ADD_OPTION(NOTIFICATIONS); } @@ -203,55 +189,30 @@ bool ShinyHunt_BenchSit::should_run_based_on_day_night( if ((Milliseconds)WALK_FORWARD_DURATION == Milliseconds::zero()){ return true; } - if (!DAY_NIGHT_FILTER.enabled()){ return true; } - 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 = m_day_night_detector->state(); - if (current_state == DayNightState::NIGHT) { + 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(); + size_t filter_mode = DAY_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; - } - 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); @@ -259,6 +220,10 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl ShinySoundHandler shiny_sound_handler(SHINY_DETECTED); + DayNightState cached_time = DayNightState::DAY; + bool cached_time_initialized = false; + uint32_t rounds_since_time_check = 0; + 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++; @@ -280,7 +245,13 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl shiny_sound_handler.process_pending(context); stats.resets++; env.update_stats(); - + if (cached_time_initialized){ + cached_time = + cached_time == DayNightState::DAY + ? DayNightState::NIGHT + : DayNightState::DAY; + rounds_since_time_check++; + } 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); @@ -295,136 +266,107 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl Milliseconds duration = WALK_FORWARD_DURATION; - bool dayNightOk = true; - bool weatherOk = true; - // Only open map if movement is enabled AND a filter is active - if (duration > Milliseconds::zero() && - (DAY_NIGHT_FILTER.enabled() || WEATHER_FILTER.enabled())){ + bool need_time_check = true; - open_map(env.console, context, false, true); + uint32_t periodic_time_check = PERIODIC_TIME_CHECK; - context.wait_for_all_requests(); - pbf_wait(context, 800ms); + if (periodic_time_check > 0 && cached_time_initialized){ + need_time_check = + rounds_since_time_check >= periodic_time_check; + } + if ( + duration > Milliseconds::zero() && + DAY_NIGHT_FILTER.enabled() && + (!cached_time_initialized || need_time_check) + ){ + open_map(env.console, context, false, true); + context.wait_for_all_requests(); + pbf_wait(context, 180ms); // zoom fully in - pbf_move_right_joystick(context, {0, 1}, 1500ms, 500ms); - + pbf_move_right_joystick(context, {0, 1}, 900ms, 120ms); context.wait_for_all_requests(); - pbf_wait(context, 500ms); - + pbf_wait(context, 120ms); // hide icons - pbf_press_button(context, BUTTON_MINUS, 500ms, 500ms); - + pbf_press_button(context, BUTTON_MINUS, 80ms, 120ms); context.wait_for_all_requests(); - pbf_wait(context, 400ms); - + pbf_wait(context, 160ms); // double snapshot ImageViewRGB32 frame1 = env.console.video().snapshot(); - - pbf_wait(context, 200ms); - + pbf_wait(context, 120ms); ImageViewRGB32 frame2 = env.console.video().snapshot(); - - dayNightOk = - should_run_based_on_day_night(frame1, env.console.overlay()) || - should_run_based_on_day_night(frame2, env.console.overlay()); - - weatherOk = - should_run_based_on_weather(frame1) || - should_run_based_on_weather(frame2); + should_run_based_on_day_night(frame1, env.console.overlay()); + should_run_based_on_day_night(frame2, env.console.overlay()); + if (m_day_night_detector){ + cached_time = m_day_night_detector->state(); + cached_time_initialized = true; + rounds_since_time_check = 0; + } // close map - pbf_wait(context, 150ms); - - pbf_press_button(context, BUTTON_PLUS, 500ms, 500ms); - + pbf_wait(context, 120ms); + pbf_press_button(context, BUTTON_PLUS, 500ms, 120ms); context.wait_for_all_requests(); - pbf_wait(context, 400ms); + pbf_wait(context, 150ms); } + // filtering + if (DAY_NIGHT_FILTER.enabled()){ + size_t filter_mode = DAY_FILTER_MODE.current_value(); - // filtering - if (!dayNightOk){ + bool predicted_ok = + filter_mode == 0 + ? cached_time == DayNightState::DAY + : cached_time == DayNightState::NIGHT; - env.console.overlay().add_log( - "Skipping move (wrong day/night)", - COLOR_ORANGE - ); + if (!predicted_ok){ - run_back_until_found_bench(env, context); - shiny_sound_handler.process_pending(context); - continue; - } + env.console.overlay().add_log( + "Skipping move (predicted wrong time of day)", + COLOR_ORANGE + ); - if (!weatherOk){ + run_back_until_found_bench(env, context); - env.console.overlay().add_log( - "Skipping move (wrong weather)", - COLOR_ORANGE - ); + shiny_sound_handler.process_pending(context); - run_back_until_found_bench(env, context); - shiny_sound_handler.process_pending(context); - continue; + continue; + } } - // movement if (duration > Milliseconds::zero()){ - - if (WALK_DIRECTION.current_value() == 0){ - + 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 + 1000ms, 0ms); - + pbf_move_left_joystick(context, {0, -1}, duration, 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_press_button(context, BUTTON_L, 130ms, 450ms); - ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); - - pbf_move_left_joystick(context, {0, -1}, duration + 150ms, 0ms); - + pbf_move_left_joystick(context, {0, -1}, duration, 0ms); pbf_move_left_joystick(context, {-1, 0}, 150ms, 0ms); } - - else if (WALK_DIRECTION.current_value() == 2){ - + 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, 130ms, 450ms); - ssf_press_button(context, BUTTON_B, 0ms, duration, 0ms); - - pbf_move_left_joystick(context, {0, -1}, duration + 150ms, 0ms); - + pbf_move_left_joystick(context, {0, -1}, duration +150ms, 0ms); pbf_move_left_joystick(context, {+1, 0}, 150ms, 0ms); } }else{ run_back_until_found_bench(env, context); } - shiny_sound_handler.process_pending(context); } }, diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h index 5aa0f89640..4224774831 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h @@ -10,7 +10,6 @@ #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" @@ -18,7 +17,6 @@ #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{ @@ -45,18 +43,15 @@ class ShinyHunt_BenchSit : public SingleSwitchProgramInstance{ 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; IntegerEnumDropdownOption WALK_DIRECTION; MillisecondsOption WALK_FORWARD_DURATION; SimpleIntegerOption PERIODIC_SAVE; + SimpleIntegerOption PERIODIC_TIME_CHECK; GroupOption DAY_NIGHT_FILTER; - IntegerEnumDropdownOption FILTER_MODE; - - GroupOption WEATHER_FILTER; - IntegerEnumDropdownOption WEATHER_FILTER_MODE; + IntegerEnumDropdownOption DAY_FILTER_MODE; ShinySoundDetectedActionOption SHINY_DETECTED; From 6c5f1dab31bad8c8dbf4d8688575ca509b7b3031 Mon Sep 17 00:00:00 2001 From: Butters Date: Sun, 19 Apr 2026 16:09:32 -0500 Subject: [PATCH 12/16] Moved the periodic check and improved log display Moved the perioic check to within the day/time filter box. Added an output to the log overlay to indicate which time is cached (day/night). Added text explaining the periodic time check field. --- .../PokemonLZA_DayNightStateDetector.cpp | 1 - .../PokemonLZA_DayNightStateDetector.h | 1 + .../PokemonLZA_ShinyHunt_BenchSit.cpp | 29 ++++++++++++------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp index d82af80103..d09696bfc4 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -60,7 +60,6 @@ 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 7eb8a670f2..61a3b44b92 100644 --- a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -33,6 +33,7 @@ class DayNightStateDetector : public StaticScreenDetector{ DayNightState m_state; + }; diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 9b1caa4e6d..bdb4b1118d 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -95,23 +95,24 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() 0 ) , PERIODIC_TIME_CHECK( - "Periodically Check Time:
" - "Re-check day/night state every this many bench sits. " - "Set to 0 to check every cycle.", - LockMode::UNLOCK_WHILE_RUNNING, - 10, - 0 + "Periodically Check Time:
" + "How often the program re-checks the actual time of day from the map.
" + "0 = check every cycle.
" + "Higher values run faster but assume time alternates each bench sit.", + LockMode::UNLOCK_WHILE_RUNNING, + 10, + 0 ) , DAY_NIGHT_FILTER( "Run Forward Only During Day/Night:", - LockMode::LOCK_WHILE_RUNNING, + LockMode::UNLOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) , DAY_FILTER_MODE( "Time filter", { - {0, "day", "Day"}, - {1, "night", "Night"}, + {0, "day", "Day"}, + {1, "night", "Night"}, }, LockMode::UNLOCK_WHILE_RUNNING, 0 @@ -136,9 +137,9 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() } PA_ADD_OPTION(WALK_FORWARD_DURATION); PA_ADD_OPTION(PERIODIC_SAVE); - PA_ADD_OPTION(PERIODIC_TIME_CHECK); PA_ADD_OPTION(DAY_NIGHT_FILTER); DAY_NIGHT_FILTER.add_option(DAY_FILTER_MODE, "FilterMode"); + DAY_NIGHT_FILTER.add_option(PERIODIC_TIME_CHECK,"PeriodicTimeCheck"); PA_ADD_OPTION(SHINY_DETECTED); PA_ADD_OPTION(NOTIFICATIONS); } @@ -266,7 +267,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl Milliseconds duration = WALK_FORWARD_DURATION; - // Only open map if movement is enabled AND a filter is active + // Only open map when movement enabled AND day/night filter requires verification bool need_time_check = true; uint32_t periodic_time_check = PERIODIC_TIME_CHECK; @@ -304,6 +305,12 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl cached_time = m_day_night_detector->state(); cached_time_initialized = true; rounds_since_time_check = 0; + std::string time_string = + cached_time == DayNightState::DAY + ? "Cached Day" + : "Cached Night"; + env.console.overlay().add_log(time_string, COLOR_GREEN); + env.log(time_string); } // close map From bfb57c79b129ac796d2f9c6d238e51681ff6eea7 Mon Sep 17 00:00:00 2001 From: Butters Date: Sun, 19 Apr 2026 16:20:18 -0500 Subject: [PATCH 13/16] formatting corrected some erroneous format changes --- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index bdb4b1118d..bd1f92bb31 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -346,30 +346,28 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl // movement if (duration > Milliseconds::zero()){ - if (WALK_DIRECTION.current_value() == 0){ //forward + 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, 0ms); run_back_until_found_bench(env, context); - } - else if (WALK_DIRECTION.current_value() == 1){//left + }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_press_button(context, BUTTON_L, 130ms, 450ms); + 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}, 150ms, 0ms); - } - else if (WALK_DIRECTION.current_value() == 2){ //right + }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, 130ms, 450ms); + 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 +150ms, 0ms); - pbf_move_left_joystick(context, {+1, 0}, 150ms, 0ms); + pbf_move_left_joystick(context, {+1, 0}, 100ms, 0ms); } }else{ run_back_until_found_bench(env, context); @@ -377,6 +375,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl shiny_sound_handler.process_pending(context); } }, + {shiny_detector} ); From c0d2f1eb0922a1008538e6aa73928b121d97174c Mon Sep 17 00:00:00 2001 From: Butters Date: Sun, 19 Apr 2026 16:24:09 -0500 Subject: [PATCH 14/16] more formatting changes --- .../ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index bd1f92bb31..2fcf883183 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -350,32 +350,33 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl 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, 0ms); run_back_until_found_bench(env, context); - }else if (WALK_DIRECTION.current_value() == 1){// left + }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_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}, 150ms, 0ms); + 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 +150ms, 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} ); From 14c31f2539368a8226d512089b73ecfefb9b5c15 Mon Sep 17 00:00:00 2001 From: Butters Date: Sun, 19 Apr 2026 16:27:14 -0500 Subject: [PATCH 15/16] formatting --- .../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 2fcf883183..920189fd18 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -351,7 +351,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl 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, 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 env.console.overlay().add_log("Move Left"); @@ -360,7 +360,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl 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); + 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); From 00919c0a348512c5382659c1d7bcfb5c94e41286 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sun, 19 Apr 2026 20:24:19 -0700 Subject: [PATCH 16/16] Cleanup and pull out helper functions. --- .../PokemonLZA_ShinyHunt_BenchSit.cpp | 303 +++++++++--------- .../PokemonLZA_ShinyHunt_BenchSit.h | 22 +- 2 files changed, 172 insertions(+), 153 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp index 920189fd18..be7a560749 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -94,22 +94,13 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() 100, 0 ) - , PERIODIC_TIME_CHECK( - "Periodically Check Time:
" - "How often the program re-checks the actual time of day from the map.
" - "0 = check every cycle.
" - "Higher values run faster but assume time alternates each bench sit.", - LockMode::UNLOCK_WHILE_RUNNING, - 10, - 0 - ) , DAY_NIGHT_FILTER( "Run Forward Only During Day/Night:", LockMode::UNLOCK_WHILE_RUNNING, GroupOption::EnableMode::DEFAULT_DISABLED ) , DAY_FILTER_MODE( - "Time filter", + "Time filter:", { {0, "day", "Day"}, {1, "night", "Night"}, @@ -117,6 +108,15 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() LockMode::UNLOCK_WHILE_RUNNING, 0 ) + , PERIODIC_TIME_CHECK( + "Periodically Check Time:
" + "How often the program re-checks the actual time of day from the map.
" + "0 = check every cycle.
" + "Higher values run faster but assume time alternates each bench sit.", + LockMode::UNLOCK_WHILE_RUNNING, + 100, + 0 + ) , SHINY_DETECTED( "Shiny Detected", "", "2000 ms", @@ -185,7 +185,8 @@ void run_back_until_found_bench( } } bool ShinyHunt_BenchSit::should_run_based_on_day_night( - const ImageViewRGB32& frame, VideoOverlay& overlay){ + const ImageViewRGB32& frame, VideoOverlay& overlay +){ if ((Milliseconds)WALK_FORWARD_DURATION == Milliseconds::zero()){ return true; @@ -214,6 +215,143 @@ bool ShinyHunt_BenchSit::should_run_based_on_day_night( } return true; } +void ShinyHunt_BenchSit::check_daynight( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context +){ + open_map(env.console, context, false, true); + context.wait_for_all_requests(); + pbf_wait(context, 180ms); + // zoom fully in + pbf_move_right_joystick(context, {0, 1}, 900ms, 120ms); + context.wait_for_all_requests(); + pbf_wait(context, 120ms); + // hide icons + pbf_press_button(context, BUTTON_MINUS, 80ms, 120ms); + context.wait_for_all_requests(); + pbf_wait(context, 160ms); + // double snapshot + ImageViewRGB32 frame1 = env.console.video().snapshot(); + pbf_wait(context, 120ms); + ImageViewRGB32 frame2 = env.console.video().snapshot(); + should_run_based_on_day_night(frame1, env.console.overlay()); + should_run_based_on_day_night(frame2, env.console.overlay()); + if (m_day_night_detector){ + m_cached_time = m_day_night_detector->state(); + m_cached_time_initialized = true; + m_rounds_since_time_check = 0; + std::string time_string = m_cached_time == DayNightState::DAY + ? "Cached Day" + : "Cached Night"; + env.console.overlay().add_log(time_string, COLOR_GREEN); + env.log(time_string); + } + + // close map + pbf_wait(context, 120ms); + pbf_press_button(context, BUTTON_PLUS, 500ms, 120ms); + context.wait_for_all_requests(); + pbf_wait(context, 150ms); +} +void ShinyHunt_BenchSit::run_rounds( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + ShinySoundHandler& shiny_sound_handler +){ + ShinyHunt_BenchSit_Descriptor::Stats& stats = env.current_stats(); + + 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(); + if (m_cached_time_initialized){ + m_cached_time = m_cached_time == DayNightState::DAY + ? DayNightState::NIGHT + : DayNightState::DAY; + m_rounds_since_time_check++; + } + 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); + pbf_mash_button(context, BUTTON_B, 2000ms); + if (save_successful){ + 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); + } + } + + Milliseconds duration = WALK_FORWARD_DURATION; + + // Only open map when movement enabled AND day/night filter requires verification + bool need_time_check = true; + + uint32_t periodic_time_check = PERIODIC_TIME_CHECK; + + if (periodic_time_check > 0 && m_cached_time_initialized){ + need_time_check = m_rounds_since_time_check >= periodic_time_check; + } + + if (duration > Milliseconds::zero() && + DAY_NIGHT_FILTER.enabled() && + (!m_cached_time_initialized || need_time_check) + ){ + check_daynight(env, context); + } + // filtering + if (DAY_NIGHT_FILTER.enabled()){ + size_t filter_mode = DAY_FILTER_MODE.current_value(); + bool predicted_ok = filter_mode == 0 + ? m_cached_time == DayNightState::DAY + : m_cached_time == DayNightState::NIGHT; + + if (!predicted_ok){ + env.console.overlay().add_log( + "Skipping move (predicted wrong time of day)", + COLOR_ORANGE + ); + run_back_until_found_bench(env, context); + shiny_sound_handler.process_pending(context); + continue; + } + } + + // movement + 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); + // 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){ // 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_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 + 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); + } +} void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ assert_16_9_720p_min(env.logger(), env.console); @@ -221,9 +359,9 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl ShinySoundHandler shiny_sound_handler(SHINY_DETECTED); - DayNightState cached_time = DayNightState::DAY; - bool cached_time_initialized = false; - uint32_t rounds_since_time_check = 0; + m_cached_time = DayNightState::DAY; + m_cached_time_initialized = false; + m_rounds_since_time_check = 0; PokemonLA::ShinySoundDetector shiny_detector(env.console, [&](float error_coefficient) -> bool{ // Warning: This callback will be run from a different thread than this function. @@ -240,142 +378,7 @@ void ShinyHunt_BenchSit::program(SingleSwitchProgramEnvironment& env, ProControl run_until( 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(); - if (cached_time_initialized){ - cached_time = - cached_time == DayNightState::DAY - ? DayNightState::NIGHT - : DayNightState::DAY; - rounds_since_time_check++; - } - 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); - pbf_mash_button(context, BUTTON_B, 2000ms); - if (save_successful){ - 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); - } - } - - Milliseconds duration = WALK_FORWARD_DURATION; - - // Only open map when movement enabled AND day/night filter requires verification - bool need_time_check = true; - - uint32_t periodic_time_check = PERIODIC_TIME_CHECK; - - if (periodic_time_check > 0 && cached_time_initialized){ - need_time_check = - rounds_since_time_check >= periodic_time_check; - } - - if ( - duration > Milliseconds::zero() && - DAY_NIGHT_FILTER.enabled() && - (!cached_time_initialized || need_time_check) - ){ - open_map(env.console, context, false, true); - context.wait_for_all_requests(); - pbf_wait(context, 180ms); - // zoom fully in - pbf_move_right_joystick(context, {0, 1}, 900ms, 120ms); - context.wait_for_all_requests(); - pbf_wait(context, 120ms); - // hide icons - pbf_press_button(context, BUTTON_MINUS, 80ms, 120ms); - context.wait_for_all_requests(); - pbf_wait(context, 160ms); - // double snapshot - ImageViewRGB32 frame1 = - env.console.video().snapshot(); - pbf_wait(context, 120ms); - ImageViewRGB32 frame2 = - env.console.video().snapshot(); - should_run_based_on_day_night(frame1, env.console.overlay()); - should_run_based_on_day_night(frame2, env.console.overlay()); - if (m_day_night_detector){ - cached_time = m_day_night_detector->state(); - cached_time_initialized = true; - rounds_since_time_check = 0; - std::string time_string = - cached_time == DayNightState::DAY - ? "Cached Day" - : "Cached Night"; - env.console.overlay().add_log(time_string, COLOR_GREEN); - env.log(time_string); - } - - // close map - pbf_wait(context, 120ms); - pbf_press_button(context, BUTTON_PLUS, 500ms, 120ms); - context.wait_for_all_requests(); - pbf_wait(context, 150ms); - } - // filtering - if (DAY_NIGHT_FILTER.enabled()){ - - size_t filter_mode = DAY_FILTER_MODE.current_value(); - - bool predicted_ok = - filter_mode == 0 - ? cached_time == DayNightState::DAY - : cached_time == DayNightState::NIGHT; - - if (!predicted_ok){ - - env.console.overlay().add_log( - "Skipping move (predicted wrong time of day)", - COLOR_ORANGE - ); - - run_back_until_found_bench(env, context); - - shiny_sound_handler.process_pending(context); - - continue; - } - } - - // movement - 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); - // 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){ // 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_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 - 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); - } + run_rounds(env, context, shiny_sound_handler); }, {shiny_detector} ); diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h index 4224774831..881ad19a82 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h @@ -41,22 +41,38 @@ 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); + void check_daynight( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context + ); + void run_rounds( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + ShinySoundHandler& shiny_sound_handler + ); + +private: PokemonLA::ShinyRequiresAudioText SHINY_REQUIRES_AUDIO; IntegerEnumDropdownOption WALK_DIRECTION; MillisecondsOption WALK_FORWARD_DURATION; SimpleIntegerOption PERIODIC_SAVE; - SimpleIntegerOption PERIODIC_TIME_CHECK; GroupOption DAY_NIGHT_FILTER; IntegerEnumDropdownOption DAY_FILTER_MODE; + SimpleIntegerOption PERIODIC_TIME_CHECK; ShinySoundDetectedActionOption SHINY_DETECTED; EventNotificationOption NOTIFICATION_STATUS; EventNotificationsOption NOTIFICATIONS; + + std::unique_ptr m_day_night_detector; + bool should_run_based_on_day_night(const ImageViewRGB32& frame, VideoOverlay& overlay); + + DayNightState m_cached_time = DayNightState::DAY; + bool m_cached_time_initialized = false; + uint32_t m_rounds_since_time_check = 0; };