Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9c46e1b
preliminary ev trainer
theastrogoth Mar 17, 2026
2cb48db
Merge branch 'main' into tag/ev-trainer
theastrogoth Mar 17, 2026
a05dbbd
add faint detection and work out a few bugs
theastrogoth Mar 17, 2026
15b1d4c
enforce filename case change
theastrogoth Mar 18, 2026
23f9f5a
Delete SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG…
theastrogoth Mar 18, 2026
2329307
Delete SerialPrograms/Source/PokemonFRLG/Programs/Farming/PokemonFRLG…
theastrogoth Mar 18, 2026
20f7bf8
Merge branch 'main' into tag/ev-trainer
theastrogoth Mar 19, 2026
77302f2
oops
theastrogoth Mar 19, 2026
865175e
tweak stats display, various fixes
theastrogoth Mar 19, 2026
cab5b82
handle post-battle evolution
theastrogoth Mar 20, 2026
e2d66c3
fixed handling of evolution
theastrogoth Mar 22, 2026
d6881b6
Merge branch 'main' into tag/ev-trainer
theastrogoth Mar 22, 2026
be373dd
implement SpD stuff
theastrogoth Mar 23, 2026
b369d52
add missing black border check
theastrogoth Mar 23, 2026
9d4a1e3
fix Pickup Farmer changes
theastrogoth Mar 23, 2026
9fad1fe
remove redundant grass_spin()
theastrogoth Mar 23, 2026
e642b31
pickup farmer fixes
theastrogoth Mar 23, 2026
8d25ac7
small fix for teak_pickup_items() timing
theastrogoth Mar 23, 2026
03c0555
better recovery for exit_wild_battle()
theastrogoth Mar 29, 2026
9935e2e
Fixed review comments
theastrogoth Mar 29, 2026
f5e4318
tweaks to wild species OCR
theastrogoth Mar 30, 2026
b44ace4
oops, add missing EV info for onix
theastrogoth Mar 30, 2026
7de9e47
pickup farmer typo
theastrogoth Apr 1, 2026
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 @@ -198,6 +198,28 @@ bool BattleLearnDialogDetector::detect(const ImageViewRGB32& screen){
return false;
}

BattleOutOfPpDetector::BattleOutOfPpDetector(Color color)
: m_box(0.692901, 0.758376, 0.275753, 0.085431)
, m_area_ratio_threshold(0.01)
{}
void BattleOutOfPpDetector::make_overlays(VideoOverlaySet& items) const{
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_box));
}
bool BattleOutOfPpDetector::detect(const ImageViewRGB32& screen){
const auto region = extract_box_reference(screen, m_box);

// Retain only red pixels from region ( ~ RGB(225, 74, 27) )
const bool replace_color_within_range = false;
const ImageRGB32 red_region = filter_rgb32_range(
region,
combine_rgb(150, 0, 0), combine_rgb(255, 150, 150), Color(0), replace_color_within_range
);
const size_t num_red_pixels = image_stats(red_region).count;
const double threshold = region.width() * region.height() * m_area_ratio_threshold;

return num_red_pixels > threshold;
}



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,25 @@ class BattleLearnDialogDetector : public StaticScreenDetector{
class BattleLearnDialogWatcher : public DetectorToFinder<BattleLearnDialogDetector>{
public:
BattleLearnDialogWatcher(Color color)
: DetectorToFinder("BattleLearnDialogDetector", std::chrono::milliseconds(250), color)
: DetectorToFinder("BattleLearnDialogWatcher", std::chrono::milliseconds(250), color)
{}
};

class BattleOutOfPpDetector : public StaticScreenDetector{
public:
BattleOutOfPpDetector(Color color);

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

private:
ImageFloatBox m_box;
double m_area_ratio_threshold;
};
class BattleOutOfPpWatcher : public DetectorToFinder<BattleOutOfPpDetector>{
public:
BattleOutOfPpWatcher(Color color)
: DetectorToFinder("BattleOutOfPpWatcher", std::chrono::milliseconds(250), color)
{}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* Map Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "CommonTools/Images/SolidColorTest.h"
#include "CommonTools/Images/ImageFilter.h"
#include "CommonFramework/ImageTools/ImageBoxes.h"
#include "CommonFramework/ImageTools/ImageStats.h"
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "CommonTools/Images/SolidColorTest.h"
#include "CommonTools/Images/WaterfillUtilities.h"
#include "PokemonFRLG/PokemonFRLG_Settings.h"
#include "PokemonFRLG_MapDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonFRLG{

KantoMapDetector::KantoMapDetector(Color color)
: m_top_box(0.010, 0.010, 0.500, 0.080) // blue (0, 122, 255)
, m_left_box(0.069, 0.110, 0.025, 0.880) // white
, m_right_box(0.902, 0.110, 0.025, 0.880) // white
, m_land_box(0.105, 0.600, 0.087, 0.028) // green (31, 173, 0)
// , m_route_25_box(0.603, 0.252, 0.090, 0.040) // orange (255, 176, 0)
{}
void KantoMapDetector::make_overlays(VideoOverlaySet& items) const{
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_top_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_left_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_right_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_land_box));
}
bool KantoMapDetector::detect(const ImageViewRGB32& screen){
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);

