diff --git a/assets/cn/battle_pass/REWARD_RECEIVE_SP.png b/assets/cn/battle_pass/REWARD_RECEIVE_SP.png new file mode 100644 index 000000000..3e4640c5a Binary files /dev/null and b/assets/cn/battle_pass/REWARD_RECEIVE_SP.png differ diff --git a/assets/en/battle_pass/REWARD_RECEIVE_SP.png b/assets/en/battle_pass/REWARD_RECEIVE_SP.png new file mode 100644 index 000000000..dfcf5a76f Binary files /dev/null and b/assets/en/battle_pass/REWARD_RECEIVE_SP.png differ diff --git a/assets/jp/battle_pass/BATTLE_PASS_RED_DOT.png b/assets/jp/battle_pass/BATTLE_PASS_RED_DOT.png new file mode 100644 index 000000000..6ce917a5c Binary files /dev/null and b/assets/jp/battle_pass/BATTLE_PASS_RED_DOT.png differ diff --git a/assets/jp/battle_pass/PURCHASE_POPUP.png b/assets/jp/battle_pass/PURCHASE_POPUP.png new file mode 100644 index 000000000..9010ce4fb Binary files /dev/null and b/assets/jp/battle_pass/PURCHASE_POPUP.png differ diff --git a/assets/jp/battle_pass/REWARD_RECEIVE_SP.png b/assets/jp/battle_pass/REWARD_RECEIVE_SP.png new file mode 100644 index 000000000..8dc02620a Binary files /dev/null and b/assets/jp/battle_pass/REWARD_RECEIVE_SP.png differ diff --git a/assets/shop/general/FoodT6_2.png b/assets/shop/general/FoodT6_2.png new file mode 100644 index 000000000..3e75b38a6 Binary files /dev/null and b/assets/shop/general/FoodT6_2.png differ diff --git a/assets/shop/guild_cn/FoodT6_2.png b/assets/shop/guild_cn/FoodT6_2.png new file mode 100644 index 000000000..3e75b38a6 Binary files /dev/null and b/assets/shop/guild_cn/FoodT6_2.png differ diff --git a/assets/shop/medal/FoodT6_2.png b/assets/shop/medal/FoodT6_2.png new file mode 100644 index 000000000..3e75b38a6 Binary files /dev/null and b/assets/shop/medal/FoodT6_2.png differ diff --git a/assets/tw/battle_pass/BATTLE_PASS_RED_DOT.png b/assets/tw/battle_pass/BATTLE_PASS_RED_DOT.png new file mode 100644 index 000000000..6ce917a5c Binary files /dev/null and b/assets/tw/battle_pass/BATTLE_PASS_RED_DOT.png differ diff --git a/assets/tw/battle_pass/PURCHASE_POPUP.png b/assets/tw/battle_pass/PURCHASE_POPUP.png new file mode 100644 index 000000000..9010ce4fb Binary files /dev/null and b/assets/tw/battle_pass/PURCHASE_POPUP.png differ diff --git a/module/battle_pass/assets.py b/module/battle_pass/assets.py index a960555a0..cab239b9b 100644 --- a/module/battle_pass/assets.py +++ b/module/battle_pass/assets.py @@ -4,6 +4,7 @@ from module.base.template import Template # This file was automatically generated by dev_tools.button_extract. # Don't modify it manually. -BATTLE_PASS_RED_DOT = Button(area={'cn': (623, 105, 629, 113), 'en': (623, 105, 629, 113), 'jp': (623, 105, 629, 113), 'tw': (623, 105, 629, 113)}, color={'cn': (202, 86, 66), 'en': (202, 86, 66), 'jp': (202, 86, 66), 'tw': (202, 86, 66)}, button={'cn': (623, 105, 629, 113), 'en': (623, 105, 629, 113), 'jp': (623, 105, 629, 113), 'tw': (623, 105, 629, 113)}, file={'cn': './assets/cn/battle_pass/BATTLE_PASS_RED_DOT.png', 'en': './assets/en/battle_pass/BATTLE_PASS_RED_DOT.png', 'jp': './assets/cn/battle_pass/BATTLE_PASS_RED_DOT.png', 'tw': './assets/cn/battle_pass/BATTLE_PASS_RED_DOT.png'}) -PURCHASE_POPUP = Button(area={'cn': (907, 204, 934, 229), 'en': (907, 204, 934, 229), 'jp': (907, 204, 934, 229), 'tw': (907, 204, 934, 229)}, color={'cn': (176, 130, 110), 'en': (176, 130, 110), 'jp': (176, 130, 110), 'tw': (176, 130, 110)}, button={'cn': (907, 204, 934, 229), 'en': (907, 204, 934, 229), 'jp': (907, 204, 934, 229), 'tw': (907, 204, 934, 229)}, file={'cn': './assets/cn/battle_pass/PURCHASE_POPUP.png', 'en': './assets/en/battle_pass/PURCHASE_POPUP.png', 'jp': './assets/cn/battle_pass/PURCHASE_POPUP.png', 'tw': './assets/cn/battle_pass/PURCHASE_POPUP.png'}) +BATTLE_PASS_RED_DOT = Button(area={'cn': (623, 105, 629, 113), 'en': (623, 105, 629, 113), 'jp': (623, 105, 629, 113), 'tw': (623, 105, 629, 113)}, color={'cn': (202, 86, 66), 'en': (202, 86, 66), 'jp': (202, 86, 66), 'tw': (202, 86, 66)}, button={'cn': (623, 105, 629, 113), 'en': (623, 105, 629, 113), 'jp': (623, 105, 629, 113), 'tw': (623, 105, 629, 113)}, file={'cn': './assets/cn/battle_pass/BATTLE_PASS_RED_DOT.png', 'en': './assets/en/battle_pass/BATTLE_PASS_RED_DOT.png', 'jp': './assets/jp/battle_pass/BATTLE_PASS_RED_DOT.png', 'tw': './assets/tw/battle_pass/BATTLE_PASS_RED_DOT.png'}) +PURCHASE_POPUP = Button(area={'cn': (907, 204, 934, 229), 'en': (907, 204, 934, 229), 'jp': (907, 204, 934, 229), 'tw': (907, 204, 934, 229)}, color={'cn': (176, 130, 110), 'en': (176, 130, 110), 'jp': (176, 130, 110), 'tw': (176, 130, 110)}, button={'cn': (907, 204, 934, 229), 'en': (907, 204, 934, 229), 'jp': (907, 204, 934, 229), 'tw': (907, 204, 934, 229)}, file={'cn': './assets/cn/battle_pass/PURCHASE_POPUP.png', 'en': './assets/en/battle_pass/PURCHASE_POPUP.png', 'jp': './assets/jp/battle_pass/PURCHASE_POPUP.png', 'tw': './assets/tw/battle_pass/PURCHASE_POPUP.png'}) REWARD_RECEIVE = Button(area={'cn': (1192, 520, 1255, 536), 'en': (1192, 522, 1254, 534), 'jp': (1192, 520, 1255, 536), 'tw': (1192, 520, 1255, 536)}, color={'cn': (191, 178, 163), 'en': (195, 182, 168), 'jp': (191, 178, 163), 'tw': (191, 178, 163)}, button={'cn': (1192, 520, 1255, 536), 'en': (1192, 522, 1254, 534), 'jp': (1192, 520, 1255, 536), 'tw': (1192, 520, 1255, 536)}, file={'cn': './assets/cn/battle_pass/REWARD_RECEIVE.png', 'en': './assets/en/battle_pass/REWARD_RECEIVE.png', 'jp': './assets/cn/battle_pass/REWARD_RECEIVE.png', 'tw': './assets/cn/battle_pass/REWARD_RECEIVE.png'}) +REWARD_RECEIVE_SP = Button(area={'cn': (1105, 579, 1184, 597), 'en': (1090, 580, 1197, 596), 'jp': (1091, 599, 1171, 618), 'tw': (1105, 579, 1184, 597)}, color={'cn': (178, 143, 126), 'en': (168, 129, 111), 'jp': (168, 127, 109), 'tw': (178, 143, 126)}, button={'cn': (1105, 579, 1184, 597), 'en': (1090, 580, 1197, 596), 'jp': (1091, 599, 1171, 618), 'tw': (1105, 579, 1184, 597)}, file={'cn': './assets/cn/battle_pass/REWARD_RECEIVE_SP.png', 'en': './assets/en/battle_pass/REWARD_RECEIVE_SP.png', 'jp': './assets/jp/battle_pass/REWARD_RECEIVE_SP.png', 'tw': './assets/cn/battle_pass/REWARD_RECEIVE_SP.png'}) diff --git a/module/battle_pass/battle_pass.py b/module/battle_pass/battle_pass.py index 5c371b80b..ac069eb63 100644 --- a/module/battle_pass/battle_pass.py +++ b/module/battle_pass/battle_pass.py @@ -72,6 +72,9 @@ class BattlePass(Combat, UI): 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 diff --git a/module/device/control.py b/module/device/control.py index af3ae4a97..4e6825862 100644 --- a/module/device/control.py +++ b/module/device/control.py @@ -1,7 +1,7 @@ import time from collections import deque -from retrying import retry +from retry import retry from module.base.timer import Timer from module.base.utils import * @@ -79,11 +79,11 @@ class Control(MiniTouch): else: self._click_adb(x, y) - @retry() + @retry(tries=10, delay=3, logger=logger) def _click_uiautomator2(self, x, y): self.device.click(int(x), int(y)) - @retry() + @retry(tries=10, delay=3, logger=logger) def _click_adb(self, x, y): self.adb_shell(['input', 'tap', str(x), str(y)]) diff --git a/module/device/screenshot.py b/module/device/screenshot.py index 51deca38d..5883873a7 100644 --- a/module/device/screenshot.py +++ b/module/device/screenshot.py @@ -6,7 +6,7 @@ from io import BytesIO from PIL import Image from cached_property import cached_property -from retrying import retry +from retry import retry from module.base.timer import Timer, timer from module.device.ascreencap import AScreenCap @@ -51,7 +51,7 @@ class Screenshot(AScreenCap): screenshot = self.adb_shell(['screencap', '-p']) return self._process_screenshot(screenshot) - # @retry(wait_fixed=5000, stop_max_attempt_number=10) + @retry(tries=10, delay=3, logger=logger) @timer def screenshot(self): """ diff --git a/module/os/globe_zone.py b/module/os/globe_zone.py index 5300a5cff..96f29a101 100644 --- a/module/os/globe_zone.py +++ b/module/os/globe_zone.py @@ -2,7 +2,6 @@ import numpy as np from module.base.decorator import cached_property from module.exception import ScriptError -from module.logger import logger from module.map.map_grids import SelectedGrids from module.os.globe_detection import GLOBE_MAP_SHAPE from module.os.map_data import DIC_OS_MAP @@ -88,11 +87,16 @@ class ZoneManager: def name_to_zone(self, name): """ + Convert a name from various format to zone instance. + Args: name (str, int, Zone): Name in CN/EN/JP/TW, zone id, or Zone instance. Returns: Zone: + + Raises: + ScriptError: If Unable to find such zone. """ if isinstance(name, Zone): return name @@ -115,7 +119,6 @@ class ZoneManager: return zone if name == parse_name(zone.tw): return zone - logger.warning(f'Unable to find OS globe zone: {name}') raise ScriptError(f'Unable to find OS globe zone: {name}') def zone_nearest_azur_port(self, zone): diff --git a/module/os/map_operation.py b/module/os/map_operation.py index 7324899aa..129225523 100644 --- a/module/os/map_operation.py +++ b/module/os/map_operation.py @@ -1,7 +1,7 @@ from module.base.decorator import Config from module.base.timer import Timer from module.base.utils import * -from module.exception import ScriptError +from module.exception import ScriptError, MapDetectionError from module.logger import logger from module.ocr.ocr import Ocr from module.os.assets import * @@ -89,17 +89,58 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle """ Returns: Zone: - """ - if not self.is_in_map(): - logger.warning('Trying to get zone name, but not in OS map') - raise ScriptError('Trying to get zone name, but not in OS map') + Raises: + MapDetectionError: If failed to parse zone name. + """ name = self.get_zone_name() logger.info(f'Map name processed: {name}') - self.zone = self.name_to_zone(name) + try: + self.zone = self.name_to_zone(name) + except ScriptError as e: + raise MapDetectionError(*e.args) logger.attr('Zone', self.zone) return self.zone + def zone_init(self, skip_first_screenshot=True): + """ + Wrap get_current_zone(), set self.zone to the current zone. + This method must be called after entering a new zone. + Handle map events and the animation that zone names appear from the top. + + Args: + skip_first_screenshot (bool): + + Returns: + Zone: Current zone. + + Raises: + MapDetectionError: If failed to parse zone name. + """ + timeout = Timer(1.5, count=5).start() + while 1: + if skip_first_screenshot: + skip_first_screenshot = False + else: + self.device.screenshot() + + if self.handle_map_event(): + timeout.reset() + continue + if self.is_in_map(): + try: + return self.get_current_zone() + except MapDetectionError: + continue + + if timeout.reached(): + logger.warning('Zone init timeout') + break + + if not self.is_in_map(): + logger.warning('Trying to get zone name, but not in OS map') + return self.get_current_zone() + def is_in_special_zone(self): """ Returns: @@ -144,4 +185,4 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle changed = True continue - self.get_current_zone() + self.zone_init() diff --git a/module/os/operation_siren.py b/module/os/operation_siren.py index eaee4df3c..cf4ce260f 100644 --- a/module/os/operation_siren.py +++ b/module/os/operation_siren.py @@ -25,30 +25,13 @@ class OperationSiren(Reward, OSMap): logger.info('Already in os map') elif self.is_in_globe(): self.os_globe_goto_map() - # Zone header has an animation to show. - self.device.sleep(0.3) - self.device.screenshot() else: if self.ui_page_appear(page_os): self.ui_goto_main() self.ui_ensure(page_os) - # Zone header has an animation to show. - self.device.sleep(0.3) - self.device.screenshot() # Init - _get_current_zone_success = False - for _ in range(5): - try: - self.get_current_zone() - _get_current_zone_success = True - break - except: - self.handle_map_event() - finally: - self.device.screenshot() - if not _get_current_zone_success: - self.get_current_zone() + self.zone_init() # self.map_init() self.hp_reset() @@ -117,7 +100,7 @@ class OperationSiren(Reward, OSMap): # IN_MAP if hasattr(self, 'zone'): del self.zone - self.get_current_zone() + self.zone_init() # Fleet repairs before starting if needed self.handle_fleet_repair(revert=False) # self.map_init() @@ -245,7 +228,7 @@ class OperationSiren(Reward, OSMap): if not result: break - self.get_current_zone() + self.zone_init() if result > 1: self.globe_goto(self.zone, refresh=True) self.run_auto_search() @@ -369,7 +352,7 @@ class OperationSiren(Reward, OSMap): self.config.task_delay(server_update=True) self.config.task_stop() - self.get_current_zone() + self.zone_init() self.os_order_execute(recon_scan=True, submarine_call=self.config.OpsiObscure_CallSubmarine) # Delay next run 30min or 60min.