diff --git a/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp new file mode 100644 index 000000000..831536dfa --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.cpp @@ -0,0 +1,61 @@ +#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), + m_state(DayNightState::DAY) +{} + + +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) { + m_state = DayNightState::NIGHT; + } + else if (day_color) { + 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 new file mode 100644 index 000000000..d3190066f --- /dev/null +++ b/SerialPrograms/Source/PokemonLZA/Inference/PokemonLZA_DayNightStateDetector.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include "Common/Cpp/Color.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 +}; + + +class DayNightStateDetector : public StaticScreenDetector{ +public: + + DayNightStateDetector(VideoOverlay* overlay = nullptr); + + virtual void make_overlays(VideoOverlaySet& items) const override; + + virtual bool detect(const ImageViewRGB32& screen) override; + + DayNightState state() const; + +private: + + ImageFloatBox m_box; + + DayNightState m_state; + +}; + + +} +} +} \ 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 aae4ecf65..18b4dd35a 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.cpp @@ -8,6 +8,7 @@ #include "CommonFramework/GlobalSettingsPanel.h" #include "CommonFramework/ProgramStats/StatsTracking.h" #include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" #include "CommonTools/Async/InferenceRoutines.h" #include "CommonTools/StartupChecks/VideoResolutionCheck.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" @@ -15,8 +16,12 @@ #include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" #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{ @@ -92,6 +97,38 @@ ShinyHunt_BenchSit::ShinyHunt_BenchSit() 100, 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 + ) , SHINY_DETECTED( "Shiny Detected", "", "2000 ms", @@ -112,6 +149,10 @@ 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_MODE, "FilterMode"); + PA_ADD_OPTION(WEATHER_FILTER); + WEATHER_FILTER.add_option(WEATHER_FILTER_MODE, "WeatherFilterMode"); PA_ADD_OPTION(SHINY_DETECTED); PA_ADD_OPTION(NOTIFICATIONS); } @@ -156,7 +197,56 @@ void run_back_until_found_bench( ); } } +bool ShinyHunt_BenchSit::should_run_based_on_day_night( + const ImageViewRGB32& frame, VideoOverlay& overlay){ + 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) { + 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; + } + 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); @@ -199,6 +289,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(); + + 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"); diff --git a/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h b/SerialPrograms/Source/PokemonLZA/Programs/ShinyHunting/PokemonLZA_ShinyHunt_BenchSit.h index 700d1e435..5aa0f8964 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,21 @@ 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; IntegerEnumDropdownOption WALK_DIRECTION; MillisecondsOption WALK_FORWARD_DURATION; SimpleIntegerOption PERIODIC_SAVE; + GroupOption DAY_NIGHT_FILTER; + IntegerEnumDropdownOption FILTER_MODE; + + GroupOption WEATHER_FILTER; + IntegerEnumDropdownOption WEATHER_FILTER_MODE; + ShinySoundDetectedActionOption SHINY_DETECTED; EventNotificationOption NOTIFICATION_STATUS; diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 16a4eb9a4..15f257029 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1807,6 +1807,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