StarRailCopilot/module/map/fleet.py
LmeSzinc 0447c6f3ab Fix: 修复一些稀有bug
- 修复了镜头没对准导致舰队图标被UI挡住, 走路卡住的问题
- 增加了镜头重新对准至格子中心的方法
- 修复了运输船刷在BOSS点时, 以为打的是BOSS的情况
2020-04-19 03:42:12 +08:00

337 lines
12 KiB
Python

from module.base.timer import Timer
from module.handler.ambush import AmbushHandler
from module.logger import logger
from module.map.camera import Camera
from module.map.map_base import location2node, location_ensure
from module.map.map_operation import MapOperation
class Fleet(Camera, MapOperation, AmbushHandler):
fleet_1_location = ()
fleet_2_location = ()
fleet_current_index = 1
battle_count = 0
mystery_count = 0
siren_count = 0
fleet_ammo = 5
ammo_count = 3
@property
def fleet_1(self):
if self.fleet_current_index != 1:
self.fleet_switch()
return self
@fleet_1.setter
def fleet_1(self, value):
self.fleet_1_location = value
@property
def fleet_2(self):
if self.fleet_current_index != 2:
self.fleet_switch()
return self
@fleet_2.setter
def fleet_2(self, value):
self.fleet_2_location = value
@property
def fleet_current(self):
if self.fleet_current_index == 2:
return self.fleet_2_location
else:
return self.fleet_1_location
def fleet_switch(self):
self.fleet_switch_click()
self.fleet_current_index = 1 if self.fleet_current_index == 2 else 2
self.camera = self.fleet_current
self.update()
self.find_path_initial()
self.map.show_cost()
self.show_fleet()
self.handle_strategy(index=self.fleet_current_index)
def switch_to(self):
pass
def _goto(self, location, expected=''):
"""Goto a grid directly and handle ambush, air raid, mystery picked up, combat.
Args:
location (tuple, str, GridInfo): Destination.
"""
location = location_ensure(location)
self.in_sight(location, sight=(-3, 0, 3, 2))
self.focus_to_grid_center()
grid = self.convert_map_to_grid(location)
result_mystery = ''
while 1:
self.ambush_color_initial()
self.enemy_searching_color_initial()
grid.__str__ = location
result = 'nothing'
self.device.click(grid)
arrived = False
# Wait to confirm fleet arrived. It does't appear immediately if fleet in combat .
arrive_timer = Timer(0.3)
arrive_unexpected_timer = Timer(1.5)
# Wait after ambushed.
ambushed_retry = Timer(0.5)
# If nothing happens, click again.
walk_timeout = Timer(10)
walk_timeout.start()
while 1:
self.device.screenshot()
grid.image = self.device.image
# Ambush
if self.handle_ambush():
ambushed_retry.start()
# Mystery
mystery = self.handle_mystery(button=grid)
if mystery:
self.mystery_count += 1
result = 'mystery'
result_mystery = mystery
# Combat
if self.combat_appear():
self.combat(expected_end=self._expected_combat_end(expected), fleet_index=self.fleet_current_index)
self.hp_get()
if self.hp_withdraw_triggered():
self.withdraw()
arrived = True
result = 'combat'
self.battle_count += 1
self.fleet_ammo -= 1
if 'siren' in expected:
self.siren_count += 1
else:
self.map[location_ensure(location)].is_cleared = True
self.handle_boss_appear_refocus()
grid = self.convert_map_to_grid(location)
walk_timeout.reset()
# Cat attack animation
if self.handle_map_cat_attack():
continue
# Arrive
if self.is_in_map() and grid.predict_fleet():
arrive_timer.start()
arrive_unexpected_timer.start()
if not arrive_timer.reached():
continue
if expected and result not in expected:
if arrive_unexpected_timer.reached():
logger.warning('Arrive with unexpected result')
else:
continue
logger.info(f'Arrive confirm. Result: {result}. Expected: {expected}')
arrived = True
break
# End
if ambushed_retry.started() and ambushed_retry.reached():
break
if walk_timeout.reached():
logger.warning('Walk timeout. Retrying.')
break
# End
if arrived:
# Ammo grid needs to click again, otherwise the next click doesn't work.
if self.map[location].may_ammo:
self.device.click(grid)
break
self.map[self.fleet_current].is_fleet = False
self.map[location].wipe_out()
self.map[location].is_fleet = True
self.__setattr__('fleet_%s_location' % self.fleet_current_index, location)
if result_mystery == 'get_carrier':
prev_enemy = self.map.select(is_enemy=True)
self.full_scan(battle_count=self.battle_count, mystery_count=self.mystery_count,
siren_count=self.siren_count, carrier_count=self.carrier_count, is_carrier_scan=True)
diff = self.map.select(is_enemy=True).delete(prev_enemy)
logger.info(f'Carrier spawn: {diff}')
self.find_path_initial()
def goto(self, location, optimize=True, expected=''):
# self.device.sleep(1000)
location = location_ensure(location)
if self.config.MAP_HAS_AMBUSH and optimize:
nodes = self.map.find_path(location)
for node in nodes:
self._goto(node, expected=expected if node == nodes[-1] else '')
else:
self._goto(location, expected=expected)
def find_path_initial(self):
self.map.find_path_initial(self.fleet_current, has_ambush=self.config.MAP_HAS_AMBUSH)
def show_fleet(self):
fleets = []
for n in [1, 2]:
fleet = self.__getattribute__('fleet_%s_location' % n)
if len(fleet):
text = 'Fleet_%s: %s' % (n, location2node(fleet))
if self.fleet_current_index == n:
text = '[%s]' % text
fleets.append(text)
logger.info(' '.join(fleets))
def find_all_fleets(self):
logger.hr('Find all fleets')
queue = self.map.select(is_spawn_point=True)
while queue:
queue = queue.sort_by_camera_distance(self.camera)
self.in_sight(queue[0], sight=(-1, 0, 1, 2))
grid = self.convert_map_to_grid(queue[0])
if grid.predict_current_fleet():
self.fleet_1 = queue[0].location
elif grid.predict_fleet():
self.fleet_2 = queue[0].location
queue = queue[1:]
def find_current_fleet(self):
logger.hr('Find current fleet')
fleets = self.map.select(is_fleet=True, is_spawn_point=True)
logger.info('Fleets: %s' % str(fleets))
count = fleets.count
if count == 1:
if not self.config.FLEET_2:
self.fleet_1 = fleets[0].location
else:
logger.info('Fleet_2 not detected.')
self.find_all_fleets()
elif count == 2:
fleets = fleets.sort_by_camera_distance(self.camera)
self.in_sight(fleets[0], sight=(-1, 0, 1, 2))
if self.convert_map_to_grid(fleets[0]).predict_current_fleet():
self.fleet_1 = fleets[0].location
self.fleet_2 = fleets[1].location
else:
self.in_sight(fleets[1], sight=(-1, 0, 1, 2))
if self.convert_map_to_grid(fleets[1]).predict_current_fleet():
self.fleet_1 = fleets[1].location
self.fleet_2 = fleets[0].location
else:
logger.warning('Current fleet not found')
self.fleet_1 = fleets[0].location
self.fleet_2 = fleets[1].location
else:
if count == 0:
logger.warning('No fleets detected.')
if count > 2:
logger.warning('Too many fleets: %s.' % str(fleets))
self.find_all_fleets()
self.fleet_current_index = 1
self.show_fleet()
return self.fleet_current
def map_init(self, map_):
logger.hr('Map init')
self.fleet_1_location = ()
self.fleet_2_location = ()
self.fleet_current_index = 1
self.battle_count = 0
self.mystery_count = 0
self.carrier_count = 0
self.siren_count = 0
self.ammo_count = 3
self.map = map_
self.map.reset()
self.hp_init()
self.handle_strategy(index=self.fleet_current_index)
self.ensure_edge_insight(preset=self.map.in_map_swipe_preset_data)
self.full_scan(battle_count=self.battle_count, mystery_count=self.mystery_count, siren_count=self.siren_count,
carrier_count=self.carrier_count)
self.find_current_fleet()
self.find_path_initial()
self.map.show_cost()
def _expected_combat_end(self, expected):
for data in self.map._spawn_data_backup:
if data.get('battle') == self.battle_count and 'boss' in expected:
return 'in_stage'
if data.get('battle') == self.battle_count + 1:
if data.get('enemy', 0) + data.get('siren', 0) + data.get('boss', 0) > 0:
return 'with_searching'
else:
return 'no_searching'
if 'boss' in expected:
return 'in_stage'
return 'no_searching'
def fleet_at(self, grid, fleet=None):
"""
Args:
grid (Grid):
fleet (int): 1, 2
Returns:
bool: If fleet is at grid.
"""
if fleet is None:
return self.fleet_current == grid.location
if fleet == 1:
return self.fleet_1_location == grid.location
else:
return self.fleet_2_location == grid.location
def check_accessibility(self, grid, fleet=None):
"""
Args:
grid (Grid):
fleet (int): 1, 2
Returns:
bool: If accessible.
"""
if fleet is None:
return grid.is_accessible
if fleet == self.fleet_current_index:
return grid.is_accessible
else:
backup = self.fleet_current_index
self.fleet_current_index = fleet
self.find_path_initial()
result = grid.is_accessible
self.fleet_current_index = backup
self.find_path_initial()
return result
def handle_boss_appear_refocus(self):
"""
"""
appear = False
for data in self.map.spawn_data:
if data.get('battle') == self.battle_count and data.get('boss', 0):
appear = True
if appear:
logger.info('Catch camera re-positioning after boss appear')
camera = self.camera
self.ensure_edge_insight()
logger.info('Refocus to previous camera position.')
self.focus_to(camera)
return True
else:
return False
def fleet_checked_reset(self):
self.map_fleet_checked = False
self.fleet_1_formation_fixed = False
self.fleet_2_formation_fixed = False