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
695 changes: 559 additions & 136 deletions SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp

Large diffs are not rendered by default.

147 changes: 144 additions & 3 deletions SerialPrograms/Source/Pokemon/Pokemon_AdvRng.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stdint.h>
#include <utility>
#include <vector>
#include <stdexcept>
#include "Pokemon_StatsCalculation.h"

namespace PokemonAutomation{
Expand All @@ -28,6 +29,25 @@ struct AdvIVs{
uint8_t spatk = 0;
uint8_t spdef = 0;
uint8_t speed = 0;

uint8_t& operator[](int index){
switch (index){
case 0:
return hp;
case 1:
return attack;
case 2:
return defense;
case 3:
return speed;
case 4:
return spatk;
case 5:
return spdef;
default:
throw std::runtime_error("Invalid IVs index. Please report this as a bug.");
}
}
};

enum class AdvNature{
Expand Down Expand Up @@ -79,12 +99,19 @@ enum class AdvShinyType{
};

enum class AdvRngMethod{
Method1,
Method2,
Method4,
Method1, // egg normal
Method2, // egg split
Method3, // egg alternate
Method4, // egg mixed
Any
};

enum class AdvEggCompatibility{
low,
medium,
high
};

struct AdvRngState{
uint16_t seed;
uint64_t advance;
Expand All @@ -94,10 +121,18 @@ struct AdvRngState{
uint32_t s2;
uint32_t s3;
uint32_t s4;
uint32_t s5;

bool operator<(const AdvRngState& rhs) const noexcept{
return this->advance < rhs.advance;
}

bool operator==(const AdvRngState& rhs) const noexcept{
return (
this->advance == rhs.advance
&& this->seed == rhs.seed\
);
}
};

struct AdvEncounterSlot{
Expand Down Expand Up @@ -125,6 +160,15 @@ struct AdvWildPokemonResult{
uint8_t level;
};

struct AdvEggResult{
uint32_t pid;
uint8_t gender;
AdvNature nature;
AdvAbility ability;
AdvIVs ivs;
AdvIVs inherited_ivs;
};

struct AdvObservedPokemon{
std::string species;
AdvGender gender;
Expand Down Expand Up @@ -155,9 +199,22 @@ void level_up_observed_pokemon(AdvObservedPokemon& pokemon, const StatReads& new
// returns the appropriate NatureAdjustments for an AdvNature
Pokemon::NatureAdjustments nature_to_adjustment(AdvNature nature);

Pokemon::AdvNature string_to_nature(const std::string& nature_string);
std::string nature_to_string(const AdvNature& nature);

std::string gender_to_string(const AdvGender& gender);

AdvGender gender_from_gender_value(uint8_t gender_value, int16_t threshold);

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

AdvPokemonResult egg_to_pokemon(
AdvEggResult& egg_result,
AdvIVs& parentA_ivs,
AdvIVs& parentB_ivs
);

class AdvRngSearcher{
public:
uint16_t seed;
Expand Down Expand Up @@ -230,6 +287,90 @@ class AdvRngWildSearcher{
};


class AdvRngEggSearcher{
public:
uint16_t held_seed;
AdvRngState held_state;

uint16_t pickup_seed;
AdvRngState pickup_state;

AdvRngEggSearcher(uint16_t held_seed, AdvRngState held_state, uint16_t pickup_seed, AdvRngState pickup_state);
AdvRngEggSearcher(
uint16_t held_seed, uint64_t min_seed_advances,
uint16_t pickup_seed, uint64_t min_pickup_advances,
AdvRngMethod method = AdvRngMethod::Any
);

void set_held_seed(uint16_t seed);
void set_held_state_advances(uint64_t advances);
void advance_held_state();

void set_pickup_seed(uint16_t seed);
void set_pickup_state_advances(uint64_t advances);
void advance_pickup_state();

AdvEggResult generate_egg();
AdvPokemonResult generate_pokemon(AdvIVs& parentA_ivs, AdvIVs& parentB_ivs);

std::vector<std::pair<AdvRngState, AdvRngState>> search(
AdvRngFilters& target,
const std::vector<uint16_t>& held_seeds,
uint64_t min_held_advances,
uint64_t max_held_advances,
const std::vector<uint16_t>& pickup_seeds,
uint64_t min_pickup_advances,
uint64_t max_pickup_advances,
AdvIVs& parentA_ivs,
AdvIVs& parentB_ivs,
AdvEggCompatibility compatibility,
int16_t gender_threshold = 126,
uint16_t tid_xor_sid = 0
);

private:

void search_held_advances_range(
std::vector<std::pair<AdvRngState, AdvRngState>>& hits,
AdvRngFilters& target,
uint64_t min_held_advances,
uint64_t max_held_advances,
const std::vector<uint16_t>& pickup_seeds,
uint64_t min_pickup_advances,
uint64_t max_pickup_advances,
AdvIVs& parentA_ivs,
AdvIVs& parentB_ivs,
AdvEggCompatibility compatibility,
int16_t gender_threshold,
uint16_t tid_xor_sid
);

void search_pickups(
std::vector<std::pair<AdvRngState, AdvRngState>>& hits,
AdvRngFilters& target,
uint16_t held_pid_half,
const std::vector<uint16_t>& pickup_seeds,
uint64_t min_pickup_advances,
uint64_t max_pickup_advances,
AdvIVs& parentA_ivs,
AdvIVs& parentB_ivs,
int16_t gender_threshold,
uint16_t tid_xor_sid
);

void search_pickup_advances_range(
std::vector<std::pair<AdvRngState, AdvRngState>>& hits,
AdvRngFilters& target,
uint16_t held_pid_half,
uint64_t min_pickup_advances,
uint64_t max_pickup_advances,
AdvIVs& parentA_ivs,
AdvIVs& parentB_ivs,
int16_t gender_threshold,
uint16_t tid_xor_sid
);
};


}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,28 @@ ImageFloatBox SelectionArrowDetector::arrow_box_for_position(SelectionArrowPosit
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid FRLG Safari Selection Arrow Position");
}

ImageFloatBox SelectionArrowDetector::arrow_box_for_position(SelectionArrowPositionNoDexMenu position){
// Safari Zone menu has the same 7 slots as the overworld menu; RETIRE occupies slot 0,
// shifting POKEDEX..EXIT each down one relative to the overworld enum.
switch (position){
case SelectionArrowPositionNoDexMenu::POKEMON:
return ImageFloatBox(0.727692, 0.0523077, 0.0369231, 0.0778846);
case SelectionArrowPositionNoDexMenu::BAG:
return ImageFloatBox(0.727692, 0.1457692, 0.0369231, 0.0778846);
case SelectionArrowPositionNoDexMenu::TRAINER:
return ImageFloatBox(0.727692, 0.2392307, 0.0369231, 0.0778846);
case SelectionArrowPositionNoDexMenu::SAVE:
return ImageFloatBox(0.727692, 0.3378846, 0.0369231, 0.0778846);
case SelectionArrowPositionNoDexMenu::OPTION:
return ImageFloatBox(0.727692, 0.4261538, 0.0369231, 0.0778846);
case SelectionArrowPositionNoDexMenu::EXIT:
return ImageFloatBox(0.727692, 0.5248076, 0.0369231, 0.0778846);
default:
break;
}
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid FRLG Safari Selection Arrow Position");
}

ImageFloatBox SelectionArrowDetector::arrow_box_for_position(SelectionArrowPositionConfirmationMenu position){
switch (position){
case SelectionArrowPositionConfirmationMenu::YES:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ enum class SelectionArrowPositionSafariMenu {
EXIT
};

const int NO_DEX_START_MENU_OPTION_COUNT = 6;
enum class SelectionArrowPositionNoDexMenu{
POKEMON,
BAG,
TRAINER,
SAVE,
OPTION,
EXIT
};

const int START_MENU_OPTION_COUNT = 7;
enum class SelectionArrowPositionStartMenu{
POKEDEX,
Expand Down Expand Up @@ -72,6 +82,8 @@ class SelectionArrowDetector : public StaticScreenDetector{

static ImageFloatBox arrow_box_for_position(SelectionArrowPositionSafariMenu position);

static ImageFloatBox arrow_box_for_position(SelectionArrowPositionNoDexMenu position);

static ImageFloatBox arrow_box_for_position(SelectionArrowPositionConfirmationMenu position);

const ImageFloatBox& last_detected() const { return m_last_detected; }
Expand Down
4 changes: 4 additions & 0 deletions SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Navigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,8 @@ void open_party_menu_from_overworld(ConsoleHandle& console, ProControllerContext
case 0:
if (menu_context == StartMenuContext::SAFARI_ZONE){
ret = move_cursor_to_position(console, context, SelectionArrowPositionSafariMenu::POKEMON);
} else if (menu_context == StartMenuContext::NO_DEX){
ret = move_cursor_to_position(console, context, SelectionArrowPositionNoDexMenu::POKEMON);
} else {
ret = move_cursor_to_position(console, context, SelectionArrowPositionStartMenu::POKEMON);
}
Expand Down Expand Up @@ -709,6 +711,8 @@ void open_bag_from_overworld(ConsoleHandle& console, ProControllerContext& conte
case 0:
if (menu_context == StartMenuContext::SAFARI_ZONE){
ret = move_cursor_to_position(console, context, SelectionArrowPositionSafariMenu::BAG);
} else if (menu_context == StartMenuContext::NO_DEX){
ret = move_cursor_to_position(console, context, SelectionArrowPositionNoDexMenu::BAG);
} else {
ret = move_cursor_to_position(console, context, SelectionArrowPositionStartMenu::BAG);
}
Expand Down
3 changes: 2 additions & 1 deletion SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Navigation.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ bool exit_wild_battle(ConsoleHandle& console, ProControllerContext& context, boo
// Starting from the start menu, a sub-screen of the start menu, or the overworld, navigate to the party screen
enum class StartMenuContext {
STANDARD,
SAFARI_ZONE
SAFARI_ZONE,
NO_DEX,
};
void open_party_menu_from_overworld(ConsoleHandle& console, ProControllerContext& context, StartMenuContext menu_context = StartMenuContext::STANDARD);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ bool move_cursor_to_position(ConsoleHandle& console, ProControllerContext& conte
);
}

bool move_cursor_to_position(ConsoleHandle& console, ProControllerContext& context, SelectionArrowPositionNoDexMenu destination){
return move_cursor_impl(
console, context,
MENU_ARROW_BOX,
NO_DEX_START_MENU_OPTION_COUNT,
[](int i){ return SelectionArrowDetector::arrow_box_for_position(static_cast<SelectionArrowPositionNoDexMenu>(i)); },
static_cast<int>(destination)
);
}

void save_game_to_overworld(ConsoleHandle& console, ProControllerContext& context){

WallClock start = current_time();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ bool move_cursor_to_position(
SelectionArrowPositionSafariMenu destination
);

// Starting from the start menu before the PokeDex has been received, move the selection arrow to the specified position.
// Return true if successful, false otherwise (e.g. if selection arrow is not detected).
bool move_cursor_to_position(
ConsoleHandle& console, ProControllerContext& context,
SelectionArrowPositionNoDexMenu destination
);

// Starting from either the overworld or the main menu, save the game.
// This function returns in the overworld.
void save_game_to_overworld(ConsoleHandle& console, ProControllerContext& context);
Expand Down
Loading
Loading