From 9d514f4e9d2001966016da81166acb29992ecd55 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Wed, 8 May 2024 21:46:53 +0800 Subject: [PATCH] Fix: Matching dungeon from map interact --- tasks/base/main_page.py | 1 + tasks/dungeon/keywords/classes.py | 44 ++++++++++++++++++++++++++++- tasks/dungeon/ui.py | 47 +++++++++++++++++++++++-------- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/tasks/base/main_page.py b/tasks/base/main_page.py index 4ea355919..acd41fdcd 100644 --- a/tasks/base/main_page.py +++ b/tasks/base/main_page.py @@ -54,6 +54,7 @@ class OcrPlaneName(OcrWhiteLetterOnComplexBackground): result = result.replace('累塔', '黑塔') if '星港' in result: result = '迴星港' + result = result.replace('太司', '太卜司') result = result.replace(' ', '') diff --git a/tasks/dungeon/keywords/classes.py b/tasks/dungeon/keywords/classes.py index 88bccc895..5b9da5a36 100644 --- a/tasks/dungeon/keywords/classes.py +++ b/tasks/dungeon/keywords/classes.py @@ -3,7 +3,7 @@ from functools import cached_property from typing import ClassVar from module.exception import ScriptError -from module.ocr.keyword import Keyword +from module.ocr.keyword import Keyword, parse_name @dataclass(repr=False) @@ -183,6 +183,48 @@ class DungeonList(Keyword): else: return '' + @classmethod + def find_dungeon_by_string(cls, cn='', en='', **kwargs): + """ + Args: + cn: Any substring in dungeon name + en: + **kwargs: Filter properties, e.g. is_Echo_of_War=True + + Returns: + DungeonList: or None + """ + if cn: + string = parse_name(cn) + lang = 'cn' + elif en: + string = parse_name(en) + lang = 'en' + else: + return None + + def find(obj: "DungeonList"): + name = obj._keywords_to_find(lang=lang, ignore_punctuation=True)[0] + if string in name: + return True + return False + + # From SelectedGrids + def matched(obj): + flag = True + for k, v in kwargs.items(): + obj_v = obj.__getattribute__(k) + if type(obj_v) != type(v) or obj_v != v: + flag = False + return flag + + dungeons = [grid for grid in cls.instances.values() if find(grid) and matched(grid)] + if len(dungeons) == 1: + return dungeons[0] + else: + return None + + @dataclass(repr=False) class DungeonEntrance(Keyword): diff --git a/tasks/dungeon/ui.py b/tasks/dungeon/ui.py index c9eec1434..f9d91a412 100644 --- a/tasks/dungeon/ui.py +++ b/tasks/dungeon/ui.py @@ -612,23 +612,46 @@ class DungeonUI(DungeonState): logger.info('No dungeon interact') return None + self.acquire_lang_checked() + ocr = OcrDungeonList(DUNGEON_COMBAT_INTERACT_TEXT) result = ocr.detect_and_ocr(self.device.image) + dungeon = None + # Special match names in English + # Second row must have at least 3 characters which is the shortest name "Ire" + # Stangnant Shadow: Shape of + # Quanta + if len(result) == 2 and len(result[1].ocr_text) >= 3: + first, second = result[0].ocr_text, result[1].ocr_text + if re.search(r'Stagnant\s*Shadow', first): + dungeon = DungeonList.find_dungeon_by_string(en=second, is_Stagnant_Shadow=True) + elif re.search(r'Cavern\s*of\s*Corrosion', first): + dungeon = DungeonList.find_dungeon_by_string(en=second, is_Cavern_of_Corrosion=True) + elif re.search(r'Echo\s*of\s*War', first): + dungeon = DungeonList.find_dungeon_by_string(en=second, is_Echo_of_War=True) + elif re.search(r'Calyx[\s(]+Golden', first): + dungeon = DungeonList.find_dungeon_by_string(en=second, is_Calyx_Golden=True, world=self.plane.world) + elif re.search(r'Calyx[\s(]+Crimson', first): + dungeon = DungeonList.find_dungeon_by_string(en=second, is_Calyx_Crimson=True, plane=self.plane) + if dungeon is not None: + logger.attr('DungeonInteract', dungeon) + return dungeon + + # Join result = ' '.join([row.ocr_text for row in result]) - # Calyx (Crimson): Bud of XXX -> Bud of XXX - result = re.sub(r'Calyx\s*\(.*?\):*', '', result) - # Stagnant Shadow: Shap XXX -> Shape of XXX - result = re.sub(r'Stagnant\s*Shadow[:\s]*\w*', 'Shape of', result) - # Cavern of Corrosion: Pa XXX -> Path of XXX - result = re.sub(r'Cavern\s*of\s*Corrosion[:\s]*\w*', 'Path of', result) - # Echo of War: XXX -> XXX - result = re.sub(r'Echo\s*of\s*War:*', '', result) - # Divine See -> Divine Seed - result = re.sub(r'Divine\s*\w*', 'Divine Seed', result) - # Destructio Beginning -> Destruction's Beginning - result = re.sub(r"Destruct[a-zA-Z0-9_']*", "Destruction's", result) + # Special match names in Chinese + # Only calyxes need spacial match + if res := re.search(r'(^.+之蕾)', result): + dungeon = DungeonList.find_dungeon_by_string(cn=res.group(1), is_Calyx_Crimson=True, plane=self.plane) + if dungeon is not None: + logger.attr('DungeonInteract', dungeon) + return dungeon + dungeon = DungeonList.find_dungeon_by_string(cn=res.group(1), is_Calyx_Golden=True, world=self.plane.world) + if dungeon is not None: + logger.attr('DungeonInteract', dungeon) + return dungeon # Dungeons try: