[打印本页]
【超级宏官方教程】【第三部分:进阶教程】【作者团联合撰写】
作者: 无色幽明    时间: 2014-03-23 14:15

标题: 【超级宏官方教程】【第三部分:进阶教程】【作者团联合撰写】

把你的宏推向新的境界!
当你写宏写到一定程度的时候,你将会需要更强大的功能和更高级的编程技术,以便更能精确的解决各种问题。
在之前,碍于各种功能限制,宏一直以来都只能满足基本循环而做不到极限循环和各种辅助,但是超级宏一些强大的功能足以让你用专业的编程态度去处理宏,打开PVE宏新的一页。

宏,从此不再是小打小闹的玩意儿。

如何写一个更高级的宏?
写宏最需要以及最重要的东西可以归纳为就两件事:
1. 宏本身的功能,此为硬性需求
2. 你的编程技术,此为软性需求

硬性需求和软性需求的重要性
用一个简单的例子来说明
如果你有很强大的驾驶技术但是没有车或者只有老爷车,那你也成就不了什么东西
而如果你有一流的跑车,但是很渣的驾驶技术,你不只成就不了任何东西,你甚至还会闹车祸搞出人命

硬性需求就好比跑车的品质,而软性需求就好比驾车的技术
必须要两者都满足才可以达到更高的境界,好刀配名士,缺一不可

此教程所准备的硬性技术以及软性技术硬性技术
为了能让写手们更快上手,我们准备了各种高级功能的教程,也包括了硬性的和软性的,都是由经验丰富的宏手写的

硬性技术教程有:
1. if 功能
2. 变量与自定义变量
3. nowtime功能

软性技术教程有:
1. 逻辑运算基础
2. 宏控制
3. 时间控制
4. 表达式优化

硬性的东西很容易掌握,但是软性的东西却不,这好比跑车可以量产,但是驾驶技术好的人却不能量产
所以软性的东西很多时候都得靠你自己,当然也不代表我们无从指导,不然的话也就不会有这个教程
而有时候,是掌握了更高级的硬性技术后,更好的软性技巧也会自然而然学会
就好像一辆跑车如果具备了更先进的控制系统,那么你就可以用锻炼出更犀利的转弯和刹车技术
所以硬性东西也可以造就软性东西的进步,电脑也是如此,有了更强大的硬件才能刺激画面更强大的游戏的发展

编程就如同人类的其他技艺一样,是无止境的,唯有不停的努力才可以一直创造出新的高峰

希望你们有朝一日也可以成为一流的作者,深刻体会到写宏的乐趣,共勉之


