コード例 #1
0
class InfoHandler(ModuleBase):
    """
    Class to handle all kinds of message.
    """
    """
    Info bar
    """

    def info_bar_count(self):
        if self.appear(INFO_BAR_3):
            return 3
        elif self.appear(INFO_BAR_2):
            return 2
        elif self.appear(INFO_BAR_1):
            return 1
        else:
            return 0

    def handle_info_bar(self):
        if self.info_bar_count():
            self.wait_until_disappear(INFO_BAR_1)
            return True
        else:
            return False

    def ensure_no_info_bar(self, timeout=0.6):
        timeout = Timer(timeout)
        timeout.start()
        while 1:
            self.device.screenshot()
            self.handle_info_bar()

            if timeout.reached():
                break

    """
    Popup info
    """
    _popup_offset = (3, 30)

    def handle_popup_confirm(self, name=''):
        if self.appear(POPUP_CANCEL, offset=self._popup_offset) \
                and self.appear(POPUP_CONFIRM, offset=self._popup_offset, interval=2):
            POPUP_CONFIRM.name = POPUP_CONFIRM.name + '_' + name
            self.device.click(POPUP_CONFIRM)
            POPUP_CONFIRM.name = POPUP_CONFIRM.name[:-len(name) - 1]
            return True
        else:
            return False

    def handle_popup_cancel(self, name=''):
        if self.appear(POPUP_CONFIRM, offset=self._popup_offset) \
                and self.appear(POPUP_CANCEL, offset=self._popup_offset, interval=2):
            POPUP_CANCEL.name = POPUP_CANCEL.name + '_' + name
            self.device.click(POPUP_CANCEL)
            POPUP_CANCEL.name = POPUP_CANCEL.name[:-len(name) - 1]
            return True
        else:
            return False

    def handle_popup_single(self, name=''):
        if self.appear(GET_MISSION, offset=self._popup_offset, interval=2):
            prev_name = GET_MISSION.name
            GET_MISSION.name = POPUP_CONFIRM.name + '_' + name
            self.device.click(GET_MISSION)
            GET_MISSION.name = prev_name
            return True

        return False

    def handle_urgent_commission(self, save_get_items=None):
        """
        Args:
            save_get_items (bool):

        Returns:
            bool:
        """
        if save_get_items is None:
            save_get_items = self.config.ENABLE_SAVE_GET_ITEMS

        appear = self.appear(GET_MISSION, offset=True, interval=2)
        if appear:
            logger.info('Get urgent commission')
            if save_get_items:
                self.handle_info_bar()
                self.device.save_screenshot('get_mission')
            self.device.click(GET_MISSION)
        return appear

    def handle_combat_low_emotion(self):
        if not self.config.IGNORE_LOW_EMOTION_WARN:
            return False

        return self.handle_popup_confirm('IGNORE_LOW_EMOTION')

    def handle_use_data_key(self):
        if not self.config.USE_DATA_KEY:
            return False

        if not self.appear(POPUP_CONFIRM, offset=self._popup_offset) \
                and not self.appear(POPUP_CANCEL, offset=self._popup_offset, interval=2):
            return False

        if self.appear(USE_DATA_KEY, offset=(20, 20)):
            self.device.click(USE_DATA_KEY_NOTIFIED)
            self.device.sleep((0.5, 0.8))
            return self.handle_popup_confirm('USE_DATA_KEY')

        return False

    """
    Guild popup info
    """
    def handle_guild_popup_confirm(self):
        if self.appear(GUILD_POPUP_CANCEL, offset=self._popup_offset) \
                and self.appear(GUILD_POPUP_CONFIRM, offset=self._popup_offset, interval=2):
            self.device.click(GUILD_POPUP_CONFIRM)
            return True

        return False

    def handle_guild_popup_cancel(self):
        if self.appear(GUILD_POPUP_CONFIRM, offset=self._popup_offset) \
                and self.appear(GUILD_POPUP_CANCEL, offset=self._popup_offset, interval=2):
            self.device.click(GUILD_POPUP_CANCEL)
            return True

        return False

    """
    Mission popup info
    """
    def handle_mission_popup_go(self):
        if self.appear(MISSION_POPUP_ACK, offset=self._popup_offset) \
                and self.appear(MISSION_POPUP_GO, offset=self._popup_offset, interval=2):
            self.device.click(MISSION_POPUP_GO)
            return True

        return False

    def handle_mission_popup_ack(self):
        if self.appear(MISSION_POPUP_GO, offset=self._popup_offset) \
                and self.appear(MISSION_POPUP_ACK, offset=self._popup_offset, interval=2):
            self.device.click(MISSION_POPUP_ACK)
            return True

        return False

    """
    Story
    """
    story_popup_timout = Timer(10, count=20)
    map_has_fast_forward = False  # Will be override in fast_forward.py

    # Area to detect the options, should include at least 3 options.
    _story_option_area = (730, 188, 1140, 480)
    # Background color of the left part of the option.
    _story_option_color = (99, 121, 156)
    _story_option_timer = Timer(2)

    def _story_option_buttons(self):
        """
        Returns:
            list[Button]: List of story options, from upper to bottom. If no option found, return an empty list.
        """
        image = color_similarity_2d(self.image_area(self._story_option_area), color=self._story_option_color) > 225
        x_count = np.where(np.sum(image, axis=0) > 40)[0]
        if not len(x_count):
            return []
        x_min, x_max = np.min(x_count), np.max(x_count)

        parameters = {
            # Option is 300`320px x 50~52px.
            'height': 280,
            'width': 45,
            'distance': 50,
            # Chooses the relative height at which the peak width is measured as a percentage of its prominence.
            # 1.0 calculates the width of the peak at its lowest contour line,
            # while 0.5 evaluates at half the prominence height.
            # Must be at least 0.
            'rel_height': 5,
        }
        y_count = np.sum(image, axis=1)
        peaks, properties = signal.find_peaks(y_count, **parameters)
        buttons = []
        total = len(peaks)
        if not total:
            return []
        for n, bases in enumerate(zip(properties['left_bases'], properties['right_bases'])):
            area = (x_min, bases[0], x_max, bases[1])
            area = area_pad(area_offset(area, offset=self._story_option_area[:2]), pad=5)
            buttons.append(
                Button(area=area, color=self._story_option_color, button=area, name=f'STORY_OPTION_{n + 1}_OF_{total}'))

        return buttons

    def story_skip(self):
        if self.story_popup_timout.started() and not self.story_popup_timout.reached():
            if self.handle_popup_confirm('STORY_SKIP'):
                self.story_popup_timout = Timer(10)
                self.interval_reset(STORY_SKIP)
                self.interval_reset(STORY_LETTERS_ONLY)
                return True
        if self.appear(STORY_LETTER_BLACK) and self.appear_then_click(STORY_LETTERS_ONLY, offset=True, interval=2):
            self.story_popup_timout.reset()
            return True
        if self._story_option_timer.reached() and self.appear(STORY_SKIP, offset=True, interval=0):
            options = self._story_option_buttons()
            if len(options):
                self.device.click(options[0])
                self._story_option_timer.reset()
                self.story_popup_timout.reset()
                self.interval_reset(STORY_SKIP)
                self.interval_reset(STORY_LETTERS_ONLY)
                return True
        if self.appear_then_click(STORY_SKIP, offset=True, interval=2):
            self.story_popup_timout.reset()
            return True
        if self.appear_then_click(GAME_TIPS, offset=(20, 20), interval=2):
            self.story_popup_timout.reset()
            return True

        return False

    def handle_story_skip(self):
        if self.map_has_fast_forward:
            return False

        return self.story_skip()

    def ensure_no_story(self, skip_first_screenshot=True):
        logger.info('Ensure no story')
        story_timer = Timer(3, count=6).start()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.story_skip():
                story_timer.reset()

            if story_timer.reached():
                break

    def handle_map_after_combat_story(self):
        if not self.config.MAP_HAS_MAP_STORY:
            return False

        self.ensure_no_story()
