diff --git a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp index e54dcbc86f..b226e9a1c3 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.cpp @@ -122,14 +122,13 @@ void FastTravelWatcher::make_overlays(VideoOverlaySet& items) const{ } bool FastTravelWatcher::process_frame(const ImageViewRGB32& screen, WallClock timestamp){ - std::vector hits = m_detector.detect_all(screen); + m_hits = m_detector.detect_all(screen); - m_hits.reset(hits.size()); - for (const ImageFloatBox& hit : hits){ - m_hits.emplace_back(m_overlay, hit, COLOR_MAGENTA); + m_hit_boxes.reset(m_hits.size()); + for (const ImageFloatBox& hit : m_hits){ + m_hit_boxes.emplace_back(m_overlay, hit, COLOR_MAGENTA); } - - return !hits.empty(); + return !m_hits.empty(); } diff --git a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.h b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.h index 14a13d7edf..ac68e42cc8 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.h +++ b/SerialPrograms/Source/PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.h @@ -58,11 +58,13 @@ class FastTravelWatcher : public VisualInferenceCallback{ virtual void make_overlays(VideoOverlaySet& items) const override; virtual bool process_frame(const ImageViewRGB32& frame, WallClock timestamp) override; + const std::vector& found_locations() const { return m_hits; } protected: VideoOverlay& m_overlay; FastTravelDetector m_detector; - FixedLimitVector m_hits; + std::vector m_hits; + FixedLimitVector m_hit_boxes; }; diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp index 592df5efe8..1dd9f3d719 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp @@ -94,7 +94,7 @@ std::vector> make_autoStory_segment_list(){ segment_list.emplace_back(std::make_unique()); segment_list.emplace_back(std::make_unique()); segment_list.emplace_back(std::make_unique()); - // segment_list.emplace_back(std::make_unique()); + segment_list.emplace_back(std::make_unique()); // segment_list.emplace_back(std::make_unique()); // segment_list.emplace_back(std::make_unique()); // segment_list.emplace_back(std::make_unique()); @@ -415,13 +415,49 @@ AutoStory::AutoStory() "direction in radians", LockMode::UNLOCK_WHILE_RUNNING, 0 - ) + ) + , FLYPOINT_TYPE( + "Flypoint type:
" + "For print_flypoint_location() and move_cursor_to_position_offset_from_flypoint()", + { + {FlyPoint::POKECENTER, "pokecenter", "Pokecenter"}, + {FlyPoint::FAST_TRAVEL, "fast-travel", "Fast Travel"}, + }, + LockMode::UNLOCK_WHILE_RUNNING, + FlyPoint::POKECENTER + ) + , TEST_FLYPOINT_LOCATIONS( + "TEST: print_flypoint_location():", + LockMode::UNLOCK_WHILE_RUNNING, + false + ) + , TEST_MOVE_CURSOR_OFFSET_FROM_FLYPOINT( + "TEST: move_cursor_to_position_offset_from_flypoint():", + LockMode::UNLOCK_WHILE_RUNNING, + false + ) + , X_OFFSET( + "X offset from flypoint", + LockMode::UNLOCK_WHILE_RUNNING, + 0 + ) + , Y_OFFSET( + "Y offset from flypoint", + LockMode::UNLOCK_WHILE_RUNNING, + 0 + ) { if (PreloadSettings::instance().DEVELOPER_MODE){ PA_ADD_OPTION(m_advanced_options); PA_ADD_OPTION(CHANGE_SETTINGS); + PA_ADD_OPTION(FLYPOINT_TYPE); + PA_ADD_OPTION(TEST_FLYPOINT_LOCATIONS); + PA_ADD_OPTION(TEST_MOVE_CURSOR_OFFSET_FROM_FLYPOINT); + PA_ADD_OPTION(X_OFFSET); + PA_ADD_OPTION(Y_OFFSET); + PA_ADD_OPTION(TEST_CURRENT_DIRECTION); PA_ADD_OPTION(TEST_CHANGE_DIRECTION); PA_ADD_OPTION(DIR_RADIANS); @@ -768,6 +804,19 @@ void AutoStory::run_autostory(SingleSwitchProgramEnvironment& env, ProController } void AutoStory::test_code(SingleSwitchProgramEnvironment& env, ProControllerContext& context){ + + if (TEST_FLYPOINT_LOCATIONS){ + print_flypoint_location(env.program_info(), env.console, context, FLYPOINT_TYPE); + // print_flypoint_location(env.program_info(), env.console, context, FlyPoint::FAST_TRAVEL); + return; + } + + if (TEST_MOVE_CURSOR_OFFSET_FROM_FLYPOINT){ + move_cursor_to_position_offset_from_flypoint(env.program_info(), env.console, context, FLYPOINT_TYPE, {X_OFFSET, Y_OFFSET}); + + return; + } + if (TEST_CURRENT_DIRECTION){ DirectionDetector direction; // direction.change_direction(env.program_info(), env.console, context, DIR_RADIANS); @@ -818,6 +867,7 @@ void AutoStory::test_code(SingleSwitchProgramEnvironment& env, ProControllerCont DirectionDetector direction; + return; } diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.h index 636dfe3a05..d4bb4cac38 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.h @@ -126,6 +126,12 @@ class AutoStory : public SingleSwitchProgramInstance, public ConfigOption::Liste BooleanCheckBoxOption TEST_CURRENT_DIRECTION; BooleanCheckBoxOption TEST_CHANGE_DIRECTION; FloatingPointOption DIR_RADIANS; + + EnumDropdownOption FLYPOINT_TYPE; + BooleanCheckBoxOption TEST_FLYPOINT_LOCATIONS; + BooleanCheckBoxOption TEST_MOVE_CURSOR_OFFSET_FROM_FLYPOINT; + FloatingPointOption X_OFFSET; + FloatingPointOption Y_OFFSET; }; const std::vector>& ALL_AUTO_STORY_SEGMENT_LIST(); diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.cpp index e7eadc9924..7bbafb4e30 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.cpp @@ -19,7 +19,6 @@ #include "PokemonSV/Inference/Overworld/PokemonSV_StationaryOverworldWatcher.h" #include "PokemonSV/Inference/PokemonSV_MainMenuDetector.h" #include "PokemonSV/Programs/PokemonSV_MenuNavigation.h" -#include "PokemonSV/Programs/PokemonSV_WorldNavigation.h" #include "PokemonSV/Programs/PokemonSV_GameEntry.h" #include "PokemonSV/Programs/PokemonSV_SaveGame.h" #include "PokemonSV/Programs/Battles/PokemonSV_Battles.h" @@ -41,178 +40,7 @@ namespace PokemonSV{ -// spam A button to choose the first move -// throw exception if wipeout or if your lead faints. -void run_battle_press_A( - VideoStream& stream, - ProControllerContext& context, - BattleStopCondition stop_condition, - std::unordered_set enum_optional_callbacks, - bool detect_wipeout -){ - int16_t num_times_seen_overworld = 0; - size_t consecutive_move_select = 0; - while (true){ - NormalBattleMenuWatcher battle(COLOR_BLUE); - SwapMenuWatcher fainted(COLOR_PURPLE); - OverworldWatcher overworld(stream.logger(), COLOR_CYAN); - AdvanceDialogWatcher dialog(COLOR_RED); - DialogArrowWatcher dialog_arrow(COLOR_RED, stream.overlay(), {0.850, 0.820, 0.020, 0.050}, 0.8365, 0.846); - GradientArrowWatcher next_pokemon(COLOR_BLUE, GradientArrowType::RIGHT, {0.50, 0.51, 0.30, 0.10}); - MoveSelectWatcher move_select_menu(COLOR_YELLOW); - - std::vector callbacks; - std::vector enum_all_callbacks; - // mandatory callbacks: Battle, Overworld, Advance Dialog, Swap menu, Move select - // optional callbacks: DIALOG_ARROW, NEXT_POKEMON - - // merge the mandatory and optional callbacks as a set, to avoid duplicates. then convert to vector - std::unordered_set enum_all_callbacks_set{CallbackEnum::BATTLE, CallbackEnum::OVERWORLD, CallbackEnum::ADVANCE_DIALOG, CallbackEnum::SWAP_MENU, CallbackEnum::MOVE_SELECT}; // mandatory callbacks - enum_all_callbacks_set.insert(enum_optional_callbacks.begin(), enum_optional_callbacks.end()); // append the mandatory and optional callback sets together - enum_all_callbacks.assign(enum_all_callbacks_set.begin(), enum_all_callbacks_set.end()); - - for (const CallbackEnum& enum_callback : enum_all_callbacks){ - switch(enum_callback){ - case CallbackEnum::ADVANCE_DIALOG: - callbacks.emplace_back(dialog); - break; - case CallbackEnum::OVERWORLD: - callbacks.emplace_back(overworld); - break; - case CallbackEnum::DIALOG_ARROW: - callbacks.emplace_back(dialog_arrow); - break; - case CallbackEnum::BATTLE: - callbacks.emplace_back(battle); - break; - case CallbackEnum::NEXT_POKEMON: // to detect the "next pokemon" prompt. - callbacks.emplace_back(next_pokemon); - break; - case CallbackEnum::SWAP_MENU: // detecting Swap Menu implies your lead fainted. - callbacks.emplace_back(fainted); - break; - case CallbackEnum::MOVE_SELECT: - callbacks.emplace_back(move_select_menu); - break; - default: - throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "run_battle_press_A: Unknown callback requested."); - } - } - context.wait_for_all_requests(); - - int ret = wait_until( - stream, context, - std::chrono::seconds(90), - callbacks - ); - context.wait_for(std::chrono::milliseconds(100)); - if (ret < 0){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "run_battle_press_A(): Timed out. Did not detect expected stop condition.", - stream - ); - } - CallbackEnum enum_callback = enum_all_callbacks[ret]; - switch (enum_callback){ - case CallbackEnum::BATTLE: // battle - stream.log("Detected battle menu."); - consecutive_move_select = 0; - pbf_press_button(context, BUTTON_A, 20, 105); - break; - case CallbackEnum::MOVE_SELECT: - stream.log("Detected move select. Spam first move"); - consecutive_move_select++; - select_top_move(stream, context, consecutive_move_select); - break; - case CallbackEnum::OVERWORLD: // overworld - stream.log("Detected overworld, battle over."); - num_times_seen_overworld++; - if (stop_condition == BattleStopCondition::STOP_OVERWORLD){ - return; - } - if(num_times_seen_overworld > 30){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "run_battle_press_A(): Stuck in overworld. Did not detect expected stop condition.", - stream - ); - } - break; - case CallbackEnum::ADVANCE_DIALOG: // advance dialog - stream.log("Detected dialog."); - - if (detect_wipeout){ - context.wait_for_all_requests(); - WipeoutDetector wipeout; - VideoSnapshot screen = stream.video().snapshot(); - // dump_snapshot(console); - if (wipeout.detect(screen)){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "run_battle_press_A(): Detected wipeout. All pokemon fainted.", - stream - ); - } - } - - if (stop_condition == BattleStopCondition::STOP_DIALOG){ - return; - } - pbf_press_button(context, BUTTON_A, 20, 105); - break; - case CallbackEnum::DIALOG_ARROW: // dialog arrow - stream.log("run_battle_press_A: Detected dialog arrow."); - pbf_press_button(context, BUTTON_A, 20, 105); - break; - case CallbackEnum::NEXT_POKEMON: - stream.log("run_battle_press_A: Detected prompt for bringing in next pokemon. Keep current pokemon."); - pbf_mash_button(context, BUTTON_B, 100); - break; - case CallbackEnum::SWAP_MENU: - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "run_battle_press_A(): Lead pokemon fainted.", - stream - ); - default: - throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "run_battle_press_A: Unknown callback triggered."); - - } - } -} - -void run_trainer_battle_press_A( - VideoStream& stream, - ProControllerContext& context, - BattleStopCondition stop_condition, - std::unordered_set enum_optional_callbacks, - bool detect_wipeout -){ - enum_optional_callbacks.insert(CallbackEnum::NEXT_POKEMON); // always check for the "Next pokemon" prompt when in trainer battles - run_battle_press_A(stream, context, stop_condition, enum_optional_callbacks, detect_wipeout); -} - -void run_wild_battle_press_A( - VideoStream& stream, - ProControllerContext& context, - BattleStopCondition stop_condition, - std::unordered_set enum_optional_callbacks, - bool detect_wipeout -){ - run_battle_press_A(stream, context, stop_condition, enum_optional_callbacks, detect_wipeout); -} - -void select_top_move(VideoStream& stream, ProControllerContext& context, size_t consecutive_move_select){ - if (consecutive_move_select > 3){ - // to handle case where move is disabled/out of PP/taunted - stream.log("Failed to select a move 3 times. Choosing a different move.", COLOR_RED); - pbf_press_dpad(context, DPAD_DOWN, 20, 40); - } - pbf_mash_button(context, BUTTON_A, 100); - -} void clear_tutorial(VideoStream& stream, ProControllerContext& context, uint16_t seconds_timeout){ bool seen_tutorial = false; @@ -1060,7 +888,7 @@ void realign_player_from_landmark( pbf_move_left_joystick(context, move_x1, move_y1, move_duration1, 1 * TICKS_PER_SECOND); // move cursor to pokecenter - if (!detect_closest_pokecenter_and_move_map_cursor_there(info, stream, context, 0.29)){ + if (!detect_closest_flypoint_and_move_map_cursor_there(info, stream, context, FlyPoint::POKECENTER, 0.29)){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, "realign_player_from_landmark(): No visible pokecenter found on map.", @@ -1133,7 +961,8 @@ void move_cursor_towards_flypoint_and_go_there( const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, - MoveCursor move_cursor_near_flypoint + MoveCursor move_cursor_near_flypoint, + FlyPoint fly_point ){ WallClock start = current_time(); @@ -1173,7 +1002,7 @@ void move_cursor_towards_flypoint_and_go_there( uint16_t move_duration1 = move_cursor_near_flypoint.move_duration; pbf_move_left_joystick(context, move_x1, move_y1, move_duration1, 1 * TICKS_PER_SECOND); - if (!fly_to_visible_closest_pokecenter_cur_zoom_level(info, stream, context)){ + if (!fly_to_visible_closest_flypoint_cur_zoom_level(info, stream, context, fly_point)){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, "move_cursor_towards_flypoint_and_go_there(): No visible pokecenter found on map.", diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.h index 6f6bc40c96..8f2cf6f047 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.h @@ -8,11 +8,11 @@ #define PokemonAutomation_PokemonSV_AutoStoryTools_H #include -#include #include "CommonFramework/Language.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/ProgramStats/StatsTracking.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "PokemonSV/Programs/PokemonSV_WorldNavigation.h" // #include "PokemonSV/Programs/PokemonSV_Navigation.h" namespace PokemonAutomation{ @@ -36,10 +36,6 @@ struct AutoStoryStats : public StatsTracker{ }; -enum class BattleStopCondition{ - STOP_OVERWORLD, - STOP_DIALOG, -}; enum class ClearDialogMode{ STOP_OVERWORLD, @@ -50,19 +46,7 @@ enum class ClearDialogMode{ }; -enum class CallbackEnum{ - ADVANCE_DIALOG, - OVERWORLD, - PROMPT_DIALOG, - WHITE_A_BUTTON, - DIALOG_ARROW, - BATTLE, - TUTORIAL, - BLACK_DIALOG_BOX, - NEXT_POKEMON, - SWAP_MENU, - MOVE_SELECT, -}; + enum class StartPoint{ INTRO_CUTSCENE, @@ -81,11 +65,7 @@ enum class StarterChoice{ QUAXLY, }; -enum class PlayerRealignMode{ - REALIGN_NEW_MARKER, - REALIGN_OLD_MARKER, - REALIGN_NO_MARKER, -}; + enum class NavigationStopCondition{ STOP_DIALOG, @@ -94,11 +74,7 @@ enum class NavigationStopCondition{ STOP_BATTLE, }; -enum class NavigationMovementMode{ - DIRECTIONAL_ONLY, - DIRECTIONAL_SPAM_A, - CLEAR_WITH_LETS_GO, -}; + struct AutoStoryOptions{ Language language; @@ -119,29 +95,6 @@ class AutoStory_Segment { AutoStoryStats& stats) const = 0; }; -// spam A button to choose the first move for trainer battles -// detect_wipeout: can be false if you have multiple pokemon in your party, since an exception will be thrown if your lead faints. -// throw exception if wipeout or if your lead faints. -void run_trainer_battle_press_A( - VideoStream& stream, - ProControllerContext& context, - BattleStopCondition stop_condition, - std::unordered_set enum_optional_callbacks = {}, - bool detect_wipeout = false -); - -// spam A button to choose the first move for wild battles -// detect_wipeout: can be false if you have multiple pokemon in your party, since an exception will be thrown if your lead faints. -// throw exception if wipeout or if your lead faints. -void run_wild_battle_press_A( - VideoStream& stream, - ProControllerContext& context, - BattleStopCondition stop_condition, - std::unordered_set enum_optional_callbacks = {}, - bool detect_wipeout = false -); - -void select_top_move(VideoStream& stream, ProControllerContext& context, size_t consecutive_move_select); // press A to clear tutorial screens // throw exception if tutorial screen never detected @@ -292,25 +245,11 @@ void change_settings(SingleSwitchProgramEnvironment& env, ProControllerContext& void checkpoint_save(SingleSwitchProgramEnvironment& env, ProControllerContext& context, EventNotificationOption& notif_status_update, AutoStoryStats& stats); -enum class ZoomChange{ - ZOOM_IN, - ZOOM_IN_TWICE, - ZOOM_OUT, - ZOOM_OUT_TWICE, - KEEP_ZOOM, -}; - -struct MoveCursor{ - ZoomChange zoom_change; - uint8_t move_x; - uint8_t move_y; - uint16_t move_duration; -}; // place a marker on the map, not relative to the current player position, but based on a fixed landmark, such as a pokecenter // How this works: // - cursor is moved to a point near the landmark, as per `move_cursor_near_landmark` -// - move the cursor onto the landmark using `detect_closest_pokecenter_and_move_map_cursor_there`. +// - move the cursor onto the landmark using `detect_closest_flypoint_and_move_map_cursor_there`. // - confirm that the pokecenter is centered within cursor. If not, close map app, and re-try. // - cursor is moved to target location, as per `move_cursor_to_target`. A marker is placed down here. void realign_player_from_landmark( @@ -331,7 +270,8 @@ void move_cursor_towards_flypoint_and_go_there( const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, - MoveCursor move_cursor_near_flypoint + MoveCursor move_cursor_near_flypoint, + FlyPoint fly_point = FlyPoint::POKECENTER ); diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.cpp index b78efb9911..f240bec483 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.cpp @@ -9,6 +9,7 @@ #include "CommonFramework/Exceptions/OperationFailedException.h" #include "CommonTools/Async/InferenceRoutines.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/Inference/NintendoSwitch_ConsoleTypeDetector.h" #include "PokemonSV/Programs/PokemonSV_GameEntry.h" #include "PokemonSV/Programs/PokemonSV_SaveGame.h" #include "PokemonSV/Programs/PokemonSV_MenuNavigation.h" @@ -61,6 +62,7 @@ void AutoStory_Segment_23::run_segment( } + void checkpoint_54( SingleSwitchProgramEnvironment& env, ProControllerContext& context, @@ -69,8 +71,7 @@ void checkpoint_54( ){ checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ - - + DirectionDetector direction; direction.change_direction(env.program_info(), env.console, context, 1.341); pbf_move_left_joystick(context, 128, 0, 450, 100); @@ -90,13 +91,12 @@ void checkpoint_54( } ); - // marker 2 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 0, 0, 0}, - {ZoomChange::ZOOM_IN, 200, 0, 80} - ); - + // marker 2. x=0.411979, y=0.730556 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.411979, 0.730556} + ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, @@ -109,11 +109,11 @@ void checkpoint_54( } ); - // marker 3 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 0, 0, 0}, - {ZoomChange::ZOOM_IN, 190, 0, 115} + // marker 3. x=0.444792, y=0.640741. zoom out + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::ZOOM_OUT, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.444792, 0.640741} ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, @@ -128,7 +128,7 @@ void checkpoint_54( } ); - // marker 4 + // marker 4. blind marker placement realign_player_from_landmark( env.program_info(), env.console, context, {ZoomChange::KEEP_ZOOM, 128, 255, 50}, @@ -146,12 +146,12 @@ void checkpoint_54( } ); - // marker 5 + // marker 5. blind marker placement realign_player_from_landmark( env.program_info(), env.console, context, {ZoomChange::KEEP_ZOOM, 128, 255, 50}, {ZoomChange::ZOOM_IN, 135, 0, 107} - ); + ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, @@ -164,13 +164,14 @@ void checkpoint_54( } ); - // marker 6 + // marker 6. blind marker placement realign_player_from_landmark( env.program_info(), env.console, context, {ZoomChange::KEEP_ZOOM, 128, 255, 50}, {ZoomChange::ZOOM_IN, 120, 0, 95} ); + // walk forward until dialog handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ @@ -200,12 +201,13 @@ void checkpoint_54( } ); - // marker 7 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 128, 255, 50}, - {ZoomChange::ZOOM_IN, 110, 0, 55} - ); + + // marker 7. x=0.505729, y=0.675926 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 128, 255, 30}, + FlyPoint::POKECENTER, + {0.505729, 0.675926} + ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, @@ -218,12 +220,12 @@ void checkpoint_54( } ); - // marker 8 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 0, 0, 0}, - {ZoomChange::ZOOM_IN, 0, 50, 60} - ); + // marker 8. x=0.591146, y=0.575926, + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.591146, 0.575926} + ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, @@ -236,12 +238,12 @@ void checkpoint_54( } ); - // marker 9. at crossroads - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 0, 0, 0}, - {ZoomChange::ZOOM_IN, 0, 110, 115} - ); + // marker 9. at crossroads. x=0.723958, y=0.55463 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.723958, 0.55463} + ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, @@ -254,18 +256,18 @@ void checkpoint_54( } ); - // marker 10 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 0, 0, 0}, - {ZoomChange::ZOOM_IN, 0, 80, 125} - ); + // marker 10. x=0.752604, y=0.643519 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.752604, 0.643519} + ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, - 128, 0, 10, 10, false); + 128, 0, 20, 10, false); }, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ pbf_move_left_joystick(context, 0, 255, 40, 50); @@ -273,37 +275,19 @@ void checkpoint_54( } ); - // marker 11 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 255, 128, 50}, - {ZoomChange::ZOOM_IN, 0, 85, 135} - ); - - handle_when_stationary_in_overworld(env.program_info(), env.console, context, - [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ - overworld_navigation(env.program_info(), env.console, context, - NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, - 128, 0, 24, 8, false); - }, - [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ - pbf_move_left_joystick(context, 255, 255, 40, 50); - realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); - } - ); - // marker 12 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 255, 128, 50}, - {ZoomChange::ZOOM_IN, 0, 70, 140} + // marker 11. x=0.752083, y=0.702778 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.752083, 0.702778} ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, - 128, 0, 24, 8, false); + 128, 0, 16, 8, false); }, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ pbf_move_left_joystick(context, 255, 255, 40, 50); @@ -311,18 +295,18 @@ void checkpoint_54( } ); - // marker 13 - realign_player_from_landmark( - env.program_info(), env.console, context, - {ZoomChange::KEEP_ZOOM, 255, 128, 50}, - {ZoomChange::ZOOM_IN, 0, 45, 130} + // marker 12. x=0.685417, y=0.748148 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.685417, 0.748148} ); handle_when_stationary_in_overworld(env.program_info(), env.console, context, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ overworld_navigation(env.program_info(), env.console, context, NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, - 128, 0, 20, 10, false); + 128, 0, 16, 8, false); }, [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ pbf_move_left_joystick(context, 255, 255, 40, 50); @@ -330,10 +314,12 @@ void checkpoint_54( } ); - fly_to_overlapping_flypoint(env.program_info(), env.console, context); + fly_to_overlapping_flypoint(env.program_info(), env.console, context); + + }); - }); + } diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.cpp index f55e48b3bb..1ed85e0518 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.cpp @@ -3,6 +3,7 @@ * From: https://github.com/PokemonAutomation/ * */ +#include "PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.h" #include "CommonFramework/Exceptions/OperationFailedException.h" #include "CommonTools/Async/InferenceRoutines.h" @@ -28,15 +29,15 @@ namespace PokemonSV{ std::string AutoStory_Segment_24::name() const{ - return ""; + return "24: Orthworm Titan: Battle Orthworm Titan"; } std::string AutoStory_Segment_24::start_text() const{ - return "Start: "; + return "Start: At East Province (Area Three) Watchtower."; } std::string AutoStory_Segment_24::end_text() const{ - return "End: "; + return "End: Beat Orthworm Titan. At East Province (Area Three) Pokecenter."; } void AutoStory_Segment_24::run_segment( @@ -52,7 +53,9 @@ void AutoStory_Segment_24::run_segment( context.wait_for_all_requests(); env.console.log("Start Segment " + name(), COLOR_ORANGE); - // checkpoint_(env, context, options.notif_status_update, stats); + checkpoint_55(env, context, options.notif_status_update, stats); + checkpoint_56(env, context, options.notif_status_update, stats); + checkpoint_57(env, context, options.notif_status_update, stats); context.wait_for_all_requests(); env.console.log("End Segment " + name(), COLOR_GREEN); @@ -69,66 +72,67 @@ void checkpoint_55( checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ - // todo: try to align to left side of tunnel. then charge at Orthworm - // reset if caught in battle. - ///////////////////// + do_action_and_monitor_for_battles(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + + DirectionDetector direction; - // get_off_ride(env.program_info(), env.console, context); + direction.change_direction(env.program_info(), env.console, context, 3.909067); + pbf_move_left_joystick(context, 128, 0, 1000, 100); - - // direction.change_direction(env.program_info(), env.console, context, 0.261); - // pbf_move_left_joystick(context, 128, 0, 500, 100); - // pbf_move_left_joystick(context, 0, 0, 500, 100); + direction.change_direction(env.program_info(), env.console, context, 5.061720); + pbf_move_left_joystick(context, 128, 0, 500, 100); + pbf_move_left_joystick(context, 255, 0, 200, 100); - // // now aligned to corner. + // now aligned to the wall next to the hole/passage - // direction.change_direction(env.program_info(), env.console, context, 3.736); - // pbf_move_left_joystick(context, 128, 0, 400, 100); + // walk away from wall slightly + pbf_move_left_joystick(context, 128, 255, 50, 100); + get_on_ride(env.program_info(), env.console, context); - // direction.change_direction(env.program_info(), env.console, context, 5.306); - // pbf_move_left_joystick(context, 128, 0, 700, 100); + direction.change_direction(env.program_info(), env.console, context, 0.366); + pbf_move_left_joystick(context, 128, 0, 250, 100); - - // direction.change_direction(env.program_info(), env.console, context, 4.988); - // pbf_move_left_joystick(context, 128, 0, 800, 100); - // pbf_move_left_joystick(context, 255, 0, 500, 100); + direction.change_direction(env.program_info(), env.console, context, 2.565); + // run at Orthworm. run into its second position as well. + pbf_move_left_joystick(context, 128, 0, 50, 0); + pbf_controller_state(context, BUTTON_LCLICK, DPAD_NONE, 128, 0, 128, 128, 500); + pbf_move_left_joystick(context, 255, 0, 300, 500); - // // now aligned to the wall next to the hole/passage + get_off_ride(env.program_info(), env.console, context); - // // walk away from wall slightly - // pbf_move_left_joystick(context, 128, 255, 50, 100); - // get_on_ride(env.program_info(), env.console, context); + direction.change_direction(env.program_info(), env.console, context, 0.261); + pbf_move_left_joystick(context, 128, 0, 500, 100); + pbf_move_left_joystick(context, 0, 0, 500, 100); - // direction.change_direction(env.program_info(), env.console, context, 0.366); - // pbf_move_left_joystick(context, 128, 0, 250, 100); + // now aligned to corner. - // direction.change_direction(env.program_info(), env.console, context, 2.565); - // // run at Orthworm. run into its second position as well. - // pbf_move_left_joystick(context, 128, 0, 50, 0); - // pbf_controller_state(context, BUTTON_LCLICK, DPAD_NONE, 128, 0, 128, 128, 500); - // pbf_move_left_joystick(context, 255, 0, 500, 500); + direction.change_direction(env.program_info(), env.console, context, 3.736); + pbf_move_left_joystick(context, 128, 0, 400, 100); - // get_off_ride(env.program_info(), env.console, context); + direction.change_direction(env.program_info(), env.console, context, 5.306); + pbf_move_left_joystick(context, 128, 0, 700, 100); - // direction.change_direction(env.program_info(), env.console, context, 0.261); - // pbf_move_left_joystick(context, 128, 0, 500, 100); - // pbf_move_left_joystick(context, 0, 0, 500, 100); + + direction.change_direction(env.program_info(), env.console, context, 4.988); + pbf_move_left_joystick(context, 128, 0, 800, 100); + pbf_move_left_joystick(context, 255, 0, 500, 100); - // // now aligned to corner. + // now aligned to the wall next to the hole/passage - // direction.change_direction(env.program_info(), env.console, context, 3.736); - // pbf_move_left_joystick(context, 128, 0, 400, 100); + // walk away from wall slightly + pbf_move_left_joystick(context, 128, 255, 100, 100); - // direction.change_direction(env.program_info(), env.console, context, 5.306); - // pbf_move_left_joystick(context, 128, 0, 700, 100); + direction.change_direction(env.program_info(), env.console, context, 5.722795); + pbf_move_left_joystick(context, 128, 0, 600, 100); - - // direction.change_direction(env.program_info(), env.console, context, 4.988); - // pbf_move_left_joystick(context, 128, 0, 800, 100); - // pbf_move_left_joystick(context, 255, 0, 500, 100); + direction.change_direction(env.program_info(), env.console, context, 0.625226); + }); - // // now aligned to the wall next to the hole/passage + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_ONLY, 30); + env.console.log("Battle Orthworm Titan phase 1."); + run_wild_battle_press_A(env.console, context, BattleStopCondition::STOP_OVERWORLD); }); @@ -143,6 +147,61 @@ void checkpoint_56( checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ + do_action_and_monitor_for_battles(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + + DirectionDetector direction; + + direction.change_direction(env.program_info(), env.console, context, 5.042435); + pbf_move_left_joystick(context, 128, 0, 900, 100); + + direction.change_direction(env.program_info(), env.console, context, 5.360763); + pbf_move_left_joystick(context, 128, 0, 500, 100); + + direction.change_direction(env.program_info(), env.console, context, 5.85); + pbf_move_left_joystick(context, 128, 0, 700, 100); + + direction.change_direction(env.program_info(), env.console, context, 5.428); + pbf_move_left_joystick(context, 128, 0, 600, 100); + + direction.change_direction(env.program_info(), env.console, context, 4.908646); + pbf_move_left_joystick(context, 128, 0, 300, 100); + + direction.change_direction(env.program_info(), env.console, context, 1.169728); + pbf_move_left_joystick(context, 128, 0, 200, 100); + pbf_move_left_joystick(context, 255, 0, 200, 100); + pbf_move_left_joystick(context, 0, 0, 200, 100); + + // now aligned to the wall next to the hole/passage + + // walk backwards + direction.change_direction(env.program_info(), env.console, context, 2.303077); + pbf_move_left_joystick(context, 128, 255, 400, 100); + direction.change_direction(env.program_info(), env.console, context, 3.908360); + + get_on_ride(env.program_info(), env.console, context); + + // charge at orthworm + pbf_move_left_joystick(context, 128, 0, 408ms, 0ms); + pbf_controller_state(context, BUTTON_LCLICK, DPAD_NONE, 128, 0, 128, 128, 102ms); + pbf_move_left_joystick(context, 128, 0, 1970ms, 0ms); + pbf_controller_state(context, BUTTON_NONE, DPAD_NONE, 128, 0, 0, 128, 432ms); + pbf_move_left_joystick(context, 128, 0, 1993ms, 0ms); + pbf_controller_state(context, BUTTON_NONE, DPAD_NONE, 128, 0, 0, 128, 301ms); + pbf_move_left_joystick(context, 128, 0, 307ms, 0ms); + pbf_controller_state(context, BUTTON_NONE, DPAD_NONE, 128, 0, 0, 128, 194ms); + pbf_move_left_joystick(context, 128, 0, 886ms, 0ms); + pbf_controller_state(context, BUTTON_NONE, DPAD_NONE, 128, 0, 0, 128, 626ms); + pbf_move_left_joystick(context, 128, 0, 2651ms, 0ms); + }); + + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_ONLY, 30); + + // battle the titan phase 2 + clear_dialog(env.console, context, ClearDialogMode::STOP_BATTLE, 60, {CallbackEnum::BATTLE}); + env.console.log("Battle Orthworm Titan phase 2."); + run_wild_battle_press_A(env.console, context, BattleStopCondition::STOP_DIALOG, {CallbackEnum::DIALOG_ARROW}); + mash_button_till_overworld(env.console, context, BUTTON_A, 360); }); @@ -156,8 +215,113 @@ void checkpoint_57( ){ checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ + // fly back to East Province (Area Three) Watchtower + move_cursor_towards_flypoint_and_go_there(env.program_info(), env.console, context, {ZoomChange::KEEP_ZOOM, 0, 0, 0}, FlyPoint::FAST_TRAVEL); + + // marker 1 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.769792, 0.725926} + ); + handle_when_stationary_in_overworld(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + overworld_navigation(env.program_info(), env.console, context, + NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, + 128, 0, 20, 10, false); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + pbf_move_left_joystick(context, 255, 128, 40, 50); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + } + ); + + // marker 2 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 0, 0, 0}, + FlyPoint::POKECENTER, + {0.280208, 0.447222} + ); + handle_when_stationary_in_overworld(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + overworld_navigation(env.program_info(), env.console, context, + NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, + 128, 0, 30, 10, false); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + pbf_move_left_joystick(context, 255, 128, 40, 50); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + } + ); + + // marker 3 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::ZOOM_IN, 0, 128, 60}, + FlyPoint::POKECENTER, + {0.354167, 0.375} + ); + handle_when_stationary_in_overworld(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + overworld_navigation(env.program_info(), env.console, context, + NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, + 128, 0, 40, 10, false); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + pbf_move_left_joystick(context, 255, 128, 40, 50); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + } + ); + + // marker 4 + place_marker_offset_from_flypoint(env.program_info(), env.console, context, + {ZoomChange::ZOOM_IN, 0, 128, 50}, + FlyPoint::POKECENTER, + {0.497917, 0.274074} + ); + handle_when_stationary_in_overworld(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + overworld_navigation(env.program_info(), env.console, context, + NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, + 128, 0, 30, 10, false); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + pbf_move_left_joystick(context, 0, 128, 40, 50); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + } + ); + + // marker 5. set marker to pokecenter + realign_player_from_landmark( + env.program_info(), env.console, context, + {ZoomChange::ZOOM_IN, 0, 0, 0}, + {ZoomChange::KEEP_ZOOM, 0, 0, 0} + ); + + handle_when_stationary_in_overworld(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + overworld_navigation(env.program_info(), env.console, context, + NavigationStopCondition::STOP_MARKER, NavigationMovementMode::DIRECTIONAL_ONLY, + 128, 0, 20, 10, false); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + pbf_move_left_joystick(context, 255, 0, 40, 50); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + } + ); + + // marker 6. set marker past pokecenter + handle_unexpected_battles(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_NEW_MARKER, 128, 0, 30); + }); + overworld_navigation(env.program_info(), env.console, context, + NavigationStopCondition::STOP_TIME, NavigationMovementMode::DIRECTIONAL_ONLY, + 128, 15, 12, 12, false); // can't wrap in handle_when_stationary_in_overworld(), since we expect to be stationary when walking into the pokecenter + + + fly_to_overlapping_flypoint(env.program_info(), env.console, context); - + }); } diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.h index 148dc778dc..7c811513e3 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_24.h @@ -28,7 +28,7 @@ class AutoStory_Segment_24 : public AutoStory_Segment{ // start: At East Province (Area Three) Watchtower. -// end: +// end: Beat Orthworm phase 1 void checkpoint_55( SingleSwitchProgramEnvironment& env, ProControllerContext& context, @@ -36,8 +36,8 @@ void checkpoint_55( AutoStoryStats& stats ); -// start: -// end: +// start: Beat Orthworm phase 1 +// end: Beat Orthworm phase 2 void checkpoint_56( SingleSwitchProgramEnvironment& env, ProControllerContext& context, @@ -45,8 +45,8 @@ void checkpoint_56( AutoStoryStats& stats ); -// start: -// end: +// start: Beat Orthworm phase 2 +// end: At East Province (Area Three) Pokecenter. void checkpoint_57( SingleSwitchProgramEnvironment& env, ProControllerContext& context, diff --git a/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggAutonomous.cpp b/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggAutonomous.cpp index dd47a8282e..0004f9a070 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggAutonomous.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggAutonomous.cpp @@ -30,6 +30,7 @@ #include "PokemonSV/Programs/Boxes/PokemonSV_BoxRelease.h" #include "PokemonSV/Programs/Sandwiches/PokemonSV_SandwichRoutines.h" #include "PokemonSV/Programs/AutoStory/PokemonSV_MenuOption.h" +#include "PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.h" #include "PokemonSV_EggAutonomous.h" namespace PokemonAutomation{ diff --git a/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp b/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp index 2717834cc1..25e74d1024 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/Eggs/PokemonSV_EggRoutines.cpp @@ -13,6 +13,7 @@ #include "CommonTools/Async/InferenceRoutines.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" #include "Pokemon/Options/Pokemon_StatsHuntFilter.h" #include "Pokemon/Pokemon_Strings.h" #include "PokemonSV/Inference/PokemonSV_WhiteButtonDetector.h" diff --git a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_MaterialFarmerTools.cpp b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_MaterialFarmerTools.cpp index fa5caa6d70..7a50b7c745 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_MaterialFarmerTools.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/Farming/PokemonSV_MaterialFarmerTools.cpp @@ -14,6 +14,7 @@ #include "CommonFramework/Notifications/ProgramNotifications.h" #include "CommonTools/Async/InferenceRoutines.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" #include "PokemonSV/Inference/Boxes/PokemonSV_IvJudgeReader.h" #include "PokemonSV/Inference/Dialogs/PokemonSV_GradientArrowDetector.h" #include "PokemonSV/Inference/Overworld/PokemonSV_OverworldDetector.h" diff --git a/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.cpp b/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.cpp index 7156c3aaa1..884a651d1d 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.cpp @@ -16,6 +16,7 @@ #include "PokemonSV/Inference/Map/PokemonSV_MapDetector.h" #include "PokemonSV/Inference/Map/PokemonSV_MapMenuDetector.h" #include "PokemonSV/Inference/Map/PokemonSV_MapPokeCenterIconDetector.h" +#include "PokemonSV/Inference/Map/PokemonSV_FastTravelDetector.h" #include "PokemonSV/Inference/Picnics/PokemonSV_PicnicDetector.h" #include "PokemonSV/Inference/PokemonSV_MainMenuDetector.h" #include "PokemonSV/Inference/PokemonSV_ZeroGateWarpPromptDetector.h" @@ -32,6 +33,9 @@ #include #include #include +using std::cout; +using std::endl; + namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSV{ @@ -218,13 +222,200 @@ void leave_picnic(const ProgramInfo& info, VideoStream& stream, ProControllerCon context.wait_for(std::chrono::seconds(3)); } +std::string get_flypoint_string(FlyPoint fly_point){ + std::string fly_point_string; + if (fly_point == FlyPoint::POKECENTER){ + fly_point_string = "Pokecenter"; + }else if(fly_point == FlyPoint::FAST_TRAVEL){ + fly_point_string = "Fast Travel"; + } + + return fly_point_string; +} + +const std::vector get_flypoint_locations(const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, FlyPoint fly_point){ + context.wait_for_all_requests(); + std::vector found_locations; + MapPokeCenterIconWatcher pokecenter_watcher(COLOR_RED, stream.overlay(), MAP_READABLE_AREA); + FastTravelWatcher fast_travel_watcher(COLOR_RED, stream.overlay(), MAP_READABLE_AREA); + int ret = -1; + if (fly_point == FlyPoint::POKECENTER){ + ret = wait_until(stream, context, std::chrono::seconds(2), {pokecenter_watcher}); + if (ret == 0){ + found_locations = pokecenter_watcher.found_locations(); + } + }else if(fly_point == FlyPoint::FAST_TRAVEL){ + ret = wait_until(stream, context, std::chrono::seconds(2), {fast_travel_watcher}); + if (ret == 0){ + found_locations = fast_travel_watcher.found_locations(); + } + } + + return found_locations; +} + +void print_flypoint_location(const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, FlyPoint fly_point){ + std::string fly_point_string = get_flypoint_string(fly_point); + + const std::vector found_locations = get_flypoint_locations(info, stream, context, fly_point); + if (found_locations.empty()){ + stream.log("No visible " + fly_point_string + " found on map"); + return; + } + + for(const auto& box: found_locations){ + std::ostringstream os; + os << "Found " + fly_point_string + " at box: x=" << box.x << ", y=" << box.y << ", width=" << box.width << ", height=" << box.height; + stream.log(os.str()); + + } +} + + + +void place_marker_offset_from_flypoint( + const ProgramInfo& info, + VideoStream& stream, + ProControllerContext& context, + MoveCursor move_cursor_near_flypoint, + FlyPoint fly_point, + ExpectedMarkerPosition marker_offset +){ + + stream.log("place_marker_offset_from_flypoint()"); + WallClock start = current_time(); + + while (true){ + if (current_time() - start > std::chrono::minutes(5)){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "place_marker_offset_from_flypoint(): Failed to place down marker after 5 minutes.", + stream + ); + } + + try { + open_map_from_overworld(info, stream, context, false); + + // move cursor near landmark (pokecenter) + switch(move_cursor_near_flypoint.zoom_change){ + case ZoomChange::ZOOM_IN: + pbf_press_button(context, BUTTON_ZR, 20, 105); + break; + case ZoomChange::ZOOM_IN_TWICE: + pbf_press_button(context, BUTTON_ZR, 20, 105); + pbf_press_button(context, BUTTON_ZR, 20, 105); + break; + case ZoomChange::ZOOM_OUT: + pbf_press_button(context, BUTTON_ZL, 20, 105); + break; + case ZoomChange::ZOOM_OUT_TWICE: + pbf_press_button(context, BUTTON_ZL, 20, 105); + pbf_press_button(context, BUTTON_ZL, 20, 105); + break; + case ZoomChange::KEEP_ZOOM: + break; + } + uint8_t move_x1 = move_cursor_near_flypoint.move_x; + uint8_t move_y1 = move_cursor_near_flypoint.move_y; + uint16_t move_duration1 = move_cursor_near_flypoint.move_duration; + pbf_move_left_joystick(context, move_x1, move_y1, move_duration1, 1 * TICKS_PER_SECOND); + + move_cursor_to_position_offset_from_flypoint(info, stream, context, fly_point, {marker_offset.x, marker_offset.y}); + + // place down marker + pbf_press_button(context, BUTTON_A, 20, 105); + pbf_press_button(context, BUTTON_A, 20, 105); + leave_phone_to_overworld(info, stream, context); + + return; + + }catch (UnexpectedBattleException&){ + run_wild_battle_press_A(stream, context, BattleStopCondition::STOP_OVERWORLD); + }catch (OperationFailedException&){ + // reset to overworld if failed to center on the pokecenter, and re-try + leave_phone_to_overworld(info, stream, context); + } + } +} + +void move_cursor_to_position_offset_from_flypoint(const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, FlyPoint fly_point, ExpectedMarkerPosition marker_offset){ + // loop through flypoint locations. find the point that is closest to marker_offset, by distance x_diff^2 + y_diff^2 + // based on the closest point, move cursor based on x_diff and y_diff. do this again until x_diff/y_diff are within certain margins + std::string fly_point_string = get_flypoint_string(fly_point); + size_t MAX_ATTEMPTS = 20; + for (size_t i = 0; i < MAX_ATTEMPTS; i++){ + const std::vector found_locations = get_flypoint_locations(info, stream, context, fly_point); + + const double expected_x = marker_offset.x; + const double expected_y = marker_offset.y; + double closest_icon_x = 0.0; + double closest_icon_y = 0.0; + double closest_dist2 = DBL_MAX; // distance^2 in pixels + + for(const auto& box: found_locations){ + const double found_x = box.x; + const double found_y = box.y; + const double x_diff = (found_x - expected_x) * 1920; + const double y_diff = (found_y - expected_y) * 1080; + const double dist2 = x_diff * x_diff + y_diff * y_diff; + + + if (dist2 < closest_dist2){ + closest_dist2 = dist2; + closest_icon_x = found_x; + closest_icon_y = found_y; + } + } + stream.log("Found closest " + fly_point_string + " icon on map: (" + std::to_string(closest_icon_x) + ", " + std::to_string(closest_icon_y) + ")."); + + + // Convert the vector from ExpectedMarkerPosition to the FlyPoint icon into a left joystick movement + const double dif_x = (closest_icon_x - expected_x) * 1920; + const double dif_y = (closest_icon_y - expected_y) * 1080; + const double magnitude = std::max(std::sqrt(closest_dist2), 1.0); + double push_x = dif_x * 64 / magnitude; + double push_y = dif_y * 64 / magnitude; + + double scale = 0.29; + if (closest_dist2 < 1000){ // if we're already very close to the target, reduce push velocity and push duration + scale = 0.1; + push_x *= 0.25; + push_y *= 0.25; + } + + if (closest_dist2 < 5){ // if we're very very close to the target, reduce push velocity and push duration even further + push_x *= 0.5; + push_y *= 0.5; + } + + cout << "sqrt(closest_dist2): " << std::sqrt(closest_dist2) << endl; + // cout << "push_x " << push_x << endl; + // cout << "dif_x "<< dif_x << endl; + // cout << "magnitude " << magnitude << endl; + + if (std::sqrt(closest_dist2) < 0.5){ + // return when we're close enough to the target + break; + } + + const uint8_t move_x = uint8_t(std::max(std::min(int(round(push_x + 128) + 0.5), 255), 0)); + const uint8_t move_y = uint8_t(std::max(std::min(int(round(push_y + 128) + 0.5), 255), 0)); + + const uint16_t push_time = std::max(uint16_t(magnitude * scale + 0.5), uint16_t(3)); + pbf_move_left_joystick(context, move_x, move_y, push_time, 30); + context.wait_for_all_requests(); + } + +} // While in the current map zoom level, detect pokecenter icons and move the map cursor there. // Return true if succeed. Return false if no visible pokcenter on map -bool detect_closest_pokecenter_and_move_map_cursor_there( +bool detect_closest_flypoint_and_move_map_cursor_there( const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, + FlyPoint fly_point, double push_scale ){ context.wait_for_all_requests(); @@ -236,21 +427,22 @@ bool detect_closest_pokecenter_and_move_map_cursor_there( double max_dist = DBL_MAX; const double center_x = 0.5 * screen_width, center_y = 0.5 * screen_height; { - MapPokeCenterIconWatcher pokecenter_watcher(COLOR_RED, stream.overlay(), MAP_READABLE_AREA); - int ret = wait_until(stream, context, std::chrono::seconds(2), {pokecenter_watcher}); - if (ret != 0){ - stream.log("No visible pokecetner found on map"); - stream.overlay().add_log("No whole PokeCenter icon"); + std::string fly_point_string = get_flypoint_string(fly_point); + const std::vector found_locations = get_flypoint_locations(info, stream, context, fly_point); + if (found_locations.empty()){ + stream.log("No visible " + fly_point_string + " found on map"); + stream.overlay().add_log("No whole " + fly_point_string + " icon"); return false; } + // Find the detected PokeCenter icon closest to the screen center (where player character is on the map). - for(const auto& box: pokecenter_watcher.found_locations()){ + for(const auto& box: found_locations){ const double loc_x = (box.x + box.width/2) * screen_width; const double loc_y = (box.y + box.height/2) * screen_height; const double x_diff = loc_x - center_x, y_diff = loc_y - center_y; const double dist2 = x_diff * x_diff + y_diff * y_diff; std::ostringstream os; - os << "Found pokecenter at box: x=" << box.x << ", y=" << box.y << ", width=" << box.width << ", height=" << box.height << + os << "Found " + fly_point_string + " at box: x=" << box.x << ", y=" << box.y << ", width=" << box.width << ", height=" << box.height << ", dist to center " << std::sqrt(dist2) << " pixels"; stream.log(os.str()); @@ -259,8 +451,8 @@ bool detect_closest_pokecenter_and_move_map_cursor_there( closest_icon_x = loc_x; closest_icon_y = loc_y; } } - stream.log("Found closest pokecenter icon on map: (" + std::to_string(closest_icon_x) + ", " + std::to_string(closest_icon_y) + ")."); - stream.overlay().add_log("Detected PokeCenter icon"); + stream.log("Found closest " + fly_point_string + " icon on map: (" + std::to_string(closest_icon_x) + ", " + std::to_string(closest_icon_y) + ")."); + stream.overlay().add_log("Detected " + fly_point_string + " icon"); } // Convert the vector from center to the PokeCenter icon into a left joystick movement @@ -285,13 +477,14 @@ bool detect_closest_pokecenter_and_move_map_cursor_there( // While in the current map zoom level, detect pokecenter icons and fly to the closest one. // Return true if succeed. Return false if no visible pokcenter on map // Throw Operation failed Exception if detected pokecenter, but failed to fly there. -bool fly_to_visible_closest_pokecenter_cur_zoom_level( +bool fly_to_visible_closest_flypoint_cur_zoom_level( const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, + FlyPoint fly_point, double push_scale ){ - if (!detect_closest_pokecenter_and_move_map_cursor_there(info, stream, context, push_scale)){ + if (!detect_closest_flypoint_and_move_map_cursor_there(info, stream, context, fly_point, push_scale)){ return false; } bool check_fly_menuitem = true; @@ -302,7 +495,7 @@ bool fly_to_visible_closest_pokecenter_cur_zoom_level( // detected pokecenter, but failed to fly there. OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "fly_to_visible_closest_pokecenter_cur_zoom_level(): Detected pokecenter, but failed to fly there as no \"Fly\" menuitem.", + "fly_to_visible_closest_flypoint_cur_zoom_level(): Detected pokecenter, but failed to fly there as no \"Fly\" menuitem.", stream ); } @@ -327,7 +520,7 @@ void fly_to_closest_pokecenter_on_map(const ProgramInfo& info, VideoStream& stre // try different magnitudes of cursor push with each failure. double push_scale = 0.29 * adjustment_table[try_count]; // std::cout << "push_scale: " << std::to_string(push_scale) << std::endl; - if (fly_to_visible_closest_pokecenter_cur_zoom_level(info, stream, context, push_scale)){ + if (fly_to_visible_closest_flypoint_cur_zoom_level(info, stream, context, FlyPoint::POKECENTER, push_scale)){ return; // success in finding the closest pokecenter. Return. } @@ -374,7 +567,7 @@ void fly_to_closest_pokecenter_on_map(const ProgramInfo& info, VideoStream& stre double push_scale = 0.29 * adjustment_table[try_count]; // std::cout << "push_scale: " << std::to_string(push_scale) << std::endl; // Now try finding the closest pokecenter at the max warpable level - if (fly_to_visible_closest_pokecenter_cur_zoom_level(info, stream, context, push_scale)){ + if (fly_to_visible_closest_flypoint_cur_zoom_level(info, stream, context, FlyPoint::POKECENTER, push_scale)){ return; // success in finding the closest pokecenter. Return. }else{ // Does not detect any pokecenter on map @@ -662,6 +855,182 @@ void heal_at_pokecenter( } +// spam A button to choose the first move +// throw exception if wipeout or if your lead faints. +void run_battle_press_A( + VideoStream& stream, + ProControllerContext& context, + BattleStopCondition stop_condition, + std::unordered_set enum_optional_callbacks, + bool detect_wipeout +){ + int16_t num_times_seen_overworld = 0; + size_t consecutive_move_select = 0; + while (true){ + NormalBattleMenuWatcher battle(COLOR_BLUE); + SwapMenuWatcher fainted(COLOR_PURPLE); + OverworldWatcher overworld(stream.logger(), COLOR_CYAN); + AdvanceDialogWatcher dialog(COLOR_RED); + DialogArrowWatcher dialog_arrow(COLOR_RED, stream.overlay(), {0.850, 0.820, 0.020, 0.050}, 0.8365, 0.846); + GradientArrowWatcher next_pokemon(COLOR_BLUE, GradientArrowType::RIGHT, {0.50, 0.51, 0.30, 0.10}); + MoveSelectWatcher move_select_menu(COLOR_YELLOW); + + std::vector callbacks; + std::vector enum_all_callbacks; + // mandatory callbacks: Battle, Overworld, Advance Dialog, Swap menu, Move select + // optional callbacks: DIALOG_ARROW, NEXT_POKEMON + + // merge the mandatory and optional callbacks as a set, to avoid duplicates. then convert to vector + std::unordered_set enum_all_callbacks_set{CallbackEnum::BATTLE, CallbackEnum::OVERWORLD, CallbackEnum::ADVANCE_DIALOG, CallbackEnum::SWAP_MENU, CallbackEnum::MOVE_SELECT}; // mandatory callbacks + enum_all_callbacks_set.insert(enum_optional_callbacks.begin(), enum_optional_callbacks.end()); // append the mandatory and optional callback sets together + enum_all_callbacks.assign(enum_all_callbacks_set.begin(), enum_all_callbacks_set.end()); + + for (const CallbackEnum& enum_callback : enum_all_callbacks){ + switch(enum_callback){ + case CallbackEnum::ADVANCE_DIALOG: + callbacks.emplace_back(dialog); + break; + case CallbackEnum::OVERWORLD: + callbacks.emplace_back(overworld); + break; + case CallbackEnum::DIALOG_ARROW: + callbacks.emplace_back(dialog_arrow); + break; + case CallbackEnum::BATTLE: + callbacks.emplace_back(battle); + break; + case CallbackEnum::NEXT_POKEMON: // to detect the "next pokemon" prompt. + callbacks.emplace_back(next_pokemon); + break; + case CallbackEnum::SWAP_MENU: // detecting Swap Menu implies your lead fainted. + callbacks.emplace_back(fainted); + break; + case CallbackEnum::MOVE_SELECT: + callbacks.emplace_back(move_select_menu); + break; + default: + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "run_battle_press_A: Unknown callback requested."); + } + } + context.wait_for_all_requests(); + + int ret = wait_until( + stream, context, + std::chrono::seconds(90), + callbacks + ); + context.wait_for(std::chrono::milliseconds(100)); + if (ret < 0){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "run_battle_press_A(): Timed out. Did not detect expected stop condition.", + stream + ); + } + + CallbackEnum enum_callback = enum_all_callbacks[ret]; + switch (enum_callback){ + case CallbackEnum::BATTLE: // battle + stream.log("Detected battle menu."); + consecutive_move_select = 0; + pbf_press_button(context, BUTTON_A, 20, 105); + break; + case CallbackEnum::MOVE_SELECT: + stream.log("Detected move select. Spam first move"); + consecutive_move_select++; + select_top_move(stream, context, consecutive_move_select); + break; + case CallbackEnum::OVERWORLD: // overworld + stream.log("Detected overworld, battle over."); + num_times_seen_overworld++; + if (stop_condition == BattleStopCondition::STOP_OVERWORLD){ + return; + } + if(num_times_seen_overworld > 30){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "run_battle_press_A(): Stuck in overworld. Did not detect expected stop condition.", + stream + ); + } + break; + case CallbackEnum::ADVANCE_DIALOG: // advance dialog + stream.log("Detected dialog."); + + if (detect_wipeout){ + context.wait_for_all_requests(); + WipeoutDetector wipeout; + VideoSnapshot screen = stream.video().snapshot(); + // dump_snapshot(console); + if (wipeout.detect(screen)){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "run_battle_press_A(): Detected wipeout. All pokemon fainted.", + stream + ); + } + } + + if (stop_condition == BattleStopCondition::STOP_DIALOG){ + return; + } + pbf_press_button(context, BUTTON_A, 20, 105); + break; + case CallbackEnum::DIALOG_ARROW: // dialog arrow + stream.log("run_battle_press_A: Detected dialog arrow."); + pbf_press_button(context, BUTTON_A, 20, 105); + break; + case CallbackEnum::NEXT_POKEMON: + stream.log("run_battle_press_A: Detected prompt for bringing in next pokemon. Keep current pokemon."); + pbf_mash_button(context, BUTTON_B, 100); + break; + case CallbackEnum::SWAP_MENU: + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "run_battle_press_A(): Lead pokemon fainted.", + stream + ); + default: + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "run_battle_press_A: Unknown callback triggered."); + + } + } +} + +void run_trainer_battle_press_A( + VideoStream& stream, + ProControllerContext& context, + BattleStopCondition stop_condition, + std::unordered_set enum_optional_callbacks, + bool detect_wipeout +){ + enum_optional_callbacks.insert(CallbackEnum::NEXT_POKEMON); // always check for the "Next pokemon" prompt when in trainer battles + run_battle_press_A(stream, context, stop_condition, enum_optional_callbacks, detect_wipeout); +} + +void run_wild_battle_press_A( + VideoStream& stream, + ProControllerContext& context, + BattleStopCondition stop_condition, + std::unordered_set enum_optional_callbacks, + bool detect_wipeout +){ + run_battle_press_A(stream, context, stop_condition, enum_optional_callbacks, detect_wipeout); +} + + + +void select_top_move(VideoStream& stream, ProControllerContext& context, size_t consecutive_move_select){ + if (consecutive_move_select > 3){ + // to handle case where move is disabled/out of PP/taunted + stream.log("Failed to select a move 3 times. Choosing a different move.", COLOR_RED); + pbf_press_dpad(context, DPAD_DOWN, 20, 40); + } + pbf_mash_button(context, BUTTON_A, 100); + +} + + } } } diff --git a/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.h b/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.h index e858a7b71d..71e5ae2153 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.h +++ b/SerialPrograms/Source/PokemonSV/Programs/PokemonSV_WorldNavigation.h @@ -9,16 +9,70 @@ #ifndef PokemonAutomation_PokemonSV_WorldNavigation_H #define PokemonAutomation_PokemonSV_WorldNavigation_H +#include #include "CommonFramework/Tools/VideoStream.h" #include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" #include "PokemonSV/Inference/PokemonSV_MainMenuDetector.h" -#include "PokemonSV/Programs/AutoStory/PokemonSV_AutoStoryTools.h" namespace PokemonAutomation{ struct ProgramInfo; namespace NintendoSwitch{ namespace PokemonSV{ +enum class PlayerRealignMode{ + REALIGN_NEW_MARKER, + REALIGN_OLD_MARKER, + REALIGN_NO_MARKER, +}; + +enum class NavigationMovementMode{ + DIRECTIONAL_ONLY, + DIRECTIONAL_SPAM_A, + CLEAR_WITH_LETS_GO, +}; + +enum class FlyPoint{ + POKECENTER, + FAST_TRAVEL, +}; +struct ExpectedMarkerPosition{ + double x; + double y; +}; + +enum class BattleStopCondition{ + STOP_OVERWORLD, + STOP_DIALOG, +}; + +enum class CallbackEnum{ + ADVANCE_DIALOG, + OVERWORLD, + PROMPT_DIALOG, + WHITE_A_BUTTON, + DIALOG_ARROW, + BATTLE, + TUTORIAL, + BLACK_DIALOG_BOX, + NEXT_POKEMON, + SWAP_MENU, + MOVE_SELECT, +}; + +enum class ZoomChange{ + ZOOM_IN, + ZOOM_IN_TWICE, + ZOOM_OUT, + ZOOM_OUT_TWICE, + KEEP_ZOOM, +}; + +struct MoveCursor{ + ZoomChange zoom_change; + uint8_t move_x; + uint8_t move_y; + uint16_t move_duration; +}; // From map, press A to fly to a travel spot. // check_fly_menuitem == true: will detect if the "Fly" menuitem is available. Return false if no "Fly" menuitem (the game @@ -34,19 +88,28 @@ void picnic_from_overworld(const ProgramInfo& info, VideoStream& stream, ProCont // While in picnic, stop picnic and back to overworld. void leave_picnic(const ProgramInfo& info, VideoStream& stream, ProControllerContext& context); +void print_flypoint_location(const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, FlyPoint fly_point); + +void place_marker_offset_from_flypoint(const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, MoveCursor move_cursor_near_flypoint, FlyPoint fly_point, ExpectedMarkerPosition marker_offset); + +// with the map open, move the cursor to a specific position offset from the flypoint, as per marker_offset +void move_cursor_to_position_offset_from_flypoint(const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, FlyPoint fly_point, ExpectedMarkerPosition marker_offset); + // While in the current map zoom level, detect pokecenter icons and move the map cursor there. // Return true if succeed. Return false if no visible pokcenter on map -bool detect_closest_pokecenter_and_move_map_cursor_there( +bool detect_closest_flypoint_and_move_map_cursor_there( const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, + FlyPoint fly_point, double push_scale = 0.29 ); -bool fly_to_visible_closest_pokecenter_cur_zoom_level( +bool fly_to_visible_closest_flypoint_cur_zoom_level( const ProgramInfo& info, VideoStream& stream, ProControllerContext& context, + FlyPoint fly_point, double push_scale = 0.29 ); @@ -137,6 +200,31 @@ void heal_at_pokecenter( ); +// spam A button to choose the first move for trainer battles +// detect_wipeout: can be false if you have multiple pokemon in your party, since an exception will be thrown if your lead faints. +// throw exception if wipeout or if your lead faints. +void run_trainer_battle_press_A( + VideoStream& stream, + ProControllerContext& context, + BattleStopCondition stop_condition, + std::unordered_set enum_optional_callbacks = {}, + bool detect_wipeout = false +); + +// spam A button to choose the first move for wild battles +// detect_wipeout: can be false if you have multiple pokemon in your party, since an exception will be thrown if your lead faints. +// throw exception if wipeout or if your lead faints. +void run_wild_battle_press_A( + VideoStream& stream, + ProControllerContext& context, + BattleStopCondition stop_condition, + std::unordered_set enum_optional_callbacks = {}, + bool detect_wipeout = false +); + +void select_top_move(VideoStream& stream, ProControllerContext& context, size_t consecutive_move_select); + + } } }