第一节:逻辑运算基础插件基础逻辑运算及逻辑结构分析
插件的逻辑运算,主要是根据lua的规则编写而成。lua的逻辑运算相当方便,使用lua的逻辑运算写宏,相当的方便。
所有这些在编写过程中并不区分字母大小写。
例如:
/Cast [life<0.3]无相诀
意思就是:如果“生命值比例小于0.3”,则释放技能“无相诀”
一般来说“中括号”里面的都属于逻辑判断的内容!
而无需判断,直接省略判断语句即可!
例如:
/Cast 无相诀
完全省略了判断语句,无需判断即能释放!
1.真假判断
在插件中,只有 false 会被判断为假,其他全部会被判断为真。
例:
/skill [fight ] 后撤
上例的意思 ,如果在战斗状态, 则释放后撤技能
2.分句间的“且”“或”逻辑运算
例句1:
/Cast [fight,life<0.3]无相诀
其中逗号,是“且”运算,表示多个条件都成立
该句的意思是:如果“战斗状态中”并且“生命值比小于0.3”,则释放技能“无相诀”
例句2:
/Cast [life<0.5 ; mana<0.5]徐如林
其中分号,是“或”运算,表示多个条件其中之一成立
这句的意思是:如果“生命值比小于0.5” 或者 “内力值比小于0.5”,则释放技能“徐如林”
例句3:
/print [fight , tar, ota]
/print [life <1; mana<1 ; buff:擒龙诀]
第一句,是连续三个判断,做“且”运算. 从左到右, 如果遇到值为false的,该判断的返回结果就是false(假). 否则会返回最后一个判断的值
如果[在战斗状态][又存在目标][自身又在读条] 则会返回 [ota]的值,即自身的运功进度。
第二句,连续三个判断,做“或”运算. 从左到右, 如果遇到值为真的 ,就会返回该判断的值, 否则会返回false(假,也是最后一个判断的值)
如果 life<1 为假 , mana<1为真 ,则会返回mana<1的值,即true(真) , 最后一个判断根本不会进行判断。
对于某些较为复杂的语句如何理解呢?
例:
/cast [buff: aaa>2 & bbb | ccc & ddd<3 ] 技能x
看起来是不是好复杂!不用怕,教你如何分解
可以看出来句子中,冒号后面的,用“&”“|”拆分后有4个部分
“aaa>2”、“bbb”、“ccc”、“ddd<3”
把这四个部分分别接上都前面的内容“buff:”,再将“&”换成逗号,将“|”换成分号,即:
[buff:aaa>2 , buff:bbb ; buff:ccc , buff:ddd<3]
就变成几个小短句了!就变成我们最熟悉的内容了!
相信你一定很容易就能掌握了!
3.关于优先级
例句:
/Cast [fight,life<0.3 ; nofight,mana<0.3] 技能x
中括号的内容如何理解?
根据优先级,“或”运算(分号)的优先级 低于 “且”运算(逗号)的优先级
为了便于理解,用小括号分解中括号的内容即是:
[(fight,life<0.3) ; (nofight,mana<0.3)]
优先级高的逗号先结合,就给他加个括号!
意思就是:如果(fight,life<0.3)或者(nofight,mana<0.3),则释放技能“技能x”
是不是很容易嘛!
关于详细的运算优先级,请参见命令文档。
4.其他的运算
除了最基本的或且运算外,超级宏还提供了非运算、大小比较运算、数字五则运算等,
在使用的过程中,注意他们的优先级,弄不明白,可以用前面提到的加括号方法来整理语句,以便理解与运用!
同时,括号可以改变默认的结合优先级,更方便的写成想要的内容!
5. if 结构
插件支持标准的IF 结构,支持多层嵌套
例:
/if [fight]
/skill 后撤
/else
/skill 蹑云逐月
/end
上句的意思是: 如果在战斗状态,则释放 [后撤] ,否则释放[蹑云逐月]。
6. 用 ”或” ”且” 结构模拟 if 结构
/if [fight]
/var [life] v_a
/else
/var [mana]v_a
/end
上句用到了自定义变量的结构.(详细请参加其他说明文档),
代码的意思就是 如果战斗状态, 则赋值v_a为生命值 ,否则赋值为内力值。
我们可以用逻辑运算来模拟这句代码的意思:
/var [fight , life ; mana] v_a
这句的意思跟上句是一模一样的。
因为根据,插件的运算规则 ,对[fight , life ; mana]进行判断, 由于“且”的结合优先级比“或”高,他就等同于[(fight , life) ; mana]
这样就类似两个分句的或运算,即(fight , life) 或 mana, 由于上面的例子讲到,或运算,返回遇到的第一个真的值,
所以(fight , life)为真就返回他的值, 否则会返回 mana的值(真假与否都会返回)。
fight , life 又是两个语句间的且运算, 且运算,返回第一个假,否则会返回最后一个值
则,如果战斗状态,返回life的值,否则会返回false(假)。
上面的串起来就是 .如果fight 返回life ,否则返回mana,跟if结构的逻辑一模一样。
用 ”或” ”且” 结构模拟 if 结构 的一个例外
/var [ fight , horse ; life]v_b
用例5的分析,这句的意思就是 如果fight ,则赋值 horse ,否则 life
但是,如果当fight为真,horse为假的时候. (fight , horse)总体的值为假,则运算结果为life
即horse为假,无论fight的值为何,都会返回life的运算结果,
这时用传统的IF结构才能胜任,如下:
/if [fight]
/var [horse]v_b
/else
/var [life] v_b
/end
7.常见逻辑结构解析
/skill [tmbufftime:钟林毓秀<1.5] 钟林毓秀   —第一句示例
/skill [tnombuff:钟林毓秀 ; tmbufftime:钟林毓秀<1.5] 钟林毓秀 —第二句示例
/skill [(tmbufftime:钟林毓秀 ; 0)<1.5]  钟林毓秀  –第三局句示例
第一句 与 第二、三句表示的逻辑原理并不相同
[tmbufftime:钟林毓秀] 返回的是 目标存在归属于自身的该buff的剩余时间,
当目标有该buff的时候就会返回剩余时间, 当没有该buff的时候会返回false
在插件中 false(假) 用来做大小比较/加减乘除余 运算的时候, 会返回false (假)
即 [false < 1.5] 会被判断为假
所以第一句的意思是: 目标存在归属自身的该buff ,且剩余时间小于1.5秒的时候释放钟林毓秀,如果要表示没有该buff,或者该buff时间 小于1.5 秒,
则为第二句 [ tnombuff:钟林毓秀 ; tmbufftime:钟林毓秀<1.5]  用 ”或”运算
但是从代码的简洁度及运算的速度来看,我们可以有更高级的表现方式
第三句 其中的 (tmbufftime:钟林毓秀 ; 0)
根据前面提到的逻辑运算方式 [ false ; 0 ]返回的是第一个遇到的 真,所以他等同于 0
那么这个小分句的意思,就是 如果存在该buff,则返回时间, 不存在则返回0
那么 [ (tmbufftime:钟林毓秀 ; 0)<1.5]的意思就可以表示为,存在该buff的时间小于1.5秒,或者不存在该buff,与第二句,完全一样! 提高 了简洁度,同时,tnombuff 的运算时间远比 一个 ”或” 运算的时间长,也提高了效率!