コード例 #2
0
    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():
                self.map_get_info()
                self.handle_fast_forward()
                if self.handle_map_stop():
                    self.enter_map_cancel()
                    raise ScriptEnd(
                        f'Reach condition: {self.config.STOP_IF_MAP_REACH}')
                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.appear_then_click(button):
                campaign_timer.reset()
                continue

            # End
            if self.handle_in_map_with_enemy_searching():
                self.handle_map_after_combat_story()
                break

        return True
コード例 #3
0
    def os_mission_enter(self, skip_first_screenshot=True):
        """
        Enter mission list and claim mission reward.

        Pages:
            in: MISSION_ENTER
            out: MISSION_CHECK
        """
        logger.info('OS mission enter')
        confirm_timer = Timer(2, count=6).start()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.appear_then_click(MISSION_ENTER,
                                      offset=(200, 5),
                                      interval=5):
                confirm_timer.reset()
                continue
            if self.appear_then_click(MISSION_FINISH,
                                      offset=(20, 20),
                                      interval=2):
                confirm_timer.reset()
                continue
            if self.handle_popup_confirm('MISSION_FINISH'):
                confirm_timer.reset()
                continue
            if self.handle_map_get_items():
                confirm_timer.reset()
                continue
            if self.handle_info_bar():
                confirm_timer.reset()
                continue

            # End
            if self.appear(MISSION_CHECK, offset=(20, 20)) \
                    and not self.appear(MISSION_FINISH, offset=(20, 20)) \
                    and not self.appear(MISSION_CHECKOUT, offset=(20, 20)):
                # No mission found, wait to confirm. Missions might not be loaded so fast.
                if confirm_timer.reached():
                    break
            elif self.appear(MISSION_CHECK, offset=(20, 20)) \
                    and self.appear(MISSION_CHECKOUT, offset=(20, 20)):
                # Found one mission.
                break
            else:
                confirm_timer.reset()
コード例 #4
0
    def _enhance_choose(self, skip_first_screenshot=True):
        """
        Pages:
            in: page_ship_enhance, without info_bar
            out: EQUIP_CONFIRM
        """
        end_activate_timer = Timer(2, count=2) if self.config.DEVICE_CONTROL_METHOD == 'minitouch' else Timer(2, count=1)
        trapped_timer = Timer(15, count=3).start()
        trapped = False
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.appear(EQUIP_CONFIRM, offset=(30, 30)):
                return True

            if not end_activate_timer.reached_and_reset():
                continue

            ensured = self.equip_sidebar_ensure(index=4)
            if ensured:
                self.wait_until_appear(ENHANCE_RECOMMEND, offset=(5, 5), skip_first_screenshot=True)
            else:
                continue

            status = color_bar_percentage(self.device.image, area=ENHANCE_RELOAD.area, prev_color=(231, 178, 74))
            logger.attr('Reload_enhanced', f'{int(status * 100)}%')
            choose = np.sum(np.array(self.device.image.crop(ENHANCE_FILLED.area)) > 200) > 100

            if trapped or self.info_bar_count():
                if status > 0.98:
                    logger.info('Fully enhanced for this ship')
                    swiped = self.equip_view_next(check_button=ENHANCE_RECOMMEND)
                    self.ensure_no_info_bar()
                    if not swiped:
                        return False
                    trapped_timer.reset()
                    trapped = False
                    continue
                else:
                    if choose:
                        logger.info('Unable to enhance this ship')
                        swiped = self.equip_view_next(check_button=ENHANCE_RECOMMEND)
                        self.ensure_no_info_bar()
                        if not swiped:
                            return False
                        trapped_timer.reset()
                        trapped = False
                        continue
                    else:
                        logger.info('Enhancement material exhausted')
                        return False

            if not trapped_timer.reached_and_reset() and self.appear_then_click(ENHANCE_RECOMMEND, offset=(5, 5), interval=2):
                self.device.sleep(0.3)
                self.device.click(ENHANCE_CONFIRM)
            else:
                logger.warning('Current status appears trapped, will force stat gauge check')
                trapped = True
コード例 #5
0
    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, interval=5):
                confirm_timer.reset()
                close_timer.reset()
                continue

            if self.appear(GUILD_DISPATCH_EMPTY, interval=5):
                self.device.click(GUILD_DISPATCH_RECOMMEND)
                self.device.sleep((0.5, 0.8))
                self.device.click(GUILD_DISPATCH_FLEET)
                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
                add_timer.reset()

            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()
                close_timer.reset()
コード例 #6
0
ファイル: fort.py プロジェクト: nEEtdo0d/AzurLaneAutoScript
    def meow_chores(self, skip_first_screenshot=True):
        """
        Loop through all chore mechanics to
        get fort xp points

        Args:
            skip_first_screenshot (bool): Skip first
            screen shot or not

        Pages:
            in: MEOWFFICER_FORT
            out: MEOWFFICER_FORT
        """
        self.interval_clear(GET_ITEMS_1)
        check_timer = Timer(1, count=2)
        confirm_timer = Timer(1.5, count=4).start()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.appear(MEOWFFICER_FORT_GET_XP_1) or \
                    self.appear(MEOWFFICER_FORT_GET_XP_2):
                check_timer.reset()
                confirm_timer.reset()
                continue

            if self.appear(GET_ITEMS_1, offset=5, interval=3):
                self.device.click(MEOWFFICER_FORT_CHECK)
                check_timer.reset()
                confirm_timer.reset()
                continue

            if check_timer.reached():
                is_chore = self.image_color_count(MEOWFFICER_FORT_CHORE,
                                                  color=(247, 186, 90),
                                                  threshold=235,
                                                  count=50)
                check_timer.reset()
                if is_chore:
                    self.device.click(MEOWFFICER_FORT_CHORE)
                    confirm_timer.reset()
                    continue

            # End
            if self.appear(MEOWFFICER_FORT_CHECK, offset=(20, 20)):
                if confirm_timer.reached():
                    break
            else:
                confirm_timer.reset()
コード例 #7
0
ファイル: fleet.py プロジェクト: zcxiong7/AzurLaneAutoScript
    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()
コード例 #8
0
    def meow_get(self, skip_first_screenshot=True):
        """
        Transition through all the necessary screens
        to acquire each trained meowfficer
        Animation is waited for as the amount can vary
        Only gold variant meowfficer will prompt for
        confirmation

        Args:
            skip_first_screenshot (bool): Skip first
            screen shot or not

        Pages:
            in: MEOWFFICER_GET_CHECK
            out: MEOWFFICER_TRAIN
        """
        # Loop through possible screen transitions
        confirm_timer = Timer(1.5, count=3).start()
        count = 0
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.handle_meow_popup_dismiss():
                confirm_timer.reset()
                continue
            if self.appear(MEOWFFICER_GET_CHECK, offset=(40, 40), interval=3):
                count += 1
                logger.attr('Meow_get', count)
                with self.stat.new(genre="meowfficer_talent",
                                   method=self.config.
                                   DropRecord_MeowfficerTalent) as drop:
                    drop.add(self.device.image)
                    list_talent_btn, special_talent = self._get_meow_talent_grid(
                    )
                    if self.config.DropRecord_MeowfficerTalent != 'do_not':
                        self._meow_talent_cap_handle(list_talent_btn, drop)
                    if self.appear(MEOWFFICER_GOLD_CHECK, offset=(40, 40)):
                        if not self.config.MeowfficerTrain_RetainTalentedGold or not special_talent:
                            self._meow_skip_lock()
                            skip_first_screenshot = True
                            confirm_timer.reset()
                            continue
                        self._meow_apply_lock()

                    if self.appear(MEOWFFICER_PURPLE_CHECK, offset=(40, 40)):
                        if self.config.MeowfficerTrain_RetainTalentedPurple and special_talent:
                            self._meow_apply_lock()

                    # Susceptible to exception when collecting multiple
                    # Mitigate by popping click_record
                    self.device.click(MEOWFFICER_TRAIN_CLICK_SAFE_AREA)
                    self.device.click_record.pop()
                    confirm_timer.reset()
                    self.interval_reset(MEOWFFICER_GET_CHECK)
                    continue

            # End
            if self.appear(MEOWFFICER_TRAIN_START, offset=(20, 20)):
                if confirm_timer.reached():
                    break
            else:
                confirm_timer.reset()
コード例 #9
0
    def battle_pass_receive(self, skip_first_screenshot=True):
        """
        Returns:
            bool: If received.

        Pages:
            in: page_battle_pass
            out: page_battle_pass
        """
        logger.hr('Battle pass receive', level=1)
        self.battle_status_click_interval = 2
        confirm_timer = Timer(1, count=3).start()
        received = False
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.appear_then_click(REWARD_RECEIVE,
                                      offset=(20, 20),
                                      interval=2):
                confirm_timer.reset()
                continue
            if self.appear_then_click(REWARD_RECEIVE_SP,
                                      offset=(20, 20),
                                      interval=2):
                confirm_timer.reset()
                continue
            if self.handle_battle_pass_popup():
                confirm_timer.reset()
                continue
            if self.handle_popup_confirm('BATTLE_PASS'):
                # Lock new META ships
                confirm_timer.reset()
                continue
            if self.handle_get_items():
                received = True
                confirm_timer.reset()
                continue
            if self.handle_get_ship():
                received = True
                confirm_timer.reset()
                continue

            # End
            if self.appear(BATTLE_PASS_CHECK,
                           offset=(20, 20)) and not self.appear(
                               REWARD_RECEIVE, offset=(20, 20)):
                if confirm_timer.reached():
                    break
            else:
                confirm_timer.reset()

        return received
コード例 #10
0
    def wait_until_walk_stable(self,
                               confirm_timer=None,
                               skip_first_screenshot=False,
                               walk_out_of_step=True,
                               drop=None):
        """
        Wait until homo_loca stabled.
        DETECTION_BACKEND must be 'homography'.

        Args:
            confirm_timer (Timer):
            skip_first_screenshot (bool):
            walk_out_of_step (bool): If catch walk_out_of_step error.
                Default to True, use False in abyssal zones.
            drop (DropImage):

        Returns:
            str: Things that fleet met on its way,
                'event', 'search', 'akashi', 'combat',
                or their combinations like 'event_akashi', 'event_combat',
                or an empty string '' if nothing met.

        Raises:
            MapWalkError: If unable to goto such grid.
        """
        logger.hr('Wait until walk stable')
        record = None
        enemy_searching_appear = False
        self.device.screenshot_interval_set(0.35)
        if confirm_timer is None:
            confirm_timer = Timer(0.8, count=2)
        result = set()

        confirm_timer.reset()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            # Map event
            if self.handle_map_event(drop=drop):
                confirm_timer.reset()
                result.add('event')
                continue
            if self.handle_retirement():
                confirm_timer.reset()
                continue
            if self.handle_walk_out_of_step():
                if walk_out_of_step:
                    raise MapWalkError('walk_out_of_step')
                else:
                    continue

            # Accident click
            if self.is_in_globe():
                self.os_globe_goto_map()
                confirm_timer.reset()
                continue
            if self.is_in_storage():
                self.storage_quit()
                confirm_timer.reset()
                continue
            if self.is_in_os_mission():
                self.os_mission_quit()
                confirm_timer.reset()
                continue
            if self.handle_os_game_tips():
                confirm_timer.reset()
                continue

            # Enemy searching
            if not enemy_searching_appear and self.enemy_searching_appear():
                enemy_searching_appear = True
                confirm_timer.reset()
                continue
            else:
                if enemy_searching_appear:
                    self.handle_enemy_flashing()
                    self.device.sleep(0.3)
                    logger.info('Enemy searching appeared.')
                    enemy_searching_appear = False
                    result.add('search')
                if self.is_in_map():
                    self.enemy_searching_color_initial()

            # Combat
            if self.combat_appear():
                # Use ui_back() for testing, because there are too few abyssal loggers every month.
                # self.ui_back(check_button=self.is_in_map)
                self.combat(expected_end=self.is_in_map,
                            fleet_index=self.fleet_show_index,
                            save_get_items=drop)
                confirm_timer.reset()
                result.add('event')
                continue

            # Akashi shop
            if self.appear(PORT_SUPPLY_CHECK, offset=(20, 20)):
                self.interval_clear(PORT_SUPPLY_CHECK)
                self.handle_akashi_supply_buy(CLICK_SAFE_AREA)
                confirm_timer.reset()
                result.add('akashi')
                continue

            # Arrive
            # Check colors, because screen goes black when something is unlocking.
            if self.is_in_map() and IN_MAP.match_appear_on(self.device.image):
                self.update_os()
                current = self.view.backend.homo_loca
                logger.attr('homo_loca', current)
                if record is None or (current is not None and np.linalg.norm(
                        np.subtract(current, record)) < 3):
                    if confirm_timer.reached():
                        break
                else:
                    confirm_timer.reset()
                record = current
            else:
                confirm_timer.reset()

        result = '_'.join(result)
        logger.info(f'Walk stabled, result: {result}')
        self.device.screenshot_interval_set()
        return result
