diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.cpp b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.cpp new file mode 100644 index 000000000..b169c744c --- /dev/null +++ b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.cpp @@ -0,0 +1,69 @@ +/* Wild Encounter Reader + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "PokemonFRLG_WildEncounterReader.h" +#include "Common/Cpp/Color.h" +#include "Common/Cpp/Exceptions.h" +#include "CommonFramework/GlobalSettingsPanel.h" +#include "CommonFramework/ImageTypes/ImageViewRGB32.h" +#include "CommonFramework/Tools/GlobalThreadPools.h" +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonTools/Images/ImageFilter.h" +#include "CommonTools/Images/ImageManip.h" +#include "CommonTools/OCR/OCR_NumberReader.h" +#include "CommonTools/OCR/OCR_Routines.h" +#include "Pokemon/Inference/Pokemon_NameReader.h" +#include "PokemonFRLG/PokemonFRLG_Settings.h" +#include "PokemonFRLG_DigitReader.h" +#include + +namespace PokemonAutomation { +namespace NintendoSwitch { +namespace PokemonFRLG { + + +WildEncounterReader::WildEncounterReader(Color color) + : m_box_name(0.075, 0.120, 0.265, 0.063) + // , m_box_level(0.325, 0.120, 0.092, 0.063) + {} + +void WildEncounterReader::make_overlays(VideoOverlaySet& items) const { + const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX; + items.add(m_color, GAME_BOX.inner_to_outer(m_box_name)); + // items.add(m_color, GAME_BOX.inner_to_outer(m_box_level)); +} + +PokemonFRLG_WildEncounter WildEncounterReader::read_encounter( + Logger& logger, Language language, + const ImageViewRGB32& frame, + std::set& subset, + double max_log10p +) { + PokemonFRLG_WildEncounter encounter; + ImageViewRGB32 game_screen = + extract_box_reference(frame, GameSettings::instance().GAME_BOX); + + // Read Name (black text on off-white background). + const std::vector name_text_color_ranges{ + {combine_rgb(0, 0, 0), combine_rgb(64, 64, 64)}, + {combine_rgb(0, 0, 0), combine_rgb(96, 96, 96)}, + {combine_rgb(0, 0, 0), combine_rgb(128, 128, 128)}, + }; + // auto name_result = Pokemon::PokemonNameReader::instance().read_substring( + auto name_result = Pokemon::PokemonNameReader(subset).read_substring( + logger, language, extract_box_reference(game_screen, m_box_name), + name_text_color_ranges, + 0.01, 0.50, max_log10p); + if (!name_result.results.empty()) { + encounter.name = name_result.results.begin()->second.token; + } + return encounter; +} + +} // namespace PokemonFRLG +} // namespace NintendoSwitch +} // namespace PokemonAutomation + diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.h b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.h new file mode 100644 index 000000000..0e13e00c4 --- /dev/null +++ b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.h @@ -0,0 +1,59 @@ +/* Wild Encounter Reader + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonFRLG_WildEncounterReader_H +#define PokemonAutomation_PokemonFRLG_WildEncounterReader_H + +#include +#include +#include "Common/Cpp/Color.h" +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include "CommonFramework/Language.h" + + +namespace PokemonAutomation{ + +class Logger; +class ImageViewRGB32; +class VideoOverlaySet; + +namespace NintendoSwitch{ +namespace PokemonFRLG{ + +struct PokemonFRLG_WildEncounter{ + std::string name; + std::optional level; + // gender +}; + +class WildEncounterReader { +public: + static constexpr double MAX_LOG10P = -1.40; + + WildEncounterReader(Color color = COLOR_RED); + + void make_overlays(VideoOverlaySet& items) const; + + // Reads species from the top left of the battle screen + // by matching to the provided subset of species + PokemonFRLG_WildEncounter read_encounter( + Logger& logger, Language language, + const ImageViewRGB32& frame, + std::set& subset, + double max_log10p = MAX_LOG10P + ); + +private: + Color m_color; + ImageFloatBox m_box_name; + // ImageFloatBox m_box_level; +}; + +} // namespace PokemonFRLG +} // namespace NintendoSwitch +} // namespace PokemonAutomation +#endif + diff --git a/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp b/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp index 2f5f1be50..b5d1b7a0f 100644 --- a/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp +++ b/SerialPrograms/Source/PokemonFRLG/PokemonFRLG_Panels.cpp @@ -19,6 +19,7 @@ #include "Programs/ShinyHunting/PokemonFRLG_ShinyHunt-Overworld.h" #include "Programs/TestPrograms/PokemonFRLG_SoundListener.h" #include "Programs/TestPrograms/PokemonFRLG_ReadStats.h" +#include "Programs/TestPrograms/PokemonFRLG_ReadEncounter.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -58,6 +59,7 @@ std::vector PanelListFactory::make_panels() const{ ret.emplace_back("---- Developer Tools ----"); ret.emplace_back(make_single_switch_program()); ret.emplace_back(make_single_switch_program()); + ret.emplace_back(make_single_switch_program()); } return ret; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.cpp new file mode 100644 index 000000000..c238f889e --- /dev/null +++ b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.cpp @@ -0,0 +1,107 @@ +/* Read Encounter + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include +#include +#include +#include "Common/Cpp/Color.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" +#include "Pokemon/Pokemon_Strings.h" +#include "Pokemon/Inference/Pokemon_NameReader.h" +#include "PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.h" +#include "PokemonFRLG_ReadEncounter.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonFRLG{ + +using namespace std::chrono_literals; + + +ReadEncounter_Descriptor::ReadEncounter_Descriptor() + : SingleSwitchProgramDescriptor( + "PokemonFRLG:ReadEncounter", + Pokemon::STRING_POKEMON + " FRLG", + "Read Wild Encounter", "", + "Read name and level of a wild encounter.", + ProgramControllerClass::StandardController_NoRestrictions, + FeedbackType::REQUIRED, + AllowCommandsWhenRunning::DISABLE_COMMANDS +){} + +ReadEncounter::ReadEncounter() + : LANGUAGE( + "Game Language:", + Pokemon::PokemonNameReader::instance().languages(), + LockMode::LOCK_WHILE_RUNNING, true + ) + , SUBSET( + "Possible Encounters:", + { + {Subset::route1, "route1", "Route 1 (Pidgey / Rattata)"}, + {Subset::route22, "route22", "Route 22 (Rattata / Spearow / Mankey"}, + {Subset::viridianforest, "viridianforest", "Viridian Forest (Caterpie / Metapod / Weedle / Kakuna / Pikachu)"}, + {Subset::rocktunnel, "rocktunnel", "Rock Tunnel (Geodude / Machop / Mankey / Onix / Zubat)"}, + {Subset::pokemontower, "pokemontower", "Pokemon Tower (Gastly, Haunter, Cubone)"}, + }, + LockMode::LOCK_WHILE_RUNNING, + Subset::route1 + ) +{ + PA_ADD_OPTION(LANGUAGE); + PA_ADD_OPTION(SUBSET); +} + +void ReadEncounter::program( + SingleSwitchProgramEnvironment& env, + ProControllerContext& context +){ + env.log( + "Starting Read Encounter program..." + ); + + std::set subset; + switch (SUBSET){ + case Subset::route1: + subset = std::set{"pidgey","rattata"}; + break; + case Subset::route22: + subset = std::set{"rattata", "spearow", "mankey"}; + break; + case Subset::viridianforest: + subset = std::set{"caterpie", "metapod", "weedle", "kakuna", "pikachu"}; + break; + case Subset::rocktunnel: + subset = std::set{"geodude", "zubat", "mankey", "machop", "onix"}; + break; + case Subset::pokemontower: + subset = std::set{"gastly", "haunter", "cubone"}; + break; + default: + subset = std::set{}; + } + + WildEncounterReader reader(COLOR_RED); + VideoOverlaySet overlays(env.console.overlay()); + reader.make_overlays(overlays); + + env.log("Reading name and level..."); + VideoSnapshot screen = env.console.video().snapshot(); + PokemonFRLG_WildEncounter encounter = reader.read_encounter(env.logger(), LANGUAGE, screen, subset); + + env.log("Name: " + encounter.name); + + env.log("Finished reading encounter.", COLOR_BLUE); + pbf_wait(context, 10s); + context.wait_for_all_requests(); +} + +} // namespace PokemonFRLG +} // namespace NintendoSwitch +} // namespace PokemonAutomation + diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.h b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.h new file mode 100644 index 000000000..b107713dc --- /dev/null +++ b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.h @@ -0,0 +1,55 @@ +/* Read Encounter + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_PokemonFRLG_ReadEncounter_H +#define PokemonAutomation_PokemonFRLG_ReadEncounter_H + +#include +#include "CommonFramework/Tools/VideoStream.h" +#include "CommonTools/Options/LanguageOCROption.h" +#include "NintendoSwitch/Controllers/Procon/NintendoSwitch_ProController.h" +#include "NintendoSwitch/NintendoSwitch_SingleSwitchProgram.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ +namespace PokemonFRLG{ + +class ReadEncounter_Descriptor : public SingleSwitchProgramDescriptor{ +public: + ReadEncounter_Descriptor(); +}; + +class ReadEncounter : public SingleSwitchProgramInstance{ +public: + ReadEncounter(); + virtual void program( + SingleSwitchProgramEnvironment &env, + ProControllerContext &context + ) override; + + virtual void start_program_border_check( + VideoStream &stream, FeedbackType feedback_type + ) override{} + +private: + enum class Subset{ + route1, + route22, + viridianforest, + rocktunnel, + pokemontower + }; + + OCR::LanguageOCROption LANGUAGE; + EnumDropdownOption SUBSET; + +}; + +} // namespace PokemonFRLG +} // namespace NintendoSwitch +} // namespace PokemonAutomation +#endif + diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index f0a89d452..e5169d9d6 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -1455,6 +1455,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonFRLG/Inference/PokemonFRLG_DigitReader.h Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.cpp Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.h + Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.cpp + Source/PokemonFRLG/Inference/PokemonFRLG_WildEncounterReader.h Source/PokemonFRLG/PokemonFRLG_Navigation.cpp Source/PokemonFRLG/PokemonFRLG_Navigation.h Source/PokemonFRLG/PokemonFRLG_Panels.cpp @@ -1481,6 +1483,8 @@ file(GLOB LIBRARY_SOURCES Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_SoundListener.h Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadStats.cpp Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadStats.h + Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.cpp + Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadEncounter.h Source/PokemonHome/Inference/PokemonHome_BallReader.cpp Source/PokemonHome/Inference/PokemonHome_BallReader.h Source/PokemonHome/Inference/PokemonHome_BoxGenderDetector.cpp