Skip to content

Commit 9f809a6

Browse files
committed
Improve reliability of AutoDA boss reading.
1 parent 665fa9d commit 9f809a6

File tree

1 file changed

+88
-53
lines changed

1 file changed

+88
-53
lines changed

SerialPrograms/Source/PokemonSwSh/MaxLair/Inference/PokemonSwSh_MaxLair_Detect_BattleMenu.cpp

Lines changed: 88 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -254,69 +254,115 @@ std::set<std::string> BattleMenuReader::read_opponent(
254254
return result;
255255
}
256256
std::set<std::string> BattleMenuReader::read_opponent_in_summary(Logger& logger, const ImageViewRGB32& screen) const{
257-
ImageViewRGB32 name = extract_box_reference(screen, m_summary_opponent_name);
258-
259-
// We can use a weaker threshold here since we are cross-checking with the type.
260-
std::set<std::string> slugs = read_pokemon_name(logger, m_language, name, -1.0);
261-
262-
ImageViewRGB32 types = extract_box_reference(screen, m_summary_opponent_types);
263-
std::multimap<double, std::pair<PokemonType, ImagePixelBox>> candidates = find_symbols(types, 0.2);
257+
// Start by reading the types.
258+
PokemonType type0, type1;
259+
{
260+
ImageViewRGB32 types = extract_box_reference(screen, m_summary_opponent_types);
261+
std::multimap<double, std::pair<PokemonType, ImagePixelBox>> candidates = find_symbols(types, 0.2);
264262

265-
std::string type_str = "Type Read Result:\n";
266-
for (const auto& item : candidates){
267-
type_str += " " + get_type_slug(item.second.first) + " : " + tostr_default(item.first ) + "\n";
263+
std::string type_str = "Type Read Result:\n";
264+
for (const auto& item : candidates){
265+
type_str += " " + get_type_slug(item.second.first) + " : " + tostr_default(item.first ) + "\n";
266+
}
267+
logger.log(type_str);
268+
269+
type0 = PokemonType::NONE;
270+
type1 = PokemonType::NONE;
271+
{
272+
auto iter = candidates.begin();
273+
if (iter != candidates.end()){
274+
type0 = iter->second.first;
275+
++iter;
276+
}
277+
if (iter != candidates.end()){
278+
type1 = iter->second.first;
279+
++iter;
280+
}
281+
}
268282
}
269-
logger.log(type_str);
270283

271-
PokemonType type0 = PokemonType::NONE;
272-
PokemonType type1 = PokemonType::NONE;
273-
{
274-
auto iter = candidates.begin();
275-
if (iter != candidates.end()){
276-
type0 = iter->second.first;
277-
++iter;
284+
// Compile a list of all possible mons that match the type.
285+
std::set<std::string> allowed_slugs;
286+
for (const auto& item : maxlair_slugs()){
287+
const MaxLairMon& mon = get_maxlair_mon(item.first);
288+
if ((type0 == mon.type[0] && type1 == mon.type[1]) ||
289+
(type0 == mon.type[1] && type1 == mon.type[0])
290+
){
291+
allowed_slugs.insert(item.first);
278292
}
279-
if (iter != candidates.end()){
280-
type1 = iter->second.first;
281-
++iter;
293+
}
294+
295+
// Special case for stunfisk-galar which changes types.
296+
if (type1 == PokemonType::NONE){
297+
switch (type0){
298+
case PokemonType::ELECTRIC:
299+
case PokemonType::GRASS:
300+
case PokemonType::FAIRY:
301+
case PokemonType::PSYCHIC:
302+
allowed_slugs.insert("stunfisk-galar");
303+
break;
304+
default:;
282305
}
283306
}
284307

285-
// cout << get_type_slug(type0) << endl;
286-
// cout << get_type_slug(type1) << endl;
308+
if (allowed_slugs.size() == 1){
309+
return allowed_slugs;
310+
}
311+
312+
313+
// Now we read the name.
314+
std::set<std::string> name_slugs;
315+
{
316+
ImageViewRGB32 name = extract_box_reference(screen, m_summary_opponent_name);
287317

288-
for (auto iter = slugs.begin(); iter != slugs.end();){
289-
const MaxLairMon& mon = get_maxlair_mon(*iter);
290-
// cout << mon.species << endl;
291-
// cout << get_type_slug(mon.type[0]) << endl;
292-
// cout << get_type_slug(mon.type[1]) << endl;
293-
if ((type0 == mon.type[0] && type1 == mon.type[1]) || (type0 == mon.type[1] && type1 == mon.type[0])){
294-
++iter;
295-
}else{
296-
iter = slugs.erase(iter);
318+
// We can use a weaker threshold here since we are cross-checking with the type.
319+
name_slugs = read_pokemon_name(logger, m_language, name, -1.0);
320+
}
321+
322+
// See if there's anything in common between the slugs that match the type
323+
// and the slugs that match the OCR'ed name.
324+
std::set<std::string> common_slugs;
325+
for (const std::string& slug : name_slugs){
326+
if (allowed_slugs.find(slug) != allowed_slugs.end()){
327+
common_slugs.insert(slug);
297328
}
298329
}
299330

300-
if (slugs.size() == 1){
301-
logger.log("Disambiguation succeeded: " + *slugs.begin(), COLOR_BLUE);
302-
return slugs;
331+
// for (const auto& slug : allowed_slugs){
332+
// cout << "allowed_slugs = " << slug << endl;
333+
// }
334+
// for (const auto& slug : name_slugs){
335+
// cout << "name_slugs = " << slug << endl;
336+
// }
337+
338+
if (common_slugs.size() == 1){
339+
logger.log("Disambiguation succeeded: " + *common_slugs.begin(), COLOR_BLUE);
340+
return common_slugs;
303341
}
304342

305-
if (slugs.empty()){
306-
logger.log("Disambiguation failed. No results.", COLOR_RED);
307-
}else{
308-
logger.log("Disambiguation failed. Still have multiple results: " + set_to_str(slugs), COLOR_RED);
343+
344+
// Special case: Korean Clefairy
345+
// Reason: Korean OCR cannot read the character: 삐
346+
if (m_language == Language::Korean &&
347+
name_slugs.empty() &&
348+
type0 == PokemonType::FAIRY &&
349+
type1 == PokemonType::NONE
350+
){
351+
logger.log("Known case that cannot be read: Korean Clefairy", COLOR_RED);
352+
return {"clefairy"};
309353
}
310354

355+
356+
311357
static std::set<std::string> KNOWN_BAD_SLUGS{
312358
"basculin-blue-striped",
313359
"basculin-red-striped",
314360
"lycanroc-midday",
315361
"lycanroc-midnight",
316-
"stunfisk-galar", // After using terrain pulse.
362+
// "stunfisk-galar", // After using terrain pulse.
317363
};
318364
bool error = true;
319-
for (const std::string& slug : slugs){
365+
for (const std::string& slug : common_slugs){
320366
auto iter = KNOWN_BAD_SLUGS.find(slug);
321367
if (iter != KNOWN_BAD_SLUGS.end()){
322368
error = false;
@@ -325,23 +371,12 @@ std::set<std::string> BattleMenuReader::read_opponent_in_summary(Logger& logger,
325371
}
326372
}
327373

328-
// Special case: Korean Clefairy.
329-
// Reason: Korean OCR cannot read the character: 삐
330-
if (m_language == Language::Korean &&
331-
slugs.empty() &&
332-
type0 == PokemonType::FAIRY &&
333-
type1 == PokemonType::NONE
334-
){
335-
logger.log("Known case that cannot be read: Korean Clefairy", COLOR_RED);
336-
return {"clefairy"};
337-
}
338-
339374
// At this point we're out of options.
340375
if (error){
341376
dump_image(logger, MODULE_NAME, "DisambiguateBoss", screen);
342377
}
343378

344-
return slugs;
379+
return common_slugs;
345380
}
346381
std::string BattleMenuReader::read_own_mon(Logger& logger, const ImageViewRGB32& screen) const{
347382
return read_pokemon_name_sprite(

0 commit comments

Comments
 (0)