魔兽世界WA插件+按键精灵一键控制
秦大圣
编辑于 2023年03月06日 20:38
收录于文集
共1篇

因为暴雪离开中国,暂时没有魔兽世界的替代品,所以就选择了不可描述服。此类服务器目前大多多脚本检测能力比较弱,甚至某些服自己售卖自动脚本,加上手残操作能力较弱,就萌生了自己解放双手的想法。

一、资料准备

首先魔兽世界自己提供了诸多API方便插件开发等,都能用的到,参考链接:

World of Warcraft API - Wowpedia - Your wiki guide to the World of Warcraft (fandom.com)

https://warcraft.huijiwiki.com/wiki/API_SetOverrideBindingMacro

https://blog.csdn.net/qq_18882253/article/details/117822181

https://www.wandhao.com/wangluoyouxi/61923.html

除了魔兽API还需要WeakAuras的一些API,另外需要部分lua知识。

https://github.com/WeakAuras/WeakAuras2/wiki/aura_env

二、实现原理

通过魔兽插件WeakAuras把需要获取的游戏信息,以色块的形式显示在屏幕固定位置,再使用按键精灵等工具对色块进行颜色判断,把需要的信息读取出来,再通过按键精灵模拟按键的方式对游戏进行控制。

其中几个需要注意的点:

1、魔兽世界UI是有缩放功能,在WA插件中设定的尺寸不一定第最终的显示尺寸,所以在识别色块之前要对色块尺寸进行校正。解决办法是游戏屏幕是原点是固定的,校正色块就固定在原点位置,以校正色块的尺寸为判定色块的距离位置。

按键精灵校对颜色部分代码:

代码块
JavaScript
自动换行
复制代码

Dim startp
Dim checklen

Sub 校对色块()
	For i = 5 To 50
		GetColor = Plugin.Bkgnd.GetPixelColor(HwndEx, i, 10)
		If IsCol(GetColor, "FFFFFF", 0.8) = False Then 
			checklen = i
			startp = i * 2.5
			设置色块检测位置
    	Exit Sub
    End If
	Next
End Sub


Sub 设置色块检测位置()
	//可否攻击
	自动p = startp
	目标p=startp+checklen
	技能p = startp + checklen * 2
End Sub

Function IsCol(col1, col2, n)
	IsCol = False
	Call Plugin.Color.ColorToRGB(col1, r1, g1, b1)
	Call Plugin.Color.ColorToRGB(col2, r2, g2, b2)
	m = 1 - (Abs(r1 - r2) + Abs(g1 - g2) + Abs(b1 - b2)) / 765
	If m>n Then 
		IsCol = True
	End If

End Function

复制成功

2、使用WA插件的aura_env.region.Color(0,0,1,0)对色块颜色处理,此函数不能覆盖WA自带条件的颜色操作。另外设置颜色函数、获取颜色函数和按键精灵的颜色处理参数位置存在差异:

代码块
JavaScript
自动换行
复制代码
region.Color(alpha,red,green,blue)
red,green,blue,alpha=region.GetColor()
#按键精灵颜色"FF00FF"为blue,green,red
复制成功

3、对于dps职业,一般目标的切换都是玩家手动选择,而且基本是固定不变的,dps职业往往更加关注技能释放的优先级,而优先级又跟玩家自身战斗资源等相关。

动作选择的处理有两种方法:(1)是将战斗资源通过色块传递给外部程序(按键精灵等),再由外部程序作出动作选择;(2)直接在WA中进行动作选择,只给外部程序传递动作信息。显然只传递动作信息可以使外部程序端更加简单,而且逻辑修改只需要在wa中进行,调试更加方便。

按键精灵技能判断:

代码块
JavaScript
自动换行
复制代码
    GetColor = Plugin.Bkgnd.GetPixelColor(HwndEx, 自动p, 10)
    If IsCol(GetColor, "00FF00", 0.8) = False Then 
    	skillkey = 0
    	skillmdf =0
    	Exit sub
    End If
    
    //检测技能
	GetColor = Plugin.Bkgnd.GetPixelColor(HwndEx, 技能p, 10)
	If IsCol(GetColor, "FFFFFF", 0.8) = True Then 
	//白色发呆
    	skillkey = 0
    	skillmdf=0
    	Exit Sub
    End If
    If IsCol(GetColor, "00FF00", 0.8) = True Then 
    	skillkey = 真盾
    	skillmdf=真盾s
    	Exit Sub
    End If
    If IsCol(GetColor, "FF0000", 0.8) = True Then 
    	//蓝色
    	skillkey = 苦修
    	skillmdf=苦修s
    	Exit Sub
    End If