第二节:条件判断(if结构)条件语句(If,Elseif,Else,End)
当您编写代码时,您常常需要为不同的判断执行不同的动作。 您可以在代码中使用条件语句来完成此任务。
if、elseif 以及else 语句用于执行基于不同条件的不同动作。 一般来说,if可以单用,但elseif和else是必须配合if使用的。
有if结构的必须由end来闭合。
1.if 语句  
在条件成立时执行一系列动作
语法:
/if [条件A]    —-可多个条件并列
/skill ……
/var ……
/end    —每个if,必须要有一个配套的end,切记
实例:
/if [tprepare:无懈可击|天音化物|雨钓江秋|火舞金刚|龙甩尾]
/skill 打断,厥阴指 —-万花打断技能
/end
2.If…Else 语句
如果您希望在某个条件成立时执行一些代码,在条件不成立时执行另一些代码,请使用 if….else 语句。
语法:
/if [条件A]
/skill ……
/var ……
/else
/skill ……
/var ……
/end    —每个if,必须要有一个配套的end,切记
实例:
/if [buff:6394]
/ownp 无诗  —万花ZB405武器
/else
/ownp 朱明承夜 —万花445特效武器
/end
3.ElseIf 语句
如果希望在多个条件之一成立时执行代码,请使用 elseif 语句:
语法:
/if [条件A]
/skill ……
/var ……
/elseif [条件B]
/skill ……
/var ……
/elseif [条件C]
/skill ……
/var ……
/end     —每个IF必须要有一个配套的end
实例:
/var [tmbufftime:商阳指] v_uy    —定义一个存储商阳指剩余时间的变量
/var [tmbufftime:钟林毓秀] v_vl   —定义一个存储钟林毓秀剩余时间的变量
/var [tmbufftime:兰摧玉折] v_lc    —定义一个存储兰摧玉折剩余时间的变量
/if [v_uy<=v_vl,v_uy<=v_lc]
/var [tmbufftime:商阳指] v_dot
/elseif [v_vl<=v_lc,v_vl<=v_uy]
/var [tmbufftime:钟林毓秀] v_dot
/elseif [v_lc<=v_uy,v_lc<=v_vl]
/var [tmbufftime:兰摧玉折] v_dot
/end
教程是固定的,命令的用法却不是固定的,教程给的只是基础的用法,深入的用法,在不违反基本语法规则的情况下,还是得靠自己灵活的应用。


第三节:变量与自定义变量变量与自定义变量变量的基本含义
例句1:
/Skill [life<0.4] 无相诀
变量的含义即是:每次运行都可能是不同的值。
变量一般都是写在方括号内进行逻辑运算,从而影响到一行语句的运行结果。
例句中,每次运行,life的值都可能是不同的值,从而影响到无相诀的施放,那么这里 life就是一个变量。
广泛一点,整个方括号内的也都可以看作一个变量。
变量的类型
目前插件的变量类型,有布尔型、数字型、字符串型。
布尔型,即 “真”<true> ,假<false> 两种结果
/Skill [horse] 战八方
如[horse]的判断结果只有两种,<true><false>
变量值为<true>的时候,判断为真,执行技能[战八方]
数字型,如life、mana、sun、moon 这类,是个数字
一般用来进行大小比较
例如:
/Skill [sun<50] 赤日轮
字符串型,很少用到。暂不讲解!
为了了解变量的类型,可以查阅说明文档中相关部分。
同时,插件提供了打印功能,可以打印出变量的运行结果
/print [horse]
/print [sun]
用这处理方式,就可以在聊天栏的黄字中看到输出的结果,便于宏的调试
关于“真”与“假”
/cast [...] 技能
类似这样的语句,中括号当中的判断结果,
如果是为<false>,那么就称之为“假”,就不会执行释放技能!
除<false>之外的所有值,都会被判断为真,而执行释放技能!
自定义变量简析
如例句1中,<life>这个变量是属于插件本身提供的判断。
而自定义变量,就是我们通过命令赋值,需要的时候再调用运算。
所有的自定义变量名都是以“v_”开头,
/var定义或者修改变量的值,使用时如同插件本身的判断一样处理即可。
例句2:
/var [life]v_life
/Skill [v_life<0.4]无相诀
上例句中,第一行通过/var 命令将life的值赋值给 自定义变量 v_life
第二行,直接引用变量进行判断,如同使用life一样
宏头部自定义开关变量
以“#”开头的宏头部命令中,#varbool、#varnum定义的开关,本质上也是一个自定义变量
例句3:(一篇结构完整的简短的宏)
#name 自定义变量
#varbool v_a
#varnum v_b,2
/Skill [v_a]后撤
/Skill [v_b=1]扶摇直上
上面的宏内容定义了两个开关,
一个是#varbool定义的开关,变量名为v_a,他的值在<true><false>之间切换,默认值为<true>
另外一个#varnum 定义的开关,变量名为v_b,他的值在<1><2>之间切换,默认值为<1>
后面两句/Skill的执行,完全依赖于这两个自定义变量的值
自定义变量的生命周期
#varbool、#varnum定义的变量,会在加载时设置默认值,会一直存在
未进行任何赋值操作的变量,默认返回值为<false>。
仅通过/var 命令赋值的变量,在游戏小退、修改宏之后会重置为<false>。

