Chapter Four
首先我要说声抱歉,因为我没注意到基地的文章发表没有办法显示"TAB"的空格.这样在查看
程序代码,一定会造成困扰.如果大家在看程序代码会眼睛痛的时候,还请见谅.
现在,让我们研究一下HunterAssistant.lua第一段:
function HunterAssistant_init()
-- define slash command here
SlashCmdList["HA_HunterMarkI"] = HA_HunterMarkI;
SLASH_HA_HunterMarkI1 = "/HAHunterMarkI";
SLASH_HA_HunterMarkI2 = "/hahmi";
SlashCmdList["HA_HunterMarkII"] = HA_HunterMarkII;
SLASH_HA_HunterMarkII1 = "/HAHunterMarkII";
SLASH_HA_HunterMarkII2 = "/hahmii";
SlashCmdList["HA_AttackMelee"] = HA_AttackMelee;
SLASH_HA_AttackMelee1 = "/HAAttackMelee";
SLASH_HA_AttackMelee2 = "/haam";
SlashCmdList["HA_AttackRangeI"] = HA_AttackRangeI;
SLASH_HA_AttackRangeI1 = "/HAAttackRangeI";
SLASH_HA_AttackRangeI2 = "/haari";
SlashCmdList["HA_AttackRangeII"] = HA_AttackRangeII;
SLASH_HA_AttackRangeII1 = "/HAAttackRangeII";
SLASH_HA_AttackRangeII2 = "/haarii";
SlashCmdList["HA_StingSerpentI"] = HA_StingSerpentI;
SLASH_HA_StingSerpentI1 = "/HAStingSerpentI";
SLASH_HA_StingSerpentI2 = "/hasseri";
SlashCmdList["HA_StingSerpentII"] = HA_StingSerpentII;
SLASH_HA_StingSerpentII1 = "/HAStingSerpentII";
SLASH_HA_StingSerpentII2 = "/hasserii";
SlashCmdList["HA_StingSerpentIII"] = HA_StingSerpentIII;
SLASH_HA_StingSerpentII1 = "/HAStingSerpentIII";
SLASH_HA_StingSerpentII2 = "/hasseriii";
SlashCmdList["HunterTest"] = HunterTest_command;
SLASH_HunterTest1 = "/HunterTest";
SLASH_HunterTest2 = "/ht";
end
附注:HA_代表的意思是HunterAssistant的缩写.
其实这里没有什么特别的.这里只是帮模块设定一些简单的"/"指令.将来我们可以直接把这
些指令用到游戏的MACRO中. 请注意的一点是,每一个指令都有一个FUNCTION相对应.另外,我
每一个指令都一个全名指令,以及一个简写指令(方便使用).在指令命名设计上,我以看到指
令名称就大概能猜到使用的结果是什么.还有就是每个指令前面加上HA_这样能有效的避免跟
其它模块的指令冲突到.另外有几个指令后面有罗马数字,这些是代表了所使用到的猎人技能
是有等级高低的.比如说HA_HunterMarkI使用的是等级1的Hunter's Mark,HA_HunterMarkII
使用的是等级2的Hunter's Mark.
另外,我的指令排列是以英文顺序为主.这样方便我个人寻找BUG.
现在让我们继续往下看.
function HA_AttackMelee()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Attack");
x=1
found=false;
while (UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Monkey")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Monkey");
end;
end;
end
这一个function的主要目的是近距离攻击.首先第一行是AssistUnit("pet");这代表了什么
?其实这是WOW的核心指令之一.AssistUnit()的意思是帮助某一个单位的意思.这个指令可以
接受不同的变量,包括玩家单位,NPC友好单位,以及宠物单位.当执行了这个指令之后,你的敌
人对象就会变成你所帮助的那个单位的敌人是同一个.在这里"pet"的意思就是主角单位的宠
物.
我在这里会用AssistUnit("pet")开头的原因是,当你的宠物在攻击的时候敌人的时候,你跟
你的宠物所选择的敌人不见得是同一个,所以我们要确定主角跟宠物攻击的对象是同一个.
(注意:目前我这样的设计好像有点逻辑上的问题.思考逻辑到底是主角该帮主宠物还是宠物
帮助主角?游戏中的基本设定是主角受到攻击,宠物就会自动帮助第一个攻击主角的敌人,可
是如果好几个人攻击主角,宠物还是会先专心的把第一个敌人解决掉.所以我一开始会这样设
计,专心的先帮助宠物解决掉第一个敌人.可是当遇到我就是有特殊原因要先解决掉其它的敌
人的时候(例如某些特殊任务),我这样的设计反而造成困扰,因为只要我一攻击,我的对象就
就转换到宠物的敌人了.所以在未来的版本中,我可能会设定另一种攻击是,宠物永远帮助主
角攻击同一个敌人,使用的指令是 PetAssistUnit("Player"). "Player"就是代表主角的意
思.)
下一行, if(not UnitExists("target")) then
TargetNearestEnemy();
end;
这里的意思是检查执行帮忙的指令之后(AssistUnit())到底有没有敌人?如果主角的宠物没
有在战斗状态,那么我们敌人的状态就是没有选择.UnitExists("target")) 就是检查我们有
没有选择任何的目标.这个也是WOW的核心指令之一. 当然如果我们有选择目标,可是目标是
有好单位呢?不用担心,WOW的设计本来就是无法攻击友好单位的.那么TargetNearestEnemy(
)又是什么意思呢?就是自动选择距离最近的非有好单位当作目标选项.所以这一段的意思就
是,如果主角跟主角的宠物都没有目标的话,帮主角动挑一个最近的非有好单位当作目标.
在来
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Attack");
这里代表的是,如果有目标的话,宠物攻击,然后主角攻击.PetAttack()是宠物攻击的指令,CastSpellByName
("Attack")的意思是主角施展技能,这个技能是攻击(Attack). 这些全都是WOW的核心指令喔
,酷吧.
继续
x=1
found=false;
while (UnitBuff("player",x)) do
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Monkey");
end;
end;
end
这里我定义了一个变量X,以及一个变量FOUND(中文是找到的意思),这两个变量不是WOW的专
有变量,而是LUA的语法喔.为什么需要这两个变量?因为当我们在近距离攻击的时候,我必须
要确定主角是在于ASPECT OF MONKEY 之下,有了这些变量可以方便我来做检查.
while (UnitBuff("player",x))的意思就是如果在主角的身上可以找到Buff的话. UnitBuff
("player",1)会在寻找主角身上第一个buff的数据,然后传回讯息.如果没找到,就会传回一
个否定的讯息.UnitBuff("player",2)就是寻找第二个buff的数据.
if(string.find(UnitBuff("player",x), "Monkey"))
string.find是lua语言上的指令,不是WOW的核心指令.这个指令的目的是寻找一个讯息中的
字符串是否有特殊的字符.所以这一整段的意思是找寻主角身上的buff的信息是否有MONKEY
(猴子)的字符串.如果有的话,就把FOUND设定为TRUE.
if(not found) then
CastSpellByName("Aspect of the Monkey");
这一段就是如果从头到尾都没有找相关的buff的话,代表了主角没有施展"Aspect of the Monkey
",所以我们就执行施展技能的指令CastSpellByName("Aspect of the Monkey").
写到这里,让我顺便提出一些要点.不晓得大家有没有发现到,在这个function里面,从头到尾
只有一个指令需要冷却时间那就是CastSpellByName("Aspect of the Monkey").其它,比如
说攻击,全部都不需要冷却时间.这也就是为什么这么多指令都可以转变成一个单一指令.但
是因为CastSpellByName("Aspect of the Monkey")需要冷却时间,所以我把她摆在最后执行
,避免错误.另外一点就是,很多人在找寻主角身上的buff数据的时候,喜欢直接用UnitBuff(
"player",1)却没有想到其实主角身上可能有很多的buff呢.
所以我这样的设计一定可以确保如果主角已经施展了Aspect of the Monkey,就绝对不会重
复施展第二次(浪费mana喔).
至于这个function 里面的一些IF, WHILE, NOT等等的用以及正确的语法,就请大家到LUA的
官方网站去看.我就不多解释了.
在来是猎人的普通远距离攻击
function HA_AttackRangeI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Auto Shot");
x=1
found=false;
while (UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Raven")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Hawk(Rank 1)");
end;
end;
end
这一段其实跟近距离的普通攻击是同样的逻辑,但是CastSpellByName("Auto Shot") 这个是
猎人专有的远距离自动攻击的指令.同样的这个指令可以跟其它需要冷却时间的指令同时使
用.另外CastSpellByName("Aspect of the Hawk(Rank 1)") 这是执行第一级的ASPECT OF
THE HAWK. 在我们模块function HA_AttackRangeII()里面就会执行第二级的ASPECT OF THE
HAWK, CastSpellByName("Aspect of the Hawk(Rank 2)")
function HA_HunterMarkI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Hunter's Mark(Rank 1)");
end;
end
这一段没有什么特别的,唯一的好处就是当主角开始使用MARK的技能的时候,就开始命令宠物
攻击.我们不需要按两个动作.另外,Hunter's Mark 也是有等级之分的,所以我写了其它相对
应的等级指令
注意:(这个FUNCTION我还没有完全的完成,因为我没有检查是否敌人已经被MARK过了,也就是
说这个指令允许重复MARK敌人,浪费MANA)
function HA_StingSerpentI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
x=1
found=false;
while (UnitDebuff("target",x)) do
if(string.find(UnitDebuff("target",x), "Quickshot")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Serpent Sting(Rank 1)");
end;
end;
end
这一个跟普通远距离攻击的指令很像,但是并不是使用普通的AUTO SHOT,而是使用了Serpent
Sting.另外这一个指令不会检查主角本身是否施展了ASPECT OF HAWK.因为Serpent Sting
跟aspect of the hawk都要冷却时间,两个写在一起,只会执行其中的一个,那么就一点意义
都没有了.既然这样,为什么要写这一个指令?其实这个指令会检查敌人身上是否已经被施展
了Serpent Sting,毕竟Serpent Sting没有加成效过,所以我们要避免重复施展Serpent Sting
.而WOW的基本Serpent Sting指令是不会做这样的检查的,所以我们还得一直盯着敌人的信息
看着,避免浪费MANA.可是设计了另外的这个指令,玩家根本不用担心浪费MANA,只要想到了就
执行一下,反证会自动检查,也不会中断AOTU SHOT的动作,更不会浪费MANA.另外,这个指令也
有设计其它不同等级的相对应指令.
最后
function HunterTest_command()
x=1
found=false;
while(UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Raven")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Hawk(Rank 1)");
end;
if(found) then
CastSpellByName("Aspect of the Monkey");
end;
end
这个指令只是我设计好玩拿来测试用的,当执行这个指令的时候,主角会交互的使用ASPECT
OF MONKEY 或者 ASPECT OF HAWK.
模块的核心指令介绍到这里,下一篇文章将教玩家如何在游戏里用这些指令.
目前我们的模块有了最基本的三个档案了.现在让我们把这三个档案放入C:Program FilesWorld
of WarcraftInterfaceAddOnsHunterAssistant这个数据夹里面.然后执行游戏.
现在让我解释一下WOW上面所谓的斜线指令("/指令")该如何用.
大家因该都清楚如何的用感情指令,或是交谈指令.这些都是斜线指令.但是WOW还有一些斜线
指令是无法直接的输入, 比如说"/attack". 基本上这是WOW官方设计的攻击指令,其背后只
是很简单的呼叫了CastSpellByName("Attack"). 但是为什么我们无法直接使用这些指令呢
?因为暴风雪为了避免玩家利用其它的程序来设计非法的MACRO.
怎么说呢?因为WOW的MACRO没有时间间隔设计,避免玩家设计机器人,那么玩家设计机器人就
必须利用其它的程序.如果,设计机器人,机器人程序就可以直接的仿真键盘输入指令,而不会
影响到玩家对于鼠标的操做.所以WOW把很多的斜线指令的操作设定成只有在WOW的MACRO下才
能使用.你设计一个MACRO以及MACRO图像按钮,你要执行这个MACRO,你就必须对这个按钮按一
下,WOW才会执行这个动作.
当然,还是有其它的办法摆脱暴风雪这样的设计,但是我不会对类似这样的问题做出任和解说
.因为暴风雪尽力的维护游戏免于外挂的侵入,身为玩家的我也有义务要帮助暴风雪.
有这样的限制的斜线指令包括了所有的会使用到执行特殊技能的指令.所以当我们设计的模
块有用到执行特殊技能的时候,我们的斜线指令也只能在WOW下面的MACRO才能执行.(当然,我
们的猎人辅助模块还是用在MACRO下面比较好,毕竟在战斗的时候谁还有时间慢慢的的用键盘
输入指令,我们又不是机器人)
要使用WOW的MACRO很简单,只要在游戏中输入"/macro"或是按下Esc 然后选择macro的选项
在macor的画面,我们必须帮macro选择一个图像按钮,替macro命名,然后输入我们想要给macro
的指令.
现在让我列出猎人辅助模块的简易斜线指令:
Hunter's Mark 包括了不同的等级
/hahmi
/hahmii
Melee Attack(近距离攻击)
/haam"
Range Attack (远距离攻击)包括了不同的等级
/haari
/haarii
Serpent Sting(远距离特技)包括了不同的等级
/hasseri
/hasserii
/hasseriii
现在我们只要把macro的图像按钮选择好,然后给个名子,最后在底下输入指令的地方,挑一个
你想要执行的辅助指令输入就好了. 注意喔,一个macro只能使用模块的一个指令喔,因为就
算你输入了很多个,在执行macro的时候,游戏也只会执行情中的一个而已.(冷却时间的考虑
)
当你设定好了macro之后,WALA~~~,你就可以把这个图形按钮抓到快捷工具栏上面使用了~~~
就像是使用任何其它的基本图形按钮依样喔.好处是,你按一次按钮,却等于其它没有用辅助
模块人按好几次按钮依样喔.还会自动帮你做一些额外的检查呢.有效率了多吧.
下一次,我将教大家如何设计辅助模块可以帮大家在半自动的施展BUFF,对象也会半自动的选
择队友,宠物,或是自己.
附注1:因为我个人玩了10角色,包括了联盟的每一个CLASS,在未来的日子里,我将会不定期的
替自己写模块.如此同时,我也会拿上来与大家分享.但是我将不会再花这么多的时间详细解
释每一个指令.除非有网友提出问题,那时我会在尽力回答.
附注2:有关WOW的核心开放给玩家使用的指令,大家可以到这个网页找到.但是这里不是完整
的列表,说明也不是很清楚,不过大家将就的用噜.
http://www.wowwiki.com/World_of_Warcraft_API 附注3:最有效率的研究模块的方式,就是到官网的UI Customization的论坛参与讨论喔.也许
大家会找到一些意想不到,但是又很有帮助的模块喔.我个人就已经发现有人设计了一个挖矿
采要的模块,这个模块会把你最到过的挖矿以及采药的地点纪录下来,然后显示在地图上.怎
么样,很有用吧.