Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8711f8a
Updated draft
Boombaastical Feb 20, 2026
f581b9c
Updated draft for adding saved paths on the go
Boombaastical Feb 21, 2026
6f35536
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGoo
Boombaastical Feb 23, 2026
fc7c2aa
Updated draft
Boombaastical Feb 23, 2026
5054e92
Added more draft changes
Boombaastical Feb 24, 2026
d12f770
Updated draft, now working logic but needs UI
Boombaastical Feb 24, 2026
846247e
Finalizing the save-on-the-go feature for MaxLair, missing the screen…
Boombaastical Feb 24, 2026
4bbfe56
Draft: updated some other fixes
Boombaastical Feb 24, 2026
401a3fe
Tweaked things a bit
Boombaastical Feb 25, 2026
19b9e3a
Saved other changes
Boombaastical Feb 26, 2026
10e5b1d
Fixed logic
Boombaastical Feb 26, 2026
8dc8317
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Feb 27, 2026
12aa9f5
Finalized logic, testing
Boombaastical Feb 27, 2026
8f2e4fd
Finalized implementation of the save-on-the-go option
Boombaastical Feb 27, 2026
d49935a
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Feb 27, 2026
22d051e
Reverted non-necessary additions
Boombaastical Feb 28, 2026
3641b06
Reverted unnecessary additions 2
Boombaastical Feb 28, 2026
1e57d55
Reverted unnecessary additions 3
Boombaastical Feb 28, 2026
d5da4be
Fixed formatting issues
Boombaastical Mar 1, 2026
4d3a748
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Mar 1, 2026
b2d7bc2
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Mar 2, 2026
b737770
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Mar 12, 2026
f3aa742
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Mar 14, 2026
8e36969
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Mar 15, 2026
0c064d4
Updated with new changes: draft
Boombaastical Mar 15, 2026
1b4b771
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Mar 18, 2026
f9e37ff
Reverted some changes to make it stop on list full and allowing multi…
Boombaastical Mar 18, 2026
4be214b
Formatting
Boombaastical Mar 18, 2026
7e76516
Formatting
Boombaastical Mar 18, 2026
5419a14
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Mar 29, 2026
17f94d2
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical Apr 21, 2026
4bde801
Merge branch 'main' into pr/1101
Mysticial Apr 25, 2026
b866fb6
minor
Mysticial Apr 25, 2026
67dc4bf
Merge branch 'MaxLair/AddedSaveOnTheGo' of https://github.com/Boombaa…
Mysticial Apr 25, 2026
4a99113
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical May 4, 2026
3cadbe3
Updated with new markers, testing...
Boombaastical May 4, 2026
0e3507d
Initial changes to the Save on the Go feature using SelectionArrowFinder
Boombaastical May 5, 2026
2d51c90
Updated with current changes
Boombaastical May 5, 2026
730a69e
Merge remote-tracking branch 'upstream' into MaxLair/AddedSaveOnTheGo
Boombaastical May 5, 2026
57df819
Removed dev mode
Boombaastical May 5, 2026
76c1f23
Merge branch 'main' into pr/1101
Mysticial May 9, 2026
7ab3d61
Merge branch 'main' into pr/1101
Mysticial May 9, 2026
b716e8a
Minor cleanup.
Mysticial May 9, 2026
43c0544
Merge branch 'main' into pr/1101
Mysticial May 9, 2026
56b545e
Merge branch 'main' into pr/1101
Mysticial May 9, 2026
d65389b
Merge branch 'main' into pr/1101
Mysticial May 10, 2026
1e81733
Fix major scheduling in PABB2. Undo timing recent timing adjustments.
Mysticial May 10, 2026
6175bbf
Merge branch 'main' into pr/1101
Mysticial May 10, 2026
c2bd099
Merge branch 'main' into pr/1101
Mysticial May 10, 2026
a6457f2
minor
Mysticial May 10, 2026
41d52f6
Merge branch 'main' into pr/1101
Mysticial May 12, 2026
8f5afe9
Add alternate implementation using state machine.
Mysticial May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class EndBattleDecider{
const PathStats& path_stats,
bool any_shiny, bool boss_is_shiny
) const = 0;

// For BossFinder: whether the boss is in the "save on the go" list.
virtual bool is_in_save_list(const std::string& boss_slug) const { return false; }
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
*
*/

#include <vector>
#include <memory>
//#include "Common/Compiler.h"
//#include "Common/Cpp/Json/JsonValue.h"
//#include "Common/Cpp/Json/JsonArray.h"
//#include "Common/Cpp/Json/JsonObject.h"
#include "Common/Cpp/Options/BooleanCheckBoxOption.h"
#include "Common/Cpp/Options/ConfigOption.h"
//#include "CommonFramework/Globals.h"
#include "Pokemon/Pokemon_Strings.h"
#include "Pokemon/Resources/Pokemon_PokemonNames.h"
Expand Down Expand Up @@ -49,10 +53,28 @@ BossActionRow::BossActionRow(std::string slug, const std::string& name_slug, con
BossAction::CATCH_AND_STOP_IF_SHINY
)
, ball(LockMode::UNLOCK_WHILE_RUNNING, "poke-ball")
, save_on_the_go(LockMode::UNLOCK_WHILE_RUNNING, false)
{
PA_ADD_STATIC(pokemon);
add_option(action, "Action");
add_option(ball, "Ball");
add_option(save_on_the_go, "Save Path");

BossActionRow::on_config_value_changed(nullptr);

action.add_listener(*this);
}

