diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp
index d8f9cd7f6a..f5b392e648 100644
--- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp
+++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.cpp
@@ -20,6 +20,7 @@
#include "NintendoSwitch/NintendoSwitch_Settings.h"
#include "NintendoSwitch/Inference/NintendoSwitch_HomeMenuDetector.h"
#include "NintendoSwitch/Inference/NintendoSwitch_UpdatePopupDetector.h"
+#include "NintendoSwitch/Inference/NintendoSwitch_StartGameUserSelectDetector.h"
#include "NintendoSwitch/Programs/NintendoSwitch_GameEntry.h"
#include "PokemonFRLG/Inference/PokemonFRLG_SelectionArrowDetector.h"
#include "PokemonFRLG/Inference/PokemonFRLG_ShinySymbolDetector.h"
@@ -102,7 +103,8 @@ RngHelper::RngHelper()
1, 0 // default, min
)
, SEED_BUTTON(
- "Seed Button:
",
+ "Seed Button:
"
+ "The button to be pressed on the title screen to set the seed.",
{
{SeedButton::A, "A", "A"},
{SeedButton::Start, "Start", "Start"},
@@ -112,44 +114,57 @@ RngHelper::RngHelper()
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.",
+ "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,
35000, 28000 // default, min
)
, SEED_CALIBRATION(
- "Seed Calibration (ms):
Modifies the seed delay time.",
+ "Seed Calibration (ms):"
+ "
Modifies the seed delay time. This should be changed in the opposite of the direction that you missed your seed.
"
+ "Example: if you missed your target seed by +16ms (meaning the button press was too late), decrease your seed calibration by -16 (shortening the delay).",
LockMode::UNLOCK_WHILE_RUNNING,
0 // default
)
, 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.",
+ "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 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.",
+ "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:
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",
+ "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:
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.",
+ "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 if your seeds are inconsistent.",
+ "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 the RNG 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
)
@@ -588,7 +603,13 @@ void RngHelper::wait_with_teachy_tv(ProControllerContext& context, const uint64_
// total non-teachy delay duration: 13700ms
}
-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){
+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,
@@ -813,7 +834,14 @@ void RngHelper::check_timings(SingleSwitchProgramEnvironment& env, int64_t FIXED
}
}
-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){
+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, FIXED_SEED_OFFSET);
load_game_after_delay(context, CONTINUE_SCREEN_DELAY);
@@ -912,26 +940,37 @@ 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){
+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
+){
+ // close the game
go_home(env.console, context);
close_game_from_home(env.console, context);
+ // start the game and quickly go back home
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
+ pbf_wait(context, 200ms); // wait a moment to ensure the game doesn't fail to launch
+ go_home(env.console, context);
// 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.",
+ "RngHelper(): Failed to reset the game 5 times in a row.",
env.console
);
}
env.log("Starting blind button presses...");
UpdateMenuWatcher update_detector(env.console);
+ StartGameUserSelectWatcher user_selection_detector(env.console);
// any other fail conditions should be added here
context.wait_for_all_requests();
int ret = run_until(
@@ -939,7 +978,7 @@ void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment&
[this, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE](ProControllerContext& context) {
perform_blind_sequence(context, FIXED_SEED_OFFSET, CONTINUE_SCREEN_DELAY, TEACHY_DELAY, INGAME_DELAY, SAFARI_ZONE);
},
- { update_detector }
+ { update_detector, user_selection_detector }
);
switch (ret){
@@ -950,6 +989,12 @@ void RngHelper::reset_and_perform_blind_sequence(SingleSwitchProgramEnvironment&
pbf_press_button(context, BUTTON_A, 80ms, 4000ms);
context.wait_for_all_requests();
continue;
+ case 1:
+ attempts++;
+ env.log("Detected the user selection screen. Reattempting to start the game");
+ pbf_press_button(context, BUTTON_A, 160ms, 1040ms);
+ go_home(env.console, context);
+ continue;
default:
return;
}
@@ -960,7 +1005,8 @@ void RngHelper::reset_and_detect_copyright_text(SingleSwitchProgramEnvironment&
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_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
+ pbf_wait(context, 200ms); // add an extra delay to try to ensure the game doesn't fail to launch
+ go_home(env.console, context);
uint8_t attempts = 0;
while(true){
@@ -973,6 +1019,7 @@ void RngHelper::reset_and_detect_copyright_text(SingleSwitchProgramEnvironment&
}
UpdateMenuWatcher update_detector(env.console);
+ StartGameUserSelectWatcher user_selection_detector(env.console);
BlackScreenWatcher blackscreen_detector(COLOR_RED);
context.wait_for_all_requests();
int ret = run_until(
@@ -980,7 +1027,7 @@ void RngHelper::reset_and_detect_copyright_text(SingleSwitchProgramEnvironment&
[](ProControllerContext& context) {
pbf_press_button(context, BUTTON_A, 80ms, 9920ms);
},
- { update_detector, blackscreen_detector },
+ { update_detector, user_selection_detector, blackscreen_detector },
1ms
);
@@ -994,7 +1041,13 @@ void RngHelper::reset_and_detect_copyright_text(SingleSwitchProgramEnvironment&
pbf_press_button(context, BUTTON_A, 80ms, 4000ms);
context.wait_for_all_requests();
continue;
- case 1:
+ case 1:
+ attempts++;
+ env.log("Detected the user selection screen. Reattempting to start the game");
+ pbf_press_button(context, BUTTON_A, 160ms, 1040ms);
+ go_home(env.console, context);
+ continue;
+ case 2:
context.wait_for_all_requests();
ret2 = wait_until(
env.console, context, 10000ms,
diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h
index e5fa50b3e3..a12697f541 100644
--- a/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h
+++ b/SerialPrograms/Source/PokemonFRLG/Programs/ShinyHunting/PokemonFRLG_RngHelper.h
@@ -75,9 +75,30 @@ class RngHelper : public SingleSwitchProgramInstance{
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 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);