Add combat error beacon and adjust combat recovery

This commit is contained in:
王鹏
2026-04-20 15:32:35 +08:00
parent 6ec468a78b
commit 66b8edf8e4
4 changed files with 82 additions and 12 deletions

View File

@@ -139,7 +139,41 @@ local function GetFollowSignal()
return 0 return 0
end end
local combatErrorSignal = 255
local errorTimer = 0
local function UpdateCombatErrorSignal(message)
if not message or message == "" then
return
end
if message == "你需要面对目标" or message == ERR_BADATTACKFACING then
combatErrorSignal = 50
elseif message == "距离太远" or message == ERR_OUT_OF_RANGE then
combatErrorSignal = 100
elseif message == "目标不在视野中" or message == ERR_NOT_IN_LOS then
combatErrorSignal = 150
elseif message == "法术还没准备好" or message == "技能还没有准备好。" then
combatErrorSignal = 200
elseif message == "能量不足" or message == "符文能量不足" or message == "没有足够的符文" then
combatErrorSignal = 220
else
return
end
errorTimer = GetTime()
end
local errorFrame = CreateFrame("Frame")
errorFrame:RegisterEvent("UI_ERROR_MESSAGE")
errorFrame:SetScript("OnEvent", function(_, _, _, message)
UpdateCombatErrorSignal(message)
end)
f:SetScript("OnUpdate", function() f:SetScript("OnUpdate", function()
if combatErrorSignal ~= 255 and (GetTime() - errorTimer > 1.5) then
combatErrorSignal = 255
end
-- [1] 锚点:永远纯白 (255, 255, 255) -- [1] 锚点:永远纯白 (255, 255, 255)
pixels[1]:SetColorTexture(1, 1, 1) pixels[1]:SetColorTexture(1, 1, 1)
@@ -200,7 +234,7 @@ f:SetScript("OnUpdate", function()
-- [10] R=跟随信号0 / 0.5 需补跟随 / 1.0 跟随中) -- [10] R=跟随信号0 / 0.5 需补跟随 / 1.0 跟随中)
local followSig = GetFollowSignal() local followSig = GetFollowSignal()
pixels[10]:SetColorTexture(followSig, 0, 0, 1) pixels[10]:SetColorTexture(followSig, combatErrorSignal / 255, 0, 1)
end) end)
-- 可拖动 -- 可拖动

View File

@@ -218,6 +218,8 @@ class AutoBot:
self.last_attack_scan_time = 0.0 self.last_attack_scan_time = 0.0
self.attack_stall_scan_threshold = 2.0 self.attack_stall_scan_threshold = 2.0
self.attack_scan_retry_sec = 2.0 self.attack_scan_retry_sec = 2.0
self.attack_stall_s_hold_sec = 0.5
self.min_effective_target_damage_pct = 5
self._last_mouse_path_scale_signature = None self._last_mouse_path_scale_signature = None
def execute_disengage_loot(self): def execute_disengage_loot(self):
@@ -513,9 +515,13 @@ class AutoBot:
hw_ctrl.keyUp('s') hw_ctrl.keyUp('s')
self._has_braked_for_target = True self._has_braked_for_target = True
# 2. 交互逻辑 # 2. 只有超过 5% 的明显掉血才算“新的有效掉血”
hp_dropped = self.last_target_hp > 0 and target_hp < self.last_target_hp hp_drop_amount = max(0, self.last_target_hp - target_hp)
if is_new_target or hp_dropped or self.last_target_damage_time is None: significant_hp_dropped = (
self.last_target_hp > 0
and hp_drop_amount > self.min_effective_target_damage_pct
)
if is_new_target or significant_hp_dropped or self.last_target_damage_time is None:
self.last_target_damage_time = current_time self.last_target_damage_time = current_time
if ( if (
@@ -524,8 +530,9 @@ class AutoBot:
and (current_time - self.last_target_damage_time) >= self.attack_stall_scan_threshold and (current_time - self.last_target_damage_time) >= self.attack_stall_scan_threshold
and (current_time - self.last_attack_scan_time) >= self.attack_scan_retry_sec and (current_time - self.last_attack_scan_time) >= self.attack_scan_retry_sec
): ):
if self.mouse_scan_attack_target(): hw_ctrl.keyDown('s')
self.last_target_damage_time = current_time time.sleep(self.attack_stall_s_hold_sec)
hw_ctrl.keyUp('s')
self.last_attack_scan_time = current_time self.last_attack_scan_time = current_time
self.last_target_hp = target_hp self.last_target_hp = target_hp
if state['combat']: if state['combat']:

View File

