Skip to content

Commit e700ddf

Browse files
authored
Frlg fixes (#1132)
* update frlg battle detectors for japanese * log gift reset target * frlg summary page detection * battle menu tests
1 parent 8b90c9e commit e700ddf

10 files changed

Lines changed: 338 additions & 7 deletions

File tree

SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_DialogDetector.cpp

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,29 @@ bool SelectionDialogDetector::detect(const ImageViewRGB32& screen){
131131
BattleDialogDetector::BattleDialogDetector(Color color)
132132
: m_dialog_top_box(0.0372308, 0.750154, 0.925538, 0.00934615)
133133
, m_dialog_right_box(0.956615, 0.7595, 0.00615385, 0.185885)
134+
, m_dialog_top_jpn_box(0.043890, 0.749227, 0.910248, 0.008023) //jpn positions might work for other languages
135+
, m_dialog_right_jpn_box(0.950583, 0.751901, 0.003556, 0.199230) //dialog might get in the way though
134136
{}
135137
void BattleDialogDetector::make_overlays(VideoOverlaySet& items) const{
136138
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
137139
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_box));
138140
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_box));
141+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_jpn_box));
142+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_jpn_box));
139143
}
140144
bool BattleDialogDetector::detect(const ImageViewRGB32& screen){
141145
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);
142146

143147
ImageViewRGB32 dialog_top_image = extract_box_reference(game_screen, m_dialog_top_box);
144148
ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box);
149+
ImageViewRGB32 dialog_top_jpn_image = extract_box_reference(game_screen, m_dialog_top_jpn_box);
150+
ImageViewRGB32 dialog_right_jpn_image = extract_box_reference(game_screen, m_dialog_right_jpn_box);
145151

146-
if (is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
147-
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
152+
if ((is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
153+
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
154+
||
155+
(is_solid(dialog_top_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
156+
&& is_solid(dialog_right_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
148157
){
149158
return true;
150159
}
@@ -157,29 +166,47 @@ BattleMenuDetector::BattleMenuDetector(Color color)
157166
, m_menu_right_box(0.961538, 0.752231, 0.00615385, 0.200423)
158167
, m_dialog_top_box(0.036, 0.749115, 0.459077, 0.0135)
159168
, m_dialog_right_box(0.490154, 0.762615, 0.00615385, 0.178615) //right side, closest to the menu
169+
, m_menu_top_jpn_box(0.593239, 0.743878, 0.373344, 0.009360) //very different positions!
170+
, m_menu_right_jpn_box(0.961538, 0.752231, 0.00615385, 0.200423)
171+
, m_dialog_top_jpn_box(0.043001, 0.750564, 0.520015, 0.002674)
172+
, m_dialog_right_jpn_box(0.559460, 0.750564, 0.003556, 0.196556)
160173
{}
161174
void BattleMenuDetector::make_overlays(VideoOverlaySet& items) const{
162175
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
163176
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_top_box));
164177
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_right_box));
165178
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_box));
166179
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_box));
180+
181+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_top_jpn_box));
182+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_menu_right_jpn_box));
183+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_jpn_box));
184+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_jpn_box));
167185
}
168186
bool BattleMenuDetector::detect(const ImageViewRGB32& screen){
169187
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);
170188

171189
//Menu is white
172190
ImageViewRGB32 menu_top_image = extract_box_reference(game_screen, m_menu_top_box);
173191
ImageViewRGB32 menu_right_image = extract_box_reference(game_screen, m_menu_right_box);
192+
ImageViewRGB32 menu_top_jpn_image = extract_box_reference(game_screen, m_menu_top_jpn_box);
193+
ImageViewRGB32 menu_right_jpn_image = extract_box_reference(game_screen, m_menu_right_jpn_box);
174194

175195
//Background dialog is teal
176196
ImageViewRGB32 dialog_top_image = extract_box_reference(game_screen, m_dialog_top_box);
177197
ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box);
198+
ImageViewRGB32 dialog_top_jpn_image = extract_box_reference(game_screen, m_dialog_top_jpn_box);
199+
ImageViewRGB32 dialog_right_jpn_image = extract_box_reference(game_screen, m_dialog_right_jpn_box);
178200

