diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index a3ae492b29..0f9bae21c1 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -1349,6 +1349,8 @@ file(GLOB MAIN_SOURCES Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_LegendaryHunt-Emerald.h Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Deoxys.cpp Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Deoxys.h + Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.cpp + Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.h Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_StarterReset.cpp Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_StarterReset.h Source/PokemonRSE/Programs/TestPrograms/PokemonRSE_SoundListener.cpp diff --git a/SerialPrograms/SerialPrograms.pro b/SerialPrograms/SerialPrograms.pro index e20efbbb59..9458654c72 100644 --- a/SerialPrograms/SerialPrograms.pro +++ b/SerialPrograms/SerialPrograms.pro @@ -666,6 +666,7 @@ SOURCES += \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_AudioStarterReset.cpp \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_LegendaryHunt-Emerald.cpp \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Deoxys.cpp \ + Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.cpp \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_StarterReset.cpp \ Source/PokemonRSE/Programs/TestPrograms/PokemonRSE_SoundListener.cpp \ Source/PokemonSV/Inference/Battles/PokemonSV_BattleBallReader.cpp \ @@ -1832,6 +1833,7 @@ HEADERS += \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_AudioStarterReset.h \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_LegendaryHunt-Emerald.h \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Deoxys.h \ + Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.h \ Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_StarterReset.h \ Source/PokemonRSE/Programs/TestPrograms/PokemonRSE_SoundListener.h \ Source/PokemonSV/Inference/Battles/PokemonSV_BattleBallReader.h \ diff --git a/SerialPrograms/Source/PokemonRSE/PokemonRSE_Panels.cpp b/SerialPrograms/Source/PokemonRSE/PokemonRSE_Panels.cpp index 9d873c8d94..96870153cc 100644 --- a/SerialPrograms/Source/PokemonRSE/PokemonRSE_Panels.cpp +++ b/SerialPrograms/Source/PokemonRSE/PokemonRSE_Panels.cpp @@ -13,6 +13,7 @@ #include "Programs/ShinyHunting/PokemonRSE_AudioStarterReset.h" #include "Programs/ShinyHunting/PokemonRSE_LegendaryHunt-Emerald.h" #include "Programs/ShinyHunting/PokemonRSE_ShinyHunt-Deoxys.h" +#include "Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.h" #include "Programs/ShinyHunting/PokemonRSE_StarterReset.h" #include "Programs/TestPrograms/PokemonRSE_SoundListener.h" @@ -41,6 +42,7 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back("---- Shiny Hunting (Emerald) ----"); ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); if (PreloadSettings::instance().DEVELOPER_MODE){ diff --git a/SerialPrograms/Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.cpp b/SerialPrograms/Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.cpp new file mode 100644 index 0000000000..459c940b86 --- /dev/null +++ b/SerialPrograms/Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.cpp @@ -0,0 +1,230 @@ +/* E Shiny Mew + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "Common/Cpp/PrettyPrint.h" +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "Pokemon/Pokemon_Strings.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" +#include "PokemonRSE/Inference/Dialogs/PokemonRSE_DialogDetector.h" +#include "PokemonRSE/PokemonRSE_Navigation.h" +#include "PokemonRSE_ShinyHunt-Mew.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonRSE{ + +ShinyHuntMew_Descriptor::ShinyHuntMew_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonRSE:ShinyHuntMew", + Pokemon::STRING_POKEMON + " RSE", "Shiny Hunt - Mew", + "ComputerControl/blob/master/Wiki/Programs/PokemonRSE/ShinyHuntMew.md", + "Use the Run Away method to shiny hunt Mew in Emerald.", + FeedbackType::VIDEO_AUDIO, + AllowCommandsWhenRunning::DISABLE_COMMANDS, + {SerialPABotBase::OLD_NINTENDO_SWITCH_DEFAULT_REQUIREMENTS} + ) +{} + +struct ShinyHuntMew_Descriptor::Stats : public StatsTracker{ + Stats() + : resets(m_stats["Resets"]) + , shinies(m_stats["Shinies"]) + { + m_display_order.emplace_back("Resets"); + m_display_order.emplace_back("Shinies"); + } + std::atomic& resets; + std::atomic& shinies; +}; +std::unique_ptr ShinyHuntMew_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + +ShinyHuntMew::ShinyHuntMew() + : NOTIFICATION_SHINY( + "Shiny Found", + true, true, ImageAttachmentMode::JPG, + {"Notifs", "Showcase"} + ) + , NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600)) + , NOTIFICATIONS({ + &NOTIFICATION_SHINY, + &NOTIFICATION_STATUS_UPDATE, + &NOTIFICATION_PROGRAM_FINISH, + }) + , m_advanced_options( + "Advanced Options: You should not need to touch anything below here." + ) + , MEW_WAIT_TIME( + "Mew wait time:
Wait this long after entering for Mew to hide in the grass.", + LockMode::LOCK_WHILE_RUNNING, + "2000 ms" + ) + , DOOR_TO_GRASS_TIME( + "Door to grass time:
Time it takes to run from the door to the edge of the tall grass. Three steps up.", + LockMode::LOCK_WHILE_RUNNING, + "400 ms" + ) + , RIGHT_GRASS_1_TIME( + "First Right time:
Time it takes to turn right and take three steps. This follows the edge of the grass.", + LockMode::LOCK_WHILE_RUNNING, + "450 ms" + ) + , UP_GRASS_1_TIME( + "Move Up time::
Time it takes turn up and take one step.", + LockMode::LOCK_WHILE_RUNNING, + "200 ms" + ) + , RIGHT_GRASS_2_TIME( + "Second Right time:
Time it takes to turn right and take two steps.", + LockMode::LOCK_WHILE_RUNNING, + "260 ms" + ) + , FACE_UP_TIME( + "Face Up time:
Time it takes to tap the up button and face up, without taking a step.", + LockMode::LOCK_WHILE_RUNNING, + "150 ms" + ) +{ + PA_ADD_OPTION(NOTIFICATIONS); + PA_ADD_STATIC(m_advanced_options); + PA_ADD_OPTION(MEW_WAIT_TIME); + PA_ADD_OPTION(DOOR_TO_GRASS_TIME); + PA_ADD_OPTION(RIGHT_GRASS_1_TIME); + PA_ADD_OPTION(UP_GRASS_1_TIME); + PA_ADD_OPTION(RIGHT_GRASS_2_TIME); + PA_ADD_OPTION(FACE_UP_TIME); +} + +void ShinyHuntMew::enter_mew(SingleSwitchProgramEnvironment& env, ProControllerContext& context) { + BlackScreenOverWatcher enter_area(COLOR_RED, {0.282, 0.064, 0.448, 0.871}); + int ret = run_until( + env.console, context, + [](ProControllerContext& context){ + pbf_press_dpad(context, DPAD_UP, 250, 20); + pbf_wait(context, 300); + }, + {enter_area} + ); + context.wait_for_all_requests(); + if (ret != 0){ + env.log("Failed to enter area.", COLOR_RED); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to enter area.", + env.console + ); + } + else { + env.log("Entered area."); + } + + //Wait for Mew ! animation to finish + pbf_wait(context, MEW_WAIT_TIME); + context.wait_for_all_requests(); + + //DO NOT pause while running! + //Run up toward the extra tall grass - 3 steps + ssf_press_button(context, BUTTON_B, 0ms, DOOR_TO_GRASS_TIME); + pbf_press_dpad(context, DPAD_UP, DOOR_TO_GRASS_TIME, 0ms); + + //Turn right, take 3 steps + ssf_press_button(context, BUTTON_B, 0ms, RIGHT_GRASS_1_TIME); + pbf_press_dpad(context, DPAD_RIGHT, RIGHT_GRASS_1_TIME, 0ms); + + //Turn up, take 1 step + ssf_press_button(context, BUTTON_B, 0ms, UP_GRASS_1_TIME); + pbf_press_dpad(context, DPAD_UP, UP_GRASS_1_TIME, 0ms); + + //Turn right, take 2 steps + ssf_press_button(context, BUTTON_B, 0ms, RIGHT_GRASS_2_TIME); + pbf_press_dpad(context, DPAD_RIGHT, RIGHT_GRASS_2_TIME, 0ms); + + //Turn up. Start battle. + pbf_press_dpad(context, DPAD_UP, FACE_UP_TIME, 0ms); + + context.wait_for_all_requests(); +} + +void ShinyHuntMew::exit_mew(SingleSwitchProgramEnvironment& env, ProControllerContext& context) { + ssf_press_button(context, BUTTON_B, 0, 50); + pbf_press_dpad(context, DPAD_DOWN, 50, 20); + + ssf_press_button(context, BUTTON_B, 0, 90); + pbf_press_dpad(context, DPAD_LEFT, 90, 20); + + ssf_press_button(context, BUTTON_B, 0, 100); + pbf_press_dpad(context, DPAD_DOWN, 100, 20); + + BlackScreenOverWatcher exit_area(COLOR_RED, {0.282, 0.064, 0.448, 0.871}); + int ret = run_until( + env.console, context, + [](ProControllerContext& context){ + pbf_press_dpad(context, DPAD_DOWN, 250, 20); + pbf_wait(context, 300); + }, + {exit_area} + ); + context.wait_for_all_requests(); + if (ret != 0){ + env.log("Failed to exit area.", COLOR_RED); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to exit area.", + env.console + ); + } + else { + env.log("Exited area."); + } +} + +void ShinyHuntMew::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + ShinyHuntMew_Descriptor::Stats& stats = env.current_stats(); + + /* + * Requires more precision to ensure a Mew encounter every time. + * Movement is very configurable due to this. + * Enter on the left side, run up and hug the grass to the edge just after the flower on the right + * This but without the bike: + * https://old.reddit.com/r/ShinyPokemon/comments/1c773oi/gen3_discuss_is_this_the_fastest_way_to_encounter/ + */ + + while (true) { + enter_mew(env, context); + + bool legendary_shiny = handle_encounter(env.console, context, true); + if (legendary_shiny) { + stats.shinies++; + env.update_stats(); + send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", env.console.video().snapshot(), true); + break; + } + env.log("No shiny found."); + flee_battle(env.console, context); + + //Close dialog + pbf_mash_button(context, BUTTON_B, 250); + context.wait_for_all_requests(); + + exit_mew(env, context); + + stats.resets++; + env.update_stats(); + } + + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); +} + +} +} +} diff --git a/SerialPrograms/Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.h b/SerialPrograms/Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.h new file mode 100644 index 0000000000..a2194603b2 --- /dev/null +++ b/SerialPrograms/Source/PokemonRSE/Programs/ShinyHunting/PokemonRSE_ShinyHunt-Mew.h @@ -0,0 +1,60 @@ +/* E Shiny Mew + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonRSE_ShinyHuntMew_H +#define PokemonAutomation_PokemonRSE_ShinyHuntMew_H + +#include "Common/Cpp/Options/StaticTextOption.h" +#include "Common/Cpp/Options/TimeDurationOption.h" +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonRSE{ + +class ShinyHuntMew_Descriptor : public SingleSwitchProgramDescriptor{ +public: + ShinyHuntMew_Descriptor(); + struct Stats; + virtual std::unique_ptr make_stats() const override; +}; + +class ShinyHuntMew : public SingleSwitchProgramInstance{ +public: + ShinyHuntMew(); + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + + virtual void start_program_border_check( + CancellableScope& scope, + VideoStream& stream, + FeedbackType feedback_type + ) override{} + +private: + EventNotificationOption NOTIFICATION_SHINY; + EventNotificationOption NOTIFICATION_STATUS_UPDATE; + EventNotificationsOption NOTIFICATIONS; + + SectionDividerOption m_advanced_options; + + MillisecondsOption MEW_WAIT_TIME; + MillisecondsOption DOOR_TO_GRASS_TIME; + MillisecondsOption RIGHT_GRASS_1_TIME; + MillisecondsOption UP_GRASS_1_TIME; + MillisecondsOption RIGHT_GRASS_2_TIME; + MillisecondsOption FACE_UP_TIME; + + void enter_mew(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + void exit_mew(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + +}; + +} +} +} +#endif +