1212#include " CommonFramework/Notifications/ProgramNotifications.h"
1313#include " CommonFramework/Tools/StatsTracking.h"
1414#include " CommonFramework/ImageTools/SolidColorTest.h"
15+ #include " CommonFramework/ImageTools/ImageBoxes.h"
16+ #include " CommonFramework/ImageTools/ImageFilter.h"
17+ #include " CommonFramework/OCR/OCR_NumberReader.h"
1518#include " NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
1619#include " NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h"
20+ #include " NintendoSwitch/Inference/NintendoSwitch_DateReader.h"
21+ #include " NintendoSwitch/Inference/NintendoSwitch_DetectHome.h"
22+ #include " NintendoSwitch/NintendoSwitch_Settings.h"
23+ #include " NintendoSwitch/Programs/NintendoSwitch_GameEntry.h"
1724#include " NintendoSwitch/Programs/NintendoSwitch_SnapshotDumper.h"
1825#include " PokemonSwSh/Inference/PokemonSwSh_IvJudgeReader.h"
26+ #include " PokemonSwSh/Commands/PokemonSwSh_Commands_DateSpam.h"
1927#include " PokemonSV/Inference/Battles/PokemonSV_NormalBattleMenus.h"
2028#include " PokemonSV/Inference/Dialogs/PokemonSV_DialogDetector.h"
2129#include " PokemonSV/Inference/Overworld/PokemonSV_OverworldDetector.h"
22- // #include "PokemonSV/Inference/Overworld/PokemonSV_StationaryOverworldWatcher.h"
30+ #include " PokemonSV/Inference/Overworld/PokemonSV_StationaryOverworldWatcher.h"
2331#include " PokemonSV/Inference/PokemonSV_MainMenuDetector.h"
2432#include " PokemonSV/Inference/Map/PokemonSV_MapMenuDetector.h"
33+ #include " PokemonSV/PokemonSV_Settings.h"
2534#include " PokemonSV/Programs/PokemonSV_Navigation.h"
2635#include " PokemonSV/Programs/PokemonSV_GameEntry.h"
2736#include " PokemonSV/Programs/PokemonSV_SaveGame.h"
@@ -380,7 +389,7 @@ bool confirm_marker_present(
380389
381390 int ret = wait_until (
382391 console, context,
383- std::chrono::seconds (10 ),
392+ std::chrono::seconds (5 ),
384393 {marker, battle}
385394 );
386395 switch (ret){
@@ -454,9 +463,11 @@ void overworld_navigation(
454463 }
455464 }
456465 }
466+ context.wait_for_all_requests ();
457467 if (should_realign){
458468 try {
459469 realign_player (info, console, context, PlayerRealignMode::REALIGN_OLD_MARKER);
470+
460471 }catch (UnexpectedBattleException&){
461472 pbf_wait (context, 30 * TICKS_PER_SECOND); // catch exception to allow the battle callback to take over.
462473 }
@@ -479,10 +490,9 @@ void overworld_navigation(
479490 if (auto_heal){
480491 auto_heal_from_menu_or_overworld (info, console, context, 0 , true );
481492 }
482-
493+ context. wait_for_all_requests ();
483494 try {
484495 realign_player (info, console, context, PlayerRealignMode::REALIGN_OLD_MARKER);
485-
486496 if (!confirm_marker_present (info, console, context)){
487497 // if marker not present, don't keep walking forward.
488498 return ;
@@ -682,7 +692,7 @@ void do_action_and_monitor_for_battles(
682692 {battle_menu}
683693 );
684694 if (ret == 0 ){ // battle detected
685- throw OperationFailedException (
695+ throw UnexpectedBattleException (
686696 ErrorReport::SEND_ERROR_REPORT, console,
687697 " do_action_and_monitor_for_battles(): Detected battle. Failed to complete action." ,
688698 true
@@ -713,52 +723,65 @@ void handle_unexpected_battles(
713723 }
714724}
715725
716- // void handle_when_stationary_in_overworld(
717- // const ProgramInfo& info,
718- // ConsoleHandle& console,
719- // BotBaseContext& context,
720- // std::function<
721- // void(const ProgramInfo& info,
722- // ConsoleHandle& console,
723- // BotBaseContext& context)
724- // >&& action,
725- // std::function<
726- // void(const ProgramInfo& info,
727- // ConsoleHandle& console,
728- // BotBaseContext& context)
729- // >&& recovery_action,
730- // size_t seconds_stationary,
731- // uint16_t minutes_timeout
732- // ){
733- // StationaryOverworldWatcher stationary_overworld(COLOR_RED, {0.865, 0.82, 0.08, 0.1}, seconds_stationary);
734- // WallClock start = current_time();
735- // while (true){
736- // if (current_time() - start > std::chrono::minutes(minutes_timeout)){
737- // throw OperationFailedException(
738- // ErrorReport::SEND_ERROR_REPORT, console,
739- // "handle_when_stationary_in_overworld(): Failed to complete action after 5 minutes.",
740- // true
741- // );
742- // }
743-
744- // int ret = run_until(
745- // console, context,
746- // [&](BotBaseContext& context){
747- // context.wait_for_all_requests();
748- // action(info, console, context);
749- // },
750- // {stationary_overworld}
751- // );
752- // if (ret < 0){
753- // // successfully completed action without being stuck in a position where the overworld is stationary.
754- // return;
755- // }else if (ret == 0){
756- // // if stationary in overworld, run recovery action then try action again
757- // context.wait_for_all_requests();
758- // recovery_action(info, console, context);
759- // }
760- // }
761- // }
726+ void handle_when_stationary_in_overworld (
727+ const ProgramInfo& info,
728+ ConsoleHandle& console,
729+ BotBaseContext& context,
730+ std::function<
731+ void (const ProgramInfo& info,
732+ ConsoleHandle& console,
733+ BotBaseContext& context)
734+ >&& action,
735+ std::function<
736+ void(const ProgramInfo& info,
737+ ConsoleHandle& console,
738+ BotBaseContext& context)
739+ >&& recovery_action,
740+ size_t seconds_stationary,
741+ uint16_t minutes_timeout,
742+ size_t max_failures
743+ ){
744+
745+ WallClock start = current_time ();
746+ size_t num_failures = 0 ;
747+ while (true ){
748+ if (current_time () - start > std::chrono::minutes (minutes_timeout)){
749+ throw OperationFailedException (
750+ ErrorReport::SEND_ERROR_REPORT, console,
751+ " handle_when_stationary_in_overworld(): Failed to complete action after " + std::to_string (minutes_timeout) + " minutes." ,
752+ true
753+ );
754+ }
755+ StationaryOverworldWatcher stationary_overworld (COLOR_RED, {0.865 , 0.825 , 0.08 , 0.1 }, seconds_stationary);
756+
757+ int ret = run_until (
758+ console, context,
759+ [&](BotBaseContext& context){
760+ context.wait_for_all_requests ();
761+ action (info, console, context);
762+ },
763+ {stationary_overworld}
764+ );
765+ if (ret < 0 ){
766+ // successfully completed action without being stuck in a position where the overworld is stationary.
767+ return ;
768+ }else if (ret == 0 ){
769+ // if stationary in overworld, run recovery action then try action again
770+ console.log (" Detected stationary overworld." );
771+ num_failures++;
772+ if (num_failures > max_failures){
773+ throw OperationFailedException (
774+ ErrorReport::SEND_ERROR_REPORT, console,
775+ " handle_when_stationary_in_overworld(): Failed to complete action within " + std::to_string (max_failures) + " attempts." ,
776+ true
777+ );
778+ }
779+ context.wait_for_all_requests ();
780+ recovery_action (info, console, context);
781+ }
782+ }
783+ }
784+
762785
763786void wait_for_gradient_arrow (
764787 const ProgramInfo& info,
@@ -860,6 +883,8 @@ bool check_ride_active(const ProgramInfo& info, ConsoleHandle& console, BotBaseC
860883}
861884
862885void get_on_ride (const ProgramInfo& info, ConsoleHandle& console, BotBaseContext& context){
886+ pbf_press_button (context, BUTTON_PLUS, 20 , 20 );
887+
863888 WallClock start = current_time ();
864889 while (!check_ride_active (info, console, context)){
865890 if (current_time () - start > std::chrono::minutes (3 )){
@@ -1065,6 +1090,76 @@ void move_cursor_towards_flypoint_and_go_there(
10651090}
10661091
10671092
1093+
1094+ void change_date (
1095+ SingleSwitchProgramEnvironment& env, BotBaseContext& context,
1096+ const DateTime& date
1097+ ){
1098+ while (true ){
1099+ context.wait_for_all_requests ();
1100+
1101+ HomeWatcher home;
1102+ DateChangeWatcher date_reader;
1103+ int ret = wait_until (
1104+ env.console , context, std::chrono::seconds (120 ),
1105+ {
1106+ home,
1107+ date_reader
1108+ }
1109+ );
1110+ switch (ret){
1111+ case 0 :
1112+ home_to_date_time (context, true , false );
1113+ pbf_press_button (context, BUTTON_A, 10 , 30 );
1114+ context.wait_for_all_requests ();
1115+ continue ;
1116+ case 1 :{
1117+ env.log (" Detected date change." );
1118+
1119+ // Set the date
1120+ VideoOverlaySet overlays (env.console .overlay ());
1121+ date_reader.make_overlays (overlays);
1122+ date_reader.set_date (env.program_info (), env.console , context, date);
1123+
1124+ // Commit the date.
1125+ pbf_press_button (context, BUTTON_A, 20 , 30 );
1126+
1127+ // Re-enter the game.
1128+ pbf_press_button (context, BUTTON_HOME, 20 , ConsoleSettings::instance ().SETTINGS_TO_HOME_DELAY );
1129+
1130+ return ;
1131+ }
1132+ default :
1133+ throw OperationFailedException (
1134+ ErrorReport::SEND_ERROR_REPORT,
1135+ env.logger (),
1136+ " Failed to set date"
1137+ );
1138+ }
1139+ }
1140+ }
1141+
1142+ void check_num_sunflora_found (SingleSwitchProgramEnvironment& env, BotBaseContext& context, int expected_number){
1143+ context.wait_for_all_requests ();
1144+ VideoSnapshot screen = env.console .video ().snapshot ();
1145+ ImageFloatBox num_sunflora_box = {0.27 , 0.02 , 0.04 , 0.055 };
1146+ int number = OCR::read_number_waterfill (env.console , extract_box_reference (screen, num_sunflora_box), 0xff000000 , 0xff808080 );
1147+
1148+ if (number != expected_number){
1149+ throw OperationFailedException (
1150+ ErrorReport::SEND_ERROR_REPORT,
1151+ env.logger (),
1152+ " The number of sunflora found is different than expected."
1153+ );
1154+ }else {
1155+ env.console .log (" Number of sunflora found: " + std::to_string (number));
1156+ }
1157+
1158+
1159+ }
1160+
1161+
1162+
10681163}
10691164}
10701165}
0 commit comments