复制成功

4、对于治疗职业,治疗一般是打地鼠操作,哪个掉血加哪个,需要不停的的寻找血少目标或者高优先级目标,对注意力消耗极大,更加需要自动脚本。而魔兽世界的目标选择功能同样是不对外开放的,所以需要绑定宏命令来实现目标切换。

魔兽友方角色分别是:

代码块
JavaScript
自动换行
复制代码
自己				    player
小队1-小队4			   party1-party4
团队1-40				 raid1-raid40
复制成功

总共需要45个按键,而目前服务器大多是处于WLK版本,最多是25人团,所以减少一下按键总共需要30个按键,因为魔兽世界允许使用组合键,所以就利用小键盘的0-9和组合键,就可以实现友方目标的选择功能。小键盘0的ASCII码为96。

这里的绑定方法是:

代码块
JavaScript
自动换行
复制代码
NUMPAD9	       player
NUMPAD5-8	    Party1-4
CTRL+NUMPAD0-9	 Raid1-10
ALT+NUMPAD0-9	 Raid11-20
NUMPAD0-4	    Raid21-25
复制成功

在wa中创建按钮并对按钮设置宏命令,再对按钮就行按键绑定。

代码块
JavaScript
自动换行
复制代码
local a = aura_env
local region = WeakAuras.GetRegion(a.id)
local stargetid=0
local bts=CreateFrame("Button", "STarget30",region, "SecureActionButtonTemplate")
bts:SetAttribute("type", "macro")
bts:SetAttribute("macrotext","/target player")
SetOverrideBindingClick(bts, true, "NUMPAD9", bts:GetName())

--party
for i=1,4 do
    stargetid=25+i
    bts=CreateFrame("Button", "STarget"..stargetid,region, "SecureActionButtonTemplate")
    bts:SetAttribute("type", "macro")
    bts:SetAttribute("macrotext","/target party"..i)
    SetOverrideBindingClick(bts, true, "NUMPAD"..(4+i), bts:GetName())
    
end


--raid
for i=1,10 do
    stargetid=i
    bts=CreateFrame("Button", "STarget"..stargetid,region, "SecureActionButtonTemplate")
    bts:SetAttribute("type", "macro")
    bts:SetAttribute("macrotext","/target raid"..i)
    SetOverrideBindingClick(bts, true, "CTRL-NUMPAD"..(i-1), bts:GetName())
    
end


for i=11,20 do
    stargetid=i
    bts=CreateFrame("Button", "STarget"..stargetid,region, "SecureActionButtonTemplate")
    bts:SetAttribute("type", "macro")
    bts:SetAttribute("macrotext","/target raid"..i)
    SetOverrideBindingClick(bts, true, "ALT-NUMPAD"..(i-11), bts:GetName())
    
end

for i=21,25 do
    stargetid=i
    bts=CreateFrame("Button", "STarget"..stargetid,region, "SecureActionButtonTemplate")
    bts:SetAttribute("type", "macro")
    bts:SetAttribute("macrotext","/target raid"..i)
    SetOverrideBindingClick(bts, true, "NUMPAD"..(i-21), bts:GetName())
    
end

复制成功

外部读取为:

代码块
JavaScript
自动换行
复制代码
Sub getTarget()
	
    //检测目标
	GetColor = Plugin.Bkgnd.GetPixelColor(HwndEx, 目标p, 10)
	id = getTargetId(GetColor)
	If id = 0 Then 
	//不进行目标选择
		targetkey = 0
		Exit Sub
	End If
	
	If id < 11 Then 
		
		targetkey=96+id-1
 		targetmdf=17
	ElseIf id > 20 Then
		targetkey=96+id-21
 		targetmdf=0
	Else 
	 
		targetkey=96+id-11
 		targetmdf=18
	
	End If
	
End Sub

Function getTargetId(col1)
	getTargetId = 30
	Call Plugin.Color.ColorToRGB(col1, r1, g1, b1)
	getTargetId=r1/25.5+g1/25.5+b1/25.5
End Function
复制成功

三、外部程序及UI部分

