MUD-武林MUD资料站-武侠MUD游戏

 找回密码
 注册

QQ登录

只需一步,快速开始

打印 上一主题 下一主题
开启左侧

[教程] 零基础MUSHclient教程

[复制链接]
跳转到指定楼层
# .
381676420 发表于 2016-1-22 04:06:26 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
本帖最后由 381676420 于 2016-1-22 22:09 编辑

  Mush是由 C++ 编写的,软件体积小,运行速度快,他有很多的优点,这里就不一一介绍了,它之所以是挖泥神器就是因为,他可以是支持很多的语言脚本,为编写机器人带来很多的可能性,还有最重要的稳定性,下面我们就从设定讲起

  上图是我们mush中全局设定中的默认界面,
  • 全局配置对所有的游戏配置都有效,在这里设置的字体、颜色、插件、触发器,别名、定时器、等等,都会应用到已有的和新建的游戏中
  • 这里可以设置所有游戏默认使用的触发、别名、定时器、颜色和字体等。当然,你也可以在每个游戏中设置不使用默认设置。

                    上图是全局设定中lua的设定
这个有点复杂,就不详细介绍用途了,允许载入DLL文件前面打个勾就可以了。

      上图是全局中的常规设定
打开游戏时自动连接  打开游戏时自动连接到游戏服务器,当然也包括通过自启动列表自动打开的游戏。
游戏断线时显示警告对话框  选中这项的话会在游戏断线的时候显示一个警告对话框。如果你在游戏脚本中使用了自动连接的函数,必须把这个选项关闭,否则它会使脚本运行不正常。
自动激活命令窗口  默认情况下,你必须先把光标定位到命令窗口才能在里面输入命令。如果选择了这项,无论光标是否在命令窗口,你都可以输入命令,此时命令窗口会自动获得焦点。
使用等宽字体编辑触发器/别名  这个选项会影响到触发器和别名设置中显示其匹配内容时使用的字体。不过在中文系统中使用等宽字体的效果并不是很好,建议取消。
正则表达式可以匹配空行  如果选中这项,正则表达式可以匹配一个空行(^$)。否则你将没有办法匹配一个空行。如果你的触发器需要匹配空行的话就把这项选上吧。
自动展开配置项  一个游戏有很多配置项,每个配置项又有一些子项,当打开游戏配置窗口时,如果选中了这项,这些配置项就会自动展开。
扩展背景色到窗口的边界  选中这项后,信息输出窗口中最后一个字符的背景色会自动延伸到窗口的边界,这会使得输出的信息很难看,建议不要选。
平滑滚动和非常平滑的滚动  这两个选项会影响信息的滚动速度,特别是非常平滑的滚动,几乎就是一个像素一个像素的滚动,虽然看起来很舒服,但是速度实在是。。。,建议这两个都不要选。
单词定界符  此项设置会影响 MUSHclient 在执行单词自动补齐和鼠标双击选择单词时对单词的判断。MUSHclient 会认为这里列出的字符都是单词的分隔符,假如你把中横线加入自动补齐中,当使用自动补齐功能时,就只有中横线前面的字符会被自动补齐。空格始终被认为是一个分隔符,所以你不需要把空格加入到里面。
窗口标签  设置是否显示窗口标签栏。当打开的窗口比较多时,通过标签栏切换窗口是很方便的,你可以隐藏它,或者显示在窗口顶端或底端。如果标签对应的窗口是游戏窗口,且不是活动窗口,当接收到了新的信息,标签上还会显示新消息的行数。如果窗口是记事本窗口,且内容已经被改变但未保存,标签上会以星号标识出来。这个选项会在下次启动 MUSHclient 时生效。

                   上图是全局设定的定时器
这个也没有什么好说的,顾名思义了,要注意的是,因为全局设定是在所有窗口生效的,所以一般这里设0。

                上图是全局中的插件设定
在这里面列出的游戏会在 MUSHclient 启动的时候自动打开,除非你在运行 MUSHclient 的时候加上了 /noauto 参数。要注意的是自动打开不等于自动连接,但是要连接一个游戏必须先打开这个游戏。如果想在打开的时候自动连接,可以在"常规"选项中设置。
添加当前游戏  把当前游戏添加到列表中。
游戏文件的默认目录  这个设置会影响到打开或者保存游戏时默认显示的目录。


以上就是我们全局设定中,最常用到的,其他部分不经常使用,我也就不多说了,有需要了解的可以自行度娘。这里就不占用春姐有限的论坛资源了

既然有全局,那么对应的肯定有局部,没错。mush下的局部设定,也叫游戏设定,这个必须在点击了新建游戏以后,才可以看到。

                上图是游戏设定中的address
这里没什么特别说明的把,就是输入Ip端口的地方,一目了然

                 如图
这个地方就是输入id跟密码是的地方,可以选择自动连接,有三种不同的形式,也可以配合脚本来执行自动连接。这里我们先了解下,后面在说。

                                  如图
这里选项比较多,详细的说下
允许响铃命令  如果选择了这项,当 MUSHclient 接收到了响铃命令(0x07)就会播放指定的音乐。
字体  设置输出窗口使用的字体。
  显示选项 粗体、斜体、下划线 则分别设置了输出窗口中遇到这些样式的文字时是否显示这些样式,如果相应的项没有选中的话就会以普通样式显示。如果你发现有些信息在输出窗口中显示有问题,可以试着不选择这里的某些项。例如,风云2005 登录时的大字标题在使用宋体的时候就不能用粗体显示,否则就会变形。
接收到新信息时播放音乐  指定一个有新信息时提醒你注意的音乐文件。当游戏窗口没有显示(处于其它游戏窗口下面)的时候,如果这个游戏接收到了新的信息,MUSHclient 会播放这个音乐文件,提示你查看新的信息。如果游戏窗口在最前面则不会播放。
输出窗口中自动换行的列号  如果一行的信息太长,这行信息就会在指定的列自动换行显示。
显示行信息  如果选择了这项,当鼠标停留在输出窗口一小段时间后,MUSHclient 会在鼠标悬停处显示鼠标所在行的一些信息,例如接收时间,行的类型等。
连接时暂停滚动信息  如果选择了这项,游戏连接后,输出窗口会处于暂停滚动状态。
自动暂停滚动信息  如果选择了这项,当你向上滚动信息查看以前的信息时,输出窗口会自动处于暂停滚动状态。当你再次向下滚动到信息的最底端时(例如按下 Ctrl+E),输出窗口又会自动恢复为自动滚动状态。
发送命令时恢复信息滚动  选择这项后,如果输出窗口正处于暂停滚动状态,当你发送任意一个命令时,输出窗口会自动定位到信息的最底端并恢复为滚动状态,这样你可以快速查看才接收到的信息。
有新信息时闪烁任务栏图标  选择这项后,如果 MUSHclient 不是系统的活动窗口,当接收到新的信息时,MUSHclient 在任务栏的图标会闪烁以提醒你注意。
段落缩进  选择这项后,如果一行的内容太长并在指定的列自动换行后,换行的内容会向里缩进一段距离,这样你就可以容易区分出这是新的一行还是自动换行时产生的行。
输出窗口大小报告给服务器  选择这项后,当你改变窗口的大小时,MUSHclient 会把改变后的窗口大小发送给服务器,这对某些跟具客户端窗口的大小自动计算分页信息的服务器特别有用,挺人性化的。不过我还没有见过这样的服务器。
服务器回车命令清除当前行  这个选项对国内服务器来说是不能选的,否则输出效果会惨不忍睹。大家都知道以前的服务器在等待你输入命令的时候默认是一个大于符号(>),但是现在很多服务器默认都改为了日期时间等这些会随时变化的提示符,其中就用到了一个特殊的命令让光标转到行首,然后输出新的信息(例如时间)把旧的信息覆盖掉,从而产生不断变化的提示信息。这在 zMUD 中表现得很好,但是 MUSHclient 就不能解析这个命令,以至于新的信息会出现在旧的信息后面,而不是把它覆盖。这个选项的本意就是为了解决这个问题,但是 MUSHclient 的开发人员做得并不是很好,结果使得输出的效果更差。所以不推荐大家选择这个选项。
  那么对于这类动态的提示符应该怎么办呢,唯一的办法就是通过命令 unset prompt 禁用它,改用最初的大于符号提示符。这样的好处有两个:
  • 节约带宽,因为不用随时接收服务器传送过来的提示符信息(不过以现在的网速来说,节约的这点带宽实在是微不足道)。
  • 方便制作触发器,一个大于符号肯定比动态的信息好捕捉吧。
UTF-8编码 (Unicode)  国内都是用的 GB 编码,肯定是不能选这项的。
切换 反转/高亮 的显示方式  这个选项我也不知道有什么用,哪位如果知道的话麻烦告诉我一下。
显示 连接/断线 信息  如果选择了这项,每当游戏连接或者断线时,输出窗口都会额外加入一些提示信息,例如连接时间、在线时长、断线时间啊这些的。
自动复制选择的文本  选择了这项后,当你用鼠标在输出窗口中选择了一些文字时,这些文字会自动复制到剪贴板中,不需要你再使用“复制”命令来获取选择的文字了。
IAC EOR/GA 命令解析为行结束符  有的时候,服务器会让你在信息行后接着输入命令,例如登录时输入角色名字和密码。当提示你输入这些命令时,服务器发送的并不是一个标识当前行已经结束的行结束符号,而是一个等待你输入命令的提示符号。MUSHclient 和 zMUD 都是在接收到行结束符后才开始把当前行的内容和触发器进行匹配,所以正常情况下你是无法马上捕捉这样的信息行的。但是选择这项后,MUSHclient 会把服务器发送的提示符号解析为一个行结束符,从而可以马上匹配这一行的信息。这样你就可以做一个灵活的自动登录机器人了(当然能使用到这个选项的地方不仅限于此),不过在需要自动登录时还是建议大家用“连接”中的自动登录功能,因为那样更方便。

                如图
脚本语言  选择你喜欢的脚本语言。推荐用 Lua。
脚本文件  指定游戏使用的脚本文件。游戏的所有脚本都应该写到这个文件里面。
游戏事件函数  当列出的事件发生时自动调用指定的脚本函数。这些函数是保存在上面指定的脚本文件里的。
注册 DLL  如果脚本没有执行,你可以试一下通过这个按钮把相关的脚本引擎的动态链接库注册到 Windows 系统中。你只需在系统中执行一次就可以了。Lua 不需要做这样做,只有 VBscript、Jscript 和 PHP 这三种语言才需要。
脚本文件被更改时重新解析  选择游戏的脚本文件被更改时,MUSHclient 的动作:
  • 总是 - 总是自动重新编译解析新的脚步内容
  • 确认 - 让你选择是否需要重新编译解析新的脚本内容
  • 从不 - 永远不重新编译新的脚本文件
脚本标识符
  设置让命令窗口把输入的命令识别为脚本命令的标识符,默认为“/”,可以设置为多个字符。如果一条命令是以脚本标识符开始的,那么它后面的命令就会被作为脚本命令交给脚本引擎解析执行

              如图
