From a1bb543c42b385f13e50c9a48253aea0b40f8afe Mon Sep 17 00:00:00 2001 From: kichithewolf Date: Wed, 19 Mar 2025 10:05:38 -0400 Subject: [PATCH] lgpe gift reset, feedback type for lgpe programs --- SerialPrograms/CMakeLists.txt | 2 + SerialPrograms/SerialPrograms.pro | 2 + .../Source/PokemonLGPE/PokemonLGPE_Panels.cpp | 2 + .../Farming/PokemonLGPE_DailyItemFarmer.cpp | 2 +- .../ShinyHunting/PokemonLGPE_AlolanTrade.cpp | 10 +- .../ShinyHunting/PokemonLGPE_GiftReset.cpp | 189 ++++++++++++++++++ .../ShinyHunting/PokemonLGPE_GiftReset.h | 49 +++++ 7 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp create mode 100644 SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index 65c92eb831..37717c0b1a 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -1380,6 +1380,8 @@ file(GLOB MAIN_SOURCES Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.h Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.cpp Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.h Source/PokemonLGPE/PokemonLGPE_Panels.cpp diff --git a/SerialPrograms/SerialPrograms.pro b/SerialPrograms/SerialPrograms.pro index 93fa2f0500..da14c4525d 100644 --- a/SerialPrograms/SerialPrograms.pro +++ b/SerialPrograms/SerialPrograms.pro @@ -677,6 +677,7 @@ SOURCES += \ Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.cpp \ Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp \ + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp \ Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.cpp \ Source/PokemonLGPE/PokemonLGPE_Panels.cpp \ Source/PokemonLGPE/PokemonLGPE_Settings.cpp \ @@ -1868,6 +1869,7 @@ HEADERS += \ Source/PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.h \ Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.h \ Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h \ + Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h \ Source/PokemonLGPE/Programs/PokemonLGPE_GameEntry.h \ Source/PokemonLGPE/PokemonLGPE_Panels.h \ Source/PokemonLGPE/PokemonLGPE_Settings.h \ diff --git a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp index 4f031207b4..2043d70d30 100644 --- a/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp +++ b/SerialPrograms/Source/PokemonLGPE/PokemonLGPE_Panels.cpp @@ -11,6 +11,7 @@ #include "Programs/Farming/PokemonLGPE_DailyItemFarmer.h" #include "Programs/ShinyHunting/PokemonLGPE_AlolanTrade.h" +#include "Programs/ShinyHunting/PokemonLGPE_GiftReset.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -31,6 +32,7 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back("---- Shiny Hunting ----"); ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); return ret; } diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp b/SerialPrograms/Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp index 8bb7bb6255..ca4868116a 100644 --- a/SerialPrograms/Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp +++ b/SerialPrograms/Source/PokemonLGPE/Programs/Farming/PokemonLGPE_DailyItemFarmer.cpp @@ -33,7 +33,7 @@ DailyItemFarmer_Descriptor::DailyItemFarmer_Descriptor() Pokemon::STRING_POKEMON + " LGPE", "Daily Item Farmer", "", "Farm daily item respawns (ex. fossils) by date-skipping.", - FeedbackType::NONE, + FeedbackType::REQUIRED, AllowCommandsWhenRunning::DISABLE_COMMANDS, {ControllerFeature::NintendoSwitch_RightJoycon}, FasterIfTickPrecise::NOT_FASTER diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp index 1cbb33b04a..0c33f98205 100644 --- a/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp +++ b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_AlolanTrade.cpp @@ -29,7 +29,7 @@ AlolanTrade_Descriptor::AlolanTrade_Descriptor() Pokemon::STRING_POKEMON + " LGPE", "Alolan Trade", "", "Shiny hunt Alolan forms by trading in-game.", - FeedbackType::NONE, + FeedbackType::REQUIRED, AllowCommandsWhenRunning::DISABLE_COMMANDS, {ControllerFeature::NintendoSwitch_RightJoycon}, FasterIfTickPrecise::NOT_FASTER @@ -136,19 +136,18 @@ void AlolanTrade::program(SingleSwitchProgramEnvironment& env, CancellableScope& /* WARNING: JOYCON TEST PROGRAM. Not well tested. Bare minimum in general. - Only works with Right joycon atm. Do not update right joycon. Decline the update before running this. - Right joycon required for home button (this means no on-switch screenshots). - Also don't remap any of the buttons in the switch button mapping settings. Yet? Could use this to add Home and Screenshot. + Also don't remap any of the buttons in the switch button mapping settings. Preconditions: DO NOT have any Pokemon you want to keep in your boxes. Move them out to Home first. Favoriting a Pokemon does not prevent it from being traded. - This must not be your first time doing the trade. (I've done all the trades, so I can't check first time trade behavior.) + ?This must not be your first time doing the trade? (I've done all the trades, so I can't check first time trade behavior.) Setup: Catch the Kanto variant of the target. Put this number in NUM_TRADES. Stand in front of trade NPC. + Save the game. Start the program in-game. Future additions?: @@ -230,6 +229,7 @@ void AlolanTrade::program(SingleSwitchProgramEnvironment& env, CancellableScope& env.update_stats(); send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", screen, true); shiny_found = true; + //TODO: Favorite the shiny. } else { env.log("Not shiny."); diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp new file mode 100644 index 0000000000..69c82b12c5 --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.cpp @@ -0,0 +1,189 @@ +/* LGPE Gift Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "CommonFramework/ProgramStats/StatsTracking.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "CommonTools/Async/InferenceRoutines.h" +#include "CommonTools/StartupChecks/VideoResolutionCheck.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" +#include "Pokemon/Pokemon_Strings.h" +#include "CommonTools/VisualDetectors/BlackScreenDetector.h" +#include "PokemonLGPE/Inference/PokemonLGPE_ShinySymbolDetector.h" +#include "PokemonLGPE/Programs/PokemonLGPE_GameEntry.h" +#include "PokemonLGPE_GiftReset.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + +GiftReset_Descriptor::GiftReset_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonLGPE:GiftReset", + Pokemon::STRING_POKEMON + " LGPE", "Gift Reset", + "", + "Shiny hunt gift Pokemon by resetting the game.", + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS, + {ControllerFeature::NintendoSwitch_RightJoycon}, + FasterIfTickPrecise::NOT_FASTER + ) +{} + +struct GiftReset_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 GiftReset_Descriptor::make_stats() const{ + return std::unique_ptr(new Stats()); +} + +GiftReset::GiftReset() + : GO_HOME_WHEN_DONE(false) + , 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, + }) +{ + PA_ADD_OPTION(GO_HOME_WHEN_DONE); + PA_ADD_OPTION(NOTIFICATIONS); +} + +void GiftReset::program(SingleSwitchProgramEnvironment& env, CancellableScope& scope){ + JoyconContext context(scope, env.console.controller()); + assert_16_9_720p_min(env.logger(), env.console); + GiftReset_Descriptor::Stats& stats = env.current_stats(); + + /* + Setup: + Stand in front of trade NPC. + Start the program in-game. + + Must have 500yen for magikarp. + Gift Pokemon: https://www.serebii.net/letsgopikachueevee/gift.shtml + Tested with Magikarp on a new save. Should work with most of the others. + Can always add a dropdown with target if it doesn't. + Fossils will be handled in a different program. + */ + + bool shiny_found = false; + while (!shiny_found) { + //Purchase Magikarp + BlackScreenOverWatcher gift_obtained(COLOR_RED); + int ret = run_until( + env.console, context, + [](JoyconContext& context){ + pbf_mash_button(context, BUTTON_A, 20000ms); + }, + {gift_obtained} + ); + context.wait_for_all_requests(); + if (ret != 0){ + env.log("Failed to receive gift Pokemon.", COLOR_RED); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to receive gift Pokemon.", + env.console + ); + } + else { + env.log("Received gift Pokemon."); + } + send_program_status_notification( + env, NOTIFICATION_STATUS_UPDATE, + "Received gift Pokemon." + ); + + //Wait a bit. + pbf_wait(context, 2500ms); + context.wait_for_all_requests(); + + //Open menu, open party, open boxes + env.log("Opening boxes."); + pbf_press_button(context, BUTTON_X, 200ms, 500ms); + pbf_press_button(context, BUTTON_A, 200ms, 1500ms); + pbf_press_button(context, BUTTON_Y, 200ms, 2000ms); + context.wait_for_all_requests(); + + //Sort by order caught + env.log("Sorting by order caught."); + pbf_press_button(context, BUTTON_Y, 200ms, 1000ms); + pbf_press_button(context, BUTTON_A, 200ms, 1000ms); + pbf_press_button(context, BUTTON_A, 200ms, 1000ms); + context.wait_for_all_requests(); + + //Press left to go to last (most recent) Pokemon + env.log("Opening summary of most recent Pokemon."); + pbf_move_joystick(context, 0, 128, 100ms, 100ms); + context.wait_for_all_requests(); + + //View summary - it takes a moment to load + env.log("Viewing summary."); + pbf_press_button(context, BUTTON_A, 200ms, 1000ms); + pbf_move_joystick(context, 128, 255, 100ms, 100ms); + pbf_move_joystick(context, 128, 255, 100ms, 100ms); + pbf_press_button(context, BUTTON_A, 200ms, 100ms); + context.wait_for_all_requests(); + + pbf_wait(context, 5000ms); + context.wait_for_all_requests(); + + //Now check for shinies. Check everything that was traded. + VideoSnapshot screen = env.console.video().snapshot(); + ShinySymbolDetector shiny_checker(COLOR_YELLOW); + bool check = shiny_checker.read(env.console.logger(), screen); + + if (check) { + env.log("Shiny detected!"); + stats.shinies++; + env.update_stats(); + send_program_notification(env, NOTIFICATION_SHINY, COLOR_YELLOW, "Shiny found!", {}, "", screen, true); + shiny_found = true; + } + else { + env.log("Not shiny. Resetting game."); + send_program_status_notification( + env, NOTIFICATION_STATUS_UPDATE, + "Not shiny. Resetting game." + ); + + //Reset game + pbf_press_button(context, BUTTON_HOME, 200ms, 2000ms); + reset_game_from_home(env, env.console, context, 3000ms); + context.wait_for_all_requests(); + + stats.resets++; + env.update_stats(); + } + } + + if (GO_HOME_WHEN_DONE) { + pbf_press_button(context, BUTTON_HOME, 200ms, 1000ms); + } + send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); +} + + +} +} +} diff --git a/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h new file mode 100644 index 0000000000..4d1d8ced2f --- /dev/null +++ b/SerialPrograms/Source/PokemonLGPE/Programs/ShinyHunting/PokemonLGPE_GiftReset.h @@ -0,0 +1,49 @@ +/* LGPE Gift Reset + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonLGPE_GiftReset_H +#define PokemonAutomation_PokemonLGPE_GiftReset_H + +#include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" +#include "CommonFramework/Notifications/EventNotificationsTable.h" +#include "Common/Cpp/Options/SimpleIntegerOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonLGPE{ + +class GiftReset_Descriptor : public SingleSwitchProgramDescriptor{ +public: + GiftReset_Descriptor(); + struct Stats; + virtual std::unique_ptr make_stats() const override; +}; + +class GiftReset : public SingleSwitchProgramInstance{ +public: + GiftReset(); + virtual void program(SingleSwitchProgramEnvironment& env, CancellableScope& scope) override; + +private: + GoHomeWhenDoneOption GO_HOME_WHEN_DONE; + + EventNotificationOption NOTIFICATION_SHINY; + EventNotificationOption NOTIFICATION_STATUS_UPDATE; + EventNotificationsOption NOTIFICATIONS; +}; + + + + +} +} +} +#endif + + +