![]() |
![]() |
#1 |
黄金会员
![]() ![]() 注册: 02年05月26日
来自: 梦幻国度
帖子: 1,061
声望力: 33
声望:
25
![]() 精华:8
现金:370两梁山币
资产:3845两梁山币
致谢数: 4
获感谢文章数:1
获会员感谢数:1 |
![]() 如何利用数据库制作全自动解谜机器人 作者:八级风(转自:西游奇旅) 这篇东东献给所有热爱XYJ,热爱Mudfan的朋友。 第一章 制作全自动解谜机器人的途径 在XYJ里,如何快速增长道行,是一个困扰许多玩家的大问题, PK、NK、打花、解谜……PK要甘冒天下之大不韪;NK到了后期很难找到合适的NPC对象; 打花的确是个好方法,我曾经8小时打了430多年,不过很多站点被cut了, :(。只有解迷,成了一个最可靠的方法。无论去哪个站点, 只要能熟练掌握解谜方法和技巧,都能较快的成长。 然而,解谜的繁琐和辛苦程度令很多玩家望而却步。解谜手册的熟记, 解谜物品的准备,问谜,解谜,清谜,再问谜,再解谜,精神 高度集中, 键盘敲个不停,就象一只陀螺,疲惫地转个不休。一个全自动的解谜机器人, 无疑是所有痴迷XYJ的玩家的梦想。把解谜变成一件轻松的事情, 留下更多时间享受聊天乐趣,让全自动机器人的梦想成真,就是这篇文章的目的。 据我了解与尝试,在现有的条件下,制作全自动解谜机器人大致 可以走以下几条路: 1、把所有任务列入Trigger中,根据问谜的结果触发,完成解谜任务; 2、利用Zmud本身提供的DDE(Dynamic Data Exchange,动态数据交换) 函数来开发一个外部程序,通过外部程序来控制Zmud的运行,实现自动解谜功能; 3、利用Zmud V5.55及其更高版本提供的Zmudapi.dll来开发一个控制Zmud运行的外部程序。 4、利用Zmud V5.x及其更高版本提供的数据库模块构建解谜数据库,配合Trigger来控制解谜。 下面我们来分析一下各种方法的利弊与可行性。 1、现有的很多所谓自动解谜机器人就是这种类型的。有些是专门做 一种解谜任务的,有些更全一点,最好的好象可以做四种任务。 说到底,这样的机器人不过是简单的触发堆积,Trigger庞大的要命,把机器拖的半死, 完成解谜任务又相当刻板,对于XYJ2000的解谜系统根本不适合的。我认为, 这样的Trigger只能拿来给新手做解谜的辅助与提示,没有更大的实际意义。 2、DDE的支持从Zmud很早的版本就开始了,当然DDE本身也是个老古董了。 对于大家常用的4.62版本来说,是除了方法1之外的唯一途径了。 当年浙大西游记的郭大路(henry)曾经用Delphi开发了一个自动解谜的外部控制程序的雏形。 他之所以选用Delphi开发,理由是: Zmud是用delphi编写的,所以用Delphi最好,VC太复杂,VB的DDE控件不行, 只有Delphi的DDE控件与它联系起来最方便。 雏形出世的时候我还没有开始玩XYJ,同时这个雏形也没有引起太多人的注意。 所以henry的计划随着他去清华读博夭折了。 用DDE开发自动解谜机器人,无疑比方法1迈进了很大一步, 但是,在开发上的难度是相当大的。 3、从Zmud V5.55开始,ZuggSoft公司提供了一个叫Zmudapi.dll的动态链接库。 这个DLL本来是提供给Zmud用户来开发各种插件(Plugin)的。 我在连到ZuggSoft站点下载Zmud 5.55的时候注意到了它的介绍。 (在Zmud 5.55中还附带了Zmudapi.hlp,这个帮助文件简单介绍了该 DLL的功能与用途。在更高版本里不提供这个帮助文件。) 它提供了对Zmud的命令控制、数据传送(单向)以及其他一些功能的函数。 当时我就决定通过调用这个DLL来替代DDE实现外部控制程序, 可惜,我用VC无论如何也无法正常调用DLL提供的函数。这也促使我转向寻找其他方法。 不过,会用Delphi的朋友可以去试一下,Zuggsoft是推荐用Delphi开发的。 4、我的目光焦点是最后转向这个方法的。从Zmud 5.x开始,提供数据库功能, 而这个数据库对于庞大的解谜系统无疑是十分适合的。 解谜的任务如果不包括玩家送物和玩家拜贤,数目接近2000个,用现成的数 据库来处理要比自己编写专门的数据处理程序要便捷的多,处理速度上也有优势。 虽然Zmud提供的数据库功能并不强大,但对于我们编写自动解谜数据库而言足矣, 控制解谜的其他部分可以用少量的Trigger来实现。 在多次尝试之后,我最终选择了第四种方法。在下一章,我会从开发 解谜机器人的实际过程开始,按我所经历的实践思路跟大家探讨: 第二章 建立解谜数据库 建立解谜数据库的最主要目的是,提供迅速快捷的解谜信息的查询。 另外,还可以利用数据库排序、选择的基本操作,来实现自动选择执行任务的功能, 这点我会在下一章里详细说明。 下面就开始搭建全自动解谜系统的基石――解谜数据库。 在Zmud 5.x和6.x版本中,工具栏里有个DB按钮,通过它进入Zmud的数据库模块。 根据上面列出的两个目的,我建立了两个数据库:一个是静态的数据库Record.db, 一个是动态的数据库Quest.db。 Record.db用来保存所有的解谜任务,里面的内容只能通过数据库的数据管理来做修改, 在自动解谜系统工作的时候,它的内容是不会发生变化的; Quest.db用来记录当前的解谜任务,总共七条记录, 它的内容随着解谜的进行不断更新, 并且通过建立Quest.db的视图按条件选取下一个该执行的任务。 两个数据库的构造如下: Record.db 这个数据库的记录有6个字段(Field): Type(任务类型,该字段为Single Option类型,字段的值为 食物、送物、拜贤、灭妖、武器、盔甲、募捐之一。) Name (任务名称, 字段类型Text) Ename(任务英文名称, 字段类型Text) Extra(任务附加选项, 字段类型Text) Place(任务地点, 字段类型Text) Todo (执行该任务的命令, 字段类型Memo) Type字段将任务的类型加以区分,对应七种不同的任务种类; Name和Ename字段在不同任务中分别对应食物、武器、盔甲、募捐的物品和送物、 拜贤的人物的中文名及英文名;Extra字段在送物中对应所送物品名称, 在拜贤中对应所询问事宜;Place字段记录任务中人物或物品所在地点; 最后一个Todo字段是最重要的,记录了执行该任务的命令操作。举例如下: Type Name Ename Extra Place Todo 拜贤 大和尚 he shang 佛学 车迟/金平府/乌鸡 略 在实际操作中,Place字段是可以省略的,但考虑到对新手具有提示作用,把该字段保留了。 建好了Record.db的框架,我们可以把记录向里面添加进去了。 如果用手动一个个填写添加,不但容易出错、遗漏,而且工作量大的惊人。 幸好Zmud的数据库对记录的输入提供了Import的功能,可以直接从文件中读入。 Import可以从两种文件读入记录,一种是普通的txt文件,这种txt文件每行为一个记录, 不同字段用Tab隔开;另一种是csv文件,用逗号(comma)来间隔字段。 实际上,这两种文件的区别只在于间隔 符号的不同,我们无须刻意选择, 因为在Import的时候,可以向Zmud指定说明间隔符号的类型。 为减少工作量,我以源码中的任务列表(/d/kaifeng/npc/quest_*.c) 为基础,把其中无用及重复的任务剔除掉,进行整理补充,将所有记录保存在QuestDB.txt中。 然后将这个txt文件Import到数据库中。在选择完Import文件之后,Zmud将弹出一个对话框, 把各个字段及其相应记录显示在一个预览表格里,如果正确,将自动把文件里的 每个记录添加到Record.db中去。这一步是相当便捷的, 也使我的热情没被添加记录的繁琐给磨灭。:) 建立完成之后,Record.db里总计有大约1800条记录。 Quest.db 我在这个数据库中新建了四个域(Field),其名称与类型分别如下: Type (任务的类型, 字段类型Single Option) Name (任务的名称, 字段类型Text) Cloud(是否有云, 字段类型Boolean) NotDo(多久未完成该项任务, 字段类型number) Type、Name的作用与Record.db中的Type、Name一样;Cloud字段是个布尔量,非零即一, 记录对应此任务的云是否存在;NotDo字段记录此任务有多久未做。 我们知道,食物、送物、拜贤、灭妖、武器、盔甲、募捐七种任 务对应的云彩分别为红、青、绿、黄、蓝、粉、白。输?quot;Quest"命令 查看当前任务的时候,可以知道身上有哪几朵彩云。我们可以利用函 数%pos(para1,para2)来得到Cloud字段的值。例如: “慢慢地一小团红白两色祥云在你的身边升起。” 我们就得到一个Colorlist=“红白”,%pos(红,@colorlist)可 以返回“红”这个字在字符串“红白”中的位置,如果不存在则返回值为零。 因为Cloud字段为布尔量,如果需要查找的字存在于字符串中,则返回值非零, 赋给Cloud就为一;反之则为零。利用这个方法 我们可以得知哪些任务有相应的云彩存在,哪些没有,为选择任务打 好基础。 建好了这两个数据库,我们可以开始构建上层建筑了。后面,我们继续讨论: 第三章 任务选择机制的实现 为了实现自动解谜,我们首先考虑机器人的工作流程。 我们可以知道,选择这一环节至关重要,它就是整个自动解谜系统的大脑。 下面我们来初步实现选择这一功能。 首先,这个流程需要一个起点,在图中“问谜”这一步引起了Quest.db的更新, 从而引发后续的整个过程,相应地,我们从游戏里也要找到这个起点。 我选择的是命令"quests"。 当下命令quests后,会显示当前需要完成的七项任务。我们通过Trigger来获取这些任务, 并将数据传送到Quest.db中。数据库中有个命令#LoadDB,这个命令用于加载一个数据库。 如果这个数据库还没有加载到内存,就从文件中读取并加载;如果这个数据库已经被加载了, 就将它作为当前的数据库激活,那么后面的数据库操作都是在这个数据库中执行。 我们用#LoadDB 命令把当前的数据库置为Quest.db,然后输入"quests"指令。接下去, 下面的Trigger会自动更新数据库内容。 #TR {^????食物:(%x)} {food=%1;0.Name=@food;0.Nodo=@red} #TR {^????送物:(%x) (%x)} {yin=%1;thing=%2;1.Name=@yin;1.Nodo=@cyan} #TR {^????拜贤:(%x)} {baixian=%1;2.Name=%1;2.Nodo=@green} #TR {^????灭妖:(%x)} {hu=%1;3.Name=@hu;3.Nodo=@yellow} #TR {^????武器:(%x)} {weapon=%1;4.Name=@weapon;4.Nodo=@blue} #TR {^????盔甲:(%x)} {armor=%1;5.Name=@armor;5.Nodo=@pink} #TR {^????募捐:(%x)} {lan=%1;6.Name=@lan;6.Nodo=@white} 其中诸如0.Name之类的变量代表数据库中编号为0的记录的Name字段。 而red、cyan、green等变量是我在Trigger里用来对某个任务未完成次数记数的, 每完成一个任务,对应的任务的记数置成零,其他任务记数加一。 那么,这个数字越大的,就代表越久没有完成。 然后,根据判断Cloud字段的值。 #TR {^????你的身上徐徐飘浮起一小团(%x)祥云。} {colorlist=%1; 0.Cloud=%pos( 红, @colorlist); 1.Cloud=%pos( 青, @colorlist); 2.Cloud=%pos( 绿, @colorlist); 3.Cloud=%pos( 黄, @colorlist); 4.Cloud=%pos( 蓝, @colorlist); 5.Cloud=%pos( 粉, @colorlist); 6.Cloud=%pos( 白, @colorlist) } #TR {^????慢慢地一小团(%x)色祥云在你的身边升起。} {colorlist=%1; 0.Cloud=%pos( 红, @colorlist); 1.Cloud=%pos( 青, @colorlist); 2.Cloud=%pos( 绿, @colorlist); 3.Cloud=%pos( 黄, @colorlist); 4.Cloud=%pos( 蓝, @colorlist); 5.Cloud=%pos( 粉, @colorlist); 6.Cloud=%pos( 白, @colorlist) } 这个时候,Quest.db的数据已经全部被更新,我们可以通过下面的方法来选择任务: 1、在数据库Quest.db中建立一张视图,取名为order。order视图按照{Cloud|Nodo}排序, 也就是排序优先级先Cloud,再Nodo。 2、下命令#View,将在Zmud中显示这张视图,排在第一行的就是我们所选取要执行的命令。 3、用Trigger得到该命令。 图例如下 #View order {Cloud|Nodo} #View 0 食物 鹫肉 - 20 2 拜贤 王孙 - 5 1 送物 孙三叔 - 4 6 募捐 雕木斜靠椅 - 3 5 盔甲 王八甲 - 1 3 灭妖 笑波儿天 - 0 4 武器 月牙弯刀 X 2 (显示"-"代表没有云彩,"X"代表有云彩) 然后,我取得下面要做的任务名为“鹫肉”,将当前数据库切换为Record.db, 用#Query命令对该任务进行查询,获得应该执行的命令。 (关于查询请参考帮助文件,这里不作赘述。) 这样,一个简单的自动解谜机器人的框架搭好了。 但是这样的模型离投入使用的成品还相差太远,需要我们一步步加以优化和调整。 最重要的还是提高“选择”的正确性,因为任务的选择直接关系到奖励的高低即Trigger的效率。 第四章 解谜技巧的应用 为了提高解谜所获得的奖励,我们要合理选择需要完成的任务, 并且将它与Trigger 的可实现性结合起来,也就是说, 判断的条件必须是可以通过Trigger 实现的,否则, 再完美的技巧也无法应用在我们的自动解谜机器人中。 首先,我们假设机器人运行在一种理想状态之下,所有的谜都是可以完成的。 那么我们将遇到下面两种情况: 一、云彩数目小于七朵。这时,下一个要执行的任务应该是没有对应的云彩的那项。 我们知道,解谜的奖励和云彩数目关系密切,云彩越多,获得奖励越多, 机器人效率也越 高。因此,任务的选择首先必须符合倾向云彩增多的原则。 例如:你的身上有青绿黄蓝粉白六彩祥云,那我们可以通过触发器判断得知缺少红色云彩, 即下一个任务应该做猪八戒的食物。做完食物这一项,就可以将云彩累积到最大数目。 二、云彩达到最大数,即七彩祥云。这种情况下我们应 该遵循FDFD(First Done First Do即最先完成最早执行)原则。 让我们先来看看上一章提到的Nodo记数,它的机理如下: 设置七个变量red、cyan、green、yellow、blue、pink、white 分别对应该种云彩对应的任务记数。当完成某项任务,则将 相应变量置零, 其他变量加一。例如: #Trigger {^????陈光蕊对你说道:多谢这位} {quest_type=拜贤;green=0;#add cyan 1;#add blue 1; #add yellow 1;#add red 1;#add white 1;#add pink 1} 这样我们可以通过这七个变量的值了解到某种类型的任务有多久没有完成。 因为云彩的存在是有时限的,自它产生以来,经历8次记数,也就是变量值为9的时候, 这朵云彩就消失了。 所以我们应该优先执行记数大的任务,以保证云彩维持在七彩。 上面提出的两种原则已经在我们的模型中采用了,即按照“Cloud|Nodo”的次序进行排序, 先考虑是否有云,然后考虑做最久未做的任务。但是,在实际解谜中,我们并不可 能完成所有的任务,一定会遇到有些谜无法完成。 所以我们在数据库Record和Quest中引入一个新的字段:CanDo。 这个字段为一,表示该任务可以完成,这个字段为零,则说明是无法完成的。 随着Player的成长,可以手动的对这个字段进行修改。 比如Player早期很难完成一些灭妖以及菩提祖师的拜贤、羊脂玉净瓶等任务, 到了后期,就可以调整为可以执行。 此外,我们对何时清谜做一个考虑。如果因为某些任务无法完成, 只能保持在较少数目云彩下解谜,奖励会降低; 而清谜会造成两个损失,一是随机减少一朵云,二是时间上的等待, 但清谜之后可以抛开那些挡路的任务,为七彩云创造条件。有得必有失, 如何选择清谜时机呢?根据我的解谜经验,六彩以下的任务是不值得做的。 我们可以判断,如果根据排序,最优先的两个任务无法完成,就可以去清谜了。 最后,我们再来考虑解谜任务的权重问题。各个任务的奖励是不同的, 在相同云彩数目下,有的任务比如兵器中的各种法宝和龙子兵器、 募捐中的龙珠等奖励高,有的任务奖 励低。这就牵涉到一个对任务赋以权值的问题。权值对两种情况造成影响: 一是在正常的要清谜的情况下如果有权值 很高的任务未做,可以考虑先做这个任务再清谜;二是当云彩少于七彩的时候, 考虑在没有其他损失的情况下,将权值高的任务放到云彩多的时候做, 以获得更高奖励。权值的设定可以不必在数据库中增加字段,将它与CanDo 字段合并, CanDo为零,代表无法完成任务,否则表示该任务权重。 好了,经过这样的补充,我们的自动解谜机器人可以算是完成了, 首先具有可执行性,其次也满足了对高效率的要求。 当然,另外还有一些技巧因为很难在机器人中实现,我 们就不在这里赘述了。 第五章 完善与展望(结束篇) 经过前面四篇文章的讨论,我们已经得到了一个可以用的自动解迷机器人, 它包含了一个容纳所有任务的数据库,以及一个用来处理当前任务选择的数据库, 可以实现自动选 择当前任务,自动完成解迷任务的功能。当然还是比较粗糙的, 在运行过程中我们可能会遇到许多非理想状况,干扰机器人的运作, 另外,注意一些细节也可以提高效率。 首先我们注意解迷的等待问题,因为用机器人解迷,动作要比手动迅速的多, 所以从接迷到完成通常只要很短的时间,就需要等待,虽然这段时间一般只有1、2分钟, 但累积起来也不是一个小数目,所以我们要采取的策略是在每完成 一个谜之后立即询问该类型的任务。比如做猪八戒的食物, 把食物给猪以后,去皇宫领赏,然后再ask zhu about food。 由于选择的任务的一般趋势是各种类型任务轮流完成,所以在你完成其他任务的时候, 也度过了等待的时间。在我的解谜机器人里是这样实现的: 设定七个alias分别对应七种任务如askzhu, askchen, askyin等等, 在完成任务的时候有七句 触发如: #trigger {^???猪八戒对你说道:多谢*} {type=zhu} 然后从皇宫领赏出来,执行alias ask@type就可以询问相 应的任务了。 其次,对于非固定位置的任务,比如送物,灭妖的NPC,要有自动寻找的手段。 这个利用路径是很合适的,例如:得到任务送物:街头小商人--黄金, 我们从数据库中得到方位在宝象,定义一个alias search如下: #alias search { #untrigger {@findname}; findname=%-1; #tr {@findname} {#cw red;find=1;#untrigger {@findname}} } 使用search @yin(yin这个变量的内容就是“街头小商人”) 就生成了一个触发,当#slow .baoxiang沿路径行走的时候, 遇到街头小商人就自动停下来,配合自动给物品的trigger就完成了这个任务。 另外,一个特定任务可能有多个选择方案,在手动解迷过程里, 如果遇到可以在多处完成的任务,我们可以自由选择, 即使一个地方没有,还可以去其他地方尝试。为了模拟手动解迷以提高任务的完成率, 我们也可以加入完成任务的多种方法。因为todo字段是一个memo变量, 我们可以输入很多内容。所以我们增加一个字段,类型为整数, 记录todo中的方法数量,然后依次执行。具体如何实现,请大家思考。 除这些以外,我们还有很多细节要考虑,比如PK(//grin), 比如小小怪的拦路,再比如@#%&^@*$#。这些问题就仁者见仁,智者见智了, 需要技术与经验的结合。不过我的原则是安全稳定第一, 处理问题的方法要简单,这个原则放在机器人制作具体的讲就是宁用alias, 少用trigger。这样说可能有失偏颇,但alias的执行是可以不考虑网速的, 而trigger往往受网速的限制。上次看到一个捡舍利子的机器人, 几乎所有动作都用trigger触发,有些明明可以 用一个alias解决的,也被拆分成了好几句trigger,害处就是第一容易被破坏, 第二机器负担太重,判断触发是相当占用时间的(当然如果你已经用上P4了,当我没说过)。 随着Zmud日益功能强大,我们可以实现的机器人也会越来越多,也会越来越完美。 目前我最看好的是automap,这个功能其实在Zmud 4.62里就有了, automap结合trigger(其实也是一种形式的数据库结合trigger,因为 automap实际上是一个储存房间记录的数据库)应该会非常强大的。 但我看了很多介绍文章,也从zuggsoft 的网站上下载了资料,就是没有办法搞定, 没有办法正常做语法分析,区别一个房间的名字、描述与出口, 另外绘制地图的时候提供的方向也少了点,只有普通的 south,north,southeast,up,down之类。不知道有哪位已经搞定automap 的,希望指点一下。 好了,我终于结束了婆婆妈妈的废话,最后希望mudfan所有朋友 好运,玩得开心。 |
![]()
生活就是做减法 ![]() |
|
![]() |
![]() |
![]() |
#2 |
初级会员
![]() ![]() 注册: 03年02月02日
帖子: 15
声望力: 0
声望:
10
![]() 现金:0两梁山币
资产:2两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
好文章!!好!!!! 可惜我是一点都不懂,真想把他做的机器人拿来跑跑 chan wxwhyzgd |
![]() |
![]() |
![]() |
#3 |
中级会员
![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 02年05月27日
帖子: 103
声望力: 24
声望:
10
![]() 现金:139两梁山币
资产:139两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
我的quest robot制作心得
---by Nirvana@xyj 以前看到的都是针对老xyj的解谜机器. 没什么事, 瞎写写. 解谜机器人.. 嗯嗯, 看起来很不错. 我们就开始做. 其中会用到的语法我就不说了, 全部可以在zmud help文件里找到, 所有做法基于zmud 5.55, 用db储存解谜数据库 流程, 效果: 首先众所周知, 做quest时云越多, 得的潜能越多, 所以做成缺哪朵云去做哪朵云是最好的. 我的方法是这样, 假设7个人都没死, 三清后领完任务后, 根据要的任务接着7个都做完. 然后不管这7个任务做好没做好都去领奖赏, 根据自己身上云的多少, 先领云少的, 再领云多的. 如果领奖赏失败立即根据所说的话领下一个. 用一个变量来确定任务是不是完成也行, 但是这样工作量会大很多, 因为有很多weapon, cloth, food, armor任务都是用一个alias来完成的. 整个机器的流程是这样的: 三清后一次领完7个任务--mingsi一点使自己能cast chuqiao---按"quests"截取7个任务的所要做什么和有几朵云每朵云有多少格, 然后通过zmud函数优化一会做完任务去领奖励的顺序---做完7个任务---根据刚才优化的结果依次领奖励---判断是否做完任务, 要没做完去三清, 如果7个任务都做完则直接去再问任务. 好有了想法, 下面具体开始一步步实现: 一: 建立数据库 zmud 5.55的数据库有一个bug, 用命令来切换多个数据库会导致zmud crash, 所以任何情况下, 我们都只能用一个数据库. 如果把所有因素都考虑到的话, 一个数据库已经完全可以执行所有任务了 首先建立这几个field: Quest_cn: 任务名称库. weapon, armor, cloth, food这4个任务中在这个field里储存武器总资料, 防具等的中文名称. ask, give, kill任务在其中储存需要用到的人物总资料. Type: Text. Quest_en: 任务英文名称. Type: Text. Type: 任务类型. Type: Single Option(Weapon;Armor;Food;Cloth;Ask;Give;Kill). Item_cn: 储存Give, Ask任务里需要的物品, 如送银子给路客, Item_cn里就是银子. 问如来佛取经, Item_cn里就是取经. Type: Text. Item_en: Item_cn的英文名称. Type: Text. Buy_id: 有的weapon, armor, cloth, food任务中买的时候是一个英文名称, 而买到手上是另外一个id, 这里专门设一个field来储存这个 Available: 用0和1判断能不能完成这个任务, 等级低时有些任务完不成(如xxt laofo, chechi daxian)可先设为0, 等等级够高时再设回1. Type: Boolean. Action: 将要做的任务. 可以填alias或者其quest的整个路径. 随自己喜欢. Type: Text Extra: 方便自己查询的一栏. 甚至可以用这一field做成为newbie查询quest物品位置的机器, 可加可不加, 建议加上以便以后查询资料. Field做好, 现在得收集整个xyj quest系统的资料. 要一个个收集这的确工作量太大了. 以前看过介绍可以从源代码里 (/d/kaifeng/npc/quest_*.c)找到全部任务列表. 这的确可行, 我就是从这里把db import进来的. 不过xyj2000总站的源码不太好找, 我一直没找到哪有, 只能从旧的源代码里export/import到db里后, 把没用的任务删除, 再加上所没有的. 我的DB大概一共有1400条记录. 二: 建立trigger, Variable使任务和数据库连接 现在需要把要做的7个任务都用trigger截下来, 并截取关键字到变量里以便以后向db查询. 例如每次下命令"quests"以后看到: 你还有如下几个正在解的迷: 食物:猪八戒对你说道:老猪我四处寻求天下美味佳肴, 正要找野鹿肉板,这位壮士可否赏老猪个大脸设法子去给弄来? 送物:殷温娇一扬签对你说道:事不宜迟请去送【太乙真经】给汉钟离。 拜贤:陈光蕊燃起一根香祭祀一番,对你说道:祖灵在天, 请您去拜访一下凌空子,并且务必探明诗歌一事。。。 灭妖:胡敬德占卦完毕对你说道:去去,将蟒蛇怪杀掉! 武器:相公想想对你说道:最近有些兵器来货不足,尤其是少了黄铜禅杖,这位壮士能否帮老夫个忙? 盔甲:相婆细想了一下对你说道:魏大人托话,说是京城有人想要什么鹅黄麻纱护裙,这位壮士能否帮相府个忙? 募捐:香兰对你说道:哦,对了,姑娘想帮人找一找什么莲花灯,这位壮士能否替姑娘想个办法? 这个任务下, 我们用DoNow_Food, DoNow_Give, DoNow_Giveitem, DoNow_Ask, DoNow_Askitem, DoNow_Kill, DoNow_Weapon, DoNow_Armor, DoNow_Cloth这几个变量分别储存食物, 送物的人, 送什么东西, 拜贤的人, 问什么事, 灭妖的人, 武器, 盔甲和募捐. 有了这几个变量, 思路也就明确了. 只差把字段赋值给变量. 比如拜贤的这个任务, ask 凌空子 about 诗歌. 我们准备把"凌空子"赋值给DoNow_ask, "诗歌"赋值给"DoNow_Askitem. 由于xyj2000机器太多, wiz把领任务的那7个人说话变得很复杂, 大概有20几种说法, 也就是说陈光蕊有可能给换一种说法给你这个任务, 所以不可能用一个trigger来抓住这两个关键字. 我是这样得到全部说法的, 派个大米站到陈光蕊跟前, 肯定会有人问任务, 把所有的话都#cap下来, 半小时后应该就收集齐了, 当然如果你有源码, 可以方便一点. 收集齐后, 发现把每种说法都做成一个trigger会显得机器极庞大, 而且复杂, 这里给出一个方便点的方法, 用"|"这个语句, 可以把全部说法做成两个trigger: First trigger: pattern: {求见|朝问|访问|查知|致意|问候|拜访|看望|得知有|问候|拜见}(%x){索问|查知|过问|探问|打听|探听|寻查|查询|查明|查问|探明|探访|探知|请问|告知|知道|调查|询问|打探}(%x){一事|的消息|之事|的问题|的情况} command: DoNow_Ask=%1 DoNow_Askitem=%2 #var DoNow_Ask %replace(@DoNow_Ask,"打探","") #var DoNow_Ask %replace(@DoNow_Ask,"探访","") #var DoNow_Ask %replace(@DoNow_Ask,"探听","") #var DoNow_Ask %replace(@DoNow_Ask,"探问","") #var DoNow_Ask %replace(@DoNow_Ask,"打听","") #var DoNow_Ask %replace(@DoNow_Ask,"调查","") #var DoNow_Ask %replace(@DoNow_Ask,"拜访","") #var DoNow_Ask %replace(@DoNow_Ask,"问候","") #var DoNow_Ask %replace(@DoNow_Ask,"一下","") #var DoNow_Ask %replace(@DoNow_Ask,"一次","") #var DoNow_Ask %replace(@DoNow_Ask,"一回","") #var DoNow_Ask %replace(@DoNow_Ask,",","") #var DoNow_Ask %replace(@DoNow_Ask,"并且","") #var DoNow_Ask %replace(@DoNow_Ask,"并","") #var DoNow_Ask %replace(@DoNow_Ask,"顺路","") #var DoNow_Ask %replace(@DoNow_Ask,"一定","") #var DoNow_Ask %replace(@DoNow_Ask,"务必","") #var DoNow_Ask %replace(@DoNow_Ask,"尽力","") #var DoNow_Ask %replace(@DoNow_Ask,"看望","") #var DoNow_Ask %replace(@DoNow_Ask,"寻查","") #var DoNow_Ask %replace(@DoNow_Ask,"拜见","") #var DoNow_Askitem %replace(@DoNow_Askitem,"打探","") #var DoNow_Askitem %replace(@DoNow_Askitem,"调查","") #var DoNow_Askitem %replace(@DoNow_Askitem,"有关","") #var DoNow_Askitem %replace(@DoNow_Askitem,"探访","") #var DoNow_Askitem %replace(@DoNow_Askitem,"关于","") Second trigger: pattern: 在天祖灵让您就(%x)一事拜访(%x),请尽早动身也。 command: DoNow_Ask=%2 DoNow_Askitem=%1 ask任务有时会叫你做问player的任务, 这需要多加个trigger, 并加一个boolean变量@Askplayer区分, 如@Askplayer=1, 则表示这是一个ask player的任务, @askplayer=0时则相反. 其他六个基本上都可以按照这种方法类推, 最关键的是得收集全7个人的每种说话内容. 需要注意的是, 在赋值这几个变量前, 都应该#Unv掉这几个变量然后再赋值, 因为有时候由于特殊原因(7个人中有人死, 小小怪挡路)没有问到任务, 这样的话没触发到trigger的变量还没保存在里面, 做任务的时候还会根据其变量做老任务, 有时还会一直循环的做这个无用的任务. 所有这些截取的trigger我把他归到"CatchQuest"这个class里面. 三: 优化领奖励的顺序(判断自己有几朵云) 下命令"quests"后, 应该会看到类似这样的图例 你解迷暂时成果统计: 食物:□ 送物:□□ 拜贤:□□□□ 灭妖:□□□ 武器:□□□□□ 盔甲: 募捐: xyj2000总站云的规则是这样实现的: 7个任务后面都带有格子, 有格子代表其有云, 格子的多少代表其云的生命力, 最多为9格, 最少没有, 表示没有云. 而且每种任务的格子数不可能重复. 如果成功做完一个任务领完赏以后其任务的格子就会恢复成9格, 而其他6个任务所拥有的格子会相应减少一格直到没有. 而且云越多, 得到的奖励越多. 所以当做完任务后去领奖时, 应先考虑领没有格的, 然后再领格少的, 直到领完, 而不是挨个按顺序领, 下面我来介绍我实现的办法: 首先设7个变量, Cloud_Food, Cloud_Give, Cloud_Ask, Cloud_Kill, Cloud_Weapon, Cloud_Armor, Cloud_cloth来准备储存7个任务的格子数. 再做trigger, 这些获取格子多少的trigger归到"CatchCloud"这个class里. 可以用%len这个函数截取有多少格子, 如" 食物:□"里有一个格子: #tr {食物:(%x)} {Cloud_Food=%len(%1); #math Cloud_Food @Cloud_Food/2; #var Cloud_Food {@Cloud_Food tofood}; } 注意"□"包括了2个string, 所以用#math把string数除以2, 才得到格子数 "#var Cloud_Food {@Cloud_Food tofood}"这句话使Cloud_Food这个变量里不单是数字, 而且有字母使之一会好排列, 这待会会讲到. #tr {食物:$} {Cloud_Food=0; #var Cloud_Food {0 tofood}; } 表示没有云的话把@Cloud_Food赋值为"0 tofood". 依此把另外6个做好. 这样我们得到了各自云的数目. 要将这些云按从少到多排列首先我想到了%sort函数. #var Cloud {@Cloud_food|Cloud_Give|Cloud_Ask|Cloud_Kill|Cloud_Weapon|Cloud_Armor} #var Cloud %sort(@Cloud) 这样, 上面图例中{1 tofood|2 togive|4 toask|3 tokill|5 toweapon|0 toarmor|0 tocloth}就将会排序成: {0 toarmor|0 tocloth|1 tofood|2 togive|3 tokill|4 toask|5 toweapon} 再做个filter: #var Cloud %replace(@Cloud,"0 ") #var Cloud %replace(@Cloud,"1 ") #var Cloud %replace(@Cloud,"2 ") #var Cloud %replace(@Cloud,"3 ") #var Cloud %replace(@Cloud,"4 ") #var Cloud %replace(@Cloud,"5 ") #var Cloud %replace(@Cloud,"6 ") #var Cloud %replace(@Cloud,"7 ") #var Cloud %replace(@Cloud,"8 ") #var Cloud %replace(@Cloud,"9 ") @Cloud就变成了{toarmor|tocloth|tofood|togive|tokill|toask|toweapon} 为云的格子多少排序就完成了. 目前只想到这个方法, 似乎有点麻烦, 有谁还有更优化的方法请告诉我. 注意每个数字后面有个空格. 当领奖励时, 可以通过做出toarmor, tocloth....7个alias, 用%item(@cloud,x)来读取, x可以是1-7这7个数字. 四: 做7个任务的trigger: 做到这里, 机器的框架已经基本完成了, 现在需要做的是为所有任务做trigger, 或alias. 首先应该去做的任务是Ask或give, 因为有些ask和give任务要去hell得cast chuqiao. 如先做Ask, 可以这样来触发, 命令"set brief doquest_ask", mud就会回应给你 设定环境变数:brief = "doquest_ask" 用这句话就可以做做ask任务的触发了. 我们再讨论这个pattern下的commands: 先加上 Do_Next=doquest_give 设定@Do_Next这个变量表明下个任务是做give, 怎么用这个变量马上会讲到. 然后要考虑到ask任务是不是一个对player的任务, 上面我们已经设了一个变量@askplayer 所以加上: #if (@askplayer=1) {ToDo} {ToDo2} 其中ToDO里面可以是一组alias, 设定如果是ask player任务时的所要做的. ToDo2里将要写的是一般ask任务的语句, 可以用#find向数据库里找有没有所要的资料. #dbreset #wa 200 #find @DoNow_Ask #wa 200 #if (!&available or %null(%rec) or @DoNow_Ask!=%trim(&Quest_cn)) {set brief @Do_Next} {Ask_id=%trim(&quest_en) #exec &action} 其中if语句中如果@available=0或者数据库中没有这条记录或者@DoNow_ask不等于数据库里所找到的第一条记录, 那么就做下一个任务也就是give任务. 相反的话那么新建变量@Ask_id等于其找到数据中Quest_en这个field里的值, 并且运行其field "action"里面的值. 这里解释一下action这个field, 里面可以填alias, 或者几个命令用";"分开, 但是不能用带"#"的语法比如不能用"#wa". 为了使机器简洁化, 应能在数据库写的就在数据库写, 必须得带"#"才用alias, 而且在其最后得接一个做下一个任务的命令, 比如每条action记录最后加上Done这个alias: #wa 5000; set brief @Do_Next 这样就连接上所有任务了. 做这些trigger将会是一个很繁琐的过程, 因为有一千多个数据库记录需要一个个输入路径, 很多任务需要额外设置trigger, alias. 不过为了以后的轻松, 现在的努力是会有回报的. :) 五: 领奖赏 做完7个任务, 然后不管有没有完成任务按照云的多少按顺序去领奖赏, 根据那7个人所说的话判断是不是失败了去下一个人那, 或者完成了去唐太宗那, 云怎么排序已经讲过了, 很容易实现. 六: 机器的优化 如果你的机器已经做到了这里, 那么机器也就差不多可以跑起来了. 但是想要完整, 还得加些内容, 比如class的管理, 机器做到这, 将会有6,70个class, 和数百的trigger. 这就需要频繁的#t+, #t-. 不然很容易的误触发, 所以每做一个trigger不是必要的话都应先disable, 甚至每个class都最好先选上Disable class when connecting to a MUD. 当要用的时候, 用相对应的alias或者trigger #t+开来, 然后用马上#t-. 我曾经就因为没管理好class以至于跑的时候老会断, 甚至好长时间找不到原因. 再就是掉枯骨洞里, 被小小怪block, 7个人有时会死掉, 防pk trigger, yalong, jindou食物, dudi momo大米等等. 呼, 写的够长的, 做出一个完整的quest机器不是件容易事, 所以spls或者现在xhg的暂时强大也并不是想当然的, 其背后的努力也不是想象中那么简单的. 所以我也非常理解前几天把我的mieyao机器删掉的原因, 那几天实在心情不佳差点把我的id全s-f了. 呵呵, 我属于婆婆妈妈的那类人, 于是就写了些这么婆婆妈妈的东西. 建议新手们以后就不要问"给我一个robot"之类的问题了, 想要, 自己做去. mud我是不准备继续玩了, 但是我要感谢xhg所有和我奋斗过的id们, 让我好好享受了这么久mud生活. 我们不能玩一辈子mud, 但是可以做一辈子朋友(zz). :D 最后祝大家Happy mudding 此帖于 2003-07-01 07:33 被 nirvana 编辑. |
![]() |
![]() |
![]() |
#4 |
中级会员
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 02年07月03日
来自: xhg
帖子: 796
声望力: 30
声望:
12
![]() 精华:3
现金:301两梁山币
资产:1237两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
hug hhcc 终于写完了,sweat hhcc 也终于脱离mud 了,snow hhcc |
![]() ![]() ![]() |
|
![]() |
![]() |
![]() |
#5 |
初级会员
![]() ![]() 注册: 03年04月27日
帖子: 19
声望力: 0
声望:
10
![]() 现金:0两梁山币
资产:0两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
hmm
思路不错,不过,好象不用那么复杂啊 我有个机器,全自动quest,不能分云,顺序完成,跑zmud465,感觉也很不错啊 我觉得有点太复杂了,delphi ? faint2 |
![]() |
![]() |
![]() |
#6 |
天平座童虎
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 02年05月24日
来自: 莲花宝座
帖子: 5,966
声望力: 98
声望:
1639
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 积分:18
精华:29
现金:4213200两梁山币
资产:4223200两梁山币
致谢数: 2
获感谢文章数:10
获会员感谢数:10 |
呵呵,自己想着怎么简单就怎么做了。 八级风的思路也就作为一个参考的文章而已。 我的quest robot分了云的,不过是在看到这篇文章之前。 所以用的方法完全不一样,自我感觉还不错。呵呵。 |
![]()
|
|
![]() ![]() |
![]() |
![]() |
#7 |
正式会员
![]() 注册: 03年07月15日
帖子: 3
声望力: 0
声望:
10
![]() 现金:0两梁山币
资产:0两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
Good procedure, but not realism. zMUD does not support more than 1 db, or various dbs transition. Mapper can be used instead of DB. Room scripts are also efficiency to auto-quests robot. |
![]() |
![]() |
![]() |
#8 |
中级会员
![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 03年07月22日
来自: 长安城west
帖子: 116
声望力: 23
声望:
10
![]() 现金:-2两梁山币
资产:-2两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
haha,这样的autoquest效率不会很高 每领完最后一个reward就去qjn了吧 不过还是不错的 |
![]()
haha dfdsfdsfdfddf |
|
![]() |
![]() |
![]() |
#9 |
中级会员
![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 02年05月27日
帖子: 103
声望力: 24
声望:
10
![]() 现金:139两梁山币
资产:139两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
@@
领完最后一个任务或者根据自己身上的云的数量去不去3清加个变量叛断就行了, 应该不是很难, 这样的细节我都省略了 可能机器效率不是最高的, 但是费的网流量会是最少的. 因为我上网按流量收费, 这样相对也会增加点网速? :D |
![]() |
![]() |
![]() |
#10 |
中级会员
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 02年12月25日
来自: 长安成西
帖子: 246
声望力: 25
声望:
10
![]() 精华:1
现金:95两梁山币
资产:39460两梁山币
致谢数: 1
获感谢文章数:0
获会员感谢数:0 |
hhcc同志虽然离开了xyj但是对我来说,他做出来的贡献是不可磨灭的。 因为我是个机器盲。不会做机器,我一直用的是hhcc给我的机器。我也在 学机器。但是天生又懒又苯,现在才学回用变量和paths。 miss hhcc |
![]()
本人长期代写小学生寒,暑假作业,通下水道,割双眼皮,跳大神,出租灵棚,苦力搬运,整容,砸墙,当伴郎. 联系QQ:78928397 |
|
![]() |
![]() |