这里的设定看的多,其实没什么好说的,他的主要作用,就是使Mush在操作使用的时候,更像Zmud,大家按照这个设就好了。

这里有个注意点,如图可以看到有个 防止过多的重复命令 他的最用就是,防止一次性重复发送过多的指令导致被雷P,可以点开,20表示的重复命相同命令20次后,发送look。
游行设定在新建里游戏以后按快捷Alt+回车就可以打开。这里还有很多的设定,我们就不一一说了,其中机器人最长用的到的就是Timers,Tirggers,Alias。考虑到这里在后面还要经常用到,这里本着之前的原则,就先不上图多做说明了。用到的时候会详细说明,刚开始的接触到的时候,可能会觉得有点复杂,但是别怕。我会本着实用的原则来告诉大家,凌晨4点了,今天就先到这里吧,明天睡起来了继续,还要准备一些图。。 ZzzZzz

PS 以上大部分内容,都是可以找到的资料。加上一点自己觉得什么实用什么没用的理解,就发出来了,想看完全内容的,可以去找找

MUD - MUD游戏 - 文字MUD - 武林MUD - 长期、稳定、高速、互助、活跃、更新的武侠MUD站点,一起MUD吧!
18# .
dllkg 发表于 2019-1-8 22:00:07 | 只看该作者
感觉讲得挺详细,收藏了
17# .
wanjia 发表于 2018-6-13 22:49:03 | 只看该作者
受教了 最近正在学 刚开始看 写的蛮好
16# .
jizong 发表于 2017-7-3 17:27:59 | 只看该作者
string.find

我在运行的时候,报错啊

[string "Script file"]:58: bad argument #1 to 'find' (string expected, got nil)
stack traceback:
        [C]: in function 'find'
        [string "Script file"]:58: in function <[string "Script file"]:19>

这个应该是内置函数,为啥要报错?

if string.find(l,'设定环境变量:no_teach = "draw_end"') or string.find(l,'设定环境变量:no_teach = "q"') then break end
15# .
ssyun 发表于 2016-10-6 22:46:13 | 只看该作者
谢谢  楼主的分享  谢谢!
14# .
萧云晨 发表于 2016-8-26 16:18:14 | 只看该作者
381676420 发表于 2016-1-25 13:21
随便那个版本,下载以后,在网上搜个mush汉化,就两小文件。然后复制粘贴到mush目录下的一个文件夹里。再去 ...

召唤,回来继续写啊
13# .
 楼主| 381676420 发表于 2016-1-25 13:21:32 | 只看该作者
随便那个版本,下载以后,在网上搜个mush汉化,就两小文件。然后复制粘贴到mush目录下的一个文件夹里。再去全局设置里改下,重启就是中文了。如何汉化有教程的,一看就明白
12# .
signwall 发表于 2016-1-25 09:50:49 | 只看该作者
381676420 发表于 2016-1-22 22:47
已经烂尾了,就别刘明了,看看赶紧回家睡吧

明明是被阿姨传染了懒癌。
对了中文版的mushclient哪里下载给个链接呗。
我准备年后看看。
11# .
 楼主| 381676420 发表于 2016-1-22 22:47:46 | 只看该作者
kingm 发表于 2016-1-22 22:17
火钳刘明 来支持henry

已经烂尾了,就别刘明了,看看赶紧回家睡吧
10# .
kingm 发表于 2016-1-22 22:17:14 | 只看该作者
火钳刘明 来支持henry
9# .
 楼主| 381676420 发表于 2016-1-22 04:13:53 | 只看该作者
本帖最后由 381676420 于 2016-2-10 19:26 编辑

作为整个教程的最后一层,在这里放上一个完整的武林师门机器人。提供大家使用跟研究。先来看整个机器人的运行结果--------------------------------------------------------------------------------------------






以上图片的运行结果,是没有加入hp判断的,下面给出的机器人实际是加了判断的,所以你们如果运行,可能结果会跟图片不一样哈。
-------------------------------------------------------------------------------------------------------
下面我们直接放出整个代码部分

————————————————————————————————————————
首先我们需要建立一个任务地点,以及抵达地点的数组,代码如下


path_sm = {  -- 坑爹的路径数组,如要修改注意格式。
        ["洛阳城南城根"] = {
                "r luoyang;s;s;s;s;s;s;s;s;w;w;w;w;nw;n;n;n;n;s;s;s;s;se;e;e;e;e;e;e;e;n;n;n;n;e;n;s;w;s;s;s;s;e;ne;n;n;n;n;n;n;s;s;e;e;w;w;w;w;w;w;w"
        },
        ["洛阳城内城南门"] = {
                ""
        },
        ["洛阳城内城西门"] = {
                ""
        },
        ["洛阳城内城北门"] = {
                ""
        },
        ["洛阳城内城东门"] = {
                ""
        },
        ["洛阳城兰薪寺"] = {
                ""
        },
        ["洛阳城茅草屋"] = {
                ""
        },
        ["洛阳城牢房"] = {
                ""
        },
        ["洛阳城洛阳中心广场"] = {
                ""
        },
        ["华山附近平心石"] = {
                ""
        },
        ["华山附近广场"] = {
                ""
        },
        ["华山附近西村口"] = {
                ""
        },
        ["华山附近打谷场"] = {
                ""
        },
        ["开封城朱雀门"] = {
                ""
        },
        ["开封城州桥"] = {
                ""
        },
        ["开封城延庆观"] = {
                ""
        },
        ["开封城山陕甘会馆"] = {
                ""
        },
        ["开封城南盈门"] = {
                ""
        },
        ["开封城放生池"] = {
                ""
        },
        ["中州城市中心"] = {
                “"
        },
        ["中州城中州南门"] = {
                ""
        },
        ["中州城中州北门"] = {
                ""
        },
        ["中州城延陵东路"] = {
                ""
        },
        ["中州城延陵东路"] = {
                ""
        },
        ["中州城西城楼"] = {
                ""
        },-
        ["昆明城南大街"] = {
                ""
        },
        ["昆明城红土路"] = {
                ""
        },
        ["昆明城小西门"] = {
                ""
        },
        ["昆明城小路"] = {
                ""
        },
        ["荆州城荆州中心"] = {
                ""
        },
        ["荆州城荆州南门"] = {
                ""
        },
        ["荆州城温泉井"] = {
                ""
        },
        ["荆州城紫竹林"] = {
                ""
        },
        ["南海一带南海渔村"] = {
                ""
        },
        ["扬州城南门"] = {
                ""
        },
        ["扬州城西门"] = {
                ""
        },
        ["扬州城北门"] = {
                ""
        },
        ["扬州城东门"] = {
                ""
        },
        ["兰州城中央广场"] = {
                ""
        },        
        ["兰州城兰州南门"] = {
                ""
        },
        ["兰州城兰州西门"] = {
                ""
        },
        ["长安城长安东城门"] = {
                ""
        },
        ["长安城长安南城门"] = {
                ""
        },
        ["长安城长安西城门"] = {
                ""
        },
        ["长安城长安北城门"] = {
                ""
        },
        ["长安城青龙街"] = {
                ""
        },
        ["长安城白虎街"] = {
                ""
        },
        ["武功镇西街"] = {
                ""
        },
        ["武功镇南街"] = {
                ""
        },
        ["佛山一带西镇街"] = {
                ""
        },
        ["佛山一带南门"] = {
                ""
        },
        ["汝州一带汝州城"] = {
                ""
        },
        ["嵩山一带天中阁"] = {
                ""
        },
        ["嵩山一带太室阙"] = {
                ""
        },
        ["嵩山一带少林寺山门"] = {
                ""
        },
        ["终南山翠屏谷"] = {
                ""
        },
        ["终南山柏树林"] = {
                ""
        },
        ["终南山太乙池"] = {
                ""
        },
        ["终南山神禾原"] = {
                ""
        },
        ["终南山半山亭"] = {
                ""
        },
        ["成都城南大街"] = {
                ""
        },
        ["成都城青羊宫"] = {
                ""
        },
        ["成都城北大街"] = {
                ""
        },
        ["星宿海天山山路"] = {
                ""
        },
        [""] = {
               ""
        },
}
由于地点太多,我就不放出全部的来,这个格式大家复制粘贴就可以用,然后自己可以添加,我没有直接给出路径,这个希望大家可以自己去录,毕竟机器人的效率很大一部分原因取决于路径的好坏。我录的不一定最好。

在教大家一个 mush下录制路径的办法,很方便。



如上图这样创建一个Alias 图片主要看选项,具体的我都会用可复制的形式写出来
别名(A) 的内容为 ^(.*)$
发送(S) 的内容为
Send("%1")
for i, v in pairs(direction) do     --direction是一个数组
    if "%1" == v then
      utils.appendtonotepad("遍历记录", "%1" .. ";")
      break
    end
end
在给出direction数组代码 这代码是在脚本中的哦

direction = {
        "n",
        "s",
        "w",
        "e",
        "ne",
        "se",
        "sw",
        "nw",
        "nu",
        "nd",
        "su",
        "sd",
        "wu",
        "wd",
        "eu",
        "ed",
        "u",
        "d",
        "enter",
        "out",
}

-------------这样使用起来的好处是,在游戏里只有输入数组中存在的元素时,才会被记录下来存入一个记事本中。大家复制下来,去使用下就知道了。

有了路径,我们就可以让机器人按我们的意愿跑起来了。特别声明:由于这个机器人,我本人还想日后继续添加更多的功能进去,所以没有封装成插件,你们复制粘贴的使用没有问题,但是记住 需要手动改变量。

我先给出变量的图片截图,在一一说明



大家在使用的时候,复制这些代码之前,我建议就先在mush中创建好这些变量。missB是定位用的10B请自己填写自己的,pfm1为使用的绝招自己填写, masteEN是师门NPC的ID根据自己情况填写。bianli_i这个变量,在第一次创建的时候另其值为1,以后就不用再管了。其他没有写到的变量,都是会自己抓取的,只需要创建出来,不用赋值。放在那里就可以。

---------------------------------------------------------------------------------------------

下面我在给出所有在mush下的触发器内的内容:



这就是全部用到的触发,其实3个触发配合脚本就可以完美的运行了,只是考虑到要发送出来给大家用,所以添加了判断气血的部分,我个人做师门是不需要判断气血的。下面我写出每条触发的内容,请注意每个触发的选项,组名,名称部分
---------------------------

匹配行 @npcCN\(@npcEN\)
发送 行
EnableTrigger("sm_go", false)
Execute("follow " .. GetVariable("npcEN"))
kill()
--------------------------------------------------------


匹配行 \"go\_next\"$
发送行
SetVariable("bianli_i", GetVariable("bianli_i") + 1)
wait.make(function()
    wait.time(0.1)
    bianli()
end)

-----------------------------------------------------------------

