From 787ad8604a016a2bf678a982471ce4b31c698839 Mon Sep 17 00:00:00 2001 From: Dalton-V Date: Mon, 15 Jun 2026 21:35:17 -0500 Subject: [PATCH 1/5] Add option to hunt dragonair --- .../Farming/PokemonFRLG_LuckyEggFarmer.cpp | 162 +++++++++++++++--- .../Farming/PokemonFRLG_LuckyEggFarmer.h | 18 +- 2 files changed, 158 insertions(+), 22 deletions(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp index eaed11ad64..25be2f9d37 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp @@ -73,7 +73,16 @@ std::unique_ptr LuckyEggFarmer_Descriptor::make_stats() const{ } LuckyEggFarmer::LuckyEggFarmer() - : LANGUAGE( + : ITEM_TO_FARM( + "Item to Farm:", + { + {ItemToFarm::LUCKY_EGG, "Lucky Egg", "Farm Chansey for Lucky Eggs."}, + {ItemToFarm::DRAGON_FANG, "Dragon Fang", "Farm Dragonair for Dragon Fangs."}, + }, + LockMode::LOCK_WHILE_RUNNING, + ItemToFarm::LUCKY_EGG + ) + , LANGUAGE( "Game Language:", { Language::English, @@ -111,6 +120,7 @@ LuckyEggFarmer::LuckyEggFarmer() &NOTIFICATION_ERROR_FATAL, }) { + PA_ADD_OPTION(ITEM_TO_FARM); PA_ADD_OPTION(LANGUAGE); PA_ADD_OPTION(STOP_AFTER_CURRENT); PA_ADD_OPTION(TAKE_VIDEO); @@ -257,6 +267,13 @@ bool LuckyEggFarmer::navigate_to_chansey(ConsoleHandle& console, ProControllerCo return true; } +void LuckyEggFarmer::navigate_to_dragonair(ConsoleHandle& console, ProControllerContext& context){ + ssf_press_button(context, BUTTON_B, 0ms, 2848ms); + pbf_press_dpad(context, DPAD_UP, 1315ms, 0ms); + pbf_press_dpad(context, DPAD_RIGHT, 755ms, 0ms); + pbf_press_dpad(context, DPAD_UP, 580ms, 0ms); +} + void LuckyEggFarmer::swap_lead_pokemon(ConsoleHandle& console, ProControllerContext& context){ open_party_menu_from_overworld(console, context, StartMenuContext::SAFARI_ZONE); pbf_press_button(context, BUTTON_A, 250ms, 100ms); @@ -271,7 +288,7 @@ void LuckyEggFarmer::swap_lead_pokemon(ConsoleHandle& console, ProControllerCont context.wait_for_all_requests(); } -bool LuckyEggFarmer::find_encounter(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +bool LuckyEggFarmer::find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ ssf_press_button(context, BUTTON_B, 0ms, 400ms); pbf_press_dpad(context, DPAD_RIGHT, 400ms, 0ms); pbf_wait(context, 100ms); @@ -310,6 +327,38 @@ bool LuckyEggFarmer::find_encounter(SingleSwitchProgramEnvironment& env, ProCont } } +bool LuckyEggFarmer::find_encounter_fishing(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + WhiteDialogWatcher fishing_dialog(COLOR_RED); + BlackScreenWatcher battle_entered(COLOR_RED); + AdvanceBattleDialogWatcher battle_dialog(COLOR_RED); + WallClock start = current_time(); + + while (true){ + if (current_time() - start > std::chrono::seconds(300)){ + env.log("No pokemon hooked after 5 minutes. Resetting."); + return false; + } + + pbf_press_button(context, BUTTON_MINUS, 200ms, 200ms); + context.wait_for_all_requests(); + + int ret = wait_until( + env.console, context, + std::chrono::milliseconds(5000), + { fishing_dialog, battle_entered, battle_dialog } + ); + + if (ret == 0){ + env.log("Fishing dialog detected."); + pbf_press_button(context, BUTTON_B, 200ms, 200ms); + context.wait_for_all_requests(); + } else if (ret == 1 || ret == 2){ + env.log("Battle entered."); + return true; + } + } +} + bool LuckyEggFarmer::is_chansey(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ std::set subset = { "nidoran-f", @@ -335,9 +384,31 @@ bool LuckyEggFarmer::is_chansey(SingleSwitchProgramEnvironment& env, ProControll return encounter.name == "chansey"; } +bool LuckyEggFarmer::is_dragonair(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + std::set subset = { + "goldeen", + "seaking", + "dratini", + "psyduck", + "slowpoke", + "dragonair" + }; + + WildEncounterReader reader(COLOR_RED); + VideoOverlaySet overlays(env.console.overlay()); + reader.make_overlays(overlays); + + env.log("Reading name..."); + VideoSnapshot screen = env.console.video().snapshot(); + PokemonFRLG_WildEncounter encounter = reader.read_encounter(env.logger(), LANGUAGE, screen, subset); + env.log("Name: " + encounter.name); + + return encounter.name == "dragonair"; +} + bool LuckyEggFarmer::attempt_catch(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int& balls_left){ //TODO: Optimal bait/ball throwing - + int distraction_thrown = 0; while (true){ BattleSelectionArrowWatcher nickname_question_arrow( COLOR_RED, @@ -345,12 +416,18 @@ bool LuckyEggFarmer::attempt_catch(SingleSwitchProgramEnvironment& env, ProContr BattleConfirmationOption::YES ); - BattleSelectionArrowWatcher battle_arrow( + BattleSelectionArrowWatcher ball_arrow( COLOR_RED, &env.console.overlay(), SafariBattleMenuOption::BALL ); + BattleSelectionArrowWatcher bait_arrow( + COLOR_RED, + &env.console.overlay(), + SafariBattleMenuOption::BAIT + ); + BlackScreenWatcher battle_end(COLOR_RED); AdvanceBattleDialogWatcher advance_battle_dialog(COLOR_RED); @@ -372,13 +449,13 @@ bool LuckyEggFarmer::attempt_catch(SingleSwitchProgramEnvironment& env, ProContr int ret = wait_until( env.console, context, std::chrono::milliseconds(2000), - { nickname_question_arrow, battle_arrow, battle_end, advance_battle_dialog } + { nickname_question_arrow, ball_arrow, battle_end, advance_battle_dialog, bait_arrow } ); context.wait_for_all_requests(); if (ret == 0 || ret == 3){ - env.log("Caught a Chansey!"); + env.log("Pokemon Caught!"); while (true){ int ret2 = wait_until( @@ -402,16 +479,38 @@ bool LuckyEggFarmer::attempt_catch(SingleSwitchProgramEnvironment& env, ProContr context.wait_for_all_requests(); return true; }else if (ret == 1){ + if (distraction_thrown < 2){ + env.log("Throwing distraction."); + pbf_press_dpad(context, DPAD_RIGHT, 200ms, 200ms); + pbf_press_button(context, BUTTON_A, 200ms, 200ms); + distraction_thrown++; + break; + } + balls_left--; env.log("Detected battle arrow. Balls left: " + std::to_string(balls_left)); pbf_press_button(context, BUTTON_A, 200ms, 200ms); context.wait_for_all_requests(); break; }else if (ret == 2){ - env.log("Failed to catch Chansey."); + env.log("Failed to catch pokemon."); pbf_wait(context, 1000ms); context.wait_for_all_requests(); return false; + } else if (ret == 4){ + if (distraction_thrown < 2){ + env.log("Throwing bait..."); + pbf_press_button(context, BUTTON_A, 200ms, 200ms); + distraction_thrown++; + break; + } + env.log("Navigating to ball."); + balls_left--; + env.log("Balls left: " + std::to_string(balls_left)); + pbf_press_dpad(context, DPAD_LEFT, 200ms, 200ms); + pbf_press_button(context, BUTTON_A, 200ms, 200ms); + context.wait_for_all_requests(); + break; } } } @@ -441,9 +540,16 @@ bool LuckyEggFarmer::run_safari_zone(SingleSwitchProgramEnvironment& env, ProCon while (chansey_count < 4){ send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE); - if (!find_encounter(env, context)){ - return false; + if (ITEM_TO_FARM == ItemToFarm::LUCKY_EGG){ + if (!find_encounter_grass(env, context)){ + return false; + } + }else{ + if (!find_encounter_fishing(env, context)){ + return false; + } } + bool encounter_shiny = handle_encounter(env.console, context, true); stats.encounters++; @@ -467,13 +573,24 @@ bool LuckyEggFarmer::run_safari_zone(SingleSwitchProgramEnvironment& env, ProCon env.update_stats(); } - if (!is_chansey(env, context)){ - env.log("Not a Chansey. Fleeing..."); - flee_battle(env.console, context); - context.wait_for_all_requests(); - continue; + if (ITEM_TO_FARM == ItemToFarm::LUCKY_EGG){ + if (!is_chansey(env, context)){ + env.log("Not a Chansey. Fleeing..."); + flee_battle(env.console, context); + context.wait_for_all_requests(); + continue; + } + }else{ + if (!is_dragonair(env, context)){ + env.log("Not a Dragonair. Fleeing..."); + flee_battle(env.console, context); + context.wait_for_all_requests(); + continue; + } } + + //TODO: Update these now that there are two hunts env.log("Chansey found!"); stats.chanseys_found++; env.update_stats(); @@ -581,13 +698,18 @@ void LuckyEggFarmer::program(SingleSwitchProgramEnvironment& env, ProControllerC pbf_wait(context, 2000ms); context.wait_for_all_requests(); - if (!navigate_to_chansey(env.console, context)){ - env.console.log("Navigation failed. Resetting..."); - soft_reset(env.console, context); - continue; - } + if (ITEM_TO_FARM == ItemToFarm::LUCKY_EGG){ + if (!navigate_to_chansey(env.console, context)){ + env.console.log("Navigation failed. Resetting..."); + soft_reset(env.console, context); + continue; + } - swap_lead_pokemon(env.console, context); + swap_lead_pokemon(env.console, context); + + }else{ // Dragon Fang + navigate_to_dragonair(env.console, context); + } if (run_safari_zone(env, context)){ GO_HOME_WHEN_DONE.run_end_of_program(context); diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h index 995d7b06b1..55ae760cb9 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h @@ -37,18 +37,31 @@ class LuckyEggFarmer : public SingleSwitchProgramInstance { } private: + enum class ItemToFarm{ + LUCKY_EGG, + DRAGON_FANG + }; + // After exiting the safari zone building navigate to grass with Chansey. // Currently only supports running. Should add Surf option... bool navigate_to_chansey(ConsoleHandle& console, ProControllerContext& context); + // After exiting the safari zone building navigate to water with Dragonair. + // Currently only supports running. + void navigate_to_dragonair(ConsoleHandle& console, ProControllerContext& context); // Swap first and second pokemon. // First pokemon used to avoid encounters on the route to Chansey. Second pokemon used to improve encounter rates. void swap_lead_pokemon(ConsoleHandle& console, ProControllerContext& context); - // Reads wild encounter name and returns true if Chansey + // Reads wild encounter name and returns true if Chansey, uses a set list of possible names in the expected area. bool is_chansey(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + // Reads wild encounter name and returns true if Dragonair, uses a set list of possible names in the expected area. + bool is_dragonair(SingleSwitchProgramEnvironment& env, ProControllerContext& context); // Handles the encounter logic. Attempts to spin in place. Resets position to the top right corner of grass. // Returns true if transition to battle detected. - bool find_encounter(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + bool find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + // Handles the encounter logic. Attempts to hook pokemon using a fishing pole registered. + // Returns true if transition to battle detected. + bool find_encounter_fishing(SingleSwitchProgramEnvironment& env, ProControllerContext& context); // Handles the catch logic. Should be updated to throw bait for better catch rates. // Returns true if catch successful. Returns in the overworld. bool attempt_catch(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int& balls_left); @@ -60,6 +73,7 @@ class LuckyEggFarmer : public SingleSwitchProgramInstance { // Returns false if we need to soft reset (out of safari balls, out of steps, caught a full party of Chansey). bool run_safari_zone(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + EnumDropdownOption ITEM_TO_FARM; OCR::LanguageOCROption LANGUAGE; DeferredStopButtonOption STOP_AFTER_CURRENT; From 914d630a93ab4ba1e6afb6a73980d2fa9acb6ae7 Mon Sep 17 00:00:00 2001 From: Dalton-V Date: Wed, 24 Jun 2026 00:01:59 -0500 Subject: [PATCH 2/5] rename lucky egg farmer to held item farmer - safari zone --- .../ProgramStats/StatsDatabase.cpp | 1 + .../Source/PokemonFRLG/PokemonFRLG_Panels.cpp | 4 +- ...PokemonFRLG_HeldItemFarmer-SafariZone.cpp} | 94 +++++++++---------- ...> PokemonFRLG_HeldItemFarmer-SafariZone.h} | 18 ++-- SerialPrograms/cmake/SourceFiles.cmake | 4 +- 5 files changed, 61 insertions(+), 60 deletions(-) rename SerialPrograms/Source/PokemonFRLG/Programs/Farming/{PokemonFRLG_LuckyEggFarmer.cpp => PokemonFRLG_HeldItemFarmer-SafariZone.cpp} (84%) rename SerialPrograms/Source/PokemonFRLG/Programs/Farming/{PokemonFRLG_LuckyEggFarmer.h => PokemonFRLG_HeldItemFarmer-SafariZone.h} (86%) diff --git a/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp b/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp index 7ecd756b27..aa7125bf00 100644 --- a/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp +++ b/SerialPrograms/Source/CommonFramework/ProgramStats/StatsDatabase.cpp @@ -37,6 +37,7 @@ const std::map STATS_DATABASE_ALIASES{ {"PokemonSV:StatsResetBloodmoon", "PokemonSV:StatsResetEventBattle"}, {"PokemonLZA:ShinyHunt-Bench", "PokemonLZA:ShinyHunt-BenchSit"}, {"PokemonLZA:BerryBuyer", "PokemonLZA:StallBuyer"}, + {"PokemonFRLG:LuckyEggFarmer", "PokemonFRLG:HeldItemFarmerSafariZone"}, }; diff --git a/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp b/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp index 7ea15a0a47..ae224517cf 100644 --- a/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp +++ b/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp @@ -9,8 +9,8 @@ #include "PokemonFRLG_Panels.h" #include "PokemonFRLG_Settings.h" +#include "Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h" #include "Programs/Farming/PokemonFRLG_ItemDuplication.h" -#include "Programs/Farming/PokemonFRLG_LuckyEggFarmer.h" #include "Programs/Farming/PokemonFRLG_NuggetBridgeFarmer.h" #include "Programs/Farming/PokemonFRLG_PickupFarmer.h" #include "Programs/Farming/PokemonFRLG_EvTrainer.h" @@ -55,7 +55,7 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); - ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); //ret.emplace_back("---- General ----"); diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp similarity index 84% rename from SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp rename to SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp index 25be2f9d37..b05c48f2c7 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp @@ -1,4 +1,4 @@ -/* Lucky Egg Farmer +/* Held Item Farmer - Safari Zone * * From: https://github.com/PokemonAutomation/ * @@ -22,57 +22,59 @@ #include "PokemonFRLG/Inference/PokemonFRLG_PokedexRegisteredDetector.h" #include "PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.h" #include "PokemonFRLG/PokemonFRLG_Navigation.h" -#include "PokemonFRLG_LuckyEggFarmer.h" +#include "PokemonFRLG_HeldItemFarmer-SafariZone.h" namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonFRLG{ -LuckyEggFarmer_Descriptor::LuckyEggFarmer_Descriptor() +HeldItemFarmerSafariZone_Descriptor::HeldItemFarmerSafariZone_Descriptor() : SingleSwitchProgramDescriptor( - "PokemonFRLG:LuckyEggFarmer", - Pokemon::STRING_POKEMON + " FRLG", "Lucky Egg Farmer", - "Programs/PokemonFRLG/LuckyEggFarmer.html", - "Farm the Lucky Egg from Chansey.", + "PokemonFRLG:HeldItemFarmerSafariZone", + Pokemon::STRING_POKEMON + " FRLG", "Held Item Farmer - Safari Zone", + "Programs/PokemonFRLG/HeldItemFarmer-SafariZone.html", + "Farm held items from Chansey and Dragonair in the Safari Zone.", ProgramControllerClass::StandardController_RequiresPrecision, FeedbackType::REQUIRED, AllowCommandsWhenRunning::DISABLE_COMMANDS ) {} -struct LuckyEggFarmer_Descriptor::Stats : public StatsTracker { +struct HeldItemFarmerSafariZone_Descriptor::Stats : public StatsTracker { public: Stats() : encounters(m_stats["Encounters"]) - , chanseys_found(m_stats["Chanseys Found"]) - , chanseys_caught(m_stats["Chanseys Caught"]) - , eggs(m_stats["Lucky Eggs"]) + , target_pokemon_found(m_stats["Target Pokemon Found"]) + , target_pokemon_caught(m_stats["Target Pokemon Caught"]) + , items(m_stats["Items"]) , shinies(m_stats["Shinies"]) , errors(m_stats["Errors"]) { m_display_order.emplace_back("Encounters"); - m_display_order.emplace_back("Chanseys Found"); - m_display_order.emplace_back("Chanseys Caught"); - m_display_order.emplace_back("Lucky Eggs"); + m_display_order.emplace_back("Target Pokemon Found"); + m_display_order.emplace_back("Target Pokemon Caught"); + m_display_order.emplace_back("Items"); m_display_order.emplace_back("Shinies", HIDDEN_IF_ZERO); m_display_order.emplace_back("Errors", HIDDEN_IF_ZERO); -// m_aliases["Chanseys Caught"] = "Caught"; - m_aliases["Lucky Eggs Found"] = "Lucky Eggs"; + m_aliases["Lucky Eggs Found"] = "Items"; + m_aliases["Lucky Eggs"] = "Items"; + m_aliases["Chanseys Found"] = "Target Pokemon Found"; + m_aliases["Chanseys Caught"] = "Target Pokemon Caught"; } std::atomic& encounters; - std::atomic& chanseys_found; - std::atomic& chanseys_caught; - std::atomic& eggs; + std::atomic& target_pokemon_found; + std::atomic& target_pokemon_caught; + std::atomic& items; std::atomic& shinies; std::atomic& errors; }; -std::unique_ptr LuckyEggFarmer_Descriptor::make_stats() const{ +std::unique_ptr HeldItemFarmerSafariZone_Descriptor::make_stats() const{ return std::unique_ptr(new Stats()); } -LuckyEggFarmer::LuckyEggFarmer() +HeldItemFarmerSafariZone::HeldItemFarmerSafariZone() : ITEM_TO_FARM( "Item to Farm:", { @@ -102,8 +104,8 @@ LuckyEggFarmer::LuckyEggFarmer() ) , GO_HOME_WHEN_DONE(false) , NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600)) - , NOTIFICATION_LUCKY_EGG( - "Lucky Egg Found", + , NOTIFICATION_HELD_ITEM( + "Held Item Found", true, true, ImageAttachmentMode::JPG, { "Notifs", "Showcase" } ) @@ -114,7 +116,7 @@ LuckyEggFarmer::LuckyEggFarmer() ) , NOTIFICATIONS({ &NOTIFICATION_STATUS_UPDATE, - &NOTIFICATION_LUCKY_EGG, + &NOTIFICATION_HELD_ITEM, &NOTIFICATION_SHINY, &NOTIFICATION_PROGRAM_FINISH, &NOTIFICATION_ERROR_FATAL, @@ -129,7 +131,7 @@ LuckyEggFarmer::LuckyEggFarmer() PA_ADD_OPTION(NOTIFICATIONS); } -bool LuckyEggFarmer::navigate_to_chansey(ConsoleHandle& console, ProControllerContext& context){ +bool HeldItemFarmerSafariZone::navigate_to_chansey(ConsoleHandle& console, ProControllerContext& context){ BlackScreenWatcher zone_exit(COLOR_RED); int ret = run_until( @@ -267,14 +269,14 @@ bool LuckyEggFarmer::navigate_to_chansey(ConsoleHandle& console, ProControllerCo return true; } -void LuckyEggFarmer::navigate_to_dragonair(ConsoleHandle& console, ProControllerContext& context){ +void HeldItemFarmerSafariZone::navigate_to_dragonair(ConsoleHandle& console, ProControllerContext& context){ ssf_press_button(context, BUTTON_B, 0ms, 2848ms); pbf_press_dpad(context, DPAD_UP, 1315ms, 0ms); pbf_press_dpad(context, DPAD_RIGHT, 755ms, 0ms); pbf_press_dpad(context, DPAD_UP, 580ms, 0ms); } -void LuckyEggFarmer::swap_lead_pokemon(ConsoleHandle& console, ProControllerContext& context){ +void HeldItemFarmerSafariZone::swap_lead_pokemon(ConsoleHandle& console, ProControllerContext& context){ open_party_menu_from_overworld(console, context, StartMenuContext::SAFARI_ZONE); pbf_press_button(context, BUTTON_A, 250ms, 100ms); pbf_press_dpad(context, DPAD_UP, 250ms, 100ms); @@ -288,7 +290,7 @@ void LuckyEggFarmer::swap_lead_pokemon(ConsoleHandle& console, ProControllerCont context.wait_for_all_requests(); } -bool LuckyEggFarmer::find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +bool HeldItemFarmerSafariZone::find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ ssf_press_button(context, BUTTON_B, 0ms, 400ms); pbf_press_dpad(context, DPAD_RIGHT, 400ms, 0ms); pbf_wait(context, 100ms); @@ -327,7 +329,7 @@ bool LuckyEggFarmer::find_encounter_grass(SingleSwitchProgramEnvironment& env, P } } -bool LuckyEggFarmer::find_encounter_fishing(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +bool HeldItemFarmerSafariZone::find_encounter_fishing(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ WhiteDialogWatcher fishing_dialog(COLOR_RED); BlackScreenWatcher battle_entered(COLOR_RED); AdvanceBattleDialogWatcher battle_dialog(COLOR_RED); @@ -359,7 +361,7 @@ bool LuckyEggFarmer::find_encounter_fishing(SingleSwitchProgramEnvironment& env, } } -bool LuckyEggFarmer::is_chansey(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +bool HeldItemFarmerSafariZone::is_chansey(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ std::set subset = { "nidoran-f", "nidoran-m", @@ -384,7 +386,7 @@ bool LuckyEggFarmer::is_chansey(SingleSwitchProgramEnvironment& env, ProControll return encounter.name == "chansey"; } -bool LuckyEggFarmer::is_dragonair(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +bool HeldItemFarmerSafariZone::is_dragonair(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ std::set subset = { "goldeen", "seaking", @@ -406,7 +408,7 @@ bool LuckyEggFarmer::is_dragonair(SingleSwitchProgramEnvironment& env, ProContro return encounter.name == "dragonair"; } -bool LuckyEggFarmer::attempt_catch(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int& balls_left){ +bool HeldItemFarmerSafariZone::attempt_catch(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int& balls_left){ //TODO: Optimal bait/ball throwing int distraction_thrown = 0; while (true){ @@ -516,7 +518,7 @@ bool LuckyEggFarmer::attempt_catch(SingleSwitchProgramEnvironment& env, ProContr } } -bool LuckyEggFarmer::check_for_lucky_egg(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building){ +bool HeldItemFarmerSafariZone::check_for_held_item(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building){ if (returned_to_building){ open_party_menu_from_overworld(console, context, StartMenuContext::STANDARD); } @@ -532,8 +534,8 @@ bool LuckyEggFarmer::check_for_lucky_egg(ConsoleHandle& console, ProControllerCo return false; } -bool LuckyEggFarmer::run_safari_zone(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ - LuckyEggFarmer_Descriptor::Stats& stats = env.current_stats(); +bool HeldItemFarmerSafariZone::run_safari_zone(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + HeldItemFarmerSafariZone_Descriptor::Stats& stats = env.current_stats(); int chansey_count = 0; int balls_left = 30; @@ -589,16 +591,14 @@ bool LuckyEggFarmer::run_safari_zone(SingleSwitchProgramEnvironment& env, ProCon } } - - //TODO: Update these now that there are two hunts - env.log("Chansey found!"); - stats.chanseys_found++; + env.log("Target Pokemon found!"); + stats.target_pokemon_found++; env.update_stats(); bool caught = attempt_catch(env, context, balls_left); if (caught){ - stats.chanseys_caught++; + stats.target_pokemon_caught++; env.update_stats(); chansey_count++; } @@ -623,25 +623,25 @@ bool LuckyEggFarmer::run_safari_zone(SingleSwitchProgramEnvironment& env, ProCon } if (caught){ - if (check_for_lucky_egg(env.console, context, in_safari_zone_building)){ - env.log("Lucky Egg found!"); - stats.eggs++; + if (check_for_held_item(env.console, context, in_safari_zone_building)){ + env.log("Held Item found!"); + stats.items++; env.update_stats(); if (TAKE_VIDEO){ pbf_press_button(context, BUTTON_CAPTURE, 2000ms, 0ms); } send_program_notification( env, - NOTIFICATION_LUCKY_EGG, + NOTIFICATION_HELD_ITEM, Color(0xffffc0cb), - "Lucky Egg found!", + "Held Item found!", {}, "", env.console.video().snapshot(), true ); return true; } - env.log("Lucky Egg not found. Continuing to farm..."); + env.log("Held Item not found. Continuing to farm..."); pbf_mash_button(context, BUTTON_B, 1500ms); context.wait_for_all_requests(); } @@ -655,7 +655,7 @@ bool LuckyEggFarmer::run_safari_zone(SingleSwitchProgramEnvironment& env, ProCon return false; } -void LuckyEggFarmer::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +void HeldItemFarmerSafariZone::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ home_black_border_check(env.console, context); diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h similarity index 86% rename from SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h rename to SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h index 55ae760cb9..c0645257a2 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h @@ -1,11 +1,11 @@ -/* Lucky Egg Farmer +/* Held Item Farmer - Safari Zone * * From: https://github.com/PokemonAutomation/ * */ -#ifndef PokemonAutomation_PokemonFRLG_LuckyEggFarmer_H -#define PokemonAutomation_PokemonFRLG_LuckyEggFarmer_H +#ifndef PokemonAutomation_PokemonFRLG_HeldItemFarmer_SafariZone_H +#define PokemonAutomation_PokemonFRLG_HeldItemFarmer_SafariZone_H #include "Common/Cpp/Options/ButtonOption.h" #include "CommonTools/Options/LanguageOCROption.h" @@ -19,16 +19,16 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonFRLG{ -class LuckyEggFarmer_Descriptor : public SingleSwitchProgramDescriptor{ +class HeldItemFarmerSafariZone_Descriptor : public SingleSwitchProgramDescriptor{ public: - LuckyEggFarmer_Descriptor(); + HeldItemFarmerSafariZone_Descriptor(); struct Stats; virtual std::unique_ptr make_stats() const override; }; -class LuckyEggFarmer : public SingleSwitchProgramInstance { +class HeldItemFarmerSafariZone : public SingleSwitchProgramInstance { public: - LuckyEggFarmer(); + HeldItemFarmerSafariZone(); virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; virtual void start_program_border_check( VideoStream& stream, @@ -67,7 +67,7 @@ class LuckyEggFarmer : public SingleSwitchProgramInstance { bool attempt_catch(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int& balls_left); // Opens the party menu from a given overworld location (safari zone, or the main safari zone building) // Checks the last four party slots for held items. Returns true if item detected. - bool check_for_lucky_egg(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building); + bool check_for_held_item(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building); // Handles the main loop once we are in the grass ready to search for a Chansey. // Returns true if a stop condition is met (lucky egg or shiny found). // Returns false if we need to soft reset (out of safari balls, out of steps, caught a full party of Chansey). @@ -81,7 +81,7 @@ class LuckyEggFarmer : public SingleSwitchProgramInstance { GoHomeWhenDoneOption GO_HOME_WHEN_DONE; EventNotificationOption NOTIFICATION_STATUS_UPDATE; - EventNotificationOption NOTIFICATION_LUCKY_EGG; + EventNotificationOption NOTIFICATION_HELD_ITEM; EventNotificationOption NOTIFICATION_SHINY; EventNotificationsOption NOTIFICATIONS; diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 902eee9a0e..9509ea9e6f 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1519,10 +1519,10 @@ file(GLOB LIBRARY_SOURCES Source/PokemonFRLG/PokemonFRLG_Panels.h Source/PokemonFRLG/PokemonFRLG_Settings.cpp Source/PokemonFRLG/PokemonFRLG_Settings.h + Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp + Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h Source/PokemonFRLG/Programs/Farming/PokemonFRLG_ItemDuplication.cpp Source/PokemonFRLG/Programs/Farming/PokemonFRLG_ItemDuplication.h - Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.cpp - Source/PokemonFRLG/Programs/Farming/PokemonFRLG_LuckyEggFarmer.h Source/PokemonFRLG/Programs/Farming/PokemonFRLG_NuggetBridgeFarmer.cpp Source/PokemonFRLG/Programs/Farming/PokemonFRLG_NuggetBridgeFarmer.h Source/PokemonFRLG/Programs/Farming/PokemonFRLG_PickupFarmer.cpp From d6d14d7555867cca638f764145f65dcc13fe6f3c Mon Sep 17 00:00:00 2001 From: Dalton-V Date: Wed, 24 Jun 2026 09:46:49 -0500 Subject: [PATCH 3/5] Use resently added fishing encounter method --- .../PokemonFRLG_HeldItemFarmer-SafariZone.cpp | 65 +++++-------------- .../PokemonFRLG_HeldItemFarmer-SafariZone.h | 9 +-- 2 files changed, 21 insertions(+), 53 deletions(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp index b05c48f2c7..1950a95333 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp @@ -290,7 +290,7 @@ void HeldItemFarmerSafariZone::swap_lead_pokemon(ConsoleHandle& console, ProCont context.wait_for_all_requests(); } -bool HeldItemFarmerSafariZone::find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +int HeldItemFarmerSafariZone::find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ ssf_press_button(context, BUTTON_B, 0ms, 400ms); pbf_press_dpad(context, DPAD_RIGHT, 400ms, 0ms); pbf_wait(context, 100ms); @@ -321,42 +321,11 @@ bool HeldItemFarmerSafariZone::find_encounter_grass(SingleSwitchProgramEnvironme case 0: case 1: env.log("Battle entered."); - return true; + bool encounter_shiny = handle_encounter(env.console, context, true); + return encounter_shiny ? 1 : 0; case 2: env.log("Out of steps dialog detected. Resetting..."); - return false; - } - } -} - -bool HeldItemFarmerSafariZone::find_encounter_fishing(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ - WhiteDialogWatcher fishing_dialog(COLOR_RED); - BlackScreenWatcher battle_entered(COLOR_RED); - AdvanceBattleDialogWatcher battle_dialog(COLOR_RED); - WallClock start = current_time(); - - while (true){ - if (current_time() - start > std::chrono::seconds(300)){ - env.log("No pokemon hooked after 5 minutes. Resetting."); - return false; - } - - pbf_press_button(context, BUTTON_MINUS, 200ms, 200ms); - context.wait_for_all_requests(); - - int ret = wait_until( - env.console, context, - std::chrono::milliseconds(5000), - { fishing_dialog, battle_entered, battle_dialog } - ); - - if (ret == 0){ - env.log("Fishing dialog detected."); - pbf_press_button(context, BUTTON_B, 200ms, 200ms); - context.wait_for_all_requests(); - } else if (ret == 1 || ret == 2){ - env.log("Battle entered."); - return true; + return -1; } } } @@ -542,20 +511,20 @@ bool HeldItemFarmerSafariZone::run_safari_zone(SingleSwitchProgramEnvironment& e while (chansey_count < 4){ send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE); + int encounter_result = -1; if (ITEM_TO_FARM == ItemToFarm::LUCKY_EGG){ - if (!find_encounter_grass(env, context)){ - return false; - } + encounter_result = find_encounter_grass(env, context); }else{ - if (!find_encounter_fishing(env, context)){ - return false; - } + encounter_result = fish_encounter(env.console, context); } - - bool encounter_shiny = handle_encounter(env.console, context, true); - stats.encounters++; - if (encounter_shiny){ + switch (encounter_result){ + case 0: + stats.encounters++; + env.update_stats(); + break; + case 1: + stats.encounters++; stats.shinies++; env.update_stats(); send_program_notification( @@ -571,8 +540,10 @@ bool HeldItemFarmerSafariZone::run_safari_zone(SingleSwitchProgramEnvironment& e pbf_press_button(context, BUTTON_CAPTURE, 2000ms, 0ms); } return true; - }else{ - env.update_stats(); + case -1: + default: + // Failed to find an encounter in the allotted time or ran out of steps in the grass. Soft Reset and try again. + return false; } if (ITEM_TO_FARM == ItemToFarm::LUCKY_EGG){ diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h index c0645257a2..53b94a7e22 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h @@ -56,12 +56,9 @@ class HeldItemFarmerSafariZone : public SingleSwitchProgramInstance { bool is_chansey(SingleSwitchProgramEnvironment& env, ProControllerContext& context); // Reads wild encounter name and returns true if Dragonair, uses a set list of possible names in the expected area. bool is_dragonair(SingleSwitchProgramEnvironment& env, ProControllerContext& context); - // Handles the encounter logic. Attempts to spin in place. Resets position to the top right corner of grass. - // Returns true if transition to battle detected. - bool find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context); - // Handles the encounter logic. Attempts to hook pokemon using a fishing pole registered. - // Returns true if transition to battle detected. - bool find_encounter_fishing(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + // Handles the grass encounter logic. Attempts to spin in place. Resets position to the top right corner of grass. + // returns -1 if no encounter is triggered, 0 if a non-shiny is encountered, and 1 if a shiny is encountered + int find_encounter_grass(SingleSwitchProgramEnvironment& env, ProControllerContext& context); // Handles the catch logic. Should be updated to throw bait for better catch rates. // Returns true if catch successful. Returns in the overworld. bool attempt_catch(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int& balls_left); From 0d0916f9890f4c1635863647c361d350e97badb2 Mon Sep 17 00:00:00 2001 From: Dalton-V Date: Wed, 24 Jun 2026 10:26:56 -0500 Subject: [PATCH 4/5] Use new party detector to know what pokemon to check for held item. Added user setup validation --- .../PokemonFRLG_HeldItemFarmer-SafariZone.cpp | 45 ++++++++++++++----- .../PokemonFRLG_HeldItemFarmer-SafariZone.h | 4 +- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp index 1950a95333..6bbe86c53e 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp @@ -5,6 +5,7 @@ */ #include "Common/Cpp/Options/ButtonOption.h" +#include "CommonFramework/Exceptions/OperationFailedException.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/Language.h" #include "CommonFramework/Notifications/ProgramNotifications.h" @@ -17,12 +18,14 @@ #include "PokemonFRLG/Inference/Dialogs/PokemonFRLG_DialogDetector.h" #include "PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.h" #include "PokemonFRLG/Inference/Menus/PokemonFRLG_PartyHeldItemDetector.h" +#include "PokemonFRLG/Inference/Menus/PokemonFRLG_PartyMenuDetector.h" #include "PokemonFRLG/Inference/Menus/PokemonFRLG_StartMenuDetector.h" #include "PokemonFRLG/Inference/PokemonFRLG_BattleSelectionArrowDetector.h" #include "PokemonFRLG/Inference/PokemonFRLG_PokedexRegisteredDetector.h" #include "PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.h" #include "PokemonFRLG/PokemonFRLG_Navigation.h" #include "PokemonFRLG_HeldItemFarmer-SafariZone.h" +#include "Common/Cpp/Exceptions.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -321,8 +324,7 @@ int HeldItemFarmerSafariZone::find_encounter_grass(SingleSwitchProgramEnvironmen case 0: case 1: env.log("Battle entered."); - bool encounter_shiny = handle_encounter(env.console, context, true); - return encounter_shiny ? 1 : 0; + return handle_encounter(env.console, context, true) ? 1 : 0; case 2: env.log("Out of steps dialog detected. Resetting..."); return -1; @@ -487,7 +489,7 @@ bool HeldItemFarmerSafariZone::attempt_catch(SingleSwitchProgramEnvironment& env } } -bool HeldItemFarmerSafariZone::check_for_held_item(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building){ +bool HeldItemFarmerSafariZone::check_for_held_item(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building, int party_count){ if (returned_to_building){ open_party_menu_from_overworld(console, context, StartMenuContext::STANDARD); } @@ -495,7 +497,7 @@ bool HeldItemFarmerSafariZone::check_for_held_item(ConsoleHandle& console, ProCo open_party_menu_from_overworld(console, context, StartMenuContext::SAFARI_ZONE); } - PartyHeldItemDetector held_item_detector(COLOR_RED, &console.overlay(), ImageFloatBox(0.432, 0.3, 0.030, 0.485)); + PartyHeldItemDetector held_item_detector(COLOR_RED, &console.overlay(), static_cast(party_count - 1)); if (held_item_detector.detect(console.video().snapshot())){ return true; } @@ -503,13 +505,12 @@ bool HeldItemFarmerSafariZone::check_for_held_item(ConsoleHandle& console, ProCo return false; } -bool HeldItemFarmerSafariZone::run_safari_zone(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ +bool HeldItemFarmerSafariZone::run_safari_zone(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int party_count){ HeldItemFarmerSafariZone_Descriptor::Stats& stats = env.current_stats(); - int chansey_count = 0; int balls_left = 30; - while (chansey_count < 4){ + while (party_count < 6){ send_program_status_notification(env, NOTIFICATION_STATUS_UPDATE); int encounter_result = -1; if (ITEM_TO_FARM == ItemToFarm::LUCKY_EGG){ @@ -571,7 +572,7 @@ bool HeldItemFarmerSafariZone::run_safari_zone(SingleSwitchProgramEnvironment& e if (caught){ stats.target_pokemon_caught++; env.update_stats(); - chansey_count++; + party_count++; } pbf_wait(context, 500ms); @@ -594,7 +595,7 @@ bool HeldItemFarmerSafariZone::run_safari_zone(SingleSwitchProgramEnvironment& e } if (caught){ - if (check_for_held_item(env.console, context, in_safari_zone_building)){ + if (check_for_held_item(env.console, context, in_safari_zone_building, party_count)){ env.log("Held Item found!"); stats.items++; env.update_stats(); @@ -632,6 +633,30 @@ void HeldItemFarmerSafariZone::program(SingleSwitchProgramEnvironment& env, ProC DeferredStopButtonOption::ResetOnExit reset_on_exit(STOP_AFTER_CURRENT); + open_party_menu_from_overworld(env.console, context, StartMenuContext::STANDARD); + PartySlot detected_party_slot = detect_last_occupied_party_slot(env.console); + int party_count = (int)detected_party_slot + 1; + + if (party_count >= 6){ + throw UserSetupError(env.console, "Party is full. Please remove some Pokemon from the party and try again."); + } + + if (ITEM_TO_FARM == ItemToFarm::LUCKY_EGG && party_count == 1){ + throw UserSetupError(env.console, "Farming Chansey requires at least 2 Pokemon in the party."); + } + + StartMenuDetector start_menu_detector(COLOR_RED); + PartyMenuDetector party_menu_detector(COLOR_RED); + + while (true){ + pbf_mash_button(context, BUTTON_B, 1000ms); + context.wait_for_all_requests(); + VideoSnapshot snapshot = env.console.video().snapshot(); + if (!start_menu_detector.detect(snapshot) && !party_menu_detector.detect(snapshot)){ + break; + } + } + while (true){ pbf_press_dpad(context, DPAD_UP, 200ms, 0ms); @@ -682,7 +707,7 @@ void HeldItemFarmerSafariZone::program(SingleSwitchProgramEnvironment& env, ProC navigate_to_dragonair(env.console, context); } - if (run_safari_zone(env, context)){ + if (run_safari_zone(env, context, party_count)){ GO_HOME_WHEN_DONE.run_end_of_program(context); return; // Already sent notification in run_safari_zone if shiny or lucky egg found. } diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h index 53b94a7e22..239afddacc 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h @@ -64,11 +64,11 @@ class HeldItemFarmerSafariZone : public SingleSwitchProgramInstance { bool attempt_catch(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int& balls_left); // Opens the party menu from a given overworld location (safari zone, or the main safari zone building) // Checks the last four party slots for held items. Returns true if item detected. - bool check_for_held_item(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building); + bool check_for_held_item(ConsoleHandle& console, ProControllerContext& context, bool returned_to_building, int party_count); // Handles the main loop once we are in the grass ready to search for a Chansey. // Returns true if a stop condition is met (lucky egg or shiny found). // Returns false if we need to soft reset (out of safari balls, out of steps, caught a full party of Chansey). - bool run_safari_zone(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + bool run_safari_zone(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int party_count); EnumDropdownOption ITEM_TO_FARM; OCR::LanguageOCROption LANGUAGE; From f3943407a81ca146229eeb8974ad35b7553862d6 Mon Sep 17 00:00:00 2001 From: Dalton-V Date: Wed, 24 Jun 2026 10:36:04 -0500 Subject: [PATCH 5/5] Hide new item behind beta --- .../PokemonFRLG_HeldItemFarmer-SafariZone.cpp | 18 ++++++++++++++---- .../PokemonFRLG_HeldItemFarmer-SafariZone.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp index 6bbe86c53e..8e3e5545e6 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.cpp @@ -4,6 +4,7 @@ * */ +#include "CommonFramework/GlobalSettingsPanel.h" #include "Common/Cpp/Options/ButtonOption.h" #include "CommonFramework/Exceptions/OperationFailedException.h" #include "CommonFramework/ImageTools/ImageBoxes.h" @@ -77,13 +78,22 @@ std::unique_ptr HeldItemFarmerSafariZone_Descriptor::make_stats() return std::unique_ptr(new Stats()); } +EnumDropdownDatabase HeldItemFarmerSafariZone::item_to_farm_options(){ + EnumDropdownDatabase options{ + {ItemToFarm::LUCKY_EGG, "Lucky Egg", "Farm Chansey for Lucky Eggs."}, + }; + + if (IS_BETA_VERSION || PreloadSettings::instance().DEVELOPER_MODE){ + options.add(ItemToFarm::DRAGON_FANG, "Dragon Fang", "Farm Dragonair for Dragon Fangs.", true); + } + + return options; +} + HeldItemFarmerSafariZone::HeldItemFarmerSafariZone() : ITEM_TO_FARM( "Item to Farm:", - { - {ItemToFarm::LUCKY_EGG, "Lucky Egg", "Farm Chansey for Lucky Eggs."}, - {ItemToFarm::DRAGON_FANG, "Dragon Fang", "Farm Dragonair for Dragon Fangs."}, - }, + item_to_farm_options(), LockMode::LOCK_WHILE_RUNNING, ItemToFarm::LUCKY_EGG ) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h index 239afddacc..e8b9b4c931 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_HeldItemFarmer-SafariZone.h @@ -42,6 +42,7 @@ class HeldItemFarmerSafariZone : public SingleSwitchProgramInstance { DRAGON_FANG }; + static EnumDropdownDatabase item_to_farm_options(); // After exiting the safari zone building navigate to grass with Chansey. // Currently only supports running. Should add Surf option...