@@ -327,10 +327,17 @@ def _perform_action(
327327 if context .tasker .stopping :
328328 return
329329
330- # 到达 bullet 阈值 → 暂停(所有暂停都用模板验证)
331- if not self ._pause (context , ctrl , lambda : context .tasker .stopping , ts = ts ):
332- self ._abort_reason = "pause failed"
333- return
330+ # 到达 bullet 阈值 → 暂停
331+ # 0 帧动作(开局部署):等 BattleOfficiallyBegin → 狂按 F → 等 Play.png
332+ # 非 0 帧动作:常规暂停确认 + R 验证
333+ if target_frame == 0 and current <= bullet_threshold :
334+ if not self ._pause_at_battle_start (context , ctrl , lambda : context .tasker .stopping ):
335+ self ._abort_reason = "pause failed"
336+ return
337+ else :
338+ if not self ._pause (context , ctrl , lambda : context .tasker .stopping , ts = ts , target_frame = target_frame ):
339+ self ._abort_reason = "pause failed"
340+ return
334341 if context .tasker .stopping :
335342 return
336343
@@ -410,17 +417,62 @@ def _detect_leak(self, context: Context, img: np.ndarray) -> bool:
410417
411418 # --- 暂停状态机(经 AFA 热键 + 模板验证) ---
412419
420+ def _pause_at_battle_start (
421+ self ,
422+ context : Context ,
423+ ctrl : Controller ,
424+ context_tasker_stopping : Callable [[], bool ],
425+ ) -> bool :
426+ """开局 0 帧暂停: 等 BattleOfficiallyBegin → 狂按 F → 等 Play.png.
427+
428+ 不发 R 验证, 避免 0 帧被推进.
429+ """
430+ # 1. 等 BattleOfficiallyBegin 出现 (战斗加载完成, 可操作)
431+ logger .debug ("开局暂停: 等待战斗加载完成" )
432+ for _ in range (50 ):
433+ if context_tasker_stopping ():
434+ return False
435+ time .sleep (0.2 )
436+ img = ctrl .post_screencap ().wait ().get ()
437+ reco = context .run_recognition ("Farm@BattleOn" , img )
438+ if reco and reco .hit :
439+ logger .debug ("开局暂停: 战斗已加载" )
440+ break
441+ else :
442+ logger .error ("开局暂停: 等待战斗加载超时" )
443+ return False
444+
445+ # 2. 狂按 F 直到 Play.png 出现
446+ for i in range (50 ):
447+ if context_tasker_stopping ():
448+ return False
449+ self ._tap_afa (afa_hotkey .VK_F , "F 开局暂停" )
450+ self ._paused = True
451+ time .sleep (0.03 )
452+ img = ctrl .post_screencap ().wait ().get ()
453+ reco = context .run_recognition ("BattlePaused" , img )
454+ if reco and reco .hit :
455+ logger .debug ("开局暂停成功 (Play.png 命中), attempt=%d" , i + 1 )
456+ return True
457+ logger .debug ("开局暂停: Play.png 未命中, attempt=%d" , i + 1 )
458+
459+ logger .error ("开局暂停: 按 F 50 次仍未暂停" )
460+ self ._paused = False
461+ return False
462+
413463 def _pause (
414464 self ,
415465 context : Context ,
416466 ctrl : Controller ,
417467 context_tasker_stopping : Callable [[], bool ],
418468 ts : TimeSource | None = None ,
469+ target_frame : int | None = None ,
419470 ) -> bool :
420471 """暂停游戏: BattlePaused 确认 + R 步进验证.
421472
422473 最多 2 次 F. 失败返回 False, 调用方中止本轮.
423474 ts 非空时, 每次模板命中后发一次测试 R 验证暂停是否真实.
475+ 非 0 帧动作进入时战斗已加载, 不需要等 BattleOfficiallyBegin.
424476 """
425477 if self ._paused :
426478 return True
@@ -442,16 +494,23 @@ def _pause(
442494 if reco and reco .hit :
443495 logger .debug ("暂停确认成功(模板命中), attempt=%d" , attempt + 1 )
444496 return self ._verify_pause_r (ctrl , ts , attempt )
497+ # 模板未命中且离目标较远时, 用 R 验证兜底
498+ # (R 会推进 1 帧, 离目标太近时不值得冒险)
499+ if ts is not None :
500+ remaining = target_frame - ts .total_elapsed_frames if target_frame is not None else 999
501+ if remaining > 3 :
502+ logger .debug ("模板未命中, 尝试 R 验证兜底, attempt=%d" , attempt + 1 )
503+ if self ._verify_pause_r (ctrl , ts , attempt ):
504+ logger .debug ("R 验证兜底成功, attempt=%d" , attempt + 1 )
505+ return True
445506 self ._paused = False
446- logger .warning ("暂停确认失败(模板未命中 ), attempt=%d" , attempt + 1 )
507+ logger .warning ("暂停确认失败(模板+R 均未通过 ), attempt=%d" , attempt + 1 )
447508 if context_tasker_stopping ():
448509 return False
449510 logger .error ("暂停确认失败: 中止本轮, 避免未暂停动作" )
450511 return False
451512
452- def _verify_pause_r (
453- self , ctrl : Controller , ts : TimeSource | None , attempt : int
454- ) -> bool :
513+ def _verify_pause_r (self , ctrl : Controller , ts : TimeSource | None , attempt : int ) -> bool :
455514 """BattlePaused 确认后, 用一次 R 验证暂停是否真实."""
456515 if ts is None :
457516 return True
0 commit comments