匹配行 ^[> ]*\S+对你道:(.*)\((.*)\).*听说他最近在(.*)附近.*$
发送行
SetVariable("npcCN", "%1")
SetVariable("npcEN", "%2")
SetVariable("city_place", "%3")
print("【任务NPC名:】" .. "%1" .. " 【任务NPCID: 】" .. "%2" .. " 【NPC所在地点:】" .. "%3")
Goto_Find_NpcSM()

----------------------------------------------------------------------------------------------------------------

匹配行  【 精 气 】\s+\d+\/\s+\d+\s+\((.*)\%\)\s+【 精 力 】\s+\d+\s+\/\s+\d+\s+\(\+.*\)\n【 气 血 】\s+\d+\/\s+\d+\s+\((.*)\%\)\s+【 内 力 】\s+\d+\s+\/\s+\d+\s+\(\+.*\)\Z
发送行
print("%1", "%2")
SetVariable("jingqi", "%1")
SetVariable("qixue", "%2")
HP()


这里注意下哦,这个是个多行匹配,我只抓取了百分比的数字作为判断健康度。
-------------------------------------------------------------------------------------


匹配行 [> ]*你缓缓睁开双目,精光四射,神清意爽。
发送行
if tonumber(GetVariable("jingqi")) < 60 then
   Execute("yun heal")
else
   EnableTrigger("hp_1", false)
   EnableTrigger("hp_2", false)
   EnableTrigger("hp_3", false)
   Execute("hp")
end

------------------------------------------------------------------------------------------

匹配行  [> ]*你运功完毕,吐出一口瘀血,自觉经脉顺畅,内伤尽去,神元气足地站了起来。
发送行
if tonumber(GetVariable("qixue")) < 60 then
    Execute("yun heal")
else
    EnableTrigger("hp_1", false)
    EnableTrigger("hp_2", false)
    EnableTrigger("hp_3", false)
    Execute("hp")
end

-------------------------------------------------------------------

匹配行  ^[> ]*.*对你说道:你今天的任务份额已经领完了,你还是自己锻炼一段时间吧。$
发送行
EnableGroup("师门", false)
print("今日可领任务完成")
还有一个计时器


发送行
Execute("yong " .. GetVariable("pfm1") .. " " .. GetVariable("npcEN"))

还有个Alias


发送行
EnableGroup("师门", true)
EnableTrigger("sm_go", true)
Execute("miss " .. GetVariable("missB") .. ";r family;" .. "quest " .. GetVariable("masteEN"))



--------------------------------------------以上就是全部的触发器内容-------------------------------

下面给出所有配合使用的代码,复制粘贴在你的新建脚本中 外加路径齐全,你就可以跑起来了,效率还是不错的
脚本头需要调用wait

require "wait"

--如果需要打印数组,还需要调用tprint

require "tprint"

function Split(szFullString, szSeparator) --把字符串形式的路径(n;e;s),转换成数组。
        local nFindStartIndex = 1
        local nSplitIndex = 1
        local nSplitArray = {}
        while true do
           local nFindLastIndex = string.find(szFullString, szSeparator, nFindStartIndex)
           if not nFindLastIndex then
                        nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, string.len(szFullString))
                        break
           end
                nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, nFindLastIndex - 1)
                nFindStartIndex = nFindLastIndex + string.len(szSeparator)
                nSplitIndex = nSplitIndex + 1
        end
    return nSplitArray
end


function Goto_Find_NpcSM() --接到任务后,给lj变量赋值,这个值是已转换成数组形式的路径
                lj = {} --每次进入函数,初始化数组。
                for i, v in pairs(path_sm) do  --遍历path_sm数组。
                        if i == GetVariable("city_place") then --判断任务地点是否存在于数组中
                                lj = Split(path_sm[GetVariable("city_place")][1], ";") --给lj赋值已转换的路径数组。注意:此时lj是一个数组
                                break        --跳出循环,减少计算量(不跳出也无所谓)
                        end
                end
                if next(lj) == nil then
                        print("没有任务地点,或者任务地点没有路径,请补充")
                else
                        SetVariable("bianli_i", 1)  -- 走路计数器变量赋值1,行走的关键,如果不是1会造成错误。
                        EnableTrigger("sm_go", true) --打开sm_go的触发器,行走前准备
                        print("六秒后出发前往:★ " .. GetVariable("city_place") .. " ★》》《《击杀:【 " .. GetVariable("npcCN") .. "(" .. GetVariable("npcEN") .. ") 】")
                        wait.make(function()  -- 携程
                        wait.time(6)  -- 等待六秒秒后出发。
                        Execute("miss " .. GetVariable("missB")) -- 游戏中的定位10B请在mush变量下,手动修改missB变量。
                        bianli()  --在函数中调用另外一个函数,开始行走。
                        end)
                end
end
等待6秒出发的原因是,防止一过去,碰见npc就刚准备杀,npc离开了,然后就不停的pfm,可是没人,而且就算follow了,一旦准备打,npc跑了, follow了也没什么用,我测试了好多次,不知道为什么。所以干脆等时间长点,让npc不在走动以后,在前进,这个数字自己可以调整。----------------------------------------------------------------------------------------------------

function kill() --看函数名字就知道什么意思咯。^_^
        EnableTrigger("find_npc", false) --关闭find_npc触发器
        Execute("kill " .. GetVariable("npcEN"))
        EnableTimer("pfm", true) --打开pfm计时器
        wait.make(function() --携程
                local l, w = wait.regexp("[> ]*" .. GetVariable("npcCN").."扑在地上挣扎了几下,腿一伸,口中喷出几口鲜血,死了!") -- 用这句话来做为触发
                EnableTimer("pfm", false)
                wait.time(3) -- 等待3秒,可以按照个人不同需求进行修改。
                --print("开始砍头") --检测是否触发成功,多养成打印的好习惯。
                Execute("cut " .. "head " .. "from " .. "corpse")
                local l, w = wait.regexp("[> ]*.*一下子(把|就把)" .. GetVariable("npcCN") .. "的尸体的头给砍下来。")
                wait.time(5) -- 等待5秒,可以按照个人不同需求进行修改。
                --print("砍头结束") --检测是否触发成功,多养成打印的好习惯
                Execute("apply yanwu dan;" .. "miss " .. GetVariable("missB") .. ";r family;" .. "give " .. GetVariable("masteEN") .. " head")
                local l, w = wait.regexp("[> ]*你拿出" .. GetVariable("npcCN") .. "的人头.*$")
                EnableTrigger("hp_1", true)
                EnableTrigger("hp_2", true)
                EnableTrigger("hp_3", true)
                wait.time(2)
                EnableTrigger("find_npc", true)
                Execute("hp")
                --Execute("hp;" .. "quest " .. GetVariable("masteEN"))
        end)        
end

最后一个等待5秒是为了防止,有时候战斗时候有3个npc,砍头以后,还在战斗,会造成你现在很忙这样的提示,我这里是偷懒,不愿意更精细的处理,所以等待时间长点算了,有能力的可以自己写个触发,来解决这个问题。
--------------------------------------------------------------------------

function HP() --判断气血的函数,没什么好说的
        local jingqi, qixue = tonumber(GetVariable("jingqi")), tonumber(GetVariable("qixue"))
        --print(jingqi, qixue)
        if jingqi < 60 then
                Execute("yun inspire")
        elseif qixue < 50 then
                Execute("yun heal")
        else
                EnableTrigger("hp_1", false)
                EnableTrigger("hp_2", false)
                EnableTrigger("hp_3", false)
                Execute("quest " .. GetVariable("masteEN"))
        end
end


  1. function bianli() --走路用的家伙
  2.       --print("lj变量的值:" .. table.concat(lj, ";"))        ----检测lj的值是否被传了进来
  3.       local i=tonumber(GetVariable("bianli_i"))-------bianli_i是个计数器,表明现在走到数组的哪一个元素了。
  4.       if lj[tonumber(GetVariable("bianli_i"))] == nil then
  5.            Note("----遍历【" .. GetVariable("city_place") .. "】完成。未找到目标,请检查或补充路径----")
  6.            return
  7.       end -------数组遍历完成之后就不要遍历了再
  8.       local s1="当前行走段一共"..tostring(table.getn(lj)).."步,现在为 第"..GetVariable("bianli_i").."步"..",当前命令:"..lj[i]              
  9.       Note(s1)---------以上两行是用来提醒自己的。
  10.       Execute(lj[i] .. ";set auto_drinkout go_next")------这才是行走的命令。
  11. end
复制代码





重要代码部分我都做了十分详细的注释,应该是可以看懂吧。
另外如果你们复制上面的代码。在游戏中运行的时候,跟我一开始的图片会有点小小的出入,图片上可以看到有”当前行走段一共41步,现在为 第26步,当前命令:east“这样的东西,你们用的时候就会变成”当前行走段一共41步,现在为 第26步,当前命令:e“这样,不影响使用的,我自己有两个转换路径的函数,所以显示后的结果不一样,那两个函数都没什么大用,所以我就不放出来,不用纠结。

机器人整体思路没有什么出彩的地方,更好的思路有,但是代码写起来太麻烦了,我容易晕,所以选择简单粗暴的。男人么,你们懂的!!哇哈哈

整个机器人这样就算是彻底的完成了,不知道武林的世界里,有多少小伙伴会去尝试上面这些东西。。

---------------------------------------------------------------------------------------------------------------------------------

这篇教程就到这里结束吧,我自己都没想到能写这么多东西。由于懒癌晚期的关系,这样一个完整的mush机器人,或者说一个完整的可以面向广大玩家使用的mush机器人,肯定不会再写了哈。

希望大家都赶紧使用mush吧



PS:重要的事说三遍是惯例,坐等mush大神机器人,我是伸手党

PS:重要的事说三遍是惯例,坐等mush大神机器人,我是伸手党
















8# .
 楼主| 381676420 发表于 2016-1-22 04:13:34 | 只看该作者
本帖最后由 381676420 于 2016-2-6 01:21 编辑

经过反复思考,决定以接取帮派任务,并抵达任务地点为典型来进阶的讲解下mush利用脚本制作机器人,别小看就仅仅是个接任务并达到地点。汉字描述起来就一句话,但是体现在脚本中,却十分复杂,要思考的地方太多。说到这里再一次忍不住吐槽下武林三大坑爹系任务,全是费劲又回报低下的事。废话少说,我会尽量以类似直播的方式来图文阐述这个过程,可能会很长。我们开始。PS: 关于table的概念,想学的就去网上度娘下把,我就不说了,真的说不清楚。
---------------------------------------------------------------------------------------------------------------

制作机器人之前最主要的一个步骤就是先要思考出一个思路来。在我设想的帮派任务中。应该是把任务分成三类,第一类是传话,第二类是寻物,第三类是调解。三个不同种类的任务,分别建立三个多维数组,用来保存任务的关键信息,比如place,obj,npc,path等。然后用变量来标记接到任务的种类,根据变量值得不同,遍历不同的数组,调用出需要的信息(这一过程是个庞大到几乎不可能完成的任务,对于我这类懒人来说。然而使用数据库会方便很多,但是数据库的建立依然是庞大的工程,外加要是用到数据库,这帖子我也就没办法写完了。),思路看起来十分简单,实现起来却又要考虑很多问题。毕竟我们是教学贴,不是发个成型的机器人出来,所以我们用调解任务来做例子,因为调解任务只会出现在帮派所在的地图上,哈哈。