コード例 #11
0
    def os_map_goto_globe(self, unpin=True, skip_first_screenshot=True):
        """
        Args:
            unpin (bool):
            skip_first_screenshot (bool):

        Pages:
            in: is_in_map
            out: is_in_globe
        """
        click_count = 0
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.appear_then_click(MAP_GOTO_GLOBE,
                                      offset=(200, 5),
                                      interval=5):
                click_count += 1
                if click_count >= 5:
                    # When there's zone exploration reward, AL just don't let you go.
                    logger.warning(
                        'Unable to goto globe, '
                        'there might be uncollected zone exploration rewards preventing exit'
                    )
                    raise GameTooManyClickError(
                        f'Too many click for a button: {MAP_GOTO_GLOBE}')
                continue
            if self.handle_map_event():
                continue
            # Popup: AUTO_SEARCH_REWARD appears slowly
            if self.appear_then_click(AUTO_SEARCH_REWARD,
                                      offset=(50, 50),
                                      interval=5):
                continue
            # Popup: Leaving current zone will terminate meowfficer searching.
            # Popup: Leaving current zone will retreat submarines
            # Searching reward will be shown after entering another zone.
            if self.handle_popup_confirm('GOTO_GLOBE'):
                continue

            # End
            if self.is_in_globe():
                break

        skip_first_screenshot = True
        confirm_timer = Timer(1, count=2).start()
        unpinned = 0
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if unpin:
                if self.handle_zone_pinned():
                    unpinned += 1
                    confirm_timer.reset()
                else:
                    if unpinned and confirm_timer.reached():
                        break
            else:
                if self.is_zone_pinned():
                    break
コード例 #12
0
    def set(self,
            main,
            left=None,
            right=None,
            upper=None,
            bottom=None,
            skip_first_screenshot=True):
        """
        Set nav bar from 1 direction.

        Args:
            main (ModuleBase):
            left (int): Index of nav item counted from left. Start from 1.
            right (int): Index of nav item counted from right. Start from 1.
            upper (int): Index of nav item counted from upper. Start from 1.
            bottom (int): Index of nav item counted from bottom. Start from 1.
            skip_first_screenshot (bool):

        Returns:
            bool: If success
        """
        if left is None and right is None and upper is None and bottom is None:
            logger.warning(
                'Invalid index to set, must set an index from 1 direction')
            return False
        text = ''
        if left is None and upper is not None:
            left = upper
        if right is None and bottom is not None:
            right = bottom
        for k in ['left', 'right', 'upper', 'bottom']:
            if locals().get(k, None) is not None:
                text += f'{k}={locals().get(k, None)} '
        logger.info(f'{self.name} set to {text.strip()}')

        interval = Timer(2, count=4)
        timeout = Timer(10, count=20).start()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                main.device.screenshot()

            if timeout.reached():
                logger.warning(f'{self.name} failed to set {text.strip()}')
                return False

            active, minimum, maximum = self.get_info(main=main)
            logger.info(
                f'Nav item active: {active} from range ({minimum}, {maximum})')
            # if active is None:
            #     continue
            index = minimum + left - 1 if left is not None else maximum - right + 1
            if not minimum <= index <= maximum:
                logger.warning(
                    f'Index to set ({index}) is not within the nav items that appears ({minimum}, {maximum})'
                )
                continue

            # End
            if active == index:
                return True

            if interval.reached():
                main.device.click(self.grids.buttons[index])
                main.device.sleep((0.1, 0.2))
                interval.reset()
コード例 #13
0
    def ui_goto(self,
                destination,
                offset=(20, 20),
                confirm_wait=0,
                skip_first_screenshot=True):
        """
        Args:
            destination (Page):
            offset:
            confirm_wait:
            skip_first_screenshot:
        """
        # Reset connection
        for page in self.ui_pages:
            page.parent = None

        # Create connection
        visited = [destination]
        visited = set(visited)
        while 1:
            new = visited.copy()
            for page in visited:
                for link in self.ui_pages:
                    if link in visited:
                        continue
                    if page in link.links:
                        link.parent = page
                        new.add(link)
            if len(new) == len(visited):
                break
            visited = new

        logger.hr(f'UI goto {destination}')
        confirm_timer = Timer(confirm_wait,
                              count=int(confirm_wait // 0.5)).start()
        while 1:
            GOTO_MAIN.clear_offset()
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            # Destination page
            if self.appear(destination.check_button, offset=offset):
                if confirm_timer.reached():
                    break
            else:
                confirm_timer.reset()

            # Other pages
            for page in visited:
                if page.parent is None or page.check_button is None:
                    continue
                if self.appear(page.check_button, offset=offset, interval=5):
                    self.device.click(page.links[page.parent])
                    confirm_timer.reset()
                    break

            # Additional
            if self.ui_additional():
                continue

        # Reset connection
        for page in self.ui_pages:
            page.parent = None
コード例 #14
0
    def wait_until_walk_stable(self,
                               confirm_timer=None,
                               skip_first_screenshot=False,
                               walk_out_of_step=True,
                               drop=None):
        """
        Wait until homo_loca stabled.
        DETECTION_BACKEND must be 'homography'.

        Args:
            confirm_timer (Timer):
            skip_first_screenshot (bool):
            walk_out_of_step (bool): If catch walk_out_of_step error.
                Default to True, use False in abyssal zones.
            drop (DropImage):

        Raises:
            MapWalkError: If unable to goto such grid.
        """
        logger.hr('Wait until walk stable')
        record = None
        enemy_searching_appear = False
        self.device.screenshot_interval_set(0.35)
        if confirm_timer is None:
            confirm_timer = Timer(0.8, count=2)

        confirm_timer.reset()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            # Map event
            if self.handle_map_event(drop=drop):
                confirm_timer.reset()
                continue
            if self.handle_retirement():
                confirm_timer.reset()
                continue
            if self.handle_walk_out_of_step():
                if walk_out_of_step:
                    raise MapWalkError('walk_out_of_step')
                else:
                    continue

            # Enemy searching
            if not enemy_searching_appear and self.enemy_searching_appear():
                enemy_searching_appear = True
                confirm_timer.reset()
                continue
            else:
                if enemy_searching_appear:
                    self.handle_enemy_flashing()
                    self.device.sleep(0.3)
                    logger.info('Enemy searching appeared.')
                    enemy_searching_appear = False
                if self.is_in_map():
                    self.enemy_searching_color_initial()

            # Combat
            if self.combat_appear():
                # Use ui_back() for testing, because there are too few abyssal loggers every month.
                # self.ui_back(check_button=self.is_in_map)
                self.combat(expected_end=self.is_in_map,
                            fleet_index=self.fleet_show_index,
                            save_get_items=drop)
                confirm_timer.reset()
                continue

            # Arrive
            # Check colors, because screen goes black when something is unlocking.
            if self.is_in_map() and IN_MAP.match_appear_on(self.device.image):
                self.update_os()
                current = self.view.backend.homo_loca
                logger.attr('homo_loca', current)
                if record is None or (current is not None and np.linalg.norm(
                        np.subtract(current, record)) < 3):
                    if confirm_timer.reached():
                        break
                else:
                    confirm_timer.reset()
                record = current
            else:
                confirm_timer.reset()

        logger.info('Walk stabled')
        self.device.screenshot_interval_set()
コード例 #15
0
    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])
