diff --git a/module/combat/level.py b/module/combat/level.py index 24714e6b0..f12a71320 100644 --- a/module/combat/level.py +++ b/module/combat/level.py @@ -2,7 +2,7 @@ from module.base.base import ModuleBase from module.base.button import * from module.base.decorator import Config from module.logger import logger -from module.ocr.ocr import Ocr +from module.ocr.ocr import Digit LV_GRID_MAIN = ButtonGrid(origin=(58, 118), delta=(0, 100), button_shape=(46, 19), grid_shape=(1, 3)) LV_GRID_VANGUARD = ButtonGrid(origin=(58, 420), delta=(0, 100), button_shape=(46, 19), grid_shape=(1, 3)) @@ -72,13 +72,7 @@ class Level(ModuleBase): return False -class LevelOcr(Ocr): - # Ocr's default argument 'threshold=128' makes some digits too thin to be recognized. - # Use 'threshold=191' instead. - def __init__(self, buttons, lang='azur_lane', letter=COLOR_WHITE, threshold=191, alphabet='0123456789', - name='LevelOcr'): - super().__init__(buttons, lang=lang, letter=letter, threshold=threshold, alphabet=alphabet, name=name) - +class LevelOcr(Digit): def pre_process(self, image): # Check the max value of red channel to find out whether the image is masked. # It would be no larger than COLOR_MASKED[0]=107 iff masked. @@ -90,16 +84,20 @@ class LevelOcr(Ocr): scalar = np.mean(COLOR_WHITE) / np.mean(COLOR_MASKED) image = cv2.addWeighted(image, scalar, image, 0, 0) - image = super().pre_process(image) + # Deal with the blue background of chars before converting to greyscale. + # The background is semi-transparent. It turns (0, 0, 0) to (33, 65, 115), and (255, 255, 255) + # to (107, 138, 189). We use the middle point (70, 102, 152). + bg = (70, 102, 152) + # BT.601 + luma_trans = (0.299, 0.587, 0.114) + luma_bg = np.dot(bg, luma_trans) + image = cv2.subtract(image, (*bg, 0)).dot(luma_trans).round().astype(np.uint8) + image = cv2.subtract(255, cv2.multiply(image, 255 / (255 - luma_bg))) # Find 'L' to strip 'LV.'. # Ruturn an empty image if 'L' is not found. letter_l = np.nonzero(image[2:15, :].max(axis=0) < 127)[0] if len(letter_l): - return image[:, letter_l[0] + 17:] - else: - return np.array([[255]], dtype=np.uint8) - - def after_process(self, result): - result = super().after_process(result) - - return int(result) if result else -1 + first_digit = letter_l[0] + 17 + if first_digit + 3 < LV_GRID_MAIN.button_shape[0]: + return image[:, first_digit:] + return np.array([[255]], dtype=np.uint8) diff --git a/module/reward/meowfficer.py b/module/reward/meowfficer.py index e8c311ea9..3f20938c1 100644 --- a/module/reward/meowfficer.py +++ b/module/reward/meowfficer.py @@ -1,3 +1,4 @@ +from module.base.timer import Timer from module.combat.assets import GET_ITEMS_1 from module.logger import logger from module.ocr.ocr import Digit, DigitCounter @@ -48,33 +49,34 @@ class RewardMeowfficer(UI): next_button=MEOWFFICER_BUY_NEXT, skip_first_screenshot=True) return True - def meow_confirm(self, skip_first_screenshot=True): + def meow_confirm(self): """ Pages: in: MEOWFFICER_BUY out: page_meowfficer """ - executed = False - while 1: - if skip_first_screenshot: - skip_first_screenshot = False - else: - self.device.screenshot() + # Here uses a simple click, to avoid clicking MEOWFFICER_BUY multiple times. + # Retry logic is in meow_buy() + self.device.click(MEOWFFICER_BUY) + + confirm_timer = Timer(1, count=2).start() + while 1: + self.device.screenshot() - if self.appear_then_click(MEOWFFICER_BUY, interval=5): - continue if self.appear_then_click(MEOWFFICER_BUY_CONFIRM, interval=5): continue if self.appear_then_click(MEOWFFICER_BUY_SKIP, interval=5): continue if self.appear(GET_ITEMS_1): self.device.click(MEOWFFICER_BUY_SKIP) - executed = True continue # End - if executed and self.appear(MEOWFFICER_BUY): - break + if self.appear(MEOWFFICER_BUY): + if confirm_timer.reached(): + break + else: + confirm_timer.reset() self.ui_click(MEOWFFICER_GOTO_DORM, check_button=MEOWFFICER_BUY_ENTER, appear_button=MEOWFFICER_BUY, offset=None) @@ -85,9 +87,16 @@ class RewardMeowfficer(UI): out: page_main """ self.ui_ensure(page_meowfficer) - if self.meow_choose(count=self.config.BUY_MEOWFFICER): - self.meow_confirm() + for _ in range(3): + if self.meow_choose(count=self.config.BUY_MEOWFFICER): + self.meow_confirm() + else: + self.ui_goto_main() + return True + + logger.warning('Too many trial in meowfficer buy, stopped.') self.ui_goto_main() + return False def handle_meowfficer(self): """