mudlet机器人脚本开发基础:Lua语言入门

从目前mud游戏客户端的情况来说,发展前景比较好的应该是tintin++和mudlet了,tintin++的机器人和大家熟悉的zmud比较类似,上手非常简单,只是tintin++没有UI,纯命令行,功能强大,但新手不习惯。而mudlet是GUI的客户端,只是界面操作和大家熟悉的zMud不太一样。

在mudlet中只通过匹配触发,也可以做机器人,但是有一些功能必须用脚本,而mudlet中脚本语言是lua,所以这里先学学lua基础。

注意,可以直接在mudlet中用命令行测试脚本,如:lua print("lua输出")。其中lua是mudlet定义的一个别名,print是lua语言中的输出函数。

Lua基础语法

内容参考自:https://www.runoob.com/lua/lua-tutorial.html

注释

单行注释用--(两个减号),如:

--这是Lua脚本中的注释

多行注释用--[[ 注释内容 --]],如:

--[[
 多行注释
 多行注释
--]]

标示符

标示符是用来定义变量的,Lua语言中变量和C语言一样,只能用大小写英文字母、阿拉伯数字和下划线_,变量首字符不能是数字。

关键词

以下列出了 Lua 的保留关键词。保留关键字不能作为常量或变量或其他用户自定义标示符:

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

变量

Lua 变量有三种类型:全局变量、局部变量、表中的域。

Lua 中的变量全是全局变量,哪怕是语句块或是函数里,除非用 local 显式声明为局部变量。

全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。

如果你想删除一个全局变量,只需要将变量赋值为nil。

局部变量的作用域为从声明位置开始到所在语句块结束,访问局部变量的速度比全局变量更快。

数据类型

Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

Lua 中有 8 个基本类型分别为:nilbooleannumberstringuserdatafunctionthreadtable

类型 描述
nil 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。
boolean 包含两个值:false和true。
number 表示双精度类型的实浮点数
string 字符串由一对双引号或单引号来表示
function 由 C 或 Lua 编写的函数
userdata 表示任意存储在变量中的C数据结构
thread 表示执行的独立线路,用于执行协同程序
table Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。

nil

对于全局变量和 table,nil 还有一个"删除"作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉。

Lua 把 falsenil 看作是 false,其他的都为 true数字 0 也是 true

string

字符串由一对双引号或单引号来表示。也可以用 2 个方括号 "[[]]" 来表示"一块"字符串。如:

html = [[
<html>
<head></head>
<body>
    <a href="https://www.mud.ren/">MudRen</a>
</body>
</html>
]]
print(html)

结果输出:

<html>
<head></head>
<body>
    <a href="https://www.mud.ren/">MudRen</a>
</body>
</html>

使用 # 来计算字符串的长度,放在字符串前面,如print(#"abc")返回3。

table

表(table)是Lua语言中唯一的数据结构,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表:

-- 创建一个空的 table
local tbl1 = {}

-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"}

Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。

a = {}
a["key"] = "value"
key = 10
a[key] = 22
a[key] = a[key] + 11
for k, v in pairs(a) do
    print(k .. " : " .. v)
end

结果输出:

key : value
10 : 33

不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始

local tbl = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl) do
    print("Key", key)
end

结果输出:

Key    1
Key    2
Key    3
Key    4

table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。

function

在 Lua 中,函数的定位和Javascript语言一样是一等公民,被看作是"第一类值(First-Class Value)",地位和其它变量一样,函数可以存在变量里:

function factorial1(n)
    if n == 0 then
        return 1
    else
        return n * factorial1(n - 1)
    end
end
print(factorial1(5))
factorial2 = factorial1
print(factorial2(5))

输出结果:

120
120

function 可以以匿名函数(anonymous function)的方式通过参数传递:

function testFun(tab,fun)
        for k ,v in pairs(tab) do
                print(fun(k,v));
        end
end

tab={key1="val1",key2="val2"};
testFun(tab,
function(key,val)--匿名函数
        return key.."="..val;
end
);

输出结果:

key1 = val1
key2 = val2

Lua 运算符

运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。Lua提供了以下几种运算符类型:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 其他运算符

算术运算符

下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为10,B 的值为 20:

操作符 描述 实例
+ 加法 A + B 输出结果 30
- 减法 A - B 输出结果 -10
* 乘法 A * B 输出结果 200
/ 除法 B / A 输出结果 2
% 取余 B % A 输出结果 0
^ 乘幂 A^2 输出结果 100
- 负号 -A 输出结果 -10

关系运算符

下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为10,B 的值为 20:

操作符 描述 实例
== 等于,检测两个值是否相等,相等返回 true,否则返回 false (A == B) 为 false。
~= 不等于,检测两个值是否相等,不相等返回 true,否则返回 false (A ~= B) 为 true。
> 大于,如果左边的值大于右边的值,返回 true,否则返回 false (A > B) 为 false。
< 小于,如果左边的值大于右边的值,返回 false,否则返回 true (A < B) 为 true。
>= 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false (A >= B) 返回 false。
<= 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false (A <= B) 返回 true。

逻辑运算符

下表列出了 Lua 语言中的常用逻辑运算符,设定 A 的值为 true,B 的值为 false:

操作符 描述 实例
and 逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。 (A and B) 为 false。
or 逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。 (A or B) 为 true。
not 逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。 not(A and B) 为 true。

其他运算符

下表列出了 Lua 语言中的连接运算符与计算表或字符串长度的运算符:

