mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-26 02:11:06 +00:00
317 lines
9.9 KiB
Python
317 lines
9.9 KiB
Python
from module.base.button import ClickButton
|
|
from module.base.timer import Timer
|
|
from module.base.utils import area_offset
|
|
from module.logger import logger
|
|
from tasks.base.page import page_rogue
|
|
from tasks.map.control.waypoint import Waypoint, ensure_waypoints
|
|
from tasks.map.route.base import RouteBase as RouteBase_
|
|
from tasks.rogue.assets.assets_rogue_reward import ROGUE_REPORT
|
|
from tasks.rogue.assets.assets_rogue_ui import BLESSING_CONFIRM
|
|
from tasks.rogue.bleesing.blessing import RogueBlessingSelector
|
|
from tasks.rogue.bleesing.bonus import RogueBonusSelector
|
|
from tasks.rogue.bleesing.curio import RogueCurioSelector
|
|
from tasks.rogue.event.event import RogueEvent
|
|
from tasks.rogue.route.exit import RogueExit
|
|
|
|
|
|
class RouteBase(RouteBase_, RogueExit, RogueEvent):
|
|
registered_domain_exit = None
|
|
|
|
def combat_expected_end(self):
|
|
if self.is_page_choose_blessing():
|
|
logger.info('Combat ended at is_page_choose_blessing()')
|
|
return True
|
|
if self.is_page_choose_curio():
|
|
logger.info('Combat ended at is_page_choose_curio()')
|
|
return True
|
|
if self.is_page_choose_bonus():
|
|
logger.info('Combat ended at is_page_choose_bonus()')
|
|
return True
|
|
|
|
return False
|
|
|
|
def combat_execute(self, expected_end=None):
|
|
return super().combat_execute(expected_end=self.combat_expected_end)
|
|
|
|
def handle_blessing(self):
|
|
"""
|
|
Returns:
|
|
bool: If handled
|
|
"""
|
|
if self.is_page_choose_blessing():
|
|
logger.hr('Choose blessing', level=2)
|
|
selector = RogueBlessingSelector(self)
|
|
selector.recognize_and_select()
|
|
return True
|
|
if self.is_page_choose_curio():
|
|
logger.hr('Choose curio', level=2)
|
|
selector = RogueCurioSelector(self)
|
|
selector.recognize_and_select()
|
|
return True
|
|
if self.is_page_choose_bonus():
|
|
logger.hr('Choose bonus', level=2)
|
|
selector = RogueBonusSelector(self)
|
|
selector.recognize_and_select()
|
|
return True
|
|
if self.handle_blessing_popup():
|
|
return True
|
|
|
|
return False
|
|
|
|
def clear_blessing(self, skip_first_screenshot=True):
|
|
"""
|
|
Pages:
|
|
in: combat_expected_end()
|
|
out: is_in_main()
|
|
"""
|
|
logger.info('Clear blessing')
|
|
switched = False
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
# End
|
|
if self.is_in_main():
|
|
logger.info(f'clear_blessing() ended at page_main')
|
|
if switched:
|
|
self.wait_until_minimap_stabled()
|
|
break
|
|
|
|
if self.handle_blessing():
|
|
switched = True
|
|
continue
|
|
|
|
def clear_occurrence(self, skip_first_screenshot=True):
|
|
"""
|
|
Pages:
|
|
in: page_rogue, occurrence
|
|
out: is_in_main()
|
|
"""
|
|
logger.info('Clear occurrence')
|
|
self.event_title = None
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
# End
|
|
if self.is_in_main():
|
|
logger.info(f'clear_occurrence() ended at page_main')
|
|
break
|
|
|
|
if self.handle_reward(interval=2):
|
|
continue
|
|
if self.is_combat_executing():
|
|
logger.hr('Combat', level=2)
|
|
self.combat_execute()
|
|
continue
|
|
if self.handle_blessing():
|
|
continue
|
|
if self.ui_page_appear(page_rogue):
|
|
if self.handle_event_continue():
|
|
continue
|
|
if self.handle_event_option():
|
|
continue
|
|
|
|
def _goto(self, *args, **kwargs):
|
|
result = super()._goto(*args, **kwargs)
|
|
if 'enemy' in result:
|
|
self.clear_blessing()
|
|
return result
|
|
|
|
def wait_until_minimap_stabled(self):
|
|
logger.info('Wait until minimap stabled')
|
|
radius = self.minimap.MINIMAP_RADIUS
|
|
area = area_offset((-radius, -radius, radius, radius), offset=self.minimap.MINIMAP_CENTER)
|
|
minimap = ClickButton(area, name='MINIMAP')
|
|
self.wait_until_stable(minimap, timeout=Timer(1.5, count=5))
|
|
|
|
"""
|
|
Additional rogue methods
|
|
"""
|
|
|
|
def clear_elite(self, *waypoints):
|
|
logger.hr('Clear elite', level=1)
|
|
waypoints = ensure_waypoints(waypoints)
|
|
end_point = waypoints[-1]
|
|
end_point.speed = 'run_2x'
|
|
|
|
# TODO: Use techniques before BOSS
|
|
pass
|
|
|
|
result = super().clear_enemy(*waypoints)
|
|
return result
|
|
|
|
def _domain_event_expected_end(self):
|
|
"""
|
|
Returns:
|
|
bool: If entered event
|
|
"""
|
|
if self.ui_page_appear(page_rogue):
|
|
return True
|
|
return False
|
|
|
|
def clear_event(self, *waypoints):
|
|
"""
|
|
Handle an event in DomainOccurrence, DomainEncounter, DomainTransaction
|
|
"""
|
|
logger.hr('Clear event', level=1)
|
|
waypoints = ensure_waypoints(waypoints)
|
|
end_point = waypoints[-1]
|
|
end_point.endpoint_threshold = 1.5
|
|
end_point.interact_radius = 7
|
|
end_point.expected_end.append(self._domain_event_expected_end)
|
|
|
|
result = self.goto(*waypoints)
|
|
self.clear_occurrence()
|
|
return result
|
|
|
|
def domain_reward(self, *waypoints):
|
|
"""
|
|
Get reward of the DomainElite and DomainBoss
|
|
"""
|
|
logger.hr('Clear reward', level=1)
|
|
|
|
# TODO: Skip if user don't want rewards or stamina exhausted
|
|
return []
|
|
|
|
result = self.goto(*waypoints)
|
|
|
|
# TODO: Get reward
|
|
pass
|
|
|
|
return result
|
|
|
|
def domain_herta(self, *waypoints):
|
|
"""
|
|
Most people don't buy herta shop, skip
|
|
"""
|
|
pass
|
|
|
|
def _domain_exit_expected_end(self):
|
|
"""
|
|
Returns:
|
|
bool: If domain exited
|
|
"""
|
|
if self.is_map_loading():
|
|
logger.info('domain exit: is_map_loading()')
|
|
return True
|
|
# No loading after elite
|
|
if self.is_map_loading_black():
|
|
logger.info('domain exit: is_map_loading_black()')
|
|
return True
|
|
# Rogue cleared
|
|
if self.appear(ROGUE_REPORT, interval=2):
|
|
logger.info(f'domain exit: {ROGUE_REPORT}')
|
|
return True
|
|
|
|
if self.handle_popup_confirm():
|
|
return False
|
|
|
|
return False
|
|
|
|
def _domain_exit_wait_next(self, skip_first_screenshot=True):
|
|
"""
|
|
Pages:
|
|
in: is_map_loading()
|
|
out: page_main
|
|
or page_rogue if rogue cleared
|
|
"""
|
|
logger.info('Wait next domain')
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
# End
|
|
if self.is_in_main():
|
|
logger.info('Entered another domain')
|
|
self.wait_until_minimap_stabled()
|
|
break
|
|
if self.is_page_rogue_main():
|
|
logger.info('Rogue cleared')
|
|
break
|
|
|
|
if self.match_template_color(ROGUE_REPORT, interval=2):
|
|
logger.info(f'{ROGUE_REPORT} -> {BLESSING_CONFIRM}')
|
|
self.device.click(BLESSING_CONFIRM)
|
|
continue
|
|
# Confirm that leave without getting rewards
|
|
if self.handle_popup_confirm():
|
|
continue
|
|
# First-time cleared reward
|
|
if self.handle_reward():
|
|
continue
|
|
|
|
def domain_single_exit(self, *waypoints):
|
|
"""
|
|
Goto a single exit, exit current domain
|
|
end_rotation is not required
|
|
"""
|
|
logger.hr('Domain single exit', level=1)
|
|
waypoints = ensure_waypoints(waypoints)
|
|
end_point = waypoints[-1]
|
|
end_point.interact_radius = 7
|
|
end_point.expected_end.append(self._domain_exit_expected_end)
|
|
|
|
result = self.goto(*waypoints)
|
|
self._domain_exit_wait_next()
|
|
return result
|
|
|
|
def domain_exit(self, *waypoints, end_rotation=None):
|
|
logger.hr('Domain exit', level=1)
|
|
waypoints = ensure_waypoints(waypoints)
|
|
end_point = waypoints[-1]
|
|
end_point.endpoint_threshold = 1.5
|
|
result = self.goto(*waypoints)
|
|
|
|
logger.hr('End rotation', level=2)
|
|
self.rotation_set(end_rotation, threshold=10)
|
|
|
|
logger.hr('Find domain exit', level=2)
|
|
direction = self.predict_door()
|
|
direction_limit = 55
|
|
if direction is not None:
|
|
if abs(direction) > direction_limit:
|
|
logger.warning(f'Unexpected direction to go: {direction}, limited in {direction_limit}')
|
|
if direction > 0:
|
|
direction = direction_limit
|
|
elif direction < 0:
|
|
direction = -direction_limit
|
|
|
|
point = Waypoint(
|
|
position=(0, 0),
|
|
min_speed='run',
|
|
lock_direction=direction,
|
|
interact_radius=10000,
|
|
expected_end=[self._domain_exit_expected_end],
|
|
)
|
|
self.goto(point)
|
|
self._domain_exit_wait_next()
|
|
|
|
return result
|
|
|
|
"""
|
|
Route
|
|
"""
|
|
|
|
def register_domain_exit(self, *waypoints, end_rotation=None):
|
|
"""
|
|
Register an exit, call `domain_exit()` at route end
|
|
"""
|
|
self.registered_domain_exit = (waypoints, end_rotation)
|
|
|
|
def before_route(self):
|
|
self.registered_domain_exit = None
|
|
|
|
def after_route(self):
|
|
if self.registered_domain_exit is not None:
|
|
waypoints, end_rotation = self.registered_domain_exit
|
|
self.domain_exit(*waypoints, end_rotation=end_rotation)
|
|
else:
|
|
logger.info('No domain exit registered')
|