一般来说,超级宏里面有四种自定义变量
1. varbool
2. varbox
3. varnum
4. v_变量

varnum是写法比较高明的varbox,故只剩下三种变种(其实严格来说还有一种,但是为了使教程通俗易懂,故不在此教程里面)

首先说下varbool和varnum,varbool和varnum是用在头部的变量,可以改变宏的界面,让用户可以通过界面选择他要的功能,达到与用户沟通的目的,是超级宏的特点功能之一。当初的主流宏的功能还是很简单的时候,宏写手们都是冲着这个功能而纷纷改用超级宏,为剑三PVE宏打开了全新的一页,新手请务必马上熟练这个功能。

varbool
指的就是布尔(bool)的方式来定义一个变量,简单的说法就是,只有开和关。
写法是:

#varbool  v_变量的名字,tip:变量的作用,tip_1:开启状态,tip_2:关闭状态,Icon:1234

分析:

#varbool
告诉插件你正在定义一个varbool变量
v_变量的名字:就是在这里定义变量,必须以v_开头,超级宏所有的变量都是以v_开头,其次是变量名字非常重要,确保对宏写手来说易于辨认,因为需要在宏里面引用,写法不可以错

tip
这里就是告诉用户这个这个变量是做什么的,你要写什么都可以,迟些在宏里面不会引用到,因为只是给用户看的,建议写得直观点,让用户可以马上明白

tip_1
:如前面所说varbool有两个状态,开或者关(真或者假),所以tip_1就是解释第一个也就是默认的状态—-开。你写什么都可以,不过一般上都是写模式开启中之类的,同样的这个也不会引用在宏里面。还有不要把tip_1和tip搞乱,tip是向用户解释整体功能,tip_1是针对开关的状态解释。

tip_2
如果你已经明白tip_1那么tip_2也是同样的道理,只是tip_2是解释第二个开关,也就是关闭状态。

icon:1234
选择你要的图标,游戏里的图标都可以通过ctrl来查找iconID,如果不设置这点的话,将会使用默认太极图图标。

那么要怎样在码里面引用这个varbool呢?
很简单:
/skill [v_变量的名字]技能
因为【v_变量的名字】非假即真,直接使用就可以

例子
#varbool  v_自动扶摇,tip:扶摇模式,tip_1:开启状态,tip_2:关闭状态,Icon:1485
[color=rgb(43, 135, 193) !important] [color=rgb(43, 135, 193) !important]
/skill [v_自动扶摇]扶摇直上

varnum
理解了varbool那么varnum就很好理解了,varnum其实是更加弹性的varbool,varbool只能有两种状态,而varnum却可以拥有一个直到N状态,也就是说varbool能做到的varnum都能做到,varnum能做到的varbool未必能做到,写法是:

#varnum  v_变量名字 ,3 ,tip:变量的作用, tip_1:开关1的作用, tip_2:开关2的作用, tip_3:开关3的作用, Icon_1:1111, Icon_2:2222, Icon_3:3333

varnum的解释和varbool一样,所以这里就只解释当中的差别

3
这个代表的是有3个状态,可以设置1~n个状态,不过1是没有意义,所以实用上是2~n个状态

tip_n的数量就看你有多少个状态了,icon也是
不过varbool虽然有两个状态但是icon只有一个,那是因为varbool是非假即真,图标只是亮着(真)和不亮(假),一个图标就可以代表两个状态。

例子
#varnum  v_日月模式 ,3 ,tip:明教技能模式, tip_1:自动模式, tip_2:主日模式, tip_3:主月模式, Icon_1:3869, Icon_2:3868, Icon_3:3808
[color=rgb(43, 135, 193) !important] [color=rgb(43, 135, 193) !important][color=rgb(43, 135, 193) !important]
在宏里面引用的话:
/skill [v_日月模式=1]自动模式的循环
/skill [v_日月模式=2]主日模式的循环
/skill [v_日月模式=3]主月模式的循环
与varbool不同,必须使用=n来决定当前状态


v_变量
这可谓是超级宏的精髓了,这个非头部的可自定义变量,你可以用也可以完全不用,因为其功能是让你的宏的结构更高明,变化更弹性,主要是用来改善宏的写法,但是在比较高级的用法会无可避免的需要用到这自定义变量不过不在这教程的讨论范围之内。

