def _equip_view_swipe(self, distance, check_button=EQUIPMENT_OPEN): swipe_count = 0 swipe_timer = Timer(5, count=10) self.ensure_no_info_bar(timeout=3) SWIPE_CHECK.load_color(self.device.image) SWIPE_CHECK._match_init = True # Disable ensure_template() on match(), allows ship to be properly determined # whether actually different or not while 1: if not swipe_timer.started() or swipe_timer.reached(): swipe_timer.reset() self.device.swipe_vector(vector=(distance, 0), box=SWIPE_AREA.area, random_range=SWIPE_RANDOM_RANGE, padding=0, duration=(0.1, 0.12), name='EQUIP_SWIPE') self.wait_until_appear(check_button) swipe_count += 1 self.device.screenshot() if SWIPE_CHECK.match(self.device.image): if swipe_count > 1: logger.info('Same ship on multiple swipes') return False continue if self.appear(check_button, offset=( 30, 30)) and not SWIPE_CHECK.match(self.device.image): logger.info('New ship detected on swipe') return True
def _equip_take_on_one(self, index): bar_timer = Timer(5) on_timer = Timer(5) while 1: self.device.screenshot() if bar_timer.reached() and not self.appear(EQUIP_1, offset=10): self.device.click(EQUIPMENT_OPEN) # self.device.sleep(0.3) bar_timer.reset() continue if on_timer.reached() and self.appear( EQUIP_1, offset=10) and not self.info_bar_count(): if index == 1: self.device.click(EQUIP_1) elif index == 2: self.device.click(EQUIP_2) elif index == 3: self.device.click(EQUIP_3) on_timer.reset() continue # End # if self.handle_info_bar(): # break if on_timer.started() and self.info_bar_count(): break
def _equip_take_off_one(self): bar_timer = Timer(5) off_timer = Timer(5) confirm_timer = Timer(5) while 1: self.device.screenshot() if bar_timer.reached() and not self.appear(EQUIP_1, offset=10): self.device.click(EQUIPMENT_OPEN) bar_timer.reset() continue if off_timer.reached( ) and not self.info_bar_count() and self.appear_then_click( EQUIP_OFF, offset=10): off_timer.reset() continue if confirm_timer.reached() and self.handle_popup_confirm(): confirm_timer.reset() continue # End # if self.handle_info_bar(): # break if off_timer.started() and self.info_bar_count(): break
def _guild_logistics_collect(self, skip_first_screenshot=True): """ Execute collect/accept screen transitions within logistics Pages: in: GUILD_LOGISTICS out: GUILD_LOGISTICS """ # Various timers for buttons and confirmation whether collection has ceased confirm_timer = Timer(3, count=6).start() mission_timer = Timer(1.5, count=3) supply_timer = Timer(1.5, count=3) while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if (not mission_timer.started() or mission_timer.reached() ) and self._guild_logistics_mission_available(): self.device.click(GUILD_MISSION) mission_timer.reset() confirm_timer.reset() continue if (not supply_timer.started() or supply_timer.reached() ) and self._guild_logistics_supply_available(): self.device.click(GUILD_SUPPLY) supply_timer.reset() confirm_timer.reset() continue if self.handle_popup_confirm('GUILD_MISSION_ACCEPT'): confirm_timer.reset() continue if self.appear_then_click(GET_ITEMS_1, interval=2): confirm_timer.reset() continue # End if self._guild_logistics_ensure(): if not self.info_bar_count() and confirm_timer.reached(): break else: confirm_timer.reset()
def _view_swipe(self, distance, check_button=EQUIPMENT_OPEN): swipe_timer = Timer(3, count=5) SWIPE_CHECK.load_color(self.device.image) while 1: if not swipe_timer.started() or swipe_timer.reached(): swipe_timer.reset() self.device.swipe(vector=(distance, 0), box=SWIPE_AREA.area, random_range=SWIPE_RANDOM_RANGE, padding=0, duration=(0.1, 0.12)) self.device.screenshot() if SWIPE_CHECK.match(self.device.image): continue if self.appear(check_button, offset=( 30, 30)) and not SWIPE_CHECK.match(self.device.image): break
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) result_mystery = '' self.movable_before = self.map.select(is_siren=True) if self.hp_withdraw_triggered(): self.withdraw() is_portal = self.map[location].is_portal while 1: sight = self.map.camera_sight self.in_sight(location, sight=(sight[0], 0, sight[2], sight[3])) self.focus_to_grid_center() grid = self.convert_map_to_grid(location) 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 . extra = 4.5 if self.config.SUBMARINE_MODE == 'hunt_only' else 0 arrive_timer = Timer(0.5 + self.round_wait + extra, count=2) arrive_unexpected_timer = Timer(1.5 + self.round_wait + extra, count=6) # Wait after ambushed. ambushed_retry = Timer(0.5) # If nothing happens, click again. walk_timeout = Timer(20) walk_timeout.start() while 1: self.device.screenshot() grid.image = np.array(self.device.image) if is_portal: self.update() grid = self.view[self.view.center_loca] # Combat if self.config.ENABLE_MAP_FLEET_LOCK and not self.is_in_map(): if self.handle_retirement(): self.map_offensive() walk_timeout.reset() if self.handle_combat_low_emotion(): walk_timeout.reset() if self.combat_appear(): self.combat( expected_end=self._expected_combat_end(expected), fleet_index=self.fleet_current_index) self.hp_get() arrived = True if not self.config.MAP_HAS_MOVABLE_ENEMY else False result = 'combat' self.battle_count += 1 self.fleet_ammo -= 1 if 'siren' in expected or ( self.config.MAP_HAS_MOVABLE_ENEMY and not expected): self.siren_count += 1 elif self.map[location].may_enemy: self.map[location].is_cleared = True self.handle_boss_appear_refocus() grid = self.convert_map_to_grid(location) walk_timeout.reset() # Ambush if self.handle_ambush(): self.hp_get() ambushed_retry.start() walk_timeout.reset() # Mystery mystery = self.handle_mystery(button=grid) if mystery: self.mystery_count += 1 result = 'mystery' result_mystery = mystery # Cat attack animation if self.handle_map_cat_attack(): walk_timeout.reset() continue if self.handle_walk_out_of_step(): raise MapWalkError('walk_out_of_step') # Arrive if self.is_in_map() and \ (grid.predict_fleet() or (walk_timeout.reached() and grid.predict_current_fleet())): if not arrive_timer.started(): logger.info(f'Arrive {location2node(location)}') 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 if is_portal: location = self.map[location].portal_link self.camera = location logger.info( f'Arrive {location2node(location)} confirm. Result: {result}. Expected: {expected}' ) arrived = True break # Story if expected == 'story': if self.handle_story_skip(): result = 'story' continue # End if ambushed_retry.started() and ambushed_retry.reached(): break if walk_timeout.reached(): logger.warning('Walk timeout. Retrying.') self.ensure_edge_insight() 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': self.full_scan_carrier() if result == 'combat': self.round_battle() self.round_next() if self.round_is_new: self.full_scan_movable(enemy_cleared=result == 'combat') self.find_path_initial() raise MapEnemyMoved self.find_path_initial()
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) siren_count = self.map.select(is_siren=True).count result_mystery = '' while 1: sight = self.map.camera_sight self.in_sight(location, sight=(sight[0], 0, sight[2], sight[3])) self.focus_to_grid_center() grid = self.convert_map_to_grid(location) 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 . add = self.config.MAP_SIREN_MOVE_WAIT * min(self.config.MAP_SIREN_COUNT, siren_count) \ if self.config.MAP_HAS_MOVABLE_ENEMY and not self.config.ENABLE_FAST_FORWARD else 0 arrive_timer = Timer(0.3 + add) arrive_unexpected_timer = Timer(1.5 + add) # Wait after ambushed. ambushed_retry = Timer(0.5) # If nothing happens, click again. walk_timeout = Timer(20) 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.config.ENABLE_MAP_FLEET_LOCK and not self.is_in_map(): if self.handle_retirement(): self.map_offensive() walk_timeout.reset() if self.handle_combat_low_emotion(): walk_timeout.reset() 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 if not self.config.MAP_HAS_MOVABLE_ENEMY else False result = 'combat' self.battle_count += 1 self.fleet_ammo -= 1 if 'siren' in expected: self.siren_count += 1 elif self.map[location].may_enemy: self.map[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(): walk_timeout.reset() continue if self.handle_walk_out_of_step(): raise MapWalkError('walk_out_of_step') # Arrive if self.is_in_map() and \ (grid.predict_fleet() or (walk_timeout.reached() and grid.predict_current_fleet())): if not arrive_timer.started(): logger.info(f'Arrive {location2node(location)}') 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 {location2node(location)} 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.') self.ensure_edge_insight() 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(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, expected=''): """Goto a grid directly and handle ambush, air raid, mystery picked up, combat. Args: location (tuple, str, GridInfo): Destination. expected (str): Expected result on destination grid, such as 'combat', 'combat_siren', 'mystery'. Will give a waring if arrive with unexpected result. """ location = location_ensure(location) result_mystery = '' self.movable_before = self.map.select(is_siren=True) self.movable_before_normal = self.map.select(is_enemy=True) if self.hp_retreat_triggered(): self.withdraw() is_portal = self.map[location].is_portal # The upper grid is submarine, may mess up predict_fleet() may_submarine_icon = self.map.grid_covered(self.map[location], location=[(0, -1)]) may_submarine_icon = may_submarine_icon and self.fleet_submarine_location == may_submarine_icon[ 0].location while 1: self.fleet_ensure(self.fleet_current_index) self.in_sight(location, sight=self._walk_sight) self.focus_to_grid_center() grid = self.convert_global_to_local(location) 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. extra = 0 if self.config.Submarine_Mode == 'hunt_only': extra += 4.5 if self.config.MAP_HAS_LAND_BASED and grid.is_mechanism_trigger: extra += grid.mechanism_wait arrive_timer = Timer(0.5 + self.round_wait + extra, count=2) arrive_unexpected_timer = Timer(1.5 + self.round_wait + extra, count=6) # Wait after ambushed. ambushed_retry = Timer(0.5) # If nothing happens, click again. walk_timeout = Timer(20) walk_timeout.start() while 1: self.device.screenshot() self.view.update(image=self.device.image) if is_portal: self.update(allow_error=True) grid = self.view[self.view.center_loca] # Combat if self.config.Campaign_UseFleetLock and not self.is_in_map(): if self.handle_retirement(): self.map_offensive() walk_timeout.reset() if self.handle_combat_low_emotion(): walk_timeout.reset() if self.combat_appear(): self.combat(expected_end=self._expected_end(expected), fleet_index=self.fleet_show_index, submarine_mode=self._submarine_mode(expected)) self.hp_get() self.lv_get(after_battle=True) arrived = True if not self.config.MAP_HAS_MOVABLE_ENEMY else False result = 'combat' self.battle_count += 1 self.fleet_ammo -= 1 if 'siren' in expected or ( self.config.MAP_HAS_MOVABLE_ENEMY and not expected): self.siren_count += 1 elif self.map[location].may_enemy: self.map[location].is_cleared = True if self.catch_camera_repositioning(self.map[location]): self.handle_boss_appear_refocus() if self.config.MAP_FOCUS_ENEMY_AFTER_BATTLE: self.camera = location self.update() grid = self.convert_global_to_local(location) arrive_timer = Timer(0.5 + extra, count=2) arrive_unexpected_timer = Timer(1.5 + extra, count=6) walk_timeout.reset() if not (grid.predict_fleet() and grid.predict_current_fleet()): ambushed_retry.start() # Ambush if self.handle_ambush(): self.hp_get() self.lv_get(after_battle=True) walk_timeout.reset() self.view.update(image=self.device.image) if not (grid.predict_fleet() and grid.predict_current_fleet()): ambushed_retry.start() # Mystery mystery = self.handle_mystery(button=grid) if mystery: self.mystery_count += 1 result = 'mystery' result_mystery = mystery # Cat attack animation if self.handle_map_cat_attack(): walk_timeout.reset() continue # Guild popup # Usually handled in combat_status, but sometimes delayed until after battle on slow PCs. if self.handle_guild_popup_cancel(): walk_timeout.reset() continue if self.handle_walk_out_of_step(): raise MapWalkError('walk_out_of_step') # Arrive arrive_predict = '' arrive_checker = False if self.is_in_map(): if not may_submarine_icon and grid.predict_fleet(): arrive_predict = '(is_fleet)' arrive_checker = True elif may_submarine_icon and grid.predict_current_fleet(): arrive_predict = '(may_submarine_icon, is_current_fleet)' arrive_checker = True elif self.config.MAP_WALK_USE_CURRENT_FLEET \ and expected != 'combat_boss' \ and not ('combat' in expected and grid.may_boss) \ and (grid.predict_fleet() or grid.predict_current_fleet()): arrive_predict = '(MAP_WALK_USE_CURRENT_FLEET, is_current_fleet)' arrive_checker = True elif walk_timeout.reached() and grid.predict_current_fleet( ): arrive_predict = '(walk_timeout, is_current_fleet)' arrive_checker = True if arrive_checker: if not arrive_timer.started(): logger.info( f'Arrive {location2node(location)} {arrive_predict}' .strip()) arrive_timer.start() arrive_unexpected_timer.start() if result == 'nothing' and 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 if is_portal: location = self.map[location].portal_link self.camera = location logger.info( f'Arrive {location2node(location)} confirm. Result: {result}. Expected: {expected}' ) arrived = True break else: if arrive_timer.started(): arrive_timer.reset() if arrive_unexpected_timer.started(): arrive_unexpected_timer.reset() # Story if expected == 'story': if self.handle_story_skip(): result = 'story' continue # End if ambushed_retry.started() and ambushed_retry.reached(): break if walk_timeout.reached(): logger.warning('Walk timeout. Retrying.') self.predict() self.ensure_edge_insight(skip_first_update=False) 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': self.full_scan_carrier() if result == 'combat': self.round_battle(after_battle=True) self.predict() self.round_next() if self.round_is_new: if result != 'combat': self.predict() self.full_scan_movable(enemy_cleared=result == 'combat') self.find_path_initial() raise MapEnemyMoved if self.round_maze_changed: self.find_path_initial() raise MapEnemyMoved self.find_path_initial() if self.config.MAP_HAS_DECOY_ENEMY: if result == 'nothing' and expected == 'combat': raise MapEnemyMoved
def _submarine_goto(self, location): """ Move submarine to given location. Args: location (tuple, str, GridInfo): Destination. Returns: bool: If submarine moved. Pages: in: SUBMARINE_MOVE_CONFIRM out: SUBMARINE_MOVE_CONFIRM """ location = location_ensure(location) moved = True while 1: self.in_sight(location, sight=self._walk_sight) self.focus_to_grid_center() grid = self.convert_global_to_local(location) grid.__str__ = location self.device.click(grid) arrived = False # Usually no need to wait arrive_timer = Timer(0.1, count=0) # If nothing happens, click again. walk_timeout = Timer(2, count=6).start() while 1: self.device.screenshot() self.view.update(image=self.device.image) # Arrive arrive_checker = grid.predict_submarine_move() if grid.predict_submarine() or (walk_timeout.reached() and grid.predict_fleet()): arrive_checker = True moved = False if arrive_checker: if not arrive_timer.started(): logger.info(f'Arrive {location2node(location)}') arrive_timer.start() if not arrive_timer.reached(): continue logger.info( f'Submarine arrive {location2node(location)} confirm.') if not moved: logger.info( f'Submarine already at {location2node(location)}') arrived = True break # End if walk_timeout.reached(): logger.warning('Walk timeout. Retrying.') self.predict() self.ensure_edge_insight(skip_first_update=False) break # End if arrived: break return moved
def _guild_operations_dispatch(self, skip_first_screenshot=True): """ Executes the dispatch sequence Pages: in: GUILD_OPERATIONS_DISPATCH out: GUILD_OPERATIONS_MAP """ confirm_timer = Timer(1.5, count=3).start() add_timer = Timer(1.5, count=3) close_timer = Timer(3, count=6).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear_then_click(GUILD_DISPATCH_QUICK, offset=(20, 20), interval=3): confirm_timer.reset() close_timer.reset() continue # Pseudo interval timer for template match_result calls if not add_timer.started() or add_timer.reached(): sim, point = TEMPLATE_OPERATIONS_ADD.match_result( self.device.image) if sim > 0.85: # Use small area to reduce random click point button = area_offset(area=(-2, -2, 24, 12), offset=point) dispatch_add = Button(area=button, color=(), button=button, name='GUILD_DISPATCH_ADD') self.device.click(dispatch_add) confirm_timer.reset() add_timer.reset() close_timer.reset() continue if self.appear(GUILD_DISPATCH_EMPTY, interval=3): self.device.click(GUILD_DISPATCH_RECOMMEND) confirm_timer.reset() close_timer.reset() continue if self.appear_then_click(GUILD_DISPATCH_FLEET, offset=(20, 20), interval=3): confirm_timer.reset() close_timer.reset() continue if self.handle_popup_confirm('GUILD_DISPATCH'): # Explicit click since GUILD_DISPATCH_FLEET # does not automatically turn into # GUILD_DISPATCH_IN_PROGRESS after confirm self.device.sleep((0.5, 0.8)) self.device.click(GUILD_DISPATCH_CLOSE) confirm_timer.reset() close_timer.reset() continue if self.appear(GUILD_DISPATCH_IN_PROGRESS): # Independent timer used instead of interval # Since can appear if at least 1 fleet already # dispatched, don't want to exit prematurely if close_timer.reached_and_reset(): self.device.click(GUILD_DISPATCH_CLOSE) confirm_timer.reset() continue # End if self.appear(GUILD_OPERATIONS_ACTIVE_CHECK): if not self.info_bar_count() and confirm_timer.reached(): break else: confirm_timer.reset()
def _guild_operations_boss_preparation(self, skip_first_screenshot=True): """ Execute preperation sequence for guild raid boss Pages: in: GUILD_OPERATIONS_BOSS out: IN_BATTLE """ # Ensure in dispatch for Guild Raid Boss self.ui_click(GUILD_BOSS_ENTER, check_button=GUILD_DISPATCH_RECOMMEND_2, skip_first_screenshot=True) # If configured, auto recommend fleet composition if self.config.ENABLE_GUILD_OPERATIONS_BOSS_RECOMMEND: self.device.click(GUILD_DISPATCH_RECOMMEND_2) is_loading = False empty_timeout = Timer(3, count=6) dispatch_count = 0 while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear(GUILD_DISPATCH_EMPTY_2): # Account for loading lag especially if using # guild support if not empty_timeout.started(): empty_timeout.reset() continue elif empty_timeout.reached(): logger.warning( 'Fleet composition is empty, cannot auto-battle Guild Raid Boss' ) return False if self.appear(GUILD_DISPATCH_FLEET, interval=3): # Button does not appear greyed out even # when empty fleet composition if not self.appear(GUILD_DISPATCH_EMPTY_2): if dispatch_count < 3: self.device.click(GUILD_DISPATCH_FLEET) dispatch_count += 1 else: logger.warning( 'Fleet cannot be dispatched for auto-battle Guild Raid Boss, verify composition manually' ) return False continue # Only print once when detected if not is_loading: if self.is_combat_loading(): is_loading = True continue if self.handle_combat_automation_confirm(): continue # End if self.is_combat_executing(): return True