Merge remote-tracking branch 'upstream/master'

This commit is contained in:
POLAR me 2025-02-13 22:45:16 +08:00
commit c1362531a8
13 changed files with 59 additions and 26 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -231,3 +231,4 @@ To add a new event, add a new row in here, and run `python -m module.config.conf
| 20250116 | raid 20250116 | Spring Fashion Festa | 华裳巧展喜事长 | Spring Fashion Festa | 新春華裳協奏曲 | - |
| 20250123 | raid 20250116 | Spring Fashion Festa | - | - | - | 華裳巧展喜事長 |
| 20250206 | event 20220818 cn | Operation Convergence Rerun | 复刻远汇点作战 | Operation Convergence Return | 結像点作戦(復刻) | - |
| 20250213 | event 20240815 cn | Windborne Steel Wings | - | - | - | 鐵翼擎風 |

View File

@ -17,14 +17,18 @@ class CampaignEvent(CampaignStatus):
tasks (list[str]): Task name
"""
with self.config.multi_set():
# Disable normal events
for task in tasks:
if task in ['GemsFarming']:
if task in GEMS_FARMINGS:
continue
keys = f'{task}.Scheduler.Enable'
logger.info(f'Disable task `{task}`')
self.config.cross_set(keys=keys, value=False)
for task in ['GemsFarming']:
# Reset GemsFarming
for task in tasks:
if task not in GEMS_FARMINGS:
continue
name = self.config.cross_get(keys=f'{task}.Campaign.Name', default='2-4')
if not self.stage_is_main(name):
logger.info(f'Reset GemsFarming to 2-4')
@ -51,7 +55,7 @@ class CampaignEvent(CampaignStatus):
if limit <= 0 or command not in tasks:
self.get_event_pt()
return False
if command == 'GemsFarming' and self.stage_is_main(self.config.Campaign_Name):
if command in GEMS_FARMINGS and self.stage_is_main(self.config.Campaign_Name):
self.get_event_pt()
return False
@ -77,7 +81,7 @@ class CampaignEvent(CampaignStatus):
command = self.config.Scheduler_Command
if command not in tasks or limit == DEFAULT_TIME:
return False
if command == 'GemsFarming' and self.stage_is_main(self.config.Campaign_Name):
if command in GEMS_FARMINGS and self.stage_is_main(self.config.Campaign_Name):
return False
now = datetime.now().replace(microsecond=0)
@ -141,7 +145,7 @@ class CampaignEvent(CampaignStatus):
"""
if self.appear(CAMPAIGN_MENU_NO_EVENT, offset=(20, 20)):
logger.info('Event unavailable, disable task')
tasks = EVENTS + COALITIONS + GEMS_FARMINGS
tasks = EVENTS + RAIDS + COALITIONS + GEMS_FARMINGS
self._disable_tasks(tasks)
self.config.task_stop()
else:
@ -190,6 +194,26 @@ class CampaignEvent(CampaignStatus):
self.ui_goto(page_coalition)
return True
def disable_raid_on_event(self):
"""
Disable raid tasks (or coalition) when entered an event,
to be foolproof if user forgot to disable raid tasks when raid is over and another event is ongoing
"""
command = self.config.Scheduler_Command
if command not in EVENTS + GEMS_FARMINGS:
return False
if command in GEMS_FARMINGS and self.stage_is_main(self.config.Campaign_Name):
return False
tasks = RAIDS + COALITIONS + MARITIME_ESCORTS
tasks = [t for t in tasks if self.config.is_task_enabled(t)]
if tasks:
logger.info('New event ongoing, disable old event tasks')
self._disable_tasks(tasks)
return True
else:
return False
@staticmethod
def stage_is_main(name) -> bool:
"""

View File

@ -434,6 +434,7 @@ class CampaignRun(CampaignEvent, ShopStatus):
self.campaign.ensure_campaign_ui(name=self.stage, mode=mode)
else:
self.campaign.ensure_campaign_ui(name=self.stage, mode=mode)
self.disable_raid_on_event()
self.handle_commission_notice()
# if in hard mode, check remain times

View File

@ -1944,12 +1944,12 @@
"display": "hide",
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",
@ -2290,12 +2290,12 @@
],
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",
@ -2751,12 +2751,12 @@
],
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",
@ -4653,12 +4653,12 @@
],
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",
@ -5135,12 +5135,12 @@
],
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",
@ -5617,12 +5617,12 @@
],
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",
@ -6099,12 +6099,12 @@
],
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",
@ -6581,12 +6581,12 @@
],
"option_bold": [
"event_20220818_cn",
"event_20231221_cn"
"event_20240815_cn"
],
"cn": "event_20220818_cn",
"en": "event_20220818_cn",
"jp": "event_20220818_cn",
"tw": "event_20231221_cn"
"tw": "event_20240815_cn"
},
"Mode": {
"type": "select",

View File

@ -969,7 +969,7 @@
"event_20240425_cn": "共鳴的PASSION",
"event_20240521_cn": "Light of the Martyrium",
"event_20240725_cn": "Interlude of Illusions",
"event_20240815_cn": "Windborne Steel Wings",
"event_20240815_cn": "鐵翼擎風",
"event_20240829_cn": "埋葬於彼岸之花",
"event_20240912_cn": "Ode of Everblooming Crimson",
"event_20241024_cn": "Tempesta and the Sleeping Sea",

View File

@ -54,7 +54,9 @@ class PlatformWindows(PlatformBase, EmulatorManager):
"""
command = command.replace(r"\\", "/").replace("\\", "/").replace('"', '"')
logger.info(f'Execute: {command}')
return subprocess.Popen(command, close_fds=True) # only work on Windows
# `close_fds` only work on Windows
# `start_new_session` to avoid emulator getting tree-killed when Alas gets killed
return subprocess.Popen(command, close_fds=True, start_new_session=True)
@classmethod
def kill_process_by_regex(cls, regex: str) -> int:

View File

@ -34,4 +34,4 @@ GUILD_REPORT_CLAIMED = Button(area={'cn': (738, 595, 1078, 637), 'en': (851, 602
GUILD_REPORT_CLOSE = Button(area={'cn': (1059, 93, 1102, 136), 'en': (1059, 93, 1102, 136), 'jp': (1059, 93, 1102, 136), 'tw': (1059, 93, 1102, 136)}, color={'cn': (71, 31, 32), 'en': (71, 31, 32), 'jp': (71, 31, 32), 'tw': (71, 31, 32)}, button={'cn': (1059, 93, 1102, 136), 'en': (1059, 93, 1102, 136), 'jp': (1059, 93, 1102, 136), 'tw': (1059, 93, 1102, 136)}, file={'cn': './assets/cn/guild/GUILD_REPORT_CLOSE.png', 'en': './assets/en/guild/GUILD_REPORT_CLOSE.png', 'jp': './assets/jp/guild/GUILD_REPORT_CLOSE.png', 'tw': './assets/tw/guild/GUILD_REPORT_CLOSE.png'})
GUILD_SUPPLY = Button(area={'cn': (1077, 617, 1233, 658), 'en': (1079, 619, 1231, 656), 'jp': (1077, 614, 1233, 655), 'tw': (1079, 619, 1231, 656)}, color={'cn': (84, 104, 154), 'en': (137, 87, 91), 'jp': (98, 100, 107), 'tw': (137, 87, 91)}, button={'cn': (1077, 617, 1233, 658), 'en': (1079, 619, 1231, 656), 'jp': (1077, 614, 1233, 655), 'tw': (1079, 619, 1231, 656)}, file={'cn': './assets/cn/guild/GUILD_SUPPLY.png', 'en': './assets/en/guild/GUILD_SUPPLY.png', 'jp': './assets/jp/guild/GUILD_SUPPLY.png', 'tw': './assets/tw/guild/GUILD_SUPPLY.png'})
OCR_GUILD_EXCHANGE_LIMIT = Button(area={'cn': (960, 383, 975, 403), 'en': (999, 383, 1018, 402), 'jp': (971, 384, 985, 403), 'tw': (962, 384, 975, 403)}, color={'cn': (59, 46, 47), 'en': (91, 93, 103), 'jp': (95, 101, 107), 'tw': (72, 57, 59)}, button={'cn': (960, 383, 975, 403), 'en': (999, 383, 1018, 402), 'jp': (971, 384, 985, 403), 'tw': (962, 384, 975, 403)}, file={'cn': './assets/cn/guild/OCR_GUILD_EXCHANGE_LIMIT.png', 'en': './assets/en/guild/OCR_GUILD_EXCHANGE_LIMIT.png', 'jp': './assets/jp/guild/OCR_GUILD_EXCHANGE_LIMIT.png', 'tw': './assets/tw/guild/OCR_GUILD_EXCHANGE_LIMIT.png'})
OCR_GUILD_OPERATIONS_PROGRESS = Button(area={'cn': (928, 501, 978, 521), 'en': (928, 501, 978, 521), 'jp': (928, 501, 978, 521), 'tw': (928, 501, 978, 521)}, color={'cn': (83, 88, 101), 'en': (83, 88, 101), 'jp': (83, 88, 101), 'tw': (83, 88, 101)}, button={'cn': (928, 501, 978, 521), 'en': (928, 501, 978, 521), 'jp': (928, 501, 978, 521), 'tw': (928, 501, 978, 521)}, file={'cn': './assets/cn/guild/OCR_GUILD_OPERATIONS_PROGRESS.png', 'en': './assets/en/guild/OCR_GUILD_OPERATIONS_PROGRESS.png', 'jp': './assets/jp/guild/OCR_GUILD_OPERATIONS_PROGRESS.png', 'tw': './assets/tw/guild/OCR_GUILD_OPERATIONS_PROGRESS.png'})
OCR_GUILD_OPERATIONS_PROGRESS = Button(area={'cn': (1064, 501, 1114, 521), 'en': (1064, 501, 1114, 521), 'jp': (1064, 501, 1114, 521), 'tw': (1064, 501, 1114, 521)}, color={'cn': (89, 94, 107), 'en': (89, 94, 107), 'jp': (89, 94, 107), 'tw': (89, 94, 107)}, button={'cn': (1064, 501, 1114, 521), 'en': (1064, 501, 1114, 521), 'jp': (1064, 501, 1114, 521), 'tw': (1064, 501, 1114, 521)}, file={'cn': './assets/cn/guild/OCR_GUILD_OPERATIONS_PROGRESS.png', 'en': './assets/cn/guild/OCR_GUILD_OPERATIONS_PROGRESS.png', 'jp': './assets/cn/guild/OCR_GUILD_OPERATIONS_PROGRESS.png', 'tw': './assets/cn/guild/OCR_GUILD_OPERATIONS_PROGRESS.png'})

View File

@ -189,6 +189,12 @@ class InfoHandler(ModuleBase):
if not self.device.app_is_running():
logger.error('Detected hot fixes from game server, game died')
raise GameNotRunningError
if self.match_template_color(LOGIN_CHECK, offset=(30, 30)):
logger.error('Account logged out, '
'probably because account kicked by server maintenance or another log in')
# Kill game, because game patches after maintenance can only be downloaded at game startup
self.device.app_stop()
raise GameNotRunningError
self._hot_fix_check_wait.clear()
return appear

View File

@ -204,8 +204,7 @@ class VoucherShop(ShopClerk, ShopStatus):
logger.info('Voucher Shop reach bottom, stop')
break
else:
# Only 4 rows of items at max, goto bottom directly
VOUCHER_SHOP_SCROLL.set_bottom(main=self)
VOUCHER_SHOP_SCROLL.next_page(main=self)
del_cached_property(self, 'shop_grid')
del_cached_property(self, 'shop_voucher_items')
continue