Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ac472b1
add initial adv rng calcs
theastrogoth Apr 12, 2026
1afa8b5
update cmake files
theastrogoth Apr 12, 2026
f4120de
trainer card detection and tid reading
theastrogoth Apr 13, 2026
5581d88
Merge branch 'tag/trainer-card-reader' into tag/sid-finder
theastrogoth Apr 13, 2026
25522ff
fix new files in cmake
theastrogoth Apr 13, 2026
42b79ff
finish up a few missed things
theastrogoth Apr 13, 2026
2e316f6
make constructors public
theastrogoth Apr 13, 2026
536000a
wip commit
theastrogoth Apr 13, 2026
88695a1
cmake
theastrogoth Apr 13, 2026
3b8d036
Merge branch 'tag/frlg-rng' into tag/sid-finder
theastrogoth Apr 13, 2026
68c25b4
expose more public methods
theastrogoth Apr 13, 2026
c689677
Merge branch 'tag/frlg-rng' into tag/sid-finder
theastrogoth Apr 13, 2026
72b37b2
another wip commit
theastrogoth Apr 13, 2026
3178b8b
fix order of operations for shiny type
theastrogoth Apr 13, 2026
3ee86de
Merge branch 'tag/frlg-rng' into tag/sid-finder
theastrogoth Apr 13, 2026
b52e9ba
fix int comparisons
theastrogoth Apr 13, 2026
1fc190c
Merge branch 'tag/frlg-rng' into tag/sid-finder
theastrogoth Apr 13, 2026
b05b0a0
small fixes
theastrogoth Apr 13, 2026
c6811f2
more fixes
theastrogoth Apr 13, 2026
364f2f4
Merge branch 'tag/frlg-rng' into tag/sid-finder
theastrogoth Apr 13, 2026
844cf07
fix panels
theastrogoth Apr 13, 2026
a650f4b
a few tweaks
theastrogoth Apr 13, 2026
854447b
small style fix
theastrogoth Apr 13, 2026
19e0fd3
Merge branch 'tag/frlg-rng' into tag/sid-finder
theastrogoth Apr 13, 2026
189e63c
fix small typo
theastrogoth Apr 13, 2026
c079530
fix string addition
theastrogoth Apr 13, 2026
de9694a
Merge branch 'tag/trainer-card-reader' into tag/sid-finder
theastrogoth Apr 13, 2026
97f5a41
Merge branch 'main' into tag/sid-finder
theastrogoth Apr 21, 2026
5b8e187
update with RNG code reorganization
theastrogoth Apr 21, 2026
f98466d
add logging of delay time
theastrogoth Apr 22, 2026
8a15f71
Merge branch 'main' into tag/sid-finder
theastrogoth Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 50 additions & 27 deletions SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@
namespace PokemonAutomation{
namespace Pokemon{

void level_up_observed_pokemon(AdvObservedPokemon& pokemon, StatReads& newstats, EVs& evyield){
uint8_t newlevel = pokemon.level.back() + 1;
pokemon.level.emplace_back(newlevel);

pokemon.stats.emplace_back(newstats);

EVs old_evs = pokemon.evs.back();
EVs new_evs;
new_evs.hp = old_evs.hp + evyield.hp;
new_evs.attack = old_evs.attack + evyield.attack;
new_evs.defense = old_evs.defense + evyield.defense;
new_evs.spatk = old_evs.spatk + evyield.spatk;
new_evs.spdef = old_evs.spdef + evyield.spdef;
new_evs.speed = old_evs.speed + evyield.speed;
pokemon.evs.emplace_back(new_evs);
}

uint32_t increment_internal_rng_state(uint32_t& state){
return state * 0x41c64e6d + 0x6073;
}
Expand Down Expand Up @@ -66,27 +83,26 @@ AdvAbility ability_from_pid(uint32_t& pid){

AdvIvGroup iv_group_from_state(uint32_t& state){
AdvIvGroup ivgroup;
uint32_t remainingbits = state;
uint32_t remainingbits = state >> 16;

ivgroup.iv0 = (remainingbits & 0xfffff) % 32;
remainingbits = remainingbits >> 5;
ivgroup.iv1 = (remainingbits & 0xfffff) % 32;
ivgroup.iv0 = remainingbits & 0x1f;
remainingbits = remainingbits >> 5;
ivgroup.iv2 = (remainingbits & 0xfffff) % 32;
ivgroup.iv1 = remainingbits & 0x1f;
remainingbits = remainingbits >> 5;
ivgroup.iv2 = remainingbits & 0x1f;

return ivgroup;
}

AdvPokemonResult pokemon_from_state(AdvRngState& state, AdvRngMethod method = AdvRngMethod::Method1){
AdvPokemonResult pokemon_from_state(AdvRngState& state){
uint32_t pid = pid_from_states(state.s0, state.s1);
uint8_t gender = gender_value_from_pid(pid);
AdvNature nature = nature_from_pid(pid);
AdvAbility ability = ability_from_pid(pid);

AdvIvGroup ivgroup1;
AdvIvGroup ivgroup2;
switch(method){
switch(state.method){

case AdvRngMethod::Method2:
ivgroup1 = iv_group_from_state(state.s3);
Expand All @@ -107,9 +123,9 @@ AdvPokemonResult pokemon_from_state(AdvRngState& state, AdvRngMethod method = Ad
ivs.hp = ivgroup1.iv0;
ivs.attack = ivgroup1.iv1;
ivs.defense = ivgroup1.iv2;
ivs.spatk = ivgroup2.iv0;
ivs.spdef = ivgroup2.iv1;
ivs.speed = ivgroup2.iv2;
ivs.speed = ivgroup2.iv0;
ivs.spatk = ivgroup2.iv1;
ivs.spdef = ivgroup2.iv2;

return {pid, gender, nature, ability, ivs};
}
Expand All @@ -134,40 +150,44 @@ bool check_for_match(AdvPokemonResult res, AdvRngFilters target, uint16_t tid_xo
&& (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 <= res.ivs.hp && target.ivs.hp.high >= res.ivs.hp)
&& (target.ivs.attack.low <= res.ivs.attack && target.ivs.attack.high >= res.ivs.attack)
&& (target.ivs.defense.low <= res.ivs.defense && target.ivs.defense.high >= res.ivs.defense)
&& (target.ivs.spatk.low <= res.ivs.spatk && target.ivs.spatk.high >= res.ivs.spatk)
&& (target.ivs.spdef.low <= res.ivs.spdef && target.ivs.spdef.high >= res.ivs.spdef)
&& (target.ivs.speed.low <= res.ivs.speed && target.ivs.speed.high >= res.ivs.speed);
&& ((target.ivs.hp.low <= res.ivs.hp) && (target.ivs.hp.high >= res.ivs.hp))
&& ((target.ivs.attack.low <= res.ivs.attack) && (target.ivs.attack.high >= res.ivs.attack))
&& ((target.ivs.defense.low <= res.ivs.defense) && (target.ivs.defense.high >= res.ivs.defense))
&& ((target.ivs.spatk.low <= res.ivs.spatk) && (target.ivs.spatk.high >= res.ivs.spatk))
&& ((target.ivs.spdef.low <= res.ivs.spdef) && (target.ivs.spdef.high >= res.ivs.spdef))
&& ((target.ivs.speed.low <= res.ivs.speed) && (target.ivs.speed.high >= res.ivs.speed));
}



AdvRng::AdvRng(uint16_t seed, AdvRngState state)
AdvRngSearcher::AdvRngSearcher(uint16_t seed, AdvRngState state)
: seed(seed)
, state(state)
{}

AdvRng::AdvRng(uint16_t seed, uint64_t min_advances, AdvRngMethod method)
AdvRngSearcher::AdvRngSearcher(uint16_t seed, uint64_t min_advances, AdvRngMethod method)
: seed(seed)
, state(rngstate_from_seed(seed, min_advances, method))
{}

void AdvRng::advance_state(){
void AdvRngSearcher::advance_state(){
advance_rng_state(state);
}

void AdvRng::set_seed(uint16_t newseed){
void AdvRngSearcher::set_seed(uint16_t newseed){
seed = newseed;
state = rngstate_from_seed(seed, 0, state.method);
}

void AdvRng::set_state_advances(uint64_t advances){
void AdvRngSearcher::set_state_advances(uint64_t advances){
state = rngstate_from_seed(seed, advances, state.method);
}

void AdvRng::search_advance_range(
AdvPokemonResult AdvRngSearcher::generate_pokemon(){
return pokemon_from_state(state);
}

void AdvRngSearcher::search_advance_range(
std::map<AdvRngState, AdvPokemonResult>& hits,
AdvRngFilters& target,
uint64_t min_advances,
Expand All @@ -194,21 +214,24 @@ void AdvRng::search_advance_range(

if ((target.method != AdvRngMethod::Any) && (target.method != method)){
continue;
}else{
state.method = method;
}

for (uint64_t a=min_advances; a<max_advances; a++){
AdvPokemonResult res = pokemon_from_state(state, method);
AdvPokemonResult res = pokemon_from_state(state);
bool match = check_for_match(res, target, tid_xor_sid, gender_threshold);
if (match){
hits[state] = res;
}
advance_state();
}
}
}

std::map<AdvRngState, AdvPokemonResult> AdvRng::search(
std::map<AdvRngState, AdvPokemonResult> AdvRngSearcher::search(
AdvRngFilters& target,
std::vector<uint16_t>& seeds,
const std::vector<uint16_t>& seeds,
uint64_t min_advances,
uint64_t max_advances,
uint16_t tid_xor_sid,
Expand Down Expand Up @@ -343,9 +366,9 @@ void shrink_iv_ranges(IvRanges& mutated_ranges, IvRanges& fixed_ranges){
shrink_iv_range(mutated_ranges.speed, fixed_ranges.speed);
}

AdvRngFilters observation_to_filter(AdvObservedPokemon& observation, BaseStats& basestats, AdvRngMethod method = AdvRngMethod::Method1){
AdvRngFilters observation_to_filters(AdvObservedPokemon& observation, BaseStats& basestats, AdvRngMethod method){
IvRanges filter_iv_ranges = {{0,31},{0,31},{0,31},{0,31},{0,31},{0,31}};
for (int i=0; i<int(observation.level.size()); i++){
for (size_t i=0; i<observation.level.size(); i++){
uint8_t lv = observation.level[i];
StatReads sts = observation.stats[i];
EVs ev = observation.evs[i];
Expand Down
21 changes: 14 additions & 7 deletions SerialPrograms/Source/Pokemon/Pokemon_AdvRng.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,21 +127,31 @@ struct AdvRngFilters{
AdvRngMethod method;
};

class AdvRng{
// updates the AdvObservedPokemon with info from leveling up
// assumes levels are earned sequentially
// input EVs are the ones earned since the last level up, not the total
void level_up_observed_pokemon(AdvObservedPokemon& pokemon, StatReads& newstats, EVs& evyield);

// returns search filters that correspond with observed stats
AdvRngFilters observation_to_filters(AdvObservedPokemon& observation, BaseStats& basestats, AdvRngMethod method = AdvRngMethod::Method1);

class AdvRngSearcher{
public:
uint16_t seed;
AdvRngState state;

AdvRng(uint16_t seed, AdvRngState state);
AdvRng(uint16_t seed, uint64_t min_advances, AdvRngMethod method = AdvRngMethod::Method1);
AdvRngSearcher(uint16_t seed, AdvRngState state);
AdvRngSearcher(uint16_t seed, uint64_t min_advances, AdvRngMethod method = AdvRngMethod::Method1);

void set_seed(uint16_t seed);
void set_state_advances(uint64_t advances);
void advance_state();

AdvPokemonResult generate_pokemon();

std::map<AdvRngState, AdvPokemonResult> search(
AdvRngFilters& target,
std::vector<uint16_t>& seeds,
const std::vector<uint16_t>& seeds,
uint64_t min_advances,
uint64_t max_advances,
uint16_t tid_xor_sid = 0,
Expand All @@ -161,9 +171,6 @@ class AdvRng{






}
}
#endif
4 changes: 2 additions & 2 deletions SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "Programs/ShinyHunting/PokemonFRLG_ShinyHunt-Fishing.h"
#include "Programs/ShinyHunting/PokemonFRLG_ShinyHunt-Overworld.h"
#include "Programs/RngManipulation/PokemonFRLG_RngHelper.h"
#include "Programs/RngManipulation/PokemonFRLG_SidHelper.h"
#include "Programs/TestPrograms/PokemonFRLG_SoundListener.h"
#include "Programs/TestPrograms/PokemonFRLG_ReadStats.h"
#include "Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.h"
Expand All @@ -47,8 +48,6 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{
ret.emplace_back(make_single_switch_program<NuggetBridgeFarmer_Descriptor, NuggetBridgeFarmer>());
ret.emplace_back(make_single_switch_program<PickupFarmer_Descriptor, PickupFarmer>());
ret.emplace_back(make_single_switch_program<EvTrainer_Descriptor, EvTrainer>());
if (PreloadSettings::instance().DEVELOPER_MODE){
}

//ret.emplace_back("---- General ----");

Expand All @@ -67,6 +66,7 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{
ret.emplace_back("---- Untested/Beta/WIP ----");
ret.emplace_back(make_single_switch_program<LuckyEggFarmer_Descriptor, LuckyEggFarmer>());
ret.emplace_back(make_single_switch_program<ItemDuplication_Descriptor, ItemDuplication>());
ret.emplace_back(make_single_switch_program<SidHelper_Descriptor, SidHelper>());
}

if (PreloadSettings::instance().DEVELOPER_MODE){
Expand Down
Loading