背景:
阅读文章

zMUD中变量和函数的应用

[日期:2007-05-13] 来源:  作者: [字体: ]

我是天龙八部的玩家,所以举的例子都源于天龙,别的mud的玩家也可以学着用,但需举一反三,不可拘泥于程式,另外,mud中变化万千,常出现一些难以解释的意外情况,用函数和变量做trigger本就是高级手法,所以如果你用我教的方法打npc,如果出了意外,请再仔细研究trigger是否有误。mud到底是玩,也别把生死太放在心上。 OK,那...咱们从哪儿聊起呢?

先说如果你要同时打许多个同样的npc时,应该怎么办呢?比如,你搬了20只大蟒,你可能要做个#alias {killsnake} {kill snake 1;kill snake 2;kill snake 3;......kill snake 19;kill snake 20},这是初级做法,我们只需用#20 kill snake %i 一句就可以完成了。我具体解释一下。


#这个指令很有用,可以重复发相同的指令,比如#20 s就是向南走20步,这我想大家都早会了,%i是用了一个变量i,大家不要把i替换成别的字母,否则就需要引进其他一些指令了。如果你要打10个xing,5个zuo,6个rong,怎么做呢?在mud中输入:
#alias {killall} {#10 kill xing %i;#5 kill zuo %i;#6 kill rong %i} 回车就可以了。然后可以随时调用killall这个alias。切记举一反三啊!!!

刚才的这个比较easy,下面说点难的,hehe,先引进三个特殊指令:
#VAR 表示赋值,如#VAR a 1或#VAR b 78,意思为设变量a=1或变量b=78;
#MATH表示计算,如#MATH a @a+1意为a=a+1,当然这个a是必须先由#VAR赋值设定过的;
#SHOW 表示显示,如#SHOW @a则显示出变量a的当前值。

大家肯定早已经糊涂了,怎么一会儿a,一会@a的,这是挺烦的。我也不分析什么道理大家多用就自然记住了。另外,#MATH可以进行加减乘除等运算,我下面举个具体例子:
#VAR a 1 赋值变量a为1
#VAR b 10 赋值变量b为10
#MATH c (@a+99)/@b*2 计算c=(a+99)/b*2
#SHOW @c 显示变量c的值 (结果显示20)

那么,我们学会使用这些变量到底有什么实际用处呢?坦白的说,用处不大,打npc是真刀真枪的战斗,取不得巧,做个状态条显示气血精神exp增长率什么的,也是闲得无聊的玩意儿,我只能说,凡是可以或需要用到计算的问题,我们都可以用这些指令解决了。比如,当我们循环后,常会算用400内力可以恢复多少气血,或者要恢复满600气血需要用多少内力等问题,那么我们可以先算出用20点内力可以恢复多少气血(精神相同),假设20点内力可以恢复45点气血,那么要恢复600气血需要600*20/45点内力,只要在mud里输入:
#VAR a 45;#VAR b 600;#MATH c @b*20/@a;#SHOW @c就可以了。不过,这看起来也没什么用,我说的只是一个思路而已。 这些变量的最大用处在于可以放在一些mud指令之后,比如#VAR a 200;exercise @a就表示用200气血打坐,当然,我们一般用于study book,exercise,meditate,learn等指令后的数字都是一个不常变化的数字,只有当出现需要经常变化(递增或递减)的情况才派上用场,如传内力就是个运用变量的好时机,随着接受内力者的内力增加,传功者打坐所需气血也应随之增加,那么这个递增变量就可以用exercise @a;#MATH a @a+1来完成。

罗嗦了半天,也许大家根本觉得没用,那就跳过那段吧。下面我说说trigger中变量的应用。常有人爱做个人缘好的dummy放在玩家常连线进来的地方,一出现"谁谁连线进入这个世界"他就打招呼,点头作揖问好,这里就包含了trigger中套用变量的基本用法。如下例:
#AC {^(%1)连线进入这个世界。} {chat hi,%1,你可来啦,想死我了!}
在这个例子中,%1可以代表为数字或字母,如果你用%a则只能取到数字。如
#AC {经验:%a} {tell buyi 我已经有%1点经验啦,xixi}

对了,忘了说了,#AC是ZMUD里一个特殊指令,其实就是我们常用的trigger,我们一般都用鼠标去点菜单上的软键,用#AC就可以直接输入做好trigger了。那个buyi是俺的大名,:P

