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
1 change: 1 addition & 0 deletions SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ GameSettings::GameSettings()
PA_ADD_STATIC(m_soft_reset_timings);
PA_ADD_OPTION(SELECT_BUTTON_MASH0);
PA_ADD_OPTION(ENTER_GAME_WAIT0);
PA_ADD_OPTION(ENTER_GAME_MASH0);
PA_ADD_STATIC(m_shiny_audio_settings);
PA_ADD_OPTION(SHINY_SOUND_THRESHOLD);
PA_ADD_OPTION(SHINY_SOUND_LOW_FREQUENCY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,88 +11,131 @@
#include "CommonFramework/ImageTools/ImageStats.h"
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "PokemonRSE/PokemonRSE_Settings.h"
#include "PokemonRSE_DialogDetector.h"

#include <iostream>
using std::cout;
using std::endl;
//#include <iostream>
//using std::cout;
//using std::endl;

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonRSE{

/*
DialogDetector::DialogDetector(Color color)
: m_left_box(0.155, 0.727, 0.015, 0.168)
, m_right_box(0.837, 0.729, 0.008, 0.161)
{}
void DialogDetector::make_overlays(VideoOverlaySet& items) const{
items.add(COLOR_RED, m_left_box);
items.add(COLOR_RED, m_right_box);
}
bool DialogDetector::detect(const ImageViewRGB32& screen) const{
ImageViewRGB32 left_image = extract_box_reference(screen, m_left_box);
ImageViewRGB32 right_image = extract_box_reference(screen, m_right_box);
if (is_solid(left_image, { 0.335, 0.331, 0.332 }) && is_solid(right_image, { 0.335, 0.331, 0.332 })){
return true;
}
return false;
}
*/

BattleDialogDetector::BattleDialogDetector(Color color)
: m_left_box(0.158, 0.725, 0.011, 0.176)
, m_right_box(0.827, 0.722, 0.013, 0.178)
: m_dialog_top_box(0.049224, 0.738530, 0.901359, 0.008023)
, m_dialog_right_box(0.943471, 0.746553, 0.007111, 0.212602)
, m_dialog_top_jpn_box(0.068780, 0.738530, 0.856913, 0.012034)
, m_dialog_right_jpn_box(0.918582, 0.747890, 0.007111, 0.208590)
{}
void BattleDialogDetector::make_overlays(VideoOverlaySet& items) const{
items.add(COLOR_RED, m_left_box);
items.add(COLOR_RED, m_right_box);
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_jpn_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_jpn_box));
}
bool BattleDialogDetector::detect(const ImageViewRGB32& screen){
ImageViewRGB32 left_image = extract_box_reference(screen, m_left_box);
ImageViewRGB32 right_image = extract_box_reference(screen, m_right_box);
if (is_solid(left_image, { 0.335, 0.331, 0.332 }) && is_solid(right_image, { 0.335, 0.331, 0.332 })){
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);

ImageViewRGB32 dialog_top_image = extract_box_reference(game_screen, m_dialog_top_box);
ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box);
ImageViewRGB32 dialog_top_jpn_image = extract_box_reference(game_screen, m_dialog_top_jpn_box);
ImageViewRGB32 dialog_right_jpn_image = extract_box_reference(game_screen, m_dialog_right_jpn_box);

if ((is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
||
(is_solid(dialog_top_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& is_solid(dialog_right_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
){
return true;
}
return false;
}

*/

BattleMenuDetector::BattleMenuDetector(Color color)
: m_left_box(0.439, 0.717, 0.021, 0.192)
, m_right_box(0.821, 0.725, 0.030, 0.181)
: m_menu_top_box(0.599462, 0.738530, 0.366233, 0.004011) //top of the white box
, m_menu_bottom_box(0.602128, 0.947120, 0.368010, 0.006686)
, m_dialog_top_box(0.068780, 0.739867, 0.488903, 0.008023) //teal boxes
, m_dialog_right_box(0.553238, 0.739867, 0.006222, 0.215276)

, m_menu_top_eme_box(0.534571, 0.746553, 0.434679, 0.008023)
, m_menu_right_eme_box(0.962138, 0.747890, 0.007111, 0.205916)
, m_dialog_top_eme_box(0.046557, 0.741204, 0.442679, 0.008023)
, m_dialog_right_eme_box(0.487458, 0.742541, 0.004445, 0.216613)
{}
void BattleMenuDetector::make_overlays(VideoOverlaySet& items) const{
items.add(COLOR_RED, m_left_box);
items.add(COLOR_RED, m_right_box);
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_top_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_bottom_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_box));

items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_top_eme_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_right_eme_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_eme_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_eme_box));
}
bool BattleMenuDetector::detect(const ImageViewRGB32& screen){
ImageViewRGB32 left_image = extract_box_reference(screen, m_left_box);
ImageViewRGB32 right_image = extract_box_reference(screen, m_right_box);
if (is_solid(left_image, { 0.335, 0.331, 0.332 }) && is_solid(right_image, { 0.25, 0.38, 0.369 })){
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);

//Menu is white
ImageViewRGB32 menu_top_image = extract_box_reference(game_screen, m_menu_top_box);
ImageViewRGB32 menu_bottom_image = extract_box_reference(game_screen, m_menu_bottom_box);
ImageViewRGB32 menu_top_jpn_image = extract_box_reference(game_screen, m_menu_top_eme_box);
ImageViewRGB32 menu_right_jpn_image = extract_box_reference(game_screen, m_menu_right_eme_box);

//Background dialog is teal
ImageViewRGB32 dialog_top_image = extract_box_reference(game_screen, m_dialog_top_box);
ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box);
ImageViewRGB32 dialog_top_jpn_image = extract_box_reference(game_screen, m_dialog_top_eme_box);
ImageViewRGB32 dialog_right_jpn_image = extract_box_reference(game_screen, m_dialog_right_eme_box);

