def _tactical_animation_running(self):
        """
        Detect the white dash line under student cards.
        If student learning in progress or position haven't been unlocked, there will be a white line under the card.
        The card with animation running, white line become gray.

        Returns:
            bool: If showing skill points increasing animation.
        """
        # Area of the white line under student cards.
        area = (360, 680, 1280, 700)
        mask = color_similarity_2d(self.image_area(area),
                                   color=(255, 255, 255)) > 235
        points = np.array(np.where(mask)).T
        # Width of card is 200 px
        points = Points(points).group(threshold=210)
        card = len(points)
        if card == 0:
            logger.warning('No student card found.')
            return False
        elif card == 3:
            return True
        elif card == 4:
            return False
        else:
            logger.warning(f'Unexpected amount of student cards: {card}')
            return False
예제 #2
0
    def campaign_match_multi(self, template, image, stage_image=None, name_offset=(75, 9), name_size=(60, 16),
                             name_letter=(255, 255, 255), name_thresh=128):
        """
        Args:
            template (Template):
            image: Screenshot
            stage_image: Screenshot to find stage entrance.
            name_offset (tuple[int]):
            name_size (tuple[int]):
            name_letter (tuple[int]):
            name_thresh (int):

        Returns:
            list[Button]: Stage clear buttons.
        """
        digits = []
        stage_image = image if stage_image is None else stage_image
        result = template.match_multi(stage_image, similarity=0.85)
        result = Points(result, config=self.config).group()

        for point in result:
            button = tuple(np.append(point, point + template.size))
            point = point + name_offset
            name = image.crop(np.append(point, point + name_size))
            name = extract_letters(name, letter=name_letter, threshold=name_thresh)
            stage = self._extract_stage_name(name)

            area = area_offset(stage, point)
            color = get_color(image, button)
            digits.append(Button(area=area, color=color, button=button, name='stage'))

        return digits
예제 #3
0
    def match_multi(self, image, similarity=0.85, threshold=3, name=None):
        """
        Args:
            image:
            similarity (float): 0 to 1.
            threshold (int): Distance to delete nearby results.
            name (str):

        Returns:
            list[Button]:
        """
        raw = image
        if self.is_gif:
            result = []
            for template in self.image:
                res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
                res = np.array(np.where(res > similarity)).T[:, ::-1].tolist()
                result += res
        else:
            result = cv2.matchTemplate(image, self.image, cv2.TM_CCOEFF_NORMED)
            result = np.array(np.where(result > similarity)).T[:, ::-1]

        # result: np.array([[x0, y0], [x1, y1], ...)
        result = Points(result).group(threshold=threshold)
        return [
            self._point_to_button(point, image=raw, name=name)
            for point in result
        ]
예제 #4
0
    def _dorm_receive_click(self):
        """
        Click coins and loves in dorm.

        Returns:
            int: Receive count.

        Pages:
            in: page_dorm
            out: page_dorm, with info_bar
        """
        image = MASK_DORM.apply(np.array(self.device.image))
        love_points = Points(TEMPLATE_DORM_LOVE.match_multi(image),
                             config=self.config).group()
        coin_points = Points(TEMPLATE_DORM_COIN.match_multi(image),
                             config=self.config).group()
        logger.info(
            f'Dorm loves: {len(love_points)}, Dorm coins: {len(coin_points)}')

        count = 0
        for point in love_points:
            button = tuple(np.append(point, point + TEMPLATE_DORM_LOVE.size))
            button = Button(area=button,
                            color=(),
                            button=button,
                            name='DORM_LOVE')
            count += 1
            # Disable click record check, because may have too many coins or loves.
            self.device.click(button, record_check=False)
            self.device.sleep((0.5, 0.8))
        for point in coin_points:
            button = tuple(np.append(point, point + TEMPLATE_DORM_LOVE.size))
            button = Button(area=button,
                            color=(),
                            button=button,
                            name='DORM_COIN')
            count += 1
            self.device.click(button, record_check=False)
            self.device.sleep((0.5, 0.8))

        return count
예제 #5
0
 def _get_medals(self):
     """
     Returns:
         np.array: [[x1, y1], [x2, y2]], location of the medal icon upper-left corner.
     """
     left_column = self.image_crop((489, 256, 1120, 572))
     medals = TEMPLATE_MEDAL_ICON.match_multi(left_column,
                                              similarity=0.5,
                                              threshold=5)
     medals = Points([(0., m.area[1]) for m in medals]).group(threshold=5)
     logger.attr('Medals_icon', len(medals))
     return medals
예제 #6
0
 def guild_lobby_get_report(self):
     """
     Returns:
         Button: Button to enter guild report.
     """
     # Find red color in the area of GUILD_REPORT_AVAILABLE
     image = color_similarity_2d(self.image_crop(GUILD_REPORT_AVAILABLE), color=(255, 8, 8))
     points = np.array(np.where(image > 221)).T[:, ::-1]
     if len(points):
         # The center of red dot
         points = Points(points).group(threshold=40) + GUILD_REPORT_AVAILABLE.area[:2]
         # Shift to the center of report icon
         area = area_offset((-51, -45, -13, 0), offset=points[0])
         return Button(area=area, color=(255, 255, 255), button=area, name='GUILD_REPORT')
     else:
         return None
예제 #7
0
    def _guild_operation_get_entrance(self):
        """
        Get 2 entrance button of guild dispatch
        If operation is on the top, after clicking expand button, operation chain moves downward, and enter button
        appears on the top. So we need to detect two buttons in real time.

        Returns:
            list[Button], list[Button]: Expand button, enter button

        Pages:
            in: page_guild, guild operation, operation map (GUILD_OPERATIONS_ACTIVE_CHECK)
        """
        # Where whole operation mission chain is
        detection_area = (152, 135, 1280, 630)
        # Offset inside to avoid clicking on edge
        pad = 5

        def point_to_entrance_1(point):
            """ Get expand button """
            area = area_limit(
                area_offset(area=(-257, 14, 12, 51), offset=point),
                detection_area)
            return Button(area=area,
                          color=(),
                          button=area_pad(area, pad),
                          name='DISPATCH_ENTRANCE_1')

        def point_to_entrance_2(point):
            """ Get enter button """
            area = area_limit(
                area_offset(area=(-257, -109, 12, -1), offset=point),
                detection_area)
            return Button(area=area,
                          color=(),
                          button=area_pad(area, pad),
                          name='DISPATCH_ENTRANCE_2')

        # Scan image and must have similarity greater than 0.85
        points = TEMPLATE_OPERATIONS_RED_DOT.match_multi(
            self.device.image.crop(detection_area))
        points += detection_area[:2]
        points = Points(points, config=self.config).group(threshold=5)
        logger.info(f'Active operations found: {len(points)}')

        return [point_to_entrance_1(point) for point in points
                ], [point_to_entrance_2(point) for point in points]