使用v_变量的方法就是赋值,赋值何解?

赋值就是,代数字上来说,如果我们要定义a为1的话,写法就是a=1,这就是赋值
v_变量可以存很多种类的数值,当中包括
–数字12345
–真假true false
–字符串
每一种方式都可以用直接与非直接方式赋值
接下来我们就看看如何为v_变量进行各种赋值,如果要检查的话,可以用print来检查结果

尝试以下数字赋值:直接方式:
/var [12345]v_数字
/print [v_数字]
打印12345
间接方式
/var [ggcd]v_数字
/print [v_数字]
打印你现在公共cd的时间

尝试以下真假赋值:直接方式:
/var [true]v_真假
/print [v_真假]
打印true
间接方式:
/var [fight]v_战斗
/print [v_战斗]
如果在战斗中会打印true反之会打印false

尝试以下的字符串赋值:直接方式
/var [string:xxx]v_string
/print [v_string]
就会打印xxx
间接方式
/var [tar]v_string
/print [v_string]
就会打印目标的名字

以上的功能都非常强大,请务必尽快掌握


第四节:时间戳(nowtime)时间戳——nowtime参数<nowtime>/<now>基本含义
该参数返回的当前时间,单位为秒。其数值本身没有实际意义。
他的常见使用方式为:
1)某一个特殊时刻,将now赋值给某一个自定义变量
2)通过该变量与now进行大小比较判断,执行需要的语句
示例一:对某部分语句进行执行频率限制
有某玩家遇到由于网络延迟,导致切换武器不停变化。
由此提出能不能只对换武器的语句段落进行频率限制,限制他0.5秒只执行一次!
so easy,好吧!使用<nowtime>命令帮助你!
示例:
/If [now>(v_Mark;0)]
/Var [now+0.5]v_Mark
/end
如上例,模拟上面语句执行过程:
第一次执行,v_mark尚未赋值,返回值为<false>,从而[(v_Mark;0)]执行结果为0,
接着[now>0]判断为真,就进入/If内部语句的执行。接着对v_Mark赋值为<现在的时间+0.5秒>。执行换武器语句段.
第二次执行,<v_mark>为数值,即为进行[now>v_mark]的判断,
如果两次间隔小于0.5秒,那么判断为假,其内部语句不会执行。
如果间隔大于0.5秒,判断为真,则执行/if内部的语句,赋值,切换武器等…
完美地对换武器语句进行了限制
对抗服务器延迟,解决冰心4玳弦问题
由于超级宏释放技能之间缝隙极小,外加服务器及网络的延迟因素导致的玳弦急曲第三段的效果延迟出现
从而使使用用常规语句的宏会多打一次玳弦
那么,我们可以从now入手,解决这个问题
/If [ota]
/if [0.2<otaleft:玳弦急曲<0.5,tmbuff:急曲=2] –识别第三段快结束时的时刻
/Var [now+0.6]v_marktime –赋值自定义变量,进行标记
/end
/Return –保护引导
/end
/Skill [tmbuff:急曲=3] 剑气长江
/Skill [tmbuff:急曲=2 , now<v_marktime] 剑气长江 –预判急曲已经三层
/Skill 玳弦急曲
上面示例通过now的时间轴变量,预判了急曲buff层数,从而完美地解决了这个问题。
也可以看作是模拟手动的一种方式!