void BossActionRow::on_config_value_changed(void* object){
switch (action){
case BossAction::CATCH_AND_STOP_PROGRAM:
save_on_the_go = false;
save_on_the_go.set_visibility(ConfigOptionState::DISABLED);
break;
case BossAction::CATCH_AND_STOP_IF_SHINY:
save_on_the_go.set_visibility(ConfigOptionState::ENABLED);
break;
}
}


Expand All @@ -72,7 +94,8 @@ std::vector<std::string> BossActionTable::make_header() const{
std::vector<std::string> ret{
STRING_POKEMON,
"Action",
STRING_POKEBALL
STRING_POKEBALL,
"Save Path"
};
return ret;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#ifndef PokemonAutomation_PokemonSwSh_MaxLair_Options_BossAction_H
#define PokemonAutomation_PokemonSwSh_MaxLair_Options_BossAction_H

#include <vector>
#include "Common/Cpp/Options/BooleanCheckBoxOption.h"
#include "Common/Cpp/Options/EnumDropdownOption.h"
#include "Common/Cpp/Options/StaticTableOption.h"
#include "CommonFramework/Options/LabelCellOption.h"
Expand All @@ -24,19 +26,21 @@ enum class BossAction{
};


class BossActionRow : public StaticTableRow{
class BossActionRow : public StaticTableRow, private ConfigOption::Listener{
public:
BossActionRow(std::string slug, const std::string& name_slug, const std::string& sprite_slug);
virtual void on_config_value_changed(void* object) override;

LabelCellOption pokemon;
EnumDropdownCell<BossAction> action;
PokemonBallSelectCell ball;
BooleanCheckBoxCell save_on_the_go;
};

class BossActionTable : public StaticTableOption{
public:
BossActionTable();
virtual std::vector<std::string> make_header() const;
virtual std::vector<std::string> make_header() const override;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ class EndBattleDecider_BossFinder : public EndBattleDecider{
}
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid enum.");
}
virtual bool is_in_save_list(const std::string& boss_slug) const override{
return get_filter(boss_slug).save_on_the_go;
}


private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@
*
*/

#include "CommonFramework/Exceptions/OperationFailedException.h"
#include "CommonFramework/Notifications/ProgramNotifications.h"
#include "CommonFramework/VideoPipeline/VideoFeed.h"
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "CommonTools/Images/SolidColorTest.h"
#include "CommonTools/Async/InferenceRoutines.h"
#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
#include "Pokemon/Resources/Pokemon_PokemonNames.h"
#include "PokemonSwSh/Inference/PokemonSwSh_SelectionArrowFinder.h"
#include "PokemonSwSh/Inference/PokemonSwSh_DialogBoxDetector.h"
#include "PokemonSwSh/Inference/PokemonSwSh_YCommDetector.h"
#include "PokemonSwSh_MaxLair_Run_Entrance.h"

namespace PokemonAutomation{
Expand All @@ -20,7 +27,7 @@ void run_entrance(
AdventureRuntime& runtime,
ProgramEnvironment& env, size_t console_index,
VideoStream& stream, ProControllerContext& context,
bool save_path,
bool followed_path,
GlobalStateTracker& state_tracker
){
GlobalState& state = state_tracker[console_index];
Expand All @@ -36,24 +43,175 @@ void run_entrance(
}
}

context.wait_for(1000ms);

OverlayBoxScope box(stream.overlay(), {0.782, 0.850, 0.030, 0.050});
// Get the boss slug
std::string boss_slug;
if (runtime.host_index < runtime.console_settings.active_consoles()){
boss_slug = state_tracker.infer_actual_state(runtime.host_index).boss;
};

bool save_path = false;

if (!followed_path){
// Check if the user checked the box to save the path when running the BossFinder program

if (!boss_slug.empty()){
save_path = runtime.actions.is_in_save_list(boss_slug);
stream.log("Boss: " + boss_slug + ", should save: " + (save_path ? "Yes" : "No"), COLOR_BLUE);
}
}else{
save_path = followed_path;
}


#if 1
bool has_seen_yesno = false;
while (true){
WhiteDialogBoxWatcher dialog;
SelectionArrowFinder arrow(stream.overlay(), {0.462377, 0.332039, 0.388222, 0.640777});
YCommIconWatcher overworld;

context.wait_for_all_requests();
context.wait_for(100ms);

int ret = wait_until(
stream, context,
std::chrono::seconds(10),
{
dialog,
arrow,
overworld,
}
);
switch (ret){
case 0:
stream.log("Detected dialog menu.");
pbf_press_button(context, BUTTON_B, 80ms, 160ms);
continue;
case 1:{
stream.log("Detected arrow.");
if (!save_path){
pbf_press_button(context, BUTTON_B, 80ms, 160ms);
continue;
}
if (!has_seen_yesno){
has_seen_yesno = true;
pbf_press_button(context, BUTTON_A, 80ms, 160ms);
continue;
}
const std::vector<ImageFloatBox>& arrows = arrow.last_detection();
if (arrows.empty()){
continue;
}
if (arrows[0].y < 0.56){
// List of bosses is full, stop the program
stream.log("Cannot save path – saved list is full. Stopping program.", COLOR_RED);
OperationFailedException::fire(
ErrorReport::NO_ERROR_REPORT,
"Paths list is full. Program stopped.",
stream
);
}
continue;
}
case 2:
stream.log("Detected overworld.");
return;
default:
throw OperationFailedException(
ErrorReport::SEND_ERROR_REPORT,
"No recognized state after 10 seconds.",
stream
);
}
}

#else
// Selection arrow in the path-list area — present when the "list is full / replace?" dialog is active
SelectionArrowFinder top_region(stream.overlay(), {0.63, 0.50, 0.22, 0.10});
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing this today. One concern I have about this line is that the length varies depending on the language.

I'm actually working on a different way to write this loop that's more consistent with the newer programs. (you might have noticed that I've pushed some SwSh detector stuff to main) So I'll probably push a few things to this branch later.


// Selection arrow in the Yes/No area — present when the "save this path?" dialog is active
SelectionArrowFinder yes_no_arrow(stream.overlay(), {0.63, 0.60, 0.22, 0.19});

// White text check for the path-list entries — confirms the "list full" dialog
OverlayBoxScope paths_box(stream.overlay(), {0.685, 0.515, 0.13, 0.013});

pbf_wait(context, 2000ms);
// Grey dialog box — used to detect that any NPC dialog is still on screen
OverlayBoxScope dialog_box(stream.overlay(), {0.78, 0.85, 0.03, 0.05});

// Timeout: 5 minutes
auto start_time = std::chrono::steady_clock::now();
const auto timeout = std::chrono::minutes(5);

while (true){
if (save_path){
pbf_press_button(context, BUTTON_A, 160ms, 1000ms);
}else{
pbf_press_button(context, BUTTON_B, 160ms, 1000ms);
auto now = std::chrono::steady_clock::now();
if (now - start_time > timeout){
stream.log("Entrance dialogue timed out after 5 minutes.", COLOR_RED);
throw OperationFailedException(ErrorReport::SEND_ERROR_REPORT, "Entrance dialogue timed out.", stream);
}

context.wait_for_all_requests();

context.wait_for(1000ms);
VideoSnapshot screen = stream.video().snapshot();
ImageStats stats = image_stats(extract_box_reference(screen, box));
if (!is_grey(stats, 400, 1000)){
break;
if (!screen) continue;

bool top_arrow_found = top_region.detect(screen);
bool bottom_arrow_found = yes_no_arrow.detect(screen);

ImageStats paths_box_stats = image_stats(extract_box_reference(screen, paths_box));
bool paths_box_present = is_white(paths_box_stats, 400, 10);
Comment thread
Mysticial marked this conversation as resolved.
Comment thread
Mysticial marked this conversation as resolved.

ImageStats dialog_box_stats = image_stats(extract_box_reference(screen, dialog_box));
bool dialog_box_present = is_grey(dialog_box_stats, 400, 1000);

if (top_arrow_found && paths_box_present){

if (save_path){
// List of bosses is full, stop the program
stream.log("Cannot save path – saved list is full. Stopping program.", COLOR_RED);
OperationFailedException::fire(
ErrorReport::NO_ERROR_REPORT,
"Paths list is full. Program stopped.",
stream
);

}else{
stream.log("Not saving path");
pbf_press_button(context, BUTTON_B, 160ms, 1000ms);
}

}else if (bottom_arrow_found){

if (save_path){
if (followed_path){
stream.log("Keeping old path.");
pbf_press_button(context, BUTTON_A, 160ms, 1000ms);
}else{
std::string display_name = get_pokemon_name(boss_slug).display_name();
stream.log("Saving new path");
pbf_press_button(context, BUTTON_A, 160ms, 1000ms);
send_program_notification(
env,
runtime.notification_status,
COLOR_BLUE,
"Path Saved",
{{"Boss: ", display_name}},
""
);
}
}else{
stream.log("Not saving new path");
pbf_press_button(context, BUTTON_B, 160ms, 1000ms);
}
}else if (!dialog_box_present){
return;
}

pbf_press_button(context, BUTTON_A, 160ms, 1000ms);
}
#endif
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void run_entrance(
AdventureRuntime& runtime,
ProgramEnvironment& env, size_t console_index,
VideoStream& stream, ProControllerContext& context,
bool save_path,
bool followed_path,
GlobalStateTracker& state_tracker
);

Expand Down
Loading