179-
if (is_white(menu_top_image)
201+
if ((is_white(menu_top_image) //All languages except japanese
180202
&& is_white(menu_right_image)
181203
&& is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20) //40, 81, 106 teal
182-
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
204+
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
205+
||
206+
(is_white(menu_top_jpn_image) //japanese
207+
&& is_white(menu_right_jpn_image)
208+
&& is_solid(dialog_top_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
209+
&& is_solid(dialog_right_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20))
183210
){
184211
return true;
185212
}
@@ -191,12 +218,18 @@ AdvanceBattleDialogDetector::AdvanceBattleDialogDetector(Color color)
191218
: m_dialog_box(0.036, 0.748077, 0.926769, 0.204577)
192219
, m_dialog_top_box(0.0372308, 0.750154, 0.925538, 0.00934615)
193220
, m_dialog_right_box(0.956615, 0.7595, 0.00615385, 0.185885)
221+
, m_dialog_jpn_box(0.043890, 0.749227, 0.911137, 0.203242) //this position is very different!
222+
, m_dialog_top_jpn_box(0.043890, 0.749227, 0.910248, 0.008023)
223+
, m_dialog_right_jpn_box(0.950583, 0.751901, 0.003556, 0.199230)
194224
{}
195225
void AdvanceBattleDialogDetector::make_overlays(VideoOverlaySet& items) const{
196226
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
197227
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_box));
198228
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_box));
199229
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_box));
230+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_jpn_box));
231+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_top_jpn_box));
232+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_dialog_right_jpn_box));
200233
}
201234
bool AdvanceBattleDialogDetector::detect(const ImageViewRGB32& screen){
202235
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);
@@ -217,13 +250,27 @@ bool AdvanceBattleDialogDetector::detect(const ImageViewRGB32& screen){
217250
cout << stats.average.b << endl;
218251
*/
219252

253+
//japanese
254+
ImageRGB32 filtered_region_jpn = filter_rgb32_range(
255+
extract_box_reference(game_screen, m_dialog_jpn_box),
256+
combine_rgb(164, 0, 0), combine_rgb(255, 114, 87), Color(0), replace_color_within_range
257+
);
258+
ImageStats stats2 = image_stats(filtered_region_jpn);
259+
220260
ImageViewRGB32 dialog_top_image = extract_box_reference(game_screen, m_dialog_top_box);
221261
ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box);
262+
ImageViewRGB32 dialog_top_jpn_image = extract_box_reference(game_screen, m_dialog_top_jpn_box);
263+
ImageViewRGB32 dialog_right_jpn_image = extract_box_reference(game_screen, m_dialog_right_jpn_box);
222264