自动脚本的外部程序部分比较简单,主要是做外部使用UI,根据预设的色块的信息传递规则,执行相应的行为动作。图方便使用按键精灵自带的库API较为详细,能够满足需要(如果深入一下的话,使用python会更好一些)。

四、WA部分

WA负责信息的获取、执行策略的选择和通过色块进行信息传递。这边使用了5个色块,底色使用红色以便于忽略游戏内的图像干扰。

色块的含义分别是:

1号白色校对色块

红色部分为底色,用于区分第一个校对色块

2号绿/白按钮游戏内控制是否开启自动脚本

3号目标色块需要选择的目标信息

4号技能色块释放技能信息

5号为是否开启自动驱散

在游戏中需要不断获取信息进行决策,所以WA自带的触发器并不太好用,使用WA的自定义初始化动作,直接执行lua代码,对色块进行操作。

通过创建一个UI帧,并对每一帧的update进行操作。

代码块
JavaScript
自动换行
复制代码
   CreateFrame("Frame"):SetScript("OnUpdate", function()
            lastTicker=lastTicker+1
            if (lastTicker)>=(a.config['toggleRate'] ) then
                
                lastTicker=0
                --r,g,b,alpha
                r0,_,_,_=c.GetColor()
                --print(c.GetColor())
                if r0==0 then
                    --绿色启动
                    ticker(a)
                end
                
            end            
    end)
复制成功

剩下的就是获取信息->逻辑判断->色块操作。

1、信息获取部分

主要使用魔兽世界提供的API进行操作。例如

(1)遍历所有队伍角色,如果与玩家距离小于40码且未死亡则XXX

代码块
JavaScript
自动换行
复制代码
for unitID in WA_IterateGroupMembers() do
    if WeakAuras.CheckRange(unitID,40,"<=")  and (not UnitIsDead(unitID)) then
        --只对40码范围内检测
    end
end
复制成功

(2)判断目标的buff/debuff

代码块
JavaScript
自动换行
复制代码
if not (WA_GetUnitDebuff(unitID, "虚弱灵魂") or WA_GetUnitBuff(unitID, "真言术:盾"))then
    --buff/debuff检查
end
复制成功

(3)判断目标debuff类型,用于选择驱散技能

代码块
JavaScript
自动换行
复制代码
for i=1 ,4 do
    --检测4个debuff类型Magic,Curse,Disease,Poison,魔法/诅咒/疾病/中毒
    x,x,x,x,debufftype=UnitDebuff(unit_id,i)
    if (debufftype =="Magic" or debufftype =="Disease"  )then
    end
end
复制成功

(4)获取目标生命值

代码块
JavaScript
自动换行
复制代码
health = UnitHealth(unitID)
ealthMax = UnitHealthMax(unitID)
复制成功

(5)技能cd

代码块
JavaScript
自动换行
复制代码
GetSpellCooldown("苦修")
复制成功

2、逻辑判断部分大家都懂,包括对各职业的理解,逻辑上肯定各不相同。

3、色块操作部分

wa的代码非常灵活,可以通过id获取其他region的操作权。

(1)获取其他色块的句柄

代码块
JavaScript
自动换行
复制代码

local b= WeakAuras.GetRegion("技能标志")
local c=WeakAuras.GetRegion("自动开关")
复制成功

(2)目标色块处理

之前已经对目标按钮进行了绑定,逻辑中可对选择目标的色块进行处理

代码块
JavaScript
自动换行
复制代码

function setmycolor(regionname)
    --只留字母
    nametext,_=regionname:gsub("%d","")
    --只留数字
    namenum,_=regionname:gsub("%D","")
    namenum=tonumber(namenum)
    --除了自己,总共是30个选择RGB分别占10个
    --print(regionname)
    --print(namenum)
    if nametext=="player" then
        --自己就是白色
        a.region.Color(1,1,1,1)
    elseif nametext=="party" then
        --print("paty-type")
        colornum=(5+namenum)/10
        a.region.Color(1,1,1,colornum)
    else
        if namenum<10  then
            colornum=(namenum)/10
            a.region.Color(1,colornum,0,0)
            
        elseif namenum>20 then
            
            colornum=(namenum-20)/10
            a.region.Color(1,1,1,colornum)
        else
            
            colornum=(namenum-10)/10
            a.region.Color(1,1,colornum,0)
        end
        
    end
    
end
复制成功

(3)技能色块处理,直接Color就行。