def predict_enemy_scale(self): """ icon on the upperleft which shows enemy scale: Large Middle Small. Returns: int: 1: Small, 2: Middle, 3: Large. """ # if not self.is_enemy: # return 0 image = self.get_relative_image((-0.415 - 0.7, -0.62 - 0.7, -0.415, -0.62)) image = np.stack( [ color_similarity_2d(image, (255, 130, 132)), color_similarity_2d(image, (255, 239, 148)), color_similarity_2d(image, (255, 235, 156)) ], axis=2 ) image = Image.fromarray(image).resize(self.ENEMY_SCALE_IMAGE_SIZE) if TEMPLATE_ENEMY_L.match(image): scale = 3 elif TEMPLATE_ENEMY_M.match(image): scale = 2 elif TEMPLATE_ENEMY_S.match(image): scale = 1 else: scale = 0 return scale
def __init__(self, image, button): """ Args: image (PIL.Image.Image): button (Button): """ image = image.crop(button.area) self.button = button self.genre = 0 color = get_color(image, (65, 35, 72, 42)) for key, value in self.color_genre.items(): if color_similar(color1=color, color2=value, threshold=30): self.genre = key self.tier = 0 color = get_color(image, (83, 61, 92, 70)) for key, value in self.color_tier.items(): if color_similar(color1=color, color2=value, threshold=30): self.tier = key color = color_similarity_2d(image.crop((15, 0, 97, 13)), color=(148, 251, 99)) self.exp = bool(np.sum(color > 221) > 50) self.valid = bool(self.genre and self.tier)
def predict_enemy_genre(self): image = self.relative_crop((-0.55, -0.2, 0.45, 0.2), shape=(50, 20)) image = color_similarity_2d(image, color=(255, 150, 24)) if TEMPLATE_ENEMY_BOSS.match(image, similarity=0.75): return 'Siren_Siren' return super().predict_enemy_genre()
def _equip_sidebar_click(self, index): """ Args: index (int): 5 for retrofit. 4 for enhancement. 3 for limit break. 2 for gem / equipment. 1 for detail. Returns: bool: if changed. """ if index <= 0 or index > 5: logger.warning( f'Sidebar index cannot be clicked, {index}, limit to 1 through 5 only' ) return False current = 0 total = 0 for idx, button in enumerate(DETAIL_SIDEBAR.buttons()): image = np.array(self.device.image.crop(button.area)) if np.sum(image[:, :, 0] > 235) > 100: current = idx + 1 total = idx + 1 continue if np.sum(color_similarity_2d(image, color=(140, 162, 181)) > 221) > 100: total = idx + 1 else: break if not current: logger.warning('No ship details sidebar active.') if total == 3: current = 4 - current elif total == 4: current = 5 - current elif total == 5: current = 6 - current else: logger.warning('Ship details sidebar total count error.') logger.attr('Detail_sidebar', f'{current}/{total}') if current == index: return False diff = total - index if total == 3 and index == 3: logger.warning('Ship is PRY, equipment research not supported') elif diff >= 0: self.device.click(DETAIL_SIDEBAR[0, diff]) else: logger.warning( f'Target index {index} cannot be clicked for this ship') return True
def predict_fleet(self): # white ammo icon # return self._relative_image_color_count( # area=(-1, -2, -0.5, -1.5), color=(255, 255, 255), color_threshold=252) > 300 # count = self._relative_image_color_hue_count(area=(-1, -2, -0.5, -1.5), h=(0, 360), s=(0, 5), v=(95, 100)) # return count > 300 image = self.get_relative_image((-1, -2, -0.5, -1.5), output_shape=self.ENEMY_SCALE_IMAGE_SIZE) image = color_similarity_2d(image, (255, 255, 255)) return TEMPLATE_FLEET_AMMO.match(image)
def _relative_image_color_count(self, area, color, output_shape=(50, 50), color_threshold=221): image = self.get_relative_image(area, output_shape=output_shape) image = color_similarity_2d(image, color=color) count = np.sum(image > color_threshold) return count
def predict_static_red_border(self): # image = self.image.transform(self.ENEMY_PERSPECTIVE_IMAGE_SIZE, Image.PERSPECTIVE, self._perspective) image = color_similarity_2d( self.image_transform.crop((0, self.RED_BORDER_IGNORE_TOP, *self.ENEMY_PERSPECTIVE_IMAGE_SIZE)), color=(255, 36, 82)) # Image.fromarray(np.array(image).astype('uint8'), mode='RGB').save(f'{self}.png') count = np.sum(image > 221) return count > 40
def predict_boss(self): # Small boss icon if self.relative_hsv_count(area=(0.03, -0.15, 0.63, 0.15), h=(358 - 3, 358 + 3), shape=(50, 20)) > 100: image = self.relative_crop((0.03, -0.15, 0.63, 0.15), shape=(50, 20)) image = color_similarity_2d(image, color=(255, 77, 82)) if TEMPLATE_ENEMY_BOSS.match(image, similarity=0.7): return True return False
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 handle_map_cat_attack(self): """ Click to skip the animation when cat attacks. """ if not self.map_cat_attack_timer.reached(): return False if np.sum(color_similarity_2d(self.image_area(MAP_CAT_ATTACK), (255, 231, 123)) > 221) > 100: logger.info('Skip map cat attack') self.device.click(MAP_CAT_ATTACK) self.map_cat_attack_timer.reset() return True return False
def handle_map_cat_attack(self): """ Click to skip the animation when cat attacks. Overridden as button position matches with MAP_EXIT for OpSi """ if not self.map_cat_attack_timer.reached(): return False if np.sum(color_similarity_2d(self.image_crop(MAP_CAT_ATTACK), (255, 231, 123)) > 221) > 100: logger.info('Skip map cat attack') self.device.click(CLICK_SAFE_AREA) self.map_cat_attack_timer.reset() return True return False
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
def get_map_is_hard_mode(self): """ Detect how many light orange lines are there. Having lines means current map has stat limits and user has satisfied at least one of them, so this is a hard map. Returns: bool: """ area = (208, 130, 226, 551) image = color_similarity_2d(self.image_area(area), color=(249, 199, 0)) height = np.max(image, axis=1) parameters = {'height': 180, 'distance': 5} peaks, _ = signal.find_peaks(height, **parameters) lines = len(peaks) logger.attr('Light_orange_line', lines) return lines > 0
def _equip_sidebar_click(self, index): """ Args: index (int): 5 for retrofit. 4 for enhancement. 3 for limit break. 2 for gem / equipment. 1 for detail. Returns: bool: if changed. """ current = 0 total = 0 for idx, button in enumerate(DETAIL_SIDEBAR.buttons()): image = np.array(self.device.image.crop(button.area)) if np.sum(image[:, :, 0] > 235) > 100: current = idx + 1 total = idx + 1 continue if np.sum(color_similarity_2d(image, color=(140, 162, 181)) > 221) > 100: total = idx + 1 else: break if not current: logger.warning('No ship details sidebar active.') if total == 4: current = 5 - current elif total == 5: current = 6 - current else: logger.warning('Ship details sidebar total count error.') logger.attr('Detail_sidebar', f'{current}/{total}') if current == index: return False self.device.click(DETAIL_SIDEBAR[0, total - index]) return True
def handle_user_agreement(self, xp, hierarchy): """ For CN only. CN client is bugged. User Agreement and Privacy Policy may popup again even you have agreed with it. This method scrolls to the bottom and click AGREE. Returns: bool: If handled. """ if server.server == 'cn': area_wait_results = self.get_for_any_ele([ XPS('//*[@text="sdk协议"]', xp, hierarchy), XPS('//*[@content-desc="sdk协议"]', xp, hierarchy) ]) if area_wait_results is False: return False agree_wait_results = self.get_for_any_ele([ XPS('//*[@text="同意"]', xp, hierarchy), XPS('//*[@content-desc="同意"]', xp, hierarchy) ]) start_padding_results = self.get_for_any_ele([ XPS('//*[@text="隐私政策"]', xp, hierarchy), XPS('//*[@content-desc="隐私政策"]', xp, hierarchy), XPS('//*[@text="用户协议"]', xp, hierarchy), XPS('//*[@content-desc="用户协议"]', xp, hierarchy) ]) start_margin_results = self.get_for_any_ele([ XPS('//*[@text="请滑动阅读协议内容"]', xp, hierarchy), XPS('//*[@content-desc="请滑动阅读协议内容"]', xp, hierarchy) ]) test_image_original = self.device.image image_handle_crop = crop( test_image_original, (start_padding_results[2], 0, start_margin_results[2], 720)) # Image.fromarray(image_handle_crop).show() sims = color_similarity_2d(image_handle_crop, color=(182, 189, 202)) points = np.sum(sims >= 255) if points == 0: return False sims_height = np.mean(sims, axis=1) # pyplot.plot(sims_height, color='r') # pyplot.show() peaks, __ = find_peaks(sims_height, height=225) if len(peaks) == 2: peaks = (peaks[0] + peaks[1]) / 2 start_pos = [ (start_padding_results[2] + start_margin_results[2]) / 2, float(peaks) ] end_pos = [ (start_padding_results[2] + start_margin_results[2]) / 2, area_wait_results[3] ] logger.info("user agreement position find result: " + ', '.join('%.2f' % _ for _ in start_pos)) logger.info("user agreement area expect: " + 'x:963-973, y:259-279') self.device.drag(start_pos, end_pos, segments=2, shake=(0, 25), point_random=(0, 0, 0, 0), shake_random=(0, -5, 0, 5)) AGREE = Button(area=agree_wait_results, color=(), button=agree_wait_results, name='AGREE') self.device.click(AGREE) return True