Skip to content
Draft
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
@@ -0,0 +1,124 @@
/* Party Held Item Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "Common/Cpp/Exceptions.h"
#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h"
#include "CommonTools/Images/WaterfillUtilities.h"
#include "PokemonFRLG/PokemonFRLG_Settings.h"
#include "PokemonFRLG_PartyHeldItemDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonFRLG{


class PartyHeldItemMatcher : public ImageMatch::WaterfillTemplateMatcher{
public:
PartyHeldItemMatcher(const char* path)
: WaterfillTemplateMatcher(
path,
Color(210, 210, 100),
Color(255, 255, 190),
20
)
{
m_aspect_ratio_lower = 0.5;
m_aspect_ratio_upper = 2.0;
m_area_ratio_lower = 0.2;
m_area_ratio_upper = 4.0;
}

static const PartyHeldItemMatcher& matcher(){
static PartyHeldItemMatcher matcher("PokemonFRLG/PartyHeldItem.png");
return matcher;
}
};

ImageFloatBox PartyHeldItemDetector::box_for_slot(PartyHeldItemSlot slot){
switch (slot){
case PartyHeldItemSlot::SLOT_1:
return ImageFloatBox(0.069, 0.285, 0.025, 0.050);
case PartyHeldItemSlot::SLOT_2:
return ImageFloatBox(0.432, 0.150, 0.025, 0.050);
case PartyHeldItemSlot::SLOT_3:
return ImageFloatBox(0.432, 0.3, 0.025, 0.050);
case PartyHeldItemSlot::SLOT_4:
return ImageFloatBox(0.432, 0.45, 0.025, 0.050);
case PartyHeldItemSlot::SLOT_5:
return ImageFloatBox(0.432, 0.6, 0.025, 0.050);
case PartyHeldItemSlot::SLOT_6:
return ImageFloatBox(0.432, 0.725, 0.025, 0.050);
default:
break;
}
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid FRLG Party Held Item Slot");
}

PartyHeldItemDetector::PartyHeldItemDetector(
Color color,
VideoOverlay* overlay,
PartyHeldItemSlot slot
)
: m_color(color)
, m_overlay(overlay)
, m_box(box_for_slot(slot))
{}
PartyHeldItemDetector::PartyHeldItemDetector(
Color color,
VideoOverlay* overlay,
const ImageFloatBox& box
)
: m_color(color)
, m_overlay(overlay)
, m_box(box)
{}
void PartyHeldItemDetector::make_overlays(VideoOverlaySet& items) const{
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(m_color, GAME_BOX.inner_to_outer(m_box));
}
bool PartyHeldItemDetector::detect(const ImageViewRGB32& screen){
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
ImageViewRGB32 game_screen = extract_box_reference(screen, GAME_BOX);

double screen_rel_size = (game_screen.height() / 1080.0);
double screen_rel_size_2 = screen_rel_size * screen_rel_size;

double min_area_1080p = 100;
double rmsd_threshold = 220;
size_t min_area = size_t(screen_rel_size_2 * min_area_1080p);

const std::vector<std::pair<uint32_t, uint32_t>> FILTERS = {
{0xffd2d264, 0xffffffbe}
};

bool found = match_template_by_waterfill(
game_screen.size(),
extract_box_reference(game_screen, m_box),
PartyHeldItemMatcher::matcher(),
FILTERS,
{min_area, SIZE_MAX},
rmsd_threshold,
[&](Kernels::Waterfill::WaterfillObject& object) -> bool {
m_last_detected = translate_to_parent(game_screen, m_box, object);
return true;
}
);

if (m_overlay){
if (found){
m_last_detected_box.emplace(*m_overlay, GAME_BOX.inner_to_outer(m_last_detected), COLOR_GREEN);
}else{
m_last_detected_box.reset();
}
}

return found;
}


}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* Party Held Item Detector
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_PokemonFRLG_PartyHeldItemDetector_H
#define PokemonAutomation_PokemonFRLG_PartyHeldItemDetector_H

#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
#include "CommonTools/VisualDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonFRLG{


enum class PartyHeldItemSlot{
SLOT_1,
SLOT_2,
SLOT_3,
SLOT_4,
SLOT_5,
SLOT_6
};

class PartyHeldItemDetector : public StaticScreenDetector{
public:
PartyHeldItemDetector(
Color color,
VideoOverlay* overlay,
const ImageFloatBox& box
);
PartyHeldItemDetector(
Color color,
VideoOverlay* overlay,
PartyHeldItemSlot slot
);

static ImageFloatBox box_for_slot(PartyHeldItemSlot slot);

const ImageFloatBox& last_detected() const { return m_last_detected; }

virtual void make_overlays(VideoOverlaySet& items) const override;

// This is not const so that detectors can save/cache state.
virtual bool detect(const ImageViewRGB32& screen) override;

private:
friend class PartyHeldItemWatcher;

const Color m_color;
VideoOverlay* m_overlay;
const ImageFloatBox m_box;

ImageFloatBox m_last_detected;
std::optional<OverlayBoxScope> m_last_detected_box;
};
class PartyHeldItemWatcher : public DetectorToFinder<PartyHeldItemDetector>{
public:
PartyHeldItemWatcher(
Color color,
VideoOverlay* overlay,
const ImageFloatBox& box,
std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250)
)
: DetectorToFinder("PartyHeldItemWatcher", hold_duration, color, overlay, box)
{}
PartyHeldItemWatcher(
Color color,
VideoOverlay* overlay,
PartyHeldItemSlot slot,
std::chrono::milliseconds hold_duration = std::chrono::milliseconds(250)
)
: DetectorToFinder("PartyHeldItemWatcher", hold_duration, color, overlay, box_for_slot(slot))
{}
};


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

#include "Common/Cpp/Exceptions.h"
#include "CommonTools/ImageMatch/WaterfillTemplateMatcher.h"
#include "CommonTools/Images/WaterfillUtilities.h"
#include "PokemonFRLG/PokemonFRLG_Settings.h"
#include "PokemonFRLG_BattleSelectionArrowDetector.h"

namespace PokemonAutomation{
namespace NintendoSwitch{
namespace PokemonFRLG{


class BattleSelectionArrowMatcher : public ImageMatch::WaterfillTemplateMatcher{
public:
BattleSelectionArrowMatcher(const char* path)
: WaterfillTemplateMatcher(
path,
Color(35, 40, 40), Color(100, 100, 100), 70
)
{
m_aspect_ratio_lower = 0.8;
m_aspect_ratio_upper = 1.2;
m_area_ratio_lower = 0.8;
m_area_ratio_upper = 1.2;
}

static const BattleSelectionArrowMatcher& matcher(){
static BattleSelectionArrowMatcher matcher("PokemonFRLG/BattleSelectionArrow.png");
return matcher;
}
};

ImageFloatBox BattleSelectionArrowDetector::box_for_option(BattleMenuOption option){
switch (option){
case BattleMenuOption::FIGHT:
return ImageFloatBox(0.533, 0.767, 0.024, 0.067);
case BattleMenuOption::BAG:
return ImageFloatBox(0.768, 0.767, 0.024, 0.067);
case BattleMenuOption::POKEMON:
return ImageFloatBox(0.533, 0.868, 0.024, 0.067);
case BattleMenuOption::RUN:
return ImageFloatBox(0.768, 0.868, 0.024, 0.067);
default:
break;
}
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid FRLG Battle Menu Option");
}
ImageFloatBox BattleSelectionArrowDetector::box_for_option(SafariBattleMenuOption option){
switch (option){
case SafariBattleMenuOption::BALL:
return ImageFloatBox(0.533, 0.767, 0.024, 0.067);
case SafariBattleMenuOption::BAIT:
return ImageFloatBox(0.768, 0.767, 0.024, 0.067);
case SafariBattleMenuOption::ROCK:
return ImageFloatBox(0.533, 0.868, 0.024, 0.067);
case SafariBattleMenuOption::RUN:
return ImageFloatBox(0.768, 0.868, 0.024, 0.067);
default:
break;
}
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid FRLG Safari Battle Menu Option");
}
ImageFloatBox BattleSelectionArrowDetector::box_for_option(BattleConfirmationOption option){
switch (option){
case BattleConfirmationOption::YES:
return ImageFloatBox(0.795, 0.465, 0.030, 0.071);
case BattleConfirmationOption::NO:
return ImageFloatBox(0.795, 0.569, 0.030, 0.071);
default:
break;
}
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Invalid FRLG Battle Confirmation Option");
}

BattleSelectionArrowDetector::BattleSelectionArrowDetector(
Color color,
VideoOverlay* overlay,
const ImageFloatBox& box
)
: m_color(color)
, m_overlay(overlay)
, m_arrow_box(box)
{}
BattleSelectionArrowDetector::BattleSelectionArrowDetector(
Color color,
VideoOverlay* overlay,
BattleMenuOption option
)
: m_color(color)
, m_overlay(overlay)
, m_arrow_box(box_for_option(option))
{}
BattleSelectionArrowDetector::BattleSelectionArrowDetector(
Color color,
VideoOverlay* overlay,
SafariBattleMenuOption option
)
: m_color(color)
, m_overlay(overlay)
, m_arrow_box(box_for_option(option))
{}
BattleSelectionArrowDetector::BattleSelectionArrowDetector(
Color color,
VideoOverlay* overlay
)
: m_color(color)
, m_overlay(overlay)
, m_arrow_box(ImageFloatBox(0.768, 0.868, 0.212, 0.159))
{
}
BattleSelectionArrowDetector::BattleSelectionArrowDetector(
Color color,
VideoOverlay* overlay,
BattleConfirmationOption option
)
: m_color(color)
, m_overlay(overlay)
, m_arrow_box(box_for_option(option))
{}
void BattleSelectionArrowDetector::make_overlays(VideoOverlaySet& items) const{
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
items.add(m_color, GAME_BOX.inner_to_outer(m_arrow_box));
}
bool BattleSelectionArrowDetector::detect(const ImageViewRGB32& screen){
const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX;
ImageViewRGB32 game_screen = extract_box_reference(screen, GAME_BOX);

double screen_rel_size = (game_screen.height() / 1080.0);
double screen_rel_size_2 = screen_rel_size * screen_rel_size;

double min_area_1080p = 700;
double rmsd_threshold = 80;
size_t min_area = size_t(screen_rel_size_2 * min_area_1080p);

const std::vector<std::pair<uint32_t, uint32_t>> FILTERS = {
{0xff232828, 0xff646464}
};

bool found = match_template_by_waterfill(
game_screen.size(),
extract_box_reference(game_screen, m_arrow_box),
BattleSelectionArrowMatcher::matcher(),
FILTERS,
{min_area, SIZE_MAX},
rmsd_threshold,
[&](Kernels::Waterfill::WaterfillObject& object) -> bool {
m_last_detected = translate_to_parent(game_screen, m_arrow_box, object);
return true;
}
);

if (m_overlay){
if (found){
m_last_detected_box.emplace(*m_overlay, GAME_BOX.inner_to_outer(m_last_detected), COLOR_GREEN);
}else{
m_last_detected_box.reset();
}
}

return found;
}


}
}
}
Loading
Loading