From 832243712cab5275e25cade7d93c81eabd72958e Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 7 Aug 2025 13:03:32 -0700 Subject: [PATCH 1/2] MysteryGift: add option for OBTAINING_METHOD. e.g. via Code vs via Internet --- .../Farming/PokemonSV_ClaimMysteryGift.cpp | 74 +++++++++++++++---- .../Farming/PokemonSV_ClaimMysteryGift.h | 12 ++- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp index 98822f0560..d7e85925e5 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp @@ -58,6 +58,7 @@ ClaimMysteryGift_Descriptor::ClaimMysteryGift_Descriptor() ClaimMysteryGift::~ClaimMysteryGift(){ + OBTAINING_METHOD.remove_listener(*this); STARTING_POINT.remove_listener(*this); } @@ -72,17 +73,28 @@ ClaimMysteryGift::ClaimMysteryGift() "Starting point:", { {StartingPoint::NEW_GAME, "new-game", "New Game: Start after you have selected your username and character appearance"}, - {StartingPoint::IN_MYSTERY_GIFT, "in-mystery-gift", "Start in Mystery Gift window, with cursor on the “1” key."}, + {StartingPoint::IN_MYSTERY_GIFT_CODE_WINDOW, "in-mystery-gift-code-window", "Start in Mystery Gift code window, with cursor on the “1” key."}, {StartingPoint::DONE_TUTORIAL, "done-tutorial", "Start in game. But with all menus closed. Tutorial must be completed. You need to be outside, where you can use Pokeportal."}, }, LockMode::LOCK_WHILE_RUNNING, StartingPoint::NEW_GAME ) + , OBTAINING_METHOD( + "Method for obtaining mystery gift:", + { + {ObtainingMethod::VIA_INTERNET_ALL, "via-internet-all", "Via Internet: Get all mystery gifts from the \"Via internet\" screen."}, + {ObtainingMethod::VIA_INTERNET_ONE, "via-internet-one", "Via Internet: Get only the top mystery gift from the \"Via internet\" screen."}, + {ObtainingMethod::VIA_CODE, "via-code", "Via Code: Get the mystery gift based on the code entered below."}, + }, + LockMode::LOCK_WHILE_RUNNING, + ObtainingMethod::VIA_INTERNET_ALL + ) , MYSTERY_GIFT_NOTE{ - "Ensure you are logged into a Nintendo account. This account does NOT need to have a subscription to Nintendo Switch Online.
" - "In the keyboard section below, you only need to adjust the option for Swtich 0. Ignore the options for the other Switches.
" - "Refer to the documentation on github for more details." + "Ensure you are logged into a Nintendo account. This account does NOT need to have a subscription to Nintendo Switch Online." } + , MULTISWITCH_NOTE{ + "In the keyboard section below, you only need to adjust the option for Swtich 0. Ignore the options for the other Switches." + } , CODE( "Mystery Gift Code:
Mystery Gift code. (not case sensitive)
" "(Box is big so it's easy to land your mouse on.)", @@ -101,8 +113,10 @@ ClaimMysteryGift::ClaimMysteryGift() { PA_ADD_OPTION(LANGUAGE); - PA_ADD_OPTION(STARTING_POINT); PA_ADD_OPTION(MYSTERY_GIFT_NOTE); + PA_ADD_OPTION(STARTING_POINT); + PA_ADD_OPTION(OBTAINING_METHOD); + PA_ADD_OPTION(MULTISWITCH_NOTE); PA_ADD_OPTION(CODE); PA_ADD_OPTION(SETTINGS); PA_ADD_OPTION(GO_HOME_WHEN_DONE); @@ -111,12 +125,28 @@ ClaimMysteryGift::ClaimMysteryGift() ClaimMysteryGift::on_config_value_changed(this); + OBTAINING_METHOD.add_listener(*this); STARTING_POINT.add_listener(*this); } void ClaimMysteryGift::on_config_value_changed(void* object){ + if (STARTING_POINT == StartingPoint::IN_MYSTERY_GIFT_CODE_WINDOW){ + OBTAINING_METHOD.set_visibility(ConfigOptionState::HIDDEN); + }else{ + OBTAINING_METHOD.set_visibility(ConfigOptionState::ENABLED); + } + if (OBTAINING_METHOD == ObtainingMethod::VIA_CODE){ + MULTISWITCH_NOTE.set_visibility(ConfigOptionState::ENABLED); + CODE.set_visibility(ConfigOptionState::ENABLED); + SETTINGS.set_visibility(ConfigOptionState::ENABLED); + }else{ + MULTISWITCH_NOTE.set_visibility(ConfigOptionState::HIDDEN); + CODE.set_visibility(ConfigOptionState::HIDDEN); + SETTINGS.set_visibility(ConfigOptionState::HIDDEN); + } + } void ClaimMysteryGift::enter_mystery_gift_code(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ @@ -138,7 +168,7 @@ void ClaimMysteryGift::enter_mystery_gift_code(SingleSwitchProgramEnvironment& e } -void ClaimMysteryGift::enter_mystery_gift_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index){ +void ClaimMysteryGift::enter_mystery_gift_code_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index){ env.console.log("Save game, then try to enter the mystery gift window.", COLOR_YELLOW); save_game_from_menu_or_overworld(env.program_info(), env.console, context, false); @@ -154,7 +184,7 @@ void ClaimMysteryGift::enter_mystery_gift_window(SingleSwitchProgramEnvironment& try { clear_dialog(env.console, context, ClearDialogMode::STOP_TIMEOUT, 10, {CallbackEnum::PROMPT_DIALOG}); }catch(OperationFailedException&){ - env.console.log("enter_mystery_gift_window: Failed to detect the dialog that leads to the Mystery Gift window. Reset game and re-try.", COLOR_YELLOW); + env.console.log("enter_mystery_gift_code_window: Failed to detect the dialog that leads to the Mystery Gift code window. Reset game and re-try.", COLOR_YELLOW); reset_game(env.program_info(), env.console, context); continue; } @@ -199,7 +229,7 @@ void ClaimMysteryGift::enter_mystery_gift_window(SingleSwitchProgramEnvironment& {key1_selected} ); if (ret < 0){ // failed to detect Key 1 being highlighted. Reset game and re-try - env.console.log("enter_mystery_gift_window: Failed to detect the Mystery Gift window. Reset game and re-try.", COLOR_YELLOW); + env.console.log("enter_mystery_gift_code_window: Failed to detect the Mystery Gift code window. Reset game and re-try.", COLOR_YELLOW); reset_game(env.program_info(), env.console, context); continue; } @@ -210,7 +240,7 @@ void ClaimMysteryGift::enter_mystery_gift_window(SingleSwitchProgramEnvironment& OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "enter_mystery_gift_window(): Failed to reach Mystery Gift screen after several attempts.", + "enter_mystery_gift_code_window(): Failed to reach Mystery Gift code window after several attempts.", env.console ); } @@ -241,13 +271,29 @@ void ClaimMysteryGift::program(SingleSwitchProgramEnvironment& env, ProControlle if (STARTING_POINT == StartingPoint::NEW_GAME){ run_autostory_until_pokeportal_unlocked(env, context); env.console.log("Done Autostory portion. Pokeportal should now be unlocked."); - enter_mystery_gift_window(env, context, 2); - enter_mystery_gift_code(env, context); - }else if(STARTING_POINT == StartingPoint::IN_MYSTERY_GIFT){ + if (OBTAINING_METHOD == ObtainingMethod::VIA_CODE){ + enter_mystery_gift_code_window(env, context, 2); + enter_mystery_gift_code(env, context); + }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ALL){ + + }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ONE){ + + } + + }else if(STARTING_POINT == StartingPoint::IN_MYSTERY_GIFT_CODE_WINDOW){ + // only claim the mystery gift via code. not via internet enter_mystery_gift_code(env, context); + }else if (STARTING_POINT == StartingPoint::DONE_TUTORIAL){ - enter_mystery_gift_window(env, context, 3); - enter_mystery_gift_code(env, context); + + if (OBTAINING_METHOD == ObtainingMethod::VIA_CODE){ + enter_mystery_gift_code_window(env, context, 3); + enter_mystery_gift_code(env, context); + }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ALL){ + + }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ONE){ + + } }else{ throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Unknown STARTING_POINT."); } diff --git a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h index 316b5e79a4..d9f9b5ffad 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h +++ b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h @@ -40,7 +40,7 @@ class ClaimMysteryGift : public SingleSwitchProgramInstance, public ConfigOption virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; void run_autostory_until_pokeportal_unlocked(SingleSwitchProgramEnvironment& env, ProControllerContext& context); - void enter_mystery_gift_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index); + void enter_mystery_gift_code_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index); void enter_mystery_gift_code(SingleSwitchProgramEnvironment& env, ProControllerContext& context); private: @@ -54,12 +54,20 @@ class ClaimMysteryGift : public SingleSwitchProgramInstance, public ConfigOption enum class StartingPoint{ NEW_GAME, - IN_MYSTERY_GIFT, + IN_MYSTERY_GIFT_CODE_WINDOW, DONE_TUTORIAL, }; + enum class ObtainingMethod{ + VIA_INTERNET_ALL, + VIA_INTERNET_ONE, + VIA_CODE, + }; + EnumDropdownOption STARTING_POINT; + EnumDropdownOption OBTAINING_METHOD; StaticTextOption MYSTERY_GIFT_NOTE; + StaticTextOption MULTISWITCH_NOTE; TextEditOption CODE; FastCodeEntrySettingsOption SETTINGS; From 4f4c49e7db1e9933fdad4dd19328577b047c7408 Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 7 Aug 2025 18:28:15 -0700 Subject: [PATCH 2/2] claim mystery gift via Internet --- .../Farming/PokemonSV_ClaimMysteryGift.cpp | 121 +++++++++++++++++- .../Farming/PokemonSV_ClaimMysteryGift.h | 4 +- 2 files changed, 117 insertions(+), 8 deletions(-) diff --git a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp index d7e85925e5..3adb34374d 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.cpp @@ -74,7 +74,7 @@ ClaimMysteryGift::ClaimMysteryGift() { {StartingPoint::NEW_GAME, "new-game", "New Game: Start after you have selected your username and character appearance"}, {StartingPoint::IN_MYSTERY_GIFT_CODE_WINDOW, "in-mystery-gift-code-window", "Start in Mystery Gift code window, with cursor on the “1” key."}, - {StartingPoint::DONE_TUTORIAL, "done-tutorial", "Start in game. But with all menus closed. Tutorial must be completed. You need to be outside, where you can use Pokeportal."}, + {StartingPoint::DONE_TUTORIAL, "done-tutorial", "Start in game. Tutorial must be completed. All menus closed. Disconnected from internet. You need to be outside, where you can use Pokeportal."}, }, LockMode::LOCK_WHILE_RUNNING, StartingPoint::NEW_GAME @@ -82,12 +82,12 @@ ClaimMysteryGift::ClaimMysteryGift() , OBTAINING_METHOD( "Method for obtaining mystery gift:", { - {ObtainingMethod::VIA_INTERNET_ALL, "via-internet-all", "Via Internet: Get all mystery gifts from the \"Via internet\" screen."}, - {ObtainingMethod::VIA_INTERNET_ONE, "via-internet-one", "Via Internet: Get only the top mystery gift from the \"Via internet\" screen."}, + // {ObtainingMethod::VIA_INTERNET_ALL, "via-internet-all", "Via Internet: Get all mystery gifts from the \"Get via Internet\" screen (except for the Mythical Pecha Berry)."}, + {ObtainingMethod::VIA_INTERNET_NONE, "via-internet-one", "Via Internet: Go to the Mystery Gift \"Get via Internet\" screen. Don't claim anything."}, {ObtainingMethod::VIA_CODE, "via-code", "Via Code: Get the mystery gift based on the code entered below."}, }, LockMode::LOCK_WHILE_RUNNING, - ObtainingMethod::VIA_INTERNET_ALL + ObtainingMethod::VIA_INTERNET_NONE ) , MYSTERY_GIFT_NOTE{ "Ensure you are logged into a Nintendo account. This account does NOT need to have a subscription to Nintendo Switch Online." @@ -168,6 +168,108 @@ void ClaimMysteryGift::enter_mystery_gift_code(SingleSwitchProgramEnvironment& e } +void ClaimMysteryGift::enter_mystery_gift_via_internet_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index){ + env.console.log("Save game, then try to enter the mystery gift via internet window.", COLOR_YELLOW); + save_game_from_menu_or_overworld(env.program_info(), env.console, context, false); + + size_t max_attempts = 5; + for (size_t i = 0; i < max_attempts; i++){ + enter_menu_from_overworld(env.program_info(), env.console, context, menu_index); + pbf_press_button(context, BUTTON_A, 20, 4 * TICKS_PER_SECOND); + pbf_press_dpad(context, DPAD_UP, 20, 105); + pbf_press_button(context, BUTTON_A, 20, 4 * TICKS_PER_SECOND); + pbf_press_button(context, BUTTON_A, 20, 4 * TICKS_PER_SECOND); + try { + clear_dialog(env.console, context, ClearDialogMode::STOP_TIMEOUT, 10, {CallbackEnum::PROMPT_DIALOG}); + }catch(OperationFailedException&){ + env.console.log("enter_mystery_gift_via_internet_window: Failed to detect the dialog that leads to the Mystery Gift code window. Reset game and re-try.", COLOR_YELLOW); + reset_game(env.program_info(), env.console, context); + continue; + } + + return; + } + + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "enter_mystery_gift_code_window(): Failed to reach Mystery Gift code window after several attempts.", + env.console + ); +} + + +// void ClaimMysteryGift::claim_internet_mystery_gift(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +// env.log("Claim Mystery Gifts via Internet."); +// context.wait_for_all_requests(); +// ImageFloatBox box{0.256326, 0.099804, 0.044004, 0.616438}; +// GradientArrowWatcher arrow(COLOR_RED, GradientArrowType::RIGHT, box); +// int ret = wait_until( +// env.console, context, +// Milliseconds(10 * 1000), +// { arrow } +// ); +// if (ret == 0){ +// env.console.log("Gradient arrow detected."); +// }else{ +// OperationFailedException::fire( +// ErrorReport::SEND_ERROR_REPORT, +// "Failed to detect gradient arrow. We might not be in the Mystery Gift via Internet screen.", +// env.console +// ); +// } + +// std::vector y_position_seen; +// // determine how many mystery gifts are available to claim +// while(true){ +// context.wait_for_all_requests(); +// ImageFloatBox result_box; +// arrow.detect(result_box, console.video().snapshot()); +// double current_y_pos = result_box.y; +// bool seen = false; +// for (double y_pos : y_position_seen){ +// // if difference is less than 0.02, then it's the same +// if (std::abs(current_y_pos - y_pos) < 0.02){ +// seen = true; +// break; +// } +// } +// if (!seen){ +// y_position_seen.emplace_back(current_y_pos); +// }else{ +// pbf_press_dpad(context, DPAD_DOWN, 160ms, 320ms); +// } +// } + +// while(true){ +// context.wait_for_all_requests(); +// ImageFloatBox result_box; +// arrow.detect(result_box, console.video().snapshot()); +// double y_pos = result_box.y; + +// pbf_press_dpad(context, DPAD_DOWN, 160ms, 320ms); +// // collect the mystery gift. Press A until you see the Gradient arrow again. +// ret = run_until( +// env.console, context, +// [&](ProControllerContext& context){ +// for (size_t i = 0; i < 40; i++){ +// pbf_press_button(context, BUTTON_A, 160ms, 1000ms); +// } +// }, +// arrow +// ); +// if (ret < 0){ +// OperationFailedException::fire( +// ErrorReport::SEND_ERROR_REPORT, +// "Failed to detect gradient arrow. We might not be in the Mystery Gift via Internet screen.", +// env.console +// ); +// } + +// } + + +// } + void ClaimMysteryGift::enter_mystery_gift_code_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index){ env.console.log("Save game, then try to enter the mystery gift window.", COLOR_YELLOW); save_game_from_menu_or_overworld(env.program_info(), env.console, context, false); @@ -275,23 +377,28 @@ void ClaimMysteryGift::program(SingleSwitchProgramEnvironment& env, ProControlle enter_mystery_gift_code_window(env, context, 2); enter_mystery_gift_code(env, context); }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ALL){ + // enter_mystery_gift_via_internet_window(env, context, 2); + // claim_internet_mystery_gift(env, context); - }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ONE){ + }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_NONE){ + enter_mystery_gift_via_internet_window(env, context, 2); } }else if(STARTING_POINT == StartingPoint::IN_MYSTERY_GIFT_CODE_WINDOW){ // only claim the mystery gift via code. not via internet enter_mystery_gift_code(env, context); - + }else if (STARTING_POINT == StartingPoint::DONE_TUTORIAL){ if (OBTAINING_METHOD == ObtainingMethod::VIA_CODE){ enter_mystery_gift_code_window(env, context, 3); enter_mystery_gift_code(env, context); }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ALL){ + // enter_mystery_gift_via_internet_window(env, context, 3); - }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_ONE){ + }else if(OBTAINING_METHOD == ObtainingMethod::VIA_INTERNET_NONE){ + enter_mystery_gift_via_internet_window(env, context, 3); } }else{ diff --git a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h index d9f9b5ffad..c721928c95 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h +++ b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_ClaimMysteryGift.h @@ -40,6 +40,8 @@ class ClaimMysteryGift : public SingleSwitchProgramInstance, public ConfigOption virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; void run_autostory_until_pokeportal_unlocked(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + void enter_mystery_gift_via_internet_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index); + void claim_internet_mystery_gift(SingleSwitchProgramEnvironment& env, ProControllerContext& context); void enter_mystery_gift_code_window(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int menu_index); void enter_mystery_gift_code(SingleSwitchProgramEnvironment& env, ProControllerContext& context); @@ -60,7 +62,7 @@ class ClaimMysteryGift : public SingleSwitchProgramInstance, public ConfigOption enum class ObtainingMethod{ VIA_INTERNET_ALL, - VIA_INTERNET_ONE, + VIA_INTERNET_NONE, VIA_CODE, };