--------------------------------------------------------------------------------------------------------------
--帮扬州城春来茶馆的阿庆嫂和戚述调解纠纷 --
这是任务领取时候的提示,这句话里有什么信息是我们需要保存的么。“春来茶馆”必然是一个,“阿庆嫂”貌似没毛用,“ 戚述”有用,但是我们要的是EN,抓取个CN回来也没毛用。先都抓出来,万一需要的时候不会再从头改,脚本的变量跟mush的变量是两个概念,有的时候存来存去,倒来倒去,外加 lua还有个全局跟局部的概念,很容易让人蒙圈,所以一定要注意这点。目标居然定了,那么我们就来建立数组,这个数组的一维就是任务的种类没,二维是任务地点,三维是到达地点的路径。(例子中我的小号是黄昏帮的,所以所有调解任务都只会出现在扬州)


path_YZ = {
        ["纠纷"] = {
                ["当铺"] = {
                        "s;r gc;s;e"
                },
                ["胭脂店"] = {
                        "s;r gc;n;n;n;e"
                },
                ["书院"] = {
                        "s;r gc;e;n"
                },
                ["钱庄"] = {
                        "s;r gc;n;w"
                },
                ["药铺"] = {
                        "s;r gc;e;e;n"
                },
                ["打铁铺"] = {
                        "s;r gc;e;e;s"
                },
                ["春来茶馆"] = {
                        "s;r gc;s;s;w"
                },
                ["赌场"] = {
                        "s;r gc;s;w"
                },
        },        
}

这就是扬州地区,我收集到的调解任务的地点,不全。。我就用这些来说明下就可以了。

数组建立以后,我们来打印一下看看 对不对,我们加个print()函数来测试效果。另外在加一个tprint()函数来测试整个数组。print如果打印数组,只能打印出他的内存地址,或者单独打印出数组中某个特定的值。不直观,tprint()可以很直观的看到数组,这个函数是mush自带的,在lua的文件夹下可以找到,要调用tprint()函数,我们需要在脚本文件头调用这个函数,具体的方法就是require "tprint"。给出整段的代码。

require "tprint"
print("扬州调解载入成功")  --这里加个打印效果,是为了在制作机器人的时候,每次重新载入都能有个提示。


path_YZ = {
        ["纠纷"] = {
                ["当铺"] = {
                        "s;r gc;s;e"
                },
                ["胭脂店"] = {
                        "s;r gc;n;n;n;e"
                },
                ["书院"] = {
                        "s;r gc;e;n"
                },
                ["钱庄"] = {
                        "s;r gc;n;w"
                },
                ["药铺"] = {
                        "s;r gc;e;e;n"
                },
                ["打铁铺"] = {
                        "s;r gc;e;e;s"
                },
                ["春来茶馆"] = {
                        "s;r gc;s;s;w"
                },
                ["赌场"] = {
                        "s;r gc;s;w"
                },
        },        
}
print ("路径:" .. path_YZ["纠纷"]["当铺"][1])
print("---------------------分割以下部分为tprint()打印的部分----------------")  --为了让你们看的更直观,我也是拼了。
tprint(path_YZ)



载入后的效果如下:




-------------------------------------------------------------------------------------------------------------

数组建立成功,接下来我们需要完成的就是接任务啦,这里我们需要用到一个触发。我选择使用是每次达到领取任务的房间后,用房间名加所在地点名作为触发。。直接给出正则部分方便大家复制 测试   ^[> ]*黄昏门分舵 \- \(你目前在扬州城\)$



----------------------------------------------------------------------------------------------------------

可以看到发送部分的get_quest()函数,这个就是我们的重点了,下来我们来编写这个函数

get_quest = function()
        Execute("l paizi")

end
以上这一步完成就可以做到,每次到这个地方都会l paizi,看了牌子我们就要选取任务了,这里我们还需要一个触发。就是调解任务的触发。同样直接给出正则 ^[> ]*(\S+)\s+帮(\S+)城(\S+)的(\S+)和(\S+)调解(\S+) 把这个触发器的分组写成帮派任务,名字叫bangpai_quest。 在这里我把这些感觉有用的东西,都做了抓取,反正抓多了也无所谓,用的时候少了就麻烦,所以我们多抓。l paizi以后会出现一个任务表。如图:



在这个表里,我们可以看到的是 最上面的部分是“任务表"三个字,然后最下面的部分是"请用choose <编号>选择你要完成的任务,放弃任务用giveup指令。" 两者中间夹的就是任务部分(上图中没有我们可以选的任务,因为触发的只是调解任务,别纠结图)。上一层的时候我说过,可以在函数内做触发,不需要每个触发都在mush下。我们现在就来完成这部分,为了更严谨的机器人,我们需要告诉机器人在看到”任务表“这三个字以后开启触发器抓取任务,看到最后一句话后,关闭触发器。实现代码如下:

get_quest = function()
        Execute("l paizi")
        wait.make(function()
                local l, w = wait.regexp("^[> ]*\s*任务表\s*")
                EnableTrigger("bangpai_quest", true)
                local l, w = wait.regexp("请用choose <编号>选择你要完成的任务,放弃任务用giveup指令。")
                EnableTrigger("get_quest", false)
         end)
end


要用到wait模块,同样需要在脚本文件头调用 方式为require "wait" 然而wait.regexp不能单独使用,需要放在wait.make(function() XXX end)下,这涉及到协程问题,不多说,就是这么用,记住就好。下面我们来看图




可以看到上边的图片就是抓取任务的触发,下边的就是抓取到任务后的结果,我先打印出来测试下一样。如上图一切都没问题。

--------------------------------------------------------------------------------------------------------------------------

现在任务已经选择了,接下来要完成的就是如何领取了。我们先来看代码

get_quest = function()
        Execute("l paizi")
        wait.make(function()
                quest_tj = {}
                local l, w = wait.regexp("^[> ]*\s*任务表\s*")
                EnableTrigger("bangpai_quest", true)
                local l, w = wait.regexp("请用choose <编号>选择你要完成的任务,放弃任务用giveup指令。")
                local quest_num, place_1, npc_one_1, npc_two_2 = get_best_quest(quest_tj) -- 留一个接口,以后有可选任务时候用。
                SetVariable("npc_1", npc_one_1)
                SetVariable("place", place_1)
                SetVariable("npc_2", npc_two_2)
                Execute("choose " .. quest_num)
        end)
end


这段代码里多出了quest_tj = {} 这是初始化一个数组,我们需要把抓带各种信息存入这个数组中。get_best_quest()这个函数是一个预留的接口,如果以后想要完善帮派机器人的话,这里就很重要,他可以帮助我选择任务,什么不选什么选。(这都是后话,在这层里我也不准备去实现,毕竟太麻烦,春姐传染我的懒癌已经到了晚期。),为了能更好的说明上面的代码,我把get_best_quest(quest_tj) 函数的代码也一起放出来。


get_best_quest = function(quest_tj)  
        -- 选择最优任务接口
        return quest_tj[1].num, quest_tj[1].place, quest_tj[1].npc_one, quest_tj[1].npc_two
end



上面这段代码的意思 目前很简单,就是返回数组数组中抓取到的值,local quest_num, place_1, npc_one_1, npc_two_2 = get_best_quest(quest_tj)
因为返回了 4个值,所以我用4个局部变量接收它。然后存入mush中,方便以后调用,存入mush的好处是,就算重新加载了机器人,变量也不会丢失。
当然了我们需要提前在mush创建出place,npc_1,npc_2三个变量,我们还需要在触发领取任务的那条触发下,把抓取到的信息添加到quste_tj这个数组中。先来看图



这个触发,我们就可以把抓起到信息添加到,我们的quest_tj中。然后我们在来看看触发后,打印quest_tj这个数组的结果



在来看看mush中变量的值



嗯,没有问题。都很完美。。。。可是接任务的那张如里,为什么显示了个没有可接任务呢?是因为去财主后院不再我们path_YZ数组中,所以我们先来优化下,我们的任务选择。看代码

get_quest = function()
        Execute("l paizi")
        wait.make(function()
                quest_tj = {}
                local l, w = wait.regexp("^[> ]*\s*任务表\s*")
                EnableTrigger("bangpai_quest", true)
                local l, w = wait.regexp("请用choose <编号>选择你要完成的任务,放弃任务用giveup指令。")
                local quest_num, place_1, npc_one_1, npc_two_2 = get_best_quest(quest_tj) -- 留一个接口,以后有可选任务时候用。
                SetVariable("npc_1", npc_one_1)
                SetVariable("place", place_1)
                SetVariable("npc_2", npc_two_2)
                for i, v in pairs(path_YZ) do
                        if path_YZ[GetVariable("quest_class")][GetVariable("place")] then
                                local lj = path_YZ[GetVariable("quest_class")][GetVariable("place")][1]
                                SetVariable("lj", lj)
                                Execute("choose " .. quest_num)
                        else
                                print ("没有合适的任务")
                        end
                end
                EnableTrigger("get_quest", false)
        end)
end


for i, v in pairs(path_YZ) do  这是一种遍历数组的形式,lua下称为泛型for循环。pairs为迭代器,这个迭代器是lua自带的,我们也可以自己编写迭代器,lua下的迭代器还有个ipairs 这里我就不细说这个东西了,说不清。自己可以去查。。我们用这个循环遍历整个path_YZ数组,然后来判断,我们接到的任务信息,数组中是否存在,存在就接,并且把路径提取出来保存到mush中,不存在就说打印没有合适任务(这部分我偷懒了,按道理说这个判断应该放在get_best_quest()函数中。而且在上面的代码中,return quest_tj[1].num, quest_tj[1].place, quest_tj[1].npc_one, quest_tj[1].npc_two 我们的返回值都是下标为1的,可是我们的quest_tj下,可能会有很多个,所以应该优化这里。如果1中没有合适的,那么应该去搜索2,类似这样。我没有写,因为我懒癌又犯了,大家知道下就好了,有兴趣的可以自己去完成。我在这里主要是说个思路,跟构造一个框架)。


-------------------------------------------------------------------------------------------------------------------------------------------


到这里,接去任务的最核心部分,也就算差不多了。下来就是怎么过去的问题了。这里我们可以在单独制作一个触发,用来触发接去任务以后的话。直接上图。



在加上一张图



这样,有了路径,我们就可以走到了。最后步骤的运行结果发个截图