if ((is_white(menu_top_image) //Ruby/Sapphire, all languages. Emerald Japan.
&& is_white(menu_bottom_image)
&& is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
||
(is_white(menu_top_jpn_image) //Emerald, all languages except Japan.
&& is_white(menu_right_jpn_image)
&& is_solid(dialog_top_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& is_solid(dialog_right_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
){
return true;
}
return false;
}


AdvanceBattleDialogDetector::AdvanceBattleDialogDetector(Color color)
: m_dialog_box(0.156, 0.715, 0.686, 0.193)
, m_left_box(0.156, 0.724, 0.010, 0.176)
, m_right_box(0.836, 0.717, 0.008, 0.189)
: m_dialog_box(0.043890, 0.737193, 0.913804, 0.227310)
, m_dialog_top_box(0.049224, 0.738530, 0.901359, 0.008023)
, m_dialog_right_box(0.943471, 0.746553, 0.007111, 0.212602)
, m_dialog_jpn_box(0.059891, 0.742541, 0.872914, 0.216613)
, m_dialog_top_jpn_box(0.068780, 0.738530, 0.856913, 0.012034)
, m_dialog_right_jpn_box(0.918582, 0.747890, 0.007111, 0.208590)
{}
void AdvanceBattleDialogDetector::make_overlays(VideoOverlaySet& items) const{
items.add(COLOR_RED, m_dialog_box);
items.add(COLOR_RED, m_left_box);
items.add(COLOR_RED, m_right_box);
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_jpn_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_jpn_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_jpn_box));
}
bool AdvanceBattleDialogDetector::detect(const ImageViewRGB32& screen){
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);

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
extract_box_reference(game_screen, m_dialog_box),
combine_rgb(164, 0, 0), combine_rgb(255, 114, 87), Color(0), replace_color_within_range
);
ImageStats stats = image_stats(filtered_region);

