From 44bd78915e3ab64d965712eb2e822c3c59b85026 Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Tue, 25 Aug 2026 21:04:05 -0500 Subject: [PATCH 1/2] add BDSP seed finder programs --- .../Source/PokemonBDSP/PokemonBDSP_Panels.cpp | 5 + .../PokemonBDSP_BedroomSeedFinder.cpp | 102 +++++++ .../PokemonBDSP_BedroomSeedFinder.h | 46 +++ .../PokemonBDSP_IntroSeedFinder.cpp | 266 ++++++++++++++++++ .../PokemonBDSP_IntroSeedFinder.h | 42 +++ SerialPrograms/cmake/SourceFiles.cmake | 4 + 6 files changed, 465 insertions(+) create mode 100644 SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.cpp create mode 100644 SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.h create mode 100644 SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp create mode 100644 SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.h diff --git a/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Panels.cpp b/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Panels.cpp index 4010f10640..42ccc6c3c1 100644 --- a/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Panels.cpp +++ b/SerialPrograms/Source/PokemonBDSP/PokemonBDSP_Panels.cpp @@ -39,6 +39,9 @@ //#include "Programs/Glitches/PokemonBDSP_CloneItemsBoxCopy.h" //#include "Programs/Glitches/PokemonBDSP_CloneItemsMenuOverlap.h" +#include "Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.h" +#include "Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.h" + #include "Programs/TestPrograms/PokemonBDSP_ShinyEncounterTester.h" #include "Programs/TestPrograms/PokemonBDSP_SoundListener.h" #include "Programs/TestPrograms/PokemonBDSP_SummaryReaderTester.h" @@ -99,6 +102,8 @@ std::vector PanelListFactory::make_panels() const{ if (IS_BETA_VERSION || STATIC_GLOBALS.DEVELOPER_MODE){ ret.emplace_back("---- Untested/Beta/WIP ----"); + ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); } if (STATIC_GLOBALS.DEVELOPER_MODE){ ret.emplace_back("---- Developer Tools ----"); diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.cpp new file mode 100644 index 0000000000..2bcf00a44b --- /dev/null +++ b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.cpp @@ -0,0 +1,102 @@ +/* BDSP Bedroom Seed Finder + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include +#include +#include +#include +#include "Common/Cpp/Exceptions.h" +#include "Common/Cpp/PrettyPrint.h" +#include "CommonFramework/Globals.h" +#include "CommonFramework/ImageTypes/ImageRGB32.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonBDSP/Inference/Rng/PokemonBDSP_BlinkScenes.h" +#include "PokemonBDSP/Inference/Rng/PokemonBDSP_EyeBlinkDetector.h" +#include "PokemonBDSP_BedroomSeedFinder.h" +#include "PokemonBDSP_BlinkRecovery.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonBDSP{ + using namespace Pokemon; + + + +BedroomSeedFinder_Descriptor::BedroomSeedFinder_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonBDSP:BedroomSeedFinder", + STRING_POKEMON + " BDSP", "Bedroom Seed Finder", + "", + "Recover the RNG seed by watching the player character's blinks in their bedroom.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::ENABLE_COMMANDS, + {} + ) +{} + + +BedroomSeedFinder::BedroomSeedFinder() + : GO_HOME_WHEN_DONE(false) +{ + PA_ADD_OPTION(PLAYER_MODEL); + PA_ADD_OPTION(COLLECTION_DISPLAY); + PA_ADD_OPTION(STATE_DISPLAY); + PA_ADD_OPTION(GO_HOME_WHEN_DONE); +} + + +void BedroomSeedFinder::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + STATE_DISPLAY.reset(); + COLLECTION_DISPLAY.reset(); + + std::vector setups = bedroom_eye_templates(PLAYER_MODEL.model_number()); + std::vector eyes = load_eye_templates(setups); + + std::vector> watchers; + std::vector callbacks; + make_blink_watchers(setups, eyes, watchers, callbacks); + + env.log( + "Watching the player blink. The overlay box should be sitting on the player's eye." + ); + + BlinkRecoveryConfig config; + config.npcs = 1; + + BlinkRecovery recovery = recover_state_from_blinks( + env, context, watchers, callbacks, COLLECTION_DISPLAY, config + ); + if (!recovery.success){ + throw UserSetupError(env.logger(), + "Gave up: " + recovery.failure_reason + ". Check the overlay box is on the " + "player's eye, that the character model above matches the one in game, and that " + "the log shows blinks arriving every few seconds." + ); + } + + uint64_t seed0 = 0; + uint64_t seed1 = 0; + xorshift128_state_to_seed_pair(recovery.state, seed0, seed1); + + env.log("--------"); + env.log("State confirmed over " + std::to_string(recovery.events) + " rolls.", COLOR_BLUE); + env.log("State: " + recovery.state.to_string(), COLOR_BLUE); + env.log("PokeFinder seeds: " + tostr_hex_padded(16, seed0) + + " " + tostr_hex_padded(16, seed1), COLOR_BLUE); + + STATE_DISPLAY.set_state(recovery.state, recovery.events); + STATE_DISPLAY.set_confidence_unique(); + + GO_HOME_WHEN_DONE.run_end_of_program(context); +} + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.h b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.h new file mode 100644 index 0000000000..54049a0be8 --- /dev/null +++ b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.h @@ -0,0 +1,46 @@ +/* BDSP Bedroom Seed Finder + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonBDSP_BedroomSeedFinder_H +#define PokemonAutomation_PokemonBDSP_BedroomSeedFinder_H + +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" +#include "PokemonBDSP/Options/PokemonBDSP_PlayerModelOption.h" +#include "PokemonBDSP_RngDisplays.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonBDSP{ + + +class BedroomSeedFinder_Descriptor : public SingleSwitchProgramDescriptor{ +public: + BedroomSeedFinder_Descriptor(); +}; + + +class BedroomSeedFinder : public SingleSwitchProgramInstance{ +public: + BedroomSeedFinder(); + + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + + PlayerModelOption PLAYER_MODEL; + + BlinkCollectionDisplay COLLECTION_DISPLAY; + RngStateDisplay STATE_DISPLAY; + + GoHomeWhenDoneOption GO_HOME_WHEN_DONE; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp new file mode 100644 index 0000000000..bc0cca3ccf --- /dev/null +++ b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp @@ -0,0 +1,266 @@ +/* BDSP Intro Seed Finder + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include +#include +#include +#include "Common/Cpp/Exceptions.h" +#include "Common/Cpp/PrettyPrint.h" +#include "CommonFramework/GlobalAutoPaths.h" +#include "CommonFramework/Globals.h" +#include "CommonFramework/ImageTypes/ImageRGB32.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "CommonTools/Async/InferenceSession.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "Pokemon/Pokemon_Strings.h" +#include "PokemonBDSP/Inference/Rng/PokemonBDSP_BlinkExtraction.h" +#include "PokemonBDSP/Inference/Rng/PokemonBDSP_EyeBlinkDetector.h" +#include "PokemonBDSP_IntroSeedFinder.h" +#include "PokemonBDSP_StateSolver.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonBDSP{ + using namespace Pokemon; + + +const Seconds KEEP_AWAKE_INTERVAL = 180s; + +// Each usable gap pins four bits, so 128 bits needs 32 of them. +const size_t MIN_USABLE_TO_TRY = 32; + +const size_t CONFIRMATION_BLINKS = 6; + +const uint16_t GIVE_UP_SECONDS = 1500; + +const double TOLERANCE_SECONDS = 0.10; + + +IntroSeedFinder_Descriptor::IntroSeedFinder_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonBDSP:IntroSeedFinder", + STRING_POKEMON + " BDSP", "Intro Seed Finder", + "", + "Recover the RNG seed from the intro cutscene by watching Munchlax blink, so that the " + "secret ID can be worked out from the trainer card afterwards.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::ENABLE_COMMANDS, + {} + ) +{} + + +IntroSeedFinder::IntroSeedFinder() + : GO_HOME_WHEN_DONE(false) +{ + PA_ADD_OPTION(COLLECTION_DISPLAY); + PA_ADD_OPTION(STATE_DISPLAY); + PA_ADD_OPTION(GO_HOME_WHEN_DONE); +} + + +// some gaps are too near a bucket boundary to be read (roughly a third at the default tolerance) +static size_t count_usable(const std::vector& intervals, double tolerance){ + size_t usable = 0; + for (double gap : intervals){ + uint32_t bucket = 0; + double margin = 0; + if (bdsp_pokemon_blink_bucket_with_margin(gap, bucket, margin) && margin >= tolerance){ + usable++; + } + } + return usable; +} + +static std::vector intervals_of(const std::vector& blinks){ + std::vector intervals; + if (blinks.size() < 2){ + return intervals; + } + intervals.reserve(blinks.size() - 1); + for (size_t c = 1; c < blinks.size(); c++){ + intervals.emplace_back(blinks[c].seconds - blinks[c - 1].seconds); + } + return intervals; +} + + +void IntroSeedFinder::program(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + STATE_DISPLAY.reset(); + COLLECTION_DISPLAY.reset(); + + double fps = env.console.video().fps_source(); + if (fps > 0){ + env.log("Capture is running at " + tostr_default(fps) + " fps."); + if (fps < 25){ + env.log( + "That is low for this. A gap has to be measured to about a tenth of a second, " + "and below roughly 30 fps the timing error alone approaches that.", + COLOR_ORANGE + ); + } + } + + ImageRGB32 eye(RESOURCE_PATH() + "PokemonBDSP/Rng/Munchlax.png"); + EyeBlinkWatcher watcher("Munchlax", eye, {0.3828, 0.6306, 0.0208, 0.0481}, COLOR_CYAN); + std::vector callbacks; + callbacks.emplace_back(watcher, 16ms); + + // Held across the whole run + CancellableHolder subcontext(static_cast(context)); + InferenceSession session(subcontext, env.console, callbacks); + + size_t expected = recommended_pokemon_blink_count(TOLERANCE_SECONDS); + env.log("Watching Munchlax. Around " + std::to_string(expected) + + " blinks are usually enough, but this stops when the answer is confirmed rather " + "than at a fixed count."); + + // how many blinks are needed comes down to luck + WallClock deadline = current_time() + std::chrono::seconds(GIVE_UP_SECONDS); + WallClock next_nudge = current_time() + KEEP_AWAKE_INTERVAL; + + bool have_candidate = false; + Xorshift128State candidate; + size_t candidate_blinks = 0; + double frozen_threshold = -1; + + double estimated_threshold = -1; + size_t estimated_from = 0; + + PokemonBlinkSolveResult confirmed; + size_t confirmed_blinks = 0; + size_t blink_count = 0; + while (true){ + if (current_time() >= deadline){ + throw UserSetupError(env.logger(), + "Gave up after " + std::to_string((int)GIVE_UP_SECONDS) + " seconds without a " + "confirmed seed. Check the overlay box is on Munchlax's eye and that the log " + "shows blinks arriving every few seconds." + ); + } + + try{ + subcontext.wait_until(std::min(deadline, current_time() + 1s)); + }catch (OperationCancelledException&){} + subcontext.throw_if_cancelled_with_exception(); + context.throw_if_cancelled(); + + if (current_time() >= next_nudge){ + pbf_move_right_joystick(context, {1.0, 0.0}, 80ms, 0ms); + context.wait_for_all_requests(); + next_nudge = current_time() + KEEP_AWAKE_INTERVAL; + } + + std::vector samples = watcher.samples(); + if (samples.empty()){ + continue; + } + double threshold = frozen_threshold; + if (threshold <= 0){ + if (estimated_threshold <= 0 || samples.size() >= estimated_from + estimated_from / 4){ + estimated_threshold = auto_blink_threshold(samples); + estimated_from = samples.size(); + } + threshold = estimated_threshold; + } + if (!(threshold > 0)){ + COLLECTION_DISPLAY.set_note("Determining blink threshold..."); + continue; + } + std::vector blinks = extract_blinks(samples, threshold); + // No need to go further until another blink is recorded + if (blinks.size() == blink_count){ + continue; + } + blink_count = blinks.size(); + + std::vector intervals = intervals_of(blinks); + size_t usable = count_usable(intervals, TOLERANCE_SECONDS); + + COLLECTION_DISPLAY.set_progress(blinks.size(), expected); + + if (usable < MIN_USABLE_TO_TRY){ + env.log(std::to_string(blinks.size()) + " blinks, " + std::to_string(usable) + + " of " + std::to_string(MIN_USABLE_TO_TRY) + " confident gaps needed before " + "solving is worth trying."); + continue; + } + if (frozen_threshold <= 0){ + frozen_threshold = threshold; + env.log("Threshold fixed at " + tostr_default(threshold) + + " for the rest of the run, so that blink numbering stops moving."); + } + + if (have_candidate && blinks.size() < candidate_blinks + CONFIRMATION_BLINKS){ + env.log(std::to_string(blinks.size()) + " blinks, " + std::to_string(usable) + + " usable. Waiting for " + + std::to_string(candidate_blinks + CONFIRMATION_BLINKS - blinks.size()) + + " more to confirm."); + continue; + } + + PokemonBlinkSolveRequest request; + request.intervals = intervals; + request.tolerance_seconds = TOLERANCE_SECONDS; + PokemonBlinkSolveResult result = solve_state_from_pokemon_blinks(request, nullptr); + if (!result.success){ + env.log(std::to_string(blinks.size()) + " blinks, " + std::to_string(usable) + + " usable, no solution yet."); + continue; + } + + if (have_candidate && result.state == candidate){ + confirmed = result; + confirmed_blinks = blinks.size(); + break; + } + if (have_candidate){ + // Two different answers means at least one came from a bad reading + env.log( + "The recovered state changed as more blinks arrived, so the earlier one was " + "wrong. Continuing.", + COLOR_ORANGE + ); + }else{ + env.log("Provisional state " + result.state.to_string() + + " from " + std::to_string(result.observations_used) + + " gaps. Collecting " + std::to_string(CONFIRMATION_BLINKS) + + " more blinks to confirm it."); + } + have_candidate = true; + candidate = result.state; + candidate_blinks = blinks.size(); + } + + uint64_t seed0 = 0; + uint64_t seed1 = 0; + xorshift128_state_to_seed_pair(confirmed.state, seed0, seed1); + + env.log("--------"); + env.log("Seed confirmed over " + std::to_string(confirmed_blinks) + " blinks.", COLOR_BLUE); + env.log("State: " + confirmed.state.to_string(), COLOR_BLUE); + env.log("PokeFinder seeds: " + tostr_hex_padded(16, seed0) + + " " + tostr_hex_padded(16, seed1), COLOR_BLUE); + env.log("Used " + std::to_string(confirmed.observations_used) + " gaps over " + + std::to_string(confirmed.attempts) + " attempt(s); worst residual " + + tostr_default(confirmed.worst_residual_seconds) + "s, weakest reading had " + + tostr_default(confirmed.weakest_margin_used) + "s of room, " + + std::to_string(confirmed.mistimed_intervals) + " gaps disagreed.", COLOR_BLUE); + + STATE_DISPLAY.set_state(confirmed.state, confirmed_blinks); + STATE_DISPLAY.set_confidence_unique(); + COLLECTION_DISPLAY.set_progress(confirmed_blinks, confirmed_blinks); + + GO_HOME_WHEN_DONE.run_end_of_program(context); +} + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.h b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.h new file mode 100644 index 0000000000..41060702e3 --- /dev/null +++ b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.h @@ -0,0 +1,42 @@ +/* BDSP Intro Seed Finder + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonBDSP_IntroSeedFinder_H +#define PokemonAutomation_PokemonBDSP_IntroSeedFinder_H + +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" +#include "PokemonBDSP_RngDisplays.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonBDSP{ + + +class IntroSeedFinder_Descriptor : public SingleSwitchProgramDescriptor{ +public: + IntroSeedFinder_Descriptor(); +}; + + +class IntroSeedFinder : public SingleSwitchProgramInstance{ +public: + IntroSeedFinder(); + + virtual void program(SingleSwitchProgramEnvironment& env, ProControllerContext& context) override; + +private: + BlinkCollectionDisplay COLLECTION_DISPLAY; + RngStateDisplay STATE_DISPLAY; + + GoHomeWhenDoneOption GO_HOME_WHEN_DONE; +}; + + +} +} +} +#endif diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 4a81f692d9..b9ebedf4b2 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1534,10 +1534,14 @@ file(GLOB LIBRARY_SOURCES Source/PokemonBDSP/Programs/PokemonBDSP_RunFromBattle.h Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_AdvanceClock.cpp Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_AdvanceClock.h + Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.cpp + Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BedroomSeedFinder.h Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkModel.cpp Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkModel.h Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkRecovery.cpp Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkRecovery.h + Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp + Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.h Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_RngDisplays.cpp Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_RngDisplays.h Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_StateReidentifier.cpp From 5180fd301671a09c74c68711ab07b7d51f6990e5 Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Wed, 26 Aug 2026 09:01:33 -0500 Subject: [PATCH 2/2] remove unnecessary try/catch for subcontext --- .../PokemonBDSP_BlinkRecovery.cpp | 16 ++++------------ .../PokemonBDSP_IntroSeedFinder.cpp | 6 +----- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkRecovery.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkRecovery.cpp index 3642005adc..0d01fcea2d 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkRecovery.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_BlinkRecovery.cpp @@ -227,11 +227,7 @@ BlinkRecovery recover_state_from_blinks( + std::to_string(config.liveness_timeout.count() / 60) + " minutes"; return ret; } - try{ - subcontext.wait_until(current_time() + config.poll_interval); - }catch (OperationCancelledException&){} - subcontext.throw_if_cancelled_with_exception(); - context.throw_if_cancelled(); + subcontext.wait_until(current_time() + config.poll_interval); keep_awake_if_due(context, next_nudge, config.keep_awake_interval); @@ -509,13 +505,9 @@ void hold_and_reanchor( // the press is timed off this anchor, so this is the most valuable check bool leaving = current_time() >= leave_at; if (!leaving){ - try{ - subcontext.wait_until(std::min({ - leave_at, next_reanchor, current_time() + config.poll_interval - })); - }catch (OperationCancelledException&){} - subcontext.throw_if_cancelled_with_exception(); - context.throw_if_cancelled(); + subcontext.wait_until(std::min({ + leave_at, next_reanchor, current_time() + config.poll_interval + })); keep_awake_if_due(context, next_nudge, config.keep_awake_interval); } diff --git a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp index bc0cca3ccf..9e0dde785f 100644 --- a/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp +++ b/SerialPrograms/Source/PokemonBDSP/Programs/RngManipulation/PokemonBDSP_IntroSeedFinder.cpp @@ -143,11 +143,7 @@ void IntroSeedFinder::program(SingleSwitchProgramEnvironment& env, ProController ); } - try{ - subcontext.wait_until(std::min(deadline, current_time() + 1s)); - }catch (OperationCancelledException&){} - subcontext.throw_if_cancelled_with_exception(); - context.throw_if_cancelled(); + subcontext.wait_until(std::min(deadline, current_time() + 1s)); if (current_time() >= next_nudge){ pbf_move_right_joystick(context, {1.0, 0.0}, 80ms, 0ms);