这样一来,我们的目的就彻底完成了。。。。到达了地点,在怎么继续就是后话了。我们就不再讨论了,同样用数组的办法,可以解决,但是工程太大。 由于快1点了,收尾的部分,真的很草率。大家见谅了。另外主要告诉大家的是脚本的使用方式,不要太在意细节的部分,毕竟我是说明。
最后补充说明下2点,一是quest_tj数组在一个函数内,每次运行了函数,才可以初始化,很麻烦,也很容易报错,我们可以在函数外添加一个 quest_tj = {} 就可以解决,第二点是由于本身代码的限制,如果任务中没有调解任务,就会报错,原因是quest_tj是空的,没有东西。毕竟是不完善的东西。

PS: 在我的理想中一直想当伸手党,谁有高能的mush机器人,发给我啊。自己写真的好辛苦。。。。























7# .
 楼主| 381676420 发表于 2016-1-22 04:13:28 | 只看该作者
本帖最后由 381676420 于 2016-2-4 16:44 编辑

      停了好多天没有更新了,我自己其实也不知道应该写些什么了。最近闲着没事, 游戏挂着分丝,于是就自己去弄了个机器人。顺便就把怎么弄的发上来,就算是实例了。因为武林中没有太复杂的任务,所以机器人做起来也相对简单,然而稍微复杂一点的任务,我都懒得去做,因为不值得,就好比独孤任务(本人从来不做)帮派任务(我靠一天就20个,用mush做起来,多维的数组就不知道要用到几个,实在麻烦)师门任务(跟帮派一个性质)再说了这些任务的机器人Zmud462下都有,稍微改改就非常适合自己,又不需要连续挂,一天就那么20个,所以不牵扯稳定性的问题。(吐槽春姐100000000000^N句)。
-----------------------------------------吐槽完毕,看机器人把---------------------------------------------------


     先说下思路,我想完成一个可以在黄果树瀑布分丝的机器人,一边分丝一边看瀑布(很多朋友都看到我不停的看到神仙姐姐了把HoHo),由于买丝一次最多买100.所以每次买100丝后就前往瀑布开始分丝,每次分丝完成以后回去先去买粮,在去装水带,最后去买丝,然后无限循环这个过程。一个简单稳定的分丝机器人就完成了。。好处是不需要计划(因为计划分丝需要往箱子里放丝,一次只能一个实在苦闷,也节约了小号。还能看飞流直下三千尺的美景,话说据说看这个加灵慧,哪位可以告诉我看一次加多少呢),下面来看看具体是实现方式。之前那么多层楼里所讲到的东西,我都会用在机器人上。方便大家理解。

这个触发,是匹配的买到100丝后我需要做什么,发送部分我用了一个gofuse()的函数,其实完全没必要,我只是为了更好的结合之前说到的东西,下面我们来看函数本身。
function gofuse()
        DoAfterSpecial (1,"r dali;s;s;s;s;s;s;s;se;sw;n;w;fuse si",10)
end

函数的构造这里就不多说了,直接来说DoAfterSpecial (1,"r dali;s;s;s;s;s;s;s;se;sw;n;w;fuse si",10)这部分,相信大家都应该能看懂这里的意思,1秒以后执行r dali;s;s;s;s;s;s;s;se;sw;n;w;fuse si这个命令,后面的10表示发送到游戏(貌似是发送到游戏吧,记不清了,这里常用的就10,12,13.这三个参数,12应该是发送到命令解析器,13应该是发送到脚本,这个可以去在mush下面查,知道这最后一个数字的意思就可以了,具体用的时候根据不同需要,自己选择),运行的结果就是每次买到100个丝以后,就等待一秒,然后去瀑布开始分丝。
刚才上面就说了,发送部分完全是没有必要使用函数的,DoAfterSpecial (1,"r dali;s;s;s;s;s;s;s;se;sw;n;w;fuse si",10)把这部分,直接写进发送部分的效果是一样的,当然了要注意发送到的位置一定要是脚本解析器。大家应该同时也发现了,我给这个触发分了类,名字是“粉丝” 这是为了我方便控制。
------------------------------------------------------------------以上为购买丝---------------------------------------------


根据上面的触发,此时我们已经抵达瀑布,并且开始分丝了,那么我们抓取分丝是的一句话,来作为连续分丝的触发。注意语句里获得多少灵慧的部分我用括号括起来了,这表明我们需要抓取这个变量,这个问题以后不再重复,以前有说过。
直接来看函数部分
function fuse(num)
        local lhnum = GetVariable("lhnum") + 1
        SetVariable ("lhnum", lhnum)
        local linghui = num + GetVariable("linghui")
        SetVariable ("linghui", linghui)
        local lh = GetVariable("linghui") / lhnum
        local times = lhnum * 10 / 60
        Note("---------------------------------------------")
        Note("共获得灵慧:" .. GetVariable("linghui"))
        Note("平均灵慧为: " .. getIntPart(lh))
        Note("分丝次数: " .. GetVariable("lhnum"))
        Note("共用时: " .. getIntPart(times) .. " 分")
        Note("=====等待10秒=====")
        Note("---------------------------------------------")
        DoAfterSpecial(10,"touch hjj;cun shi;fuse si",10)
end

-----------------------------------------------------------------------
local lhnum = GetVariable("lhnum") + 1 这一步的意思就是我希望统计出,我一共分丝了多少次。SetVariable ("lhnum", lhnum) 这一步的意思是,把每一次加1以后的结果存入mush的变量中。local linghui = num + GetVariable("linghui") 这一步是用来统计在分丝过程中,一共获得了多少灵慧。SetVariable ("linghui", linghui) 同样存入mush中。


ocal times = lhnum * 10 / 60 因为每一次分丝之后间隔10秒才开始下一次分丝,所以这里我用来统计一共花费了多长时间。
Note的所有部分,就是把这些结果显示在屏幕上方便我随时看。
————————————————————————————————————————————————————————————
以上这些都是个人统计用的,其实没有这些,也是可以的。完全不影响什么,另外如果要用到这些统计,那么必须手动在mush中添加两个变量,一个是lhnum,另外一个是linghui 他们的值都是 0 如果没有这两个变量 会报错,之前讲过GetVariable() SetVariable ()这两个函数了,报错的原因我就不说了
有人可能注意到SetVariable ("lhnum", lhnum)中,两个变量的名字都是lhnum.这里说下“lhnum”是mush下的变量名,lhnum是脚本中的一个局部变量,这两个变量是不一样的。所以可以这样使用。


整个函数中那么多乱七八糟的,其实真正有用的就一句话DoAfterSpecial(10,"touch hjj;cun shi;fuse si",10) 每次分丝完成以后,间隔10秒执行什么什么命令。。


跟第一个触发一样,如果不需要这些乱七八糟的东西,直接在发送里写 DoAfterSpecial(10,"touch hjj;cun shi;fuse si",10) 然后发送到脚本,其实就可以完成分丝的连续循环了。


这里给出一个我自己写的提取整数部分的代码,因为lua的计算结果的返回值会精确到小数点后无数位,为了美观也为了直观,所以我单独写个函数用于体提取整数,代码如下

function getIntPart(x)
        if x <= 0 then
                return math.ceil(x)
        end
        if math.ceil(x) == x then
                x = math.ceil(x)
        else
                x = math.ceil(x) - 1
        end
                return x
end


用法很简单,Note("共用时: " .. getIntPart(times) .. " 分") HoHo 这样就用了
-----------------------------------------------------------------------------------------------------------------------


把身上的100个丝分完了,就需要回去在重新买了,这里我就不给出代码了,看了这么多,相信大家已经可以自己完成了。买丝之前,先去判断干粮装水袋,这样就不会因为饮食问题导致机器人停止,怎么实现大家自己弄吧。


如上图,做这样一个触发的目的是防止10秒的等待不够,这样的目的是为了保证机器人的稳定性。怎么样防止,大家也自己写。

-----------------------------------------------------------------------------------------------------------------------------------------------
由于mush没有zmud的#ig功能,所以为了方便中途停止机器人,我们做下面两个Alias 来控制它


如上图定义一个stop的alias 发送的内容其实就是关闭“粉丝”这个类 注意发送到的位置


有个停止,我们在相应的做个开始的alias,至于是买丝开始 还是直接开始,就看大家的需要了。
最后放上机器人运行的结果:



------------------------------------------------------------------------------------------------------------------------------------------
到这里整个机器人的大框架就算建立起来了,中间当然还可以添加一些自己需要的东西,这个就看个人的需要了。另外完全可以使用一个触发,就把上面的所有内容都完成,在函数体内在做触发,这样的好处就是可以减少mush下的触发,脚本的强大也就显现了出来,当然那是另外一个层次的东西。先不去讨论,刚开始学习的时候,说太多中办法,容易搞的头脑不清晰,所以我们就先按照最笨的办法来,等熟练了在去尝试更高级的东西。


    说到这里就顺便用例子给大家说一下lua的判断语句。。     lua的判断语句有三种格式:
if <表达式> then <语句块> end
if <表达式> then <语句块1> else <语句块2> end
if <表达式1> then <语句块1> elseif <表达式2> then <语句块2> .......else <语句块N> end

以上三种形式前两种没什么好说的,第三种稍微说下,elseif <表达式> then <语句块> 在一个if语句中可以有N多个,但是 if 和 else 还有 end 只能有一个。不知道能理解不,用例子来说明吧。

^[> ]*观赏着飞流直下的水瀑,你不由得感叹自然造化的奇妙,隐隐然对武学也有了一点领会。
这是一句在瀑布分丝时看到水瀑并且成功以后的话,我们用来做触发,我想实现以下效果,如果是第一次看到,那么我就说:“我。我。我看到神仙姐姐了”,如果是第10次看到,我就说:我。我。我又看到神仙姐姐了,我为什么要说又呢?。如果是第20次看到,我就说:“神仙姐姐,我真的好累啊!”,
如果是第50次看到,我就说:“我已经看到麻木了。”    下面我们看具体的代码。

function chat_now()
        local n = n + 1
        if n >= 1 and n < 10 then
                Execute("chat 我。我。我看到神姐姐拉。")
        elseif n >= 10 and n < 20 then
                Execute("chat 我。我。我又看到神仙姐姐拉,我为什么要说又呢?")
        elseif n >= 20 and n < 50 then
                Execute("chat 神仙姐姐,我真的好累啊!")
        else
                Execute("chat 我已经看到麻木了。")
        end
end


大家看这个例子 别去纠结变量n ,因为单独这个例子n目前是没有值的,会报错。我们这里主要看的是if语句的格式。如果想要实现,可以在mush中设置一个变量n 另值为 0 然后把 local n = n + 1 改成 local n = GetVariable("n") + 1 就可以了,嘿嘿,是不是这里觉得有点问题,以前不是说过这样的变量都是字符串的么,不可以用作比大小。能发现这个问题的朋友,真的是非常不错。没错,但是在这里这样却没有任何问题,原因就是lua下有个特性。在做运算的时候,lua会自动把这个 字符串格式的“0” 变成数字格式的 0  大家记住哈。




PS:经过仔细的思考,我觉得回头在游戏中找个有代表性的例子,直接用制作机器人的办法,来说明数组,这样也许更方便大家理解。。给我几年时间,让我慢慢寻找,哈哈哈