第五节:宏控制宏控制
首先恭喜读者你跳过/看懂了前面的人写的乱七八糟的东西,进入到了这个小节。 注意:这个小节的部分内容需要你能够了解前面大部分内容,并且有一定的宏基础的情况下再仔细研读。
本小节主要要针对的内容,是如何控制宏的各语句运行。 由于众所周知的原因,初涉写宏的新人经常会发现,在不必要的时候打了不必要的技能,技能顺序混乱,或者出于输出的需要要调整一部分技能的顺序,这些需求会越来越多。本节将要讲的,是如何应用超级宏的函数,对这些进行控制。
1.顺序控制
由于众所周知的原因,超级宏的代码是逐行运行的。例如:
Code 1-1
/skill [条件A]技能A
/skill 技能B
/skill 技能A
那么宏在执行的时候会首先判断:如果满足了条件A,那么执行技能A(当然这里会有一个合法释放的前提,如果技能A不能被释放,那么自然不会释放);然后顺序执行下一行,执行技能B,再下一行,执行技能A,结束。
但是事实上,如果技能A和技能B之间有公共CD,那么技能B和后续的技能A均会被公共CD限制,从而,一旦执行成功一个技能,那么后面的技能会进入公共CD而无法执行。
顺序控制在宏的写作过程中,都已经被有意识的应用于宏的各个角落,但毫无疑问,通过调整语句顺序来控制技能顺序,是控制中最简便的一种。然而,大多数情况下,当我们遇到问题时,简单的顺序控制无法达成其应有的效果。
2./if
顺序控制的原理,是各技能之间有公共CD,通过公共CD使技能不能发动而达成限制后续技能执行,从而达到控制执行顺序的问题。
然而,并非所有的技能都与大部分技能公共CD。每个门派都或多或少有一些非常重要但没有公共CD的技能,包括特效腰坠的使用也是没有公共CD的。此外,如果在引导读条中通过宏发动了非引导读条技能,那么会中断引导读条。如上例,若技能A是一个引导读条技能,那么假如条件A是真,技能A的读条会一闪而逝,因为其读条被技能B的执行强制打断。
另有一些情况下,简单的使用顺序调整,无法达到控制技能发动的目的,此时,/if就会派上用场。
与/if相配合的是/else(/elseif)和/end。使用/if可以简单的控制一个技能序列是否在指定的条件下执行,同时可以使用/if来合并多个相同条件的技能的使用。
例如:以下语句用来实现,只在条件1下执行这些技能序列:
Code 2-1
/if [条件1]
/skill 技能A
/var [true] v_参数A
/skil 技能B
/print [v_参数A]
/end
以下是一个技能序列:
Code 2-2
/skill [条件1]技能A
/skill [条件1,条件3]技能B
/skill [条件1,条件2,条件3]技能C
/skill [条件1,条件4,!条件3]技能D
/skill [!条件1,条件2]技能B
/skill [!条件1,条件3]技能D
上面的技能序列可以使用/if合并为:
Code 2-3
/if [条件1]
/skill 技能A
/skill [条件3]技能B
/skill [条件2,条件3]技能C
/skill [条件4,!条件3]技能D
/else
/skill [条件2]技能B
/skill [条件3]技能D
/end


3.更多的/if
使用/if,可以简单的为多个技能或技能组合划定发动条件,同时使我们的宏看上去高端大气上档次了很多。
如果有必要,可以在/if里面再用一个/if。例如,上面的code 2-3还可以写作:
Code 3-1
/if [条件1]
/skill 技能A
/if [条件3]
/skill 技能B
/skill [条件2]技能C
/else
/skill [条件4]技能D
/end
/else
/skill [条件2]技能B
/skill [条件3]技能D
/end
唯一需要注意的是,每使用一个/if,都要有一个/end与之对应,同时注意与/if对应的/else(/elseif),以免产生不必要的逻辑错误。
4./return
/return从作用上来讲,相当于一个/if:只要满足/return的条件,在这个/return之后的所有语句都不会再执行。
最常见的用法当属众所周知的/return [ota],用来保护读条的语句。
5./var
变量可以使宏变化多端,这并不是随便说说。变量分两种,一是在头部定义的控制变量,二是在宏中直接定义的宏变量。这两者在使用时并没有太大区别,唯一区别是控制变量可以由使用者在宏面板上任意改变。
使用变量来控制一个技能的执行,如下例:
Code 5-1
#name 测试
#varbool v_变量A,tip:这是一个变量
/skill [v_变量A] 技能A
/skill 技能B
这是一个完整的宏,通过调整面板上变量开关,可以使宏执行,或不执行技能A。
当然,我们也可以这样复杂一点:
Code 5-2
#name 另一个测试
#varnum v_等级,6,tip:只是一个等级
/if [v_等级>3]
/var [true] v_test
/else
/var [false] v_test
/end
/skill [v_等级<2] 技能A
/skill [1<v_等级<4] 技能B
/skill [v_等级+buff:效果A<4] 技能C
/skill [v_等级] 技能D
/skill [v_test,buff:效果A] 技能E
这个宏定义了一个v_等级的变量,此外,我们还在宏内容中定义了一个变量v_test,该变量被赋予true与false两种值,通过这些变量计算不同的条件真假,判断不同技能的执行。
需要注意的是,数字型变量当单独作为条件时,只要拥有确切的数值,不论数值是多少,一概认为条件成立。


