|
|
@@ -0,0 +1,128 @@
|
|
|
+"""T7 — 五行之力: renwu_qwyd,33 → NPC10031 → func17_wxqh,1。"""
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
+import json
|
|
|
+import time
|
|
|
+from pathlib import Path
|
|
|
+
|
|
|
+from pipeline.ctx import PipelineContext, TaskResult
|
|
|
+
|
|
|
+TASK_TITLE = "T7 开启五行之力"
|
|
|
+
|
|
|
+_ASSETS = Path(__file__).resolve().parents[2] / "assets"
|
|
|
+_NPC_ID = "10031"
|
|
|
+_MENU_INDEX = 33
|
|
|
+_ZLIB_MAGIC = b"x\x9c"
|
|
|
+_SIGNAL_TASK = "新手指引五" # SC-1 大帧文本: 任务链推进(协议定案 §三.2)
|
|
|
+_SIGNAL_ITEM = b'"Index":50675' # SC-1 大帧文本: 五行珠入包(where=12)
|
|
|
+_TELEPORT_WAIT_S = 20.0
|
|
|
+_PANEL_WAIT_S = 10.0
|
|
|
+_PANEL_RECLICK_S = 5.0
|
|
|
+_SUCCESS_WAIT_S = 15.0
|
|
|
+_RESEND_WAIT_S = 10.0
|
|
|
+
|
|
|
+
|
|
|
+def _cs1011(ctx: PipelineContext, act: str) -> None:
|
|
|
+ """CS1011 QFunction 菜单 Act 帧(UserID=999999999 面板标准 ID)。"""
|
|
|
+ body = json.dumps({"UserID": "999999999", "Act": act,
|
|
|
+ "index": 999999999}, separators=(",", ":")).encode()
|
|
|
+ _ = ctx.conn.send_frame(1011, 0, 0, 0, ctx.sid, body)
|
|
|
+
|
|
|
+
|
|
|
+def _click_npc(ctx: PipelineContext) -> None:
|
|
|
+ """CS1010 点击五行 NPC 10031(menuIndex=33)。"""
|
|
|
+ body = json.dumps({"UserID": _NPC_ID, "index": _MENU_INDEX},
|
|
|
+ separators=(",", ":")).encode()
|
|
|
+ _ = ctx.conn.send_frame(1010, 0, 0, 0, ctx.sid, body)
|
|
|
+
|
|
|
+
|
|
|
+def _scan_batch_text(body: bytes) -> str | None:
|
|
|
+ """SC-1 大帧 zlib→decode6 后搜成功信号; 命中返回信号描述。
|
|
|
+
|
|
|
+ 双信号(协议定案 §三.2): ①[主线]新手指引五(任务链推进);
|
|
|
+ ②五行珠入包 Index=50675。坏帧(zlib/decode 失败)只跳过不致命。
|
|
|
+ """
|
|
|
+ import zlib
|
|
|
+
|
|
|
+ from pbot.codec.bitbuf import decode6
|
|
|
+
|
|
|
+ if body[:2] != _ZLIB_MAGIC:
|
|
|
+ return None
|
|
|
+ try:
|
|
|
+ raw = zlib.decompress(body)
|
|
|
+ # 协议定案 §四.1: QFunction 大帧 body 编码 = zlib → decode6 双层
|
|
|
+ variants = (raw, decode6(raw))
|
|
|
+ except Exception: # noqa: BLE001 — 坏帧不得中断任务
|
|
|
+ return None
|
|
|
+ for v in variants:
|
|
|
+ if _SIGNAL_TASK.encode() in v:
|
|
|
+ return "任务链推进至[主线]新手指引五"
|
|
|
+ if _SIGNAL_ITEM in v:
|
|
|
+ return "五行珠入包(Index=50675)"
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def _wait_success(ctx: PipelineContext, timeout: float) -> str | None:
|
|
|
+ """收帧窗口扫成功信号: SC-1 大帧文本 or 新 SC643 面板已消费。"""
|
|
|
+ from pbot.bot.runner import pump
|
|
|
+
|
|
|
+ deadline = time.time() + timeout
|
|
|
+ while time.time() < deadline:
|
|
|
+ frames = pump(ctx.conn, ctx.world, ctx.updater, 0.5)
|
|
|
+ for f in frames:
|
|
|
+ if f.msg_id == -1:
|
|
|
+ if sig := _scan_batch_text(f.body):
|
|
|
+ return sig
|
|
|
+ elif f.msg_id == 643:
|
|
|
+ # 独立 SC643 且 sMsg 不再含 yd_wxjh = 面板已被激活消费
|
|
|
+ dlg = ctx.world.npc_dialog
|
|
|
+ smsg = str(dlg.get("sMsg", "")) if dlg else ""
|
|
|
+ if "yd_wxjh" not in smsg:
|
|
|
+ return "五行面板已消费(SC643 无 yd_wxjh)"
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def run_task(ctx: PipelineContext) -> TaskResult:
|
|
|
+ """CS3031→传送盟重→点NPC10033→激活→扫双成功信号(超时重发一次)。"""
|
|
|
+ # 1) 任务面板体 + 前往(服务端自动传送盟重土城)
|
|
|
+ body = (_ASSETS / "cs3031_full.bin").read_bytes()
|
|
|
+ _ = ctx.conn.send_frame(3031, 0, 0, 0, ctx.sid, body)
|
|
|
+ time.sleep(1.2) # 黄金时序: 3031→1011 间隔≥1.2s
|
|
|
+ ctx.pump(0.5)
|
|
|
+ _cs1011(ctx, "@renwu_qwyd,33")
|
|
|
+ # 2) 等传送落地盟重(20s 未落地即失败, 不尝试跑图)
|
|
|
+ deadline = time.time() + _TELEPORT_WAIT_S
|
|
|
+ while time.time() < deadline:
|
|
|
+ ctx.pump(0.5)
|
|
|
+ if "土城" in ctx.world.me.map_name:
|
|
|
+ break
|
|
|
+ if "土城" not in ctx.world.me.map_name:
|
|
|
+ return TaskResult.fail(f"未落地盟重(当前 {ctx.world.me.map_name})")
|
|
|
+ ctx.checklist.note("五行: 已落地盟重, 点击 NPC 10031")
|
|
|
+ # 3) 点 NPC → 等面板(yd_wxjh); 显式时间戳 5s 无面板重点一次
|
|
|
+ _click_npc(ctx)
|
|
|
+ last_click = time.time()
|
|
|
+ deadline = last_click + _PANEL_WAIT_S
|
|
|
+ seen_panel = False
|
|
|
+ while time.time() < deadline:
|
|
|
+ ctx.pump(0.5)
|
|
|
+ dlg = ctx.world.npc_dialog
|
|
|
+ if dlg and "yd_wxjh" in str(dlg.get("sMsg", "")):
|
|
|
+ seen_panel = True
|
|
|
+ break
|
|
|
+ if time.time() - last_click >= _PANEL_RECLICK_S:
|
|
|
+ _click_npc(ctx)
|
|
|
+ last_click = time.time()
|
|
|
+ if not seen_panel:
|
|
|
+ return TaskResult.fail("五行面板未出现(SC643 无 yd_wxjh)")
|
|
|
+ # 4) 激活 → 等成功信号; 15s 无信号重发一次再等 10s
|
|
|
+ time.sleep(0.5)
|
|
|
+ _cs1011(ctx, "@func17_wxqh,1")
|
|
|
+ if sig := _wait_success(ctx, _SUCCESS_WAIT_S):
|
|
|
+ return TaskResult.done(sig)
|
|
|
+ ctx.log.warning("[T7] %.0fs 无成功信号 — 重发 @func17_wxqh,1 一次",
|
|
|
+ _SUCCESS_WAIT_S)
|
|
|
+ _cs1011(ctx, "@func17_wxqh,1")
|
|
|
+ if sig := _wait_success(ctx, _RESEND_WAIT_S):
|
|
|
+ return TaskResult.done(f"重发后: {sig}")
|
|
|
+ return TaskResult.fail("激活后 25s 未捕获成功信号(任务链/入包/面板消费均无)")
|