在trigger的Pattern前面加个^号,是表示激活该trigger的话必须顶头出现,很多人都做了读书睡觉的trigger,Pattern为"你一觉醒来,觉得身体完全恢复了!"这样,如果有人捣乱用rumor说"你一觉醒来,觉得身体完全恢复了!",那你的trigger就被激活,乱了套了,trigger多了,自然要保护好,把Pattern做成"^你一觉醒来,觉得身体完全恢复了!"就不怕了。如果你自己想测试这个trigger,那就用#SA来搞定。在这里必须提醒一句,mud里常出现">"这个符号,常让trigger不能顶头出现,从而trigger失效,这是个很讨厌的问题。我的解决方法是把trigger加上颜色,具体方法如下操作:
先用鼠标将要取的Pattern抓下,然后打开trigger,new一个新的,点Options,选中Color Trigger,然后在pattern里用Ctrl-v复制上去。这样,你的trigger就变成一行你自己都看不懂的乱码了,没关系,zmud能看的懂,好了,你的trigger加了颜色,无论谁也无法打乱你的trigger了。 :)

faint..好像说走题了,我们言归正传。
前面咱们说到在trigger前面加上一个^符号就可以完善了很多,那么当Pattern重复出现时,我们怎么解决呢?比如,我们一般会做出"看来该找机会逃跑了..."就一口气跑到仙人洞或客栈睡觉,但如果move和dodge的有效值比较低的情况下会被拦住,trigger会被多次激活,当然,我们在逃跑前加个投降(surrender)可以万无一失的逃掉,可如果网一慢,仍旧会出现Pattern重复激活trigger的情况,后果轻者去judge那答题,重者可能要被踢出去,那么,我们如何解决这个问题呢?hehe,easy....下面我先着重介绍两个指令"#T+ , #T-"。
#T+、#T-是做高级trigger中最常用的两个指令,它可以打开或关闭指定的trigger,甚至打开或关闭一类trigger。trigger中的class是分类标志,那么比如:#T+ fight就表示打开class为fight的所有trigger,#T- sleep就表示关闭class为sleep的trigger,ok,看明白这两个指令就好办了。下面举个例子:
假设我们在打三个戏迷,路径大家都熟吧,trigger如下:

1、class---fight_escape
pattern:{看来该找机会逃跑了...}
commands:{#T- fight_escape;#T+ fight_wake;surrender;s;s;n;#3 e;s;give 1 silver to waiter;u;e;u;w;u;s;u;n;shui}

2、class---fight_wake
pattern:{你一觉醒来,觉得身体完全恢复了!}
commands:{#T- fight_wake;#T+ fight_escape;#wa 10000;n;w;w;w;n;kill viewer;kill viewer 2;kill viewer 3}

这套trigger我主要介绍四个重点:
第一、class应区分开,这样用#T+、#T-时才不会混乱,当逃跑时关闭escape,睡醒后再打开,就可以防止多次激活trigger;
第二、surrender后一定要用s;s;n;#3 e是因为有时候你碰巧逃掉了,位于大理西街1,直接3个e就可以去客栈,但如果没逃掉就需要s;#3 e,那么最保险的走法是s;s;n;#3 e,因为到了段家当铺就没有向南的出口了,这看起来简单,但实际上是一种做trigger的思路,我将在以后详细讲这个部分。比如,我给你们留个题想想:怎么能在大理南1,北1,东1,西1四个位置都用同一套路径走到天龙客栈?
第三、在客栈抢房间睡觉是我们常遇到的问题,那么把四个房间都试一遍才是上选。当然,如果碰巧四个房间都满了,这trigger就停下来了,怎么解决呢?据我所知有多种方法,无非是往出走几步取描述、做emote等等,其实最好加个变量a,一出现客满那句就#add a 1,最后加个#IF {@a=4} {#wa 2000;u;e;u;w;u;s;u;n;shui;#VAR a 0}就可以了。 :)
第四、如果有的trigger这句你既没有加上颜色也没法在前面加^,那就最好当不用时就#T-关上,比如,我们fight时最好把"你一觉醒来"之类的关上,等跑去睡觉时再打开,以防混乱。OK,我们趁热打铁,我再做个抢仙人洞的trigger,请大家着重注意#T+、#T-的用法。先做几个alias:

#alias {xrd1} {s;s;s;s;w;w;w;w;w;w;w;n}
#alias {xrd2} {s;s;s;s;w;w;w;w;w;s;s;w;w;n}
#alias {xrd3} {s;s;s;s;w;w;w;w;w;s;s;s;s;w;w;n}
#alias {xrd4} {s;s;s;s;w;w;w;w;w;s;s;s;s;s;s;w;w;w;n}
#alias {killall} {#3 kill viewer %i}
trigger如下:

1、class---fight_escape
pattern:{看来该找机会逃跑了...}
commands:{#T- fight_escape;#T+ hole1;surrender;s;s;n;e;xrd1;n;n;shui}

2、class---hole1
pattern:{大理钱庄}
commands:{#T- hole1;#T+ hole2;#WA 2000;s;w;w;u;#WA 5000;d;xrd2;n;n;shui}

3、class---hole2
pattern:{大理钱庄}
commands:{#T- hole2;#T+ hole3;#WA 2000;s;w;w;u;#WA 5000;d;xrd3;n;n;shui}

4、class---hole3
pattern:{大理钱庄}
commands:{#T- hole3;#T+ hole4;#WA 2000;s;w;w;u;#WA 10000;d;xrd4;n;n;shui}

5、class---hole4
pattern:{大理钱庄}
commands:{#T- hole4;#T+ hole1;#WA 2000;s;w;w;u;#WA 10000;d;xrd1;n;n;shui}

6、class---hole_wake
pattern:{你一觉醒来,觉得身体完全恢复了!}
commands:{#T- hole_wake;#T- hole1;#T+ fight_escape;#WA 4000;e;w;n;killall}

这样,就可以实现选洞了,如果1洞有人,就选第二个,直到第四个若仍有人,那就再从第一个试起,直到睡上为止。需要注意的是,因为去仙人洞的路比较远,所以在选洞之间要加比较长的延时,而且越往后越长,我只是做个例子,具体加多少合适,大家自己摸索吧。
上面这套trigger基本上把#T+、#T-的用法发挥得淋漓尽致了,但这仍不是最高级的trigger,光一个选洞就用了4套才完成,如果再把我前面讲的变量知识用上,那就更简单了,请看:

1、class---fight_escape
pattern:{看来该找机会逃跑了...}
commands:{#T- fight_escape;#T+ hole;#VAR a 1;surrender;s;s;n;e;xrd@a;n;n;shui}

2、class---hole
pattern:{大理钱庄}
commands:{#ADD a 1;#IF {@a=5} {#VAR a 1};#WA 2000;s;w;w;u;#WA 5000;xrd@a;n;n;shui}

3、class---hole_wake
pattern:{你一觉醒来,觉得身体完全恢复了!}
commands:{#T- hole_wake;#T- hole;#T+ fight_escape;#WA 4000;e;w;n;killall}

:P,这样就简化为三个trigger了,试试吧!
在此,我想再重申一遍,我讲的是一种思路和方法,真正玩mud时会出现千奇百怪的变化,而且pig wiz们也都在挖空心思琢磨怎么抓robot,所以请大家不要牵强附会的套用我做的trigger,也许你做得更好更实用呢,别忘了给我发封mail,也教教我啊。 :)
这次主要说的是#T+、#T-,也许大家注意到了,我的trigger里面多了个#IF语句,这是一个更有意思的指令了,下次,我专门给大家讲这个,OK?
无论任何时候,大家都可以给我发mail(wanq@163.net),来一起探讨trigger问题,我在文章中尽量把trigger写得详尽,但我希望大家别要求我把trigger做好mail给你,好么?

因前一段时间工作较忙,我停了一段时间没写,再次拿起笔来已有些犹豫,这第三篇我本写的是#IF语句的用法,可我想,真正在玩MUD时用#IF语句的玩家真是少之又少。#IF语句的精华在于判断变量的大小而做出不同的反映,比如:
#IF {@a>100} {haha} {sigh}
这句话就表示当变量a>100时haha大笑,不大于100时(包括小于和等于)就sigh叹气,如果我们用前面讲的方法把气血或内力从屏幕上取下赋值为a,那就可以做一个判断气血内力多少的trigger来打npc。
有不少人用双倍force的方法打npc,当被npc打出来时就发呆10-20秒,因真气高气血恢复得多,所以很快能恢复满继续冲进去战斗,这种简便易行的办法足以应付简单的战斗进程。而应用了#IF和变量取值等高级trigger后反而会出现种种问题,我自己就曾做了用变量判断内力多少来决定是否中止战斗出去循环,可也死在上面两次,都是trigger混乱导致的。所以,告诫大家,应用变量和函数是trigger中的高级做法,如果不是trigger大法深不可测之人,切忌舍易求难,一切应从实用出发。说到这里,我想起来一个有趣的例子,记得数月前,我在天龙跟一帮朋友探讨trigger,一个玩家提出如何做过黄土大道的trigger,那时雪山,少林等都还没设客栈,所以要想回去跟master学功夫简直难上加难,路途远不说,而且黄土大道是随机重复的,如果做单程去的还算容易,可回来的路就不太好办了。现在,我们知道,首先可以用#T+,#T-的方法,去时打开gowest class,回来打开goeast class,就很容易解决。再有,我们可以用#IF来进行判断,去时可以可以把变量a设成1,跟师傅学完回来时设成0,那么当屏幕上出现"黄土大道"时,我们就会用到下面的方法:
#IF {@a=1} {w} {e}
我想我不解释大家应该可以明白了。最后有一个玩家提出"何必如此麻烦",去时只要#30 w,然后加10秒延时不就可以了。回来可以用#30 e;#wa 10000;#20 e;#6 w就可回到开封中心了。乍一看来如此trigger有些令人不屑,可其实最简单易行。我玩天龙前期一直是用这套trigger来往返黄土大道的。好了,上面的问题不多说了。下面我专门要讲一种路径思维。
先从简单的说起,比如我们要走以下路径(您可以对照着天龙八部的地图来看下面的例子)
从客栈走到包子铺,路径如下:n;w;w;w;w;s
从钱庄走到包子铺,路径如下:s;w;w;w;w;s
那么如果我不一定是从客栈还是钱庄开始,如何只用一条路径就走到包子铺呢,我们也许会用:n;n;s;w;w;w;w;s
意思就是说我先从客栈走到钱庄,然后再重复从钱庄到包子铺的路径。这样,即使出发点在钱庄,那么上面的路径也一样可以走到包子铺。那如果我们再增加一个出发点在珠宝店呢?这就有点麻烦了。我们可以用下面的路径:n;n;s;#7 w;e;e;e;s
意思是,我们先n;n;s可以走到大理东街上,不一定是东1街还是东2街,然后7个w可以一直撞到西头,然后3个e即返回到西2街,再s就到了。最后,我提个难题,很多新手都会打行人(walker),在大理南3街上有三个行人可以打,但那里有4个出口,而且逃跑时不一定能逃掉,如何做个trigger可以只用一条路径就能准确到达客栈呢?hehe,看看下面的-----
#trigger {看起来该找机会逃跑了...} {surrender;#4 s;w;w;e;#3 s;#6 n;e;e;s}
这条路径关键在于用到南头是天龙寺工地,只有一个出口为north。当我们在战斗时,无论是向南跑还是向北跑,4个s都可以到达天龙寺工地,然后假设我们往西或东逃跑了,那w;w;e可以回到南3街,然后3个s还可以到达工地,最后6个n,e;e;s就回客栈了。
上面讲解的可能部分玩家还是不明白,希望能把这种"撞头"的路径思维吃透,当然,我们打NPC时最好还是搬到只有一个出口的地方打,如果有人跟你抢NPC时,heng,看谁狠!干脆搬到大理十字广场打,hehe,恐怕没人能跟你抢了。grin...不过,可不要影响别人啊,下了剑的大理士兵和皇宫禁卫可杀气极高,不能乱放啊! :P

在大理十字广场打NPC的trigger如下:
#trigger {看起来该找机会逃跑了...} {surrender;#7 s;#6 n;w;n;s;#6 w;#7 e;s}
用此路径必到客栈,有兴趣的朋友可以试试。

一说到路径,我还有点其他的想补充,那就是我们都常做alias,alias是别名的意思,有时在MUD中alias就是路径的代名词了,那么如果我们想做个到少林大雄宝殿的alias,估计不少玩家会走一步,拿笔记一步,最后再敲一遍,感觉挺麻烦,少林路途算近的,要做个找蛇的,去雪山的恐怕就太慢了。很多MUD站点都在介绍如何使用Map功能,如果以后有时间,我也专门给大家讲讲,不过在此,我说个更简便的方法,如下:

在MUD中输入:
#REC (然后你就开始走吧,比如...)
n;nw;n;nw;n;nw;n;nw;n;nw;nu;n;eu;n;nw;nu;nu;n;n;n;nu;nu;n;n;nu;nu
#REC shaolin (走完把这个路径设名为shaolin,OK啦!)
现在看看aliases,已经自动记下了你刚才走的路,去大雄宝殿的alias做好啦!要想删除某个alias,就用#unalias xxx即可,简单吧?! :)

这最后一篇文章,我酝酿了一月有余。我做了zili的trigger,以实验各种函数和变量的应用。在这一月中,我还多次拜访了东方英雄的主页(http://www.nease.net/~jjwk),仔细学习了如何使用zMUD中提供的automapper来制作mud地图,而且,我在river的主页“zMUD从入门到精通”中看到了zMUD4.62帮助文件的全中文翻译,深感佩服。我不得不承认,前人的研究远胜于己。在MUD中练功无止无休,zMUD的研究也是永无止境,即使已经熟悉了各种变量函数,仍可以求简化、求精深。
忽然想起这样一个小问题,有的朋友曾问我,当同时fight10个同名的npc时,如何只打后面5个,放过前面5个不打。我们可以用#loop语句轻松完成,如例:

#loop {5,10} kill snake %i

这个例子中的5和10可以换成变量来操作,配合抓蛇的trigger,可以几个人在一起练功不互相干扰,比如#loop {@a,@a+5} kill snake %i。还有朋友曾问起我如何制作自动打招呼的trigger,关键是如何获取player的英文id,这是有一定难度,我将zili trigger部分公布,下面进行讲解。

1、Class --- come (enable)
Pattern:(%1)走了过来。
Commands:#t- come;#t+ come1;#var cname %remove(> ,%1);id here

此trigger中关键是用id here来将玩家的中文名字转换成英文id,因为在mud中顶头经常出现“>”符号,所以用%remove函数将“>”去掉,值得注意的是,在“>”后应多加一个空格,然后才是
“,%1”,这样才能准确获得玩家的中文名字,以便准确激活下面的trigger。

2、Class --- come1 (disable)
Pattern:@cname (%s) = %1
Commands:#var ename %1;l @ename;#t+ come2

打“id here”后,同一房间内玩家的中文名字和英文id都显示出来,但应注意的是在中文名字后的空格长短不一,需要用%s来替代,而在“=”后面的英文id就不需要考虑空格的问题了。
另外,我在这里介绍另一个函数%trim(@a),这个变量可以消去变量a两旁的空格,用%trimleft(@a)是去掉左边的空格,%trimright(@a)是去掉右边的,这个函数在某些因空格数不一定的trigger中能起到非常好的作用。

3、Class --- come2 (disable)
Pattern:他看起来约(%x)多岁。
Commands:#var sex male;#var cage %1

此句取来者年龄性别。

4、Class --- come2 (disable)
Pattern:她看起来约(%x)多岁。
Commands:#var sex female;#var cage %1

性别本来应该可以做了变量取下来用#if {%1=~"他"} {#var sex nan} {#var sex female}来判断识别,可我在trigger中反复调试竟然不成,这是我一直没有解决的问题,哪位高手知道希望能不吝赐教。似乎问题在于=~" "引号里面的内容不能是汉字,是英文就可以,搞不懂怎么回事。

5、Class --- come2 (disable)
Pattern:武功(%1)
Commands:#var wugong %1;#if {@sex=~"female"} {#case %random {xixi @ename;#wa 3000;say @cname妹妹,你刚@cage几岁,武功都练到@wugong啦!} {pat @ename;#wa 3000;say @cname,@cname2都等了你好久啦,怎么才来!;#var @cname2 @cname} {kiss @ename;#wa 3000;say 大功告成,亲个嘴儿!}} {#case %random {pig @ename;#wa 3000;say @cname,你的武功怎么还是@wugong呀,@cage多年真是白活了!} {jump;#wa 3000;say @cname大哥来啦,@cname2呢,快给上茶!;#var @cname2 @cname} {heng @ename;#wa 3000;say @cname,你还有脸来见我,快自己了断了吧!}}

这句比较长,请大家仔细看清楚语法结构。主要用了#case和%random函数,在cake的文章中已经有比较详细的论述,我这里不再多说了。主要用#case可以使打招呼的话变各种花样,把player的id,中文名字,性别,武功等级都取下来做在trigger中,显得更生动有趣,还可以把player的容貌、身体状况和穿戴也取下来,我这里也不多讲了。 本想写一篇关于如何制作回答审判官(judge)问题的文章,我自己也苦心制作了trigger,可我看了一个朋友给我的trigger后,无论怎样也无法超越前人的杰作了。并且,我也并不赞成judge triger的推广,因为如果那样的话,巫师也许会制作更难缠的judge来抓玩家,或者将指令数限制的更严。不过,我在此也要多说一句,黄土大道是天龙八部的一个败笔,重复的路无形中增加了玩家的指令输入量,而且平淡无味,只觉烦人,连接大城的路怎能做成这样?在许多MUD中,大城到了晚上就会关闭城门,无法进出,这种设计很真实,虽然等城门开时有点无聊,但不能不说也是一种不错的思路。

下面我再讲讲zili trigger中一个有趣的设计,就是做一个玩家描述的文本档案,当别人ask zili about id时,zili会说出与所问id有关的一段话。我的trigger是仿照西游记中对诗的trigger制作成的。有兴趣的朋友可以对照看看。

1、Class --- ask
Pattern --- 向你打听有关『%1』的消息。
Commands:#if {%1=@askname} {#math dask @dask+1} {#var dask 0};#if {@dask>6} {heng;say 你别老问个不停好不好?不理你了!;#t- ask;#wa 60000;#t+ ask;say 好吧,再跟你们聊一会儿吧,别老问个不停呦。} {#t+ ask1;askname=%1;#if {%len(@askname)<3} {shake;say 你听说过有人叫@askname么?} {#sh %grep(1,"@askname");#var aass %grep(1,"@askname");#if {@aass=~""} {#case %random {shake;say 不太清楚...} {?;say 天龙有这号人么?我怎么不知道?} {heng;say 我不想谈他,换个话题吧...} {sigh;say 我脑子里也记不住这么多人呀!} {blink;say sorry,我不知道,不过,你可以tell我“记录 <id> <描述>”,我就可以记住啦,try!}}}}

这个trigger比较复杂,前面部分在于防止有人连续ask捣乱,让你跑到judge那里,所以如果同一人连续ask6遍以上,就会停止trigger一分钟。中间部分是防止所问id过短(少于3个字母),如果过短会出现混乱。第三部分#sh %grep(1,"@askname");#var aass %grep(1,"@askname")是关键内容。用%grep函数来找出与所问id匹配的描述。最后部分是防止所问id为中文或者在文本档案中没有记录的部分。

2、Class --- ask1
Pattern --- (@askname)(%s)(%1)
Commands:#t- ask1;askname2=%1;say @askname2

当找到匹配的描述后,会在屏幕上显示出来,就用这个trigger取下id后面的中文描述,剩下的就简单了。
我知道我讲解的过于简单了,可实际上很多东西是难于在字面上解释清楚的,你自己实际操作一下,会发现很容易,而且理解的更透。
Trigger在练功中可以省去我们很多指令输入,是玩Mud的一个重要帮手,其实能迅速准确的激发,完成你要达到的目的就可以了。我这篇文章从浅入深谈zMUD的函数与变量,到后面其实已经脱离了练功trigger的范畴。做一个智能的机器人,用trigger来模仿真人的说话和emote,甚至完成一个完整的事件,已成为了一些trigger高手的趣向。如果我们再给机器人加上具有个性的言谈和emote,并且自动寻找出口四处走动,那几乎可以“以假乱真”。

我们作为真人,竟用机器人来模仿真人,有点可笑,是吧? :-)


 
 尊重作者 转载请注明出处52mud.com

收藏 推荐 打印 | 录入:sbso | 阅读:
相关内容      
本文评论   [发表评论]   全部评论 (0)
内容推送
52mud提供
一起回忆泥巴游戏QQ群68186072
52mud官方微信公众平台
热门评论