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 enemy_searching_appear(self): if not self.is_in_map(): return False return red_overlay_transparency( MAP_ENEMY_SEARCHING.color, get_color(self.device.image, MAP_ENEMY_SEARCHING.area) ) > self.MAP_ENEMY_SEARCHING_OVERLAY_TRANSPARENCY_THRESHOLD
def commission_parse(self): # Name # This is different from CN, EN has longer names area = area_offset((176, 23, 420, 51), self.area[0:2]) button = Button(area=area, color=(), button=area, name='COMMISSION') ocr = Ocr(button, lang='cnocr', back=(74, 97, 148), use_binary=False) self.button = button self.name = ocr.ocr(self.image) self.genre = self.commission_name_parse(self.name) # Duration time area = area_offset((290, 74, 390, 92), self.area[0:2]) button = Button(area=area, color=(), button=area, name='DURATION') ocr = Ocr(button, lang='stage', back=(57, 85, 132)) self.duration = self.parse_time(ocr.ocr(self.image)) # Expire time area = area_offset((-49, 68, -45, 84), self.area[0:2]) button = Button(area=area, color=(189, 65, 66), button=area, name='IS_URGENT') if button.appear_on(self.image): area = area_offset((-49, 73, 45, 91), self.area[0:2]) button = Button(area=area, color=(), button=area, name='EXPIRE') ocr = Ocr(button, lang='stage', back=(189, 65, 66)) self.expire = self.parse_time(ocr.ocr(self.image)) else: self.expire = None # Status area = area_offset((179, 71, 187, 93), self.area[0:2]) dic = {0: 'finished', 1: 'running', 2: 'pending'} self.status = dic[int(np.argmax(get_color(self.image, area)))]
def check_screen_black(self): if self._screen_black_checked: return True # Check screen color # May get a pure black screenshot on some emulators. color = get_color(self.image, area=(0, 0, 1280, 720)) if sum(color) < 1: if self.config.Emulator_ScreenshotMethod == 'uiautomator2': logger.warning( f'Received pure black screenshots from emulator, color: {color}' ) logger.warning('Uninstall minicap and retry') self.uninstall_minicap() self._screen_black_checked = False return False else: logger.critical( f'Received pure black screenshots from emulator, color: {color}' ) logger.critical( f'Screenshot method `{self.config.Emulator_ScreenshotMethod}` ' f'may not work on emulator `{self.serial}`') logger.critical('Please use other screenshot methods') raise RequestHumanTakeover else: self._screen_black_checked = True return True
def check_screen(self): """ Screen size must be 1280x720. Take a screenshot before call. """ # Check screen size width, height = self.image.size logger.attr('Screen_size', f'{width}x{height}') if not (width == 1280 and height == 720): logger.critical(f'Resolution not supported: {width}x{height}') logger.critical('Please set emulator resolution to 1280x720') raise RequestHumanTakeover # Check screen color # May get a pure black screenshot on some emulators. color = get_color(self.image, area=(0, 0, 1280, 720)) if sum(color) < 1: logger.critical( f'Received pure black screenshots from emulator, color: {color}' ) logger.critical( f'Screenshot method `{self.config.Emulator_ScreenshotMethod}` ' f'may not work on emulator `{self.serial}`') logger.critical('Please use other screenshot methods') raise RequestHumanTakeover
def commission_parse(self): # Name area = area_offset((176, 23, 420, 53), self.area[0:2]) button = Button(area=area, color=(), button=area, name='COMMISSION') ocr = Ocr(button, lang='cnocr', threshold=256) self.button = button self.name = ocr.ocr(self.image) self.genre = self.commission_name_parse(self.name) # Duration time area = area_offset((290, 68, 390, 95), self.area[0:2]) button = Button(area=area, color=(), button=area, name='DURATION') ocr = Ocr(button, alphabet='0123456789:') self.duration = self.parse_time(ocr.ocr(self.image)) # Expire time area = area_offset((-49, 68, -45, 84), self.area[0:2]) button = Button(area=area, color=(189, 65, 66), button=area, name='IS_URGENT') if button.appear_on(self.image): area = area_offset((-49, 67, 45, 94), self.area[0:2]) button = Button(area=area, color=(), button=area, name='EXPIRE') ocr = Ocr(button, alphabet='0123456789:') self.expire = self.parse_time(ocr.ocr(self.image)) else: self.expire = None # Status area = area_offset((179, 71, 187, 93), self.area[0:2]) dic = {0: 'finished', 1: 'running', 2: 'pending'} self.status = dic[int(np.argmax(get_color(self.image, area)))]
def check_screen(self): """ Screen size must be 1280x720. Take a screenshot before call. """ # Check screen size width, height = self.image.size if height > width: width, height = height, width logger.attr('Screen_size', f'{width}x{height}') if width == 1280 and height == 720: return True else: logger.warning(f'Not supported screen size: {width}x{height}') logger.warning('Alas requires 1280x720') logger.hr('Script end') exit(1) # Check screen color # May get a pure black screenshot on some emulators. color = get_color(self.image, area=(0, 0, 1280, 720)) if sum(color) < 1: logger.warning('Received a pure black screenshot') logger.warning(f'Color: {color}') exit(1)
def _extract(image, file): size = image_size(image) if size != (1280, 720): logger.warning(f'{file} has wrong resolution: {size}') bbox = get_bbox(image) mean = get_color(image=image, area=bbox) mean = tuple(np.rint(mean).astype(int)) return bbox, mean
def is_active(self): color = get_color(image=self.device.image, area=DAILY_ACTIVE.area) color = np.array(color).astype(float) color = (np.max(color) + np.min(color)) / 2 active = color > 30 if active: logger.attr(f'Daily_{self.daily_current}', 'active') else: logger.attr(f'Daily_{self.daily_current}', 'inactive') return active
def campaign_predict_mode(self): """ Returns: str: 'normal' or 'hard' """ color = get_color(self.device.image, MODE_CHANGE.area) if np.max(color) - np.min(color) < 50: logger.warning(f'Unexpected color: {color}') index = np.argmax(color) # R, G, B if index == 0: return 'normal' # Red button. (214, 117, 115) elif index == 2: return 'hard' # Blue button. (115, 146, 214) else: logger.warning(f'Unexpected color: {color}')
def _get_archives_entrance(self, name): """ Create entrance button to target archive campaign using a template acquired by event folder name Args: name(str): event folder name """ template = dic_archives_template[name] sim, point = template.match_result(self.device.image) if sim < 0.85: return None button = area_offset(area=(-12, -12, 44, 32), offset=point) color = get_color(self.device.image, button) entrance = Button(area=button, color=color, button=button, name=name) return entrance
def _research_has_finished_at(self, button): """ Args: button (Button): Returns: bool: True if a research finished """ color = get_color(self.device.image, button.area) if np.max(color) - np.min(color) < 40: logger.warning(f'Unexpected color: {color}') index = np.argmax(color) # R, G, B if index == 1: return True # Green elif index == 2: return False # Blue else: logger.warning(f'Unexpected color: {color}') return False
def _tactical_animation_running(self): """ Returns: bool: If showing skill points increasing animation. """ color_height = np.mean(self.device.image.crop((922, 0, 1036, 720)).convert('L'), axis=1) parameters = {'height': 200} peaks, _ = signal.find_peaks(color_height, **parameters) peaks = [y for y in peaks if y > 67 + 243] if not len(peaks): logger.warning('No student card found.') for y in peaks: student_area = (447, y - 243, 1244, y) area = area_offset((677, 172, 761, 183), student_area[0:2]) # Normal: 160, In skill-increasing animation: 109 if np.mean(get_color(self.device.image, area)) < 135: return True return False
def _get_archives_entrance(self, name): """ Create entrance button to target archive campaign using a template acquired by event folder name TODO: Each server have different selectable campaign Need something similar to commission to scroll or turn page. CN/JP have more than 4 atm. Args: name(str): event folder name """ template = dic_archives_template[name] sim, point = template.match_result(self.device.image) if sim < 0.85: raise CampaignNameError button = area_offset(area=(-12, -12, 44, 32), offset=point) color = get_color(self.device.image, button) entrance = Button(area=button, color=color, button=button, name=name) return entrance
def _retirement_choose(self, amount=10, target_rarity=('N', )): """ Args: amount (int): Amount of cards retire. 0 to 10. target_rarity (tuple(str)): Card rarity. N, R, SR, SSR. Returns: int: Amount of cards have retired. """ cards = [] rarity = [] for x, y, button in CARD_RARITY_GRIDS.generate(): card_color = get_color(image=self.device.image, area=button.area) f = False for r, rarity_color in CARD_RARITY_COLORS.items(): if color_similar(card_color, rarity_color, threshold=15): cards.append([x, y]) rarity.append(r) f = True if not f: logger.warning( f'Unknown rarity color. Grid: ({x}, {y}). Color: {card_color}' ) logger.info(' '.join([r.rjust(3) for r in rarity[:7]])) logger.info(' '.join([r.rjust(3) for r in rarity[7:]])) selected = 0 for card, r in zip(cards, rarity): if r in target_rarity: self.device.click(CARD_GRIDS[card]) self.device.sleep((0.1, 0.15)) selected += 1 if selected >= amount: break return selected
def check_screen_black(self): if self._screen_black_checked: return True # Check screen color # May get a pure black screenshot on some emulators. color = get_color(self.image, area=(0, 0, 1280, 720)) if sum(color) < 1: if self.config.Emulator_Serial == 'wsa-0': for _ in range(2): display = self.get_display_id() if display == 0: return True logger.info(f'Game running on display {display}') logger.warning( 'Game not running on display 0, will be restarted') self.app_stop_uiautomator2(self.config.Emulator_PackageName) return False elif self.config.Emulator_ScreenshotMethod == 'uiautomator2': logger.warning( f'Received pure black screenshots from emulator, color: {color}' ) logger.warning('Uninstall minicap and retry') self.uninstall_minicap() self._screen_black_checked = False return False else: logger.critical( f'Received pure black screenshots from emulator, color: {color}' ) logger.critical( f'Screenshot method `{self.config.Emulator_ScreenshotMethod}` ' f'may not work on emulator `{self.serial}`') logger.critical('Please use other screenshot methods') raise RequestHumanTakeover else: self._screen_black_checked = True return True
def battle_pass_red_dot_appear(self): """ Returns: bool: If appear. Page: in: page_reward """ if self.appear(REWARD_GOTO_BATTLE_PASS, offset=(10, 150)): # Load button offset from REWARD_GOTO_BATTLE_PASS, # because entrance may not be the top one. BATTLE_PASS_RED_DOT.load_offset(REWARD_GOTO_BATTLE_PASS) # Not using self.appear() here, because it's transparent, # color may be different depending on background. r, _, _ = get_color(self.device.image, BATTLE_PASS_RED_DOT.area) if r > BATTLE_PASS_RED_DOT.color[0] - 40: logger.info('Found battle pass red dot') return True else: logger.info('No battle pass red dot') return False else: logger.warning('No battle pass entrance') return False
def extract(file): image = load_image(file) bbox = get_bbox(image) mean = get_color(image=image, area=bbox) mean = tuple(np.rint(mean).astype(int)) return bbox, mean
def _ambush_appear(self): return red_overlay_transparency(MAP_AMBUSH.color, get_color(self.device.image, MAP_AMBUSH.area)) > \ self.MAP_AMBUSH_OVERLAY_TRANSPARENCY_THRESHOLD
def _air_raid_appear(self): return red_overlay_transparency(MAP_AIR_RAID.color, get_color(self.device.image, MAP_AIR_RAID.area)) > \ self.MAP_AIR_RAID_OVERLAY_TRANSPARENCY_THRESHOLD