操作符 描述 实例
.. 连接两个字符串 a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。
# 一元运算符,返回字符串或表的长度。 #"Hello" 返回 5

运算符优先级

从高到低的顺序:

^
not    - (unary)
*      /       %
+      -
..
<      >      <=     >=     ~=     ==
and
or

赋值语句

赋值是改变一个变量的值和改变表域的最基本的方法。

Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。

a, b = 10, 20       -- a=10; b=20

遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值:

x, y = y, x         -- swap 'x' for 'y'

Lua 循环

Lua 语言提供了以下几种循环处理方式:

循环类型 描述
while 循环 在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
for 循环 重复执行指定语句,重复次数可在 for 语句中控制。
repeat...until 重复执行循环,直到 指定的条件为真时为止
循环嵌套 可以在循环内嵌套一个或多个循环语句(while do ... end;for ... do ... end;repeat ... until;)

while 循环

Lua 编程语言中 while 循环语句在判断条件为 true 时会重复执行循环体语句。

Lua 编程语言中 while 循环语法:

while(condition)
do
   statements
end

for 循环

Lua 编程语言中 for 循环语句可以重复执行指定语句,重复次数可在 for 语句中控制。

Lua 编程语言中 for语句有两大类::

  • 数值for循环
  • 泛型for循环

Lua 编程语言中数值 for 循环语法格式:

for var=exp1,exp2,exp3 do  
    <执行体>  
end  

泛型 for 循环通过一个迭代器函数ipairs来遍历所有值,类似 java 中的 foreach 语句。

Lua 编程语言中泛型 for 循环语法格式:

--打印数组a的所有值  
a = {"one", "two", "three"}
for i, v in ipairs(a) do
    print(i, v)
end 

i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。

repeat...until

Lua 编程语言中 repeat...until 循环语句不同于 for 和 while循环,for 和 while 循环的条件语句在当前循环执行开始时判断,而 repeat...until 循环的条件语句在当前循环结束后判断。

Lua 编程语言中 repeat...until 循环语法格式:

repeat
   statements
until( condition )

循环控制语句

Lua 支持以下循环控制语句:

控制语句 描述
break 语句 退出当前循环或语句,并开始脚本执行紧接着的语句。
goto 语句 将程序的控制点转移到一个标签处。

Lua 语言中的 goto 语句允许将控制流程无条件地转到被标记的语句处。

语法格式如下所示:

goto Label

Label 的格式为:

:: Label ::

请注意:mudlet中不支持goto

Lua 流程控制

Lua 提供了以下控制结构语句:

语句 描述
if 语句 if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。
if...else 语句 if 语句 可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码。
if 嵌套语句 你可以在if 或 else if中使用一个或多个 if 或 else if 语句 。

Lua if 语句

Lua if 语句由一个布尔表达式作为条件判断,其后紧跟其他语句组成。

Lua if 语句语法格式如下:

if(布尔表达式)
then
   --[ 在布尔表达式为 true 时执行的语句 --]
end

if...else 语句

Lua if 语句可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码块。

Lua if...else 语句语法格式如下:

if(布尔表达式)
then
   --[ 布尔表达式为 true 时执行该语句块 --]
else
   --[ 布尔表达式为 false 时执行该语句块 --]
end

Lua if 语句允许嵌套, 这就意味着你可以在一个 if 或 else if 语句中插入其他的 if 或 else if 语句。

Lua if 嵌套语句语法格式如下:

if( 布尔表达式 1)
then
   --[ 布尔表达式 1 为 true 时执行该语句块 --]
   if(布尔表达式 2)
   then
      --[ 布尔表达式 2 为 true 时执行该语句块 --]
   end
end

你可以用同样的方式嵌套 else if...else 语句。

Lua 函数

Lua 编程语言函数定义格式如下:

optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
    function_body
    return result_params_comma_separated
end

解析:

  • optional_function_scope: 该参数是可选的制定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。
  • function_name: 指定函数名称。
  • argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
  • function_body: 函数体,函数中需要执行的代码语句块。
  • result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。

注意:Lua函数可以返回多个结果值,比如string.find,其返回匹配串"开始和结束的下标"(如果不存在匹配串返回nil)。

s, e = string.find("bbs.mud.ren", "mud") 
print(s, e)

返回值:5 7

Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数。

function add(...)  
local s = 0  
  for i, v in ipairs{...} do   --> {...} 表示一个由所有变长参数构成的数组  
    s = s + v  
  end  
  return s  
end  
print(add(3,4,5,6,7))  --->25

function average(...)
   result = 0
   local arg={...}    --> arg 为一个表,局部变量
   for i,v in ipairs(arg) do
      result = result + v
   end
   print("总共传入 " .. #arg .. " 个数")
   return result/#arg
end

print("平均值为",average(10,5,3,4,5,6))

有时候我们可能需要几个固定参数加上可变参数,固定参数必须放在变长参数之前。

我们也可以通过 select("#",...) 来获取可变参数的数量。通常在遍历变长参数的时候只需要使用 {…},然而变长参数可能会包含一些 nil,那么就可以用 select 函数来访问变长参数了:select('#', …) 或者 select(n, …)

  • select('#', …) 返回可变参数的长度。
  • select(n, …) 用于返回从起点 n 开始到结束位置的所有参数列表。

调用 select 时,必须传入一个固定实参 selector(选择开关) 和一系列变长参数。如果 selector 为数字 n,那么 select 返回参数列表中从索引 n 开始到结束位置的所有参数列表,否则只能为字符串 '#',这样 select 返回变长参数的总数。

京ICP备13031296号-4