diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.cpp b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.cpp index d045a928b5..3c33cc87f6 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.cpp @@ -224,13 +224,15 @@ bool BattleOutOfPpDetector::detect(const ImageViewRGB32& screen){ return num_red_pixels > threshold; } -BattleLevelUpDetector::BattleLevelUpDetector(Color color, BattleLevelUpDialog dialog_type) +BattleLevelUpDetector::BattleLevelUpDetector(Color color, BattleLevelUpDialog dialog_type, Language language) : dialog_type(dialog_type) + , jpn(language == Language::Japanese) , m_border_top_box(0.619231, 0.374038, 0.362179, 0.001923) // gray (120, 115, 140) , m_border_right_box(0.982692, 0.376923, 0.001923, 0.597115) , m_dialog_top_box(0.626282, 0.393492, 0.341026, 0.006175) // white , m_dialog_right_box(0.967949, 0.401923, 0.003846, 0.550962) , m_plus_box(0.862663, 0.402852, 0.034267, 0.553560) + , m_plus_box_jpn(0.895663, 0.402852, 0.021267, 0.553560) {} void BattleLevelUpDetector::make_overlays(VideoOverlaySet& items) const{ const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX; @@ -251,12 +253,23 @@ bool BattleLevelUpDetector::detect(const ImageViewRGB32& screen){ ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box); //Plus box is not solid white on the first screen, but is white on the second one - ImageViewRGB32 plus_image = extract_box_reference(game_screen, m_plus_box); - bool good_plus_image = ( - dialog_type == BattleLevelUpDialog::either - || (dialog_type == BattleLevelUpDialog::plus && !is_white(plus_image)) - || (dialog_type == BattleLevelUpDialog::stats && is_white(plus_image)) - ); + //For Japanese, this logic is flipped. The first screen will have no text in the 10s place, + //and the second screen always will + ImageViewRGB32 plus_image = extract_box_reference(game_screen, jpn ? m_plus_box_jpn : m_plus_box); + bool good_plus_image = false; + if (dialog_type == BattleLevelUpDialog::either){ + good_plus_image = true; + }else if (jpn){ + good_plus_image = ( + (dialog_type == BattleLevelUpDialog::plus && is_white(plus_image)) || + (dialog_type == BattleLevelUpDialog::stats && !is_white(plus_image)) + ); + }else{ + good_plus_image = ( + (dialog_type == BattleLevelUpDialog::plus && !is_white(plus_image)) || + (dialog_type == BattleLevelUpDialog::stats && is_white(plus_image)) + ); + } if (is_solid(border_top_image, { 0.320, 0.307, 0.373 }, 0.25, 20) && is_solid(border_right_image, { 0.320, 0.307, 0.373 }, 0.25, 20) diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.h b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.h index f314ed55e9..964825dd45 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.h +++ b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_BattleDialogs.h @@ -11,6 +11,7 @@ #include "Common/Cpp/Color.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonFramework/Language.h" #include "CommonTools/VisualDetector.h" #include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h" @@ -148,23 +149,25 @@ enum class BattleLevelUpDialog{ class BattleLevelUpDetector : public StaticScreenDetector{ public: - BattleLevelUpDetector(Color color, BattleLevelUpDialog dialog_type); + BattleLevelUpDetector(Color color, BattleLevelUpDialog dialog_type, Language Language); virtual void make_overlays(VideoOverlaySet& items) const override; virtual bool detect(const ImageViewRGB32& screen) override; private: BattleLevelUpDialog dialog_type; + bool jpn; ImageFloatBox m_border_top_box; ImageFloatBox m_border_right_box; ImageFloatBox m_dialog_top_box; ImageFloatBox m_dialog_right_box; ImageFloatBox m_plus_box; + ImageFloatBox m_plus_box_jpn; }; class BattleLevelUpWatcher : public DetectorToFinder{ public: - BattleLevelUpWatcher(Color color, BattleLevelUpDialog dialog_type) - : DetectorToFinder("BattleLevelUpWatcher", std::chrono::milliseconds(250), color, dialog_type) + BattleLevelUpWatcher(Color color, BattleLevelUpDialog dialog_type, Language language) + : DetectorToFinder("BattleLevelUpWatcher", std::chrono::milliseconds(250), color, dialog_type, language) {} }; diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.cpp b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.cpp index 4cdfb3b203..6d3887b21b 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.cpp @@ -41,13 +41,15 @@ bool PartySelectionDetector::detect(const ImageViewRGB32& screen){ } -PartyLevelUpDetector::PartyLevelUpDetector(Color color, PartyLevelUpDialog dialog_type) +PartyLevelUpDetector::PartyLevelUpDetector(Color color, PartyLevelUpDialog dialog_type, Language language) : dialog_type(dialog_type) + , jpn(language == Language::Japanese) , m_border_top_box(0.619231, 0.023038, 0.362179, 0.001923) // gray (120, 115, 140) , m_border_right_box(0.982692, 0.025923, 0.001923, 0.597115) , m_dialog_top_box(0.626282, 0.042492, 0.341026, 0.006175) // white , m_dialog_right_box(0.967949, 0.050923, 0.003846, 0.550962) , m_plus_box(0.862663, 0.051852, 0.034267, 0.553560) + , m_plus_box_jpn(0.895663, 0.051852, 0.021267, 0.553560) {} void PartyLevelUpDetector::make_overlays(VideoOverlaySet& items) const{ const BoxOption& GAME_BOX = GameSettings::instance().GAME_BOX; @@ -66,12 +68,23 @@ bool PartyLevelUpDetector::detect(const ImageViewRGB32& screen){ ImageViewRGB32 dialog_right_image = extract_box_reference(game_screen, m_dialog_right_box); //Plus box is not solid white on the first screen, but is white on the second one - ImageViewRGB32 plus_image = extract_box_reference(game_screen, m_plus_box); - bool good_plus_image = ( - dialog_type == PartyLevelUpDialog::either - || (dialog_type == PartyLevelUpDialog::plus && !is_white(plus_image)) - || (dialog_type == PartyLevelUpDialog::stats && is_white(plus_image)) - ); + //For Japanese, this logic is flipped. The first screen will have no text in the 10s place, + //and the second screen always will + ImageViewRGB32 plus_image = extract_box_reference(game_screen, jpn ? m_plus_box_jpn : m_plus_box); + bool good_plus_image = false; + if (dialog_type == PartyLevelUpDialog::either){ + good_plus_image = true; + }else if (jpn){ + good_plus_image = ( + (dialog_type == PartyLevelUpDialog::plus && is_white(plus_image)) || + (dialog_type == PartyLevelUpDialog::stats && !is_white(plus_image)) + ); + }else{ + good_plus_image = ( + (dialog_type == PartyLevelUpDialog::plus && !is_white(plus_image)) || + (dialog_type == PartyLevelUpDialog::stats && is_white(plus_image)) + ); + } if (is_solid(border_top_image, { 0.320, 0.307, 0.373 }, 0.25, 20) && is_solid(border_right_image, { 0.320, 0.307, 0.373 }, 0.25, 20) diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.h b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.h index 4d6e711112..5b987af377 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.h +++ b/SerialPrograms/Source/PokemonFRLG/Inference/Dialogs/PokemonFRLG_PartyDialogs.h @@ -11,6 +11,7 @@ #include "Common/Cpp/Color.h" #include "CommonFramework/ImageTools/ImageBoxes.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonFramework/Language.h" #include "CommonTools/VisualDetector.h" #include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h" @@ -49,23 +50,25 @@ enum class PartyLevelUpDialog{ class PartyLevelUpDetector : public StaticScreenDetector{ public: - PartyLevelUpDetector(Color color, PartyLevelUpDialog dialog_type); + PartyLevelUpDetector(Color color, PartyLevelUpDialog dialog_type, Language language); virtual void make_overlays(VideoOverlaySet& items) const override; virtual bool detect(const ImageViewRGB32& screen) override; private: PartyLevelUpDialog dialog_type; + bool jpn; ImageFloatBox m_border_top_box; ImageFloatBox m_border_right_box; ImageFloatBox m_dialog_top_box; ImageFloatBox m_dialog_right_box; ImageFloatBox m_plus_box; + ImageFloatBox m_plus_box_jpn; }; class PartyLevelUpWatcher : public DetectorToFinder{ public: - PartyLevelUpWatcher(Color color, PartyLevelUpDialog dialog_type) - : DetectorToFinder("BattleLevelUpWatcher", std::chrono::milliseconds(250), color, dialog_type) + PartyLevelUpWatcher(Color color, PartyLevelUpDialog dialog_type, Language language) + : DetectorToFinder("PartyLevelUpWatcher", std::chrono::milliseconds(250), color, dialog_type, language) {} }; diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_BattleLevelUpReader.cpp b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_BattleLevelUpReader.cpp index 3fdafa8d1d..eeccc9c9c2 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_BattleLevelUpReader.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_BattleLevelUpReader.cpp @@ -30,12 +30,12 @@ namespace PokemonFRLG { BattleLevelUpReader::BattleLevelUpReader(Color color) : m_color(color) - , m_box_hp(0.904069, 0.402852, 0.068535, 0.079387) - , m_box_attack(0.904069, 0.496052, 0.068535, 0.079387) - , m_box_defense(0.904069, 0.589252, 0.068535, 0.079387) - , m_box_sp_attack(0.904069, 0.682452, 0.068535, 0.079387) - , m_box_sp_defense(0.904069, 0.775652, 0.068535, 0.079387) - , m_box_speed(0.904069, 0.868852, 0.068535, 0.0793879) + , m_box_hp(0.844069, 0.402852, 0.128535, 0.079387) + , m_box_attack(0.844069, 0.496052, 0.128535, 0.079387) + , m_box_defense(0.844069, 0.589252, 0.128535, 0.079387) + , m_box_sp_attack(0.844069, 0.682452, 0.128535, 0.079387) + , m_box_sp_defense(0.844069, 0.775652, 0.128535, 0.079387) + , m_box_speed(0.844069, 0.868852, 0.128535, 0.0793879) {} void BattleLevelUpReader::make_overlays(VideoOverlaySet &items) const { diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_PartyLevelUpReader.cpp b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_PartyLevelUpReader.cpp index ab2c887752..4c9a26ce4d 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_PartyLevelUpReader.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_PartyLevelUpReader.cpp @@ -30,12 +30,12 @@ namespace PokemonFRLG { PartyLevelUpReader::PartyLevelUpReader(Color color) : m_color(color) - , m_box_hp(0.904069, 0.051852, 0.068535, 0.079387) - , m_box_attack(0.904069, 0.145052, 0.068535, 0.079387) - , m_box_defense(0.904069, 0.238252, 0.068535, 0.079387) - , m_box_sp_attack(0.904069, 0.331452, 0.068535, 0.079387) - , m_box_sp_defense(0.904069, 0.424652, 0.068535, 0.079387) - , m_box_speed(0.904069, 0.517852, 0.068535, 0.0793879) + , m_box_hp(0.844069, 0.051852, 0.128535, 0.079387) + , m_box_attack(0.844069, 0.145052, 0.128535, 0.079387) + , m_box_defense(0.844069, 0.238252, 0.128535, 0.079387) + , m_box_sp_attack(0.844069, 0.331452, 0.128535, 0.079387) + , m_box_sp_defense(0.844069, 0.424652, 0.128535, 0.079387) + , m_box_speed(0.844069, 0.517852, 0.128535, 0.0793879) {} void PartyLevelUpReader::make_overlays(VideoOverlaySet &items) const { diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.cpp b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.cpp index 3f7712114c..1d4b58ed63 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.cpp @@ -27,40 +27,64 @@ namespace NintendoSwitch { namespace PokemonFRLG { StatsReader::StatsReader(Color color) - : m_color(color), m_box_nature(0.028976, 0.729610, 0.502487, 0.066639), - m_box_level(0.052000, 0.120140, 0.099000, 0.069416), - m_box_name(0.163158, 0.122917, 0.262811, 0.066639), - m_box_gender(0.430769, 0.114423, 0.034615, 0.081731), - m_box_hp(0.805274, 0.131247, 0.183790, 0.066639), - m_box_attack(0.891000, 0.245089, 0.097607, 0.066639), - m_box_defense(0.891000, 0.325612, 0.097607, 0.066639), - m_box_sp_attack(0.891000, 0.406134, 0.097607, 0.066639), - m_box_sp_defense(0.891000, 0.486657, 0.097607, 0.066639), - m_box_speed(0.891000, 0.567180, 0.097607, 0.066639){} + : m_color(color), + m_box_nature(0.028976, 0.729610, 0.502487, 0.066639), + m_box_level(0.052000, 0.120140, 0.099000, 0.069416), + m_box_name(0.163158, 0.122917, 0.262811, 0.066639), + m_box_gender(0.430769, 0.114423, 0.034615, 0.081731), + m_box_hp(0.805274, 0.131247, 0.183790, 0.066639), + m_box_attack(0.891000, 0.245089, 0.097607, 0.066639), + m_box_defense(0.891000, 0.325612, 0.097607, 0.066639), + m_box_sp_attack(0.891000, 0.406134, 0.097607, 0.066639), + m_box_sp_defense(0.891000, 0.486657, 0.097607, 0.066639), + m_box_speed(0.891000, 0.567180, 0.097607, 0.066639), + m_box_nature_jpn(0.048718, 0.752884, 0.458205, 0.064423), + m_box_level_jpn(0.060256, 0.116346, 0.124359, 0.075962), + m_box_name_jpn(0.176282, 0.114423, 0.257051, 0.077885), + m_box_gender_jpn(0.435256, 0.115384, 0.035256, 0.076923), + m_box_hp_jpn(0.717165, 0.131662, 0.269632, 0.066876), + m_box_attack_jpn(0.859615, 0.243269, 0.121795, 0.068269), + m_box_defense_jpn(0.859615, 0.323792, 0.121795, 0.068269), + m_box_sp_attack_jpn(0.859615, 0.404315, 0.121795, 0.068269), + m_box_sp_defense_jpn(0.859615, 0.484838, 0.121795, 0.068269), + m_box_speed_jpn(0.859615, 0.565361, 0.121795, 0.068269) +{} void StatsReader::make_overlays(VideoOverlaySet &items) const { const BoxOption &GAME_BOX = GameSettings::instance().GAME_BOX; items.add(m_color, GAME_BOX.inner_to_outer(m_box_nature)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_level)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_name)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_gender)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_hp)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_attack)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_defense)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_sp_attack)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_sp_defense)); items.add(m_color, GAME_BOX.inner_to_outer(m_box_speed)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_level_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_name_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_gender_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_hp_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_attack_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_defense_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_sp_attack_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_sp_defense_jpn)); + items.add(m_color, GAME_BOX.inner_to_outer(m_box_speed_jpn)); } void StatsReader::read_page1( - Logger &logger, Language language, - const ImageViewRGB32 &frame, - PokemonFRLG_Stats &stats, + Logger& logger, Language language, + const ImageViewRGB32& frame, + PokemonFRLG_Stats& stats, const std::set& subset ){ const bool save_debug_images = GlobalSettings::instance().SAVE_DEBUG_IMAGES; ImageViewRGB32 game_screen = extract_box_reference(frame, GameSettings::instance().GAME_BOX); + + const bool jpn = language == Language::Japanese; // Read Name (white text on lilac background). // Use multifiltered OCR across multiple narrow white bands. This tolerates // brightness shifts (down to ~0xc0) while still preferring cleaner bands. @@ -72,14 +96,14 @@ void StatsReader::read_page1( if (subset.size() > 0){ auto name_result = Pokemon::PokemonNameReader(subset).read_substring( - logger, language, extract_box_reference(game_screen, m_box_name), + logger, language, extract_box_reference(game_screen, jpn ? m_box_name_jpn : m_box_name), name_text_color_ranges); if (!name_result.results.empty()){ stats.name = name_result.results.begin()->second.token; } }else{ auto name_result = Pokemon::PokemonNameReader::instance().read_substring( - logger, language, extract_box_reference(game_screen, m_box_name), + logger, language, extract_box_reference(game_screen, jpn ? m_box_name_jpn : m_box_name), name_text_color_ranges); if (!name_result.results.empty()){ stats.name = name_result.results.begin()->second.token; @@ -87,7 +111,7 @@ void StatsReader::read_page1( } // Detect gender by comparing red vs blue pixels - ImageViewRGB32 gender_box = extract_box_reference(game_screen, m_box_gender); + ImageViewRGB32 gender_box = extract_box_reference(game_screen, jpn ? m_box_gender_jpn : m_box_gender); const bool replace_color_within_range = false; const ImageRGB32 red_region = filter_rgb32_range( @@ -114,7 +138,7 @@ void StatsReader::read_page1( - ImageViewRGB32 level_box = extract_box_reference(game_screen, m_box_level); + ImageViewRGB32 level_box = extract_box_reference(game_screen, jpn ? m_box_level_jpn : m_box_level); ImageRGB32 level_upscaled = level_box.scale_to(level_box.width() * 4, level_box.height() * 4); @@ -188,7 +212,7 @@ void StatsReader::read_page1( // Morph close on the inverted image (text=white) bridges gaps in text // regions by growing white->eroding back. Works per-channel on CV_8UC4. const static Pokemon::NatureReader reader("Pokemon/NatureCheckerOCR.json"); - ImageViewRGB32 nature_raw = extract_box_reference(game_screen, m_box_nature); + ImageViewRGB32 nature_raw = extract_box_reference(game_screen, jpn ? m_box_nature_jpn : m_box_nature); if (save_debug_images){ nature_raw.save("DebugDumps/ocr_nature_0_raw.png"); } @@ -319,13 +343,15 @@ void StatsReader::read_page1( } void StatsReader::read_page2( - Logger &logger, const ImageViewRGB32 &frame, - PokemonFRLG_Stats &stats + Logger& logger, Language language, + const ImageViewRGB32& frame, PokemonFRLG_Stats& stats ){ + const bool jpn = language == Language::Japanese; + ImageViewRGB32 game_screen = extract_box_reference(frame, GameSettings::instance().GAME_BOX); - auto read_stat = [&](const ImageFloatBox &box, const std::string &name){ + auto read_stat = [&](const ImageFloatBox& box, const std::string& name){ ImageViewRGB32 stat_region = extract_box_reference(game_screen, box); if (!GlobalSettings::instance().USE_PADDLE_OCR){ @@ -350,23 +376,45 @@ void StatsReader::read_page2( ); }; - // HP box: shift right 55% to clear the "/" character. - ImageFloatBox total_hp_box( - m_box_hp.x + m_box_hp.width * 0.60, m_box_hp.y, - m_box_hp.width * 0.40, m_box_hp.height - ); + auto read_hp = [&](const ImageFloatBox& box){ + // this captures the current HP, "/", and total HP + int res = read_stat(box, "hp"); + + // check for wrong numbers of digits to remove the "/" + // since hp will always be a 2 or 3 digit number. + // Be warned: "/" is usually ignored entirely, but is sometimes detected as 2. + // Current HP can be anything between 0 and the total + std::string res_str = std::to_string(res); + + // >5 digits unambiguously indicates the total HP should be 3 read digits + // For non-fainted Pokemon (a leading 0 would throw things off), 3 read digits unambiguously indicates the total HP should be 2 digits + // 4-5 read digits is ambiguous: + // case 1: a 3-digit total where the "/" is included and current HP is one digit (5 digits read) + // case 2: a 2-digit total where the "/" is included and the current HP is two digits (5 digits read) + // case 3: a 3-digit total where the "/" is dropped and the current HP is one digit (4 digits read) + // case 4: a 2-digit total where the "/" is dropped and the current HP is two digits (4 digits read) + // This will assume a 2-digit HP total in case of ambiguity, consistent with a Pokemon at full HP + if (res_str.size() > 5){ + return std::stoi(res_str.substr(res_str.size() - 3)); + } + if (res_str.size() > 2){ + return std::stoi(res_str.substr(res_str.size() - 2)); + } + return res; + }; auto assign_stat = [](std::optional& field, int value){ if (value != -1){ field = static_cast(value); } }; - assign_stat(stats.hp, read_stat(total_hp_box, "hp")); - assign_stat(stats.attack, read_stat(m_box_attack, "attack")); - assign_stat(stats.defense, read_stat(m_box_defense, "defense")); - assign_stat(stats.sp_attack, read_stat(m_box_sp_attack, "spatk")); - assign_stat(stats.sp_defense, read_stat(m_box_sp_defense, "spdef")); - assign_stat(stats.speed, read_stat(m_box_speed, "speed")); + + assign_stat(stats.hp, read_hp(jpn ? m_box_hp_jpn : m_box_hp)); + assign_stat(stats.attack, read_stat(jpn ? m_box_attack_jpn : m_box_attack, "attack")); + assign_stat(stats.defense, read_stat(jpn ? m_box_defense_jpn : m_box_defense, "defense")); + assign_stat(stats.sp_attack, read_stat(jpn ? m_box_sp_attack_jpn : m_box_sp_attack, "spatk")); + assign_stat(stats.sp_defense, read_stat(jpn ? m_box_sp_defense_jpn : m_box_sp_defense, "spdef")); + assign_stat(stats.speed, read_stat(jpn ? m_box_speed_jpn : m_box_speed, "speed")); } } // namespace PokemonFRLG diff --git a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.h b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.h index bbcf9b996d..df2b6c8f56 100644 --- a/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.h +++ b/SerialPrograms/Source/PokemonFRLG/Inference/PokemonFRLG_StatsReader.h @@ -51,15 +51,15 @@ class StatsReader { // Reads from page 1 (Nature, Level, Name) void read_page1( - Logger &logger, Language language, - const ImageViewRGB32 &frame, PokemonFRLG_Stats &stats, + Logger& logger, Language language, + const ImageViewRGB32& frame, PokemonFRLG_Stats& stats, const std::set& subset = {} ); // Reads from page 2 (Stats: HP, Atk, Def, SpA, SpD, Spe) void read_page2( - Logger &logger, const ImageViewRGB32 &frame, - PokemonFRLG_Stats &stats + Logger& logger, Language language, + const ImageViewRGB32& frame, PokemonFRLG_Stats& stats ); private: @@ -74,6 +74,16 @@ class StatsReader { ImageFloatBox m_box_sp_attack; ImageFloatBox m_box_sp_defense; ImageFloatBox m_box_speed; + ImageFloatBox m_box_nature_jpn; + ImageFloatBox m_box_level_jpn; + ImageFloatBox m_box_name_jpn; + ImageFloatBox m_box_gender_jpn; + ImageFloatBox m_box_hp_jpn; + ImageFloatBox m_box_attack_jpn; + ImageFloatBox m_box_defense_jpn; + ImageFloatBox m_box_sp_attack_jpn; + ImageFloatBox m_box_sp_defense_jpn; + ImageFloatBox m_box_speed_jpn; }; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp index 4a03bb4b37..4656f249a3 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_GiftRng.cpp @@ -257,7 +257,7 @@ AdvObservedPokemon GiftRng::read_summary(SingleSwitchProgramEnvironment& env, Pr env.log("Reading Page 2 (Stats)..."); VideoSnapshot screen2 = env.console.video().snapshot(); - reader.read_page2(env.logger(), screen2, stats); + reader.read_page2(env.logger(), LANGUAGE, screen2, stats); StatReads statreads = { static_cast(stats.hp.value_or(0)), @@ -343,7 +343,7 @@ bool GiftRng::use_rare_candy( } // watch for level up stats - PartyLevelUpWatcher level_up(COLOR_RED, PartyLevelUpDialog::stats); + PartyLevelUpWatcher level_up(COLOR_RED, PartyLevelUpDialog::stats, LANGUAGE); context.wait_for_all_requests(); int ret2 = run_until( env.console, context, diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp index a928861104..084c4ca8e1 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StarterRng.cpp @@ -240,7 +240,7 @@ AdvObservedPokemon StarterRng::read_summary(SingleSwitchProgramEnvironment& env, env.log("Reading Page 2 (Stats)..."); VideoSnapshot screen2 = env.console.video().snapshot(); - reader.read_page2(env.logger(), screen2, stats); + reader.read_page2(env.logger(), LANGUAGE, screen2, stats); StatReads statreads = { static_cast(stats.hp.value_or(0)), @@ -418,7 +418,7 @@ bool StarterRng::auto_battle_rival( } // slowly advance dialog until level-up stats are visible - BattleLevelUpWatcher level_up_stats(COLOR_RED, BattleLevelUpDialog::stats); + BattleLevelUpWatcher level_up_stats(COLOR_RED, BattleLevelUpDialog::stats, LANGUAGE); BlackScreenWatcher black_screen(COLOR_RED); context.wait_for_all_requests(); int ret4 = run_until( @@ -561,7 +561,7 @@ int StarterRng::autolevel_on_route1( // auto battle BattleResult ret2 = spam_first_move(env.console, context); - BattleLevelUpWatcher level_up(COLOR_RED, BattleLevelUpDialog::stats); + BattleLevelUpWatcher level_up(COLOR_RED, BattleLevelUpDialog::stats, LANGUAGE); BlackScreenWatcher black_screen(COLOR_RED); VideoSnapshot screen; int ret3; diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp index 1890be6351..e674c2262a 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_StaticRng.cpp @@ -411,7 +411,7 @@ AdvObservedPokemon StaticRng::read_summary(SingleSwitchProgramEnvironment& env, env.log("Reading Page 2 (Stats)..."); VideoSnapshot screen2 = env.console.video().snapshot(); - reader.read_page2(env.logger(), screen2, stats); + reader.read_page2(env.logger(), LANGUAGE, screen2, stats); StatReads statreads = { static_cast(stats.hp.value_or(0)), @@ -497,7 +497,7 @@ bool StaticRng::use_rare_candy( } // watch for level up stats - PartyLevelUpWatcher level_up(COLOR_RED, PartyLevelUpDialog::stats); + PartyLevelUpWatcher level_up(COLOR_RED, PartyLevelUpDialog::stats, LANGUAGE); context.wait_for_all_requests(); int ret2 = run_until( env.console, context, diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp index 549f8e225f..4b6cebc004 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/RngManipulation/PokemonFRLG_WildRng.cpp @@ -427,7 +427,7 @@ AdvObservedPokemon WildRng::read_summary(SingleSwitchProgramEnvironment& env, Pr env.log("Reading Page 2 (Stats)..."); VideoSnapshot screen2 = env.console.video().snapshot(); - reader.read_page2(env.logger(), screen2, stats); + reader.read_page2(env.logger(), LANGUAGE, screen2, stats); StatReads statreads = { static_cast(stats.hp.value_or(0)), @@ -513,7 +513,7 @@ bool WildRng::use_rare_candy( } // watch for level up stats - PartyLevelUpWatcher level_up(COLOR_RED, PartyLevelUpDialog::stats); + PartyLevelUpWatcher level_up(COLOR_RED, PartyLevelUpDialog::stats, LANGUAGE); context.wait_for_all_requests(); int ret2 = run_until( env.console, context, diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.cpp index 0331db3186..a3aad765ad 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.cpp @@ -12,6 +12,7 @@ #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/Dialogs/PokemonFRLG_BattleDialogs.h" #include "PokemonFRLG/Inference/PokemonFRLG_BattleLevelUpReader.h" #include "PokemonFRLG_ReadBattleLevelUp.h" @@ -35,7 +36,14 @@ ReadBattleLevelUp_Descriptor::ReadBattleLevelUp_Descriptor() ){} ReadBattleLevelUp::ReadBattleLevelUp() -{} + : LANGUAGE( + "Game Language:", + Pokemon::PokemonNameReader::instance().languages(), + LockMode::LOCK_WHILE_RUNNING, true + ) +{ + PA_ADD_OPTION(LANGUAGE); +} void ReadBattleLevelUp::program( SingleSwitchProgramEnvironment &env, @@ -45,8 +53,8 @@ void ReadBattleLevelUp::program( "Starting Read Battle Level Up program..." ); - BattleLevelUpDetector plus_detector(COLOR_RED, BattleLevelUpDialog::plus); - BattleLevelUpDetector stats_detector(COLOR_RED, BattleLevelUpDialog::stats); + BattleLevelUpDetector plus_detector(COLOR_RED, BattleLevelUpDialog::plus, LANGUAGE); + BattleLevelUpDetector stats_detector(COLOR_RED, BattleLevelUpDialog::stats, LANGUAGE); env.log("Detecting the relevant dialogue box..."); VideoSnapshot screen = env.console.video().snapshot(); diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.h b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.h index 2b61cc99ef..ac8d5f98bc 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.h +++ b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadBattleLevelUp.h @@ -34,6 +34,7 @@ class ReadBattleLevelUp : public SingleSwitchProgramInstance{ VideoStream &stream, FeedbackType feedback_type ) override{} + OCR::LanguageOCROption LANGUAGE; }; } // namespace PokemonFRLG diff --git a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadStats.cpp b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadStats.cpp index c405233be8..89f168aca7 100644 --- a/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadStats.cpp +++ b/SerialPrograms/Source/PokemonFRLG/Programs/TestPrograms/PokemonFRLG_ReadStats.cpp @@ -84,7 +84,7 @@ void ReadStats::program( env.log("Reading Page 2 (Stats)..."); VideoSnapshot screen2 = env.console.video().snapshot(); - reader.read_page2(env.logger(), screen2, stats); + reader.read_page2(env.logger(), LANGUAGE, screen2, stats); env.log("HP (Total): " + (stats.hp.has_value() ? std::to_string(*stats.hp) : "???")); env.log("Attack: " +