From 550d814b9ec9394188352a4dadc47c261f717c6f Mon Sep 17 00:00:00 2001 From: ZHDreamer Date: Sat, 9 May 2026 17:31:14 -0700 Subject: [PATCH 1/4] Add Hoopa to ZA Stats Reset --- .../NonShinyHunting/PokemonLZA_StatsReset.cpp | 126 +++++++++++++++++- .../NonShinyHunting/PokemonLZA_StatsReset.h | 4 + 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp index f09ec9a64c..c81b7e8147 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp @@ -23,6 +23,7 @@ #include "PokemonLZA/Programs/PokemonLZA_BasicNavigation.h" #include "PokemonLZA/Programs/PokemonLZA_FastTravelNavigation.h" #include "PokemonLZA/Programs/PokemonLZA_MenuNavigation.h" +#include "PokemonLZA/Programs/PokemonLZA_TrainerBattle.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -80,6 +81,7 @@ StatsReset::StatsReset() {GiftPokemon::MELTAN, "meltan", "Meltan" }, {GiftPokemon::MELMETAL, "melmetal", "Melmetal"}, {GiftPokemon::VOLCANION,"volcanion","Volcanion"}, + {GiftPokemon::HOOPA, "hoopa", "Hoopa"}, }, LockMode::LOCK_WHILE_RUNNING, GiftPokemon::FLOETTE @@ -134,6 +136,7 @@ StatsReset::StatsReset() PA_ADD_OPTION(SCROLL_RELEASE); PA_ADD_OPTION(POST_THROW_WAIT); PA_ADD_OPTION(DOWN_SCROLLS); + PA_ADD_OPTION(BATTLE_AI); PA_ADD_OPTION(HP); PA_ADD_OPTION(ATTACK); PA_ADD_OPTION(DEFENSE); @@ -154,13 +157,16 @@ StatsReset::~StatsReset(){ void StatsReset::on_config_value_changed(void* object){ ConfigOptionState state_ball = (POKEMON == GiftPokemon::GENESECT || POKEMON == GiftPokemon::MELTAN || POKEMON == GiftPokemon::VOLCANION) ? ConfigOptionState::ENABLED : ConfigOptionState::HIDDEN; - ConfigOptionState state_donut = (POKEMON == GiftPokemon::GENESECT || POKEMON == GiftPokemon::MELMETAL) + ConfigOptionState state_donut = (POKEMON == GiftPokemon::GENESECT || POKEMON == GiftPokemon::MELMETAL || POKEMON == GiftPokemon::HOOPA) ? ConfigOptionState::ENABLED : ConfigOptionState::HIDDEN; + ConfigOptionState state_battle = (POKEMON == GiftPokemon::HOOPA) + ? ConfigOptionState::ENABLED : ConfigOptionState::HIDDEN; RIGHT_SCROLLS.set_visibility(state_ball); SCROLL_HOLD.set_visibility(state_ball); SCROLL_RELEASE.set_visibility(state_ball); POST_THROW_WAIT.set_visibility(state_ball); DOWN_SCROLLS.set_visibility(state_donut); + BATTLE_AI.set_visibility(state_battle); } void StatsReset::enter_portal(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ @@ -441,6 +447,122 @@ void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerConte pbf_mash_button(context, BUTTON_A, 20s); } + if (POKEMON == GiftPokemon::HOOPA){ + // fly to cafe soleil + FastTravelState travel_status = open_map_and_fly_to(env.console, context, LANGUAGE, Location::CAFE_SOLEIL); + if (travel_status != FastTravelState::SUCCESS){ + stats.errors++; + env.update_stats(); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to travel to Café Soleil", + env.console + ); + } + context.wait_for(100ms); + env.log("Detected overworld. Fast traveled to Café Soleil"); + + // run to holovator + pbf_move_left_joystick(context, {1, 0.12}, 200ms, 500ms); + pbf_press_button(context, BUTTON_L, 50ms, 500ms); + ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); + pbf_move_left_joystick(context, {0, 1}, 6500ms, 500ms); + pbf_mash_button(context, BUTTON_A, 1s); + context.wait_for_all_requests(); + wait_until_overworld(env.console, context); + + // run to the right of roof + pbf_press_button(context, BUTTON_Y, 100ms, 1s); + pbf_move_left_joystick(context, {1, 0.12}, 200ms, 500ms); + for (int i = 0; i < 6; ++i){ + pbf_press_button(context, BUTTON_Y, 100ms, 1s); + } + + ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); + pbf_move_left_joystick(context, {1, 0.12}, 1s, 500ms); + + // run forward to the ladder + pbf_move_left_joystick(context, {0, 1}, 200ms, 500ms); + for (int i = 0; i < 5; ++i){ + pbf_press_button(context, BUTTON_Y, 100ms, 1s); + } + + ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); + pbf_move_left_joystick(context, {0, 1}, 1s, 500ms); + + pbf_press_button(context, BUTTON_Y, 100ms, 1s); + pbf_press_button(context, BUTTON_Y, 100ms, 1s); + + ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); + pbf_move_left_joystick(context, {-0.2, 1}, 4s, 0ms); + ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); + pbf_move_left_joystick(context, {-0.8, 1}, 1500ms, 500ms); + + // climb ladder + pbf_mash_button(context, BUTTON_A, 500ms); + pbf_move_left_joystick(context, {0, 1}, 8s, 1500ms); + + ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); + pbf_move_left_joystick(context, {-1, 0}, 2s, 500ms); + + enter_portal(env, context); + context.wait_for(100ms); + + // run toward hoopa to start battle + ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); + pbf_move_left_joystick(context, {0, +1}, 8s, 0ms); + + RunFromBattleWatcher battle_menu(COLOR_GREEN, &env.console.overlay(), 10ms); + OverworldPartySelectionWatcher overworld(COLOR_WHITE, &env.console.overlay(), 100ms); + TrainerBattleState battle_state(BATTLE_AI); + context.wait_for_all_requests(); + bool has_error = false; + while (true){ + int ret = run_until( + env.console, context, + [](ProControllerContext& context){ + pbf_mash_button(context, BUTTON_B, 120s); + }, + { + battle_menu, + overworld, + } + ); + + switch (ret){ + case 0: + env.log("Detected battle menu."); + if (!battle_state.attempt_one_attack(env, env.console, context)){ + pbf_press_button(context, BUTTON_UP, 500ms, 1s); + } + continue; + case 1: + env.log("Detected overworld."); + break; + default: + has_error = true; + break; + } + break; + } + if (has_error){ + stats.errors++; + env.log("Error during battle.", COLOR_RED); + // fail safely and start over + go_home(env.console, context); + reset_game_from_home(env, env.console, context, true); + continue; + } + context.wait_for(100ms); + // run toward hoopa to catch + ssf_press_button(context, BUTTON_B, 0ms, 2s, 0ms); + pbf_move_left_joystick(context, {0.05, +1}, 1500ms, 0ms); + pbf_mash_button(context, BUTTON_A, 1s); + // incase did not run + pbf_move_left_joystick(context, {0.05, +1}, 500ms, 0ms); + pbf_mash_button(context, BUTTON_A, 1s); + } + context.wait_for_all_requests(); { BlackScreenOverWatcher detector; @@ -453,6 +575,8 @@ void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerConte pbf_mash_button(context, BUTTON_A, 60s); }else if (POKEMON == GiftPokemon::MAGEARNA){ pbf_mash_button(context, BUTTON_A, 60s); + }else if (POKEMON == GiftPokemon::HOOPA) { + pbf_mash_button(context, BUTTON_A, 120s); }else{ pbf_mash_button(context, BUTTON_A, 30s); } diff --git a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h index 4123a44c47..1cbb995b2c 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h +++ b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.h @@ -16,6 +16,7 @@ #include "Pokemon/Options/Pokemon_IvJudgeOption.h" #include "Common/Cpp/Options/TimeDurationOption.h" #include "Common/Cpp/Options/SimpleIntegerOption.h" +#include "PokemonLZA/Options/PokemonLZA_BattleAIOption.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -57,6 +58,7 @@ class StatsReset : public SingleSwitchProgramInstance, public ConfigOption::List MELTAN, MELMETAL, VOLCANION, + HOOPA, }; EnumDropdownOption POKEMON; @@ -67,6 +69,8 @@ class StatsReset : public SingleSwitchProgramInstance, public ConfigOption::List SimpleIntegerOption DOWN_SCROLLS; + BattleAIOption BATTLE_AI; + IVJudgeFilterOption HP; IVJudgeFilterOption ATTACK; IVJudgeFilterOption DEFENSE; From 151faf67c82c3d8920b52fe892b461bb866ebcc5 Mon Sep 17 00:00:00 2001 From: ZHDreamer Date: Thu, 21 May 2026 21:04:17 -0700 Subject: [PATCH 2/4] Replace trying to move again by detection based method --- .../Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp index c81b7e8147..39acbea2e4 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp @@ -555,11 +555,7 @@ void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerConte } context.wait_for(100ms); // run toward hoopa to catch - ssf_press_button(context, BUTTON_B, 0ms, 2s, 0ms); - pbf_move_left_joystick(context, {0.05, +1}, 1500ms, 0ms); - pbf_mash_button(context, BUTTON_A, 1s); - // incase did not run - pbf_move_left_joystick(context, {0.05, +1}, 500ms, 0ms); + run_towards_gate_with_A_button(env.console, context, 0.063, 1, 2s); pbf_mash_button(context, BUTTON_A, 1s); } From c5b650ddc385377bdc88ad8693031a475f311dc8 Mon Sep 17 00:00:00 2001 From: ZHDreamer Date: Thu, 21 May 2026 22:24:40 -0700 Subject: [PATCH 3/4] Replace fly sequence by no fly sequence --- .../NonShinyHunting/PokemonLZA_StatsReset.cpp | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp index 39acbea2e4..576c9f178f 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp @@ -448,25 +448,14 @@ void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerConte } if (POKEMON == GiftPokemon::HOOPA){ - // fly to cafe soleil - FastTravelState travel_status = open_map_and_fly_to(env.console, context, LANGUAGE, Location::CAFE_SOLEIL); - if (travel_status != FastTravelState::SUCCESS){ - stats.errors++; - env.update_stats(); - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Failed to travel to Café Soleil", - env.console - ); - } - context.wait_for(100ms); - env.log("Detected overworld. Fast traveled to Café Soleil"); - - // run to holovator - pbf_move_left_joystick(context, {1, 0.12}, 200ms, 500ms); + // run to holovator from bleu pokemon center + pbf_move_left_joystick(context, {1, -0.5}, 200ms, 500ms); + pbf_press_button(context, BUTTON_Y, 100ms, 1s); + pbf_move_left_joystick(context, {-0.14, -1}, 200ms, 500ms); pbf_press_button(context, BUTTON_L, 50ms, 500ms); ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); - pbf_move_left_joystick(context, {0, 1}, 6500ms, 500ms); + pbf_move_left_joystick(context, {0, 1}, 6s, 0ms); + pbf_move_left_joystick(context, {0.05, 1}, 4800ms, 0ms); pbf_mash_button(context, BUTTON_A, 1s); context.wait_for_all_requests(); wait_until_overworld(env.console, context); From b261fb8516860f93157a68164dc3d169556f2647 Mon Sep 17 00:00:00 2001 From: ZHDreamer Date: Thu, 21 May 2026 22:25:13 -0700 Subject: [PATCH 4/4] Adjust timing and style --- .../Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp index 576c9f178f..67a791a073 100644 --- a/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp +++ b/SerialPrograms/Source/PokemonLZA/Programs/NonShinyHunting/PokemonLZA_StatsReset.cpp @@ -458,7 +458,7 @@ void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerConte pbf_move_left_joystick(context, {0.05, 1}, 4800ms, 0ms); pbf_mash_button(context, BUTTON_A, 1s); context.wait_for_all_requests(); - wait_until_overworld(env.console, context); + wait_until_overworld(env.console, context, 10s); // run to the right of roof pbf_press_button(context, BUTTON_Y, 100ms, 1s); @@ -485,21 +485,21 @@ void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerConte ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); pbf_move_left_joystick(context, {-0.2, 1}, 4s, 0ms); ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); - pbf_move_left_joystick(context, {-0.8, 1}, 1500ms, 500ms); + pbf_move_left_joystick(context, {-0.8, 1}, 1500ms, 0ms); // climb ladder pbf_mash_button(context, BUTTON_A, 500ms); pbf_move_left_joystick(context, {0, 1}, 8s, 1500ms); ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); - pbf_move_left_joystick(context, {-1, 0}, 2s, 500ms); + pbf_move_left_joystick(context, {-1, 0}, 2s, 0ms); enter_portal(env, context); context.wait_for(100ms); // run toward hoopa to start battle ssf_press_button(context, BUTTON_B, 0ms, 1s, 0ms); - pbf_move_left_joystick(context, {0, +1}, 8s, 0ms); + pbf_move_left_joystick(context, {0, 1}, 8s, 0ms); RunFromBattleWatcher battle_menu(COLOR_GREEN, &env.console.overlay(), 10ms); OverworldPartySelectionWatcher overworld(COLOR_WHITE, &env.console.overlay(), 100ms); @@ -560,7 +560,7 @@ void StatsReset::program(SingleSwitchProgramEnvironment& env, ProControllerConte pbf_mash_button(context, BUTTON_A, 60s); }else if (POKEMON == GiftPokemon::MAGEARNA){ pbf_mash_button(context, BUTTON_A, 60s); - }else if (POKEMON == GiftPokemon::HOOPA) { + }else if (POKEMON == GiftPokemon::HOOPA){ pbf_mash_button(context, BUTTON_A, 120s); }else{ pbf_mash_button(context, BUTTON_A, 30s);