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
8 changes: 4 additions & 4 deletions SerialPrograms/Source/Pokemon/Pokemon_AdvRng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ void AdvRngSearcher::search_advance_range(
state.method = method;
}

for (uint64_t a=min_advances; a<max_advances; a++){
for (uint64_t a=min_advances; a<=max_advances; a++){
AdvPokemonResult res = pokemon_from_state(state, roaming);
bool match = check_for_match(res, target, gender_threshold, tid_xor_sid);
if (match){
Expand Down Expand Up @@ -818,7 +818,7 @@ void AdvRngWildSearcher::search_advance_range(
state.method = method;
}

for (uint64_t a=min_advances; a<max_advances; a++){
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){
Expand Down Expand Up @@ -941,7 +941,7 @@ void AdvRngEggSearcher::search_pickup_advances_range(
pickup_state.method = method;
}

for (uint64_t a=min_pickup_advances; a<max_pickup_advances; a++){
for (uint64_t a=min_pickup_advances; a<=max_pickup_advances; a++){
AdvEggResult egg_res = egg_from_pickup_state(pickup_state, held_pid_half);
AdvPokemonResult poke_res = egg_to_pokemon(egg_res, parentA_ivs, parentB_ivs);
bool match = check_for_match(poke_res, target, gender_threshold, tid_xor_sid);
Expand Down Expand Up @@ -987,7 +987,7 @@ void AdvRngEggSearcher::search_held_advances_range(
uint16_t tid_xor_sid
){
set_held_state_advances(min_held_advances);
for (uint64_t a=min_held_advances; a<max_held_advances; a++){
for (uint64_t a=min_held_advances; a<=max_held_advances; a++){
if (egg_held_at_state(held_state.s0, compatibility)){
uint16_t held_pid_half = (((held_state.s1) >> 16) % 0xfffe) + 1;
search_pickups(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,16 @@ void trigger_held_daycare_egg_after_delay(ProControllerContext& context, const u
}

void collect_daycare_egg_after_delay(ProControllerContext& context, const uint64_t& ingame_delay){
// wait with the start menu open to avoid overworld stuff causing extra advances
pbf_press_button(context, BUTTON_PLUS, 200ms, 300ms);
pbf_wait(context, std::chrono::milliseconds(ingame_delay - 12000)); // 4000ms + 500ms + 500ms + 6000ms + 1000ms
pbf_press_button(context, BUTTON_B, 200ms, 300ms);
// 5 dialog presses
pbf_press_button(context, BUTTON_A, 200ms, 1300ms);
pbf_press_button(context, BUTTON_A, 200ms, 1300ms);
pbf_press_button(context, BUTTON_A, 200ms, 1300ms);
pbf_press_button(context, BUTTON_A, 200ms, 1300ms);
pbf_press_button(context, BUTTON_A, 200ms, std::chrono::milliseconds(ingame_delay - 10200)); // 4000ms + 6000ms + 200ms
pbf_press_button(context, BUTTON_A, 200ms, 800ms);
// accept egg
pbf_press_button(context, BUTTON_A, 200ms, 2800ms);
// exit dialogue
Expand Down Expand Up @@ -520,16 +524,16 @@ void check_timings(
if (timings.ingame_delay < 4000) {
OperationFailedException::fire(
ErrorReport::NO_ERROR_REPORT,
"Togepi: the in-game delay cannot be less than 4000ms (320 advances). Check your in-game advances and calibration or pick a new target.",
"Togepi: the in-game delay cannot be less than 4000ms (350 advances). Check your in-game advances and calibration or pick a new target.",
console
);
}
return;
case PokemonFRLG_RngTarget::eggpickup:
if (timings.ingame_delay < 4000) {
if (timings.ingame_delay < 12000) {
OperationFailedException::fire(
ErrorReport::NO_ERROR_REPORT,
"Togepi: the in-game delay cannot be less than 10500ms (1100 advances). Check your in-game advances and calibration or pick a new target.",
"Togepi: the in-game delay cannot be less than 12000ms (1440 advances). Check your in-game advances and calibration or pick a new target.",
console
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext&

Milliseconds launch_delay = INITIAL_LAUNCH_DELAY;

RngAdvanceHistory advance_history;
RngUncertainHistory uncertain_history;
RngCalibrationHistory calibration_history;

uint16_t failed_searches = 0;
Expand Down Expand Up @@ -410,7 +410,7 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext&
}

// if previous resets had uncertain advances, slightly modify the seed delay to try to hit a different target
double seed_bump = SEED_BUMPS[advance_history.results.size() % 5];
double seed_bump = SEED_BUMPS[uncertain_history.results.size() % 5];
calibrations.seed_offset += seed_bump;

uint64_t ingame_advances = ADVANCES - CONTINUE_SCREEN_FRAMES;
Expand Down Expand Up @@ -462,7 +462,7 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext&
std::vector<AdvRngState> search_hits = get_search_results(env.console, searcher, filters, SEED_VALUES, ADVANCES, advances_radius, GENDER_THRESHOLD);
RNG_CALIBRATION.set_hits(search_hits);
bool finished = update_history(
env.console, advance_history, calibration_history, MAX_HISTORY_LENGTH,
env.console, uncertain_history, calibration_history, MAX_HISTORY_LENGTH,
calibrations, search_hits, 1
);

Expand Down Expand Up @@ -490,7 +490,7 @@ void GiftRng::program(SingleSwitchProgramEnvironment& env, ProControllerContext&
|| all_indistinguishable(search_hits, searcher, GENDER_THRESHOLD)
);
finished = update_history(
env.console, advance_history,
env.console, uncertain_history,
calibration_history, MAX_HISTORY_LENGTH,
calibrations, search_hits,
1, 2, force_finish
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ double get_seed_calibration_frames(
return average_offset;
}

double get_advances_calibration_frames(const RngCalibrationHistory& history, const uint64_t& advance_target){
double get_advances_calibration(const RngCalibrationHistory& history, const uint64_t& advance_target){
double sum = 0;
uint16_t len = 0;
for (size_t i=0; i<history.results.size(); i++){
Expand All @@ -388,40 +388,53 @@ RngCalibrations get_calibrations(
const RngCalibrationHistory& history,
const std::vector<uint16_t>& seed_values,
const int16_t& seed_position,
const uint64_t& advances
const uint64_t& advances,
bool csf_first
){
RngCalibrations calibrations{};

if (history.results.size() > 0){

calibrations.seed_offset = get_seed_calibration_frames(history, seed_values, seed_position);
calibrations.ingame_offset = get_advances_calibration_frames(history, advances);

AdvRngState prev_hit = history.results.back();
double prev_csf_offset = history.calibrations.back().csf_offset;
double prev_ingame_offset = history.calibrations.back().ingame_offset;
int64_t prev_advance_miss = int64_t(prev_hit.advance) - int64_t(advances);
if (prev_advance_miss != 0 && std::abs(prev_advance_miss) < 2){
console.log("Attempting to correct for off-by-one miss by modifying continue screen frames.");

if (prev_advance_miss == 0){
// don't change anything if the advance target has been hit
calibrations.csf_offset = prev_csf_offset;
calibrations.ingame_offset = prev_ingame_offset;
}else if (std::abs(prev_advance_miss) < 2){
// when very close, take the previous calibration and bump the CSF in the right direction
if (prev_advance_miss > 0){
calibrations.csf_offset = prev_csf_offset - 0.5;
}else{
calibrations.csf_offset = prev_csf_offset + 0.5;
}
calibrations.csf_offset = fmod(calibrations.csf_offset, 2);
calibrations.ingame_offset = prev_ingame_offset; // leave unchanged
}else if(csf_first){
// adjust the csf, putting anything beyond +/-2 frames into the in-game calibration
double new_advances_calibration = get_advances_calibration(history, advances);
double total_diff = new_advances_calibration - prev_ingame_offset - prev_csf_offset;
calibrations.csf_offset = fmod(prev_csf_offset + total_diff, 2);
double csf_diff = calibrations.csf_offset - prev_csf_offset;
calibrations.ingame_offset -= csf_diff;
calibrations.ingame_offset = prev_ingame_offset + total_diff - csf_diff;
}else{
// only adjust the in-game offset
calibrations.ingame_offset = get_advances_calibration(history, advances);
}
}

console.log("Seed calibration (frames): " + std::to_string(calibrations.seed_offset));
console.log("Continue screen adjustment (frames): " + std::to_string(calibrations.csf_offset));
console.log("Advance calibration (frames x2): " + std::to_string(calibrations.ingame_offset));
return calibrations;
}


bool update_history(
ConsoleHandle& console,
RngAdvanceHistory& advance_history,
RngUncertainHistory& uncertain_history,
RngCalibrationHistory& calibration_history,
const uint16_t& max_history_length,
const RngCalibrations calibrations,
Expand All @@ -448,44 +461,46 @@ bool update_history(
calibration_history.calibrations.erase(calibration_history.calibrations.begin());
calibration_history.results.erase(calibration_history.results.begin());
}
advance_history.results.clear();
advance_history.seed_calibrations.clear();
uncertain_history.results.clear();
uncertain_history.calibrations.clear();
return true;
}

std::vector<uint64_t> advances;
std::vector<int64_t> uncal_advances;
std::vector<AdvRngState> hits;
for(auto hit : search_hits) {
advances.emplace_back(hit.advance);
uncal_advances.emplace_back(int64_t(std::round(hit.advance - calibrations.csf_offset - calibrations.ingame_offset)));
hits.emplace_back(hit);
}

// get unique advances
std::sort(advances.begin(), advances.end());
std::vector<uint64_t>::iterator iter;
iter = std::unique(advances.begin(), advances.begin() + advances.size());
advances.resize(std::distance(advances.begin(), iter));
std::sort(uncal_advances.begin(), uncal_advances.end());
std::vector<int64_t>::iterator iter;
iter = std::unique(uncal_advances.begin(), uncal_advances.begin() + uncal_advances.size());
uncal_advances.resize(std::distance(uncal_advances.begin(), iter));

advance_history.seed_calibrations.emplace_back(calibrations.seed_offset);
advance_history.results.emplace_back(hits);
uncertain_history.calibrations.emplace_back(calibrations);
uncertain_history.results.emplace_back(hits);

// check advance history for repeated values
std::vector<uint64_t> counts;
uint64_t best = 0;
uint64_t mode = 0;
int64_t mode = 0; // sum of calibration and hit advance
bool tie = false;
for (uint64_t& adv : advances){
for (int64_t& uadv : uncal_advances){
uint64_t count = 0;
for (auto& res : advance_history.results){
for (size_t i=0; i<uncertain_history.results.size(); i++){
auto& cals = uncertain_history.calibrations[i];
auto& res = uncertain_history.results[i];
for (auto& state : res){
if (std::abs(int64_t(state.advance) - int64_t(adv)) <= advance_radius){
if (std::abs(int64_t(std::round(state.advance - cals.csf_offset - cals.ingame_offset)) - uadv) <= advance_radius){
count++;
break; // only count one possible hit from each attempt
}
}
}
if (count > best){
mode = adv;
mode = uadv;
best = count;
tie = false;
}else if (count == best){
Expand All @@ -500,19 +515,20 @@ bool update_history(


// add the closest possibility to the advances mode for each attempt to the calibration history
console.log("Inferred hits from previous " + std::to_string(advance_history.results.size()) + " attempts: ");
for (size_t i=0; i<advance_history.results.size(); i++){
auto& res = advance_history.results[i];
console.log("Inferred hits from previous " + std::to_string(uncertain_history.results.size()) + " attempts: ");
for (size_t i=0; i<uncertain_history.results.size(); i++){
auto& cals = uncertain_history.calibrations[i];
auto& res = uncertain_history.results[i];
AdvRngState most_likely_hit;
int64_t lowest_dist = INTMAX_MAX;
for (auto& state : res){
int64_t state_dist = std::abs(int64_t(state.advance) - int64_t(mode));
int64_t state_dist = std::abs(int64_t(state.advance - cals.csf_offset - cals.ingame_offset) - int64_t(mode));
if (state_dist < lowest_dist){
most_likely_hit = state;
lowest_dist = state_dist;
}
}
calibration_history.calibrations.emplace_back(calibrations);
calibration_history.calibrations.emplace_back(cals);
calibration_history.results.emplace_back(most_likely_hit);
console.log(" " + to_hex_string(most_likely_hit.seed) + " / " + std::to_string(most_likely_hit.advance));
}
Expand All @@ -523,8 +539,8 @@ bool update_history(
calibration_history.results.erase(calibration_history.results.begin());
}

advance_history.results.clear();
advance_history.seed_calibrations.clear();
uncertain_history.results.clear();
uncertain_history.calibrations.clear();

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,23 @@ using namespace Pokemon;
static const double FRLG_FRAMERATE = 59.999977; // FPS
static const double FRLG_FRAME_DURATION = 1000.0 / FRLG_FRAMERATE;


struct RngAdvanceHistory{
std::vector<double> seed_calibrations;
std::vector<std::vector<AdvRngState>> results;
};

struct RngCalibrations{
double seed_offset;
double csf_offset;
double ingame_offset;

bool operator==(const RngCalibrations& other) const {
return (
seed_offset == other.seed_offset
&& csf_offset == other.csf_offset
&& ingame_offset == other.ingame_offset
);
}
};

struct RngUncertainHistory{
std::vector<RngCalibrations> calibrations;
std::vector<std::vector<AdvRngState>> results;
};

struct RngCalibrationHistory{
Expand Down Expand Up @@ -126,21 +133,22 @@ double get_seed_calibration_frames(
);

// get advances calibration based on average offset in the RNG calibration history
double get_advances_calibration_frames(const RngCalibrationHistory& calibration_history, const uint64_t& advances);
double get_advances_calibration(const RngCalibrationHistory& calibration_history, const uint64_t& advances);

// get RngCalibrations from the RNG calibration history
RngCalibrations get_calibrations(
ConsoleHandle& console,
const RngCalibrationHistory& history,
const std::vector<uint16_t>& seed_values,
const int16_t& seed_position,
const uint64_t& advances
const uint64_t& advances,
bool csf_first = false
);

// infer hit seeds/advances, update the calibration history, and return whether or not the search is finished
bool update_history(
ConsoleHandle& console,
RngAdvanceHistory& advance_history,
RngUncertainHistory& advance_history,
RngCalibrationHistory& calibration_history,
const uint16_t& max_history_length,
const RngCalibrations calibrations,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ void RngFilterDisplay::reset(){

}

RngCalibrationDisplay::RngCalibrationDisplay()
: GroupOption("RNG Calibration", LockMode::READ_ONLY)
RngCalibrationDisplay::RngCalibrationDisplay(std::string label)
: GroupOption(label, LockMode::READ_ONLY)
, seed_calibration("<b>Seed Calibration (ms):</b>", LockMode::LOCK_WHILE_RUNNING, 0)
, csf_calibration("<b>Continue Screen Frames Calibration:</b>", LockMode::LOCK_WHILE_RUNNING, 0.0)
, advances_calibration("<b>In-Game Advances Calibration:</b>", LockMode::LOCK_WHILE_RUNNING, 0.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class RngFilterDisplay : public GroupOption{

class RngCalibrationDisplay : public GroupOption{
public:
RngCalibrationDisplay();
RngCalibrationDisplay(std::string label = "RNG Calibration");

void set_calibrations(const RngCalibrations& calibrations);
void set_hits(const std::vector<AdvRngState>& rng_states);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,8 @@ bool use_rare_candy(
const BaseStats& base_stats,
AdvRngMethod method,
bool safari_zone,
bool first
bool first,
int from_last
){
// navigate to the bag (only needed for the first use)
if (first){
Expand Down Expand Up @@ -327,8 +328,9 @@ bool use_rare_candy(
// only needed on the first use
if (first){
context.wait_for_all_requests();
pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms);
pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms);
for (int i=0; i<(2+from_last); i++){
pbf_move_left_joystick(context, {0, +1}, 200ms, 300ms);
}
}

// watch for level up stats
Expand Down Expand Up @@ -365,8 +367,8 @@ bool use_rare_candy(
// return to the bag (possibly learning a move, but trying to prevent evolution)
int attempts = 0;
while (true){
if (attempts > 5){
console.log("use_rare_candy(): failed to return to bag menu in 5 attempts.");
if (attempts > 25){
console.log("use_rare_candy(): failed to return to bag menu.");
return true;
}
BagWatcher bag_menu(COLOR_RED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ bool use_rare_candy(
const BaseStats& base_stats,
AdvRngMethod method = AdvRngMethod::Method1,
bool safari_zone = false,
bool first = false
bool first = false,
int from_last = 0
);

int watch_for_shiny_encounter(ConsoleHandle& console, ProControllerContext& context);
Expand Down
Loading
Loading