def _guild_logistics_collect(self, skip_first_screenshot=True): """ Execute collect/accept screen transitions within logistics Args: skip_first_screenshot (bool): Returns: bool: If all guild logistics are check, no need to check them today. Pages: in: GUILD_LOGISTICS out: GUILD_LOGISTICS """ logger.hr('Guild logistics') confirm_timer = Timer(1.5, count=3).start() exchange_interval = Timer(1.5, count=3) click_interval = Timer(0.5, count=1) supply_checked = False mission_checked = False exchange_checked = False exchange_count = 0 while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() # Handle all popups if self.handle_popup_confirm('GUILD_LOGISTICS'): confirm_timer.reset() exchange_interval.reset() continue if self.appear_then_click(GET_ITEMS_1, interval=2): confirm_timer.reset() exchange_interval.reset() continue if self.appear_then_click(GUILD_MISSION_SELECT, offset=(20, 20), interval=2): # Select guild mission for guild leader # Hard-coded to select mission: Siren Subjugation III, defeat 300 enemies # This mission has the most guild supply and it's the easiest one for members to finish confirm_timer.reset() continue if self._is_in_guild_logistics(): # Supply if not supply_checked and self._guild_logistics_supply_available( ): if click_interval.reached(): self.device.click(GUILD_SUPPLY) click_interval.reset() confirm_timer.reset() continue else: supply_checked = True # Mission if not mission_checked and self._guild_logistics_mission_available( ): if click_interval.reached(): self.device.click(GUILD_MISSION) click_interval.reset() confirm_timer.reset() continue else: mission_checked = True # Exchange if not exchange_checked and exchange_interval.reached(): if self._guild_exchange(): confirm_timer.reset() exchange_interval.reset() exchange_count += 1 continue else: exchange_checked = True # End if not self.info_bar_count() and confirm_timer.reached(): break # if supply_checked and mission_checked and exchange_checked: # break if exchange_count >= 5: # If you run AL across days, then do guild exchange. # There will show an error, said time is not up. # Restart the game can't fix the problem. # To fix this, you have to enter guild logistics once, then restart. # If exchange for 5 times, this bug is considered to be triggered. logger.warning('Triggered guild logistics refresh bug') raise LogisticsRefreshBugHandler( 'Triggered guild logistics refresh bug') else: confirm_timer.reset() logger.info( f'supply_checked: {supply_checked}, mission_checked: {mission_checked}, ' f'exchange_checked: {exchange_checked}, mission_finished: {self._guild_logistics_mission_finished}' ) return all([ supply_checked, mission_checked, exchange_checked, self._guild_logistics_mission_finished ])
def os_shop_get_coins(self): self._shop_yellow_coins = OCR_SHOP_YELLOW_COINS.ocr(self.device.image) self._shop_purple_coins = OCR_SHOP_PURPLE_COINS.ocr(self.device.image) logger.info( f'Yellow coins: {self._shop_yellow_coins}, purple coins: {self._shop_purple_coins}' )
def update(self, camera=True): """Update map image Args: camera: True to update camera position and perspective data. """ self.device.screenshot() if not camera: self.grids.update(image=self.device.image) return True try: self.grids = Grids(self.device.image, config=self.config) except Exception as e: if self.info_bar_count(): logger.info('Perspective error cause by info bar. Waiting.') self.handle_info_bar() return self.update(camera=camera) else: raise e # Catch perspective error known_exception = self.info_bar_count() if len(self.grids.horizontal) > self.map.shape[1] + 2 or len( self.grids.vertical) > self.map.shape[0] + 2: if not known_exception: logger.info('Perspective Error. Too many lines') self.grids.correct = False if len(self.grids.horizontal) <= 3 or len(self.grids.vertical) <= 3: if not known_exception: logger.info('Perspective Error. Too few lines') self.grids.correct = False if not self.grids.correct: if self.info_bar_count(): logger.info('Perspective error cause by info bar. Waiting.') self.handle_info_bar() return self.update(camera=camera) else: self.grids.save_error_image() # Set camera position if self.grids.left_edge: x = 0 + self.grids.center_grid[0] elif self.grids.right_edge: x = self.map.shape[0] - self.grids.shape[ 0] + self.grids.center_grid[0] else: x = self.camera[0] if self.grids.lower_edge: y = 0 + self.grids.center_grid[1] elif self.grids.upper_edge: y = self.map.shape[1] - self.grids.shape[ 1] + self.grids.center_grid[1] else: y = self.camera[1] if self.camera != (x, y): logger.info( f' camera corrected: {location2node(self.camera)} -> {location2node((x, y))}' ) self.camera = (x, y) self.show_camera()
def enter_map(self, button, mode='normal'): """Enter a campaign. Args: button: Campaign to enter. mode (str): 'normal' or 'hard' or 'cd' """ logger.hr('Enter map') campaign_timer = Timer(5) map_timer = Timer(5) fleet_timer = Timer(5) checked_in_map = False self.stage_entrance = button while 1: self.device.screenshot() if not checked_in_map and self.is_in_map(): logger.info('Already in map, skip enter_map.') return False else: checked_in_map = True # Map preparation if map_timer.reached() and self.handle_map_preparation(): if self.handle_map_clear_mode_stop(): self.enter_map_cancel() raise ScriptEnd( f'Reach condition: {self.config.CLEAR_MODE_STOP_CONDITION}' ) self.handle_fast_forward() self.device.click(MAP_PREPARATION) map_timer.reset() campaign_timer.reset() continue # Fleet preparation if fleet_timer.reached() and self.appear(FLEET_PREPARATION): if self.config.ENABLE_FLEET_CONTROL: if mode == 'normal' or mode == 'hard': self.fleet_preparation() self.device.click(FLEET_PREPARATION) fleet_timer.reset() campaign_timer.reset() continue # Retire if self.handle_retirement(): continue # Emotion if self.handle_combat_low_emotion(): continue # Urgent commission if self.handle_urgent_commission(): continue # Story skip if self.handle_story_skip(): campaign_timer.reset() continue # Enter campaign if campaign_timer.reached() and self.is_in_stage(): self.device.click(button) campaign_timer.reset() continue # End if self.handle_in_map_with_enemy_searching(): break return True
def _reward_mission(self): """ Returns: bool: If rewarded. """ if not self.config.ENABLE_MISSION_REWARD: return False logger.hr('Mission reward') if not self.appear(MISSION_NOTICE): logger.info('No mission reward') return False self.ui_goto(page_mission, skip_first_screenshot=True) reward = False exit_timer = Timer(2) click_timer = Timer(1) timeout = Timer(10) exit_timer.start() timeout.start() while 1: self.device.screenshot() for button in [GET_ITEMS_1, GET_ITEMS_2]: if self.appear_then_click(button, offset=(30, 30), interval=1): exit_timer.reset() timeout.reset() reward = True continue for button in [MISSION_MULTI, MISSION_SINGLE]: if not click_timer.reached(): continue if self.appear_then_click(button, interval=1): exit_timer.reset() click_timer.reset() timeout.reset() continue if not self.appear(MISSION_CHECK): if self.appear_then_click(GET_SHIP, interval=1): click_timer.reset() exit_timer.reset() timeout.reset() continue if self.story_skip(): click_timer.reset() exit_timer.reset() timeout.reset() continue # End if reward and exit_timer.reached(): break if timeout.reached(): logger.warning('Wait get items timeout.') break self.ui_goto(page_main, skip_first_screenshot=True) return reward
def prev(self): self.daily_current -= 1 logger.info('Switch to %s' % str(self.daily_current)) self.device.click(DAILY_PREV) self._wait_daily_switch() self.device.screenshot()
def _commission_choose(self, daily, urgent): """ Args: daily (SelectedGrids): urgent (SelectedGrids): Returns: SelectedGrids, SelectedGrids: Chosen daily commission, Chosen urgent commission """ # Count Commission total = daily.add_by_eq(urgent) self.max_commission = 4 for comm in total: if comm.genre == 'event_daily': self.max_commission = 5 running_count = int(np.sum([1 for c in total if c.status == 'running'])) logger.attr('Running', f'{running_count}/{self.max_commission}') if running_count >= self.max_commission: return SelectedGrids([]), SelectedGrids([]) # Filter COMMISSION_FILTER.load(self.config.Commission_CommissionFilter) run = COMMISSION_FILTER.apply(total.grids, func=self._commission_check) logger.attr('Filter_sort', ' > '.join([str(c) for c in run])) run = SelectedGrids(run) # Add shortest no_shortest = run.delete(SelectedGrids(['shortest'])) if no_shortest.count + running_count < self.max_commission: if no_shortest.count < run.count: logger.info( 'Not enough commissions to run, add shortest daily commissions' ) COMMISSION_FILTER.load(SHORTEST_FILTER) shortest = COMMISSION_FILTER.apply(daily, func=self._commission_check) run = no_shortest.add_by_eq(SelectedGrids(shortest)) logger.attr('Filter_sort', ' > '.join([str(c) for c in run])) else: logger.info('Not enough commissions to run') # Separate daily and urgent run = run[:self.max_commission - running_count] daily_choose = run.intersect_by_eq(daily) urgent_choose = run.intersect_by_eq(urgent) if daily_choose: logger.info('Choose daily commission') for comm in daily_choose: logger.info(comm) if urgent_choose: logger.info('Choose urgent commission') for comm in urgent_choose: logger.info(comm) return daily_choose, urgent_choose
def daily_execute(self, remain=3, stage=1, fleet=1): """ Args: remain (int): Remain daily challenge count. stage (int): Index of stage counted from top, 1 to 3. fleet (int): Index of fleet to use. Returns: bool: True if success, False if daily locked. Pages: in: page_daily out: page_daily """ logger.hr(f'Daily {self.daily_current}') logger.info(f'remain={remain}, stage={stage}, fleet={fleet}') def daily_enter_check(): return self.appear(DAILY_ENTER_CHECK) def daily_end(): if self.appear(BATTLE_PREPARATION, interval=2): self.device.click(BACK_ARROW) return self.appear(DAILY_ENTER_CHECK) or self.appear(BACK_ARROW) self.ui_click(click_button=DAILY_ENTER, check_button=daily_enter_check, appear_button=DAILY_CHECK, skip_first_screenshot=True) if self.appear(DAILY_LOCKED): logger.info('Daily locked') self.ui_click(click_button=BACK_ARROW, check_button=DAILY_CHECK) self.device.sleep((1, 1.2)) return False button = DAILY_MISSION_LIST[stage - 1] for n in range(remain): logger.hr(f'Count {n + 1}') result = self.daily_enter(button) if not result: break if self.daily_current == 3: logger.info('Submarine daily skip not unlocked, skip') self.ui_click(click_button=BACK_ARROW, check_button=daily_enter_check, skip_first_screenshot=True) break # Execute classic daily run self.ui_ensure_index(fleet, letter=OCR_DAILY_FLEET_INDEX, prev_button=DAILY_FLEET_PREV, next_button=DAILY_FLEET_NEXT, fast=False, skip_first_screenshot=True) self.combat(emotion_reduce=False, save_get_items=False, expected_end=daily_end, balance_hp=False) self.ui_click(click_button=BACK_ARROW, check_button=DAILY_CHECK, additional=self.handle_daily_additional, skip_first_screenshot=True) self.device.sleep((1, 1.2)) return True
def auto_search_combat(self, drop=None): """ Args: drop (DropImage): Returns: bool: True if enemy cleared, False if fleet died. Pages: in: is_combat_loading() out: combat status """ logger.info('Auto search combat loading') self.device.screenshot_interval_set('combat') while 1: self.device.screenshot() if self.handle_combat_automation_confirm(): continue # End if self.handle_os_auto_search_map_option(drop=drop): break if self.is_combat_executing(): break if self.is_in_map(): break logger.info('Auto Search combat execute') self.submarine_call_reset() submarine_mode = 'do_not_use' if self.config.Submarine_Fleet: submarine_mode = self.config.Submarine_Mode success = True while 1: self.device.screenshot() if self.handle_submarine_call(submarine_mode): continue if self.handle_os_auto_search_map_option(drop=drop, enable=success): continue # End if self.is_combat_executing(): continue if self.handle_auto_search_battle_status(): success = False continue if self.handle_auto_search_exp_info(): success = False continue if self.handle_map_event(): continue if self.is_in_map(): self.device.screenshot_interval_set() break logger.info('Combat end.') return success
def main(ini_name=''): if not ini_name: ini_name = pyw_name ini_name = ini_name.lower() # Load default value from .ini file. config_file = f'./config/{ini_name}.ini' config = configparser.ConfigParser(interpolation=None) try: config.read_file(codecs.open(config_file, "r", "utf8")) except FileNotFoundError: logger.info('Config file not exists, copy from ./config/template.ini') shutil.copy('./config/template.ini', config_file) config.read_file(codecs.open(config_file, "r", "utf8")) config = update_config_from_template(config, file=config_file) event_folder = [f for f in os.listdir('./campaign') if f.startswith('event_') and f.split('_')[-1] == server.server] event_latest = sorted([f for f in event_folder], reverse=True)[0] event_folder = [dic_eng_to_true_eng.get(f, f) for f in event_folder][::-1] event_latest = dic_eng_to_true_eng.get(event_latest, event_latest) saved_config = {} for opt, option in config.items(): for key, value in option.items(): key = dic_eng_to_true_eng.get(key, key) if value in dic_eng_to_true_eng: value = dic_eng_to_true_eng.get(value, value) if value == 'None': value = '' saved_config[key] = value def default(name): """Get default value in .ini file. Args: name (str): option, in chinese. Returns: str: Default value, in chinese. """ name = name.strip('-') return saved_config.get(name, '') def choice_list(total): return [str(index) for index in range(1, total + 1)] # Don't use checkbox in gooey, use drop box instead. # https://github.com/chriskiehl/Gooey/issues/148 # https://github.com/chriskiehl/Gooey/issues/485 parser = GooeyParser(description=f'AzurLaneAutoScript, An Azur Lane automation tool. Config: {config_file}') subs = parser.add_subparsers(help='commands', dest='command') # ==========setting========== setting_parser = subs.add_parser('setting') # 选择关卡 stage = setting_parser.add_argument_group('Level settings', 'Need to run once to save options') stage.add_argument('--enable_stop_condition', default=default('--enable_stop_condition'), choices=['yes', 'no']) stage.add_argument('--enable_fast_forward', default=default('--enable_fast_forward'), choices=['yes', 'no'], help='Enable or disable clearing mode') stop = stage.add_argument_group('Stop condition', 'After triggering, it will not stop immediately. It will complete the current attack first, and fill in 0 if it is not needed.') stop.add_argument('--if_count_greater_than', default=default('--if_count_greater_than'), help='The previous setting will be used, and the number\n of deductions will be deducted after completion of the attack until it is cleared.') stop.add_argument('--if_time_reach', default=default('--if_time_reach'), help='Use the time within the next 24 hours, the previous setting will be used, and it will be cleared\n after the trigger. It is recommended to advance about\n 10 minutes to complete the current attack. Format 14:59') stop.add_argument('--if_oil_lower_than', default=default('--if_oil_lower_than')) stop.add_argument('--if_trigger_emotion_control', default=default('--if_trigger_emotion_control'), choices=['yes', 'no'], help='If yes, wait for reply, complete this time, stop \nIf no, wait for reply, complete this time, continue') stop.add_argument('--if_dock_full', default=default('--if_dock_full'), choices=['yes', 'no']) # 出击舰队 fleet = setting_parser.add_argument_group('Attack fleet', 'No support for alternate lane squadrons, inactive map or weekly mode will ignore the step setting') fleet.add_argument('--enable_fleet_control', default=default('--enable_fleet_control'), choices=['yes', 'no']) fleet.add_argument('--enable_map_fleet_lock', default=default('--enable_map_fleet_lock'), choices=['yes', 'no']) f1 = fleet.add_argument_group('Mob Fleet', 'Players can choose a formation before battle. Though it has no effect appearance-wise, the formations applies buffs to certain stats.\nLine Ahead: Increases Firepower and Torpedo by 15%, but reduces Evasion by 10% (Applies only to Vanguard fleet)\nDouble Line: Increases Evasion by 30%, but decreases Firepower and Torpedo by 5% (Applies only to Vanguard fleet)\nDiamond: Increases Anti-Air by 20% (no penalties, applies to entire fleet)') f1.add_argument('--fleet_index_1', default=default('--fleet_index_1'), choices=['1', '2', '3', '4', '5', '6']) f1.add_argument('--fleet_formation_1', default=default('--fleet_formation_1'), choices=['Line Ahead', 'Double Line', 'Diamond']) f1.add_argument('--fleet_step_1', default=default('--fleet_step_1'), choices=['1', '2', '3', '4', '5', '6'], help='In event map, fleet has limit on moving, so fleet_step is how far can a fleet goes in one operation, if map cleared, it will be ignored') f2 = fleet.add_argument_group('Boss Fleet') f2.add_argument('--fleet_index_2', default=default('--fleet_index_2'), choices=['do_not_use', '1', '2', '3', '4', '5', '6']) f2.add_argument('--fleet_formation_2', default=default('--fleet_formation_2'), choices=['Line Ahead', 'Double Line', 'Diamond']) f2.add_argument('--fleet_step_2', default=default('--fleet_step_2'), choices=['1', '2', '3', '4', '5', '6'], help='In event map, fleet has limit on moving, so fleet_step is how far can a fleet goes in one operation, if map cleared, it will be ignored') f3 = fleet.add_argument_group('Alternate Mob Fleet') f3.add_argument('--fleet_index_3', default=default('--fleet_index_3'), choices=['do_not_use', '1', '2', '3', '4', '5', '6']) f3.add_argument('--fleet_formation_3', default=default('--fleet_formation_3'), choices=['Line Ahead', 'Double Line', 'Diamond']) f3.add_argument('--fleet_step_3', default=default('--fleet_step_3'), choices=['1', '2', '3', '4', '5', '6'], help='In event map, fleet has limit on moving, so fleet_step is how far can a fleet goes in one operation, if map cleared, it will be ignored') f4 = fleet.add_argument_group('Auto-mode') f4.add_argument('--combat_auto_mode', default=default('--combat_auto_mode'), choices=['combat_auto', 'combat_manual', 'stand_still_in_the_middle']) # 潜艇设置 submarine = setting_parser.add_argument_group('Submarine settings', 'Only supported: hunt_only, do_not_use and every_combat') submarine.add_argument('--fleet_index_4', default=default('--fleet_index_4'), choices=['do_not_use', '1', '2']) submarine.add_argument('--submarine_mode', default=default('--submarine_mode'), choices=['do_not_use', 'hunt_only', 'every_combat', 'when_no_ammo', 'when_boss_combat', 'when_boss_combat_boss_appear']) # 心情控制 emotion = setting_parser.add_argument_group('Mood control') emotion.add_argument('--enable_emotion_reduce', default=default('--enable_emotion_reduce'), choices=['yes', 'no']) emotion.add_argument('--ignore_low_emotion_warn', default=default('--ignore_low_emotion_warn'), choices=['yes', 'no']) e1 = emotion.add_argument_group('Mob Fleet') e1.add_argument('--emotion_recover_1', default=default('--emotion_recover_1'), choices=['not_in_dormitory', 'dormitory_floor_1', 'dormitory_floor_2']) e1.add_argument('--emotion_control_1', default=default('--emotion_control_1'), choices=['keep_high_emotion', 'avoid_green_face', 'avoid_yellow_face', 'avoid_red_face']) e1.add_argument('--hole_fleet_married_1', default=default('--hole_fleet_married_1'), choices=['yes', 'no']) e2 = emotion.add_argument_group('BOSS Fleet') e2.add_argument('--emotion_recover_2', default=default('--emotion_recover_2'), choices=['not_in_dormitory', 'dormitory_floor_1', 'dormitory_floor_2']) e2.add_argument('--emotion_control_2', default=default('--emotion_control_2'), choices=['keep_high_emotion', 'avoid_green_face', 'avoid_yellow_face', 'avoid_red_face']) e2.add_argument('--hole_fleet_married_2', default=default('--hole_fleet_married_2'), choices=['yes', 'no']) e3 = emotion.add_argument_group('Alternate Mob Fleet', 'Will be used when the first team triggers mood control') e3.add_argument('--emotion_recover_3', default=default('--emotion_recover_3'), choices=['not_in_dormitory', 'dormitory_floor_1', 'dormitory_floor_2']) e3.add_argument('--emotion_control_3', default=default('--emotion_control_3'), choices=['keep_high_emotion', 'avoid_green_face', 'avoid_yellow_face', 'avoid_red_face']) e3.add_argument('--hole_fleet_married_3', default=default('--hole_fleet_married_3'), choices=['yes', 'no']) # 血量平衡 hp = setting_parser.add_argument_group('HP control', 'Fleet lock must be turned off to take effect') hp.add_argument('--enable_hp_balance', default=default('--enable_hp_balance'), choices=['yes', 'no']) hp.add_argument('--enable_low_hp_withdraw', default=default('--enable_low_hp_withdraw'), choices=['yes', 'no']) hp_balance = hp.add_argument_group('HP Balance', '') hp_balance.add_argument('--scout_hp_difference_threshold', default=default('--scout_hp_difference_threshold'), help='When the difference in HP volume is greater than the threshold, transpose') hp_balance.add_argument('--scout_hp_weights', default=default('--scout_hp_weights'), help='Should be repaired when there is a difference in Vanguard, format 1000,1000,1000') hp_add = hp.add_argument_group('Emergency repair', '') hp_add.add_argument('--emergency_repair_single_threshold', default=default('--emergency_repair_single_threshold'), help='Used when single shipgirl is below the threshold') hp_add.add_argument('--emergency_repair_hole_threshold', default=default('--emergency_repair_hole_threshold'), help='Used when all front rows or all back rows are below the threshold') hp_withdraw = hp.add_argument_group('Low HP volume withdrawal', '') hp_withdraw.add_argument('--low_hp_withdraw_threshold', default=default('--low_hp_withdraw_threshold'), help='When HP is below the threshold, retreat') # 退役选项 retire = setting_parser.add_argument_group('Retirement settings', '') retire.add_argument('--enable_retirement', default=default('--enable_retirement'), choices=['yes', 'no']) retire.add_argument('--retire_method', default=default('--retire_method'), choices=['enhance', 'one_click_retire', 'old_retire']) retire.add_argument('--retire_amount', default=default('--retire_amount'), choices=['retire_all', 'retire_10']) retire.add_argument('--enhance_favourite', default=default('--enhance_favourite'), choices=['yes', 'no']) rarity = retire.add_argument_group('Retirement rarity', 'The ship type selection is not supported yet. Ignore the following options when using one-key retirement') rarity.add_argument('--retire_n', default=default('--retire_n'), choices=['yes', 'no'], help='N') rarity.add_argument('--retire_r', default=default('--retire_r'), choices=['yes', 'no'], help='R') rarity.add_argument('--retire_sr', default=default('--retire_sr'), choices=['yes', 'no'], help='SR') rarity.add_argument('--retire_ssr', default=default('--retire_ssr'), choices=['yes', 'no'], help='SSR') # 掉落记录 drop = setting_parser.add_argument_group('Drop record', 'Save screenshots of dropped items, which will slow down the click speed when settlement is enabled') drop.add_argument('--enable_drop_screenshot', default=default('--enable_drop_screenshot'), choices=['yes', 'no']) drop.add_argument('--drop_screenshot_folder', default=default('--drop_screenshot_folder')) clear = setting_parser.add_argument_group('Wasteland mode', 'Unopened maps will stop after completion. Opened maps will ignore options, and its done if you do not open up') clear.add_argument('--enable_map_clear_mode', default=default('--enable_map_clear_mode'), choices=['yes', 'no']) clear.add_argument('--clear_mode_stop_condition', default=default('--clear_mode_stop_condition'), choices=['map_100', 'map_3_star', 'map_green']) clear.add_argument('--map_star_clear_all', default=default('--map_star_clear_all'), choices=['index_1', 'index_2', 'index_3', 'do_not_use'], help='The first few stars are to destroy all enemy ships') # ==========reward========== reward_parser = subs.add_parser('reward') reward_condition = reward_parser.add_argument_group('Triggering conditions', 'Need to run once to save the options, after running it will enter the on-hook vegetable collection mode') reward_condition.add_argument('--enable_reward', default=default('--enable_reward'), choices=['yes', 'no']) reward_condition.add_argument('--reward_interval', default=default('--reward_interval'), choices=['20', '30', '60'], help='How many minutes to trigger collection') reward_oil = reward_parser.add_argument_group('Oil supplies', '') reward_oil.add_argument('--enable_oil_reward', default=default('--enable_oil_reward'), choices=['yes', 'no']) reward_oil.add_argument('--enable_coin_reward', default=default('--enable_coin_reward'), choices=['yes', 'no']) reward_mission = reward_parser.add_argument_group('mission rewards', '') reward_mission.add_argument('--enable_mission_reward', default=default('--enable_mission_reward'), choices=['yes', 'no']) reward_commission = reward_parser.add_argument_group('Commission settings', '') reward_commission.add_argument('--enable_commission_reward', default=default('--enable_commission_reward'), choices=['yes', 'no']) reward_commission.add_argument('--commission_time_limit', default=default('--commission_time_limit'), help='Ignore orders whose completion time exceeds the limit, Format: 23:30. Fill in 0 if it is not needed') priority1 = reward_commission.add_argument_group('Commission priority by time duration', '') priority1.add_argument('--duration_shorter_than_2', default=default('--duration_shorter_than_2'), help='') priority1.add_argument('--duration_longer_than_6', default=default('--duration_longer_than_6'), help='') priority1.add_argument('--expire_shorter_than_2', default=default('--expire_shorter_than_2'), help='') priority1.add_argument('--expire_longer_than_6', default=default('--expire_longer_than_6'), help='') priority2 = reward_commission.add_argument_group('Daily Commission priority', '') priority2.add_argument('--daily_comm', default=default('--daily_comm'), help='Daily resource development, high-level tactical research and development') priority2.add_argument('--major_comm', default=default('--major_comm'), help='1200 oil / 1000 oil commission') priority3 = reward_commission.add_argument_group('Additional commission priority', '') priority3.add_argument('--extra_drill', default=default('--extra_drill'), help='Short-range Sailing Training, Coastal Defense Patrol') priority3.add_argument('--extra_part', default=default('--extra_part'), help='Small Merchant Escort, Forest Protection Commission') priority3.add_argument('--extra_cube', default=default('--extra_cube'), help='Fleet Exercise Ⅲ, Fleet Escort ExerciseFleet Exercise Ⅲ') priority3.add_argument('--extra_oil', default=default('--extra_oil'), help='Small-scale Oil Extraction, Large-scale Oil Extraction') priority3.add_argument('--extra_book', default=default('--extra_book'), help='Small Merchant Escort, Large Merchant Escort') priority4 = reward_commission.add_argument_group('Urgent commission priority', '') priority4.add_argument('--urgent_drill', default=default('--urgent_drill'), help='Defend the transport troops, annihilate the enemy elite troops') priority4.add_argument('--urgent_part', default=default('--urgent_part'), help='Support Vila Vela Island, support terror Banner') priority4.add_argument('--urgent_cube', default=default('--urgent_cube'), help='Rescue merchant ship, enemy attack') priority4.add_argument('--urgent_book', default=default('--urgent_book'), help='Support Tuhaoer Island, support Moe Island') priority4.add_argument('--urgent_box', default=default('--urgent_box'), help='BIW Gear Transport, NYB Gear Transport') priority4.add_argument('--urgent_gem', default=default('--urgent_gem'), help='BIW VIP Escort, NYB VIP Escort') priority4.add_argument('--urgent_ship', default=default('--urgent_ship'), help='Small Launch Ceremony, Fleet Launch Ceremony, Alliance Launch Ceremony') reward_tactical = reward_parser.add_argument_group('Classroom', 'Only support continuation of skill books, not new skills') reward_tactical.add_argument('--enable_tactical_reward', default=default('--enable_tactical_reward'), choices=['yes', 'no']) reward_tactical.add_argument('--tactical_night_range', default=default('--tactical_night_range'), help='Format 23:30-06:30') reward_tactical.add_argument('--tactical_book_tier', default=default('--tactical_book_tier'), choices=['3', '2', '1'], help='Wich skill book will use first\nT3 is a gold book, T2 is a purple book, T1 is a blue book') reward_tactical.add_argument('--tactical_exp_first', default=default('--tactical_exp_first'), choices=['yes', 'no'], help='Choose Yes, give priority to the 150% bonus \nSelect No, give priority to the skills book with the same rarity') reward_tactical.add_argument('--tactical_book_tier_night', default=default('--tactical_book_tier_night'), choices=['3', '2', '1']) reward_tactical.add_argument('--tactical_exp_first_night', default=default('--tactical_exp_first_night'), choices=['yes', 'no']) # ==========emulator========== emulator_parser = subs.add_parser('emulator') emulator = emulator_parser.add_argument_group('Emulator', 'Need to run once to save the options, it will check whether the game is started \nIf the game has not started, it will be started') emulator.add_argument('--serial', default=default('--serial'), help='Bluestacks 127.0.0.1:5555 \nNox 127.0.0.1:62001') emulator.add_argument('--package_name', default='com.YoStarEN.AzurLane', help='') debug = emulator_parser.add_argument_group('Debug settings', '') debug.add_argument('--enable_error_log_and_screenshot_save', default=default('--enable_error_log_and_screenshot_save'), choices=['yes', 'no']) debug.add_argument('--enable_perspective_error_image_save', default=default('--enable_perspective_error_image_save'), choices=['yes', 'no']) adb = emulator_parser.add_argument_group('ADB settings', '') adb.add_argument('--use_adb_screenshot', default=default('--use_adb_screenshot'), choices=['yes', 'no'], help='It is recommended to enable it to reduce CPU usage') adb.add_argument('--use_adb_control', default=default('--use_adb_control'), choices=['yes', 'no'], help='Recommended off, can speed up the click speed') adb.add_argument('--combat_screenshot_interval', default=default('--combat_screenshot_interval'), help='Slow down the screenshot speed during battle and reduce CPU') # ==========每日任务========== daily_parser = subs.add_parser('daily') # 选择每日 daily = daily_parser.add_argument_group('Choose daily', 'Daily tasks, exercises, difficulty charts') daily.add_argument('--enable_daily_mission', default=default('--enable_daily_mission'), help='If there are records on the day, skip', choices=['yes', 'no']) daily.add_argument('--enable_hard_campaign', default=default('--enable_hard_campaign'), help='If there are records on the day, skip', choices=['yes', 'no']) daily.add_argument('--enable_exercise', default=default('--enable_exercise'), help='If there is a record after refreshing, skip', choices=['yes', 'no']) # 每日设置 daily_task = daily_parser.add_argument_group('Daily settings', 'Does not support submarine daily') daily_task.add_argument('--tactical_training', default=default('--tactical_training'), choices=['daily_air', 'daily_gun', 'daily_torpedo']) daily_task.add_argument('--fierce_assault', default=default('--fierce_assault'), choices=['index_1', 'index_2', 'index_3']) daily_task.add_argument('--escort_mission', default=default('--escort_mission'), choices=['index_1', 'index_2', 'index_3']) daily_task.add_argument('--advance_mission', default=default('--advance_mission'), choices=['index_1', 'index_2', 'index_3']) daily_task.add_argument('--daily_fleet', default=default('--daily_fleet'), choices=['1', '2', '3', '4', '5', '6']) daily_task.add_argument('--daily_equipment', default=default('--daily_equipment'), help='Change equipment before playing, unload equipment after playing, do not need to fill in 0 \ncomma, such as 3, 1, 0, 1, 1, 0') # 困难设置 hard = daily_parser.add_argument_group('Difficult setting', 'Need to turn on weekly mode, only support 10-1, 10-2 and 10-4 temporarily') hard.add_argument('--hard_campaign', default=default('--hard_campaign'), help='For example 10-4') hard.add_argument('--hard_fleet', default=default('--hard_fleet'), choices=['1', '2']) hard.add_argument('--hard_equipment', default=default('--hard_equipment'), help='Change equipment before playing, unload equipment after playing, do not need to fill in 0 \ncomma, such as 3, 1, 0, 1, 1, 0') # 演习设置 exercise = daily_parser.add_argument_group('Exercise settings', 'Only support the most experience for the time being') exercise.add_argument('--exercise_choose_mode', default=default('--exercise_choose_mode'), choices=['max_exp', 'max_ranking', 'good_opponent'], help='Only support the most experience for the time being') exercise.add_argument('--exercise_preserve', default=default('--exercise_preserve'), help='Only 0 are temporarily reserved') exercise.add_argument('--exercise_try', default=default('--exercise_try'), help='The number of attempts by each opponent') exercise.add_argument('--exercise_hp_threshold', default=default('--exercise_hp_threshold'), help='HHP <Retreat at Threshold') exercise.add_argument('--exercise_low_hp_confirm', default=default('--exercise_low_hp_confirm'), help='After HP is below the threshold, it will retreat after a certain period of time \nRecommended 1.0 ~ 3.0') exercise.add_argument('--exercise_equipment', default=default('--exercise_equipment'), help='Change equipment before playing, unload equipment after playing, do not need to fill in 0 \ncomma, such as 3, 1, 0, 1, 1, 0') # ==========event_daily_ab========== event_ab_parser = subs.add_parser('event_daily_bonus') event_name = event_ab_parser.add_argument_group('Choose an event', 'bonus for first clear each day') event_name.add_argument('--event_name_ab', default=event_latest, choices=event_folder, help='There a dropdown menu with many options') # event_name.add_argument('--enable_hard_bonus', default=default('--enable_hard_bonus'), choices=['yes', 'no'], help='Will enable Daily bonus for Event hard maps') # Trying implement all event maps # ==========main========== main_parser = subs.add_parser('Main_campaign') # 选择关卡 stage = main_parser.add_argument_group('Choose a level', 'Main campaign, Currently, not all maps are being supported, check the folder /doc/development_en.md to know how add new maps') stage.add_argument('--main_stage', default=default('--main_stage'), help='E.g 7-2') # ==========event========== event_parser = subs.add_parser('event') description = """ Support "Iris of Light and Dark Rerun" (event_20200521_en), optimized for D2 """ event = event_parser.add_argument_group( 'Choose a level', '\n'.join([line.strip() for line in description.strip().split('\n')])) event.add_argument('--event_stage', default=default('--event_stage'), choices=['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3', 'd1', 'd2', 'd3'], help='E.g d3') event.add_argument('--sp_stage', default=default('--sp_stage'), choices=['sp1', 'sp2', 'sp3'], help='E.g sp3') event.add_argument('--event_name', default=event_latest, choices=event_folder, help='There a dropdown menu with many options') # ==========半自动========== semi_parser = subs.add_parser('semi_auto') semi = semi_parser.add_argument_group('Semi-automatic mode', 'Manual selection of enemies, automatic settlement, used to attack unsuited pictures') semi.add_argument('--enable_semi_map_preparation', default=default('--enable_semi_map_preparation'), help='', choices=['yes', 'no']) semi.add_argument('--enable_semi_story_skip', default=default('--enable_semi_story_skip'), help='Note that this will automatically confirm all the prompt boxes, including the red face attack', choices=['yes', 'no']) # ==========c72_mystery_farming========== c_7_2_parser = subs.add_parser('c7-2_mystery_farming') c_7_2 = c_7_2_parser.add_argument_group('c72_mystery_farming', '') c_7_2.add_argument('--boss_fleet_step_on_a3', default=default('--boss_fleet_step_on_a3'), choices=['yes', 'no'], help='A3 has enemies, G3, C3, E3') # ==========c122_leveling========== c_12_2_parser = subs.add_parser('c12-2_leveling') c_12_2 = c_12_2_parser.add_argument_group('12-2 enemy search settings', '') c_12_2.add_argument('--s3_enemy_tolerance', default=default('--s3_enemy_tolerance'), choices=['0', '1', '2', '10'], help='The maximum number of battles to fight against large enemies') # ==========c124_leveling========== c_12_4_parser = subs.add_parser('c12-4_leveling') c_12_4 = c_12_4_parser.add_argument_group('12-4 Search enemy settings', 'Need to ensure that the team has a certain strength') c_12_4.add_argument('--non_s3_enemy_enter_tolerance', default=default('--non_s3_enemy_enter_tolerance'), choices=['0', '1', '2'], help='Avoid enemy too strong') c_12_4.add_argument('--non_s3_enemy_withdraw_tolerance', default=default('--non_s3_enemy_withdraw_tolerance'), choices=['0', '1', '2', '10'], help='How many battles will be fought after there is no large scale') c_12_4.add_argument('--ammo_pick_up_124', default=default('--ammo_pick_up_124'), choices=['2', '3', '4', '5'], help='How much ammunition to pick after the battle') args = parser.parse_args() # Convert option from chinese to english. out = {} for key, value in vars(args).items(): key = dic_true_eng_to_eng.get(key, key) value = dic_true_eng_to_eng.get(value, value) out[key] = value args = out # Update option to .ini file. command = args['command'].capitalize() config['Command']['command'] = command for key, value in args.items(): config[command][key] = str(value) config.write(codecs.open(config_file, "w+", "utf8")) # Call AzurLaneAutoScript alas = AzurLaneAutoScript(ini_name=ini_name) alas.run(command=command)
def show(self): for y in range(self.shape[1] + 1): text = ' '.join([self[(x, y)].str if (x, y) in self else '..' for x in range(self.shape[0] + 1)]) logger.info(text)
def _shipyard_buy_confirm(self, text, skip_first_screenshot=True): """ Handles screen transitions to use/buy BPs Args: text (str): for handle_popup_confirm skip_first_screenshot (bool): """ success = False append = self._shipyard_get_append() button = globals()[f'SHIPYARD_CONFIRM_{append}'] ocr = globals()[f'OCR_SHIPYARD_TOTAL_{append}'] ocr_timer = Timer(10, count=10).start() confirm_timer = Timer(1, count=2).start() self.interval_clear(button) while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if ocr_timer.reached(): logger.warning( 'Failed to detect for normal exit routine, resort to OCR check' ) current = ocr.ocr(self.device.image) if not current: logger.info( 'Confirm action has completed, setting flag for exit') self.interval_reset(button) success = True ocr_timer.reset() continue if self.appear_then_click(button, offset=(20, 20), interval=3): continue if self.handle_popup_confirm(text): self.interval_reset(button) ocr_timer.reset() confirm_timer.reset() continue if self.story_skip(): self.interval_reset(button) success = True ocr_timer.reset() confirm_timer.reset() continue if self.handle_info_bar(): self.interval_reset(button) success = True ocr_timer.reset() confirm_timer.reset() continue # End if success and \ (self.appear(SHIPYARD_UI_CHECK, offset=(20, 20)) or self.appear(SHIPYARD_IN_FATE, offset=(20, 20))): if confirm_timer.reached(): break else: confirm_timer.reset()
def _guild_logistics_mission_available(self): """ Color sample the GUILD_MISSION area to determine whether the button is enabled, mission already in progress, or no more missions can be accepted Used at least twice, 'Collect' and 'Accept' Returns: bool: If button active Pages: in: GUILD_LOGISTICS out: GUILD_LOGISTICS """ r, g, b = get_color(self.device.image, GUILD_MISSION.area) if g > max(r, b) - 10: # Green tick at the bottom right corner if guild mission finished logger.info('Guild mission has finished this week') self._guild_logistics_mission_finished = True return False # 0/300 in EN is bold and pure white, and Collect rewards is blue white, so reverse the if condition elif self.image_color_count(GUILD_MISSION, color=(255, 255, 255), threshold=235, count=100): logger.info('Guild mission button inactive') return False elif self.image_color_count(GUILD_MISSION, color=(255, 255, 255), threshold=180, count=50): # white pixels less than 50, but has blue-white pixels logger.info('Guild mission button active') return True else: # No guild mission counter logger.info( 'No guild mission found, mission of this week may not started') if self.image_color_count(GUILD_MISSION_CHOOSE, color=(255, 255, 255), threshold=221, count=100): # Guild mission choose available if user is guild master logger.info('Guild mission choose found') return True else: logger.info('Guild mission choose not found') return False
def _guild_exchange_check(options, item_priority, grade_to_plate_priorities): """ Sift through all exchangeable options Record details on each to determine selection order Pages: in: GUILD_LOGISTICS out: GUILD_LOGISTICS """ # Contains the details of all options choices = dict() for i, (option, in_red) in enumerate(options): # Options already sorted sequentially # Button indexes are in sync btn = EXCHANGE_BUTTONS[i, 0] # Defaults set absurd values, which tells ALAS to skip option item_weight = len(DEFAULT_ITEM_PRIORITY) plate_weight = len(DEFAULT_PLATE_PRIORITY) can_exchange = False # Player lacks inventory of this item # so leave this choice under all defaults # to skip if not in_red: # Plate perhaps, extract last # 2 characters to ensure grade = option[-2:] if grade in GRADES: item_weight = item_priority.index(grade) can_exchange = True plate_priority = grade_to_plate_priorities.get(grade) plate_name = option[5:-2] if plate_name in plate_priority: plate_weight = plate_priority.index(plate_name) # Did weight update? # If not, then this choice given less priority # also set to absurd cost to avoid using if plate_weight == len(DEFAULT_PLATE_PRIORITY): item_weight = len(DEFAULT_ITEM_PRIORITY) can_exchange = False # Else normal item, check normally # Plates are skipped since only grade in priority if option in item_priority: item_weight = item_priority.index(option) can_exchange = True choices[f'{i + 1}'] = [ item_weight, plate_weight, i + 1, can_exchange, btn ] logger.info( f'Choice #{i + 1} - Name: {option:15}, Weight: {item_weight:3}, Exchangeable: {can_exchange}' ) return choices
def _commission_choose(self, daily, urgent, priority, time_limit=None): """ Args: daily (CommissionGroup): urgent (CommissionGroup): priority (dict): time_limit (datetime): Returns: CommissionGroup, CommissionGroup: Chosen daily commission, Chosen urgent commission """ # Count Commission commission = daily.commission + urgent.commission running_count = int( np.sum([1 for c in commission if c.status == 'running'])) logger.attr('Running', running_count) if running_count >= 4: return [], [] # Calculate priority commission = [ c for c in commission if c.valid and c.status == 'pending' ] comm_priority = [] for comm in commission: pri = priority[comm.genre] if comm.duration <= timedelta(hours=2): pri += priority['duration_shorter_than_2'] if comm.duration >= timedelta(hours=6): pri += priority['duration_longer_than_6'] if comm.expire: if comm.expire <= timedelta(hours=2): pri += priority['expire_shorter_than_2'] if comm.expire >= timedelta(hours=6): pri += priority['expire_longer_than_6'] comm_priority.append(pri) # Sort commission = list( np.array(commission)[np.argsort(comm_priority)])[::-1] # Select priority > 0 commission = [comm for comm in commission if priority[comm.genre] > 0] # Select within time_limit if time_limit: commission = [ comm for comm in commission if datetime.now() + comm.duration <= time_limit ] commission = commission[:4 - running_count] daily_choose, urgent_choose = CommissionGroup( self.config), CommissionGroup(self.config) for comm in commission: if comm in daily: daily_choose.commission.append(comm) if comm in urgent: urgent_choose.commission.append(comm) if daily_choose: logger.info('Choose daily commission') for comm in daily_choose: logger.info(comm) if urgent_choose: logger.info('Choose urgent commission') for comm in urgent_choose: logger.info(comm) return daily_choose, urgent_choose
def _guild_logistics_collect(self, skip_first_screenshot=True): """ Execute collect/accept screen transitions within logistics Args: skip_first_screenshot (bool): Returns: bool: If all guild logistics are check, no need to check them today. Pages: in: GUILD_LOGISTICS out: GUILD_LOGISTICS """ logger.hr('Guild logistics') logger.attr('Guild master/official', self.config.GuildOperation_SelectNewOperation) confirm_timer = Timer(1.5, count=3).start() exchange_interval = Timer(1.5, count=3) click_interval = Timer(0.5, count=1) supply_checked = False mission_checked = False exchange_checked = False exchange_count = 0 while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() # Handle all popups if self.handle_popup_confirm('GUILD_LOGISTICS'): confirm_timer.reset() exchange_interval.reset() continue if self.appear_then_click(GET_ITEMS_1, interval=2): confirm_timer.reset() exchange_interval.reset() continue if self._handle_guild_fleet_mission_start(): confirm_timer.reset() continue if self._is_in_guild_logistics(): # Supply if not supply_checked and self._guild_logistics_supply_available( ): if click_interval.reached(): self.device.click(GUILD_SUPPLY) click_interval.reset() confirm_timer.reset() continue else: supply_checked = True # Mission if not mission_checked and self._guild_logistics_mission_available( ): if click_interval.reached(): self.device.click(GUILD_MISSION) click_interval.reset() confirm_timer.reset() continue else: mission_checked = True # Exchange if not exchange_checked and exchange_interval.reached(): if self._guild_exchange(): confirm_timer.reset() exchange_interval.reset() exchange_count += 1 continue else: exchange_checked = True # End if not self.info_bar_count() and confirm_timer.reached(): break # if supply_checked and mission_checked and exchange_checked: # break if exchange_count >= 5: # If you run AL across days, then do guild exchange. # There will show an error, said time is not up. # Restart the game can't fix the problem. # To fix this, you have to enter guild logistics once, then restart. # If exchange for 5 times, this bug is considered to be triggered. logger.warning( 'Unable to do guild exchange, probably because the timer in game was bugged' ) raise GameBugError('Triggered guild logistics refresh bug') else: confirm_timer.reset() logger.info( f'supply_checked: {supply_checked}, mission_checked: {mission_checked}, ' f'exchange_checked: {exchange_checked}, mission_finished: {self._guild_logistics_mission_finished}' ) # Azur Lane receives new guild missions now # No longer consider `self._guild_logistics_mission_finished` as a check return all([supply_checked, mission_checked, exchange_checked])
def next(self): self.daily_current += 1 logger.info('Switch to %s' % str(self.daily_current)) self.device.click(DAILY_NEXT) self._wait_daily_switch() self.device.screenshot()
def handle_camera_outside_map(self, e): msg = str(e).split(':')[1].strip() logger.info(f'Camera outside map: {msg}') dic = {'to the left': (2, 0), 'to the right': (-2, 0), 'to the lower': (0, 2), 'to the upper': (0, -2)} self._map_swipe(dic[msg])
def daily_check(self, n=None): if not n: n = self.daily_current self.daily_checked.append(n) logger.info(f'Checked daily {n}') logger.info(f'Checked_list: {self.daily_checked}')
def clear_potential_boss(self): """ Method to step on all boss spawn point when boss not detected. """ grids = self.map.select(may_boss=True, is_accessible=True) logger.info('May boss: %s' % grids) battle_count = self.battle_count for grid in grids: logger.hr('Clear potential BOSS') grids = grids.sort('weight', 'cost') logger.info('Grid: %s' % str(grid)) self.fleet_boss.clear_chosen_enemy(grid) if self.battle_count > battle_count: logger.info('Boss guessing correct.') return True else: logger.info('Boss guessing incorrect.') grids = self.map.select(may_boss=True, is_accessible=False) logger.info('May boss: %s' % grids) for grid in grids: logger.hr('Clear potential BOSS roadblocks') fleet = 2 if self.config.FLEET_BOSS == 2 and self.config.FLEET_2 else 1 roadblocks = self.brute_find_roadblocks(grid, fleet=fleet) roadblocks = roadblocks.sort('weight', 'cost') logger.info('Grids: %s' % str(roadblocks)) self.fleet_1.clear_chosen_enemy(roadblocks[0]) return True return False
def _commission_start_click(self, comm, is_urgent=False): """ Start a commission. Args: comm (Commission): is_urgent (bool): Returns: bool: If success Pages: in: page_commission out: page_commission, info_bar, commission details unfold """ logger.hr('Commission start') self.interval_clear(COMMISSION_ADVICE) self.interval_clear(COMMISSION_START) comm_timer = Timer(7) count = 0 while 1: if comm_timer.reached(): self.device.click(comm.button) self.device.sleep(0.3) comm_timer.reset() if self.handle_popup_confirm('COMMISSION_START'): comm_timer.reset() pass if self.appear(COMMISSION_ADVICE, offset=(5, 20), interval=7): area = (0, 0, image_size(self.device.image)[0], COMMISSION_ADVICE.button[1]) current = self.commission_detect(area=area) if is_urgent: current.call('convert_to_night' ) # Convert extra commission to night if current.count >= 1: current = current[0] if current == comm: logger.info('Selected to the correct commission') else: logger.warning('Selected to the wrong commission') return False else: logger.warning( 'No selected commission detected, assuming correct') self.device.click(COMMISSION_ADVICE) count += 1 comm_timer.reset() pass if self.appear_then_click(COMMISSION_START, offset=(5, 20), interval=7): comm_timer.reset() pass # End if self.info_bar_count(): break if count >= 3: # Restart game and handle commission recommend bug. # After you click "Recommend", your ships appear and then suddenly disappear. # At the same time, the icon of commission is flashing. logger.warning('Triggered commission list flashing bug') raise GameStuckError('Triggered commission list flashing bug') self.device.screenshot() return True
def fleet_2_push_forward(self): """Move fleet 2 to the grid with lower grid.weight This will reduce the possibility of Boss fleet get stuck by enemies, especially for those one-way-road map from chapter 7 to chapter 9. Know more (in Chinese simplified): 9章道中战最小化路线规划 (Route Planning for battle minimization in chapter 9) https://wiki.biligame.com/blhx/9%E7%AB%A0%E9%81%93%E4%B8%AD%E6%88%98%E6%9C%80%E5%B0%8F%E5%8C%96%E8%B7%AF%E7%BA%BF%E8%A7%84%E5%88%92 Returns: bool: If pushed forward. """ if not self.config.FLEET_2: return False logger.info('Fleet_2 push forward') grids = self.map.select(is_land=False).sort('weight', 'cost') if self.map[self.fleet_2_location].weight <= grids[0].weight: logger.info('Fleet_2 pushed to destination') return False fleets = SelectedGrids( [self.map[self.fleet_1_location], self.map[self.fleet_2_location]]) grids = grids.select(is_accessible_2=True, is_sea=True).delete(fleets) if not grids: logger.info('Fleet_2 has no where to push') return False if self.map[self.fleet_2_location].weight <= grids[0].weight: logger.info('Fleet_2 pushed to closest grid') return False logger.info(f'Grids: {grids}') logger.info(f'Push forward: {grids[0]}') self.fleet_2.goto(grids[0]) self.fleet_1.switch_to() return True
def update(self, camera=True): """Update map image Args: camera: True to update camera position and perspective data. """ self.device.screenshot() if not camera: self.view.update(image=self.device.image) return True self._view_init() try: self.view.load(self.device.image) except (MapDetectionError, AttributeError) as e: if self.info_bar_count(): logger.info('Perspective error cause by info bar. Waiting.') self.handle_info_bar() return self.update(camera=camera) elif self.appear(GET_ITEMS_1): logger.warning('Items got. Trying handling mystery.') self.handle_mystery() return self.update(camera=camera) elif self.is_in_stage(): logger.warning('Image is in stage') raise CampaignEnd('Image is in stage') elif not self.appear(IN_MAP): logger.warning('Image to detect is not in_map') if self.appear_then_click(GAME_TIPS, offset=(20, 20)): logger.warning('Game tips found, retrying') self.device.screenshot() self.view.load(self.device.image) else: raise e elif 'Camera outside map' in str(e): string = str(e) logger.warning(string) x, y = string.split('=')[1].strip('() ').split(',') self._map_swipe((-int(x.strip()), -int(y.strip()))) else: raise e if self._prev_view is not None and np.linalg.norm( self._prev_swipe) > 0: if self.config.MAP_SWIPE_PREDICT: swipe = self._prev_view.predict_swipe(self.view) if swipe is not None: self._prev_swipe = swipe self.camera = tuple(np.add(self.camera, self._prev_swipe)) self._prev_view = None self._prev_swipe = None self.show_camera() if not self._correct_camera: self.show_camera() return False # Set camera position if self.view.left_edge: x = 0 + self.view.center_loca[0] elif self.view.right_edge: x = self.map.shape[0] - self.view.shape[0] + self.view.center_loca[ 0] else: x = self.camera[0] if self.view.lower_edge: y = 0 + self.view.center_loca[1] elif self.view.upper_edge: y = self.map.shape[1] - self.view.shape[1] + self.view.center_loca[ 1] else: y = self.camera[1] if self.camera != (x, y): logger.attr_align( 'camera_corrected', f'{location2node(self.camera)} -> {location2node((x, y))}') self.camera = (x, y) self.show_camera()
def main(ini_name=''): if not ini_name: ini_name = pyw_name ini_name = ini_name.lower() # Load default value from .ini file. config_file = f'./config/{ini_name}.ini' config = configparser.ConfigParser(interpolation=None) try: config.read_file(codecs.open(config_file, "r", "utf8")) except FileNotFoundError: logger.info('Config file not exists, copy from ./config/template.ini') shutil.copy('./config/template.ini', config_file) config.read_file(codecs.open(config_file, "r", "utf8")) config = update_config_from_template(config, file=config_file) event_folder = [ dic_eng_to_chi.get(f, f) for f in os.listdir('./campaign') if f.startswith('event_') ][::-1] saved_config = {} for opt, option in config.items(): for key, value in option.items(): key = dic_eng_to_chi.get(key, key) if value in dic_eng_to_chi: value = dic_eng_to_chi.get(value, value) if value == 'None': value = '' saved_config[key] = value def default(name): """Get default value in .ini file. Args: name (str): option, in chinese. Returns: str: Default value, in chinese. """ name = name.strip('-') return saved_config.get(name, '') def choice_list(total): return [str(index) for index in range(1, total + 1)] # Don't use checkbox in gooey, use drop box instead. # https://github.com/chriskiehl/Gooey/issues/148 # https://github.com/chriskiehl/Gooey/issues/485 parser = GooeyParser( description= f'AzurLaneAutoScript, An Azur Lane automation tool. Config: {config_file}' ) subs = parser.add_subparsers(help='commands', dest='command') # ==========出击设置========== setting_parser = subs.add_parser('出击设置') # 选择关卡 stage = setting_parser.add_argument_group('关卡设置', '需要运行一次来保存选项') stage.add_argument('--启用停止条件', default=default('--启用停止条件'), choices=['是', '否']) stage.add_argument('--使用周回模式', default=default('--使用周回模式'), choices=['是', '否']) stop = stage.add_argument_group('停止条件', '触发后不会马上停止会先完成当前出击, 不需要就填0') stop.add_argument('--如果出击次数大于', default=default('--如果出击次数大于'), help='会沿用先前设置, 完成出击将扣除次数, 直至清零') stop.add_argument( '--如果时间超过', default=default('--如果时间超过'), help='使用未来24小时内的时间, 会沿用先前设置, 触发后清零. 建议提前10分钟左右, 以完成当前出击. 格式 14:59') stop.add_argument('--如果石油低于', default=default('--如果石油低于')) stop.add_argument('--如果触发心情控制', default=default('--如果触发心情控制'), choices=['是', '否'], help='若是, 等待回复, 完成本次, 停止\n若否, 等待回复, 完成本次, 继续') stop.add_argument('--如果船舱已满', default=default('--如果船舱已满'), choices=['是', '否']) # 出击舰队 fleet = setting_parser.add_argument_group('出击舰队', '暂不支持备用道中队, 非活动图或周回模式会忽略步长设置') fleet.add_argument('--启用舰队控制', default=default('--启用舰队控制'), choices=['是', '否']) fleet.add_argument('--启用阵容锁定', default=default('--启用阵容锁定'), choices=['是', '否']) f1 = fleet.add_argument_group('道中队') f1.add_argument('--舰队编号1', default=default('--舰队编号1'), choices=['1', '2', '3', '4', '5', '6']) f1.add_argument('--舰队阵型1', default=default('--舰队阵型1'), choices=['单纵阵', '复纵阵', '轮形阵']) f1.add_argument('--舰队步长1', default=default('--舰队步长1'), choices=['1', '2', '3', '4', '5', '6']) f2 = fleet.add_argument_group('BOSS队') f2.add_argument('--舰队编号2', default=default('--舰队编号2'), choices=['不使用', '1', '2', '3', '4', '5', '6']) f2.add_argument('--舰队阵型2', default=default('--舰队阵型2'), choices=['单纵阵', '复纵阵', '轮形阵']) f2.add_argument('--舰队步长2', default=default('--舰队步长2'), choices=['1', '2', '3', '4', '5', '6']) f3 = fleet.add_argument_group('备用道中队') f3.add_argument('--舰队编号3', default=default('--舰队编号3'), choices=['不使用', '1', '2', '3', '4', '5', '6']) f3.add_argument('--舰队阵型3', default=default('--舰队阵型3'), choices=['单纵阵', '复纵阵', '轮形阵']) f3.add_argument('--舰队步长3', default=default('--舰队步长3'), choices=['1', '2', '3', '4', '5', '6']) f4 = fleet.add_argument_group('自律模式') f4.add_argument('--战斗自律模式', default=default('--战斗自律模式'), choices=['自律', '手操', '中路站桩']) # 潜艇设置 submarine = setting_parser.add_argument_group('潜艇设置', '仅支持: 不使用, 仅狩猎, 每战出击') submarine.add_argument('--舰队编号4', default=default('--舰队编号4'), choices=['不使用', '1', '2']) submarine.add_argument( '--潜艇出击方案', default=default('--潜艇出击方案'), choices=['不使用', '仅狩猎', '每战出击', '空弹出击', 'BOSS战出击', 'BOSS战BOSS出现后召唤']) # 心情控制 emotion = setting_parser.add_argument_group('心情控制') emotion.add_argument('--启用心情消耗', default=default('--启用心情消耗'), choices=['是', '否']) emotion.add_argument('--无视红脸出击警告', default=default('--无视红脸出击警告'), choices=['是', '否']) e1 = emotion.add_argument_group('道中队') e1.add_argument('--心情回复1', default=default('--心情回复1'), choices=['未放置于后宅', '后宅一楼', '后宅二楼']) e1.add_argument('--心情控制1', default=default('--心情控制1'), choices=['保持经验加成', '防止绿脸', '防止黄脸', '防止红脸']) e1.add_argument('--全员已婚1', default=default('--全员已婚1'), choices=['是', '否']) e2 = emotion.add_argument_group('BOSS队') e2.add_argument('--心情回复2', default=default('--心情回复2'), choices=['未放置于后宅', '后宅一楼', '后宅二楼']) e2.add_argument('--心情控制2', default=default('--心情控制2'), choices=['保持经验加成', '防止绿脸', '防止黄脸', '防止红脸']) e2.add_argument('--全员已婚2', default=default('--全员已婚2'), choices=['是', '否']) e3 = emotion.add_argument_group('备用道中队', '会在主队触发心情控制时使用') e3.add_argument('--心情回复3', default=default('--心情回复3'), choices=['未放置于后宅', '后宅一楼', '后宅二楼']) e3.add_argument('--心情控制3', default=default('--心情控制3'), choices=['保持经验加成', '防止绿脸', '防止黄脸', '防止红脸']) e3.add_argument('--全员已婚3', default=default('--全员已婚3'), choices=['是', '否']) # 血量平衡 hp = setting_parser.add_argument_group('血量控制', '需关闭舰队锁定才能生效') hp.add_argument('--启用血量平衡', default=default('--启用血量平衡'), choices=['是', '否']) hp.add_argument('--启用低血量撤退', default=default('--启用低血量撤退'), choices=['是', '否']) hp_balance = hp.add_argument_group('血量平衡', '') hp_balance.add_argument('--先锋血量平衡阈值', default=default('--先锋血量平衡阈值'), help='血量差值大于阈值时, 换位') hp_balance.add_argument('--先锋血量权重', default=default('--先锋血量权重'), help='先锋肉度有差别时应修改, 格式 1000,1000,1000') hp_add = hp.add_argument_group('紧急维修', '') hp_add.add_argument('--紧急维修单人阈值', default=default('--紧急维修单人阈值'), help='单人低于阈值时使用') hp_add.add_argument('--紧急维修全队阈值', default=default('--紧急维修全队阈值'), help='前排全部或后排全部低于阈值时使用') hp_withdraw = hp.add_argument_group('低血量撤退', '') hp_withdraw.add_argument('--低血量撤退阈值', default=default('--低血量撤退阈值'), help='任意一人血量低于阈值时, 撤退') # 退役选项 retire = setting_parser.add_argument_group('退役设置', '') retire.add_argument('--启用退役', default=default('--启用退役'), choices=['是', '否']) retire.add_argument('--使用一键退役', default=default('--使用一键退役'), choices=['是', '否']) retire.add_argument('--退役方案', default=default('--退役方案'), choices=['退役全部', '退役10个']) rarity = retire.add_argument_group('退役稀有度', '暂不支持舰种选择, 使用一键退役时忽略以下选项') rarity.add_argument('--退役白皮', default=default('--退役白皮'), choices=['是', '否'], help='N') rarity.add_argument('--退役蓝皮', default=default('--退役蓝皮'), choices=['是', '否'], help='R') rarity.add_argument('--退役紫皮', default=default('--退役紫皮'), choices=['是', '否'], help='SR') rarity.add_argument('--退役金皮', default=default('--退役金皮'), choices=['是', '否'], help='SSR') # 掉落记录 drop = setting_parser.add_argument_group('掉落记录', '保存掉落物品的截图, 启用后会放缓结算时的点击速度') drop.add_argument('--启用掉落记录', default=default('--启用掉落记录'), choices=['是', '否']) drop.add_argument('--掉落保存目录', default=default('--掉落保存目录')) clear = setting_parser.add_argument_group( '开荒模式', '未开荒地图会在完成后停止, 已开荒的地图会忽略选项, 无脑开就完事了') clear.add_argument('--启用开荒', default=default('--启用开荒'), choices=['是', '否']) clear.add_argument('--开荒停止条件', default=default('--开荒停止条件'), choices=['地图通关', '地图三星', '地图绿海']) clear.add_argument('--地图全清星星', default=default('--地图全清星星'), choices=['第一个', '第二个', '第三个', '不使用'], help='第几颗星星是击破所有敌舰') # ==========收菜设置========== reward_parser = subs.add_parser('收菜设置') reward_condition = reward_parser.add_argument_group( '触发条件', '需要运行一次来保存选项, 运行后会进入挂机收菜模式') reward_condition.add_argument('--启用收获', default=default('--启用收获'), choices=['是', '否']) reward_condition.add_argument('--收菜间隔', default=default('--收菜间隔'), choices=['20', '30', '60'], help='每隔多少分钟触发收菜') reward_oil = reward_parser.add_argument_group('石油物资', '') reward_oil.add_argument('--启用石油收获', default=default('--启用石油收获'), choices=['是', '否']) reward_oil.add_argument('--启用物资收获', default=default('--启用物资收获'), choices=['是', '否']) reward_mission = reward_parser.add_argument_group('任务奖励', '') reward_mission.add_argument('--启用任务收获', default=default('--启用任务收获'), choices=['是', '否']) reward_commission = reward_parser.add_argument_group('委托设置', '') reward_commission.add_argument('--启用委托收获', default=default('--启用委托收获'), choices=['是', '否']) reward_commission.add_argument('--委托时间限制', default=default('--委托时间限制'), help='忽略完成时间超过限制的委托, 格式: 23:30') priority1 = reward_commission.add_argument_group('委托耗时优先级', '') priority1.add_argument('--委托耗时小于2h', default=default('--委托耗时小于2h'), help='') priority1.add_argument('--委托耗时超过6h', default=default('--委托耗时超过6h'), help='') priority1.add_argument('--委托过期小于2h', default=default('--委托过期小于2h'), help='') priority1.add_argument('--委托过期大于6h', default=default('--委托过期大于6h'), help='') priority2 = reward_commission.add_argument_group('日常委托优先级', '') priority2.add_argument('--日常委托', default=default('--日常委托'), help='日常资源开发, 高阶战术研发') priority2.add_argument('--主要委托', default=default('--主要委托'), help='1200油/1000油委托') priority3 = reward_commission.add_argument_group('额外委托优先级', '') priority3.add_argument('--钻头类额外委托', default=default('--钻头类额外委托'), help='短距离航行训练, 近海防卫巡逻') priority3.add_argument('--部件类额外委托', default=default('--部件类额外委托'), help='矿脉护卫委托, 林木护卫委托') priority3.add_argument('--魔方类额外委托', default=default('--魔方类额外委托'), help='舰队高阶演习, 舰队护卫演习') priority3.add_argument('--石油类额外委托', default=default('--石油类额外委托'), help='小型油田开发, 大型油田开发') priority3.add_argument('--教材类额外委托', default=default('--教材类额外委托'), help='小型商船护卫, 大型商船护卫') priority4 = reward_commission.add_argument_group('紧急委托优先级', '') priority4.add_argument('--钻头类紧急委托', default=default('--钻头类紧急委托'), help='保卫运输部队, 歼灭敌精锐部队') priority4.add_argument('--部件类紧急委托', default=default('--部件类紧急委托'), help='支援维拉维拉岛, 支援恐班纳') priority4.add_argument('--魔方类紧急委托', default=default('--魔方类紧急委托'), help='解救商船, 敌袭') priority4.add_argument('--教材类紧急委托', default=default('--教材类紧急委托'), help='支援土豪尔岛, 支援萌岛') priority4.add_argument('--装备类紧急委托', default=default('--装备类紧急委托'), help='BIW装备运输, NYB装备研发') priority4.add_argument('--钻石类紧急委托', default=default('--钻石类紧急委托'), help='BIW要员护卫, NYB巡视护卫') priority4.add_argument('--观舰类紧急委托', default=default('--观舰类紧急委托'), help='小型观舰仪式, 同盟观舰仪式') reward_tactical = reward_parser.add_argument_group('战术学院', '只支持续技能书, 不支持学新技能') reward_tactical.add_argument('--启用战术学院收获', default=default('--启用战术学院收获'), choices=['是', '否']) reward_tactical.add_argument('--战术学院夜间时段', default=default('--战术学院夜间时段'), help='格式 23:30-06:30') reward_tactical.add_argument('--技能书稀有度', default=default('--技能书稀有度'), choices=['3', '2', '1'], help='最多使用T几的技能书\nT3是金书, T2是紫书, T1是蓝书') reward_tactical.add_argument('--技能书优先使用同类型', default=default('--技能书优先使用同类型'), choices=['是', '否'], help='选是, 优先使用有150%加成的\n选否, 优先使用同稀有度的技能书') reward_tactical.add_argument('--技能书夜间稀有度', default=default('--技能书夜间稀有度'), choices=['3', '2', '1']) reward_tactical.add_argument('--技能书夜间优先使用同类型', default=default('--技能书夜间优先使用同类型'), choices=['是', '否']) # ==========设备设置========== emulator_parser = subs.add_parser('设备设置') emulator = emulator_parser.add_argument_group( '模拟器', '需要运行一次来保存选项, 会检查游戏是否启动\n若启动了游戏, 触发一次收菜') emulator.add_argument('--设备', default=default('--设备'), help='例如 127.0.0.1:62001') emulator.add_argument('--包名', default=default('--包名'), help='') debug = emulator_parser.add_argument_group('调试设置', '') debug.add_argument('--出错时保存log和截图', default=default('--出错时保存log和截图'), choices=['是', '否']) debug.add_argument('--保存透视识别出错的图像', default=default('--保存透视识别出错的图像'), choices=['是', '否']) adb = emulator_parser.add_argument_group('ADB设置', '') adb.add_argument('--使用ADB截图', default=default('--使用ADB截图'), choices=['是', '否'], help='建议开启, 能减少CPU占用') adb.add_argument('--使用ADB点击', default=default('--使用ADB点击'), choices=['是', '否'], help='建议关闭, 能加快点击速度') adb.add_argument('--战斗中截图间隔', default=default('--战斗中截图间隔'), help='战斗中放慢截图速度, 降低CPU使用') # ==========每日任务========== daily_parser = subs.add_parser('每日任务困难演习') # 选择每日 daily = daily_parser.add_argument_group('选择每日', '每日任务, 演习, 困难图') daily.add_argument('--打每日', default=default('--打每日'), help='若当天有记录, 则跳过', choices=['是', '否']) daily.add_argument('--打困难', default=default('--打困难'), help='若当天有记录, 则跳过', choices=['是', '否']) daily.add_argument('--打演习', default=default('--打演习'), help='若在刷新后有记录, 则跳过', choices=['是', '否']) # 每日设置 daily_task = daily_parser.add_argument_group('每日设置', '不支持潜艇每日') daily_task.add_argument('--战术研修', default=default('--战术研修'), choices=['航空', '炮击', '雷击']) daily_task.add_argument('--斩首行动', default=default('--斩首行动'), choices=['第一个', '第二个', '第三个']) daily_task.add_argument('--商船护航', default=default('--商船护航'), choices=['第一个', '第二个', '第三个']) daily_task.add_argument('--海域突进', default=default('--海域突进'), choices=['第一个', '第二个', '第三个']) daily_task.add_argument('--每日舰队', default=default('--每日舰队'), choices=['1', '2', '3', '4', '5', '6']) daily_task.add_argument( '--每日舰队快速换装', default=default('--每日舰队快速换装'), help='打之前换装备, 打完后卸装备, 不需要就填0\n逗号分割, 例如 3, 1, 0, 1, 1, 0') # 困难设置 hard = daily_parser.add_argument_group('困难设置', '需要开启周回模式, 暂时仅支持 10-4') hard.add_argument('--困难地图', default=default('--困难地图'), help='比如 10-4') hard.add_argument('--困难舰队', default=default('--困难舰队'), choices=['1', '2']) hard.add_argument('--困难舰队快速换装', default=default('--困难舰队快速换装'), help='打之前换装备, 打完后卸装备, 不需要就填0\n逗号分割, 例如 3, 1, 0, 1, 1, 0') # 演习设置 exercise = daily_parser.add_argument_group('演习设置', '暂时仅支持经验最多') exercise.add_argument('--演习对手选择', default=default('--演习对手选择'), choices=['经验最多', '排名最前', '福利队'], help='暂时仅支持经验最多') exercise.add_argument('--演习次数保留', default=default('--演习次数保留'), help='暂时仅支持保留0个') exercise.add_argument('--演习尝试次数', default=default('--演习尝试次数'), help='每个对手的尝试次数, 打不过就换') exercise.add_argument('--演习SL阈值', default=default('--演习SL阈值'), help='HP<阈值时撤退') exercise.add_argument('--演习低血量确认时长', default=default('--演习低血量确认时长'), help='HP低于阈值后, 过一定时长才会撤退\n推荐 1.0 ~ 3.0') exercise.add_argument( '--演习快速换装', default=default('--演习快速换装'), help='打之前换装备, 打完后卸装备, 不需要就填0\n逗号分割, 例如 3, 1, 0, 1, 1, 0') # ==========每日活动图三倍PT========== event_ab_parser = subs.add_parser('每日活动图三倍PT') event_name = event_ab_parser.add_argument_group('选择活动', '') event_name.add_argument('--活动名称ab', default=default('--活动名称ab'), choices=event_folder, help='例如 event_20200326_cn') # ==========主线图========== main_parser = subs.add_parser('主线图') # 选择关卡 stage = main_parser.add_argument_group('选择关卡', '主线图出击, 目前仅支持前六章和7-2') stage.add_argument('--主线地图出击', default=default('--主线地图出击'), help='例如 7-2') # ==========活动图========== event_parser = subs.add_parser('活动图') description = """ 支持「穹顶下的圣咏曲」(event_20200521_cn), 针对D1D3有优化 D3第一次进图和100%通关时均有剧情战斗, 会导致报错 出击未优化关卡或地图未达到安全海域时, 使用开荒模式运行(较慢) """ event = event_parser.add_argument_group( '选择关卡', '\n'.join([line.strip() for line in description.strip().split('\n')])) event.add_argument('--活动地图', default=default('--活动地图'), choices=[ 'a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3', 'd1', 'd2', 'd3' ], help='例如 d3') event.add_argument('--sp地图', default=default('--sp地图'), choices=['sp1', 'sp2', 'sp3'], help='例如 sp3') event.add_argument('--活动名称', default=default('--活动名称'), choices=event_folder, help='例如 event_20200312_cn') # ==========半自动========== semi_parser = subs.add_parser('半自动辅助点击') semi = semi_parser.add_argument_group('半自动模式', '手动选敌, 自动结算, 用于出击未适配的图') semi.add_argument('--进图准备', default=default('--进图准备'), help='', choices=['是', '否']) semi.add_argument('--跳过剧情', default=default('--跳过剧情'), help='注意, 这会自动确认所有提示框, 包括红脸出击', choices=['是', '否']) # ==========7-2三战拣垃圾========== c_7_2_parser = subs.add_parser('7-2三战拣垃圾') c_7_2 = c_7_2_parser.add_argument_group('7-2三战拣垃圾', '') c_7_2.add_argument('--BOSS队踩A3', default=default('--BOSS队踩A3'), choices=['是', '否'], help='A3有敌人就G3, C3, E3') # ==========12-2打中型练级========== c_12_2_parser = subs.add_parser('12-2打中型练级') c_12_2 = c_12_2_parser.add_argument_group('12-2索敌设置', '') c_12_2.add_argument('--大型敌人忍耐', default=default('--大型敌人忍耐'), choices=['0', '1', '2', '10'], help='最多打多少战大型敌人, 不挑敌人选10') # ==========12-4打大型练级========== c_12_4_parser = subs.add_parser('12-4打大型练级') c_12_4 = c_12_4_parser.add_argument_group('12-4索敌设置', '需保证队伍有一定强度') c_12_4.add_argument('--非大型敌人进图忍耐', default=default('--非大型敌人进图忍耐'), choices=['0', '1', '2'], help='忍受进场多少战没有大型') c_12_4.add_argument('--非大型敌人撤退忍耐', default=default('--非大型敌人撤退忍耐'), choices=['0', '1', '2', '10'], help='没有大型之后还会打多少战, 不挑敌人选10') c_12_4.add_argument('--拣弹药124', default=default('--拣弹药124'), choices=['2', '3', '4', '5'], help='多少战后拣弹药') args = parser.parse_args() # Convert option from chinese to english. out = {} for key, value in vars(args).items(): key = dic_chi_to_eng.get(key, key) value = dic_chi_to_eng.get(value, value) out[key] = value args = out # Update option to .ini file. command = args['command'].capitalize() config['Command']['command'] = command for key, value in args.items(): config[command][key] = str(value) config.write(codecs.open(config_file, "w+", "utf8")) # Call AzurLaneAutoScript alas = AzurLaneAutoScript(ini_name=ini_name) alas.run(command=command)
def fleet_preparation(self): """Change fleets. Returns: bool: True if changed. """ logger.info( f'Using fleet: {[self.config.Fleet_Fleet1, self.config.Fleet_Fleet2, self.config.Submarine_Fleet]}' ) if self.map_fleet_checked: return False self.map_is_hard_mode = self.get_map_is_hard_mode() if self.map_is_hard_mode: logger.info('Hard Campaign. No fleet preparation') return False fleet_1 = FleetOperator(choose=FLEET_1_CHOOSE, bar=FLEET_1_BAR, clear=FLEET_1_CLEAR, in_use=FLEET_1_IN_USE, main=self) fleet_2 = FleetOperator(choose=FLEET_2_CHOOSE, bar=FLEET_2_BAR, clear=FLEET_2_CLEAR, in_use=FLEET_2_IN_USE, main=self) submarine = FleetOperator(choose=SUBMARINE_CHOOSE, bar=SUBMARINE_BAR, clear=SUBMARINE_CLEAR, in_use=SUBMARINE_IN_USE, main=self) # Submarine. if submarine.allow(): if self.config.Submarine_Fleet: submarine.ensure_to_be(self.config.Submarine_Fleet) else: submarine.clear() # No need, this may clear FLEET_2 by mistake, clear FLEET_2 in map config. # if not fleet_2.allow(): # self.config.FLEET_2 = 0 if self.config.Fleet_Fleet2: # Using both fleets. # Force to set it again. # Fleets may reversed, because AL no longer treat the fleet with smaller index as first fleet fleet_2.clear() fleet_1.ensure_to_be(self.config.Fleet_Fleet1) fleet_2.ensure_to_be(self.config.Fleet_Fleet2) else: # Not using fleet 2. if fleet_2.allow(): fleet_2.clear() fleet_1.ensure_to_be(self.config.Fleet_Fleet1) # Check if submarine is empty again. if submarine.allow(): if self.config.Submarine_Fleet: pass else: submarine.clear() return True
def ui_get_current_page(self, skip_first_screenshot=True): """ Args: skip_first_screenshot: Returns: Page: """ logger.info('UI get current page') @run_once def app_check(): if not self.device.app_is_running(): raise GameNotRunningError('Game not running') @run_once def minicap_check(): if self.config.Emulator_ControlMethod == 'uiautomator2': self.device.uninstall_minicap() timeout = Timer(5, count=10).start() while 1: if skip_first_screenshot: skip_first_screenshot = False if not hasattr(self.device, 'image') or self.device.image is None: self.device.screenshot() else: self.device.screenshot() # End if timeout.reached(): break # Known pages for page in self.ui_pages: if page.check_button is None: continue if self.ui_page_appear(page=page): logger.attr('UI', page.name) self.ui_current = page return page # Unknown page but able to handle logger.info('Unknown ui page') if self.appear_then_click(GOTO_MAIN, offset=(20, 20), interval=2) or self.ui_additional(): timeout.reset() continue app_check() minicap_check() # Unknown page, need manual switching logger.warning('Unknown ui page') logger.attr('EMULATOR__SCREENSHOT_METHOD', self.config.Emulator_ScreenshotMethod) logger.attr('EMULATOR__CONTROL_METHOD', self.config.Emulator_ControlMethod) logger.attr('SERVER', self.config.SERVER) logger.warning('Starting from current page is not supported') logger.warning( f'Supported page: {[str(page) for page in self.ui_pages]}') logger.warning( f'Supported page: Any page with a "HOME" button on the upper-right' ) logger.critical( 'Please switch to a supported page before starting Alas') raise GamePageUnknownError
def research_receive(self, skip_first_screenshot=True, save_get_items=False): logger.info('Research receive') executed = False while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot_interval_set(0.5) self.device.screenshot() if self.appear(RESEARCH_CHECK, interval=10): if self._research_has_finished_at(RESEARCH_STATUS[self._research_finished_index]): if save_get_items: self.device.save_screenshot('research_project', interval=0, to_base_folder=True) self.device.click(RESEARCH_ENTRANCE[self._research_finished_index]) continue if self.appear(GET_ITEMS_1, interval=5): self.wait_until_get_items_stable() logger.info('Get items 1 stabled') if not self.appear(GET_ITEMS_1, interval=0): continue self.device.sleep(2) if save_get_items: self.device.screenshot() self.device.save_screenshot('research_items', to_base_folder=True) self.device.click(GET_ITEMS_RESEARCH_SAVE) executed = True continue if self.appear(GET_ITEMS_2, interval=5): self.wait_until_get_items_stable() logger.info('Get items 2 stabled') if not self.appear(GET_ITEMS_2, interval=0): continue self.device.sleep(2) if save_get_items: self.device.screenshot() self.device.save_screenshot('research_items', to_base_folder=True) self.device.click(GET_ITEMS_RESEARCH_SAVE) executed = True continue if self.appear(GET_ITEMS_3, interval=5): self.wait_until_get_items_stable() logger.info('Get items 3 stabled') if not self.appear(GET_ITEMS_3, interval=0): continue self.device.sleep(3) if save_get_items: self.device.screenshot() self.device.save_screenshot('research_items', to_base_folder=True) self.device.swipe((0, 250), box=ITEMS_3_SWIPE.area, random_range=(-10, -10, 10, 10), padding=0) self.device.sleep(2) self.device.screenshot() self.device.save_screenshot('research_items', interval=0, to_base_folder=True) self.device.click(GET_ITEMS_RESEARCH_SAVE) executed = True continue # End if executed and self._in_research(): self.ensure_research_stable() break self.device.screenshot_interval_set(0.1)
def run(self, name, folder='campaign_main', total=0): """ Args: name (str): Name of .py file. folder (str): Name of the file folder under campaign. total (int): """ name, folder = self.handle_stage_name(name, folder) self.load_campaign(name, folder=folder) self.run_count = 0 while 1: if self.handle_app_restart(): self.campaign.fleet_checked_reset() if self.handle_reward(): self.campaign.fleet_checked_reset() if self.config.GUILD_POPUP_TRIGGERED: self.ensure_auto_search_exit() self.handle_guild( ) # Will reset self.config.GUILD_POPUP_TRIGGERED afterwards self.campaign.config.GUILD_POPUP_TRIGGERED = False self.campaign.fleet_checked_reset() # End if total and self.run_count == total: break # Log logger.hr(name, level=1) if self.config.STOP_IF_COUNT_GREATER_THAN > 0: logger.info( f'Count: [{self.run_count}/{self.config.STOP_IF_COUNT_GREATER_THAN}]' ) else: logger.info(f'Count: [{self.run_count}]') # UI ensure self.device.screenshot() self.campaign.device.image = self.device.image if self.campaign.is_in_map(): logger.info('Already in map, skip ensure_campaign_ui.') elif self.campaign.is_in_auto_search_menu(): logger.info('In auto search menu, skip ensure_campaign_ui.') else: self.campaign.ensure_campaign_ui( name=self.stage, mode=self.config.CAMPAIGN_MODE if self.config.COMMAND.lower() == 'main' else 'normal') if self.config.ENABLE_REWARD and self.commission_notice_show_at_campaign( ): logger.info('Commission notice found') if self.reward(): self.campaign.fleet_checked_reset() continue # End if self.triggered_stop_condition( oil_check=not self.campaign.is_in_auto_search_menu()): self.campaign.ensure_auto_search_exit() break # Run try: self.campaign.run() except ScriptEnd as e: logger.hr('Script end') logger.info(str(e)) break # After run self.run_count += 1 self.config.GUILD_POPUP_TRIGGERED = self.campaign.config.GUILD_POPUP_TRIGGERED if self.config.STOP_IF_COUNT_GREATER_THAN > 0: count = self.config.STOP_IF_COUNT_GREATER_THAN - self.run_count count = 0 if count < 0 else count self.config.config.set('Setting', 'if_count_greater_than', str(count)) self.config.save() # One-time stage limit if self.campaign.config.MAP_IS_ONE_TIME_STAGE: if self.run_count >= 1: logger.hr('Triggered one-time stage limit') break self.campaign.ensure_auto_search_exit()
def show_camera(self): logger.info(' Camera: %s' % location2node(self.camera))
def find_current_fleet(self): logger.hr('Find current fleet') if not self.config.POOR_MAP_DATA: fleets = self.map.select(is_fleet=True, is_spawn_point=True) else: fleets = self.map.select(is_fleet=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.') if self.config.POOR_MAP_DATA and not self.map.select( is_spawn_point=True): self.fleet_1 = fleets[0].location elif self.map.select(is_spawn_point=True).count == 2: logger.info('Predict fleet to be spawn point') another = self.map.select(is_spawn_point=True).delete( SelectedGrids([fleets[0]]))[0] if fleets[0].is_current_fleet: self.fleet_1 = fleets[0].location self.fleet_2 = another.location else: self.fleet_1 = another.location self.fleet_2 = fleets[0].location else: cover = self.map.grid_covered(fleets[0], location=[(0, -1)]) if fleets[0].is_current_fleet and len( cover) and cover[0].is_spawn_point: self.fleet_1 = fleets[0].location self.fleet_2 = cover[0].location else: self.find_all_fleets() elif count == 2: current = self.map.select(is_current_fleet=True) if current.count == 1: self.fleet_1 = current[0].location self.fleet_2 = fleets.delete(current)[0].location else: 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.') fleets = self.map.select(is_current_fleet=True) if fleets.count: self.fleet_1 = fleets[0].location 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