From 48a2b387390123210c6c254c3d9b35dc933aa018 Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Tue, 19 May 2026 19:28:16 -0500 Subject: [PATCH 1/4] more logging, more calibration displays, neater program UI --- .../Source/Pokemon/Pokemon_AdvRng.cpp | 20 +-- .../Farming/PokemonFRLG_PickupFarmer.cpp | 4 +- .../PokemonFRLG_BlindNavigation.cpp | 2 +- .../RngManipulation/PokemonFRLG_GiftRng.cpp | 113 ++++++------ .../RngManipulation/PokemonFRLG_GiftRng.h | 20 ++- .../PokemonFRLG_RngCalibration.cpp | 58 +++---- .../PokemonFRLG_RngCalibration.h | 2 + .../PokemonFRLG_RngDisplays.cpp | 85 ++++++--- .../RngManipulation/PokemonFRLG_RngDisplays.h | 37 ++-- .../RngManipulation/PokemonFRLG_RngHelper.cpp | 33 +++- .../RngManipulation/PokemonFRLG_RngHelper.h | 10 +- .../PokemonFRLG_RngNavigation.cpp | 2 +- .../PokemonFRLG_StarterRng.cpp | 110 ++++++------ .../RngManipulation/PokemonFRLG_StarterRng.h | 20 +-- .../RngManipulation/PokemonFRLG_StaticRng.cpp | 136 ++++++++------- .../RngManipulation/PokemonFRLG_StaticRng.h | 22 +-- .../RngManipulation/PokemonFRLG_WildRng.cpp | 162 ++++++++++-------- .../RngManipulation/PokemonFRLG_WildRng.h | 26 +-- 18 files changed, 478 insertions(+), 384 deletions(-) diff --git a/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp b/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp index 971c6f183a..a4b3b1a536 100644 --- a/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp +++ b/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp @@ -414,20 +414,6 @@ bool check_for_match(AdvWildPokemonResult res, AdvRngFilters target, int16_t gen && ((target.ivs.speed.low <= res.ivs.speed) && (target.ivs.speed.high >= res.ivs.speed)); } -// bool check_for_match(AdvEggResult res, AdvRngFilters target, int16_t gender_threshold, AdvIVs parentA_ivs, AdvIVs parentB_ivs, uint16_t tid_xor_sid){ -// AdvIVs final_ivs = apply_inherited_ivs(res.ivs, res.inherited_ivs, parentA_ivs, parentB_ivs); -// return (target.nature == AdvNature::Any || (res.nature == target.nature)) -// && (target.ability == AdvAbility::Any || (res.ability == target.ability)) -// && (target.gender == AdvGender::Any || (gender_from_gender_value(res.gender, gender_threshold) == target.gender)) -// && (target.shiny == AdvShinyType::Any || (shiny_type_from_pid(res.pid, tid_xor_sid) == target.shiny)) -// && ((target.ivs.hp.low <= final_ivs.hp) && (target.ivs.hp.high >= final_ivs.hp)) -// && ((target.ivs.attack.low <= final_ivs.attack) && (target.ivs.attack.high >= final_ivs.attack)) -// && ((target.ivs.defense.low <= final_ivs.defense) && (target.ivs.defense.high >= final_ivs.defense)) -// && ((target.ivs.spatk.low <= final_ivs.spatk) && (target.ivs.spatk.high >= final_ivs.spatk)) -// && ((target.ivs.spdef.low <= final_ivs.spdef) && (target.ivs.spdef.high >= final_ivs.spdef)) -// && ((target.ivs.speed.low <= final_ivs.speed) && (target.ivs.speed.high >= final_ivs.speed)); -// } - Pokemon::NatureAdjustments nature_to_adjustment(AdvNature nature){ NatureAdjustments ret; ret.attack = NatureAdjustment::NEUTRAL; @@ -664,11 +650,11 @@ AdvRngFilters observation_to_filters(const AdvObservedPokemon& observation, cons std::string gender_to_string(const AdvGender& gender){ switch (gender){ case AdvGender::Male: - return "Male"; + return "♂"; case AdvGender::Female: - return "Female"; + return "♀"; default: - return "Any"; + return "-"; } } diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_PickupFarmer.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_PickupFarmer.cpp index 9f93faa7d7..062762addb 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_PickupFarmer.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG_PickupFarmer.cpp @@ -239,7 +239,7 @@ void PickupFarmer::program(SingleSwitchProgramEnvironment& env, ProControllerCon default: OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Option not yet implemented.", + "Travel option not recognized. Please report this as a bug.", env.console ); } @@ -257,7 +257,7 @@ void PickupFarmer::program(SingleSwitchProgramEnvironment& env, ProControllerCon default: OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Option not yet implemented.", + "Game location not recognized. Please report this as a bug.", env.console ); } diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp index efdd55518c..c5c4b73ab8 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp @@ -656,7 +656,7 @@ void check_timings( default: OperationFailedException::fire( ErrorReport::NO_ERROR_REPORT, - "Option not yet implemented.", + "RNG target not recognized. Please report this as a bug.", console ); } diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp index 6072cd78f2..428fb01918 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp @@ -60,7 +60,13 @@ std::unique_ptr GiftRng_Descriptor::make_stats() const{ } GiftRng::GiftRng() - : LANGUAGE( + : m_calibration_displays( + "Calibration Displays — These will update automatically as the program runs" + ) + , m_game_info( + "Game Information" + ) + , LANGUAGE( "Game Language:", { Language::English, @@ -73,8 +79,11 @@ GiftRng::GiftRng() LockMode::LOCK_WHILE_RUNNING, true ) + , m_target_settings( + "Target Settings — Get these from an RNG search tool" + ) , TARGET( - "Target:
", + "Target:", { {PokemonFRLG_RngTarget::magikarp, "magikarp", "Magikarp"}, {PokemonFRLG_RngTarget::hitmonchan, "hitmonchan", "Hitmonchan"}, @@ -96,18 +105,6 @@ GiftRng::GiftRng() LockMode::LOCK_WHILE_RUNNING, PokemonFRLG_RngTarget::magikarp ) - , MAX_RESETS( - "Max Resets:
", - LockMode::UNLOCK_WHILE_RUNNING, - 50, 0 // default, min - ) - , MAX_RARE_CANDIES( - "Max Rare Candies:
" - "The number of rare candies in your bag. Make sure these are at the top position of the bag.
" - "Rare candies used during calibration will be restored after resetting.", - LockMode::UNLOCK_WHILE_RUNNING, - 0, 0, 999 // default, min, max - ) , SEED( false, "Target Seed:", @@ -124,7 +121,7 @@ GiftRng::GiftRng() true ) , SEED_BUTTON( - "Seed Button:
", + "Seed Button:", { {SeedButton::A, "A", "A"}, {SeedButton::Start, "Start", "Start"}, @@ -156,11 +153,9 @@ GiftRng::GiftRng() LockMode::LOCK_WHILE_RUNNING, 10000, 520, 1000000000 // default, min, max ) - // , CONTINUE_SCREEN_FRAMES( - // "Continue Screen Frames:
The number of RNG advances to pass on the continue screen.
This should be less than the total number of advances above.", - // LockMode::LOCK_WHILE_RUNNING, - // 1000, 192 // default, min - // ) + , m_program_settings( + "Program Settings" + ) , USE_TEACHY_TV( "Use Teachy TV:" "
Opens the Teachy TV to quickly advance the RNG at 313x speed.
" @@ -168,6 +163,18 @@ GiftRng::GiftRng() LockMode::LOCK_WHILE_RUNNING, false // default ) + , MAX_RESETS( + "Max Resets:", + LockMode::UNLOCK_WHILE_RUNNING, + 50, 0 // default, min + ) + , MAX_RARE_CANDIES( + "Max Rare Candies:
" + "The number of rare candies in your bag. Make sure these are at the top position of the bag.
" + "Rare candies used during calibration will be restored after resetting.", + LockMode::UNLOCK_WHILE_RUNNING, + 0, 0, 999 // default, min, max + ) , PROFILE( "User Profile Position:
" "The position, from left to right, of the Switch profile with the FRLG save you'd like to use.
" @@ -193,20 +200,24 @@ GiftRng::GiftRng() &NOTIFICATION_PROGRAM_FINISH, }) { + PA_ADD_OPTION(m_calibration_displays); + PA_ADD_OPTION(RNG_TARGET); PA_ADD_OPTION(RNG_FILTERS); PA_ADD_OPTION(RNG_CALIBRATION); + PA_ADD_OPTION(m_game_info); PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(TARGET); - PA_ADD_OPTION(MAX_RESETS); - PA_ADD_OPTION(MAX_RARE_CANDIES); PA_ADD_OPTION(SEED); PA_ADD_OPTION(SEED_LIST); PA_ADD_OPTION(SEED_BUTTON); PA_ADD_OPTION(EXTRA_BUTTON); PA_ADD_OPTION(SEED_DELAY); PA_ADD_OPTION(ADVANCES); - // PA_ADD_OPTION(CONTINUE_SCREEN_FRAMES); + PA_ADD_OPTION(m_program_settings); PA_ADD_OPTION(USE_TEACHY_TV); + PA_ADD_OPTION(MAX_RESETS); + PA_ADD_OPTION(MAX_RARE_CANDIES); PA_ADD_OPTION(PROFILE); PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(GO_HOME_WHEN_DONE); @@ -229,21 +240,17 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& home_black_border_check(env.console, context); RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.reset_hits(); const uint16_t TARGET_SEED = parse_seed(env.console, SEED); const std::vector SEED_VALUES = parse_seed_list(env.console, SEED_LIST); const int16_t SEED_POSITION = seed_position_in_list(TARGET_SEED, SEED_VALUES); if (SEED_POSITION == -1){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "GiftRng(): Target Seed is missing from the list of nearby seeds.", - env.console - ); + throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); } - env.log("Target Seed Value (base10): " + std::to_string(TARGET_SEED)); + env.log("Target Seed Value: " + to_hex_string(TARGET_SEED)); BaseStats BASE_STATS; int16_t GENDER_THRESHOLD = -1; @@ -324,16 +331,21 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& const uint8_t MAX_HISTORY_LENGTH = USE_TEACHY_TV ? 2 : 10; - - RngCalibrations calibrations = { - RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, - RNG_CALIBRATION.csf_calibration, - RNG_CALIBRATION.advances_calibration + static const std::set SPECIES_LIST = { + "magikarp", "hitmonchan", "hitmonlee", "eevee", "lapras", + "omanyte", "kabuto", "aerodactyl", + "abra", "clefairy", "dratini", "scyther", "pinsir", "porygon", + "togepi" }; + env.log("RNG Target: " + std::to_string(TARGET.current_value())); + env.log("Target Seed: " + to_hex_string(TARGET_SEED)); + env.log("Target Advances: " + std::to_string(ADVANCES)); + AdvRngSearcher searcher(TARGET_SEED, ADVANCES, AdvRngMethod::Method1); AdvPokemonResult target_result = searcher.generate_pokemon(); - env.log("Target PID (base 10): " + std::to_string(target_result.pid)); + RNG_TARGET.set_target(target_result, GENDER_THRESHOLD); + env.log("Target PID: " + to_hex_string(target_result.pid)); env.log("Target Nature: " + nature_to_string(target_result.nature)); env.log("Target IVs:"); env.log(" HP: " + std::to_string(target_result.ivs.hp)); @@ -343,6 +355,15 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& env.log(" SpD: " + std::to_string(target_result.ivs.spdef)); env.log(" Spe: " + std::to_string(target_result.ivs.speed)); + RngCalibrations calibrations = { + RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, + RNG_CALIBRATION.csf_calibration, + RNG_CALIBRATION.advances_calibration + }; + env.log("Initial Seed calibration (frames): " + std::to_string(calibrations.seed_offset)); + env.log("Initial CSF calibration (frames): " + std::to_string(calibrations.csf_offset)); + env.log("Initial In-game calibration (frames x2): " + std::to_string(calibrations.ingame_offset)); + RngAdvanceHistory advance_history; RngCalibrationHistory calibration_history; @@ -409,13 +430,15 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& stats.resets++; RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.set_calibrations(calibrations); + RNG_CALIBRATION.reset_hits(); bool shiny_found = check_for_shiny(env.console, context, TARGET); if (shiny_found){ env.log("Shiny found!"); stats.shinies++; + RNG_CALIBRATION.hits.set("Shiny!"); send_program_notification( env, NOTIFICATION_SHINY, @@ -431,17 +454,12 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& break; } - AdvObservedPokemon pokemon = read_summary(env.console, context, LANGUAGE); + AdvObservedPokemon pokemon = read_summary(env.console, context, LANGUAGE, SPECIES_LIST); AdvRngFilters filters = observation_to_filters(pokemon, BASE_STATS); RNG_FILTERS.set(filters); std::vector search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); bool finished = update_history( env.console, advance_history, calibration_history, MAX_HISTORY_LENGTH, calibrations, search_hits, 1 @@ -463,12 +481,7 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& RNG_FILTERS.set(filters); search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); bool force_finish = failed || (i == (MAX_RARE_CANDIES - 1)); finished = update_history( diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h index 5b5f1584c8..a9a2007552 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h @@ -10,6 +10,7 @@ #include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/FloatingPointOption.h" #include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/StaticTextOption.h" #include "Common/Cpp/Options/TextEditOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "CommonTools/Options/LanguageOCROption.h" @@ -45,26 +46,27 @@ class GiftRng : public SingleSwitchProgramInstance{ bool have_hit_target(SingleSwitchProgramEnvironment& env, const uint32_t& TARGET_SEED, const AdvRngState& hit); - OCR::LanguageOCROption LANGUAGE; - - EnumDropdownOption TARGET; - - SimpleIntegerOption MAX_RESETS; - SimpleIntegerOption MAX_RARE_CANDIES; - + SectionDividerOption m_calibration_displays; + RngTargetDisplay RNG_TARGET; RngFilterDisplay RNG_FILTERS; RngCalibrationDisplay RNG_CALIBRATION; + SectionDividerOption m_game_info; + OCR::LanguageOCROption LANGUAGE; + + SectionDividerOption m_target_settings; + EnumDropdownOption TARGET; StringOption SEED; TextEditOption SEED_LIST; EnumDropdownOption SEED_BUTTON; EnumDropdownOption EXTRA_BUTTON; SimpleIntegerOption SEED_DELAY; - SimpleIntegerOptionADVANCES; + SectionDividerOption m_program_settings; BooleanCheckBoxOption USE_TEACHY_TV; - + SimpleIntegerOption MAX_RESETS; + SimpleIntegerOption MAX_RARE_CANDIES; SimpleIntegerOption PROFILE; BooleanCheckBoxOption TAKE_VIDEO; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.cpp index 7a358de6e7..37937b23b5 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.cpp @@ -37,21 +37,13 @@ void check_seed_validity(ConsoleHandle& console, std::string seed_string){ }; if (seed_string.size() != 4){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "GiftRng(): Invalid seed length. Seeds should be 4 characters.", - console - ); + throw UserSetupError(console, "Invalid seed length. Seeds should be 4 characters."); } for (char ch : seed_string){ auto iter = MAP.find(ch); if (iter == MAP.end()){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "GiftRng(): Invalid seed character. Seeds should be hex strings (valid characters are 0-9 and A-F).", - console - ); + throw UserSetupError(console, "Invalid seed character. Seeds should be valid hex strings (valid characters are 0-9 and A-F"); } } } @@ -82,6 +74,16 @@ int16_t seed_position_in_list(uint16_t seed, std::vector list){ return -1; } +std::string to_hex_string(const uint16_t& val){ + std::ostringstream s; + s << std::hex << val; + return s.str(); +} +std::string to_hex_string(const uint32_t& val){ + std::ostringstream s; + s << std::hex << val; + return s.str(); +} RngTimings prepare_timings( ConsoleHandle& console, @@ -96,11 +98,7 @@ RngTimings prepare_timings( ){ double modified_ingame_advances = INGAME_ADVANCES + calibrations.ingame_offset + FIXED_ADVANCES_OFFSET; if (modified_ingame_advances < 0) { - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "In-game advances cannot be negative. Check your in-game advances and calibration.", - console - ); + throw UserSetupError(console, "In-game advances cannot be negative. Check your in-game advances and calibration."); } bool safari_zone = ( @@ -121,38 +119,26 @@ RngTimings prepare_timings( TEACHY_ADVANCES = uint64_t((int)std::floor((modified_ingame_advances - TEACHY_TV_BUFFER + 7500) / 313) * 313); } + console.log("Seed calibration (frames): " + std::to_string(calibrations.seed_offset)); + console.log("CSF calibration (frames): " + std::to_string(calibrations.csf_offset)); + console.log("In-game calibration (frames x2): " + std::to_string(calibrations.ingame_offset)); + double seed_delay = SEED_DELAY + calibrations.seed_offset + FIXED_SEED_OFFSET; double csf_delay = (CONTINUE_SCREEN_FRAMES + calibrations.csf_offset) * FRLG_FRAME_DURATION; double teachy_delay = TEACHY_ADVANCES * FRLG_FRAME_DURATION / 313; double ingame_delay = (modified_ingame_advances - TEACHY_ADVANCES) * FRLG_FRAME_DURATION / 2 - (should_use_teachy_tv ? 14067 : 0); if (seed_delay < 0){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "prepare_timings(): seed delay cannot be negative. Check your calibration values.", - console - ); + throw UserSetupError(console, "prepare_timings(): seed delay cannot be negative. Check your calibration values."); } if (csf_delay < 0){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "prepare_timings(): CSF duration cannot be negative. Check your calibration values.", - console - ); + throw UserSetupError(console, "prepare_timings(): CSF duration cannot be negative. Check your calibration values."); } if (teachy_delay < 0){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "prepare_timings(): Teachy TV duration cannot be negative. Check your calibration values.", - console - ); + throw UserSetupError(console, "prepare_timings(): Teachy TV duration cannot be negative. Check your calibration values."); } if (ingame_delay < 0){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "prepare_timings(): in-game duration cannot be negative. Check your calibration values.", - console - ); + throw UserSetupError(console, "prepare_timings(): in-game duration cannot be negative. Check your calibration values."); } RngTimings timings; @@ -430,7 +416,7 @@ RngCalibrations get_calibrations( console.log("Seed calibration (frames): " + std::to_string(calibrations.seed_offset)); console.log("Continue screen adjustment (frames): " + std::to_string(calibrations.csf_offset)); - console.log("Advance calibration (frames / 2): " + std::to_string(calibrations.ingame_offset)); + console.log("Advance calibration (frames x2): " + std::to_string(calibrations.ingame_offset)); return calibrations; } diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.h index 36549f30da..acb8be21f0 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngCalibration.h @@ -45,6 +45,8 @@ uint16_t parse_seed(ConsoleHandle& console, std::string seed_string); std::vector parse_seed_list(ConsoleHandle& console, std::string seed_list_string); int16_t seed_position_in_list(uint16_t seed, std::vector list); +std::string to_hex_string(const uint16_t& val); +std::string to_hex_string(const uint32_t& val); RngTimings prepare_timings( ConsoleHandle& console, diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp index 3feee9b7a9..e4031757dc 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "Pokemon/Resources/Pokemon_PokemonNames.h" #include "PokemonFRLG_RngDisplays.h" namespace PokemonAutomation{ @@ -37,26 +38,66 @@ void SidHelperDisplay::set(uint16_t trainerId, const std::vectorSpecies:", LockMode::READ_ONLY, "-", "") + , gender(false, "Gender:", LockMode::READ_ONLY, "-", "") + , nature(false, "Nature:", LockMode::READ_ONLY, "-", "") , hp(false, "HP IV:", LockMode::READ_ONLY, "-", "") + , level(false, "Level:", LockMode::READ_ONLY, "-", "") , atk(false, "Attack IV:", LockMode::READ_ONLY, "-", "") , def(false, "Defense IV:", LockMode::READ_ONLY, "-", "") , spatk(false, "Special Attack IV:", LockMode::READ_ONLY, "-", "") , spdef(false, "Special Defense IV:", LockMode::READ_ONLY, "-", "") , speed(false, "Speed IV:", LockMode::READ_ONLY, "-", "") - , gender(false, "Gender:", LockMode::READ_ONLY, "-", "") - , nature(false, "Nature:", LockMode::READ_ONLY, "-", "") -{ +{ + PA_ADD_OPTION(species); + PA_ADD_STATIC(gender); + PA_ADD_STATIC(nature); + PA_ADD_STATIC(level); PA_ADD_STATIC(hp); PA_ADD_STATIC(atk); PA_ADD_STATIC(def); PA_ADD_STATIC(spatk); PA_ADD_STATIC(spdef); PA_ADD_STATIC(speed); - PA_ADD_STATIC(gender); - PA_ADD_STATIC(nature); + } std::string RngFilterDisplay::get_range_string(const IvRange& range){ @@ -70,25 +111,30 @@ std::string RngFilterDisplay::get_range_string(const IvRange& range){ } void RngFilterDisplay::set(const AdvRngFilters& filter){ + species.set(get_pokemon_name(filter.species).display_name()); + gender.set(gender_to_string(filter.gender)); + nature.set(nature_to_string(filter.nature)); + level.set(std::to_string(filter.level)); hp.set(get_range_string(filter.ivs.hp)); atk.set(get_range_string(filter.ivs.attack)); def.set(get_range_string(filter.ivs.defense)); spatk.set(get_range_string(filter.ivs.spatk)); spdef.set(get_range_string(filter.ivs.spdef)); speed.set(get_range_string(filter.ivs.speed)); - gender.set(gender_to_string(filter.gender)); - nature.set(nature_to_string(filter.nature)); } void RngFilterDisplay::reset(){ + species.set("-"); + gender.set("-"); + nature.set("-"); + level.set("-"); hp.set("-"); atk.set("-"); def.set("-"); spatk.set("-"); spdef.set("-"); speed.set("-"); - gender.set("-"); - nature.set("-"); + } RngCalibrationDisplay::RngCalibrationDisplay() @@ -124,22 +170,17 @@ std::string RngCalibrationDisplay::get_hits_string(const std::vector& rng_states -){ - seed_calibration.set(int64_t(std::round(s_calibration))); - csf_calibration.set(c_calibration); - advances_calibration.set(a_calibration); +void RngCalibrationDisplay::set_calibrations(const RngCalibrations& calibrations){ + seed_calibration.set(int64_t(std::round(calibrations.seed_offset * FRLG_FRAME_DURATION))); + csf_calibration.set(calibrations.csf_offset); + advances_calibration.set(calibrations.ingame_offset); +} + +void RngCalibrationDisplay::set_hits(const std::vector& rng_states){ hits.set(get_hits_string(rng_states)); } -void RngCalibrationDisplay::reset(){ - // seed_calibration.set(0.0); - // csf_calibration.set(0.0); - // advances_calibration.set(0.0); +void RngCalibrationDisplay::reset_hits(){ hits.set("-"); } diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.h index ce7a738a67..1c8383a123 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.h @@ -14,6 +14,7 @@ #include "Common/Cpp/Options/FloatingPointOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" +#include "PokemonFRLG_RngCalibration.h" #include "Pokemon/Pokemon_AdvRng.h" @@ -37,6 +38,25 @@ class SidHelperDisplay: public GroupOption{ TextEditOption sids; }; +class RngTargetDisplay : public StringOption{ +public: + RngTargetDisplay() + : StringOption( + false, + "Target Details:", + LockMode::READ_ONLY, + "-", "" + ) + {} + + void set_target(const AdvPokemonResult& pokemon, const int16_t& gender_threshold); + void set_target(const AdvWildPokemonResult& pokemon, const int16_t& gender_threshold); + +private: + std::string result_to_string(const AdvPokemonResult& pokemon, const int16_t& gender_threshold); + std::string result_to_string(const AdvWildPokemonResult& pokemon, const int16_t& gender_threshold); +}; + class RngFilterDisplay : public GroupOption{ public: RngFilterDisplay(); @@ -48,14 +68,16 @@ class RngFilterDisplay : public GroupOption{ static std::string get_range_string(const IvRange& range); public: + StringOption species; + StringOption gender; + StringOption nature; + StringOption level; StringOption hp; StringOption atk; StringOption def; StringOption spatk; StringOption spdef; StringOption speed; - StringOption gender; - StringOption nature; }; @@ -63,17 +85,12 @@ class RngCalibrationDisplay : public GroupOption{ public: RngCalibrationDisplay(); - void set( - double s_calibraiton, - double c_calibration, - double a_calibration, - std::vector& rng_states - ); - void reset(); + void set_calibrations(const RngCalibrations& calibrations); + void set_hits(const std::vector& rng_states); + void reset_hits(); private: static std::string get_hits_string(const std::vector& rng_states); - static std::string get_hits_string(const std::map& hits_map); public: SimpleIntegerOption seed_calibration; FloatingPointOption csf_calibration; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.cpp index abca148165..65999efaad 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.cpp @@ -51,7 +51,10 @@ std::unique_ptr RngHelper_Descriptor::make_stats() const{ } RngHelper::RngHelper() - : TARGET( + : m_target_settings( + "Target Settings — Get these from an RNG search tool" + ) + , TARGET( "Target:", { {PokemonFRLG_RngTarget::starters, "starters", "Bulbasaur / Squirtle / Charmander"}, @@ -89,12 +92,6 @@ RngHelper::RngHelper() LockMode::LOCK_WHILE_RUNNING, PokemonFRLG_RngTarget::starters ) - , NUM_RESETS( - "Max Resets:
" - "This program requires manual calibration, so this should usually be set to 1 while calibrating.", - LockMode::UNLOCK_WHILE_RUNNING, - 1, 0 // default, min - ) , SEED_BUTTON( "Seed Button:
" "The button to be pressed on the title screen to set the seed.", @@ -160,6 +157,9 @@ RngHelper::RngHelper() LockMode::UNLOCK_WHILE_RUNNING, 0 // default ) + , m_program_settings( + "Program Settings" + ) , USE_TEACHY_TV( "Use Teachy TV:" "
Opens the Teachy TV to quickly advance the RNG at 313x speed.
" @@ -167,6 +167,12 @@ RngHelper::RngHelper() LockMode::LOCK_WHILE_RUNNING, false // default ) + , NUM_RESETS( + "Max Resets:
" + "This program requires manual calibration, so this should usually be set to 1 while calibrating.", + LockMode::UNLOCK_WHILE_RUNNING, + 1, 0 // default, min + ) , PROFILE( "User Profile Position:
" "The position, from left to right, of the Switch profile with the FRLG save you'd like to use.
" @@ -192,8 +198,8 @@ RngHelper::RngHelper() &NOTIFICATION_PROGRAM_FINISH, }) { + PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(TARGET); - PA_ADD_OPTION(NUM_RESETS); PA_ADD_OPTION(SEED_BUTTON); PA_ADD_OPTION(EXTRA_BUTTON); PA_ADD_OPTION(SEED_DELAY); @@ -202,7 +208,9 @@ RngHelper::RngHelper() PA_ADD_OPTION(CONTINUE_SCREEN_CALIBRATION); PA_ADD_OPTION(INGAME_ADVANCES); PA_ADD_OPTION(INGAME_CALIBRATION); + PA_ADD_OPTION(m_program_settings); PA_ADD_OPTION(USE_TEACHY_TV); + PA_ADD_OPTION(NUM_RESETS); PA_ADD_OPTION(PROFILE); PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(GO_HOME_WHEN_DONE); @@ -240,12 +248,21 @@ void RngHelper::program(SingleSwitchProgramEnvironment& env, ProControllerContex || TARGET == PokemonFRLG_RngTarget::safarizonesurf || TARGET == PokemonFRLG_RngTarget::safarizonefish ); + + env.log("Target: " + std::to_string(TARGET.current_value())); + env.log("Seed Delay: " + std::to_string(SEED_DELAY) + "ms"); + env.log("Continue Screen Frames: " + std::to_string(CONTINUE_SCREEN_FRAMES) + " frames"); + env.log("In-game Advances: " + std::to_string(INGAME_ADVANCES) + " advances"); const RngCalibrations CALIBRATIONS = { static_cast(SEED_CALIBRATION), CONTINUE_SCREEN_CALIBRATION, INGAME_CALIBRATION }; + env.log("Seed calibration (frames): " + std::to_string(CALIBRATIONS.seed_offset)); + env.log("CSF calibration (frames): " + std::to_string(CALIBRATIONS.csf_offset)); + env.log("In-game calibration (frames x2): " + std::to_string(CALIBRATIONS.ingame_offset)); + while (!shiny_found){ RngTimings timings = prepare_timings( diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.h index ec0cb8b9b6..3a99a0bfd5 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngHelper.h @@ -10,6 +10,7 @@ #include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/FloatingPointOption.h" #include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/StaticTextOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" #include "NintendoSwitch/Options/NintendoSwitch_GoHomeWhenDoneOption.h" @@ -36,23 +37,20 @@ class RngHelper : public SingleSwitchProgramInstance{ ) override{} private: + SectionDividerOption m_target_settings; EnumDropdownOption TARGET; - SimpleIntegerOption NUM_RESETS; - EnumDropdownOption SEED_BUTTON; EnumDropdownOption EXTRA_BUTTON; SimpleIntegerOption SEED_DELAY; SimpleIntegerOption SEED_CALIBRATION; - - SimpleIntegerOption CONTINUE_SCREEN_FRAMES; FloatingPointOption CONTINUE_SCREEN_CALIBRATION; - SimpleIntegerOption INGAME_ADVANCES; FloatingPointOption INGAME_CALIBRATION; + SectionDividerOption m_program_settings; BooleanCheckBoxOption USE_TEACHY_TV; - + SimpleIntegerOption NUM_RESETS; SimpleIntegerOption PROFILE; BooleanCheckBoxOption TAKE_VIDEO; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngNavigation.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngNavigation.cpp index 045dde5830..7cae9735e1 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngNavigation.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngNavigation.cpp @@ -503,7 +503,7 @@ bool check_for_shiny(ConsoleHandle& console, ProControllerContext& context, Poke default: OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "Option not yet implemented.", + "RNG target not recognized. Please report this as a bug.", console ); } diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp index ceb3368710..b6eea3495d 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp @@ -66,7 +66,13 @@ std::unique_ptr StarterRng_Descriptor::make_stats() const{ } StarterRng::StarterRng() - : LANGUAGE( + : m_calibration_displays( + "Calibration Displays — These will update automatically as the program runs" + ) + , m_game_info( + "Game Information" + ) + , LANGUAGE( "Game Language:", { Language::English, @@ -79,8 +85,11 @@ StarterRng::StarterRng() LockMode::LOCK_WHILE_RUNNING, true ) + , m_target_settings( + "Target Settings — Get these from an RNG search tool" + ) , STARTER( - "Target:
", + "Starter Species:", { {Starter::bulbasaur, "bulbasaur", "Bulbasaur"}, {Starter::squirtle, "squirtle", "Squirtle"}, @@ -89,11 +98,6 @@ StarterRng::StarterRng() LockMode::LOCK_WHILE_RUNNING, Starter::bulbasaur ) - , MAX_RESETS( - "Max Resets:
", - LockMode::UNLOCK_WHILE_RUNNING, - 50, 0 // default, min - ) , SEED( false, "Target Seed:", @@ -110,7 +114,7 @@ StarterRng::StarterRng() true ) , SEED_BUTTON( - "Seed Button:
", + "Seed Button:", { {SeedButton::A, "A", "A"}, {SeedButton::Start, "Start", "Start"}, @@ -138,17 +142,22 @@ StarterRng::StarterRng() 31338, 30400 // default, min ) , ADVANCES( - "Advances:
The total number of RNG advances for your target.", + "Advances:
" + "The total number of RNG advances for your target.", LockMode::LOCK_WHILE_RUNNING, 10000, 940, 1000000000 // default, min ) - // , CONTINUE_SCREEN_FRAMES( - // "Continue Screen Frames:
The number of RNG advances to pass on the continue screen.
This should be less than the total number of advances above.", - // LockMode::LOCK_WHILE_RUNNING, - // 1000, 192 // default, min - // ) + , m_program_settings( + "Program Settings" + ) + , MAX_RESETS( + "Max Resets:", + LockMode::UNLOCK_WHILE_RUNNING, + 50, 0 // default, min + ) , IGNORE_WILD_SHINIES( - "Ignore wild shinies
Do not stop the program when a wild shiny is encountered.", + "Ignore wild shinies
" + "Do not stop the program when a wild shiny is encountered.", LockMode::LOCK_WHILE_RUNNING, false // default ) @@ -160,7 +169,8 @@ StarterRng::StarterRng() 0, 0, 8 // default, min, max ) , TAKE_VIDEO( - "Take Video:
Record a video when the shiny is found.", + "Take Video:
" + "Record a video when the shiny is found.", LockMode::LOCK_WHILE_RUNNING, true // default ) @@ -177,18 +187,22 @@ StarterRng::StarterRng() &NOTIFICATION_PROGRAM_FINISH, }) { + PA_ADD_OPTION(m_calibration_displays); + PA_ADD_OPTION(RNG_TARGET); PA_ADD_OPTION(RNG_FILTERS); PA_ADD_OPTION(RNG_CALIBRATION); + PA_ADD_OPTION(m_game_info); PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(STARTER); - PA_ADD_OPTION(MAX_RESETS); PA_ADD_OPTION(SEED); PA_ADD_OPTION(SEED_LIST); PA_ADD_OPTION(SEED_BUTTON); PA_ADD_OPTION(EXTRA_BUTTON); PA_ADD_OPTION(SEED_DELAY); PA_ADD_OPTION(ADVANCES); - // PA_ADD_OPTION(CONTINUE_SCREEN_FRAMES); + PA_ADD_OPTION(m_program_settings); + PA_ADD_OPTION(MAX_RESETS); PA_ADD_OPTION(PROFILE); PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(GO_HOME_WHEN_DONE); @@ -553,21 +567,17 @@ void StarterRng::program(SingleSwitchProgramEnvironment& env, ProControllerConte home_black_border_check(env.console, context); RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.reset_hits(); const uint16_t TARGET_SEED = parse_seed(env.console, SEED); const std::vector SEED_VALUES = parse_seed_list(env.console, SEED_LIST); const int16_t SEED_POSITION = seed_position_in_list(TARGET_SEED, SEED_VALUES); if (SEED_POSITION == -1){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "StarterRng(): Target Seed is missing from the list of nearby seeds.", - env.console - ); + throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); } - env.log("Target Seed Value (base10): " + std::to_string(TARGET_SEED)); + env.log("Target Seed Value: " + to_hex_string(TARGET_SEED)); BaseStats BASE_STATS; switch (STARTER){ @@ -597,17 +607,16 @@ void StarterRng::program(SingleSwitchProgramEnvironment& env, ProControllerConte static const int16_t GENDER_THRESHOLD = 30; + static const std::set SPECIES_LIST = { "bulbasuar", "squirtle", "charmander" }; - RngCalibrations calibrations = { - RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, - RNG_CALIBRATION.csf_calibration, - RNG_CALIBRATION.advances_calibration - }; - + env.log("RNG Target: " + std::to_string(STARTER.current_value())); + env.log("Target Seed: " + to_hex_string(TARGET_SEED)); + env.log("Target Advances: " + std::to_string(ADVANCES)); AdvRngSearcher searcher(TARGET_SEED, ADVANCES, AdvRngMethod::Method1); AdvPokemonResult target_result = searcher.generate_pokemon(); - env.log("Target PID (base 10): " + std::to_string(target_result.pid)); + RNG_TARGET.set_target(target_result, GENDER_THRESHOLD); + env.log("Target PID: " + to_hex_string(target_result.pid)); env.log("Target Nature: " + nature_to_string(target_result.nature)); env.log("Target IVs:"); env.log(" HP: " + std::to_string(target_result.ivs.hp)); @@ -616,7 +625,15 @@ void StarterRng::program(SingleSwitchProgramEnvironment& env, ProControllerConte env.log(" SpA: " + std::to_string(target_result.ivs.spatk)); env.log(" SpD: " + std::to_string(target_result.ivs.spdef)); env.log(" Spe: " + std::to_string(target_result.ivs.speed)); - + + RngCalibrations calibrations = { + RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, + RNG_CALIBRATION.csf_calibration, + RNG_CALIBRATION.advances_calibration + }; + env.log("Initial Seed calibration (frames): " + std::to_string(calibrations.seed_offset)); + env.log("Initial CSF calibration (frames): " + std::to_string(calibrations.csf_offset)); + env.log("Initial In-game calibration (frames x2): " + std::to_string(calibrations.ingame_offset)); RngAdvanceHistory advance_history; RngCalibrationHistory calibration_history; @@ -690,13 +707,15 @@ void StarterRng::program(SingleSwitchProgramEnvironment& env, ProControllerConte stats.resets++; RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.set_calibrations(calibrations); + RNG_CALIBRATION.reset_hits(); bool shiny_found = check_for_shiny(env.console, context, PokemonFRLG_RngTarget::starters); if (shiny_found){ env.log("Shiny found!"); stats.shinies++; + RNG_CALIBRATION.hits.set("Shiny!"); send_program_notification( env, NOTIFICATION_SHINY, @@ -713,17 +732,12 @@ void StarterRng::program(SingleSwitchProgramEnvironment& env, ProControllerConte } // Stage 1: initial search -- starter received - AdvObservedPokemon pokemon = read_summary(env.console, context, LANGUAGE); + AdvObservedPokemon pokemon = read_summary(env.console, context, LANGUAGE, SPECIES_LIST); AdvRngFilters filters = observation_to_filters(pokemon, BASE_STATS); RNG_FILTERS.set(filters); std::vector search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); bool finished = update_history( env.console, advance_history, calibration_history, MAX_HISTORY_LENGTH, calibrations, search_hits, 1 @@ -752,12 +766,7 @@ void StarterRng::program(SingleSwitchProgramEnvironment& env, ProControllerConte } if (pokemon.level.size() > 1){ search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); env.log("Number of search hits: " + std::to_string(search_hits.size())); finished = update_history( env.console, advance_history, calibration_history, @@ -825,12 +834,7 @@ void StarterRng::program(SingleSwitchProgramEnvironment& env, ProControllerConte if (pokemon.level.size() > num_levels){ num_levels = pokemon.level.size(); search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); env.log("Number of search hits: " + std::to_string(search_hits.size())); update_history( env.console, advance_history, calibration_history, diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.h index a1b01ec170..46bb4c4303 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.h @@ -10,6 +10,7 @@ #include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/FloatingPointOption.h" #include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/StaticTextOption.h" #include "Common/Cpp/Options/TextEditOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "CommonTools/Options/LanguageOCROption.h" @@ -68,27 +69,26 @@ class StarterRng : public SingleSwitchProgramInstance{ const BaseStats& BASE_STATS ); - - OCR::LanguageOCROption LANGUAGE; - - EnumDropdownOption STARTER; - - SimpleIntegerOption MAX_RESETS; - + SectionDividerOption m_calibration_displays; + RngTargetDisplay RNG_TARGET; RngFilterDisplay RNG_FILTERS; RngCalibrationDisplay RNG_CALIBRATION; + SectionDividerOption m_game_info; + OCR::LanguageOCROption LANGUAGE; + + SectionDividerOption m_target_settings; + EnumDropdownOption STARTER; StringOption SEED; TextEditOption SEED_LIST; EnumDropdownOption SEED_BUTTON; EnumDropdownOption EXTRA_BUTTON; SimpleIntegerOption SEED_DELAY; - SimpleIntegerOptionADVANCES; - // SimpleIntegerOptionCONTINUE_SCREEN_FRAMES; + SectionDividerOption m_program_settings; + SimpleIntegerOption MAX_RESETS; BooleanCheckBoxOption IGNORE_WILD_SHINIES; - SimpleIntegerOption PROFILE; BooleanCheckBoxOption TAKE_VIDEO; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp index b009f421c9..7a4ffc3a7a 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp @@ -57,7 +57,13 @@ std::unique_ptr StaticRng_Descriptor::make_stats() const{ } StaticRng::StaticRng() - : LANGUAGE( + : m_calibration_displays( + "Calibration Displays — These will update automatically as the program runs" + ) + , m_game_info( + "Game Information" + ) + , LANGUAGE( "Game Language:", { Language::English, @@ -70,8 +76,11 @@ StaticRng::StaticRng() LockMode::LOCK_WHILE_RUNNING, true ) + , m_target_settings( + "Target Settings — Get these from an RNG search tool" + ) , TARGET( - "Target:
", + "Target:", { {PokemonFRLG_RngTarget::electrode, "electrode", "Electrode"}, {PokemonFRLG_RngTarget::snorlax, "snorlax", "Snorlax"}, @@ -88,25 +97,6 @@ StaticRng::StaticRng() LockMode::LOCK_WHILE_RUNNING, PokemonFRLG_RngTarget::electrode ) - , MAX_RESETS( - "Max Resets:
", - LockMode::UNLOCK_WHILE_RUNNING, - 50, 0 // default, min - ) - , MAX_RARE_CANDIES( - "Max Rare Candies:
" - "The number of rare candies in your bag. Make sure these are at the top position of the bag.
" - "Rare candies used during calibration will be restored after resetting.", - LockMode::UNLOCK_WHILE_RUNNING, - 0, 0, 999 // default, min, max - ) - , MAX_BALL_THROWS( - "Max Balls Thrown:
" - "The number of " + STRING_POKEBALL + "s in your bag to attempt to throw. Make sure these are at the top position of the bag.
" - "Balls thrown during calibration will be restored after resetting.", - LockMode::UNLOCK_WHILE_RUNNING, - 20, 1, 999 // default, min, max - ) , SEED( false, "Target Seed:", @@ -123,7 +113,7 @@ StaticRng::StaticRng() true ) , SEED_BUTTON( - "Seed Button:
", + "Seed Button:", { {SeedButton::A, "A", "A"}, {SeedButton::Start, "Start", "Start"}, @@ -155,11 +145,9 @@ StaticRng::StaticRng() LockMode::LOCK_WHILE_RUNNING, 10000, 520, 1000000000 // default, min ) - // , CONTINUE_SCREEN_FRAMES( - // "Continue Screen Frames:
The number of RNG advances to pass on the continue screen.
This should be less than the total number of advances above.", - // LockMode::LOCK_WHILE_RUNNING, - // 1000, 192 // default, min - // ) + , m_program_settings( + "Program Settings" + ) , USE_TEACHY_TV( "Use Teachy TV:" "
Opens the Teachy TV to quickly advance the RNG at 313x speed.
" @@ -167,6 +155,25 @@ StaticRng::StaticRng() LockMode::LOCK_WHILE_RUNNING, false // default ) + , MAX_RESETS( + "Max Resets:", + LockMode::UNLOCK_WHILE_RUNNING, + 50, 0 // default, min + ) + , MAX_RARE_CANDIES( + "Max Rare Candies:
" + "The number of rare candies in your bag. Make sure these are at the top position of the bag.
" + "Rare candies used during calibration will be restored after resetting.", + LockMode::UNLOCK_WHILE_RUNNING, + 0, 0, 999 // default, min, max + ) + , MAX_BALL_THROWS( + "Max Balls Thrown:
" + "The number of " + STRING_POKEBALL + "s in your bag to attempt to throw. Make sure these are at the top position of the bag.
" + "Balls thrown during calibration will be restored after resetting.", + LockMode::UNLOCK_WHILE_RUNNING, + 20, 1, 999 // default, min, max + ) , PROFILE( "User Profile Position:
" "The position, from left to right, of the Switch profile with the FRLG save you'd like to use.
" @@ -192,21 +199,25 @@ StaticRng::StaticRng() &NOTIFICATION_PROGRAM_FINISH, }) { + PA_ADD_OPTION(m_calibration_displays); + PA_ADD_OPTION(RNG_TARGET); PA_ADD_OPTION(RNG_FILTERS); PA_ADD_OPTION(RNG_CALIBRATION); + PA_ADD_OPTION(m_game_info); PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(TARGET); - PA_ADD_OPTION(MAX_RESETS); - PA_ADD_OPTION(MAX_BALL_THROWS); - PA_ADD_OPTION(MAX_RARE_CANDIES); PA_ADD_OPTION(SEED); PA_ADD_OPTION(SEED_LIST); PA_ADD_OPTION(SEED_BUTTON); PA_ADD_OPTION(EXTRA_BUTTON); PA_ADD_OPTION(SEED_DELAY); PA_ADD_OPTION(ADVANCES); - // PA_ADD_OPTION(CONTINUE_SCREEN_FRAMES); + PA_ADD_OPTION(m_program_settings); PA_ADD_OPTION(USE_TEACHY_TV); + PA_ADD_OPTION(MAX_RESETS); + PA_ADD_OPTION(MAX_BALL_THROWS); + PA_ADD_OPTION(MAX_RARE_CANDIES); PA_ADD_OPTION(PROFILE); PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(GO_HOME_WHEN_DONE); @@ -229,21 +240,17 @@ void StaticRng::program(SingleSwitchProgramEnvironment& env, ProControllerContex home_black_border_check(env.console, context); RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.reset_hits(); const uint16_t TARGET_SEED = parse_seed(env.console, SEED); const std::vector SEED_VALUES = parse_seed_list(env.console, SEED_LIST); const int16_t SEED_POSITION = seed_position_in_list(TARGET_SEED, SEED_VALUES); if (SEED_POSITION == -1){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "StaticRng(): Target Seed is missing from the list of nearby seeds.", - env.console - ); + throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); } - env.log("Target Seed Value (base10): " + std::to_string(TARGET_SEED)); + env.log("Target Seed Value: " + to_hex_string(TARGET_SEED)); BaseStats BASE_STATS; int16_t GENDER_THRESHOLD = -1; @@ -307,16 +314,20 @@ void StaticRng::program(SingleSwitchProgramEnvironment& env, ProControllerContex const uint64_t INITIAL_ADVANCES_RADIUS = USE_TEACHY_TV ? 4096 : 1024; - - RngCalibrations calibrations = { - RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, - RNG_CALIBRATION.csf_calibration, - RNG_CALIBRATION.advances_calibration + static const std::set SPECIES_LIST = { + "electrode", "snorlax", + "articuno", "zapdos", "moltres", "mewtwo" + "hypno", "ho-oh", "lugia", "deoxys" }; + env.log("RNG Target: " + std::to_string(TARGET.current_value())); + env.log("Target Seed: " + to_hex_string(TARGET_SEED)); + env.log("Target Advances: " + std::to_string(ADVANCES)); + AdvRngSearcher searcher(TARGET_SEED, ADVANCES, AdvRngMethod::Method1); AdvPokemonResult target_result = searcher.generate_pokemon(); - env.log("Target PID (base 10): " + std::to_string(target_result.pid)); + RNG_TARGET.set_target(target_result, GENDER_THRESHOLD); + env.log("Target PID: " + to_hex_string(target_result.pid)); env.log("Target Nature: " + nature_to_string(target_result.nature)); env.log("Target IVs:"); env.log(" HP: " + std::to_string(target_result.ivs.hp)); @@ -326,6 +337,15 @@ void StaticRng::program(SingleSwitchProgramEnvironment& env, ProControllerContex env.log(" SpD: " + std::to_string(target_result.ivs.spdef)); env.log(" Spe: " + std::to_string(target_result.ivs.speed)); + RngCalibrations calibrations = { + RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, + RNG_CALIBRATION.csf_calibration, + RNG_CALIBRATION.advances_calibration + }; + env.log("Initial Seed calibration (frames): " + std::to_string(calibrations.seed_offset)); + env.log("Initial CSF calibration (frames): " + std::to_string(calibrations.csf_offset)); + env.log("Initial In-game calibration (frames x2): " + std::to_string(calibrations.ingame_offset)); + RngAdvanceHistory advance_history; RngCalibrationHistory calibration_history; @@ -343,13 +363,7 @@ void StaticRng::program(SingleSwitchProgramEnvironment& env, ProControllerContex } if (failed_searches >= 5){ - env.log("Failed to find any matches 5 times in a row"); - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "Failed to find any matches 5 times in a row. Check your seed and advances settings.", - env.console - ); - break; + throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); } if (stats.resets > MAX_RESETS){ @@ -391,13 +405,15 @@ void StaticRng::program(SingleSwitchProgramEnvironment& env, ProControllerContex stats.resets++; RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.set_calibrations(calibrations); + RNG_CALIBRATION.reset_hits(); bool shiny_found = check_for_shiny(env.console, context, TARGET); if (shiny_found){ env.log("Shiny found!"); stats.shinies++; + RNG_CALIBRATION.hits.set("Shiny!"); send_program_notification( env, NOTIFICATION_SHINY, @@ -427,17 +443,12 @@ void StaticRng::program(SingleSwitchProgramEnvironment& env, ProControllerContex } go_to_summary(env.console, context); - AdvObservedPokemon pokemon = read_summary(env.console, context, LANGUAGE); + AdvObservedPokemon pokemon = read_summary(env.console, context, LANGUAGE, SPECIES_LIST); AdvRngFilters filters = observation_to_filters(pokemon, BASE_STATS); RNG_FILTERS.set(filters); std::vector search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); bool finished = update_history( env.console, advance_history, calibration_history, MAX_HISTORY_LENGTH, calibrations, search_hits, 1 @@ -458,12 +469,7 @@ void StaticRng::program(SingleSwitchProgramEnvironment& env, ProControllerContex RNG_FILTERS.set(filters); search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); bool force_finish = failed || (i == (MAX_RARE_CANDIES - 1)); finished = update_history( diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.h index 9f82cf7fe1..a36c3f5cfa 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.h @@ -10,6 +10,7 @@ #include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/FloatingPointOption.h" #include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/StaticTextOption.h" #include "Common/Cpp/Options/TextEditOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "CommonTools/Options/LanguageOCROption.h" @@ -45,27 +46,28 @@ class StaticRng : public SingleSwitchProgramInstance{ bool have_hit_target(SingleSwitchProgramEnvironment& env, const uint32_t& TARGET_SEED, const AdvRngState& hit); - OCR::LanguageOCROption LANGUAGE; - - EnumDropdownOption TARGET; - - SimpleIntegerOption MAX_RESETS; - SimpleIntegerOption MAX_RARE_CANDIES; - SimpleIntegerOption MAX_BALL_THROWS; - + SectionDividerOption m_calibration_displays; + RngTargetDisplay RNG_TARGET; RngFilterDisplay RNG_FILTERS; RngCalibrationDisplay RNG_CALIBRATION; + SectionDividerOption m_game_info; + OCR::LanguageOCROption LANGUAGE; + + SectionDividerOption m_target_settings; + EnumDropdownOption TARGET; StringOption SEED; TextEditOption SEED_LIST; EnumDropdownOption SEED_BUTTON; EnumDropdownOption EXTRA_BUTTON; SimpleIntegerOption SEED_DELAY; - SimpleIntegerOptionADVANCES; + SectionDividerOption m_program_settings; BooleanCheckBoxOption USE_TEACHY_TV; - + SimpleIntegerOption MAX_RESETS; + SimpleIntegerOption MAX_RARE_CANDIES; + SimpleIntegerOption MAX_BALL_THROWS; SimpleIntegerOption PROFILE; BooleanCheckBoxOption TAKE_VIDEO; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp index 293931f1f2..3220df07f5 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp @@ -62,7 +62,22 @@ std::unique_ptr WildRng_Descriptor::make_stats() const{ } WildRng::WildRng() - : LANGUAGE( + : m_calibration_displays( + "Calibration Displays — These will update automatically as the program runs" + ) + , m_game_info( + "Game Information" + ) + , GAME_VERSION( + "Game Version:", + { + {GameVersion::firered, "firered", "FireRed"}, + {GameVersion::leafgreen, "leafgreen", "LeafGreen"} + }, + LockMode::LOCK_WHILE_RUNNING, + GameVersion::firered + ) + , LANGUAGE( "Game Language:", { Language::English, @@ -75,14 +90,8 @@ WildRng::WildRng() LockMode::LOCK_WHILE_RUNNING, true ) - , GAME_VERSION( - "Game Version:", - { - {GameVersion::firered, "firered", "FireRed"}, - {GameVersion::leafgreen, "leafgreen", "LeafGreen"} - }, - LockMode::LOCK_WHILE_RUNNING, - GameVersion::firered + , m_target_settings( + "Target Settings — Get these from an RNG search tool" ) , ENCOUNTER_TYPE( "Encounter Type:", @@ -104,24 +113,18 @@ WildRng::WildRng() LockMode::LOCK_WHILE_RUNNING, "route_1" ) - , MAX_RESETS( - "Max Resets:
", - LockMode::UNLOCK_WHILE_RUNNING, - 50, 0 // default, min - ) - , MAX_RARE_CANDIES( - "Max Rare Candies:
" - "The number of rare candies in your bag. Make sure these are at the top position of the bag.
" - "Rare candies used during calibration will be restored after resetting.", - LockMode::UNLOCK_WHILE_RUNNING, - 0, 0, 999 // default, min, max - ) - , MAX_BALL_THROWS( - "Max Balls Thrown:
" - "The number of " + STRING_POKEBALL + "s in your bag to attempt to throw. Make sure these are at the top position of the bag.
" - "Balls thrown during calibration will be restored after resetting.", - LockMode::UNLOCK_WHILE_RUNNING, - 20, 1, 999 // default, min, max + , RNG_METHOD( + "RNG Method:
" + "This should usually be set to Method1 for Grass encounters.
" + "All RNG methods are checked during calibration regardless of this setting.", + { + {AdvRngMethod::Method1, "Method1", "Method1"}, + {AdvRngMethod::Method2, "Method2", "Method2"}, + {AdvRngMethod::Method4, "Method4", "Method4"}, + + }, + LockMode::LOCK_WHILE_RUNNING, + AdvRngMethod::Method1 ) , SEED( false, @@ -139,7 +142,7 @@ WildRng::WildRng() true ) , SEED_BUTTON( - "Seed Button:
", + "Seed Button:", { {SeedButton::A, "A", "A"}, {SeedButton::Start, "Start", "Start"}, @@ -171,11 +174,9 @@ WildRng::WildRng() LockMode::LOCK_WHILE_RUNNING, 10000, 700, 1000000000 // default, min ) - // , CONTINUE_SCREEN_FRAMES( - // "Continue Screen Frames:
The number of RNG advances to pass on the continue screen.
This should be less than the total number of advances above.", - // LockMode::LOCK_WHILE_RUNNING, - // 1000, 192 // default, min - // ) + , m_program_settings( + "Program Settings" + ) , USE_TEACHY_TV( "Use Teachy TV:" "
Opens the Teachy TV to quickly advance the RNG at 313x speed.
" @@ -183,6 +184,25 @@ WildRng::WildRng() LockMode::LOCK_WHILE_RUNNING, false // default ) + , MAX_RESETS( + "Max Resets:", + LockMode::UNLOCK_WHILE_RUNNING, + 50, 0 // default, min + ) + , MAX_RARE_CANDIES( + "Max Rare Candies:
" + "The number of rare candies in your bag. Make sure these are at the top position of the bag.
" + "Rare candies used during calibration will be restored after resetting.", + LockMode::UNLOCK_WHILE_RUNNING, + 0, 0, 999 // default, min, max + ) + , MAX_BALL_THROWS( + "Max Balls Thrown:
" + "The number of " + STRING_POKEBALL + "s in your bag to attempt to throw. Make sure these are at the top position of the bag.
" + "Balls thrown during calibration will be restored after resetting.", + LockMode::UNLOCK_WHILE_RUNNING, + 20, 1, 999 // default, min, max + ) , PROFILE( "User Profile Position:
" "The position, from left to right, of the Switch profile with the FRLG save you'd like to use.
" @@ -208,23 +228,28 @@ WildRng::WildRng() &NOTIFICATION_PROGRAM_FINISH, }) { + PA_ADD_OPTION(m_calibration_displays); + PA_ADD_OPTION(RNG_TARGET); PA_ADD_OPTION(RNG_FILTERS); PA_ADD_OPTION(RNG_CALIBRATION); - PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(m_game_info); PA_ADD_OPTION(GAME_VERSION); + PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(ENCOUNTER_TYPE); PA_ADD_OPTION(GAME_LOCATION); - PA_ADD_OPTION(MAX_RESETS); - PA_ADD_OPTION(MAX_BALL_THROWS); - PA_ADD_OPTION(MAX_RARE_CANDIES); + PA_ADD_OPTION(RNG_METHOD); PA_ADD_OPTION(SEED); PA_ADD_OPTION(SEED_LIST); PA_ADD_OPTION(SEED_BUTTON); PA_ADD_OPTION(EXTRA_BUTTON); PA_ADD_OPTION(SEED_DELAY); PA_ADD_OPTION(ADVANCES); - // PA_ADD_OPTION(CONTINUE_SCREEN_FRAMES); + PA_ADD_OPTION(m_program_settings); PA_ADD_OPTION(USE_TEACHY_TV); + PA_ADD_OPTION(MAX_RESETS); + PA_ADD_OPTION(MAX_BALL_THROWS); + PA_ADD_OPTION(MAX_RARE_CANDIES); PA_ADD_OPTION(PROFILE); PA_ADD_OPTION(TAKE_VIDEO); PA_ADD_OPTION(GO_HOME_WHEN_DONE); @@ -247,7 +272,7 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& home_black_border_check(env.console, context); RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.reset_hits(); // prepare database of base stats and gender thresholds RngStatsDatabase STATS_DATA("PokemonFRLG/BaseStats.json"); @@ -265,11 +290,7 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& std::map> location_map = encounters_data.get_throw(enc_slug); if (location_map.find(loc_slug)==location_map.end()){ - OperationFailedException::fire( - ErrorReport::NO_ERROR_REPORT, - "Invalid combination for encounter type and location.", - env.console - ); + throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); } std::vector ENCOUNTER_SLOTS = location_map.find(loc_slug)->second; @@ -295,14 +316,10 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& const int16_t SEED_POSITION = seed_position_in_list(TARGET_SEED, SEED_VALUES); if (SEED_POSITION == -1){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "WildRng(): Target Seed is missing from the list of nearby seeds.", - env.console - ); + throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); } - env.log("Target Seed Value (base10): " + std::to_string(TARGET_SEED)); + env.log("Target Seed Value: " + to_hex_string(TARGET_SEED)); PokemonFRLG_RngTarget TARGET = PokemonFRLG_RngTarget::sweetscent; @@ -356,27 +373,36 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& const uint8_t MAX_HISTORY_LENGTH = USE_TEACHY_TV ? 2 : 10; + env.log("Game Location: " + loc_slug); + env.log("Encounter Type: " + enc_slug); + env.log("Target Seed: " + to_hex_string(TARGET_SEED)); + env.log("Target Advances: " + std::to_string(ADVANCES)); - RngCalibrations calibrations = { - RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, - RNG_CALIBRATION.csf_calibration, - RNG_CALIBRATION.advances_calibration - }; - - AdvRngWildSearcher searcher(TARGET_SEED, ADVANCES, ENCOUNTER_SLOTS, AdvRngMethod::Any); + AdvRngWildSearcher searcher(TARGET_SEED, ADVANCES, ENCOUNTER_SLOTS, RNG_METHOD); AdvWildPokemonResult target_result = searcher.generate_pokemon(SUPER_ROD); + RNG_TARGET.set_target(target_result, STATS_DATA.get_nothrow(target_result.species)->gender_threshold); env.log("Target Species: " + target_result.species); env.log("Target Level: " + std::to_string(target_result.level)); env.log("Target Encounter Slot: " + std::to_string(target_result.slot)); - env.log("Target PID (base10): " + std::to_string(target_result.pid)); + env.log("Target PID: " + to_hex_string(target_result.pid)); env.log("Target Nature: " + nature_to_string(target_result.nature)); - env.log("Target IVs (assuming Method 1):"); + env.log("Target IVs:"); env.log(" HP: " + std::to_string(target_result.ivs.hp)); env.log(" Atk: " + std::to_string(target_result.ivs.attack)); env.log(" Def: " + std::to_string(target_result.ivs.defense)); env.log(" SpA: " + std::to_string(target_result.ivs.spatk)); env.log(" SpD: " + std::to_string(target_result.ivs.spdef)); env.log(" Spe: " + std::to_string(target_result.ivs.speed)); + + RngCalibrations calibrations = { + RNG_CALIBRATION.seed_calibration / FRLG_FRAME_DURATION, + RNG_CALIBRATION.csf_calibration, + RNG_CALIBRATION.advances_calibration + }; + env.log("Initial Seed calibration (frames): " + std::to_string(calibrations.seed_offset)); + env.log("Initial CSF calibration (frames): " + std::to_string(calibrations.csf_offset)); + env.log("Initial In-game calibration (frames x2): " + std::to_string(calibrations.ingame_offset)); + RngAdvanceHistory advance_history; RngCalibrationHistory calibration_history; @@ -442,7 +468,8 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& stats.resets++; RNG_FILTERS.reset(); - RNG_CALIBRATION.reset(); + RNG_CALIBRATION.set_calibrations(calibrations); + RNG_CALIBRATION.reset_hits(); int ret = watch_for_shiny_encounter(env.console, context); if (ret < 0){ @@ -462,6 +489,7 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& if (shiny_found){ env.log("Shiny found!"); stats.shinies++; + RNG_CALIBRATION.hits.set("Shiny!"); send_program_notification( env, NOTIFICATION_SHINY, @@ -507,12 +535,7 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& RNG_FILTERS.set(filters); std::vector search_hits = get_wild_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, gender_threshold, SUPER_ROD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); bool finished = update_history(env.console, advance_history, calibration_history, MAX_HISTORY_LENGTH, calibrations, search_hits, 1); finished = finished || all_indistinguishable(search_hits, searcher, gender_threshold, SUPER_ROD); @@ -530,12 +553,7 @@ void WildRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& } search_hits = get_wild_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, gender_threshold, SUPER_ROD); - RNG_CALIBRATION.set( - calibrations.seed_offset * FRLG_FRAME_DURATION, - calibrations.csf_offset, - calibrations.ingame_offset, - search_hits - ); + RNG_CALIBRATION.set_hits(search_hits); bool force_finish = failed || (i == (MAX_RARE_CANDIES - 1)); finished = update_history( diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.h index 47ee18a032..481bf7c779 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.h @@ -10,6 +10,7 @@ #include "Common/Cpp/Options/SimpleIntegerOption.h" #include "Common/Cpp/Options/FloatingPointOption.h" #include "Common/Cpp/Options/BooleanCheckBoxOption.h" +#include "Common/Cpp/Options/StaticTextOption.h" #include "Common/Cpp/Options/TextEditOption.h" #include "CommonFramework/Notifications/EventNotificationsTable.h" #include "CommonTools/Options/LanguageOCROption.h" @@ -60,31 +61,32 @@ class WildRng : public SingleSwitchProgramInstance{ bool have_hit_target(SingleSwitchProgramEnvironment& env, const uint32_t& TARGET_SEED, const AdvRngState& hit); - OCR::LanguageOCROption LANGUAGE; + SectionDividerOption m_calibration_displays; + RngTargetDisplay RNG_TARGET; + RngFilterDisplay RNG_FILTERS; + RngCalibrationDisplay RNG_CALIBRATION; + SectionDividerOption m_game_info; EnumDropdownOption GAME_VERSION; - EnumDropdownOption ENCOUNTER_TYPE; + OCR::LanguageOCROption LANGUAGE; + SectionDividerOption m_target_settings; + EnumDropdownOption ENCOUNTER_TYPE; StringSelectDatabase LOCATIONS_DATABASE; StringSelectOption GAME_LOCATION; - - SimpleIntegerOption MAX_RESETS; - SimpleIntegerOption MAX_RARE_CANDIES; - SimpleIntegerOption MAX_BALL_THROWS; - - RngFilterDisplay RNG_FILTERS; - RngCalibrationDisplay RNG_CALIBRATION; - + EnumDropdownOption RNG_METHOD; StringOption SEED; TextEditOption SEED_LIST; EnumDropdownOption SEED_BUTTON; EnumDropdownOption EXTRA_BUTTON; SimpleIntegerOption SEED_DELAY; - SimpleIntegerOptionADVANCES; + SectionDividerOption m_program_settings; BooleanCheckBoxOption USE_TEACHY_TV; - + SimpleIntegerOption MAX_RESETS; + SimpleIntegerOption MAX_RARE_CANDIES; + SimpleIntegerOption MAX_BALL_THROWS; SimpleIntegerOption PROFILE; BooleanCheckBoxOption TAKE_VIDEO; From 055c1cd5f7d07768abee6f093f9fee9072d70d8c Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Tue, 19 May 2026 21:47:54 -0500 Subject: [PATCH 2/4] add missing return after safarizonewest blind sequence --- .../Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp index c5c4b73ab8..ce40abe0b2 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_BlindNavigation.cpp @@ -779,6 +779,7 @@ void perform_blind_sequence( modified_ingame_delay = timings.ingame_delay - 51430; walk_to_safarizonewest(context); use_sweet_scent(context, modified_ingame_delay, true); + return; case PokemonFRLG_RngTarget::safarizonesurf: modified_ingame_delay = timings.ingame_delay - 30300; walk_to_safarizonesurf(context); From e7f788941f8bc704875227e9a71c9d3982ef9292 Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Tue, 19 May 2026 22:11:16 -0500 Subject: [PATCH 3/4] oops --- .../Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp index e4031757dc..b19cf56a1a 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngDisplays.cpp @@ -79,8 +79,8 @@ RngFilterDisplay::RngFilterDisplay() , species(false, "Species:", LockMode::READ_ONLY, "-", "") , gender(false, "Gender:", LockMode::READ_ONLY, "-", "") , nature(false, "Nature:", LockMode::READ_ONLY, "-", "") - , hp(false, "HP IV:", LockMode::READ_ONLY, "-", "") , level(false, "Level:", LockMode::READ_ONLY, "-", "") + , hp(false, "HP IV:", LockMode::READ_ONLY, "-", "") , atk(false, "Attack IV:", LockMode::READ_ONLY, "-", "") , def(false, "Defense IV:", LockMode::READ_ONLY, "-", "") , spatk(false, "Special Attack IV:", LockMode::READ_ONLY, "-", "") From e7b807d0f0f9ca7985d2ac6d329ab0687ff2d42e Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Tue, 19 May 2026 22:24:49 -0500 Subject: [PATCH 4/4] avoid non-ascii characters for gender --- SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp b/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp index a4b3b1a536..bc0d4c147a 100644 --- a/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp +++ b/SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp @@ -650,9 +650,9 @@ AdvRngFilters observation_to_filters(const AdvObservedPokemon& observation, cons std::string gender_to_string(const AdvGender& gender){ switch (gender){ case AdvGender::Male: - return "♂"; + return "\u2642"; case AdvGender::Female: - return "♀"; + return "\u2640"; default: return "-"; }