223-
if (is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
265+
if ((is_solid(dialog_top_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
224266
&& is_solid(dialog_right_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
225267
&& (stats.average.r > stats.average.b + 180)
226-
&& (stats.average.r > stats.average.g + 180)
268+
&& (stats.average.r > stats.average.g + 180))
269+
||
270+
(is_solid(dialog_top_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
271+
&& is_solid(dialog_right_jpn_image, { 0.176, 0.357, 0.467 }, 0.25, 20)
272+
&& (stats2.average.r > stats2.average.b + 180)
273+
&& (stats2.average.r > stats2.average.g + 180))
227274
){
228275
return true;
229276
}

SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_DialogDetector.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ class BattleDialogDetector : public StaticScreenDetector{
138138
private:
139139
ImageFloatBox m_dialog_top_box;
140140
ImageFloatBox m_dialog_right_box;
141+
142+
ImageFloatBox m_dialog_top_jpn_box;
143+
ImageFloatBox m_dialog_right_jpn_box;
141144
};
142145
class BattleDialogWatcher : public DetectorToFinder<BattleDialogDetector>{
143146
public:
@@ -161,6 +164,11 @@ class BattleMenuDetector : public StaticScreenDetector{
161164
ImageFloatBox m_menu_right_box;
162165
ImageFloatBox m_dialog_top_box;
163166
ImageFloatBox m_dialog_right_box;
167+
168+
ImageFloatBox m_menu_top_jpn_box;
169+
ImageFloatBox m_menu_right_jpn_box;
170+
ImageFloatBox m_dialog_top_jpn_box;
171+
ImageFloatBox m_dialog_right_jpn_box;
164172
};
165173
class BattleMenuWatcher : public DetectorToFinder<BattleMenuDetector>{
166174
public:
@@ -184,6 +192,10 @@ class AdvanceBattleDialogDetector : public StaticScreenDetector{
184192
ImageFloatBox m_dialog_box;
185193
ImageFloatBox m_dialog_top_box;
186194
ImageFloatBox m_dialog_right_box;
195+
196+
ImageFloatBox m_dialog_jpn_box;
197+
ImageFloatBox m_dialog_top_jpn_box;
198+
ImageFloatBox m_dialog_right_jpn_box;
187199
};
188200
class AdvanceBattleDialogWatcher : public DetectorToFinder<AdvanceBattleDialogDetector>{
189201
public:
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/* Summary Detector
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#include "CommonTools/Images/SolidColorTest.h"
8+
#include "CommonTools/Images/ImageFilter.h"
9+
#include "CommonFramework/ImageTools/ImageBoxes.h"
10+
#include "CommonFramework/ImageTools/ImageStats.h"
11+
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
12+
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
13+
#include "CommonTools/Images/SolidColorTest.h"
14+
#include "CommonTools/Images/WaterfillUtilities.h"
15+
#include "PokemonFRLG/PokemonFRLG_Settings.h"
16+
#include "PokemonFRLG_SummaryDetector.h"
17+
18+
namespace PokemonAutomation{
19+
namespace NintendoSwitch{
20+
namespace PokemonFRLG{
21+
22+
SummaryDetector::SummaryDetector(Color color)
23+
: m_page_1_box(0.441235, 0.033869, 0.016889, 0.030754) //white
24+
, m_page_2_box(0.509681, 0.035206, 0.014223, 0.026742) //blue
25+
, m_page_3_box(0.577239, 0.039218, 0.012445, 0.021394) //blue
26+
{}
27+
void SummaryDetector::make_overlays(VideoOverlaySet& items) const{
28+
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
29+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_1_box));
30+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_2_box));
31+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_3_box));
32+
}
33+
bool SummaryDetector::detect(const ImageViewRGB32& screen){
34+
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);
35+
36+
ImageViewRGB32 page_1_image = extract_box_reference(game_screen, m_page_1_box);
37+
ImageViewRGB32 page_2_image = extract_box_reference(game_screen, m_page_2_box);
38+
ImageViewRGB32 page_3_image = extract_box_reference(game_screen, m_page_3_box);
39+
if (is_white(page_1_image)
40+
&& is_solid(page_2_image, { 0, 0.3333, 0.6666 }, 0.25, 20)
41+
&& is_solid(page_3_image, { 0, 0.3333, 0.6666 }, 0.25, 20)
42+
){
43+
return true;
44+
}
45+
return false;
46+
}
47+
48+
SummaryPage2Detector::SummaryPage2Detector(Color color)
49+
: m_page_1_box(0.441235, 0.033869, 0.016889, 0.030754) //tan
50+
, m_page_2_box(0.509681, 0.035206, 0.014223, 0.026742) //white
51+
, m_page_3_box(0.577239, 0.039218, 0.012445, 0.021394) //blue
52+
{}
53+
void SummaryPage2Detector::make_overlays(VideoOverlaySet& items) const{
54+
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
55+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_1_box));
56+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_2_box));
57+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_3_box));
58+
}
59+
bool SummaryPage2Detector::detect(const ImageViewRGB32& screen){
60+
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);
61+
62+
ImageViewRGB32 page_1_image = extract_box_reference(game_screen, m_page_1_box);
63+
ImageViewRGB32 page_2_image = extract_box_reference(game_screen, m_page_2_box);
64+
ImageViewRGB32 page_3_image = extract_box_reference(game_screen, m_page_3_box);
65+
if (is_solid(page_1_image, { 0.5117, 0.3763, 0.2294 }, 0.25, 20)
66+
&& is_white(page_2_image)
67+
&& is_solid(page_3_image, { 0, 0.3333, 0.6666 }, 0.25, 20)
68+
){
69+
return true;
70+
}
71+
return false;
72+
}
73+
74+
SummaryPage3Detector::SummaryPage3Detector(Color color)
75+
: m_page_1_box(0.441235, 0.033869, 0.016889, 0.030754) //tan
76+
, m_page_2_box(0.509681, 0.035206, 0.014223, 0.026742) //tan
77+
, m_page_3_box(0.577239, 0.039218, 0.012445, 0.021394) //white
78+
{}
79+
void SummaryPage3Detector::make_overlays(VideoOverlaySet& items) const{
80+
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
81+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_1_box));
82+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_2_box));
83+
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_page_3_box));
84+
}
85+
bool SummaryPage3Detector::detect(const ImageViewRGB32& screen){
86+
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);
87+
88+
ImageViewRGB32 page_1_image = extract_box_reference(game_screen, m_page_1_box);
89+
ImageViewRGB32 page_2_image = extract_box_reference(game_screen, m_page_2_box);
90+
ImageViewRGB32 page_3_image = extract_box_reference(game_screen, m_page_3_box);
91+
if (is_solid(page_1_image, { 0.5117, 0.3763, 0.2294 }, 0.25, 20)
92+
&& is_solid(page_2_image, { 0.5117, 0.3763, 0.2294 }, 0.25, 20)
93+
&& is_white(page_3_image)
94+
){
95+
return true;
96+
}
97+
return false;
98+
}
99+
100+
101+
}
102+
}
103+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* Summary Detector
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_PokemonFRLG_SummaryDetector_H
8+
#define PokemonAutomation_PokemonFRLG_SummaryDetector_H
9+
10+
#include <chrono>
11+
#include <atomic>
12+
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
13+
#include "Common/Cpp/Color.h"
14+
#include "CommonFramework/ImageTools/ImageBoxes.h"
15+
#include "CommonTools/VisualDetector.h"
16+
#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h"
17+
18+
namespace PokemonAutomation{
19+
class CancellableScope;
20+
class VideoFeed;
21+
namespace NintendoSwitch{
22+
namespace PokemonFRLG{
23+
24+
// Detect the default (first) Pokemon Summary page
25+
// This has nature and OT, but no stats
26+
// This will work with all languages, as the page indicators are in the same positions
27+
class SummaryDetector : public StaticScreenDetector{
28+
public:
29+
SummaryDetector(Color color);
30+
31+
virtual void make_overlays(VideoOverlaySet& items) const override;
32+
virtual bool detect(const ImageViewRGB32& screen) override;
33+
34+
private:
35+
ImageFloatBox m_page_1_box;
36+
ImageFloatBox m_page_2_box;
37+
ImageFloatBox m_page_3_box;
38+
};
39+
class SummaryWatcher : public DetectorToFinder<SummaryDetector>{
40+
public:
41+
SummaryWatcher(Color color)
42+
: DetectorToFinder("SummaryWatcher", std::chrono::milliseconds(250), color)
43+
{}
44+
};
45+
46+
// Detect that we are on page 2 of a pokemon summary
47+
// This is the stats screen
48+
// Note that when switching pages, wait a bit before pressing left/right
49+
class SummaryPage2Detector : public StaticScreenDetector{
50+
public:
51+
SummaryPage2Detector(Color color);
52+
53+
virtual void make_overlays(VideoOverlaySet& items) const override;
54+
virtual bool detect(const ImageViewRGB32& screen) override;
55+
56+
private:
57+
ImageFloatBox m_page_1_box;
58+
ImageFloatBox m_page_2_box;
59+
ImageFloatBox m_page_3_box;
60+
};
61+
class SummaryPage2Watcher : public DetectorToFinder<SummaryPage2Detector>{
62+
public:
63+
SummaryPage2Watcher(Color color)
64+
: DetectorToFinder("SummaryPage2Watcher", std::chrono::milliseconds(250), color)
65+
{}
66+
};
67+
68+
// Detect that we are on page 3 of a pokemon summary
69+
// This contains the pokemon's moves
70+
class SummaryPage3Detector : public StaticScreenDetector{
71+
public:
72+
SummaryPage3Detector(Color color);
73+
74+
virtual void make_overlays(VideoOverlaySet& items) const override;
75+
virtual bool detect(const ImageViewRGB32& screen) override;
76+
77+
private:
78+
ImageFloatBox m_page_1_box;
79+
ImageFloatBox m_page_2_box;
80+
ImageFloatBox m_page_3_box;
81+
};
82+
class SummaryPage3Watcher : public DetectorToFinder<SummaryPage3Detector>{
83+
public:
84+
SummaryPage3Watcher(Color color)
85+
: DetectorToFinder("SummaryPage3Watcher", std::chrono::milliseconds(250), color)
86+
{}
87+
};
88+
89+
}
90+
}
91+
}
92+
93+
#endif

SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Navigation.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "PokemonFRLG/Inference/Sounds/PokemonFRLG_ShinySoundDetector.h"
1919
#include "PokemonFRLG/Inference/Menus/PokemonFRLG_StartMenuDetector.h"
2020
#include "PokemonFRLG/Inference/Menus/PokemonFRLG_LoadMenuDetector.h"
21+
#include "PokemonFRLG/Inference/Menus/PokemonFRLG_SummaryDetector.h"
2122
#include "PokemonFRLG/PokemonFRLG_Settings.h"
2223
#include "PokemonFRLG_Navigation.h"
2324

@@ -181,6 +182,21 @@ bool try_open_slot_six(ConsoleHandle& console, ProControllerContext& context){
181182
console.log("open_slot_six(): Unable to enter summary.", COLOR_RED);
182183
return false;
183184
}
185+
186+
//Double check that we are on summary
187+
SummaryWatcher sum1(COLOR_RED);
188+
int sm1 = wait_until(
189+
console, context,
190+
std::chrono::seconds(5),
191+
{{ sum1 }}
192+
);
193+
if (sm1 == 0){
194+
console.log("Summary page dots detected.");
195+
}else{
196+
console.log("open_slot_six(): Unable to detect summary screen.", COLOR_RED);
197+
return false;
198+
}
199+
184200
pbf_wait(context, 1000ms);
185201
context.wait_for_all_requests();
186202
return true;

0 commit comments

Comments
 (0)