Skip to content

Commit

Permalink
stats reset: turn 1 quickball, move table options
Browse files Browse the repository at this point in the history
  • Loading branch information
kichithewolf committed Sep 24, 2023
1 parent 81ff69e commit 696e44a
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 37 deletions.
2 changes: 2 additions & 0 deletions SerialPrograms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<BattleMoveType>& Battle_move_enum_database(){
static EnumDatabase<BattleMoveType> 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<EditableTableRow> BattleMoveTableRow::clone() const{
std::unique_ptr<BattleMoveTableRow> ret(new BattleMoveTableRow());
ret->type.set(type);
ret->notes.set(notes);
return ret;
}

BattleMoveTable::BattleMoveTable()
: EditableTableOption_t<BattleMoveTableRow>(
"<b>Move Table:</b><br>"
"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<std::string> BattleMoveTable::make_header() const{
return {
"Move",
"Notes",
};
}
std::vector<std::unique_ptr<EditableTableRow>> BattleMoveTable::make_defaults(){
std::vector<std::unique_ptr<EditableTableRow>> ret;
ret.emplace_back(new BattleMoveTableRow());
return ret;
}


}
}
}
Original file line number Diff line number Diff line change
@@ -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<BattleMoveType>& Battle_move_enum_database();

class BattleMoveTableRow : public EditableTableRow{
public:
BattleMoveTableRow();
virtual std::unique_ptr<EditableTableRow> clone() const override;

public:
EnumDropdownCell<BattleMoveType> type;
StringCell notes;
};

class BattleMoveTable : public EditableTableOption_t<BattleMoveTableRow>{
public:
BattleMoveTable();

virtual std::vector<std::string> make_header() const;
static std::vector<std::unique_ptr<EditableTableRow>> make_defaults();
};


}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ StatsReset::StatsReset()
LockWhileRunning::UNLOCKED,
"poke-ball"
)
, QUICKBALL(
"<b>Throw Quick Ball:</b><br>Use a Quick Ball on the first turn. If there are moves in the Move Table, they will run <i>after</i> 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({
Expand All @@ -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);
Expand Down Expand Up @@ -165,8 +172,12 @@ bool StatsReset::run_battle(SingleSwitchProgramEnvironment& env, BotBaseContext&

uint8_t switch_party_slot = 1;

size_t table_turn = 0;
std::vector<std::unique_ptr<BattleMoveTableRow>> 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,
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 696e44a

Please sign in to comment.