本帖最后由 花九黎 于 2012-8-17 12:13 编辑
高级篇 第十一章 variable和alias的进一步应用 以后将主要介绍我在胡一刀和推车机器人中用到的遍历方法,会出现大量的嵌套alias,也会大量的应用list变量,如果你阅读的比较吃力,请多翻翻前面的章节. 阅读前请确认你已经熟练掌握了以下命令:%item(),%additem(),%delitem(),%numitems(),%ismember(),%dups(),%sort()以及对应的#additem,#delitem,#delnitem 本章用list变量实现path的全部功能,教你做出属于自己的遍历机器人 有些人回帖说看不懂,补充紫色部分,看不懂的话在zmud里试验这5个例子吧
-------------------------------------------------------------------------- #var abc 20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1
%item(n,@abc)表示abc的第n项,比如%item(14,@abc)就是7, %item(2,@abc)是19
先定义一个变量abc来试验,下面来遍历abc这个变量
A 先遍历2步
#alias bianli {#if @n {%item(@n,@abc);#add n -1;bianli}}
#var n 2
然后输入bianlin,结果就是先执行第2项19,n减1,接着执行第1项20,n再减1,执行了这2项之后n已经被减成0了,#if @n判断不为真,遍历结束
要小心,#alias a {north;;#add n -1;a}这个alias是无限次嵌套,永远不会停止,命令行里输入a的话在将会死机崩溃,因为没有语句让它停止,谨慎!!
B 遍历20步
#alias bianli {#if @n {%item(@n,@abc);#add n -1;bianli}}
#var n 20
在命令行里输入bianli,结果就是1;2;3;4;5;6;7;...;20
C 每遍历2步停止1秒,一直遍历20步
多用一个命令%mod(),是数学里的模,%mod(@n,10)意思是@n除以10后的余数,如果#var n 18,那么%mod(@n,10)的值是8
#if (%mod(@n,2)=0) {say n是偶数} {say n是奇数}
一个判断n是偶数还是奇数的办法
#alias bianli {#if @n {#if (%mod(@n,2)=0) {%item(@n,@abc)} {#wa 1000;%item(@n,@abc)};#add n -1;bianli}}
#var n 20
跟例子B不同的是,直接执行第n项被替代成了先判断奇偶,n是偶数直接执行,n是奇数就wait 1000然后执行
命令行里输入bianli,结果等同于#wa 1000;1;2;#wa 1000;3;4;#wa 1000;5;...18;#wa 1000;19;20
D 执行到第5项的时候中止遍历,用trigger来让它继续
#var abc 20|19|18|17|kill zhang|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1
第5项被替换成了kill zhang
#alias bianli {#if @n {#if (@n=5) {%item(@n,@abc)} {%item(@n,@abc);bianli};#add n -1}}
#var n 20
#trigger 张死了 {bianli}
命令行里输入bianli,结果就是1;2;3;4;5;......;13;14;15;kill zhang,等张死了,继续17;18;19;20E 执行到第5项时等待10秒再执行,其他的直接执行,用这个方法来坐船
#var abc 20|19|18|17|16|enter boat|14|13|12|11|10|9|8|7|6|5|4|3|2|1
第6项被替换成了enter boat
#alias bianli {#if @n {#if (@n=5) {#wait 10000;%item(@n,@abc)} {%item(@n,@abc)};#add n -1;bianli}}
#var n 20
命令行里输入bianli,结果就是1;2;3;4;...;13;14;enter boat;#wait 10000;16;17;18;19;20
-------------------------------------11.1 给出一个路径.从ct出发到无量山溜一圈回到ct的所有方向组成的list,用一个变量保存起来.#var wuliang {s|s|s|s|s|s|s|s|s|sw|w|w|nw|w|e|sw|sw|sw|n|n|n|s|s|s|s|sw|sw|ne|ne|n|sw|wu|nu|sd|ed|nw|n|s|nu|nu|nu|climb stiff|up|climb yafeng|e|se|sw|n|s|sw|sw|sw|s|e|n|w|n|w|e|s|ne|ne|ne|s|push stone|s|e|ed|ed|push men|e|n|s|e|w|s|out|guo qiao|d|s|se|ne|ne|ne|ne|se|e|e|ne|n|n|n|n|n|n|n|n|n} 这个路径的制作方法可以模拟path路径录制的方法,下一章再详细讲,先不管这个. 比path路径要灵活的是,不需要定义方向,可以将任何命令添加到list里面去.这里说的任何命令,不光是上面@wuliang包含的常规方向和非常规方向,类似#var xxx xxx,#wa xxx,#alarm xxx,tell @myid xxx都可以添加进去,甚至你可以自己定义复杂的alias和function,然后把alias和function添加进去.总之,没有什么是不能添加的,而这种灵活性将使你的遍历非常强大. 11.2 快速行走 快速行走方法一:
#forall @wuliang {%i}
//这就已经完全模拟了path的快速行走,但是这个模拟跟path的快速行走一样太简单了.上面的路径总共包含98个item,命令输入过多游戏拒绝执行. 快速行走方法二:
#alias bianli {#if (@step<=@steps) {#if (%mod(@step,@bushu)=0) {#wa @wait;halt;%item(@area,@step);#add step 1;bianli} {%item(@area,@step);#add step 1;bianli}}}
//一个简单的嵌套,@step表示你的当前步数,@steps表示要走完的步数,因此@step<=@steps作为嵌套结束的判断条件.这个alias能让你从第@step-1步开始走完第@steps步.路径保存在@area中
//当@step<=@steps时,判断%mod(@step,@bushu)是否为0:如果为0,休息一会#wa @wait之后走一步%item(@area,@step),当前步数加1进入下一次嵌套;否则,直接走一步,当前步数加1进入下一次嵌套
//这里@bushu,@wait用来控制行走的快慢,每次连续走@bushu步就停@wait秒,然后接着走.这里不用具体数字而是用变量来控制行走快慢,可以让你更方便的调节行走速度.#alarm 00:30:00 {#var bushu 15;#var wait 1000}
#alarm 12:30:00 {#var bushu 8;#var wait 1500}
//用这2个trigger来自动调节行走速度,晚上人少网络流畅,可以走快些,中午过后网络不好可以走慢些.当然自动调整不满意,你可以随时手动调整,或者制作按钮来改变@bushu和@wait的值无量山的快速行走
#alias 无量山 {#var step 1;#var area @wuliang;#var steps %numitems(@area);bianli}
//将@wuliang保存在@area中,@step值为1表示从第0步开始,@steps值为所有item的个数,表示走完全程
//你只需要在命令行输入"无量山"即可完成无量山的快速行走注一:可以看到这个方法和path相比强大的多,你可以10步一走,也可以2步一走,也可以走一步停一下(这就已经是慢速行走了),完全可以随心所欲. 细心的同学会发现climb stiff和guo qiao有busy,上述方法有问题.没错,下面做出修改. #alias bianli {#if (@step<=@steps) {#if %ismember(@step,@busy) {#wa @time;halt;%item(@area,@step);#add step 1;bianli} {{#if (%mod(@step,@bushu)=0) {#wa @wait;halt;%item(@area,@step);#add step 1;bianli} {%item(@area,@step);#add step 1;bianli}}}}
//与前面唯一不同的是先判断当前步数是否属于有busy的步数,如果是等待@time,接着走;否则跟上面完全一样
//有busy的步数保存在变量@busy中
#alias 无量山 {#var step 1;#var area @wuliang;#var steps %numitems(@area);#var time 30000;#var busy 43|79;bianli}
//手动输入#show %ismember("guo qiao",@wuliang)%ismember("climb stiff",@wuliang)显示为7842,所以需要在"无量山"这个alias中添加#var busy 43|79,并且,#var time 30000将busy的等待时间设置为30秒
//如果你的路径中没有这类具有busy的方向,比如丐帮洛阳,你只需要#var busy {}
//climb stiff和guo qiao命令输入之后都将等待30秒输入下一个命令,可以用下面的trigger调整#tri {突然你突然脚下踏了个空,向下一滑,身子登时堕下了去。} {#wa 1}
#tri {你终于一步步的终于挨到了桥头} {#wa 1}
//这里利用#wa命令的缺点,用#wa 1来替代#wa 30000,起到加速的作用,不会真的等待30秒那么长的时间,也绝不会等待时间太短,就是刚刚好事实上,所有的方向无非就是有busy和没busy两种(杀挡路npc也可以算是有busy的方向的一种),因此用上面的方法已经可以做出一个跟dammya完全一样的遍历机器人了,还缺少的只是下一章的路径录制方法. 注二:这里将所有的有busy的方向统一处理.事实上,你可以做得更精细一些,分成几类来处理效果会更好 11.3 慢速行走
慢速行走方法一:把上面的@bushu值改为1就是慢速行走了,不过这种行走无法停下来,#stop,#step,#back都无法实现 慢速行走方法二:
#alias bianli2 {#if (@step<=@steps) {#if (@finddbr=0) {#wa @time;halt;%item(@area,@step);#add step 1;bianli2}}
//行走前先判断@finddbr的值,如果为0,表示没有找到dbr,走下一步;否则嵌套结束,停止行走
//不管当前步数有没有busy,统一等待@time,@time在下面的alias中设置为30000 #alias 无量山2 {#var finddbr 0;#var step 1;#var area @wuliang;#var steps %numitems(@area);#var time 30000;#var busy 43|79;bianli2}
//慢速行走之前将@finddbr的值改变为0,表示没有找到dbr
剩下的就是做trigger了#tri {这里明显的出口是} {#if %ismember(@step,@busy) {#wa 1}}
//成功走出了一步.如果下一步没有busy,用#wa 1加速;否则什么都不做 注意;在无量山,成功的push stone,push men都有相应的描述,都表示成功走出一步,因此都需要做trigger加速.不加速的话也只是浪费点时间而已 #tri {突然你突然脚下踏了个空,向下一滑,身子登时堕下了去。} {#wa 1}
#tri {你终于一步步的终于挨到了桥头} {#wa 1}
//有busy的步数用专门的trigger来加速#tri {盗 宝 人*@dbrname~(@dbr~)} {#var finddbr 1;#wa 1;大开杀戒}
//找到dbr之后先改变finddbr的值,再加速然后开杀 任务完成返回:
顺向返回:没什么好说的,很简单的返回方法了 逆向返回:
#var fangxiang {n|e|nw|ne|nu|nd|eu|ed|u|enter|s|w|se|sw|sd|su|wd|wu|d|out}
#var fangxiangb {s|w|se|sw|sd|su|wd|wu|d|out|n|e|nw|ne|nu|nd|eu|ed|u|enter}
//2个变量对应的方向正好相反依次取出前一个方向,通过@fangxiang获得序号,通过序号在@fangxiangb里查找反方向,行走的具体做法我就不写了 注三:无量山这里只能顺向返回.你也可以在返回时加入自己的判断,从而把顺向返回和逆向返回结合起来,从而将效率最大化. 注四:上面只给出了标准方向的反方向获取方法.对于非标准且可逆的方向,都可以相应的添加到上面的@fangxiang,@fangxiangb中. 注五:丐帮暗道2的反方向是sw,但是sw的反方向可能是2,也可能是ne,解决的办法也有很多.实在想不出什么好办法,你也可以为2和se制作专门的alias,然后将alias作为2和se的替代方向来使用. 注五:对于其他的路径,有的需要开门,有的需要给钱老板gold,这些命令都可以作为方向添加到路径里去,慢速行走时作好相应的trigger来加速,不一一细说了 注六:行走失败时,无非是被系统跘住或者被自动叫杀的npc纠缠住或者busy还没结束不能移动,此时当前步数减一继续行走,不详细给出相应的trigger了. 注七:此方向效率比path高很多倍,慢速行走每步之间的间隔几乎没有.如果你用path来做遍历,至少要设置等半秒吧,一个大型区域比如丐帮洛阳凌霄都有几百步,需要几分钟才能走完,一个胡一刀任务的完成时间通常就会超过15分钟. 注八:上面的方法已经实现了#step,#stop,#back,#pause等功能.事实上实现的方法有很多种,上面的方法也肯定不会是最佳的一种. 注九:还是那句话,遍历做起来工作量很大,需要很多trigger来使用路径. 下一章将介绍路径的制作方法,以及完成更多path根本做不到的事情.
第十二章 遍历实现的一种方法 本章继续介绍遍历的制作.先给出路径的制作方法,然后将遍历以及返回的方式多样化. 注:在机器人制作过程中,并不一定要用到本章及随后两章介绍的所有方法。一切以你给机器人设定的功能为基础,兼顾稳定效率简洁选择合适的方法。如果你觉得有些方法实现起来太复杂,你可以简化它,也可以不用理会它或者改进它。本章及随后两章仅供参考。 12.1 路径的制作
一个list变量如果手动添加item以及间隔符号"|",不仅浪费时间,也容易出错,参考path的制作过程,制作下面的alias 制作路径之前需要将相关变量清空,为此制作一个按钮 #button 0 #mark {#var area {};#var busy {}}
//这里的按钮相当于path路径制作#mark的功能,所以取名为#mark,路径临时保存在@area中,busy方向的序号保存在@busy中 如果你把有busy的方向分得更精细,你还需要更多的变量来保存这些方向的序号,请一并清空 #alias g {%1;#var area %additem(%1,@area);#say @area}
//定义一个alias,在走路的同时将方向添加到@area中,并且显示出@area的内容 有了这个alias,你只需要用g s,g e,g "enter boat",g "aliasname"这些命令在游戏里走路就可以了.在你走路的同时,s,e,enter boat,aliasname都自动添加到变量@area中了,并且同步显示出变量@area的内容. #var pathname @area;#var area {}
//路径制作完毕之后,保存到pathname中,同时清空@area准备下一条路径的制作 再用下面的按钮辅助就更省事了
#button 0 记录busy方向 {#var busy %additem(%numitems(@area),@busy)}
#button 0 显示busy方向 {#say @busy}
//碰到有busy的方向,轻轻点击一下第一个按钮.等整个路径走完之后点击第二个按钮就可以知道哪些步数有busy了.在保存路径的同时顺便将路径的遍历方法一并写好.
注一:你可以边走路边制作trigger,例如上一章中快速行走慢速行走需要的trigger都在走路的时候就作好,将会节约你大量的时间注二:整个路径走完,与该路径有关的alias,variable,trigger就已经全部制作好了,当场测试一遍确认无误就可以开始下一条路径的制作! 为了让遍历的方式更加多样化,在制作路径的时候可以记录更多的内容,本章的第2小节将会用到.
#button 0 记录关键地点 {#var room %additem(%prompt("","关键地点"),@room);#var roomnum %additem(%numitems(@area),@roomnum)}
#button 0 记录关键npc {#var npc %additem(%prompt("","关键npc"),@npc);#var npcnum %additem(%numitems(@area),@npcnum)}
//用到函数%prompt(),跟#pr类似,不过这个函数不会将你输入的内容赋值给变量,而是将你输入的内容作为函数的值.
//在录制路径的时候,点击这2个按钮,会弹出一个对话框,让你输入"关键地点"或者"关键npc",你可以为当前地点或者这个房间的npc取一个名字,名字被保存在@room或@npc中,当前地点的编号自动保存在@roomnum或@npcnum中
//比如你在发呆室,可以点第一个按钮输入"修理装备"来保存修理装备的地点
//你在胡一刀那里,可以点第二个按钮输入"老胡"来保存胡一刀的位置12.2 遍历的多样化
步骤一:请大家自己动手完成这一步,用上一章的方法,写好针对@area的遍历,包括顺向快速行走,逆向快速行走,顺向慢速行走,逆向慢速行走 为了下面叙述方便,假设你已经完成了上一步,顺向快速行走的alias是fastwalk,逆向快速行走是fastwalkb,顺向慢速行走是slowwalk,逆向慢速行走是slowwalkb 这些alias中用到的变量有:
@step--表示你的当前位置,在起点位置为1,在终点位置为%numitems(@area)+1,依次类推
@steps--表示行走的终点位置,即顺(逆)向快(慢)行走停止之后你所在位置应该为@steps
@busy--有busy的方向在路径中的编号 注三:有兴趣动手完成这个步骤的同学,可以在做好这4个alias之后测试一下,一定要确保行走停止之后@steps和@step的意义与上面所述相同,如有差异请稍作修改。对list变量的遍历感到陌生的同学,这会是一个很好的锻炼
步骤二:用遍历行走的时候,不管你是什么原因停了下来,你的trigger都应该保证@step的值是你当前所在的位置。 注四:由于某些trigger无法判断的原因,导致@step中的值不是你当前所在的位置,我们称这一现象为"乱入",这在胡一刀和护镖任务中都可能发生,解决办法留待后面2章介绍,现在暂时不管这个。 步骤三:制作功能更强大的遍历alias #alias fastgoto {#if %isnumber(%1) {#var steps %1};#if %ismember(%1,@room) {#var steps %item(@roomnum,%ismember(%1,@room))};#if %ismember(%1,@npc) {#var steps %item(@npcnum,%ismember(%1,@npc))};#if (@steps>@step) {fastwalk} {fastwalkb}}
//快速行走的alias,拥有一个参数,这个参数可以是一个数字,也可以是房间的名字,也可以是npc的名字
//%isnumber()这个函数可以判断是否为数字,如果是直接赋值给@steps
//如果参数时房间的名字或者npc的名字,将房间的编号赋值给@stpes
//通过比较@step和@steps的大小关系,选择是顺向行走还是逆向行走
fastgoto 修理装备:从任意地点走到发呆室修装备
fastgoto 老胡:从任意地点走到胡一刀那里
fastgoto [@step+1]:从任意地点顺向走一步
fastgoto [@step-1]:从任意地点逆向走一步
fastgoto 1或者fastgoto [%numitems(@area)+1]:从任意地点走到起点或者终点
fastgoto %1:如果%1=@step,停留在原地
可以看到这个遍历功能很多,如果你在制作路径的时候记录的npc或者房间名称很丰富,你的行走将随心所欲此命令有2个缺点:
(1)无法判断路径是否可逆
(2)路径是全区域的遍历,因此行走过程中可能要走很多不必要的步数 注五:下一章会修改这个alias,将所有的情况用一个alias来完成.如果可逆就逆向行走至目的地,如果不可逆就顺向返回起点再顺向行走至目的地;并且在不需要遍历的时候将路径简化,只走最短路线 慢速行走完全类似
#alias slowgoto {#if %isnumber(%1) {#var steps %1};#if %ismember(%1,@room) {#var steps %item(@roomnum,%ismember(%1,@room))};#if %ismember(%1,@npc) {#var steps %item(@npcnum,%ismember(%1,@npc))};#if (@steps>@step) {slowwalk} {slowwalkb}}
|