From 385c1b2905e0f3fea59249c52b8b5b1e0003a3c2 Mon Sep 17 00:00:00 2001 From: Mysticial Date: Mon, 2 Oct 2023 21:49:47 -0700 Subject: [PATCH] IV Range Filter update for Ursaluna. --- .../Source/CommonFramework/Globals.cpp | 4 +- .../Options/Pokemon_StatsHuntFilter.cpp | 182 ++++++++++---- .../Pokemon/Options/Pokemon_StatsHuntFilter.h | 31 ++- .../Eggs/PokemonBDSP_EggAutonomousState.cpp | 2 +- .../Boxes/PokemonSV_StatsResetChecker.cpp | 2 +- .../Programs/Eggs/PokemonSV_EggRoutines.cpp | 2 +- .../General/PokemonSV_StatsResetBloodmoon.cpp | 230 ++++++++++++++---- .../General/PokemonSV_StatsResetBloodmoon.h | 26 +- .../PokemonSV_ShinyHunt-AreaZeroPlatform.cpp | 2 +- .../EggPrograms/PokemonSwSh_EggAutonomous.cpp | 2 +- 10 files changed, 355 insertions(+), 128 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/Globals.cpp b/SerialPrograms/Source/CommonFramework/Globals.cpp index 76cf543f7..3136188f2 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.cpp +++ b/SerialPrograms/Source/CommonFramework/Globals.cpp @@ -22,8 +22,8 @@ namespace PokemonAutomation{ const bool IS_BETA_VERSION = true; const int PROGRAM_VERSION_MAJOR = 0; -const int PROGRAM_VERSION_MINOR = 41; -const int PROGRAM_VERSION_PATCH = 8; +const int PROGRAM_VERSION_MINOR = 42; +const int PROGRAM_VERSION_PATCH = 1; const std::string PROGRAM_VERSION_BASE = "v" + std::to_string(PROGRAM_VERSION_MAJOR) + diff --git a/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.cpp b/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.cpp index 0ae0dd569..010c11ffe 100644 --- a/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.cpp +++ b/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.cpp @@ -26,7 +26,7 @@ std::string gender_to_string(StatsHuntGenderFilter gender){ } -const EnumDatabase& EggHatchAction_Database(){ +const EnumDatabase& StatsHuntAction_Database(){ static const EnumDatabase database({ {StatsHuntAction::StopProgram, "stop", "Stop Program"}, {StatsHuntAction::Keep, "keep", "Keep"}, @@ -34,7 +34,7 @@ const EnumDatabase& EggHatchAction_Database(){ }); return database; } -const EnumDatabase& EggHatchShinyFilter_Database(){ +const EnumDatabase& StatsHuntShinyFilter_Database(){ static const EnumDatabase database({ {StatsHuntShinyFilter::Anything, "anything", "Anything"}, {StatsHuntShinyFilter::NotShiny, "not-shiny", "Not Shiny"}, @@ -42,7 +42,7 @@ const EnumDatabase& EggHatchShinyFilter_Database(){ }); return database; } -const EnumDatabase& EggHatchGenderFilter_Database(){ +const EnumDatabase& StatsHuntGenderFilter_Database(){ static const EnumDatabase database({ {StatsHuntGenderFilter::Any, "any", "Any"}, {StatsHuntGenderFilter::Male, "male", "Male"}, @@ -74,10 +74,16 @@ const char* StatsHuntIvJudgeFilterTable_Label_Regular = StatsHuntRowMisc::StatsHuntRowMisc(const StatsHuntMiscFeatureFlags& p_feature_flags) : feature_flags(p_feature_flags) - , action(EggHatchAction_Database(), LockMode::LOCK_WHILE_RUNNING, StatsHuntAction::Keep) - , shiny(EggHatchShinyFilter_Database(), LockMode::LOCK_WHILE_RUNNING, StatsHuntShinyFilter::Anything) - , gender(EggHatchGenderFilter_Database(), LockMode::LOCK_WHILE_RUNNING, StatsHuntGenderFilter::Any) - , nature(NatureCheckerFilter_Database(), LockMode::LOCK_WHILE_RUNNING, NatureCheckerFilter::Any) + , action( + StatsHuntAction_Database(), + LockMode::UNLOCK_WHILE_RUNNING, + feature_flags.action + ? StatsHuntAction::Keep + : StatsHuntAction::StopProgram + ) + , shiny(StatsHuntShinyFilter_Database(), LockMode::UNLOCK_WHILE_RUNNING, StatsHuntShinyFilter::Anything) + , gender(StatsHuntGenderFilter_Database(), LockMode::UNLOCK_WHILE_RUNNING, StatsHuntGenderFilter::Any) + , nature(NatureCheckerFilter_Database(), LockMode::UNLOCK_WHILE_RUNNING, NatureCheckerFilter::Any) {} void StatsHuntRowMisc::set(const StatsHuntRowMisc& x){ action.set(x.action); @@ -85,6 +91,38 @@ void StatsHuntRowMisc::set(const StatsHuntRowMisc& x){ gender.set(x.gender); nature.set(x.nature); } +bool StatsHuntRowMisc::matches( + bool shiny, + StatsHuntGenderFilter gender, + NatureCheckerValue nature +) const{ + // Check the shiny filter. + switch (this->shiny){ + case StatsHuntShinyFilter::Anything: + break; + case StatsHuntShinyFilter::NotShiny: + if (shiny){ + return false; + } + break; + case StatsHuntShinyFilter::Shiny: + if (!shiny){ + return false; + } + break; + } + + StatsHuntGenderFilter filter_gender = this->gender; + if (filter_gender != gender && filter_gender != StatsHuntGenderFilter::Any){ + return false; + } + + if (!NatureChecker_filter_match(this->nature, nature)){ + return false; + } + + return true; +} StatsHuntIvJudgeFilterRow::StatsHuntIvJudgeFilterRow(const StatsHuntMiscFeatureFlags& feature_flags) @@ -128,24 +166,12 @@ std::unique_ptr StatsHuntIvJudgeFilterRow::clone() const{ } bool StatsHuntIvJudgeFilterRow::matches( bool shiny, - const IvJudgeReader::Results& IVs, StatsHuntGenderFilter gender, - NatureReader::Results nature + NatureCheckerValue nature, + const IvJudgeReader::Results& IVs ) const{ - // Check the shiny filter. - switch (misc.shiny){ - case StatsHuntShinyFilter::Anything: - break; - case StatsHuntShinyFilter::NotShiny: - if (shiny){ - return false; - } - break; - case StatsHuntShinyFilter::Shiny: - if (!shiny){ - return false; - } - break; + if (!misc.matches(shiny, gender, nature)){ + return false; } // Check all the IV filters. @@ -156,15 +182,6 @@ bool StatsHuntIvJudgeFilterRow::matches( if (!IvJudge_filter_match(iv_spdef, IVs.spdef)) return false; if (!IvJudge_filter_match(iv_speed, IVs.speed)) return false; - StatsHuntGenderFilter filter_gender = misc.gender; - if (filter_gender != gender && filter_gender != StatsHuntGenderFilter::Any){ - return false; - } - - if (!NatureChecker_filter_match(misc.nature, nature.nature)){ - return false; - } - return true; } @@ -172,7 +189,7 @@ StatsHuntIvJudgeFilterTable::StatsHuntIvJudgeFilterTable( const std::string& label, const StatsHuntMiscFeatureFlags& p_feature_flags ) - : EditableTableOption_t(label, LockMode::LOCK_WHILE_RUNNING) + : EditableTableOption_t(label, LockMode::UNLOCK_WHILE_RUNNING) , feature_flags(p_feature_flags) { set_default(make_defaults()); @@ -210,16 +227,16 @@ std::vector> StatsHuntIvJudgeFilterTable::make } StatsHuntAction StatsHuntIvJudgeFilterTable::get_action( bool shiny, - const IvJudgeReader::Results& IVs, StatsHuntGenderFilter gender, - NatureReader::Results nature + NatureCheckerValue nature, + const IvJudgeReader::Results& IVs ) const{ StatsHuntAction action = StatsHuntAction::Discard; std::vector> list = copy_snapshot(); for (size_t c = 0; c < list.size(); c++){ const StatsHuntIvJudgeFilterRow& filter = *list[c]; - if (!filter.matches(shiny, IVs, gender, nature)){ + if (!filter.matches(shiny, gender, nature, IVs)){ continue; } @@ -243,6 +260,14 @@ StatsHuntAction StatsHuntIvJudgeFilterTable::get_action( + +const char* StatsHuntIvRangeFilterTable_Label_Regular = + "Stop Conditions:
" + "If the Pok\u00e9mon matches one of these filters, the program will stop.
" + "Partially overlapping IV ranges will count as a match. So if a filter is for 0-1, but the IV calculation returns a range 1-2, it will count."; + + + StatsHuntIvRangeFilterRow::StatsHuntIvRangeFilterRow(const StatsHuntMiscFeatureFlags& feature_flags) : misc(feature_flags) , iv_hp(LockMode::UNLOCK_WHILE_RUNNING, 0, 31, 0, 0, 0, 31, 31, 31) @@ -277,12 +302,49 @@ std::unique_ptr StatsHuntIvRangeFilterRow::clone() const{ ret->iv_speed.set(iv_speed); return ret; } +bool StatsHuntIvRangeFilterRow::match_iv(const IvRange& desired, const IvRange& actual){ + if (desired.low == 0 && desired.high == 31){ + return true; + } + if (actual.high < desired.low){ + return false; + } + if (desired.high < actual.low){ + return false; + } + return true; +} +bool StatsHuntIvRangeFilterRow::match_iv(const IntegerRangeCell& desired, const IvRange& actual){ + uint8_t lo, hi; + desired.current_values(lo, hi); + return match_iv(IvRange{(int8_t)lo, (int8_t)hi}, actual); +} +bool StatsHuntIvRangeFilterRow::matches( + bool shiny, + StatsHuntGenderFilter gender, + NatureCheckerValue nature, + const IvRanges& IVs +) const{ + if (!misc.matches(shiny, gender, nature)){ + return false; + } + + if (!match_iv(iv_hp, IVs.hp)) return false; + if (!match_iv(iv_atk, IVs.attack)) return false; + if (!match_iv(iv_def, IVs.defense)) return false; + if (!match_iv(iv_spatk, IVs.spatk)) return false; + if (!match_iv(iv_spdef, IVs.spdef)) return false; + if (!match_iv(iv_speed, IVs.speed)) return false; + + return true; +} + StatsHuntIvRangeFilterTable::StatsHuntIvRangeFilterTable( const std::string& label, const StatsHuntMiscFeatureFlags& p_feature_flags ) - : EditableTableOption_t(label, LockMode::LOCK_WHILE_RUNNING) + : EditableTableOption_t(label, LockMode::UNLOCK_WHILE_RUNNING) , feature_flags(p_feature_flags) { // set_default(make_defaults()); @@ -302,30 +364,46 @@ std::vector StatsHuntIvRangeFilterTable::make_header() const{ ret.emplace_back("Nature"); } -#if 1 ret.emplace_back("HP"); ret.emplace_back("Atk"); ret.emplace_back("Def"); ret.emplace_back("SpAtk"); ret.emplace_back("SpDef"); ret.emplace_back("Spd"); -#else - ret.emplace_back("HP (low)"); - ret.emplace_back("HP (high)"); - ret.emplace_back("Atk (low)"); - ret.emplace_back("Atk (high)"); - ret.emplace_back("Def (low)"); - ret.emplace_back("Def (high)"); - ret.emplace_back("SpAtk (low)"); - ret.emplace_back("SpAtk (high)"); - ret.emplace_back("SpDef (low)"); - ret.emplace_back("SpDef (high)"); - ret.emplace_back("Spd (low)"); - ret.emplace_back("Spd (high)"); -#endif return ret; } +StatsHuntAction StatsHuntIvRangeFilterTable::get_action( + bool shiny, + StatsHuntGenderFilter gender, + NatureCheckerValue nature, + const IvRanges& IVs +) const{ + StatsHuntAction action = StatsHuntAction::Discard; + std::vector> list = copy_snapshot(); + for (size_t c = 0; c < list.size(); c++){ + const StatsHuntIvRangeFilterRow& filter = *list[c]; + + if (!filter.matches(shiny, gender, nature, IVs)){ + continue; + } + + StatsHuntAction filter_action = filter.misc.action; + + // No action matched so far. Take the current action and continue. + if (action == StatsHuntAction::Discard){ + action = filter_action; + continue; + } + + // Conflicting actions. + if (action != filter_action){ + global_logger_tagged().log("Multiple filters matched with conflicting actions. Stopping program...", COLOR_RED); + return StatsHuntAction::StopProgram; + } + } + return action; +} diff --git a/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.h b/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.h index 2eddbf363..3f38c8093 100644 --- a/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.h +++ b/SerialPrograms/Source/Pokemon/Options/Pokemon_StatsHuntFilter.h @@ -61,6 +61,12 @@ struct StatsHuntRowMisc{ StatsHuntRowMisc(const StatsHuntMiscFeatureFlags& p_feature_flags); void set(const StatsHuntRowMisc& x); + bool matches( + bool shiny, + StatsHuntGenderFilter gender, + NatureCheckerValue nature + ) const; + const StatsHuntMiscFeatureFlags& feature_flags; EnumDropdownCell action; @@ -82,9 +88,9 @@ class StatsHuntIvJudgeFilterRow : public EditableTableRow{ bool matches( bool shiny, - const IvJudgeReader::Results& IVs, StatsHuntGenderFilter gender, - NatureReader::Results nature + NatureCheckerValue nature, + const IvJudgeReader::Results& IVs ) const; public: @@ -108,9 +114,9 @@ class StatsHuntIvJudgeFilterTable : public EditableTableOption_t& desired, const IvRange& actual); + public: StatsHuntRowMisc misc; @@ -158,9 +173,9 @@ class StatsHuntIvRangeFilterTable : public EditableTableOption_tHP:", LockMode::READ_ONLY, "-", "") + , atk(false, "Attack:", LockMode::READ_ONLY, "-", "") + , def(false, "Defense:", LockMode::READ_ONLY, "-", "") + , spatk(false, "Special Attack:", LockMode::READ_ONLY, "-", "") + , spdef(false, "Special Defense:", LockMode::READ_ONLY, "-", "") + , speed(false, "Speed:", LockMode::READ_ONLY, "-", "") +{ + PA_ADD_STATIC(hp); + PA_ADD_STATIC(atk); + PA_ADD_STATIC(def); + PA_ADD_STATIC(spatk); + PA_ADD_STATIC(spdef); + PA_ADD_STATIC(speed); +} +std::string IvDisplay::get_range_string(const IvRange& range){ + if (range.low < 0 || range.high < 0){ + return "(invalid or unable to read)"; + } + if (range.low == range.high){ + return std::to_string(range.low); + } + return std::to_string(range.low) + " - " + std::to_string(range.high); +} +void IvDisplay::set(const IvRanges& ivs){ + hp.set(get_range_string(ivs.hp)); + atk.set(get_range_string(ivs.attack)); + def.set(get_range_string(ivs.defense)); + spatk.set(get_range_string(ivs.spatk)); + spdef.set(get_range_string(ivs.spdef)); + speed.set(get_range_string(ivs.speed)); +} + + StatsResetBloodmoon_Descriptor::StatsResetBloodmoon_Descriptor() : SingleSwitchProgramDescriptor( "PokemonSV:StatsResetBloodmoon", @@ -81,6 +120,7 @@ StatsResetBloodmoon::StatsResetBloodmoon() LockMode::UNLOCK_WHILE_RUNNING, false ) +#if 0 , FILTERS( StatsHuntIvJudgeFilterTable_Label_Regular, { @@ -90,8 +130,9 @@ StatsResetBloodmoon::StatsResetBloodmoon() .nature = false, } ) +#endif , FILTERS0( - StatsHuntIvJudgeFilterTable_Label_Regular, + StatsHuntIvRangeFilterTable_Label_Regular, { .action = false, .shiny = false, @@ -107,6 +148,7 @@ StatsResetBloodmoon::StatsResetBloodmoon() & NOTIFICATION_ERROR_FATAL, }) { +#if 0 { std::vector> ret; { @@ -121,27 +163,31 @@ StatsResetBloodmoon::StatsResetBloodmoon() } FILTERS.set_default(std::move(ret)); } +#endif { std::vector> ret; { - auto row = std::make_unique(FILTERS.feature_flags); + auto row = std::make_unique(FILTERS0.feature_flags); row->iv_atk.set(0, 1); ret.emplace_back(std::move(row)); } { - auto row = std::make_unique(FILTERS.feature_flags); + auto row = std::make_unique(FILTERS0.feature_flags); row->iv_speed.set(0, 1); ret.emplace_back(std::move(row)); } FILTERS0.set_default(std::move(ret)); } +// if (PreloadSettings::instance().DEVELOPER_MODE){ + PA_ADD_STATIC(CALCULATED_IVS); +// } PA_ADD_OPTION(LANGUAGE); PA_ADD_OPTION(BALL_SELECT); PA_ADD_OPTION(TRY_TO_TERASTILLIZE); - PA_ADD_OPTION(FILTERS); - if (PreloadSettings::instance().DEVELOPER_MODE){ +// PA_ADD_OPTION(FILTERS); +// if (PreloadSettings::instance().DEVELOPER_MODE){ PA_ADD_OPTION(FILTERS0); - } +// } PA_ADD_OPTION(GO_HOME_WHEN_DONE); PA_ADD_OPTION(NOTIFICATIONS); } @@ -156,8 +202,7 @@ void StatsResetBloodmoon::enter_battle(SingleSwitchProgramEnvironment& env, BotB int ret = wait_until(env.console, context, Milliseconds(4000), { advance_detector }); if (ret == 0){ env.log("Dialog detected."); - } - else { + }else{ env.log("Dialog not detected."); } //Yes, ready @@ -174,8 +219,7 @@ void StatsResetBloodmoon::enter_battle(SingleSwitchProgramEnvironment& env, BotB ); if (retPrompt != 0){ env.log("Failed to detect prompt dialog!", COLOR_RED); - } - else { + }else{ env.log("Detected prompt dialog."); } context.wait_for_all_requests(); @@ -195,8 +239,7 @@ void StatsResetBloodmoon::enter_battle(SingleSwitchProgramEnvironment& env, BotB ); if (retPrompt2 != 0){ env.log("Failed to detect prompt (again) dialog!", COLOR_RED); - } - else { + }else{ env.log("Detected prompt (again) dialog."); } context.wait_for_all_requests(); @@ -215,8 +258,7 @@ void StatsResetBloodmoon::enter_battle(SingleSwitchProgramEnvironment& env, BotB ); if (ret_battle != 0){ env.log("Failed to detect battle start!", COLOR_RED); - } - else { + }else{ env.log("Battle started."); } context.wait_for_all_requests(); @@ -321,8 +363,7 @@ bool StatsResetBloodmoon::run_battle(SingleSwitchProgramEnvironment& env, BotBas stats.catches++; env.update_stats(); env.log("Ursaluna caught."); - } - else { + }else{ env.log("Battle against Ursaluna lost.", COLOR_RED); env.update_stats(); send_program_status_notification( @@ -335,6 +376,7 @@ bool StatsResetBloodmoon::run_battle(SingleSwitchProgramEnvironment& env, BotBas return true; } +#if 0 bool StatsResetBloodmoon::check_stats(SingleSwitchProgramEnvironment& env, BotBaseContext& context){ StatsResetBloodmoon_Descriptor::Stats& stats = env.current_stats(); bool match = false; @@ -350,8 +392,7 @@ bool StatsResetBloodmoon::check_stats(SingleSwitchProgramEnvironment& env, BotBa env, NOTIFICATION_STATUS_UPDATE, "One or more empty slots in party. Ursaluna was not caught." ); - } - else { + }else{ //Navigate to last party slot move_box_cursor(env.program_info(), env.console, context, BoxCursorLocation::PARTY, 5, 0); @@ -392,6 +433,96 @@ bool StatsResetBloodmoon::check_stats(SingleSwitchProgramEnvironment& env, BotBa return match; } +#endif + +bool StatsResetBloodmoon::check_stats_after_win(SingleSwitchProgramEnvironment& env, BotBaseContext& context){ +#if 0 + // Clear out dialog until we're free + OverworldWatcher overworld(COLOR_YELLOW); + int retOverworld = run_until( + env.console, context, + [](BotBaseContext& context){ + pbf_mash_button(context, BUTTON_B, 10000); + }, + { overworld } + ); + if (retOverworld != 0){ + env.log("Failed to detect overworld after catching.", COLOR_RED); + }else{ + env.log("Detected overworld."); + } + context.wait_for_all_requests(); + return check_stats(env, context); +#else + + while (true){ + PromptDialogWatcher add_to_party(COLOR_PURPLE, {0.500, 0.395, 0.400, 0.100}); + PromptDialogWatcher view_summary(COLOR_PURPLE, {0.500, 0.470, 0.400, 0.100}); + PromptDialogWatcher nickname(COLOR_GREEN, {0.500, 0.545, 0.400, 0.100}); + PokemonSummaryWatcher summary(COLOR_MAGENTA); + AdvanceDialogWatcher advance(COLOR_YELLOW); + context.wait_for_all_requests(); + int ret = wait_until( + env.console, context, std::chrono::seconds(60), + { + add_to_party, + view_summary, + nickname, + summary, + advance, + } + ); + switch (ret){ + case 0: + env.console.log("Detected add-to-party prompt."); + pbf_press_dpad(context, DPAD_DOWN, 20, 60); + continue; + case 1: + env.console.log("Detected cursor over view summary."); + pbf_press_button(context, BUTTON_A, 20, 105); + continue; + case 2: + env.console.log("Detected nickname prompt."); + pbf_press_button(context, BUTTON_B, 20, 105); + continue; + case 3:{ + env.console.log("Detected summary."); + VideoOverlaySet overlays(env.console.overlay()); + + SummaryStatsReader reader; + reader.make_overlays(overlays); + + pbf_press_dpad(context, DPAD_RIGHT, 20, 230); + context.wait_for_all_requests(); + + auto snapshot = env.console.video().snapshot(); + IvRanges ivs = reader.calc_ivs(env.logger(), snapshot, {113, 70, 120, 135, 65, 52}); + + CALCULATED_IVS.set(ivs); + + StatsHuntAction action = FILTERS0.get_action(false, StatsHuntGenderFilter::Any, NatureCheckerValue::Hardy, ivs); + + return action != StatsHuntAction::Discard; + } + case 4:{ + StatsResetBloodmoon_Descriptor::Stats& stats = env.current_stats(); + stats.errors++; + env.update_stats(); + throw UserSetupError(env.logger(), "Did not detect add-to-party prompt. Make sure your party is full and \"Send to Boxes\" to \"Manual\"."); + } + default: + StatsResetBloodmoon_Descriptor::Stats& stats = env.current_stats(); + stats.errors++; + env.update_stats(); + throw OperationFailedException( + ErrorReport::SEND_ERROR_REPORT, env.console, + "StatsResetBloodmoon::check_stats_after_win(): No state detected after 1 minute." + ); + } + } + +#endif +} void StatsResetBloodmoon::program(SingleSwitchProgramEnvironment& env, BotBaseContext& context){ assert_16_9_720p_min(env.logger(), env.console); @@ -408,45 +539,38 @@ void StatsResetBloodmoon::program(SingleSwitchProgramEnvironment& env, BotBaseCo // Connect the controller. pbf_press_button(context, BUTTON_L, 10, 10); - bool stats_matched = false; - while (!stats_matched){ + while (true){ enter_battle(env, context); - bool battle_won = run_battle(env, context); - if (battle_won){ - //Clear out dialog until we're free - OverworldWatcher overworld(COLOR_YELLOW); - int retOverworld = run_until( - env.console, context, - [](BotBaseContext& context){ - pbf_mash_button(context, BUTTON_B, 10000); - }, - { overworld } - ); - if (retOverworld != 0){ - env.log("Failed to detect overworld after catching.", COLOR_RED); - } - else { - env.log("Detected overworld."); - } - context.wait_for_all_requests(); - stats_matched = check_stats(env, context); + if (run_battle(env, context) && check_stats_after_win(env, context)){ + break; } - if (!battle_won || !stats_matched){ - //Reset - stats.resets++; - env.update_stats(); - send_program_status_notification( - env, NOTIFICATION_STATUS_UPDATE, - "Resetting game." - ); - pbf_press_button(context, BUTTON_HOME, 20, GameSettings::instance().GAME_TO_HOME_DELAY); - reset_game_from_home(env.program_info(), env.console, context, 5 * TICKS_PER_SECOND); - } + // Reset + stats.resets++; + env.update_stats(); + send_program_status_notification( + env, NOTIFICATION_STATUS_UPDATE, + "Resetting game." + ); + pbf_press_button(context, BUTTON_HOME, 20, GameSettings::instance().GAME_TO_HOME_DELAY); + reset_game_from_home(env.program_info(), env.console, context, 5 * TICKS_PER_SECOND); } env.update_stats(); + + auto snapshot = env.console.video().snapshot(); + GO_HOME_WHEN_DONE.run_end_of_program(context); - send_program_finished_notification(env, NOTIFICATION_PROGRAM_FINISH); + send_program_finished_notification( + env, NOTIFICATION_PROGRAM_FINISH, + "HP: " + (std::string)CALCULATED_IVS.hp + "\n" + + "Atk: " + (std::string)CALCULATED_IVS.atk + "\n" + + "Def: " + (std::string)CALCULATED_IVS.def + "\n" + + "SpAtk: " + (std::string)CALCULATED_IVS.spatk + "\n" + + "SpDef: " + (std::string)CALCULATED_IVS.spdef + "\n" + + "Speed: " + (std::string)CALCULATED_IVS.speed, + snapshot, + true + ); } } diff --git a/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsResetBloodmoon.h b/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsResetBloodmoon.h index 3404ccdb9..b73a844a8 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsResetBloodmoon.h +++ b/SerialPrograms/Source/PokemonSV/Programs/General/PokemonSV_StatsResetBloodmoon.h @@ -7,7 +7,7 @@ #ifndef PokemonAutomation_PokemonSV_StatsResetBloodmoon_H #define PokemonAutomation_PokemonSV_StatsResetBloodmoon_H -#include "Common/Cpp/Options/StaticTextOption.h" +#include "Common/Cpp/Options/StringOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "CommonFramework/Options/LanguageOCROption.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" @@ -19,18 +19,25 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ namespace PokemonSV{ +using namespace Pokemon; + class IvDisplay : public GroupOption{ public: IvDisplay(); + void set(const IvRanges& ivs); + private: - StaticTextOption m_hp; - StaticTextOption m_atk; - StaticTextOption m_def; - StaticTextOption m_spatk; - StaticTextOption m_spdef; - StaticTextOption m_speed; + static std::string get_range_string(const IvRange& range); + +public: + StringOption hp; + StringOption atk; + StringOption def; + StringOption spatk; + StringOption spdef; + StringOption speed; }; @@ -48,13 +55,16 @@ class StatsResetBloodmoon : public SingleSwitchProgramInstance{ virtual void program(SingleSwitchProgramEnvironment& env, BotBaseContext& context) override; private: + bool check_stats_after_win(SingleSwitchProgramEnvironment& env, BotBaseContext& context); +private: + IvDisplay CALCULATED_IVS; OCR::LanguageOCROption LANGUAGE; PokemonSwSh::PokemonBallSelectOption BALL_SELECT; BooleanCheckBoxOption TRY_TO_TERASTILLIZE; - Pokemon::StatsHuntIvJudgeFilterTable FILTERS; +// Pokemon::StatsHuntIvJudgeFilterTable FILTERS; Pokemon::StatsHuntIvRangeFilterTable FILTERS0; // REMOVE: Temporary for development GoHomeWhenDoneOption GO_HOME_WHEN_DONE; diff --git a/SerialPrograms/Source/PokemonSV/Programs/ShinyHunting/PokemonSV_ShinyHunt-AreaZeroPlatform.cpp b/SerialPrograms/Source/PokemonSV/Programs/ShinyHunting/PokemonSV_ShinyHunt-AreaZeroPlatform.cpp index d39de07aa..0a375c5fb 100644 --- a/SerialPrograms/Source/PokemonSV/Programs/ShinyHunting/PokemonSV_ShinyHunt-AreaZeroPlatform.cpp +++ b/SerialPrograms/Source/PokemonSV/Programs/ShinyHunting/PokemonSV_ShinyHunt-AreaZeroPlatform.cpp @@ -384,7 +384,7 @@ void ShinyHuntAreaZeroPlatform::run_state(SingleSwitchProgramEnvironment& env, B } if (m_pending_platform_reset){ - console.log("Executing: Platform Reset (time-based)..."); + console.log("Executing: Platform Reset"); return_to_inside_zero_gate(info, console, context); inside_zero_gate_to_platform(info, console, context, NAVIGATE_TO_PLATFORM); m_current_location = Location::AREA_ZERO; diff --git a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggAutonomous.cpp b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggAutonomous.cpp index 7e53525df..ae1bbe395 100644 --- a/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggAutonomous.cpp +++ b/SerialPrograms/Source/PokemonSwSh/Programs/EggPrograms/PokemonSwSh_EggAutonomous.cpp @@ -630,7 +630,7 @@ bool EggAutonomous::process_hatched_pokemon(SingleSwitchProgramEnvironment& env, env.log("Gender: " + gender_to_string(gender), COLOR_GREEN); NatureReader::Results nature = nature_detector.read(env.console.logger(), screen); - StatsHuntAction action = FILTERS.get_action(shiny, IVs, gender, nature); + StatsHuntAction action = FILTERS.get_action(shiny, gender, nature.nature, IVs); auto send_keep_notification = [&](){ if (!shiny){