6# .
 楼主| 381676420 发表于 2016-1-22 04:13:22 | 只看该作者
本帖最后由 381676420 于 2016-1-26 00:06 编辑

    这层楼,我们来简单的介绍下lua。个人觉得这篇基本是废的,看我发的还不如去看教程,教程会更加的详细,我发的,只是我个人认为对mush有用的才会写出来。我自己也就全当回忆回忆过去学过的知识了,本人并非计算机专业,我自学过两种语言,都是为了玩游戏能自己做出外挂/机器人。 Hoho~~有木有觉得像我这样的也真是拼了。虽然在生活工作中确实没什么大用,但是真的很有帮助,起码对逻辑思考能力是有提高的。而且,每当我回忆曾经玩游戏的时候,我都能回想起来,那时候两眼发直的看各种教程的经历,但是游戏里谁帮过我,谁杀过我,我杀过谁,真的都记不住了。玩都不能认真玩的人,还能干好什么呢?我一直都是这么认为的。好了闲的不扯了。我们进入正题。
    开始前,我先要大家明白一个概念,不是说lua工程师就能很简单的利用 mush写一个很牛X的机器人,这跟他对游戏的了解没有关系,而是对mush了解。mush跟lua是两个概念。懂lua语言只是能帮助自己更好的使用mush...然后不懂mush,lua语言在牛X,也什么都不行。mush所支持的其他语言,也是一样的。仅仅是了解了mush,并且能熟练使用mush下自带的函数裤,就可以做出非常牛X的机器人了。但是mush本身自带了对lua语言的扩展函数库。所以lua语言,懂一点就显得很有帮助。可以理解么?就算不理解我也没办法了,高中文凭词穷啊。

---------------------------------------------我是正式进入的分割线--------------------------------------------------------------------
先从lua的一些基本规定讲起把,可能十分没有章法,但是这些规定也不分先后的,所以不用深究章法哈。

先说说lua下的关键字,分别是

and   or   if   for   break   do   
else  elseif  end  false  true  while function   local   id    in   nil   not
return   repeat     until

应该就这些吧,如果没记错的话

关键字是不能用来作为标识符的,这么说要是不好理解,那么换个说话,关键之是不能用来作为变量名,或者函数名,或者组名的。这部分死记就好
lua是对大小写敏感的,比如:
and = "abc"  -----这样的的不允许的
And = "abc"  -----这样的就是可以的
aNd = "bcd"
anD = "efg"
And,aNd,anD分别是三个不同的值,好理解把。

——————————————————————————————————————————————————————————
在lua下,只有 false 和 nil 被认为是假 其他都为真,注意哦 0 这个数字在lua是被认为真的。 nil 是 空的意思,就是什么都没有

既然说到这里了,那么我们就说说lua下的 变量把。首先来说说如何赋值。

a = 123   b = 456  c = 789  这样的形式就叫赋值,好懂吧。。。另外 “=” 号 是赋值符号,而不是等于号,在lua 下的等于号 需要写成 "=="
而不等于,需要写成 ”~=“ 引号内的部分是,不算引号。在看来这样一组赋值的形式


a,b,c = 123,456 789 ---这个跟上面的,分别一一赋值效果是一样的,lua会一次把右边的值赋给 左边的变量名。在来看


a,b = 123,456,789 ---这样也是可以的,lua不会报错,只不过当右边的值比左边的变量名多时,在一一赋值的过程中 789找不到自己要赋值的对象,lua会自动把他舍弃。。在来看


a,b,c = 123,456 ----这样也是可以的,lua也不会报错,只不过当变量名少于值的时候,找不过值得那个变量c会被赋值nil 如果我们print(c)的话,屏幕上显示nil。理解了把。


PS:强调一点,lua下的变量赋值,跟mush中的变量,完全是两回事。别理解混乱了哦,我们现在说的东西,跟mush没有任何关系.


-------------------------------------------------------再来说说什么呢---------------------------------------------------------------
我们就说说lua 的类型于值把。
由于lua是一种动态类型的语言,在语言中并没有类型定义的语法,而每个值都携带有自身的类型信息 (这段是不是很难理解。我也不知道应该怎么解释,看不懂就飘一眼就好了) lua包括八中基础类型 分别是
nil (空)
boolean (布尔)
number (数字)
strring    (字符串)
table (表)
function (函数)
最后一种我就不说了,属于高级范畴,不是我能说明白的,有兴趣的可以自己去看看

nil就是空,他就表示空,在lua下 我们如果想删除一个全局变量,只要给他赋空值就可以了  例如 a = nil 这样就删除了变量a 删除数组也是一样的。

number,strring 这两形式没什么好说的,a = 123  b = "123"  这里的 a就是数字型 b 就是字符串型,好理解吧

table 这个是lua的重点,可以说lua玩的是table 能玩转table,你就是lua高能。既然说到这里了,那么就简单的深入下table的概念


             突然不知道怎么来表达这部分了,感觉要讲 明白这部分 要说的真是太庞大了,先留在这里吧



---------------------------------------------------------------------------------------------------------------------------------------


5# .
 楼主| 381676420 发表于 2016-1-22 04:13:16 | 只看该作者
本帖最后由 381676420 于 2016-1-23 16:53 编辑

这里原本想说说正则的,但是凭我这高中文凭,高考语文的作文冥思苦想40多分也没憋出来一个字的实力来看,真的没有办法用语言吧正则这个东西讲清楚,真心需要的朋友自己去网上找找正则的关系,肯定比我说的更好,这里发一段武林里,匹配精气的的正则,大家没事,试试抓取变量什么的把。。。。


^\s*【\s*精\s*气\s*】\s*(\d*)\/\s*(\d*)\s*\(.*\)$


另外说一下,100个人可能有100个正则写法,只要是对的就不要深究为什么这样写。。。

闲来无事,在网上翻翻看看,突然看到某人写的一篇自己学习mush的时的记录于心得,顿时膜拜了,对正则的部分,真是讲解的精辟,另人佩服。所以引用他的话,来补充自己的部分。。

正则一点都不难,不过复杂点的一次成功率很低,总得修改。


正则表达式描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
正则好像是计算机软件方面常用的东西,倒是非常适合写触发


先从简了,好入门。然后再系统地学习,慢慢提高。
\d  单个数字。
\w  单个字母。
\s  单个空格。
.    单个数字,字母,空格。
大写是相反的,\D非数字,\W非字母,\S非空格。
————————————————————————————
要匹配多个,后边加上说明就行。
? 0个或1个。
+  1个或多个。
*  0个或多个。
————————————————————————————
\d?=0个或1个数字。
\w+=1个或多个字母。
\s*=0个或多个空格。
.*=0个或多个数字,字母,空格。
————————————————————————————
()   引用。(\d+)写在别名触发里,就可以在下面引用了。
[]   范围。[1-3]匹配1,2,3。[13]匹配1,3。[1|3|5]匹配1,3,5。“|”是选择的意思。
{}  次数。5{3}匹配555。\d{5}匹配5个数。\s{2,5}匹配2-5个空格。
     ?={0,1}
     +={1}
     *={0,}
     后边不写范围,就是无穷大。
————————————————————————————
^   行首。
$   行尾。
\    还原。Zmud里好像是~。
     上边那么多字母符号有本来的意思,但是会被正则解读成另外的意思。加上\就还是原来的意思。
     \\=\。\*=*。\(\)=()。
————————————————————————————————————————————————————
以上为通配符,有点机器人基础的,都很好理解,这对于写mush触发的帮助很大。而且原作者对每个通配符的解释也很到位,就是这样的感觉,嗯。。。。怎么说呢,就是这样用的,没为什么呢。。记死了,就这么用。
4# .
 楼主| 381676420 发表于 2016-1-22 04:13:09 | 只看该作者
本帖最后由 381676420 于 2016-1-24 14:29 编辑

原本打算好好的将这篇教程结束,可是后来突然觉得,就算写的在精细,估计也没多少人看,就算看了,估计也没多少人愿意研究,所以现在决定,不必要的就不说了。就算是烂尾了把,嗯 现在网上流行这个。这个单章用来讲解下变量的抓取跟使用问题。特别注明,这个单章是为兰兰开的,因为他很需要了解这个问题。期盼他的 mush机器人早点问世,我准备坚决的当伸手党。。。。。开始。首先借用下北侠大神的代码,这个代码很能说明问题

test1 = "阿姨是最美的" --测试用字符串
test2 = 1314521  --测试用数字(注意前缀)
SetVariable ("test", "直接输入") --直接将字符串存入mush
SetVariable ("test", 521) --直接将数字存入mush,注意后一条命令,把前一条数据覆盖
SetVariable ("test1", test1) --将变量test1存入mush中的变量test1
print(GetVariable("test1")) -- 直接输出mush中变量test1的内容
SetVariable ("test1", test2) --注意,这后面是test2
print(GetVariable("test1")) -- 同上一个print()中的内容是一样的,但输出结果不同


一步一步说明,首先我们在脚本中 定义两个变量 test1,test2 注意没有任何注明的变量 就是全局变量,他在整个脚本中的任何地方出现,都是成立的。
我们将"阿姨是最美的”这个字符串赋给test1。 1314521赋给了test2注意,在这里的1314521没有加引号,表示他是变量类型是number。
接下来SetVariable()这个函数的作用是将脚本中的变量存入mush中。那么第一个SetVariable ("test", "直接输入")的意思就是在mush存一个名为”test“的变量,他的值是“直接输入” 注意在这里的test是有引号的,之前有提过为什么,这里就不多说明了。这个函数在被执行后,mush中就有了一个test名的函数,值也可以看到,但是整个过程还没有结束,脚本会一次性把上面这段代码全部解析了。那么我们来看第二句SetVariable ("test", 521),这一句执行后的结果是什么呢?没错,就是把上一句的内容替换了,此时mush下 test的值变成了521 并且test类型也变成了number,第三句是同理,在mush中存入一个名为test1的变量,他的值是“阿姨是最美的”,接下来们用GetVariable("test1")函数,他的意思是从mush中提取test1这个变量,print(GetVariable("test1"))整句的意思就是提取mush下test1的值,并输出在屏幕上 print同Note的作用是相似的。然后会有一个输出结果显示在屏幕上,接下来继续完成SetVariable ("test1", test2),这个函数执行后,原本mush中test1变量的值发生变化。在执行print(GetVariable("test1"))后,输出的结果也就完全不一样,虽然同样执行的一条函数,参数什么的都没变,但是输出结果完全不一样,大家可以复制代码自己测试下。对理解有帮助。


以上主要让大家认识了SetVariable()函数跟GetVariable()函数,他们的作用相信已经了解了。这是在使用触发器,配合脚本中,抓取使用变量最简单的方式。下面我们来看看实际的例子


触发里内容,之前已经讲过,这里不再细说,只是放图出来,大家看看。下面是运行结果


