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
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,100 @@ bool SelectionDialogDetector::detect(const ImageViewRGB32& screen){
return false;
}

BattleDialogDetector::BattleDialogDetector(Color color)
: m_dialog_top_box(0.152, 0.721, 0.694, 0.008)
, m_dialog_right_box(0.842, 0.730, 0.004, 0.171)
{}
void BattleDialogDetector::make_overlays(VideoOverlaySet& items) const{
items.add(COLOR_RED, m_dialog_top_box);
items.add(COLOR_RED, m_dialog_right_box);
}
bool BattleDialogDetector::detect(const ImageViewRGB32& screen){
ImageViewRGB32 dialog_top_image = extract_box_reference(screen, m_dialog_top_box);
ImageViewRGB32 dialog_right_image = extract_box_reference(screen, m_dialog_right_box);

if (is_solid(dialog_top_image, { 0.176, 0.357, 0.467 })
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 })
){
return true;
}
return false;
}


BattleMenuDetector::BattleMenuDetector(Color color)
: m_menu_top_box(0.522, 0.716, 0.331, 0.011)
, m_menu_right_box(0.845, 0.727, 0.008, 0.175)
, m_dialog_top_box(0.153, 0.720, 0.343, 0.014) //top of the white dialog box
, m_dialog_right_box(0.486, 0.722, 0.009, 0.177) //right side, closest to the menu
{}
void BattleMenuDetector::make_overlays(VideoOverlaySet& items) const{
items.add(COLOR_RED, m_menu_top_box);
items.add(COLOR_RED, m_menu_right_box);
items.add(COLOR_RED, m_dialog_top_box);
items.add(COLOR_RED, m_dialog_right_box);
}
bool BattleMenuDetector::detect(const ImageViewRGB32& screen){
//Menu is white
ImageViewRGB32 menu_top_image = extract_box_reference(screen, m_menu_top_box);
ImageViewRGB32 menu_right_image = extract_box_reference(screen, m_menu_right_box);

//Background dialog is teal
ImageViewRGB32 dialog_top_image = extract_box_reference(screen, m_dialog_top_box);
ImageViewRGB32 dialog_right_image = extract_box_reference(screen, m_dialog_right_box);

if (is_solid(menu_top_image, { 0.335, 0.332, 0.335 }) //253, 251, 254 white
&& is_solid(menu_right_image, { 0.335, 0.332, 0.335 })
&& is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }) //40, 81, 106 teal
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 })
){
return true;
}
return false;
}


AdvanceBattleDialogDetector::AdvanceBattleDialogDetector(Color color)
: m_dialog_box(0.152, 0.721, 0.694, 0.177)
, m_dialog_top_box(0.152, 0.721, 0.694, 0.008)
, m_dialog_right_box(0.842, 0.730, 0.004, 0.171)
{}
void AdvanceBattleDialogDetector::make_overlays(VideoOverlaySet& items) const{
items.add(COLOR_RED, m_dialog_box);
items.add(COLOR_RED, m_dialog_top_box);
items.add(COLOR_RED, m_dialog_right_box);
}
bool AdvanceBattleDialogDetector::detect(const ImageViewRGB32& screen){
const bool replace_color_within_range = false;

//Filter out background
ImageRGB32 filtered_region = filter_rgb32_range(
extract_box_reference(screen, m_dialog_box),
combine_rgb(185, 0, 1), combine_rgb(255, 32, 33), Color(0), replace_color_within_range
);
ImageStats stats = image_stats(filtered_region);

/*
filtered_region.save("./filtered_only.png");
cout << stats.average.r << endl;
cout << stats.average.g << endl;
cout << stats.average.b << endl;
*/

ImageViewRGB32 dialog_top_image = extract_box_reference(screen, m_dialog_top_box);
ImageViewRGB32 dialog_right_image = extract_box_reference(screen, m_dialog_right_box);

if (is_solid(dialog_top_image, { 0.176, 0.357, 0.467 })
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 })
&& (stats.average.r > stats.average.b + 200)
&& (stats.average.r > stats.average.g + 200)
)
{
return true;
}
return false;
}


}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,70 @@ class SelectionDialogWatcher : public DetectorToFinder<SelectionDialogDetector>{
{}
};

// Battle dialog boxes are teal, similar to r/s/e
class BattleDialogDetector : public StaticScreenDetector{
public:
BattleDialogDetector(Color color);

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool detect(const ImageViewRGB32& screen) override;

private:
ImageFloatBox m_dialog_top_box;
ImageFloatBox m_dialog_right_box;
};
class BattleDialogWatcher : public DetectorToFinder<BattleDialogDetector>{
public:
BattleDialogWatcher(Color color)
: DetectorToFinder("BattleDialogWatcher", std::chrono::milliseconds(250), color)
{}
};


