mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-16 14:31:16 +00:00
252 lines
8.7 KiB
Python
252 lines
8.7 KiB
Python
import re
|
|
|
|
from module.base.timer import Timer
|
|
from module.exception import RequestHumanTakeover
|
|
from module.logger import logger
|
|
from module.ocr.ocr import Ocr
|
|
from tasks.base.assets.assets_base_main_page import ROGUE_LEAVE_FOR_NOW
|
|
from tasks.base.assets.assets_base_page import MAP_EXIT
|
|
from tasks.base.page import page_guide, page_main, page_rogue
|
|
from tasks.dungeon.keywords import DungeonList
|
|
from tasks.dungeon.keywords.dungeon import Simulated_Universe_World_1
|
|
from tasks.dungeon.keywords.tab import Survival_Index
|
|
from tasks.dungeon.ui import DungeonUI
|
|
from tasks.forgotten_hall.assets.assets_forgotten_hall_ui import TELEPORT
|
|
from tasks.rogue.assets.assets_rogue_entry import LEVEL_CONFIRM, OCR_WORLD, WORLD_ENTER, WORLD_NEXT, WORLD_PREV
|
|
from tasks.rogue.assets.assets_rogue_path import CONFIRM_PATH
|
|
from tasks.rogue.assets.assets_rogue_reward import REWARD_CLOSE, REWARD_ENTER
|
|
from tasks.rogue.assets.assets_rogue_ui import ROGUE_LAUNCH
|
|
from tasks.rogue.entry.path import RoguePathHandler
|
|
from tasks.rogue.entry.reward import RogueRewardHandler
|
|
|
|
|
|
def chinese_to_arabic(chinese_number: str) -> int:
|
|
chinese_numerals = {
|
|
'一': 1, '二': 2, '三': 3, '四': 4, '五': 5,
|
|
'六': 6, '七': 7, '八': 8, '九': 9, '零': 0
|
|
}
|
|
result = 0
|
|
current_number = 0
|
|
|
|
for char in chinese_number:
|
|
if char in chinese_numerals:
|
|
# If the character is a valid Chinese numeral, accumulate the value.
|
|
current_number = chinese_numerals[char]
|
|
else:
|
|
# If it's not a valid Chinese numeral, assume it's a multiplier (e.g., 十 for 10).
|
|
multiplier = 1
|
|
if char == '十':
|
|
multiplier = 10
|
|
elif char == '百':
|
|
multiplier = 100
|
|
elif char == '千':
|
|
multiplier = 1000
|
|
elif char == '万':
|
|
result += current_number * 10000
|
|
current_number = 0
|
|
continue
|
|
|
|
result += current_number * multiplier
|
|
current_number = 0
|
|
|
|
result += current_number # Add the last accumulated number.
|
|
return result
|
|
|
|
|
|
class OcrRogueWorld(Ocr):
|
|
def format_result(self, result: str) -> int:
|
|
res = re.search(r'第([一二三四五六七八九十])世界', result)
|
|
if res:
|
|
return chinese_to_arabic(res.group(1))
|
|
res = re.search(r'world[\s_]?(\d)', result.lower())
|
|
if res:
|
|
return int(res.group(1))
|
|
return 0
|
|
|
|
|
|
class RogueEntry(DungeonUI, RogueRewardHandler, RoguePathHandler):
|
|
def _rogue_world_set(self, world: int | DungeonList, skip_first_screenshot=True):
|
|
"""
|
|
Args:
|
|
world: 7 or KEYWORDS_DUNGEON_LIST.Simulated_Universe_World_7
|
|
skip_first_screenshot:
|
|
|
|
Pages:
|
|
in: is_page_rogue_main()
|
|
"""
|
|
ocr = OcrRogueWorld(OCR_WORLD)
|
|
if isinstance(world, DungeonList):
|
|
w = ocr.format_result(world.en)
|
|
if w:
|
|
world = w
|
|
else:
|
|
logger.error(f'Invalid rogue world: {world}')
|
|
raise RequestHumanTakeover
|
|
|
|
logger.info(f'Rogue world set: {world}')
|
|
interval = Timer(1, count=3)
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
# Additional
|
|
if self.appear_then_click(REWARD_CLOSE, interval=2):
|
|
continue
|
|
if self.handle_ui_close(LEVEL_CONFIRM, interval=2):
|
|
interval.clear()
|
|
continue
|
|
|
|
if self.is_page_rogue_main() \
|
|
and self.image_color_count(OCR_WORLD, color=(255, 255, 255), threshold=221, count=50):
|
|
# End
|
|
current = ocr.ocr_single_line(self.device.image)
|
|
if current and current == world:
|
|
logger.info(f'At world {world}')
|
|
break
|
|
# Click
|
|
if interval.reached():
|
|
diff = world - current
|
|
if diff > 0:
|
|
# 0.5s at min
|
|
self.device.multi_click(WORLD_NEXT, n=abs(diff), interval=(0.5, 0.7))
|
|
interval.reset()
|
|
elif diff < 0:
|
|
self.device.multi_click(WORLD_PREV, n=abs(diff), interval=(0.5, 0.7))
|
|
interval.reset()
|
|
else:
|
|
logger.error(f'Invalid world diff: {diff}')
|
|
|
|
def _rogue_world_enter(self, skip_first_screenshot=True):
|
|
"""
|
|
Pages:
|
|
in: is_page_rogue_main()
|
|
out: is_page_rogue_launch()
|
|
"""
|
|
logger.info('Rogue world enter')
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
# End
|
|
if self.is_page_rogue_launch():
|
|
logger.info('At is_page_rogue_launch()')
|
|
break
|
|
|
|
# Click
|
|
if self.interval_is_reached(REWARD_ENTER, interval=2) and self.is_page_rogue_main():
|
|
self.device.click(WORLD_ENTER)
|
|
self.interval_reset(REWARD_ENTER, interval=2)
|
|
continue
|
|
if self.appear_then_click(LEVEL_CONFIRM, interval=2):
|
|
continue
|
|
if self.appear_then_click(REWARD_CLOSE, interval=2):
|
|
continue
|
|
|
|
def rogue_world_exit(self, skip_first_screenshot=True):
|
|
"""
|
|
Pages:
|
|
in: is_page_rogue_launch()
|
|
out: is_page_rogue_main()
|
|
"""
|
|
logger.info('Rogue world exit')
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
# End
|
|
if self.is_page_rogue_main():
|
|
logger.info('At is_page_rogue_main()')
|
|
break
|
|
|
|
# Click
|
|
# From _rogue_world_enter()
|
|
if self.handle_ui_close(ROGUE_LAUNCH):
|
|
continue
|
|
if self.handle_ui_back(LEVEL_CONFIRM):
|
|
continue
|
|
if self.appear_then_click(REWARD_CLOSE, interval=2):
|
|
continue
|
|
# From _is_page_rogue_path()
|
|
if self.handle_ui_back(CONFIRM_PATH):
|
|
pass
|
|
if self.handle_ui_back(self._is_page_rogue_path):
|
|
continue
|
|
# From ui_leave_special()
|
|
if self.appear_then_click(MAP_EXIT, interval=2):
|
|
continue
|
|
if self.handle_popup_confirm():
|
|
continue
|
|
if self.appear_then_click(ROGUE_LEAVE_FOR_NOW, interval=2):
|
|
continue
|
|
|
|
def _rogue_teleport(self, skip_first_screenshot=True):
|
|
"""
|
|
Pages:
|
|
in: page_guide, Survival_Index, Simulated_Universe
|
|
out: page_rogue
|
|
"""
|
|
logger.info('Rogue teleport')
|
|
self.interval_clear(page_guide.check_button)
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
# End
|
|
if self.ui_page_appear(page_rogue):
|
|
break
|
|
|
|
if self.appear_then_click(REWARD_CLOSE, interval=2):
|
|
continue
|
|
if self.appear(page_guide.check_button, interval=2):
|
|
buttons = TELEPORT.match_multi_template(self.device.image)
|
|
if len(buttons):
|
|
buttons = sorted(buttons, key=lambda x: x.area[1])
|
|
self.device.click(buttons[0])
|
|
continue
|
|
|
|
self.interval_clear(page_guide.check_button)
|
|
|
|
def goto_rogue(self):
|
|
self.dungeon_tab_goto(Survival_Index)
|
|
self._dungeon_nav_goto(Simulated_Universe_World_1)
|
|
self._rogue_teleport()
|
|
|
|
def rogue_world_enter(self, world: int | DungeonList):
|
|
"""
|
|
Args:
|
|
world: 7 or KEYWORDS_DUNGEON_LIST.Simulated_Universe_World_7
|
|
|
|
Pages:
|
|
in: page_rogue
|
|
out: is_page_rogue_launch()
|
|
"""
|
|
logger.hr('Rogue world enter', level=1)
|
|
current = self.ui_get_current_page()
|
|
if current == page_rogue:
|
|
if self.is_page_rogue_main():
|
|
logger.info('At is_page_rogue_main()')
|
|
else:
|
|
self.rogue_world_exit()
|
|
elif current == page_main:
|
|
self.handle_lang_check(page=page_main)
|
|
if self.plane.rogue_domain:
|
|
logger.info('At rogue domain')
|
|
return
|
|
else:
|
|
self.goto_rogue()
|
|
else:
|
|
self.goto_rogue()
|
|
|
|
# Enter
|
|
self._rogue_world_set(world)
|
|
self._rogue_world_enter()
|
|
self.rogue_path_select(self.config.RoguePath_Path)
|