Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
241 changes: 225 additions & 16 deletions SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,8 @@ AdvIvGroup iv_group_from_state(uint32_t& state){
return ivgroup;
}

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

AdvIvGroup ivgroup1;
Expand Down Expand Up @@ -130,6 +128,129 @@ AdvPokemonResult pokemon_from_state(AdvRngState& state){
return {pid, gender, nature, ability, ivs};
}

AdvPokemonResult pokemon_from_state(AdvRngState& state){
uint32_t pid = pid_from_states(state.s0, state.s1);
AdvNature nature = nature_from_pid(pid);
return pokemon_from_state(state, pid, nature);
}

AdvPokemonResult reroll_wild_pokemon(uint8_t nature, uint16_t seed, uint64_t advances, uint32_t state, AdvRngMethod method){
uint32_t lowstate = state;
uint32_t highstate = increment_internal_rng_state(state);
while (true){
uint32_t pid = pid_from_states(lowstate, highstate);
if ((pid % 25) == nature){
AdvRngState rngstate = rngstate_from_internal_state(seed, advances, lowstate, method);
return pokemon_from_state(rngstate, pid, AdvNature(nature));
}else{
lowstate = increment_internal_rng_state(highstate);
highstate = increment_internal_rng_state(lowstate);
}
}
}

uint8_t slot_number_from_roll(uint8_t roll, size_t size, bool super_rod) {
switch(size){
case 12: // grass
if (roll < 20){
return 0;
}else if(roll < 40){
return 1;
}else if(roll < 50){
return 2;
}else if(roll < 60){
return 3;
}else if(roll < 70){
return 4;
}else if(roll < 80){
return 5;
}else if(roll < 85){
return 6;
}else if(roll < 90){
return 7;
}else if(roll < 94){
return 8;
}else if(roll < 98){
return 9;
}else if(roll < 99){
return 10;
}else{
return 11;
}
case 5:
if (super_rod){ // super rod
if (roll < 40){
return 0;
}else if(roll < 70){
return 1;
}else if(roll < 85){
return 2;
}else if(roll < 95){
return 3;
}else{
return 4;
}
}else{
if (roll < 60){ // surfing and rock smash
return 0;
}else if(roll < 90){
return 1;
}else if(roll < 95){
return 2;
}else if(roll < 99){
return 3;
}else{
return 4;
}
}
case 3: // good rod
if (roll < 60){
return 0;
}else if(roll < 80){
return 1;
}else{
return 2;
}
case 2: // old rod
if (roll < 70){
return 0;
}else{
return 1;
}
default:
return 0;
}
}

AdvWildPokemonResult wild_pokemon_from_state(AdvRngState state, std::vector<AdvEncounterSlot> slots, bool super_rod){

uint8_t slot_roll = (state.s0 >> 16) % 100;
uint16_t level_roll = state.s1 >> 16;
uint8_t nature = (state.s2 >> 16) % 25;

uint8_t slot_num = slot_number_from_roll(slot_roll, slots.size(), super_rod);
AdvEncounterSlot slot = slots[slot_num];

uint8_t diff = slot.maxlevel - slot.minlevel;
if (slot.maxlevel < slot.minlevel) {
diff = 0;
}
uint8_t level = slot.minlevel + (level_roll % (diff + 1));

AdvPokemonResult temp_poke = reroll_wild_pokemon(nature, state.seed, state.advance, state.s3, state.method);

return {
slot.species,
temp_poke.pid,
temp_poke.gender,
temp_poke.nature,
temp_poke.ability,
temp_poke.ivs,
slot_num,
level,
};
}

AdvShinyType shiny_type_from_pid(uint32_t pid, uint16_t tid_xor_sid){
uint16_t pid0 = pid >> 16;
uint16_t pid1 = pid & 0xffff;
Expand Down Expand Up @@ -158,7 +279,20 @@ bool check_for_match(AdvPokemonResult res, AdvRngFilters target, int16_t gender_
&& ((target.ivs.speed.low <= res.ivs.speed) && (target.ivs.speed.high >= res.ivs.speed));
}


bool check_for_match(AdvWildPokemonResult res, AdvRngFilters target, int16_t gender_threshold, uint16_t tid_xor_sid){
return (target.species == res.species)
&& (target.level == res.level)
&& (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 <= 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));
}