// Battle menu is a white box on the right with FIGHT/POKEMON/BAG/RUN
// The dialog box with "what will POKEMON do?" is dark teal/navy
class BattleMenuDetector : public StaticScreenDetector{
public:
BattleMenuDetector(Color color);

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool detect(const ImageViewRGB32& screen) override;

private:
ImageFloatBox m_menu_top_box;
ImageFloatBox m_menu_right_box;
ImageFloatBox m_dialog_top_box;
ImageFloatBox m_dialog_right_box;
};
class BattleMenuWatcher : public DetectorToFinder<BattleMenuDetector>{
public:
BattleMenuWatcher(Color color)
: DetectorToFinder("BattleMenuWatcher", std::chrono::milliseconds(250), color)
{}
};


// Detect the red advancement arrow by filtering for red.
// No red colored text in battle?
// reuse the battledialog checks for the top and right
class AdvanceBattleDialogDetector : public StaticScreenDetector{
public:
AdvanceBattleDialogDetector(Color color);

virtual void make_overlays(VideoOverlaySet& items) const override;
virtual bool detect(const ImageViewRGB32& screen) override;

private:
ImageFloatBox m_dialog_box;
ImageFloatBox m_dialog_top_box;
ImageFloatBox m_dialog_right_box;
};
class AdvanceBattleDialogWatcher : public DetectorToFinder<AdvanceBattleDialogDetector>{
public:
AdvanceBattleDialogWatcher(Color color)
: DetectorToFinder("AdvanceBattleDialogWatcher", std::chrono::milliseconds(250), color)
{}
};



Expand Down
103 changes: 82 additions & 21 deletions SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Navigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,67 +136,88 @@ void open_slot_six(ConsoleHandle& console, ProControllerContext& context){
context.wait_for_all_requests();
}

/*
bool handle_encounter(VideoStream& stream, ProControllerContext& context, bool send_out_lead) {
bool handle_encounter(ConsoleHandle& console, ProControllerContext& context, bool send_out_lead) {
float shiny_coefficient = 1.0;
ShinySoundDetector shiny_detector(stream.logger(), [&](float error_coefficient) -> bool{
ShinySoundDetector shiny_detector(console.logger(), [&](float error_coefficient) -> bool{
shiny_coefficient = error_coefficient;
return true;
});
AdvanceBattleDialogWatcher legendary_appeared(COLOR_YELLOW);

stream.log("Starting battle.");
pbf_mash_button(context, BUTTON_A, 4320ms);
context.wait_for_all_requests();

int res = run_until<ProControllerContext>(
stream, context,
console, context,
[&](ProControllerContext& context) {
int ret = wait_until(
stream, context,
std::chrono::seconds(30),
console, context,
std::chrono::seconds(30), //More than enough time for shiny sound
{{legendary_appeared}}
);
if (ret == 0) {
stream.log("Advance arrow detected.");
console.log("Battle Advance arrow detected.");
} else {
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"handle_encounter(): Did not detect battle start.",
stream
"handle_encounter(): Did not detect battle advance arrow.",
console
);
}
pbf_wait(context, 1000ms);
context.wait_for_all_requests();

/*
//Send out shiny lead to test detection
BattleMenuWatcher battle_menu(COLOR_RED);
console.log("Sending out lead Pokemon.");
pbf_press_button(context, BUTTON_A, 320ms, 320ms);

int ret2 = wait_until(
console, context,
std::chrono::seconds(15),
{ {battle_menu} }
);
if (ret2 == 0) {
console.log("Battle menu detecteed!");
}
else {
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"handle_encounter(): Did not detect battle menu.",
console
);
}
pbf_wait(context, 100000ms); //extreme audio delay on my cheap test device
context.wait_for_all_requests();
*/

},
{{shiny_detector}}
);
shiny_detector.throw_if_no_sound();
if (res == 0){
stream.log("Shiny detected!");
console.log("Shiny detected!");
return true;
}
stream.log("Shiny not found.");
console.log("No shiny detected.");

if (send_out_lead) {
//Send out lead, no shiny detection needed.
//Send out lead, no shiny detection needed. (Or wanted.)
BattleMenuWatcher battle_menu(COLOR_RED);
stream.log("Sending out lead Pokemon.");
console.log("Sending out lead Pokemon.");
pbf_press_button(context, BUTTON_A, 320ms, 320ms);

int ret = wait_until(
stream, context,
console, context,
std::chrono::seconds(15),
{ {battle_menu} }
);
if (ret == 0) {
stream.log("Battle menu detecteed!");
console.log("Battle menu detecteed!");
}
else {
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"handle_encounter(): Did not detect battle menu.",
stream
console
);
}
pbf_wait(context, 1000ms);
Expand All @@ -205,7 +226,47 @@ bool handle_encounter(VideoStream& stream, ProControllerContext& context, bool s

return false;
}
*/

