Fix: Echo of war navigation

This commit is contained in:
LmeSzinc 2024-09-10 23:44:13 +08:00
parent f81b40963d
commit 706c5c1f7b

View File

@ -4,9 +4,10 @@ import cv2
from pponnxcr.predict_system import BoxedResult from pponnxcr.predict_system import BoxedResult
from module.base.base import ModuleBase from module.base.base import ModuleBase
from module.base.button import ClickButton
from module.base.decorator import run_once from module.base.decorator import run_once
from module.base.timer import Timer from module.base.timer import Timer
from module.base.utils import area_center, area_offset, crop, image_size from module.base.utils import area_center, area_limit, area_offset, crop, image_size
from module.logger import logger from module.logger import logger
from module.ocr.ocr import Ocr, OcrResultButton from module.ocr.ocr import Ocr, OcrResultButton
from module.ocr.utils import split_and_pair_button_attr, split_and_pair_buttons from module.ocr.utils import split_and_pair_button_attr, split_and_pair_buttons
@ -37,7 +38,8 @@ class OcrDungeonName(Ocr):
result = re.sub(r'-[V][I]', '-Ⅵ', result) result = re.sub(r'-[V][I]', '-Ⅵ', result)
# 苏乐达™热砂海选会场 # 苏乐达™热砂海选会场
result = re.sub(r'(苏乐达|蘇樂達|SoulGlad|スラーダ|FelizAlma)[rtT]*M', r'\1', result) result = re.sub(r'(苏乐达|蘇樂達|SoulGlad|スラーダ|FelizAlma)[rtT]*M*', r'\1', result)
result = re.sub(r'["\']', '', result)
result = super().after_process(result) result = super().after_process(result)
@ -64,10 +66,15 @@ class OcrDungeonList(OcrDungeonName):
# Keep __init__ parameter unused # Keep __init__ parameter unused
def __init__(self, button: ButtonWrapper = None, lang=None, name=None): def __init__(self, button: ButtonWrapper = None, lang=None, name=None):
super().__init__(button=button, lang=lang, name='OcrDungeonList') super().__init__(button=button, lang=lang, name='OcrDungeonList')
# target_dungeon: Dungeon attribute to use map planes to predict dungeons only.
self.target_dungeon = None
# limit_entrance: True to ensure the teleport button is insight
self.limit_entrance = False self.limit_entrance = False
def detect_and_ocr(self, image, direct_ocr=False) -> list[BoxedResult]: def detect_and_ocr(self, image, direct_ocr=False) -> list[BoxedResult]:
if self.button != OCR_DUNGEON_NAME: if self.button != OCR_DUNGEON_NAME:
if self.limit_entrance:
self.button = ClickButton((*self.button.area[:3], self.button.area[3] - 70))
return super().detect_and_ocr(image, direct_ocr=direct_ocr) return super().detect_and_ocr(image, direct_ocr=direct_ocr)
# Concat OCR_DUNGEON_NAME and OCR_DUNGEON_TELEPORT # Concat OCR_DUNGEON_NAME and OCR_DUNGEON_TELEPORT
@ -99,37 +106,38 @@ class OcrDungeonList(OcrDungeonName):
return results return results
class OcrDungeonListUsingPlane(OcrDungeonList):
def _match_result(self, *args, **kwargs): def _match_result(self, *args, **kwargs):
""" """
Convert MapPlane object to their corresponding DungeonList object Convert MapPlane object to their corresponding DungeonList object
""" """
plane = super()._match_result(*args, **kwargs) matched = super()._match_result(*args, **kwargs)
if plane is not None: if self.target_dungeon is not None and matched is not None:
for dungeon in DungeonList.instances.values(): if self.target_dungeon.is_Calyx_Golden:
if dungeon.is_Calyx_Golden and dungeon.plane == plane: # convert MapPlane and ignore DungeonList
return dungeon if isinstance(matched, DungeonList):
return plane return
for dungeon in DungeonList.instances.values():
if dungeon.is_Calyx_Golden and dungeon.plane == matched:
return dungeon
if self.target_dungeon.is_Calyx_Crimson:
if isinstance(matched, DungeonList):
return
for dungeon in DungeonList.instances.values():
if dungeon.is_Calyx_Crimson and dungeon.plane == matched:
return dungeon
else:
if isinstance(matched, MapPlane):
return
return matched
class OcrDungeonListLimitEntrance(OcrDungeonList):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.limit_entrance = True
class OcrDungeonListUsingPlaneLimitEntrance(OcrDungeonListUsingPlane, OcrDungeonListLimitEntrance):
pass
class DraggableDungeonList(DraggableList): class DraggableDungeonList(DraggableList):
teleports: list[OcrResultButton] = [] teleports: list[OcrResultButton] = []
navigates: list[OcrResultButton] = [] navigates: list[OcrResultButton] = []
# use_plane: True to use map planes to predict dungeons only. # target_dungeon: Dungeon attribute to use map planes to predict dungeons only.
# Can only be True in Calyx Crimson target_dungeon = None
use_plane = False
# limit_entrance: True to ensure the teleport button is insight # limit_entrance: True to ensure the teleport button is insight
limit_entrance = False limit_entrance = False
@ -139,19 +147,16 @@ class DraggableDungeonList(DraggableList):
main: main:
allow_early_access: True to allow dungeons that are in temporarily early access during events allow_early_access: True to allow dungeons that are in temporarily early access during events
""" """
relative_area = (0, 0, 1280, 120) relative_area = (0, -40, 1280, 120)
if self.use_plane:
self.keyword_class = [MapPlane, DungeonEntrance] def create_ocr_class(*args, **kwargs):
if self.limit_entrance: # Passing to OcrDungeonList
self.ocr_class = OcrDungeonListUsingPlaneLimitEntrance obj = OcrDungeonList(*args, **kwargs)
else: obj.target_dungeon = self.target_dungeon
self.ocr_class = OcrDungeonListUsingPlane obj.limit_entrance = self.limit_entrance
else: return obj
self.keyword_class = [DungeonList, DungeonEntrance]
if self.limit_entrance: self.ocr_class = create_ocr_class
self.ocr_class = OcrDungeonListLimitEntrance
else:
self.ocr_class = OcrDungeonList
super().load_rows(main=main) super().load_rows(main=main)
# Check early access dungeons # Check early access dungeons
@ -238,7 +243,7 @@ class DungeonUIList(UI):
else: else:
DUNGEON_LIST.search_button = OCR_DUNGEON_NAME DUNGEON_LIST.search_button = OCR_DUNGEON_NAME
# Predict dungeon by plane name in calyxes where dungeons share the same names # Predict dungeon by plane name in calyxes where dungeons share the same names
DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx) DUNGEON_LIST.target_dungeon = dungeon
DUNGEON_LIST.check_row_order = True DUNGEON_LIST.check_row_order = True
# Insight dungeon # Insight dungeon
@ -281,7 +286,7 @@ class DungeonUIList(UI):
logger.hr('Dungeon insight (sort)', level=2) logger.hr('Dungeon insight (sort)', level=2)
logger.info(f'Dungeon insight: {dungeon}') logger.info(f'Dungeon insight: {dungeon}')
DUNGEON_LIST.search_button = OCR_DUNGEON_NAME DUNGEON_LIST.search_button = OCR_DUNGEON_NAME
DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx_Golden) DUNGEON_LIST.target_dungeon = dungeon
DUNGEON_LIST.check_row_order = False DUNGEON_LIST.check_row_order = False
for _ in range(3): for _ in range(3):
@ -342,7 +347,7 @@ class DungeonUIList(UI):
out: COMBAT_PREPARE, FORGOTTEN_HALL_CHECK out: COMBAT_PREPARE, FORGOTTEN_HALL_CHECK
""" """
logger.hr('Dungeon enter', level=2) logger.hr('Dungeon enter', level=2)
DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx_Crimson) DUNGEON_LIST.target_dungeon = dungeon
skip_first_load = skip_first_screenshot skip_first_load = skip_first_screenshot
@run_once @run_once
@ -374,6 +379,8 @@ class DungeonUIList(UI):
DUNGEON_LIST.load_rows(main=self) DUNGEON_LIST.load_rows(main=self)
entrance = DUNGEON_LIST.keyword2button(dungeon) entrance = DUNGEON_LIST.keyword2button(dungeon)
if entrance is not None: if entrance is not None:
# Avoid clicking the soring button
entrance.button = area_limit(entrance.button, OCR_DUNGEON_TELEPORT.area)
self.device.click(entrance) self.device.click(entrance)
screenshot_interval_set() screenshot_interval_set()
self.interval_reset(page_guide.check_button) self.interval_reset(page_guide.check_button)
@ -383,3 +390,9 @@ class DungeonUIList(UI):
continue continue
self.device.screenshot_interval_set() self.device.screenshot_interval_set()
if __name__ == '__main__':
self = DungeonUIList('src')
self.device.screenshot()
self.dungeon_insight(KEYWORDS_DUNGEON_LIST.Echo_of_War_Divine_Seed)