Expand All @@ -103,15 +146,28 @@ bool AdvanceBattleDialogDetector::detect(const ImageViewRGB32& screen){
cout << stats.average.b << endl;
*/

ImageViewRGB32 left_image = extract_box_reference(screen, m_left_box);
ImageViewRGB32 right_image = extract_box_reference(screen, m_right_box);

if (is_solid(left_image, { 0.335, 0.331, 0.332 })
&& is_solid(right_image, { 0.335, 0.331, 0.332 })
&& (stats.average.r > stats.average.b + 200)
&& (stats.average.r > stats.average.g + 200)
)
{
//japanese
ImageRGB32 filtered_region_jpn = filter_rgb32_range(
extract_box_reference(game_screen, m_dialog_jpn_box),
combine_rgb(164, 0, 0), combine_rgb(255, 114, 87), Color(0), replace_color_within_range
);
ImageStats stats2 = image_stats(filtered_region_jpn);

ImageViewRGB32 dialog_top_image = extract_box_reference(game_screen, m_dialog_top_box);
ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box);
ImageViewRGB32 dialog_top_jpn_image = extract_box_reference(game_screen, m_dialog_top_jpn_box);
ImageViewRGB32 dialog_right_jpn_image = extract_box_reference(game_screen, m_dialog_right_jpn_box);

if ((is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& (stats.average.r > stats.average.b + 180)
&& (stats.average.r > stats.average.g + 180))
||
(is_solid(dialog_top_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& is_solid(dialog_right_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
&& (stats2.average.r > stats2.average.b + 180)
&& (stats2.average.r > stats2.average.g + 180))
){
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,9 @@ namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonRSE{

/*
// TODO: Detect that a dialog box is on screen by looking for the white of the box
class DialogDetector : public StaticScreenDetector{
public:
DialogDetector(Color color);

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

private:
ImageFloatBox m_left_box;
ImageFloatBox m_right_box;
};
class DialogWatcher : public DetectorToFinder<DialogDetector>{
public:
DialogWatcher(Color color)
: DetectorToFinder("DialogWatcher", std::chrono::milliseconds(250), color)
{}
};
*/

// Battle dialog boxes are teal
// This is unused right now so isn't tested well
/*
class BattleDialogDetector : public StaticScreenDetector{
public:
BattleDialogDetector(Color color);
Expand All @@ -51,19 +32,24 @@ class BattleDialogDetector : public StaticScreenDetector{
virtual bool detect(const ImageViewRGB32& screen) override;

private:
ImageFloatBox m_left_box;
ImageFloatBox m_right_box;
ImageFloatBox m_dialog_top_box;
ImageFloatBox m_dialog_right_box;

ImageFloatBox m_dialog_top_jpn_box;
ImageFloatBox m_dialog_right_jpn_box;
};
class BattleDialogWatcher : public DetectorToFinder<BattleDialogDetector>{
public:
BattleDialogWatcher(Color color)
: DetectorToFinder("BattleDialogWatcher", std::chrono::milliseconds(250), color)
{}
};
*/


// Battle menu is up when it is white on the right and teal on the left
// For emerald the text is more flush to the left, so we target the right of the battle menu box
// Battle menu is a white box on the right
// Teal dialog box remains on the left
// For R/S, the selection arrow is only in JPN ver, other languages use a box
// Positions slightly different on non-JPN Emerald but all langs use an arrow
class BattleMenuDetector : public StaticScreenDetector{
public:
BattleMenuDetector(Color color);
Expand All @@ -72,8 +58,17 @@ class BattleMenuDetector : public StaticScreenDetector{
virtual bool detect(const ImageViewRGB32& screen) override;

private:
ImageFloatBox m_left_box;
ImageFloatBox m_right_box;
//R/S both JPN and ENG, E for JPN
ImageFloatBox m_menu_top_box;
ImageFloatBox m_menu_bottom_box;
ImageFloatBox m_dialog_top_box;
ImageFloatBox m_dialog_right_box;

//Emerald for non-JPN
ImageFloatBox m_menu_top_eme_box;
ImageFloatBox m_menu_right_eme_box;
ImageFloatBox m_dialog_top_eme_box;
ImageFloatBox m_dialog_right_eme_box;
};
class BattleMenuWatcher : public DetectorToFinder<BattleMenuDetector>{
public:
Expand All @@ -85,8 +80,7 @@ class BattleMenuWatcher : public DetectorToFinder<BattleMenuDetector>{


// Detect the red advancement arrow by filtering for red.
// This works for now, I don't think there's colored text?
// TODO: Change this to detect that the dialog arrow is in the dialog box by filtering for the red arrow
// This is the same as BattleDialogDetector apart from the arrow
class AdvanceBattleDialogDetector : public StaticScreenDetector{
public:
AdvanceBattleDialogDetector(Color color);
Expand All @@ -96,8 +90,12 @@ class AdvanceBattleDialogDetector : public StaticScreenDetector{

private:
ImageFloatBox m_dialog_box;
ImageFloatBox m_left_box;
ImageFloatBox m_right_box;
ImageFloatBox m_dialog_top_box;
ImageFloatBox m_dialog_right_box;

ImageFloatBox m_dialog_jpn_box;
ImageFloatBox m_dialog_top_jpn_box;
ImageFloatBox m_dialog_right_jpn_box;
};
class AdvanceBattleDialogWatcher : public DetectorToFinder<AdvanceBattleDialogDetector>{
public:
Expand All @@ -107,7 +105,6 @@ class AdvanceBattleDialogWatcher : public DetectorToFinder<AdvanceBattleDialogDe
};

// Future note: when given a choice popup, there is no advance arrow.
// FRLG doesn't have an advance arrow, that's a future issue.


}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ float ShinySoundDetector::get_score_threshold() const{
std::unique_ptr<SpectrogramMatcher> ShinySoundDetector::build_spectrogram_matcher(size_t sample_rate){
return std::make_unique<SpectrogramMatcher>(
"Shiny Sound",
AudioTemplateCache::instance().get_throw("PokemonRSE/ShinySound", sample_rate),
AudioTemplateCache::instance().get_throw("PokemonFRLG/ShinySound", sample_rate),
SpectrogramMatcher::Mode::SPIKE_CONV, sample_rate,
GameSettings::instance().SHINY_SOUND_LOW_FREQUENCY
);
Expand Down
Loading
Loading