ImageViewRGB32 top_image = extract_box_reference(game_screen, m_top_box);
ImageViewRGB32 left_image = extract_box_reference(game_screen, m_left_box);
ImageViewRGB32 right_image = extract_box_reference(game_screen, m_right_box);
ImageViewRGB32 land_image = extract_box_reference(game_screen, m_land_box);
if (is_solid(top_image, { 0.0000, 0.3236, 0.6764 }, 0.25, 20)
&& is_white(left_image)
&& is_white(right_image)
&& is_solid(land_image, { 0.1520, 0.8480, 0.0000 }, 0.25, 20)
){
return true;
}
return false;
}



}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* Map Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonFRLG_MapDetector_H
#define PokemonAutomation_PokemonFRLG_MapDetector_H

#include <chrono>
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "Common/Cpp/Color.h"
#include "CommonFramework/ImageTools/ImageBoxes.h"
#include "CommonTools/VisualDetector.h"
#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h"

namespace PokemonAutomation{
class CancellableScope;
class VideoFeed;
namespace NintendoSwitch{
namespace PokemonFRLG{

// Detect the map screen for Kanto
class KantoMapDetector : public StaticScreenDetector{
public:
KantoMapDetector(Color color);

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

private:
ImageFloatBox m_top_box;
ImageFloatBox m_left_box;
ImageFloatBox m_right_box;
ImageFloatBox m_land_box;
};
class KantoMapWatcher : public DetectorToFinder<KantoMapDetector>{
public:
KantoMapWatcher(Color color)
: DetectorToFinder("KantoMapWatcher", std::chrono::milliseconds(250), color)
{}
};



}
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* Battle Pokemon Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "CommonTools/Images/SolidColorTest.h"
#include "CommonTools/Images/ImageFilter.h"
#include "CommonFramework/ImageTools/ImageBoxes.h"
#include "CommonFramework/ImageTools/ImageStats.h"
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "CommonTools/Images/SolidColorTest.h"
#include "CommonTools/Images/WaterfillUtilities.h"
#include "PokemonFRLG/PokemonFRLG_Settings.h"
#include "PokemonFRLG_BattlePokemonDetector.h"

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

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonFRLG{

BattlePokemonDetector::BattlePokemonDetector(Color color)
// be warned: the name/level/hp box moves up and down a little bit
: m_left_box(0.577404, 0.504327, 0.001442, 0.121875) // off-white (255, 255, 236), can be interrupted by a status condition
, m_right_box(0.948558, 0.585096, 0.000481, 0.063462) // dark teal (74, 111, 102)
, m_top_box(0.594712, 0.481971, 0.325962, 0.002163) // off-white, movement makes this unreliable
, m_bottom_box(0.554808, 0.674519, 0.034615, 0.002163) // dark teal
{}
void BattlePokemonDetector::make_overlays(VideoOverlaySet& items) const{
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_left_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_right_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_top_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_bottom_box));
}
bool BattlePokemonDetector::detect(const ImageViewRGB32& screen){
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);

ImageViewRGB32 left_image = extract_box_reference(game_screen, m_left_box);
ImageViewRGB32 right_image = extract_box_reference(game_screen, m_right_box);
ImageViewRGB32 top_image = extract_box_reference(game_screen, m_top_box);
ImageViewRGB32 bottom_image = extract_box_reference(game_screen, m_bottom_box);
if (is_solid(left_image, { 0.3418, 0.3418, 0.3164 })
&& is_solid(right_image, { 0.2578, 0.3868, 0.3554 }, 0.075, 5)
&& is_solid(top_image, { 0.3418, 0.3418, 0.3164 })
&& is_solid(bottom_image, { 0.2578, 0.3868, 0.3554 }, 0.075, 5)
){
return true;
}
return false;
}

