From 9950cac9862035bd99d6e539a264ab94670ae769 Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Tue, 14 Apr 2026 23:25:07 -0500 Subject: [PATCH 1/4] no more blind resets --- .../ShinyHunting/PokemonFRLG_RngHelper.cpp | 914 ++++++++++-------- .../ShinyHunting/PokemonFRLG_RngHelper.h | 6 + 2 files changed, 509 insertions(+), 411 deletions(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp index 1662f64793..ac5a63fc9f 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp @@ -17,6 +17,10 @@ #include "CommonTools/StartupChecks/StartProgramChecks.h" #include "Pokemon/Pokemon_Strings.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/NintendoSwitch_Settings.h" +#include "NintendoSwitch/Inference/NintendoSwitch_HomeMenuDetector.h" +#include "NintendoSwitch/Inference/NintendoSwitch_UpdatePopupDetector.h" +#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h" #include "PokemonFRLG/Inference/PokemonFRLG_SelectionArrowDetector.h" #include "PokemonFRLG/Inference/PokemonFRLG_ShinySymbolDetector.h" #include "PokemonFRLG/Inference/Dialogs/PokemonFRLG_DialogDetector.h" @@ -172,56 +176,6 @@ RngHelper::RngHelper() namespace{ -void hard_reset(ProControllerContext& context){ - // close the game - pbf_press_button(context, BUTTON_HOME, 200ms, 1300ms); - pbf_press_button(context, BUTTON_X, 200ms, 1300ms); - pbf_press_button(context, BUTTON_A, 200ms, 2800ms); - // press A to select game - pbf_press_button(context, BUTTON_A, 200ms, 2300ms); - // press A to select profile and launch the game - pbf_press_button(context, BUTTON_A, 200ms, 300ms); - // return to HOME menu and wait a moment - pbf_press_button(context, BUTTON_HOME, 125ms, 2000ms); - // open game - pbf_press_button(context, BUTTON_A, 125ms, 0ms); -} - - -uint64_t wait_for_copyright_text(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ - // wait for copyright text to appear - BlackScreenWatcher black_screen(COLOR_RED); - context.wait_for_all_requests(); - WallClock start_time = current_time(); // immediately (more or less) after the button press to enter the game - int black_ret = wait_until( - env.console, context, 10000ms, - {black_screen}, - 1ms - ); - if (black_ret < 0){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Black screen not detected within 10 seconds of starting game.", - env.console - ); - } - BlackScreenOverWatcher copyright_detected(COLOR_RED); - int ret = wait_until( - env.console, context, 10000ms, - {copyright_detected }, - 1ms - ); - if (ret < 0){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Black screen detected for more than 10 seconds after starting game.", - env.console - ); - } - auto elapsed = current_time() - start_time; // when the copyright text appears - return std::chrono::duration_cast(elapsed).count(); -} - void set_seed_after_delay(ProControllerContext& context, SimpleIntegerOption& SEED_DELAY, SimpleIntegerOption& SEED_CALIBRATION, int64_t& FIXED_SEED_OFFSET){ // wait on title screen for the specified delay pbf_wait(context, std::chrono::milliseconds(SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET)); @@ -229,14 +183,7 @@ void set_seed_after_delay(ProControllerContext& context, SimpleIntegerOption 0){ + wait_with_teachy_tv(context, TEACHY_DELAY); + } + + uint64_t MODIFIED_INGAME_DELAY; + switch (TARGET){ + case Target::starters: + collect_starter_after_delay(context, INGAME_DELAY); + return; + case Target::magikarp: + collect_magikarp_after_delay(context, INGAME_DELAY); + return; + case Target::hitmon: + collect_hitmon_after_delay(context, INGAME_DELAY); + return; + case Target::eevee: + collect_eevee_after_delay(context, INGAME_DELAY); + return; + case Target::lapras: + collect_lapras_after_delay(context, INGAME_DELAY); + return; + case Target::fossils: + collect_fossil_after_delay(context, INGAME_DELAY); + return; + case Target::gamecornerabra: + collect_gamecorner_after_delay(context, INGAME_DELAY, 0); + return; + case Target::gamecornerclefairy: + collect_gamecorner_after_delay(context, INGAME_DELAY, 1); + return; + case Target::gamecornerdratini: + collect_gamecorner_after_delay(context, INGAME_DELAY, 2); + return; + case Target::gamecornerbug: + collect_gamecorner_after_delay(context, INGAME_DELAY, 3); + return; + case Target::gamecornerporygon: + collect_gamecorner_after_delay(context, INGAME_DELAY, 4); + return; + case Target::togepi: + collect_togepi_egg_after_delay(context, INGAME_DELAY); + return; + case Target::staticencounter: + encounter_static_after_delay(context, INGAME_DELAY); + return; + case Target::snorlax: + encounter_snorlax_after_delay(context, INGAME_DELAY); + return; + case Target::mewtwo: + encounter_mewtwo_after_delay(context, INGAME_DELAY); + return; + case Target::hooh: + encounter_hooh_after_delay(context, INGAME_DELAY); + return; + case Target::hypno: + encounter_hypno_after_delay(context, INGAME_DELAY); + return; + case Target::sweetscent: + use_sweet_scent(context, INGAME_DELAY, SAFARI_ZONE); + return; + case Target::fishing: + use_registered_fishing_rod(context, INGAME_DELAY); + return; + case Target::safarizonecenter: + MODIFIED_INGAME_DELAY = INGAME_DELAY - 20670; + walk_to_safarizonecenter(context); + use_sweet_scent(context, MODIFIED_INGAME_DELAY, true); + return; + case Target::safarizoneeast: + MODIFIED_INGAME_DELAY = INGAME_DELAY - 36160; + walk_to_safarizoneeast(context); + use_sweet_scent(context, MODIFIED_INGAME_DELAY, true); + return; + case Target::safarizonenorth: + MODIFIED_INGAME_DELAY = INGAME_DELAY - 37410; + walk_to_safarizonenorth(context); + use_sweet_scent(context, MODIFIED_INGAME_DELAY, true); + return; + case Target::safarizonewest: + MODIFIED_INGAME_DELAY = INGAME_DELAY - 51430; + walk_to_safarizonewest(context); + use_sweet_scent(context, MODIFIED_INGAME_DELAY, true); + case Target::safarizonesurf: + MODIFIED_INGAME_DELAY = INGAME_DELAY - 30300; + walk_to_safarizonesurf(context); + use_sweet_scent(context, MODIFIED_INGAME_DELAY, true); + return; + case Target::safarizonefish: + MODIFIED_INGAME_DELAY = INGAME_DELAY - 30300; + walk_to_safarizonefish(context); + use_registered_fishing_rod(context, MODIFIED_INGAME_DELAY); + return; + } +} + +void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ + go_home(env.console, context); + close_game_from_home(env.console, context); + start_game_from_home(env.console, context, ConsoleSettings::instance().TOLERATE_SYSTEM_UPDATE_MENU_SLOW, uint8_t(0), uint8_t(0)); // TODO: add option for user slot if needed + go_home(env.console, context); // happens as soon as a black screen is detected + + // attempt to resume the game and perform the blind sequence + // by this point, the license check should be over, so we don't need to worry about it when resuming the game + // profile selection is also already taken care of + uint8_t attempts = 0; + while(true){ + if (attempts >= 5){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "RngHelper(): Failed to resume the game 5 times in a row.", + env.console + ); + } + + UpdateMenuWatcher update_detector(env.console); + context.wait_for_all_requests(); + int ret = run_until( + env.console, context, + [this, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE](ProControllerContext& context) { + pbf_press_button(context, BUTTON_A, 80ms, 0ms); + perform_blind_sequence(context, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); + }, + { update_detector } + ); + + switch (ret){ + case 0: + attempts++; + env.log("Detected update window.", COLOR_RED); + pbf_press_dpad(context, DPAD_UP, 40ms, 0ms); + pbf_press_button(context, BUTTON_A, 80ms, 4000ms); + context.wait_for_all_requests(); + continue; + default: + return; + } + } +} + +void RngHelper::reset_and_detect_copyright_text(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + go_home(env.console, context); + close_game_from_home(env.console, context); + start_game_from_home(env.console, context, ConsoleSettings::instance().TOLERATE_SYSTEM_UPDATE_MENU_SLOW, uint8_t(0), uint8_t(0)); // TODO: add option for user slot if needed + go_home(env.console, context); // happens as soon as a black screen is detected + + uint8_t attempts = 0; + while(true){ + if (attempts >= 5){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "RngHelper(): Failed to resume the game 5 times in a row.", + env.console + ); + } + + UpdateMenuWatcher update_detector(env.console); + BlackScreenWatcher blackscreen_detector(COLOR_RED); + context.wait_for_all_requests(); + int ret = run_until( + env.console, context, + [](ProControllerContext& context) { + pbf_press_button(context, BUTTON_A, 80ms, 9920ms); + }, + { update_detector, blackscreen_detector }, + 1ms + ); + + BlackScreenOverWatcher copyright_detector(COLOR_RED); + int ret2; + switch (ret){ + case 0: + attempts++; + env.log("Detected update window.", COLOR_RED); + pbf_press_dpad(context, DPAD_UP, 40ms, 0ms); + pbf_press_button(context, BUTTON_A, 80ms, 4000ms); + context.wait_for_all_requests(); + continue; + case 1: + context.wait_for_all_requests(); + ret2 = wait_until( + env.console, context, 10000ms, + {copyright_detector }, + 1ms + ); + if (ret2 < 0){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Black screen detected for more than 10 seconds after starting game.", + env.console + ); + } + return; + default: + env.log("No black screen or update popup detected. Pressing A again..."); + continue; + } + } + +} + +bool RngHelper::check_for_shiny(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + switch (TARGET){ + case Target::starters: + return shiny_check_starter_summary(env, context); + case Target::togepi: + hatch_togepi_egg(env, context); + case Target::magikarp: + case Target::hitmon: + case Target::eevee: + case Target::lapras: + case Target::fossils: + case Target::gamecornerabra: + case Target::gamecornerclefairy: + case Target::gamecornerdratini: + case Target::gamecornerbug: + case Target::gamecornerporygon: + return shiny_check_summary(env, context); + case Target::staticencounter: + case Target::snorlax: + case Target::mewtwo: + case Target::hooh: + case Target::hypno: + case Target::sweetscent: + case Target::fishing: + case Target::safarizonecenter: + case Target::safarizoneeast: + case Target::safarizonenorth: + case Target::safarizonewest: + case Target::safarizonesurf: + case Target::safarizonefish: + return watch_for_shiny_encounter(env, context) == 1; + default: + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Option not yet implemented.", + env.console + ); + } +} + void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ /* @@ -771,7 +1047,9 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex int64_t FIXED_SEED_OFFSET = USE_COPYRIGHT_TEXT ? -2048 : -800; // milliseconds. approximate, might be console-specific (?) int64_t FIXED_ADVANCES_OFFSET = 0; // frames + while (!shiny_found){ + // prepare timings double MODIFIED_INGAME_ADVANCES = INGAME_ADVANCES + FIXED_ADVANCES_OFFSET + INGAME_CALIBRATION; if (MODIFIED_INGAME_ADVANCES < 0) { OperationFailedException::fire( @@ -792,7 +1070,7 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex uint64_t TEACHY_TV_BUFFER = SAFARI_ZONE ? 12000 : 5000; // Safari zone targets need extra time to walk to the right position - bool should_use_teachy_tv = USE_TEACHY_TV && MODIFIED_INGAME_ADVANCES > TEACHY_TV_BUFFER; // don't use Teachy TV for short in-game advance targets + bool should_use_teachy_tv = USE_TEACHY_TV && (TARGET != Target::starters) && (MODIFIED_INGAME_ADVANCES > TEACHY_TV_BUFFER); // don't use Teachy TV for short in-game advance targets if (should_use_teachy_tv) { TEACHY_ADVANCES = uint64_t((int)std::floor((MODIFIED_INGAME_ADVANCES - TEACHY_TV_BUFFER) / 313) * 313); } @@ -805,204 +1083,18 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex env.log("Teachy TV delay: " + std::to_string(TEACHY_DELAY) + "ms"); env.log("Total time: " + std::to_string(SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET + LOAD_DELAY + INGAME_DELAY + TEACHY_DELAY) + "ms"); - if (SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET < 28000){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "The title screen delay cannot be less than 28000ms. Check your seed calibration.", - env.console - ); - } - - hard_reset(context); - if (USE_COPYRIGHT_TEXT) { - uint64_t STARTUP_DELAY = wait_for_copyright_text(env, context); - env.log("Startup delay: " + std::to_string(STARTUP_DELAY) + "ms"); - } - - set_seed_after_delay(context, SEED_DELAY, SEED_CALIBRATION, FIXED_SEED_OFFSET); - load_game_after_delay(env, context, LOAD_DELAY); - if (should_use_teachy_tv){ - wait_with_teachy_tv(context, TEACHY_DELAY); - } - - int ret; - uint64_t MODIFIED_INGAME_DELAY; - switch (TARGET){ - case Target::starters: - collect_starter_after_delay(env, context, INGAME_DELAY); - shiny_found = shiny_check_starter_summary(env, context); - break; - case Target::magikarp: - collect_magikarp_after_delay(env, context, INGAME_DELAY); - shiny_found = shiny_check_summary(env, context); - break; - case Target::hitmon: - collect_hitmon_after_delay(env, context, INGAME_DELAY); - shiny_found = shiny_check_summary(env, context); - break; - case Target::eevee: - collect_eevee_after_delay(env, context, INGAME_DELAY); - shiny_found = shiny_check_summary(env, context); - break; - case Target::lapras: - collect_lapras_after_delay(env, context, INGAME_DELAY); - shiny_found = shiny_check_summary(env, context); - break; - case Target::fossils: - collect_fossil_after_delay(env, context, INGAME_DELAY); - shiny_found = shiny_check_summary(env, context); - break; - case Target::gamecornerabra: - collect_gamecorner_after_delay(env, context, INGAME_DELAY, 0); - shiny_found = shiny_check_summary(env, context); - break; - case Target::gamecornerclefairy: - collect_gamecorner_after_delay(env, context, INGAME_DELAY, 1); - shiny_found = shiny_check_summary(env, context); - break; - case Target::gamecornerdratini: - collect_gamecorner_after_delay(env, context, INGAME_DELAY, 2); - shiny_found = shiny_check_summary(env, context); - break; - case Target::gamecornerbug: - collect_gamecorner_after_delay(env, context, INGAME_DELAY, 3); - shiny_found = shiny_check_summary(env, context); - break; - case Target::gamecornerporygon: - collect_gamecorner_after_delay(env, context, INGAME_DELAY, 4); - shiny_found = shiny_check_summary(env, context); - break; - case Target::togepi: - collect_togepi_egg_after_delay(env, context, INGAME_DELAY); - hatch_togepi_egg(env, context); - shiny_found = shiny_check_summary(env, context); - break; - case Target::staticencounter: - encounter_static_after_delay(env, context, INGAME_DELAY); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::snorlax: - encounter_snorlax_after_delay(env, context, INGAME_DELAY); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::mewtwo: - encounter_mewtwo_after_delay(env, context, INGAME_DELAY); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::hooh: - encounter_hooh_after_delay(env, context, INGAME_DELAY); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::hypno: - encounter_hypno_after_delay(env, context, INGAME_DELAY); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::sweetscent: - use_sweet_scent(env, context, INGAME_DELAY); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::fishing: - use_registered_fishing_rod(env, context, INGAME_DELAY); - ret = watch_for_shiny_encounter(env, context); - if (ret < 0 ){ - continue; - // keep going if "Not even a nibble..." - } - shiny_found = ret == 1; - break; - case Target::safarizonecenter: - if (INGAME_DELAY < 21000){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Safari Zone Center: in-game delay cannot be less than 21000ms (2520 frames). Check your in-game advances and calibration.", - env.console - ); - } - MODIFIED_INGAME_DELAY = INGAME_DELAY - 20670; - walk_to_safarizonecenter(context); - use_sweet_scent(env, context, MODIFIED_INGAME_DELAY, true); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::safarizoneeast: - if (INGAME_DELAY < 36500){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Safari Zone East: in-game delay cannot be less than 36500ms (4380 frames). Check your in-game advances and calibration.", - env.console - ); - } - MODIFIED_INGAME_DELAY = INGAME_DELAY - 36160; - walk_to_safarizoneeast(context); - use_sweet_scent(env, context, MODIFIED_INGAME_DELAY, true); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::safarizonenorth: - if (INGAME_DELAY < 38000){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Safari Zone North: in-game delay cannot be less than 38000ms (4560 frames). Check your in-game advances and calibration.", - env.console - ); - } - MODIFIED_INGAME_DELAY = INGAME_DELAY - 37410; - walk_to_safarizonenorth(context); - use_sweet_scent(env, context, MODIFIED_INGAME_DELAY, true); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::safarizonewest: - if (INGAME_DELAY < 52000){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Safari Zone West: in-game delay cannot be less than 52000ms (6240 frames). Check your in-game advances and calibration.", - env.console - ); - } - MODIFIED_INGAME_DELAY = INGAME_DELAY - 51430; - walk_to_safarizonewest(context); - use_sweet_scent(env, context, MODIFIED_INGAME_DELAY, true); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::safarizonesurf: - if (INGAME_DELAY < 31000){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Safari Zone Surfing: in-game delay cannot be less than 31000ms (3720 frames). Check your in-game advances and calibration.", - env.console - ); - } - MODIFIED_INGAME_DELAY = INGAME_DELAY - 30300; - walk_to_safarizonesurf(context); - use_sweet_scent(env, context, MODIFIED_INGAME_DELAY, true); - shiny_found = watch_for_shiny_encounter(env, context) == 1; - break; - case Target::safarizonefish: - if (INGAME_DELAY < 24500){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Safari Zone Fishing: in-game delay cannot be less than 24500ms (2940 frames). Check your in-game advances and calibration.", - env.console - ); - } - MODIFIED_INGAME_DELAY = INGAME_DELAY - 30300; - walk_to_safarizonefish(context); - use_registered_fishing_rod(env, context, MODIFIED_INGAME_DELAY); - ret = watch_for_shiny_encounter(env, context); - if (ret < 0 ){ - continue; - // keep going if "Not even a nibble..." - } - shiny_found = ret == 1; - break; - default: - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "Option not yet implemented.", - env.console - ); + // handle the blind part + if (USE_COPYRIGHT_TEXT){ + reset_and_detect_copyright_text(env, context); + perform_blind_sequence(context, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); + }else{ + reset_and_perform_blind_sequence(env, context, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); } - stats.resets++; + + // detect shinies + shiny_found = check_for_shiny(env, context); if (shiny_found){ env.log("Shiny found!"); stats.shinies++; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h index 1716d34c78..571a551015 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h @@ -68,6 +68,12 @@ class RngHelper : public SingleSwitchProgramInstance{ // roaming }; + void check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); + void perform_blind_sequence(ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); + void reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); + void reset_and_detect_copyright_text(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + bool check_for_shiny(SingleSwitchProgramEnvironment& env, ProControllerContext& context); + EnumDropdownOption TARGET; SimpleIntegerOption NUM_RESETS; From 5bb8edf0cc33556bda0575665bff4e5540e4222b Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Tue, 14 Apr 2026 23:45:39 -0500 Subject: [PATCH 2/4] tweaked text for clarity, added seed button options --- .../ShinyHunting/PokemonFRLG_RngHelper.cpp | 140 +++++++++++------- .../ShinyHunting/PokemonFRLG_RngHelper.h | 26 ++-- 2 files changed, 102 insertions(+), 64 deletions(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp index ac5a63fc9f..62aa90ba49 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp @@ -101,6 +101,16 @@ RngHelper::RngHelper() LockMode::UNLOCK_WHILE_RUNNING, 1, 0 // default, min ) + , SEED_BUTTON( + "Seed Button:
", + { + {SeedButton::A, "A", "A"}, + {SeedButton::Start, "Start", "Start"}, + {SeedButton::L, "L", "L (L=A)"}, + }, + LockMode::LOCK_WHILE_RUNNING, + SeedButton::A + ) , SEED_DELAY( "Seed Delay Time (ms):
The delay between starting the game and advancing past the title screen. Set this to match your target seed.", LockMode::LOCK_WHILE_RUNNING, @@ -111,13 +121,14 @@ RngHelper::RngHelper() LockMode::UNLOCK_WHILE_RUNNING, 0 // default ) - , LOAD_ADVANCES( - "Load Screen Advances (frames):
The number of frames to advance before loading the game.
These pass at the \"normal\" rate compared to other consoles.", + , CONTINUE_SCREEN_ADVANCES( + "Continue Screen Advances (frames):
The number of frames to advance before loading the game.
These pass at the \"normal\" rate compared to other consoles.", LockMode::LOCK_WHILE_RUNNING, 1000, 192 // default, min ) - , LOAD_CALIBRATION( - "Load Screen Advances Calibration (frames):
A \"fine adjustment\" that modifies the frame advances passed on the load screen.
", + , CONTINUE_SCREEN_CALIBRATION( + "Continue Screen Advances Calibration (frames):
A \"fine adjustment\" that modifies the frame advances passed on the Continue Screen.
" + "Example: if your target advance was 10000 and you hit 10025, you can decrease your calibration value by 25.", LockMode::UNLOCK_WHILE_RUNNING, 0 // default ) @@ -127,7 +138,8 @@ RngHelper::RngHelper() 12345, 480 // default, min ) , INGAME_CALIBRATION( - "In-Game Advances Calibration (frames):
A \"coarse adjustment\" that modifies the frame advances passed after loading the game.
", + "In-Game Advances Calibration (frames):
A \"coarse adjustment\" that modifies the frame advances passed after loading the game.
" + "Example: if your target advance was 10000 and you hit 8500, you can increase your calibration value by 1500.", LockMode::UNLOCK_WHILE_RUNNING, 0 // default ) @@ -161,10 +173,11 @@ RngHelper::RngHelper() { PA_ADD_OPTION(TARGET); PA_ADD_OPTION(NUM_RESETS); + PA_ADD_OPTION(SEED_BUTTON); PA_ADD_OPTION(SEED_DELAY); PA_ADD_OPTION(SEED_CALIBRATION); - PA_ADD_OPTION(LOAD_ADVANCES); - PA_ADD_OPTION(LOAD_CALIBRATION); + PA_ADD_OPTION(CONTINUE_SCREEN_ADVANCES); + PA_ADD_OPTION(CONTINUE_SCREEN_CALIBRATION); PA_ADD_OPTION(INGAME_ADVANCES); PA_ADD_OPTION(INGAME_CALIBRATION); PA_ADD_OPTION(USE_COPYRIGHT_TEXT); @@ -176,40 +189,6 @@ RngHelper::RngHelper() namespace{ -void set_seed_after_delay(ProControllerContext& context, SimpleIntegerOption& SEED_DELAY, SimpleIntegerOption& SEED_CALIBRATION, int64_t& FIXED_SEED_OFFSET){ - // wait on title screen for the specified delay - pbf_wait(context, std::chrono::milliseconds(SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET)); - // hold A for a few seconds through the transition to the load screen - pbf_press_button(context, BUTTON_A, 3000ms, 0ms); -} - -void load_game_after_delay(ProControllerContext& context, const uint64_t& LOAD_DELAY){ - pbf_wait(context, std::chrono::milliseconds(LOAD_DELAY - 3000)); - pbf_press_button(context, BUTTON_A, 33ms, 1467ms); - // skip recap - pbf_press_button(context, BUTTON_B, 33ms, 2467ms); - // need to later subtract 4000ms from delay to hit desired number of advances -} - -void wait_with_teachy_tv(ProControllerContext& context, const uint64_t& TEACHY_DELAY){ - // open start menu -> bag -> key items -> Teachy TV -> use - pbf_press_button(context, BUTTON_PLUS, 200ms, 300ms); - pbf_move_left_joystick(context, {0, -1}, 200ms, 300ms); - pbf_move_left_joystick(context, {0, -1}, 200ms, 300ms); - pbf_press_button(context, BUTTON_A, 200ms, 2300ms); - pbf_move_left_joystick(context, {+1, 0}, 200ms, 2300ms); - pbf_press_button(context, BUTTON_A, 200ms, 300ms); - pbf_press_button(context, BUTTON_A, 200ms, std::chrono::milliseconds(TEACHY_DELAY)); - // close teachy tv -> close bag -> reset start menu cursor position - > close start menu - pbf_press_button(context, BUTTON_B, 200ms, 2300ms); - pbf_press_button(context, BUTTON_B, 200ms, 2300ms); - pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms); - pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms); - pbf_press_button(context, BUTTON_B, 200ms, 300ms); - // total non-teachy delay duration: 13700ms - // if used in the Safari Zone: 14200ms -} - void collect_starter_after_delay(ProControllerContext& context, const uint64_t& INGAME_DELAY){ // Advance through starter dialogue and wait on "really quite energetic!" pbf_press_button(context, BUTTON_A, 200ms, 1300ms); @@ -560,11 +539,62 @@ void walk_to_safarizonewest(ProControllerContext& context){ } // namespace -void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ - if (LOAD_DELAY < 3200){ + +void RngHelper::set_seed_after_delay(ProControllerContext& context, int64_t& FIXED_SEED_OFFSET){ + // wait on title screen for the specified delay + pbf_wait(context, std::chrono::milliseconds(SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET)); + // hold the specified button for a few seconds through the transition to the Continue Screen + Button button; + switch (SEED_BUTTON){ + case SeedButton::A: + button = BUTTON_A; + break; + case SeedButton::Start: + button = BUTTON_PLUS; + break; + case SeedButton::L: + button = BUTTON_L; + break; + default: + button = BUTTON_A; + break; + } + BUTTON_A; + pbf_press_button(context, button, 3000ms, 0ms); +} + +void RngHelper::load_game_after_delay(ProControllerContext& context, const uint64_t& CONTINUE_SCREEN_DELAY){ + pbf_wait(context, std::chrono::milliseconds(CONTINUE_SCREEN_DELAY - 3000)); + pbf_press_button(context, BUTTON_A, 33ms, 1467ms); + // skip recap + pbf_press_button(context, BUTTON_B, 33ms, 2467ms); + // need to later subtract 4000ms from delay to hit desired number of advances +} + +void RngHelper::wait_with_teachy_tv(ProControllerContext& context, const uint64_t& TEACHY_DELAY){ + // open start menu -> bag -> key items -> Teachy TV -> use + pbf_press_button(context, BUTTON_PLUS, 200ms, 300ms); + pbf_move_left_joystick(context, {0, -1}, 200ms, 300ms); + pbf_move_left_joystick(context, {0, -1}, 200ms, 300ms); + pbf_press_button(context, BUTTON_A, 200ms, 2300ms); + pbf_move_left_joystick(context, {+1, 0}, 200ms, 2300ms); + pbf_press_button(context, BUTTON_A, 200ms, 300ms); + pbf_press_button(context, BUTTON_A, 200ms, std::chrono::milliseconds(TEACHY_DELAY)); + // close teachy tv -> close bag -> reset start menu cursor position - > close start menu + pbf_press_button(context, BUTTON_B, 200ms, 2300ms); + pbf_press_button(context, BUTTON_B, 200ms, 2300ms); + pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms); + pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms); + pbf_press_button(context, BUTTON_B, 200ms, 300ms); + // total non-teachy delay duration: 13700ms + // if used in the Safari Zone: 14200ms +} + +void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ + if (CONTINUE_SCREEN_DELAY < 3200){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "The load screen delay cannot be less than 3200ms (192 frames). Check your load screen calibration.", + "The Continue Screen delay cannot be less than 3200ms (192 frames). Check your Continue Screen calibration.", env.console ); } @@ -785,10 +815,10 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED } } -void RngHelper::perform_blind_sequence(ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ +void RngHelper::perform_blind_sequence(ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ pbf_press_button(context, BUTTON_A, 80ms, 0ms); // start the game from the Home screen - set_seed_after_delay(context, SEED_DELAY, SEED_CALIBRATION, FIXED_SEED_OFFSET); - load_game_after_delay(context, LOAD_DELAY); + set_seed_after_delay(context, FIXED_SEED_OFFSET); + load_game_after_delay(context, CONTINUE_SCREEN_DELAY); if (TEACHY_DELAY > 0){ wait_with_teachy_tv(context, TEACHY_DELAY); } @@ -884,7 +914,7 @@ void RngHelper::perform_blind_sequence(ProControllerContext& context, int64_t FI } } -void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ +void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ go_home(env.console, context); close_game_from_home(env.console, context); start_game_from_home(env.console, context, ConsoleSettings::instance().TOLERATE_SYSTEM_UPDATE_MENU_SLOW, uint8_t(0), uint8_t(0)); // TODO: add option for user slot if needed @@ -907,9 +937,9 @@ void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& context.wait_for_all_requests(); int ret = run_until( env.console, context, - [this, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE](ProControllerContext& context) { + [this, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE](ProControllerContext& context) { pbf_press_button(context, BUTTON_A, 80ms, 0ms); - perform_blind_sequence(context, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); + perform_blind_sequence(context, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); }, { update_detector } ); @@ -1075,21 +1105,21 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex TEACHY_ADVANCES = uint64_t((int)std::floor((MODIFIED_INGAME_ADVANCES - TEACHY_TV_BUFFER) / 313) * 313); } - const uint64_t LOAD_DELAY = uint64_t((LOAD_ADVANCES + LOAD_CALIBRATION) * FRAME_DURATION); + const uint64_t CONTINUE_SCREEN_DELAY = uint64_t((CONTINUE_SCREEN_ADVANCES + CONTINUE_SCREEN_CALIBRATION) * FRAME_DURATION); const uint64_t TEACHY_DELAY = uint64_t(TEACHY_ADVANCES * FRAME_DURATION / 313); const uint64_t INGAME_DELAY = uint64_t((MODIFIED_INGAME_ADVANCES - TEACHY_ADVANCES) * FRAME_DURATION / 2) - (should_use_teachy_tv ? 13700 : 0); - env.log("Load screen delay: " + std::to_string(LOAD_DELAY) + "ms"); + env.log("Continue Screen delay: " + std::to_string(CONTINUE_SCREEN_DELAY) + "ms"); env.log("In-game delay: " + std::to_string(INGAME_DELAY) + "ms"); env.log("Teachy TV delay: " + std::to_string(TEACHY_DELAY) + "ms"); - env.log("Total time: " + std::to_string(SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET + LOAD_DELAY + INGAME_DELAY + TEACHY_DELAY) + "ms"); + env.log("Total time: " + std::to_string(SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET + CONTINUE_SCREEN_DELAY + INGAME_DELAY + TEACHY_DELAY) + "ms"); // handle the blind part if (USE_COPYRIGHT_TEXT){ reset_and_detect_copyright_text(env, context); - perform_blind_sequence(context, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); + perform_blind_sequence(context, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); }else{ - reset_and_perform_blind_sequence(env, context, FIXED_SEED_OFFSET, LOAD_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); + reset_and_perform_blind_sequence(env, context, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); } stats.resets++; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h index 571a551015..c1c5081b97 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h @@ -35,10 +35,6 @@ class RngHelper : public SingleSwitchProgramInstance{ ) override{} private: - enum class ResetType{ - hard, - soft, - }; enum class Target{ starters, magikarp, @@ -68,9 +64,20 @@ class RngHelper : public SingleSwitchProgramInstance{ // roaming }; - void check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); - void perform_blind_sequence(ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); - void reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& LOAD_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); + enum class SeedButton{ + A, + Start, + L + }; + + void set_seed_after_delay(ProControllerContext& context, int64_t& FIXED_SEED_OFFSET); + void load_game_after_delay(ProControllerContext& context, const uint64_t& LOAD_DELAY); + void wait_with_teachy_tv(ProControllerContext& context, const uint64_t& TEACHY_DELAY); + + + void check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); + void perform_blind_sequence(ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); + void reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE); void reset_and_detect_copyright_text(SingleSwitchProgramEnvironment& env, ProControllerContext& context); bool check_for_shiny(SingleSwitchProgramEnvironment& env, ProControllerContext& context); @@ -78,11 +85,12 @@ class RngHelper : public SingleSwitchProgramInstance{ SimpleIntegerOption NUM_RESETS; + EnumDropdownOption SEED_BUTTON; SimpleIntegerOption SEED_DELAY; SimpleIntegerOption SEED_CALIBRATION; - SimpleIntegerOption LOAD_ADVANCES; - FloatingPointOption LOAD_CALIBRATION; + SimpleIntegerOption CONTINUE_SCREEN_ADVANCES; + FloatingPointOption CONTINUE_SCREEN_CALIBRATION; SimpleIntegerOption INGAME_ADVANCES; FloatingPointOption INGAME_CALIBRATION; From be055b65e4ecfde490392432e80f0bbdaf41927d Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Wed, 15 Apr 2026 02:47:42 -0500 Subject: [PATCH 3/4] tweaks --- .../ShinyHunting/PokemonFRLG_RngHelper.cpp | 85 ++++++++++--------- .../ShinyHunting/PokemonFRLG_RngHelper.h | 2 +- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp index 62aa90ba49..bf8f74f776 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp @@ -121,35 +121,35 @@ RngHelper::RngHelper() LockMode::UNLOCK_WHILE_RUNNING, 0 // default ) - , CONTINUE_SCREEN_ADVANCES( - "Continue Screen Advances (frames):
The number of frames to advance before loading the game.
These pass at the \"normal\" rate compared to other consoles.", + , CONTINUE_SCREEN_FRAMES( + "Continue Screen Frames:
The number of RNG advances before loading the game.
These pass at the \"normal\" rate compared to other consoles.", LockMode::LOCK_WHILE_RUNNING, 1000, 192 // default, min ) , CONTINUE_SCREEN_CALIBRATION( - "Continue Screen Advances Calibration (frames):
A \"fine adjustment\" that modifies the frame advances passed on the Continue Screen.
" + "Continue Screen Frames Calibration:
A \"fine adjustment\" that modifies the RNG advances passed on the Continue Screen.
" "Example: if your target advance was 10000 and you hit 10025, you can decrease your calibration value by 25.", LockMode::UNLOCK_WHILE_RUNNING, 0 // default ) , INGAME_ADVANCES( - "In-Game Advances (frames):
The number of frames to advance before triggering the gift/encounter.
These pass at double the rate compared to other consoles, where every 2nd frame is skipped.
Warning: this needs to be long enough to accomodate all in-game button presses prior to the gift/encounter", + "In-Game Advances:
The number of in-game RNG advances before triggering the gift/encounter.
These pass at double the rate compared to other consoles, where every frame results in 2 advances.
Warning: this needs to be long enough to accomodate all in-game button presses prior to the gift/encounter", LockMode::LOCK_WHILE_RUNNING, 12345, 480 // default, min ) , INGAME_CALIBRATION( - "In-Game Advances Calibration (frames):
A \"coarse adjustment\" that modifies the frame advances passed after loading the game.
" + "In-Game Advances Calibration:
A \"coarse adjustment\" that modifies the RNG advances passed after loading the game.
" "Example: if your target advance was 10000 and you hit 8500, you can increase your calibration value by 1500.", LockMode::UNLOCK_WHILE_RUNNING, 0 // default ) , USE_COPYRIGHT_TEXT( - "Detect Copyright Text:
Start the seed timer only after detecting the copyright text. Can be helpful for improving seed consistency.", + "Detect Copyright Text:
Start the seed timer only after detecting the copyright text. Can be helpful if your seeds are inconsistent.", LockMode::LOCK_WHILE_RUNNING, true // default ) , USE_TEACHY_TV( - "Use Teachy TV:
Opens the Teachy TV to quickly advance in-game frames at 313x speed.
Warning: can result in larger misses.", + "Use Teachy TV:
Opens the Teachy TV to quickly advance the RNG at 313x speed.
Warning: can result in larger misses.", LockMode::LOCK_WHILE_RUNNING, false // default ) @@ -176,7 +176,7 @@ RngHelper::RngHelper() PA_ADD_OPTION(SEED_BUTTON); PA_ADD_OPTION(SEED_DELAY); PA_ADD_OPTION(SEED_CALIBRATION); - PA_ADD_OPTION(CONTINUE_SCREEN_ADVANCES); + PA_ADD_OPTION(CONTINUE_SCREEN_FRAMES); PA_ADD_OPTION(CONTINUE_SCREEN_CALIBRATION); PA_ADD_OPTION(INGAME_ADVANCES); PA_ADD_OPTION(INGAME_CALIBRATION); @@ -587,14 +587,13 @@ void RngHelper::wait_with_teachy_tv(ProControllerContext& context, const uint64_ pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms); pbf_press_button(context, BUTTON_B, 200ms, 300ms); // total non-teachy delay duration: 13700ms - // if used in the Safari Zone: 14200ms } void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ if (CONTINUE_SCREEN_DELAY < 3200){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "The Continue Screen delay cannot be less than 3200ms (192 frames). Check your Continue Screen calibration.", + "The Continue Screen delay cannot be less than 3200ms (192 advances). Check your Continue Screen calibration.", env.console ); } @@ -611,7 +610,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 7500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Starters: the in-game delay cannot be less than 7500ms (900 frames). Check your in-game advances and calibration.", + "Starters: the in-game delay cannot be less than 7500ms (900 advances). Check your in-game advances and calibration.", env.console ); } @@ -620,7 +619,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 7500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Magikarp: the in-game delay cannot be less than 7500ms (900 frames). Check your in-game advances and calibration.", + "Magikarp: the in-game delay cannot be less than 7500ms (900 advances). Check your in-game advances and calibration.", env.console ); } @@ -629,7 +628,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 4500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Hitmonchan/Hitmonlee: the in-game delay cannot be less than 4500ms (540 frames). Check your in-game advances and calibration.", + "Hitmonchan/Hitmonlee: the in-game delay cannot be less than 4500ms (540 advances). Check your in-game advances and calibration.", env.console ); } @@ -638,7 +637,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 4000){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Eevee: the in-game delay cannot be less than 4000ms (480 frames). Check your in-game advances and calibration.", + "Eevee: the in-game delay cannot be less than 4000ms (480 advances). Check your in-game advances and calibration.", env.console ); } @@ -647,7 +646,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 7500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Lapras: the in-game delay cannot be less than 7500ms (900 frames). Check your in-game advances and calibration.", + "Lapras: the in-game delay cannot be less than 7500ms (900 advances). Check your in-game advances and calibration.", env.console ); } @@ -656,7 +655,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 6000){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Fossils: the in-game delay cannot be less than 6000ms (720 frames). Check your in-game advances and calibration.", + "Fossils: the in-game delay cannot be less than 6000ms (720 advances). Check your in-game advances and calibration.", env.console ); } @@ -669,7 +668,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 8500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Game Corner: the in-game delay cannot be less than 8500ms (1020 frames). Check your in-game advances and calibration.", + "Game Corner: the in-game delay cannot be less than 8500ms (1020 advances). Check your in-game advances and calibration.", env.console ); } @@ -678,7 +677,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 12000) { OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Togepi: the in-game delay cannot be less than 12000ms (1440 frames). Check your in-game advances and calibration.", + "Togepi: the in-game delay cannot be less than 12000ms (1440 advances). Check your in-game advances and calibration.", env.console ); } @@ -687,7 +686,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 5000){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Static Encounter: the in-game delay cannot be less than 5000ms (600 frames). Check your in-game advances and calibration.", + "Static Encounter: the in-game delay cannot be less than 5000ms (600 advances). Check your in-game advances and calibration.", env.console ); } @@ -696,7 +695,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 16000){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Snorlax: the in-game delay cannot be less than 16000ms (1920 frames). Check your in-game advances and calibration.", + "Snorlax: the in-game delay cannot be less than 16000ms (1920 advances). Check your in-game advances and calibration.", env.console ); } @@ -705,7 +704,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 4500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Mewtwo: the in-game delay cannot be less than 4500ms (540 frames). Check your in-game advances and calibration.", + "Mewtwo: the in-game delay cannot be less than 4500ms (540 advances). Check your in-game advances and calibration.", env.console ); } @@ -714,7 +713,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 4000){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Ho-oh: the in-game delay cannot be less than 4000ms (480 frames). Check your in-game advances and calibration.", + "Ho-oh: the in-game delay cannot be less than 4000ms (480 advances). Check your in-game advances and calibration.", env.console ); } @@ -723,7 +722,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 13000){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Hypno: the in-game delay cannot be less than 13000ms (1560 frames). Check your in-game advances and calibration.", + "Hypno: the in-game delay cannot be less than 13000ms (1560 advances). Check your in-game advances and calibration.", env.console ); } @@ -732,13 +731,13 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (!SAFARI_ZONE && INGAME_DELAY < 8500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Sweet Scent: the in-game delay cannot be less than 8500ms (1020 frames). Check your in-game advances and calibration.", + "Sweet Scent: the in-game delay cannot be less than 8500ms (1020 advances). Check your in-game advances and calibration.", env.console ); }else if (SAFARI_ZONE && INGAME_DELAY < 9500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Sweet Scent: the in-game delay cannot be less than 9500ms (1140 frames). Check your in-game advances and calibration.", + "Sweet Scent: the in-game delay cannot be less than 9500ms (1140 advances). Check your in-game advances and calibration.", env.console ); } @@ -747,7 +746,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 5500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Fishing: the in-game delay cannot be less than 5500ms (1800 frames). Check your in-game advances and calibration.", + "Fishing: the in-game delay cannot be less than 5500ms (1800 advances). Check your in-game advances and calibration.", env.console ); } @@ -756,7 +755,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 30500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Safari Zone Center: in-game delay cannot be less than 30500ms (3660 frames). Check your in-game advances and calibration.", + "Safari Zone Center: in-game delay cannot be less than 30500ms (3660 advances). Check your in-game advances and calibration.", env.console ); } @@ -765,7 +764,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 36500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Safari Zone East: in-game delay cannot be less than 36500ms (4380 frames). Check your in-game advances and calibration.", + "Safari Zone East: in-game delay cannot be less than 36500ms (4380 advances). Check your in-game advances and calibration.", env.console ); } @@ -774,7 +773,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 47500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Safari Zone North: in-game delay cannot be less than 47500ms (5700 frames). Check your in-game advances and calibration.", + "Safari Zone North: in-game delay cannot be less than 47500ms (5700 advances). Check your in-game advances and calibration.", env.console ); } @@ -783,7 +782,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 61500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Safari Zone West: in-game delay cannot be less than 52000ms (7380 frames). Check your in-game advances and calibration.", + "Safari Zone West: in-game delay cannot be less than 52000ms (7380 advances). Check your in-game advances and calibration.", env.console ); } @@ -792,7 +791,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 40500){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Safari Zone Surfing: in-game delay cannot be less than 40500ms (4860 frames). Check your in-game advances and calibration.", + "Safari Zone Surfing: in-game delay cannot be less than 40500ms (4860 advances). Check your in-game advances and calibration.", env.console ); } @@ -801,7 +800,7 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED if (INGAME_DELAY < 30000){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Safari Zone Fishing: in-game delay cannot be less than 30000ms (3600 frames). Check your in-game advances and calibration.", + "Safari Zone Fishing: in-game delay cannot be less than 30000ms (3600 advances). Check your in-game advances and calibration.", env.console ); } @@ -917,7 +916,7 @@ void RngHelper::perform_blind_sequence(ProControllerContext& context, int64_t FI void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env, ProControllerContext& context, int64_t FIXED_SEED_OFFSET, const uint64_t& CONTINUE_SCREEN_DELAY, const uint64_t& TEACHY_DELAY, const uint64_t& INGAME_DELAY, bool SAFARI_ZONE){ go_home(env.console, context); close_game_from_home(env.console, context); - start_game_from_home(env.console, context, ConsoleSettings::instance().TOLERATE_SYSTEM_UPDATE_MENU_SLOW, uint8_t(0), uint8_t(0)); // TODO: add option for user slot if needed + start_game_from_home(env.console, context, ConsoleSettings::instance().TOLERATE_SYSTEM_UPDATE_MENU_FAST, uint8_t(0), uint8_t(0)); // TODO: add option for user slot if needed go_home(env.console, context); // happens as soon as a black screen is detected // attempt to resume the game and perform the blind sequence @@ -932,13 +931,13 @@ void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& env.console ); } - + env.log("Starting blind button presses..."); UpdateMenuWatcher update_detector(env.console); + // any other fail conditions should be added here context.wait_for_all_requests(); int ret = run_until( env.console, context, [this, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE](ProControllerContext& context) { - pbf_press_button(context, BUTTON_A, 80ms, 0ms); perform_blind_sequence(context, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); }, { update_detector } @@ -961,7 +960,7 @@ void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment& void RngHelper::reset_and_detect_copyright_text(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ go_home(env.console, context); close_game_from_home(env.console, context); - start_game_from_home(env.console, context, ConsoleSettings::instance().TOLERATE_SYSTEM_UPDATE_MENU_SLOW, uint8_t(0), uint8_t(0)); // TODO: add option for user slot if needed + start_game_from_home(env.console, context, ConsoleSettings::instance().TOLERATE_SYSTEM_UPDATE_MENU_FAST, uint8_t(0), uint8_t(0)); // TODO: add option for user slot if needed go_home(env.console, context); // happens as soon as a black screen is detected uint8_t attempts = 0; @@ -1071,16 +1070,14 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex bool shiny_found = false; - double FRAMERATE = 59.999977; // FPS. from Dhruv (don't know original source) + double FRAMERATE = 59.999977; // FPS double FRAME_DURATION = 1000 / FRAMERATE; - int64_t FIXED_SEED_OFFSET = USE_COPYRIGHT_TEXT ? -2048 : -800; // milliseconds. approximate, might be console-specific (?) - int64_t FIXED_ADVANCES_OFFSET = 0; // frames - + int64_t FIXED_SEED_OFFSET = USE_COPYRIGHT_TEXT ? -2140 : -845; // milliseconds. approximate while (!shiny_found){ // prepare timings - double MODIFIED_INGAME_ADVANCES = INGAME_ADVANCES + FIXED_ADVANCES_OFFSET + INGAME_CALIBRATION; + double MODIFIED_INGAME_ADVANCES = INGAME_ADVANCES + INGAME_CALIBRATION; if (MODIFIED_INGAME_ADVANCES < 0) { OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, @@ -1105,7 +1102,7 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex TEACHY_ADVANCES = uint64_t((int)std::floor((MODIFIED_INGAME_ADVANCES - TEACHY_TV_BUFFER) / 313) * 313); } - const uint64_t CONTINUE_SCREEN_DELAY = uint64_t((CONTINUE_SCREEN_ADVANCES + CONTINUE_SCREEN_CALIBRATION) * FRAME_DURATION); + const uint64_t CONTINUE_SCREEN_DELAY = uint64_t((CONTINUE_SCREEN_FRAMES + CONTINUE_SCREEN_CALIBRATION) * FRAME_DURATION); const uint64_t TEACHY_DELAY = uint64_t(TEACHY_ADVANCES * FRAME_DURATION / 313); const uint64_t INGAME_DELAY = uint64_t((MODIFIED_INGAME_ADVANCES - TEACHY_ADVANCES) * FRAME_DURATION / 2) - (should_use_teachy_tv ? 13700 : 0); env.log("Continue Screen delay: " + std::to_string(CONTINUE_SCREEN_DELAY) + "ms"); @@ -1113,14 +1110,18 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex env.log("Teachy TV delay: " + std::to_string(TEACHY_DELAY) + "ms"); env.log("Total time: " + std::to_string(SEED_DELAY + SEED_CALIBRATION + FIXED_SEED_OFFSET + CONTINUE_SCREEN_DELAY + INGAME_DELAY + TEACHY_DELAY) + "ms"); + check_timings(env, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, INGAME_DELAY, SAFARI_ZONE); + // handle the blind part if (USE_COPYRIGHT_TEXT){ reset_and_detect_copyright_text(env, context); + env.log("Starting blind button presses..."); perform_blind_sequence(context, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); }else{ reset_and_perform_blind_sequence(env, context, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE); } + env.log("Blind button presses complete."); stats.resets++; // detect shinies diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h index c1c5081b97..e5fa50b3e3 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h @@ -89,7 +89,7 @@ class RngHelper : public SingleSwitchProgramInstance{ SimpleIntegerOption SEED_DELAY; SimpleIntegerOption SEED_CALIBRATION; - SimpleIntegerOption CONTINUE_SCREEN_ADVANCES; + SimpleIntegerOption CONTINUE_SCREEN_FRAMES; FloatingPointOption CONTINUE_SCREEN_CALIBRATION; SimpleIntegerOption INGAME_ADVANCES; From a7bb75539ecdfa3a353114955d3e8bddbaeab757 Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Wed, 15 Apr 2026 03:12:15 -0500 Subject: [PATCH 4/4] oops --- .../PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp index bf8f74f776..d8f9cd7f6a 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp @@ -559,7 +559,6 @@ void RngHelper::set_seed_after_delay(ProControllerContext& context, int64_t& FIX button = BUTTON_A; break; } - BUTTON_A; pbf_press_button(context, button, 3000ms, 0ms); }