看到了吗?我说了两个不同的时间跟收益,测试结果分别显示在了屏幕上,惯例先看代码
function shouyi(time_fen,gold_1)
        local gold = gold_1
        local _time = time_fen
        Note("用了".._time.."分")
        Note("转到"..gold.."两黄金")
end

我定义了一个名为shouyi的函数,这个函数带有两个参数分别是time_fen,gold_1...在函数中我注明了局部变量gold,用来接收 gold_1的值,用局部变量_time接time_fen的值。这样就完成了变量的抓取,然后使用Note来测试抓取的结果,如图,完全没有问题。但是注意,这样抓取到的变量,是在脚本内的,在mush点开变量是找不到的。想要存在mush中,我没还需改改代码。上面已经明确的讲过了,有兴起的自己去测试下,并且显示在屏幕上吧。

同样的代码,我们来看


function shouyi(time_fen,gold_1)
        local gold = gold_1
        local _time = time_fen
        Note("用了".._time.."分")
        Note("转到"..gold.."两黄金")
        if gold < 100 and _time > 20 then
                Execute("say".." 阿姨绝对是最最最最最美丽的")
                else
                Execute("say".." Henry是最最最帅的")
        end
end

这段函数体内多了一个if else end语句,格式就是这样,作用就好比Zmud下#if 表达式 {} {} 是一样的,在这里我用到了关系表达式 and 他的意思就是和,也就是说 1 和 2 都成立是 表达式为true,一个不为真表达式就不为真。有和的关系当然就有或的关系,在lua中 或用 or 来表示,或关系是一个条件为真,表达式就为真。引用zmud 下的例子来说 上边这个 if语句就等于  #if (@gold<100 and @_time>20) {say 阿姨绝对是最最最最最美丽的} {say  Henry是最最最帅的},有这个对比,兰兰你在看不懂,你就没脸见人了。
简单的介绍了下lua下的判断表达式,现在重点是,大家觉得这段代码可以正常运行吗? 想学习的朋友先别往下看,自己脑子想想,这对以后制作机器人有很大的帮助。















————————————————我是苦逼的等待线———————————————



等了这么久了,我给出图片结果

看到这个结果,很多人都蒙圈了把,明明两个变量的值,都可以正常的显示出来,可为什么接下来的if判断就出错了呢?有想明白的朋友么?

这里告诉大家,我们在抓取这两个变量的触发里,是不是有shouyi("%1","%2")呢?在匹配抓取的时候,我们的%1,%2都是带引号的,也就是说,我们抓取回来的是字符串,而不是一个数字。然后再if 语句中,我们判断表达式的时候,是用的gold < 100 and _time > 20 到这里到家应该明吧了把,简单的例子就是 你好吗 < 100 这个判断,相信在不附加条件的情况下,永远是不可能成立的,然后再lua下,这不仅仅是成立的问题,而是错误。这样的错误lua 是不能执行的。所以代码的后半部分是错误的,那么应该怎么解决呢?看代码
function shouyi(time_fen,gold_1)
        local gold = tonumber(gold_1)
        local _time = tonumber(time_fen)
        Note("用了".._time.."分")
        Note("转到"..gold.."两黄金")
        if gold < 100 and _time > 20 then
                Execute("say".." 阿姨绝对是最最最最最美丽的")
                else
                Execute("say".." Henry是最最最帅的")
        end
end

整个代码中,我这在gold_1 和 time_fen 前面加了tonumber()函数,运行结果如下


一个简单的函数,导致完全不同的运行结果,tonumber()函数的作用是,把字符串转换成数字。同样也有把数字转换成字符串的函数是tostring()
一定要养成良好的习惯,在使用变量值得时候,一定要确定他是什么,实在不确定,但是要进行判断的时候的时候,都加上转换函数,是完全没有问题的,而且避免出错。

抓取变量的方式还有很多种,个人认为最简单的就是这种了把。还有一些方式,以后要是遇到了,会在说明吧,还有以后么,真心不知道啊
当然了最简单的方法就是直接在发送里写SetVariable("gold",%1)  SetVariable("time_",%2)了,可以自己去测试下。



                                        兰兰你看懂了么?????












3# .
 楼主| 381676420 发表于 2016-1-22 04:13:02 | 只看该作者
本帖最后由 381676420 于 2016-1-22 22:27 编辑

