From a808ef794f2f181a8dff880df2c90bd8f02c5a76 Mon Sep 17 00:00:00 2001 From: theAstrogoth Date: Fri, 24 Jul 2026 15:41:08 -0500 Subject: [PATCH] add FRLG SeedsDatabase and simplify RNG program UI --- .../RngManipulation/PokemonFRLG_EggRng.cpp | 135 ++++--------- .../RngManipulation/PokemonFRLG_EggRng.h | 15 +- .../RngManipulation/PokemonFRLG_GiftRng.cpp | 85 ++++---- .../RngManipulation/PokemonFRLG_GiftRng.h | 14 +- .../PokemonFRLG_RngLoopRoutines.h | 6 +- .../PokemonFRLG_RoamingLegendaryRng.cpp | 85 ++++---- .../PokemonFRLG_RoamingLegendaryRng.h | 14 +- .../PokemonFRLG_SeedsDatabase.cpp | 182 ++++++++++++++++++ .../PokemonFRLG_SeedsDatabase.h | 68 +++++++ .../PokemonFRLG_StarterRng.cpp | 86 ++++----- .../RngManipulation/PokemonFRLG_StarterRng.h | 15 +- .../RngManipulation/PokemonFRLG_StaticRng.cpp | 85 ++++---- .../RngManipulation/PokemonFRLG_StaticRng.h | 14 +- .../RngManipulation/PokemonFRLG_WildRng.cpp | 75 +++----- .../RngManipulation/PokemonFRLG_WildRng.h | 9 +- SerialPrograms/cmake/SourceFiles.cmake | 2 + 16 files changed, 527 insertions(+), 363 deletions(-) create mode 100644 SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_SeedsDatabase.cpp create mode 100644 SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_SeedsDatabase.h diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.cpp index 1c496b7215..629e337a6a 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.cpp @@ -143,6 +143,16 @@ EggRng::EggRng() LockMode::LOCK_WHILE_RUNNING, GameVersion::firered ) + , SOUND( + "Sound:
" + "Your in-game sound setting. This affects the possible seeds.", + { + {SoundSetting::Mono, "mono", "Mono"}, + {SoundSetting::Stereo, "stereo", "Stereo"} + }, + LockMode::LOCK_WHILE_RUNNING, + SoundSetting::Mono + ) , m_target_settings("Target Settings") , EGG_SPECIES( "Egg Species:", @@ -166,42 +176,6 @@ EggRng::EggRng() "70FE", "70FE", true ) - , HELD_SEED_LIST( - "Nearby Held Seeds:
" - "This box should contain a list of seeds (in order) around and including your held seed, with one seed on each line", - LockMode::LOCK_WHILE_RUNNING, - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - true - ) - , HELD_SEED_BUTTON( - "Held Seed Button:
", - { - {SeedButton::A, "A", "A"}, - {SeedButton::Start, "Start", "Start"}, - {SeedButton::L, "L", "L (L=A)"}, - }, - LockMode::LOCK_WHILE_RUNNING, - SeedButton::A - ) - , HELD_EXTRA_BUTTON( - "Held Seed Extra Button:
" - "Additional button presses that affect the seed.", - { - {BlackoutButton::None, "None", "None"}, - {BlackoutButton::L, "L", "Blackout L"}, - {BlackoutButton::R, "R", "Blackout R"}, - }, - LockMode::LOCK_WHILE_RUNNING, - BlackoutButton::None - ) - , HELD_SEED_DELAY( - "Held Seed Delay Time (ms):
" - "The delay between starting the game and advancing past the title screen. Set this to match your held seed.
" - "If using Ten Lines, select Nintendo Switch 1 as your console even if using a Switch 2.", - LockMode::LOCK_WHILE_RUNNING, - 31338, 30400 // default, min - ) , HELD_ADVANCES( "Held Advances:
The total number of RNG advances for your held target.", LockMode::LOCK_WHILE_RUNNING, @@ -215,48 +189,18 @@ EggRng::EggRng() "70FE", "70FE", true ) - , PICKUP_SEED_LIST( - "Nearby Pickup Seeds:
" - "This box should contain a list of seeds (in order) around and including your held seed, with one seed on each line", - LockMode::LOCK_WHILE_RUNNING, - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - true - ) - , PICKUP_SEED_BUTTON( - "Pickup Seed Button:
", - { - {SeedButton::A, "A", "A"}, - {SeedButton::Start, "Start", "Start"}, - {SeedButton::L, "L", "L (L=A)"}, - }, - LockMode::LOCK_WHILE_RUNNING, - SeedButton::A - ) - , PICKUP_EXTRA_BUTTON( - "Pickup Seed Extra Button:
" - "Additional button presses that affect the seed.", - { - {BlackoutButton::None, "None", "None"}, - {BlackoutButton::L, "L", "Blackout L"}, - {BlackoutButton::R, "R", "Blackout R"}, - }, - LockMode::LOCK_WHILE_RUNNING, - BlackoutButton::None - ) - , PICKUP_SEED_DELAY( - "Pickup Seed Delay Time (ms):
" - "The delay between starting the game and advancing past the title screen. Set this to match your held seed.
" - "If using Ten Lines, select Nintendo Switch 1 as your console even if using a Switch 2.", - LockMode::LOCK_WHILE_RUNNING, - 31338, 30400 // default, min - ) , PICKUP_ADVANCES( "Pickup Advances:
The total number of RNG advances for your pickup target.", LockMode::LOCK_WHILE_RUNNING, 10000, 700, 1000000000 // default, min ) , m_program_settings("Program Settings") + , SEED_RADIUS( + "Nearby Seed Radius:
" + "The number of nearby seeds on each side of the target to search when identifying which seed was hit.", + LockMode::LOCK_WHILE_RUNNING, + 5, 1 // default, min + ) , STARTING_POINT( "Starting Point:", { @@ -319,25 +263,19 @@ EggRng::EggRng() PA_ADD_OPTION(m_game_info); PA_ADD_OPTION(LANGUAGE); PA_ADD_OPTION(GAME_VERSION); + PA_ADD_OPTION(SOUND); PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(EGG_SPECIES); PA_ADD_OPTION(COMPATIBILITY); PA_ADD_OPTION(PARENT_IVS); PA_ADD_OPTION(m_held_settings); PA_ADD_OPTION(HELD_SEED); - PA_ADD_OPTION(HELD_SEED_LIST); - PA_ADD_OPTION(HELD_SEED_BUTTON); - PA_ADD_OPTION(HELD_EXTRA_BUTTON); - PA_ADD_OPTION(HELD_SEED_DELAY); PA_ADD_OPTION(HELD_ADVANCES); PA_ADD_OPTION(m_pickup_settings); PA_ADD_OPTION(PICKUP_SEED); - PA_ADD_OPTION(PICKUP_SEED_LIST); - PA_ADD_OPTION(PICKUP_SEED_BUTTON); - PA_ADD_OPTION(PICKUP_EXTRA_BUTTON); - PA_ADD_OPTION(PICKUP_SEED_DELAY); PA_ADD_OPTION(PICKUP_ADVANCES); PA_ADD_OPTION(m_program_settings); + PA_ADD_OPTION(SEED_RADIUS); PA_ADD_OPTION(STARTING_POINT); PA_ADD_OPTION(MAX_RESETS); PA_ADD_OPTION(MAX_BALL_THROWS); @@ -404,6 +342,8 @@ bool EggRng::reset_and_check_seed( const uint64_t& SEED_DELAY = frame_target.seed_delay; const std::vector& SEED_VALUES = frame_target.seed_values; const int16_t& SEED_POSITION = frame_target.seed_position; + const SeedButton& SEED_BUTTON = frame_target.seed_button; + const BlackoutButton& EXTRA_BUTTON = frame_target.extra_button; static const int64_t FIXED_SEED_OFFSET = -845; // ms, approximate const int64_t FIXED_ADVANCES_OFFSET = pickup_frame ? -246 : 135; // frames, approximate @@ -439,9 +379,8 @@ bool EggRng::reset_and_check_seed( // Step 1: reset and perform blind sequence env.log("Resetting Game..."); reset_and_perform_blind_sequence( - env.console, context, target, - pickup_frame ? PICKUP_SEED_BUTTON : HELD_SEED_BUTTON, - pickup_frame ? PICKUP_EXTRA_BUTTON : HELD_EXTRA_BUTTON, + env.console, context, target, + SEED_BUTTON, EXTRA_BUTTON, timings, launch_delay, false, PROFILE ); stats.resets++; @@ -792,35 +731,37 @@ void EggRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& SPECIES_LIST.emplace(slot.species); } + const SeedsDatabase seeds_db(seeds_json_path(GAME_VERSION == GameVersion::firered, LANGUAGE)); + // held timings const uint16_t TARGET_HELD_SEED = parse_seed(env.console, HELD_SEED); - const std::vector HELD_SEED_VALUES = parse_seed_list(env.console, HELD_SEED_LIST); - const int16_t HELD_SEED_POSITION = seed_position_in_list(TARGET_HELD_SEED, HELD_SEED_VALUES); - if (HELD_SEED_POSITION == -1){ + const SeedMatch held_match = seeds_db.find_seed(TARGET_HELD_SEED, SOUND, SEED_RADIUS); + if (!held_match.found){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "EggRng(): Held Seed is missing from the list of nearby seeds.", + "EggRng(): Held Seed was not found in the seed database for this game version, language, and sound setting.", env.console - ); + ); } - env.log("Target Held Seed Value: " + to_hex_string(TARGET_HELD_SEED)); + env.log("Target Held Seed Value: " + to_hex_string(TARGET_HELD_SEED) + + " (delay " + std::to_string(held_match.seed_delay) + "ms, button mode " + held_match.button_mode + ")"); // pickup timings const uint16_t TARGET_PICKUP_SEED = parse_seed(env.console, PICKUP_SEED); - const std::vector PICKUP_SEED_VALUES = parse_seed_list(env.console, PICKUP_SEED_LIST); - const int16_t PICKUP_SEED_POSITION = seed_position_in_list(TARGET_PICKUP_SEED, PICKUP_SEED_VALUES); - if (PICKUP_SEED_POSITION == -1){ + const SeedMatch pickup_match = seeds_db.find_seed(TARGET_PICKUP_SEED, SOUND, SEED_RADIUS); + if (!pickup_match.found){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "EggRng(): Pickup Seed is missing from the list of nearby seeds.", + "EggRng(): Pickup Seed was not found in the seed database for this game version, language, and sound setting.", env.console - ); + ); } - env.log("Target Pickup Seed Value: " + to_hex_string(TARGET_PICKUP_SEED)); + env.log("Target Pickup Seed Value: " + to_hex_string(TARGET_PICKUP_SEED) + + " (delay " + std::to_string(pickup_match.seed_delay) + "ms, button mode " + pickup_match.button_mode + ")"); EggFrameTargets frame_targets{ - { HELD_SEED_DELAY, HELD_SEED_VALUES, HELD_SEED_POSITION }, - { PICKUP_SEED_DELAY, PICKUP_SEED_VALUES, PICKUP_SEED_POSITION } + { held_match.seed_delay, held_match.seed_values, held_match.seed_position, held_match.seed_button, held_match.extra_button }, + { pickup_match.seed_delay, pickup_match.seed_values, pickup_match.seed_position, pickup_match.seed_button, pickup_match.extra_button } }; // searchers diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.h index 2e2fc59ddf..1d1d31815c 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_EggRng.h @@ -23,6 +23,7 @@ #include "PokemonFRLG_RngStatsDatabase.h" #include "PokemonFRLG_RngDisplays.h" #include "PokemonFRLG_RngLoopRoutines.h" +#include "PokemonFRLG_SeedsDatabase.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -146,6 +147,7 @@ class EggRng : public SingleSwitchProgramInstance, public ConfigOption::Listener SectionDividerOption m_game_info; OCR::LanguageOCROption LANGUAGE; EnumDropdownOption GAME_VERSION; + EnumDropdownOption SOUND; SectionDividerOption m_target_settings; PokemonNameSelectOption EGG_SPECIES; @@ -153,22 +155,15 @@ class EggRng : public SingleSwitchProgramInstance, public ConfigOption::Listener ParentIVsTable PARENT_IVS; SectionDividerOption m_held_settings; - StringOption HELD_SEED; - TextEditOption HELD_SEED_LIST; - EnumDropdownOption HELD_SEED_BUTTON; - EnumDropdownOption HELD_EXTRA_BUTTON; - SimpleIntegerOption HELD_SEED_DELAY; + StringOption HELD_SEED; SimpleIntegerOptionHELD_ADVANCES; SectionDividerOption m_pickup_settings; - StringOption PICKUP_SEED; - TextEditOption PICKUP_SEED_LIST; - EnumDropdownOption PICKUP_SEED_BUTTON; - EnumDropdownOption PICKUP_EXTRA_BUTTON; - SimpleIntegerOption PICKUP_SEED_DELAY; + StringOption PICKUP_SEED; SimpleIntegerOptionPICKUP_ADVANCES; SectionDividerOption m_program_settings; + SimpleIntegerOption SEED_RADIUS; EnumDropdownOption STARTING_POINT; SimpleIntegerOption MAX_RESETS; SimpleIntegerOption MAX_RARE_CANDIES; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp index 6bb33be2f9..523a6dc47f 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp @@ -67,6 +67,15 @@ GiftRng::GiftRng() , 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:", { @@ -80,6 +89,16 @@ GiftRng::GiftRng() LockMode::LOCK_WHILE_RUNNING, true ) + , SOUND( + "Sound:
" + "Your in-game sound setting. This affects the possible seeds.", + { + {SoundSetting::Mono, "mono", "Mono"}, + {SoundSetting::Stereo, "stereo", "Stereo"} + }, + LockMode::LOCK_WHILE_RUNNING, + SoundSetting::Mono + ) , m_target_settings( "Target Settings — Get these from an RNG search tool" ) @@ -113,43 +132,6 @@ GiftRng::GiftRng() "70FE", "70FE", true ) - , SEED_LIST( - "Nearby Seeds:
" - "This box should contain a list of seeds (in order) around and including your target seed, with one seed on each line", - LockMode::LOCK_WHILE_RUNNING, - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - true - ) - , SEED_BUTTON( - "Seed Button:", - { - {SeedButton::A, "A", "A"}, - {SeedButton::Start, "Start", "Start"}, - {SeedButton::L, "L", "L (L=A)"}, - }, - LockMode::LOCK_WHILE_RUNNING, - SeedButton::A - ) - , EXTRA_BUTTON( - "Extra Button:
" - "Additional button presses that affect the seed.", - { - {BlackoutButton::None, "None", "None"}, - {BlackoutButton::L, "L", "Blackout L"}, - {BlackoutButton::R, "R", "Blackout R"}, - }, - LockMode::LOCK_WHILE_RUNNING, - BlackoutButton::None - ) - , SEED_DELAY( - "Seed Delay Time (ms):
" - "The delay between starting the game and advancing past the title screen. Set this to match your target seed.
" - "If using Ten Lines for seed info, select Nintendo Switch 1 as your console even if using a Switch 2.
" - "Warning: values close to 30500ms can sometimes cause problems, and you may need to manually increase your initial seed calibration or pick a new target.", - LockMode::LOCK_WHILE_RUNNING, - 31338, 30400 // default, min - ) , ADVANCES( "Advances:
The total number of RNG advances for your target.", LockMode::LOCK_WHILE_RUNNING, @@ -165,6 +147,12 @@ GiftRng::GiftRng() LockMode::LOCK_WHILE_RUNNING, false // default ) + , SEED_RADIUS( + "Nearby Seed Radius:
" + "The number of nearby seeds on each side of the target to search when identifying which seed was hit.", + LockMode::LOCK_WHILE_RUNNING, + 5, 1 // default, min + ) , MAX_RESETS( "Max Resets:", LockMode::UNLOCK_WHILE_RUNNING, @@ -207,17 +195,16 @@ GiftRng::GiftRng() PA_ADD_OPTION(RNG_FILTERS); PA_ADD_OPTION(RNG_CALIBRATION); PA_ADD_OPTION(m_game_info); + PA_ADD_OPTION(GAME_VERSION); PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(SOUND); PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(TARGET); 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(m_program_settings); PA_ADD_OPTION(USE_TEACHY_TV); + PA_ADD_OPTION(SEED_RADIUS); PA_ADD_OPTION(MAX_RESETS); PA_ADD_OPTION(MAX_RARE_CANDIES); PA_ADD_OPTION(PROFILE); @@ -241,12 +228,18 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext& 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){ - throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); + SeedsDatabase seeds_db(seeds_json_path(GAME_VERSION == GameVersion::firered, LANGUAGE)); + const SeedMatch seed_match = seeds_db.find_seed(TARGET_SEED, SOUND, SEED_RADIUS); + if (!seed_match.found){ + throw UserSetupError(env.console, "The target Seed was not found in the seed database for this game version, language, and sound setting."); } + const std::vector SEED_VALUES = seed_match.seed_values; + const int16_t SEED_POSITION = seed_match.seed_position; + const uint64_t SEED_DELAY = seed_match.seed_delay; + const SeedButton SEED_BUTTON = seed_match.seed_button; + const BlackoutButton EXTRA_BUTTON = seed_match.extra_button; + env.log("Seed delay: " + std::to_string(SEED_DELAY) + "ms, button mode: " + seed_match.button_mode + + ", column: " + seed_match.column_name); BaseStats BASE_STATS; int16_t GENDER_THRESHOLD = -1; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h index 5356f09ef0..a20c749915 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.h @@ -21,6 +21,7 @@ #include "PokemonFRLG_BlindNavigation.h" #include "PokemonFRLG_RngCalibration.h" #include "PokemonFRLG_RngDisplays.h" +#include "PokemonFRLG_SeedsDatabase.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -43,6 +44,10 @@ class GiftRng : public SingleSwitchProgramInstance{ ) override{} private: + enum class GameVersion{ + firered, + leafgreen + }; SectionDividerOption m_calibration_displays; RngTargetDisplay RNG_TARGET; @@ -50,19 +55,18 @@ class GiftRng : public SingleSwitchProgramInstance{ RngCalibrationDisplay RNG_CALIBRATION; SectionDividerOption m_game_info; + EnumDropdownOption GAME_VERSION; OCR::LanguageOCROption LANGUAGE; + EnumDropdownOption SOUND; SectionDividerOption m_target_settings; EnumDropdownOption TARGET; - StringOption SEED; - TextEditOption SEED_LIST; - EnumDropdownOption SEED_BUTTON; - EnumDropdownOption EXTRA_BUTTON; - SimpleIntegerOption SEED_DELAY; + StringOption SEED; SimpleIntegerOptionADVANCES; SectionDividerOption m_program_settings; BooleanCheckBoxOption USE_TEACHY_TV; + SimpleIntegerOption SEED_RADIUS; SimpleIntegerOption MAX_RESETS; SimpleIntegerOption MAX_RARE_CANDIES; SimpleIntegerOption PROFILE; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngLoopRoutines.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngLoopRoutines.h index 7e217cc69c..89dc40eeee 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngLoopRoutines.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RngLoopRoutines.h @@ -17,6 +17,7 @@ #include "CommonFramework/Notifications/EventNotificationOption.h" #include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" #include "Pokemon/Pokemon_AdvRng.h" +#include "PokemonFRLG_BlindNavigation.h" #include "PokemonFRLG_RngCalibration.h" #include "PokemonFRLG_RngStatsDatabase.h" @@ -50,11 +51,14 @@ struct EggCalibrationHistories{ } }; -// Per-frame seed configuration: the nearby-seed list, the target's position in it, and the seed delay. +// Per-frame seed configuration: the nearby-seed list, the target's position in it, the seed +// delay, and the button combination (derived from the seed database) that reaches the seed. struct EggFrameTarget{ uint64_t seed_delay; std::vector seed_values; int16_t seed_position; + SeedButton seed_button; + BlackoutButton extra_button; }; struct EggFrameTargets{ EggFrameTarget held; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.cpp index f7ccdad480..3ee66efd53 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.cpp @@ -67,6 +67,15 @@ RoamingLegendaryRng::RoamingLegendaryRng() , 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:", { @@ -80,6 +89,16 @@ RoamingLegendaryRng::RoamingLegendaryRng() LockMode::LOCK_WHILE_RUNNING, true ) + , SOUND( + "Sound:
" + "Your in-game sound setting. This affects the possible seeds.", + { + {SoundSetting::Mono, "mono", "Mono"}, + {SoundSetting::Stereo, "stereo", "Stereo"} + }, + LockMode::LOCK_WHILE_RUNNING, + SoundSetting::Mono + ) , m_target_settings( "Target Settings — Get these from an RNG search tool" ) @@ -100,43 +119,6 @@ RoamingLegendaryRng::RoamingLegendaryRng() "70FE", "70FE", true ) - , SEED_LIST( - "Nearby Seeds:
" - "This box should contain a list of seeds (in order) around and including your target seed, with one seed on each line", - LockMode::LOCK_WHILE_RUNNING, - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - "D000\n199A\n77A1\nAABC\n280C\n70FE\nB573\n02F2\n8084\nA533\nED1E", - true - ) - , SEED_BUTTON( - "Seed Button:", - { - {SeedButton::A, "A", "A"}, - {SeedButton::Start, "Start", "Start"}, - {SeedButton::L, "L", "L (L=A)"}, - }, - LockMode::LOCK_WHILE_RUNNING, - SeedButton::A - ) - , EXTRA_BUTTON( - "Extra Button:
" - "Additional button presses that affect the seed.", - { - {BlackoutButton::None, "None", "None"}, - {BlackoutButton::L, "L", "Blackout L"}, - {BlackoutButton::R, "R", "Blackout R"}, - }, - LockMode::LOCK_WHILE_RUNNING, - BlackoutButton::None - ) - , SEED_DELAY( - "Seed Delay Time (ms):
" - "The delay between starting the game and advancing past the title screen. Set this to match your target seed.
" - "If using Ten Lines for seed info, select Nintendo Switch 1 as your console even if using a Switch 2.
" - "Warning: values close to 30500ms can sometimes cause problems, and you may need to manually increase your initial seed calibration or pick a new target.", - LockMode::LOCK_WHILE_RUNNING, - 31338, 30400 // default, min - ) , ADVANCES( "Advances:
The total number of RNG advances for your target.", LockMode::LOCK_WHILE_RUNNING, @@ -152,6 +134,12 @@ RoamingLegendaryRng::RoamingLegendaryRng() LockMode::LOCK_WHILE_RUNNING, false // default ) + , SEED_RADIUS( + "Nearby Seed Radius:
" + "The number of nearby seeds on each side of the target to search when identifying which seed was hit.", + LockMode::LOCK_WHILE_RUNNING, + 5, 1 // default, min + ) , MAX_RESETS( "Max Resets:", LockMode::UNLOCK_WHILE_RUNNING, @@ -202,17 +190,16 @@ RoamingLegendaryRng::RoamingLegendaryRng() PA_ADD_OPTION(RNG_FILTERS); PA_ADD_OPTION(RNG_CALIBRATION); PA_ADD_OPTION(m_game_info); + PA_ADD_OPTION(GAME_VERSION); PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(SOUND); PA_ADD_OPTION(m_target_settings); PA_ADD_OPTION(TARGET); 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(m_program_settings); PA_ADD_OPTION(USE_TEACHY_TV); + PA_ADD_OPTION(SEED_RADIUS); PA_ADD_OPTION(MAX_RESETS); PA_ADD_OPTION(MAX_RARE_CANDIES); PA_ADD_OPTION(MAX_BALL_THROWS); @@ -237,12 +224,18 @@ void RoamingLegendaryRng::program(SingleSwitchProgramEnvironment& env, ProContro 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){ - throw UserSetupError(env.console, "The target Seed is missing from the list of nearby seeds."); + SeedsDatabase seeds_db(seeds_json_path(GAME_VERSION == GameVersion::firered, LANGUAGE)); + const SeedMatch seed_match = seeds_db.find_seed(TARGET_SEED, SOUND, SEED_RADIUS); + if (!seed_match.found){ + throw UserSetupError(env.console, "The target Seed was not found in the seed database for this game version, language, and sound setting."); } + const std::vector SEED_VALUES = seed_match.seed_values; + const int16_t SEED_POSITION = seed_match.seed_position; + const uint64_t SEED_DELAY = seed_match.seed_delay; + const SeedButton SEED_BUTTON = seed_match.seed_button; + const BlackoutButton EXTRA_BUTTON = seed_match.extra_button; + env.log("Seed delay: " + std::to_string(SEED_DELAY) + "ms, button mode: " + seed_match.button_mode + + ", column: " + seed_match.column_name); BaseStats BASE_STATS; int16_t GENDER_THRESHOLD = -1; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.h b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.h index d12267a9fb..36d4d290fd 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_RoamingLegendaryRng.h @@ -21,6 +21,7 @@ #include "PokemonFRLG_BlindNavigation.h" #include "PokemonFRLG_RngCalibration.h" #include "PokemonFRLG_RngDisplays.h" +#include "PokemonFRLG_SeedsDatabase.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -43,6 +44,10 @@ class RoamingLegendaryRng : public SingleSwitchProgramInstance{ ) override{} private: + enum class GameVersion{ + firered, + leafgreen + }; SectionDividerOption m_calibration_displays; RngTargetDisplay RNG_TARGET; @@ -50,19 +55,18 @@ class RoamingLegendaryRng : public SingleSwitchProgramInstance{ RngCalibrationDisplay RNG_CALIBRATION; SectionDividerOption m_game_info; + EnumDropdownOption GAME_VERSION; OCR::LanguageOCROption LANGUAGE; + EnumDropdownOption SOUND; SectionDividerOption m_target_settings; EnumDropdownOption TARGET; - StringOption SEED; - TextEditOption SEED_LIST; - EnumDropdownOption SEED_BUTTON; - EnumDropdownOption EXTRA_BUTTON; - SimpleIntegerOption SEED_DELAY; + StringOption SEED; SimpleIntegerOptionADVANCES; SectionDividerOption m_program_settings; BooleanCheckBoxOption USE_TEACHY_TV; + SimpleIntegerOption SEED_RADIUS; SimpleIntegerOption MAX_RESETS; SimpleIntegerOption MAX_RARE_CANDIES; SimpleIntegerOption MAX_BALL_THROWS; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_SeedsDatabase.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_SeedsDatabase.cpp new file mode 100644 index 0000000000..e0603f03c9 --- /dev/null +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_SeedsDatabase.cpp @@ -0,0 +1,182 @@ +/* Seeds Database + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "Common/Cpp/Exceptions.h" +#include "Common/Cpp/Json/JsonValue.h" +#include "Common/Cpp/Json/JsonObject.h" +#include "Common/Cpp/Json/JsonArray.h" +#include "CommonFramework/Globals.h" +#include "PokemonFRLG_SeedsDatabase.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonFRLG{ + + +std::string seeds_json_path(bool firered, Language language){ + std::string version = firered ? "FR" : "LG"; + std::string lang = (language == Language::Japanese) ? "Jpn" : "Eng"; + return "PokemonFRLG/RngSeeds/" + version + "_" + lang + ".json"; +} + + +namespace{ + +uint16_t parse_hex_seed(const std::string& text, const std::string& path){ + try{ + size_t consumed = 0; + unsigned long value = std::stoul(text, &consumed, 16); + if (consumed != text.size() || value > 0xFFFF){ + throw FileException(nullptr, PA_CURRENT_FUNCTION, "Invalid seed value: " + text, path); + } + return uint16_t(value); + }catch (const std::invalid_argument&){ + throw FileException(nullptr, PA_CURRENT_FUNCTION, "Invalid seed value: " + text, path); + }catch (const std::out_of_range&){ + throw FileException(nullptr, PA_CURRENT_FUNCTION, "Invalid seed value: " + text, path); + } +} + +// Column names have the form " /