From 696e44a1e5befd7f94f3ed387b11fe0f25dd88da Mon Sep 17 00:00:00 2001 From: kichithewolf Date: Sun, 24 Sep 2023 13:25:53 -0400 Subject: [PATCH] stats reset: turn 1 quickball, move table options --- SerialPrograms/CMakeLists.txt | 2 + .../Options/PokemonSV_BattleMoveTable.cpp | 63 ++++++ .../Options/PokemonSV_BattleMoveTable.h | 50 +++++ .../Programs/General/PokemonSV_StatsReset.cpp | 183 ++++++++++++++---- .../Programs/General/PokemonSV_StatsReset.h | 3 + 5 files changed, 264 insertions(+), 37 deletions(-) create mode 100644 SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.cpp create mode 100644 SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.h diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index ec840927a..7992a67ed 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -1351,6 +1351,8 @@ file(GLOB MAIN_SOURCES Source/PokemonSV/Options/PokemonSV_AuctionItemTable.cpp Source/PokemonSV/Options/PokemonSV_AuctionItemTable.h Source/PokemonSV/Options/PokemonSV_AutoHostOptions.h + Source/PokemonSV/Options/PokemonSV_BattleMoveTable.cpp + Source/PokemonSV/Options/PokemonSV_BattleMoveTable.h Source/PokemonSV/Options/PokemonSV_EggPowerSandwichOption.cpp Source/PokemonSV/Options/PokemonSV_EggPowerSandwichOption.h Source/PokemonSV/Options/PokemonSV_EncounterActionsTable.cpp diff --git a/SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.cpp b/SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.cpp new file mode 100644 index 000000000..031eee09c --- /dev/null +++ b/SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.cpp @@ -0,0 +1,63 @@ +/* Battle Move Table + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#include "PokemonSV_BattleMoveTable.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSV{ + +const EnumDatabase& Battle_move_enum_database(){ + static EnumDatabase database{ + {BattleMoveType::Move1, "move1", "Move 1"}, + {BattleMoveType::Move2, "move2", "Move 2"}, + {BattleMoveType::Move3, "move3", "Move 3"}, + {BattleMoveType::Move4, "move4", "Move 4"}, + //{BattleMoveType::tera, "tera", "Tera"}, + }; + return database; +} + +BattleMoveTableRow::BattleMoveTableRow() + : type(Battle_move_enum_database(), LockWhileRunning::UNLOCKED, BattleMoveType::Move1) + , notes(false, LockWhileRunning::UNLOCKED, "", "(e.g. False Swipe, Thunder Wave)") +{ + PA_ADD_OPTION(type); + PA_ADD_OPTION(notes); +} +std::unique_ptr BattleMoveTableRow::clone() const{ + std::unique_ptr ret(new BattleMoveTableRow()); + ret->type.set(type); + ret->notes.set(notes); + return ret; +} + +BattleMoveTable::BattleMoveTable() + : EditableTableOption_t( + "Move Table:
" + "Run this sequence of moves for your lead Pokemon only. " + "If your lead faints or the end of the table is reached, the program will switch to throwing the selected ball. ", + LockWhileRunning::LOCKED, + make_defaults() + ) +{} + +std::vector BattleMoveTable::make_header() const{ + return { + "Move", + "Notes", + }; +} +std::vector> BattleMoveTable::make_defaults(){ + std::vector> ret; + ret.emplace_back(new BattleMoveTableRow()); + return ret; +} + + +} +} +} diff --git a/SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.h b/SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.h new file mode 100644 index 000000000..611342267 --- /dev/null +++ b/SerialPrograms/Source/PokemonSV/Options/PokemonSV_BattleMoveTable.h @@ -0,0 +1,50 @@ +/* Battle Move Table + * + * From: https://github.com/PokemonAutomation/Arduino-Source + * + */ + +#ifndef PokemonAutomation_PokemonSV_BattleMoveTable_H +#define PokemonAutomation_PokemonSV_BattleMoveTable_H + +#include "Common/Cpp/Options/SimpleIntegerOption.h" +#include "Common/Cpp/Options/StringOption.h" +#include "Common/Cpp/Options/EnumDropdownOption.h" +#include "Common/Cpp/Options/EditableTableOption.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonSV{ + + +enum class BattleMoveType{ + Move1, + Move2, + Move3, + Move4, +}; +const EnumDatabase& Battle_move_enum_database(); + +class BattleMoveTableRow : public EditableTableRow{ +public: + BattleMoveTableRow(); + virtual std::unique_ptr clone() const override; + +public: + EnumDropdownCell type; + StringCell notes; +}; + +class BattleMoveTable : public EditableTableOption_t{ +public: + BattleMoveTable(); + + virtual std::vector make_header() const; + static std::vector> make_defaults(); +}; + + +} +} +} +#endif diff --git a/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.cpp b/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.cpp index 281d436a6..7be7993ed 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.cpp @@ -91,6 +91,11 @@ StatsReset::StatsReset() LockWhileRunning::UNLOCKED, "poke-ball" ) + , QUICKBALL( + "Throw Quick Ball:
Use a Quick Ball on the first turn. If there are moves in the Move Table, they will run after the Quick Ball is thrown.", + LockWhileRunning::LOCKED, + false + ) , GO_HOME_WHEN_DONE(false) , NOTIFICATION_STATUS_UPDATE("Status Update", true, false, std::chrono::seconds(3600)) , NOTIFICATIONS({ @@ -102,6 +107,8 @@ StatsReset::StatsReset() PA_ADD_OPTION(TARGET); PA_ADD_OPTION(LANGUAGE); //This is required PA_ADD_OPTION(BALL_SELECT); + PA_ADD_OPTION(QUICKBALL); + PA_ADD_OPTION(BATTLE_MOVES); PA_ADD_OPTION(FILTERS); //Note: None of these can be shiny, and the quartet will have some perfect IVs. PA_ADD_OPTION(GO_HOME_WHEN_DONE); PA_ADD_OPTION(NOTIFICATIONS); @@ -165,8 +172,12 @@ bool StatsReset::run_battle(SingleSwitchProgramEnvironment& env, BotBaseContext& uint8_t switch_party_slot = 1; + size_t table_turn = 0; + std::vector> move_table = BATTLE_MOVES.copy_snapshot(); + bool target_fainted = false; bool out_of_balls = false; + bool quickball_thrown = false; int ret = run_until( env.console, context, @@ -190,52 +201,150 @@ bool StatsReset::run_battle(SingleSwitchProgramEnvironment& env, BotBaseContext& ); } - //Navigate to correct ball and repeatedly throw it until caught - pbf_press_button(context, BUTTON_X, 20, 100); - context.wait_for_all_requests(); - - BattleBallReader reader(env.console, LANGUAGE); - int quantity = move_to_ball(reader, env.console, context, BALL_SELECT.slug()); - if (quantity == 0) { - out_of_balls = true; - env.console.log("Unable to find appropriate ball/out of balls."); - send_program_status_notification( - env, NOTIFICATION_STATUS_UPDATE, - "Unable to find appropriate ball/out of balls." - ); - break; - } - if (quantity < 0) { - stats.errors++; + //Quick ball occurs before anything else in battle, so we can throw the ball without worrying about bounce/fainted/etc. + if (QUICKBALL && !quickball_thrown) { + env.log("Quick Ball option checked. Throwing Quick Ball."); + + pbf_press_button(context, BUTTON_X, 20, 100); + context.wait_for_all_requests(); + + BattleBallReader reader(env.console, LANGUAGE); + int quantity = move_to_ball(reader, env.console, context, "quick-ball"); + if (quantity == 0) { + //Stop so user can check they have quick balls. + env.console.log("Unable to find Quick Ball on turn 1."); + stats.errors++; + env.update_stats(); + throw OperationFailedException( + ErrorReport::SEND_ERROR_REPORT, env.console, + "Unable to find Quick Ball on turn 1.", + true + ); + } + if (quantity < 0) { + stats.errors++; + env.update_stats(); + env.console.log("Unable to read ball quantity.", COLOR_RED); + } + //Throw ball + pbf_mash_button(context, BUTTON_A, 150); + context.wait_for_all_requests(); + + quickball_thrown = true; + + stats.balls++; env.update_stats(); - env.console.log("Unable to read ball quantity.", COLOR_RED); + pbf_mash_button(context, BUTTON_B, 900); + context.wait_for_all_requests(); } - //Throw ball - pbf_mash_button(context, BUTTON_A, 150); - context.wait_for_all_requests(); + else if (switch_party_slot == 1 && !move_table.empty() && table_turn < move_table.size()) { + //Lead pokemon not fainted and table has not been completed + //Run through moves in table + env.log("Lead has not fainted, using move."); + + MoveSelectDetector move_select(COLOR_BLUE); + BattleMoveType move = move_table.at(table_turn)->type; + uint8_t move_slot = 0; + + //Leaving room to expand to other battle actions later + switch (move) { + case BattleMoveType::Move1: + move_slot = 0; + break; + case BattleMoveType::Move2: + move_slot = 1; + break; + case BattleMoveType::Move3: + move_slot = 2; + break; + case BattleMoveType::Move4: + move_slot = 3; + break; + } - //Check for battle menu - //If found after a second then assume Chi-Yu used Bounce and is invulnerable - //Use first attack this turn! - NormalBattleMenuWatcher battle_menu(COLOR_YELLOW); - int ret = wait_until( - env.console, context, - std::chrono::seconds(4), - { battle_menu } - ); - if (ret == 0) { - env.console.log("Battle menu detected early. Using first attack."); - pbf_mash_button(context, BUTTON_A, 250); + //Select and use move + pbf_press_button(context, BUTTON_A, 10, 50); + move_select.move_to_slot(env.console, context, move_slot); + pbf_press_button(context, BUTTON_A, 10, 50); + pbf_wait(context, 100); context.wait_for_all_requests(); + table_turn++; + + //Check for battle menu + //If found after a second, assume out of PP and stop as this is a setup issue + //None of the target pokemon for this program have disable, taunt, etc. + NormalBattleMenuWatcher battle_menu(COLOR_YELLOW); + int ret = wait_until( + env.console, context, + std::chrono::seconds(4), + { battle_menu } + ); + if (ret == 0) { + env.console.log("Battle menu detected early. Out of PP, please check your setup."); + stats.errors++; + env.update_stats(); + throw OperationFailedException( + ErrorReport::SEND_ERROR_REPORT, env.console, + "Battle menu detected early. Out of PP, please check your setup.", + true + ); + } + else { + env.log("Move successfully used."); + if (table_turn == move_table.size()) { + env.log("End of table reached. Switch to throwing balls."); + } + } } else { - //Wild pokemon's turn/wait for catch animation - stats.balls++; - env.update_stats(); - pbf_mash_button(context, BUTTON_B, 900); + //Navigate to correct ball and repeatedly throw it until caught + pbf_press_button(context, BUTTON_X, 20, 100); context.wait_for_all_requests(); + + BattleBallReader reader(env.console, LANGUAGE); + int quantity = move_to_ball(reader, env.console, context, BALL_SELECT.slug()); + if (quantity == 0) { + out_of_balls = true; + env.console.log("Unable to find appropriate ball/out of balls."); + send_program_status_notification( + env, NOTIFICATION_STATUS_UPDATE, + "Unable to find appropriate ball/out of balls." + ); + break; + } + if (quantity < 0) { + stats.errors++; + env.update_stats(); + env.console.log("Unable to read ball quantity.", COLOR_RED); + } + //Throw ball + pbf_mash_button(context, BUTTON_A, 150); + context.wait_for_all_requests(); + + //Check for battle menu + //If found after a second then assume Chi-Yu used Bounce and is invulnerable + //Use first attack this turn! + NormalBattleMenuWatcher battle_menu(COLOR_YELLOW); + int ret = wait_until( + env.console, context, + std::chrono::seconds(4), + { battle_menu } + ); + if (ret == 0) { + env.console.log("Battle menu detected early. Using first attack."); + pbf_mash_button(context, BUTTON_A, 250); + context.wait_for_all_requests(); + } + else { + //Wild pokemon's turn/wait for catch animation + stats.balls++; + env.update_stats(); + pbf_mash_button(context, BUTTON_B, 900); + context.wait_for_all_requests(); + } } + NormalBattleMenuWatcher battle_menu(COLOR_YELLOW); OverworldWatcher overworld(COLOR_BLUE); SwapMenuWatcher fainted(COLOR_YELLOW); int ret2 = wait_until( diff --git a/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.h b/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.h index 95cfe7afc..c017dc2e0 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.h +++ b/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsReset.h @@ -12,6 +12,7 @@ #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" #include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" #include "PokemonSwSh/Options/PokemonSwSh_BallSelectOption.h" +#include "PokemonSV/Options/PokemonSV_BattleMoveTable.h" #include "Pokemon/Options/Pokemon_StatsResetFilter.h" namespace PokemonAutomation { @@ -42,6 +43,8 @@ class StatsReset : public SingleSwitchProgramInstance { OCR::LanguageOCROption LANGUAGE; PokemonSwSh::PokemonBallSelectOption BALL_SELECT; + BooleanCheckBoxOption QUICKBALL; + BattleMoveTable BATTLE_MOVES; Pokemon::StatsResetFilterTable FILTERS; GoHomeWhenDoneOption GO_HOME_WHEN_DONE;