From 102b7eeaf7ff0ff6e233d2b396bf5151dd71c867 Mon Sep 17 00:00:00 2001 From: ArecaSapling <115386623+sui-feng-cb@users.noreply.github.com> Date: Wed, 18 Feb 2026 09:10:41 +0800 Subject: [PATCH 1/7] Upd: blueprint purchase for DR5 & PR6 (#5518) --- module/config/argument/args.json | 6 ++++-- module/config/argument/argument.yaml | 4 ++-- module/config/config_generated.py | 4 ++-- module/config/i18n/en-US.json | 6 ++++-- module/config/i18n/ja-JP.json | 6 ++++-- module/config/i18n/zh-CN.json | 6 ++++-- module/config/i18n/zh-TW.json | 6 ++++-- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/module/config/argument/args.json b/module/config/argument/args.json index ba6a6e53e..d54d06da8 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -7879,7 +7879,8 @@ "option": [ 2, 3, - 4 + 4, + 5 ] }, "ShipIndex": { @@ -7914,7 +7915,8 @@ 2, 3, 4, - 5 + 5, + 6 ] }, "ShipIndex": { diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index b0a79ab51..4cc3205db 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -541,7 +541,7 @@ CoreShop: ShipyardDr: ResearchSeries: value: 2 - option: [ 2, 3, 4 ] + option: [ 2, 3, 4, 5 ] ShipIndex: value: 0 option: [ 0, 1, 2, 3, 4, 5, 6 ] @@ -550,7 +550,7 @@ ShipyardDr: Shipyard: ResearchSeries: value: 1 - option: [ 1, 2, 3, 4, 5 ] + option: [ 1, 2, 3, 4, 5, 6 ] ShipIndex: value: 0 option: [ 0, 1, 2, 3, 4, 5, 6 ] diff --git a/module/config/config_generated.py b/module/config/config_generated.py index 808993bb1..7c057779a 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -297,13 +297,13 @@ class GeneratedConfig: CoreShop_Filter = 'Array' # Group `ShipyardDr` - ShipyardDr_ResearchSeries = 2 # 2, 3, 4 + ShipyardDr_ResearchSeries = 2 # 2, 3, 4, 5 ShipyardDr_ShipIndex = 0 # 0, 1, 2, 3, 4, 5, 6 ShipyardDr_BuyAmount = 2 ShipyardDr_LastRun = datetime.datetime(2020, 1, 1, 0, 0) # Group `Shipyard` - Shipyard_ResearchSeries = 1 # 1, 2, 3, 4, 5 + Shipyard_ResearchSeries = 1 # 1, 2, 3, 4, 5, 6 Shipyard_ShipIndex = 0 # 0, 1, 2, 3, 4, 5, 6 Shipyard_BuyAmount = 2 Shipyard_LastRun = datetime.datetime(2020, 1, 1, 0, 0) diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index adaa84ac0..3eb2b2788 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -1888,7 +1888,8 @@ "help": "", "2": "DR2", "3": "DR3", - "4": "DR4" + "4": "DR4", + "5": "DR5" }, "ShipIndex": { "name": "Ship Index", @@ -1922,7 +1923,8 @@ "2": "PR2", "3": "PR3", "4": "PR4", - "5": "PR5" + "5": "PR5", + "6": "PR6" }, "ShipIndex": { "name": "Ship Index", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 9fb20cc05..c0c0e82ab 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -1888,7 +1888,8 @@ "help": "ShipyardDr.ResearchSeries.help", "2": "2", "3": "3", - "4": "4" + "4": "4", + "5": "5" }, "ShipIndex": { "name": "ShipyardDr.ShipIndex.name", @@ -1922,7 +1923,8 @@ "2": "2", "3": "3", "4": "4", - "5": "5" + "5": "5", + "6": "6" }, "ShipIndex": { "name": "Shipyard.ShipIndex.name", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 4f94e0cc8..fe479362c 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -1888,7 +1888,8 @@ "help": "", "2": "二期科研", "3": "三期科研", - "4": "四期科研" + "4": "四期科研", + "5": "五期科研" }, "ShipIndex": { "name": "舰船序号", @@ -1922,7 +1923,8 @@ "2": "二期科研", "3": "三期科研", "4": "四期科研", - "5": "五期科研" + "5": "五期科研", + "6": "六期科研" }, "ShipIndex": { "name": "舰船序号", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 10fb4caac..e04b97219 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -1888,7 +1888,8 @@ "help": "", "2": "二期科研", "3": "三期科研", - "4": "四期科研" + "4": "四期科研", + "5": "五期科研" }, "ShipIndex": { "name": "艦船序號", @@ -1922,7 +1923,8 @@ "2": "二期科研", "3": "三期科研", "4": "四期科研", - "5": "五期科研" + "5": "五期科研", + "6": "六期科研" }, "ShipIndex": { "name": "艦船序號", From d99b759a08e69acac0927182e6dee243b4dc553d Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Wed, 18 Feb 2026 07:37:37 +0800 Subject: [PATCH 2/7] Fix: no poor sleep in fleet_preparation_sidebar_ensure --- module/handler/auto_search.py | 58 +++++++++++++---------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/module/handler/auto_search.py b/module/handler/auto_search.py index d5d098791..48e67dfbe 100644 --- a/module/handler/auto_search.py +++ b/module/handler/auto_search.py @@ -2,6 +2,7 @@ import numpy as np from module.base.button import ButtonGrid from module.base.decorator import Config +from module.base.timer import Timer from module.handler.assets import * from module.handler.enemy_searching import EnemySearchingHandler from module.logger import logger @@ -49,21 +50,14 @@ class AutoSearchHandler(EnemySearchingHandler): origin=(1185, 155 + offset), delta=(0, 111), button_shape=(53, 104), grid_shape=(1, 3), name='FLEET_SIDEBAR') - def _fleet_preparation_sidebar_click(self, index): + def _fleet_preparation_get(self): """ - Args: - index (int): + Returns: + int: 1 for formation 2 for meowfficers 3 for auto search setting - - Returns: - bool: If changed. """ - if index <= 0 or index > 3: - logger.warning(f'Sidebar index cannot be clicked, {index}, limit to 1 through 5 only') - return False - current = 0 total = 0 sidebar = self._fleet_sidebar() @@ -81,46 +75,38 @@ class AutoSearchHandler(EnemySearchingHandler): if not current: logger.warning('No fleet sidebar active.') logger.attr('Fleet_sidebar', f'{current}/{total}') - if current == index: - return False + return current - self.device.click(sidebar[0, index - 1]) - return True - - def fleet_preparation_sidebar_ensure(self, index, skip_first_screenshot=True): + def fleet_preparation_sidebar_ensure(self, index): """ Args: index (int): 1 for formation 2 for meowfficers 3 for auto search setting - skip_first_screenshot (bool): - Returns: - bool: whether sidebar could be ensured - at most 3 attempts are made before - return False otherwise True + Returns: + bool: whether sidebar could be ensured + at most 3 attempts are made before + return False otherwise True """ if index <= 0 or index > 5: logger.warning(f'Sidebar index cannot be ensured, {index}, limit 1 through 5 only') return False - counter = 0 - while 1: - if skip_first_screenshot: - skip_first_screenshot = False - else: - self.device.screenshot() - - if self._fleet_preparation_sidebar_click(index): - if counter >= 2: - logger.warning('Sidebar could not be ensured') - return False - counter += 1 - self.device.sleep((0.3, 0.5)) - continue - else: + interval = Timer(1, count=2) + sidebar = self._fleet_sidebar() + for _ in self.loop(timeout=3): + current = self._fleet_preparation_get() + if current == index: return True + if interval.reached(): + self.device.click(sidebar[0, index - 1]) + interval.reset() + continue + else: + logger.warning('Sidebar could not be ensured') + return False def _auto_search_set_click(self, setting): """ From 74bbaf8395605888687aae789cf9e3fe9ffaf478 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:57:50 +0800 Subject: [PATCH 3/7] Fix: first ui switch must be ui_ensure --- module/raid/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/raid/run.py b/module/raid/run.py index 2149b9891..d9a26050b 100644 --- a/module/raid/run.py +++ b/module/raid/run.py @@ -95,7 +95,7 @@ class RaidRun(Raid, CampaignEvent): # UI switches if not self._raid_has_oil_icon: - self.ui_goto(page_campaign_menu) + self.ui_ensure(page_campaign_menu) if self.triggered_stop_condition(oil_check=True, coin_check=True): break From 986d825a81cbf30e140ed4c443604635f096432a Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:58:10 +0800 Subject: [PATCH 4/7] Fix: [EN] UI switch to page_game_room --- module/minigame/minigame.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/module/minigame/minigame.py b/module/minigame/minigame.py index 6537dc1de..7af152045 100644 --- a/module/minigame/minigame.py +++ b/module/minigame/minigame.py @@ -3,8 +3,8 @@ from module.combat.assets import GET_ITEMS_1 from module.logger import logger from module.minigame.assets import * from module.ocr.ocr import Digit -from module.ui.assets import GAME_ROOM_CHECK -from module.ui.page import page_game_room +from module.ui.assets import ACADEMY_GOTO_GAME_ROOM, GAME_ROOM_CHECK +from module.ui.page import page_academy, page_game_room from module.ui.scroll import Scroll from module.ui.ui import UI @@ -131,6 +131,7 @@ class Minigame(UI): in: page_game_room main_page/choose_game_page out: page_game_room main_page """ + logger.info('minigame go_to_main_page') while 1: if skip_first_screenshot: skip_first_screenshot = False @@ -183,8 +184,19 @@ class Minigame(UI): in: Any page out: page_game_room """ + # TEMP: 2026.02.18 separate self.ui_ensure(page_game_room) into 2 steps + # EN has different page_academy detection, to use ui_ensure(page_game_room), + # ui_goto must use `if self.ui_page_appear(page)` instead of `if self.appear(page.check_button)` + # But that would cause page_main/page_main_white clicking a static switch button + self.ui_ensure(page_academy) + # page_academy -> page_game_room + for _ in self.loop(): + if self.ui_page_appear(page_game_room): + break + if self.ui_page_appear(page_academy, interval=5): + self.device.click(ACADEMY_GOTO_GAME_ROOM) + continue - self.ui_ensure(page_game_room) # game room and choose game have same header, go to game room first self.go_to_main_page() coin_collected = False From 0a4f2a89fc230b314c5b0e5caa64b5612b9072a0 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Thu, 19 Feb 2026 02:15:25 +0800 Subject: [PATCH 5/7] Fix: handle raid remain like "915/", "1515" --- module/raid/raid.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/module/raid/raid.py b/module/raid/raid.py index 126247a9c..2d160eb8a 100644 --- a/module/raid/raid.py +++ b/module/raid/raid.py @@ -15,6 +15,15 @@ from module.ui.assets import RAID_CHECK from module.ui.page import page_rpg_stage +class RaidCounterPostMixin(DigitCounter): + def after_process(self, result): + # fix result like "915/", "1515" + result = result.strip('/') + if result.isdigit() and len(result) > 2 and result.endswith('15'): + result = f'{result[:-2]}/15' + return result + + class RaidCounter(DigitCounter): def pre_process(self, image): image = super().pre_process(image) @@ -163,7 +172,7 @@ def raid_ocr(raid, mode): if mode == 'ex': return Digit(button, letter=(255, 239, 215), threshold=128) else: - return DigitCounter(button, lang='cnocr', letter=(154, 148, 133), threshold=128) + return RaidCounterPostMixin(button, lang='cnocr', letter=(154, 148, 133), threshold=128) def pt_ocr(raid): From a538739910e044ca9cee7bb047233d95f507e52f Mon Sep 17 00:00:00 2001 From: gepotumu <116505126+gepotumu@users.noreply.github.com> Date: Thu, 19 Feb 2026 02:19:08 +0800 Subject: [PATCH 6/7] Fix: infinite loop in _handle_use_box_amount when box count insufficient (#5516) When requesting more boxes than available (e.g. requesting 8 but only 3 in stack), the amount-setting loop would never exit because the UI caps at the available count while the script keeps clicking AMOUNT_PLUS. Added click_count tracking: if multi_click() has been called 2 times without the amount reaching the target, treat it as the UI cap and break. Also changed the return value from bool to the actual amount set, so _storage_use_one_box tracks the correct number of boxes used. --- module/storage/storage.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/module/storage/storage.py b/module/storage/storage.py index a18423c6a..62be757ff 100644 --- a/module/storage/storage.py +++ b/module/storage/storage.py @@ -45,8 +45,12 @@ class StorageHandler(StorageUI): def _handle_use_box_amount(self, amount): """ + Args: + amount (int): Expected amount to set + Returns: - bool: if clicked + int: Actual amount set in the UI. + May be less than expected if not enough boxes available. Pages: in: SHOP_BUY_CONFIRM_AMOUNT @@ -84,6 +88,7 @@ class StorageHandler(StorageUI): logger.info(f'Set box amount: {amount}') skip_first = True retry = Timer(1, count=2) + click_count = 0 for _ in self.loop(): if skip_first: skip_first = False @@ -92,13 +97,19 @@ class StorageHandler(StorageUI): diff = amount - current if diff == 0: break + if click_count >= 2: + logger.warning(f'Box amount stuck at {current}, ' + f'requested {amount} but only {current} available') + break if retry.reached(): button = AMOUNT_PLUS if diff > 0 else AMOUNT_MINUS self.device.multi_click(button, n=abs(diff), interval=(0.1, 0.2)) + click_count += 1 retry.reset() - return True + logger.info(f'Box amount set to {current}') + return current def _storage_use_one_box(self, button, amount=1): """ @@ -155,10 +166,10 @@ class StorageHandler(StorageUI): # use match_template_color on BOX_AMOUNT_CONFIRM # a long animation that opens a box, will be on the top of BOX_AMOUNT_CONFIRM if self.match_template_color(BOX_AMOUNT_CONFIRM, offset=(20, 20), interval=5): - self._handle_use_box_amount(amount) + actual = self._handle_use_box_amount(amount) self.device.click(BOX_AMOUNT_CONFIRM) self.interval_reset(BOX_AMOUNT_CONFIRM) - used = amount + used = actual continue if self.appear_then_click(EQUIP_CONFIRM, offset=(20, 20), interval=5): self.interval_reset(MATERIAL_CHECK) From c014140c6e915a4e9ceb58f563e3cdd886641538 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Thu, 19 Feb 2026 03:13:43 +0800 Subject: [PATCH 7/7] Fix: [CN] Remove more dash-like characters (fixed #5522) --- module/os/map_operation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/os/map_operation.py b/module/os/map_operation.py index 1330cdfcb..1f9ea5697 100644 --- a/module/os/map_operation.py +++ b/module/os/map_operation.py @@ -47,7 +47,7 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle name = ocr.ocr(self.device.image) name = "".join(name.split()) name = name.lower() - name = name.strip('\\/-') + name = name.strip('\\/-—–-') if '-' in name: name = name.split('-')[0] if 'é' in name: # Méditerranée name maps @@ -80,7 +80,7 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle # For JP only ocr = Ocr(MAP_NAME, lang='jp', letter=(157, 173, 192), threshold=127, name='OCR_OS_MAP_NAME') name = ocr.ocr(self.device.image) - name = name.strip('\\/-') + name = name.strip('\\/-—–-') self.is_zone_name_hidden = '安全' in name # Remove punctuations for char in '・': @@ -109,7 +109,7 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle # For TW only ocr = Ocr(MAP_NAME, lang='tw', letter=(198, 215, 239), threshold=127, name='OCR_OS_MAP_NAME') name = ocr.ocr(self.device.image) - name = name.strip('\\/-') + name = name.strip('\\/-—–-') self.is_zone_name_hidden = '安全' in name # Remove '塞壬要塞海域' if '塞' in name: @@ -123,7 +123,7 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle # For CN only ocr = Ocr(MAP_NAME, lang='cnocr', letter=(214, 231, 255), threshold=127, name='OCR_OS_MAP_NAME') name = ocr.ocr(self.device.image) - name = name.strip('\\/-') + name = name.strip('\\/-—–-') self.is_zone_name_hidden = '安全' in name if '-' in name: name = name.split('-')[0]