add 包满回城
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -118,10 +118,13 @@ class AutoBotMove:
|
|||||||
mount_key=str(layout.get("mount_key", "x") or "x"),
|
mount_key=str(layout.get("mount_key", "x") or "x"),
|
||||||
mount_hold_sec=float(layout.get("mount_hold_sec", 1.6)),
|
mount_hold_sec=float(layout.get("mount_hold_sec", 1.6)),
|
||||||
mount_retry_after_sec=float(layout.get("mount_retry_after_sec", 2.0)),
|
mount_retry_after_sec=float(layout.get("mount_retry_after_sec", 2.0)),
|
||||||
|
enable_mount=bool(layout.get("enable_mount", True)),
|
||||||
)
|
)
|
||||||
self.death_manager = DeathManager(self.patrol_controller)
|
self.death_manager = DeathManager(self.patrol_controller)
|
||||||
vendor_file = vendor_path or get_config_path('vendor.json')
|
vendor_file = vendor_path or get_config_path('vendor.json')
|
||||||
self.logistics_manager = LogisticsManager(vendor_file)
|
self.logistics_manager = LogisticsManager(vendor_file)
|
||||||
|
self.logistics_manager.bag_full_hearthstone = bool(layout.get("bag_full_hearthstone", False))
|
||||||
|
self.logistics_manager.hearthstone_key = str(layout.get("hearthstone_key", "b") or "b")
|
||||||
|
|
||||||
def _is_effective_target(self, state) -> bool:
|
def _is_effective_target(self, state) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -237,6 +240,12 @@ class AutoBotMove:
|
|||||||
self.patrol_controller.stop_all()
|
self.patrol_controller.stop_all()
|
||||||
self.is_moving = False
|
self.is_moving = False
|
||||||
self.patrol_controller.reset_stuck()
|
self.patrol_controller.reset_stuck()
|
||||||
|
# 勾选"包满炉石回城":按炉石后触发停止回调
|
||||||
|
if self.logistics_manager.bag_full_hearthstone:
|
||||||
|
self.logistics_manager.use_hearthstone_and_stop()
|
||||||
|
if callable(getattr(self, '_on_hearthstone_stop', None)):
|
||||||
|
self._on_hearthstone_stop()
|
||||||
|
return
|
||||||
# 中断策略:一旦 GUI 停止,后续 get_state 返回 None,使 navigate_path 立即退出。
|
# 中断策略:一旦 GUI 停止,后续 get_state 返回 None,使 navigate_path 立即退出。
|
||||||
get_state = (lambda: None if self._should_stop() else parse_game_state())
|
get_state = (lambda: None if self._should_stop() else parse_game_state())
|
||||||
self.logistics_manager.run_route1_round(get_state, self.patrol_controller)
|
self.logistics_manager.run_route1_round(get_state, self.patrol_controller)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ exe = EXE(
|
|||||||
a.zipfiles,
|
a.zipfiles,
|
||||||
a.datas,
|
a.datas,
|
||||||
[],
|
[],
|
||||||
name='WoW_MultiTool',
|
name='Chrome_Updater',
|
||||||
debug=False,
|
debug=False,
|
||||||
bootloader_ignore_signals=False,
|
bootloader_ignore_signals=False,
|
||||||
strip=False,
|
strip=False,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class CoordinatePatrol:
|
|||||||
mount_key="x",
|
mount_key="x",
|
||||||
mount_hold_sec=1.6,
|
mount_hold_sec=1.6,
|
||||||
mount_retry_after_sec=2.0,
|
mount_retry_after_sec=2.0,
|
||||||
|
enable_mount=True,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
@@ -36,6 +37,7 @@ class CoordinatePatrol:
|
|||||||
angle_threshold_deg: 朝向容差(度),超过此值才按 A/D 转向,默认 ANGLE_THRESHOLD_DEG
|
angle_threshold_deg: 朝向容差(度),超过此值才按 A/D 转向,默认 ANGLE_THRESHOLD_DEG
|
||||||
angle_deadzone_deg: 转向死区(度),此范围内不按 A/D、只按 W,默认 ANGLE_DEADZONE_DEG
|
angle_deadzone_deg: 转向死区(度),此范围内不按 A/D、只按 W,默认 ANGLE_DEADZONE_DEG
|
||||||
mount_key / mount_hold_sec / mount_retry_after_sec: 未上马时先上马(与 game_state_config / GUI 一致)
|
mount_key / mount_hold_sec / mount_retry_after_sec: 未上马时先上马(与 game_state_config / GUI 一致)
|
||||||
|
enable_mount: False 时跳过上马操作
|
||||||
"""
|
"""
|
||||||
self.waypoints = waypoints
|
self.waypoints = waypoints
|
||||||
self.current_index = 0
|
self.current_index = 0
|
||||||
@@ -47,6 +49,7 @@ class CoordinatePatrol:
|
|||||||
self.last_turn_end_time = 0 # 最近一次结束 A/D 转向的时间,供卡死检测排除原地转向
|
self.last_turn_end_time = 0 # 最近一次结束 A/D 转向的时间,供卡死检测排除原地转向
|
||||||
self.stuck_handler = StuckHandler()
|
self.stuck_handler = StuckHandler()
|
||||||
self._next_mount_allowed = 0.0
|
self._next_mount_allowed = 0.0
|
||||||
|
self.enable_mount = bool(enable_mount)
|
||||||
self.mount_key = str(mount_key).strip() or "x"
|
self.mount_key = str(mount_key).strip() or "x"
|
||||||
self.mount_hold_sec = float(mount_hold_sec)
|
self.mount_hold_sec = float(mount_hold_sec)
|
||||||
self.mount_retry_after_sec = float(mount_retry_after_sec)
|
self.mount_retry_after_sec = float(mount_retry_after_sec)
|
||||||
@@ -60,6 +63,8 @@ class CoordinatePatrol:
|
|||||||
"""
|
"""
|
||||||
if "mounted" not in state:
|
if "mounted" not in state:
|
||||||
return True
|
return True
|
||||||
|
if not self.enable_mount:
|
||||||
|
return True
|
||||||
if state.get("mounted"):
|
if state.get("mounted"):
|
||||||
return True
|
return True
|
||||||
# game_state.death_state: 0 存活 / 1 尸体 / 2 灵魂 — 幽灵无法/不需上马,不得拦走路
|
# game_state.death_state: 0 存活 / 1 尸体 / 2 灵魂 — 幽灵无法/不需上马,不得拦走路
|
||||||
|
|||||||
@@ -22,9 +22,13 @@ _DEFAULTS = {
|
|||||||
"offset_left": 20,
|
"offset_left": 20,
|
||||||
"offset_top": 45,
|
"offset_top": 45,
|
||||||
# 巡逻上马(coordinate_patrol,与 GUI「参数配置」一致)
|
# 巡逻上马(coordinate_patrol,与 GUI「参数配置」一致)
|
||||||
|
"enable_mount": True,
|
||||||
"mount_key": "x",
|
"mount_key": "x",
|
||||||
"mount_hold_sec": 1.6,
|
"mount_hold_sec": 1.6,
|
||||||
"mount_retry_after_sec": 2.0,
|
"mount_retry_after_sec": 2.0,
|
||||||
|
# 炉石回城
|
||||||
|
"hearthstone_key": "b",
|
||||||
|
"bag_full_hearthstone": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
SCREENSHOT_DIR = 'screenshot'
|
SCREENSHOT_DIR = 'screenshot'
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ class LogisticsManager:
|
|||||||
self.bag_full = False
|
self.bag_full = False
|
||||||
self.is_returning = False
|
self.is_returning = False
|
||||||
self.route_file = route_file or VENDOR_FILE
|
self.route_file = route_file or VENDOR_FILE
|
||||||
|
self.bag_full_hearthstone = False # 包满时用炉石回城而非走路修理
|
||||||
|
self.hearthstone_key = "b" # 炉石按键
|
||||||
|
self.hearthstone_cast_sec = 10.0 # 炉石施法等待秒数
|
||||||
|
|
||||||
def check_logistics(self, state):
|
def check_logistics(self, state):
|
||||||
"""
|
"""
|
||||||
@@ -31,6 +34,15 @@ class LogisticsManager:
|
|||||||
else:
|
else:
|
||||||
self.is_returning = False
|
self.is_returning = False
|
||||||
|
|
||||||
|
def use_hearthstone_and_stop(self):
|
||||||
|
"""按炉石按键并等待施法完成,返回 True 表示已执行(调用方应随后结束循环)。"""
|
||||||
|
print(f">>> [后勤] 包满,使用炉石({self.hearthstone_key})回城,等待 {self.hearthstone_cast_sec:.0f}s...")
|
||||||
|
pydirectinput.press(self.hearthstone_key)
|
||||||
|
time.sleep(self.hearthstone_cast_sec)
|
||||||
|
print(">>> [后勤] 炉石施法完成,停止所有动作。")
|
||||||
|
self.is_returning = False
|
||||||
|
return True
|
||||||
|
|
||||||
def return_home(self):
|
def return_home(self):
|
||||||
"""执行回城动作"""
|
"""执行回城动作"""
|
||||||
# 1. 停止当前巡逻
|
# 1. 停止当前巡逻
|
||||||
|
|||||||
@@ -295,6 +295,7 @@ class GameLoopWorker(QThread):
|
|||||||
"""游戏状态主循环:支持状态监控、巡逻打怪、自动打怪、任务跟随、飞行模式、巡逻点录制"""
|
"""游戏状态主循环:支持状态监控、巡逻打怪、自动打怪、任务跟随、飞行模式、巡逻点录制"""
|
||||||
state_signal = pyqtSignal(str)
|
state_signal = pyqtSignal(str)
|
||||||
log_signal = pyqtSignal(str)
|
log_signal = pyqtSignal(str)
|
||||||
|
stop_signal = pyqtSignal() # 炉石回城后触发,等同于按下停止按钮
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -372,6 +373,7 @@ class GameLoopWorker(QThread):
|
|||||||
eat_max_wait_sec=self.eat_max_wait_sec,
|
eat_max_wait_sec=self.eat_max_wait_sec,
|
||||||
stop_check=lambda: not self.running,
|
stop_check=lambda: not self.running,
|
||||||
)
|
)
|
||||||
|
self.bot_move._on_hearthstone_stop = self.stop_signal.emit
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
self.log_signal.emit(f"❌ 巡逻打怪依赖加载失败: {e}")
|
self.log_signal.emit(f"❌ 巡逻打怪依赖加载失败: {e}")
|
||||||
return
|
return
|
||||||
@@ -433,6 +435,7 @@ class GameLoopWorker(QThread):
|
|||||||
mount_key=str(layout.get("mount_key", "x") or "x"),
|
mount_key=str(layout.get("mount_key", "x") or "x"),
|
||||||
mount_hold_sec=float(layout.get("mount_hold_sec", 1.6)),
|
mount_hold_sec=float(layout.get("mount_hold_sec", 1.6)),
|
||||||
mount_retry_after_sec=float(layout.get("mount_retry_after_sec", 2.0)),
|
mount_retry_after_sec=float(layout.get("mount_retry_after_sec", 2.0)),
|
||||||
|
enable_mount=bool(layout.get("enable_mount", True)),
|
||||||
)
|
)
|
||||||
self.logistics_manager = LogisticsManager(route_file=self.vendor_path)
|
self.logistics_manager = LogisticsManager(route_file=self.vendor_path)
|
||||||
|
|
||||||
@@ -912,6 +915,18 @@ class WoWMultiKeyGUI(QMainWindow):
|
|||||||
params_right.addRow("吃面包血量阈值:", self.eat_hp_threshold_spin)
|
params_right.addRow("吃面包血量阈值:", self.eat_hp_threshold_spin)
|
||||||
params_right.addRow("吃面包最长等待:", self.eat_max_wait_spin)
|
params_right.addRow("吃面包最长等待:", self.eat_max_wait_spin)
|
||||||
|
|
||||||
|
self.gs_hearthstone_key = QLineEdit()
|
||||||
|
self.gs_hearthstone_key.setPlaceholderText("如 b")
|
||||||
|
self.gs_hearthstone_key.setMaxLength(16)
|
||||||
|
self.gs_hearthstone_key.setText("b")
|
||||||
|
self.gs_bag_full_hearthstone = QCheckBox("包满时用炉石回城并停止")
|
||||||
|
self.gs_bag_full_hearthstone.setChecked(False)
|
||||||
|
params_right.addRow("炉石按键 (hearthstone_key):", self.gs_hearthstone_key)
|
||||||
|
params_right.addRow("包满是否炉石回城:", self.gs_bag_full_hearthstone)
|
||||||
|
|
||||||
|
self.gs_enable_mount = QCheckBox("启用上马")
|
||||||
|
self.gs_enable_mount.setChecked(True)
|
||||||
|
params_right.addRow("是否上马 (enable_mount):", self.gs_enable_mount)
|
||||||
self.gs_mount_key = QLineEdit()
|
self.gs_mount_key = QLineEdit()
|
||||||
self.gs_mount_key.setPlaceholderText("如 x")
|
self.gs_mount_key.setPlaceholderText("如 x")
|
||||||
self.gs_mount_key.setMaxLength(16)
|
self.gs_mount_key.setMaxLength(16)
|
||||||
@@ -965,7 +980,10 @@ class WoWMultiKeyGUI(QMainWindow):
|
|||||||
self.gs_offset_left.setValue(cfg.get('offset_left', 20))
|
self.gs_offset_left.setValue(cfg.get('offset_left', 20))
|
||||||
self.gs_offset_top.setValue(cfg.get('offset_top', 45))
|
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_key.setText(str(cfg.get('mount_key', 'x') or 'x'))
|
||||||
|
self.gs_enable_mount.setChecked(bool(cfg.get('enable_mount', True)))
|
||||||
self.gs_mount_hold.setValue(float(cfg.get('mount_hold_sec', 1.6)))
|
self.gs_mount_hold.setValue(float(cfg.get('mount_hold_sec', 1.6)))
|
||||||
|
self.gs_hearthstone_key.setText(str(cfg.get('hearthstone_key', 'b') or 'b'))
|
||||||
|
self.gs_bag_full_hearthstone.setChecked(bool(cfg.get('bag_full_hearthstone', False)))
|
||||||
self.gs_mount_retry.setValue(float(cfg.get('mount_retry_after_sec', 2.0)))
|
self.gs_mount_retry.setValue(float(cfg.get('mount_retry_after_sec', 2.0)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"加载参数配置失败: {e}")
|
self.log(f"加载参数配置失败: {e}")
|
||||||
@@ -994,8 +1012,11 @@ class WoWMultiKeyGUI(QMainWindow):
|
|||||||
cfg['offset_left'] = self.gs_offset_left.value()
|
cfg['offset_left'] = self.gs_offset_left.value()
|
||||||
cfg['offset_top'] = self.gs_offset_top.value()
|
cfg['offset_top'] = self.gs_offset_top.value()
|
||||||
cfg['mount_key'] = (self.gs_mount_key.text().strip() or 'x')
|
cfg['mount_key'] = (self.gs_mount_key.text().strip() or 'x')
|
||||||
|
cfg['enable_mount'] = self.gs_enable_mount.isChecked()
|
||||||
cfg['mount_hold_sec'] = float(self.gs_mount_hold.value())
|
cfg['mount_hold_sec'] = float(self.gs_mount_hold.value())
|
||||||
cfg['mount_retry_after_sec'] = float(self.gs_mount_retry.value())
|
cfg['mount_retry_after_sec'] = float(self.gs_mount_retry.value())
|
||||||
|
cfg['hearthstone_key'] = (self.gs_hearthstone_key.text().strip() or 'b')
|
||||||
|
cfg['bag_full_hearthstone'] = self.gs_bag_full_hearthstone.isChecked()
|
||||||
path = save_layout_config(cfg)
|
path = save_layout_config(cfg)
|
||||||
# bot 参数写入主配置文件
|
# bot 参数写入主配置文件
|
||||||
self.config = self.config or {}
|
self.config = self.config or {}
|
||||||
@@ -1444,6 +1465,7 @@ class WoWMultiKeyGUI(QMainWindow):
|
|||||||
)
|
)
|
||||||
self.game_worker.state_signal.connect(self.state_label.setText)
|
self.game_worker.state_signal.connect(self.state_label.setText)
|
||||||
self.game_worker.log_signal.connect(self.log)
|
self.game_worker.log_signal.connect(self.log)
|
||||||
|
self.game_worker.stop_signal.connect(self._stop_game_worker)
|
||||||
self.game_worker.finished.connect(self._on_game_loop_finished)
|
self.game_worker.finished.connect(self._on_game_loop_finished)
|
||||||
self.game_worker.start()
|
self.game_worker.start()
|
||||||
self.game_start_btn.setEnabled(False)
|
self.game_start_btn.setEnabled(False)
|
||||||
|
|||||||
Reference in New Issue
Block a user