3楼最后的那个问题,相信大家已经看出来了,没错。触发不了。为什么呢,因为那样的匹配,mush不认识。所以我们要把他改改。看图
相信大家都看到了,这里跟上面有很大其别,尤其是红色箭头部分,正则表达式别勾选了,那么触发行内,就要已正则的形式来匹配
^\s+岁月如歌兰帮主\s+星宿派第二代传人\s+全宜人\(iqib\)$ 这就是匹配的部分,现在来简单说明下
^表示从这行的头开始(跟mud一样),   \s+ 表示此处出现过至少一次或者更多次的空格\s表示空格
\(  这个是用来匹配 ( 的 \号在这里作为转义符出现,相信有Zmud机器人基础的朋友都不难理解,$这个表示到此为止
这样一来一个简单的正则就算完成了。大家可以试试自己去匹配匹配。然后看下面的结果



是不是每当我Look这个地方的时候都能看到这个货,然后每次触发器都起作用了呢。。相信细心的人一定会发现一个问题,在这个例子中(iqib)就是整个触发的结尾了,有的朋友肯定发现了,有的时候玩家名字最后会出现<发呆中>的描述,如果有,那么上面的触发还能实现么?当然是能的,因为$符号明确的告诉了mush,到这里为止,之前的都是给你用来触发的,之后的咱们就不管了。
有关正则的部分,后面开单层说明。

下面我们通过例子,来说明脚本的建立跟使用。

还是这张图,用来说明建立脚本,如图可以看到 脚本文件的后面有个新建,大家点击这里,然后输入一个文件名,点确定就可以为自己创建一个脚本了,当然创建之前需要选择语言,lua语言,只要在能打字的环境下,都是可以实现的。图上我有lua语言编辑器,所以我选择了,大家要是没用的话,只需要在使用记事本编辑脚本前面打勾就可以了,一样可以完成编辑工作,这些都完成了,点击编辑脚本就可以进入到脚本的编辑中,说简单了,就是在一个记事本中打字。只不过打的内容是lua语言。下面我来看最最简单的例子。


上面的图中,匹配的内容没有任何变化,但是发送中变成了 kk() 然后发送到变成了脚本解析器。一个个来说明
首先发送到脚本解析器是因为kk()这个函数 是在脚本中定义好的函数。
我们来说说KK(),先放出代码
function kk()      --function是lua语言下的关键字,整段的意思表示建立一个名为KK,没有参数的函数
        Execute("hi")   --Execute()这个函数是mush的扩展函数,意思是发送命令到命令解析器。
end                         --end用来作为一个语句块的结尾标志。


这里来简单的说明下lua。从 fun开始一直到end,就是lua下一个最简单的语句块。他表示建立一个kk()函数,函数的内容是,立即发送hi到命令解析器。
细心的朋友一定有注意到了,这里的hi是被双引号引起来的。没错,这就是lua的要求(我这么说可能不准确,但是为了让大家别有那么多歧义,你们只要记住就可以了),Lua中带""的,会被视为字符串;不带""的数字,会被视为数字;而不带""的非数字,都会被视为变量。这个很重要,不需要明白,只需要死记就好。

下面我们在来看一个例子

看到上面的匹配内容是不是发送了变化,原来的\(iqib\) 变成了现在的 \((.*)\) 首先说明下(.*)的作用 .*表示无论这里边是什么就好比mud下的* (.*)用小括号括起来表示,我要抓起里面被.*匹配到的任何东西,这里也跟 Zmud里是一样的,大家是不是很好理解。写法不同,但是表达的意思是一样的,效果也是一样的,这里简单的提了下mush 中抓取变量的问题,在这里我不想详细说明,大家只要知道就可以了
来看send的内容 kk1("%1"),这有什么意思呢,相信有的人已经看出来,先来运行结果


现在放出代码,结合上图一起说明,代码如下:
kk1 = function(name) --这里function的()里有一个name,这个是参数,此参数名可以任意定义。
        Note(name)      --这里是把name的内容显示在屏幕上,仅仅是显示,类似zmud下#sh @name
        local a = string.lower(name)    --这里用到了local这个关键字还有srting.lower()这个字符串函数
        Execute("ask "..a.." about all")  --有没有人注意到ask后面其实还有个空格呢,没错""号中的空格,一样会被当成字符串
        end

在这个函数体中,是不是比第一个例子又多出了些东西,而且结构有些不一样呢?我们来一一说明下
第一个例子中建立函数用的 function kk(), 现在变成了kk1 = function(name) 这两个看起来有点区别,但是他们的区别之是在于一个是无参数的,一个是有参数的 name就是kk1的参数。同样的这里 function kk1(name) 的结构,跟kk1 = function(name)  所表达意思完全一样。带参数的函数是什么,以后开单章专门简单介绍lua的时候,在说明吧,这里大家只要知道name是一个参数就好了。

Note(name)的作用就是大家在图中看到的蓝色iqib。。。Note的作用就是在屏幕上输出。这里的参数name被赋了"iqib"这个值。可以理解吧。
然后local这个是lua中的关键字,表示注明一个变量为局部变量,局部变量的好处是,只在注明的函数体内起作用,出了函数体就完全失效了。多使用局部变量可以大大提高运算速度。这里也是简单介绍,以后再说, local a = string.lower(name) 这句话完整的意思就是,注明一个变量名为a的变量,他只在kk1(name)函数体内有效,把string.lower(name)的值赋给a。。好理解吧
现在我们来看string.lower(name),这里的string.lower()函数,是lua下自带的字符串函数,他的作用是将 name中储存的字符串全部换成小写。类似于 ZMUD中的%lower()。大家肯定看出了,在这个例子中,我们完全没有必要用到这个大写换小写的函数,没错,是这样的,因为抓取回来的字符串本身就是小写的,我在这里用到,也只是多引个函数出来罢了,这里也完全可以写成 local a = name  运行结果不会发生变化的。
来看Execute后的内容,前面我们已经知道了这个函数的作用,那么现在我们主要说明下后面,首先看到"ask "注意ask后面有空格,这是告诉lua ask加空格作为一个字符串,".."两个点的符号在lua中是连接符,a 是一个变量,所以不能加""号,不然lua会认为他也是个字符串,将不会引用a中的值。
这个部分的最后写法就是"ask "..a.." about all"(注意这里about前也有空格) 执行的结果就是ask iqib about all  当然了在武林中about是可以省略的,这里改成"ask "..a.." all"执行结果完全不变。。。

累死了,这一部分就到这里吧,有什么疑问或者需要可以 Q我。。。


PS:这里有点需要补充,在mush下,经常接收到的的行,最前面都会有个>,我们在制作机器人的时候,要养成好的习惯,可以把他也放进匹配了去,避免触发器不工作的情况。所以每个触发都使用正则的好处就显示出来了。

2# .
 楼主| 381676420 发表于 2016-1-22 04:12:53 | 只看该作者
本帖最后由 381676420 于 2016-1-22 22:19 编辑

2楼的内容大家看后,就应该对mush的触发有了一定的了解,那么下来,我们就来看实际的例子。废话少说,看图
如上图,我自己使用say 这里是兰兰的聊天室  作为一次匹配,下面的命令是先Look这里,然后hi iqib
注意红圈内的选择,我只选择了启用,其他一概没选,红色箭头中,我选择发送的位置是命令解析器,2楼的时候,我们就教过,只要不是发送脚本的,通常我们都发送到这里。下面我们来看执行的结果。

一目了然是不是,上面的框内,是我的触发器触发到那句话的以后所执行的命令,下面的红框就是结果。没错,到这里,一个mush下最简单的触发,就完成了,大家觉得跟Zmud有什么区别吗?除了那个发送到?是不是很简单。接下来我们用其他例子,来讲解下别的东西,出境人还是iqib,(请评价导师iqihz,命令是pingjia iqihz。别问我为什么,这么输了点回车就对了,兰兰出境费跟广告费抵消了啊)
继续看图

我用看到这个人,作为触发,然后发送hi,想要达到的效果就是每次看到这个货,都hi一下。大家可以先用心看看。在自己心里想一下,这样的触发能不能被实现,跟上面的例子有什么不同。


1# .
 楼主| 381676420 发表于 2016-1-22 04:12:46 | 只看该作者
本帖最后由 381676420 于 2016-1-22 22:12 编辑

中午好,我总算起来了,那么我们就继续,由于我也是突然兴起才写这个东西,没有过多的安排跟思考,可能内容比较凌乱,不过大家看懂了就可以。之前我们用很大的篇幅明确的讲解了mush的设置,那么接下来我们就要进入最核心的问题,怎么样使用mush制作自己的机器人呢?在此之前我先要告诉大家一个概念,很多人都觉得mush难,要用到计算机语言才可能完成一个机器人,其实这样的想法是很错误的,严格的说使用了语言可以完成强大复杂的机器人制作,而不是用语言,我们一样可以制作出机器人。这之前先讲讲一个很重要的东西,先看图吧

点开游戏设定,点击红框内的选项,就是进入触发器的界面,在进入界面之后,点击篮筐内的“添加”就可以新建立一个触发了。

点击新建以后,会弹出这样的窗口,这里就是完成触发的地方。在这里黄色的位置就是你要匹配的语句,蓝色部分就是你要发送的命令。黑色框包含的部分,序号:(这里默认是100)这个的作用是调整触发的优先级别,假如两个触发,一个是99 一个是100,那么mush在匹配到这俩句话后,后根据优先级的不同来执行命令,这里不多说,一般都是100没有问题。数字越小优先级越高。名称:是这个触发自己的名字,填写的好处是可以随时单独控制。组名:就是zmud下的 class (类)同样是控制开关使用的。可以使用函数一次性关闭或者打开一组名为相同的触发,就好比Zmud下#t+ #t-的作用,在mush下我们使用EnableGroup(组名,true/false)函数来控制类,例子:
EnableGroup("quest",true)    --这里表示开启quest这类名字的全部触发
EnableGroup("quest",false)   --这里表示关闭quest这类名字的全部触发
不要问为什么是true/false,只需要记住true是开false是关就可以了。我们本着实用性,而不是探求真理。。。
这里注意下在quest作为EnableGroup()函数参数的时候,我使用了""号,这里一定要记住,后面在涉及到更多的lua语法时,我在仔细说。总之记住必须这样用。
差点忘记了,EnableGroup()函数不仅仅是针对触发,同样对别名跟计时器是一样有效的,假如你有一组名为quest的别名,那么上面例子的函数,就不是关闭触发类,而是关闭别名类了,计时器是同样的道理,很好理解,大家记住就可以了。
尼玛mush讲起来就是很复杂,大爷的。还要在强调下,EnableGroup()这个函数是Mush自带的通用扩展函数,不是计算机语言下的函数。这个能分辨就好,不需要理解。mush下自带了很多通用扩展函数,还有为lua语言专门的扩展函数,这是为什么推荐使用lua语言的原因。如有需要大家可以去网上找找有没有mush的扩展函数表,实在找不到,可以群里小窗口我,如果后文中出现mush自带的扩展函数,我会尽量注明,如果忘记了,那么就没办法了,我脑子不好。
下面我们着重说下左边第一个红框里的内容:
启用  允许使用这个触发器。【这个没什么好说的。字面意思】
不区分大小写  匹配触发器的时候不区分大小写。【同上】
不记录到记录文件中  不在记录文件中记录被匹配的行。【同上,一般都不会选择】
不显示匹配行  不在输出窗口显示被匹配的行。【同上】
保持有效性  默认情况下,当一行文字和一个触发器匹配后,这行文字不会再尝试匹配其它的触发器,也就是说一行文字最多只能匹配一个触发器。如果选择了这项,这行文字就会在所有触发器中尝试匹配。这样就可以让一行文字同时匹配多个触发器。【同上】
正则表达式  选择这项后,触发器将会被作为一个正则表达式处理。【正则,我们在后面说,因为太复杂,我需要想想】
允许一行匹配多次  如果选择了这项,同一行文字可以多次匹配这个触发器。例如,假如一行文字中有多个你想匹配的单词,如果不选这项,只有第一个匹配的单词会触发这个触发器。反之,则每个单词都会匹配这个触发器。
展开变量  发送命令时展开命令中的变量。命令中的变量以“@”开始,后面跟着变量的名称。选中这项后,如果要在发送命令中使用“@”字符,你必须用“@@”代替。【这里貌似只使用一个@号,也是可以发送的。大家不妨试试看】
临时触发器  如果选择了这项,这个触发器不会保存到配置文件中。也就是说它仅在当前游戏会话中有效,游戏关闭时这个触发器会被自动删除 。
多行匹配  触发器默认只能匹配一行,选择这项后就可以匹配多行,同时你还必须设置这个触发器匹配的行数。这里的行是逻辑行,是服务器传送过来的行,而不是你在输出窗口看到的行。也就是说如果一行的文字太长,在输出窗口呈两行或者更多行显示,它仍然算一行。
  使用多行匹配必须选择“正则表达式”选项。【在这里我不建议大家使用多行匹配,个人觉得一点求用都没有,特殊情况例外】
  多行匹配的局限性:
  • 触发器匹配的行数越多,性能就越低。
  • 要使用多行触发器,必须先启用“正则表达式”,因为普通方式无法匹配一个换行符。
  • 因为实现方式的不同,使用了多行触发器就不能启用其它一些功能(例如,改变颜色,不在输出窗口中显示匹配行,不纪录到记录文件中)。
  • 即使前一个触发器(普通触发器,设置了“保持有效性”)选择了不显示匹配行,这一行信息仍然会被后面的多行触发器使用。
这上面的东西,大家作为了解就好,最有用的就是启用跟正则表达式了,其他的不会经常性用到。


接下来是重点,大家一定要看明白了,不然整个触发都不可能被实现。相信大家都看到了,mush下的触发有一个十分特别的地方,那就是发送给:这个发送给下有很多的选项分别是
  • 游戏 (MUD 服务器)--这里就像zmud下直接发送给了服务器一样,但是有区别,这里了解就好。
  • 命令窗口 (显示在命令窗口中)--这里只是把命令显示在了你的命令窗口中,但是不发送给服务器。
  • 输出窗口 (显示在输出窗口中,就像使用 Note 函数显示注释一样)--[[这里的显示会把命令显示在游戏窗口中,但是注意,仅仅是显示,他没有经过mud的服务器,所以不会被执行,类似 Zmud下#sh eat liang--]]
  • 状态栏 (显示在状态栏上)--  一目了然的东西就不说了
  • 记事本 - 新建 (创建一个新的记事本窗口并把发送内容添加进去)   --很少用到的也不会说了
  • 记事本 - 追加 (把发送内容添加到现有记事本窗口的最后面)   --很少用到的也不会说了
  • 记录文件 (把发送内容直接添加到记录文件中)      --很少用到的也不会说了
  • 记事本 - 替换 (把现有记事本中窗口的内容用发送内容替换掉)  --很少用到的也不会说了
  • 游戏 - 命令队列 (把发送内容添加到命令队列中,队列的时间间隔可以在“命令”配置对话框中设置)-- 字面意思,而且不常用
  • 变量 (把发送内容赋值给一个变量,必须在变量框中输入变量的名称)--这里我们放下在面说。
  • 命令解析器 - 执行 (通过命令解析器执行,这是发送内容中可以包含别名、快速行走等等)--[[这里是最长用到的,只要不是发送给脚本的,我们一般都选择发送到这里,记住我说的只要不是...都...大家这么用就好了--]]
  • 快速行走 (把发送内容作为快速行走的路径来执行)--原本是很用的,但是由于武林里有坐骑,还有高科技的定位仪器,这玩意就废了。
  • 脚本解析器 (把发送内容作为脚本命令来执行)--最为重要的,只要使用了mush下的扩展函数,都要发送到这里,我们后面看。
  • 游戏 - 立即发送 (把发送内容立即发送给服务器,不管当前队列中是否有命令) --区别于命令列队的。
上面的东西很重要,理解能力强的朋友注解可以不看,另外机器人制作中另外两个常用到的东西(Timers,Alias)也有发送到这个选项,用法是一样的,后面遇到,我就不重复说明了。
想了想,还是对以上内容做部分补充说明吧,上面讲到的EnableGroup()函数,有点太过简单,这里补充说明下
EnableTriggerGroup()---这个函数是不是跟上面的很想,没错。这个是针对性更强的函数,只能针对触发
EnableTimerGroup()---同理这个只能针对定时器
EnableAliasGroup()  ---只能针对别名
用法都是一样的("组名",true/false)...还有一些有联系的函数,我在这里一并给出
DeleteGroup(“组名")--这个函数只有一个参数,故名思议删除一组名为""的触发 别名 定时器。跟上面的函数一样,有这样的广义删除,那么也有针对的
DeleteTriggerGroup() --删除触发组名
DeleteTimerGroup() ---删除定时器组名
DeleteAliasGroup()---删除别名组名

尼玛的,这稍微补充下就说不完了,下面还有,大家看
DeleteTrigger("触发器名") -- 这里说明下,这里是触发器的名字,而不是组名,
EnableTrigger("触发器名",true/false)--- 同样的,这里是开启关闭触发器名字,而不是组名,

有删除自然有添加

AddTrigger() --这个函数带有很多的参数,这里我不多做说明了,有表可以查的。

Delete还对应有Timer/Alias,这些都跟上面是同理,注意参数的使用就好。Add也是一样,要把这些都一一说完,我觉得是不可能完成的任务




这层就盖到这里吧。。。


Archiver|武林MUD资料站 ( 鲁ICP备17038480号 本站关键词:mud 武林mud mud游戏 文字mud

GMT+8, 2024-11-24 12:54

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表