diff --git a/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.cpp b/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.cpp index 3ca2aa9361..97fcd5aa07 100644 --- a/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.cpp +++ b/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.cpp @@ -6,8 +6,11 @@ #include "Common/Cpp/Exceptions.h" #include "Kernels/Waterfill/Kernels_Waterfill_Types.h" +#include "CommonFramework/Globals.h" #include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h" #include "CommonTools/Images/WaterfillUtilities.h" +#include "CommonTools/Images/ImageFilter.h" +#include "CommonTools/Images/BinaryImage_FilterRgb32.h" #include "PokemonPokopia_MovesDetection.h" namespace PokemonAutomation{ @@ -23,10 +26,12 @@ OverworldDetector::OverworldDetector( : m_color(color) , m_overlay(overlay) {} + void OverworldDetector::make_overlays(VideoOverlaySet& items) const{ items.add(m_color, MOVES_LEFT_ARROW_BOX); items.add(m_color, MOVES_RIGHT_ARROW_BOX); } + bool OverworldDetector::detect(const ImageViewRGB32& screen){ ButtonDetector moves_left_detector(m_color, ButtonType::ButtonDpadLeft, MOVES_LEFT_ARROW_BOX, m_overlay); ButtonDetector moves_right_detector(m_color, ButtonType::ButtonDpadRight, MOVES_RIGHT_ARROW_BOX, m_overlay); @@ -36,6 +41,48 @@ bool OverworldDetector::detect(const ImageViewRGB32& screen){ return found; } +PPDetector::PPDetector( + Color color, + VideoOverlay* overlay +) + : m_color(color) + , m_pp_box({0.827000, 0.772500, 0.137500, 0.075000}) +{} + +void PPDetector::make_overlays(VideoOverlaySet& items) const{ + items.add(m_color, m_pp_box); +} + +bool PPDetector::detect(const ImageViewRGB32& screen){ + ImageViewRGB32 region = extract_box_reference(screen, m_pp_box); + ImageRGB32 cropped = region.copy(); + + const size_t box_w = cropped.width(); + const size_t box_h = cropped.height(); + + // Apply mask to region to isolate the curved PP bar + static const ImageRGB32 mask_template(RESOURCE_PATH() + "PokemonPokopia/PPDetector-Mask.png"); + ImageRGB32 mask = mask_template.scale_to(box_w, box_h); + PackedBinaryMatrix opaque = compress_rgb32_to_binary_range(mask, 0xff000000, 0xffffffff); + filter_by_mask(opaque, cropped, Color(0, 0, 0, 0), true); + + // Apply filters to get percentage of bar filled and the color of the bar + std::vector filters = { + {Color(0), false, 0xff000000, 0xffffffff}, // fully opaque + {Color(0), false, 0xfff0af00, 0xfffff5b9}, // yellow: RGB(240, 175, 0), RGB(255, 245, 185) + {Color(0), false, 0xff6496e6, 0xffc8d7ff}, // blue: RGB(100, 150, 230), RGB(200, 215, 255) + }; + std::vector> filter_out = filter_rgb32_range(cropped, filters); + m_yellow_ratio = filter_out[0].second > 0 ? (double)filter_out[1].second / filter_out[0].second : 0.0; + m_blue_ratio = filter_out[0].second > 0 ? (double)filter_out[2].second / filter_out[0].second : 0.0; + + if (m_yellow_ratio > 0 || m_blue_ratio > 0){ + m_pp_percent = std::max(m_yellow_ratio, m_blue_ratio); + m_powered_up = m_yellow_ratio > 0.01 && m_blue_ratio < 0.01; + return true; + } + return false; +} } diff --git a/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.h b/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.h index 2c99a0a391..4b20c9a02f 100644 --- a/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.h +++ b/SerialPrograms/Source/PokemonPokopia/Inference/PokemonPokopia_MovesDetection.h @@ -40,6 +40,7 @@ class OverworldDetector : public StaticScreenDetector{ ImageFloatBox m_last_detected; std::optional m_last_detected_box; }; + class OverworldWatcher : public DetectorToFinder{ public: OverworldWatcher( @@ -50,6 +51,7 @@ class OverworldWatcher : public DetectorToFinder{ : DetectorToFinder("OverworldWatcher", hold_duration, color, overlay) {} }; + class OverworldGoneWatcher : public DetectorToFinder{ public: OverworldGoneWatcher( @@ -61,6 +63,37 @@ class OverworldGoneWatcher : public DetectorToFinder{ {} }; +class PPDetector : public StaticScreenDetector{ +public: + PPDetector( + Color color, + VideoOverlay* overlay = nullptr + ); + virtual void make_overlays(VideoOverlaySet& items) const override; + virtual bool detect(const ImageViewRGB32& screen) override; + + double get_pp_percent() const { return m_pp_percent; } + bool is_powered_up() const { return m_powered_up; } + +private: + Color m_color; + ImageFloatBox m_pp_box; + double m_yellow_ratio = 0.0; + double m_blue_ratio = 0.0; + double m_pp_percent = 0.0; + bool m_powered_up = false; +}; + +class PPWatcher : public DetectorToFinder{ +public: + PPWatcher( + Color color, + VideoOverlay* overlay = nullptr, + std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250) + ) + : DetectorToFinder("PPWatcher", hold_duration, color, overlay) + {} +}; } diff --git a/SerialPrograms/Source/PokemonPokopia/PokemonPokopia_Panels.cpp b/SerialPrograms/Source/PokemonPokopia/PokemonPokopia_Panels.cpp index 35ea78bfd0..8baba16d80 100644 --- a/SerialPrograms/Source/PokemonPokopia/PokemonPokopia_Panels.cpp +++ b/SerialPrograms/Source/PokemonPokopia/PokemonPokopia_Panels.cpp @@ -12,6 +12,7 @@ // General #include "Programs/PokemonPokopia_CloudIslandReset.h" +#include "Programs/PokemonPokopia_AutoMiner.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -39,6 +40,8 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back("---- Untested/Beta/WIP ----"); ret.emplace_back(make_single_switch_program()); if (IS_BETA_VERSION || PreloadSettings::instance().DEVELOPER_MODE){ + ret.emplace_back("---- Untested/Beta/WIP ----"); + ret.emplace_back(make_single_switch_program()); } // if (PreloadSettings::instance().DEVELOPER_MODE){ diff --git a/SerialPrograms/Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.cpp b/SerialPrograms/Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.cpp new file mode 100644 index 0000000000..7f76184edc --- /dev/null +++ b/SerialPrograms/Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.cpp @@ -0,0 +1,92 @@ +/* Auto Miner + * + * From: https://github.com/PokemonAutomation/ + * + */ + +//#include "CommonFramework/Logging/Logger.h" +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/Tools/ErrorDumper.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "CommonTools/StartupChecks/VideoResolutionCheck.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonPokopia/Inference/PokemonPokopia_ButtonDetector.h" +#include "PokemonPokopia/Inference/PokemonPokopia_MovesDetection.h" +#include "PokemonPokopia/Inference/PokemonPokopia_PCDetection.h" +#include "PokemonPokopia/Inference/PokemonPokopia_SettingsScreenDetector.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" + +#include "PokemonPokopia/Programs/PokemonPokopia_PCNavigation.h" +#include "PokemonPokopia/Programs/PokemonPokopia_AutoMiner.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonPokopia{ + +using namespace Pokemon; + + +AutoMiner_Descriptor::AutoMiner_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonPokopia:AutoMiner", + STRING_POKEMON + " Pokopia", "Auto Miner", + "Programs/PokemonPokopia/AutoMiner.html", + "Automatically mine resources on a Dream Island.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS + ) +{} +class AutoMiner_Descriptor::Stats : public StatsTracker{ +public: + Stats() + : errors(m_stats["Errors"]) + { + m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); + } + + std::atomic& errors; +}; +std::unique_ptr AutoMiner_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + + +AutoMiner::AutoMiner() + : GO_HOME_WHEN_DONE(false) + , NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600)) + , NOTIFICATIONS({ + &NOTIFICATION_STATUS_UPDATE, + &NOTIFICATION_PROGRAM_FINISH, + &NOTIFICATION_ERROR_FATAL, + }) +{ + PA_ADD_OPTION(GO_HOME_WHEN_DONE); + PA_ADD_OPTION(NOTIFICATIONS); +} + +void AutoMiner::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + assert_16_9_720p_min(env.logger(), env.console); + + // AutoMiner_Descriptor::Stats& stats = env.current_stats(); + + PPWatcher pp_watcher(COLOR_YELLOW, &env.console.overlay()); + wait_until( + env.console, context, + 60s, + {pp_watcher} + ); + env.console.log("percent: " + std::to_string(pp_watcher.get_pp_percent() * 100) + "%, powered up: " + (pp_watcher.is_powered_up() ? "yes" : "no")); + + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); + GO_HOME_WHEN_DONE.run_end_of_program(context); +} + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.h b/SerialPrograms/Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.h new file mode 100644 index 0000000000..9460d275ea --- /dev/null +++ b/SerialPrograms/Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.h @@ -0,0 +1,57 @@ +/* Auto Miner + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonPokopia_AutoMiner_H +#define PokemonAutomation_PokemonPokopia_AutoMiner_H + +#include "Common/Cpp/Options/SimpleIntegerOption.h" +#include "Common/Cpp/Options/ButtonOption.h" +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" + +namespace PokemonAutomation{ + +template class ControllerContext; + +namespace NintendoSwitch{ + +class ProController; +using ProControllerContext = ControllerContext; + +namespace PokemonPokopia{ + + +class AutoMiner_Descriptor : public SingleSwitchProgramDescriptor{ +public: + AutoMiner_Descriptor(); + + class Stats; + virtual std::unique_ptr make_stats() const override; +}; + + +class AutoMiner : public SingleSwitchProgramInstance{ +public: + AutoMiner(); + + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + +private: + GoHomeWhenDoneOption GO_HOME_WHEN_DONE; + + EventNotificationOption NOTIFICATION_STATUS_UPDATE; + EventNotificationsOption NOTIFICATIONS; +}; + + + +} +} +} +#endif diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 487aa970bf..551b5b459b 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1994,6 +1994,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonPokopia/PokemonPokopia_Panels.h Source/PokemonPokopia/PokemonPokopia_Settings.cpp Source/PokemonPokopia/PokemonPokopia_Settings.h + Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.cpp + Source/PokemonPokopia/Programs/PokemonPokopia_AutoMiner.h Source/PokemonPokopia/Programs/PokemonPokopia_CloudIslandReset.cpp Source/PokemonPokopia/Programs/PokemonPokopia_CloudIslandReset.h Source/PokemonPokopia/Programs/PokemonPokopia_PCNavigation.cpp