33# github https://github.com/runhey
44import time
55from time import sleep
6- import re
76
87from enum import Enum
98from cached_property import cached_property
@@ -61,16 +60,16 @@ def run(self):
6160
6261 def check_challenge_done (self ) -> bool :
6362 """
64- OCR识别现世逢魔顶部"今日挑战次数:X/1"
65- :return: True表示0/1今日已打过
63+ OCR识别现世逢魔顶部"今日挑战次数:剩余/总", 支持老号X/1与新号X/2
64+ DigitCounter 返回 (current, remain, total), current 即剩余次数
65+ :return: True表示剩余=0, 今日已打过
6666 """
67- results = self .O_DE_CHALLENGE_COUNT .detect_and_ocr (self .device .image )
68- text = '' .join (r .ocr_text for r in results )
69- m = re .search (r'([01])\s*/\s*1' , text )
70- if not m :
71- logger .warning (f'Challenge count not recognized: [{ text } ], continue by default' )
72- return False
73- return m .group (1 ) == '0'
67+ current , _remain , total = self .O_DE_CHALLENGE_COUNT .ocr (self .device .image )
68+ if total > 0 :
69+ logger .info (f'Demon encounter challenge count: { current } /{ total } ' )
70+ return current == 0
71+ logger .warning ('Challenge count not recognized, assume attempts remain' )
72+ return False
7473
7574 def checkout_soul (self ):
7675 """
@@ -94,40 +93,77 @@ def execute_boss(self):
9493 logger .hr ('Start boss battle' , 1 )
9594
9695 def find_boss ():
97- find_btn_clicked = False
98- timer_find_boss = Timer (10 * 60 )
99- timer_find_boss .start ()
100- while 1 :
96+ search_button = self .I_DE_BOSS_BEST if self .best_demon_enable else self .I_DE_BOSS
97+ boss_name = 'best boss' if self .best_demon_enable else 'normal boss'
98+
99+ # 每轮搜索前若中央有未购买的宝箱展示, 先点左下角定位(小指针)把它挪开;
100+ # 一整轮(2次搜索)都没找到则重进逢魔之时清状态, 最多3轮。
101+ for reenter_round in range (1 , 4 ):
101102 self .screenshot ()
102- if self .appear (self .I_BOSS_FIRE ) or self .appear (self .I_BEST_BOSS_FIRE ):
103- break
104- if timer_find_boss .reached ():
105- logger .warning ('find boss timeout' )
106- self .set_next_run (task = 'DemonEncounter' , success = False , finish = True , server = False )
107- raise TaskEnd ('DemonEncounter' )
108- if self .appear (self .I_JADE_50 ):
109- # 没找到boss但地图中央出现宝箱,导致点击宝箱出现50勾玉购买界面
110- self .ui_click_until_smt_disappear (self .I_DE_FIND , self .I_JADE_50 , interval = 1 )
111- continue
112- if find_btn_clicked and self .click (self .C_DM_BOSS_CLICK , interval = 5 ):
113- find_btn_clicked = False
114- continue
115- if self .best_demon_enable :
103+ if self .appear (self .I_DE_BOX_CENTER ):
104+ logger .info (
105+ f'Box display at map center, click location to reset view '
106+ f'(round { reenter_round } /3)'
107+ )
108+ self .appear_then_click (self .I_DE_LOCATION , interval = 2 )
109+ time .sleep (1 )
110+
111+ # 最多重新执行两轮“逢魔/极逢魔 -> 地图中央首领”的完整流程。
112+ for search_attempt in range (1 , 3 ):
116113 self .device .click_record_clear ()
117- if self .appear (self .I_DE_BOSS_BEST ) and (not find_btn_clicked ):
118- self .device .click_record_remove (self .I_DE_BOSS_BEST )
119- if self .click (self .I_DE_BOSS_BEST , interval = 4 ):
120- logger .info ("Finding best boss..." )
121- find_btn_clicked = True
122- continue
123- else :
124- if self .appear (self .I_DE_BOSS ) and (not find_btn_clicked ):
125- self .device .click_record_remove (self .I_DE_BOSS )
126- if self .click (self .I_DE_BOSS , interval = 4 ):
127- logger .info ("Finding normal boss..." )
128- find_btn_clicked = True
114+ self .screenshot ()
115+ if self .appear (self .I_BOSS_FIRE ) or self .appear (self .I_BEST_BOSS_FIRE ):
116+ return True
117+ # 没找到boss但地图中央出现宝箱, 导致点击宝箱出现50勾玉购买界面(事后补救)
118+ if self .appear (self .I_JADE_50 ):
119+ self .ui_click_until_smt_disappear (self .I_DE_FIND , self .I_JADE_50 , interval = 1 )
129120 continue
130- return True
121+ if not self .appear_then_click (search_button , interval = 2 ):
122+ raise GameStuckError (f'Cannot find { boss_name } search button' )
123+ logger .info (
124+ f'Finding { boss_name } , attempt { search_attempt } /2 '
125+ f'(re-enter round { reenter_round } /3)...'
126+ )
127+ time .sleep (1 )
128+
129+ # 每轮点击地图中央框选的红色“集结”区域至多两次,
130+ # 每次等待集结挑战标志5秒。
131+ for center_attempt in range (1 , 3 ):
132+ self .click (self .C_DM_BOSS_CLICK , interval = 2 )
133+ deadline = time .monotonic () + 5
134+ while time .monotonic () < deadline :
135+ self .screenshot ()
136+ if self .appear (self .I_BOSS_FIRE ) or self .appear (self .I_BEST_BOSS_FIRE ):
137+ logger .info (
138+ f'{ boss_name } gather appeared after center click '
139+ f'{ center_attempt } /2'
140+ )
141+ return True
142+ time .sleep (0.2 )
143+ logger .warning (
144+ f'{ boss_name } gather did not appear after center click '
145+ f'{ center_attempt } /2'
146+ )
147+
148+ # 本轮失败,返回逢魔地图,重新点击逢魔/极逢魔进行下一轮搜寻。
149+ self .screenshot ()
150+ if self .appear (self .I_UI_BACK_RED ):
151+ self .appear_then_click (self .I_UI_BACK_RED , interval = 2 )
152+ deadline = time .monotonic () + 5
153+ while time .monotonic () < deadline :
154+ self .screenshot ()
155+ if self .appear (search_button ):
156+ break
157+ time .sleep (0.2 )
158+
159+ # 2次搜索都没找到: 重进地图清状态, 最多3轮
160+ logger .info (f'Boss not found, re-enter demon encounter map (round { reenter_round } /3)' )
161+ self .goto_page (page_demon_encounter )
162+ self .goto_page (page_demon_encounter_realworld )
163+
164+ raise GameStuckError (
165+ f'Cannot enter { boss_name } after 3 re-enter rounds'
166+ )
131167
132168 def enter_boss ():
133169 logger .info ('trying to enter boss...' )
@@ -293,11 +329,13 @@ def check_lantern(self, index: int = 1):
293329 :param index: 四个灯笼,从1开始
294330 :return:
295331 """
332+ # 分类模板的搜索区(须容纳完整灯笼图案), 与点击区 C_DE_* 分离:
333+ # 点击区只包住内部图形, 模板放不进搜索区会全部误判成 battle
296334 match_roi = {
297- 1 : self .C_DE_1 .roi_front ,
298- 2 : self .C_DE_2 .roi_front ,
299- 3 : self .C_DE_3 .roi_front ,
300- 4 : self .C_DE_4 .roi_front ,
335+ 1 : self .C_DE_MATCH_1 .roi_front ,
336+ 2 : self .C_DE_MATCH_2 .roi_front ,
337+ 3 : self .C_DE_MATCH_3 .roi_front ,
338+ 4 : self .C_DE_MATCH_4 .roi_front ,
301339 }
302340 match_empty = {
303341 1 : self .I_DE_DEFEAT_1 ,
@@ -422,9 +460,10 @@ def answer():
422460 break
423461 # 如果没有出现红色关闭按钮,说明答题结束
424462 if not self .appear (self .I_LETTER_CLOSE ):
425- time .sleep (1.8 )
463+ time .sleep (2.5 )
426464 self .screenshot ()
427465 if not self .appear (self .I_LETTER_CLOSE ):
466+ self .ui_reward_appear_click ()
428467 logger .warning ('Answer finish' )
429468 return
430469
0 commit comments