|
|
|
@ -114,8 +114,10 @@ class PokemonDataExtractorImpl( |
|
|
|
async { extractTextFromDetection("nature", screenMat, detectionMap["nature_name"]?.firstOrNull()) }, |
|
|
|
async { extractTextFromDetection("ability", screenMat, detectionMap["ability_name"]?.firstOrNull()) }, |
|
|
|
async { extractTextFromDetection("otName", screenMat, detectionMap["original_trainer_name"]?.firstOrNull()) }, |
|
|
|
async { extractTextFromDetection("otId", screenMat, detectionMap["original_trainder_number"]?.firstOrNull()) }, |
|
|
|
async { extractTextFromDetection("otId", screenMat, detectionMap["original_trainer_number"]?.firstOrNull()) }, |
|
|
|
async { extractTextFromDetection("language", screenMat, detectionMap["language"]?.firstOrNull()) }, |
|
|
|
async { extractLevelFromDetection(screenMat, detectionMap["pokemon_level"]?.maxByOrNull { it.boundingBox.width }) }, |
|
|
|
async { extractNationalDexFromDetection(screenMat, detectionMap["national_dex_number"]?.maxByOrNull { it.boundingBox.width }) }, |
|
|
|
async { extractStatsFromDetections(screenMat, detectionMap) }, |
|
|
|
async { extractMovesFromDetections(screenMat, detectionMap) }, |
|
|
|
async { extractTypesFromDetections(screenMat, detectionMap) } |
|
|
|
@ -139,10 +141,12 @@ class PokemonDataExtractorImpl( |
|
|
|
ability = results?.get(3) as? String, |
|
|
|
otName = results?.get(4) as? String, |
|
|
|
otId = results?.get(5) as? String, |
|
|
|
level = results?.get(6) as? Int, |
|
|
|
stats = results?.get(7) as? PokemonStats, |
|
|
|
moves = results?.get(8) as? List<String> ?: emptyList(), |
|
|
|
types = results?.get(9) as? List<String> ?: emptyList() |
|
|
|
language = results?.get(6) as? String, |
|
|
|
level = results?.get(7) as? Int, |
|
|
|
nationalDexNumber = results?.get(8) as? String, |
|
|
|
stats = results?.get(9) as? PokemonStats, |
|
|
|
moves = results?.get(10) as? List<String> ?: emptyList(), |
|
|
|
types = results?.get(11) as? List<String> ?: emptyList() |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
@ -159,7 +163,9 @@ class PokemonDataExtractorImpl( |
|
|
|
pokeballType = detectPokeballType(detectionMap), |
|
|
|
isShiny = detectionMap["shiny_icon"]?.isNotEmpty() == true, |
|
|
|
teraType = detectTeraType(detectionMap), |
|
|
|
gameSource = detectGameSource(detectionMap) |
|
|
|
gameSource = detectGameSource(detectionMap), |
|
|
|
originMark = detectOriginMark(detectionMap), |
|
|
|
isAlpha = detectAlphaMark(detectionMap) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
@ -218,6 +224,21 @@ class PokemonDataExtractorImpl( |
|
|
|
return levelText?.replace("[^0-9]".toRegex(), "")?.toIntOrNull() |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Extract National Dex number with proper formatting (1-1400+, 0-padded to 4 digits) |
|
|
|
*/ |
|
|
|
private suspend fun extractNationalDexFromDetection(screenMat: Mat, detection: Detection?): String? { |
|
|
|
val dexText = extractTextFromDetection("national_dex", screenMat, detection) |
|
|
|
val dexNumber = dexText?.replace("[^0-9]".toRegex(), "")?.toIntOrNull() |
|
|
|
|
|
|
|
return if (dexNumber != null && dexNumber > 0 && dexNumber <= 9999) { |
|
|
|
// 0-pad to 4 digits (e.g., 1 -> "0001", 150 -> "0150", 1000 -> "1000") |
|
|
|
String.format("%04d", dexNumber) |
|
|
|
} else { |
|
|
|
null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Extract Pokemon stats from multiple stat detections |
|
|
|
*/ |
|
|
|
@ -300,7 +321,15 @@ class PokemonDataExtractorImpl( |
|
|
|
"ball_icon_greatball" to "Great Ball", |
|
|
|
"ball_icon_ultraball" to "Ultra Ball", |
|
|
|
"ball_icon_masterball" to "Master Ball", |
|
|
|
"ball_icon_safariball" to "Safari Ball", |
|
|
|
"ball_icon_levelball" to "Level Ball", |
|
|
|
"ball_icon_lureball" to "Lure Ball", |
|
|
|
"ball_icon_moonball" to "Moon Ball", |
|
|
|
"ball_icon_friendball" to "Friend Ball", |
|
|
|
"ball_icon_loveball" to "Love Ball", |
|
|
|
"ball_icon_heavyball" to "Heavy Ball", |
|
|
|
"ball_icon_fastball" to "Fast Ball", |
|
|
|
"ball_icon_sportball" to "Sport Ball", |
|
|
|
"ball_icon_premierball" to "Premier Ball", |
|
|
|
"ball_icon_repeatball" to "Repeat Ball", |
|
|
|
"ball_icon_timerball" to "Timer Ball", |
|
|
|
@ -313,7 +342,13 @@ class PokemonDataExtractorImpl( |
|
|
|
"ball_icon_duskball" to "Dusk Ball", |
|
|
|
"ball_icon_cherishball" to "Cherish Ball", |
|
|
|
"ball_icon_dreamball" to "Dream Ball", |
|
|
|
"ball_icon_beastball" to "Beast Ball" |
|
|
|
"ball_icon_beastball" to "Beast Ball", |
|
|
|
"ball_icon_strangeparts" to "Strange Ball", |
|
|
|
"ball_icon_parkball" to "Park Ball", |
|
|
|
"ball_icon_gsball" to "GS Ball", |
|
|
|
"ball_icon_originball" to "Origin Ball", |
|
|
|
"ball_icon_pokeball_hisui" to "Hisuian Poké Ball", |
|
|
|
"ball_icon_ultraball_husui" to "Hisuian Ultra Ball" |
|
|
|
) |
|
|
|
|
|
|
|
for ((className, ballName) in pokeballTypes) { |
|
|
|
@ -361,13 +396,34 @@ class PokemonDataExtractorImpl( |
|
|
|
* Detect game source from stamp detections |
|
|
|
*/ |
|
|
|
private fun detectGameSource(detectionMap: Map<String, List<Detection>>): String? { |
|
|
|
val gameSources = mapOf( |
|
|
|
"last_game_stamp_sh" to "Sword/Shield", |
|
|
|
"last_game_stamp_bank" to "Bank", |
|
|
|
val gameStamps = mapOf( |
|
|
|
"last_game_stamp_home" to "Pokémon HOME", |
|
|
|
"last_game_stamp_lgp" to "Let's Go Pikachu", |
|
|
|
"last_game_stamp_lge" to "Let's Go Eevee", |
|
|
|
"last_game_stamp_sw" to "Sword", |
|
|
|
"last_game_stamp_sh" to "Shield", |
|
|
|
"last_game_stamp_bank" to "Pokémon Bank", |
|
|
|
"last_game_stamp_bd" to "Brilliant Diamond", |
|
|
|
"last_game_stamp_sp" to "Shining Pearl", |
|
|
|
"last_game_stamp_pla" to "Legends: Arceus", |
|
|
|
"last_game_stamp_sc" to "Scarlet/Violet", |
|
|
|
"last_game_stamp_sc" to "Scarlet", |
|
|
|
"last_game_stamp_vi" to "Violet", |
|
|
|
"last_game_stamp_go" to "Pokémon GO", |
|
|
|
"last_game_stamp_go" to "Pokémon GO" |
|
|
|
) |
|
|
|
|
|
|
|
for ((className, sourceName) in gameStamps) { |
|
|
|
if (detectionMap[className]?.isNotEmpty() == true) { |
|
|
|
return sourceName |
|
|
|
} |
|
|
|
} |
|
|
|
return null |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Detect origin mark from icon detections |
|
|
|
*/ |
|
|
|
private fun detectOriginMark(detectionMap: Map<String, List<Detection>>): String? { |
|
|
|
val originMarks = mapOf( |
|
|
|
"origin_icon_vc" to "Virtual Console", |
|
|
|
"origin_icon_xyoras" to "XY/ORAS", |
|
|
|
"origin_icon_smusum" to "SM/USUM", |
|
|
|
@ -379,14 +435,21 @@ class PokemonDataExtractorImpl( |
|
|
|
"origin_icon_sv" to "Scarlet/Violet" |
|
|
|
) |
|
|
|
|
|
|
|
for ((className, sourceName) in gameSources) { |
|
|
|
for ((className, originName) in originMarks) { |
|
|
|
if (detectionMap[className]?.isNotEmpty() == true) { |
|
|
|
return sourceName |
|
|
|
return originName |
|
|
|
} |
|
|
|
} |
|
|
|
return null |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Detect if Pokemon is Alpha from alpha mark |
|
|
|
*/ |
|
|
|
private fun detectAlphaMark(detectionMap: Map<String, List<Detection>>): Boolean { |
|
|
|
return detectionMap["alpha_mark"]?.isNotEmpty() == true |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Expand bounding box for better OCR accuracy |
|
|
|
*/ |
|
|
|
@ -513,10 +576,12 @@ class PokemonDataExtractorImpl( |
|
|
|
nickname = textData.nickname, |
|
|
|
gender = iconData.gender, |
|
|
|
level = textData.level, |
|
|
|
language = null, // TODO: Implement language detection |
|
|
|
language = textData.language, |
|
|
|
gameSource = iconData.gameSource, |
|
|
|
originMark = iconData.originMark, |
|
|
|
isAlpha = iconData.isAlpha, |
|
|
|
isFavorited = false, // TODO: Detect favorite status |
|
|
|
nationalDexNumber = null, // TODO: Implement dex number mapping |
|
|
|
nationalDexNumber = textData.nationalDexNumber?.toIntOrNull(), |
|
|
|
species = textData.species, |
|
|
|
primaryType = textData.types.getOrNull(0), |
|
|
|
secondaryType = textData.types.getOrNull(1), |
|
|
|
@ -587,7 +652,9 @@ class PokemonDataExtractorImpl( |
|
|
|
val ability: String?, |
|
|
|
val otName: String?, |
|
|
|
val otId: String?, |
|
|
|
val language: String?, |
|
|
|
val level: Int?, |
|
|
|
val nationalDexNumber: String?, |
|
|
|
val stats: PokemonStats?, |
|
|
|
val moves: List<String>, |
|
|
|
val types: List<String> |
|
|
|
@ -601,6 +668,8 @@ class PokemonDataExtractorImpl( |
|
|
|
val pokeballType: String?, |
|
|
|
val isShiny: Boolean, |
|
|
|
val teraType: String?, |
|
|
|
val gameSource: String? |
|
|
|
val gameSource: String?, |
|
|
|
val originMark: String?, |
|
|
|
val isAlpha: Boolean |
|
|
|
) |
|
|
|
} |