コード例 #16
0
    def _guild_operations_ensure(self, skip_first_screenshot=True):
        """
        Ensure guild operation is loaded
        After entering guild operation, background loaded first, then dispatch/boss
        """
        logger.attr('Guild master/official',
                    self.config.GuildOperation_SelectNewOperation)
        confirm_timer = Timer(1.5, count=3).start()
        click_count = 0
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            # End
            if click_count > 5:
                # Info bar showing `none4302`.
                # Probably because guild operation has been started by another guild officer already.
                # Enter guild page again should fix the issue.
                logger.warning(
                    'Unable to start/join guild operation, '
                    'probably because guild operation has been started by another guild officer already'
                )
                raise GameBugError('Unable to start/join guild operation')

            if self._handle_guild_operations_start():
                confirm_timer.reset()
                continue
            if self.appear(GUILD_OPERATIONS_JOIN, interval=3):
                if self.image_color_count(GUILD_OPERATIONS_MONTHLY_COUNT,
                                          color=(255, 93, 90),
                                          threshold=221,
                                          count=20):
                    logger.info(
                        'Unable to join operation, no more monthly attempts left'
                    )
                    self.device.click(GUILD_OPERATIONS_CLICK_SAFE_AREA)
                else:
                    current, remain, total = GUILD_OPERATIONS_PROGRESS.ocr(
                        self.device.image)
                    threshold = total * self.config.GuildOperation_JoinThreshold
                    if current <= threshold:
                        logger.info(
                            'Joining Operation, current progress less than '
                            f'threshold ({threshold:.2f})')
                        self.device.click(GUILD_OPERATIONS_JOIN)
                    else:
                        logger.info(
                            'Refrain from joining operation, current progress exceeds '
                            f'threshold ({threshold:.2f})')
                        self.device.click(GUILD_OPERATIONS_CLICK_SAFE_AREA)
                confirm_timer.reset()
                continue
            if self.handle_popup_confirm('JOIN_OPERATION'):
                click_count += 1
                confirm_timer.reset()
                continue
            if self.handle_popup_single('FLEET_UPDATED'):
                logger.info(
                    'Fleet composition altered, may still be dispatch-able. However '
                    'fellow guild members have updated their support line up. '
                    'Suggestion: Enable Boss Recommend')
                confirm_timer.reset()
                continue

            # End
            if self.appear(GUILD_BOSS_ENTER) or self.appear(
                    GUILD_OPERATIONS_ACTIVE_CHECK, offset=(20, 20)):
                if not self.info_bar_count() and confirm_timer.reached():
                    break
コード例 #17
0
    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.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()
                    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 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()
コード例 #18
0
    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_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 = self._shipyard_get_total()
                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._shipyard_in_ui():
                if confirm_timer.reached():
                    break
            else:
                confirm_timer.reset()
コード例 #19
0
ファイル: ash.py プロジェクト: nEEtdo0d/AzurLaneAutoScript
    def _ash_assist_enter_from_map(self,
                                   offset=(200, 5),
                                   skip_first_screenshot=True):
        """
        Args:
            offset:
            skip_first_screenshot:

        Pages:
            in: IN_MAP
            out: is_in_ash
        """
        confirm_timer = Timer(1, count=2).start()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.appear_then_click(MAP_GOTO_GLOBE,
                                      offset=offset,
                                      interval=5):
                confirm_timer.reset()
                continue
            if self.appear_then_click(ASH_SHOWDOWN,
                                      offset=(30, 30),
                                      interval=5):
                confirm_timer.reset()
                continue
            if self.appear_then_click(ASH_ENTRANCE, offset=offset, interval=5):
                confirm_timer.reset()
                continue
            if self._handle_ash_beacon_reward():
                confirm_timer.reset()
                continue
            if self.handle_popup_confirm('GOTO_GLOBE'):
                # Popup: Leaving current zone will terminate meowfficer searching
                confirm_timer.reset()
                continue
            if self.handle_map_event():
                confirm_timer.reset()
                continue

            # End
            if self.is_in_ash():
                if confirm_timer.reached():
                    break
            else:
                confirm_timer.reset()
コード例 #20
0
    def os_mission_overview_accept(self):
        """
        Accept all missions in mission overview.

        Returns:
            bool: True if all missions accepted or no mission found.
                  False if unable to accept more missions.

        Pages:
            in: is_in_map
            out: is_in_map
        """
        logger.hr('OS mission overview accept', level=1)
        # is_in_map
        self.os_map_goto_globe(unpin=False)
        # is_in_globe
        self.ui_click(MISSION_OVERVIEW_ENTER,
                      check_button=MISSION_OVERVIEW_CHECK,
                      offset=(200, 20),
                      retry_wait=3,
                      skip_first_screenshot=True)

        # MISSION_OVERVIEW_CHECK
        confirm_timer = Timer(1, count=3).start()
        skip_first_screenshot = True
        success = True
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.info_bar_count():
                logger.info(
                    'Unable to accept missions, because reached the maximum number of missions'
                )
                success = False
                break
            if self.appear_then_click(MISSION_OVERVIEW_ACCEPT,
                                      offset=(20, 20),
                                      interval=0.2):
                confirm_timer.reset()
                continue
            else:
                # End
                if confirm_timer.reached():
                    success = True
                    break
            if self.appear_then_click(MISSION_OVERVIEW_ACCEPT_SINGLE,
                                      offset=(20, 20),
                                      interval=0.2):
                confirm_timer.reset()
                continue

        # is_in_globe
        self.ui_back(appear_button=MISSION_OVERVIEW_CHECK,
                     check_button=self.is_in_globe,
                     skip_first_screenshot=True)
        # is_in_map
        self.os_globe_goto_map()
        return success
