From f517c29579929cc870dd87149895e0431f7a8b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Mon, 23 Mar 2026 09:50:08 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E5=B7=A1=E9=80=BB=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=BC=98=E5=85=88=E4=B8=8A=E9=A9=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/auto_bot_move.cpython-311.pyc | Bin 13468 -> 13956 bytes __pycache__/coordinate_patrol.cpython-311.pyc | Bin 15325 -> 17598 bytes __pycache__/game_state.cpython-311.pyc | Bin 11529 -> 11617 bytes auto_bot_move.py | 10 +- coordinate_patrol.py | 50 +++++- game_state.py | 4 + game_state_config.json | 5 +- recorder/地狱火半岛剥皮310-375.json | 142 ++++++++++++++++++ screenshot/game_state.png | Bin 88 -> 667 bytes screenshot/game_state_combat.png | Bin 74 -> 91 bytes screenshot/game_state_flight_block.png | Bin 74 -> 87 bytes screenshot/game_state_follow.png | Bin 74 -> 84 bytes screenshot/game_state_hp.png | Bin 74 -> 90 bytes screenshot/game_state_logistics_death.png | Bin 74 -> 83 bytes screenshot/game_state_mp.png | Bin 74 -> 91 bytes screenshot/game_state_target.png | Bin 74 -> 88 bytes screenshot/game_state_x.png | Bin 74 -> 84 bytes screenshot/game_state_y.png | Bin 74 -> 83 bytes stuck_handler.py | 4 +- wow_multikey_gui.py | 24 +++ 20 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 recorder/地狱火半岛剥皮310-375.json diff --git a/__pycache__/auto_bot_move.cpython-311.pyc b/__pycache__/auto_bot_move.cpython-311.pyc index b20f60523e7e105368cecd6f072122b3172441b2..656a55bbd61ab5654a6672749ded1089ddd23d42 100644 GIT binary patch delta 2484 zcmZuyU2Gdw7M?r)w`0d{MLRue9nG5TT1&{J2)sc|K=AkxZjG8hmAHFgu_kBP8GKH(8O0`jh(@kuoa-zwYHr!%apV)5_~bjTd`Bg`#T#4MI`SPDRa$9R zJJ1`htfV%)fv9wND@;kFs#8r~72~$`IK{}iEQ_(-JJ3YJx3e2>BeNTsJ)4+5HOX&? zk}a{^$wwS*F*SLU;YQ)p9E>)}KHtUfi=Dpi9syb{Ce3%+`gVzCuv!3Jm5YV4D(gnU zP|a;6t)R%I!lG6)XbO@GC>RJ5gov`wYjYK7 zqj`X!l`nV(qA^mn7S%O}auxd$JTr3U)Dx2@r%uZglaGyW z__aKmcCD&ba0y*Qq%bA1xhk8{saDcyuvQ9KDZE%%tYR>R4!QbW-vgVkmjc>Ju#4Ys zeR{H;mUNb@@`Ac3Ibo1A0|fgB_7glrZ~#H_{VW*Bl4>`>9)2w-1u1>#LojXAGesES zE5SY%;}3!nHe8Q{hD4tal{S3-dsVET-R@;P+Z#wf_BCjlkx>rKIjZp7v&O4ohU$unqMB>+WzMH+CU4Hh{ z?v=!WM&iKj#4kSYUWpuSM2_A`rk5kP5;qdJ_Z<0rdZlx;(K))39BU-U?sVzzGJA&8j4R`AM79o}Wpr?`L!_ocNoG(PL zvY3^`VGLDb@HGDEbiH7+@pOEM&DGDw&)b)%eN1t-y3swWXZOz`Q!H0ETFL4$(?;j* zP*mI$_zk`adl4irJV9=pP{5NbTbm9tY0nazBbX*AAei10<7ecNsi~2%6L4?{8Od!$ zXF9B#433cH3;`9JY1a+43bQnyL(ts_KiT0XrFzd_duUrloM+-imIq*3A z5+y0!jOQtoO}B1f*%V48I6+e%s5;(mx>1{6fYX+NR*|i$F#S-g$cBbR165sxDSj_A z?0gJu;2eKgdNfS?3KfFK2^4~Z{C83&JxStv`lgHWof;WkO%qD|UsBpvBO{6wUgVx^ z3a^|@wvSz||0)}{?|hDU%cHfxWt@H}K!RAhDPhzCekB)c3p!3;mvpJqj__V>nhBu#e4WG8FZ=6?OwAOF4l>LD=rANr5` zD8}=)^x`25^!xr^*3OdyQhQJH4z<1@^JoFB1lCE*{OmxR2zLJbKy-;Z(b`$7<6w%W zE`m1*s2*T}!0O&pBw1f3tD|!?9VW2yeG?_qc1|;(M4Z*xo@NIdFBw*Trfar}A1N^4 zRWi9O97UwcGealT#dBH#l*tNSK~Sq2z{zBNPw%^rlr^PRQjfy>sGv^KNBQ{RSmf|+ xVT&KXHu&zqagp`i6}HBE7XRH(wNv%t-fnT*?qh-RM})sU5}fec{@%h6{|~lYOV0oR delta 2108 zcmZuxO>7%Q6rS0&9mkFx=hr`p6FX^|Y!bKmX&RA6xNb0$?;S==02_!&5fOt~ zy?O7=`+97*MnOsSnvX7L@RcSpuW*Be+OT*n4*qrGus zH;;WwVKw|_kkqRo;ty^dzKTdd4RZ`~erOB7;aZv8l&^criKpq>YipX=N_$2nb`)4hcgQ$uW3 zki_8i2v0(7Kn<;8o+|#87DhZq+o>pfC`8>Y+Yqg^IL)k6jMZS%S4dJ_Rnp0vs^~`2 zP>XMfts)K-Z#X^^cDlKZF_<&_QrDgK82KF8RFFRk}FJa?gM z9J5-INJ7agp4Fi>A`xnN@`6k`om?#NU<{qciq48hqI(+z)CRDfRr`)kG=NJ-uAt1T zi;{!(fMh2?AHXhvet-cElKY8Zs05-;fG&2+C;8y|w3~w|re@Q0C;QVE3s~X!tZybzm%VDQujUHi z%Ub8eg4d{FUwT50*UOAngjlRO(8o2Z*EI+_f+WWjh5Ss9rAzDw@w4vN)I8DX4oId{ z!!Fbx!-MR%djGaKS23#}i*~JM6e>hJ0AeiYZ(t+-+L#@bJw)Z@RC39DGObeT0A5vA zOJ{T=lhW7ul9R3Y6K&&Qz-pDX2$b1OR@I%H9a&q{&+hv>gzpdw2hLYVdv8fUMu+c2 zhcDXhIGcVAORORI3~!sG!FO@MGB?BzOPEgaKOLH!w*h+;isMu<-f-5o1cfz)xx!{$ z(^uYu^-bIqa)r$zTh%v3-VUansM+KqeSsgPy&NPLod7cqn&fHA(cK_82Jj+)3~(G^ zhJ)#v9Gy`T)6|rrnw+x(75*04Sht(+#yiUx9s+!;{H49od7mVlnas z=C{tb{9GoQ_zauu+}*!cPPA8wlp>l0b57mR3Q97YrK7NQQ&s1aryC2Yd3uoD>I~yU z?EB8Wjxlg3v)Zl$b&x?i3$P#HC4fPucXdQYfZVvKSq3+oPV8H|5GCw(SHztIB@Lj! z?shd{KeKno@TFpZcb#qfH1I8pmV=9Y`w61(U|G{j6F?DlA3 zv=i)?p1#^SPzQ$#HV%J$xI9EpuxM`tD{NnHTX3E;O*~`bsRgU2e!u$Z-Ro}+(JWi; z-S37N&x(=7As*;Yy=}OGJ?NE|T1#_my<#W12897E)f8@Sx;CFe3iE1Kr8JF_OrF1u z@RU(4OCcC~5CCR^9s+<#peq2-6*L9V0dN4odO2aJ#%T=p&?lv2T;h}|p41FVfCs&1 zmY0UiIAd6sH_PS<+%+}mGN?dO>2dZ~pTG5OAUCr6pK~~;k%g@KEWO4BFdh0ZYwsWN ywf}&&{Md5;2R#V^$L^u0<3ASv-^Zon#lyQ=g=* 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 diff --git a/__pycache__/game_state.cpython-311.pyc b/__pycache__/game_state.cpython-311.pyc index 1de3258699d42af7a0cb5c13641c533b053e67ed..40147b922b54985347e1272cf91767e8e0112ae7 100644 GIT binary patch delta 1849 zcmZ9MUuauZ7{GIKlXPj5H0j#3N%yBoTDRNLxj$taI=j{`-HL6dc6BVy-QC`MlHNAS z4d>phsZ&-(WC{hx0dZq68HgxzPU1vFMVJph`QU?$Blw5;5>OcUqQ1=UySMv;2lC4~ z-}jw!zw`Y$Z{&Z=Z+Sl)ZuP(jUHr!Qu-D_cjf;E3(ZJ%b&(Cl9IIp+qAw7I4n2+d@ ze7oMBkLuCaJo%U&19s>g!1eliV5i;*?9#h{aXk*~*1Lf{dJix`lX_y&i{D^*uZQ;P zNj^w+k`4R>Nk|*7ZsK*anQZ3okQC|TUyuw*@t?`AZb9nBix+VGbD+59;iw$s9o`c= zgJrW;v6V%-EF$i7-Yn^gMK#got{Ju2vZ5Aj%23=Wdw(GQ3>=f@2YttUDVXu|-gx7N z?;4rxhSh{vr%Y!jpB|f;5gs|n(3T|;5G9ZBEtp0{w2dFhO-vqACMKt{B0%egWm~KV zjS`3fel^g$A&vG?rATc>Gb;t7s8m&Zo(+L`E59AMLQ;*_TmB&XLm+5kTtrx-6?D`r z6fA1Xt&Xkm>4s*DpmH!fF*ZAObmoCKOy<{unNi0vNh=fuDTqMHRCTHgvS|6?%sw2< zais$_N=aQdYxg{22f$>w5o=xbk~F^@+O^>@2&@?3?-kES+V#|R^^<`Q7OpO=cvy=6 z8A{8J0eagv>K+?YY-T8yt=d#6Fte;MHVx`5-xuBuDJ+G5B2V(ekv_7U8J&n%*maxD@}bT` z+PP@FV6w7mD@C&F3>>){GZ z^M#(hq{grG44uVd5oC$&K&zdI-GB+%D*{GEht!D>tynci71h!VBPaWv1hPG7x)-qz z0QszytFq7ej$2d`WQ6Spo#g|Zx*wSiOFd2RXN>0(0e>BjX&g_yO9D}x#`xXj@Ig!? zdl7L40GDZ50*}lkOGr!R(!)1etA!9&C8!jm0>OF(Hl5*1y(NrG?=yk^m++_vq8))1 z%EE|Yg!>_WJUuk>9IlTcjwA8_(Oxo(&=7`ZDNcHv@0Eop349Ek|JWAfe!&0u&ZmgHac_n*a%Wm^CuNGr86Wzamrr!liC{0yEn z-Dx2?DWs}txrJh(HJKOT@xx=eTy{#yjZJ4~*qbQ!RiM(Hvr;Y(TCcHU58`NHEs=@lc1wjITwBe1Tqm41y{%U zmvYYzEN%B?!Y5GpY@joO`Rd>%x35!Zl?ME~ZhzU-Yb83uzJ?`% zpOxU>4}RMHYpnBDJaKDd-<__uu=kD!uoAqJY`nE?p2R|X$0g5ADLURQ-Ha39f1V)U Aa{vGU delta 1661 zcmZvcO>7%g5P@))B)_0I)Nc601Qh(V7Jr-?2#i^(9-`q(Z>kbd?HnY0KFHflLhzhU{7*kiDwpPjd@ zIQl@!bL^@+Shv_eB_zPEIs$IA(-0!ezH!9dK@__X1MCk+w6`Bb!!H(OUCgWHRiz+S zviceoK%Hb0Z5K&j{kyh1gt*zRGctf`!zL+t-EfKvix15$A3L6IxksNv>@R16gjvir z0I|-wy6yLadZK>P^|}QVcRZ71fyMX;Z09gPC@g?c!<@vAQZtYaQKyQi=~-PCSE*VO zDSZ^obL=I43f5fbe;~8$O>dlxvoE~K=6WlxkH?!1{QDdfvpKm)Q(%6WS$&VgPSU>b zZB~P9u(9BD1Py}Au$zA~oRSRt7WECCF0mJatAl1dp;eWZvbtEvmgH7gMWrm$by&Mp zw{?wK!0S{vPZGVLp$NfhSjHykVI0o@v}SzUw4Yt?o*~b%yWOJ!JS&6L=)E{=6fw>Y z_QY2(zjP8Yg_s6Fx~rv%U^AW3Flwx7Rj2oXq}c$c{@r}1mOU+t#q1{7Tc=5@Fr!?* z)bl=Z_&}t7mWoa<;Hl6WVgmpnx7C!gq}DXUT2pKL<8I~Eg9QR6Q7J=8&cLD?`zl(* z-S;jzlAGv?M|cr#gaHCNRt!5;t7XY-6Cq+)E2`G4lnTx!YX(36$XqJ5cuY*qJ+_#pFQeL4hI%%S z#jxho4Z4HwUqj^3Y+tL0l?}sQYJT!Lc4bKD{=bYzU^=@y)HN7C3QwyAD_N?^`&x!x zhFRz8!}q*mg&zJ)NG%V7LLi1!hQJ>Lxr(LZy8Y#~+b{0?dimn5?XyD6EdJ)zg4dN{ z)0L8JIP&^tMb_wBsB%{}p)8w~OP^=y1BcRwK;LYjw^2$WVhFRd%(BM|#k>{FE;bv) zOuZSV(JqRZ98omv6{?hVnqxm6=x??+){(i#KieNDsZzBl&(a&9!+Trvv%Znfy?cBc gZ`tDj+s?ht`fnp^q{BHg&v7?7|9sGTGeCg<00wK7D*ylh diff --git a/auto_bot_move.py b/auto_bot_move.py index 0ea037e..6ca2d19 100644 --- a/auto_bot_move.py +++ b/auto_bot_move.py @@ -5,7 +5,7 @@ import sys import time import pydirectinput -from game_state import parse_game_state +from game_state import parse_game_state, load_layout_config from coordinate_patrol import CoordinatePatrol from death_manager import DeathManager from logistics_manager import LogisticsManager @@ -91,7 +91,13 @@ class AutoBotMove: if waypoints is None: path = waypoints_path or get_config_path(WAYPOINTS_FILE) waypoints = load_waypoints(path) or DEFAULT_WAYPOINTS - self.patrol_controller = CoordinatePatrol(waypoints) + layout = load_layout_config() + self.patrol_controller = CoordinatePatrol( + waypoints, + mount_key=str(layout.get("mount_key", "x") or "x"), + mount_hold_sec=float(layout.get("mount_hold_sec", 1.6)), + mount_retry_after_sec=float(layout.get("mount_retry_after_sec", 2.0)), + ) self.death_manager = DeathManager(self.patrol_controller) vendor_file = vendor_path or get_config_path('vendor.json') self.logistics_manager = LogisticsManager(vendor_file) diff --git a/coordinate_patrol.py b/coordinate_patrol.py index 278e85f..e14f2f5 100644 --- a/coordinate_patrol.py +++ b/coordinate_patrol.py @@ -15,7 +15,6 @@ ANGLE_DEADZONE_DEG = 5.0 # 死区,此范围内不按 A/D、只按 W,减 # 随机行为:跳跃概率(每帧触发概率,0.005 ≈ 平均 200 帧一次) RANDOM_JUMP_PROB = 0.05 - class CoordinatePatrol: """按航点坐标巡逻,用 pyautogui 按键转向与前进。""" @@ -26,6 +25,9 @@ class CoordinatePatrol: angle_threshold_deg=ANGLE_THRESHOLD_DEG, angle_deadzone_deg=ANGLE_DEADZONE_DEG, random_jump_prob=RANDOM_JUMP_PROB, + mount_key="x", + mount_hold_sec=1.6, + mount_retry_after_sec=2.0, ): """ Args: @@ -33,6 +35,7 @@ class CoordinatePatrol: arrival_threshold: 到达判定距离(游戏坐标单位),默认 0.5 angle_threshold_deg: 朝向容差(度),超过此值才按 A/D 转向,默认 ANGLE_THRESHOLD_DEG angle_deadzone_deg: 转向死区(度),此范围内不按 A/D、只按 W,默认 ANGLE_DEADZONE_DEG + mount_key / mount_hold_sec / mount_retry_after_sec: 未上马时先上马(与 game_state_config / GUI 一致) """ self.waypoints = waypoints self.current_index = 0 @@ -43,6 +46,33 @@ class CoordinatePatrol: self.logger = logging.getLogger(__name__) self.last_turn_end_time = 0 # 最近一次结束 A/D 转向的时间,供卡死检测排除原地转向 self.stuck_handler = StuckHandler() + self._next_mount_allowed = 0.0 + self.mount_key = str(mount_key).strip() or "x" + self.mount_hold_sec = float(mount_hold_sec) + self.mount_retry_after_sec = float(mount_retry_after_sec) + + def _ensure_mounted(self, state): + """ + 已上马返回 True。 + 未上马则松开移动键、按住上马键 MOUNT_HOLD_SEC,本帧不走路;返回 False。 + state 无 mounted 字段时视为无法判断,不拦巡逻(兼容未开 LogicBeacon)。 + """ + if "mounted" not in state: + return True + if state.get("mounted"): + return True + self.stop_all() + now = time.time() + if now < self._next_mount_allowed: + return False + self.logger.info( + f">>> 未上马,先按 {self.mount_key} {self.mount_hold_sec:.1f}s 上马" + ) + pyautogui.keyDown(self.mount_key) + time.sleep(self.mount_hold_sec) + pyautogui.keyUp(self.mount_key) + self._next_mount_allowed = time.time() + self.mount_retry_after_sec + return False @staticmethod def get_distance(p1, p2): @@ -168,6 +198,9 @@ class CoordinatePatrol: self.stop_all() return + if not self._ensure_mounted(state): + return + # 2. 卡死检测:位移检测逻辑保持在巡逻中 if self.stuck_handler.check_stuck(state, self.last_turn_end_time): self.logger.error("!!! 检测到卡死,启动脱困程序 !!!") @@ -250,6 +283,9 @@ class CoordinatePatrol: self.stop_all() return False + if not self._ensure_mounted(state): + return False + # 1. 卡死检测 if self.stuck_handler.check_stuck(state, self.last_turn_end_time): self.stop_all() @@ -311,6 +347,7 @@ class CoordinatePatrol: """ 按 path 依次走完所有点后返回。每次调用都必须传入 path。 get_state: 可调用对象,每次调用返回当前状态 dict,需包含 'x','y','facing'。 + 若含 'mounted'(LogicBeacon),路径开始前会先上马,每段 navigate_to_point 也会校验。 path: [[x,y], ...] 或 [(x,y), ...](如 json.load 得到),本次要走的全部航点。 forward: True=正序(0→n),False=倒序(n→0)。 阻塞直到走完 path 中所有点或出错,走完返回 True。内含卡死检测。 @@ -321,6 +358,17 @@ class CoordinatePatrol: points = [(float(p[0]), float(p[1])) for p in path] if not forward: points = points[::-1] + + # 路径开始前:若 state 含 mounted 且未上马,先完成上马再逐点移动 + while True: + state = get_state() + if state is None: + self.stop_all() + return False + if self._ensure_mounted(state): + break + time.sleep(0.05) + for i, target in enumerate(points): self.logger.info(f">>> 路径点 {i + 1}/{len(points)}: {target}") while True: diff --git a/game_state.py b/game_state.py index d197438..f30f4cd 100644 --- a/game_state.py +++ b/game_state.py @@ -21,6 +21,10 @@ _DEFAULTS = { "scan_region_height": 15, "offset_left": 20, "offset_top": 45, + # 巡逻上马(coordinate_patrol,与 GUI「参数配置」一致) + "mount_key": "x", + "mount_hold_sec": 1.6, + "mount_retry_after_sec": 2.0, } SCREENSHOT_DIR = 'screenshot' diff --git a/game_state_config.json b/game_state_config.json index dc832e1..8da3a81 100644 --- a/game_state_config.json +++ b/game_state_config.json @@ -4,5 +4,8 @@ "scan_region_width": 190, "scan_region_height": 15, "offset_left": 20, - "offset_top": 45 + "offset_top": 45, + "mount_key": "x", + "mount_hold_sec": 1.6, + "mount_retry_after_sec": 2.0 } diff --git a/recorder/地狱火半岛剥皮310-375.json b/recorder/地狱火半岛剥皮310-375.json new file mode 100644 index 0000000..9fcc4ec --- /dev/null +++ b/recorder/地狱火半岛剥皮310-375.json @@ -0,0 +1,142 @@ +[ + [ + 12.1, + 54.99 + ], + [ + 11.62, + 54.79 + ], + [ + 11.16, + 54.54 + ], + [ + 10.82, + 54.13 + ], + [ + 10.54, + 53.7 + ], + [ + 10.3, + 53.24 + ], + [ + 10.06, + 52.75 + ], + [ + 9.82, + 52.31 + ], + [ + 9.55, + 51.86 + ], + [ + 9.42, + 51.35 + ], + [ + 9.39, + 50.83 + ], + [ + 9.24, + 50.35 + ], + [ + 9.15, + 49.85 + ], + [ + 9.5, + 49.44 + ], + [ + 9.94, + 49.14 + ], + [ + 10.38, + 48.85 + ], + [ + 10.81, + 48.56 + ], + [ + 11.23, + 48.26 + ], + [ + 11.65, + 47.94 + ], + [ + 12.11, + 47.65 + ], + [ + 12.59, + 47.49 + ], + [ + 12.54, + 48.01 + ], + [ + 12.44, + 48.53 + ], + [ + 12.32, + 49.03 + ], + [ + 12.2, + 49.54 + ], + [ + 12.1, + 50.07 + ], + [ + 12.1, + 50.6 + ], + [ + 12.33, + 51.1 + ], + [ + 12.55, + 51.59 + ], + [ + 12.68, + 52.11 + ], + [ + 12.78, + 52.62 + ], + [ + 12.86, + 53.12 + ], + [ + 12.83, + 53.65 + ], + [ + 12.76, + 54.17 + ], + [ + 12.1, + 54.99 + ] +] \ No newline at end of file diff --git a/screenshot/game_state.png b/screenshot/game_state.png index bb19555904b9fd7cfc7ecc4b35d2cbb2d6328387..f0d994607b53de0c6aafe5425df99a1cb6a31141 100644 GIT binary patch delta 642 zcmV-|0)72hn+1>~e*$7jL_t(|obA}Vj#DuZ2H=^oeXiN;Cd*!sB7~5TXlM{Zya~@k z$NTUaAUbHESc%)RS#tOB@nwcOWzr-<{`z13WlOfk`0n+KrL!|@XV!V)1P}p)g#h0F zoWhR2*0^f~0G>M8BL%YaTDvCz0ABU`q&~lSxohOvrw@B9fAsNYkKNm6Bi=rLRMd^C zN)YIKM?ttLtCCbfwA|P(^e#jeNwU{*X8*6yIn=tW8)Y;np`mF!r;F3EAsQ&{9dA0n z*|^TfLs!j?OYfXtZwPhO468v)Uv7Uix(+d1pPY}I=BlYqjR^t>`PRv{Fr!<{S9gC< z>9QJ--E`mYfA3D}A!>T^a55R6owvoPDPn%GvTadQmw0vitDF68Mq`~2qL0(XtgTuU zesVoA>Icjhf^_Jr*>UlbDo`%+;`3j-W-7V&Ibv7)k68D-$vj0~~ zW(hGETCMx#%{M|tL;ybe7=Pd10UF!;tI@@Sx;}K(f9$waCoQEq39kyZuvV`Uw??lZ zls*CYaL<#=D`oKU^}|C~&5lb&K*Q2nq|`fI5i)Or2SgFJfn)Tu)uJxSvM3H+H9Im& z8Ev#FL>Ek`dl1)mV^bpP+Nik;0xKlE9E}d$G&?TV1wcR$t&}pPk=YBbQ_uxftXr*I zh-0ut1PVMdKatwM=7wSCblK_r2>wE%fI&$bLoLIB(I#(G7l5r_q~ z5)trG3;_@+qIKULx@vY@gekI|)`|euF_B0FW?*6x%Tbg%DJ!Kks{F5$ZRsOxje(0n cT@?cV0I8@loZi9sd;kCd07*qoM6N<$g2YHP=l}o! delta 59 zcmbQu8ZklHltJFp#WAE}&f9~Aj0_A6hZcPG&txw{JPgg&e IbxsLQ012fKyZ`_I diff --git a/screenshot/game_state_combat.png b/screenshot/game_state_combat.png index 2da3e803ca4321469776e8b923e401aeb3b9c022..0359d24f881ced42bcce1935f66a57ae6839d38e 100644 GIT binary patch delta 60 zcmeZ@o}gl`!7rjcgTe~DWM4fR1*}- delta 43 xcmWIdnxLX4=;`7ZQZXkvL4tL0g2)A71_tI52FA=MGs_u(z|+;wWt~$(695kf3}gTR diff --git a/screenshot/game_state_follow.png b/screenshot/game_state_follow.png index 2da3e803ca4321469776e8b923e401aeb3b9c022..3f5cb771a156ad80d824719e8d3132bbf7fd5db3 100644 GIT binary patch delta 53 zcmeYYnV@1I?djqeQZXkvA>qe)2c-n1(8DX{1=>10@b6_{SZ={6vo866Is*`Ry85}S Ib4q9e0Q`0mLI3~& delta 43 xcmWIXnxLX4=;`7ZQZXkvL4tL0g2)A71_tI52FA=MGs_u(z|+;wWt~$(695i|3}FBO diff --git a/screenshot/game_state_hp.png b/screenshot/game_state_hp.png index 2da3e803ca4321469776e8b923e401aeb3b9c022..2d0c1fa121e40c160c176286f3835449bb3a95f3 100644 GIT binary patch delta 59 zcmeZ@nxJB)=;`7ZQZXla&)I_xDgl2#${$Kl3S$?NxN5vAeZ%X8;tUMtwal_hjAjWk O0D-5gpUXO@geCx}%WQZXml?;2b&+~PaHUKz@>>zLgK3Ns`L%77m715yuZOD``_!t QaRwmpboFyt=akR{02sF!IsgCw delta 43 xcma#{nxLX4=;`7ZQZXkvL4tL0g2)A71_tI52FA=MGs_u(z|+;wWt~$(695mh3}^rV diff --git a/screenshot/game_state_target.png b/screenshot/game_state_target.png index 2da3e803ca4321469776e8b923e401aeb3b9c022..704ad582e2760fe8c76502faca39dd31a8c9cd42 100644 GIT binary patch delta 57 zcmeZ@n4n@J@9E+gQZXm_&v^$agWo3)xGWN5V`~evU0lVsSFVbYp~H&Fr(|pC5e6Xe MboFyt=akR{0Ad6b6#xJL delta 43 xcma#>nxLX4=;`7ZQZXkvL4tL0g2)A71_tI52FA=MGs_u(z|+;wWt~$(695k~3}pZS diff --git a/screenshot/game_state_x.png b/screenshot/game_state_x.png index 2da3e803ca4321469776e8b923e401aeb3b9c022..d1b2d169bdb868847bf730ab9ee48ad616bd89e4 100644 GIT binary patch delta 53 zcmeYYnV@1I?djqeQZXm_37qLYpgEag?IzLfG7LcA>FVdQ I&MBb@0O?*4y8r+H delta 43 xcmWIXnxLX4=;`7ZQZXkvL4tL0g2)A71_tI52FA=MGs_u(z|+;wWt~$(695i|3}FBO diff --git a/screenshot/game_state_y.png b/screenshot/game_state_y.png index 2da3e803ca4321469776e8b923e401aeb3b9c022..5b8c1f9beb280948b1b1fdd3b03c380d380ad1f0 100644 GIT binary patch delta 52 zcmeYYo}i*H<>}%WQZXmlWLmm{sKLZF$sy-g%saTgJ&u7Pd>cc7TK~lv3_#%N>gTe~ HDWM4f@x&6f delta 43 xcmWIcnxLX4=;`7ZQZXkvL4tL0g2)A71_tI52FA=MGs_u(z|+;wWt~$(695id3}65N diff --git a/stuck_handler.py b/stuck_handler.py index 0bc5301..6ca69e3 100644 --- a/stuck_handler.py +++ b/stuck_handler.py @@ -69,11 +69,11 @@ class StuckHandler: pyautogui.keyDown(turn_key) # 倒车时间稍长一点,离开障碍物 - time.sleep(0.3) + time.sleep(0.5) # 3. 尝试跳跃脱离地形卡位 pyautogui.press("space") - time.sleep(0.3) + time.sleep(0.5) pyautogui.keyUp(turn_key) pyautogui.keyUp("s") diff --git a/wow_multikey_gui.py b/wow_multikey_gui.py index 21f24df..825437a 100644 --- a/wow_multikey_gui.py +++ b/wow_multikey_gui.py @@ -746,6 +746,24 @@ class WoWMultiKeyGUI(QMainWindow): self.skinning_wait_spin.setSuffix(" 秒") params_right.addRow("剥皮等待时间:", self.skinning_wait_spin) + self.gs_mount_key = QLineEdit() + self.gs_mount_key.setPlaceholderText("如 x") + self.gs_mount_key.setMaxLength(16) + self.gs_mount_key.setText("x") + self.gs_mount_hold = QDoubleSpinBox() + self.gs_mount_hold.setRange(0.1, 30.0) + self.gs_mount_hold.setSingleStep(0.1) + self.gs_mount_hold.setValue(1.6) + self.gs_mount_hold.setSuffix(" 秒") + self.gs_mount_retry = QDoubleSpinBox() + self.gs_mount_retry.setRange(0.0, 60.0) + self.gs_mount_retry.setSingleStep(0.1) + self.gs_mount_retry.setValue(2.0) + self.gs_mount_retry.setSuffix(" 秒") + params_right.addRow("上马按键 (mount_key):", self.gs_mount_key) + params_right.addRow("上马按住时长 (mount_hold_sec):", self.gs_mount_hold) + params_right.addRow("上马重试间隔 (mount_retry_after_sec):", self.gs_mount_retry) + params_row.addLayout(params_left) params_row.addLayout(params_right) params_layout.addWidget(params_content) @@ -780,6 +798,9 @@ class WoWMultiKeyGUI(QMainWindow): self.gs_scan_height.setValue(cfg.get('scan_region_height', 15)) self.gs_offset_left.setValue(cfg.get('offset_left', 20)) self.gs_offset_top.setValue(cfg.get('offset_top', 45)) + self.gs_mount_key.setText(str(cfg.get('mount_key', 'x') or 'x')) + self.gs_mount_hold.setValue(float(cfg.get('mount_hold_sec', 1.6))) + self.gs_mount_retry.setValue(float(cfg.get('mount_retry_after_sec', 2.0))) except Exception as e: self.log(f"加载参数配置失败: {e}") try: @@ -800,6 +821,9 @@ class WoWMultiKeyGUI(QMainWindow): cfg['scan_region_height'] = self.gs_scan_height.value() cfg['offset_left'] = self.gs_offset_left.value() cfg['offset_top'] = self.gs_offset_top.value() + cfg['mount_key'] = (self.gs_mount_key.text().strip() or 'x') + cfg['mount_hold_sec'] = float(self.gs_mount_hold.value()) + cfg['mount_retry_after_sec'] = float(self.gs_mount_retry.value()) path = save_layout_config(cfg) # bot 参数写入主配置文件 self.config = self.config or {}