@@ -273,6 +273,8 @@ class AutoBotMove:
self.last_attack_scan_time = 0.0 self.last_attack_scan_time = 0.0
self.attack_stall_scan_threshold = 2.0 self.attack_stall_scan_threshold = 2.0
self.attack_scan_retry_sec = 2.0 self.attack_scan_retry_sec = 2.0
self.attack_stall_s_hold_sec = 0.5
self.min_effective_target_damage_pct = 5
self._last_mouse_path_scale_signature = None self._last_mouse_path_scale_signature = None
# stop_check: 返回 True 表示需要立即停止(用于中断阻塞中的后勤/路线导航) # stop_check: 返回 True 表示需要立即停止(用于中断阻塞中的后勤/路线导航)
self._stop_check = stop_check if callable(stop_check) else (lambda: False) self._stop_check = stop_check if callable(stop_check) else (lambda: False)
@@ -698,9 +700,13 @@ class AutoBotMove:
hw_ctrl.keyUp('s') hw_ctrl.keyUp('s')
self._has_braked_for_target = True self._has_braked_for_target = True
# 2. 交互键KEY_LOOT按键策略 # 2. 只有超过 5% 的明显掉血才算“新的有效掉血”
hp_dropped = self.last_target_hp > 0 and target_hp < self.last_target_hp hp_drop_amount = max(0, self.last_target_hp - target_hp)
if is_new_target or hp_dropped or self.last_target_damage_time is None: significant_hp_dropped = (
self.last_target_hp > 0
and hp_drop_amount > self.min_effective_target_damage_pct
)
if is_new_target or significant_hp_dropped or self.last_target_damage_time is None:
self.last_target_damage_time = now self.last_target_damage_time = now
# 目标血量100%且超过2秒没掉血按交互键尝试选中/攻击 # 目标血量100%且超过2秒没掉血按交互键尝试选中/攻击
@@ -715,8 +721,9 @@ class AutoBotMove:
and (now - self.last_target_damage_time) >= self.attack_stall_scan_threshold and (now - self.last_target_damage_time) >= self.attack_stall_scan_threshold
and (now - self.last_attack_scan_time) >= self.attack_scan_retry_sec and (now - self.last_attack_scan_time) >= self.attack_scan_retry_sec
): ):
if self.mouse_scan_attack_target(): hw_ctrl.keyDown('s')
self.last_target_damage_time = now time.sleep(self.attack_stall_s_hold_sec)
hw_ctrl.keyUp('s')
self.last_attack_scan_time = now self.last_attack_scan_time = now
self.last_target_hp = target_hp self.last_target_hp = target_hp

View File

@@ -88,6 +88,22 @@ def _tri_state_label(value, low_mid_high):
return low_mid_high[2] return low_mid_high[2]
_COMBAT_ERROR_SIGNALS = (50, 100, 150, 200, 220, 255)
_COMBAT_ERROR_LABELS = {
50: '需转身',
100: '距离远',
150: '不在视野',
200: '技能CD',
220: '资源不足',
255: '正常',
}
def _combat_error_signal_from_g(channel_byte):
"""Lua G 通道离散状态码还原为最近的约定值。"""
return min(_COMBAT_ERROR_SIGNALS, key=lambda t: abs(t - int(channel_byte)))
def format_game_state_line(state): def format_game_state_line(state):
"""单行状态文字(中文),供 CLI 与 GUI 共用。""" """单行状态文字(中文),供 CLI 与 GUI 共用。"""
death_txt = ('存活', '尸体', '灵魂')[state.get('death_state', 0)] death_txt = ('存活', '尸体', '灵魂')[state.get('death_state', 0)]
@@ -108,12 +124,16 @@ def format_game_state_line(state):
state.get('follow', 0), state.get('follow', 0),
('未跟随', '需补跟随', '跟随中'), ('未跟随', '需补跟随', '跟随中'),
) )
combat_error_txt = state.get('combat_error_label') or _COMBAT_ERROR_LABELS.get(
state.get('combat_error_signal', 255), '未知'
)
return ( return (
f"{hp_part} | " f"{hp_part} | "
f"{combat_txt} {target_txt} | " f"{combat_txt} {target_txt} | "
f"空格:{state.get('free_slots', 0)} 耐久:{state.get('durability', 0):.0%} {death_txt} | " f"空格:{state.get('free_slots', 0)} 耐久:{state.get('durability', 0):.0%} {death_txt} | "
f"x:{state['x']} y:{state['y']} 朝向:{state['facing']:.1f}° | " f"x:{state['x']} y:{state['y']} 朝向:{state['facing']:.1f}° | "
f"{flight_txt} {mounted_txt} {flyable_txt} {follow_txt}" f"{flight_txt} {mounted_txt} {flyable_txt} {follow_txt} | "
f"战斗信号:{combat_error_txt}"
) )
@@ -213,6 +233,8 @@ def parse_game_state():
# 第 10 像素Lua pixels[10]R=跟随信号 # 第 10 像素Lua pixels[10]R=跟随信号
p10 = get_val(8) p10 = get_val(8)
state['follow'] = _tri_state_from_r(p10[0]) state['follow'] = _tri_state_from_r(p10[0])
state['combat_error_signal'] = _combat_error_signal_from_g(p10[1])
state['combat_error_label'] = _COMBAT_ERROR_LABELS.get(state['combat_error_signal'], '未知')
return state return state