コード例 #21
0
    def enter_map(self, button, mode='normal', skip_first_screenshot=True):
        """Enter a campaign.

        Args:
            button: Campaign to enter.
            mode (str): 'normal' or 'hard' or 'cd'
            skip_first_screenshot (bool):
        """
        logger.hr('Enter map')
        campaign_timer = Timer(5)
        map_timer = Timer(5)
        fleet_timer = Timer(5)
        campaign_click = 0
        map_click = 0
        fleet_click = 0
        checked_in_map = False
        self.stage_entrance = button

        with self.stat.new(
                genre=self.config.campaign_name, save=self.config.DropRecord_SaveCombat, upload=False
        ) as drop:
            while 1:
                if skip_first_screenshot:
                    skip_first_screenshot = False
                else:
                    self.device.screenshot()

                # Check errors
                if campaign_click > 5:
                    logger.critical(f"Failed to enter {button}, too many click on {button}")
                    logger.critical("Possible reason #1: You haven't reached the commander level to unlock this stage.")
                    raise RequestHumanTakeover
                if fleet_click > 5:
                    logger.critical(f"Failed to enter {button}, too many click on FLEET_PREPARATION")
                    logger.critical("Possible reason #1: "
                                    "Your fleets haven't satisfied the stat restrictions of this stage.")
                    logger.critical("Possible reason #2: "
                                    "This stage can only be farmed once a day, "
                                    "but it's the second time that you are entering")
                    raise RequestHumanTakeover

                # Already in map
                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():
                    self.map_get_info()
                    self.handle_fast_forward()
                    self.handle_auto_search()
                    if self.triggered_map_stop():
                        self.enter_map_cancel()
                        self.handle_map_stop()
                        raise ScriptEnd(f'Reach condition: {self.config.StopCondition_MapAchievement}')
                    self.device.click(MAP_PREPARATION)
                    map_click += 1
                    map_timer.reset()
                    campaign_timer.reset()
                    continue

                # Fleet preparation
                if fleet_timer.reached() and self.appear(FLEET_PREPARATION, offset=(20, 20)):
                    if mode == 'normal' or mode == 'hard':
                        self.handle_2x_book_setting(mode='prep')
                        self.fleet_preparation()
                        self.handle_auto_submarine_call_disable()
                        self.handle_auto_search_setting()
                        self.map_fleet_checked = True
                    self.device.click(FLEET_PREPARATION)
                    fleet_click += 1
                    fleet_timer.reset()
                    campaign_timer.reset()
                    continue

                # Auto search continue
                if self.handle_auto_search_continue():
                    campaign_timer.reset()
                    continue

                # Retire
                if self.handle_retirement():
                    campaign_timer.reset()
                    map_timer.reset()
                    fleet_timer.reset()
                    continue

                # Use Data Key
                if self.handle_use_data_key():
                    continue

                # Emotion
                if self.handle_combat_low_emotion():
                    continue

                # Urgent commission
                if self.handle_urgent_commission(drop=drop):
                    continue

                # 2X book popup
                if self.handle_2x_book_popup():
                    continue

                # Story skip
                if self.handle_story_skip():
                    campaign_timer.reset()
                    continue

                # Enter campaign
                if campaign_timer.reached() and self.appear_then_click(button):
                    campaign_click += 1
                    campaign_timer.reset()
                    continue

                # End
                if self.map_is_auto_search:
                    if self.is_auto_search_running():
                        break
                else:
                    if self.handle_in_map_with_enemy_searching():
                        self.handle_map_after_combat_story()
                        break

        return True
コード例 #22
0
    def reward_receive(self, oil, coin, exp, skip_first_screenshot=True):
        """
        Args:
            oil (bool):
            coin (bool):
            exp (bool):
            skip_first_screenshot (bool):

        Returns:
            bool: If rewarded.

        Pages:
            in: page_reward
            out: page_reward, with info_bar if received
        """
        if not oil and not coin and not exp:
            return False

        logger.hr('Reward receive')
        logger.info(f'oil={oil}, coin={coin}, exp={exp}')
        confirm_timer = Timer(1, count=3).start()
        # Set click interval to 0.3, because game can't respond that fast.
        click_timer = Timer(0.3)
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if oil and click_timer.reached() and self.appear_then_click(
                    OIL, interval=60):
                confirm_timer.reset()
                click_timer.reset()
                continue
            if coin and click_timer.reached() and self.appear_then_click(
                    COIN, interval=60):
                confirm_timer.reset()
                click_timer.reset()
                continue
            if exp and click_timer.reached() and self.appear_then_click(
                    EXP, interval=60):
                confirm_timer.reset()
                click_timer.reset()
                continue

            # End
            if confirm_timer.reached():
                break

        logger.info('Reward receive end')
        return True
コード例 #23
0
class InfoHandler(ModuleBase):
    """
    Class to handle all kinds of message.
    """
    """
    Info bar
    """
    def info_bar_count(self):
        if self.appear(INFO_BAR_3):
            return 3
        elif self.appear(INFO_BAR_2):
            return 2
        elif self.appear(INFO_BAR_1):
            return 1
        else:
            return 0

    def handle_info_bar(self):
        if self.info_bar_count():
            self.wait_until_disappear(INFO_BAR_1)
            return True
        else:
            return False

    def ensure_no_info_bar(self, timeout=0.6):
        timeout = Timer(timeout)
        timeout.start()
        while 1:
            self.device.screenshot()
            self.handle_info_bar()

            if timeout.reached():
                break

    """
    Popup info
    """
    _popup_offset = (3, 30)

    def handle_popup_confirm(self, name=''):
        if self.appear(POPUP_CANCEL, offset=self._popup_offset) \
                and self.appear(POPUP_CONFIRM, offset=self._popup_offset, interval=2):
            POPUP_CONFIRM.name = POPUP_CONFIRM.name + '_' + name
            self.device.click(POPUP_CONFIRM)
            POPUP_CONFIRM.name = POPUP_CONFIRM.name[:-len(name) - 1]
            return True
        else:
            return False

    def handle_popup_cancel(self, name=''):
        if self.appear(POPUP_CONFIRM, offset=self._popup_offset) \
                and self.appear(POPUP_CANCEL, offset=self._popup_offset, interval=2):
            POPUP_CANCEL.name = POPUP_CANCEL.name + '_' + name
            self.device.click(POPUP_CANCEL)
            POPUP_CANCEL.name = POPUP_CANCEL.name[:-len(name) - 1]
            return True
        else:
            return False

    def handle_urgent_commission(self, save_get_items=None):
        """
        Args:
            save_get_items (bool):

        Returns:
            bool:
        """
        if save_get_items is None:
            save_get_items = self.config.ENABLE_SAVE_GET_ITEMS

        appear = self.appear(GET_MISSION, offset=True, interval=2)
        if appear:
            logger.info('Get urgent commission')
            if save_get_items:
                self.handle_info_bar()
                self.device.save_screenshot('get_mission')
            self.device.click(GET_MISSION)
        return appear

    def handle_combat_low_emotion(self):
        if not self.config.IGNORE_LOW_EMOTION_WARN:
            return False

        return self.handle_popup_confirm('IGNORE_LOW_EMOTION')

    """
    Story
    """

    story_popup_timout = Timer(10, count=20)

    def story_skip(self):
        if self.story_popup_timout.started(
        ) and not self.story_popup_timout.reached():
            if self.handle_popup_confirm('STORY_SKIP'):
                self.story_popup_timout = Timer(10)
                return True
        if self.appear_then_click(STORY_SKIP, offset=True, interval=2):
            self.story_popup_timout.reset()
            return True
        if self.appear(STORY_LETTER_BLACK) and self.appear_then_click(
                STORY_LETTERS_ONLY, offset=True, interval=2):
            self.story_popup_timout.reset()
            return True
        if self.appear_then_click(STORY_CHOOSE, offset=True, interval=2):
            self.story_popup_timout.reset()
            return True
        if self.appear_then_click(STORY_CHOOSE_2, offset=True, interval=2):
            self.story_popup_timout.reset()
            return True

        return False

    def handle_story_skip(self):
        if not self.config.ENABLE_MAP_CLEAR_MODE:
            return False
        if self.config.ENABLE_FAST_FORWARD:
            return False

        return self.story_skip()

    def ensure_no_story(self, skip_first_screenshot=True):
        logger.info('Ensure no story')
        story_timer = Timer(5, count=10).start()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.story_skip():
                story_timer.reset()

            if story_timer.reached():
                break

    def handle_map_after_combat_story(self):
        if not self.config.MAP_HAS_MAP_STORY:
            return False

        self.ensure_no_story()