AdvRngSearcher::AdvRngSearcher(uint16_t seed, AdvRngState state)
: seed(seed)
Expand Down Expand Up @@ -188,7 +322,7 @@ AdvPokemonResult AdvRngSearcher::generate_pokemon(){
}

void AdvRngSearcher::search_advance_range(
std::map<AdvRngState, AdvPokemonResult>& hits,
std::vector<AdvRngState>& hits,
AdvRngFilters& target,
uint64_t min_advances,
uint64_t max_advances,
Expand Down Expand Up @@ -222,46 +356,119 @@ void AdvRngSearcher::search_advance_range(
AdvPokemonResult res = pokemon_from_state(state);
bool match = check_for_match(res, target, gender_threshold, tid_xor_sid);
if (match){
hits[state] = res;
hits.emplace_back(state);
}
advance_state();
}
}
}

std::map<AdvRngState, AdvPokemonResult> AdvRngSearcher::search(
std::vector<AdvRngState> AdvRngSearcher::search(
AdvRngFilters& target,
const std::vector<uint16_t>& seeds,
uint64_t min_advances,
uint64_t max_advances,
int16_t gender_threshold,
uint16_t tid_xor_sid
){
std::map<AdvRngState, AdvPokemonResult> hits;
std::vector<AdvRngState> hits;
for (uint16_t seed : seeds){
set_seed(seed);
search_advance_range(hits, target, min_advances, max_advances, gender_threshold, tid_xor_sid);
}
return hits;
}

void AdvRngSearcher::refine_search(
std::map<AdvRngState, AdvPokemonResult>& map,

AdvRngWildSearcher::AdvRngWildSearcher(uint16_t seed, AdvRngState state, const std::vector<AdvEncounterSlot>& encounter_slots)
: seed(seed)
, state(state)
, encounter_slots(encounter_slots)
{}

AdvRngWildSearcher::AdvRngWildSearcher(uint16_t seed, uint64_t min_advances, const std::vector<AdvEncounterSlot>& encounter_slots, AdvRngMethod method)
: seed(seed)
, state(rngstate_from_seed(seed, min_advances, method))
, encounter_slots(encounter_slots)
{}

void AdvRngWildSearcher::advance_state(){
advance_rng_state(state);
}

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

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

AdvWildPokemonResult AdvRngWildSearcher::generate_pokemon(bool super_rod){
return wild_pokemon_from_state(state, encounter_slots, super_rod);
}

void AdvRngWildSearcher::search_advance_range(
std::vector<AdvRngState>& hits,
AdvRngFilters& target,
uint64_t min_advances,
uint64_t max_advances,
int16_t gender_threshold,
bool super_rod,
uint16_t tid_xor_sid
){
for (auto iter = map.begin(); iter != map.end(); ){
state = iter->first;
AdvPokemonResult res = pokemon_from_state(state);
if (!check_for_match(res, target, gender_threshold, tid_xor_sid)){
iter = map.erase(iter);
for (uint8_t m=0; m<3; m++){
set_state_advances(min_advances);

AdvRngMethod method;
switch (m){
case 1:
method = AdvRngMethod::Method2;
break;
case 2:
method = AdvRngMethod::Method4;
break;
case 0:
default:
method = AdvRngMethod::Method1;
break;
}

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

for (uint64_t a=min_advances; a<max_advances; a++){
AdvWildPokemonResult res = wild_pokemon_from_state(state, encounter_slots, super_rod);
bool match = check_for_match(res, target, gender_threshold, tid_xor_sid);
if (match){
hits.emplace_back(state);
}
advance_state();
}
}
}

std::vector<AdvRngState> AdvRngWildSearcher::search(
AdvRngFilters& target,
const std::vector<uint16_t>& seeds,
uint64_t min_advances,
uint64_t max_advances,
int16_t gender_threshold,
bool super_rod,
uint16_t tid_xor_sid
){
std::vector<AdvRngState> hits;
for (uint16_t seed : seeds){
set_seed(seed);
search_advance_range(hits, target, min_advances, max_advances, gender_threshold, super_rod, tid_xor_sid);
}
return hits;
}


Pokemon::NatureAdjustments nature_to_adjustment(AdvNature nature){
NatureAdjustments ret;
Expand Down Expand Up @@ -396,6 +603,8 @@ AdvRngFilters observation_to_filters(const AdvObservedPokemon& observation, cons
}

return AdvRngFilters {
observation.species,
observation.level[0],
observation.gender,
observation.nature,
observation.ability,
Expand Down
Loading