Skip to content
19 changes: 18 additions & 1 deletion SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,23 @@ std::map<AdvRngState, AdvPokemonResult> AdvRngSearcher::search(
return hits;
}

void AdvRngSearcher::refine_search(
std::map<AdvRngState, AdvPokemonResult>& map,
AdvRngFilters& target,
uint16_t tid_xor_sid,
uint8_t gender_threshold
){
for (auto iter = map.begin(); iter != map.end(); ){
state = iter->first;
AdvPokemonResult res = pokemon_from_state(state);
if (!check_for_match(res, target, tid_xor_sid, gender_threshold)){
iter = map.erase(iter);
}else{
iter++;
}
}
}


Pokemon::NatureAdjustments nature_to_adjustment(AdvNature nature){
NatureAdjustments ret;
Expand Down Expand Up @@ -366,7 +383,7 @@ void shrink_iv_ranges(IvRanges& mutated_ranges, IvRanges& fixed_ranges){
shrink_iv_range(mutated_ranges.speed, fixed_ranges.speed);
}

AdvRngFilters observation_to_filters(AdvObservedPokemon& observation, BaseStats& basestats, AdvRngMethod method){
AdvRngFilters observation_to_filters(const AdvObservedPokemon& observation, const BaseStats& basestats, AdvRngMethod method){
IvRanges filter_iv_ranges = {{0,31},{0,31},{0,31},{0,31},{0,31},{0,31}};
for (size_t i=0; i<observation.level.size(); i++){
uint8_t lv = observation.level[i];
Expand Down
9 changes: 8 additions & 1 deletion SerialPrograms/Source/Pokemon/Pokemon_AdvRng.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ struct AdvRngFilters{
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);
AdvRngFilters observation_to_filters(const AdvObservedPokemon& observation, const BaseStats& basestats, AdvRngMethod method = AdvRngMethod::Method1);

class AdvRngSearcher{
public:
Expand All @@ -158,6 +158,13 @@ class AdvRngSearcher{
uint8_t gender_threshold = 126
);

void refine_search(
std::map<AdvRngState, AdvPokemonResult>& map,
AdvRngFilters& target,
uint16_t tid_xor_sid = 0,
uint8_t gender_threshold = 126
);

private:
void search_advance_range(
std::map<AdvRngState, AdvPokemonResult>& hits,
Expand Down
2 changes: 2 additions & 0 deletions SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "Programs/ShinyHunting/PokemonFRLG_ShinyHunt-Overworld.h"
#include "Programs/RngManipulation/PokemonFRLG_RngHelper.h"
#include "Programs/RngManipulation/PokemonFRLG_SidHelper.h"
#include "Programs/RngManipulation/PokemonFRLG_StarterRng.h"
#include "Programs/TestPrograms/PokemonFRLG_SoundListener.h"
#include "Programs/TestPrograms/PokemonFRLG_ReadStats.h"
#include "Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.h"
Expand Down Expand Up @@ -67,6 +68,7 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{
ret.emplace_back("---- Untested/Beta/WIP ----");
ret.emplace_back(make_single_switch_program<ItemDuplication_Descriptor, ItemDuplication>());
ret.emplace_back(make_single_switch_program<SidHelper_Descriptor, SidHelper>());
ret.emplace_back(make_single_switch_program<StarterRng_Descriptor, StarterRng>());
}

if (PreloadSettings::instance().DEVELOPER_MODE){
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/* RNG Displays
*
* From: https://github.com/PokemonAutomation/
*
*/

#include <vector>
#include <iostream>
#include <sstream>
#include "PokemonFRLG_RngDisplays.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonFRLG{

using namespace Pokemon;

RngFilterDisplay::RngFilterDisplay()
: GroupOption("Observed Stats", LockMode::READ_ONLY)
, hp(false, "<b>HP IV:</b>", LockMode::READ_ONLY, "-", "")
, atk(false, "<b>Attack IV:</b>", LockMode::READ_ONLY, "-", "")
, def(false, "<b>Defense IV:</b>", LockMode::READ_ONLY, "-", "")
, spatk(false, "<b>Special Attack IV:</b>", LockMode::READ_ONLY, "-", "")
, spdef(false, "<b>Special Defense IV:</b>", LockMode::READ_ONLY, "-", "")
, speed(false, "<b>Speed IV:</b>", LockMode::READ_ONLY, "-", "")
, gender(false, "<b>Gender:</b>", LockMode::READ_ONLY, "-", "")
, nature(false, "<b>Nature:</b>", LockMode::READ_ONLY, "-", "")
{
PA_ADD_STATIC(hp);
PA_ADD_STATIC(atk);
PA_ADD_STATIC(def);
PA_ADD_STATIC(spatk);
PA_ADD_STATIC(spdef);
PA_ADD_STATIC(speed);
PA_ADD_STATIC(gender);
PA_ADD_STATIC(nature);

}
std::string RngFilterDisplay::get_range_string(const IvRange& range){
if (range.low < 0 || range.high < 0){
return "(invalid or unable to read)";
}
if (range.low == range.high){
return std::to_string(range.low);
}
return std::to_string(range.low) + " - " + std::to_string(range.high);
}
std::string RngFilterDisplay::get_gender_string(const AdvGender& gender){
switch (gender){
case AdvGender::Male:
return "Male";
case AdvGender::Female:
return "Female";
default:
return "Any";
}
}
std::string RngFilterDisplay::get_nature_string(const AdvNature& nature){
switch (nature){
case AdvNature::Hardy:
return "Hardy";
case AdvNature::Lonely:
return "Lonely";
case AdvNature::Brave:
return "Brave";
case AdvNature::Adamant:
return "Adamant";
case AdvNature::Naughty:
return "Naughty";
case AdvNature::Bold:
return "Bold";
case AdvNature::Docile:
return "Docile";
case AdvNature::Relaxed:
return "Relaxed";
case AdvNature::Impish:
return "Impish";
case AdvNature::Lax:
return "Lax";
case AdvNature::Timid:
return "Timid";
case AdvNature::Hasty:
return "Hasty";
case AdvNature::Serious:
return "Serious";
case AdvNature::Jolly:
return "Jolly";
case AdvNature::Naive:
return "Naive";
case AdvNature::Modest:
return "Modest";
case AdvNature::Mild:
return "Mild";
case AdvNature::Quiet:
return "Quiet";
case AdvNature::Bashful:
return "Bashful";
case AdvNature::Rash:
return "Rash";
case AdvNature::Calm:
return "Calm";
case AdvNature::Gentle:
return "Gentle";
case AdvNature::Sassy:
return "Sassy";
case AdvNature::Careful:
return "Careful";
case AdvNature::Quirky:
return "Quirky";
default:
return "Any";
}
}
void RngFilterDisplay::set(const AdvRngFilters& filter){
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(get_gender_string(filter.gender));
nature.set(get_nature_string(filter.nature));
}

void RngFilterDisplay::reset(){
hp.set("-");
atk.set("-");
def.set("-");
spatk.set("-");
spdef.set("-");
speed.set("-");
gender.set("-");
nature.set("-");
}

PossibleHitsDisplay::PossibleHitsDisplay()
: GroupOption("Possible Hits", LockMode::READ_ONLY)
, hits(false, "<b>Seeds/Advances:</b>", LockMode::READ_ONLY, "-", "")
{
PA_ADD_STATIC(hits);
}

std::vector<AdvRngState> PossibleHitsDisplay::get_rng_states_from_map(const std::map<AdvRngState,AdvPokemonResult>& hits_map){
std::vector<AdvRngState> rng_states;
for(std::map<AdvRngState,AdvPokemonResult>::const_iterator it = hits_map.begin(); it != hits_map.end(); ++it) {
rng_states.emplace_back(it->first);
}
return rng_states;
}

std::string PossibleHitsDisplay::get_hits_string(const std::vector<AdvRngState>& rng_states){
std::string hits_string;
for (size_t i=0; i<rng_states.size(); i++){
if (i > 0){
hits_string += ", ";
}
AdvRngState hit = rng_states[i];
uint16_t seed = hit.seed;
std::ostringstream s;
s << std::hex << seed;
hits_string += s.str();
hits_string += "/";
hits_string += std::to_string(hit.advance);
}
if (hits_string.size() == 0){
hits_string += "No matches found";
}
return hits_string;
}
std::string PossibleHitsDisplay::get_hits_string(const std::map<AdvRngState, AdvPokemonResult>& hits_map){
return get_hits_string(get_rng_states_from_map(hits_map));
}

void PossibleHitsDisplay::set(const std::vector<AdvRngState>& rng_states){
hits.set(get_hits_string(rng_states));
}
void PossibleHitsDisplay::set(const std::map<AdvRngState, AdvPokemonResult>& hits_map){
std::vector<AdvRngState> rng_states = get_rng_states_from_map(hits_map);
set(rng_states);
}

void PossibleHitsDisplay::reset(){
hits.set("-");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you have - as the empty state. But get_hits_string() returns empty string on empty state. Which one should it be?

Copy link
Copy Markdown
Contributor Author

@theastrogoth theastrogoth Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a more descriptive message in the case where there are no search hits. - will correspond with the empty state before a search has been done, while No matches found will be displayed if a search turns up empty.

}

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* RNG Displays
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonFRLG_RngDisplays_H
#define PokemonAutomation_PokemonFRLG_RngDisplays_H

#include <vector>
#include "Common/Cpp/Options/StringOption.h"
#include "CommonFramework/Notifications/EventNotificationsTable.h"
#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h"
#include "Pokemon/Pokemon_AdvRng.h"


namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonFRLG{

using namespace Pokemon;

class RngFilterDisplay : public GroupOption{
public:
RngFilterDisplay();

void set(const AdvRngFilters& filter);
void reset();

private:
static std::string get_range_string(const IvRange& range);
static std::string get_gender_string(const AdvGender& gender);
static std::string get_nature_string(const AdvNature& nature);

public:
StringOption hp;
StringOption atk;
StringOption def;
StringOption spatk;
StringOption spdef;
StringOption speed;
StringOption gender;
StringOption nature;
};


class PossibleHitsDisplay : public GroupOption{
public:
PossibleHitsDisplay();

void set(const std::vector<AdvRngState>& rng_states);
void set(const std::map<AdvRngState, AdvPokemonResult>& hits_map);
void reset();

private:
static std::vector<AdvRngState> get_rng_states_from_map(const std::map<AdvRngState, AdvPokemonResult>& hits_map);
static std::string get_hits_string(const std::vector<AdvRngState>& rng_states);
static std::string get_hits_string(const std::map<AdvRngState, AdvPokemonResult>& hits_map);
public:
StringOption hits;
};

}
}
}
#endif
Loading