From b121e004a748e54fcaa2a36f13b87756e739fb43 Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 29 Aug 2025 23:54:10 -0700 Subject: [PATCH 1/5] autostory: checkpoint 50. arrive at Levincia (South) Pokecenter. --- .../PokemonSV_AutoStory_Segment_21.cpp | 3 - .../PokemonSV_AutoStory_Segment_22.cpp | 74 +++++++++++++++++-- .../PokemonSV_AutoStory_Segment_22.h | 4 +- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_21.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_21.cpp index bda462f8f6..fdb08a3b59 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_21.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_21.cpp @@ -7,11 +7,8 @@ #include "CommonTools/Async/InferenceRoutines.h" #include "CommonFramework/Exceptions/OperationFailedException.h" -#include "CommonFramework/VideoPipeline/VideoOverlay.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" #include "PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.h" -#include "PokemonSV/Programs/PokemonSV_GameEntry.h" -#include "PokemonSV/Programs/PokemonSV_SaveGame.h" #include "PokemonSV/Programs/PokemonSV_MenuNavigation.h" #include "PokemonSV/Programs/PokemonSV_WorldNavigation.h" #include "PokemonSV_AutoStoryTools.h" diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp index bf62ec7240..ddf67b3380 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp @@ -4,12 +4,11 @@ * */ +#include "PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.h" #include "CommonFramework/Exceptions/OperationFailedException.h" -#include "CommonTools/Async/InferenceRoutines.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" -#include "PokemonSV/Programs/PokemonSV_GameEntry.h" -#include "PokemonSV/Programs/PokemonSV_SaveGame.h" +#include "PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.h" #include "PokemonSV/Programs/PokemonSV_MenuNavigation.h" #include "PokemonSV/Programs/PokemonSV_WorldNavigation.h" #include "PokemonSV_AutoStoryTools.h" @@ -29,7 +28,7 @@ namespace PokemonSV{ std::string AutoStory_Segment_22::name() const{ - return "22: "; + return "22: Levincia Gym (Electric)"; } std::string AutoStory_Segment_22::start_text() const{ @@ -53,7 +52,7 @@ void AutoStory_Segment_22::run_segment( context.wait_for_all_requests(); env.console.log("Start Segment " + name(), COLOR_ORANGE); - // checkpoint_(env, context, options.notif_status_update, stats); + // checkpoint_50(env, context, options.notif_status_update, stats); context.wait_for_all_requests(); env.console.log("End Segment " + name(), COLOR_GREEN); @@ -68,6 +67,71 @@ void checkpoint_50( ){ checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ + + context.wait_for_all_requests(); + // set down marker 1 + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_NEW_MARKER, 255, 60, 50); + + DirectionDetector direction; + direction.change_direction(env.program_info(), env.console, context, 0); + pbf_move_left_joystick(context, 128, 0, 150, 100); + + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + 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, 60, 20, false); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + pbf_move_left_joystick(context, 0, 128, 128, 255); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + } + ); + + get_off_ride(env.program_info(), env.console, context); + + // marker 2 + realign_player_from_landmark( + env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 255, 50, 50}, + {ZoomChange::ZOOM_IN, 0, 100, 60} + ); + 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); + } + ); + + get_on_ride(env.program_info(), env.console, context); + + // marker 3 + realign_player_from_landmark( + env.program_info(), env.console, context, + {ZoomChange::KEEP_ZOOM, 255, 128, 20}, + {ZoomChange::ZOOM_IN, 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, 40, 10, false); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + // jump over the fence when stationary + context.wait_for_all_requests(); + pbf_controller_state(context, BUTTON_B, DPAD_NONE, 128, 0, 128, 128, 100); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_OLD_MARKER); + } + ); + + fly_to_overlapping_flypoint(env.program_info(), env.console, context); }); diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h index 887a7522bc..bdf3f362b0 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h @@ -27,8 +27,8 @@ class AutoStory_Segment_22 : public AutoStory_Segment{ }; -// start: -// end: +// start: Defeated Team Star (Fire). At East Province (Area Two) Pokecenter. +// end: At Levincia (South) Pokecenter. void checkpoint_50( SingleSwitchProgramEnvironment& env, ProControllerContext& context, From 5650aa59fdccb76de8cf724bd9dd24f4fb3f274c Mon Sep 17 00:00:00 2001 From: jw098 Date: Wed, 3 Sep 2025 20:41:31 -0700 Subject: [PATCH 2/5] Autostory: checkpoint 51: At Levincia gym building. Talked to Hassel, met Rika. --- .../AutoStory/PokemonSV_AutoStory.cpp | 17 +++++++++- .../PokemonSV_AutoStory_Segment_22.cpp | 33 ++++++++++++++++++- .../PokemonSV_AutoStory_Segment_22.h | 4 +-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp index ca28feee6c..e559f6be83 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp @@ -84,7 +84,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()); @@ -798,7 +798,22 @@ void AutoStory::test_code(SingleSwitchProgramEnvironment& env, ProControllerCont // 128, 0, 60, 10, false); DirectionDetector direction; + + // talk to receptionist + env.console.log("Talk to Levincia gym receptionist."); + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_SPAM_A, 10); + clear_dialog(env.console, context, ClearDialogMode::STOP_OVERWORLD, 60, {CallbackEnum::OVERWORLD}); + pbf_move_left_joystick(context, 128, 255, 500, 100); + pbf_wait(context, 3 * TICKS_PER_SECOND); + // wait for dialog after leaving gym + // clear_dialog(env.console, context, ClearDialogMode::STOP_OVERWORLD, 60, {CallbackEnum::OVERWORLD}); + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_SPAM_A, 20, 128, 255); + + // mash A until grey bar at top. + + // the cursor will automatically zoom in on the desired target + return; } diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp index ddf67b3380..e4cf003f2c 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp @@ -52,7 +52,9 @@ void AutoStory_Segment_22::run_segment( context.wait_for_all_requests(); env.console.log("Start Segment " + name(), COLOR_ORANGE); - // checkpoint_50(env, context, options.notif_status_update, stats); + checkpoint_50(env, context, options.notif_status_update, stats); + checkpoint_51(env, context, options.notif_status_update, stats); + checkpoint_52(env, context, options.notif_status_update, stats); context.wait_for_all_requests(); env.console.log("End Segment " + name(), COLOR_GREEN); @@ -148,6 +150,26 @@ void checkpoint_51( checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ + context.wait_for_all_requests(); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_NEW_MARKER, 0, 128, 50); + pbf_move_left_joystick(context, 128, 0, 400, 100); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_NEW_MARKER, 170, 0, 60); + pbf_move_left_joystick(context, 128, 0, 1800, 100); + realign_player(env.program_info(), env.console, context, PlayerRealignMode::REALIGN_NEW_MARKER, 255, 85, 60); + + handle_when_stationary_in_overworld(env.program_info(), env.console, context, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_ONLY, 20); + }, + [&](const ProgramInfo& info, VideoStream& stream, ProControllerContext& context){ + pbf_move_left_joystick(context, 0, 0, 100, 50); // move forward/left + }, + 5, 5 + ); + + // enter gym building. talk to Hassel, meet Rika + clear_dialog(env.console, context, ClearDialogMode::STOP_OVERWORLD, 60, {CallbackEnum::PROMPT_DIALOG, CallbackEnum::OVERWORLD}); + }); @@ -161,6 +183,15 @@ void checkpoint_52( ){ checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ + // talk to receptionist + env.console.log("Talk to Levincia gym receptionist."); + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_SPAM_A, 10); + clear_dialog(env.console, context, ClearDialogMode::STOP_OVERWORLD, 60, {CallbackEnum::OVERWORLD}); + + pbf_move_left_joystick(context, 128, 255, 500, 100); + pbf_wait(context, 3 * TICKS_PER_SECOND); + // wait for overworld after leaving gym + wait_for_overworld(env.program_info(), env.console, context, 30); }); diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h index bdf3f362b0..0b42f035e7 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h @@ -36,8 +36,8 @@ void checkpoint_50( AutoStoryStats& stats ); -// start: -// end: +// start: At Levincia (South) Pokecenter. +// end: At Levincia gym building. Talked to Hassel, met Rika. void checkpoint_51( SingleSwitchProgramEnvironment& env, ProControllerContext& context, From 8c9bfa1d791357f036b082613961552caafcc64b Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 4 Sep 2025 08:53:11 -0700 Subject: [PATCH 3/5] Autostory: checkpoint 52: Finished Levincia gym challenge. --- SerialPrograms/CMakeLists.txt | 2 + .../PokemonSV_WhiteTriangleDetector.cpp | 113 +++++++++++++++++ .../PokemonSV_WhiteTriangleDetector.h | 60 +++++++++ .../AutoStory/PokemonSV_AutoStory.cpp | 17 +-- .../PokemonSV_AutoStory_Segment_22.cpp | 117 +++++++++++++++++- .../PokemonSV_AutoStory_Segment_22.h | 4 +- 6 files changed, 295 insertions(+), 18 deletions(-) create mode 100644 SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp create mode 100644 SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.h diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index 02d1d73f4e..85c795e530 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -1710,6 +1710,8 @@ file(GLOB MAIN_SOURCES Source/PokemonSV/Inference/PokemonSV_TutorialDetector.h Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.cpp Source/PokemonSV/Inference/PokemonSV_WhiteButtonDetector.h + Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp + Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.h Source/PokemonSV/Inference/PokemonSV_ZeroGateWarpPromptDetector.cpp Source/PokemonSV/Inference/PokemonSV_ZeroGateWarpPromptDetector.h Source/PokemonSV/Inference/Tera/PokemonSV_TeraCardDetector.cpp diff --git a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp new file mode 100644 index 0000000000..1136a6d371 --- /dev/null +++ b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp @@ -0,0 +1,113 @@ +/* White Triangle Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "Common/Cpp/Containers/FixedLimitVector.tpp" +#include "CommonFramework/ImageTypes/ImageViewRGB32.h" +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonTools/Images/WaterfillUtilities.h" +#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h" +#include "Kernels/Waterfill/Kernels_Waterfill_Types.h" +#include "PokemonSV_WhiteTriangleDetector.h" + +// #include +// using std::cout; +// using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSV{ + + +class WhiteTriangleMatcher : public ImageMatch::WaterfillTemplateMatcher{ +public: + + WhiteTriangleMatcher() : WaterfillTemplateMatcher( + "PokemonSV/WhiteTriangleIcon-Template.png", Color(200,200,200), Color(255, 255, 255), 50 + ){ + m_aspect_ratio_lower = 0.8; + m_aspect_ratio_upper = 1.2; + m_area_ratio_lower = 0.9; + m_area_ratio_upper = 1.4; + + } + + static const ImageMatch::WaterfillTemplateMatcher& instance(){ + static WhiteTriangleMatcher matcher; + return matcher; + } +}; + + +WhiteTriangleDetector::~WhiteTriangleDetector() = default; + +WhiteTriangleDetector::WhiteTriangleDetector(Color color, const ImageFloatBox& box) + : m_color(color) + , m_box(box) +{} + +void WhiteTriangleDetector::make_overlays(VideoOverlaySet& items) const{ + items.add(m_color, m_box); +} + + +bool WhiteTriangleDetector::detect(const ImageViewRGB32& screen) { + const std::vector> filters = { + {combine_rgb(200, 200, 200), combine_rgb(255, 255, 255)}, + + }; + + const double rmsd_threshold = 50.0; + + const double min_object_size = 100.0; + + const double screen_rel_size = (screen.height() / 1080.0); + const size_t min_size = size_t(screen_rel_size * screen_rel_size * min_object_size); + + bool is_found = false; + + ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_box); + match_template_by_waterfill( + extract_box_reference(screen, m_box), + WhiteTriangleMatcher::instance(), + filters, + {min_size, SIZE_MAX}, + rmsd_threshold, + [&](Kernels::Waterfill::WaterfillObject& object) -> bool { + is_found = true; + return true; + } + ); + + return is_found; +} + + + +// WhiteTriangleWatcher::~WhiteTriangleWatcher() = default; + +// WhiteTriangleWatcher::WhiteTriangleWatcher(Color color, const ImageFloatBox& box) +// : VisualInferenceCallback("WhiteTriangleWatcher") +// , m_detector(color, box) +// {} + +// void WhiteTriangleWatcher::make_overlays(VideoOverlaySet& items) const{ +// m_detector.make_overlays(items); +// } + +// bool WhiteTriangleWatcher::process_frame(const ImageViewRGB32& screen, WallClock timestamp){ +// return m_detector.detect(screen); +// } + + + + + + + + +} +} +} diff --git a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.h b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.h new file mode 100644 index 0000000000..255ba808c9 --- /dev/null +++ b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.h @@ -0,0 +1,60 @@ +/* White Triangle Detector + + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonSV_WhiteTriangleDetector_H +#define PokemonAutomation_PokemonSV_WhiteTriangleDetector_H + +#include +#include "Common/Cpp/Color.h" +#include "Common/Cpp/Containers/FixedLimitVector.h" +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h" +#include "CommonTools/VisualDetector.h" + +namespace PokemonAutomation{ + +class VideoOverlaySet; +class VideoOverlay; +class OverlayBoxScope; + +namespace NintendoSwitch{ +namespace PokemonSV{ + +class WhiteTriangleDetector : public StaticScreenDetector{ +public: + WhiteTriangleDetector(Color color, const ImageFloatBox& box); + virtual ~WhiteTriangleDetector(); + + virtual void make_overlays(VideoOverlaySet& items) const override; + virtual bool detect(const ImageViewRGB32& screen) override; + +protected: + Color m_color; + ImageFloatBox m_box; +}; + + + +class WhiteTriangleWatcher : public DetectorToFinder{ +public: + WhiteTriangleWatcher( + Color color, + const ImageFloatBox& box, + std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250) + ) + : DetectorToFinder("WhiteTriangleDetector", hold_duration, color, box) + {} +}; + + + + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp index e559f6be83..b54b7465c6 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp @@ -3,6 +3,9 @@ * From: https://github.com/PokemonAutomation/ * */ +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonTools/Async/InferenceRoutines.h" + #include "CommonFramework/GlobalSettingsPanel.h" #include "CommonFramework/Notifications/ProgramNotifications.h" @@ -799,20 +802,6 @@ void AutoStory::test_code(SingleSwitchProgramEnvironment& env, ProControllerCont DirectionDetector direction; - // talk to receptionist - env.console.log("Talk to Levincia gym receptionist."); - walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_SPAM_A, 10); - clear_dialog(env.console, context, ClearDialogMode::STOP_OVERWORLD, 60, {CallbackEnum::OVERWORLD}); - - pbf_move_left_joystick(context, 128, 255, 500, 100); - pbf_wait(context, 3 * TICKS_PER_SECOND); - // wait for dialog after leaving gym - // clear_dialog(env.console, context, ClearDialogMode::STOP_OVERWORLD, 60, {CallbackEnum::OVERWORLD}); - walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_SPAM_A, 20, 128, 255); - - // mash A until grey bar at top. - - // the cursor will automatically zoom in on the desired target return; } diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp index e4cf003f2c..15a5c99dbc 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp @@ -5,6 +5,9 @@ */ #include "PokemonSV/Inference/Overworld/PokemonSV_DirectionDetector.h" +#include "PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.h" +#include "PokemonSV/Inference/Battles/PokemonSV_NormalBattleMenus.h" +#include "CommonTools/Async/InferenceRoutines.h" #include "CommonFramework/Exceptions/OperationFailedException.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" @@ -190,8 +193,118 @@ void checkpoint_52( pbf_move_left_joystick(context, 128, 255, 500, 100); pbf_wait(context, 3 * TICKS_PER_SECOND); - // wait for overworld after leaving gym - wait_for_overworld(env.program_info(), env.console, context, 30); + // wait for dialog after leaving gym + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_ONLY, 20, 128, 255); + + WhiteTriangleWatcher white_triangle(COLOR_RED, ImageFloatBox(0.948773, 0.034156, 0.013874, 0.024668)); + // mash A until detect top right white triangle 1 + int ret = run_until( + env.console, context, + [&](ProControllerContext& context){ + pbf_mash_button(context, BUTTON_A, 200000ms); + }, + {white_triangle} + ); + if (ret < 0){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to detect white triangle in top right, which is an indicator of the Levincia Hide-and-Seek gym challenge.", + env.console + ); + } + env.console.log("Detected white triangle in top right. Assume we are in the Levincia Hide-and-Seek gym challenge."); + + // select Clavell 1 + pbf_move_left_joystick(context, 255, 0, 2000ms, 480ms); + pbf_move_left_joystick(context, 10, 255, 100, 100); + pbf_mash_button(context, BUTTON_A, 1000ms); + + // mash B until detect battle 1 + NormalBattleMenuWatcher battle(COLOR_BLUE); + ret = run_until( + env.console, context, + [&](ProControllerContext& context){ + pbf_mash_button(context, BUTTON_B, 100000ms); // press B so we don't mash past the Battle menu + }, + {battle} + ); + if (ret < 0){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to detect white triangle in top right, which is an indicator of the Levincia Hide-and-Seek gym challenge.", + env.console + ); + } + + run_trainer_battle_press_A(env.console, context, BattleStopCondition::STOP_DIALOG); + + // mash B until detect top right white triangle 2 + ret = run_until( + env.console, context, + [&](ProControllerContext& context){ + pbf_mash_button(context, BUTTON_B, 100000ms); // press B so we don't accidentally select random guy + }, + {white_triangle} + ); + if (ret < 0){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to detect white triangle in top right, which is an indicator of the Levincia Hide-and-Seek gym challenge.", + env.console + ); + } + env.console.log("Detected white triangle in top right. Assume we are in the Levincia Hide-and-Seek gym challenge."); + + // select Clavell 2 + pbf_move_left_joystick(context, 0, 0, 3000ms, 480ms); + pbf_move_left_joystick(context, 255, 250, 100, 100); + pbf_mash_button(context, BUTTON_A, 1000ms); + + // mash B until detect battle 2 + ret = run_until( + env.console, context, + [&](ProControllerContext& context){ + pbf_mash_button(context, BUTTON_B, 100000ms); // press B so we don't mash past the Battle menu + // for (size_t i = 0; i < 200; i++){ + // pbf_press_button(context, BUTTON_A, 100, 100); + // } + }, + {battle} + ); + if (ret < 0){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to detect white triangle in top right, which is an indicator of the Levincia Hide-and-Seek gym challenge.", + env.console + ); + } + + run_trainer_battle_press_A(env.console, context, BattleStopCondition::STOP_DIALOG); + + // mash B until detect top right white triangle 3 + ret = run_until( + env.console, context, + [&](ProControllerContext& context){ + pbf_mash_button(context, BUTTON_B, 100000ms); + }, + {white_triangle} + ); + if (ret < 0){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "Failed to detect white triangle in top right, which is an indicator of the Levincia Hide-and-Seek gym challenge.", + env.console + ); + } + + env.console.log("Detected white triangle in top right. Assume we are in the Levincia Hide-and-Seek gym challenge."); + + // select Clavell 3 + pbf_move_left_joystick(context, 255, 0, 2000ms, 480ms); + pbf_move_left_joystick(context, 85, 255, 80, 100); + + mash_button_till_overworld(env.console, context, BUTTON_A); + }); diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h index 0b42f035e7..6cf796402c 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h @@ -46,8 +46,8 @@ void checkpoint_51( ); -// start: -// end: +// start: At Levincia gym building. Talked to Hassel, met Rika. +// end: Finished Levincia gym challenge. void checkpoint_52( SingleSwitchProgramEnvironment& env, ProControllerContext& context, From d2a1005a183bc4a57bb746ec9db48c779ec98d5f Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 4 Sep 2025 12:35:29 -0700 Subject: [PATCH 4/5] WhiteTriangleDetector: add more color filters --- .../Inference/PokemonSV_WhiteTriangleDetector.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp index 1136a6d371..dbea2213b9 100644 --- a/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp +++ b/SerialPrograms/Source/PokemonSV/Inference/PokemonSV_WhiteTriangleDetector.cpp @@ -55,7 +55,10 @@ void WhiteTriangleDetector::make_overlays(VideoOverlaySet& items) const{ bool WhiteTriangleDetector::detect(const ImageViewRGB32& screen) { const std::vector> filters = { - {combine_rgb(200, 200, 200), combine_rgb(255, 255, 255)}, + {combine_rgb(240, 240, 240), combine_rgb(255, 255, 255)}, + {combine_rgb(220, 220, 220), combine_rgb(240, 240, 240)}, + {combine_rgb(200, 200, 200), combine_rgb(220, 220, 220)}, + {combine_rgb(190, 190, 190), combine_rgb(210, 210, 210)}, }; @@ -67,8 +70,6 @@ bool WhiteTriangleDetector::detect(const ImageViewRGB32& screen) { const size_t min_size = size_t(screen_rel_size * screen_rel_size * min_object_size); bool is_found = false; - - ImagePixelBox pixel_search_area = floatbox_to_pixelbox(screen.width(), screen.height(), m_box); match_template_by_waterfill( extract_box_reference(screen, m_box), WhiteTriangleMatcher::instance(), From 5b5afd0188c21aa47920250fcbe3b66cf7bc14ef Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 4 Sep 2025 21:42:07 -0700 Subject: [PATCH 5/5] Autostory: checkpoint 53: Defeated Levincia Gym (Electric). At Levincia (North) Pokecenter. --- .../AutoStory/PokemonSV_AutoStory.cpp | 5 + .../PokemonSV_AutoStory_Segment_22.cpp | 47 +++++---- .../PokemonSV_AutoStory_Segment_22.h | 23 +---- .../PokemonSV_AutoStory_Segment_23.cpp | 97 +++++++++++++++++++ .../PokemonSV_AutoStory_Segment_23.h | 65 +++++++++++++ 5 files changed, 191 insertions(+), 46 deletions(-) diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp index b54b7465c6..21d8e1fa0d 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory.cpp @@ -641,6 +641,11 @@ void AutoStory::test_checkpoints( checkpoint_list.push_back([&](){checkpoint_53(env, context, notif_status_update, stats);}); checkpoint_list.push_back([&](){checkpoint_54(env, context, notif_status_update, stats);}); checkpoint_list.push_back([&](){checkpoint_55(env, context, notif_status_update, stats);}); + checkpoint_list.push_back([&](){checkpoint_56(env, context, notif_status_update, stats);}); + checkpoint_list.push_back([&](){checkpoint_57(env, context, notif_status_update, stats);}); + checkpoint_list.push_back([&](){checkpoint_58(env, context, notif_status_update, stats);}); + checkpoint_list.push_back([&](){checkpoint_59(env, context, notif_status_update, stats);}); + checkpoint_list.push_back([&](){checkpoint_60(env, context, notif_status_update, stats);}); for (int checkpoint = start; checkpoint <= end; checkpoint++){ diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp index 15a5c99dbc..bf8df4d11b 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.cpp @@ -39,7 +39,7 @@ std::string AutoStory_Segment_22::start_text() const{ } std::string AutoStory_Segment_22::end_text() const{ - return "End: "; + return "End: Defeated Levincia Gym (Electric). At Levincia (North) Pokecenter."; } void AutoStory_Segment_22::run_segment( @@ -58,6 +58,7 @@ void AutoStory_Segment_22::run_segment( checkpoint_50(env, context, options.notif_status_update, stats); checkpoint_51(env, context, options.notif_status_update, stats); checkpoint_52(env, context, options.notif_status_update, stats); + checkpoint_53(env, context, options.notif_status_update, stats); context.wait_for_all_requests(); env.console.log("End Segment " + name(), COLOR_GREEN); @@ -320,39 +321,35 @@ void checkpoint_53( checkpoint_reattempt_loop(env, context, notif_status_update, stats, [&](size_t attempt_number){ + // realign camera. + pbf_press_button(context, BUTTON_L, 30, 30); - }); - -} - -void checkpoint_54( - SingleSwitchProgramEnvironment& env, - ProControllerContext& context, - EventNotificationOption& notif_status_update, - AutoStoryStats& stats -){ - checkpoint_reattempt_loop(env, context, notif_status_update, stats, - [&](size_t attempt_number){ - + // walk backwards into the Gym building + pbf_move_left_joystick(context, 128, 255, 500, 100); + pbf_wait(context, 3 * TICKS_PER_SECOND); - }); + // talk to Gym receptionist + walk_forward_until_dialog(env.program_info(), env.console, context, NavigationMovementMode::DIRECTIONAL_SPAM_A, 30); -} + clear_dialog(env.console, context, ClearDialogMode::STOP_BATTLE, 60, {CallbackEnum::PROMPT_DIALOG, CallbackEnum::BATTLE, CallbackEnum::DIALOG_ARROW}); + env.console.log("Battle Electric Gym leader."); + run_trainer_battle_press_A(env.console, context, BattleStopCondition::STOP_DIALOG); + mash_button_till_overworld(env.console, context, BUTTON_A); -void checkpoint_55( - SingleSwitchProgramEnvironment& env, - ProControllerContext& context, - EventNotificationOption& notif_status_update, - AutoStoryStats& stats -){ - checkpoint_reattempt_loop(env, context, notif_status_update, stats, - [&](size_t attempt_number){ + // Gym leader defeated. Standing in Gym building + pbf_move_left_joystick(context, 128, 255, 500, 100); + pbf_wait(context, 3 * TICKS_PER_SECOND); + // wait for overworld after leaving Gym + wait_for_overworld(env.program_info(), env.console, context, 30); + // fly to Levincia (North) Pokecenter + move_cursor_towards_flypoint_and_go_there(env.program_info(), env.console, context, {ZoomChange::KEEP_ZOOM, 100, 0, 50}); - }); + }); } + } } } diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h index 6cf796402c..08bcfd5320 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_22.h @@ -56,8 +56,8 @@ void checkpoint_52( ); -// start: -// end: +// start: Finished Levincia gym challenge. Standing outside Levincia gym. +// end: Defeated Levincia Gym (Electric). At Levincia (North) Pokecenter. void checkpoint_53( SingleSwitchProgramEnvironment& env, ProControllerContext& context, @@ -66,25 +66,6 @@ void checkpoint_53( ); -// start: -// end: -void checkpoint_54( - SingleSwitchProgramEnvironment& env, - ProControllerContext& context, - EventNotificationOption& notif_status_update, - AutoStoryStats& stats -); - - -// start: -// end: -void checkpoint_55( - SingleSwitchProgramEnvironment& env, - ProControllerContext& context, - EventNotificationOption& notif_status_update, - AutoStoryStats& stats -); - 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 cf594b140d..6994d2c0b7 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.cpp @@ -59,6 +59,103 @@ void AutoStory_Segment_23::run_segment( } +void checkpoint_54( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +){ + checkpoint_reattempt_loop(env, context, notif_status_update, stats, + [&](size_t attempt_number){ + + + }); + +} + +void checkpoint_55( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +){ + checkpoint_reattempt_loop(env, context, notif_status_update, stats, + [&](size_t attempt_number){ + + + }); + +} + +void checkpoint_56( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +){ + checkpoint_reattempt_loop(env, context, notif_status_update, stats, + [&](size_t attempt_number){ + + + }); + +} + +void checkpoint_57( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +){ + checkpoint_reattempt_loop(env, context, notif_status_update, stats, + [&](size_t attempt_number){ + + + }); + +} + +void checkpoint_58( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +){ + checkpoint_reattempt_loop(env, context, notif_status_update, stats, + [&](size_t attempt_number){ + + + }); + +} + +void checkpoint_59( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +){ + checkpoint_reattempt_loop(env, context, notif_status_update, stats, + [&](size_t attempt_number){ + + + }); + +} + +void checkpoint_60( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +){ + checkpoint_reattempt_loop(env, context, notif_status_update, stats, + [&](size_t attempt_number){ + + + }); + +} diff --git a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.h b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.h index d3108fd88f..a284f144cf 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.h +++ b/SerialPrograms/Source/PokemonSV/Programs/AutoStory/PokemonSV_AutoStory_Segment_23.h @@ -27,6 +27,71 @@ class AutoStory_Segment_23 : public AutoStory_Segment{ }; +// start: +// end: +void checkpoint_54( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +); + + +// start: +// end: +void checkpoint_55( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +); + +// start: +// end: +void checkpoint_56( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +); + +// start: +// end: +void checkpoint_57( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +); + +// start: +// end: +void checkpoint_58( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +); + +// start: +// end: +void checkpoint_59( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +); + +// start: +// end: +void checkpoint_60( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context, + EventNotificationOption& notif_status_update, + AutoStoryStats& stats +); + + }