コード例 #24
0
    def _reward_mission_collect(self, interval=1):
        """
        Streamline handling of mission rewards for
        both 'all' and 'weekly' pages

        Args:
            interval (int): Configure the interval for
                            assets involved

        Returns:
            bool, if encountered at least 1 GET_ITEMS_*
        """
        # Reset any existing interval for the following assets
        [
            self.interval_clear(asset) for asset in [
                GET_ITEMS_1, GET_ITEMS_2, MISSION_MULTI, MISSION_SINGLE,
                GET_SHIP
            ]
        ]

        # Basic timers for certain scenarios
        exit_timer = Timer(2)
        click_timer = Timer(1)
        timeout = Timer(10)
        exit_timer.start()
        timeout.start()

        reward = False
        while 1:
            self.device.screenshot()

            for button in [GET_ITEMS_1, GET_ITEMS_2]:
                if self.appear_then_click(button,
                                          offset=(30, 30),
                                          interval=interval):
                    exit_timer.reset()
                    timeout.reset()
                    reward = True
                    continue

            for button in [MISSION_MULTI, MISSION_SINGLE]:
                if not click_timer.reached():
                    continue
                if self.appear(button, offset=(0, 200), interval=interval) \
                        and button.match_appear_on(self.device.image):
                    self.device.click(button)
                    exit_timer.reset()
                    click_timer.reset()
                    timeout.reset()
                    continue

            if not self.appear(MISSION_CHECK):
                if self.appear_then_click(GET_SHIP, interval=interval):
                    exit_timer.reset()
                    click_timer.reset()
                    timeout.reset()
                    continue

            if self.handle_mission_popup_ack():
                exit_timer.reset()
                click_timer.reset()
                timeout.reset()
                continue

            # Story
            if self.handle_vote_popup():
                exit_timer.reset()
                click_timer.reset()
                timeout.reset()
                continue
            if self.story_skip():
                exit_timer.reset()
                click_timer.reset()
                timeout.reset()
                continue

            if self.handle_popup_confirm('MISSION_REWARD'):
                exit_timer.reset()
                click_timer.reset()
                timeout.reset()
                continue

            # End
            if reward and exit_timer.reached():
                break
            if timeout.reached():
                logger.warning('Wait get items timeout.')
                break

        return reward
コード例 #25
0
    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
コード例 #26
0
    def _tactical_class_receive(self, skip_first_screenshot=True):
        """
        Receive tactical rewards and fill books.

        Args:
            skip_first_screenshot (bool):

        Returns:
            bool: If rewarded.

        Pages:
            in: page_reward, TACTICAL_CLASS_START
            out: page_tactical
        """
        logger.hr('Tactical class receive', level=1)
        tactical_class_timout = Timer(10, count=10).start()
        tactical_animation_timer = Timer(2, count=3).start()
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if self.appear_then_click(REWARD_2, interval=1):
                tactical_class_timout.reset()
                tactical_animation_timer.reset()
                continue
            if self.appear_then_click(REWARD_GOTO_TACTICAL,
                                      offset=(20, 20),
                                      interval=1):
                tactical_class_timout.reset()
                tactical_animation_timer.reset()
                continue
            if self.handle_popup_confirm('TACTICAL'):
                tactical_class_timout.reset()
                tactical_animation_timer.reset()
                continue
            if self.handle_urgent_commission():
                # Only one button in the middle, when skill reach max level.
                tactical_class_timout.reset()
                tactical_animation_timer.reset()
                continue
            if self.appear(TACTICAL_CLASS_CANCEL, offset=(30, 30), interval=2) \
                    and self.appear(TACTICAL_CLASS_START, offset=(30, 30)):
                self.device.sleep(0.3)
                self._tactical_books_choose()
                self.interval_reset(TACTICAL_CLASS_CANCEL)
                tactical_class_timout.reset()
                tactical_animation_timer.reset()
                continue

            # End
            if self.appear(TACTICAL_CHECK, offset=(20, 20)):
                self.ui_current = page_tactical
                if not self._tactical_animation_running():
                    if tactical_animation_timer.reached():
                        logger.info('Tactical reward end.')
                        break
                else:
                    tactical_animation_timer.reset()
            if tactical_class_timout.reached():
                logger.info('Tactical reward timeout.')
                break

        return True
コード例 #27
0
ファイル: fleet.py プロジェクト: Kitakana/AzurLaneAutoScript
    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()