BattleOpponentDetector::BattleOpponentDetector(Color color)
: m_left_box(0.067308, 0.140865, 0.001442, 0.090144) // off-white (255, 255, 236)
, m_right_box(0.422596, 0.132211, 0.000481, 0.054808) // off-white
, m_top_box(0.085577, 0.119952, 0.329327, 0.000721) // off-white
, m_bottom_box(0.109615, 0.264182, 0.328365, 0.001442) // dark teal (74, 111, 102)
{}
void BattleOpponentDetector::make_overlays(VideoOverlaySet& items) const{
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_left_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_right_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_top_box));
items.add(COLOR_RED, GAME_BOX.inner_to_outer(m_bottom_box));
}
bool BattleOpponentDetector::detect(const ImageViewRGB32& screen){
ImageViewRGB32 game_screen = extract_box_reference(screen, GameSettings::instance().GAME_BOX);

ImageViewRGB32 left_image = extract_box_reference(game_screen, m_left_box);
ImageViewRGB32 right_image = extract_box_reference(game_screen, m_right_box);
ImageViewRGB32 top_image = extract_box_reference(game_screen, m_top_box);
ImageViewRGB32 bottom_image = extract_box_reference(game_screen, m_bottom_box);

if (is_solid(left_image, { 0.3418, 0.3418, 0.3164 })
&& is_solid(right_image, { 0.3418, 0.3418, 0.3164 })
&& is_solid(top_image, { 0.3418, 0.3418, 0.3164 })
&& is_solid(bottom_image, { 0.2578, 0.3868, 0.3554 }, 0.075, 5)
){
return true;
}
return false;
}



}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* Map Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonFRLG_BattlePokemonDetector_H
#define PokemonAutomation_PokemonFRLG_BattlePokemonDetector_H

#include <chrono>
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "Common/Cpp/Color.h"
#include "CommonFramework/ImageTools/ImageBoxes.h"
#include "CommonTools/VisualDetector.h"
#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h"

namespace PokemonAutomation{
class CancellableScope;
class VideoFeed;
namespace NintendoSwitch{
namespace PokemonFRLG{

// Detect a player's Pokemon that is currently battling (not fainted)
class BattlePokemonDetector : public StaticScreenDetector{
public:
BattlePokemonDetector(Color color);

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

private:
ImageFloatBox m_left_box;
ImageFloatBox m_right_box;
ImageFloatBox m_top_box;
ImageFloatBox m_bottom_box;
};

// Watches for the player's Pokemon to disappear
class BattleFaintWatcher : public DetectorToFinder<BattlePokemonDetector>{
public:
BattleFaintWatcher(Color color)
: DetectorToFinder("BattleFaintWatcher", FinderType::GONE, std::chrono::milliseconds(2000), color)
{}
};

// Detect an opposing Pokemon that is currently battling (not fainted)
class BattleOpponentDetector : public StaticScreenDetector{
public:
BattleOpponentDetector(Color color);

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

private:
ImageFloatBox m_left_box;
ImageFloatBox m_right_box;
ImageFloatBox m_top_box;
ImageFloatBox m_bottom_box;
};

// Watches for the opponent to disappear
class BattleOpponentFaintWatcher : public DetectorToFinder<BattleOpponentDetector>{
public:
BattleOpponentFaintWatcher(Color color)
: DetectorToFinder("BattleOPponentFaintWatcher", FinderType::GONE, std::chrono::milliseconds(1000), color)
{}
};





}
}
}

#endif
Loading
Loading