From b50e3fd8947599cbfcf3b14a4d250a27ada85378 Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Sat, 14 Feb 2026 20:33:02 +0100 Subject: [PATCH 1/8] Movement according which of the 2 trainers is available --- .../PokemonBDSP_MoneyFarmerRoute210.cpp | 60 ++++++++++++++++++- .../Farming/PokemonBDSP_MoneyFarmerRoute210.h | 8 +++ .../PokemonSwSh_MaxLair_Run_CaughtScreen.cpp | 8 ++- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp index bc740d1b4b..06460da9ba 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp @@ -19,6 +19,10 @@ #include "PokemonBDSP/Inference/Battles/PokemonBDSP_EndBattleDetector.h" #include "PokemonBDSP_MoneyFarmerRoute210.h" +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include +#include + namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonBDSP{ @@ -245,6 +249,56 @@ bool MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControl ); } +void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, ProControllerContext& context, const std::vector& bubbles +){ + + const ImagePixelBox* closest = nullptr; + double best_dist_sq = std::numeric_limits::max(); + + // Calculate the distance between the character and the closest box + for (const auto& box : bubbles) { + double dx = box.min_x - 540.0; + double dy = box.min_y - 163.0; + double dist_sq = dx*dx + dy*dy; + + if (dist_sq < best_dist_sq) { + best_dist_sq = dist_sq; + closest = &box; + } + } + + if (!closest) return; + + if (closest->min_x < 350) { + // The trainer who wants to battle is to the far-left, behind the other trainer + pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); + pbf_press_dpad(context, DPAD_LEFT, 500ms, 0ms); + pbf_mash_button(context, BUTTON_A, 1000ms); + pbf_press_dpad(context, DPAD_DOWN, 300ms, 0ms); + pbf_mash_button(context, BUTTON_A, 1000ms); + } else if (closest->min_x < 450) { + // The trainer who wants to battle is on the character's left + if (closest->min_y < 110) { + // The trainer who wants to battle is one step above us + pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); + pbf_press_dpad(context, DPAD_LEFT, 300ms, 0ms); + } else { + // The trainer who wants to battle is on our left, right next to us + pbf_press_dpad(context, DPAD_LEFT, 300ms, 0ms); + } + } else if (closest->min_x < 560) { + // The trainer who wants to battle is right above us + pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); + } else { + // The trainer who wants to battle is above us, one step to our right + pbf_press_dpad(context, DPAD_RIGHT, 300ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); + } + + pbf_mash_button(context, BUTTON_A, 1000ms); + +} + void MoneyFarmerRoute210::heal_at_center_and_return( Logger& logger, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4] @@ -410,10 +464,14 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro stats.m_react++; } for (const ImagePixelBox& box : bubbles){ - env.log("Reaction at: " + std::to_string(box.min_x), COLOR_BLUE); + env.log("Reaction at X: " + std::to_string(box.min_x) + "Y: " + std::to_string(box.min_y), COLOR_BLUE); + } + if (!bubbles.empty()) { + move_to_trainer(env, context, bubbles); } if (this->battle(env, context, pp0, pp1)){ + env.update_stats(); return; } if (!has_pp(pp0, pp1)){ diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h index 9c735d2014..02938aec6d 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h @@ -14,6 +14,9 @@ #include "PokemonBDSP/Options/PokemonBDSP_ShortcutDirection.h" #include "PokemonBDSP/Options/PokemonBDSP_LearnMove.h" +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include + namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonBDSP{ @@ -38,6 +41,11 @@ class MoneyFarmerRoute210 : public SingleSwitchProgramInstance{ bool battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]); // From the bottom row of the Ace Trainer pair, heal Pokemon and return. // Return true if VS Seeker needs charging. + void move_to_trainer( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + const std::vector& bubbles + ); bool heal_after_battle_and_return( SingleSwitchProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp index 4e849c5833..73faa9aac9 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp @@ -217,7 +217,7 @@ StateMachineAction run_caught_screen( if (is_host){ runtime.path_stats.clear(); } - if (shinies.empty() || shinies[0] == 3){ + if (shinies.empty()){ console.log("Quitting back to entrance.", COLOR_PURPLE); tracker.leave_summary(); synchronize_caught_screen(console_index, console, context, state_tracker); @@ -226,8 +226,10 @@ StateMachineAction run_caught_screen( pbf_press_button(context, BUTTON_A, 80ms, 920ms); return mash_A_to_entrance(runtime, console, context, entrance); }else{ - console.log("Taking non-shiny boss and returning to entrance...", COLOR_BLUE); - tracker.scroll_to(shinies[0]); + + size_t take_index = shinies.back(); + console.log("Taking shiny at slot " + std::to_string(take_index) + " and returning to entrance...", COLOR_BLUE); + tracker.scroll_to(take_index); tracker.enter_summary(); // Enter summary to verify you're on the right mon. tracker.leave_summary(); synchronize_caught_screen(console_index, console, context, state_tracker); From 39a546b3f163185b04b6b8e26d1194fd8dd32665 Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Wed, 18 Feb 2026 17:46:00 +0100 Subject: [PATCH 2/8] Reverted unintentional changes --- ...PokemonSwSh_MaxLair_Options_BossAction.cpp | 58 ++++++++++++++++++- .../PokemonSwSh_MaxLair_Options_BossAction.h | 15 ++++- .../PokemonSwSh_MaxLair_Run_CaughtScreen.cpp | 50 ++++++++-------- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp index 61d467e4c6..1f4b388cc9 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp @@ -15,6 +15,10 @@ #include "PokemonSwSh/Resources/PokemonSwSh_PokemonSprites.h" #include "PokemonSwSh/Resources/PokemonSwSh_MaxLairDatabase.h" #include "PokemonSwSh_MaxLair_Options_BossAction.h" +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/ConfigOption.h" +#include +#include //#include //using std::cout; @@ -49,12 +53,41 @@ BossActionRow::BossActionRow(std::string slug, const std::string& name_slug, con BossAction::CATCH_AND_STOP_IF_SHINY ) , ball(LockMode::UNLOCK_WHILE_RUNNING, "poke-ball") + , save_on_the_go(LockMode::UNLOCK_WHILE_RUNNING, "Save when seen?", false) { PA_ADD_STATIC(pokemon); add_option(action, "Action"); add_option(ball, "Ball"); + add_option(save_on_the_go, "Save when seen?"); + + save_on_the_go.set_visibility( + action.enum_value() == BossAction::CATCH_AND_STOP_IF_SHINY ? ConfigOptionState::ENABLED : ConfigOptionState::DISABLED + ); + + action.add_listener(*this); } +void BossActionRow::value_changed(void* object, const EnumDropdownOption& option, BossAction value) { + if (&option == &action) { + save_on_the_go.set_visibility( + value == BossAction::CATCH_AND_STOP_IF_SHINY ? + ConfigOptionState::ENABLED : ConfigOptionState::DISABLED + ); + + if (value != BossAction::CATCH_AND_STOP_IF_SHINY) { + save_on_the_go = false; + } + } +} + +class BossActionTable : public StaticTableOption { + public: + BossActionTable(); + virtual std::vector make_header() const override; + private: + std::vector m_rows; +}; + BossActionTable::BossActionTable() : StaticTableOption("Boss Actions:", LockMode::UNLOCK_WHILE_RUNNING) @@ -64,15 +97,36 @@ BossActionTable::BossActionTable() const MaxLairSlugs& slugs = get_maxlair_slugs(item.second); const std::string& sprite_slug = *slugs.sprite_slugs.begin(); const std::string& name_slug = slugs.name_slug; - add_row(std::make_unique(item.second, name_slug, sprite_slug)); + + auto row = std::make_unique(item.second, name_slug, sprite_slug); + m_rows.push_back(row.get()); + add_row(std::move(row)); } finish_construction(); + + // Check function for only being able to select max 3 bosses to be saved on the go + for (auto* row : m_rows) { + auto& checkbox = row->save_on_the_go; + checkbox.add_listener([this, &checkbox](const BooleanCheckBoxOption&, bool value) { + if (value) { + size_t count = 0; + for (auto* r : m_rows) { + if (r->save_on_the_go) count++; + } + if (count > 3) { + // Make all other checkboxes equal to false + const_cast(checkbox).set_value(false); + } + } + }); + } } std::vector BossActionTable::make_header() const{ std::vector ret{ STRING_POKEMON, "Action", - STRING_POKEBALL + STRING_POKEBALL, + "Save Path?" }; return ret; } diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h index 3e228c5089..fa2fee42be 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h @@ -11,6 +11,8 @@ #include "Common/Cpp/Options/StaticTableOption.h" #include "CommonFramework/Options/LabelCellOption.h" #include "PokemonSwSh/Options/PokemonSwSh_BallSelectOption.h" +#include "Common/Cpp/Options/ConfigOption.h" +#include "Common/Cpp/Options/BooleanCheckBoxOption.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -24,19 +26,26 @@ enum class BossAction{ }; -class BossActionRow : public StaticTableRow{ +class BossActionRow : public StaticTableRow, + public OptionListener>{ public: BossActionRow(std::string slug, const std::string& name_slug, const std::string& sprite_slug); + + virtual void value_changed(void* object, const EnumDropdownOption& option, BossAction value) override; LabelCellOption pokemon; - EnumDropdownCell action; + EnumDropdownOption action; PokemonBallSelectCell ball; + BooleanCheckBoxOption save_on_the_go; }; class BossActionTable : public StaticTableOption{ public: BossActionTable(); - virtual std::vector make_header() const; + virtual std::vector make_header() const override; + +private: + std::vector m_rows; }; diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp index 73faa9aac9..190bd846f5 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp @@ -217,33 +217,31 @@ StateMachineAction run_caught_screen( if (is_host){ runtime.path_stats.clear(); } - if (shinies.empty()){ - console.log("Quitting back to entrance.", COLOR_PURPLE); - tracker.leave_summary(); - synchronize_caught_screen(console_index, console, context, state_tracker); - pbf_press_dpad(context, DPAD_DOWN, 80ms, 400ms); - pbf_press_button(context, BUTTON_B, 80ms, 1000ms); - pbf_press_button(context, BUTTON_A, 80ms, 920ms); - return mash_A_to_entrance(runtime, console, context, entrance); - }else{ - - size_t take_index = shinies.back(); - console.log("Taking shiny at slot " + std::to_string(take_index) + " and returning to entrance...", COLOR_BLUE); - tracker.scroll_to(take_index); - tracker.enter_summary(); // Enter summary to verify you're on the right mon. - tracker.leave_summary(); - synchronize_caught_screen(console_index, console, context, state_tracker); - StateMachineAction state = mash_A_to_entrance(runtime, console, context, entrance); - if (state == StateMachineAction::RESET_RECOVER){ - throw_and_log( - console.logger(), - ErrorReport::NO_ERROR_REPORT, - "Unable to take " + Pokemon::STRING_POKEMON + ". Did you forget to disable nicknames?", - console - ); + if (shinies.empty() || shinies[0] == 3){ + console.log("Quitting back to entrance.", COLOR_PURPLE); + tracker.leave_summary(); + synchronize_caught_screen(console_index, console, context, state_tracker); + pbf_press_dpad(context, DPAD_DOWN, 80ms, 400ms); + pbf_press_button(context, BUTTON_B, 80ms, 1000ms); + pbf_press_button(context, BUTTON_A, 80ms, 920ms); + return mash_A_to_entrance(runtime, console, context, entrance); + }else{ + console.log("Taking non-shiny boss and returning to entrance...", COLOR_BLUE); + tracker.scroll_to(shinies[0]); + tracker.enter_summary(); // Enter summary to verify you're on the right mon. + tracker.leave_summary(); + synchronize_caught_screen(console_index, console, context, state_tracker); + StateMachineAction state = mash_A_to_entrance(runtime, console, context, entrance); + if (state == StateMachineAction::RESET_RECOVER){ + throw_and_log( + console.logger(), + ErrorReport::NO_ERROR_REPORT, + "Unable to take " + Pokemon::STRING_POKEMON + ". Did you forget to disable nicknames?", + console + ); + } + return state; } - return state; - } case CaughtScreenAction::RESET: console.log("Resetting game...", COLOR_BLUE); From c6fcd1be52a8d77a718c134e81fcbe81f5821e6a Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Wed, 18 Feb 2026 18:00:46 +0100 Subject: [PATCH 3/8] Reverted unintentional changes 2 --- ...PokemonSwSh_MaxLair_Options_BossAction.cpp | 58 +------------------ .../PokemonSwSh_MaxLair_Options_BossAction.h | 15 +---- 2 files changed, 5 insertions(+), 68 deletions(-) diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp index 1f4b388cc9..61d467e4c6 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.cpp @@ -15,10 +15,6 @@ #include "PokemonSwSh/Resources/PokemonSwSh_PokemonSprites.h" #include "PokemonSwSh/Resources/PokemonSwSh_MaxLairDatabase.h" #include "PokemonSwSh_MaxLair_Options_BossAction.h" -#include "Common/Cpp/Options/BooleanCheckBoxOption.h" -#include "Common/Cpp/Options/ConfigOption.h" -#include -#include //#include //using std::cout; @@ -53,41 +49,12 @@ BossActionRow::BossActionRow(std::string slug, const std::string& name_slug, con BossAction::CATCH_AND_STOP_IF_SHINY ) , ball(LockMode::UNLOCK_WHILE_RUNNING, "poke-ball") - , save_on_the_go(LockMode::UNLOCK_WHILE_RUNNING, "Save when seen?", false) { PA_ADD_STATIC(pokemon); add_option(action, "Action"); add_option(ball, "Ball"); - add_option(save_on_the_go, "Save when seen?"); - - save_on_the_go.set_visibility( - action.enum_value() == BossAction::CATCH_AND_STOP_IF_SHINY ? ConfigOptionState::ENABLED : ConfigOptionState::DISABLED - ); - - action.add_listener(*this); } -void BossActionRow::value_changed(void* object, const EnumDropdownOption& option, BossAction value) { - if (&option == &action) { - save_on_the_go.set_visibility( - value == BossAction::CATCH_AND_STOP_IF_SHINY ? - ConfigOptionState::ENABLED : ConfigOptionState::DISABLED - ); - - if (value != BossAction::CATCH_AND_STOP_IF_SHINY) { - save_on_the_go = false; - } - } -} - -class BossActionTable : public StaticTableOption { - public: - BossActionTable(); - virtual std::vector make_header() const override; - private: - std::vector m_rows; -}; - BossActionTable::BossActionTable() : StaticTableOption("Boss Actions:", LockMode::UNLOCK_WHILE_RUNNING) @@ -97,36 +64,15 @@ BossActionTable::BossActionTable() const MaxLairSlugs& slugs = get_maxlair_slugs(item.second); const std::string& sprite_slug = *slugs.sprite_slugs.begin(); const std::string& name_slug = slugs.name_slug; - - auto row = std::make_unique(item.second, name_slug, sprite_slug); - m_rows.push_back(row.get()); - add_row(std::move(row)); + add_row(std::make_unique(item.second, name_slug, sprite_slug)); } finish_construction(); - - // Check function for only being able to select max 3 bosses to be saved on the go - for (auto* row : m_rows) { - auto& checkbox = row->save_on_the_go; - checkbox.add_listener([this, &checkbox](const BooleanCheckBoxOption&, bool value) { - if (value) { - size_t count = 0; - for (auto* r : m_rows) { - if (r->save_on_the_go) count++; - } - if (count > 3) { - // Make all other checkboxes equal to false - const_cast(checkbox).set_value(false); - } - } - }); - } } std::vector BossActionTable::make_header() const{ std::vector ret{ STRING_POKEMON, "Action", - STRING_POKEBALL, - "Save Path?" + STRING_POKEBALL }; return ret; } diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h index fa2fee42be..3e228c5089 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Options/PokemonSwSh_MaxLair_Options_BossAction.h @@ -11,8 +11,6 @@ #include "Common/Cpp/Options/StaticTableOption.h" #include "CommonFramework/Options/LabelCellOption.h" #include "PokemonSwSh/Options/PokemonSwSh_BallSelectOption.h" -#include "Common/Cpp/Options/ConfigOption.h" -#include "Common/Cpp/Options/BooleanCheckBoxOption.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -26,26 +24,19 @@ enum class BossAction{ }; -class BossActionRow : public StaticTableRow, - public OptionListener>{ +class BossActionRow : public StaticTableRow{ public: BossActionRow(std::string slug, const std::string& name_slug, const std::string& sprite_slug); - - virtual void value_changed(void* object, const EnumDropdownOption& option, BossAction value) override; LabelCellOption pokemon; - EnumDropdownOption action; + EnumDropdownCell action; PokemonBallSelectCell ball; - BooleanCheckBoxOption save_on_the_go; }; class BossActionTable : public StaticTableOption{ public: BossActionTable(); - virtual std::vector make_header() const override; - -private: - std::vector m_rows; + virtual std::vector make_header() const; }; From eca5aa055cfc0237e37c3f8778001e710470d70d Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Fri, 20 Feb 2026 16:11:03 +0100 Subject: [PATCH 4/8] Reverted unintentional changes 3 --- .../PokemonSwSh_MaxLair_Run_CaughtScreen.cpp | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp index 190bd846f5..4e849c5833 100644 --- a/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp +++ b/SerialPrograms/Source/PokemonSwSh/MaxLair/Program/PokemonSwSh_MaxLair_Run_CaughtScreen.cpp @@ -217,31 +217,31 @@ StateMachineAction run_caught_screen( if (is_host){ runtime.path_stats.clear(); } - if (shinies.empty() || shinies[0] == 3){ - console.log("Quitting back to entrance.", COLOR_PURPLE); - tracker.leave_summary(); - synchronize_caught_screen(console_index, console, context, state_tracker); - pbf_press_dpad(context, DPAD_DOWN, 80ms, 400ms); - pbf_press_button(context, BUTTON_B, 80ms, 1000ms); - pbf_press_button(context, BUTTON_A, 80ms, 920ms); - return mash_A_to_entrance(runtime, console, context, entrance); - }else{ - console.log("Taking non-shiny boss and returning to entrance...", COLOR_BLUE); - tracker.scroll_to(shinies[0]); - tracker.enter_summary(); // Enter summary to verify you're on the right mon. - tracker.leave_summary(); - synchronize_caught_screen(console_index, console, context, state_tracker); - StateMachineAction state = mash_A_to_entrance(runtime, console, context, entrance); - if (state == StateMachineAction::RESET_RECOVER){ - throw_and_log( - console.logger(), - ErrorReport::NO_ERROR_REPORT, - "Unable to take " + Pokemon::STRING_POKEMON + ". Did you forget to disable nicknames?", - console - ); - } - return state; + if (shinies.empty() || shinies[0] == 3){ + console.log("Quitting back to entrance.", COLOR_PURPLE); + tracker.leave_summary(); + synchronize_caught_screen(console_index, console, context, state_tracker); + pbf_press_dpad(context, DPAD_DOWN, 80ms, 400ms); + pbf_press_button(context, BUTTON_B, 80ms, 1000ms); + pbf_press_button(context, BUTTON_A, 80ms, 920ms); + return mash_A_to_entrance(runtime, console, context, entrance); + }else{ + console.log("Taking non-shiny boss and returning to entrance...", COLOR_BLUE); + tracker.scroll_to(shinies[0]); + tracker.enter_summary(); // Enter summary to verify you're on the right mon. + tracker.leave_summary(); + synchronize_caught_screen(console_index, console, context, state_tracker); + StateMachineAction state = mash_A_to_entrance(runtime, console, context, entrance); + if (state == StateMachineAction::RESET_RECOVER){ + throw_and_log( + console.logger(), + ErrorReport::NO_ERROR_REPORT, + "Unable to take " + Pokemon::STRING_POKEMON + ". Did you forget to disable nicknames?", + console + ); } + return state; + } case CaughtScreenAction::RESET: console.log("Resetting game...", COLOR_BLUE); From 2b46a1e949b3b11db8909b4afa4a324d52f8f390 Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Wed, 25 Feb 2026 14:12:20 +0100 Subject: [PATCH 5/8] Tweaked the timing for the movement a bit to make it safer --- .../PokemonBDSP_MoneyFarmerRoute210.cpp | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp index 7e15da249f..02aafae7a5 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp @@ -274,8 +274,8 @@ bool MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControl } void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, ProControllerContext& context, const std::vector& bubbles -){ - + ){ + const ImagePixelBox* closest = nullptr; double best_dist_sq = std::numeric_limits::max(); @@ -295,32 +295,37 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P if (closest->min_x < 350) { // The trainer who wants to battle is to the far-left, behind the other trainer - pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); pbf_press_dpad(context, DPAD_LEFT, 500ms, 0ms); pbf_mash_button(context, BUTTON_A, 1000ms); - pbf_press_dpad(context, DPAD_DOWN, 300ms, 0ms); + context.wait_for_all_requests(); + pbf_press_dpad(context, DPAD_DOWN, 400ms, 0ms); pbf_mash_button(context, BUTTON_A, 1000ms); + context.wait_for_all_requests(); } else if (closest->min_x < 450) { // The trainer who wants to battle is on the character's left if (closest->min_y < 110) { // The trainer who wants to battle is one step above us - pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); - pbf_press_dpad(context, DPAD_LEFT, 300ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); + pbf_press_dpad(context, DPAD_LEFT, 400ms, 0ms); + context.wait_for_all_requests(); } else { // The trainer who wants to battle is on our left, right next to us - pbf_press_dpad(context, DPAD_LEFT, 300ms, 0ms); + pbf_press_dpad(context, DPAD_LEFT, 400ms, 0ms); } } else if (closest->min_x < 560) { // The trainer who wants to battle is right above us - pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); } else { // The trainer who wants to battle is above us, one step to our right - pbf_press_dpad(context, DPAD_RIGHT, 300ms, 0ms); - pbf_press_dpad(context, DPAD_UP, 300ms, 0ms); + pbf_press_dpad(context, DPAD_RIGHT, 400ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); + context.wait_for_all_requests(); } pbf_mash_button(context, BUTTON_A, 1000ms); - + context.wait_for_all_requests(); +} void MoneyFarmerRoute210::check_pickup_items( ProControllerContext& context, const bool pickup_slots[6] From 24358f428ff8dece74206b4e19e8f2b4d1826eb1 Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Sun, 15 Mar 2026 18:27:27 +0100 Subject: [PATCH 6/8] Initial safety changes to improve reliability, draft --- .../PokemonBDSP_MoneyFarmerRoute210.cpp | 26 ++++++++++++++++--- .../Farming/PokemonBDSP_MoneyFarmerRoute210.h | 3 +++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp index 91aeb7ed66..bb2dd61ed2 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp @@ -326,6 +326,17 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P pbf_mash_button(context, BUTTON_A, 1000ms); context.wait_for_all_requests(); } + +void MoneyFarmerRoute210::recover_from_failed_battle_start(ProControllerContext& context){ + env.log("Recovering from failed battle start – moving to safe position."); + + pbf_move_left_joystick(context, {0, +1}, 2000ms, 0ms); + pbf_move_left_joystick(context, {+1, 0}, 2000ms, 0ms); + pbf_move_left_joystick(context, {0, -1}, 4000ms, 0ms); + // Wait a bit to ensure we're settled. + pbf_wait(context, 500ms); + context.wait_for_all_requests(); +} void MoneyFarmerRoute210::check_pickup_items( ProControllerContext& context, const bool pickup_slots[6] @@ -511,6 +522,8 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro } pbf_move_left_joystick(context, {+1, 0}, 1120ms, 0ms); } + + uint8_t consecutive_failures = 0; while (true){ env.update_stats(); @@ -564,9 +577,16 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro move_to_trainer(env, context, bubbles); } - if (this->battle(env, context, pp0, pp1)){ - env.update_stats(); - return; + // Attempt the battle + bool battle_success = battle(env, context, pp0, pp1); + if (!battle_success) { + consecutive_failures++; + if (consecutive_failers >= 3) { + heal_after_battle_and_return(env, env.console, context, pp0, pp1); + } + env.log("Battle did not start. Recovering and retrying."); + recover_from_failed_battle_start(context); + continue; } pickup_counter++; diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h index 54b3ed968b..71cd69180d 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h @@ -52,6 +52,9 @@ class MoneyFarmerRoute210 : public SingleSwitchProgramInstance{ ProControllerContext& context, const std::vector& bubbles ); + void recover_from_failed_battle_start( + ProControllerContext& context + ); bool heal_after_battle_and_return( SingleSwitchProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, From 3ff60c38a50559fc5fda75811a2e573b88ac1573 Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Tue, 17 Mar 2026 20:37:38 +0100 Subject: [PATCH 7/8] Tweaks adding recovery and ultimate resort flying back and heal --- .../PokemonBDSP_MoneyFarmerRoute210.cpp | 57 ++++++++++++------- .../Farming/PokemonBDSP_MoneyFarmerRoute210.h | 12 +++- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp index bb2dd61ed2..26806bd5c2 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp @@ -137,7 +137,7 @@ MoneyFarmerRoute210::MoneyFarmerRoute210() -bool MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]){ +MoneyFarmerRoute210::BattleOutcome MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]){ MoneyFarmerRoute210_Descriptor::Stats& stats = env.current_stats(); env.log("Starting battle!"); @@ -161,7 +161,7 @@ bool MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControl stats.m_errors++; env.log("Failed to detect start of battle after 20 seconds.", COLOR_RED); pbf_mash_button(context, BUTTON_B, 1000ms); - return false; + return BattleOutcome::FAILED_START; } } pbf_wait(context, 5000ms); @@ -247,7 +247,7 @@ bool MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControl case 1: env.log("Battle finished!", COLOR_BLUE); pbf_mash_button(context, BUTTON_B, 2000ms); - return false; + return BattleOutcome::FINISHED; case 2: env.log("Detected move learn!", COLOR_BLUE); if (ON_LEARN_MOVE == OnLearnMove::DONT_LEARN){ @@ -255,7 +255,7 @@ bool MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControl pbf_press_button(context, BUTTON_ZL, 160ms, 840ms); break; } - return true; + return BattleOutcome::MOVE_LEARN; default: stats.m_errors++; OperationFailedException::fire( @@ -293,10 +293,12 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P if (!closest) return; + pbf_press_dpad(context, DPAD_RIGHT, 200ms, 0ms); + if (closest->min_x < 350) { // The trainer who wants to battle is to the far-left, behind the other trainer - pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); - pbf_press_dpad(context, DPAD_LEFT, 500ms, 0ms); + //pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); + //pbf_press_dpad(context, DPAD_LEFT, 500ms, 0ms); pbf_mash_button(context, BUTTON_A, 1000ms); context.wait_for_all_requests(); pbf_press_dpad(context, DPAD_DOWN, 400ms, 0ms); @@ -311,7 +313,7 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P context.wait_for_all_requests(); } else { // The trainer who wants to battle is on our left, right next to us - pbf_press_dpad(context, DPAD_LEFT, 400ms, 0ms); + //pbf_press_dpad(context, DPAD_LEFT, 400ms, 0ms); } } else if (closest->min_x < 560) { // The trainer who wants to battle is right above us @@ -323,18 +325,20 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P context.wait_for_all_requests(); } - pbf_mash_button(context, BUTTON_A, 1000ms); + //pbf_mash_button(context, BUTTON_A, 1000ms); context.wait_for_all_requests(); } -void MoneyFarmerRoute210::recover_from_failed_battle_start(ProControllerContext& context){ +void MoneyFarmerRoute210::recover_from_failed_battle_start( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context +){ env.log("Recovering from failed battle start – moving to safe position."); - pbf_move_left_joystick(context, {0, +1}, 2000ms, 0ms); - pbf_move_left_joystick(context, {+1, 0}, 2000ms, 0ms); - pbf_move_left_joystick(context, {0, -1}, 4000ms, 0ms); - // Wait a bit to ensure we're settled. - pbf_wait(context, 500ms); + pbf_press_dpad(context, DPAD_LEFT, 600ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 1000ms, 0ms); + pbf_press_dpad(context, DPAD_LEFT, 1000ms, 0ms); + pbf_press_dpad(context, DPAD_DOWN, 5000ms, 0ms); context.wait_for_all_requests(); } @@ -441,9 +445,17 @@ void MoneyFarmerRoute210::fly_to_center_heal_and_return( bool MoneyFarmerRoute210::heal_after_battle_and_return( SingleSwitchProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, - uint8_t pp0[4], uint8_t pp1[4]) + uint8_t pp0[4], uint8_t pp1[4], bool has_pickup_mons) { if (HEALING_METHOD == HealMethod::CelesticTown){ + if (has_pickup_mons){ + // Move the menu cursor back to the Pokemon icon + pbf_press_button(context, BUTTON_X, 40ms, 600ms); + pbf_press_dpad(context, DPAD_UP, 80ms, 600ms); + pbf_press_dpad(context, DPAD_RIGHT, 80ms, 600ms); + pbf_wait(context, 400ms); + pbf_mash_button(context, BUTTON_B, 1000ms); + } // Go to Celestic Town Pokecenter to heal the party. fly_to_center_heal_and_return(stream.logger(), context, pp0, pp1); return false; @@ -578,20 +590,23 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro } // Attempt the battle - bool battle_success = battle(env, context, pp0, pp1); - if (!battle_success) { + BattleOutcome outcome = battle(env, context, pp0, pp1); + if (outcome == BattleOutcome::FAILED_START) { consecutive_failures++; - if (consecutive_failers >= 3) { - heal_after_battle_and_return(env, env.console, context, pp0, pp1); + if (consecutive_failures > 3) { + stats.m_errors++; + env.log("Battle did not 4 times in a row. Flying back."); + heal_after_battle_and_return(env, env.console, context, pp0, pp1, has_pickup_mons); + consecutive_failures = 0; } env.log("Battle did not start. Recovering and retrying."); - recover_from_failed_battle_start(context); + recover_from_failed_battle_start(env, context); continue; } pickup_counter++; if (!has_pp(pp0, pp1)){ - need_to_charge = heal_after_battle_and_return(env, env.console, context, pp0, pp1); + need_to_charge = heal_after_battle_and_return(env, env.console, context, pp0, pp1, has_pickup_mons); continue; } } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h index 71cd69180d..c86358ba94 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h @@ -38,8 +38,13 @@ class MoneyFarmerRoute210 : public SingleSwitchProgramInstance{ virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; private: - // Run the battle loop. Return true if the program should stop. - bool battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]); + enum class BattleOutcome { + FINISHED, + FAILED_START, + MOVE_LEARN + }; + // Run the battle loop. Returns the outcome of the battle attempt. + BattleOutcome battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]); // Check for items generated through the Pickup ability void check_pickup_items( ProControllerContext& context, @@ -53,12 +58,13 @@ class MoneyFarmerRoute210 : public SingleSwitchProgramInstance{ const std::vector& bubbles ); void recover_from_failed_battle_start( + SingleSwitchProgramEnvironment& env, ProControllerContext& context ); bool heal_after_battle_and_return( SingleSwitchProgramEnvironment& env, VideoStream& stream, ProControllerContext& context, - uint8_t pp0[4], uint8_t pp1[4] + uint8_t pp0[4], uint8_t pp1[4], bool has_pickup_mons ); // Starting in front of the Celestic Town Pokecenter, heal and return // to the Ace Trainer pair. From 100732012e41c0ffa5849a1f71219aaea347d318 Mon Sep 17 00:00:00 2001 From: Boombaastical Date: Wed, 18 Mar 2026 14:40:04 +0100 Subject: [PATCH 8/8] Added recovery and failsafe to the movement to either of the 2 trainers, also improved reliability of Pickup --- .../PokemonBDSP_MoneyFarmerRoute210.cpp | 51 +++++++++++-------- .../Farming/PokemonBDSP_MoneyFarmerRoute210.h | 12 +++-- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp index 26806bd5c2..e9a792d66f 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.cpp @@ -47,16 +47,19 @@ struct MoneyFarmerRoute210_Descriptor::Stats : public StatsTracker{ , m_errors(m_stats["Errors"]) , m_noreact(m_stats["No React"]) , m_react(m_stats["React"]) + , m_pickup(m_stats["Pickup"]) { m_display_order.emplace_back("Searches"); m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); m_display_order.emplace_back("No React"); m_display_order.emplace_back("React"); + m_display_order.emplace_back("Pickup", HIDDEN_IF_ZERO); } std::atomic& m_searches; std::atomic& m_errors; std::atomic& m_noreact; std::atomic& m_react; + std::atomic& m_pickup; }; std::unique_ptr MoneyFarmerRoute210_Descriptor::make_stats() const{ return std::unique_ptr(new Stats()); @@ -137,7 +140,9 @@ MoneyFarmerRoute210::MoneyFarmerRoute210() -MoneyFarmerRoute210::BattleOutcome MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]){ +MoneyFarmerRoute210::BattleOutcome MoneyFarmerRoute210::battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, + uint8_t pp0[4], uint8_t pp1[4], + const std::vector& bubbles){ MoneyFarmerRoute210_Descriptor::Stats& stats = env.current_stats(); env.log("Starting battle!"); @@ -146,7 +151,8 @@ MoneyFarmerRoute210::BattleOutcome MoneyFarmerRoute210::battle(SingleSwitchProgr StartBattleDetector detector(env.console); int ret = run_until( env.console, context, - [](ProControllerContext& context){ + [this, &env, &bubbles](ProControllerContext& context){ + move_to_trainer(env, context, bubbles); pbf_press_button(context, BUTTON_ZL, 80ms, 80ms); for (size_t c = 0; c < 17; c++){ pbf_press_dpad(context, DPAD_UP, 40ms, 80ms); @@ -293,12 +299,10 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P if (!closest) return; - pbf_press_dpad(context, DPAD_RIGHT, 200ms, 0ms); - if (closest->min_x < 350) { // The trainer who wants to battle is to the far-left, behind the other trainer - //pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); - //pbf_press_dpad(context, DPAD_LEFT, 500ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 400ms, 0ms); + pbf_press_dpad(context, DPAD_LEFT, 500ms, 0ms); pbf_mash_button(context, BUTTON_A, 1000ms); context.wait_for_all_requests(); pbf_press_dpad(context, DPAD_DOWN, 400ms, 0ms); @@ -313,7 +317,7 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P context.wait_for_all_requests(); } else { // The trainer who wants to battle is on our left, right next to us - //pbf_press_dpad(context, DPAD_LEFT, 400ms, 0ms); + pbf_press_dpad(context, DPAD_LEFT, 400ms, 0ms); } } else if (closest->min_x < 560) { // The trainer who wants to battle is right above us @@ -325,7 +329,7 @@ void MoneyFarmerRoute210::move_to_trainer(SingleSwitchProgramEnvironment& env, P context.wait_for_all_requests(); } - //pbf_mash_button(context, BUTTON_A, 1000ms); + pbf_mash_button(context, BUTTON_A, 1000ms); context.wait_for_all_requests(); } @@ -346,10 +350,15 @@ void MoneyFarmerRoute210::check_pickup_items( ProControllerContext& context, const bool pickup_slots[6] ){ - // Open menu + // Open the menu and the map no matter where the cursor is and leaving the menu again to make sure of its position pbf_press_button(context, BUTTON_X, 80ms, 1000ms); + pbf_press_button(context, BUTTON_PLUS, 80ms, 1920ms); + pbf_mash_button(context, BUTTON_B, 2000ms); - // Open Pokemon menu + // Open the menu and move to the Pokemon menu + pbf_press_button(context, BUTTON_X, 40ms, 600ms); + pbf_press_dpad(context, DPAD_UP, 80ms, 600ms); + pbf_press_dpad(context, DPAD_RIGHT, 80ms, 600ms); pbf_press_button(context, BUTTON_A, 80ms, 1000ms); // Loop over each pokemon that has Pickup according to the settings @@ -448,6 +457,8 @@ bool MoneyFarmerRoute210::heal_after_battle_and_return( uint8_t pp0[4], uint8_t pp1[4], bool has_pickup_mons) { if (HEALING_METHOD == HealMethod::CelesticTown){ + // Go to Celestic Town Pokecenter to heal the party. + fly_to_center_heal_and_return(stream.logger(), context, pp0, pp1); if (has_pickup_mons){ // Move the menu cursor back to the Pokemon icon pbf_press_button(context, BUTTON_X, 40ms, 600ms); @@ -456,8 +467,6 @@ bool MoneyFarmerRoute210::heal_after_battle_and_return( pbf_wait(context, 400ms); pbf_mash_button(context, BUTTON_B, 1000ms); } - // Go to Celestic Town Pokecenter to heal the party. - fly_to_center_heal_and_return(stream.logger(), context, pp0, pp1); return false; }else{ // Use Global Room to heal the party. @@ -516,10 +525,11 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro PICKUP_SLOT6, }; + + bool has_pickup_mons = PICKUP_SLOT1 || PICKUP_SLOT2 || PICKUP_SLOT3 || PICKUP_SLOT4 || PICKUP_SLOT5 || PICKUP_SLOT6; uint32_t pickup_counter = 0; - uint32_t total_pickup_checks = 0; // Connect the controller. pbf_press_button(context, BUTTON_B, 40ms, 40ms); @@ -541,11 +551,6 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro env.update_stats(); send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE); - - if (has_pickup_mons && pickup_counter % CHECK_PICKUP_FREQ.current_value() == 0 && pickup_counter != total_pickup_checks){ - check_pickup_items(context, pickup_slots_selected); - total_pickup_checks = pickup_counter; - } if (need_to_charge){ pbf_move_left_joystick(context, {+1, 0}, 1120ms, 0ms); @@ -585,12 +590,9 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro for (const ImagePixelBox& box : bubbles){ env.log("Reaction at X: " + std::to_string(box.min_x) + "Y: " + std::to_string(box.min_y), COLOR_BLUE); } - if (!bubbles.empty()) { - move_to_trainer(env, context, bubbles); - } // Attempt the battle - BattleOutcome outcome = battle(env, context, pp0, pp1); + BattleOutcome outcome = battle(env, context, pp0, pp1, bubbles); if (outcome == BattleOutcome::FAILED_START) { consecutive_failures++; if (consecutive_failures > 3) { @@ -603,7 +605,12 @@ void MoneyFarmerRoute210::program(SingleSwitchProgramEnvironment& env, ProContro recover_from_failed_battle_start(env, context); continue; } + pickup_counter++; + if (has_pickup_mons && pickup_counter % CHECK_PICKUP_FREQ.current_value() == 0) { + check_pickup_items(context, pickup_slots_selected); + stats.m_pickup++; + } if (!has_pp(pp0, pp1)){ need_to_charge = heal_after_battle_and_return(env, env.console, context, pp0, pp1, has_pickup_mons); diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h index c86358ba94..65a38d4685 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h +++ b/SerialPrograms/Source/PokemonBDSP/Programs/Farming/PokemonBDSP_MoneyFarmerRoute210.h @@ -44,12 +44,14 @@ class MoneyFarmerRoute210 : public SingleSwitchProgramInstance{ MOVE_LEARN }; // Run the battle loop. Returns the outcome of the battle attempt. - BattleOutcome battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]); + BattleOutcome battle(SingleSwitchProgramEnvironment& env, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4], + const std::vector& bubbles + ); // Check for items generated through the Pickup ability void check_pickup_items( ProControllerContext& context, const bool pickup_slots_selected[6] - ); + ); // From the bottom row of the Ace Trainer pair, heal Pokemon and return. // Return true if VS Seeker needs charging. void move_to_trainer( @@ -68,7 +70,11 @@ class MoneyFarmerRoute210 : public SingleSwitchProgramInstance{ ); // Starting in front of the Celestic Town Pokecenter, heal and return // to the Ace Trainer pair. - void heal_at_center_and_return(Logger& logger, ProControllerContext& context, uint8_t pp0[4], uint8_t pp1[4]); + void heal_at_center_and_return( + Logger& logger, + ProControllerContext& context, + uint8_t pp0[4], uint8_t pp1[4] + ); // Fly from the Ace Trainer pair to Hearthome Pokecenter, heal and return. void fly_to_center_heal_and_return( Logger& logger, ProControllerContext& context,