第七节:表达式优化表达式优化
在进入本节之前,我们的重点内容依然是注意事项:
注意:请在阅读本节前,仔细阅读并确保自己已经明确不同的判断参数返回值的类型属于true、false和num中的何种,并确保自己知道true、false、num之间的区别。请在阅读本节前,尽可能掌握变量命令/var的基本用法。
1.变量
前文已经对变量进行了最基本的介绍,那么请读者在此处回忆一下变量的几种情况,以及各种基本运算符号。
注意:本节中所有的变量,意指由宏定义的,以v_开头的具有相应数值的量。相应的,所有数字、true或false,以及通过参数引入的数值或真值(如:buff:调息,bufftime:风·灭气>5),均视为常量。
我们为什么要引入一个变量?
最主要也是最广泛使用的作用,就是引入变量开关,使使用者可以通过调整变量的值来控制宏的语句执行。
第二个比较广泛的应用,是通过将复杂的条件定义为一个新的变量,来方便对这个条件进行引用。通常此类变量拥有一个十分有意义的名字,如某知名唐门宏中的v_队里有一堆唐门,v_救命啊他要放追命了,等等。
变量的另一个广泛应用,就是用来存储一些中间结果,以应用到后面的宏或变量表达式中。如不少宏,通过开关定义了加速阈值等级,再通过计算获得对应的技能的时间,以用于后文的计算。
2.变量表达式
变量表达式是区别于常量表达式的一个概念。表达式的概念请右转百度百科。
我们在写宏的时候,每个语句中,使用中括号[]所括起来的整个部分,就是一个表达式。当用于/skill、/if、/dia等等语句的时候,以表达式的真值来决定其运行;用于/var或/print时,则是对相应表达式的值进行赋值或打印。
常量表达式指表达式的所有量均为常量的表达式;使用了变量的表达式则称为变量表达式。
3.表达式优化
本节的重点,是如何针对宏中的大量表达式进行优化。
本节所有例子将均从本站知名宏中节选,部分内容可能有删改。
3-1 常量表达式优化
常量表达式通常不需要进行大量优化,但在超级宏的架构上,可以将部分庞大的表达式进行合并。
例如:
/skill [tpre:掷锤>0.5,nobuff:镇山河] 打断,后撤
/skill [tar:何莘涯,dis<10,nobuff:镇山河,tpre:力拔千钧>0.7] 打断,后撤
可以优化为
/skill [nobuff:镇山河,(tpre:掷锤>0.5;tar:何莘涯,dis<10,tpre:力拔千钧>0.7] 打断,后撤
又如:
/skill [tnopre:掷锤|吞云吐纳|骨牢|皇之怒,buff:莺鸣,nobuff:夜雨,sktest:四季剑法|三柴剑法,tbufftime:梅隐香>3] 风来吴山
/skill [tnopre:掷锤|吞云吐纳|骨牢|皇之怒,buff:莺鸣,nobuff:夜雨,sktest:四季剑法|三柴剑法,!tar:boss] 风来吴山
可以优化为:
/skill [tnopre:掷锤|吞云吐纳|骨牢|皇之怒,buff:莺鸣,nobuff:夜雨,sktest:四季剑法|三柴剑法,(tbufftime:梅隐香>3;!tar:boss)] 风来吴山
此类例子较多,但有时合并会导致表达式变得冗长不利于阅读。

3-2 /if下的/skill(/dia、/return等等)优化
实际上,由于除/var和/print以外的语句表达式的真值即决定其是否执行,因此在实际应用中,如果不是需要降低表达式长度以利阅读,此类语句可以通过优化不使用/if即完成判断。/var也可以使用相应的表达式算法来优化使之不需要/if。唯有/print,由于种种原因,必须使用/if来限制其执行与否以防止刷屏。
在进行带有/else的/if的优化时,需要预先计算好,优化后的语句真值是否与优化前相同。
针对/if下的/skill优化举例:
/if [mount:问水诀,cdtime:平湖断月>1.5]
/skill [tarisem,mount:问水诀,rage>82,fight,sktest:四季剑法|三柴剑法,cd:黄龙吐翠] 啸日
/else
/skill [tarisem,mount:问水诀,rage>82,fight,sktest:四季剑法|三柴剑法] 啸日
/end
/if [(rage<17,v_剑气=1);(rage<20,v_剑气=2)]
/skill [tarisem,mount:山居剑意,cdtime:雪断桥>1.5&雪断桥<60&莺鸣柳>1.5&莺鸣柳<110] 啸日
/end
可以优化为:
/skill [tarisem,mount:问水诀,rage>82,fight,sktest:四季剑法|三柴剑法,(cd:黄龙吐翠,cdtime:平湖断月>1.5;!cdtime:平湖断月>1.5)] 啸日
/skill [tarisem,mount:山居剑意,cdtime:雪断桥>1.5&雪断桥<60&莺鸣柳>1.5&莺鸣柳<110,(rage<17,v_剑气=1;rage<20,v_剑气=2)] 啸日
当然,本例中的两个语句可以通过合并为一个语句,但那样将会导致语句过长。
一般情况下,通过/if的优化获得的语句还可以进一步优化。
3-3 真值表达式的优化
在深入本节之前,请再次确认自己已经明白三种基本逻辑运算(或、且、非;超级宏中分别为’;'、’,'、’!')的关系。
观察上例中的(cd:黄龙吐翠,cdtime:平湖断月>1.5;!cdtime:平湖断月>1.5)。如果我们定义:
/var [cd:黄龙吐翠] v_a
/var [cdtime:平湖断月>1.5] v_b
那么这个表达式可以写作(v_a,v_b;!v_b)。可以很清楚的明确,这个表达式只有当v_a与!v_b同为假时才为假,其他时候均为真。因此这个表达式可以写作(v_a;!v_b),也即(cd:黄龙吐翠;cdtime:平湖断月<=1.5)
绝大多数情况下,只涉及到两个量的布尔表达式,都可以进行一定程度上的简化。
3-4 数值表达式的优化
超级宏中,数值型变量均可参与简单的加减乘除计算,如上例中的(rage<17,v_剑气=1;rage<20,v_剑气=2),可以简单的简化为rage<14+v_剑气*3(前提是v_剑气只能取为1或2)。
又例如,计算花间在梦歌状态下的加速,可以写作:
/var [6.26] v_speed –无BUFF的面板加速
/var [v_speed+(buff:梦歌;0)*0.9765625] v_nowspeed
3-5 混合表达式算法
在超级宏中,涉及到数值的计算,以及数值与真值的混合计算,参考下面的规则:
true and 3 = 3
2 and 3 = 3
false and 3 = false
true or 3 = true
2 or 3 = 2
false or 3 = 3
根据这一点,我们可以简化很多混合表达式。最常用的简化形式是(a,b;c)型表达式,意为当a为真是,值为b,否则为c。



3-6 /if下的/var优化
最简单的情况是下面这种情况,在很多宏中都有这样的情况:
/if [v_快雪>0.15;v_快雪=0;noota:快雪时晴]
/var [true] v_快雪可断
/else
/var [false] v_快雪可断
/end
此种情况可以很直接的写成:
/var [v_快雪>0.15;v_快雪=0;noota:快雪时晴] v_快雪可断
另一种可以优化的情况是如下的情况:
/if [v_动态打断,ping<0.5]
/var [ping] v_动态变量
/else
/var [0.02] v_动态变量
/end
该情况可以利用上文所述的(a,b;c)型表达式简单的优化成:
/var [v_动态打断,ping<0.5,ping;0.02] v_动态变量
有的时候,/if语句是对/var有着执行约束,如下例:
/if [cdtime:芙蓉并蒂>=5]
/var [false] v_ind
/end
该语句限制了只有在cdtime:芙蓉并蒂>=5时才对v_ind修改数值,因此此例可以同样写为:
/if [cdtime:芙蓉并蒂>=5]
/var [false] v_ind
/else
/var [v_ind] v_ind
/end
从而可以优化为
/var [cdtime:芙蓉并蒂>=5,false;v_ind] v_ind
再根据真值优化可以进一步简化为
/var [cdtime:芙蓉并蒂<5,v_ind] v_ind
下面是一个针对变量的综合优化例子,是某宏中的一个限定执行模块,只在当前循环中v_st9=1时执行一次:
【声明:此模块及其优化结果引自变速箱-花间宏,直接转载或引用请注明引用来源】
/if [v_st9=1]
/var [false] v_mention
/var [false] v_tomention
/else
/var [!v_mention] v_tomention
/end
/if [v_tomention]
/print [v_st9=2,string:xxx]
/var [true] v_mention
/var [false] v_tomention
/end
前面的一个/if块可以简单的优化为
/var [v_st9=2,v_mention] v_mention
/var [v_st9=2,!v_mention] v_tomention
后面一个/if因为限制了只有当v_tomention为真的时候才执行,而当v_tomention为假时,需要保持原来的值,因此可以写为
/var [v_tomention;v_mention] v_mention
/var [false] v_tomention
根据上下文语句,由于当v_mention置为true时,v_tomention会在下一个循环置为false,因此最后一个语句可以被省略。
全文优化结果为:
/var [v_st9=2,v_mention] v_mention
/var [v_st9=2,!v_mention] v_tomention
/if [v_tomention]
/print [v_st9=2,string:xxx]
/end
/var [v_tomention;v_mention] v_mention


补充内容:一些宏语句简化技巧
BY燕羽天@大明宫
[a,b;c]等效于if a, b ,else c                相当于a是b与c的选择开关
[!a,b] 等效于if a,恒为false,else b.        相当于a是b的赋值开关
[a;b]        if a为 恒为true,else b
[(a,b;0)+x]等效于 if a,b+x, else x.        相当于a是b的加法选择开关
[sklv:a+2*sklv:b]等效于if a,1,elseif b,2相当于奇穴a,b的判断开关
[v_a;x] 等效于 初始化变量a为x,a不能为布尔变量




2013/12/26 第三章·第7节:表达式优化—— 主稿:楚玄枫
2013/12/26 第三章·第6节:时间控制 —— 主稿:楚玄枫
2013/12/26 第三章·第5节:宏控制 —— 主稿:楚玄枫
2013/12/26 第三章·第4节:时间戳(nowtime) —— 主稿:YYL
2013/12/26 第三章·第3节:变量与自定义变量(var) —— 主稿:龙蔡、YYL
2013/12/26 第三章·第2节:条件判断(if结构) —— 主稿:Jachou
2013/12/26 第三章·第1节:逻辑运算基础—— 主稿:YYL
2013/12/26 第三章·中级教程:引言—— 龙蔡