StarRailCopilot/module/retire/retirement.py
LmeSzinc 6b56215d71 Fix: 修复地图特效导致的章节名识别错误和进图等待
- 章节名识别错误时有20次重试的机会
- 进图时不再使用章节图标识别
- 更改了exception文件的位置
2020-04-25 17:10:22 +08:00

264 lines
8.5 KiB
Python

from module.base.button import ButtonGrid
from module.base.decorator import Config
from module.base.utils import get_color, color_similar
from module.combat.assets import GET_ITEMS_1
from module.handler.info_bar import InfoBarHandler
from module.handler.popup import PopupHandler
from module.logger import logger
from module.exception import ScriptError
from module.retire.assets import *
from module.ui.ui import UI
CARD_GRIDS = ButtonGrid(origin=(93, 76), delta=(164 + 2 / 3, 227), button_shape=(138, 204), grid_shape=(7, 2), name='CARD')
CARD_RARITY_GRIDS = ButtonGrid(origin=(93, 76), delta=(164 + 2 / 3, 227), button_shape=(138, 5), grid_shape=(7, 2), name='RARITY')
CARD_RARITY_COLORS = {
'N': (174, 176, 187),
'R': (106, 195, 248),
'SR': (151, 134, 254),
'SSR': (248, 223, 107)
# Not support marriage cards.
}
class Retirement(UI, InfoBarHandler, PopupHandler):
def _handle_retirement_cards_loading(self):
self.device.sleep((1, 1.5))
def _retirement_choose(self, amount=10, target_rarity=('N',)):
"""
Args:
amount (int): Amount of cards retire. 0 to 10.
target_rarity (tuple(str)): Card rarity. N, R, SR, SSR.
Returns:
int: Amount of cards have retired.
"""
cards = []
rarity = []
for x, y, button in CARD_RARITY_GRIDS.generate():
card_color = get_color(image=self.device.image, area=button.area)
f = False
for r, rarity_color in CARD_RARITY_COLORS.items():
if color_similar(card_color, rarity_color, threshold=15):
cards.append([x, y])
rarity.append(r)
f = True
if not f:
logger.warning(f'Unknown rarity color. Grid: ({x}, {y}). Color: {card_color}')
logger.info(' '.join([r.rjust(3) for r in rarity[:7]]))
logger.info(' '.join([r.rjust(3) for r in rarity[7:]]))
selected = 0
for card, r in zip(cards, rarity):
if r in target_rarity:
self.device.click(CARD_GRIDS[card])
self.device.sleep((0.1, 0.15))
selected += 1
if selected >= amount:
break
return selected
def _retirement_set_sort_method(self, method):
"""
Args:
method (str): ASC for ascending, DESC for descending.
Returns:
bool: If method change.
"""
current = 'UNKNOWN'
self.device.screenshot()
if self.appear(SORT_ASC):
current = 'ASC'
if self.appear(SORT_DESC):
current = 'DESC'
logger.info(f'Current sorting: {current}')
if current != method:
logger.info(f'Sorting set to {method}')
self.device.click(SORTING_CLICK)
self._handle_retirement_cards_loading()
self.device.screenshot()
return True
else:
return False
def _retirement_set_common_ship_filter(self, enable=False):
"""
Args:
enable (bool): If enable common_ship_filter
Returns:
bool: If changed.
"""
# self.device.screenshot()
if self.appear(COMMON_SHIP_FILTER_ENABLE):
current = True
elif self.appear(COMMON_SHIP_FILTER_DISABLE):
current = False
else:
logger.warning('Common ship filter not detected, skipped')
return False
if current != enable:
logger.info(f'Common ship filter set to {enable}')
self.device.click(COMMON_SHIP_FILTER_ENABLE)
self._handle_retirement_cards_loading()
self.device.screenshot()
return True
else:
return False
def _retirement_confirm(self):
executed = False
while 1:
self.device.screenshot()
if self.config.RETIRE_SR or self.config.RETIRE_SSR or self.config.USE_ONE_CLICK_RETIREMENT:
if self.handle_popup_confirm():
continue
if self.appear_then_click(SHIP_CONFIRM, offset=30, interval=2):
continue
if self.appear_then_click(SHIP_CONFIRM_2, offset=30, interval=2):
continue
if self.appear_then_click(EQUIP_CONFIRM, offset=30, interval=2):
continue
if self.appear_then_click(EQUIP_CONFIRM_2, offset=30, interval=2):
executed = True
continue
if self.appear(GET_ITEMS_1, interval=2):
self.device.click(GET_ITEMS_1_RETIREMENT_SAVE)
self.interval_reset(SHIP_CONFIRM)
continue
# End
if executed and self.appear(IN_RETIREMENT_CHECK):
# self._handle_retirement_cards_loading()
# self.device.screenshot()
self.handle_info_bar()
self.device.screenshot()
break
def retirement_appear(self):
return self.appear(RETIRE_APPEAR_1, offset=30) \
and self.appear(RETIRE_APPEAR_2, offset=30) \
and self.appear(RETIRE_APPEAR_3, offset=30)
def _retirement_quit_check_func(self):
return not self.appear(IN_RETIREMENT_CHECK)
def _retirement_quit(self):
self.ui_back(check_button=self._retirement_quit_check_func, skip_first_screenshot=True)
@property
def _retire_amount(self):
if self.config.RETIRE_MODE == 'all':
return 2000
if self.config.RETIRE_MODE == '10':
return 10
return 10
@property
def _retire_rarity(self):
rarity = set()
if self.config.RETIRE_N:
rarity.add('N')
if self.config.RETIRE_R:
rarity.add('R')
if self.config.RETIRE_SR:
rarity.add('SR')
if self.config.RETIRE_SSR:
rarity.add('SSR')
return rarity
@Config.when(USE_ONE_CLICK_RETIREMENT=True)
def retire_ships(self, amount=None, rarity=None):
logger.hr('Retirement')
logger.info('Using one click retirement.')
if amount is None:
amount = self._retire_amount
end = False
total = 0
while 1:
self.handle_info_bar()
while 1:
self.device.screenshot()
if self.appear(SHIP_CONFIRM_2):
break
if self.info_bar_count():
logger.info('No more ships to retire.')
end = True
break
if self.appear_then_click(ONE_CLICK_RETIREMENT, interval=2):
continue
if end:
break
self._retirement_confirm()
total += 10
if total >= amount:
break
logger.info(f'Total retired round: {total // 10}')
return total
@Config.when(USE_ONE_CLICK_RETIREMENT=False)
def retire_ships(self, amount=None, rarity=None):
"""
Args:
amount (int): Amount of cards retire. 0 to 2000.
rarity (tuple(str)): Card rarity. N, R, SR, SSR.
Returns:
int: Total retired.
"""
if amount is None:
amount = self._retire_amount
if rarity is None:
rarity = self._retire_rarity
logger.hr('Retirement')
logger.info(f'Amount={amount}. Rarity={rarity}')
self._retirement_set_sort_method('ASC')
self._retirement_set_common_ship_filter()
total = 0
while amount:
selected = self._retirement_choose(amount=10 if amount > 10 else amount, target_rarity=rarity)
total += selected
if selected == 0:
break
self._retirement_confirm()
amount -= selected
if amount <= 0:
break
self._retirement_set_sort_method('DESC')
logger.info(f'Total retired: {total}')
return total
def handle_retirement(self, amount=None, rarity=None):
if not self.config.ENABLE_RETIREMENT:
return False
if not self.retirement_appear():
return False
self.ui_click(RETIRE_APPEAR_1, check_button=IN_RETIREMENT_CHECK, skip_first_screenshot=True)
self._handle_retirement_cards_loading()
total = self.retire_ships(amount=amount, rarity=rarity)
self._retirement_quit()
self.config.DOCK_FULL_TRIGGERED = True
if total == 0:
logger.warning('No ship retired, exit')
raise ScriptError('No ship retired, exit')
return True