mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-25 10:01:10 +00:00
258 lines
8.3 KiB
Python
258 lines
8.3 KiB
Python
import re
|
|
from typing import Optional
|
|
|
|
from module.base.base import ModuleBase
|
|
from module.base.timer import Timer
|
|
from module.exception import ScriptError
|
|
from module.logger import logger
|
|
from module.ocr.ocr import Ocr, OcrResultButton
|
|
from module.ui.draggable_list import DraggableList
|
|
from module.ui.scroll import Scroll
|
|
from tasks.base.page import page_map, page_world
|
|
from tasks.base.ui import UI
|
|
from tasks.map.assets.assets_map_bigmap import *
|
|
from tasks.map.keywords import KEYWORDS_MAP_PLANE, MapPlane
|
|
|
|
FLOOR_BUTTONS = [FLOOR_1, FLOOR_2, FLOOR_3]
|
|
|
|
|
|
def world_entrance(plane: MapPlane) -> ButtonWrapper:
|
|
if plane.world.is_Herta:
|
|
return WORLD_HERTA
|
|
if plane.world.is_Jarilo:
|
|
return WORLD_JARILO
|
|
if plane.world.is_Luofu:
|
|
return WORLD_LUOFU
|
|
raise ScriptError(f'world_entrance() got unknown plane: {plane}')
|
|
|
|
|
|
class OcrMapPlane(Ocr):
|
|
merge_thres_y = 20
|
|
|
|
def after_process(self, result):
|
|
result = super().after_process(result)
|
|
result = re.sub(r'[+→★“”,.,、。]', '', result).strip()
|
|
if self.lang == 'cn':
|
|
result = result.replace('迎星港', '迴星港')
|
|
if result == '星港':
|
|
result = '迴星港'
|
|
return result
|
|
|
|
|
|
class DraggablePlaneList(DraggableList):
|
|
def is_row_selected(self, button: OcrResultButton, main: ModuleBase) -> bool:
|
|
# Items have an animation to be selected, check if the rightmost become black.
|
|
x = OCR_PLANE.area[2]
|
|
area = (x - 20, button.area[1], x, button.area[3])
|
|
if main.image_color_count(area, color=(40, 40, 40), threshold=221, count=100):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
SCROLL_PLANE = Scroll(PLANE_SCROLL, color=(67, 67, 67), name='SCROLL_PLANE')
|
|
PLANE_LIST = DraggablePlaneList('PlaneList', keyword_class=MapPlane, ocr_class=OcrMapPlane, search_button=OCR_PLANE)
|
|
|
|
|
|
class BigmapPlane(UI):
|
|
# Current plane
|
|
plane: MapPlane = KEYWORDS_MAP_PLANE.Herta_ParlorCar
|
|
# Floor name in game (B1, F1, F2, ...)
|
|
floor: str = 'F1'
|
|
|
|
def _bigmap_world_set(self, plane: MapPlane):
|
|
"""
|
|
Pages:
|
|
in: Any
|
|
out: page_map
|
|
"""
|
|
self.ui_goto(page_world)
|
|
self.ui_click(appear_button=page_world.check_button,
|
|
click_button=world_entrance(plane),
|
|
check_button=page_map.check_button,
|
|
retry_wait=1)
|
|
|
|
def _bigmap_get_current_plane(self) -> Optional[MapPlane]:
|
|
"""
|
|
Get current plane.
|
|
After entering page_map, the current plane is selected by default.
|
|
|
|
Pages:
|
|
in: page_map
|
|
"""
|
|
PLANE_LIST.load_rows(main=self)
|
|
selected = PLANE_LIST.get_selected_row(main=self)
|
|
if selected is None:
|
|
return None
|
|
else:
|
|
return selected.matched_keyword
|
|
|
|
def _bigmap_get_current_plane_wrapped(self) -> MapPlane:
|
|
"""
|
|
Get current plane with reties.
|
|
"""
|
|
for n in range(2):
|
|
self.ui_ensure(page_map)
|
|
|
|
# Wait select animation
|
|
timeout = Timer(2).start()
|
|
skip_first_screenshot = True
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
current = self._bigmap_get_current_plane()
|
|
if current is not None:
|
|
self.plane = current
|
|
return self.plane
|
|
if timeout.reached():
|
|
logger.warning('No plane was selected')
|
|
if n == 0:
|
|
# Nothing selected, probably because it has been switched to page_map before running.
|
|
# Exit and re-enter should fix it.
|
|
self.ui_goto_main()
|
|
break
|
|
|
|
logger.error('Cannot find current plane, return the first plane in list instead')
|
|
try:
|
|
first = PLANE_LIST.cur_buttons[0].matched_keyword
|
|
if first is not None:
|
|
self.plane = first
|
|
return self.plane
|
|
else:
|
|
self.plane = KEYWORDS_MAP_PLANE.Herta_ParlorCar
|
|
return self.plane
|
|
except IndexError:
|
|
self.plane = KEYWORDS_MAP_PLANE.Herta_ParlorCar
|
|
return self.plane
|
|
|
|
def bigmap_plane_set(self, plane: MapPlane) -> bool:
|
|
"""
|
|
Set map to the given plane.
|
|
|
|
Args:
|
|
plane:
|
|
|
|
Returns:
|
|
bool: If success.
|
|
|
|
Pages:
|
|
in: Any
|
|
out: page_map
|
|
"""
|
|
logger.info(f'Bigmap plane set: {plane}')
|
|
self._bigmap_get_current_plane_wrapped()
|
|
logger.attr('CurrentPlane', self.plane)
|
|
|
|
if self.plane.world != plane.world:
|
|
logger.info(f'Switch to world {plane.world}')
|
|
self._bigmap_world_set(plane)
|
|
PLANE_LIST.load_rows(main=self)
|
|
|
|
if SCROLL_PLANE.appear(main=self):
|
|
if plane.page == 'top':
|
|
if SCROLL_PLANE.set_top(main=self):
|
|
PLANE_LIST.load_rows(main=self)
|
|
elif plane.page == 'bottom':
|
|
if SCROLL_PLANE.set_bottom(main=self):
|
|
PLANE_LIST.load_rows(main=self)
|
|
|
|
PLANE_LIST.select_row(plane, main=self, insight=False)
|
|
self.plane = plane
|
|
return True
|
|
|
|
def _bigmap_get_current_floor(self) -> int:
|
|
"""
|
|
Pages:
|
|
in: page_map
|
|
"""
|
|
for index, button in enumerate(FLOOR_BUTTONS):
|
|
# Gray button, not current floor
|
|
if self.image_color_count(button, color=(117, 117, 117), threshold=221, count=200):
|
|
continue
|
|
# White button, current floor
|
|
if self.image_color_count(button, color=(233, 233, 233), threshold=221, count=200):
|
|
return index + 1
|
|
|
|
# logger.warning('Cannot get current floor')
|
|
return 0
|
|
|
|
def _bigmap_floor_set_execute(self, index: int, skip_first_screenshot=True) -> bool:
|
|
"""
|
|
Args:
|
|
index: 1 to 3, note that floor always starts from 1 (1, 2, 3, ...),
|
|
different from the floor name in game (B1, F1, F2).
|
|
|
|
Returns:
|
|
bool: If success.
|
|
|
|
Pages:
|
|
in: page_map
|
|
"""
|
|
logger.info(f'Bigmap floor index set: {index}')
|
|
try:
|
|
button = FLOOR_BUTTONS[index - 1]
|
|
except IndexError:
|
|
logger.error(f'No floor button matches floor index: {index}')
|
|
return False
|
|
|
|
interval = Timer(2)
|
|
click_count = 0
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
current = self._bigmap_get_current_floor()
|
|
logger.attr('FloorIndex', current)
|
|
|
|
# End
|
|
if current == index:
|
|
logger.info('Selected at target floor index')
|
|
return True
|
|
if click_count >= 3:
|
|
logger.warning('Unable to set floor after 3 trial, assume floor set')
|
|
return False
|
|
|
|
# Click
|
|
if interval.reached():
|
|
self.device.click(button)
|
|
interval.reset()
|
|
click_count += 1
|
|
continue
|
|
|
|
def bigmap_floor_set(self, floor: int | str, skip_first_screenshot=True) -> bool:
|
|
"""
|
|
bigmap_plane_set() or _bigmap_get_current_plane_wrapped() must be called first
|
|
which means `self.plane` is set.
|
|
|
|
Args:
|
|
floor: int for floor index counted from bottom, started from 1, such as 1, 2, 3.
|
|
str for flooe name in game, such as "B1", "F1", "F2".
|
|
skip_first_screenshot:
|
|
|
|
Returns:
|
|
bool: If success.
|
|
|
|
Raises:
|
|
ScriptError: If the given floor doesn't exist on current plane.
|
|
|
|
Pages:
|
|
in: page_map
|
|
|
|
Examples:
|
|
self = BigmapPlane('alas')
|
|
self.bigmap_plane_set(KEYWORDS_MAP_PLANE.Jarilo_RivetTown)
|
|
self.bigmap_floor_set('F2')
|
|
"""
|
|
if isinstance(floor, int):
|
|
self.plane.convert_to_floor_name(floor)
|
|
index = floor
|
|
else:
|
|
floor = str(floor)
|
|
index = self.plane.convert_to_floor_index(floor)
|
|
|
|
return self._bigmap_floor_set_execute(index, skip_first_screenshot=skip_first_screenshot)
|