void flee_battle(ConsoleHandle& console, ProControllerContext& context) {
console.log("Navigate to Run.");
pbf_press_dpad(context, DPAD_RIGHT, 160ms, 160ms);
pbf_press_dpad(context, DPAD_DOWN, 160ms, 160ms);
pbf_press_button(context, BUTTON_A, 160ms, 320ms);

AdvanceBattleDialogWatcher ran_away(COLOR_YELLOW);
int ret2 = wait_until(
console, context,
std::chrono::seconds(5),
{{ran_away}}
);
if (ret2 == 0) {
console.log("Running away...");
} else {
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"flee_battle(): Unable to navigate to flee button.",
console
);
}

pbf_press_button(context, BUTTON_A, 320ms, 320ms);
BlackScreenOverWatcher battle_over(COLOR_RED, {0.282, 0.064, 0.448, 0.871});
int ret3 = wait_until(
console, context,
std::chrono::seconds(5),
{{battle_over}}
);
if (ret3 == 0) {
console.log("Successfully fled the battle.");
} else {
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"flee_battle(): Unable to flee from battle.",
console
);
}
}


}
}
Expand Down
8 changes: 5 additions & 3 deletions SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Navigation.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ void soft_reset(const ProgramInfo& info, VideoStream& stream, ProControllerConte
void open_slot_six(ConsoleHandle& console, ProControllerContext& context);

// After press A/walking up to enter a battle, run this handle the battle start and to check if opponent is shiny.
// Set send_out_lead to true and then use flee_battle() after if game is Emerald.
// For R/S, send_out_lead as false and then soft_reset() to save time.
//bool handle_encounter(VideoStream& stream, ProControllerContext& context, bool send_out_lead);
// Set send_out_lead to true and then use flee_battle() after if for run away resets
// For soft resets, send_out_lead as false and then soft_reset() to save time.
bool handle_encounter(ConsoleHandle& console, ProControllerContext& context, bool send_out_lead);

// Run from battle. Cursor must start on the FIGHT button. Assumes fleeing will always work. (Smoke Ball)
void flee_battle(ConsoleHandle& console, ProControllerContext& context);

}
}
Expand Down
4 changes: 4 additions & 0 deletions SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "PokemonFRLG_Settings.h"

#include "Programs/ShinyHunting/PokemonFRLG_GiftReset.h"
#include "Programs/ShinyHunting/PokemonFRLG_LegendaryReset.h"
#include "Programs/ShinyHunting/PokemonFRLG_LegendaryRunAway.h"
#include "Programs/ShinyHunting/PokemonFRLG_PrizeCornerReset.h"
#include "Programs/TestPrograms/PokemonFRLG_SoundListener.h"

Expand All @@ -34,6 +36,8 @@ std::vector<PanelEntry> PanelListFactory::make_panels() const{

ret.emplace_back("---- Shiny Hunting ----");
ret.emplace_back(make_single_switch_program<GiftReset_Descriptor, GiftReset>());
ret.emplace_back(make_single_switch_program<LegendaryReset_Descriptor, LegendaryReset>());
ret.emplace_back(make_single_switch_program<LegendaryRunAway_Descriptor, LegendaryRunAway>());
ret.emplace_back(make_single_switch_program<PrizeCornerReset_Descriptor, PrizeCornerReset>());


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ GiftReset::GiftReset()
)
, GO_HOME_WHEN_DONE(true)
, NOTIFICATION_SHINY(
"Shiny",
"Shiny found",
true, true, ImageAttachmentMode::JPG,
{"Notifs", "Showcase"}
)
Expand Down Expand Up @@ -255,7 +255,7 @@ void GiftReset::open_summary(SingleSwitchProgramEnvironment& env, ProControllerC
if (ret1 == 0){
env.log("Entered party menu.");
}else{
env.log("Timed out waiting to enter game.", COLOR_RED);
env.log("Unable to enter party menu.", COLOR_RED);
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"open_summary(): Unable to enter Party menu.",
Expand Down Expand Up @@ -283,7 +283,7 @@ void GiftReset::open_summary(SingleSwitchProgramEnvironment& env, ProControllerC
if (ret2 == 0){
env.log("Entered summary.");
}else{
env.log("Timed out waiting to enter game.", COLOR_RED);
env.log("Unable to enter summary.", COLOR_RED);
OperationFailedException::fire(
ErrorReport::SEND_ERROR_REPORT,
"open_summary(): Unable to enter summary.",
Expand Down
Loading