コード例 #28
0
class Scroll:
    color_threshold = 221
    drag_threshold = 0.05
    edge_add = (0.1, 0.2)

    def __init__(self, area, color, is_vertical=True, name='Scroll'):
        """
        Args:
            area (Button, tuple): A button or area of the whole scroll.
            color (tuple): RGB of the scroll
            is_vertical (bool): True if vertical, false if horizontal.
            name (str):
        """
        if isinstance(area, Button):
            name = area.name
            area = area.area
        self.area = area
        self.color = color
        self.is_vertical = is_vertical
        self.name = name

        if self.is_vertical:
            self.total = self.area[3] - self.area[1]
        else:
            self.total = self.area[2] - self.area[0]
        # Just default value, will change in match_color()
        self.length = self.total / 2
        self.drag_interval = Timer(1)

    def match_color(self, main):
        """
        Args:
            main (ModuleBase):

        Returns:
            np.ndarray: Shape (n,), dtype bool.
        """
        image = main.image_crop(self.area)
        image = color_similarity_2d(image, color=self.color)
        mask = np.max(image,
                      axis=1 if self.is_vertical else 0) > self.color_threshold
        self.length = np.sum(mask)
        return mask

    def cal_position(self, main):
        """
        Args:
            main (ModuleBase):

        Returns:
            float: 0 to 1.
        """
        mask = self.match_color(main)
        middle = np.mean(np.where(mask)[0])

        position = (middle - self.length / 2) / (self.total - self.length)
        position = position if position > 0 else 0.0
        position = position if position < 1 else 1.0
        logger.attr(
            self.name,
            f'{position:.2f} ({middle}-{self.length / 2})/({self.total}-{self.length})'
        )
        return position

    def position_to_screen(self, position, random_range=(-0.05, 0.05)):
        """
        Convert scroll position to screen coordinates.
        Call cal_position() or match_color() to get length, before calling this.

        Args:
            position (int, float):
            random_range (tuple):

        Returns:
            tuple[int]: (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y)
        """
        position = np.add(position, random_range)
        middle = position * (self.total - self.length) + self.length / 2
        middle = middle.astype(int)
        if self.is_vertical:
            middle += self.area[1]
            area = (self.area[0], middle[0], self.area[2], middle[1])
        else:
            middle += self.area[0]
            area = (middle[0], self.area[1], middle[1], self.area[3])
        return area

    def appear(self, main):
        """
        Args:
            main (ModuleBase):

        Returns:
            bool
        """
        return np.mean(self.match_color(main)) > 0.1

    def at_top(self, main):
        return self.cal_position(main) < 0.05

    def at_bottom(self, main):
        return self.cal_position(main) > 0.95

    def set(self,
            position,
            main,
            random_range=(-0.05, 0.05),
            skip_first_screenshot=True):
        """
        Set scroll to a specific position.

        Args:
            position (float, int): 0 to 1.
            main (ModuleBase):
            random_range (tuple(int, float)):
            skip_first_screenshot:
        """
        logger.info(f'{self.name} set to {position}')
        self.drag_interval.clear()
        if position == 0:
            random_range = np.subtract(0, self.edge_add)
        if position == 1:
            random_range = self.edge_add

        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                main.device.screenshot()

            current = self.cal_position(main)
            if abs(position - current) < self.drag_threshold:
                break
            if not self.length:
                logger.warning('Scroll disappeared, assume scroll set')
                break

            if self.drag_interval.reached():
                p1 = random_rectangle_point(self.position_to_screen(current),
                                            n=1)
                p2 = random_rectangle_point(self.position_to_screen(
                    position, random_range=random_range),
                                            n=1)
                main.device.swipe(p1, p2, name=self.name)
                main.device.sleep(0.3)
                self.drag_interval.reset()

    def set_top(self,
                main,
                random_range=(-0.05, 0.05),
                skip_first_screenshot=True):
        return self.set(0.00,
                        main=main,
                        random_range=random_range,
                        skip_first_screenshot=skip_first_screenshot)

    def set_bottom(self,
                   main,
                   random_range=(-0.05, 0.05),
                   skip_first_screenshot=True):
        return self.set(1.00,
                        main=main,
                        random_range=random_range,
                        skip_first_screenshot=skip_first_screenshot)

    def drag_page(self,
                  page,
                  main,
                  random_range=(-0.05, 0.05),
                  skip_first_screenshot=True):
        """
        Drag scroll forward or backward.

        Args:
            page (int, float): Relative position to drag. 1.0 means next page, -1.0 means previous page.
            main (ModuleBase):
            random_range (tuple[int]):
            skip_first_screenshot:
        """
        if not skip_first_screenshot:
            main.device.screenshot()
        current = self.cal_position(main)

        multiply = self.length / (self.total - self.length)
        target = current + page * multiply
        target = round(min(max(target, 0), 1), 3)
        self.set(target,
                 main=main,
                 random_range=random_range,
                 skip_first_screenshot=True)

    def next_page(self,
                  main,
                  random_range=(-0.01, 0.01),
                  skip_first_screenshot=True):
        self.drag_page(0.8,
                       main=main,
                       random_range=random_range,
                       skip_first_screenshot=skip_first_screenshot)

    def prev_page(self,
                  main,
                  random_range=(-0.01, 0.01),
                  skip_first_screenshot=True):
        self.drag_page(-0.8,
                       main=main,
                       random_range=random_range,
                       skip_first_screenshot=skip_first_screenshot)
コード例 #29
0
ファイル: reward.py プロジェクト: gflong00/AzurLaneAutoScript
    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
コード例 #30
0
    def meow_menu_close(self, skip_first_screenshot=True):
        """
        Exit from any meowfficer menu popups

        Pages:
            in: MEOWFFICER_FORT_CHECK, MEOWFFICER_BUY, MEOWFFICER_TRAIN_START, etc
            out: page_meowfficer
        """
        logger.hr('Meowfficer menu close')
        click_timer = Timer(3)
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            # End
            if self.appear(MEOWFFICER_CHECK, offset=(20, 20)) \
                    and MEOWFFICER_CHECK.match_appear_on(self.device.image):
                break
            else:
                if click_timer.reached():
                    # MEOWFFICER_CHECK is safe to click
                    self.device.click(MEOWFFICER_CHECK)
                    click_timer.reset()
                    continue

            # Fort
            if self.appear(MEOWFFICER_FORT_CHECK, offset=(20, 20), interval=3):
                self.device.click(MEOWFFICER_CHECK)
                click_timer.reset()
                continue
            # Buy
            if self.appear(MEOWFFICER_BUY, offset=(20, 20), interval=3):
                self.device.click(MEOWFFICER_CHECK)
                click_timer.reset()
                continue
            # Train
            if self.appear(MEOWFFICER_TRAIN_FILL_QUEUE,
                           offset=(20, 20),
                           interval=3):
                self.device.click(MEOWFFICER_CHECK)
                click_timer.reset()
                continue
            if self.appear(MEOWFFICER_TRAIN_FINISH_ALL,
                           offset=(20, 20),
                           interval=3):
                self.device.click(MEOWFFICER_CHECK)
                click_timer.reset()
                continue
            # Popups
            if self.appear(MEOWFFICER_CONFIRM, offset=(40, 20), interval=3):
                self.device.click(MEOWFFICER_CHECK)
                click_timer.reset()
                continue
            if self.appear(MEOWFFICER_CANCEL, offset=(40, 20), interval=3):
                self.device.click(MEOWFFICER_CHECK)
                click_timer.reset()
                continue
            if self.appear_then_click(GET_ITEMS_1, offset=5, interval=3):
                click_timer.reset()
                continue