MUGEN 1.1 英文教程翻译

MUGEN 1.1

英文教程翻译

翻译: FantasyFT

目录

关于控制器

关于触发器

关于背景和舞台

关于CNS文件格式

坐标空间解释

CNS变量设置

DEF变量设置

必要图像素材

System(画面包等)相关参数设置

Fight(血条等)相关参数设定

CFG相关参数设定

Select.def相关参数设置

Mugen1.1Beta1已知Bug

进阶知识目录

初级AI教程

高级AI教程


初级AI教程

目录

1.trigger和ai开关

2.def，cmd和cns

3.基本的trigger指令

4.防御

5.移动

6.切反，抓硬直，插动

7.连段


1.trigger和ai开关

                本页内容由net教授撰写. 由【softmgr】整理编辑.

从本章开始，教程由net教授提供，本网站会为排版做些内容调整，该教程内容会与口水轩的初级ai教程有一部分重复。

先说一句，制作ai不是那么容易的，必须十分熟悉角色的各种性能，连段，立回，防御，压制都得考虑，是很耗时间的，
特别是要花大量时间作测试。万一出错还得debug……
即使如此你还是要做ai？那么……覚悟しろ！（师匠音）
本人才疏学浅，只是对mugen就ai方面有点了解，所以有错误欢迎各位高手指出。

注意事项
1 写ai时数学，标点符号请用英文半角，否则系统不认
2 永远记得改ai前把文件备份一次。否则后果自负……最好写到某个阶段就备份下，免得以后改出问题
3 未经过原人物作者同意，或原ai作者同意。
不得公开发布私自制作或改造的ai（主要就是别去mc新闻区这种公共场所发布）。 私底下小范围传播，自己用来做做视频没事。
4 请注意人物版本的对应。
要准备的东西
1 mugen主程序及人物。至少懂得加人物，打ai补丁之类的mugen基础知识。
2 记事本。推荐用notepad2，可以转码。
3 其他好像没啥要准备的了……

本文参考资料：
⑨氏主页上的ai相关资料
平成氏ai说明书
trigger表和script表，文档翻译版下载:
https://pan.baidu.com/s/1eQ4HoyA
其他……

Episode 0 trigger和type
最好看一下这2个表，尤其是trigger表，熟悉一下trigger（触发器）是啥东西。不看也无所谓……就在下面的教程中慢慢熟悉也可。
type表也有种说法是script表。
这2个表在\winmugen\docs里有。trigger.html和sctrls.html就是，不过是英文版
简单的说trigger就是“当发生啥情况的时候”，type就是“做什么”，trigger是条件，type是结果。
一般在ai里用得最多的type是changestate，其次是varset，其他的用的不多。

举个简单的例子
[state -1]
type = poweradd ;加气
triggerall = roundstate = 2 ;比赛必须在进行的时候（不是刚开始或者已经分出胜负的时候）
trigger1 = stateno = 500 ;处于state号为500的动作时（假设是聚气动作） trigger2 = life<=300 ;血小于300时
trigger2 = var(30) = 2 ;当某个变量var(30)为2的时候
value = 5 ;加气的值为5
其中triggerall是最主要的条件，满足后接下来才判断是否能满足trigger1或者trigger2。而trigger1和trigger2两者之间是或的关系。但2个trigger2之间是和的关系，2者都得满足，才算是真正满足trigger2。如果有3个trigger2，那3个的条件都得满足，依此类推。
只要满足triggerall，再满足trigger1或trigger2两者之一，就能执行type所定义的事情（这里是加气）。
注意：写的时候trigger1后面别直接跟trigger3，别跳号，会出问题的……
所以这个state的解读就是，当比赛进行中的前提下，在做state号为500的聚气动作的时候，或者血量小于300且var(30)=2的时候，就加5气。
由于mugen是每帧判断一次trigger，通常在60FPS下1秒有60帧，所以实际效果是在满足条件的时候，每秒钟回复300气。
PS：分号后是注释，你可以随便写点说明文字之类的话，程序不会把分号后的内容读进去的。但分号必须用英文半角（上面说过了）。

最后再介绍下常用的逻辑符号
&& 和
|| 或
! 否
比如trigger1 = (life > 500 && power<1000) || var(30)!=2
就是当血量大于500且能量小于1000，或var(30)不等于2的时候，trigger成立
另外像!var(59)这种表达，就相当于var(59)=0

Episode 1 ai开关
ai开关有什么用？是控制ai的开启和关闭的。
一个人物有被人操纵的时候，和被ai操纵的时候。
ai开关的作用，就是被人操纵的时候，不开启ai。而cpu操纵的时候，会自动判断并开启ai。所以说好的ai开关要判断出到底是人在操作，还是电脑在操纵。该开ai的时候开，不该开的时候不开。
首先要说明一点：mugen是有自带的ai的，只是这个ai是随机发招，防御而已，相当于乱按流，出招频率也不高，很纱布，但我们可以利用这个默认ai来判断是不是人在操作。

先给个ai开关的实例吧。
ai开关通常分2部分，第1部分通常在cmd里，就是为ai设计的指令，以下就是某体术青子的ai用cmd
; AI
[Command]
Name = "AI_01"
Command = a, b, c, x, y, z, s
Time = 0
[Command]
Name = "AI_02"
Command = x, y, z, a, b, c, s
Time = 0
[Command]
Name = "AI_03"
Command = z, y, x, c, b, a, s
Time = 0
[Command]
Name = "AI_04"
Command = c, b, a, z, y, x, s
Time = 0
[Command]
Name = "AI_05"
Command = a, b, c, z, y, x, s
Time = 0
[Command]
Name = "AI_06"
Command = z, y, x, a, b, c, s
Time = 0
[Command]
Name = "AI_07"
Command = x, y, z, c, b, a, s
Time = 0
[Command]
Name = "AI_08"
Command = c, b, a, x, y, z, s
Time = 0
[Command]
Name = "AI_09"
Command = a, a, a, a, a, s
Time = 0
[Command]
Name = "AI_10"
Command = b, b, b, b, b, s
Time = 0
[Command]
Name = "AI_11"
Command = c, c, c, c, c, s
Time = 0
[Command]
Name = "AI_12"
Command = x, x, x, x, x, s
Time = 0
[Command]
Name = "AI_13"
Command = y, y, y, y, y, s
Time = 0
[Command]
Name = "AI_14"
Command = z, z, z, z, z, s
Time = 0
[Command]
Name = "AI_15"
Command = s, s, s, s, s, s
Time = 0
[Command]
Name = "AI_16"
Command = U, U, U, U
Time = 0
[Command]
Name = "AI_17"
Command = D, D, D, D
Time = 0
[Command]
Name = "AI_18"
Command = F, F, F, F
Time = 0
[Command]
Name = "AI_19"
Command = B, B, B, B
Time = 0
这些指令应该能看懂吧，以防万一再说以下，U＝UP（上）,F＝forward（前），B＝back（后），D＝down（下）
小写的a,b,c,x,y,z就表示6个拳脚之类的攻击键,s是start键，time就是表示必须在几F内输入指令才会成功。

至于其他符号
1.保持状态 (/) 例如:/D 意思为必须保持 "下" 这个按键不放.
当然也可以用在一组命令里,意为在按下控制键之前方向键保持按下状态,当然/后可以用控制键,不光是方向键.
注意:标记“~”用于设置按键状态为放开 例如: ~a表示这个键不用保持按下状态,可以按下后即放开.
在~前加一个数字,用于表达按下时间的长短.例如:~30a
2.动作方向 ($) 例如:$D 意为DB,DF 也在.
3.按键同时 (+) 例如:a+b+c 意为这三个键同时按下.
这些命令是可以组合的,例如: ~30$D,a+b
所以第一个“ai_0”的command的意思是
必须在0F内输入a, b, c, x, y, z, s，显然这是人办不到的，以下19个ai指令都必须在0F内输入，都是人类完成不了的事。
所以当人操作的时候，是不会成功按出这19个ai指令的，永远都不可能发出ai指令。 但是当cpu操纵的时候就不一样。mugen自带的ai虽然纱布，但是ai和人不一样，不用“输入”，便可以直接成功发出指令。
mugen自带的ai是只要是定义过的指令都会随机用。那样就会有相当概率发出ai指令。
发出ai指令的后果是怎样？当然不能没结果，我们要的结果就是当有一个人类不能完成的ai指令被发动时，就判断出这是cpu在操纵人物，然后启动我们自己编写的ai
而这必须由ai开关的第二部分完成。看一下实例吧。

第2部分，ai的启动
[State -3, AI]
Type = VarSet ;设置变量的值
TriggerAll = Var(59) = 0 ;当var(59)=0(ai没有被开启的时候)
triggerall = RoundState = [1,2] ;当对局处于开始阶段或进行阶段的时候
Trigger1 = command = "AI_01"
Trigger2 = command = "AI_02"
Trigger3 = command = "AI_03"
Trigger4 = command = "AI_04"
Trigger5 = command = "AI_05"
Trigger6 = command = "AI_06"
Trigger7 = command = "AI_07"
Trigger8 = command = "AI_08"
Trigger9 = command = "AI_09"
Trigger10 = command = "AI_10"
Trigger11 = command = "AI_11"
Trigger12 = command = "AI_12"
Trigger13 = command = "AI_13"
Trigger14 = command = "AI_14"
Trigger15 = command = "AI_15"
Trigger16 = command = "AI_16"
Trigger17 = command = "AI_17"
Trigger18 = command = "AI_18"
Trigger19 = command = "AI_19" ;当以上19个ai指令中有一个被发动时
;trigger20 = 1 ;无条件触发，就是所谓的ai常时启动，不过此时这个trigger20被分号注释掉了，程序不会读
V = 59
Value = 1 ;这2行就是使var(59)这个变量的值为1
IgnoreHitPause = 1
这里var(59)这个变量就充当了ai的开关。
用其他var也可以，不过一般最常见的是var(59)，之后的文章里假设ai开关就是var(59)。
var(59)=0的时候，ai不开启。
当mugen默认ai发动任何一个人类不可能发动的ai指令的时候，设置var(59)=1，此时对应此人物的专门的ai就开启了。
简而言之，ai开关的作用机制就是：
检测到人在操作的时候－关闭ai
检测到mugen自带ai操作的时候－开启专门的ai
顺便说下
Trigger1 = command = "AI_01" 和
Trigger1 = command = "AI_01" = 1
是一回事，"= 1"可以省略。
当然"= 2"是不能省略的

ai的常时启动
注意下trigger20，如果把前面的分号去掉的话，程序就会读这一行trigger20 = 1，此时ai就会常时启动，这时你进训练模式，那ai也会自动启动，夺取你的控制权。
当然你要自己玩时，不可以让ai常时启动，但如果录ai比赛的视频时，推荐采取ai常时启动的方式。
为什么？因为前面说过，如果没有设置常时启动ai，要让自己编写的ai启动，得先让mugen自带的ai发动那19条ai指令之一，但mugen自带的ai又不聪明，它是随机发动指令的，要正好发动到那19条ai指令（而不是正常指令）需要一定时间，所以就会出现ai发呆的情况。
另外有些人物即使在ai已经启动的时候(var(59)=1时)，某些情况下会不明原因自动关掉ai(使var(59)=0)，这时ai又要花时间重新通过发动ai指令启动ai，在这段ai空白期内就会发生乱动或发呆的现象(mugen自带ai很纱布嘛)。所以有些人物ai常时启动与否可谓大不一样，比如GG的囧尼之类。

小技巧
通常ai开关也掌管ai等级。如果要在一片state里迅速找到控制ai等级的var，最好的方法就是搜索cmd里定义的ai指令的名字（比如"AI_15"）。
往下拉就能看到了


2.def，cmd和cns

                本页内容由net教授撰写. 由【softmgr】整理编辑.

（一）ai写在什么地方？
最常见的有2种情况
1 写在cmd里，使用state -1
2 写在cns里，使用state -3
一般state -2的cns是定义声音，效果，修正和各种辅助变量（各种var和fvar）用的。
虽然也有少数人会把ai写在state -2里，但一般不这么做。
而0以上的state是定义招式性质用的。
新手的话推荐先写在cmd里，用state -1，因为可以方便查找state号。另外不容易出错。
要写在cns里也行，用state -3。写在cns里有个好处就是不必和人用的指令混在一起，不会影响其他文件。老手推荐写在-3里面。
1 如果决定写在cmd里面，就直接在下面接着写就可以了。
2 如果决定写在cns里面
如果有现成的含state -3的cns，就接着写在下面即可。
如果没有就新建个-3.cns或ai.cns（名字随便你改）
然后首先加入下面一行
[Statedef -3]　　;定义state -3，如果没有cns定义过state -3则一定要定义，有其他cns定义过state -3就不要写。
然后在下面写ai，最后别忘记def文件要加入你新建的那个cns。
举个例子：
[Files]
Cmd = Meirin.cmd
Cns = Meirin.cns
St = Meirin.cns
St0 = Meirin_Special.Cns
St1 = Meirin_Spell.Cns
St2 = Helper.Cns
St3 = -2.cns
St4 = -3.cns ;这个就是你新加的cns，加个st的定义就可以，注意和trigger一样别跳号。
StCommon = Meirin_Common.cns
Sprite = Meirin.Sff
Anim = Meirin.Air
Sound = Meirin.Snd
Pal1 = Meirin1.Act
Pal2 = Meirin2.Act

ai绿色化
有时我们想在写ai的同时，保持原有文件，可以有以下2种做法。
先把def复制一下，改一个文件名（比如meirin ai.def）。
记得在select.def里指定这个def载入人物
A
把要改的文件复制后改名，比如要改meirin.cmd，我们可以复制个复件，然后把复件改名为meirin ai.cmd
再进入meirin ai.def里就改一下相关的cmd文件名。
[Files]
Cmd = Meirin ai.cmd
这样原有的def，cmd就全保留着。要用ai启动时载入meirin ai.def就行了。cns啥的也一样
不过有些人物不支持这种方法。可以试试下面的
B
在要改的人物的目录底下新建一个文件夹，比如ai
然后把要改的文件复制进去，再改就行。
def里就这么改
[Files]
Cmd = ai/Meirin.cmd ;注意是正斜杠
个人推荐用方法B

PS：注意def的info里
name不可以改，displayname可以改。

（二）AI开关的书写
首先我们先做一个ai开关（改别人的ai的话，ai开关肯定已经做好了，你只要找到就可以了）
第1部分的ai指令，这个必须写在cmd里面。
然后是第2部分。
假设是从零开始写ai的话，如果要写在cmd里，就写在cmd最下面。如果要写在cns里，就直接写在[Statedef -3]下面
举个例子，首先在cmd里写ai开关第一部分。这里为了举例方便，只写了5个ai指令，实际上最好多写点，这样会灵敏点（发呆时间少点，cmd一共支持128个指令，蛋疼的话全部用上也无所谓，不过一般50-60个足够了）
指令稍微写复杂点，time最好都写0，免得人操作的时候误触发
; AI
[Command]
Name = "AI_01"
Command = a, b, c, x, y, z, s
Time = 0
[Command]
Name = "AI_02"
Command = x, y, z, a, b, c, s
Time = 0
[Command]
Name = "AI_03"
Command = z, y, x, c, b, a, s
Time = 0
[Command]
Name = "AI_04"
Command = c, b, a, z, y, x, s
Time = 0
[Command]
Name = "AI_05"
Command = a, b, c, z, y, x, s
Time = 0
然后在如果cmd里写，就在文件底部写一个state（改ai的话直接查找"ai_01"就能看到ai开关了）
[State -1, AI] ;逗号后面的内容可以当注释随便改，方便你自己记忆就行。记得别漏了另一半方括号
Type = VarSet
TriggerAll = Var(59) = 0 && RoundState != 3
Trigger1 = command = "AI_01"
Trigger2 = command = "AI_02"
Trigger3 = command = "AI_03"
Trigger4 = command = "AI_04"
Trigger5 = command = "AI_05"
;trigger6 = 1
V = 59
Value = 1
IgnoreHitPause = 1
如果是在-3.cns里写，就把state -1改成state -3，其他不必改，写在[Statedef -3]下面即可
偷懒的话，直接复制前面教程里的ai开关也可以。。。。
然后再把具体的ai写在ai开关的下面

（三）人用指令和ai的区别
不多说，直接看例子。要注意到因为我们已经写好了ai开关，var(59)这个变量就在这里起到了作用。
state号就是动作的代号
这是cmd里的人用指令的定义
;立a
[State －1]
Type = ChangeState ;转换动作(可以理解为做动作)
Value = 200
TriggerAll = Var(59) = 0 ;ai没有开启
TriggerAll = Command = "a" ;输入了"a"
TriggerAll = Command != "holddown" ;没有按着“下”
TriggerAll = StateType != A ;不在空中
Trigger1 = Ctrl ;可以自由行动的状态
解读下就是在ai没开启的状态下，输入了a，没有按着下，不在空中，可以自由行动的状态下，出立a（做出立a的动作）。

这是ai
;立a
[State -3]
Type = ChangeState
Value = 200
TriggerAll = Var(59) > 0　　　;ai开启
TriggerAll = StateType != A
Trigger1 = Ctrl
这个应该能自己解读了吧。。。
看出来ai和人用指令的最大区别在哪里了么？
首先是var(59)的值
第2就是ai出招不用输入指令。
所以我们要把人用指令转换为ai指令
首先triggerall里面除了var(59)和command，其他条件一定要完全复制，这样才能保证ai不会做出系统所不允许的动作。否则ai就可能做出不满气都能出超杀，或者还没到条件就直接用死星技，在空中出地面技等作弊行为。
这也意味着，我们最好把这些系统所限制的条件都写到triggerall里面。而不是写在trigger1，2里面。
然后var(59) = 0改为var(59) > 0。
没有关于var(59)的triggeall就加上var(59) > 0（所有人用指令最好也加上var(59)=0，以免mugen自带的ai捣乱）
最后把command的部分删除。
至于trigger1，2的ai具体怎么写，下一章再详细讲。


3.基本的trigger指令

                本页内容由net教授撰写. 由【softmgr】整理编辑.

首先我们来了解一点基本的trigger指令
statetype 或p2statetype= S or C or A or L
statetype是自己的状态，p2statetype是对手的状态。p2就表示是对手的，下面都是这样
S是站立，C是蹲下，A是空中，L是倒地
（也就是stand，crouch，air，lie的首字母）

Movetype或p2movetype = I or A or H
这是动作状态，I是通常，A是攻击，H是受击（被打或防御都算受击）

stateno 或p2stateno = 数字
state号和对手的state号。State号就可以看作是动作的代号。

ctrl = 0 or 1；
判断是不是处于可控制状态，下面的文章里有详细说明

canrecover = 0 or 1 ；
判断是不是可以受身、0=受身不可、1=受身可能

P2dist x或p2bodydist X 与对手的水平方向距离
P2dist y 或p2bodydist Y 与对手的垂直方向距离，这2个下面有详细说明
Backedgebodydist 与背后版边的距离
Frontedgebodydist 与面前版边的距离

random 随机数，下面有说

movecontact攻击接触到对手（打到或被防）
movehit 攻击成功击中对手
moveguarded攻击被对手防住

life或p2life 自己或对手的血量
power 能量值。

enemy, 以敌人为对象，读取敌人的数值。双人战时指定较远的那个敌人
enemynear, 和上面差不多，只不过是双人战时读取离自己较近的敌人。
比如Trigger1 = enemy,power < 1000，就是当对手的能量值小于1000时

Stateno的查找
Ai开关写好后，我们就正式开始写ai。
但要写ai，我们先要知道什么招对应的是什么state号。State号就是各种招式和动作的代号。
那如何找出招式的stateno呢？有2种方法

注：下面有时会用数字表示方向，至于什么数字表示啥方向，看你的小键盘就知道了，比如624b就是前下后b

1 看cmd
Cmd文件本身就是定义“按什么键出什么招”的文件。如果你对人物的出招比较熟，可以看cmd查找相应的stateno
举个例子：
比如要查找下前a这招的stateno，我们先打开cmd。
[Command]里的招式定义部分应该会读了吧，不懂的回去复习episode 1。

很明显，下前a就是这个（df是过渡）
[Command]
Name = "236a"
Command = ~D, DF, F, a
Time = 14

然后我们看到这个招被定义了一个名字叫“236a”，然后我们搜索这个236a
可以找到下面那段
[State -1]
Type = ChangeState ;这个表示切换状态，即做动作，前面说过了
Value = 1300 ;这就是state号，不过value也有可能写在下面
TriggerAll = Var(59) = 0
TriggerAll = Command = "236a"
TriggerAll = StateType != A
Trigger1 = Ctrl

其他先不用管，我们要知道的就是下前a这招的stateno就是1300

2 进入debug模式
打开winmugen\data目录里的mugen.cfg
查找字符串“debug”
找到这段
[Debug]
;Set to 0 to disable starting in debug mode by default.
Debug =0
把Debug = 0，改为Debug = 1即可。
然后进入mugen，进入训练模式，用1p选你所要修改ai的角色，会发现左下角出现了不少字。

注意到那个“STATE NO：”了么？这时你只要出招，这招的stateno就会自动出现。

common1.cns
有时我们会发现，有些基本动作的state在cmd里没有定义指令。比如防御，跳跃啥的。
因为这是定义在common的cns里的。哪个是定义common的cns呢？要看def

def里一般有这行
stcommon = common1.cns
但这个common1.cns，可能在人物目录里找不到

如果我们在这个人物的文件夹底下没找到这个common1.cns，那这个文件就是指winmugen\data底下的common1.cns
这是一个系统默认的通用动作定义文件。定义的是一般人物都有的防御，跳跃，前进等动作。具体怎么定义这里不深究，我们只要知道common1.cns定义的一些动作的state号就行。

写几个比较重要的
0 站立
20 步行
40 跳跃启动(在地面) 仅在人物离地时
100 向前跑/急冲
105 急退
120 防御-启动
130 防御-站-摆势
131 防御-蹲-摆势
132 防御-空-摆势 　（此时人物做出防御动作，但并未受击）
140 防御-站-结束
141 防御-蹲-结束
142 防御-空-结束
150 防御-站-状态
151 防御-蹲-状态
152 防御-空-状态
-------受创--------（5000-5300）
5110 躺倒
5120 起身
5121 opt 起身 （有些人物有2种起身方式）
5201 恢复近地 （地面受身）
5210 恢复近空 （空中受身）
5300 眩晕

简易ai的制作以及ai的基本立回

个人推荐写ai时，不怕麻烦的话，立回，连段，压制，起攻，插动等等最好分开写，且加上注释，这样的话比较清晰。

首先介绍一下立回的含义：就是敌我双方都能自由行动的状态，没有一方被压制，被连段，或处于倒地等各种行动不能的状态。

在ai上怎么体现呢？我们先来看一个立回ai的代码

[State -3,立x]
type = ChangeState
value = 200
triggerall = Var（59）= 1 && roundstate = 2 ;ai开关开启且对局进行中
triggerall = Statetype != A && p2statetype !=L;不在空中且对手不是倒地
triggerall = p2movetype != H ;对手不是受击状态，表明不是在连段中
triggerall = ctrl ;可以控制，即可以自由行动
trigger1 = P2dist X = [0,40] ;在与对手中心距离在0到40像素的情况下
trigger1 = random < 300 ;随机数小于300（给出招加一个概率）

这就是立x的立回ai
立回的重要特征是ctrl（可控制，即可以自由行动）以及p2movetype !=H（对手不受击）
P2statetype !=L不加也可以，因为一般对手倒地时，系统是判断p2movetype=H的

修改一个ai的时候，经常会看到原ai作者把连段和立回的一起写。
像这样：
[State -1, 236B]
type = ChangeState
triggerall = var(59) > 0 && RoundState = 2 && !ishelper && var(41)%10 = 0
triggerall = StateType = S
triggerall = p2bodydist X = [80,150]
trigger1 = Ctrl && random <=300
trigger2 = stateno = 230 && movecontact
value = 1210

其中trigger1是立回，trigger2是连段。
但是由于trigger1里面只有ctrl，没有p2movetype !=H，所以这个236B可能会影响某些目押连段。

关于ctrl状态
Ctrl即可以自由行动的状态，那什么情况下ctrl = 0呢
1 出招的时候
2 受击的时候（无论防御，还是直接被打）
3 倒地的时候以及其他不能控制的时候

写立回时的ai不加ctrl会产生很严重的后果。
如果是攻击动作，就拿上面的立x来说，写ai时不加ctrl的话，那只要符合条件（比如上文里距离在0到40之间），那在这种情况下，会不断的出立x，而且会在立x动作没有完成甚至还没产生判定的情况下，再强行重头做立x的动作。
你就会发现ai会在这个距离内鬼畜般的重复做立x的动作，而且很可能打不中人。（因为很可能判定还没出来又重新出立x了），这时游戏可能会卡。
即使被对手在这时候命中，也不会做被打中的动作，还是强行出立x。
如果是防御动作没加ctrl，那在出任何招的过程中，都能无视硬直强行收招防御，甚至被打了，都能强行转入防御，一个bug人物就此诞生。

所以写立回ai的时候，一定要加ctrl。但连段“取消”的时候，不能加ctrl（关于连段，下个教程会说明）

关于p2dist和p2bodydist
P2dist表示p1与p2两者中心之间的相对距离，p2bodydist表示2者人物框之间的相对距离，一般来说差别不大。除非某些特殊情况下，一般2者都可以随便用。
一般情况下推荐用p2bodydist。某些特殊情况才用p2dist
P2dist有p2dist x和p2dist y之分，p2bodydist也一样。
P2dist x表示x方向，即水平方向的距离，y则表示垂直方向的距离
P2dist x的数值大于0 表示p2在p1前面，小于0就是在后面
P2dist y的数值大于0表示p2在p1下面，小于0表示在上面

另外自己和对手相对于地面的绝对高度可以用pos Y和enemy, pos Y表示，enemy也可以换成enemynear，表示离自己最近的敌人，在双人赛里有用。
用enemy和enemynear不只可以读取对手的位置，可以读取对手的各种参数，在ai中可以用来判断对手状态，很有用。

以上的各种参数具体请参阅trigger表

关于random（随机数）
系统每一F都会产生一个0到999的随机数，这就是random，每F都在变化
random是控制概率用的，random<300，就是每F有30％的概率。Random>700也是30％概率。Random<=1000就是100％的概率，random=500就只有千分之一的概率。（注意不是random<=500）
比如那个立x的立回ai就是当对手在0,40之间，每F都有30％的概率出立x。
剩下70％的可能就是做其他动作，包括发呆

用debug模式测量距离
所谓简易ai，就是知道且只知道在什么距离下出什么招的ai。
所以我们要做简易ai，就要知道招式的有效距离为多少。按距离出招也是立回的最主要模式
那怎么才能测出招式的距离呢？这时我们就继续使用万能的debug模式。

在state -2或者state -3中加入DisplaytoClipboard的type
当然只是显示距离的话，写在哪里都可以，但要显示其他var或fvar等变量的话
一般ai是写在state -3里就写在state -3的最下面。
没state -3就写在-2里面，不过要写在所要显示的var的定义指令下面
总之现在只是显示距离的话，不用管这么多。没有的话就随便写，有现成的type = DisplaytoClipboard的指令就在这上面直接改就好了

只是要显示距离的话，不必那么复杂
直接复制进去下面的指令就够了（其实下面推荐用p2bodydist x和p2bodydist y，但图是显示p2dist的，懒得再截一幅图了）
[State -2, Display] ;或者state -3
type = DisplaytoClipboard
trigger1 = 1
text = "p2dist x : %d | p2dist y: %| eposY : %d| frontedgedist: %d"
params = ceil(p2dist x) , ceil(p2dist y) , ceil(enemy,pos Y), ceil(frontedgedist)

text是屏幕上显示的文字，%d则与下面的params一一对应。ceil是取整，因为%d对应的是整型变量（整数）。
而%f可以对应浮点型变量（小数）。这里用不着。
Frontedgedist表示自己离前面版边的距离，在版边的行动中有作用

然后以1p进入mugen的训练模式，就可以看到左下方的信息中最后1条就是刚才添加的信息。

主要看p2dist x。在不同距离出招，看能否打中，记下能打中的p2dist x的值的范围。
至于p2dist y，由于人物跳起时高度不断变化，很难测，要求不高的话大概记得个范围就可以了。
地面技的对空范围也可以用enemy,pos Y表示
一人站在左版边，一人站在右版边的话
双方p2dist x 290－300，p2bodydist x大概为260。
而屏幕上下的距离大概150左右（可能有误，自己再测测吧）。

然后就按照上面的例子，写每一招的立回ai就可以了
[State -3,立x]
type = ChangeState
value = 200
triggerall = Var（59）= 1 && roundstate = 2
triggerall = Statetype != A
triggerall = p2movetype != H
triggerall = ctrl
trigger1 = P2dist X = [0,40]
trigger1 = p2dist y = [-30,30]
trigger1 = random < 300

[State -3,立y]
type = ChangeState
value = 201
triggerall = Var（59）= 1 && roundstate = 2
triggerall = Statetype != A
triggerall = p2movetype != H
triggerall = ctrl
trigger1 = P2dist X = [0,60]
trigger1 = p2statetype= S || p2statetype = C ;如果某一招基本只能打到在地面的人物的，就可以这样写，不用管p2dist y了。
trigger1 = random < 350
依次类推。

注意
Trigger1 = p2dist x =[0,40] && random < 300
这样系统是不认的，会出错，必须改成这样
Trigger1 = (p2dist x = [0,40]) && random < 300

小技巧：在debug模式里测招式的发生速度
Debug状态下，看那个time
一般招式击中对手时，会暂停一下。
趁这个瞬间看time：xx/yy，左边的xx就是这招的发生速度
还有个办法就是用fight factory或mcm看air文件了。这个比较麻烦。

投技的距离判断
一般“前+强攻击”这种形式发生的投技，cmd里一般在人用指令已经规定好距离的。（因为不在投技范围内按前＋强攻击，就会变成强攻击）
找到这个距离写在ai里即可
有些投技是用“ab”这种方式按的，或者是指令投，只好自己在debug模式里试试距离了
注意写投技的立回ai时通常要加一句
Triggerall = p2movetype != H
因为决大多数投技，投不了在防御硬直中的对手。

Ai里立回招式的书写顺序
Ai里立回招式的书写顺序也有讲究。因为系统读ai的时候，每一F都是从上往下读的。这样会造成一些问题。

比如
[State -3,立x]
type = ChangeState
value = 200
triggerall = Var（59）= 1 && roundstate = 2
triggerall = Statetype != A
triggerall = p2movetype != H
triggerall = ctrl
trigger1 = P2dist X = [0,40]
trigger1 = p2dist y = [-30,30]
trigger1 = random < 300

[State -3,立a]
type = ChangeState
value = 230
triggerall = Var（59）= 1 && roundstate = 2
triggerall = Statetype != A
triggerall = p2movetype != H
triggerall = ctrl
trigger1 = P2dist X = [0,30]
trigger1 = p2dist y = [-30,30]
trigger1 = random < 300

比如这样写的话。你会发现ai在水平距离0，40的范围里只会出立x，不会出立a。
因为当满足立a的条件时，必定满足立x，而ai是自上而下读取的，所以条件满足时必定先执行立x。
如果我们把立a写在立x前面呢，那水平距离在0，30范围内会出立a，而水平距离在30，40之间时会出立x
但如果我们把立a的random<300的条件，改成random = [300,600]，那在0,30的距离内，就既可能出立a也可能出立x了。
注意：此处原文描述存在错误。random应该是每次调用都会返回不一样的结果，而并非文中提及的每帧为一个结果，所以实际上立a依然可以执行（例如立x的随机数为400，立a的随机数为100）。若希望做到文中描述的效果，需要把random的结果赋值给变量来实现。

如果要做ai等级的话，通常就是用random和控制ai等级的变量来调整出招几率
比如用var(59)作为ai等级，那可以给某招加上
Triggerall = random <= 50*var(59)
这样var（59）越高，出招几率就越高了。

所以我们写立回ai的时候
原则上把使用条件苛刻的招写在前面（如超杀等）
凹技写在防御前面
主力技可以适当上调
其他普通技啥的写在后面

另外如果控制好距离差距的话，近距离用轻拳，轻脚或投，中距离用中，重拳脚，远距离才用飞行道具。这样对于几个攻击距离不太相近的招而言，顺序也不太重要。

也不一定要死套这个原则，有时具体情况要具体分析，可以看一个现成的ai。最主要的是要明白这个招是干什么用的，这样才能合理确定这招应该写在ai的哪个位置。


4.防御

                本页内容由net教授撰写. 由【softmgr】整理编辑.

虽说进入防御状态时，就脱离立回的状态了。
但是防御的确是格斗里最重要的一种动作。
当攻击无法打到对手，或者攻击处于不利的局面的时候，就是该防御的时候了。
这里先说点基本的。
一般的防御代码是这样的。
;---------------------------------------------------------------------------
[State -3,蹲防]
type = ChangeState
value = 131 ;蹲防的stateno
triggerall = var(59) && statetype !=A ;ai开启且自身不在空中
triggerall = p2statetype = C
triggerall = ctrl && p2statetype !=A ;这里加一个对手不在空中保险起见。
trigger1 = inguarddist ;inguarddist下面再详细解释
trigger2 = p2bodydist x < 0 && p2movetype = A ;当对手在你背后时不算在inguarddist内
;---------------------------------------------------------------------------
[State -3,立防]
type = ChangeState
value = 130 ;站防stateno
triggerall = var(59) && statetype !=A
triggerall = p2statetype != C
triggerall = ctrl
trigger1 = inguarddist
trigger2 = p2bodydist x < 0 && p2movetype = A
;---------------------------------------------------------------------------
[State -3,空防]
type = ChangeState
value = 132 ;空防stateno
triggerall = var(59)
triggerall = statetype = A ;自身在空中
trigger1 = inguarddist
trigger2 = p2bodydist x < 0 && p2movetype = A
;---------------------------------------------------------------------------

INGUARDDIST
什么叫inguarddist？字面意思是在防御距离以内。
那防御距离如何定义？
具体来说，当敌人的攻击接近你到一定距离以内，此时你按后，不再是后退，而是做防御动作，这个距离以内就叫做防御距离。此时也就是inguarddist。
对手不攻击或攻击离你太远，自然就!inguarddist。注意并不是说打得到你才是inguarddist，得看是不是在某个距离以内。
这个要看对手攻击的attackdist的定义。没有的话就用默认的值（好像是普通攻击160，道具90）
如果有一招把attackdist定义为0，那这招就算不是投技也没法防御。
其实实际运用时，你根本不需要知道inguarddist的定义，但这里解释下清楚一点。

防御和进攻的平衡
众所周知，防御的时候是不能进攻的，但不进攻就不能赢。
进攻的时候是无法防御的（除非你防御代码不加ctrl，这样是作弊），进攻必定出现破绽。
这就是防御与进攻平衡的难题。
给大家2个建议
1 强烈推荐除了可以用来凹的招以外，所有其他招都加上triggerall = !inguarddist。这样在对手先出手的情况下不会贸然进攻。
2 有特殊防御系统的（比如精防，弹刀），但进攻不是很强的可以适当限制下进攻。
如对手0.5秒内不攻击，才先出手。不过别太ws，比如等个10s再出招。这样会打得很难看。

蹲防和站防
在地面时，一般是对手蹲下时或对手的攻击属性为C时选择蹲防，其他的时候选择站防。
一般在空中不太会打出下段（这种情况也有，但极少，比如efz的狐狸的2424系列的空中扫射），
蹲下时一般不可能打出中段。

要注意中段才是蹲防不能，上段是蹲防和站防皆可，这是格斗基本知识，很多人搞错
但站立时既能打出下段的攻击，又能打出中段的攻击，经常见到ai被这种攻击打中。

原因就是对手站立时出招的属性难以判断。
这种时候可能需要用ai记忆攻击来做对策，我对这方面也不太清楚。
偷懒的话，可以尝试用蹲防完全代替站防，因为蹲防可以防下大部分的地面攻击，

对手在地面只能用中段技来打蹲防。
但中段技通常发生很慢，通常有足够空隙让你凹，甚至直接轻拳插掉。
话说回来，正因为如此，所以推荐让ai在有道具掩护等有利情况下再用中段技崩对手的蹲防。
所以对于完美的ai来说并不推荐这样偷懒的方法。。。

另外还有一个大问题，上面写的蹲防，站防代码只适用于第1次攻击。
对于之后ai在连携压制中的站蹲转换，系统是随机切换站蹲防的。。。
所以要改common1.cns。一般就是前面所说的winmugen\data下的那个系统默认的common1.cns
（不一定所有人物都用这个文件，看def里定义的stcommon）
如果是要改那个系统默认的common1.cns，请复制到此人物自己的目录里再改，最好再新建个文件夹（比如ai）
def里改一下stcommon = ai/common1.cns
因为这个common1是公用的，你改了这个会影响到所有人物。
我们一般要改的是common1.cns里的120-155这段的state
先看120，首先找到
[statedef 120]

看到这2段没有？
[State 120, Hi to Lo]
type = StateTypeSet
trigger1 = statetype = S && command = "holddown"
statetype = C
physics = C

[State 120, Lo to Hi]
type = StateTypeSet
trigger1 = statetype = C && command != "holddown"
statetype = S
physics = S
这就是人操作时的站蹲防切换指令。

我们把这2段改一下。

[state 120，Hi to Lo]
type = StateTypeSet
triggerall = statetype = S
trigger1 = var(59) = 0
trigger1 = command = "holddown"
trigger2 = var(59) > 0
trigger2 = p2statetype = C || (p2statetype = S && random >= 500) ;对手蹲下时蹲防，对手站立时，50%概率蹲防。
statetype = C
physics = C

[state 120，Lo to Hi]
type = StateTypeSet
triggerall = statetype = C
trigger1 = var(59) = 0
trigger1 = command != "holddown"
trigger2 = var(59) > 0
trigger2 = p2statetype = A || (p2statetype = S && random < 500) ;对手空中时立防，对手站立时，50%概率立防。
statetype = S
physics = S

然后再把
[State 120, Stop Guarding]
type = ChangeState
trigger1 = command != "holdback"
trigger2 = !inguarddist
value = 140
trigger1下面再加一行trigger1 = var(59) = 0
下面130-132的stop guarding也一样修改。就不多说了。

接着看state 130和131
[State 130, Hi to Lo]
type = ChangeState
trigger1 = command = "holddown"
value = 131

这里改成
[State 130, Hi to Lo]
type = ChangeState
trigger1 = var(59) = 0
trigger1 = command = "holddown"
trigger2 = var(59) > 0
trigger2 = p2statetype = C || (p2statetype = S && random >= 500)
value = 131

[State 131, Lo to Hi]
type = ChangeState
trigger1 = command != "holddown"
value = 130
改成
[State 131, Lo to Hi]
type = ChangeState
trigger1 = var(59) = 0
trigger1 = command != "holddown"
trigger2 = var(59) > 0
trigger2 = p2statetype = A || (p2statetype = S && random < 500)
value = 130

下面的state 140-142,state 150-153的
hi to lo和lo to hi的改法和120的基本一致，就不说了，注意state号别写错就行。
最后就是改state 150-155了

[State 150, 2]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*(command = "holddown")
这里改成
[State 150, 2]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*ifelse(var(59) = 0,(command = "holddown"),(p2statetype = C || (p2statetype = S && random >=500)))

[State 152, 3]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*(command = "holddown")
这里也一样改成:
[State 152, 3]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*ifelse(var(59) = 0,(command = "holddown"),(p2statetype = C || (p2statetype = S && random >=500)))
这样，防御中对敌人的中下段切换就会做出应对了。


5.移动

                本页内容由net教授撰写. 由【softmgr】整理编辑.

下面会出现triggerN，就表示triggerall底下的trigger1，2，3，4这些，那数字就用N泛指了。

先介绍个新的trigger
以下由trigger表精简＋补充

HitDefAttr(*,***)（击中定义属性）
获得游戏者当前活动HitDef中的属性参数。若游戏者不在攻击状态中，则该条件不触发。
能在CMD文件内从弱攻击到强攻击的简单招式中断中使用。
Format:（格式：）
HitDefAttr = value1, value2
value1
一个至少含有“S”、“C”和“A”其中之一的字母分别表示
站、蹲和空中攻击。例如，“SA”表示站立和空中攻击。
value2
2字符的字符串集，由逗号格开。每2字符的字符串必须是如下描
述的形式：
第一个字符可以是“N”表示“普通”，“S”表示“必杀”，
或“H”表示“超（必杀）”，“A”表示“所有”
第二个字符必须是“A"表示“打击” （一个普通hit打击），
“T”表示“投掷”，“P”表示“道具”
Example:（示例：）
1 trigger1 = A, NA，SA，HA
当游戏者在攻击状态，且当前攻击是空中的普通打击攻击，必杀打击攻击，或超杀打击攻击时触发
2 trigger1 = SCA, AT
当游戏者在攻击状态，且当前攻击是地面，蹲下，空中的所有种类投技时触发。

跳跃
如果你的人物的空中攻击性能很好，可以以空战为主的话。
那就不必加限制
如果你的人物空战能力相当弱的话，
我只推荐在1个时候跳，就是对手的攻击是投技的时候,即enemynear,hitdefattr = SC,AT。
不过要注意，当对手的攻击hitdefattr属性出来的时候，对手的判定也出来了。
当跳跃不是0F开始就对投无敌的话，那也没办法。还是指望无敌技凹吧。
其他的时候可以作一下限制

[State -3,跳跃限制]
type = ChangeState
value = 0
triggerall = var(59)
triggerall = statetype != A
triggerall = roundstate = 2
triggerall = enemynear,hitdefattr != SC,AT ;对手出投技时不限制起跳
trigger1 = stateno = 40
ctrl = 1 ;重新设置ctrl状态
IgnoreHitPause = 1 ;忽略暂停，即暂停的时候也继续执行trigger
这样就限制了人物的起跳了。其实其他动作也可以这样限制，不过除了跳跃外，要用到的不多。
另外跳跃性能高的话。还可以用来回避飞行道具。

跳跃方向的控制
一般def里使用默认的common1.cns定义跳跃的话。
无论往前跳还是往后跳，起跳动作都只有1个stateno，就是stateno 40。
注意这个stateno 40，定义的是起跳一瞬间的动作，此时人物还在地面上。
而在这瞬间，便决定了到底是往前还是往后还是原地笔直的跳。
人操作时，很明显，跳跃时按前后或者不按就可以操纵跳跃的方向。
但要控制ai的起跳方向就必须改点东西。

这里要用到一个系统变量sysvar(1)
这个就是控制起跳方向的变量。
sysvar(1) = 1就是往前跳，= 0就是原地跳，= -1就是往后跳

那我们就通过varset，让ai在某个条件下，向某个方向跳跃。
到def里stcommon指定的cns里找
[statedef 40]
一般可以看到下面有这2段文字
[State 40, 2]
type = VarSet
trigger1 = command = "holdfwd"
sysvar(1) = 1

[State 40, 3]
type = VarSet
trigger1 = command = "holdback"
sysvar(1) = -1
把2者改成

[State 40, 2]
type = VarSet
Trigger1 = var(59) = 0
Trigger1 = command = "holdfwd"
Trigger2 = var(59) > 0
Trigger2 = EnemyNear,StateType != L || P2BodyDist X >= (30左右)
Trigger2 = EnemyNear,MoveType = H || Random <= 333 || EnemyNear,StateType = L
Trigger2 = p2bodydist x >= 0
sysvar(1) = 1

[State 40, 3]
type = VarSet
Trigger1 = var(59) = 0
Trigger1 = command = "holdback"
Trigger2 = var(59) < 0
Trigger2 = EnemyNear,StateType != L
Trigger2 = EnemyNear,MoveType != H
Trigger2 = BackEdgeBodyDist>60
Trigger2 = Random <= 500 || p2bodydist x < 0
sysvar(1) = -1

注意
Trigger2 = EnemyNear,StateType != L || P2BodyDist X >= (30左右)
后面的p2bodydist >=(30左右)是为了起攻打逆用的个。具体多少数字看人物的跳跃和空中技性能。要是空中技没法打逆的话就删了吧。

回避
最主要的就是用来回避飞行道具。一般这么写
[State -1, 回避飞道]
type = changestate
value = 61 ;回避的stateno，这里随便写了个，具体你那个人物的回避动作是啥请自己到debug模式里看
triggerall = roundstate = 2 && ctrl && var(59)
triggerall = random <= 300
triggerall = prevstateno != 61 ;别连续回避
triggerall = facing !=enemy,facing ;和敌人的脸朝向不相同，面对面（如果朝向相同的话，就代表要么在敌人背后，要么敌人在自己背后）
trigger1 = enemynear,numproj >=1 || (enemynear,numhelper >=1 && p2movetype = A) ;敌人的project数大于等于1或敌人的helper数大于等于1且在进攻。
trigger1 = inguarddist
注意这里用了inguarddist，判断飞行道具是否接近你，这样就不会道具还远在天边的时候就开始回避了。。。
注意躲道具的回避动作要写在防御前面

道具有用project定义的，也有用helper定义的（这2东西具体区别就不说了，很麻烦，只要知道名字就行），但helper并不一定是用来攻击的。
所以enemy,numhelper>=1后要加个p2movetype = A。最好再加个p2bodydist x > 160之类的，因为有些人物近身普通攻击也带helper。
距离远的话，这攻击是道具的可能性就大大增加了

如果用来闪避近身攻击的话，
最好是闪避到对手身后，这个在debug模式里测下距离就行，通常做攻击动作时对手还会稍微接近点。

而且通常我们希望闪避完以后，对手还没收招。这样就可以确反了。
进debug模式训练时，左下角看见那个time没有?
通常以xx/xx的形式表示的，xx是数字。作不同动作时那个数字会变化
左边那个xx就是你当前这个动作进行了多少帧，右边那个是这个动作的全体时间。
我们要作的是先用一次闪避，搞清楚你的闪避动作的全体时间，假设是30F
那我们接下来写ai时就这么写,比如triggerN = ctrl && p2movetype = A && p2statetype !=A && enemynear,animtime <-30
animtime就是读取动作的剩余时间，总是负数,animtime = 0表示动作正好做完。
没有好的防空技的话，当对手从空中冲过来攻击的时候，闪避也可以防空用。
闪避性能好的话一般可以写在防御的前面。不过由于不加!inguarddist的条件，所以除了躲道具用的回避动作，其他写在防御后面好像也可以。

前冲
一般stateno = 100。主要是接近用，记得加!inguarddist。
对手倒地时(p2statetype = L)如果要压制也可以冲过去，当然你那人物压制能力要强。
不强的话，还是原地做蓄气，或者加buff之类的动作吧。
在有道具掩护的情况下跑上前压制也很常见.

前冲停止
到def里stcommon指定的cns里找
[statedef 100]
然后往下看能看到类似的文字。
[State 100, 4]
type = ChangeState
trigger1 = command != "holdfwd"
value = 0 ;某些人物这里写的是101，不用改
改成
[State 100, 4]
type = ChangeState
triggerall = roundstate = 2
trigger1 = var(59) = 0
trigger1 = command != "holdfwd"
trigger2 = var(59) > 0
Trigger2 = EnemyNear,MoveType!=H
Trigger2 = P2BodyDist X<=(約90)
Trigger2 = P2BodyDist Y>=(約-120)
trigger3 = var(59) > 0
Trigger3 = P2BodyDist X<=(約10)
value = 0
ctrl = 1 ;设置为ctrl态
距离可以更改，只要攻击打得到人就行

后退
一般stateno = 105。后退带无敌的可以躲攻击。
对手倒地后，也可以用来拉开距离
招式挥空，或者被防也可以后退弥补破绽。（用向后闪避也可以）
[State -1, 后退]
type = changestate
value = 105
triggerall = roundstate = 2 && ctrl && var(59)
triggerall = random <= 300
triggerall = facing !=enemy,facing
trigger1 ＝stateno = 430 && (movecontact = 0 || moveguarded) ;stateno是430的那招被防了或者挥空了（其实可以简化为!movehit）
trigger1 = animtime = 0 ;动作必须做完

总之这里只说了点基本的，具体的移动立回如何写，还得看人物性能具体问题具体分析
有些人物空中也有dash和backdash，这些人物的立回更复杂。
推荐看看别人写的ai作为参考。

受身
[State -3, 空中受身]
Type = ChangeState
TriggerAll = Vel Y > -1
TriggerAll = Alive && var(59) > 0
TriggerAll = CanRecover
trigger1 = stateno = 5050
Trigger1 = (p2movetype = A && enemynear,hitdefattr = sca,aa,ap,at) || p2movetype = H || p2statetype = L
Value = 5210
推荐这么写。
能受身的时候别着急受身，等对手攻击的瞬间再受身，利用受身无敌时间躲过对手的判定，这样比较有利。
太早受身的话，由于mugen默认受身后一段时间内无法防御，被对手抓受身的话会很惨。。。


6.切反，抓硬直，插动

                本页内容由net教授撰写. 由【softmgr】整理编辑.

切反就是在11区人编写的ai中常看见的“切り替えし”
有点类似于凹招。

先解释下凹的定义，凹其实就是对手攻击时，用带无敌的升龙或超杀等技，利用无敌时间，躲过对手的判定，打中对手。
连段中用升龙或超杀不算凹

再说下切反和凹的同异。
相同点是2者都是在p2movetype = A时做的动作。而且必须写在防御前面，不能加!inguarddist。
不同点是凹必须是用攻击反击回去，而且一般是在立回态。
切反不一定是用攻击，用带无敌的44后退，无敌的移动技（阿修罗闪空之类）躲避对手攻击也可以。
而且也包括了在防御硬直中才能发动的防反技。
其实写起来很简单，p2movetype = A的时候，出对应的招就行。。。

超反应相关
在p2movetype = A的时候，不考虑对手的出招整体时间的快慢，在符合条件的情况下立刻用各种切反，那就是超反应。
如果在某些情况下，不要超反应，那就得加个限制。
可以用random限制下几率
也可以设置反应时间
举个例子：
[state -3,626c]
type = changestate
value = 1320
triggerall = roundstate = 2 && var(59) > 0 && statetype !=A
triggerall = power >= 1000
trigger1 = ctrl && p2movetype = A
如果你不要超反应，那再加个条件：
triggerall = enemynear,time >= 30。
这样你的反应就是30F，当对手出招时间超过30F时再反应过来凹。
如果你想ai等级11以上开启超反应。
那么就这么写：
triggerall = enemynear,time >= 30 || var(59) >= 11 ;这里假设var(59)是控制ai等级的
或者使ai等级直接与反应时间挂钩也行：
triggerall = enemynear,time >= (33-3*var(59))

一般凹招必须再加一句triggerall = enemynear,animtime < -X
免得出现对手都快收招了你再凹结果被防的杯具。
X是升龙的发生时间，用前面教程里提到的方法测一下。
triggerall = enemynear,animtime < -X || var(59) < 9
写成这样的话,ai等级9以下就不计算对手收招时间了.。
最好再用random限制下概率：
triggerall = random <= 90*var(59)
做对人向的ai时，不推荐加入超反应。

抓硬直（隙付き）
先用前面教程里所讲的测招式发生速度的办法，测下某招的发生速度
假设测出某招是15F，那在这招的state下加入：
triggerN = !inguarddist && enemynear,animtime < -15
triggerN = p2movetype = A || (p2movetype = I && !enemynear,ctrl) ;对手在攻击时或做无法控制的非攻击动作时。
推荐把作为起手连段伤害高的招写在前面

插动（抢招）
这个是一种赌博般的行动。
不是用无敌技凹，是用发生快的轻拳，轻脚打掉对手的攻击，一般写在防御前面，不写!inguarddist。
11区那边写的ai里以“暴発”表示
一般含有类似语句：
triggerall = p2movetype = A
triggerall = ctrl
triggerall = enemynear,time <= 1 ;重点是这句，必须在对手出手后1F以内。否则风险大增。
trigger1 = random <= 100 ;概率不能太高，毕竟是赌博。
trigger1 = p2stateno != 200 && p2stateno != 400 ;可以考虑加这句，一般对手的轻拳和蹲下轻拳是这2个state号，出轻拳时一般插不掉。
通常用来插动的轻拳或轻脚发生要快点，最好5F以下，7F以上的还是免了。攻击范围越长越好。


7.连段

                本页内容由net教授撰写. 由【softmgr】整理编辑.

先介绍下连段和连携的区别。
你打中对手了，之后进行的是连段。
对手防住了，你之后进行的是连携，也就是一般所说的压制。

（1）连段开发
你要做连段的ai，当然你自己得会这个人物的ai。
如果你对这个人物不熟悉咋办？
最好查阅相关的资料wiki，看这人物有什么连段。有些人物的readme文件里也有写连段。
如果是原创人物，没有相关连段资料，那就得自己进行连段开发。

连段开发不是瞎摸索，是有规律的。
最主要的是要知道这个人物的取消链。
所谓“知道取消链”，用俗话说就是知道“哪招后面可以接哪招”，
不过有点微妙的不同，暂时这样理解也没啥问题。

先说下什么叫取消：
A招后用B招先“取消了A的收招硬直”，然后出B招，那叫做取消。
A招后等A自然收招，再出B招，那就不算取消。

一般性人物的取消链是：
A：普通技（单发的a，b，z啥的）－特殊技（6a，6x这种）－必杀（24a，626c这种）－超杀（2624，426426之类）
B：普通技或特殊技 - 必杀或超杀

A类型的取消链就比较长，
B类型的取消链就比较短。（普通技和特殊技，必杀和超杀之间不能相互取消）

有些系统普通技中可以按轻拳（A）－中拳（B）－重拳（C）的方式取消，那也是比较常见的abc系统。

某些系统有更特殊的取消链
比如mbac这种，可以A-B-C，也可以C-B-A。但A-B-C-B-A是不行的，前面取消用过的招不能再用。（但等C完全收招以后，再出b是可行的，因为这不算取消了）
像efz在某些必杀甚至超杀后，都可以用22c强制取消，不过要消耗RF槽。
这些看看相关系统的说明就知道了。

有不少系统，在某些技后可以用跳跃取消，那就是跳取消（jump cancel）。
有些系统某些技后可以用66之类的前dash取消，那就是前冲取消(dash cancel)，空中的就是空dash cancel。
其他更多的就不多说了。

一般取消链在人物目录下的readme文件里有写，有些readme里面还直接给出几个连段，那样更好。

你也可以看cmd文件里的人用指令：
举个例子
[State -1, 623A]
Type = ChangeState
Value = 1002
TriggerAll = var(59) = 0
TriggerAll = var(50) != 101
TriggerAll = StateType != A
TriggerAll = Command = "623a"
Trigger1 = (Ctrl) || (StateNo = 100)
Trigger2 = ((StateNo = [200,204]) && (MoveContact)
Trigger3 = ((StateNo = 205) && (Time > 35) && (MoveContact))
Trigger4 = ((StateNo = 400 || StateNo = 402)) && (MoveContact)
Trigger5 = ((StateNo = 250) && (Time > 22))
Trigger6 = ((StateNo = 251) && (Time > 33))
Trigger7 = ((StateNo = 252) && (Time > 35))
Trigger8 = ((StateNo = 450) && (Time > 13))

其中trigger1是立回，trigger2以下就是取消了。
挑几个说，
trigger2表示state号1002这招，可以取消stateno为200到204的招式（也就是可以接在这些招的后面），不过有个条件是movecontact。
这说明，你200－204，这几个招，必须打到对手（被防也可以），才能取消1002。挥空就无法取消，只能等招式收招。。。
但只要是击中对手，在200-204收招之前，无论何时都可以取消1002这招。
假设204全体动作有60F（约1秒），那只要击中，那60F之内无论何时都能自由取消1002。

trigger3里面stateno = 205后有个time，说明这招打中后，不是立刻就能取消1002的，要等到35F以后才能取消。挥空同样不能取消。
在trigger5里注意没有movecontact，说明不管打中对手与否，只要time>22，都可以取消1002。这种叫做“空振取消”。

如果嫌看cmd很麻烦的话，还是自己进训练模式摸索吧。

另外说点写连段的原则
一般人物为了防止无限。总是会加各种限制的。
比如浮空时，打过几下后，对手将不再被普通技击中。（但有些超杀此时可以击中，当然超杀一般是不能无限用的）
修正低于一定值后无法命中之类。

不过有些人物还是有无限的。（有些无限虽然因为修正很难打死人，但可以用来拖时间）
格斗新手来说可能很喜欢玩无限，
但在老手眼里，无限连是很无聊的东西。
因为这就相当于把包含立回，压制，充满各种攻防转换的格斗游戏变成了单纯的一方的连招游戏。

所以请写ai的各位自重，尽量不要写无限连。
如果还是想写，也必须加个var做开关（或者与ai等级挂钩也可以），能让人自由开启或关闭无限。
发布的时候请在readme里面注明。
消耗低，难度低的10割连也请这样处理。
除非你是想做凶狂级别的人物。否则最好这么做，免得自己写出的ai被人喷。

（2）正式连段教程

A 取消式连段
通过取消形成的连段。这是连段的最基本形式。
还是来看例子吧。

首先还是看cmd里的人用指令。假设你想在某招后连623a

[State -1, 623A]
Type = ChangeState
Value = 1002
TriggerAll = var(59) = 0
TriggerAll = var(50) != 101
TriggerAll = StateType != A
TriggerAll = Command = "623a"
Trigger1 = (Ctrl) || (StateNo = 100)
Trigger2 = ((StateNo = [200,204]) && (MoveContact)
Trigger3 = ((StateNo = 205) && (Time > 35) && (MoveContact))
Trigger4 = ((StateNo = 400 || StateNo = 402)) && (MoveContact)
Trigger5 = ((StateNo = 250) && (Time > 22))
Trigger6 = ((StateNo = 251) && (Time > 33))
Trigger7 = ((StateNo = 252) && (Time > 35))
Trigger8 = StateNo = 450

这是人用指令

不看trigger1，后面的trigger告诉你，这么多招后都是可以接1002的。
但我们不需要写那么多。也不能把这些代码都原封不动照搬到ai上去。
为什么呢？
我们要对这些招具体分析

假设你写的是一个abc系统的连招，
假设上面那些trigger告诉你的是，a后面可以接这623a（1022这招），b后面也可以，c后也可以连,
2a,2b,2c以及其他某些招后也都可以

但我们不可能让a后就直接连那个623a的吧？
原因1：a后面的硬直可能连不上623a
原因2：就算能连上，伤害并非最优的。a b c 623a这样伤害更高。

所以我们只要就写c或2c后连623a就行了
然后在下面再写a后连b（或2b），b后连c（或2c）的代码。

由于我们是写连段，所以应该把movecontact改成movehit。确认命中后再接623a。
当然如果623a被防后仍然有利的话，那保持movecontact不改也可以，否则，一定要改成movehit。
不是所有招既可以用来连段，也能用来连携的。

接着注意trigger5以后。由于是空振取消，你如果不加movehit，那即使stateno = 250那招挥空了，也会取消623a，可能会造成很大的破绽。
不过由于是空振的属性，也可以这么用，250挥空时如果对手想抓住这个破绽进攻，可以取消623a，凹掉对手的攻击（当然这个623a得有无敌时间）

如果251或252后接623a没有价值（比如修正太低，没伤害，或者根本接不上），那我们只需要写空振后防止对手进攻的代码就行了。

假设450这招是个多段技，可以看出这招全程都可以取消623a。
我们当然希望要让这个多段技所有段数打满再接623a，而不是第1下就接623a，这时就不要直接写movehit
而是写一个time >= 39（time = 39也可以，不过用>=保险点） ，假设39F以后才是打满，之后再写movehit。
这种也算是延迟取消

PS：其实可以写成movehit >= 39。
本来就可以用movehit = X或[a,b]这种形式来指定这招击中后的时间。
不过个人感觉还是写time >= 39保险点。

[State -1, 623A]
Type = ChangeState
Value = 1002
TriggerAll = var(59) > 0 ;ai启动时，这样就与人用指令区别开来了。
TriggerAll = var(50) != 101 ;triggerall里除了command和ai开关以外的东西必须照抄，即使你不知道这是啥意思，这是为了防止ai做出系统不允许做出的动作。
TriggerAll = StateType != A
Trigger1 = (Ctrl || StateNo = 100) && p2movetype !=H ;加个p2movetype != H是为了防止影响某些非取消性连段。其实最好把立回指令写在别的地方。
trigger2 = stateno = 202 || stateno = 402) && movehit ;假设这2招就是c和2c的stateno，在这2招后接623a
Trigger3 = StateNo = 250 && Time > 22 && (movehit || p2movetype = A) ;要么接上，要么对手此时在进攻，对手不进攻就不取消，否则破绽大（注意movehit的时候，p2movetype必定为H，而不是A）
Trigger4 = StateNo = 251 && Time > 33 && p2movetype = A
Trigger5 = StateNo = 252 && Time > 35 && p2movetype = A ;这2招无连段价值，只需要写提防对手进攻的代码就行了
Trigger6 = StateNo = 450
trigger6 = (Time >= 39 && movehit) || p2movetype = A ;打中了当然要等这招打满再接623a，没打中的话只要对手进攻，就得立刻反击，否则来不及。

然后下面再写a接b或2b，b接c或2c的指令

[State -1, c]
type = changestate
value = 202
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype !=A
triggerall = p2statetype !=C ;假设c打不到蹲下的人
trigger1 = stateno = 201 || stateno = 401 ;接在b或者2b的后面
trigger1 = movecontact && random < 500 ;给连段加点变化，b后面可以接2c也可以接c。用movecontact表明即使b被防，取消c也没啥关系，不用确认命中。

[State -1, 2c]
type = changestate
value = 402
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype !=A
trigger1 = stateno = 201 || stateno = 401
trigger1 = movecontact ;这里不加random，就能保证在没接c的情况下一定接上2c，因为代码是自上而下读取执行的。

[State -1, b]
type = changestate
value = 201
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype !=A
triggerall = p2bodydist x < 50 ;这b比较短，必须距离比较近才能接上
trigger1 = stateno = 200 || stateno = 400 ;接在a或2a后面
trigger1 = movecontact && random < 600 ;由于伤害稍高，可以提高几率

[State -1, 2b]
type = changestate
value = 401
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype !=A
trigger1 = stateno = 200 || stateno = 400
trigger1 = movecontact

a的指令在立回指令里，a前面自然没啥东西好连的。

这样a/2a - b/2b - c/2c - 623a的一套连段就完成了

一般写连段推荐把取消链等级比较高的先写（比如超杀，必杀），等级比较低（轻拳啥的）写在后面。

但有时候必须反过来。比如想让2aaa多点几次再连b，那么就得把2a写在b前面，否则2a一次后直接连b了。
不过要加点限制，不然由于系统是自上而下执行指令，会造成一直点2a而不接b

比如这样
[state -1, c]
略

[state -1, 2a]
type = changestate
value = 400
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype !=A
trigger1 = ctrl && p2movetype !=H && !inguarddist ;立回用
trigger2 = stateno = 400 && movecontact && (p2bodydist x = [0,30]) ;后面的距离限制要用括号括起来，否则会出错。没距离限制会一直点2a不接b，直到距离不够挥空为止。

[state -1, b]
略

用跳取消空连的话也差不多，比如写一个2abc 5c jbc jbc （j是跳的意思）
前面就按地面取消那样写，5c后那个跳取消就这样。

[state -1, varset]
triggerall = var(59) > 0 && roundstate = 2
trigger1 = p2movetype = A && p2movetype = H
trigger1 = p2dist x >= 0
sysvar(1) = 1 ;这里前面教程里讲过，保证连段里必须往前跳。

[state -1, jump cancel]
type = changestate
value = 40
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype != A ;注意stateno 40是起跳瞬间，此时人还在地上。
trigger1 = stateno = 202 && movehit && p2statetype = A ;对手在空中，对手不在空中跳了会连不上

[state -1, jb]
type = changestate
value = 601
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype = A ; 这里自己在空中了
trigger1 = p2bodydist x = [0,40]
trigger1 = p2bodydist y = [-40,20] ;限定距离，别刚跳上去，对手还离得远远的就出jb了，看jb的判定自己调整
trigger1 = ctrl && p2movetype = H && p2statetype = A && (p2stateno != [120,159]) ;跳取消后处于ctrl态，对手是空中受击态，且不在防御，其实这里算是空中目押。

[state -1, jc]
type = changestate
value = 602
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype = A
trigger1 = stateno = 601 && movehit ;一般jb打中后必定能接上jc的话，就不用限制距离了

[state -1, air jump cancel]
type = changestate
value = 45 ;空中跳的state
triggerall = var(59) > 0 && roundstate = 2
triggerall = statetype = A
triggerall = var(6) <= 1 ;一般都有个限定空中跳取消次数的变量，否则会让你一直jbc jbc突破天际的- =
trigger1 = stateno = 602 && movehit

然后jb，jc就不必写了。

因为第2次jbc和第1次的条件没啥2样。

其他的取消式连段也是类似情况。多看看别人写的ai会更好的理解。

B 非取消式连段

不是取消的话，就是得等某招完全收招后再连。
分2种情况，一种是最速，一种是目押。
这里的目押和一般格斗意义上的不同，就是泛指非取消式的连段。
（一般格斗意义里严格的目押还有时间限制的意义，必须在几F内，不能早也不能晚。不过对ai来说，目押的难度不在于时间的长短。）
非取消连段里的最速也算包含在目押内，但情况比较特殊，所以分开讲。

  • 1) 最速

    • 就是在某一招收招后，立刻出另一招
    2种做法
    一种是利用animtime = 0，一种是利用prevstateno。

    还是例子

    [state -1, 26a]
    type = changestate
    value = 1000
    triggerall = var(59) > 0 && roundstate = 2
    triggerall = statetype != A
    trigger1 = stateno = 1201 && movehit && animtime = 0
    trigger2 = prevstateno = 1201 && ctrl
    trigger2 = p2movetype = H && p2statetype = A

    这2种都是表示在state号1201的招后最速接26a(stateno 1000)。其实2个trigger只要用1个就行了。
    这2者有些微妙的区别。

    trigger1表示此时动作的state号还是为1201，不过已经进行到最后1F了，但此时并非ctrl态，而且可以用movehit确认1201是否命中。
    trigger2表示前面那招是1201，此时处于ctrl态，动作号已经不是1201了，一般此时动作号是0，此时不能用movehit确认命中情况了，必须用其他方法确认。
    严格来说trigger1比trigger2快一点点，但trigger2是人类能够做到的，trigger1是不可能的，因为要操作角色必须在ctrl态。
    不过一般2者看不出啥区别。我个人推荐最好用trigger2的形式，有时用trigger1的形式会出现点bug。
    不过trigger1能确认movehit和调整连段确率，有时更方便。

    PS：trigger2那种形式的也不一定是最速，因为mugen自带ai的干扰，有小概率会做出下蹲，跳跃等动作，这样会导致连段失败。
    此时可以考虑用trigger1那种形式。或者对特定状态下的下蹲和跳跃做限制。

    再说个prevstateno的用法

    假设A接B后可以接C，但D接B后只能接E，
    那在stateno = B命中的时候，可以用prevstateno判断前面那招到底是A还是D。

    比如这样
    [state -3]
    type = changestate
    value = 202
    triggerall = var(59) && roundstate = 2
    trigger1 = prevstateno = 200
    trigger1 = stateno = 201 && movehit

    [state -3]
    type = changestate
    value = 203
    triggerall = var(59) && roundstate = 2
    trigger1 = prevstateno = 205
    trigger1 = stateno = 201 && movehit

  • 2) 目押

    • 和最速的不同在于不能立刻出另一招，必须得在某些条件下才出招

    比如必须让对手自由下落到某一个高度再接某招：
    [state -1, b]
    type = changestate
    value = 201
    triggerall = var(59) > 0 && roundstate = 2
    triggerall = statetype != A
    trigger1 = prevstateno = 1300 && ctrl
    trigger1 = p2movetype = H && p2statetype = A
    trigger1 = p2stateno != [120,159]
    trigger1 = enemynear, vel y > 0 && enemynear, pos Y >= -80 ;前面是表示当对手下落速度大于0时（小于0就是上升），确认其处于下落阶段，后面是确定对手的绝对高度（由于statetype != A，所以可以不用p2dist y这种相对高度来测量）

    这是比较基本的目押，一般要求不高就这样好了。
    如果要提高精度的话，可以把速度计算进去。不过这样就很麻烦了，需要计算，下落不是恒速的还要算加速度。如果不是要求特别高不必这样。

    还有些就像空连后最后控制高度再出招，使得j攻击后能连上地面普通技，这也是一种目押。
    具体的看其他人写的ai吧。

    一些复杂系统的连招

    这里没啥实质性内容。只是吐点槽。
    如bbb，北斗，ggxx，efz，墙角心等格斗的连招是很复杂的，一套没10几，20几hit下不来。
    要把连招做得好一点，不是靠简单的取消就可以完成的的。
    要靠各种var或fvar来控制。

    有些连段，看上去好像很民工，实际上无论自己试过就知道完全不是那回事。
    很多连段起跳后不能立刻接j攻击，必须压低高度目押出j攻击，为了之后连招方便。
    有时为了提高伤害，jb后必须延迟取消jc，这样落地后才能接上地面招增加伤害。
    而地面接招必须要计算高度，要精确目押的话还要计算重力加速度。
    连超杀还得考虑修正因素，否则接了超杀没伤害反而浪费气。
    还必须有var限制起跳和空dash次数。
    还得考虑连段后的起攻情况

    墙角心和北斗也可以看出空连时有延迟的情况。

    所以实际编起ai来很复杂，很辛苦。新手的话不推荐编这种连段比较复杂的系统的ai。
    实在有爱的话，请做好觉悟。最好从已经有的ai改起。
    要让ai乖乖听话可并不是很容易的事情，有一个变量没搞好就会经常出状况。

    这里说点原则
    1 尽量用人物已经有的变量来控制连段，比如修正，hit数(用enemynear,gethitvar(hitcount)来读取)之类。
    实在不行才用自己设置的变量。而且这个变量不能与已有变量冲突。

    2 用自己设置的变量也最好做到用一个变量对应几个连段，而不是用多个变量对应多个连段

    比如用一个fvar(20)就可以对应很多情况了
    [state -3]
    type = varset
    trigger1 = 条件1
    fv = 20
    value = 0.1 ;fvar最好用这种方式定义，不要直接写fvar(20) = 0.1，否则容易出错

    [state -3]
    type = varset
    trigger1 = 条件2
    fv = 20
    value = 1.5

    。。。。。。

    3 一般人物可以用var(0)-var(59),fvar(0)-fvar(39)共60个var，40个fvar
    变量如果用完了可以定义一个helper
    helper自己的var(0),fvar(0)等与本体的var不冲突。

    比如这样
    [State -3,ai helper]
    Type = Helper
    Trigger1 = NumHelper(7777) = 0
    Name = "AI helper"
    StateNo = 7777
    ID = 7777
    PosType = P1
    Pos = 0, 0
    Ownpal = 1
    IgnoreHitPause = 1
    SuperMoveTime = 99999
    PauseMoveTime = 99999
    SprPriority = 7

    注意stateno和id不要与已有的helper冲突。

    然后在ai文件里新建个
    [Statedef 7777]
    Anim = 9999
    Ctrl = 0

    再在下面定义变量即可

    [State 7777,fv26]
    Type = VarSet
    TriggerAll = Parent,Var(59)>0
    trigger1 = Parent,stateno = 1020 ;对于本体的各种数据必须加上parent前缀，是helper(7777)自己的变量或stateno就不要加前缀了
    trigger1 = enemynear,movetype = H && enemynear,statetype = A
    trigger1 = enemynear,stateno != [120,159]
    Fv = 26
    value = 1
    IgnoreHitPause = 1

    这里就定义了一个helper(7777)的fvar(26)
    在ai里用的时候就这样写
    trigger1 = helper(7777),fvar(26) = 1 ;一定不能忘记helper(7777)的前缀，否则系统会判定为本体的fvar(26)

    （3）连段的测试
    编了一套连段总得做测试。但直接进watch模式看ai对战，效率实在太低，不一定正好有机会能用到你编写的连段。
    这里推荐一个小技巧，就是利用ai开关。

    比如你要测试2abc 5c jbc jbc的空连。
    前面的取消基本没啥问题，关键是看5c（立c）打中空中的敌人后，ai是不是会好好的空连。

    [State -3, ai switch]
    Type = VarSet
    triggerall = Var(59) = 0
    trigger1 = Command = "AI00" || Command = "AI01" || Command = "AI02"
    trigger2 = Command = "AI03" || Command = "AI04" || Command = "AI05"
    trigger3 = Command = "AI06" || Command = "AI07" || Command = "AI08"
    trigger4 = Command = "AI09" || Command = "AI10" || Command = "AI11"
    trigger5 = Command = "AI12" || Command = "AI13" || Command = "AI14"
    trigger6 = Command = "AI15" || Command = "AI16" || Command = "AI17"
    trigger7 = Command = "AI18" || Command = "AI19" || Command = "AI20"
    trigger8 = Command = "AI21" || Command = "AI22" || Command = "AI23"
    trigger9 = Command = "AI24" || Command = "AI25" || Command = "AI26"
    trigger10 = Command = "AI27" || Command = "AI28" || Command = "AI29"
    trigger11 = Command = "AI30" || Command = "AI31" || Command = "AI32"
    trigger12 = Command = "AI33" || Command = "AI34" || Command = "AI35"
    trigger13 = Command = "AI36" || Command = "AI37" || Command = "AI38"
    trigger14 = Command = "AI39" || Command = "AI40" || Command = "AI41"
    trigger15 = Command = "AI42" || Command = "AI43" || Command = "AI44"
    trigger16 = Command = "AI45" || Command = "AI46" || Command = "AI47"
    trigger17 = Command = "AI48" || Command = "AI49" || Command = "AI50"
    trigger18 = Command = "AI51" || Command = "AI52" || Command = "AI53"
    trigger19 = Command = "AI54" || Command = "AI55" || Command = "AI56"
    trigger20 = Command = "AI57" || Command = "AI58" || Command = "AI59"
    trigger21 = Command = "AI60"
    trigger22 = stateno = 202 ;加上这条trigger，假设202就是5c的stateno

    然后进入训练模式
    自己连2abc 5c，当你出完5c后，ai就接管控制权了，你自己就无法继续控制了。这样就知道ai是否能顺利完成之后的空连了。

    之后的预定
    连携与起攻
    helper与var

    各种小技巧与问题等等


高级AI教程

目录

1.前言及新手须知

2.AI概念简述及Mugen人物运作基础知识

3.语法、运算符与表达式

4.常用Sctrl与trigger与常见错误

5.变量Var简介、Cmd简介、AI开关设置及手操指令修改

6.debug相关、Air简介、人物性能调查

7.AI框架与代码顺序

8.公用状态修改：移动、跳跃、受身及防御


1.前言及新手须知

                本页内容由口水轩撰写. 由【softmgr】整理编辑.

大家好，欢迎收看此教程。该教程由口水轩编写，并由本网站根据实际情况进行了部分增删内容，以下是正文

首先笔者才疏学浅，这篇东西也没什么资格叫做教程的，暂且做个标题党骗骗新人吧XD。
先声明，写AI并不是一件容易的事，就好像你要教一个小孩子走路，没有一定的毅力和爱是坚持不下来的。
而且需要长时间的测试磨合debug，第一次写一个好的AI就需要起码3个月的时间
（笔者驽钝第一个成功的人物就写了半年，当然写熟了之后时间可以大大缩短）。
如果做好了心理准备真心要学，

     ＼ ／
     ＼ ∧_∧ ／
     | ∩( ^ω^)∩ |
     ／ \ / ＼
     ／ (⌒つ⌒) ＼

想开课，好！

另外在此必须感谢一直/曾奋斗在Mugen一线的前辈/朋友们，如Net教授、四娘、螺丝、凯少、MKII君、南风君、DIO爷等。
Net教授在AI方面非常著名，例如华丽哥、神奈等。
当然还有那经典的AI教程，本文会经常借（chao）鉴（xi）Net教授的教程（说实话我真想直接把Net教授的教程抄过来...OTL）。
四娘精通Mugen多个层面，在技术层面也给了很多的帮助。
先感谢两位的指导OTL。
螺丝前辈也经常解答新人们的问题，在此致以敬意。
凯少、MKII君、南风君、DIO爷也是相当有名的AI作者，不多说了，多谢几位平时的交流。
理论上来说，懂得基础计算机理论的朋友可能学的比较轻松，Mugen这个引擎本来就是C写的。
不过没有计算机理论的朋友也不用灰心，用努力绝对能够补得回来。
起码笔者学的时候也是没学C的，除了VB啥都不会...
其实Mugen写AI能用到的东西...笔者作为一名计算机系学生...我们的课3周内就说完了OTL...之后课程讲凶恶向...
PS：本文全部例子全部使用KFM，因为毕竟笔者写过KFM的AI，对其比较熟悉，人物简单易懂，具有普遍性。
另，如需转载，麻烦不要删作者就行了OTL

==================================================
1.3新手须知
==================================================
--------------------------------------------------
新手须知：
1.国际惯例：请用英文半角写，这不是识别中文的Mugen
2.请勤备份，否则改出个BUG来不会改回去的后果自负，起码笔者是每次改动都备份一次的
3.请尊重人物作者，修改性能要谨慎（后面会讲AI和性能的区别，2.1），公开AI之前要先向人物原作者取得同意
4.要有耐心和毅力，罗马不是一天建成的，笔者见过不少人坚持不下来TJ掉的。初次看不懂在说什么其实不要紧，毕竟初次接触新的事物总得要慢慢消化吸收的，坚持就是胜利
5.切勿好高骛远，作为新手能把一个正常AI能到凶级的性能的人物编成没有BUG的非魔改强级就不错了，踏踏实实学一定会有进步的
6.请对你的人物倾注你的爱，这样你才能在人物编的不好的时候领悟到悲伤（PIA飞）
7.多读多练：看别人写的AI，尝试理解为什么别人这么写；还有就是多实践，实践出真知，动手实践便知对错
8.如Net教授所说，一开始请先尝试改别人写好的AI，因为整个框架别人已经写好，不易出错，方便练手；之后就可以尝试按照自己的思路写AI，建议先尝试系统简单、变化少的人物，例如KFM、王者之拳、侍魂、街霸2、KOF94之类的人物，系统、连段太复杂的人物会搞得新手很绝望的（如GG北斗什么的）...
9.⑨最强
10.待续...

准备材料：
必备：
记事本（即txt）/notepad2/notepad++用于编写AI，notepad2/notepad++还可以当日文乱码翻译+检查括号数（笑）
trigger表和Sctrl表基础语句，这个都没读的话还真不知道怎么写，文档翻译版下载
Mugen原程序+至少一个人物包呃...不解释
推荐：
Fighter Factory(FF)如果不习惯用txt可以用于编写AI，还可以用于查看各种人物性能
另外用FF看air会比较直观，建议使用，下载地址：//pan.baidu.com/s/1o63KKXk


2.AI概念简述及Mugen人物运作基础知识

                本页内容由口水轩撰写. 由【softmgr】整理编辑.

==================================================
2.1AI概念简述
==================================================

显而易见，AI就是爱的拼音...所以没有了爱，人物就弱了很多，必须有爱才能领悟到悲伤...（PIA飞）
AI是人工智能(Artificial Intelligence)的缩写，是计算机科学的一个分支。
它企图了解智能的实质，并生产出一种新的能以人类智能相似的方式做出反应的智能机器。

一说到AI，就有不少人认为它是高深莫测的东西。
在现实的人工智能学术领域，不但要懂计算机，还要懂心理和哲♂学（误）等等相关学科，才能模拟出人的智能。
但是在Mugen当中，AI并没那么复杂，有计算机基础的同学可以大概理解为，所谓电脑AI，其实是一组组if语句。
（if语句即判定所给定的条件是否满足，根据判定的结果（真或假）决定执行给出的两种操作之一）

简单来说，就是你要教电脑在什么时候做什么东西。例如，
如果对方打你，你就防御...
如果对方在远处，你就出个飞行道具吓吓他...
如果对方被你打中了，你就打一套连段...

这么一解释下来，就容易理解多了，Mugen里面的AI其实是令人物根据人物性能根据实际情况作出相关反应的代码。
在游戏里面反映人的智能，本来人工智能要考虑人类心理之类的东西，现在无非就是看人要做什么事情了。
所以其实要学Mugen里面的AI并不难，你知道现实当中手操该怎么打，你就用个if语句还原那个动作就可以了。
另外你不必是FTG的触手，我这种被人纯波流跳都跳不过去，直接被PREFECT的纯沙包都可以写出AI，相信各位也不会有问题的（什么？你不信我是个沙包？用不用给你看看我玩KOF94连第一队都过不了的惨况XDDD）。
至于Mugen里面怎么写，就得先说说Mugen的语句之类的了，详细请看3.1。

--------------------------------------------------
既然说起了AI，就顺带说说性能和AI的区别，毕竟对新人来说这一点很容易有理解偏差。
简单来说，性能就是你是否拥有这能力或者是否能这么做，AI就是你是否在适合的时候做适合的事情。
如果要详细的说，那♂太♂长♂了：

性能：
最大生命值、最大能量值、特殊资源、攻击力、防御力、移动速度、攻击/受击框、冲刺/奔跑、能否二段跳/空中冲刺、出招时间、收招时间、无敌时间、霸体/格挡/精防/当身、单段/多段攻击判定、是否有飞行道具、取消链、能否空振取消，等等，太长不列...

AI：
出招时机、连段方式、移动走位、铁壁防御，等等...

举个两个例子：

Mugen：

KFM有必杀超升龙需要消耗1气，可以用来取消重拳。要消耗1气和可以用来取消重拳是他原来的设定，是性能，结果你在你没气的时候，一个超升龙向对方挥过去，这就是违反了原来的设定，是修改性能；
在只考虑胜利的前提下，你一个重拳打过去中了而且有气继续连超升龙而且连了就赢了，但是你没连，这是低AI，但如果你果断一个超升龙挥过去啪的一下中了，这就是高AI。

非Mugen：

假设有一部元祖高达，设定中你只能用火神炮，光束剑和镭射枪，结果你使出了石破天惊拳那就是修改性能。
假设有一部白色木马，左右舷都有相同的弹幕可以用，左舷是低AI，右舷是高AI。
（林有德：......）

作为AI作者，我们要知道，我们修改的是AI，不是性能。
对AI作者来说，修改性能是一件不太提倡的事，毕竟人物有原来的设定。
当然，并不是说不能修改性能。例如人物数据明显和原作有很大差别的话，你改回原作性能别人也不会怪你的；
而且Mugen当中不少人物性能都被不同程度的强化，合理强化也是可以理解的事（当然个人提倡还原原作）。
不过如果要修改，公开前首先要得到人物作者的允许，说明自己修改了什么地方。
毕竟人物是别人做的，你乱修改了别人的人物参数公开出来就是对别人的不尊重。
而且人物作者有可能是很辛苦一帧一帧看原作得出的精确数据，随便修改了也不太好。

AI与性能的关系是：AI发挥性能，没有性能就没有AI。
人物性能各有高低，性能好不必骄傲，性能差也不用悲伤。
如果你选择的是高性能的人物，那么恭喜你，那是人物作者赐予你的礼物。
如果老是觉得自己人物性能不够好的请记住一句话：
性能劣势用AI弥补。

==================================================
2.2Mugen人物运作基础知识
==================================================

--------------------------------------------------
写这个章节要对Mugen原理有深刻理解，笔者能力有限，如发现错误麻烦请马上指出避免误导，谢谢各位OTL.
要知道怎么写AI，还是先学学人物运作基础的东西吧...

--------------------------------------------------
先说人物构成，一个人物一般分为以下几个文件：

Def定义文件，内含人物的基本信息（如名字）和所用到的相关文件（路径）
Cmd操作指令文档，内含手操输入指令的定义和手操进入状态变换
Cns常量文件，人物的常量数值，例如血量、攻、防、走/跑速度等
St状态文件，人物的各个非公用状态，通常是以后缀.st的形式出现（把st写在cns的多数是偷懒XD）
Stcommon公用状态文件，人物的公用状态，默认为系统自带的common1.cns，当然也可以人物自带覆盖掉
Sprite(Sff)图像文件，人物的图像，是除了公用图像以外人物所用到的所有图片的集合
Anim(Air)动画文件，人物各动作的图像连接和图像时长，攻击判定框及受击判定框
Sound(Snd)声效文件，人物的声效，是除了公用声效以外人物所用到的所有音频的集合
Ai系统AI用文件，由于是1.0的新东西，资料不详
Palette(Pal)色表文件，选择1~12P不同的颜色
（还有个OP板和ED板就无视了XD）

其中，Sff、Snd、Pal是AI作者基本不用碰的（难不成写着写着AI去画张图？233）。同时这三个文件不影响性能。

Def基本就是改改路径，例如 cmd = AI/kfm.cmd 就是指该人物的cmd文档是AI子文件夹当中的kfm.cmd。
Cns是常量，常量是定下来的通常不会改。不过有时St会写在Cns里面，如KFM，到时只改Cns的St部分即可。
Ai不熟就不乱讲以免误导，记得也是不能改的。
Air主要是改性能或者加动画，也比较少用，还有调查性能时会用到，详细会在第6章讲解。

所以最终要改的就是Cmd、St和Stcommon三种文件。
至于怎么读怎么改...别急，下章3.1才开始讲呢- -...继续先打好基础再说吧...

PS：另外，Def、Cmd、Cns、St、Stcommon本质上来说都是txt（文本文档），平时直接拉进txt里面就可以开了。
PS2：其实这几个文档的后缀都是可以舍弃的东西...文件后缀不会影响文件读取...想起某人物的猎奇后缀，连AVI都出来了XDDD

--------------------------------------------------
接着说说人物是如何运行的。

首先补充一下说时间单位。1s = 60f（即1秒 = 60帧，一秒切换60次画面），标准单位通常也用f（帧）。
不过好像官方叫tick？不管了，反正看的懂，大家都习惯叫f了...233

Mugen的人物运行类似于有限状态自动机。
有限状态自动机是一个计算机模型，拥有有限数量的状态，
每个状态可以迁移到零个或多个状态，输入字串决定执行哪个状态的迁移。
（以上是计算机专业术语，不必太深究，如果想形象点了解的话建议去百度图片搜索 有限状态自动机 即可）

而Mugen人物运行其实就是一个个不同我们可以看见的动作的切换，这种切换的东西就叫做状态，State。
人物的每一个状态都有他自己的定义，在Cns和St里面，这种定义就叫做Statedef。
Statedef的数字也就是状态号，也就是我们平时见到的Stateno。因为没有相同的动作，Statedef不能重复。
Statedef下面的东西就是这个状态号将要做的东西，由一个个不同的状态控制器（state controller，以后简称Sctrl）组成，之后，如果状态控制器满足了触发器（trigger）的条件的话就会运行。
PS：状态控制器和触发器会在第3章慢慢详细谈，暂时不理解是什么也没有所谓。

之后人物会因为满足不同的条件（也就是trigger）而切换着状态和各种属性（也就是Sctrl控制的东西）。
人物一帧一帧地运行，不时从一个状态跳到另一个状态，最后就动起来了成为我们看到的样子。

所以要知道人物在某个动作做了什么的话，首先查他的状态号，之后到相应Statedef看看里面有什么东西就行了。

Statedef一般是非负数，不过有三个特殊例子，[statedef -3][statedef -2]和[statedef -1]。
以下引用一下四娘的话：

-3下的代码只会在自己存在在自己的状态号的情况下才会运行（注：有时角色会被拉到对方角色的状态号里，比如投技）
-2则是在任何状态下都会执行
-1一般包含由键盘输入的手动操作命令
同时-3-2-1每一帧只会运行一次，changestate和selfstate也不会进入-3-2-1中
当然，自己的-3-2-1只会对自己有效，对敌人毫无效果（除非是会影响到对手的那些代码

还有一点很重要的是，一个人物的运行顺序，
单个人物每一帧里，会按照[statedef -3]->[statedef -2]->[statedef -1]->[statedef 当前状态号]的顺序运行。
而人物间的运行顺序是按照1P->2P->3P->4P的顺序运行。
顺序运行看上去没用，事实上也的确很少用到，但以后讲到超反应就知道为什么要提及这些...

--------------------------------------------------
在补充一点豆知识吧...有些基本的东西要说清楚才行...

正如上面所说时间标准单位通常用f（帧），1s = 60f（即1秒 = 60帧，一秒切换60次画面）

屏幕大小X*Y=320*240，宽屏不清楚
屏幕坐标(0,0)点坐标位于X轴方向正中间，Y轴方向地面的交点
X轴正方向+，反方向-；Y轴向上-，向下+（Y轴很奇葩...要慢慢习惯）

主队第一人物叫1P，开场时在屏幕左侧
客队第一人物叫2P，开场时在屏幕右侧
双打时主队第二人物叫3P，开场时在屏幕左侧
双打时客队第二人物叫4P，开场时在屏幕右侧
1P和3P统称为1P侧，2P和4P统称为2P侧

现实中的数字分很多种，整数、分数、有理数、无理数等等。计算机领域的数字也有各种种类。
Mugen里面的数字与普通计算机很类似，以整型int和浮点型float为主。
整型int其实可以简单的理解为整数。另外取值范围是-2^31到2^31-1（包含-2^31和2^31-1）。
而浮点型float可以理解为可以带有小数的数，可以是整数也可以带小数。

对战中键盘Pause键可以暂停，暂停中ScrollLock键可以跳至下一帧

好，基础知识学的差不多了，下章开始学习怎么写-w-


3.语法、运算符与表达式

                本页内容由口水轩撰写. 由【softmgr】整理编辑.

--------------------------------------------------
写AI之前先说说语法之类跟计算机编程之类相关的东西。不过请放心，内容挺简单的。
因为Mugen本来就是给广大FTG爱好者一起玩的游戏引擎，所以其编写也是相当简单的。
另外学过计算机编程的同学这章可以看得快一点，毕竟很多都是学过的东西，注意一下某些跟C语言的区别就行了。

==================================================
3.1语法
==================================================

--------------------------------------------------
首先，分号;后面的是注释，也就是说;后面的东西是读不了的...

例子：

;例如这一句就是读不了的
;这一句也是...好神奇啊^ ^
分号前还是读得了 ; 分号后面就读不了了...T T
这句整句能读XD...好了不卖萌了

上面的例子计算机能读得到的就是“分号前还是读得了”和“这句整句能读XD...好了不卖萌了”，其他都读不到。
";"的用途主要是给自己/别人写注释，养成写注释的好习惯方便自己阅读，要不日后拿起来都不知道写了什么...
当然，有些不知道以后是否需要的代码，可以用";"把他们先屏蔽掉，以后有用再拿出来（这点很实用...）。

然后，要看一段语句是否运行，就要看里面的条件是否满足，也就是真或假。
与C语言相似，你的输入的值非0是真，0是假；系统返回值1是真，0是假。
呃，输入值和返回值是什么？
输入值是你告诉计算机的数值，而返回值是计算机处理一段代码后得到的结果，反过来告诉你。举些例子吧：
你告诉系统-1，不是0，系统就知道你说的是真，同理输入233也是真；
你告诉系统0，系统就知道你说的是假。
1+2=3，运算后系统发现这个是真，所以最后你得到一个1；
1+2=233，运算后系统发现这个是假，所以最后你得到一个0。

--------------------------------------------------
紧接着就是讲状态控制器（state controller或sctrl）和触发器（trigger）的格式了。
Cmd、St和Stcommon三种文件里都经常看到一种写法：

例子，Cmd里KFM的站轻拳（因为详细的trigger还没看过所以右边有文字注释）：

;Stand Light Punch
[State -1, Stand Light Punch]
type = ChangeState;改变状态
value = 200;改变状态的值为200
triggerall = command = "x";按x键
triggerall = command != "holddown";没有按着↓键
trigger1 = statetype = S;站姿
trigger1 = ctrl;处于可控状态
trigger2 = stateno = 200;状态号为200
trigger2 = time > 6;时间大于6

其模板为：

[State XX, ...]
type = XXX
value = XXX
triggerall = ...
trigger1 = ...
trigger1 = ...
trigger2 = ...
trigger2 = ...
...
triggerN = ...

而这个模板就是sctrl的模板。

[State XX, ...]是整段的开始，其实没啥用途，但是你不能去掉...囧
XX其实可以随便填的，不过通常写在[Statedef XX]里就填XX，方便日后debug，例子中Cmd是[Statedef -1]。
中括号里逗号后面的省略号是文字注释，不影响运行。
type是你要做的事件类型，比如说例子里面ChangeState（即改变状态），
value是你要赋予的值，比如说例子里面就是200，
例子中结合type和value来看，就是改变状态到200号动作，即变为站轻拳。

紧接着就是一大串的trigger，即触发器，满足条件就触发这个状态控制器的事件，
学过编程的朋友可以理解为if语句。
trigger是按数字排序，编号为数字从1到N，按顺序从小到大检测是否满足，
一旦满足同编号trigger马上执行同数字的trigger要同时全部满足才算满足（当然同数字的只有一个的话只看那个就行了）。
如例子中trigger2就是状态号是200而且时间大于6两个条件同时满足才触发trigger2。
不过有一个特例，triggerall，是所有情况都需要满足的trigger，否则就不执行。
例子当中triggerall为你按x而且你没有按着向下方向键↓，否则下面的trigger1和trigger2满足了也没用。
如果从逻辑角度上来说，trigger的运作就是：

满足triggerall 而且 （ 满足全部trigger1
或者 满足全部trigger2
或者 ......
或者 满足全部triggerN）

另外trigger在Winmugen里有长度限制，太长会报错，但是貌似Mugen1.0里面没有。
反正就是不要写太长（不过初学者应该不会写得很长的）。
还有要注意至少要有一个后缀为数字的trigger（也就是trigger1），只有triggerall的话会报错哦。

...什么还是看不懂？引用四娘语录：

type =
吃饭
（干什么）

type =
value =
吃“一碗”饭
（量）

type =
trigger1 =
value =
“在中午”吃一碗饭
（什么时候）

果然四娘就是四娘简单暴力直接易懂的吃饭教学请允许在下跪拜OTL

--------------------------------------------------
语法例子若干：

继续使用上面的例子：
;Stand Light Punch
[State -1, Stand Light Punch]
type = ChangeState;改变状态
value = 200;改变状态的值为200
triggerall = command = "x";按x键
triggerall = command != "holddown";没有按着↓键
trigger1 = statetype = S;站姿
trigger1 = ctrl;处于可控状态
trigger2 = stateno = 200;状态号为200
trigger2 = time > 6;时间大于6

1.有按x键和↓键，站姿，处于可控状态，状态号不为200，时间大于6
满足command = "x"，不满足command != "holddown"，所以不满足triggerall，下面全部不满足trigger

2.有按x键，没有按着↓键，站姿，处于可控状态，状态号不为200，时间大于6
满足triggerall，满足所有trigger1，所以满足trigger，执行

3.有按x键，没有按着↓键，蹲姿，处于可控状态，状态号为200，时间大于6
满足triggerall，蹲姿不满足trigger1，满足trigger2，所以满足trigger，执行

4.有按x键，没有按着↓键，蹲姿，处于可控状态，状态号不为200，时间大于6
满足triggerall，但不满足trigger1和trigger2，不满足trigger，所以不执行

好，语法其实就是这么多，Cmd、St和Stcommon基本都是以这个格式写的。
其实前半部分是Sctrl，后半部分就是trigger。
做AI能用到的Sctrl的类型其实也只有ChangeState等为数不多的几种，
当然要做人物的话就要用到各种各样的type，不过在AI教程里面就不予赘述了。
trigger倒是需要多知道一些，毕竟写AI要考虑各种各样不同情况。
至于常用Sctrl与trigger，笔者会在下章讲。
想了解更多的建议多看看trigger表和Sctrl表，里面解释的挺清楚的。

==================================================
3.2运算符与表达式
==================================================

--------------------------------------------------
运算符就是各种各样的运算符号，跟数字之类的结合成为表达式。
毕竟mugen里面的AI还是与数学和计算机密切相关的，这些基础的东西还是要提及一下。

--------------------------------------------------
括号

( ) 括号，括号内优先运行，跟数学里的意义基本一样，不多说了
此外，有时在语句长、逻辑关系十分混乱或语句有歧义时，用括号分段会有很好的效果

--------------------------------------------------
算术运算符

+ - * / 加减乘除这四个就不解释了- -...不懂的朋友建议重新读小学XD...
% 取余，A % B，例如5 % 2余数就是1
** 乘方，A ** B，就是A的B次方，需要注意的是winmugen里面乘方运算有BUG，1.0被修复，使用时小心

--------------------------------------------------
逻辑运算符

! NOT，非，表示否定，!A，真假颠倒，即真的变成假，假的变成真
&& AND，并且，A && B，AB同时为真才为真，否则为假
|| OR，或者，A || B，AB同时为假才为假，否则为真
^^ XOR，异或，A ^^ B，AB只有一个为真才为真，否则为假

--------------------------------------------------
关系运算符

= 等于号，A = B，当AB同为整型或浮点型且相等的时候为真，否则为假。
!= 不等于号，A != B，当AB同为整型或浮点型且不相等的时候为真，否则为假。
< 小于号，A < B,当两边同为整型或浮点型且A小于B的时候为真，否则为假。
<= 不大于号，与小于号相似，A = B时亦为真
> 大于号，A > B,当两边同为整型或浮点型且A大于B的时候为真，否则为假。
>= 不小于号，与大于号相似，A = B时亦为真
以上判断大小关系运算符，若AB类型不同，系统会自动转化为浮点型再比较

=[,] 以下的都是A “=或!=” “[或(” B,C “]或)” 的形式，例如X=[Y,Z],表示区间
!=[,] 嘛，集合是高一数学的内容（我应该没记错吧...）
=[,) =和!=我就不多说了，[]是闭区间，包含区间端点，()是开区间，不包含区间端点，另外B <= C
!=[,)另外请注意这八种区间的表达如果不是用在这行的末端，会造成语句歧义而报错
=(,]解决方法是加括号，例：Trigger1 = (Power = [1000,2000]) && Life < 300
!=(,]
=(,)
!=(,)

--------------------------------------------------
赋值运算符

:= 赋值号，用于赋予变量值，以后讲到变量Var和浮点变量FVar再提及

--------------------------------------------------
二进制运算符

没学过二进制的朋友可能会比较难理解，而且应用面不广，这部分选读即可（拓展内容www）。
我们平时生活中应用的数字是十进制，数字从0~9一个十个数字，每逢十个就进一位。
二进制就是只由0和1两个数字组成，每逢两个就进一位，在计算机当中有广泛运用（用0/1表示关/开非常方便）。
例如十进制的6 = (2^2)*1 + (2^1)*1 + (2^0)*0 -> 二进制的110（1个2的2次方 加 1个2的1次方 加 1个2的0次方）。
mugen里面的运用多数用于大量的布尔型数据（即真或假）的储存，
注意进行二进制计算请用整型

! NOT，非，表示否定，!A，真假颠倒，即真的变成假，假的变成真
& AND，并且，A & B，AB同时为真才为真，否则为假
| OR，或者，A | B，AB同时为假才为假，否则为真
^ XOR，异或，A ^ B，AB只有一个为真才为真，否则为假

二进制的逻辑其实就是每个数位独立出来运算...
还是举个两个例子吧（下面的^符号代表数学运算中的乘方运算）...

6&5其实等价于((2^3)*0 + (2^2)*1 + (2^1)*1 + (2^0)*0) & ((2^3)*0 + (2^2)*1 + (2^1)*0 + (2^0)*1)
6|5其实等价于((2^3)*0 + (2^2)*1 + (2^1)*1 + (2^0)*0) | ((2^3)*0 + (2^2)*1 + (2^1)*0 + (2^0)*1)

0110
& 0101
--------
0100
一共四个字节，只有第三个字节是上下同为1，所以只有第三个字节是1，其他是0
返回((2^3)*0 + (2^2)*1 + (2^1)*0 + (2^0)*0) = 4

0110
| 0101
--------
0111
一共四个字节，只有第四个字节是上下同为0，所以只有第四个字节是0，其他是1
返回((2^3)*0 + (2^2)*1 + (2^1)*1 + (2^0)*1) = 7

--------------------------------------------------
运算符优先级

优先级从上到下排列，同一行的是同级运算。
如果同级的运算是按从左到右次序进行，多层括号由里向外。

! ~ -（负号）
**
* / %
+ -（减号）
> >= < <=
= !=
:=
&
^
|
&&
^^
||

--------------------------------------------------
表达式例子若干：

1.1
直接返回1，为真

2.1 && 0 || 1
根据运算符优先级可知，先考虑1 && 0，返回0；再考虑 0 || 1，返回1

3.1 + 1 = 2 && 1 + 2 != 3
根据运算符优先级可知，先考虑1 + 1 = 2，再考虑1 + 2 != 3，最后考虑两个的式子的关系
1 + 1 = 2为真，返回1；
1 + 2 != 3为假，返回0；
1 && 0为假，返回0

==================================================
课后作业：

1.
!((5 % 2) || (1 >= 2) && ((1 ** 233 + 2) * 3 != 10086) && (1 = [0,2)) && 0)
按步骤分析上述表达式并写出过程

2.
[State 233, 莫伸手]
type = 伸手党处理方法
triggerall = LZ伸手
trigger1 = 帖子问题与精品贴中某教程帖吻合
trigger1 = LZ没翻过置顶/精品贴
trigger2 = 借话题水
triggerX = YYY
value = ifelse(吧务心情不好, 删帖, 不删放着让大家水)
分别给以下两种情况，赋予YYY适合的触发条件
a). X = 2
b). X = 3

3.
如何利用二进制运算符有效地储存布尔型数据？理论上可以储存多少个布尔型数据？
附加题，难度较大，对二进制运算感兴趣的同学可以试试，不过对计算机专业的朋友来说应该是小菜一碟-w-


4.常用Sctrl与trigger与常见错误

                本页内容由口水轩撰写. 由【softmgr】整理编辑.

--------------------------------------------------
继续讲状态控制器（state controller或sctrl）和触发器（trigger）的知识。
如果把Mugen代码比喻成一本书的话，那么Sctrl和trigger就可以比喻为文字。
书的内容其实是一个一个字组合而成，Mugen代码亦然，是由Sctrl与trigger拼凑而成。
Sctrl是状态变化的类型，也可以理解为想要触发的事件，例如说切换动作、改变速度之类。
trigger是触发器，满足条件就触发，用来判断该事件是否符合条件被触发，例如判断对方的名字是否叫KFM之类。
这章只讲讲比较常用并且与性能或AI相关的Sctrl与trigger，而且也只是相当概括性的讲讲其用途，详细想知道更多的请自己阅读Sctrl与trigger两个表。

注：以下内容int代表整型数字，float代表浮点型数字，string代表字符串

==================================================
4.1常用Sctrl
==================================================

--------------------------------------------------
Sctrl通用参数
--------------------------------------------------
IgnoreHitPause

必选参数： 0 = OFF, 1 = ON
无视打击暂停，是每一个Sctrl都可以使用的参数。双方打斗中击中时会有打击暂停（也就是打中的时候卡一下），ON的话就是在打击暂停时这个Sctrl依旧可以被触发，OFF则不会。实际应用中var改变等某些情况会用到。

例子：IgnoreHitPause = 1

--------------------------------------------------
改变动作相关
--------------------------------------------------
ChangeState
ChangeAnim
SelfState

必选参数： value = int
ChangeState为改变状态，是写AI过程中用得最多的Sctrl没有之一。正如前面所提及，Mugen人物运行其实就是状态切换，此Sctrl的作用就是从当前状态切换到指定状态号的状态。
ChangeAnim为改变动画。多数情况下，一个动作对应一个动画，但是有些情况同一个状态里需要呈现不同的动画，就会用到ChangeAnim。因为动画涉及攻击框受击框，所以注意。
SelfState其实与ChangeState很类似，不过通常用于拉回自己状态，通常用于把对方拉进特殊状态后让对方还原。

--------------------------------------------------
改变攻防相关
--------------------------------------------------
AttackMulSet
DefenceMulSet

必选参数： value = float
攻击/防御改变。当value = N时，AttackMulSet获得效果攻击*N，DefenceMulSet获得效果防御/N（略猎奇）。
另外DefenceMulSet需要在受击开始后才生效。
例子：同样是value = 0.5，对AttackMulSet来说就是攻击变成0.5倍，对DefenceMulSet来说就是防御变成2倍。

--------------------------------------------------
无敌相关
--------------------------------------------------
HitBy
NotHitBy

必选参数： value = string (attr，即攻击类型)
可选参数： time = int
HitBy和NotHitBy都是无敌，HitBy是仅可以被描述的攻击类型的攻击击中，而NotHitBy是不能被描述的攻击类型的攻击击中。
如果加入time参数，则无敌时间延长X帧。

例子1：不被任何攻击击中
type = NotHitBy
value = SCA
例子2：仅可被地面普通攻击击中
type = HitBy
value = S, NA

--------------------------------------------------
血量气量相关
--------------------------------------------------
LifeAdd
LifeSet
PowerAdd
PowerSet

必选参数： value = int
改变血量及气量的Sctrl，就是简单的加法和直接赋值，不予赘述。

--------------------------------------------------
打击相关
--------------------------------------------------
HitDef
Projectile
ReversalDef

必选参数： 太长不写（因为真的很长），具体请看hitdef
三种打击类型，打击定义（通常用来写打击技和投技）、飞行道具和反射定义（通常用来写当身、格挡等特殊防御技）。
打击定义和飞行道具就是我们所说的攻击所造成效果的定义（比如伤害、硬直等），只要我方攻击框接触对方受击框就会生效。
而反射定义比较特殊，需要对方攻击框与我方攻击框才能生效。

--------------------------------------------------
暂停相关
--------------------------------------------------
Pause
SuperPause

必选参数： Pause: time = int, SuperPause: None
顾名思义，Pause就是普通的暂停，而SuperPause指的是某些会出现特效的特殊暂停（比如超杀前的暗转暂停）。

--------------------------------------------------
变量相关
--------------------------------------------------
VarAdd
VarRandom
VarRangeSet
VarSet
ParentVarAdd
ParentVarSet

变量Var的具体介绍会在第6章出现，暂时大概理解为可以赋值的一些数字吧。
如果说ChangeState是写AI过程中用得最多的Sctrl，那VarAdd和VarSet可以说是紧随其后。
变量对于AI的意义非常重大，可以说相当于人类的记忆。带有学习功能的AI必须使用变量记录。
前四个是对Var的赋值，通常来说VarAdd和VarSet比较常用。VarRandom用于给Var赋予随机值，VarSet则是批量的对Var赋值。至于ParentVarAdd和ParentVarSet，有时也会用于飞行道具或helper对本体赋值，不过不常用。

--------------------------------------------------
位置与速度相关
--------------------------------------------------
PosAdd
PosFreeze
PosSet
VelAdd
VelMul
VelSet

可选参数： x = float, y = float

前缀Pos的是位置相关，前缀是Vel的是速度相关，在正常移动、突进技、移动技等地方广泛使用。
有两个可选参数分别控制横坐标和纵坐标。单纯的改变位置不会有速度变化，但是速度变化会引起位置变化。
另外人物在地面时速度会收到摩擦力影响，在空中时不会。

--------------------------------------------------
其他
--------------------------------------------------
AssertSpecial

必选参数： flag = string (flag_name)
可选参数： flag2 = string (flag_name), flag3 = string (flag_name)
特殊断言，每个AssertSpecial可以插最多三个flag。
这些flag的内容多数是一些比较特殊的效果和性能，例如隐藏血条和气条、自身人物不能空防/站防/蹲防、自己的攻击不能被防御
等等。

CtrlSet

必选参数： value = int, 0 = OFF, 非0 = ON
控制设置，设置为0变成不受控制，或设置为非0变成受控制。可控制状态就是指该状态下人物可以通过输入命令做出相应动作，比如普通的站姿，按前就是向前走，按上就是跳，被攻击时按后就是防御，按ABCXYZ是攻击，这就是处于可控制状态。

DisplayToClipboard

很常用的debug用Sctrl，通常放在-1、-2或-3下，可以直接把想用的最多5个量直接显示在屏幕最下方。
（当然你需要比较好的视力去看清楚究竟里面写了什么...）
例子：
[State -1, Display]
type = DisplaytoClipboard
Trigger1 = 1
text = "X : %d | Y : %d | Var : %d | FX : %d | BX: %d "
params = ceil(P2bodydist X) , ceil(P2bodydist Y) , ceil(Var(0)), ceil(FrontEdgeBodyDist), ceil(BackEdgeBodyDist)
（这个例子所显示的是双方X轴Y轴距离，Var(0)的值，和人物跟画面边缘的前后距离）

Helper

援护，非常有用的东西，飞行道具、画面特效、幽波纹（误）之类的很多制作方面的东西都可以通过helper做到。
另外在AI领域，由于人物本体变量不够用甚至本体变量已经被人物作者用光了，我们可以建立AI helper利用helper里面的Var来记录我们需要记录的信息。

StateTypeSet

状态种类改变，状态种类一共是4种，S C A L 分别对应站姿 蹲姿 空中 倒地。这个Sctrl可以在某个状态中改变其状态种类。

Turn

转向，把人物的朝向变成反方向。

Width

改变人物宽度，两人物横向宽度重叠的时候会发生排挤。可以把人物宽度理解为排挤框（身位框？）大小。

==================================================
4.2常用trigger
==================================================

--------------------------------------------------
重定向
--------------------------------------------------

在讲trigger之前必须先说说重定向。 我们在读取本体信息的时候不需要加任何前缀。但是我们怎么才能读取其他人（例如对方、队友、援护）信息呢？
这个时候我们需要用重定向，用特定的前缀来获取指定对象的信息。

常用的重定向前缀有：

parent
重定向到人物的亲人物（也就是生成这个援护的人物），而且该人物必须是个援助。不过多数情况下直接用root。

root
重定向到人物的根人物（可以理解为人物本体了）。用于直接调取人物本体相关信息。

helper / helper(ID)
重定向到第一个找到的援助。/ 重定向到相应ID的援助。用于检测自身helper相关信息。

target / target(ID)
重定向到第一个找到的目标。/ 重定向到相应ID号的目标。目标是指你攻击命中的对象。

partner
重定向到人物的队友。很明显常用在双人游戏里。

enemy / enemy(n)
重定向到第一个最远的对手。/ 重定向到第n+1个最远的对手。

enemynear / enemynear(n)
重定向到最靠近的对手。/ 重定向到第n+1个靠近的对手。通常来说，enemynear比enemy要常用因为通常我们关心较近的敌人。

playerID(ID)
重定向到具有唯一对应ID号的人物。这个要通过调查对方ID之后才能用。

例子：
root,statetype人物本体的状态种类
enemynear,time最近敌人的时间
helper(1005),statenoID为1005的援护的状态号

注意：多重重定向（例如，root,target,time）现在还不支持。

--------------------------------------------------
动画相关
--------------------------------------------------
Anim
AnimElem
AnimElemNo
AnimElemTime

以上四个都是动画相关的trigger，但是作用还是有挺大差异的。动画里面的每一幅图被称为元素。
Anim是返回当前动画号，其他三个是动画元素及动画时间相关的trigger，具体请看trigger文档，视情况灵活运用。

--------------------------------------------------
画面边缘相关
--------------------------------------------------
BackEdgeBodyDist
BackEdgeDist
FrontEdgeBodyDist
FrontEdgeDist

画面的前后边缘距离检测，注意不是场景边缘是画面边缘，场景边缘需要用特殊的方法检测。
另外貌似由于Mugen自带BUG，带不带Body都是一样的OTL，希望E小组尽快修正吧。

--------------------------------------------------
数学运算用
--------------------------------------------------
Abs
Ceil
Floor

绝对值、向上取整、向下取整，不予赘述。

--------------------------------------------------
血量气量相关
--------------------------------------------------
Life
LifeMax
Power
PowerMax

当前血量、最大血量、当前气量、最大气量，不予赘述。

--------------------------------------------------
打击接触相关
--------------------------------------------------
MoveContact
MoveGuarded
MoveHit
MoveReversed

一个人物攻击如果接触了对方，将会出现三种情况：击中，被防御和被反射。以上四个就是分别代表这些情况。
MoveHit用于连段，MoveGuarded用于压制，而MoveReversed就自求多福吧。
另外请注意MoveContact是MoveHit或MoveGuarded，而不包含MoveReversed。

--------------------------------------------------
人物状态相关
--------------------------------------------------
StateType
MoveType

状态种类和动作种类。状态种类一共是4种，S C A L 分别对应站姿 蹲姿 空中 倒地。
动作种类一共是3种，A H I分别对应攻击 受击 空闲。AI里时常需要这两个trigger来判断对方的行动。

--------------------------------------------------
位置、距离与速度相关
--------------------------------------------------
P2BodyDist X/Y
P2Dist X/Y
Pos X/Y
Vel X/Y
RootDist X/Y

以上五个trigger都有分X轴和Y轴，千万不要忘掉。
P2BodyDist是指我方与对方的身体边界（人物原点坐标-双方人物宽度）之间的距离，而P2Dist是指我方与对方人物原点坐标之间的距离。
需要注意的是由于人物宽度只有X轴存在，所以P2BodyDist Y = P2Dist Y。Pos是绝对坐标，Vel是速度。RootDist用于helper与本体之间的距离检测。

--------------------------------------------------
个数相关
--------------------------------------------------
NumEnemy
NumHelper
NumProj
NumProjID

敌人个数、援护个数、飞行道具个数、相应飞行道具个数，不予赘述。

--------------------------------------------------
变量相关
--------------------------------------------------
Var
FVar
SysVar
SysFVar

四种变量，比较常用的是Var和FVar，直接可以调用，返回相应变量的值。变量的具体使用第6章会讲。

--------------------------------------------------
状态号相关
--------------------------------------------------
StateNo
PrevStateNo

除了可以用StateNo直接调查当前状态号，我们还可以用PrevStateNo调查当前状态之前的状态号。

--------------------------------------------------
比赛相关
--------------------------------------------------
RoundNo
RoundState

RoundNo是当前局数。RoundState是当前局状态号，0:预开场阶段 ，1:开场阶段 ，2:格斗阶段，3:胜负判定阶段，4:结束阶段。
通常AI能动的是RoundState = 2，胜利挑衅之类的属于RoundState = 3。

--------------------------------------------------
时间相关
--------------------------------------------------
Time
AnimTime

Time返回当前动作已经使用时间。而AnimTime返回到动画结束还需要多少时间，其值<=0，当=0时动画结束。
因为绝大多数情况下动画结束就引起状态改变，所以可以用AnimTime探测还有多长硬直时间。
另外需要注意的是，如果对方动作是循环的话（例如KOF人物在空中出招完成后会变成循环的下落的动画），因为动画不会结束所以返回的是Time的值，其值>0。

--------------------------------------------------
对方相关
--------------------------------------------------
P2Life
P2MoveType
P2Name
P2StateNo
P2StateType

其实上述这些只是加了P2作为前缀，变成探测对方。用重定向也有类似的效果。

--------------------------------------------------
其他
--------------------------------------------------
AILevel

AI等级，1.0新增的trigger，返回option里面设置的难度，对于做手操整合的朋友可谓是福音。
另外可以用于1.0里面不影响手操的AI常时启动。

Alive

存活，通常AI要求人物要存活才能行动，所以会直接加在triggerall以防非存活继续乱动。

AuthorName

作者名，多与Name配合写人物对策。

CanRecover

判断目前受击状态是否可以受身。

Command

手操指令，辨别手操按键满足cmd里面的某个指令。由于AI是模仿人的操作，所以通常有command的地方都要写AI。
还有很重要的一点，关于command的trigger在AI里面基本是不需要的。
因为这个trigger是用来辨别手操按键是否满足cmd里面的某个指令，然而AI的编写不需要辨别手操按键，所以写AI的时候通常不需要command。

Const

常量，可以用于调查攻击、防御、行走速度、奔跑速度、Y轴重力加速度等等Cns里面标好的常量。

Ctrl

判断是否可控状态，非取消的切换动作都需要这trigger否则会有BUG，而且不可控状态乱切换动作是新人常犯的错误（我以前就曾经被这个坑过两回）。

Facing

面向，若游戏者面向右方则返回1，若游戏者面向左方则返回-1。通常用于鉴别双方是否面对面（或背对）。

GetHitVar

获得对象被击中时的数据，例如速度、伤害、硬直等等，可选参数很多，具体请到trigger表查找。

HitCount

当前动作打击次数，多用于写连段时到第几次打击时取消。

ID

每个玩家和援护都会有自己独有的ID，有时候需要记下ID来锁定目标。

IfElse

如果...则...否则...，格式为 ifelse(条件,满足时则XX,否则YY)，与if语句比较相似，但是要注意的是必须为两项选其一，即if和else都不能为空。

InGuardDist

判断是否有能打到自己的攻击判定（例如对方本体攻击或者飞行道具）而且自己处于在防御范围内。很有效的防御时机鉴别。
另外防御范围是一个0~N（N>=0）的范围，所以如果攻击方飞过了你的位置的话，你将检测不了攻击方的攻击判定，利用这个可以做出打逆的效果（这个后面再说）。

IsHelper

判断是否援护，可以用于防止helper乱动。

Name

多与AuthorName配合写人物对策。

PalNo

色表号，1~12，也就是经常被人说的P数，通过选人时的按键锁决定。

Random

随机数，返回一个0到999之间的随机整数（包含0与999）。很常用的trigger，如果不用随机，人物就是一个只会死板运行的程序，随机令AI变得多样而丰满。
值得注意的是，每次使用Random时，他都会重新在0到到999之间随机找一个整数，所以不要误以为同一帧里面随机数都是一样的。

--------------------------------------------------
大概清楚上面的这些基本知识以后就可以开始去拆人物了，翻着两个表慢慢弄清楚人物的结构也是一种学习-w-

==================================================
4.3常见错误
==================================================

--------------------------------------------------
常见报错类型
--------------------------------------------------

在此只讨论AI编写过程中常见错误（路径错误那种不在讨论范围之内）

--------------------------------------------------
2500 loop / 2500循环：

如果电脑不幸进入了死循环，整个电脑就会掉尽无限的轮回而卡住。
Mugen里面为了避免死循环，Mugen程序限定一帧里面只可以改变状态（Changestate）2500次，若超过则会出现2500 loop报错。
死循环例子：
state A 直接 changestate 到 state A
state A 转到 state B 再转回 state A
....
解决方法：根据返回信息检查代码，找出循环部分并合理排除。

--------------------------------------------------
Type mismatch detected / 种类不匹配：

数据分很多种类，我们Mugen里面通常用到的是数字。而数字也分很多种，例如整型int，浮点型float。
种类不匹配错误通常出现在把浮点型数据和整型数据的不适当使用，例如：
trigger1 = 2.5 % 2用浮点型数据进行只适用整型数据的运算
trigger2 = Var(0) := 1.2把浮点型数据赋值给整型变量Var
...
解决方法：根据返回信息找出错处，用ceil和floor对其取整，或者赋值时用浮点型变量FVar。

--------------------------------------------------
Need at least 1 trigger / 至少一个触发器

除了忘了写以外，只有triggerall一样会报错。记得至少要有一个数字trigger。

--------------------------------------------------
Invalid trigger / 触发器无效
Library error message: Died parsing / 错误信息：语法分析错误

除了你打错字的可能性以外，不兼容的语句也可能出现这个问题。
例如在Winmugen里面用1.0代码，比如AIlevel。
若是使用Winmugen，trigger一行有字数限制，trigger写得过长也有可能出现该错误，所以注意及时换行。

--------------------------------------------------
Error while precaching / 预缓存时错误

打开人物读取数据时发生的错误，多数是打错字或者语法不对，根据返回信息应该比较容易检查出来。

未完待续（欢迎提供各种AI常见报错）

==================================================
课后作业：
==================================================

1.
以下这段语句是什么意思
[State 200, 7]
type = ChangeState
trigger1 = AnimTime = 0
value = 0
ctrl = 1

2.
以下是KFM的[Statedef 240]，请解释为什么出招之后人物会有向前的位移。
[State 240, 1]
type = PlaySnd
trigger1 = Time = 2
value = 0, 1

[State 240, 2]
type = HitDef
trigger1 = Time = 0
attr = S, NA
animtype = Medium
damage = 63
guardflag = MA
pausetime = 12,12
sparkno = 1
sparkxy = -10,-60
hitsound = 5,2
guardsound = 6,0
ground.type = Low
ground.slidetime = 12
ground.hittime = 15
ground.velocity = -6
air.velocity = -2.2,-3.2

[State 240, 3]
type = PosAdd
trigger1 = AnimElem = 7
x = 12

[State 240, 4]
type = ChangeState
trigger1 = AnimTime = 0
value = 0
ctrl = 1

3.
在data文件夹里默认common1.cns里的[Statedef 5120]（倒地起身动作）有以下描述，请解释这三段是什么意思：
[State 5120, 3]
type = NotHitBy
trigger1 = 1
value = SCA
time = 1

[State 5120, 5] ;Can't be thrown right after getting up
type = NotHitBy
trigger1 = AnimTime = 0
value = , NT,ST,HT
time = 12

[State 5120, 6] ;Can't be hit right after getting up (short time)
type = NotHitBy
trigger1 = AnimTime = 0
value2 = SCA
time = 3

4.
请写出怎么知道对方剩下多少%的血量。

5.
请写出如何令人物常时满气。

6.
请写出每两帧触发一次的trigger，并类推出如何令人物每X帧恢复Y点血量。
提示：使用gametime（自己查表）和取余运算（忘记怎么用的话看上一章）


5.变量Var简介、Cmd简介、AI开关设置及手操指令修改

                本页内容由口水轩撰写. 由【softmgr】整理编辑.

==================================================
5.1变量Var简介
==================================================

--------------------------------------------------
在平时mugen的讨论当中总会出现变量也就是Var这个莫名其妙的词，出现频率高用途广，是制作者经常用到的东西。
但是不知道为什么这词总是给新人一种强烈的威慑力和压迫感，令新手们敬而远之。

其实变量（Variable，缩写为Var）并不可怕，就是一个任意赋值修改的数字。
变量分为Var、Fvar、Sysvar、Sysfvar等几种。Var和Sysvar是整型变量，Fvar和Sysfvar是浮点型变量（F的意思是float）。
一个人物里面共有60个Var（Var(0)～Var(59)）、40个Fvar（Fvar(0)～Fvar(39)），Sysvar和Sysfvar各5个。
用途上来说Sysvar、Sysfvar是系统变量，一般不使用。所以平时通常使用的变量是Var和Fvar，共有100个。
本体的变量可以通过修改参数把留到下一局。在CNS的[Data]部分，修改IntPersistIndex和FloatPersistIndex的值。
在这两个值以上的本体Var和Fvar在下一局开局不会被重置为0。不过现在应该暂时用不到...
最后补充一句所有变量默认值为0。

--------------------------------------------------
（为了方便，下文用Var统称所有变量）
我们可以对变量进行各种各样的操作：例如查看数值（Var/Fvar）、增加（Varadd）、赋值（Varset/:=）等等。例如：

查看及对比：
trigger1 = Var(59) && Fvar(0) = 10086;查看Var的值和对比Fvar的值

增加/赋值：
[State -1]
type = Varadd/Varset;增加或者赋值
trigger1 = ...
V = XXX / FV = XXX;对哪一个变量进行操作
value = 1;需要操作的量

:= （赋值运算符）：
[State -1]
...
trigger1 = Var(59) := 1|| 1;对Var(59)赋值并继续运行下面的代码
...
（Var(59) := 1的作用是和Varset把V = 59, value = 1一样。需要注意的是，:=赋值所返回的值是赋值的值，可能会影响以后的
trigger判断。后面可以根据实际需求加上 || 1 或者 && 0，分别用于确保后面语句触发或者不触发）
使用该运算符的好处是可以一次对多个Var进行赋值。

--------------------------------------------------
如果是懂得计算机的朋友，上面这么多废话说完就一句话：
变量即是用特殊函数赋值的初始值为0的int i[60]或者float j[40]。

--------------------------------------------------
Var相关的常用代码就上面这几种，但是这些简单的数字对作者来说具有非常重要的意义：
它像是纸+铅笔+橡皮擦，你可以任意修改里面的值；
又像是红绿灯，你可以根据里面的内容来分析下一步的应对方案；
又像是一本笔记本，你可以把需要记忆的东西记录下来。
虽然Var本身没有任何意义，但是会因为作者的不同需求而被赋予各种各样的意义。
当中的奇妙之处需要时间慢慢领悟，一大波变量Var使用实例会在15章详细介绍。
而下文将要介绍的就是Var最简单的用法之一，也是AI制作当中几乎一个必不可少的步骤——AI开关。

==================================================
5.2Cmd简介
==================================================

--------------------------------------------------
在讲解AI开关之前，因为涉及到手操指令的部分，就顺便把Cmd文件也简单介绍一下吧。
因为KFM的Cmd里面有Cmd的相关介绍，所以笔者就直接在MKII君翻译的中文KFM的Cmd文件提取并整理相关介绍了：

Cmd文件一共由两大部分组成——手操指令定义和切换相关状态。

--------------------------------------------------
手操指令定义部分用于定义人物可以接受到什么按键（及按键组合）。
按键一共有八种方向、六种攻击和一种挑衅。

八种方向（全大写）：
B, DB, D, DF, F, UF, U, UB
后，下后，下，下前，前，前上，上，上后
（上面八个方向通常对应数字键盘上面的8个数字 4 1 2 3 6 9 8 7，剩下的5为没有方向按键）

六种攻击及一种挑衅（全小写）：
a, b, c, x, y, z, s

此外还可以用特殊符号前缀来达到鉴别按住按键（/号）、松开按键（~号）、同时按多个键（+号）等等手操指令的，具体请看自己
查阅相关资料，在此不予赘言。

手操指令定义的例子：

[Command]
name = "236x";手操指令名称为"236x"
command = ~D, DF, F, x;需要按下的按键是：下 下前（过渡） 前 x
buffer.time = 1;输入缓存的时间为1f

[Command]
name = "x";手操指令名称为"x"
command = x;需要按下的按键是：x
time = 1;需要在这规定时间（1f）内完成输入

其模板为：

[Command]
name = "XXX"
command = X(, Y, Z, ....)
time = XXX;（可选参数，单位为帧，默认为15）
buffer.time = XXX;（可选参数，单位为帧，默认为1）

最后注意一下command的最大数量为128个...注意超过之后会报错...

--------------------------------------------------
切换相关状态部分用于接收到手操指令后决定人物切换到什么状态，全部写在[statedef -1]以下。
[statedef -1]我们在第2章已经提及过，每帧执行一次看看有没有适合的手操指令，并且切换到相关状态。
其语法即第3章提及的与St和Stcommon相同的写法（sctrl和trigger）。
不过这些sctrl都有相同的特点，也就是trigger里面都有一条写着要由手操指令来触发：

[State -1, XXX]
...
triggerall = command = "XXX"
...

最后要注意一下如果command A（例如"x"）是command B（例如"236x"）的子集的话，记得要把command B的sctrl放在command A的
前面，否则会因为command A的切换状态被优先读到而触发令command B的切换状态一直不能被触发。
（这个其实是人物制作的小技巧，不过AI里面也会有涉及，在第7章会详细讨论）

==================================================
5.3AI开关
==================================================

--------------------------------------------------
AI开关是一个用于判断AI是否开启的Var。
通过判断Var是否为0来辨别现在正处于手操控制还是AI控制，是Var最简单的用法之一。
通常来说作者们喜欢用Var(59)作为AI开关（虽然不是强制要求但是可以说是大家默认的潜规则）。
在AI开关还可以调整AI等级，给Var赋予不同的值，通过判断Var值的大小来辨别现在正在使用什么等级的AI。

例子（设定AI为5）：

[State -1]
type = Varset
trigger1 = ...;相关条件
V = 59;假设选择Var(59)作为AI开关
value = 5;5级AI，共有多少个等级由作者自己决定

--------------------------------------------------
可能有读者会问：只有这么一个简单的Var赋值就可以让AI动起来吗？
当然不是了，设定好AI开关只是写AI的最开始一步而已。
在以后写AI语句的时候，都要补充上一句类似于triggerall = Var(59)的条件来让电脑知道，下面的代码是当AI开关打开的时候才
运作。
如果是有AI等级的话，则是使用类似于Var(59) = X的表达式。

用回第3章的例子：

;Stand Light Punch
[State -1, Stand Light Punch]
type = ChangeState
value = 200
triggerall = Var(59) > 2;AI等级大于2的时候才会触发
trigger1 = stateno = 200;状态号为200
trigger1 = time > 6;时间大于6

上面这个就是AI等级要大于2才会触发的例子，只要一旦出站轻拳就会鬼畜重复。
这就是识别自己AI开关是否开启的办法，至于详细AI的内容我们日后再谈。

--------------------------------------------------
在上面例子中，笔者仅介绍了如何设置AI开关，但是AI开关的具体条件没有讲。
在这个地方出现了一个难点——就是如何区分出手操和AI操作。
毕竟格斗游戏是用手来玩的，通常希望AI在适当的时候才接管控制权。
Mugen里面没有直接鉴别是否手操，为此作者们想出了不同类型的开关来解决这个问题，例如设计出人类按键输入做不到的事情，
一旦这种事情发生了，我们就知道控制的应该是AI而不是玩家了。
各种开关的区别主要在于启动速度和正确率，下文也会围绕这两点讨论各种AI开关。

--------------------------------------------------
5.3.1常时AI开关
--------------------------------------------------

最简单的一种AI开关。不管是手操还是AI操作直接常时打开AI开关。
常时AI开关实例：

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -1]
type = Varset
trigger1 = 1
V = 59
value = 1

优点：因为常时启动，不用考虑启动慢的问题
缺点：希望手操时依然停不下来...

--------------------------------------------------
5.3.2Cmd乱数启动型AI开关
--------------------------------------------------

较为简单的一种AI开关。
Mugen.cfg内有项参数叫做AI.cheat，默认为1。
其作用是即使电脑没有确实按到整套手操指令也可以用类似作弊的方法强制发动一个手操指令。
我们可以利用这一点来作为辨别是否手操。
AI作者在Cmd文件里的手操指令定义加入多个人类不可能完成的command，比较常用的是要在0f以内输入几个带有重复按键的指令。
因为就算是打寒颤的情况人类的手抖速度也不可能在六十分之一秒里面完成多次重复输入（交流电也就50Hz而已人怎可可能有这么
鬼畜...），所以可以认定并非玩家在操作。
而AI.cheat拥有无论多难的手操指令都有可能直接强制发动的特性，所以依旧可以输入看似不可能完成的指令。
Cmd乱数启动型AI开关实例：

;下面一段放到Cmd文件的手操指令定义部分
;--------------------------------------------------
[Command]
name = "AI0"
command = a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a
time = 0
[Command]
name = "AI1"
command = b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b
time = 0
[Command]
name = "AI2"
command = c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c
time = 0
[Command]
name = "AI3"
command = x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x
time = 0
[Command]
name = "AI4"
command = y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y
time = 0
[Command]
name = "AI5"
command = z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI6"
command = s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s
time = 0
[Command]
name = "AI7"
command = F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F
time = 0
[Command]
name = "AI8"
command = D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D
time = 0
[Command]
name = "AI9"
command = B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B
time = 0
[Command]
name = "AI10"
command = U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U
time = 0
[Command]
name = "AI11"
command = a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a
time = 0
[Command]
name = "AI12"
command = c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c
time = 0
[Command]
name = "AI13"
command = x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x
time = 0
[Command]
name = "AI14"
command = y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y
time = 0
[Command]
name = "AI15"
command = z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI16"
command = s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s
time = 0
[Command]
name = "AI17"
command = a,B,c,x,y,z,s,B,D,F,U,a,b,c,x,y,z,s,s
time = 0
[Command]
name = "AI18"
command = a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a
time = 0
[Command]
name = "AI19"
command = b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b
time = 0
[Command]
name = "AI20"
command = c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c
time = 0
[Command]
name = "AI21"
command = x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x
time = 0
[Command]
name = "AI22"
command = y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y
time = 0
[Command]
name = "AI23"
command = z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI24"
command = s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s
time = 0
[Command]
name = "AI25"
command = F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F
time = 0
[Command]
name = "AI26"
command = D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D
time = 0
[Command]
name = "AI27"
command = B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B
time = 0
[Command]
name = "AI28"
command = U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U
time = 0
[Command]
name = "AI29"
command = a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a
time = 0
[Command]
name = "AI30"
command = c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c
time = 0
[Command]
name = "AI31"
command = x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x
time = 0
[Command]
name = "AI32"
command = y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y,y
time = 0
[Command]
name = "AI33"
command = z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI34"
command = s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s,s
time = 0
[Command]
name = "AI35"
command = z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI36"
command = z,z,z,z,z,z,a,a,a,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI37"
command = z,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,z,z,z
time = 0
[Command]
name = "AI38"
command = z,z,z,z,z,a,a,a,z,z,z,z,z,a,a,a,z,z,z
time = 0
[Command]
name = "AI39"
command = z,z,z,z,z,a,a,a,z,z,z,z,z,z,a,a,z,z,z
time = 0
[Command]
name = "AI40"
command = z,z,z,z,a,a,a,z,z,z,z,a,z,z,a,a,z,z,z
time = 0
[Command]
name = "AI41"
command = z,z,z,a,z,z,z,z,z,z,z,z,z,a,a,z,z,z,z
time = 0
[Command]
name = "AI42"
command = z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI43"
command = z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,z,a,a,z
time = 0
[Command]
name = "AI44"
command = z,z,a,a,a,a,z,z,z,z,z,z,z,z,z,a,a,a,z
time = 0
[Command]
name = "AI45"
command = z,z,z,z,z,z,a,a,z,z,z,z,z,a,a,a,a,z,z
time = 0
[Command]
name = "AI46"
command = z,z,z,z,z,z,z,z,a,a,a,a,a,a,z,z,z,z,z
time = 0
[Command]
name = "AI47"
command = z,z,z,a,a,a,a,z,z,z,z,z,z,z,z,z,z,z,z
time = 0
[Command]
name = "AI48"
command = z,z,z,z,z,a,a,a,z,z,z,a,a,a,z,z,a,z,a
time = 0
[Command]
name = "AI49"
command = z,z,z,z,a,a,a,z,z,z,z,z,a,a,a,z,z,z,z
time = 0
[Command]
name = "AI50"
command = z,z,z,a,a,z,z,z,z,z,z,z,z,z,a,a,z,z,z
time = 0

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -3, AIフラグセット]
type = VarSet
triggerall = !var(59)
triggerall = RoundState = [1,2]
trigger1 = Command = "AI0"
trigger2 = Command = "AI1"
trigger3 = Command = "AI2"
trigger4 = Command = "AI3"
trigger5 = Command = "AI4"
trigger6 = Command = "AI5"
trigger7 = Command = "AI6"
trigger8 = Command = "AI7"
trigger9 = Command = "AI8"
trigger10 = Command = "AI9"
trigger11 = Command = "AI10"
trigger12 = Command = "AI11"
trigger13 = Command = "AI12"
trigger14 = Command = "AI13"
trigger15 = Command = "AI14"
trigger16 = Command = "AI15"
trigger17 = Command = "AI16"
trigger18 = Command = "AI17"
trigger19 = Command = "AI18"
trigger20 = Command = "AI19"
trigger21 = Command = "AI20"
trigger22 = Command = "AI21"
trigger23 = Command = "AI22"
trigger24 = Command = "AI23"
trigger25 = Command = "AI24"
trigger26 = Command = "AI25"
trigger27 = Command = "AI26"
trigger28 = Command = "AI27"
trigger29 = Command = "AI28"
trigger30 = Command = "AI29"
trigger31 = Command = "AI30"
trigger32 = Command = "AI31"
trigger33 = Command = "AI32"
trigger34 = Command = "AI33"
trigger35 = Command = "AI34"
trigger36 = Command = "AI35"
trigger37 = Command = "AI36"
trigger38 = Command = "AI37"
trigger39 = Command = "AI38"
trigger40 = Command = "AI39"
trigger41 = Command = "AI40"
trigger42 = Command = "AI41"
trigger43 = Command = "AI42"
trigger44 = Command = "AI43"
trigger45 = Command = "AI44"
trigger46 = Command = "AI45"
trigger47 = Command = "AI46"
trigger48 = Command = "AI47"
trigger49 = Command = "AI48"
trigger50 = Command = "AI49"
trigger51 = Command = "AI50"
var(59) = 1

优点：误触发率低
缺点：启动速度慢（因为不知道AI何时才会碰巧执行你写的command...可以说是碰运气），需要新增较多command（数量越多效果越
好），AI.cheat需要打开（默认打开）

--------------------------------------------------
5.3.3Helper型AI开关
--------------------------------------------------

此开关需要创建一个可以接受手操指令（keyctrl = 1）的Helper。
在手操时，玩家输入手操指令，人物本体和创建的Helper会同时接收到玩家的指令；
但若是AI操作的情况，AI可以做到单独触发人物本体的command但是不触发Helper的command。
一旦遇到人物本体的command和Helper的command不一致的情况，便可以察觉出并非玩家在操作。
注意使用时最好不要跳开场（跳开场会增大误触发的几率）。
（下面的例子直接复制被广泛使用的平成氏AI教程里面的AI开关...呃...其实删了一个ctrl）
Helper型AI开关实例：

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -3, 创建AI启动用Helper]
type=helper
trigger1=!NumHelper(10000)
trigger1=roundstate=2
trigger1=alive
trigger1=var(59)=0
Trigger1=PrevStateNo=(开场前状态号)||PrevStateNo=5900
Trigger1=stateno=0
helpertype=normal
name="AI"
stateno=10000
ID=10000
pos=9999,9999
keyctrl=1;令Helper接受手操指令
pausemovetime=2147483647
supermovetime=2147483647
persistent = 0

[State -3, Helper持续保持在状态10000]
type=changestate
trigger1= ishelper(10000)
trigger1= stateno!=10000
value=10000

[State -3, AIフラグセット]
type = VarSet
triggerall = !var(59)
triggerall = RoundState = [1,2]
Trigger1 = Helper(10000),var(59);Helper里面的开关打开时，本体AI开关打开
var(59) = 1

;下面五段放到St文件里任意一个合适的地方
;--------------------------------------------------
[Statedef 10000];Helper的状态定义
anim=10000 ;请保证修改Air文件使得存在一个动画（例如10000）是无任何框的空白动画
ctrl=0

[State 10000, 如果本体错误跳进状态10000就切换回站姿]
type=selfstate
trigger1=!ishelper
value=0

[State 10000, 人物本体和Helper的command相同时返回赋值Var(59)为-1]
type=varset
trigger1=command="up"&&root,command="up"
trigger2=command="down"&&root,command="down"
trigger3=command="back"&&root,command="back"
trigger4=command="fwd"&&root,command="fwd"
trigger5=command="a"&&root,command="a"
trigger6=command="b"&&root,command="b"
trigger7=command="c"&&root,command="c"
trigger8=command="x"&&root,command="x"
trigger9=command="y"&&root,command="y"
trigger10=command="z"&&root,command="z"
trigger11=command="start"&&root,command="start"
var(59)=-1

[State 10000, AI已开启或者人物本体和Helper的command相同时销毁Helper]
Type = DestroySelf
triggerAll = isHelper
Trigger1 = root,var(59)||var(59)=-1
trigger2=command="up"&&root,command="up"
trigger3=command="down"&&root,command="down"
trigger4=command="back"&&root,command="back"
trigger5=command="fwd"&&root,command="fwd"
trigger6=command="a"&&root,command="a"
trigger7=command="b"&&root,command="b"
trigger8=command="c"&&root,command="c"
trigger9=command="x"&&root,command="x"
trigger10=command="y"&&root,command="y"
trigger11=command="z"&&root,command="z"
trigger12=command="start"&&root,command="start"

[State 10000, 当Helper的Var(59)不为-1（意味着两者command没有相同的）而且本体有command时打开AI开关]
type=varset
triggerall=var(59)!=-1
trigger1=root,command="up"
trigger2=root,command="down"
trigger3=root,command="back"
trigger4=root,command="fwd"
trigger5=root,command="a"
trigger6=root,command="b"
trigger7=root,command="c"
trigger8=root,command="x"
trigger9=root,command="y"
trigger10=root,command="z"
trigger11=root,command="start"
var(59)=1

优点：启动速度快
缺点：误触发率较高，需要占用一个Helper

--------------------------------------------------
5.3.4XOR型AI开关
--------------------------------------------------

此AI开关与Cmd乱数启动型AI开关比较类似，无论是对AI.cheat的依赖还是两种AI开关的优缺点。
XOR即是异或运算符，A ^^ B，AB只有一个为真才为真，否则为假。
此开关需要创建多个与原来已经存在的手操指令重复的手操指令（例如名为"x"和"x2"的两个指令都是按x键）。
在手操时，玩家输入手操指令，两个要求相同输入的command会被同时鉴别为真；
但若是AI操作的情况，AI可以做到单独发动其中一个command。
一旦遇到只发动其中一个command的情况，便可以察觉出并非玩家在操作。
（下面的例子直接引用鱼姐（muigoloroh）在tieba.baidu.com/p/1440470506的实例）
XOR型AI开关实例：

;下面一段放到Cmd文件的手操指令定义部分
;--------------------------------------------------
[Command]
name = "a2"
command = a
time = 1
[Command]
name = "b2"
command = b
time = 1
[Command]
name = "c2"
command = c
time = 1
[Command]
name = "x2"
command = x
time = 1
[Command]
name = "y2"
command = y
time = 1
[Command]
name = "z2"
command = z
time = 1
[Command]
name = "start2"
command = s
time = 1
[Command]
name = "holdfwd2"
command = /$F
time = 1
[Command]
name = "holdback2"
command = /$B
time = 1
[Command]
name = "holdup2"
command = /$U
time = 1
[Command]
name = "holddown2"
command = /$D
time = 1

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -1, XOR AI开关]
type = VarSet
triggerall = var(59) = 0 && !hitpausetime
trigger1 = command = "a" ^^ command = "a2"
trigger2 = command = "b" ^^ command = "b2"
trigger3 = command = "c" ^^ command = "c2"
trigger4 = command = "x" ^^ command = "x2"
trigger5 = command = "y" ^^ command = "y2"
trigger6 = command = "z" ^^ command = "z2"
trigger7 = command = "holdfwd" ^^ command = "holdfwd2"
trigger8 = command = "holdback" ^^ command = "holdback2"
trigger9 = command = "holdup" ^^ command = "holdup2"
trigger10 = command = "holddown" ^^ command = "holddown2"
trigger11 = command = "start" ^^ command = "start2"
var(59) = 1

优点：误触发率低
缺点：启动速度慢（因为不知道AI何时才会碰巧执行你写的command...可以说是碰运气），需要新增较多command（数量越多效果越
好），AI.cheat需要打开（默认打开）

--------------------------------------------------
5.3.5AILevel型AI开关
--------------------------------------------------

1.0及以上的版本Mugen新增了一个trigger——AILevel。
当AI控制的时候，AILevel返回option里面设置的难度（1~8）；而玩家控制的时候，会因为不是AI控制而返回0。
自此，AI开关问题被新增的内容完美解决。AI作者不必再为AI开关的准确性和速度而纠结。
AILevel型AI开关实例：

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -1]
type = Varset
trigger1 = AILevel
V = 59
value = 1

优点：必定以最快速度准确地启动AI
缺点：仅能在1.0或以上的专用人物使用（1.0+大法好，退Win保平安...这不是缺点是优点你懂吗！）

==================================================
5.4手操指令修改
==================================================

--------------------------------------------------
当人物处于非手操场合，Mugen里面有自带的脸滚键盘式（如k87uy6ttfr4567yu8rgtf54...啊，脸好痛）的随机按键，
而Cmd文件里面切换相关状态部分会根据command切换状态。
那么问题来了，AI技术哪家强...不对...重新来一遍。
那么问题来了，Mugen的随机按键会随机触发Cmd里面的状态切换，
那么人物将会在我们控制之外随机做不同的动作，但是这种乱出招并不是我们所希望看到的。
于是，我们既然设好了AI开关，紧跟着就要修改相关的sctrl，使得他们在AI开启的情况下不再乱动。

用回第3章的例子：

;Stand Light Punch
[State -1, Stand Light Punch]
type = ChangeState
value = 200
triggerall = !Var(59);只有Var(59)为0，也就是AI开关关闭的时候才能用手操触发
triggerall = command = "x"
triggerall = command != "holddown"
trigger1 = statetype = S
trigger1 = ctrl
trigger2 = stateno = 200
trigger2 = time > 6

在前面加上triggerall = !Var(59)即可。所有带有command的sctrl都需要加上限制以免被随机按键触发。
另外，带有command的sctrl绝大多数情况出现在Cmd文件里面，但是在其他文件例如St和Stcommon文件里面同样可能存在不少带有
command的sctrl。以下这段是在kfm.cns里面出现的sctrl：

;------------------
; Light Kung Fu Knee - jump
...
[Statedef 1051]
...
[State 1051, 2]
type = ChangeState
trigger1 = Command = "a" || Command = "b"
trigger1 = Vel y < -1
value = 1055

跟Cmd文件的处理方式一样，加上一条triggerall = !Var(59)即可。

--------------------------------------------------
在所有带有command的sctrl前加完了triggerall = !Var(59)...这样总算是告一段落了......唉？还没完事？
没错，除了带有command的sctrl以外，Mugen里面还存在内置的隐性的用手操指令切换状态，
例如下蹲（Stateno 10）、走动（Stateno 20）和跳跃（Stateno 40）。
理论上来说，人物只要处于可控状态（例如站姿），按下会下蹲，按前后会走动，按上会跳跃。
但是无论在什么地方，我们都找不到这些状态是如何切换的，这情况相当难处理。
当然，AI作者们已经早已解决了这个难题，具体解决方法较麻烦，所以在第8章我们再慢慢讨论解决方案。

==================================================
课后作业：

1.
为什么Cmd乱数启动型AI开关与XOR型AI开关新增command数量越多效果越好？

2.
以上谈及的3种AI开关——Cmd乱数启动型AI开关、Helper型AI开关和XOR型AI开关，是否可以混合使用？为什么？


6.debug相关、Air简介、人物性能调查

                本页内容由口水轩撰写. 由【softmgr】整理编辑.
--------------------------------------------------
这一章我们要介绍的内容虽然不是AI，但是是与写AI密切相关的一些东西。

==================================================
6.1debug模式与十德
==================================================

--------------------------------------------------
Mugen作为一个格斗游戏制作平台，自然少不了代码。说到了代码，自然少不了debug。
所以，Mugen自身也是带有debug模式的。
在data文件夹里面的mugen.cfg文件里面有下面一段代码：

[Debug]
;Set to 0 to disable starting in debug mode by default.
Debug = 1

;Set to 0 to disallow switching to debug mode by pressing Ctrl-D.
;If Debug = 1, this will be ignored.
AllowDebugMode = 1

...（后略）

debug模式开启的方法有两种：

方法1. 一次性开启：
若Debug = 0而且AllowDebugMode = 1，在战斗界面按 ctrl + D，之后屏幕上面多了好几串代码的话那就对了。
方法2. 永久开启：
若Debug = 1，则永久开启。
（另外多按几下 ctrl + D，可以切换不同人物/helper的数据。上面两种方法都适用。）

--------------------------------------------------
那么开启debug模式有什么用呢？
我们可以关注一下左下角，这里面包含了很多我们想知道的信息：
ACTION ID, SPR(sprite), ELEMNO(element number), TIME, STATENO, CTRL, TYPE(statetype), MOVETYPE.
分别是 动作编号，图像号，元素号，时间，状态号，是否可控，状态类型，动作类型。
这些都是我们在AI编写的时候经常想知道的数据。

可能有读者会问，能不能知道更多的东西，例如AI开了没有呢？
没问题，还记得在第四章我们提及过的DisplayToClipboard吗？这里就能排上用场。例如：
[State -1, Display]
type = DisplaytoClipboard
Trigger1 = 1
text = "X : %d | Y : %d | Var : %d | FX : %d | BX: %d "
params = ceil(P2bodydist X) , ceil(P2bodydist Y) , ceil(Var(59)), ceil(FrontEdgeBodyDist), ceil(BackEdgeBodyDist)
（这个例子所显示的是双方X轴Y轴距离，Var(59)的值，和人物跟画面边缘的前后距离）
假设这里的Var(59)是AI开关的话，我们就可以知道AI开关究竟是不是已经开启了。

顺便请注意键盘Pause键可以暂停，暂停中ScrollLock键可以跳至下一帧，这两个键可以让你不必使用动态视力去看debug。

--------------------------------------------------
可能有学过计算机的读者会说，这debug太垃圾了，字这么小，还只能显示5个自定义量，这能忍？
笔者在此可以严肃的告诉各位，我也觉得不能忍啊！有木有！！！

于是，下面要介绍一款因为Mugen自带debug模式不能忍而生的软件——十德（窓无限の十徳ナイフ）。
这款软件的作者是MnsUouxgOs氏。在此必须向这位造福多少作者的软件作者表示感谢OTL。
这款软件目前可以在WinMugen和Mugen1.0上面使用（1.1党请保重）。
他强大之处在于，可以同时简单监控各个人物、helper的各种数据和Var。
具体教程可以看看贴吧精品区唯酱写的教程《窓无限の十徳ナイフ 图文简易 使用教程》，里面有具体的介绍，而且本身这软件也
不难使用，在此不予赘言。
但是其劣势还是存在的，例如不能像自带debug那样直接监视自由输入的一长段条件而只能监视常用的数据。
不过对比起来，还是比自带的debug模式舒服了不知道多少倍了XD，而且十德和自带debug一起使用也是没问题的。
强烈建议尝试这个神奇的软件！

==================================================
6.2Air简介
==================================================

--------------------------------------------------
本来Air文件没有太大必要介绍，但是因为攻击判定框受和击判定框都是由Air文件决定，还是简单介绍一下吧。

因为Air比较容易理解，我们直接上例子，分别是KFM的站姿和站轻拳的Air：

; Standing Animation
[Begin Action 0]
Clsn2Default: 2
Clsn2[0] = -13, 0, 16,-79
Clsn2[1] = 5,-79, -7,-93
0,0, 0,0, 10
0,1, 0,0, 7
0,2, 0,0, 7
0,3, 0,0, 7
0,4, 0,0, 7
0,5, 0,0, 45
0,4, 0,0, 7
0,3, 0,0, 7
0,2, 0,0, 7
0,1, 0,0, 7
0,0, 0,0, 40

; Stand Light Punch
[Begin Action 200]
Clsn2Default: 2
Clsn2[0] = -10, 0, 19,-80
Clsn2[1] = 0,-94, 12,-80
200,0, 0,0, 2
200,1, 0,0, 1
Clsn1: 1
Clsn1[0] = 16,-80, 61,-71
Clsn2: 3
Clsn2[0] = 19, 0,-10,-80
Clsn2[1] = 6,-94, 18,-78
Clsn2[2] = 19,-80, 61,-71
200,2, 0,0, 4
200,1, 0,0, 3
200,0, 0,0, 2

首先由[Begin Action XXX]开始整个段落，标明这是XXX编号的动作。
之后Clsn1代表攻击判定框，Clsn2代表受击判定框，如果后面跟着Default的话则代表该动作内这些框一直生效，
冒号后面紧跟着的数字N代表有多少个框。
因为有N个框，我们要将其画出来，也就是下面的 Clsn1[0] / Clsn2[0] 到 Clsn1[N-1] / Clsn2[N-1]。
等号后面紧跟着的四个数字代表 X方向1，Y方向1，X方向2，Y方向2，也就是框的四个顶点坐标。
再下面的五个数字分别代表 Sff的图像组和组内的第几张图，X轴偏移量，Y轴偏移量，持续时间。

知道了又有什么用呢？举个例子，我们要知道KFM的站轻拳的攻击判定相关资料，我们需要读的是：

; Stand Light Punch
[Begin Action 200]
Clsn2Default: 2
Clsn2[0] = -10, 0, 19,-80
Clsn2[1] = 0,-94, 12,-80
200,0, 0,0, 2;第一幅图用时2f，只有默认受击判定框
200,1, 0,0, 1;第二幅图用时1f，只有默认受击判定框
Clsn1: 1;攻击判定出现
Clsn1[0] = 16,-80, 61,-71;攻击判定框的大小
Clsn2: 3;新的受击判定框，暂时来说对我们没用
Clsn2[0] = 19, 0,-10,-80
Clsn2[1] = 6,-94, 18,-78
Clsn2[2] = 19,-80, 61,-71
200,2, 0,0, 4;攻击判定出现前用时2+1=3f，持续时间4f，所以4~7f是攻击判定
200,1, 0,0, 3
200,0, 0,0, 2

其模板为：

[Begin Action XXX]
Clsn2Default: N;（Clsn2Default和Clsn2的区别只有一直生效）
Clsn2[0] = AA, BB, CC, DD
...
Clsn2[N-1] = EE, FF, GG, HH
Clsn1 / Clsn2: N;（攻击判定框或者受击判定框）
Clsn1[0] / Clsn2[0] = AA, BB, CC, DD;（框的大小）
...
Clsn1[N-1] / Clsn2[N-1] =
EE, FF, GG, HH
III,J, K,L, M;（这些框对应的图像，偏移量和持续时间）
OOO,P, Q,R, S;（如果没写框就只有图像）
Clsn1 / Clsn2: N
...

--------------------------------------------------
在这里顺便提一提Mugen对人物制作有很大帮助的Fighter Factory（简称FF）。
作为一个Mugen爱好者制作的辅助软件，FF的功能应有尽有，可以给人物作者很大的帮助。
例如人物代码可以一键生成Sctrl模板；可视化的Sff、Air调整等等。
但是AI制作和人物制作不一样，FF对AI制作的帮助不大。
AI制作的Sctrl基本是Changestate和Var相关，Changestate方面直接复制Cmd的原Changestate就行了（因为写AI反正都不能违背原
本Cmd的要求），Var相关也不用什么模板，那么代码编写除了检查括号以外其他功能就没有必要了，这么一来还不如用notepad++。
FF对AI制作的最大帮助应该就是Air相关，可以更加直观查看攻击判定框和防御判定框，还有发生时间和持续时间。
所以即使FF毫无疑问是一个很好用的工具，此教程不打算对其进行具体介绍。

==================================================
6.3人物性能调查
==================================================

--------------------------------------------------
在第二章我们曾经提及，AI与性能的关系是AI发挥性能。
那么我们要写AI的话，自然是离不开人物的性能了，所以写AI之前，通常或多或少也得要先调查人物的性能。
只有对人物有了更加深刻的了解，才能更好的发挥其性能，作出更强更能发挥性能的AI。

--------------------------------------------------
人物性能调查项目
--------------------------------------------------

那么通常来说我们需要知道什么方面的性能呢？笔者写AI时要调查的内容如下：

非攻击：跑动启动及停止硬直、跳跃高度及滞空时间。
各个招式：状态号、能量消耗、伤害、攻击范围、受击范围、攻击发生帧、击中有利帧、被防有利帧、无敌时间及种类、是否中下
段/不可防、时长、juggle、取消链和能否空振。

下面来解释一下这些数据的作用和意义：

跑动启动及停止硬直：如果硬直大的话，跑起来或者停下来时就很容易被人攻击，所以跑动硬直越大要越谨慎。
跳跃高度及滞空时间：跳跃高度越高，躲避水平飞来飞行道具的能力就越好；而滞空时间越短，跳跃的风险越低。

状态号、能量消耗、伤害：...不解释。
攻击范围、受击范围：攻击范围越大越容易击中对方；受击范围越小越好，比人物宽度还小或者上下段没有受击判定的话甚至可以
当切反技。
攻击发生帧、击中有利帧、被防有利帧：攻击发生的越快，对方越难反击，也可以用于抢招；击中有利帧、被防优势帧则是让人物
在击中/压制造成对方受击硬直/防御硬直时，有更多的时间进行连段/压制，造成硬直越长越容易让连段（特别是目押连段）成立，
而硬直差不利可能会造成对方反取得先手。
无敌时间及种类：这里包括开始时间和持续时间，开始时间越早、持续时间越长切反性能越佳。
中下段/不可防：上下择及不可防的破防手段。
时长：过长的动作硬直可能会被对方躲避后反击。
juggle：Mugen特有的空中连击系统，决定受击浮空的目标是否能被继续连段，在第11章会详细介绍。
取消链：越丰富的取消链可使人物越灵活，也使人物的表现越精彩。
空振：空振令人物在某些动作的硬直中不需要接触对方也可以取消成为其他动作，使人物更加灵活。

--------------------------------------------------
人物性能调查方法
--------------------------------------------------

要调查这些数据，其实都是不必使用其他额外的东西完成的：

跑动启动及停止硬直：打开St文件调查是否有跑动启动及停止硬直，以及硬直时间。
跳跃高度及滞空时间：打开Mugen自己跳一次。

状态号：打开Cmd文件，或者开debug直接手操用一次，都能很直观的看出来。
伤害：打开St文件搜索damage/lifeadd相关。
能量消耗：打开St文件搜索power相关，不要求精确的话直接手操用一次不就行了吗...
攻击范围、受击范围：打开Air文件调查，另外攻击范围我们通常关注的是能触碰到对方的最大P2bodydist，P2bodydist X是攻击判
定框最前端坐标-人物前端宽度（Cns内可查得），P2bodydist Y和P2dist Y一致，所以只要调查框的大小就行了。
攻击发生帧、击中有利帧、被防有利帧：攻击发生帧直接可以打开Air文件调查（如果是超必杀技之类有暂停时间的话要减去）；击
中有利帧、被防有利帧与hitdef里面的参数（pausetime、ctrltime、hittime、hitshaketime）和动作剩余时长有关，直接计算比
较困难，通常是打开Mugen击中后暂停一帧帧数双方回到可控状态的时间差。
无敌时间及种类：打开St文件搜索Hitby相关（包括NotHitby），注意需要减去暂停时间。
中下段/不可防：打开St文件看guardflag，还有是否有特殊断言（AssertSpecial）不可防御（unguardable）。
时长：看看会使用什么动画，把这些动画的时间都加起来。
juggle：打开St文件看juggle。
取消链：打开Cmd文件看看可以被什么状态取消。
空振：打开Cmd文件，如果能在!Movecontact的条件下取消就是可以空振。

--------------------------------------------------
可能有读者会说，这一个个调查也太麻烦了吧，就没有AI作者搞过性能调查的辅助工具吗？
好，下面笔者就要来介绍一个调查人物性能用的Mugen人物和该人物的两个补丁。
人物名字叫“training”，就是训练（沙包）的意思，作者是stupa氏（先拜OTL）。
如果你在视频网站看过某些人物展示视频，对面是个身边有数字的KFM或者抖M天子，基本就是这人物了。
两个补丁由ADI氏（继续拜OTL）提供，作用分别是training的功能扩展和在training基础上制作的攻击数据调查（名为
Attacks-Storage，简称为atks）。
这三份作品起码把笔者调查性能的时间起码缩减了一半，对笔者而言stupa氏和ADI氏简直是救世主一般的存在OTL。

--------------------------------------------------
首先介绍training，其实就是一个类似于众多格斗游戏训练模式的人物。
作为AI作者，通常可以把training放在2P侧默认选人位置，测试性能是选取人物会非常方便。
另外请不要被人物默认头像欺骗你的眼睛，否则你打开人物之后只会剩下失望和沮丧。
进入战斗界面后，1P侧随便按几下攻击，你会发现1P侧会出现一些数字。
人物后下方较大的数字是之前的状态攻击第一次接触对方的时间，如果没有攻击成功会出现从不可控状态开始到恢复可控状态的时
间，最多一共可记录三个。
人物后上方较小的数字貌似是按ABCXYZ几个键才会触发更新，是之前状态的状态号和攻击第一次接触对方的时间，如果没有攻击成
功会出现Changestate前所经过的时间，最多一共可记录三个。
training前下方的数字代表的是对方的P2bodydist X（可以改成P2dist X）。
按X键会出现一个倒计时的攻击，按6X会出现一个发生慢速度慢的飞行道具，用来测试当身/格挡/精防和飞道返。
按Y键会出现很多数据，包括上一次造成的伤害、上一个连段造成的总伤害、开局以来造成的最大连段伤害、最大连击数、有利帧、
对方是否可控。基本上就和众多格斗游戏的训练模式的数据一样，不予赘言。
按Z键会出现一个标尺，用于大约测量双方框的大小和位置。
按S键会出现一个菜单，分别是人物状态类型（SCA）、距离（任意或者远中近）、自动防御开关、受身开关、受身时间、距离标识
类型（P2bodydist X或P2dist X）、倒地时间和起身类型。也是和和众多格斗游戏的训练模式的数据一样，不予赘言。
另外这个人物有非常多可以调整的参数，具体的麻烦自己看readme并按照自己喜好修改。
利用training，我们就可以比较方便的调查招式的伤害、攻击发生帧、有利帧、中下段/不可防、时长等数据了。

--------------------------------------------------
然后介绍atks。
通常可以把atks放在training旁边，反正测起来就是两个一起用。
atks一共有五种模式可以选择，分别是A中下段、B攻击范围、C无敌时间、D有利帧、E气回收量。
前四个模式应该都很不错，不过因为training基本可以调查大部分数据，笔者通常只用B模式调查training也难以调查的攻击范围。
因为ADI氏不但写了详尽的文字解释，还制作了html网页图文并茂的讲解每个细节，在此不予赘言。
特别说明一下某些注意点：按住S键按ABCDE可以切换模式（最后F4重启切换）；切记S键是重制；空中招式在Statetype = S的情况
下使用会直接落地，记住调整Statetype；B模式下把时间间隔调成1f就是每帧检测，可以顺便测出持续时间；B模式下按Y键可以取
消位移对距离的影响。
另外这个人物也有非常多可以调整的参数，具体的麻烦自己看readme并按照自己喜好修改。
于是，招式的中下段/不可防、攻击发生帧、有利帧、攻击范围、无敌时间及种类也可以轻松调查了。

--------------------------------------------------
但是有了上面这些神器还是不够的，能量消耗、受击范围、juggle、取消链和能否空振还是要自己动手。
不过剩下的这些除了受击范围以外都是比较容易调查的，上面的两个人物算是把不少麻烦的调查给解决了。

==================================================
课后作业：

1.
下载并尝试使用十德、FF、training和atks。

2.
调查KFM的蹲轻拳的攻击发生帧和击中有利帧（然后你就懂了KFM的世纪末轻拳原理了XD）。


7.AI框架与代码顺序

                本页内容由口水轩撰写. 由【softmgr】整理编辑.

==================================================
7.1AI框架、代码顺序对AI的影响
==================================================

--------------------------------------------------
先说说AI框架对AI的影响。
在Cmd里面，通常一个状态只会由一个changestate控制，因为一个changestate里面足以应付所有按键输入的情况。
但是在AI里面，只用一个changestate控制所有情况是不科学的。
AI需要做的事情有很多，例如切反、连段、立回等。如果把他们全部塞在一起，就算作者自己也会觉得晕。
此外，因为代码顺序也会对AI造成影响（下文会详细提及）。
我们通常会把AI按照功能分成不同板块，分开编写，最后按顺序结合起来成为一个完整的AI。
这个就是我们所说的AI框架，其作用在于使AI更有条理，避免顺序冲突和方便阅读。

--------------------------------------------------
然后说说代码顺序对AI的影响。
虽然看上去随意调换代码的顺序对AI不会有影响，但事实并非如此。
在第3章我们有提及过运算符优先级，其实不单运算符是如此顺序执行，所有代码的执行顺序都是类似的。
因为代码的读取是从上到下、从左到右，所以在上面的代码先执行，其次同一行的代码前面的先执行。

请看下面两段代码：

[State -1, 升龙]
type = ChangeState
value = 1100
Triggerall = Var(59) > 0
Triggerall = Roundstate = 2
Triggerall = Statetype != A
Triggerall = ctrl
Trigger1 = EnemyNear,Movetype = A
Trigger1 = Random < 500

[State -1, 立防]
type = ChangeState
value = 130
Triggerall = Var(59) > 0
Triggerall = Roundstate = 2
Triggerall = Statetype != A
Triggerall = ctrl
Trigger1 = EnemyNear,Movetype = A

人物在非空中可控的情况下被对方攻击时，上面两段代码就会被触发。
如果是按照上面的顺序安排升龙和站姿防御两段代码的话，人物在第一帧所做的动作将会是50%几率凹升龙，50%触发防御。
但是如果将两段代码顺序反过来的话，人物在第一帧所做的动作将会必定触发防御。

从上述的例子可见按，如果两段不同功能的代码的触发条件类似，一不注意就会因为次序不同而产生不同的结果。
这个也就是为什么要注意代码顺序，以触发自己想要的代码。

==================================================
7.2AI框架范例
==================================================

--------------------------------------------------
说到这个首先得列出平成氏AI教程所提及的AI框架：

順番をまとめると
[AIフラグ]
│
[切り替えし]
│
[ガード]
│
[(起き攻め)]
│├[地上]─[地上起き攻め]
│└[空中]─[空中起き攻め(詐欺飛び)]
[(連続技関連)]
│├[地上]┬[地上目押し]
││　　　├[地上隙突き]
││　　　└[地上繋ぎ]
│└[空中]┬[空中目押し]
│　　　　├[空中隙突き]
│　　　　└[空中繋ぎ]
[(地上)]
│├[地上移動関係]
│└[地上立ち回り技振り]
[(空中)]
├[空中移動関係]
└[空中立ち回り技振り]

这个是很多AI作者都在使用的一个AI框架。笔者使用的AI框架也是在这个基础上建立起来的，再次感谢平成氏OTL
不过为了方便解释，下文会使用笔者自己常用而比较熟悉的在平成氏框架基础上作修改的AI框架进行讲解：

[AI开关]┐
││
[AI helper]│
│├ 1
[变量]│
││
[对策、双打]┘
│
[抓硬直、受身狩]┐
││
[抢招]├ 2
││
[切反]┘
│
[起攻、压制、诈飞]┐
│├[地上]│
│└[空中]│
│├ 3
[连招、目押、倒地追击]│
│├[地上]│
│└[空中]┘
│
[立回、骗招、乱动]┐
││
[防御]│
│├ 4
[移动]│
││
[蓄气]┘

笔者使用的这个模板主要是根据该板块对AI强度的影响来排列。
这么排列的好处在于对AI最有利的行为总会被最先运行。
下面开始对每个板块进行解说（下面会有很多格斗游戏术语，对格斗游戏不熟悉的读者建议先去查阅相关资料）。

--------------------------------------------------
1. 第一大板块里面的板块是关于AI前期准备和特殊需要提前处理的代码。
[AI开关]顾名思义就是第五章所说的AI开关。
[AI helper]的内容会在第十五、十六章详细讲，此处要做的建立用于学习和记录的helper。
[变量]就是一些AI会用到的作为辅助的本体变量。
[对策、双打]因为是属于特殊情况，一个是面对特殊人物才会触发，一个是双打情况才会触发，和普通的1V1的战斗有所不同，
所以放在前面以防被其他代码干扰。

2. 第二大板块里面的板块是一些令人物在非优势情况（通常是对方攻击时）下取得优势的板块。
[抓硬直、受身狩]是关于对方卖（攻击、受身）硬直时抓住机会打击对方获得先机。
[抢招]是指对方出发生较慢的招式时我方用发生较快的招式用时间差优势反先打击对方。
[切反]指的是用无敌、霸体等强力性能反击、回避对方招式。
因为一般来说抓硬直和抢招可以使用连段取消链比较低层的招式，而切反一般是处于取消链高层，所以为了效益会把切反放在后面
（当然无敌升龙还能接连段的话那没所谓...不过真有这么随便无敌升龙还能接连段的BUG人物吗）。

3. 第三大板块里面的板块是一些令人物在优势情况下扩大优势的板块。
[起攻]是指对方在倒地起身动作不受控制时，我方可以比对方优先做出攻击动作进行压制。
[压制]是关于对方在防御硬直内、自己有飞行道具掩护等对自己有利的情况下为了打开对方防御的进攻。
[连招]明显就是已经击中对方之后为了增大伤害而一直打下去的连段（Combo）了。

4. 第四大板块里面的板块是一些令双方相持情况下令自己可能获得优势的板块。
[立回]这里的定义和格斗游戏的（双方在未接触情况下为了获得优势而做的所有行为）有点不一样，特指自己（通常来说）没有收到对方威胁的试探性攻击。
[防御]...字面意思。
[移动]是指走、跑、跳等单纯令人物位移的动作。
[蓄气]...也是字面意思（当然也有连段把对方打倒接蓄气的，那种写进连招后面也无妨）。

==================================================
7.3AI框架顺序须知
==================================================

--------------------------------------------------
上面这两个模板仅供参考，希望各位读者不要死记硬背照抄，而应该结合自己的需求和理解进行修改。
但是要对这些模板进行修改的话，有一些顺序是建议遵守的。
简单来说，就是两个不同功能的板块的触发条件类似的话，更有利的一个尽量放在前面。

1. [抢招、切反] -> [防御]
如同7.1里面所举的例子，两者都是被攻击时触发的板块，顺序如果反过来的话，有可能一直铁壁防御了。

2. [抓硬直] -> [立回]
对方出现硬直时，我方没有收到威胁而且对方不受控制，通常会用尽可能造成高伤害的起手，而不是试探性攻击。

3. 其实好像没啥了...其他的基本不会因为顺序有太大冲突...
个人比较建议遵守的是 [立回] -> [防御] -> [移动]，[抓硬直、抢招] -> [切反]。
起码进入攻击范围会先攻击，进入防御范围会先防御，而不是乱走动；以及能最大化连段的收益。

--------------------------------------------------
这么一来，万事俱备只欠东风。理论知识和准备工作都做好了，下一章开始就是实际动手了AI...呵呵呵...

     ＼ ／
     ＼ ∧_∧ ／
     | ∩( +ω+)∩ |
     ／ \ / ＼
     ／ (⌒つ⌒) ＼

做好觉悟了吗

==================================================
课后作业：

1.
新人人物作者通常会在Cmd文件犯一种常见的错误。如下：

;Stand Light Punch
[State -1, Stand Light Punch]
type = ChangeState
value = 200
triggerall = command = "x"
trigger1 = statetype = S
trigger1 = ctrl

;Crouching Light Punch
;偟傖偑傒庛僷儞僠
[State -1, Crouching Light Punch]
type = ChangeState
value = 400
triggerall = command = "x"
trigger1 = statetype = C
trigger1 = ctrl

;Light Kung Fu Palm
[State -1, Light Kung Fu Palm]
type = ChangeState
value = 1000
triggerall = command = "236x"
trigger1 = statetype != A
trigger1 = ctrl

为什么这个顺序会导致state1000这个招式使用不出来？

2.
如果把[AI开关]和[AI helper]这两个板块放在整个AI框架的最后，会对AI有什么严重的影响吗？


8.公用状态修改：移动、跳跃、受身及防御

                本页内容由口水轩撰写. 由【softmgr】整理编辑.

终于真正的开始写AI了。从第8章开始到第13章，都是关于AI的编写。
从这章开始我们正式接触人物里面的代码。代码比较长可能比较难理解，建议一段一段的读，不要被长度给吓到，多壮观的建筑都
是一砖一瓦搭成的，无论多长的代码也是如此，把每段代码逐个击破合起来就是你想要的答案。
首先我们先从各个人物几乎都有的状态开始入手，也就是公用状态。

==================================================
8.1公用状态与Stcommon简介
==================================================

--------------------------------------------------
公用状态是一些各个人物几乎都有的状态，而这些状态的状态号基本上也是固定的。
例如站姿0，蹲姿10~12，行走20，起跳40，跑/前冲100，后撤105，防御120～155，倒地5110，起身5120等等。

Stcommon是一个存放公用状态的特殊st文件。
如果其他st文件没有重复定义Stcommon里面的状态，人物将会使用Stcommon里面定义的状态。
Mugen在data文件夹里面附有默认的common1.cns，如果人物没有自带Stcommon文件，那么人物会调用这个common1.cns。
因此，如果人物自带Stcommon文件，那么我们就直接对那个文件进行修改；如果人物没有自带Stcommon文件的话，就要在人物文件
夹内自己新建/复制一个Stcommon文件，并把Def文件内的Stcommon路径改成你文件的路径。

打开common1.cns后我们可以发现，其实Stcommon和一般的st文件没有太多不同。
里面很多Sctrl其实是不需要管的，如第5章所说，我们只需要看会被command影响的某些Sctrl。
一般来说这些涉及的内容包括：移动（行走、跑、前冲、后撤、跳跃）、受身及防御。

==================================================
8.2行走
==================================================

--------------------------------------------------
行走是格斗游戏最为常见的移动方式之一。
虽然移动速度比较慢，但是全程都是属于可控状态，可以随时应对各种情况，是最安全的移动方式。

默认的common1.cns中代码如下：

;--------------------------------------------------
; Walk
[Statedef 20]
type = S
physics = S
sprpriority = 0

[State 20, 1]
type = VelSet
trigger1 = command = "holdfwd"
x = const(velocity.walk.fwd.x)

[State 20, 2]
type = VelSet
trigger1 = command = "holdback"
x = const(velocity.walk.back.x)

[State 20, 3]
type = ChangeAnim
triggerall = vel x > 0
trigger1 = Anim != 20 && Anim != 5
trigger2 = Anim = 5 && AnimTime = 0
value = 20

[State 20, 4]
type = ChangeAnim
triggerall = vel x < 0
trigger1 = Anim != 21 && Anim != 5
trigger2 = Anim = 5 && AnimTime = 0
value = 21

如代码所示，默认的行走分为向前走和向后走，这两个方向的行走用的是同一个状态号20。
这个状态会根据手操按键的不同（也就是前和后）而切换为对应的动画（动画20和21）和速度。
然而这样一个状态包含两个不同属性的动作的情况是相当不利于AI编写的。
因为这样不但要在Statedef -1/-3里面加入对应的trigger使其动起来，还要在stcommon文件里面区分前后两种情况，
分开两个地方去管理一类型动作。这么做相当麻烦还容易出错，所以我们要对其进行一定的调整。
比较常用的方法是新建一个（或者一些）状态来区分不同的动作，以后写状态切换的时候就会简单不少。

实例如下：

;下面两段放到[Statedef 20]附近
;--------------------------------------------------
; Walk B 向后走
[Statedef 19]
type = S
physics = S
sprpriority = 0

[State 20, 2]
type = VelSet
trigger1 = 1
x = const(velocity.walk.back.x)

[State 20, 4]
type = ChangeAnim
trigger1 = Anim != 21 && Anim != 5
trigger2 = Anim = 5 && AnimTime = 0
value = 21

;--------------------------------------------------
; Walk F 向前走
[Statedef 21]
type = S
physics = S
sprpriority = 0

[State 20, 1]
type = VelSet
trigger1 = 1
x = const(velocity.walk.fwd.x)

[State 20, 3]
type = ChangeAnim
trigger1 = Anim != 20 && Anim != 5
trigger2 = Anim = 5 && AnimTime = 0
value = 20

之后写上让人物行走的Changestate就可以了：

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -1, 向前走]
type = ChangeState
value = 21
Triggerall = Var(59) > 0;AI开启时
Triggerall = Roundstate = 2;在格斗阶段
Triggerall = Statetype != A;不在空中
Triggerall = Frontedgebodydist >= 10;不在画面边缘
Triggerall = Stateno != 20 && Stateno != 100;不是步行状态和跑步状态
Triggerall = ctrl;可控时
Trigger1 = P2bodydist X > 135 && Random < P2bodydist X * 2 - 250;Trigger1~4根据距离不同分段改变概率
Trigger2 = P2bodydist X > 100 && Random < P2bodydist X
Trigger3 = P2bodydist X > 50 && Random < 100
Trigger4 = P2bodydist X > 0 && Random < 25

;--------------------------------------------------
[State -1, 向后走]
type = ChangeState
value = 19
Triggerall = Var(59) > 0
Triggerall = Roundstate = 2
Triggerall = Statetype != A
Triggerall = Backedgebodydist >= 10
Triggerall = !inguarddist;非防御距离，因为防御距离内按后会变成防御而不是向后走
Triggerall = ctrl
Trigger1 = P2bodydist X < 75 && Random > 950 + P2bodydist X / 2;近距离低几率触发

之后人物就会根据不同的距离以不同的概率随机前后行走了。

==================================================
8.3跑/前冲/后撤
==================================================

--------------------------------------------------
跑/前冲也是格斗游戏非常常见的移动方式。
虽然移动速度比较快，但是跟行走对比起来相对不灵活，有一定的风险。
然而较快的速度令它在抢硬直、连段目押等需要快速移动的情况大展身手。

默认的common1.cns中代码如下：

;--------------------------------------------------
; Run forward
[Statedef 100]
type = S
physics = S
anim = 100
sprpriority = 1

[State 100, 1]
type = VelSet
trigger1 = 1
x = const(velocity.run.fwd.x)

[State 100, 2] ;Prevent run from canceling into walk
type = AssertSpecial
trigger1 = 1
flag = NoWalk

[State 100, 3] ;Prevent from turning
type = AssertSpecial
trigger1 = 1
flag = NoAutoTurn

[State 100, 4]
type = ChangeState
trigger1 = command != "holdfwd"
value = 0

如代码所示，默认的是跑，是可控的匀速前进，并且可以随时停下。
然而，很多格斗游戏里面的跑并不是这么简单的，通常是由起步、匀速运动、停止之类的部分组成。
因为起步和停止都是有一定硬直的动作，如果在较短的距离开始跑，对方一旦使用攻击，你将没法停下来进行防御。
和行走对比起来，这类型的跑使用起来需要考虑更多问题。

虽然跑并没有行走那样有两个方向的烦恼，但是跑的启动和停止是分开控制的，并不是像行走那样不需要变为State 0的Sctrl。
所以除了启动我们还要改写Statedef 100下的停止条件：

;--------------------------------------------------
; Run forward
[Statedef 100]

...

[State 100, 4]
type = ChangeState
trigger1 = Var(59) = 0;AI未开启时
trigger1 = command != "holdfwd";和原来一样接受手操指令
trigger2 = Var(59) > 0
trigger2 = EnemyNear,movetype != H || (EnemyNear,movetype = H && p2dist x < 0);对方不在受击状态或者对方在受击状态但跑过头了
trigger2 = p2bodydist x <= (30+random/40) || Frontedgebodydist <= 10;比较近的距离或者画面边缘
trigger3 = Var(59) > 0
trigger3 = Roundstate != 2;防止非战斗阶段时一直跑根本停不下来
value = 0

之后写上让人物跑的Changestate就可以了：

;下面一段放到[Statedef -1]或[Statedef -3]下面

;--------------------------------------------------
[State -1, 前跑]
type = ChangeState
value = 100
Triggerall = Var(59) > 0
Triggerall = Roundstate = 2
Triggerall = Statetype != A
Triggerall = Frontedgebodydist >= 20;避免在画面边缘开始跑
Triggerall = ctrl
Trigger1 = P2bodydist X > 200 && Random < P2bodydist X*5 - 720;Trigger1~4根据距离不同分段改变概率
Trigger2 = P2bodydist X > 135 && Random < P2bodydist X*2 - 120
Trigger3 = P2bodydist X > 90 && Random < P2bodydist X*1.75 - 90
Trigger4 = (P2bodydist X = [45,90]) && Random < P2bodydist X *1.2 - 45

--------------------------------------------------
虽然Mugen内默认的状态100是跑，但一些游戏当中双击前方向键（66）并不一定是跑，还有可能是前冲（冲刺/Dash）。
前冲很有可能是长时间硬直的向前移动，若乱使用可以说破绽百出，使用时比起跑要更小心，否则就是给对方送硬直。

后撤默认使用的是状态105，是双击后方向键（44）所发出来的。
在Mugen中，后撤默认为空中状态，也就是启动的瞬间就在空中，所以可以利用这个特性躲避投技。
而在不少格斗游戏作品当中，后撤会有短暂无敌的性能，我们也可以利用这性能对对方攻击进行闪避。

因为默认并没有前冲，所以在此只给出后撤的例子：

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -1, 后撤]
type = ChangeState
value = 105
Triggerall = Var(59) > 0
Triggerall = Roundstate = 2
Triggerall = Statetype != A
Triggerall = (Random < Var(59)*200) || (Var(59) > 3)
Triggerall = ctrl
Trigger1 = EnemyNear,Movetype = A && EnemyNear,Stateno >= 200;对方攻击状态
Trigger1 = facing != EnemyNear,facing;双方面对面
Trigger1 = EnemyNear,hitdefattr = SC,AT;对手攻击带投技判定
Trigger1 = P2bodydist X = [-20,100];一定距离内

==================================================
8.4跳跃
==================================================

--------------------------------------------------
跳跃同样是格斗游戏常见的移动方式。
因为跳跃能令攻击方式多样化（上下择和落地投等）而且有着相当高的回报，在手操里有着很重要的地位。
同时还可以躲避投技和远处飞行道具，并获得先机。
但是先不说mugen当中空防并不能防御下段攻击和一大堆无敌升龙，通常来说人物在空中只能按照一定的轨迹移动，
而且多数格斗游戏中人物在地面的性能比空中要好，跳跃也需要好好考虑位置和时机才能在AI战里面使用。

默认的common1.cns中代码如下：

;--------------------------------------------------
; Jump Start
[Statedef 40]
type = S
physics = S
anim = 40
ctrl = 0
sprpriority = 1
facep2 = 1

[State 40, 1]
type = VarSet
trigger1 = Time = 0
sysvar(1) = 0

[State 40, 2]
type = VarSet
trigger1 = command = "holdfwd"
sysvar(1) = 1

[State 40, 3]
type = VarSet
trigger1 = command = "holdback"
sysvar(1) = -1

[State 40, 4]
type = VelSet
trigger1 = AnimTime = 0
x = ifelse(sysvar(1)=0, const(velocity.jump.neu.x), ifelse(sysvar(1)=1, const(velocity.jump.fwd.x), const(velocity.jump.back.x)))
y = const(velocity.jump.y)

[State 40, 5]
type = VelSet
trigger1 = AnimTime = 0
trigger1 = prevstateno = 100 ;RUN_FWD
trigger1 = sysvar(1) = 1
x = const(velocity.runjump.fwd.x)

[State 40, 6]
type = ChangeState
trigger1 = AnimTime = 0
value = 50
ctrl = 1

如代码所示，和行走类似，默认的跳跃分为前跳、后跳、原地跳和跑跳，用的是同一个状态号40。
也是通过按键不同区分开不同的方向和速度。
而在某些有大小跳的作品里面，跳跃的分类会更多。
所以我们会采用和行走一样的办法来处理。

实例如下：
;--------------------------------------------------
;Statedef 39后跳 41前跳 42原地跳

[Statedef 39]
type = S
physics = S
anim = 40
ctrl = 0
sprpriority = 1

[State 40, 1]
type = VarSet
trigger1 = 1
sysvar(1) = -1

[State 40, 4]
type = VelSet
trigger1 = AnimTime = 0
x = const(velocity.jump.back.x)
y = const(velocity.jump.y)

[State 40, 6]
type = ChangeState
trigger1 = AnimTime = 0
value = 50
ctrl = 1

;--------------------------------------------------
[Statedef 41]
type = S
physics = S
anim = 40
ctrl = 0
sprpriority = 1

[State 40, 1]
type = VarSet
trigger1 = 1
sysvar(1) = 1

[State 40, 4]
type = VelSet
trigger1 = AnimTime = 0
x = const(velocity.jump.fwd.x)
y = const(velocity.jump.y)

[State 40, 5]
type = VelSet
trigger1 = AnimTime = 0
trigger1 = prevstateno = 100 ;RUN_FWD
trigger1 = sysvar(1) = 1
x = const(velocity.runjump.fwd.x)

[State 40, 6]
type = ChangeState
trigger1 = AnimTime = 0
value = 50
ctrl = 1

;--------------------------------------------------
[Statedef 42]
type = S
physics = S
anim = 40
ctrl = 0
sprpriority = 1

[State 40, 1]
type = VarSet
trigger1 = 1
sysvar(1) = 0

[State 40, 4]
type = VelSet
trigger1 = AnimTime = 0
x = const(velocity.jump.neu.x)
y = const(velocity.jump.y)

[State 40, 6]
type = ChangeState
trigger1 = AnimTime = 0
value = 50
ctrl = 1

====================================================
8.5受身
====================================================

--------------------------------------------------
受身是指受击身体恢复，通常是空中或者低空受击硬直后，或者倒地时可以更快的恢复成为可控状态。
更快的恢复可控状态可以用于躲避对方的伪连（指中途可被受身回避的连段），或者更容易作出反击。

默认的common1.cns中代码如下（此处因为WinMugen版本写的比较简单容易理解，我用WinMugen版本的代码进行讲解）：

;--------------------------------------------------
; HITA_FALL (knocked up, falling)
[Statedef 5050]
type = A
movetype= H
physics = N

...

[State 5050, 4] ;Recover near ground
type = ChangeState
triggerall = Vel Y > 0
triggerall = Pos Y >= -20
triggerall = alive
triggerall = CanRecover
trigger1 = Command = "recovery"
value = 5200 ;HITFALL_RECOVER

[State 5050, 5]; Recover in mid air
type = ChangeState
triggerall = Vel Y > -1
triggerall = alive
triggerall = CanRecover
trigger1 = Command = "recovery"
value = 5210 ;HITFALL_AIRRECOVER

...

--------------------------------------------------
; HIT_FALLRECOVER (still falling)
[Statedef 5200]
type = A
movetype= H
physics = N

[State 5200, 1] ;Change anim if done with transition
type = ChangeAnim
trigger1 = Anim = 5035
trigger1 = AnimTime = 0
value = 5050

[State 5200, 2]
type = VelAdd
trigger1 = 1
y = GetHitVar(yaccel)

[State 5200, 3]
type = SelfState
trigger1 = Vel Y > 0
trigger1 = Pos Y >= 10
value = 5201

;--------------------------------------------------
; HIT_FALLRECOVER (on the ground)
[Statedef 5201]
type = A
movetype= H
physics = A
anim = 5200

[State 5201, 1] ;Turn if not facing opponent
type = Turn
trigger1 = Time = 0
trigger1 = p2dist X < -5

[State 5201, 2]
type = VelSet
trigger1 = Time = 0
x = -.15
y = -3.5

[State 5201, 3]
type = PosSet
trigger1 = Time = 0
y = 0

[State 5201, 4]
type = NotHitBy
trigger1 = 1
value = SCA
time = 1

[State 5201, 5] ;Blink white
type = PalFX
trigger1 = Time = 0
time = 3
add = 128,128,128 ;256,256,256

[State 5201, 6]
type = GameMakeAnim
trigger1 = Time = 1
value = 60
pos = 0, 0
under = 1

;--------------------------------------------------
; HIT_AIRFALLRECOVER
[Statedef 5210]
type = A
movetype= I
physics = N
anim = 5210
ctrl = 0

[State 5210, 1] ;Blink white
type = PalFX
trigger1 = Time = 0
time = 3
add = 128,128,128 ;256,256,256

[State 5210, 1]
type = PosFreeze
trigger1 = Time = 0
value = 4

[State 5210, 2] ;Turn if not facing opponent
type = Turn
trigger1 = Time = 0
trigger1 = p2dist X < -20

[State 5210, 1]
type = VelMul
trigger1 = Time = 4
x = .8
y = .8

[State 5210, 1]
type = VelAdd
trigger1 = Time = 4
y = -4.5

[State 5210, 1]
type = VelMul
trigger1 = Time = 4
trigger1 = Vel Y > 0
y = .5

[State 5210, 1]
type = VelAdd
trigger1 = Time = 4
trigger1 = Vel Y > -3
y = -2

[State 5210, 1]
type = VelAdd
trigger1 = Time = 4
trigger1 = Vel Y > -2
y = -1

[State 5210, 2] ;Go up
type = VelAdd
trigger1 = Time = 4
trigger1 = Command = "holdup"
y = -2

[State 5210, 2] ;Go down
type = VelAdd
trigger1 = Time = 4
trigger1 = Command = "holddown"
y = 1.5

[State 5210, 2] ;Go fwd
type = VelMul
trigger1 = Time = 4
trigger1 = Command = "holdfwd"
x = 1

[State 5210, 2] ;Go back
type = VelAdd
trigger1 = Time = 4
trigger1 = Command = "holdback"
x = -1

[State 5210, 3]
type = NotHitBy
trigger1 = Time = 0
value = SCA
time = 15

[State 5210, 4]
type = CtrlSet
trigger1 = Time = 20
value = 1

[State 5210, 5]
type = VelAdd;Gravity
trigger1 = Time >= 4
y = .35

[State 5210, 5] ;Land on ground
type = ChangeState
trigger1 = Vel Y > 0
trigger1 = Pos Y >= 0
value = 52 ;JUMP_LAND
ctrl = 1

如代码所示，Mugen当中默认有两种受身，分别是高空受身和低空受身，分别是状态5210和5200。
其发动条件是在掉落状态5050当中处于可恢复状态时，速度和高度符合条件即可。
高空受身5210是受身后20f恢复可控，而低空受身5200是进入预备状态到达低空高度转变为状态5201。
值得一提的是，高空受身有15f的无敌，而低空受身在到达低空高度直到落地前的状态5201有全程无敌。
如果可以在对方伪连时合理利用高空受身这15f的无敌和低空受身状态5201的全程无敌躲开对方的攻击判定，
甚至之后在对方攻击硬直中反击命中对方的话，可以说是相当大的收益。
然而受身其实也是有一定的风险的。高空受身在15f无敌以后有5f的硬直，而低空受身不可控，不可切换成防御状态，
落地也有硬直，乱受身的话很容易被写了受身狩（也就是抓受身）抓住机会。
另外有些AI也会用低硬直的招式骗对方手受身，一旦对方上当形成受身狩就是一套额外的连段。
因为我们暂时还没有学出招记录等技术，没法特别精确地用受身躲避对方伪连，
所以要注意受身的几率不要太高，以免被受身狩循环致死。

实例如下：

;--------------------------------------------------
; HITA_FALL (knocked up, falling)
[Statedef 5050]
type = A
movetype= H
physics = N

...

[State 5050, 4] ;Recover near ground
type = ChangeState
triggerall = Vel Y > 0
triggerall = Pos Y >= -20
triggerall = alive
triggerall = CanRecover
trigger1 = Var(59) = 0;当手操时由手操命令控制
trigger1 = Command = "recovery"
trigger2 = Var(59) > 0
trigger2 = EnemyNear,Movetype = H || EnemyNear,Statetype = L;对方倒地或者受击
value = 5200 ;HITFALL_RECOVER

[State 5050, 5]; Recover in mid air
type = ChangeState
triggerall = Vel Y > -1
triggerall = alive
triggerall = CanRecover
trigger1 = Var(59) = 0;当手操时由手操命令控制
trigger1 = Command = "recovery"
trigger2 = Var(59) > 0
trigger2 = EnemyNear,Movetype = H || EnemyNear,Statetype = L
Trigger3 = Var(59) > 0
Trigger3 = EnemyNear,Movetype = A && EnemyNear,Stateno >= 200;对方攻击状态
Trigger3 = EnemyNear,AnimTime <= -Random/40+5;对方有一定硬直时间
Trigger3 = Random < 100;低几率触发
value = 5210 ;HITFALL_AIRRECOVER

...

;--------------------------------------------------
; HIT_AIRFALLRECOVER
[Statedef 5210]
type = A
movetype= I
physics = N
anim = 5210
ctrl = 0

...
;具体方向控制看喜好

[State 5210, 2] ;Go up
type = VelAdd
triggerall = Time = 4
trigger1 = Var(59) = 0
trigger1 = Command = "holdup"
y = -2

[State 5210, 2] ;Go down
type = VelAdd
triggerall = Time = 4
trigger1 = Var(59) = 0
trigger1 = Command = "holddown"
trigger2 = Var(59) > 0
y = 1.5

[State 5210, 2] ;Go fwd
type = VelMul
triggerall = Time = 4
trigger1 = Var(59) = 0
trigger1 = Command = "holdfwd"
trigger2 = Var(59) > 0
x = 1

[State 5210, 2] ;Go back
type = VelAdd
triggerall = Time = 4
trigger1 = Var(59) = 0
trigger1 = Command = "holdback"
x = -1

==================================================
8.6防御
==================================================

--------------------------------------------------
格斗有攻就有守，防御不必多说是格斗游戏里面很重要的一环。
防御对于攻击来说算相对简单，因为无论你怎么攻击，防御就三种：站防、蹲防、空防（有些游戏甚至没有空防）。
除了投技不可防御、破防技等特殊情况，攻击判定（打击技和飞行道具）有分为上中下三段，可以被对应的防御防住。
（PS：格斗游戏中，上段站、蹲防均可，中段不可蹲防，下段不可站防。但是Mugen当中，上段（guardflag = H）不可蹲防，
中段（guardflag = M = HL）站、蹲防均可，下段（guardflag = L）不可站防，另外guardflag = A决定是否能空防。
在本教程里统一用格斗游戏的说法，即中段不可蹲防，下段不可站防）

默认的common1.cns中代码如下：

;--------------------------------------------------
; GUARD (start)
[Statedef 120]
type = U ;Leave state type unchanged
physics = U ;Leave physics unchanged

[State 120, 1]
type = ChangeAnim
trigger1 = Time = 0
value = 120 + (statetype = C) + (statetype = A)*2;这种写法用一段代码完成了三段代码的工作，值得学习

[State 120, 2]
type = StateTypeSet
trigger1 = Time = 0 && statetype = S
physics = S

[State 120, 3]
type = StateTypeSet
trigger1 = Time = 0 && statetype = C
physics = C

[State 120, 4]
type = StateTypeSet
trigger1 = Time = 0 && statetype = A
physics = A

[State 120, Hi to Lo]
type = StateTypeSet
trigger1 = statetype = S && command = "holddown"
statetype = C
physics = C

[State 120, Lo to Hi]
type = StateTypeSet
trigger1 = statetype = C && command != "holddown"
statetype = S
physics = S

[State 120, 5]
type = ChangeState
trigger1 = AnimTime = 0
value = 130 + (statetype = C) + (statetype = A)*2

[State 120, Stop Guarding]
type = ChangeState
trigger1 = command != "holdback"
trigger2 = !inguarddist
value = 140

;--------------------------------------------------
; STAND GUARD (guarding)
[Statedef 130]
type = S
physics = S

[State 130, 1]
type = ChangeAnim
trigger1 = Anim != 130
value = 130

[State 130, Hi to Lo]
type = ChangeState
trigger1 = command = "holddown"
value = 131

[State 130, Stop Guarding]
type = ChangeState
trigger1 = command != "holdback"
trigger2 = !inguarddist
value = 140

;--------------------------------------------------
; CROUCH GUARD (guarding)
[Statedef 131]
type = C
physics = C

[State 131, 1]
type = ChangeAnim
trigger1 = Anim != 131
value = 131

[State 131, Lo to Hi]
type = ChangeState
trigger1 = command != "holddown"
value = 130

[State 131, Stop Guarding]
type = ChangeState
trigger1 = command != "holdback"
trigger2 = !inguarddist
value = 140

;--------------------------------------------------
; AIR GUARD (guarding)
[Statedef 132]
type = A
physics = N

[State 132, 1]
type = ChangeAnim
trigger1 = Anim != 132
value = 132

[State 132, 2]
type = VelAdd
trigger1 = 1
y = Const(movement.yaccel)

[State 132, 3]
type = VarSet
trigger1 = 1
sysvar(0) = (pos y >= 0) && (vel y > 0)

[State 132, 4]
type = VelSet
trigger1 = sysvar(0)
y = 0

[State 132, 5]
type = PosSet
trigger1 = sysvar(0)
y = 0

[State 132, 6]
type = ChangeState
trigger1 = sysvar(0)
trigger1 = command = "holdback"
trigger1 = inguarddist
value = 130

[State 132, 7]
type = ChangeState
trigger1 = sysvar(0)
value = 52

[State 132, Stop Guarding]
type = ChangeState
trigger1 = command != "holdback"
trigger2 = !inguarddist
value = 140

;--------------------------------------------------
; GUARD (end)
[Statedef 140]
type = U ;Leave state type unchanged
physics = U ;Leave physics unchanged
ctrl = 1

[State 140, 1]
type = ChangeAnim
trigger1 = Time = 0
value = 140 + (statetype = C) + (statetype = A)*2

[State 140, 2]
type = StateTypeSet
trigger1 = Time = 0 && statetype = S
physics = S

[State 140, 3]
type = StateTypeSet
trigger1 = Time = 0 && statetype = C
physics = C

[State 140, 4]
type = StateTypeSet
trigger1 = Time = 0 && statetype = A
physics = A

[State 140, Hi to Lo]
type = StateTypeSet
trigger1 = statetype = S && command = "holddown"
statetype = C
physics = C

[State 140, Lo to Hi]
type = StateTypeSet
trigger1 = statetype = C && command != "holddown"
statetype = S
physics = S

;[State 140, 5] ;Implemented within engine
;type = ChangeState
;trigger1 = AnimTime = 0
;value = (statetype = C)*11 + (statetype = A)*51

;--------------------------------------------------
; SGUARDHIT (shaking)
[Statedef 150]
type = S
movetype= H
physics = N
velset = 0,0

[State 150, 1]
type = ChangeAnim
trigger1 = 1
value = 150

[State 150, 2]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*(command = "holddown")

[State 150, Hi to Lo]
type = StateTypeSet
trigger1 = statetype = S && command = "holddown"
statetype = C
physics = C

[State 150, Lo to Hi]
type = StateTypeSet
trigger1 = statetype = C && command != "holddown"
statetype = S
physics = S

[State 150, 3]
type = ForceFeedback
trigger1 = time = 0
waveform = square
time = 3

;--------------------------------------------------
; SGUARDHIT2 (knocked back)
[Statedef 151]
type = S
movetype= H
physics = S
anim = 150

[State 151, 1]
type = HitVelSet
trigger1 = Time = 0
x = 1

[State 151, 2]
type = VelSet
trigger1 = Time = GetHitVar(slidetime)
trigger2 = HitOver
x = 0

[State 151, 3]
type = CtrlSet
trigger1 = Time = GetHitVar(ctrltime)
value = 1

[State 151, Hi to Lo]
type = StateTypeSet
trigger1 = statetype = S && command = "holddown"
statetype = C
physics = C

[State 151, Lo to Hi]
type = StateTypeSet
trigger1 = statetype = C && command != "holddown"
statetype = S
physics = S

[State 151, 4]
type = ChangeState
trigger1 = HitOver
value = 130
ctrl = 1

;--------------------------------------------------
; CGUARDHIT (shaking)
[Statedef 152]
type = C
movetype= H
physics = N
velset = 0,0

[State 152, 1]
type = ChangeAnim
trigger1 = 1
value = 151

[State 152, 3]
type = ChangeState
trigger1 = HitShakeOver
value = 151 + 2*(command = "holddown")

[State 152, Hi to Lo]
type = StateTypeSet
trigger1 = statetype = S && command = "holddown"
statetype = C
physics = C

[State 152, Lo to Hi]
type = StateTypeSet
trigger1 = statetype = C && command != "holddown"
statetype = S
physics = S

[State 152, 4]
type = ForceFeedback
trigger1 = time = 0
waveform = square
time = 4

;--------------------------------------------------
; CGUARDHIT2 (knocked back)
[Statedef 153]
type = C
movetype= H
physics = C
anim = 151

[State 153, 1]
type = HitVelSet
trigger1 = Time = 0
x = 1

[State 153, 2]
type = VelSet
trigger1 = Time = GetHitVar(slidetime)
trigger2 = HitOver
x = 0

[State 153, 3]
type = CtrlSet
trigger1 = Time = GetHitVar(ctrltime)
value = 1

[State 153, Hi to Lo]
type = StateTypeSet
trigger1 = statetype = S && command = "holddown"
statetype = C
physics = C

[State 153, Lo to Hi]
type = StateTypeSet
trigger1 = statetype = C && command != "holddown"
statetype = S
physics = S

[State 153, 4]
type = ChangeState
trigger1 = HitOver
value = 131
ctrl = 1

;--------------------------------------------------
; AGUARDHIT (shaking)
[Statedef 154]
type = A
movetype= H
physics = N
velset = 0,0

[State 154, 1]
type = ChangeAnim
trigger1 = 1
value = 152

[State 154, 2]
type = ChangeState
trigger1 = HitShakeOver
value = 155 ;AGUARDHIT2

[State 154, 3]
type = ForceFeedback
trigger1 = time = 0
waveform = square
time = 4

;--------------------------------------------------
; AGUARDHIT2 (knocked away)
[Statedef 155]
type = A
movetype= H
physics = N
anim = 152

[State 155, 1]
type = HitVelSet
trigger1 = Time = 0
x = 1
y = 1

[State 155, 2]
type = VelAdd
trigger1 = 1
y = Const(movement.yaccel)

[State 155, 3]
type = CtrlSet
trigger1 = Time = GetHitVar(ctrltime)
value = 1

[State 155, 4]
type = VarSet
trigger1 = 1
sysvar(0) = (pos y >= 0) && (vel y > 0)

[State 155, 5]
type = VelSet
trigger1 = sysvar(0)
y = 0

[State 155, 6]
type = PosSet
trigger1 = sysvar(0)
y = 0

[State 155, 6]
type = ChangeState
trigger1 = sysvar(0)
trigger1 = command = "holdback"
trigger1 = inguarddist
value = 130

[State 155, 7]
type = ChangeState
trigger1 = sysvar(0)
value = 52

防御状态默认占据了状态号[120,155]，中间根据防御不同阶段又细分了好几个状态。
120是防御准备状态，也就是按下后方向键人物进入的动作，只用于转变为防御未受击状态；
[130,132]是防御未受击状态，也就是做好了防御动作但是尚未被攻击的阶段，[130,132]分别对应站、蹲、空；
140是防御结束状态，也就是防御准备状态、未受击状态或者受击状态结束时松开后方向键进入的状态，只用于离开防御状态；
[150,155]是防御受击状态，防御准备状态或防御未受击状态受到攻击时进入的状态，[150,151]、[152,153]、[154,155]分别对应: 站、蹲、空，偶数为受击震动，奇数为受击滑动。在受击硬直后若还按着后方向键进入防御未受击状态，否则进入防御结束状态。

防御状态的切换是已经写好了的，我们需要管的地方只有手操指令的切换。
而这些切换无非控制的其实是站/蹲防的切换（空防你只有防与不放不用想太多）和停止防御状态两种。
通常来说，站姿攻击多为上段和中段，蹲姿攻击多为上段和下段，空中攻击多为上段和中段。
所以在地面上对站姿攻击和空中攻击我们用站防应对，对蹲姿攻击我们用蹲防应对，对方停止攻击的时候我们停止防御就行了。

实例如下：

;--------------------------------------------------
; GUARD (start)
[Statedef 120]
type = U ;Leave state type unchanged
physics = U ;Leave physics unchanged

...

[State 120, Hi to Lo]
type = StateTypeSet
triggerall = statetype = S;当我方是站姿
trigger1 = !Var(59) && command = "holddown"
trigger2 = Var(59) && EnemyNear,Statetype = C;而对方是蹲姿的时候
statetype = C;变为蹲姿
physics = C

[State 120, Lo to Hi]
type = StateTypeSet
triggerall = statetype = C;当我方是蹲姿
trigger1 = !Var(59) && command != "holddown"
trigger2 = Var(59) && EnemyNear,Statetype = S;而对方是站姿的时候
statetype = S;变为站姿
physics = S

[State 120, 5]
type = ChangeState
trigger1 = AnimTime = 0
value = 130 + (statetype = C) + (statetype = A)*2

[State 120, Stop Guarding]
type = ChangeState
trigger1 = !Var(59) && command != "holdback"
trigger2 = !inguarddist
value = 140

;--------------------------------------------------
; STAND GUARD (guarding)
[Statedef 130]
type = S
physics = S

[State 130, 1]
type = ChangeAnim
trigger1 = Anim != 130
value = 130

[State 130, Hi to Lo]
type = ChangeState
trigger1 = !Var(59) && command = "holddown"
trigger2 = Var(59) && EnemyNear,Statetype = C
value = 131

[State 130, Stop Guarding]
type = ChangeState
trigger1 = !Var(59) && command != "holdback"
trigger2 = !inguarddist
value = 140

;因为下面的站/蹲姿切换都是类似的代码，以上面的当做参考足矣，下略
......

之后还有启动防御的Changestate：

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -1, 防御]
type = ChangeState
value = 120
Triggerall = Var(59) > 0
Triggerall = Roundstate = 2
Triggerall = Statetype != A
Triggerall = ctrl
Triggerall = !(EnemyNear(Var(54)),hitdefattr = sca,at);对方不是投技判定
Trigger1 = Inguarddist ;在防御范围内

完成这段的修改，你也限制了人物攻击的话，你的人物已经算是铁壁了。
什么？你说铁壁这么简单？没错，只要不主动攻击卖硬直，铁壁就是这么简单。

====================================================
8.7限制隐性手操指令切换状态
====================================================

--------------------------------------------------
到这里我们已经把带有command的Sctrl修改完了，但是这章内容尚未完结。
还记得笔者在第5章提及的内容吗：除了带有command的Sctrl以外，Mugen里面还存在内置的隐性的手操指令切换状态，
例如下蹲（Stateno 10）、行走（Stateno 20）和跳跃（Stateno 40）等。
我们虽然修改了这几个动作里面的带command的内容，但是我们还没有对它们的触发进行限制。
只要人物处于可控状态，只要内置的隐性的用手操指令刚好被触发，这几个动作依然会不受控制的动起来。
所以除了上面的内容，我们还要限制隐性手操指令切换状态。

--------------------------------------------------
因为人物要处于可控状态才会切换状态为下蹲、行走和跳跃等状态，所以首先我们可以把一些可控的状态改成不可控。
在Statedef开始的地方，如果没有标注说是否可控，将会继承上一个状态的可控与否。
例如从可控的站姿切换到行走，行走并没有标注是否可控，行走也将变成可控。
分析之前的代码可知，Mugen默认的行走和跑都可以从可控状态进入，所以这两个状态都可能会被隐性的手操指令切换状态。
于是我们可以进行修改，实例如下：

;因为我们已经采用了新的行走状态State 19/21，所以我们可以不用修改State 20
;--------------------------------------------------
; Walk B 向后走
[Statedef 19]
type = S
physics = S
sprpriority = 0
ctrl = 0;不可控

...

;--------------------------------------------------
; Walk F 向前走
[Statedef 21]
type = S
physics = S
sprpriority = 0
ctrl = 0;不可控

;而State 100，我们可以像行走那样添加新的状态，设置为不可控，或者是像下面这么修改
;--------------------------------------------------
; Run forward
[Statedef 100]

...

[State 100, AI Ctrlset];添加不可控设置
type = Ctrlset
trigger1 = Var(59) > 0;当AI开关打开的时候
value = 0;不可控

通过这样的修改，在行走和跑步的时候就不会被手操指令影响了，但缺点就是不可控状态可能会混淆对方AI，我们在写AI的时候也要注意这种写法可能对我们带来的不良影响。
另外，由于原来可控的状态现在变成了不可控，所以其他Sctrl里原来triggerX = ctrl的条件不作相应调整的话人物就变得不会动了，因此我们还需要调整这些trigger，令他们可以在这些原来是可控的状态里跟原来一样切换状态。例如：

;Stand Light Punch
[State -1, Stand Light Punch]
type = ChangeState
value = 200
trigger1 = Var(59) > 0
trigger1 = statetype = S
trigger1 = ctrl

改为

;Stand Light Punch
[State -1, Stand Light Punch]
type = ChangeState
value = 200
trigger1 = Var(59) > 0
trigger1 = statetype = S
trigger1 = ctrl || (Stateno = [19,21]) || Stateno = 100;这样就算不可控，行走和跑时都可以切换状态了

--------------------------------------------------
然而修改了行走和跑步依然还是不够的，站姿等可控的情况下依然会乱动。
所以为了对应大多数的可控情况，我们还需要一段泛用的限制代码：

;下面一段放到[Statedef -1]或[Statedef -3]下面
;--------------------------------------------------
[State -1, 地面动作限制]
type = ChangeState
value = 0;强行拉回站姿
Triggerall = Var(59) > 0
Triggerall = Statetype != A
Triggerall = Roundstate = 2
Trigger1 = Stateno = 10;下蹲
Trigger2 = Stateno = 20;行走
Trigger3 = Stateno = 40;跳
ctrl = 1

虽然有部分魔改的成分（笑），但是这种是比较常用而且实在的限制乱动的写法了。

--------------------------------------------------
至此，公用状态算是基本完成了。
随着以后不同目的的章节的探讨，我们还会继续给这些公用状态添加一些trigger，令它们在适当的时候触发。
不过那是之后的事了，本章只讲这么多。

====================================================
课后作业：

1.
格斗游戏中，什么段攻击可以击破蹲防？什么段攻击可以击破站防？

2.
为什么说章节8.7的这段代码有部分魔改的成分？

[State -1, 地面动作限制]
type = ChangeState
value = 0
Triggerall = Var(59) > 0
Triggerall = Statetype != A
Triggerall = Roundstate = 2
Trigger1 = Stateno = 10
Trigger2 = Stateno = 20
Trigger3 = Stateno = 40
ctrl = 1


1 引言

玩家的CNS文件有两个目的:

他定义了玩家的变量,像是行走速度,绘制缩放系数等等.
他包含了玩家的状态(状态描述了玩家能出的所有招式).
状态就像是积木,你能用他创建从简单到复杂的招式.
就像许多其他人物的文件,CNS是一个文本文档,你能用任何文本编辑工具来编辑.

在CNS文件中,分号";"被认为是"注释"字符.
分号同一行之后的文字会被程序忽略.
CNS文件几乎不区分大小写,即,"MyName"会和"myname"或"mYnAMe"作为一样处理.
除了command等一些触发器.


1.1 一些术语

当我们提到"group(组)",意味着任何块,行,文字由看上去像是由"[groupname]"开始,结束于下一个组之前.
例如,下面的Foo组包含了开始的三行:

[Foo]
line1
line2

[Group 2]
more lines

一个组中,参数能以任何顺序表现出来.所以,

[SomeGroup]
value1 = 1234
value2 = "A string"

与下面的相同:

[SomeGroup]
value2 = "A string"
value1 = 1234


2 玩家变量

目前还没有完全的参考资料.查看chars/kfm/kfm.cns中每个参数的注释.

一些要点需要注意:

在[Size]组中,你能使用xscale和yscale改变人物的高度和宽度.
省去了缩放单张图像的麻烦.
[Velocity]组可以设置玩家的速度.
[Movement]组中yaccel参数设置了玩家下落加速度.


3 状态 StateDef

动画和声音在一个mugen人物中几乎是实时表现的,但是人物的真正"心脏"是他的CNS文件.
CNS文件,同时被称为人物的"state(状态)"文件,包含了给予人物功能的代码.
例如,输入指令时能出招,打击对手,或者遵守重力规律.

CNS文件的结构是简单的.代码被组织成一个组(称为[StateDef]).
[Statedef]块被编号,一个典型的人物可能含有成百上千个[Statedef]块.
每个[Statedef]块中有一些[State]块,也被称为状态控制器.
每个状态控制器是一对触发动作,他指定了人物采取的一些行动,且控制器下面指定了将要执行的条件.

在游戏的每个时刻(游戏的时间单位是游戏帧),人物执行一些[StateDef]块下的代码.
例如,人物正空闲的站立着,则通常会执行[StateDef 0]程序块.简而言之,我们就说人物在"state 0"中.
人物在"state 0"的每一帧时间内,将从头到尾的计算[StateDef 0]程序块状态控制器,检测条件,采取指定的行动.
如果人物要转换进入其他的[StateDef]程序块(假定要进入state 417),我们就告诉"state 417"因为要执行一次行动,他能执行ChangeState控制器试成功转换状态.
人物随后将以完全相同的方式执行[StateDef 417]程序块下的代码.

每个mugen人物额外有3个特殊的状态,编号为-1,-2,-3.这些编号是仅允许使用的负数编号.
"[StateDef -1]"通常包含决定状态中基于用户输入指令转换规则的状态控制器.
"[StateDef -2]"包含需要每帧都检测的其他状态控制器.
"[StateDef -3]"包含每帧都要检测的状态控制器除非玩家正临时使用其他玩家的数据.(例如被投掷技击中)
(也就是说处于p2stateno或者targetstate中,"[statedef -3]"将不会执行)

总而言之:对每个游戏帧,mugen对每个指定状态创建一次从头到尾的单向(检测),按照-3,-2,-1这样的顺序.
每个状态控制器都是这种情况,他的条件型触发器被计算,如果满足条件,控制器将被执行.
然后进程将继续,执行状态中的下一个控制器.任何指定状态中的状态转换(ChangeState)将更新玩家当前状态号,且将放弃执行(原状态)剩下的控制器.
指定状态中所有控制器都被检测后,玩家如果还处于当前状态,将再一次对此状态的控制器从头到尾(或者理解为从上到下)的检测.
如果执行了状态转换离开了当前状态,此状态剩下的控制器(如果有任何)将被跳过,检测控制器的进程将从新的状态开始.
若当前状态结束且没有执行状态转换,进程将等待.

上述情况有个例外.如果人物是一个"helper"型人物,即,被helper控制器创建,此人物将不含有指定的-3,-2.
同时也不含有指定的-1,除非能接受键盘输入.(这由helper状态控制器在创建时控制)


3.1 状态介绍

创建人物最难的部分就是编写状态.需要大量的工作,测试,有事还需要不断摸索.
我们称状态正被编辑的人为p1,他的对手是p2.

如果你第一次读此篇文章有很多不明白的地方请不要灰心.
理解关于状态最好的方法就是,首先摆弄一下1个完整人物的CNS变量,然后看看这些数值对他(她)起什么作用.
调整CNS代码没什么可怕的;mugen被设计成会检测语法错误然后报出来.

mugen程序压缩包中包含了名叫Kung Fu Man的人物(简称KFM).
你能在路径chars/kfm中找到.

CMD文件包含command指令和state -1定义(用于控制人物如何出招的指定状态)的申明,

下面是一些对你来说将很有用的概念.


3.1.1 生命值和能量值

玩家的生命条(血条)是在屏幕顶端靠近自身一侧的黄色条.
当血条到达0,玩家就被击倒了.
他的能量条是蓝色的条,每次攻击或被击中都会增加.
当能量条到达某个值,能发出(超级攻击)超必杀.


3.1.2 控制

当我们说玩家"受控制",就是说他准备好了开始走,跳或者攻击.
不受控制的玩家将不会接受你的输入指令(从键盘或手柄).
例如,当p1在他的站立状态,他是受控制的,如果你按向前的按钮就会向前行走.
玩家在攻击状态中通常是不受控制的,否则你在出拳出到一般的时候就能走开了.

但是也有个例外.有时候你想让玩家接受某些指令即使他不受控制.
这被称为"招式打断",或者"招式取消".查看CMD文档获得详情.
(通常的连招出招就是这类情况).

我们经常会提到玩家的"控制标示".一个"标示"是一个真或假的值(0或1).
如果我们说玩家的控制标示为真,就是说他受控制.


3.1.3 游戏时间和状态时间

mugen跟踪游戏中经过的时间.
每次游戏被更新(这包括更新玩家,检测碰撞,绘制到屏幕),我们就说游戏时间增加1.
玩家在一个状态中消耗的时间被称为"状态时间".
状态时间在状态中从0开始计时,每个游戏帧增加1.


3.1.4 位置,速度和加速度

运用你的基本数学知识将理解这些概念.mugen使用下面的坐标系.
x位置越大,越是向右远离玩家.x位置越小,越靠近左边.
地面的位置正好是y位置为0的时候.当玩家y位置变大,他向下运动.例如,y位置为负数表示他在空中.
相同的,当我们说玩家的x方向速度是正的,就是说他向前运动,如果他的x方向速度是负,他就朝后运动.
玩家的y方向速度是正,他向下运动,y方向速度为负,他向上运动.
正的x方向加速度表示玩家的x方向速度正在增加,负值表示减少.
y方向加速度同理.


3.1.5 连击点数

mugen允许某些招式实现"连击点数",就是说,为了能击中被打到空中,或者已经倒地的玩家.
juggling(连击点数)系统工作方式如下:每个人的第一次击中(从设置的连击点数开始)使他们处于下落状态,通常这个值是15.

一些快速术语:当我们说玩家处于"正在下落中",就是说他在空中不会恢复或受身,将落在地面上.

如果玩家在下落中或躺在地上时被攻击,他的连击点数将减少(数值由这次攻击的连击点数决定).
当攻击时需要的连击点数大于对手剩余时,这次攻击将miss.
任何导致 对手瞬间下落的招式将在第一次攻击中减去连击点数.

例如,一次需要7个连击点数的攻击 理论上能用于 连击对手2次(假如你开始的点数是15),对手还剩下1点连击点数.
随后此类攻击将miss.(因为此类攻击的juggle是7,大于对手剩下的1点juggle).

设置此连击系统的原因在于防止空中无限连击.


3.2 一个状态的基础部分

注意:此章节假定你至少浏览过AIR文件的相关文档,理解了动画的概念,同时了解了一个动画中的关键名字和短语.例如(action(动作)和element(元素),详见animelem控制器)

这是一个简短的p1状态的例子:

[Statedef 200]
type = S
physics = S
movetype = I
ctrl = 0
anim = 200
velset = 0

[State 200, 1]
type = ChangeState
trigger1 = AnimTime = 0
value = 0
ctrl = 1

此状态播放了P1动画中的 Action 200,动画结束后返回了p1的站立状态.
在此情况下,假定Action 200 是有限循环次数的.就是说, Action 200 没有计算出时间为-1的元素.

这点上,你不必担心详情.让我们从理解一个状态的组成开始.

所有的状态必须含有一个单独的Statedef章节,且一个或更多的State章节.

Statedef包含了一个状态开始的状态信息,就像此状态的类型(站立,蹲下,空中),招式类型(攻击,空闲).

每个State章节涉及到诸如状态控制器或者简短的控制器.
控制器告诉程序对p1做什么,什么时候做.有很多类型的控制器,每个都有自己的函数.
例如,有些控制器用于改变玩家的位置和速度,定义攻击的效果,创建飞行道具,改变动画,改变状态,等等.
每个控制器至少要含有一个触发条件.触发条件是使控制器激活的一个事件.
例如:状态开始时触发,动画结束时触发,当某个动画播放至某个元素时触发,当p2在p1某个范围内时触发,等等.


3.3 Statedef的详情

每个状态必须从一个精确的StateDef组开始,也被称为StateDef章节.
一个StateDef组必须看上去像这样(在小圆点的地方设置一个或更多的参数):

[Statedef state_number]
. state_parameters
.
.

将state_number更换成你要编写的状态号.除了特别的组号(见附录A 特殊状态号),你允许使用任何挑选的状态号码.
为了避免选择特殊的状态号码,请好不要选择0-199,5000-5999.
每个StateDef的state_number必须是整个人物中唯一的.

之后将包含下面的基本参数:

  • type

    • 请参阅 StateType
    若要保持与上一个状态相同的type,设置为U.

  • movetype

    • 请参阅 MoveType
    若要保持与上一个状态相同的movetype,设置为U.

  • physics
    • 若要保持与上一个状态相同的physics,设置为U.

  • anim

    请参阅 Anim

这里也能包含额外的可选参数.

  • velset

  • ctrl

  • poweradd

  • juggle

  • facep2

  • hitdefpersist

  • movehitpersist

  • hitcountpersist

  • sprpriority


3.3.1 type

这是P1在这个状态中的状态类型.定义了他是站立,蹲下,在空中,还是躺着.
相对应的字母分别是"S", "C" , "A" 和 "L"(不带引号).
要保持上一个状态的状态类型,使用"U".如果缺省这行,则假定为"S".
你将经常用到"S","C"和"A".例如,一个蹲下的状态类型必须是下面这行:

  • type = C

这个状态用来决定几个因素,最重要的,P1被击中时将是什么反应.
例如,在站立类型状态中,P1将作出犹如站在地面上一样的反应.
如果类型是"空中",则P1将作出相应的受击反应.


3.3.10 hitdefpersist

如果设置为1,任何从一个状态过渡到这个状态时激活中的HitDef将任然处于激活中.
如果设置为0,默认值,当状态过渡完成后任何上述情况的HitDef将无效.
(HitDef的作用被延续到下一个状态,原本HitDef只在一个状态内起作用)


3.3.11 movehitpersist

如果设置为1,上一个状态中招式击中的信息(无论是击中,miss,被防住等,详见"Move*"触发器)将延续到这个状态.
如果设置为0(默认值),此信息将在进入这个状态时复位.
(Move*系列 的作用被延续到下一个状态,原本Move*系列只在一个状态内起作用)


3.3.12 hitcountpersist

如果设置为1,连击数(这次攻击完成了多少hit)将被从上一个状态延续到这个状态.
如果设置为0(默认值),连击数将在状态过渡后复位.
此参数不会影响显示在屏幕上的连击计数器.
查看HitCount和UniqHitCount触发器文档,了解如何检测连击数.


3.3.13 sprpriority

如果使用这个参数,玩家的(图片)素材优先层级将被设置为指定的值.
如果缺省, 图片优先级将保持不变.common1.cns(共用cns文件)定义了站立,蹲下时人物的图像优先级是0,跳跃时是1.
对于大多数攻击状态,应该设置sprpriority = 2,以便攻击显示在上层.
查看sctrls中的SprPriority文档,了解如何使用控制器来改变图像优先级.


3.3.2 movetype

P1招式的类型:"A"表示攻击,"I"表示空闲,"H"表示受击.
要保持上一个状态的招式类型,使用"U".如果缺省这行,则假定为"I".
"A"和"H"应该不言自明."I"用于P1既不攻击也不受击的状态.
例如,一个攻击状态应该是下面这行:

  • movetype = A

你需要指定招式类型以便程序知道如何处理这个状态.
错误的指定招式类型也许会导致P1行动不正确.


3.3.3 physics

你需要指定在此状态中的物理属性.
有效值是,"S"表示站立,"C"表示蹲下,"A"表示空中,"N"表示无.
要保持上一个状态的物理属性,使用"U".如果缺省这行,则假定为"N".
物理属性的种类用来决定P1的行为特征.

  • 对"S"物理属性来说,P1将经受地面摩擦力.摩擦力系数设置在player的变量中.
  • 对"C"物理属性来说,P1将经受摩擦力,就像"S"状态.
  • 对"A"物理属性来说,P1将加速向下,如果他的y方向位置大于0(即,他触及了地面),他将立即进入落地状态.
  • 如果你使用"N",P1将不会有这些程序设定的物理状态.

不要把"physics"和"type"混淆.通常他们是相同的,但是给了你更好控制人物的机会.
例如,你也许会选择使用"N"(没有物理属性),且在空中状态中指定你自己的加速度和落地检测.


3.3.4 anim

此参数改变P1的动画.指定动作号.
如果你不想在状态开始时改变P1的动画,缺省这个参数.

在400号状态中,玩家正在进行一个蹲下的攻击,动作号为400,典型参数是:

  • [Statedef 400]
    type = c
    movetype = a
    physics = c
    anim = 400


3.3.5 velset

你能使用velset来设置状态起始时P1的速度.
格式是一对数字,分别代表x和y方向速度.
缺省将不改变P1原来速度.例如:

  • velset = 4,-8

使P1向上,向前移动.
这里有个特例.即使你设置了velset=0,在版边攻击P2的时候P1将被弹开.

注: 在Winmugen中,可以设置z轴,即velset=x,y,z,可是该语法放在mugen1.x中时运行会报错,解决办法是删除z轴参数.


3.3.6 ctrl

此参数将设置P1是否受控制.0表示不受控制,1表示受控制.
若缺省,P1的控制状态将保持上一状态不变.例如,给P1控制权,使用

  • ctrl = 1


3.3.7 poweradd

包含这个参数时,poweradd参数将被加到玩家的能量条中.poweradd值是一个数字,可正可负.
此参数典型的被用在攻击招式中,你想让玩家通过攻击来获得能量.例如,增加40能量,打上

  • poweradd = 40


3.3.8 juggle

juggle参数仅在攻击中起作用.指定了招式需要的连击点数.
若在攻击中缺省,则如果上一个攻击状态成功连击了,这次攻击也将连击.
你应该再所有的攻击中都指定juggle参数.
如果一个攻击跨越多个状态,只需要在攻击的第一个状态中设置juggle参数.也参见 3.1.5 连击点数.


3.3.9 facep2

当包含了facep2 = 1,玩家将在状态开始的时候转向对手.
facep2缺省默认值为0.


3.4.1 控制器格式 State格式

所有的状态必须包含至少一个状态控制器,否则会报错.状态控制器组有如下的格式:

  • [State state_number, some_number]
    type = controller_type
    trigger1 = condition_exp
    <universal optional parameters>
    <additional parameters depending on controller>

state_number必须与此状态 StateDef 设定的号码相同.
some_number可以是任何你所选的号码;
当遇到错误时会显示这个号码,以便你知道哪个控制器需要修复.
(其实state_number,some_number在做人物时可以任意指定(画面包,背景制作时必须state_number和def的一样),主要还是为了养成一个好习惯,不仅自己看懂此代码的意义,也有助于别人看懂,同时报错的时候能及时找到问题所在)
人物State的state_number和some_number都是可选的,可以都不写.

通用(能应用于任何控制器)可选参数是ignorehitpause和persistent.
如果ignorehitpause设成1,mugen会在打击停顿的时候也检测此控制器.否则在打击停顿的时候不会检测.
默认值是0,推荐使用这个值,除了少数情况(表述一个持续性的参数,详见触发器持续性).

controller_type是控制器的名字.每个控制器有不同的名字,需要不同的参数.详见控制器的相关介绍.

控制器的顺序是值得注意的.第一个列出的控制器首先被检测,如果必要,首先被执行.

这里是一个给予p1在状态开始时控制权的例子:
(在StateDef下面设置参数ctrl = 1有相同的效果)

  • [State 300, 1] ;State 300. 只是一个主观上的号码.
    type = CtrlSet ;改变控制标示.
    trigger1 = Time = 0
    value = 1

此例中,CtrlSet使你改变p1的控制标示.
trigger1 = Time = 0这行表示状态时间为0的时候激活,即,状态的起始.
value = 1 这行表示我们要把控制标示设置成1,表示真.
如果我们要让状态起始时p1不受控制,只要把最后一行改成value = 0.

看另一个例子.此控制器使p1向前移动10像素2次:在当前动画播放到第2第3元素的时候.
如果你不知道什么参数匹配什么样的控制请不要担心.
请参看关于控制器的详细说明.

  • [State 300, 2]
    type = PosAdd ;增加p1位置
    trigger1 = AnimElem = 2 ;第2元素时触发.
    trigger2 = AnimElem = 3 ;第3元素时触发.
    x = 10

如你所见,每个控制器必须至少含有1个触发条件.
一个触发条件能使控制器被激活.此例有2个触发条件,只要其中一个为真,控制器就能被激活.


3.4.2.1 触发器逻辑性

第一个触发条件总是trigger1,下面的应该是trigger2,之后是trigger3等等.
控制器执行的逻辑是:

1.所有trigger1都为真?如果是,就激活控制器.
2.否则,检测trigger2,等等,直到找不到剩余的触发条件.

你能把它想象成逻辑"或".

注意;跳过trigger后面的数字会造成某些触发条件被忽略.
例如,如果你有了trigger1,trigger2,trigger4而没有trigger3,那trigger4将被忽略.

如果你想在控制器被激活前列出更多的条件该怎么做?
这是一个常用例子,检测处于空中的玩家是否落地.触发条件:

  • trigger1 = Vel Y > 0 ; 向下运动
    trigger1 = Pos Y > 0 ; 在地面之下

在这点上，你也许会对触发条件的格式感到困惑.不要担心,我们会很快说到.

如你所见,相同的触发条件有相同的号码.当一些触发条件有相同的号码,他们执行的是逻辑"且".
就是说,相同号码的触发条件都为真才能激活控制器,只要有一个为假就不能激活.

你可以把他们结合起来.例如:

  • trigger1 = Vel Y > 0 ; 向下运动
    trigger1 = Pos Y > 0 ; 在地面之下
    trigger2 = Time = 5 ; 状态时间是5为真

玩家落地或者状态时间为5都能激活此控制器.

总结:

相同号码的触发条件只有所有条件为真才能激活控制器.
不同号码的触发条件只要有一个条件为真就能激活控制器.

触发条件格式为:

  • trigger? = condition_exp

condition_exp是一个用于检测的算术表达式.如果是0,触发条件为假.如果是非0值,触发条件为真.
condition_exp通常是和上面例子相同的一些简单式子,但也能按要求变的很复杂.

在表达式间可以运用逻辑运算符.例如,此例与上例相同.

  • trigger1 = ((Vel Y > 0) && (Pos Y > 0)) || Time = 5

详情见表达式部分.

triggerall是你可能见到的有用结构.指定了一个对所有触发条件来说都要为真的触发条件.例如,考虑:

  • triggerall = Vel X = 0
    trigger1 = Pos Y > -2
    trigger2 = AnimElem = 3
    trigger3 = Time = [2,9]

对于从trigger1到trigger3需要被检测的条件,triggerall必须同时为真.
此情况下,只要x方向速度不是0,则这个控制器不会被激活.
你能按需要设置更多的triggerall条件.
注意,即使你指定了triggerall,trigger1也至少要有1个.


3.4.2.2 触发器持续性

如果你不想在每次条件为真的时候都触发,则你需要加上一个参数persistent.让我们开始一个例子:

  • [State 310, 1]
    type = PosAdd
    trigger1 = Vel Y > 1
    x = 10

此控制器使p1每帧朝前移动10像素,只要p1的y方向速度大于1.
就是说,每次触发条件为真都能激活控制器.如果我们只要控制器被激活1次,我们要加上这行:

  • [State 310, 1]
    type = PosAdd
    trigger1 = Vel Y > 1
    persistent = 0 ;<-- 加上这行
    x = 10

persistent默认值为1,表示只要触发条件为真控制器每次都能被激活.
persistent设置为0只允许在此状态中激活控制器1次.
直到p1离开此状态都会保留真.如果p1之后再次进入此状态,此控制器还是只激活1次.

persistent的参数也能取0,1之外的数:

[State 310, 1]
type = PosAdd
trigger1 = Vel Y > 1
persistent = 2 ;<-- 改变此行
x = 10

此情况下,设置persistent为2表示每2次触发条件为真,控制器被激活1次.
设置persistent为3表示每3次触发条件为真,控制器被激活1次.等等.


3.4.2.3 触发器重定向

如果需要检测玩家目标的状态时间,或者玩家的父级(如果玩家是helper),等等.
这就可能用到(重定向触发器).详见表达式部分.


3.4.3 常用控制器

null控制器常用于调试.null控制器基本上没什么用.你能用他临时关闭某些控制器,而不需要把整个章节注释掉.
例如,你也许想废弃这些代码:

  • [State 300, 1]
    type = VelAdd
    trigger1 = Time >= 0
    x = .8

只要简单的注释一下type同时插入null;

  • [State 300, 1]
    type = null ;VelAdd
    trigger1 = Time >= 0
    x = .8

之后如果你要重新使用之前的控制器,只要把type改成原来的.

让我们回看这个例子:

  • [Statedef 200]
    type = S
    physics = S
    movetype = I
    ctrl = 0
    anim = 200
    velset = 0

    [State 200, 1]
    type = ChangeState
    trigger1 = AnimTime = 0
    value = 0
    ctrl = 1

[State 200, 1]是ChangeState控制器.顾名思义,改变p1的状态号.value参数要包含改变为的状态号.
可选的ctrl参数能被设置成当转换状态时的控制标示(进入下一状态时是否受控).

现在我们来创建一个攻击状态.首先,动画动作需要绘制攻击框.
快速看一下AIR文档的格式:clsn1是攻击框,clsn2是受击框.
所以只要p1的任何clsn1框接触了p2的任何clsn2框,p1就击中了p2.

这个例子,我们假定p1的动画就像下面这样:

  • [Begin Action 200]
    200,0, 0,0, 3
    200,1, 0,0, 4
    200,2, 0,0, 4
    200,3, 0,0, 3

定义了攻击/受击框之后,看上去就是:

  • [Begin Action 200]
    Clsn2: 1
    Clsn2[0] = -10,0, 10,-80
    200,0, 0,0, 3
    Clsn1: 1
    Clsn1[0] = 10,-70, 40,-60
    Clsn2: 2
    Clsn2[0] = -10, 0, 10,-80
    Clsn2[1] = 10,-70, 40,-60
    200,1, 0,0, 4
    Clsn2Default: 1
    Clsn2[0] = -10,0, 10,-80
    200,2, 0,0, 4
    200,3, 0,0, 3

如你所见,每个元素含有都有clsn2框定义(至少有2个元素使用相同的框).
仅含有Clsn1框的是第二个元素.

注意:对动画中每个元素定义clsn1框是没问题的,但在第一个元素中定义clsn1框,此次攻击将变为瞬间的,变得不能防御(因为没有出招时间,对手来不及防御).
最后,推荐在第一个元素之后定义clsn1框.

下面我们开始设置CNS中的状态.下面将解释一些改变.

  • [Statedef 200]
    type = S
    physics = S
    movetype = A ;<-- changed from "I" to "A"
    ctrl = 0
    anim = 200
    velset = 0

    [State 200, 1] ;<-- Added this state controller
    type = HitDef
    trigger1 = AnimElem = 2
    attr = S, NA
    animtype = Light
    damage = 10
    guardflag = MA
    pausetime = 12,12
    sparkxy = 0,-55
    hitsound = 5,0
    guardsound = 6,0
    ground.type = High
    ground.slidetime = 12
    ground.hittime = 15
    ground.velocity = -5
    air.velocity = -2.5,-3.5

    [State 200, 2]
    type = ChangeState
    trigger1 = AnimTime = 0
    value = 0
    ctrl = 1

statedef下movetype参数设置成A表示"攻击".记住在所有攻击状态中设置此参数为A.
如前,p1在动作结束后返回站立状态.

hitdef控制器看起来很恐怖!别担心,我们下面会慢慢介绍.

  • type = HitDef
    trigger1 = AnimElem = 2

指定了控制器类型为hitdef,表示"攻击定义".
在动画的第2元素时被触发.任何此时间点的clsn2框,触发器被激活时,将携带此攻击定义.

假如,举例,你在第2,第3元素中都有clsn1框,在第2元素触发单个hitdef将使他同时作用于两个元素.
所以p1至少将打击1次:如果第2元素击中了,第3元素将miss.如果第3元素击中了,第2元素将miss.
要使攻击hit2次,你必须每个元素都触发hitdef控制器.

  • attr = S, NA

攻击的属性.用于决定是否攻击能击中p2.
此例中,这是一个站立普通攻击.

下面的所有参数详见hitdef控制器,在此不一一解释了.


4 common1.cns常用状态

如果你看了玩家的DEF文件,会看见如下内容:

  • stcommon = common1.cns ;Common states

每个玩家分享了一些常用状态,这是游戏引擎的基础部分.这些常用状态可以在data/common1.cns中找到.
一些例子是跑步和受击的状态.在特殊状态号中完整的列表是有效的.

如果你想为某些玩家覆盖常用状态,只要在玩家CNS中创建一个相同状态号(和需要覆盖的状态号相同)的状态.
则当玩家改变到那个指定的状态号时,他将进入新的状态,而不是common1.cns中的那个.
(因为stcommon = common1.cns执行优先级很低,大多数CNS文件的优先级都高于他)

要记住当覆盖mugen中某些有特殊代码的状态时,新创建的状态也有这些特殊代码.
例如,跑动的状态(state 100)中,设置玩家的速度为你在玩家变量中指定的值.
如果你覆盖了state 100,新状态将仍然含有这些设定.

一个普通的例子就是覆盖跑动状态.
mugen跑动状态的默认特征就是让玩家以恒定的速度持续向前运动,直到你放开向前的按键.
之后就回到了站立的状态.

现在,我们希望让玩家(这里称为p1)用前跳来代替跑,就像按两次向后键就会后跳那样.
你可以在p1的cns文件中这么设置.

  • ; RUN_FWD (overridden to dash-type)
    [Statedef 100]
    type = S ;Running is on the ground
    physics = N ;We'll define our own physics
    anim = 100 ;Anim action 100
    ctrl = 0 ;No control for duration of dash

    [State 100, 1] ;To start dashing forwards
    type = VelSet
    trigger1 = Time = [0,5]
    x = 6

    [State 100, 2] ;Friction after initial dash
    type = VelMul
    trigger1 = Time > 5
    x = .85

    [State 100, 3] ;
    type = ChangeState
    trigger1 = AnimTime = 0
    value = 0
    ctrl = 1

这里我们假定action 100是有限循环的.
[Velocity]下设置的run.fwd速度没有真的被忽略,但是[State 100,1]设置了x方向速度为6覆盖了这个细节.


5 特殊状态号

除非你想覆盖常用状态,否则请避免选择这些状态号(从0-199,5000-5999).
这里是common1.cns中的状态列表.

状态号 | 描述 | Ctrl(默认控制flag)
0 | 站立 | 1
10 | 站立到蹲下 | 1
11 | 蹲下 | 1
12 | 蹲下到站立 | 1
20 | 走 | 1
40 | 跳跃开始(起身阶段) | 0
45 | 空中跳跃开始 | 0
50 | 跳跃空中阶段 | 1
51 | 跳跃空中下落阶段(一般为空状态) | 1
52 | 跳跃落地 | 0
100 | 向前跑 | 1 (若有101状态则为0)
101 | 向前跑停止 | 0或1均可
105 | 向后小跳 | 0
106 | 向后小跳落地 | 0
120 | 防御(开始阶段) | 1
130 | 站立防御 (防御中) | 1
131 | 蹲下防御 (防御中) | 1
132 | 空中防御 (防御中) | 1
140 | 防御 (结束阶段) | 1
150 | 站立防御住攻击 (震动) | 0
151 | 站立防御住攻击 (被击退) | 0
152 | 蹲下防御住攻击 (震动) | 0
153 | 蹲下防御住攻击 (被击退) | 0
154 | 空中防御住攻击 (震动) | 0
155 | 空中防御住攻击 (被击飞) | 0
170 | 输了 (时间终了) | 0
175 | 平局 (时间终了) | 0
180 | 胜利姿势 (state 180--189) | 0
190 | 准备开场介绍 | 0
191 | 开场介绍 (覆盖此状态给人物一个开场介绍) | 0
5000 | 站立受击(震动) | 0
5001 | 站立受击(被击退) | 0
5010 | 蹲下受击(震动) | 0
5011 | 蹲下受击(被击退) | 0
5020 | 空中受击(震动) | 0
5030 | 空中受击(被击飞) | 0
5035 | 空中受击(过渡阶段) | 0
5040 | 空中受击(空中恢复，没有进入下落状态) | 0
5050 | 空中受击(下落状态) | 0
5070 | 绊倒受击(震动) | 0
5071 | 绊倒受击(被击飞) | 0
5080 | 倒地受击(震动) | 0
5081 | 倒地受击(被击退) | 0
5100 | 倒地受击(下落状态撞击地面) | 0
5101 | 倒地受击(从地面弹起) | 0
5110 | 倒地受击(躺在地上) | 0
5120 | 倒地受击(起身) | 0
5150 | 倒地受击(被击败时的躺在地上姿势) | 0
5200 | 空中受击(在地面上受身，仍然处于下落状态) | 0
5201 | 空中受击(在地面上受身) | 0
5210 | 空中受击(空中受身) | 0
5500 | 接关动画 | 0
5900 | 初始化(每回合开始时) | 0

请参阅 必要图像素材


6 表达式

MUGEN在大多数触发器和状态控制器中都支持算术表达式.
这比仅使用固定值显得更加灵活和特征可定制性.
此章节给出表达式概念和替代的描述.


6.1 数据类型

MUGEN使用3种数据类型:32位整数,32位浮点数,特殊null值"bottom".
整数代表从-2^31到2^31-1的所有数目,或者大约-20亿到20亿.
浮点数是单精度浮点数.也就是说,这个数字有一个7位有效数字的小数部分.
浮点数能用来表示很小的分数或者是非常庞大的数字.

当你在表达式中写数字时,MUGEN从存在的小数点中推导数据类型.
因此"7"一直是一个整数,举个例子.如果你想让7变成和浮点数一样,则你要写成"7.0".

"bottom"是一个特殊的数据类型,任何出现"bottom"的表达式将被清零(除了一些非常有限的例外).
它的出现标志着存在一些错误条件类型.你应该尝试如此的方式编程使bottom不再产生.
关于详情,你可以查看bottom的专属章节.

算术表达式的特征很大程度上取决于用来表示数字的基本数据类型.
同时,状态控制器也许期望他们的输入以某种类型输出,如果提供了错误的类型将出错.
(控制器指定的输出类型与实际输出类型不相符)

当不同数据类型值需要通过一些方式合并时(例如,加),"强制类型转换"就会发生.
通常,这表示一个整型将被转换成浮点型,同时有可能在此过程中产生误差.(强制转换)
下面的章节中我们将注意任何有关强制类型转换情况.


6.10 状态和状态控制器参数中的表达式

大多数情况,statedef(状态定义)或者状态控制器中的任何参数都能是一个表达式.
那些给定类型为字符串型的参数例外.例如,hit属性,guardflags,等等.不能指定成表达式.
同样,ignorehitpause和persistent参数(任何控制器中)也是例外,它们也不能用表达式作为参数.

状态控制器被触发后便计算它的参数,过后将不会重新计算,除了控制器被再次触发.
用逗号分隔的参数是从左到右计算的.要实现控制器参数的连续计算,则此控制器必须被持续触发.

在某些控制器如HitDef的情况中,并不希望控制器处于持续触发状态中,因为这样会降低观赏性且同时会招致不受欢迎的行为.
在这种情况下,程序员将希望试图尽可能久的延迟HitDef触发状态,以便计算HitDef参数时正好被使用.


6.11 代码效率

处理表达式不是向电脑收费,所以你代码的可读性比微优化表达式更重要.
然而,下面的某些好的做法将提高效率同时不影响最终的效果.

MUGEN在状态控制器中计算条件型触发器遵循如下原则:
首先计算triggerall,从上到下顺序计算.
如果任何triggerall计算出0,则剩余的触发器将被跳过且将计算下一个控制器.
如果所有triggerall计算结果都是非0,则引擎开始计算trigger1,也是从上到下顺序计算.
如果它们中任何一个计算出0,则跳过所有剩下的trigger1转而计算第一个trigger2,诸如此类等等.
如果一个块中的所有trigger(除了triggerall)都计算出非0,则将开始计算状态控制器参数且控制器被触发.

换句话说,触发器计算的逻辑是类似短路型的.在类似C语言的标记法中,这种方式也许被记为
triggerall,1 && triggerall,2 && ... && ((trigger1,1 && trigger1,2 && ...) || (trigger2,1 && trigger2,2 && ...) || ... )
这里 trigger1,2 记作 trigger1 第2行; trigger2,1 记作 trigger2 第1行,等等.
这个trigger组的逻辑计算将是短路型的,就像C一样.

(注:通过那个逻辑关系式,表示了triggerall组与后面trigger1,trigger2等所有组关系是'&&',也就是说只要triggerall组一个是0,就不能触发.
通俗说法就是triggerall里面只要有1个是0就不能触发,要触发必须triggerall全部非0.
逻辑关系式还能看出trigger1组和trigger2组...之间都是'||',也就是这些组中只要有一个组为1就能触发(前提是triggerall已经检测为非0.)
而在每个trigger组中,他们之间的关系是'&&',比如trigger1组中,要保证trigger1的情况下触发,必须每个trigger1都非0.
控制器被触发的通俗说法就是:首先每个triggerall都要非0,然后每个 triggerN组 中最少要有1个非0,triggerN组 要非0,必须每个triggerN都非0. )

由于这个系统,可以通过 组织好表达式以便条件型触发器里的数字尽可能的即小又少 来实现大大提高效率.
状态控制器参数可以减少工作量(代码量),这些参数在触发时仅计算一次,而不是玩家在状态中每帧都计算.例如

[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power < 1000
value = 3000

[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power >= 1000
value = 3001

[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power >= 2000
value = 3002
可以进一步简化为:

[State -1]
type = ChangeState
trigger1 = command = "a"
value = 3000 + (power >= 1000) + (power >= 2000)
你同时能为引擎排忧解难,通过把最容易计算出false的triggerall放在triggerall块的顶部.(可以减少引擎计算量)
同样,trigger1块应该是最可能被触发的块,但是在trigger1块内部,最有可能计算出0的trigger1应该放置在顶部.
对于有很多包含重复条件trigger的状态控制器,最好将这个控制器打断为2个独立的块,每个块独立设置triggerall.

如果你有一个复杂的条件,这个条件是许多连续状态控制器的触发条件,你可以把这个条件的值存储到一个变量中,然后把这个变量作为后面触发器的控制条件.
例如:

trigger1 = (command="abc" && command!="holddown" && power>=1000) || (command="abc" && command!="holddown" && var(5)) || ((command != "abc" || command = "holddown") && power>=2000)
可以被写成 (直接给 var(0) 赋值是可行的):

trigger1 = (var(0):=(command="abc" && command !="holddown") && power>=1000) || (var(0) && var(5)) || (!var(0) && power>=2000)
这里,你必须权衡提高可读性.(在使用子表达式和使用:=运算符这两种情况中权衡,这2种情况都会降低可读性)
(或者使用varset控制器:
[State -1]
type = varset
...
var(0) = command="abc" && command !="holddown"
然后:
trigger1 = var(0)&&power>=1000 || var(0)&&var(5) || !var(0)&&power>=2000
由于&&运算等级高于||,所以这么写不违背原意.)


6.2 算术运算符

算术运算符允许你执行像加法,乘法,除法等等那样的基本操作.
MUGEN拥有下列运算符:
(下面就不翻译原话了,大多数运算符和其他编程中的定义一样,只写出每个运算符通俗含义)

  • +
    把两数相加.其他类型与浮点型相加会先把其他类型强制转换成浮点型再相加,结果为浮点型.
  • -
    减号.强制类型转换和+号一样.
  • *
    乘号.强制类型转换和+号一样.
  • /
    除号.强制类型转换和+号一样.需要注意的是整型除以整型结果还是整型,不会出现小数点.也就是说8/3等于2.
    示例:10/3=3,12.0/3.0=4.0,20/4.0=5.0.
    除以0会产生bottom.
  • %
    求余.返回x除以y的余数.只要x或y是浮点型或者y是0就会产生bottom.
    (此运算符运用时一定要注意,尤其是注意浮点数用此运算符会错误,而且通过报错信息很难找到错误位置)
  • **
    幂运算.如果x,y是非负整数,x**y就是x的y次方.(定义0**0=1)
    如果幂运算的时候导致数据太大,就会出现MAX_INT(整数的上限)警告.
    如果x,y中有一个是负的或者浮点型,那2个数都会强制转换成浮点型,计算结果是实数.
    像-1**0.5这类运算会出bottom(负数不能开根号).
  • !
    逻辑运算符 否.x为非0时,!x等于0.x为0时,!x等于1.
    (逻辑运算符操作数分为非0和0,非0被看做1处理.返回值为布尔型,也就是true和false.用整数表示:1对应true(真),0对应false(假).)
  • &&
    逻辑运算符 且.x,y中只有当x和y都是非0,x&&y才会等于1,否则结果都是0.
  • ||
    逻辑运算符 或.x,y中只有当x和y都是0,x&&y才会等于0,否则结果都是1.
  • ^^
    逻辑运算符 异或.x,y中当x和y都是0或都是非0,x&&y才会等于0,否则结果都是1.
    （用0,1表示就是说,x,y数值不同时x^^y=1,数值相同时x^^y=0)
  • ~
    按位取反运算符.位运算符的运算方法是先把整数转换成2进制数,然后运算,再转换成10进制.
    取反计算原理是0的地方变1,1的地方变0.10110011取反就是01001100.
    如果对浮点数取反就会出bottom.
  • &
    按位与运算符.遵循0&1=0,1&1=1,0&0=0.
    运算方式同"~".
    操作数中出现浮点数会出bottom.
  • |
    按位或运算符.遵循0|1=1,1|1=1,0|0=0.
    运算方式同"~".
    操作数中出现浮点数会出bottom.
  • ^
    按位异或运算符.遵循0^1=1,0^0=0,1^1=0.
    运算方式同"~".
    操作数中出现浮点数会出bottom.
  • =
    关系运算符 等于.用来比较两个数是否相等.如果两数都是整型或都是浮点型且他们相等,则返回1,否则返回0.
    如果有一个数是浮点型,则比较的时候会将非浮点型的数强制转换成浮点型进行比较.
  • :=
    赋值 运算符.
    例子:
    var(4):=1 表示把整型值1赋给var(4).
    如果指定var(4):=1.1 则赋值的时候会将1.1转换为整型再赋给var(4)(var(4)的值为1).
    如果指定fvar(4):=1 则赋值的时候会将1转换为浮点型再赋给fvar(4)(fvar(4)的值为1.000000).
    (注:在MUGEN中":="运算符可以实现在触发条件中直接对var参数赋值.
    比如 trigger1 = var(0):=12.3 也就是直接把12.3赋给var(0)使得var(0)为12,然后再判断这个触发条件,也就是trigger1 = 12 ,此触发条件恒成立.
  • !=
    关系运算符 不等于.如果x,y类型相同,如果x不等于y,则x != y 返回1,否则返回0.
    如果有一个数是浮点型,则比较的时候会将非浮点型的数强制转换成浮点型进行比较.
  • <
    关系运算符 小于.如果x小于y,则x<y返回1,否则返回0.处理方式同"!=".
  • <=
    关系运算符 小于等于.如果x小于等于y,则x<=y返回1,否则返回0.处理方式同"!=".
  • >
    关系运算符 大于.如果x大于y,则x>y返回1,否则返回0.处理方式同"!=".
  • >=
    关系运算符 大于等于.如果x大于等于y,则x>=y返回1,否则返回0.处理方式同"!=".
  • =[,] !=[,] =[,) !=[,) =(,] !=(,] =(,) !=(,)
    区间运算符.
    举例来说,x=[y,z] 表示 x>=y && x<=z .而 x=(y,z) 表示 x>y && x<z .他们的区别就是是否包含边界.x=[y,z) 表示 x>=y && x<z.
    所以可以知道x!=[y,z]的含义了.也就是不包含在y和z之间.(x<y || x>z)而 x!=(y,z) 表示 x>=y || x<=z .
    运用此运算符特别要注意的就是优先级以及合法性,此运算符的优先级很低,且很多写法都非法,所以在用的时候以防万一还是加上括号.(详见运算符优先级以及表达式语法)


6.3 运算符优先级与联合性

如果你考虑这样一个表达式:3+2*5,先计算*和先计算+所得到的结果是不同的.
为了消除表达式的这种歧义,运算符被分配了不同的优先级别.
这种情况下,*的优先级要高于+的优先级,所以将先计算*再计算+,所以3+2*5的结果是13.

如果两个运算符同级,则处理方式从左到右,除了单目运算符和赋值运算符,他们联合方式从右到左.
例如,*和/是同级的,所以5.0*5/6等于25.0/6等于4.166667.
另一方面,5/6*5.0等于0*5.0等于0.0.
与此相反,单目运算符从右到左计算,-!0也就是-(!0),也就是-1.

如果表达式的某个部分用使用了括号"()",则此部分将最先运算.
例如,表达式(3+2)*5,首先计算+,然后计算*,结果是25.
如果嵌套多个括号,则最里层的括号首先运算.

运算符优先级基本上和C一样.
完整的运算符优先级列表,从高到底,如下:

运算符 | 优先级
! ~ - (单目运算符) | 最高级
** | ?
* / % | ?
+ - | ?
> >= < <= | ?
= != 区间运算符 | ?
:= | ?
& | ?
^ | ?
| | ?
&& | ?
^^ | ?
|| | 最低级

鼓励程序员使用括号使表达式在必要时保持清晰(可读性).
否则,由于运算符优先级细微的错误而产生的bug几乎很难被查明.


6.4 表达式语法

基本上来说,任何普通算术表达式都是合法的.
此外,因为关系运算符(>,<=,等等)被视为返回整型,能够运算他们的返回值,有点看起来不像普通的表达式.

  • 1.0 = (2 = (1 > 0) + !(0 < 1))
    1>0返回值1,0<1返回值0.!(0<1)等于1,所以这个表达式就等同于
  • 1.0 = (2 = 1 + 1)
    因为2=1+1返回1,所以表达式可以更简化为
  • 1.0 = 1.0
    返回1.

语法表达式中一个值得注意的限制地方是区间运算符仅允许出现在表达式最右方.
若表达式中有括号,在表达式括号部分中,那部分被认为是子表达式,区间表达式允许出现在子表达式的右边.
下面是一个有效格式的表达式:

  • (1 = [0,2]) = (0,1)
    但是下面的不是一个有效格式的表达式:
  • 1 = [0,2] = (0,1)

另外,只有"="和"!="符号允许出现在区间表达式前面.
所以 5 > [0,2],或 4 + [1,4) 此类表达式是非法的.

在逗号分隔的参数列表中,比如给函数型触发器或者状态控制器参数赋值,每个列表中的表达式被认为是一个单独的子表达式,因此区间运算符可以出现在这些子表达式的末尾.

例子:
trigger1 = stateno=[0,1000] && p2stateno=[0,1000] ;非法,而且此种错误很难检测出来
trigger1 = (stateno=[0,1000]) && p2stateno=[0,1000] ;合法,满足区间表达式出现在表达式最右方以及子表达式右方.


6.5 条件型触发器和函数型触发器

由于历史原因,两种不同类型都被称为"触发器".
第一种也许更确切的叫法是"条件型触发器",第二种也许更确切的叫法是"函数型触发器".
例如,在CNS中,一个典型的状态控制器也许看起来像下面的:

  • [State 1234, 5]
    type = ChangeState
    trigger1 = time = 0
    value = 0

"trigger1 = time = 0"就是一个条件型触发器.
如果表达式"time=0"计算出非0值,则ChangeState控制器将被执行.
如果表达式"time=0"计算出0,则ChangeState控制器将不被执行.
也就是说条件是非0或0影响着控制器是否被触发.

另一方面,表达式中出现的"time"是一个函数型触发器.
它返回一个值,即,玩家在状态1234中的状态时间.
注意一个函数型触发器不触发任何东西.它只是给出一个在表达式中起作用的值.

为了进一步了解不同之处,让我们思考一个不同的状态控制器:

  • [State 1234, 5]
    type = VarSet
    trigger1 = 1
    v = 0
    value = time + 5

注意条件型触发器"trigger1 = 1"此时不含有任何函数型触发器.
因为表达式"1"总是计算出1,此控制器将每帧都触发.
为了确定什么值被赋予给了var(0),就要计算"time + 5"的值.
函数型触发器"time"返回玩家的状态时间.然后加上5,结果算出的值赋给var(0).

完整的函数型触发器列表请详见触发器篇.


6.6 触发器重定向

在上例中,time触发器返回玩家的状态时间.但有时候希望检测玩家目标的状态时间,或者玩家父级的(如果玩家是一个helper),等等.
这能通过 在触发器名字前加上关键字说明应返回谁的信息 来完成.
此过程被称为触发器重定向.例如.

  • 5 + (parent, time)
    返回5+玩家父级的状态时间.

重定向键值关键列表如下:

  • parent
    重定向触发器到玩家的父级.(玩家必须是helper)
  • root
    重定向触发器到根级(最上级).
  • helper
    重定向触发器到第一个出现的helper.详见触发器文档中相关触发器"NumHelper".
  • helper(ID)
    ID应该是一个有效格式的表达式,计算出的值为正整数.
    触发器被重定向到一个拥有此ID号的helper上.
  • target
    重定向触发器到第一个出现的目标.
  • target(ID)
    ID应该是一个有效格式的表达式,计算出的值为非负整数.
    则将重定向触发器到指定ID号的目标.
    targetID在HitDef控制器的"ID"参数中指定.
  • partner
    重定向触发器到玩家的同伴.普通helper和中立玩家不被认为是同伴.
    详见触发器文档中相关触发器"NumPartner".
  • enemy
    重定向触发器到第一个出现的敌人.普通helper和中立玩家不被认为是对手.
    详见触发器文档中相关触发器"NumEnemy".
    注: 双人战时读取距离自己较远的敌人.
  • enemy(n)
    n应该是一个有效格式的表达式,计算出非负整数.
    触发器被重定向到第n个对手.
  • enemyNear
    重定向触发器到距离最近的对手.
    注: 双人战时读取距离自己较近的敌人.
  • enemyNear(n)
    n应该是一个有效格式的表达式,计算出非负整数.
    触发器被重定向到距离第n接近的对手.
  • PlayerID(ID)
    ID应该是一个有效格式的表达式,计算出非负整数.
    触发器被重定向到拥有唯一ID号且等于ID的玩家.详见触发器文档中相关触发器"ID"和"PlayerIDExist".

如果触发器被重定向到一个不存在的地址(例如,当没有helper时将触发器重定向到helper),则会返回bottom.

注意:
不支持递归重定向(例如,"root,target,time")


6.7 bottom

表达式中有几种无法补救的错误.
例如,可能试图去除以0,计算负数的平方根,或者试图重定向触发器到不存在的地址.
在这些情况下,bottom被用于优雅的完成表达式计算的一种方式.
如果bottom出现在表达式的任何地方(注意下面两个异常: 见Special Forms),则整个表达式的会变成bottom.
例如,思考这个表达式:

  • 5 + fvar(0) ** 0.5
    如果fvar(0)计算出-1,则此表达式变为5+bottom,产生bottom.

bottom在条件型触发器中被认为是0.
因此,一个产生错误的表达式将不会引起触发器崩溃.所以,例如,在

  • type = ChangeState
    trigger1 = helper, statetype = A
    value = 0

中,ChangeState控制器将永远不会被执行如果没有helper存在,因为表达式"helper, statetype = A"将计算出bottom,被认为是0.
(注:此种情况在debug时会出warning,解决方式就是在这条触发条件上方加上:

  • type = ChangeState
    trigger1 = numhelper
    trigger1 = helper, statetype = A
    value = 0

由于控制器检测的时候遵循从上到下的顺序,所以会先检测trigger1 = numhelper,如果numhelper非0,表示有helper,则将继续检测trigger1 = helper, statetype = A
因为有了helper存在,才不会使控制器重定向到不存在的地址.如果numhelper不存在,则根据检测顺序原理,就不会再检测trigger1 = helper, statetype = A,也就不会出warning. )

通常当产生bottom时,MUGEN的调试控制台会输出warning.
这是因为bottom的存在指示一个可能的逻辑上的错误或者是歧义.
例如,在上面的ChangeState的例子中,如果不存在helper,则声明"helper, statetype = A"是空的,且无法判断该认为是真还是假.


6.7.1 特殊格式

ifelse和cond触发器用一种特殊的方式处理bottom.他们的格式都为:

  • <trigger_name>(<exp_cond>,<exp_true>,<exp_false>)

<exp_cond>是条件表达式,根据是否为非0,控制<exp_true>和<exp_false>哪个将被返回.
如果还没有被返回前产生了bottom,则将不会把bottom传播至表达式其余部分.
例如,思考表达式IfElse(time > 0, 1.0/time, 2)),如果time>0,则表达式的值为1.0/time,一个有效的浮点值.
如果time=0,则表达式的值为2,即使是不使用的部分除以0产生了bottom.

然而,即使上面的ifelse触发器从不返回bottom,它仍然有一个烦人的特征:除以0仍然会生产一个warning在debug的时候.
这是因为ifelse计算了所有的参数,甚至是没用到的那部分.相反,Cond将只计算实际用到的参数.
因此,如果我们重写表达式为 Cond(time > 0, 1.0/time, 2),当time等于0的时候参数 1.0/time 将永远不会被计算,所以也就不会生产warning了.

你也许想知道何时使用Cong和IfElse.
回答是你几乎经常要用到Cond,除非你需要<exp_true>或<exp_false>中的副作用.
换句话说,如果你正在给变量赋值(在一个经常需要被执行的分支中,无论<exp_cond>的值是什么),则你需要使用ifelse.
否则,你应该使用Cond,尤其是为了隔离bottom.


6.8 避免警告

一些常见的错误条件在人物中经常产生大量的warning.
下面是一些最常见的情况和如何避免他们.

强制转换浮点型为整型

如果MUGEN期望某处是一个整型值(例如,一个var索引值),但却产生了一个浮点型值,则MUGEN将把浮点型转换成整型.
然而,它会抱怨,因为这也许会对你来说表示一个错误.
要摆脱warning,通过提供显式转换将浮点型转换为整型,也就是floor()或ceil().

重定向触发器到不存在的目标

如果你重定向到一个不存在的目标,就像你根本没有helper而你重定向到了helper,则bottom会产生且记录了warning.
这是因为表达式逻辑上模糊了(就是上篇文章提到的有歧义).你能通过在重定向前检测目标是否存在来避免warning.所以,

trigger1 = helper(1234), time > 20
将产生warning如果helper1234不存在.

trigger1 = numhelper(1234) > 0
trigger1 = helper(1234), time > 20
将不会.具体原因见上一篇文章的"注意"

另外,你能使用Cond触发器来隔离能潜在产生warning的代码.
假设我们要用一个表达式设定helper(1234)的生命值(如果他存在),如果不存在的话就设置player的生命值.则我们可以这么写:

Cond(numhelper(1234) > 0, (helper(1234), life), life)
(围绕helper(1234),life有一个额外的括号,它不是必要的,但能提高可读性)

缺少必要的 动作/图片素材

这不是表达式的问题.把缺失的补上!


6.9 触发器参数中的表达式

大多数函数型触发器要么没有参数要么有一个参数列表.
例如,time触发器没有参数,而ifelse却有3个参数.

  • ifelse(exp1,exp2,exp3)

这里exp1, exp2, exp3是所有有效的表达式.
在这种情况下,exp1, exp2, exp3都被认为是单独的子表达式,所以区间运算符可以出现在每个子表达式的最右方.
参数表运算顺序是从左到右.

由于不规则的语法,一些旧式函数型触发器不能使用表达式作为参数.
因为这个原因,它们不能通过标准方式被纳入表达式中.
对于这些类型的非标准触发器,触发器仅能与某些特定运算符和参数一起出现.
特别是,这些触发器不能用表达式作为参数.例如,

  • trigger1 = AnimElem = (1+1)
    是一个无效表达式.

旧式函数型触发器仅出现在"trigger, relational operator, argument"格式的"条款"中.
这些条款被视为一个独立的单元(特别的,单个0元触发器)用于表达式的计算.
这表示,在这些事物中,运算符优先级的概念在旧式函数型触发器条款中不适用.
例如,在

  • trigger1 = AnimElem = 5 + 4
    中,表达式分为3部分.
  • AnimElem = 5 + 4
    |________| |_| |_|

"AnimElem=5"部分被视为0元触发器的名字,于是'+'运算符的等级不在'='之上,从"AnimElem=5"中就能看出来.
换句话说,这个表达式意味着这样的计算方式"执行触发器调用'Animelem=5',然后加上4得到结果"

一些旧式函数型触发器拥有可替换的触发器(可用表达式作为参数).它们是下面的:

AnimElem, 被 AnimElemTime 取代
TimeMod, 被 % 运算符取代
ProjHit, ProjContact, ProjGuarded; 被 ProjHitTime, ProjContactTime, ProjGuardedTime 取代
完整的不规则触发器列表,详见trigger部分.不规则触发器用***标示出来.


关于CNS格式

  • 1 引言
    • 1.1 一些术语
  • 2 玩家变量
  • 3 状态
    • 3.1 状态介绍
      • 3.1.1 生命值和能量值
      • 3.1.2 控制
      • 3.1.3 游戏时间和状态时间
      • 3.1.4 位置,速度和加速度
      • 3.1.5 连击点数
    • 3.2 一个状态的基础部分
    • 3.3 Statedef的详情
      • 3.3.1 type
      • 3.3.2 movetype
      • 3.3.3 physics
      • 3.3.4 anim
      • 3.3.5 velset
      • 3.3.6 ctrl
      • 3.3.7 poweradd
      • 3.3.8 juggle
      • 3.3.9 facep2
      • 3.3.10 hitdefpersist
      • 3.3.11 movehitpersist
      • 3.3.12 hitcountpersist
      • 3.3.13 sprpriority
    • 3.4 状态控制器详情
      • 3.4.1 控制器格式
      • 3.4.2 触发器
        • 3.4.2.1 触发器逻辑性
        • 3.4.2.2 触发器持续性
        • 3.4.2.3 触发器重定向
      • 3.4.3 常用控制器
  • 4 common1.cns常用状态
  • 5 特殊状态号
  • 6 表达式
    • 6.1 数据类型
    • 6.2 算术运算符
    • 6.3 运算符优先级与联合性
    • 6.4 表达式语法
    • 6.5 条件型触发器和函数型触发器
    • 6.6 触发器重定向
    • 6.7 bottom
      • 6.7.1 特殊格式
    • 6.8 避免产生警告
    • 6.9 触发器参数中的表达式
    • 6.10 状态和状态控制器参数中的表达式
    • 6.11 代码效率


概述

mugen1.0支持其他不同的坐标空间.不同坐标空间创建的人物,主题(画面包等),舞台背景运行时在一个单独的通用坐标空间中相互处理.
这个通用坐标空间被称为"游戏坐标空间".一种坐标空间转换为另一种被称为"转换".

在mugen中,游戏坐标空间在mugen.cfg中指定([Config]组下GameWidth/GameHeight参数).

坐标空间矢量的转换缩放系数 是目标空间宽度与源空间宽度的比例.
例如,一个用320*240坐标空间创建的人物放入1280x720时将放大4倍.


人物

人物坐标空间在人物def文件[Info]组下指定.


术语

游戏坐标空间
一个交互作用计算的通用坐标空间.人物,主题,舞台的矢量坐标转换成交互的游戏空间坐标.

转换
将一种空间坐标转换成另一种.

宽高比
一种坐标空间的宽度和高度的比例.

游戏宽高
游戏坐标空间的宽高比


舞台

舞台坐标空间在system.def中[StageInfo]组设置.


主题

主题的坐标空间在system.def中[Info]组下指定.
1.0版本中主题有个局限性,不能适应游戏长宽比(如果游戏的长宽比和主题不同的话).


坐标空间解释

内容

  • 概述
    • 术语
  • 人物
  • 主题
  • 舞台


CFG相关参数设定

;-=====================================================-
; Configuration file for mugen.exe
;-=====================================================-

;-------------------------------------------------------
; 游戏选项配置,就是MUGEN中option画面设置的参数.
; 不包含设置键位
[Options]
; 基本设置
Difficulty = 8 ;难度
Life = 300 ;生命值
Time = -1 ;每回合时间,-1就是无限
GameSpeed = 0 ;速度

; 组队模式仅有的配置
Team.1VS2Life = 150 ;1v2的时候血量
Team.LoseOnKO = 1 ;team模式里你挂掉了是不是AI继续打

; 设置应用的画面包
; options画面中不能设置这个
motif = data/mugen1/system.def ;这里就是默认画面包的位置

;-------------------------------------------------------
[Rules]
;设置VS不要改.目前只支持这个.
GameType = VS

;这是当成功击中对手时获得的能量.是实际伤害值的系数.
;例如,设置为3,一次造成10点伤害的攻击将获得30点能量.
Default.Attack.LifeToPowerMul = .7

;和上面的一样,只是这个是受击状态中的.
;这两个系数能被CNS中HitDef控制器"getpower"和"givepower"选项覆盖.
Default.GetHit.LifeToPowerMul = .6

;这参数控制当你连接一个超级攻击时此超级攻击的伤害.
;它实际上是对手防御力的一个乘数.
;一个较大的数值表示会对对手造成少的伤害值.
;如果你想超级攻击在连招的时候体现出平时的伤害值,设置此参数为1.
;注意1:增加防御力的效果将保持到对手倒下后从地面起身.
;注意2:当"superpause"控制器执行时,程序便知道你要进行超级攻击.此参数有效的就是从这个时机开始.
Super.TargetDefenceMul = 1.5
;-------------------------------------------------------
[Config]
;设置游戏的速度.默认是每秒60帧.数字越大,运行的越快.不要用10以下的数字.
GameSpeed = 60

;本地游戏的宽度和高度.
;推荐设置是:
; 640x480 标清 4:3
; 1280x720 高清 16:9
; 1920x1080 全高清 16:9
GameWidth = 640
GameHeight = 480

;首选语言 (ISO 639-1标准), 例如 en, es, ja, 等等.
;详见 http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
;空着将自动检测系统语言
Language = "en"

;设置1绘制阴影(默认).设置0(不绘制阴影)如果你的机器比较烂,想加快游戏速度.
DrawShadows = 1

;允许同时存在的残影数量.
;数值设的小可以减少内存使用.(默认1)
AfterImageMax = 16

;能绘制的最大图层图片数.
;数值设的小可以减少内存使用.(最小32)
LayeredSpriteMax = 256

;图片压缩缓存大小(KB).当许多图片或大型图片(或两种情况都有)在短时间内一起显示出来 造成运行速度减慢,增加这个数值也许可以解决这个问题.
;可接受的性能最小值为256.如果你设置的太大,也许同样会造成性能下降.
SpriteDecompressionBufferSize = 16384

;总共允许的explod最大数量.注意打击火花也算在explod内.
;数值设的小可以减少内存使用.(最小8)
ExplodMax = 256

;系统explod允许的最大数量.
;数值设的小可以减少内存使用.(最小8)
SysExplodMax = 128

;总共允许的helper最大数量.
;数值设的小可以减少内存使用.(最小4,最大56)
HelperMax = 56

;每个人允许的飞行道具最大数量.
;数值设的小可以减少内存使用.(最小5)
PlayerProjectileMax = 32

;1表示第一次运行这个MUGEN程序
FirstRun = 0
;-------------------------------------------------------
[Debug]
;debug开关
Debug = 1

;设置0禁止通过Ctrl-D的方式转换debug模式.
;如果Debug = 1,此参数将被忽略.
AllowDebugMode = 1

;设置1随时可以使用debug键.否则debug键只能debug模式里使用.
AllowDebugKeys = 1

;设置1以最大速度运行.
Speedup = 0

;快速对决时默认的初始舞台.
StartStage = stages/stage0-720.def

;设置1影藏开始时的开发标语.(就是标题画面时的顶层绿色条)
HideDevelopmentBuildBanner = 0

;-------------------------------------------------------
[Video]

;屏幕渲染模式.
;OpenGL - 实验性的OPENGL渲染 (推荐)
;System - 默认SDL渲染模式 (即Windows中的winbid)
;DirectX - DirectX 5渲染
;System和DirectX模式不支持高级功能(如RGB图像和改变窗口大小).
RenderMode = System

;设置1允许使用安全模式,主要针对老显卡.
;许多功能都不能使用.
SafeMode = 0

;图像分辨率默认和游戏分辨率一样.
;窗口模式下,这参数指定窗口大小
;你能强制转换分辨率(去掉下面的注释).
;Width = 1280
;Height = 720

;MUGEN运行时的色深.
;RenderMode=System时此参数忽略.(强制为16)
Depth = 32

;设置1开启垂直同步扫描.RenderMode=OpenGL时才支持.
VRetrace = 0

;设置1进入全屏模式,0是窗口模式.
;允许专用全屏模式,可能比窗口模式表现更佳.
FullScreen = 0

;设置为1允许在窗口模式中调整窗口大小.
;仅当RenderMode=OpenGL和OpenGLScreen(貌似是1.0版本的参数)时有效.
Resizable = 1

;设置为1表示强制宽高比
KeepAspect = 1

;绘图模式
;Normal(快速)和PageFlip (测试较少的图像)
;RenderMode=OpenGL时此值忽略
BlitMode = Normal

;舞台适应模式
;0 - 舞台按照屏幕宽度绘制(可能会把高度裁切掉)
;1 - 根据屏幕尺寸收缩适应
;RenderMode=System时忽略此参数(强制为0)
StageFit = 1

;系统适应模式
;0 - 系统按照屏幕宽度绘制(可能会把高度裁切掉)
;1 - 根据屏幕尺寸收缩适应
;RenderMode=System时忽略此参数(强制为0)
SystemFit = 1

;-------------------------------------------------------
; 声音配置
[Sound]
;是否启用声音.
Sound = 1

;设置游戏音频采样率.高频率产生高质量但需要更多系统资源.
;如果你声音设备有问题就设置的低一点.
;建议的几个声频 22050, 44100, 48000.
SampleRate = 44100

;设置音频缓存大小.缓存越大占用CPU越少但在播放声音时会引起很多潜在问题.
;缓存越小能减少潜在问题但是会占用更多CPU.
;同时,如果缓存空间小于你系统能处理的,你可能出现音频问题.
;
;缓存大小设置为2^n,n是你要指定的值.n的有效值是8-15.
;
;一个有效的经验方法是22050Hz设置10,或者44100 Hz和48000 Hz时设置11.
;机器越烂可能需要的缓存空间越大.
BufferSize = 11

;设置1实现游戏中stereo声效.0禁用.
StereoEffects = 1

;这是音源平移的宽度.如果你增加这个数值,stereo效果将听起来更靠近中心.
;设置的越小使立体声效果越分离.
;仅当StereoEffects为1时有效.
PanningWidth = 240

;设置1将使你声卡中左右声道互换.
ReverseStereo = 0

;声道数量.
WavChannels = 32

;所有声音的主要音量,用百分比表示(0-100)
MasterVolume = 100

;声音效果和说话声的音量,用百分比表示(0-100)
WavVolume = 80

;音乐的主要音量控制(0-100)
BGMVolume = 75

;声音效果转换率方法.
;从下面选择:
; *) SDL (无差值,低质量,耗资源低)
; *) libresample (有限差值, 中高质量, 耗资源高)
SFXResampleMethod = libresample

;重采样的质量,如果使用libresample.
;有效值是0(中等质量)或1(高质量).
SFXResampleQuality = 0

;BGM重采样的质量,如果使用libresample.
;有效值是0(中等质量)或1(高质量).
BGMResampleQuality = 0

[Music]
;这里是配置音乐插件和任何的可选参数.格式在下面:
; plugin = <pluginname> [, <pluginfile1>]
; <optional_param_1> = <value>
; <optional_param_2> = <value>
; plugin = <pluginname2> [, <pluginfile2>]
; ...
;有效参数取决于插件.每个BGM文件将被列表中确认的顶部插件播放.
;对于系统插件,<pluginfile>参数没用.

;系统插件(内置):mpg123
;只用来播放MP3.采样方面提供循环点(AB之间循环播放).
;可选参数:
; decoder = <decodername>
;要求使用特别的mpg123代码引擎(要求不一定能兑现,取决于文件).
;这里应该缺省除非你知道自己在做什么.有效值为:
;SSE, 3DNowExt, 3DNow, MMX, i586, i586_dither, i386, generic, generic_dither.
; rva = <mode>
;指定ReplayGain调整音量.有效值为:
; off (default; disables ReplayGain)
; track
; album
; volume = <vol>
;全局音量调节,百分比.这是一个线性缩放系数,此系数乘以输出的振幅.
;不要指定超过100的值除非你知道自己在做什么.
; extensions = <extensionlist>
;指定被识别为MP3的文件扩展名.这是用逗号分隔的列表,且没有空白.例如:
; extensions = mp3,mpeg3,mpe
;将用此插件为.mp3, .mpeg3, .mpe文件注册扩展名.缺省默认是"mp3".
plugin = mpg123
rva = track
extensions =
volume = 100.0

;Plugin (add-on): vorbisplug (Ogg插件参数)不翻译了...
;Plays Ogg Vorbis files using the libvorbisfile library. Supports loop
; points and ReplayGain volume adjustment. Does not support files with
; more than 2 audio channels.
;Optional parameters:
; rva = <mode>
; Specifies ReplayGain volume adjustment. Valid values are:
; off (default; disables ReplayGain)
; track
; album
; volume = <vol>
; Overall volume adjustment, in percent. This is a linear scale factor
; that multiplies the output amplitude. Do not specify a value over
; 100.0 unless you know what you are doing.
; extensions = <extensionlist>
; Specifies file extensions to recognize as MP3. This is a comma-
; separated list with no whitespace. For instance,
; extensions = ogg,vorbis,vorb
; would register the .ogg, .vorbis, and .vorb file extensions with this
; plugin. Defaults to "ogg,vorbis" if omitted.
plugin = vorbisplug, plugins/vorbisplug.dll
rva = track
extensions =
volume = 100.0

;System plugin (built-in): sdlmix (midi序列插件)
;Plays MIDI with native playback; MODs and other tracker files
; (with MikMod)
;
;Looppoints are not supported. Performs seamless end-to-beginning loops.
;
;Optional parameters:
; midivolume = <volume>
; Specifies volume scaling for MIDI in percent.
; 100 means no change (default).
; modvolume = <volume>
; Same as midivolume, but for MODs and other tracker files.
plugin = sdlmix
midivolume =
modvolume =

;-------------------------------------------------------
[Misc]
;内存中存储的额外玩家数量
;数量设置的小可以减少内存使用,但会使loading变的更频繁.
PlayerCache = 4

;设置1允许预缓存.预缓存尽可能早的尝试loading玩家资料,减少比赛之间的loading次数.
;要让程序完美运行,至少设置PlayerCache为1.
;当预缓存开启时PlayerCache最佳数字是4.DOS中不提供预缓存.
Precache = 1

;设置1开启图片和声音数据的大型缓存区.
;设置为0(关闭)减少内存使用,代价是loading变慢.
BufferedRead = 1

;设置1尽可能释放内存中system.def数据.
;减少内存使用,换取系统画面前的loading时间.
UnloadSystem = 0

;设置1当窗口不在当前时停止mugen运行.
PauseOnDefocus = 0

;窗口在背景中时声音效果和说话声处理配置.
;设置"Mute"关闭声效,"Play"播放声效.
SFXBackgroundMode = Play

;窗口在背景中时BGM处理配置.
;设置"Pause"停止音乐,"Mute"关闭音乐但是音乐其实还是在播放的(类似音量为0),"Play"和平常一样播放.
;如果在全屏模式下运行,则此选项总是设置为"Pause".
BGMBackgroundMode = Play

;设置非0值强制舞台背景使用指定的缩放系数.
;此选项对某些舞台(设置了背景的zoomin或zoomout参数,而没有使用默认值1)无效.
;此调试参数可能在将来的版本中移除.
;ForceStageZoomout = .75

;-------------------------------------------------------
[Arcade]
;设置0,电脑选人只用1号色表.
;设置1,电脑选人用随机色表.
AI.RandomColor = 1

;允许电脑不通过按键的方式输入指令.1开启,0关闭.
AI.Cheat = 1

;AI难度阶梯
;下面的2个参数,第一个数字对应获胜场次号,第2个是电脑难度偏移量.(也就是越往后打难度越高这种设置)
;实际难度是AI难度级别(options菜单中设置)与特定场次偏移量之和.
; AIramp.start = start_match, start_diff
; AIramp.end = end_match, end_diff
; e_d /----------
; /
; s_d _______/
; ^ ^ ^ ^
; 1st_m s_m e_m last_m
;例如,如果:
; AIramp.start = 2,0
; AIramp.end = 4,2
;难度4,打6局, 难度将是:
; 4,4,4,5,6,6
;第2局以前的难度是不变的,到了2以后就按0-2的线性比例增加,直到第4局的时候难度变为6.
arcade.AIramp.start = 2, 0
arcade.AIramp.end = 4, 2

;组队模式
team.AIramp.start = 1, 0
team.AIramp.end = 3, 2

;生存模式
survival.AIramp.start = 0, -3
survival.AIramp.end = 16, 4
;-------------------------------------------------------
[Input]
;是否允许键盘使用
P1.UseKeyboard = 1
P2.UseKeyboard = 1
;是否允许手柄使用
;0 - 关闭
;1 - 开启
P1.Joystick.type = 1
P2.Joystick.type = 1

;指令输入方向模式
;0 - 指令输入和玩家方向相同
;1 - 指令输入朝向最近的对手(处于实验性阶段,不要使用)
InputDirMode = 0

;0 - 只有pause键能解除暂停
;1 - 如果没有菜单,任何键都能解除暂停
AnyKeyUnpauses = 0

;-------------------------------------------------------
;具体键盘值查看相应教程.
; P1 键位设定 (M.U.G.E.N中配置)
[P1 Keys]
Jump = 119
Crouch = 115
Left = 97
Right = 100
A = 107
B = 59
C = 44
X = 106
Y = 108
Z = 109
Start = 49

; P2 键位设定 (M.U.G.E.N中配置)
[P2 Keys]
Jump = 273
Crouch = 274
Left = 276
Right = 275
A = 260
B = 261
C = 262
X = 257
Y = 258
Z = 259
Start = 50

[P1 Joystick]
Jump = 1
Crouch = 2
Left = 3
Right = 4
A = 13
B = 14
C = 20
X = 15
Y = 16
Z = 18
Start = 24

[P2 Joystick]
Jump = 33
Crouch = 34
Left = 35
Right = 36
A = 41
B = 42
C = 48
X = 43
Y = 44
Z = 46
Start = 50

;-------------------------------------------------------
[Console Init];控制台指令,也指明了快捷键的含义
; ~ Alt
; $ Shift
; ^ Control
keybind["^tilde"] = "toggleconsole()"
keybind["space"] = "mugen.lifereset()"
keybind["F1"] = "mugen.killteam(2)"
keybind["^F1"] = "mugen.killteam(1)"
keybind["F2"] = "mugen.almostkillteam()"
keybind["$F2"] = "mugen.almostkillteam(1)"
keybind["^F2"] = "mugen.almostkillteam(2)"
keybind["F3"] = "mugen.maxteampower()"
keybind["$^F3"] = "mugen.togglemaxpowermode()"
keybind["F4"] = "mugen.roundreset()"
keybind["$F4"] = "mugen.matchreload()"
keybind["F5"] = "mugen.setroundtimeleft(1)"
keybind["F8"] = "mugen.clearclipboards()"
keybind["^1"] = "mugen.toggleplayerai(1)"
keybind["^2"] = "mugen.toggleplayerai(2)"
keybind["^3"] = "mugen.toggleplayerai(3)"
keybind["^4"] = "mugen.toggleplayerai(4)"
keybind["^L"] = "mugen.togglebardisplay()"
keybind["^C"] = "mugen.toggleclsndisplay()"
keybind["^I"] = "mugen.forceplayersintostand()"
keybind["^~1"] = "player.enableset(1, not player.enabled(1))" ;-- Hack: use at your own risk
keybind["^~2"] = "player.enableset(2, not player.enabled(2))" ;-- Hack: use at your own risk
keybind["^~3"] = "player.enableset(3, not player.enabled(3))" ;-- Hack: use at your own risk
keybind["^~4"] = "player.enableset(4, not player.enabled(4))" ;-- Hack: use at your own risk
keybind["^T"] = "mugen.toggletrainingmode()" ;-- Hack: use at your own risk
; Test stuff
keybind["1"] = "dofile 'test.lua'"


CNS变量设置

[Data]
life = 1000
;起始的生命值

attack = 100
;攻击力(数值越高越强)

defence = 100
;防御力(数值越高越强)

fall.defence_up = 50
;玩家倒下时每时间单位增加的防御力百分比

liedown.time = 60
;玩家倒地起身前的时间(持续按键会加速起身时间)

airjuggle = 15
;默认连击点数(通常,连招中每招的连击点数之和超过这个数字就无法继续连击)

sparkno = 2
;HitDef中默认的击中火花号

guard.sparkno = 40
;默认的防御火花号

KO.echo = 0
;设置1实现KO时回声效果

volume = 0
;音量(负值声音变小)

IntPersistIndex = 60
FloatPersistIndex = 40
;大于等于此索引号的变量在round或match之间将不会复位(初始化)到0.
;有60个整型变量(索引号从0到59)和40个浮点型变量(索引号从0到39)供使用.
;如果缺省,默认分别有60个整型变量和40个浮点型变量,意味着没有一个变量被persist(指保留上一回合的数据),即所有变量都复位.
;如果你想让变量在回合结束时能保留上一回合的数据,你需要覆盖common1.cns中的[statedef 5900](此状态管理每回合结束时的变量初始化).

[Size]
xscale = 1 ;水平方向缩放因数
yscale = 1 ;垂直方向缩放因数
ground.back = 15 ;玩家在地面时的后方宽度
ground.front = 16 ;玩家在地面时的前方宽度
air.back = 12 ;玩家在空中时的后方宽度
air.front = 12 ;玩家在空中时的前方宽度
height = 60 ;玩家的高度 (对手能否跳过你的身体)
attack.dist = 160 ;默认的攻击距离 (在此距离之内攻击对手,对手可作出防御动作,超出这个距离就不能了)
proj.attack.dist = 90 ;飞行道具的默认攻击距离
proj.doscale = 0 ;设置为1使得飞行道具也受xscale和yscale影响
head.pos = -5, -90 ;近似头部位置
mid.pos = -5, -60 ;近似中部位置
shadowoffset = 0 ;影子垂直偏移量像素值
draw.offset = 0,0 ;玩家显示在屏幕上的x,y偏移量像素值,建议0,0.

[Velocity]
walk.fwd = 2.4 ;向前走的速度
walk.back = -2.2 ;向后走的速度
run.fwd = 4.6, 0 ;向前跑x,y方向速度(y方向非0表示跳跃前进)
run.back = -4.5,-3.8 ;向后小跳x,y方向速度
jump.neu = 0,-8.4 ;正向上跳x,y方向速度
jump.back = -2.55 ;向后跳x,y方向速度
jump.fwd = 2.5 ;向前跳x,y方向速度
runjump.back = -2.55,-8.1 ;跑动中跳跃 (可选)
runjump.fwd = 4,-8.1 ;
airjump.neu = 0,-8.1 ;空中跳跃 (可选)
airjump.back = -2.55 ;
airjump.fwd = 2.5 ;
air.gethit.groundrecover = -.15,-3.5 ;地面受身状态的x,y速度 **MUGEN 1.0**
air.gethit.airrecover.mul = .5,.2 ;空中受身状态x,y速度的乘数 **MUGEN 1.0**
air.gethit.airrecover.add = 0,-4.5 ;空中受身的x,y速度偏移量 **MUGEN 1.0**
air.gethit.airrecover.back = -1 ;空中受身按住向后键时给予x方向额外的速度 **MUGEN 1.0**
air.gethit.airrecover.fwd = 0 ;空中受身按住向前键时给予x方向额外的速度 **MUGEN 1.0**
air.gethit.airrecover.up = -2 ;空中受身按住向上键时给予y方向额外的速度 **MUGEN 1.0**
air.gethit.airrecover.down = 1.5 ;空中受身按住向下键时给予y方向额外的速度 **MUGEN 1.0**

[Movement]
airjump.num = 1 ;空中允许跳跃的次数(可选)
airjump.height = 35 ;空中跳跃时应满足的最低高度 (可选)
yaccel = .44 ;垂直方向加速度
stand.friction = .85 ;站立时的摩擦系数
crouch.friction = .82 ;蹲下时的摩擦系数
stand.friction.threshold = 2 ;站立时如果玩家的速度降低到低于这个界限,他会停止运动 **MUGEN 1.0**
crouch.friction.threshold = .05 ;蹲下时如果玩家的速度降低到低于这个界限,他会停止运动 **MUGEN 1.0**
air.gethit.groundlevel = 25 ;指定一个Y方向位置,当下落中的玩家低于这个位置时被认为是落地了 **MUGEN 1.0**
air.gethit.groundrecover.ground.threshold = -20 ;指定一个Y方向位置,当下落中的玩家低于这个位置时才能使用(地面)受身指令 **MUGEN 1.0**
air.gethit.groundrecover.groundlevel = 10 ;指定一个Y方向位置,玩家进入地面受身状态到达此位置被认为触及地面 **MUGEN 1.0**
air.gethit.airrecover.threshold = -1 ;指定一个Y方向位置,在此位置之上玩家可以使用空中受身指令 **MUGEN 1.0**
air.gethit.airrecover.yaccel = .35 ;玩家在空中受身状态时的垂直加速度 **MUGEN 1.0**
air.gethit.trip.groundlevel = 15 ;指定一个Y方向位置,玩家在被绊倒状态中到达此位置被认为触及地面 **MUGEN 1.0**
down.bounce.offset = 0, 20 ;玩家从地面弹起的x,y偏移量 **MUGEN 1.0**
down.bounce.yaccel = .4 ;玩家从地面弹起的垂直方向加速度 **MUGEN 1.0**
down.bounce.groundlevel = 12 ;指定一个Y方向位置,玩家从地面反弹又落下,到达此位置被认为触及地面 **MUGEN 1.0**
down.friction.threshold = .05 ;倒下时如果玩家的速度降低到低于这个界限,他会停止运动 **MUGEN 1.0**

;默认的胜利引语语种 (可选). **MUGEN 1.0**
;如果包含了此章节, 默认的胜利引语语种必须是英语.
[Quotes]
; 每个语种能指定100个胜利引语 (victory0 - victory99)
victory1 = "You must defeat Tu Shou to stand a chance."
victory2 = "You need a lot of training. Come back in ten years."
victory3 = "You look familiar. Did I see you on TV "
victory4 = "Your moves are too predictable. You want to learn Kung Fu Palm It's not for novices."
victory5 = "That was a good workout."
victory6 = "I want to challenge more skilled fighters."
victory7 = "What do you mean my girlfriend is in another temple "

;胜利引语替代语种 (可选).
;可以增加替代语种, 前面加上ISO 639-1 代码再加上".",例如"[ja.Quotes]"
;详情见mugen.cfg中语言设置
[ja.Quotes]
victory1 = "カンフー突き手を破らぬ限り、お前に勝ち目はない！"
victory2 = "十年早いんだぞ"
victory3 = "お前は見覚えがあるな.テレビにでも…？"
victory4 = "お前の動きは見破りやすすぎる.　なに、カンフー突き手が覚えたいんだと？　素人には無理だぞ"
victory5 = "ふー.　いい汗だった"
victory6 = "もっと強い相手に挑戦したい"
victory7 = "なんだと！彼女はここにもいないと？"


DEF变量设置

; player信息
[Info]
name = "Player" ;人物名字
displayname = "Player" ;人物显示的名字
versiondate = 09,09,2009 ;人物版本日期 (MM-DD-YYYY或X.XX)
mugenversion = 1.0 ;人物运行的MUGEN版本(X.XX)
author = "My Name" ;人物作者名
pal.defaults = 1,2,3,4 ;默认的色表优先顺序 ,从1开始编号
localcoord = 320,240 ;本地坐标空间宽和高

; player文件
[Files]
cmd = player.cmd ;设置Command文件
cns = player.cns ;设置Constants文件
st = player.cns ;设置States文件
stcommon = common1.cns ;公共状态 (从 data/ 或 motif)
sprite = player.sff ;图像资源素材
anim = player.air ;动画文件
sound = ;声音文件(没有就别设)
ai = kfm.ai ;AI文件

;将选择键与色表映射
[Palette Keymap]
x = 1 ;按X键选择色表1,等等
y = 2
z = 3
a = 4
b = 5
c = 6
;x2 = 7 ;按住start再按X键选择色表7,等等
;y2 = 8
;z2 = 9
;a2 = 10
;b2 = 11
;c2 = 12

; 街机模式
;一般街机格斗游戏中每个人都有简单的故事情节
[Arcade]
intro.storyboard = ;开场剧情
ending.storyboard = ;结束剧情


FIGHT(血条等)相关参数设定

如何自定义

首先在[Files]下面设置文件名.

其次,你能自定义fight画面中的任何部件.
部件可以是从血条到K.O.文字的任何东西.

每个部件从名字开始,然后是点,最后是它元素的名字.
例如"bg"部件中的"anim"元素应该是这样表示"bg.anim"

这是几个主要的元素类型
1. anim (动画)
2. spr (图片)
3. font (文字)
4. snd (声音)

1. anim
格式: anim = actionno
actionno是动作号.你必须指定定义在这个文件中的有效动作号.
动作中的图片来自于[Files]组下面设定的"sff".
你能在此文件中任何位置定义动作,只要不在一个组模块之间
例如,要是用p1.bg0部件的第5号动作:p1.bg0.anim = 5
2. spr
格式: spr = spritegrp, spriteno
这是图片的一对识别号.例如,要显示 p1.throw部件的103,0图片素材:p1.throw.spr = 103,0
3. font
格式: font = fontno, fontbank, alignmnt, R, G, B
text = text
设置字体(和可选的文本内容).fontno是定义在[Files]下面的字体号.
例如,对于"font2 = font/num1.fnt",则fontno就是2.
fontbank字体使用的color bank(颜色库?).指的是此字体拥有的color bank.
alignmt是字体对齐方式.1-左对齐,0-中间对齐,-1-右对齐
R,G,B是字体颜色的校准值.默认是256,256,256(无颜色校准)
所有字体值都是可选的.如果缺省fontno,将不会显示任何字体.
"text"(文字)元素应该伴随着字体元素出现,必要时.
下面的例子将显示"FIGHT!"使用1号字体,1号库,中间对齐方式.
fight.font = 1,1, 0
fight.text = FIGHT!
4. snd
格式: snd = sndgrp, sndno
声音的一对识别符.
例子:
level1.snd = 21,0
注意,anim,spr,font元素类型是互斥的,你只能部件中使用他们中的一个.

支持的元素类型随部件的变化而变化.通常anim,spr,font元素对部件是通用的.但是在某些情况下,只能使用1种元素类型.
能在[Combo]下发现这样的例子:counter.font = 2,4(连击数的字体),你不能用动画或者图片来表示连击数,所以这种情况只能定义一个使用的字体.

还有一些元素类型,他们自身不起什么作用.他们能用于更精确控制元素类型.
对于snd元素无效.
5. offset (偏移量)
6. displaytime (显示时间)
7. facing (水平倒转)
8. vfacing (垂直倒转)
9. layerno (层号)
10. scale (缩放)

5. offset
格式: offset = x, y
设置元素x,y方向偏移量.缺省默认是0,0.
6. displaytime
格式: displaytime = time_in_ticks
定义元素显示的时间.若缺省,默认值随元素类型而变化.
对于spr和font元素,默认显示时间是1.对anim,是动画的循环时间.
显示"FIGHT!"文字45帧:
fight.font = 1,1, 0
fight.text = FIGHT!
fight.displaytime = 45
7. facing
格式: facing = dir
设置显示的元素是否水平翻转.1是不翻转,-1翻转.
对字体无效,缺省默认是1.
8. vfacing
格式: vfacing = dir
垂直方向的翻转.
9. layerno
格式: layerno = no
设置层号.0-在背景的上方,但是在人物的下方.1-在玩家上方,但是在前景下方.2-在前景上方.
大多数情况下设置为0.如果你要让血条和能量条显示在最上方,就把相关部件都设置layerno = 2.
10. scale
格式: scale = xscale, yscale
设置x,y方向缩放系数.默认是1,1.不支持字体.
一些部件还有他们独特的元素.

; 定义fight画面

; 这部分同system.def

[Files]
sff = fight.sff
snd = fight.snd
font1 = jg.fnt
font2 = num1.fnt
font3 = name1.fnt
fightfx.sff = fightfx.sff
fightfx.air = fightfx.air
common.snd = common.snd

;-----------------------------------------------------------
[FightFx]
scale = 1

;-----------------------------------------------------------
[Lifebar]
;Player 1
p1.pos = 140,12
p1.bg0.anim = 10 ;指的是血条相应的框架背景,血条框架背景由几个图像元素构成,也就是bg0,bg1...貌似只能指定到2还是3
p1.bg1.spr = 11,0
p1.mid.spr = 12,0 ;扣血时的红血印
p1.front.spr = 13,0 ;血条图像
p1.range.x = 0,-127 ;血条的范围,扣血就会在这个范围里进行,例如血条的左边缘位置是10,右边缘是100,难么范围也要用这个值,如果指定的范围不在10-100之间,就不正常了
;(这里只是举例子,坐标位置不一定就是这个,具体要看血条的边缘位置.)
;Player 2
p2.pos = 178,12
p2.bg0.anim = 10
p2.bg0.facing = -1
p2.bg1.spr = 11,0
p2.bg1.facing = -1
p2.mid.spr = 12,0
p2.mid.facing = -1
p2.front.spr = 13,0
p2.front.facing = -1
p2.range.x = 0,127

[Begin Action 10] ;Darkened lifebar background
10,0, 0,0, 1, , S

[Simul Lifebar] ;2v2时的血条
;Player 1
p1.pos = 140,12
p1.bg0.anim = 20
p1.bg1.spr = 21,0
p1.mid.offset = 0,-1
p1.mid.spr = 22,0
p1.front.offset = 0,-1
p1.front.spr = 23,0
p1.range.x = 0,-127
;Player 2
p2.pos = 178,12
p2.bg0.anim = 20
p2.bg0.facing = -1
p2.bg1.spr = 21,0
p2.bg1.facing = -1
p2.mid.offset = 0,-1
p2.mid.spr = 22,0
p2.mid.facing = -1
p2.front.offset = 0,-1
p2.front.spr = 23,0
p2.front.facing = -1
p2.range.x = 0,127
;Player 3
p3.pos = 140,15
p3.mid.spr = 22,0
p3.front.spr = 23,0
p3.range.x = 0,-127
;Player 4
p4.pos = 178,15
p4.mid.spr = 22,0
p4.mid.facing = -1
p4.front.spr = 23,0
p4.front.facing = -1
p4.range.x = 0,127

[Begin Action 20] ;Darkened lifebar background (team)
20,0, 0,0, 1, , S

[Turns Lifebar];turn模式的血条
;Player 1
p1.pos = 140,12
p1.bg0.anim = 10
p1.bg1.spr = 11,0
p1.mid.spr = 12,0
p1.front.spr = 13,0
p1.range.x = 0,-127
;Player 2
p2.pos = 178,12
p2.bg0.anim = 10
p2.bg0.facing = -1
p2.bg1.spr = 11,0
p2.bg1.facing = -1
p2.mid.spr = 12,0
p2.mid.facing = -1
p2.front.spr = 13,0
p2.front.facing = -1
p2.range.x = 0,127

;-----------------------------------------------------------
[Powerbar];能量条(原理和血条一样)
;Player 1
p1.pos = 140,22
p1.bg0.anim = 40
p1.bg1.spr = 41,0
;p1.mid.spr = 42,0
p1.front.spr = 43,0
p1.range.x = 0,-107
p1.counter.offset = -108,6
p1.counter.font = 1,0, 0

;Player 2
p2.pos = 178,22
p2.bg0.anim = 40
p2.bg0.facing = -1
p2.bg1.spr = 41,0
p2.bg1.facing = -1
;p2.mid.spr = 42,0
;p2.mid.facing = -1
p2.front.spr = 43,0
p2.front.facing = -1
p2.range.x = 0,107
p2.counter.offset = 109,6
p2.counter.font = 1,0, 0

; --等级的声音---
;1000power称为等级1,能量蓄满1000时的声音
level1.snd = 21,0
level2.snd = 21,0
level3.snd = 21,0

[Begin Action 40] ;Darkened powerbar background
40,0, 0,0, 1, , S
;-----------------------------------------------------------
[Face] ;血条上的头像
;Player 1
p1.pos = 2,12
p1.bg.spr = 50,0
p1.face.spr = 9000,0
p1.face.facing = 1
p1.face.offset = 0,10
;Player 2
p2.pos = 316,12
p2.bg.spr = 50,0
p2.bg.facing = -1
p2.face.spr = 9000,0
p2.face.facing = -1
p2.face.offset = 0,10

[Simul Face];2v2
;Player 1
p1.pos = 1,12
p1.bg.spr = 60,0
p1.face.spr = 9000,0
p1.face.scale = 0.6,0.6
p1.face.facing = 1
p1.face.offset = 0,10
;Player 2
p2.pos = 317,12
p2.bg.spr = 60,0
p2.bg.facing = -1
p2.face.spr = 9000,0
p2.face.scale = 0.6,0.6
p2.face.facing = -1
p2.face.offset = 0,10
;Player 3
p3.pos = 2,12
p3.face.spr = 9000,0
p3.face.scale = 0.6,0.6
p3.face.facing = 1
p3.face.offset = 11,10
;Player 4
p4.pos = 316,12
p4.bg.facing = -1
p4.face.spr = 9000,0
p4.face.scale = 0.6,0.6
p4.face.facing = -1
p4.face.offset = -11,10

[Turns Face];turn模式
;Player 1
p1.pos = 2,12
p1.bg.spr = 50,0
p1.face.spr = 9000,0
p1.face.facing = 1
p1.face.offset = 0,10
p1.teammate.pos = 1,49
p1.teammate.spacing = 13,0
p1.teammate.bg.spr = 70,0
p1.teammate.ko.spr = 71,0
p1.teammate.face.spr = 9000,0
p1.teammate.face.scale = 0.5,0.53
p1.teammate.face.facing = 1
p1.teammate.face.offset = 1,0
;Player 2
p2.pos = 316,12
p2.bg.spr = 50,0
p2.bg.facing = -1
p2.face.spr = 9000,0
p2.face.facing = -1
p2.face.offset = 0,10
p2.teammate.pos = 317,49
p2.teammate.spacing = -13,0
p2.teammate.bg.spr = 70,0
p2.teammate.bg.facing = -1
p2.teammate.ko.spr = 71,0
p2.teammate.ko.facing = -1
p2.teammate.face.spr = 9000,0
p2.teammate.face.scale = 0.5,0.53
p2.teammate.face.facing = -1
p2.teammate.face.offset = -1,0

;-----------------------------------------------------------
[Name];名字
p1.pos = 14,10
;p1.bg. =
p1.name.font = 3,0, 1
;p2.bg. =
p2.pos = 305,10
p2.name.font = 3,0, -1

[Simul Name]
p1.pos = 14,10
p1.name.font = 3,0, 1
p2.pos = 305,10
p2.name.font = 3,0, -1
p3.pos = 138,10
p3.name.font = 3,0, -1
p4.pos = 181,10
p4.name.font = 3,0, 1

[Turns Name]
p1.pos = 14,10
;p1.bg. =
p1.name.font = 3,0, 1
;p2.bg. =
p2.pos = 305,10
p2.name.font = 3,0, -1

;-----------------------------------------------------------
[Time];时间
pos = 160,23

;bg.spr = ;时间的框架背景
counter.offset = 0,0
counter.font = 2,0, 0 ;时间字体
; 每倒记1时间经过多少帧
framespercount = 60

;-----------------------------------------------------------
[Combo] ;连击数
team1.pos = 10,80 ;起始坐标
team1.start.x = -40 ;初始x坐标
team1.counter.font = 2,4,1
team1.counter.shake = 1 ;击中时连击数能震动
team1.text.text = Rush! ;%i表示连击数,比如KOF98中是 RUSH 10 HITS,则写法是 RUSH %i HITS.
team1.text.font = 1,0,1
team1.text.offset = 3,0
team1.displaytime = 90 ;连击数显示的时间
team2.pos = 309,80
team2.start.x = 359
team2.counter.font = 2,4,-1
team2.counter.shake = 1
team2.text.text = Rush!
team2.text.font = 1,0,-1
team2.text.offset = 3,0
team2.displaytime = 90

;-----------------------------------------------------------
[Round] ;回合相关
match.wins = 2 ;要赢几局才能最终获胜
match.maxdrawgames = 1 ;允许几次平局(-1表示无限) *2001.11.01 NEW*
start.waittime = 30 ;开场介绍前等待的时间

; 所有元素的默认位置
pos = 0,0

; ROUND X
round.time = 0 ;显示round字样的时间
round.default.offset = 160, 100
;默认每局显示的问题.Round %i表示第几回合
; 使用"round.default.anim"代替输出文字
round.default.font = 1,0, 0
round.default.text = Round %i
round.default.displaytime = 60
; 每回合的声音(最多指定9个回合)
round1.snd = 0,1
round2.snd = 0,2
round3.snd = 0,3
round.sndtime = 0 ;播放声音的时间
; 设置每回合图像元素的参数(最多指定9个回合)
;round1.offset = 160, 100
;round1.anim =

; FIGHT
fight.time = 0 ;显示FIGHT的时间
fight.offset = 160, 110
fight.anim = 80
fight.snd = 1,0
fight.sndtime = 0

ctrl.time = 30 ;"Fight"出现后多久player才能受控制

; 显示KO字样相关设置
KO.time = 0
KO.offset = 160, 70
KO.anim = 200
KO.snd = 2,0
; Double KO字样相关设置
DKO.offset = 160, 70
DKO.font = 1,5
DKO.text = Double K.O.
DKO.displaytime = 60
DKO.snd = 2,1
; Time Over字样相关设置
TO.offset = 160, 70
TO.font = 1,5
TO.text = Time Over
TO.displaytime = 60
TO.snd = 2,2
KO.sndtime = 0 ; KO, DKO ,TO播放的时间.
slow.time = 60 ;Time for KO slowdown (in ticks)
over.waittime = 45 ;KO结束后player停止前的时间
over.hittime = 10 ;KO结束后player还能攻击的时间
over.wintime = 45 ;player进入胜利状态前的时间
over.time = 210 ;回合结束前等待的时间
; win/draw信息显示前的时间
win.time = 60
; Win text
win.offset = 160, 70
win.font = 1,0
win.text = %s Wins
win.displaytime = 540
; 2-player win text
win2.offset = 160, 70
win2.font = 1,0
win2.text = %s and %s Win
win2.displaytime = 540
; Draw text
draw.offset = 160, 70
draw.font = 1,0
draw.text = Draw Game
draw.displaytime = 540

;"Fight!" Animation
[Begin Action 80]
80,0, 0,0, 1
80,6, 0,0, 1
80,7, 0,0, 1
80,6, 0,0, 1
80,0, 0,0, 30
80,1, 0,0, 1
80,2, 0,0, 1
80,3, 0,0, 1
80,4, 0,0, 1
80,5, 0,0, 1

;"K.O." Animation
[Begin Action 200]
-1,-1, 0,0, 5
200,2, 0,0, 2, ,A1
200,1, 0,0, 2, ,A
200,2, 0,0, 2, ,A
200,2, 0,0, 18, ,A1
200,4, 0,0, 2, ,A1
200,3, 0,0, 2, ,A
200,4, 0,0, 2, ,A
200,4, 0,0, 18, ,A1
200,0, 0,0, 2, ,A1
200,5, 0,0, 2, ,A1
200,5, 0,0, 2, ,A
200,5, 0,0, 2, ,A1
200,0, 0,0, 2, ,A1
200,0, 0,0, 50
200,6, 0,0, 1, ,A1
200,7, 0,0, 1, ,A1
200,8, 0,0, 1, ,A1
200,9, 0,0, 1, ,A1
200,10, 0,0, 1, ,A1

;-----------------------------------------------------------
[WinIcon] ;胜利图标
p1.pos = 34,43 ;33,43
p2.pos = 284,43 ;286,43
; 下个图标的位移 (x,y)
p1.iconoffset = 12,0
p2.iconoffset = -12,0
; Counter字体和位移
p1.counter.offset = 0,0
p1.counter.font = 2,1
p2.counter.offset = 0,0
p2.counter.font = 2,1
; Win by normal
p1.n.spr = 100,0
p2.n.spr = 100,0
; Win by special
p1.s.spr = 101,0
p2.s.spr = 101,0
; Win by hyper (super)
p1.h.spr = 102,0
p2.h.spr = 102,0
; Win by normal throw
p1.throw.spr = 103,0
p2.throw.spr = 103,0
; Win by cheese
p1.c.spr = 104,0
p2.c.spr = 104,0
; Win by time over
p1.t.spr = 105,0
p2.t.spr = 105,0
; Win by suicide (here's a fun one)对手自杀
p1.suicide.spr = 106,0
p2.suicide.spr = 106,0
; Opponent beaten by his own teammate (another fun one)被自己队友杀死
p1.teammate.spr = 107,0
p2.teammate.spr = 107,0
; Win by perfect (overlay icon)
p1.perfect.spr = 110,0
p2.perfect.spr = 110,0
; Use icons up until this number of wins 最多能使用的图标数量
useiconupto = 4


Select.def相关参数设置

                本页内容由【softmgr】撰写.

select.def一般位于data目录中，定义于system.def文件的:

[Files]
select = select.def

select.def整个文件共有3个小节，分别为:

  [Characters]
  [ExtraStages]
  [Options]

下面分别对这3个小节进行介绍:

;----------------------------

[Characters]
游戏中的所有人物和一部分场景都在此小节中.人物定义格式为:
人物目录名/人物.def,场景目录名/场景.def,music=背景音乐名,includestage=1或0,order=出场顺序号 ;注释
  人物目录名/人物.def 如果人物.def与人物目录名相同,则可以只输入人物目录名.
  场景目录名/场景.def 场景目录名通常为stages,也可以自定义目录名.在arcade模式该人物为电脑出场时使用的场景.
  music=背景音乐名 通常为mp3音乐文件.在arcade模式该人物为电脑出场时使用的背景音乐.
  includestage=1或0 如果定义了上述场景,则该项才有意义.值为1时,在arcade模式的其他人物出场时,也可以随机调用该场景.值为0时,在arcade模式只有该人物才能使用该场景.
  order=出场顺序号 在arcade模式的出场顺序.从1开始,到本def文件的[Options]中定义的关数为止之间的数字.如果不让该人物出场,定义为0即可.
  注释 分号;之后的内容为注释.

其中: 场景目录名/场景.def,music=背景音乐名 为可选项,即如果不定义,不用输入多余的逗号. 而如果要定义order,就必须先输入includestage或多加一个逗号.
示例:
Mai/Mai.def,stages/stage0-720.def,music=sound/sample.mp3,includestage=1,order=1
Mai,stages/stage0-720.def,includestage=1,order=2
Mai,includestage=0,order=3
Mai,,order=4
Mai ;这是注释

另外,输入BLANK或一个不存在的人物名,则该格子显示为空白(用于选单界面摆放成各种形状).
输入randomselect显示一个"?"按钮,即随机选择一个人物.

;----------------------------

[ExtraStages]
在[Characters]之外,还允许在这儿定义多个场景,一行一个.格式为:
场景目录名/场景.def
进入游戏之后的显示顺序为先显示[Characters]中定义的,后显示[ExtraStages]中定义的.
如果这儿定义了与[Characters]中相同的场景名,会忽略重复场景,不会显示两遍.

;----------------------------

[Options]
本小节共有2个设置项: arcade.maxmatches 和 team.maxmatches, 分别为arcade(单人街机模式)和team(多人街机模式)的关数配置项.与[Characters]中人物定义的order有对应关系.
这两项的设置方法相同,以arcade.maxmatches为例, 每个逗号分隔的数字代表该关卡一共有多少个随机人物(即要打多少个电脑人物才能过这一关).
例如:
arcade.maxmatches = 25,5,1,0,0,0,0,0,0,0
以上示例代表:第1关,一共有25个电脑随机人物,会在[Characters]中人物order=1或者未定义order的所有人物中进行随机抽取,共进行25场.
第2关,一共有5个电脑随机人物,会在[Characters]中人物order=2或者未定义order的所有人物中进行随机抽取,共进行5场.
第3关,一共有1个电脑随机人物,会在[Characters]中人物order=3或者未定义order的所有人物中进行随机抽取,共进行1场.
由于第4个数字为0,则第3关之后就会显示ending画面(即人物def中定义的ending.storyboard,如未定义,会显示mugen默认的ending画面).之后进入Game Over并重新进入主菜单.

通过以上介绍,我们知道关数与人物order是有对应关系的,故人物中的order如果定义太大或太小,则该人物都不会被街机模式抽取,从而不能与该人物对战.
如人物order=5或order=0,而arcade.maxmatches = 25,5,1,0,0,0,0,0,0,0 那么该人物也不会出现.如果要该人物出现,那么人物order=1-3之间.


System(画面包等)相关参数设置

; 定义系统画面

; 具体的格式类似背景定义.

; 关于字体的注意事项:
; - [Files]章节最多能指定10个字体
; - 这里的字体索引不是指的fight.def中的
; - 按下面的顺序搜索字体:
; 1. 系统目录
; 2. mugen程序目录(不建议把字体放在这里)
; 3. data/ (不建议把字体放在这里)
; 4. font/

;----------------------------
[Info]
name = "Default" ;主题的名称
author = "Elecbyte" ;主题作者名
versiondate = 09,01,2009 ;主题版本日期 (MM-DD-YYYY) (MUGEN 2009 新增)
mugenversion = 1.0 ;适用的mugen版本号 (MUGEN 2009 新增)
localcoord = 320,240 ;局部坐标空间的宽高 (MUGEN 2009 新增)

;----------------------------
;路径检测顺序:
;1. system.def所在的当前路径
;2. data/
;3. 你MUGEN路径

[Files]
spr = system.sff ;图片数据名称
snd = system.snd ;声音数据名称
logo.storyboard = ;标志剧情介绍 (可选)
intro.storyboard = ;开场剧情定义 (可选)
select = select.def ;人物,舞台选择列表
fight = fight.def ;fight(血条,能量条等)定义
font1 = f-4x6.def ;系统字体
font2 = f-6x9.def ;系统字体
font3 = jg.fnt ;系统字体

;----------------------------
[Music]
;把MOD,MP3,MIDI文件的文件名放置在这里,或者如果你没有声音就空着
;如果给出一个不存在的文件名,则不会播放声音
;要从sound/路径播放mymusic.mp3,写上:
; title.bgm = sound/mymusic.mp3
;如果文件名相同则声音将持续在屏幕中播放,且同时背景音乐被设置为循环播放

;在标题画面中播放的音乐.
;loop-循环,loopstart-循环开始的时间,loopend-循环结束的时间
title.bgm =
title.bgm.volume = 100 ;调节音量,默认100
title.bgm.loop = 1 ;声音是否循环
title.bgm.loopstart =
title.bgm.loopend =
;人物选择画面音乐
select.bgm =
select.bgm.volume =
select.bgm.loop = 1
select.bgm.loopstart =
select.bgm.loopend =
;VS画面音乐
vs.bgm =
vs.bgm.volume =
vs.bgm.loop = 0
vs.bgm.loopstart =
vs.bgm.loopend =
;胜利画面音乐
victory.bgm =
victory.bgm.volume =
victory.bgm.loop = 0
victory.bgm.loopstart =
victory.bgm.loopend =

;-------------------------------------------------------------------
;标题画面定义(模式选项画面)
[Title Info]
fadein.time = 10 ;画面淡入时间,设置一个透明渐变过渡,刚进入标题画面时画面从全黑渐渐变为标题画面.(貌似对字体无效)
fadeout.time = 10 ; 画面淡出时间,选择完模式后标题画面变为全黑.
menu.pos = 159,158 ;选项菜单的位置(屏幕左上角为0,0)
menu.item.font = 3,0,0 ;选项菜单字体(第1组数字是要调用的字体编号,第3组数字为对齐方式,0-居中对齐,1-左对齐,-1-右对齐)
menu.item.active.font = 3,5,0, 150,240,240 ;当光标放在这个选项上时的字体,后3组为指定字体遮罩颜色RGB数值.
menu.item.spacing = 0, 13 ;每个选项纵向间距
;菜单中每个选项的名称.名字必须在引号中.要禁用某个选项,使用"".如果所有选项都禁止,直接进入demo(观看)模式.(按Esc可以退出demo模式)
menu.itemname.arcade = "ARCADE"
menu.itemname.versus = "VS MODE"
menu.itemname.teamarcade = "TEAM ARCADE"
menu.itemname.teamversus = "TEAM VS"
menu.itemname.teamcoop = "TEAM CO-OP"
menu.itemname.survival = "SURVIVAL"
menu.itemname.survivalcoop = "SURVIVAL CO-OP"
menu.itemname.training = "TRAINING"
menu.itemname.watch = "WATCH"
menu.itemname.options = "OPTIONS"
menu.itemname.exit = "EXIT"
;定义选项菜单可见性
menu.window.margins.y = 12, 8 ;定义选项菜单上方的可见范围
menu.window.visibleitems = 5 ;总共有多少项设置为可见
menu.boxcursor.visible = 1 ;设置选项光标是否可见，1为显示，0反之.
menu.boxcursor.coords = -120,-27,120,2;设置选项光标位置大小. 是由4个点组成的矩形.
; 选项中的声音
cursor.move.snd = 100,0 ;移动光标的声音
cursor.done.snd = 100,1 ;确认选项的声音(光标选中的声音)
cancel.snd = 100,2 ;退出的声音(返回主界面时的声音)

;传统字体的概念即为定义字符,其实mugen的字体严格上来说不叫字体,更确切的说法其实是图像,字体中其实是通过定义图像上的某一部分区域来表示一个字母的.
;所以可以利用字体图像的特征结合菜单选项做出非传统mugen的选单效果.
;例如:设置
;menu.itemname.arcade = "A"
;menu.itemname.versus = "B"
;然后可以将字体绘制成图像模式,将字体A和B的区域定义成不同图像来实现特殊效果.

;此种方式应用很广泛,在背景预览,血条,能量条上都有用到.

;----------------------------
;标题背景定义
;除上述设置外的其他元素都要定义在这里(具体说明详见背景教程)
[TitleBGdef]
bgclearcolor = 0,0,0

[TitleBG 0]
type = parallax
spriteno = 5, 1
start = 0, 145
width = 400, 1200
yscalestart = 100
yscaledelta = 1
tile = 1,1
velocity = -1

[TitleBG 1]
type = normal
spriteno = 5, 2
start = -160, 145
trans = sub

[TitleBG 2]
type = normal
spriteno = 5,0
start = 0, 10
tile = 1,2
velocity = -1
mask = 0

[TitleBG 3]
type = normal
spriteno = 0,0
start = 0, 40
mask = 1
trans = add

;-------------------------------------------------------------------
;选人画面定义
[Select Info]
fadein.time = 10 ;淡入时间
fadeout.time = 10 ;淡出时间
; *** 注意 ***
; 你想增加更多的行和列吗
; 在 MUGEN 1.0, 默认画面包定义是在 data/mugen1/system.def.
; 你同时可以编辑 mugen.cfg 来选择"big"主题.

;注:大多数时候可以对图像素材(图片或者动画)进行缩放,例如:p1.cursor.done.spr =,则缩放的语句为p1.cursor.done.scale =
;除非有说明,否则使用图片的地方也可以使用动画,即p1.cursor.active.spr =也可以使用p1.cursor.active.anim =
;大多数时候,可以从最后一组字符串中猜到具体含义.
;spr-图像,anim-动画,offset-位置偏移量,snd-声音,font-字体,scale-缩放,facing-朝向,text-文字,spacing-间距,layerno-层号,time-时间
;总之就这么多花样,要注意的地方会另外注明.

rows = 2 ;设置行数和列数,都从0开始
columns = 5
wrapping = 0 ;设置1,使得光标移到最右边时,再按一次右就能回到最左边
pos = 90,170 ;第一个选人格子的起始位置
showemptyboxes = 0 ;是否显示空的格子
moveoveremptyboxes = 0 ;是否可以移动到空的格子上
cell.size = 27,27 ;每个选人框的x,y大小(像素).
cell.spacing = 2 ;选人框间距
cell.bg.spr = 150,0 ;选人框的图片.(不要使用动画)
cell.random.spr = 151,0 ;随机图标(不要使用动画)
cell.random.switchtime = 4;随机选择时变化的频率(时间帧数)
p1.cursor.startcell = 0,0 ;p1起始选人光标停留在选人框什么位置
p1.cursor.active.spr = 160,0 ;p1选人光标的图片(可使用动画即p1.cursor.active.anim = )
p1.cursor.done.spr = 161,0 ;p1光标选定时的图片
p1.cursor.move.snd = 100,0 ;p1光标移动时的声音
p1.cursor.done.snd = 100,1 ;p1光标选定时的声音
p1.random.move.snd = 100,0 ;p1随机选择的声音
p2.cursor.startcell = 0,4 ;同p1
p2.cursor.active.spr = 170,0
p2.cursor.done.spr = 171,0
p2.cursor.blink = 1 ;若p1光标和p2重叠是否闪烁
p2.cursor.move.snd = 100,0
p2.cursor.done.snd = 100,1
p2.random.move.snd = 100,0
random.move.snd.cancel = 0;设置1,随机声音反复播放时取消
stage.move.snd = 100,0 ;选舞台时,移动的声音
stage.done.snd = 100,1 ;选舞台时,选定时的声音
cancel.snd = 100,2 ;取消的声音
portrait.spr = 9000,0 ;选人格中小头像的图片(9000,0不要改)
portrait.offset = 0,0 ;选人格中小头像的位置(相对于选人格子)
portrait.scale = 1,1 ;缩放
title.offset = 159,13 ;指定此模式的标题位置
title.font = 3,0,0 ;标题字体
;
;大头像
p1.face.spr = 9000,1 ;9000,1不要改
p1.face.offset = 18,13 ;位置
p1.face.scale = 1,1
p1.face.facing = 1 ;朝向
p2.face.spr = 9000,1
p2.face.offset = 301,13
p2.face.scale = 1,1
p2.face.facing = -1
;名字
p1.name.offset = 10,162 ;名字的位置
p1.name.font = 3,4,1 ;-1不显示
p1.name.spacing = 0,-27 ;名字间距,旧版本貌似不能设置
p2.name.offset = 309,162
p2.name.font = 3,1,-1
p2.name.spacing = 0,-27
;舞台选择
stage.pos = 160,237
stage.active.font = 3,0,0
stage.active2.font = 3,2
stage.done.font = 3,0
;队伍菜单(此部分用图示)
teammenu.move.wrapping = 1
p1.teammenu.pos = 20, 30
;p1.teammenu.bg.spr = ;team菜单背景框
p1.teammenu.selftitle.font = 3,0, 1
p1.teammenu.selftitle.text = Select team mode
p1.teammenu.enemytitle.font = 3,0, 1
p1.teammenu.enemytitle.text = Opponent team mode
p1.teammenu.move.snd = 100,0
p1.teammenu.value.snd = 100,0
p1.teammenu.done.snd = 100,1
p1.teammenu.item.offset = 0,20
p1.teammenu.item.spacing = 0,15
p1.teammenu.item.font = 3,0, 1
p1.teammenu.item.active.font = 3,3, 1
p1.teammenu.item.active2.font = 3,0, 1 ;闪烁时第2种字体
p1.teammenu.item.cursor.offset = -10, 0 ;光标
p1.teammenu.item.cursor.anim = 180
p1.teammenu.value.icon.offset = 60,1
p1.teammenu.value.icon.spr = 181,0
p1.teammenu.value.empty.icon.offset = 60,1
p1.teammenu.value.empty.icon.spr = 182,0
p1.teammenu.value.spacing = 6,0
;p2 team
p2.teammenu.pos = 299, 30
;p2.teammenu.bg.spr =
p2.teammenu.selftitle.font = 3,0, -1
p2.teammenu.selftitle.text = Select team mode
p2.teammenu.enemytitle.font = 3,0, -1
p2.teammenu.enemytitle.text = Opponent team mode
p2.teammenu.move.snd = 100,0
p2.teammenu.value.snd = 100,0
p2.teammenu.done.snd = 100,1
p2.teammenu.item.offset = 0,20
p2.teammenu.item.spacing = 0,15
p2.teammenu.item.font = 3,0, -1
p2.teammenu.item.active.font = 3,1, -1
p2.teammenu.item.active2.font = 3,0, -1
p2.teammenu.item.cursor.offset = 10, 0
p2.teammenu.item.cursor.anim = 190
p2.teammenu.value.icon.offset = -60,1
p2.teammenu.value.icon.spr = 191,0
p2.teammenu.value.empty.icon.offset = -60,1
p2.teammenu.value.empty.icon.spr = 192,0
p2.teammenu.value.spacing = -6,0
;

[Begin Action 180] ;P1 Team mode cursor
180,0, 0,0, 1
180,0, 1,0, 1
180,0, 2,0, 1
180,0, 3,0, 1
180,0, 4,0, 1
180,0, 5,0, 1
180,0, 6,0, 1
180,0, 7,0, 1

[Begin Action 190] ;P2 Team mode cursor
190,0, 0,0, 1
190,0,-1,0, 1
190,0,-2,0, 1
190,0,-3,0, 1
190,0,-4,0, 1
190,0,-5,0, 1
190,0,-6,0, 1
190,0,-7,0, 1

;-----------------------
;定义选人画面背景元素
[SelectBGdef]
;spr = graphics/selectbg.sff ;Filename of sprite data

[SelectBG 0] ;Scrolling background
type = normal
spriteno = 100,0
layerno = 0
start = 0,0
tile = 1,1
velocity = -1, -1

[SelectBG 1] ;Dark box
type = normal
spriteno = 100,1
layerno = 0
start = 0, 166
delta = 0,0
tile = 1,0
trans = sub
window = 85,0, 235,239
velocity = -1, 0

[SelectBG 2.A] ;Title background
type = normal
spriteno = 102,0
layerno = 0
start = 0, 2
delta = 0,0
tile = 1,0
trans = sub
velocity = -1, 0

[SelectBG 2.B] ;Title background B
type = normal
spriteno = 102,1
layerno = 0
start = 0, 2
delta = 0,0
tile = 1,0
trans = add
velocity = -3, 0

[SelectBG 2.C] ;Title background C
type = normal
spriteno = 102,2
layerno = 0
start = 0, 2
delta = 0,0
tile = 1,0
trans = add
velocity = -6, 0

;-------------------------------------------------------------------
[VS Screen]
time = 150 ;显示的时间
fadein.time = 15
fadeout.time = 15
;arcade模式中的文字
match.text = "Match %i" ;%i表示局数
match.offset = 159, 12
match.font = 3,0,0
;大头像
p1.spr = 9000, 1
p1.offset = 20,31
p1.facing = 1
p1.scale = 1,1
p2.spr = 9000, 1
p2.offset = 299,31
p2.facing = -1
p2.scale = 1,1
;名字
p1.name.offset = 78,190
p1.name.font = 3,0,0
p2.name.offset = 241,190
p2.name.font = 3,0,0

;-----------------------
;VS背景定义
[VersusBGdef]

[VersusBG 1]
type = normal
spriteno = 100,0
start = 0,0
tile = 1,1
velocity = 0,1.5

[VersusBG 2] ;VS Screen
type = normal
spriteno = 100,1
start = 20,13
tile = 1,1
trans = sub
window = 19,30, 140,171
velocity = -2, 0

[VersusBG 3] ;VS Screen
type = normal
spriteno = 100,1
start = 20,13
tile = 1,1
trans = sub
window = 179,30, 300,171
velocity = 2, 0

[VersusBG 4] ;VS Logo
type = anim
actionno = 200
layerno = 1 ; Front
start = 0,95

[Begin Action 200]
200,4, 0,0, 1
200,3, 0,0, 2
200,2, 0,0, 3
200,1, 0,0, 4
200,0, 0,0, 8
200,5, 0,0, 3
200,6, 0,0, 3
200,7, 0,0, 3
200,8, 0,0, 3
200,0, 0,0, -1

;-------------------------------------------------------------------
;Demo模式定义
[Demo Mode]
enabled = 1 ;设置0禁用Demo
select.enabled = 0 ;设置1在demo里面显示选人画面
vsscreen.enabled = 0 ;设置1在demo里面显示VS画面
title.waittime = 600 ;设置title画面显示多久(也就是进入游戏后什么都不按)后进入demo
fight.endtime = 1500 ;demo里电脑打多久
fight.playbgm = 0 ;demo中对战时是否播放BGM
fight.stopbgm = 1 ;是否禁止title的BGM(仅当playbgm = 0)
fight.bars.display = 0 ;是否显示血条
intro.waitcycles = 1 ;过场动画再次播放前是否等待
debuginfo = 0 ;debug模式中是否隐藏debug信息

;-------------------------------------------------------------------
;续关画面定义
[Continue Screen]
enabled = 1 ;是否禁用

;-------------------------------------------------------------------
;Game over画面定义
[Game Over Screen]
enabled = 0 ;是否禁用
storyboard = ;如有情节,设置SFF名称

;-------------------------------------------------------------------
;胜利者画面定义
;arcade模式获胜一场后显示
;不是显示在arcade模式最后一场获胜后
[Victory Screen]
enabled = 1
time = 300 ;持续时间
fadein.time = 8
fadeout.time = 15
;胜利者的头像和名字
p1.offset = 100,20
p1.spr = 9000,2
p1.facing = 1
p1.scale = 1,1
p1.window = 0,0, 319,160
p1.name.offset = 20,180
p1.name.font = 3,0,1
;胜利后的文字
winquote.text = "Winner!" ;默认就是这个
winquote.offset = 20,192
winquote.font = 2,0,1
winquote.window = 18,171, 301,228
winquote.textwrap = w ;自动换行

;-----------------------
;Victory screen background
[VictoryBGdef]

[VictoryBG 1]
type = normal
spriteno = 100,0
start = 0,0
tile = 1,1
velocity = 0,1.5

[VictoryBG 2]
type = normal
spriteno = 100,1
start = 20,13
tile = 1,1
trans = sub
window = 0,19, 319,160
velocity = -2, 0

[VictoryBG 3]
type = normal
spriteno = 100,1
start = 10,170
tile = 1,1
trans = sub
window = 15,170, 304,229
velocity = 0, 0

;-------------------------------------------------------------------
;胜利画面定义
;arc模式获胜后显示
;如果你有剧情ending就不会显示
[Win Screen]
enabled = 1 ;是否禁用
wintext.text = "Congratulations!"
wintext.font = 2,0,0
wintext.offset = 159,70
wintext.displaytime = -1
wintext.layerno = 2
fadein.time = 32
pose.time = 300
fadeout.time = 64

;-------------------------------------------------------------------
;Game ending画面定义
;Win Screen后显示
;如果你有剧情ending就不会显示
[Default Ending]
enabled = 0 ;是否显示
storyboard = ;默认的剧情ending名字

;-------------------------------------------------------------------
;片尾字幕定义
;Win Screen和Ending之后显示
[End Credits]
enabled = 0 ;是否禁用
storyboard = ;文件名

;-------------------------------------------------------------------
;Survival模式结果画面
;生存模式胜利后显示
;有剧情ending的人物不会显示
[Survival Results Screen]
enabled = 1
winstext.text = "Rounds survived: %i" ;%i 胜利局数
winstext.font = 3,0,0
winstext.offset = 159,70
winstext.displaytime = -1
winstext.layerno = 2
fadein.time = 32
show.time = 300
fadeout.time = 64
roundstowin = 5

;-------------------------------------------------------------------
;Options画面定义
[Option Info]
cursor.move.snd = 100,0
cursor.done.snd = 100,1
cancel.snd = 100,2

;-------------------
;Options screen background
[OptionBGdef]

[OptionBG 1]
type = normal
spriteno = 100,0
start = 0,0
tile = 1,1
velocity = -1, -1


必要图像素材

标准受击姿势

关键字: 5000 5001 5002 5010 5011 5012 5020 5030 5031 5032 5040 5041 5042 5060 5061 5062 5070 5071 5072

  • 你必须严格按照以下表格中的数字来制作.
  • 如果角色站立时重心固定在与所需框架相同的位置, 则标有"脚将在的位置"的轴的轴线应大致位于双脚位置之间.
  • 标有"中段"的轴应围绕在腰部区域.
  • 标有"头"的轴应该在人物头部中间轴线处.
  • 有些数字: 如5000,1到5000,9 可供您选择添加中间帧.
  • 有关图片素材的大致外观以及轴的放置位置的示例, 请参见下方的 图解.

    • 图片 | 描述 | 坐标(原点)
5000,0 | 站立时被击中上部，头稍微往后 | 脚(两脚之间)
5000,10 | 站立时被击中上部，头往后的幅度较大 | 脚
5000,20 | 站立时被击中上部，头往后的幅度最大 | 脚
5001,0 | 同图片 5000,0 | 中段
5001,10 | 同图片 5000,10 | 中段
5001,20 | 同图片 5000,20 | 中段
5002,0 | 同图片 5000,0 | 头
5002,10 | 同图片 5000,10 | 头
5002,20 | 同图片 5000,20 | 头
5010,0 | 站立时被击中下部，身体稍微弯曲 | 脚
5010,10 | 站立时被击中下部，身体弯曲幅度较大 | 脚
5010,20 | 站立时被击中下部，身体弯曲幅度最大 | 脚
5011,0 | 同图片 5010,0 | 中段
5011,10 | 同图片 5010,10 | 中段
5011,20 | 同图片 5010,20 | 中段
5012,0 | 同图片 5010,0 | 头
5012,10 | 同图片 5010,10 | 头
5012,20 | 同图片 5010,20 | 头
5020,0 | 蹲下时被击中，头稍微往后 | 脚
5020,10 | 蹲下时被击中，头往后的幅度较大 | 脚
5020,20 | 蹲下时被击中，头往后的幅度最大 | 脚
5030,0 | 被背后击中，头稍微往后 | 假如站立时脚的位置
5030,10 | 被背后击中，头往后的幅度很大 | 脚将在的位置
5030,20 | 被击中腹部，身体成水平 | 脚将在的位置
5030,30 | 被背后击中，身体成水平 | 脚将在的位置
5030,40 | 下落中，头稍微朝下 | 脚将在的位置
5030,50 | 下落中，头朝下幅度很大 | 脚将在的位置
5031,0 | 同图片 5030,0 | 中段
5031,10 | 同图片 5030,10 | 中段
5031,20 | 同图片 5030,20 | 中段
5031,30 | 同图片 5030,30 | 中段
5031,40 | 同图片 5030,40 | 中段
5031,50 | 同图片 5030,50 | 中段
5032,0 | 同图片 5030,0 | 头
5032,10 | 同图片 5030,10 | 头
5032,20 | 同图片 5030,20 | 头
5032,30 | 同图片 5030,30 | 头
5032,40 | 同图片 5030,40 | 头
5032,50 | 同图片 5030,50 | 头
5040,0 | 下落撞击地面 | 地平线 (例如背部)
5040,10 | 躺在地上 | 地平线
5040,20 | 躺在地上时被攻击 | 地平线
5041,0 | 同图片 5040,0 | 身体中部
5041,10 | 同图片 5040,10 | 身体中部
5041,20 | 同图片 5040,20 | 身体中部
5042,0 | 同图片 5040,0 | 头
5042,10 | 同图片 5040,10 | 头
5042,20 | 同图片 5040,20 | 头
5060,0 | 被打飞，头指向上方，身体垂直 | 假如站立时脚的位置
5060,10 | 头指向下方，身体垂直 | 脚将在的位置
5061,0 | 同图片 5060,0 | 中段
5061,10 | 同图片 5060,10 | 中段
5062,0 | 同图片 5060,0 | 头
5062,10 | 同图片 5060,10 | 头
5070,0 | 被抓投，身体稍微前倾 | 假如站立时脚的位置
5070,10 | 被抓投，身体前倾幅度很大 | 脚将在的位置
5070,20 | 被抓头，身体水平，头指向前方 | 脚将在的位置
5071,0 | 同图片 5070,0 | 中段
5071,10 | 同图片 5070,10 | 中段
5071,20 | 同图片 5070,20 | 中段
5072,0 | 同图片 5070,0 | 头
5072,10 | 同图片 5070,10 | 头
5072,20 | 同图片 5070,20 | 头

    图解

    推荐组号

    组号 | 描述
0 | 站立
5 | 转身
10 | 站立到蹲下
11 | 蹲下
12 | 蹲下到站立
20 | 向前走
21 | 向后走
40 | 开始跳跃(此时还在地面上)
41 | 正向上跳(上升过程中)
42 | 向前跳(上升过程中)
43 | 向后跳(上升过程中)
44 | 正向上跳(下落过程中)
45 | 向前跳(下落过程中)
46 | 向后跳(下落过程中)
47 | 落地
100 | 向前跑
105 | 向后小跳
120 | 开始防御(站立)
121 | 开始防御(蹲下)
122 | 开始防御(空中)
130 | 防御(站立)
131 | 防御(蹲下)
132 | 防御(空中)
140 | 结束防御(站立)
141 | 结束防御(蹲下)
142 | 结束防御(空中)
150 | 防御一次攻击(站立)
151 | 防御一次攻击(蹲下)
152 | 防御一次攻击(空中)

    请参阅 特殊状态号


Mugen1.1Beta1已知Bug

                本页内容由【softmgr】撰写.

  • NotHitBy

  • AfterImageTime

  • ReversalDef

  • BackEdgeBodyDist 和 BackEdgeDist 的效果是相同的.

  • FrontEdgeBodyDist 和 FrontEdgeDist 的效果是相同的.

  • HitDefAttr

  • InGuardDist


AfterImage

实现玩家的残影效果.
人物的画面存入一个历史缓存区,一段时间之后作为残影被显示出来.

必要参数:
无

可选参数:
time = duration(整型)
指定残影将被显示的帧数.设置-1将被永久显示.默认值为1.

length = no_of_frames (整型)
设置画面历史缓存区的容量.历史缓存区将容纳no_of_frames幅人物最近保存的画面.
假设timegap和framegap是常数,增加长度能增加一段时间中残影显示的数量和"寿命"(缺少更好的词来形容).
最大长度是60,默认是20.

palcolor = col (整型)
见下方.

palinvertall = invertall (布尔型整数)
见下方.

palbright = add_r, add_g, add_b (整型)
见下方.

palcontrast = mul_r, mul_g, mul_b (整型)
见下方.

palpostbright = add2_r, add2_g, add2_b (整型)
这些参数决定了应用到所有残影上的色表效果.
首先,色彩等级通过palcolor的值调整,然后如果palinvertall的值是非0则颜色会反向.
然后,palbright分量增加到玩家色表的相对应分量之上,每一分量乘以相对应的palcontrast分量除以256,最后加上palpostbright的分量.
palcolor取值范围是0(灰度)到256(正常色).例如,如果人物色表上的红色分量记作pal_r,那么残影色表上红色分量就是(pal_r + add_r) * mul_r / 256 + add2_r,假定palcolor和palinvert保留默认值.
palcolor有效值为0-256,palbright和palpostbright的分量有效值为0-255,palcontrast分量的取值为非负整数.

默认值为:
palcolor = 256
palinvertall = 0
palbright = 30,30,30
palcontrast = 120,120,220
palpostbright = 0,0,0

paladd = add_r, add_g, add_b (整型)
见下方.

palmul = mul_r, mul_g, mul_b (浮点型)
这些参数指定了多次应用到残影连续画面的色表效果.
在一个色表效果的应用中,首先paladd分量被加到残影的色表上,然后此分量乘以palmul的分量.
这些效果应用方式如下：
最新的残影画面没有效果,第2新的残影画面应用1次,第3新的残影画面应用2次,等等.
paladd分量有效值为0-255,palmul乘数有效值为任何非负浮点数.

默认值为:
paladd = 10,10,25
palmul = .65,.65,.75

timegap = value (整型)
保存玩家画面至历史缓存区并作为残影显示 此过程中跳过的画面数.
默认值是1(不跳过任何画面).
如果每3幅画面保存一次(举个例子),你将使用timegap = 3.

framegap = value (整型)
历史缓存区中每value幅画面将被当成残影显示.
例如,如果framegap = 4(默认值),则第1幅,第5幅,第9幅...历史缓存区中的画面将被当做残影显示.

trans = type (字符串型)
指定残影的透明模式.有效值类型为"none"(不透明),"add","add1","sub".默认为"none" (详见trans控制器)

示例:
无


AfterImageTime

改变玩家残影效果的持续时间,如果当前有此效果.
如果当前没有残影效果,此控制器无效.
已经得知的bug: 如果原来的AfterImage控制器中timegap参数没有被设置成1,AfterImageTime将引起画面位置被重置.

必要参数:
time = new_duration (整型)
设置残影在被移除前显示的新的帧数.
一般设置time=0去除残影效果.

代替语法:
value = new_duration (整型)

可选参数:
无

示例:
无


AllPalFX

与PalFX相似,只是AllPalFX影响背景和血条以及所有人物和爆炸火花的色表.(无论ownpal参数如何设定)
要获得AllPalFX的详情,参看 PalFX 控制器.


AngleAdd

用于AngleDraw控制器,增加绘制的角度.

必要参数:
value = add_angle (浮点型)
add_angle必须以角度形式给出.

可选参数:
无

示例:
无


AngleDraw

通过AngleSet控制器绘制玩家(1幅画面)通过自身轴心设置的角度旋转.
面向右方时,正值表示逆时针方向.

必要参数:
无

可选参数:
value = angle (浮点型)
设置绘制的角度(角度制表示)

scale = xscale, yscale (浮点型,浮点型)
缩放player的sprite(子画面).

注意:
旋转/缩放不会影响player的碰撞块(即红框和蓝框).

在mugen1.1中,屏幕缩放会影响该缩放值: 即相同的scale在不同的屏幕缩放时,最终显示大小会有不同.

示例:
无


AngleMul

用于AngleDraw控制器绘制的旋转角度乘以指定因数.

必要参数:
value = angle_multiplier (浮点型)
绘制的角度乘以angle_multiplier.

可选参数:
无

示例:
无


AngleSet

设置用于AngleDraw控制器中绘制的旋转角度.角度的初始化值为0.

假设人物面向右方,设置的角度为正值将以逆时针方向进行旋转,负值为顺时针方向(第一象限x轴右方向为0度).

此控制器设置角度之后,必须调用AngleDraw控制器才能实际生效(AngleDraw控制器中也能重新设置旋转角度).

必要参数:
value = angle (浮点型)
角度值必须用角度制表示.

可选参数:
无

示例:
无


AppendToClipboard

此控制器与DisplayToClipboard相似,只是另起新的一行而不是覆盖剪贴板上已经存在的文字.
查看 DisplayToClipboard 获得更多的信息.

通常作Debug用,但也可以用来显示作者自定义信息.


AssertSpecial

此控制器此允许你同时断言3个特殊的标示.
因为MUGEN会在每个游戏帧内自动撤销这些断言,所以如果想让他在一段时间内被激活,你必须在这段时间内每帧都断言.

必要参数:
flag = flag_name
flag_name是需要断言的指定字符串标示.

可选参数:
flag2 = flag2_name
一个可选的断言标示.

flag3 = flag3_name
另一个可选的断言标示.

详情:
标示名可以是以下的一种:

intro
告诉MUGEN人物正在表演开场姿势.开场时(该标示)必须每帧都被断言.

invisible
断言后人物变的不可见.不会影响显示的残影.

roundnotover
告诉MUGEN人物正在表演胜利姿势.胜利时(此标示)每帧都该被断言.

nobardisplay
当断言后,血条,能量条等等将不被显示.

noBG
关闭背景,屏幕被清黑.

noFG
无法显示舞台的1号图层.

nostandguard
断言期间,人物将不能站立防御.

nocrouchguard
断言期间,人物将不能蹲下防御.

noairguard
断言期间,人物将不能空中防御.

noautoturn
断言期间,阻止人物自动转向对手.

nojugglecheck
断言期间,juggle(连击数)将不会被检测.无论连击点数是多少,P2都能被连击.

nokosnd
阻止已被击败的玩家播放11,0号声音(被KO的声音).
对于拥有KO回声设定的玩家来说,为了压制住各种回声效果,nokosnd必须在玩家被KO之后断言大于等于50个帧数.

nokoslow
断言期间,阻止MUGEN用慢动作显示一局的结束.

noko
断言期间,阻止人物死亡.（Alive不变0,回合不结束,但是TU时还是会出胜负判定,用超即死很容易突破.）

noshadow
断言期间,将无法显示玩家的影子.

globalnoshadow
断言期间,所有玩家,helper,explod都不能显示影子.

nomusic
断言期间,停止播放背景音乐.

nowalk
断言期间,player不能进入行走状态,即使受控制.用于防止跑动状态取消为行走.

timerfreeze
断言期间,阻止回合的倒计时.用于阻止回合的TimeOver(时间终了).

unguardable
任何断言中玩家的Hitdef变得不可防御.即,他们的guardflag被忽略.

示例:
无


AttackDist

改变玩家当前HitDef中guard.dist参数值.
guard.dist是到P1的X方向距离,在此距离中如果P2控制远离P1的方向则P2将进入防御状态.
guard.dist的效果仅当P1的movetype = A时才体现出来.

必要参数:
value = guard_dist (整型)
新的防御距离,单位是像素.

可选参数:
无

示例:
无


AttackMulSet

设置玩家的攻击系数.玩家的任何伤害值都会按此系数缩放.

必要参数:
value = attack_mul (浮点型)
指定所需的乘数.例如,attack_mul设置为2表示2倍伤害值.

可选参数:
无

示例:
无


BGPalFX

与PalFX相同,只是BGPalFX影响背景和血条的色表而不是人物的色表.
要获得BGPalFX的详情,参看 PalFX 控制器.


BindToParent

如果玩家是一个helper,将这个玩家绑定到相对于他父级(上一级)的指定位置.
如果这个玩家不是helper,此控制器无效.

必要参数:
无

可选参数:
time = bind_time (整型)
指定绑定的有效时间帧数.默认为1.

facing = facing_flag (整型)
如果facing_flag是-1,在绑定期间使玩家总是朝着父级相反的方向.
如果facing_flag是1,在绑定期间使玩家总是朝着父级相同的方向.
如果facing_flag是0,在绑定期间无论父级的朝向如何玩家不会转向.默认为0.

pos = pos_x (浮点型), pos_y (浮点型)
pos_x和pos_y指定绑定的偏移量(距离父级的坐标轴).默认为0,0.

注意:
如果player的父级被销毁了(例如,如果父级是helper,且执行了DestroySelf),则BindToParent的效果将被终止.

示例:
无


BindToRoot

如果玩家是一个helper,将这个玩家绑定到相对于他的根级(最顶级)的指定位置.
如果这个玩家不是helper,此控制器无效.

必要参数:
无

可选参数:
time = bind_time (整型)
指定绑定的有效时间帧数.默认为1.

facing = facing_flag (整型)
如果facing_flag是-1,在绑定期间使玩家总是朝着根级相反的方向.
如果facing_flag是1,在绑定期间使玩家总是朝着根级相同的方向.
如果facing_flag是0,在绑定期间无论根级的朝向如何玩家不会转向.默认为0.

pos = pos_x (浮点型), pos_y (浮点型)
pos_x和pos_y指定绑定的偏移量(距离根级的坐标轴).默认为0,0.

注意:
如果玩家的根级被销毁了(例如,如果他是helper,且执行了DestroySelf),则BindToRoot的效果将被终止.

示例:
无


BindToTarget

把玩家绑定到相对于指定目标的指定位置.

必要参数:
无

可选参数:
time = bind_time (整型)
指定绑定的有效时间帧数.默认为1.

ID = bind_id (整型)
指定要绑定的目标ID号.默认为-1(选择任何目标).

pos = pos_x (浮点型), pos_y (浮点型), postype (字符串型)
pos_x和pos_y指定绑定的偏移量(距离绑定点).默认为0,0.
绑定点默认为目标的坐标轴心.
如果"postype"是"Foot",则绑定点是目标的坐标轴心.
如果"postype"是"Mid",则绑定点是目标的中段.
如果"postype"是"Head",则绑定点是目标的头部.
对于后2种情况,绑定点由目标人物CNS文件中head.pos和mid.pos参数值决定.
绑定点不保证正好与目标头部或者中段位置相匹配.

示例:
无

注:
TargetBind是把目标绑定到你身上,BindToTarget是把你绑定到目标身上.


ChangeAnim

改变玩家动作号.

必要参数:
value = anim_no (整型)
anim_no是要改变的动作号.

可选参数:
elem = elem_no (整型)
elem_no是指定开始动画的元素号.

示例:
无

请参阅: AnimExist, ChangeAnim2.


ChangeAnim2

和 ChangeAnim 一样,只是此控制器应用在如下的情况中:
如果你已置P2于一个自定义状态且希望把P2的动作改为P1指定air文件中的动作.
例如,当制作投掷动作时,使用此控制器来改变P2被投掷的动画.

实际应用中,常出现的问题是: P1的air文件中定义的图片编号,在P2的Sff文件中并不存在相应实际图片,将会导致P2变成空白(消失了)的状态.
要解决该问题,可以把所有人物Sff补齐相应编号的受击图片. 如嫌麻烦,可以使用以下代码:

[State ]
type = ChangeAnim2
Trigger1 = Time = 0
Trigger1 = SelfAnimExist(1320) ;p2的air编号存在才进行设置
value = 1320

[State ]
type = ChangeAnim
Trigger1 = time = 0
Trigger1 = !SelfAnimExist(1320) ;p2的air编号不存在,使用通用的受击动画
value = 5000

请参阅: SelfAnimExist.


ChangeState

改变玩家的状态号.

必要参数:
value = state_no (整型)
state_no是改变为的状态号.

可选参数:
ctrl = ctrl_flag (整型)
ctrl_flag设置玩家是否受控制.0表示不受控制,非0表示受控制.

anim = anim_no (整型)
切换的动作号.如果省略,玩家的动画将不变.

示例:
;转换为站立姿势,且使玩家受控制.
type = ChangeState
value = 0
ctrl = 1


ClearClipboard

清除玩家当前剪贴板上任何文字.

必要参数:
无

可选参数:
无

示例:
无

参阅: DisplayToClipboard AppendToClipboard


CtrlSet

设置玩家的控制标示.

必要参数:
value = ctrl_flag (整型)
非0表示受控制,0表示不受控制.

可选参数:
无

示例:
无


DefenceMulSet

设置玩家的防御系数.玩家受到的所有伤害将会按此系数缩放.

必要参数:
value = defense_mul (浮点型)
指定的防御系数.

可选参数:
无

注意:
LifeAdd控制器不会被玩家的防御系数影响.

示例:
;玩家受到的所有伤害减半.
type = DefenceMulSet
value = .5


DestroySelf

如果(此控制器)被helper类型人物调用,DestroySelf将导致此人物从游戏画面中被移除.
DestroySelf对非helper人物无效.

必要参数:
无

可选参数:
recursive = recursive_flag (int)
若值为1,此helper派生出的所有helper将同时被销毁.默认为0.

removeexplods = remove_explods (int)
若值为1,所有属于此helper的explod也将被移除.
若recursive_flag值为1,派生出的所有helper的explod也将被移除.默认为0

注意:
任何束缚于此helper的玩家或explod,在DestroySelf执行时将强制解除束缚.
任何此helper没有被移除的explod都会被孤立.

示例:
无


DisplayToClipboard

此控制器仅用于调试.
DisplayToClipboard清空玩家的剪贴板,打印出指定信息.
在调试模式中能够显示出玩家的剪贴板(按Ctrl+D).

必要参数:
text = "format_string"
format_string必须写在双引号里面.
format_string是一个printf格式字符串型,所以如果你对printf了解,你可以跳过这段描述.
此格式字符串包含了任何你想要显示的文字.
你也可以使用 \n 生成一个换行符, \t 生成一个tab字符(tab的宽度等于4个字符宽度).
如要显示一个算术表达式的值,你得放入 %d(显示整型) 或者 %f(显示浮点型) 格式字符串,然后在参数列表中指定表达式.
如要显示 % 字符,你必须放入 %% 格式字符串.

只有指定的有符号整数和浮点型格式被接受:
%d(有符号十进制整数)
%i(同%d)
%f(浮点数,十进制记数法)
%F(貌似什么也不显示)
%e(用科学计数法表示的浮点数)
%E(同%e)
%g(浮点数,不显示无意义的0)
%G(基本同%g)
不支持长修饰格式.(例如,%lld)
认可的转义字符为 \n(换行符),\t(水平制表符 Tab键),\\(反斜杠字符)和\"(双引号字符).

可选参数:
params = exp_1, exp_2, exp_3, exp_4, exp_5, exp_6
最多指定6个格式字符串作为数值参数. (如超过6个数值, 请使用 AppendToClipboard)
这些应该被整齐的列在params项目之下.
每个参数的格式必须与指定格式相匹配.
你不能指定多于或者少于被调用的格式字符串参数.

如果指定格式和实际提供的参数不匹配,则实际参数的值将以适当(对那种类型来说)格式显示出来,使用默认的格式化选项.

示例:
[state ]
type = DisplayToClipboard
trigger1 = 1
text="The value of var(17) is %d, which is %f%% of 23.\n\t--Kiwi."
params = var(17):=1,var(17)/.230
;":="为赋值运算符,直接将值赋给var参数,如果类型不一样,将强制转换后再赋值.

下列信息将会显示在玩家的剪贴板上(按Ctrl+D切换显示):
The value of var(17) is 1, which is 4.347826% of 23.
--Kiwi.

注:
通常作Debug用,但也可以用来显示作者自定义信息.


EnvColor

将整个屏幕变为一种纯色,前景层中打击火花和设置了"ontop"参数的explod除外.
舞台的前景层将不可见.

必要参数:
无

可选参数:
value = col_r, col_g, col_b (整型)
指定要将屏幕设置成某种颜色的R,G,B数值分量.
每个数值应该是一个0-255之间的整数.数字越大,环境色中此成分的颜色将会越多.
默认值为255,255,255.(纯白)

time = effective_time (整型)
指定环境色将被显示的时间帧数.
默认为1帧.设置-1则EnvColor将永久持续.

under = under_flag (int)
设置under_flag为1使得环境色在人物和飞行道具下面绘制.
换句话说,人物和飞行道具在着色背景上将可见.
(也就是说EnvColor的效果将在所有人物和飞行道具的下层而不会遮挡人物和飞行道具的显示.)
默认为0.

示例:
无


EnvShake

引起屏幕垂直的震动.

必要参数:
time = shake_time (整型)
指定屏幕将要震动的时间帧数.

可选参数:
freq = shake_speed (浮点型)
shake_speed是一个0(缓慢的)到180(快速的)的浮点数.默认为60.

ampl = shake_amplitude (整型)
振幅越大,屏幕上下震动的越远.
振幅为负数意味着屏幕将首先向下震动.
默认值是-4(在240p设定下),-8(在480p设定下),-16(在720p设定下).

phase = phase_offset (浮点型)
指定震动的相位偏移.默认为0.
频率乘数大于等于90时,默认相位偏移是90.

示例:
无


Explod

Explod(一般称为爆炸火花)控制器是显示诸如火花,尘土以及其他视觉效果动画的灵活工具.
它的功能包含了目前不推荐使用的GameMakeAnim控制器.

必要参数:
anim = [F]anim_no (整型)
anim_no指定要播放的动画号.
前缀'F'是可选的:如果包含了'F',则动画将从fightfx.air中播放.例如:anim=F60

可选参数:
ID = id_no (整型)
id_no指定了此explod的ID号.
用于识别在触发器和控制器中的特殊explod.

space = space (字符串型)
指定创建explod的坐标空间.space的有效值为:

  • screen
    此坐标空间映射到屏幕.
    左上角是0,0右下角是ScreenWidth,ScreenHeight(参见触发器).
    通过此空间创建的explod将不会受到视角移动或缩放的影响.
  • stage
    此坐标空间映射到舞台空间.
    坐标0,0舞台地平线的中间.
    通过此空间创建的explod将会受到视角移动或缩放的影响.此为默认值.

pos = off_x, off_y (整型,整型)
如果explod未被束缚,off_x和off_y指定创建explod的位置.
如果explod被束缚,off_x和off_y指定到束缚点的偏移量.

facing = facing (整型)
设置facing为1使得explod与正的off_x朝向一样,-1使得explod朝向相反.默认为1.

vfacing = vfacing (整型)
设置vfacing为-1使explod显示时垂直翻转,1表示显示的时候不翻转.默认为1.

bindID = bind_id (整型)
玩家或helper绑定的ID号.被束缚的explod位置相对于他要束缚的物体.
指定-1(绑定到任何单独玩家)和-2(不绑定).默认是-2.
如果bindID不是-2则需要给出bindtime参数.Screen空间的explod不能被束缚.

bindtime = bind_time (整型)
指定explod被束缚持续的游戏帧数.bindtime过期后,explod将不再被束缚在这个绑定点,且将保持他的位置(除非被vel或accel参数影响).
如果bindtime为-1,则explod将一直被束缚直到此explod被移除或者另一个控制器影响了bindtime.

vel = x_vel, y_vel (浮点型, 浮点型)
指定explod初始的X和Y分量的速度.这些被解释为相对于explod的"facing"方向.
若省略则默认为0.

accel = x_accel, y_accel (浮点型, 浮点型)
指定explod初始的X和Y分量的加速度.默认为0.

removetime = rem_time (整型)
如果rem_time是正数,explod将在被显示rem_time帧数后被移除.
如果rem_time是-1,explod将被永久显示.
如果rem_time是-2,explod将在animtime到达0时移除.
默认为-2.

supermovetime = move_time (整型)
指定explod在SuperPause中将不被冻结的帧数.
当在SuperPause中想让explod做动画的时候使用,例如自定义的超级火花.
默认为0.

pausemovetime = move_time (整型)
指定explod在Pause中将不被冻结的帧数.默认为0.

scale = x_scale, y_scale (浮点型, 浮点型)
x_scale和y_scale指定用于explod水平和垂直方向的缩放因数.
如果省略则都默认为1.(不缩放)

sprpriority = pr (整型)
pr指定explod的绘制优先级.更高优先级的动画将绘制在较低优先级的动画上方.
例如,设置sprpriority = -3时将使explod绘制在大多数人物和其他explod下方.大多数人物和explod的sprpriority都大于等于-2.
若省略,则默认为0.

angle = angle (浮点型)
angle指定explod绘制的角度.默认为0.

yangle = y_angle (浮点型)
y_angle指定绘制出explod绕y轴旋转的角度.默认为0.

xangle = x_angle (浮点型)
x_angle指定绘制出explod绕x轴旋转的角度.默认为0.

ontop = bvalue (布尔型)
设置 ontop = 1 使得explod绘制在所有图片层和背景层的上方.
此参数优先于sprpriority.默认为0.

shadow = shadow (整型)
如果shadow不为0,将绘制阴影,否则不会.默认为0.

ownpal = ownpal_flag (布尔型)
如果ownpal_flag为0,explod颜色将被随后执行的PalFX和RemapPal控制器影响.通常情况下这是默认值.
如果ownpal_flag为1,explod颜色将不会被随后执行的PalFX和RemapPal控制器影响.如果是从fightfx.air播放动画的,这是默认值.

remappal = dst_pal_grp, dst_pal_item (整型, 整型)
强制色表从explod索引颜色图像重映射到指定的色表.
此参数仅当ownpal_flag为非0且没有使用fight.def中的动画时有效.
如果dst_pal_grp是-1,此参数将被忽略.默认-1,0.

removeongethit = bvalue (布尔型)
此值设置成1时如果玩家受到攻击将使explod被移除.默认为0.

ignorehitpause = bvalue (布尔型)
如果此值为1,explod将独立于创建它的玩家而播放动画.
如果设置成0,在玩家进入hitpause状态的时候explod将不会被更新.默认为1.

trans = trans_type (字符串型)
覆盖explod动画的透明度设定.查看Trans控制器获得详情.
如果trans_type是"addalpha"则"alpha"参数必须被指定.若省略,什么也不做.

废弃参数:
postype = postype_string (字符串型)
postype_string指定如何解释pos(位置)参数.在所有情况下,正的off_y表示向下位移.
下面是有效的postype_string值:

  • p1
    说明了相对于P1坐标轴的位置.正的off_x朝向P1的前方.这是mugen1.0和1.0以下的postype默认值.
    参照此控制器最后的"注意"描述.
    该类型Anim的大小,位置,速度均为屏幕绝对空间.
  • p2
    说明了相对于P2坐标轴的位置.正的off_x朝向P2的前方.
    该类型Anim的大小,位置,速度均为屏幕绝对空间.
  • front
    说明了off_x相对于P1朝向的屏幕边缘,off_y相对于屏幕顶端.
    正的off_x朝向屏幕的右方,而负的off_x朝向左.
    该类型Anim的大小,位置,速度均为人物def中定义的localcoord坐标相对位置而言.
  • back
    说明了off_x相对于P1背朝向的屏幕边缘,off_y相对于屏幕顶端.
    正的off_x朝向屏幕的中心,而负的off_x远离中心.
    由于历史原因,偏移量的特征与postype = front不相符.
    该类型Anim的大小,位置,速度均为人物def中定义的localcoord坐标相对位置而言.
  • left
    说明了off_x和off_y是相对于屏幕的左上角.
    正的off_x朝向屏幕的右方,负的off_x向屏幕左侧之外移动.
    该类型Anim的大小,位置,速度均为人物def中定义的localcoord坐标相对位置而言.
  • right
    说明了off_x和off_y是相对于屏幕的右上角.
    正的off_x向屏幕右方移动(屏幕右侧之外),负的off_x朝向屏幕的左方.
    该类型Anim的大小,位置,速度均为人物def中定义的localcoord坐标相对位置而言.
  • none
    说明了off_x和off_y绝对位置.这是mugen1.1和1.1以上的postype默认值.

使用postype中的p1或p2将在舞台空间创建一个explod.
使用front,back,left,right将在屏幕空间创建一个explod.

postype参数在1.1版本中被废弃,他的功能被space和bindID参数的组合以及ScreenWidth,ScreenHeight和测定边界的触发器取代.

1.1版本中,可替代postype的参数为:

  • postype = p1
    space = stage
    pos = Pos X + CameraPos X, Pos Y
    facing = facing
  • postype = p2
    space = stage
    pos = (enemynear, Pos X) + CameraPos X, (enemynear, Pos Y)
    facing = enemynear, facing
  • postype = front
    space = screen
    pos = ifelse(facing = -1, 0, ScreenWidth), 0
    facing = 1
  • postype = back
    space = screen
    pos = ifelse(facing = 1, 0, ScreenWidth), 0
    facing = facing
  • postype = left
    space = screen
    pos = 0, 0
    facing = 1
  • postype = right
    space = screen
    pos = ScreenWidth, 0
    facing = 1

注: 在1.1版本中的实际操作中,如果没有定义space和bindID参数的组合,如果有postype参数仍然会生效,但需要注意使用pos,scale和bindtime搭配出效果.

random = rand_x, rand_y (整型, 整型)
使得explod的绑定点创建时被一个随机数取代.
rand_x指定x方向的替代范围,rand_y指定y方向的替代范围.
例如,如果pos = 0,0和random = 40,80,则explod的x方向位置将是-20到19的一个随机数,y方向位置将是-40到39的一个随机数.
如果省略则这2个参数都为0.

supermove = bvalue (布尔型)
此参数不推荐使用 -- 请使用supermovetime来代替.
设置supermove = 1使得explod一直持续直到超级暂停结束,无论removetime如何设置.
默认为0.

注意:
一个束缚于玩家的explod的位置仅当所有玩家完成更新后才被决定.
(对比helper,当控制器被执行时,helper是相对于玩家的即时位置被创建的)
此特征对explod正确绑定到玩家的屏幕位置是必要的.

例如,假定玩家的位置是(160,0),x方向速度为5.
如果一个相对于P1偏移量为0,0的explod被创建,则此explod实际屏幕位置将是165,0.


ExplodBindTime

改变玩家的explod位置绑定时间.

必要参数:
无

可选参数:
ID = id_no (整型)
仅当explod拥有的ID号等于id_no时才能影响他们的位置绑定.
设置ID为-1来影响所有的explod.
默认值为-1.

time = binding_time (整型)
指定explod应该被约束到绑定点的时间帧数.(explod被创建时定义)
默认为1帧.time为-1时explod将被永久绑定或者直到另外的控制器改变绑定时间.

替代语法:
value = binding_time
也许可以用来代替time = binding_time.

示例:
无


FallEnvShake

使用攻击中设定的fall.envshake参数(详见HitDef控制器)使屏幕震动.
此控制器仅当GetHitVar(fall.envshake.time)不为0的时候才有效,且被执行后将GetHitVar(fall.envshake.time)设置为0.
此控制器被用于common1.cns中当一个玩家落地时使屏幕震动,其他没什么用.

必要参数:
无

可选参数:
无

示例:
见common1.cns.


ForceFeedback

为支持的力反馈装置创建力反馈.
此控制器在MUGEN1.0中未能实现.
ForceFeedback控制器中的参数也许不能用算术表达式来指定.
关于这方面是个例外.

必要参数:
无

可选参数:
waveform = wave_type (字符串型)
有效的waveform(波形)是"sine(正弦波)","square(方波)","sinesquare(正弦方波？)",和"off".
对双震动控制器(手柄)来说,一个正弦波对应着马达发出大型隆隆声,一个方波对应着马达发出小的蜂鸣声.
当然,正弦方波同时对应着2个马达.使用"off"来关闭目前存在的任何力反馈.waveform默认是sine.

time = duration (整型常量)
指定力反馈将持续多少时间,用帧数表示.默认为60.

freq = start (整型常量), d1, d2, d3 (浮点型常量)
力反馈的频率在0-255之间变化.
决定力反馈频率的公式是:start + d1 * t + d2 * t ** 2 + d3 * t ** 3
这里的t代表从力反馈被启动时逝去的时间帧数.
默认 freq = 128,0,0,0.目前来说,频率参数被完全忽略.

ampl = start (整型常量), d1, d2, d3 (浮点型常量)
力反馈的振幅在0-255之间变化.
决定力反馈频率的公式是:start + d1 * t + d2 * t ** 2 + d3 * t ** 3
这里的t代表从力反馈被启动时逝去的时间帧数.
默认 ampl = 128,0,0,0.

self = self_flag (布尔型常量)
如果self_flag是1,则P1的pad(应该指的是joypad游戏手柄)将震动.
如果是0,则P2的手柄将震动.默认是1.

示例:
见common1.cns.


GameMakeAnim

创建一个游戏动画,比如一个打击火花或者一个超级冲击效果.
此控制器已被Explod取代且目前正考虑废弃.
在未来的版本中也许不会再支持它.
注:该动画缩放(scale)为1(不缩放).且在mugen1.1中可能显示位置不正确.

必要参数:
无

可选参数:
value = anim_no (整型)
指定要播放的动画号(从fightfx.air中).默认是0.

under = under_flag (整型)
如果under_flag是1,动画将绘制在人物图层下方.默认是0.(绘制在人物上方)

pos = x_pos, y_pos (浮点型)
指定动画被显示的位置,相对于玩家的坐标轴.默认是0,0.

random = rand_amt (整型)
动画的位置将被x和y方向的(不同)随机数替代.
这种替换和rand_amt的一半一样大.(可能指的是:如果pos = 0,0;random = 10,则动画实际出现的x和y位置均在-5~5之内)
默认是0.

示例:
无


Gravity

使用玩家的"yaccel"常量值加速玩家下降.

必要参数:
无

可选参数:
无

示例:
; 整个状态中提供加速度常量.
trigger1 = 1
type = Gravity


Helper

创建玩家的另一个实例作为一个helper(援助)人物.

必要参数:
无

可选参数:
helpertype = type_string (字符串型)
不推荐使用此参数,不支持使用player型的helper.
如果helpertype = normal,则helper将被允许离开(走出)屏幕.
此外,摄像机将不会因为要使helper停留在画面内而移动.(也就是说摄像机不会跟着helper走)
如果helpertype = player,则helper将被约束在屏幕内且摄像机将跟随他移动,就像普通玩家一样.默认是normal.
如果你想用helper来操纵摄像机,不要使用player型的helper.
使用设置了"movecamera"参数的ScreenBound控制器可以代替.

name = "name_string" (字符串型)
指定helper的名字,必须写在双引号里面.
如果省略,此名字默认是"<parent>'s helper",这里的<parent>代表创建此helper的玩家的名字.

ID = id_no (整型)
设置此helper的ID号.默认是0.

pos = off_x, off_y (整型)
指定这个helper将要被创建的位置.(x和y方向偏移量)
这些参数的准确意义得依赖于postype.默认是0,0.

postype = postype_string (字符串型)
postype_string指定postype -- 如何解读pos参数.
所有情况下,一个正的y偏移量意味着向下的位移.
所有情况下,off_y是相对于玩家位置而言的.

下面是有效的postype_string值:

  • p1
    说明了相对于P1坐标轴的位置.正的off_x朝向P1的前方.这是postype默认值.
    该类型自身Anim的大小,位置,速度均为屏幕绝对空间.
  • p2
    说明了相对于P2坐标轴的位置.正的off_x朝向P2的前方.
    如果P2不存在,位置的计算是和P1有关的且会记录一次警告.
    该类型自身Anim的大小,位置,速度均为屏幕绝对空间.
  • front
    说明了off_x相对于P1朝向的屏幕边缘.(p1朝向右边时,x=0为屏幕右边缘)
    正的off_x远离屏幕的中心,而负的off_x朝向中心.
    y=0时与地平面相同位置.负值向上移动.
    该类型自身Anim的大小,位置,速度均为屏幕绝对空间.
  • back
    说明了off_x相对于P1背向的屏幕边缘.(p1朝向右边时,x=0为屏幕左边缘)
    正的off_x朝向屏幕的中心,而负的off_x远离中心.
    y=0时与地平面相同位置.负值向上移动.
    该类型自身Anim的大小,位置,速度均为屏幕绝对空间.
  • left
    说明了off_x相对于屏幕的左边缘.(无论p1朝向哪边,x=0为屏幕左边缘)
    正的off_x朝向屏幕右方.负值off_x向屏幕左边(屏幕左侧之外)移动.
    y=0时与地平面相同位置.负值向上移动.
    该类型自身Anim的大小,位置为屏幕绝对空间.速度为人物def中定义的localcoord坐标相对坐标位置而言.
  • right
    说明了off_x相对于屏幕的右边缘.(无论p1朝向哪边,x=0为屏幕右边缘)
    正的off_x朝向屏幕左方.负值off_x向屏幕右边(屏幕右侧之外)移动.
    y=0时与地平面相同位置.负值向上移动.
    该类型自身Anim的大小,位置为屏幕绝对空间.速度为人物def中定义的localcoord坐标相对坐标位置而言.

facing = facing (整型)
如果postype是left或者right,设置facing为1将使helper朝右,值为-1使helper朝左.
除了P2以外的其他postype值,如果facing是1,helper的朝向将和玩家一样.如果是-1,则与玩家朝向相反.
postype = p2这种情况下,facing的效果和上面一样,只是和P2的朝向有关而不是P1.默认是1.

stateno = start_state (整型)
确定helper的初始状态号.默认为0.
([StateDef 0]一般是人物默认站立姿势,所以有时候对战时发现会突然多个人出来,就要检查一下是不是哪里创建了helper但是没有指定stateno.
或者是创建了意料之外的helper而没有销毁. )

keyctrl = ctrl_flag (布尔型)
如果ctrl_flag是1,则helper能够接受玩家输入的指令.(例如键盘,手柄)
同样,此helper将继承他根级(最顶级)的state -1.
如果ctrl_flag是0,则helper不能访问输入的指令,且不能继承 state -1.
如果ctrl_flag是1,helpertype=player类型将会执行state -1,state -2,state -3,而normal类型只会执行state -1.请注意相关变量在这些状态中的赋值和读取,变量前加上【helper(ID),】防止与root(人物本体)产生混淆.
ctrl_flag默认值为0.

ownpal = ownpal_flag (布尔型)
如果ownpal_flag是0,helper将受父级PalFX和RemapPal控制器影响.此为默认值.
如果ownpal_flag是1,helper将有自己暂时的色表,独立于他的父级.

remappal = dst_pal_grp, dst_pal_item (整型, 整型)
强制色表从helper索引颜色图像重映射到指定的色表.
此参数仅当ownpal_flag为非0时有效.
如果dst_pal_grp是-1,此参数将被忽略.默认-1,0.

supermovetime = move_time (整型)
指定helper在SuperPause中不被冻结住的帧数.默认为0.

pausemovetime = move_time (整型)
指定helper在Pause中不被冻结住的帧数.默认为0.

size.xscale (浮点型)
如果未设置,默认为人物[Size]参数中的xscale值.设置之后将替换为新值.该值为屏幕绝对空间大小比例.
见下方.

size.yscale (浮点型)
如果未设置,默认为人物[Size]参数中的yscale值.设置之后将替换为新值.该值为屏幕绝对空间大小比例.
见下方.

size.ground.back (整型)
见下方.

size.ground.front (整型)
见下方.

size.air.back (整型)
见下方.

size.air.front (整型)
见下方.

size.height (整型)
见下方.

size.proj.doscale (整型)
见下方.

size.head.pos (整型,整型)
见下方.

size.mid.pos (整型,整型)
见下方.

size.shadowoffset (整型)
这些参数与根级CNS文件相应参数意义相同.
你能指定某几个参数将它们的值改变成适合helper的数值.
否则,它们将从父级继承默认值.

示例:
无

另: 如需动态改变Helper的大小和显示角度等,请参阅 AngleDraw

请注意在创建Helper时使用size.xscale和size.yscale,以及在Helper内使用AngleDraw等方式改变大小后,动画的攻击和防御框大小均不会自动进行缩放! (即air中定义的CLSN1和CLSN2不会自动缩放,需手动进行调整.)


HitAdd

增加当前连击数。

必要参数:
value = add_count (整型)
add_count指定增加到当前连击上的打击数字。

可选参数:
无

示例:
无


HitBy

临时指定允许击中玩家的攻击类型.

必要参数:
value = attr_string 或者 value2 = attr_string
上面的参数只有1种能被指定.
attr_string应该是一个标准的攻击属性字符串.见详情.

可选参数:
time = effective_time (整型)
指定HitBy属性有效的时间帧数.默认为1.

详情:
在HitBy控制器中,玩家有2个能被设定且运用的攻击属性槽value 或 value2.这些属性槽也能被NotHitBy控制器设定.
当设置了一个属性槽,便会获得一个计时器(有效的时间),此计时器会朝0倒计时.
计时到0之前属性槽被认为是激活的.
仅当Hitdef的(attr)属性出现在当前所有激活的属性槽中,玩家才能被此HitDef击中.
使用HitBy控制器设置指定的属性槽包含仅那些出现在HitBy属性字符串中的攻击属性.

HitBy同时也与HitDef的attr参数遥相呼应. 请参阅 HitDef

示例:
; 仅能被站立普通攻击击中.
trigger1 = 1
type = HitBy
value = S, NA


HitDef

定义玩家攻击中的单个hit(属性).
如果玩家的Clsn1框(即红框/攻击框)与对手的Clsn2框(即兰框/受击框)接触,且HitDef被定义在这个特定时间点或之前,则将应用指定的效果.
这是一个较复杂的,但是最常用的控制器.单个HitDef仅对单个hit有效.
要使一个招式产生多次hit,你必须在攻击中触发多个HitDef.

必要参数:
attr = hit_attribute (字符串型)
这是攻击的属性.用来确定是否攻击可以击中P2.格式为:
attr = arg1, arg2
这里:arg1是"S","C","A"任意组合(Stand Crouch Air). 类似于 StateDef 中的 StateType ,这里说明攻击类型为站立(S),蹲下(C)或者空中(A).
arg2是由2个字符组成的字符串.首字符是"N"(Normal普通),"S"(Special特殊),"H"(Hyper超级),"A"(普通+特殊+超级)中的一个.
第2个字符必须是"A"(Attack直接攻击),"T"(Throw投掷),"P"(Projectile飞行道具)中一个.

触发器HitDefAttr 检测的也正是这个值.该参数同时也与HitBy、NotHitBy遥相呼应.
它的格式和HitBy一样,例如:
SCA, AA,AT,AP （即 SCA,NA,SA,HA,NP,SP,HP,NT,ST,HT）

可选参数:
hitflag = hit_flags (字符串型)
此参数说明如果P1要击中P2,则P2必须处于的状态类型.
hit_flags是一个包含了下列组合的字符串（可选值 HLAFDP+-）:

"H"(上段),"L"(下段),"A"(空中).
"M"(中段)等于"HL".
"F"作用于下落状态,如果包含了"F"将允许P1对处于空中下落状态的对手进行连击.
"D"作用于"躺下"的时候,如果包含了"D"将允许P1击中躺在地上的对手.
"P"飞行道具.
"H","L"或"A" (或"M")必须出现在hitflag字符串中.
注意：AF都在空中,但本质不同,挨打movetype=H的空中算F不算A.

"+"和"-"是2个可选字符.
+加号表示该次攻击只能命中"已经挨打的角色".
-减号表示该次攻击只能命中"没有挨打的角色",如普通投.
如果加上了"+",则hit仅在别人处于受击状态时有效.
这也许对chain-moves(招式连击)有用,而将不会对某些对手起作用,这些对手指的是没有被招式连击中第一招击中的对手.
(上面这句话举例子说就是,连招中只有第1招击中了对手,第2招才能击中("+"字符用于此种情况下).
如果第1招没击中,即使第2招动作做出来,且红框与对手兰框接触,也不会判定击中对手(因为此时对手没有处于受击状态))
如果加上了"-",则hit仅在玩家不处于受击状态时有效.
你应该在投掷攻击和其他不想让P1能够连击的招式中使用"-".(KOF98中大部分的慢性投掷技都是这类判定)
"+"和"-"是互斥的,即,不能同时使用.缺省hitflag默认值为"MAF".

guardflag = hit_flags (字符串型)
(感觉guardflag = guard_flags更形象)
此参数决定P2要如何防御住这次攻击.guard_flags是一个包含了下列字符组合的字符串（可选值 MHLA）:
"H"(上段),"L"(下段),"A"(空中)."M"(中段)等于"HL".
还有一个隐含参数 "N"或者不写,表示完全的不可防御.
缺省默认是一个empty(空的)字符串,意味着P2无法防御这次攻击.

PS:hitflag用于在对方【非防御】时决定能否命中,guardflag用于在对方【防御】时决定能否命中.

affectteam = team_type (字符串型)
team_type指定HitDef能击中哪个队伍的玩家.
使用 B 表示2个队伍(所有玩家),E 表示敌方队伍(对手)或者 F 表示友方队伍(你自己的队伍).
默认为E.

animtype = anim_type (字符串型)
指的是当被击中时P2将进入的动画类型.
从"light", "medium", "hard", "back", "up",或 "diagup"中选择.前3个(意思)是不言自明的(受 轻,中,重 攻击).
"Back"是P2被打翻天时的动画."Up"应该在人物笔直向上被打到空中时使用(例如,被上勾拳).
"DiagUp"应被用于人物被打到空中,向后,最终头着地. 默认值是"Light".

air.animtype = anim_type (字符串型)
同"animtype"参数相似,此动画类型设置的是P2在空中而不是地面.
缺省默认值和"animtype"参数相同.

fall.animtype = anim_type (字符串型)
同"animtype"参数相似,此动画类型设置P2在下落时被击中.
如果air.animtype是Up则fall.animtype默认是Up否则是Back.

priority = hit_prior (整型), hit_type (字符串型)
指定hit的优先级(优先顺序).高优先级的hit优先于低优先级的hit.
hit_prior的有效值是1-7,默认是4.

如果指定了hit_type则给出了hit的优先级类别.
有效的优先级类别是Dodge,Hit,Miss.
优先级类别决定了当相同hit优先级的P1和P2相互同时击中对方时的决定性特征.
P1 vs. P2 时的特征如下:

Hit vs. Hit: P1和P2同时击中对方.
Hit vs. Miss: P1击中,P2没击中.
Hit vs. Dodge: 都没击中.
Dodge vs. Dodge: 都没击中.
Dodge vs. Miss: 都没击中.
Miss vs. Miss: 都没击中.
在都没击中的情况下,各自的HitDef仍保持有效.
"Miss" 或 "Dodge" 通常用于投掷,因为这里P1和P2不应该能同时击中对手.
hit_type默认值是"Hit".

damage = hit_damage, guard_damage (整型, 整型)
hit_damage是P2被击中时的伤害值.可选的guard_damage参数是P2防御住攻击时的伤害值.
如果都忽略,则默认为0.

pausetime = p1_pausetime, p2_shaketime (整型, 整型)
这是hit时每个玩家将会停止(停顿)的时间(打击停顿,ignorehitpause就是针对这个参数).
p1_pausetime是冻结P1的时间,单位是游戏帧数.
p2_pausetime是在被击中后退前造成P2震动的时间.
缺省则默认为0,0.

guard.pausetime = p1_pausetime, p2_shaketime (整型, 整型)
同"pausetime"参数相似,如果攻击被防御住,这参数是使每个玩家停止的时间.
缺省默认和"pausetime"参数值相同.

sparkno = action_no (整型)
如果成功击中显示的火花动作号.要播放玩家的.air文件之外的火花(data目录中的FightFX.air和FightFX.sff),在动作号前面加上S,例如"sparkno = S10".
如果火花动作号没有S前缀,则只会播放FightFX.air中的火花.不能加F前缀.
缺省默认为玩家变量中设置的值.(在cns文件[Data]组下面的sparkno)

guard.sparkno = action_no (整型)
如果hit被防御住显示的火花动作号.要播放玩家的.air文件之外的火花(data目录中的FightFX.air和FightFX.sff),在动作号前面加上S.
如果火花动作号没有S前缀,则只会播放FightFX.air中的火花.不能加F前缀.
缺省默认为玩家变量中设置的值.(在cns文件[Data]组下面的guard.sparkno)

sparkxy = spark_x, spark_y (整型, 整型)
这是创建 击中/防御 火花的位置.spark_x是相对于P2前方的坐标值.负值使火花更深入P2内部.
这里说的"前方"指的是P2坐标轴指向P1的x方向偏移量除去P2玩家变量[Size]组中相应的宽度值.
(就是说如果spark_x=0,那这个位置相对于P2就是他的前方(也就是p2[Size]组中ground.front这个位置.)
相对于P1来说就是P1和P2坐标原点的距离减去P2的ground.front,也就是上面说的指向P2的距离减去了P2的宽度参数. )
spark_y相对于P1.负值使火花更高.
你能使用AirView这类工具来测定这些值.(通过将光标放在 "attack spot" 然后读出y方向数值)
缺省默认是0,0.

hitsound = snd_grp, snd_item (整型, 整型)
在hit时播放的声音(从common.snd中).内置的fight.snd可让你选择从5,0(轻击声音)到5,4(痛苦重击).
要从玩家自己的SND文件中播放声音,在第一个数字前加上"S".例如,"hitsound = S1,0".
缺省默认为玩家变量中设置的值.

guardsound = snd_grp, snd_item (整型, 整型)
在hit被防御住时播放的声音(从common.snd中).目前仅有6,0可用.
要从玩家自己的SND文件中播放声音,在第一个数字前加上"S".
没有设备支持从对手的SND文件中播放声音.
缺省默认为玩家变量中设置的值.

ground.type = attack_type (字符串型)
如果P2在地面上的攻击类型.选择如下:
- "High": 攻击使对手头向后移.
- "Low": 击中对手腹部.
- "Trip": 扫腿攻击.(一般蹲下重脚就是这种)
如果使用"Trip"类型,则ground.velocity参数y方向速度应非0,且fall参数应该设置为1.
对手如果被绊倒,将不会通过反弹下落到地面.(也就是说不会落地后弹起再落地)
- "None": 攻击除了在pausetime参数指定的时间内使P1和P2停顿外没有任何效果.
如果P2被从后方攻击,"High"将被当成"Low"显示,反之亦然.
如果AnimType参数是"Back",则P2的"High","Low"类型动画将被替代.
缺省默认是"High".

air.type = attack_type (字符串型)
P2在空中时的攻击种类.缺省默认和"ground.type"的值一样.

ground.slidetime = slide_time (整型)
这是P2被击中后向后滑动的时间(游戏帧数).(这时间不包括p2的pausetime)
应用于使P2保持在地面上的hit.缺省默认为0.

guard.slidetime = slide_time (整型)
同"ground.slidetime"相同,但这个值是P2防御住攻击时的.
默认值和"ground.slidetime"一样.

ground.hittime = hit_time (整型)
P2被击中后停留在受击状态的时间.请小心调整此参数值使得有可能连击.
应用于使P2保持在地面上的hit.缺省默认为0.

guard.hittime = hit_time (整型)
同"ground.hittime"相同,但这个值是P2防御住攻击时的.
默认值和"ground.hittime"一样.

air.hittime = hit_time (整型)
P2被击中(在空中被击中或者击飞致空中,又能防御之前)后停留在hit状态的时间.
如果"fall"参数设置为1则此参数无效.缺省默认为20.

guard.ctrltime = ctrl_time (整型)
P2在地面防御状态中恢复控制之前的时间.
缺省默认为"guard.slidetime"的值.

guard.dist = x_dist (整型)
距P1的x方向距离.在此距离中如果P2向P1反方向运动就会进入防御状态.
缺省默认为玩家变量中设置的值.(在cns文件[Size]组下面)通常你不需要使用这个参数.
(主要用于远程攻击,不设置此参数对手无法防御,因为超出了防御距离
或者用于近程投掷攻击,一般设置guard.dist=0使对手做不出防御动作)

yaccel = accel (浮点型)
击中后给予P2y方向的加速度.默认是0.35(240p),0.7(480p),1.4(720p).

ground.velocity = x_velocity, y_velocity (浮点型, 浮点型)
P2被击中后的初始速度,如果P2在地面上.如果y_velocity非0,P2将被打致空中.
缺省默认都是0.如果想让P2保持在地面上你可以缺省y_velocity.

guard.velocity = x_velocity (浮点型)
给予P2的速度,如果P2在地面上防御住了攻击.
缺省默认值是"ground.velocity"中x_velocity参数.

air.velocity = x_velocity, y_velocity (浮点型, 浮点型)
给予P2的初始速度,如果P2在空中被击中.缺省默认是0,0.

airguard.velocity = x_velocity, y_velocity (浮点型, 浮点型)
给予P2的速度,如果P2在空中防御住攻击.
默认值是x_velocity * 1.5, y_velocity / 2,这里的 x_velocity和y_velocity是"air.velocity"参数的值.

ground.cornerpush.veloff = x_velocity (浮点型)
确定给予玩家的额外速度(速度偏移量)如果他在地面版边攻击.
(也就是版边攻击会使自己后退的速度)
此数值设置的越高将导致玩家反弹离版边更远.
缺省默认值取决于attr参数.如果attr中arg1是"A",默认是0.
否则,默认值是1.3*guard.velocity.

air.cornerpush.veloff = x_velocity (浮点型)
确定给予玩家的额外速度(速度偏移量)如果他在版边攻击空中的对手.
此数值设置的越高将导致玩家反弹离版边更远.
缺省默认值是ground.cornerpush.veloff.

down.cornerpush.veloff = x_velocity (浮点型)
确定给予玩家的额外速度(速度偏移量)如果他在版边攻击蹲下的对手.
此数值设置的越高将导致玩家反弹离版边更远.
缺省默认值是ground.cornerpush.veloff.

guard.cornerpush.veloff = x_velocity (浮点型)
确定给予玩家的额外速度(速度偏移量)如果他在版边的攻击被对手防御住.
此数值设置的越高将导致玩家反弹离版边更远.
缺省默认值是ground.cornerpush.veloff.

airguard.cornerpush.veloff = x_velocity (浮点型)
确定给予玩家的额外速度(速度偏移量)如果他在版边的攻击被对手空中防御住.
此数值设置的越高将导致玩家反弹离版边更远.
缺省默认值是guard.cornerpush.veloff.

airguard.ctrltime = ctrl_time (浮点型)
P2在空防状态恢复控制前的时间.缺省默认为"guard.ctrltime"的值.

air.juggle = juggle_points (浮点型)
hit要求的额外连击点数.不要与StateDef中的"juggle"参数混淆.
你通常不需要使用这个参数,除了HitDef中的飞行道具.缺省默认值是0.

mindist = x_pos, y_pos (整型, 整型)
见下方.

maxdist = x_pos, y_pos (整型, 整型)
这些参数能让你控制在P2被击中后相对于P1最小和最大距离.
这些参数不常用.缺省默认不改变P2位置.

snap = x_pos, y_pos (整型, 整型)
击中后移动P2到相对于P1的指定位置.这参数不常用.
如果你想在投掷中捕捉P2到一个特定的位置,建议你在P1投掷状态中使用 TargetBind 控制器来代替.
缺省默认不改变P2位置.

p1sprpriority = drawing_priority (整型)
绘制P1图像的优先级如果招式击中或被P2防御住.
与p2sprpriority参数一起,控制是否P1绘制在P2上方或下方.默认值是1.

p2sprpriority = drawing_priority (整型)
绘制P2图像的优先级如果招式击中或被P2防御住.
默认值是0.

p1facing = facing (整型)
如果成功击中,设置-1使P1转向.
默认值保持P1朝向不变.

p1getp2facing = facing (整型)
设置1让P1的朝向与P2被击中后一致,-1使P1和P2反向.
默认为0(不改变).如果非0,则此参数优先于p1facing.

p2facing = facing (整型)
如果成功击中,设置1使P2与P1朝向相同,-1使P2朝向相反.
默认值是0,不改变P2朝向.

p1stateno = state_no (整型)
如果成功击中,设置P1进入的状态号.这个状态必须是一个攻击状态(movetype = A)且至少要有1帧.
主要用于投掷.默认是-1,不改变.

p2stateno = state_no (整型)
如果成功击中,设置P2进入的状态号.P2将获得P1(指定的)状态和动画数据.
P2将保持P1(指定的)状态和动画数据直到P2开始攻击,或者SelfState控制器被使用,返回P2到他自己的状态.
这个状态必须是一个受击状态(movetype = H)且至少要有1帧.
主要用于投掷.也可用于自定义攻击反应.默认是-1,不改变.

p2getp1state = bvalue (布尔型)
设置0防止P2获得P1(指定的)状态和动画数据,假如你不想使用"p2stateno"参数默认的特征
默认为1如果"p2stateno"参数被使用.否则被忽略.

forcestand = bvalue (布尔型)
设置1强制P2(原来处于蹲下状态)进入站立状态类型如果成功击中.如果P2在空中状态则无效.
通常默认为0,但如果"ground.velocity"中y_velocity参数是非0,则默认值是1.

fall = bvalue (布尔型)
设置1如果你想让P2进入"fall(下落)"状态.(P2着地前不恢复控制)
如果你想用一招"击倒"P2就是用他.默认是0.

fall.xvelocity = x_velocity (布尔型)
当处于"fall"状态从地面反弹时P2获得的x方向速度.缺省默认为不变.

fall.yvelocity = y_velocity (布尔型)
当处于"fall"状态从地面反弹时P2获得的y方向速度.
默认 -4.5(240p), -9(480p), -18(720p).

fall.recover = bvalue (布尔型)
设置为0如果你不想让P2在"fall"状态中能够恢复.
缺省默认为1.(可以恢复)

fall.recovertime = recover_time (整型)
在P2通过输入恢复指令,能够从"fall"状态恢复之前必须经过的时间.
不包含P2被停止(攻击中引起的震动)的时间.缺省默认为4.

fall.damage = damage_amt (整型)
指示当P2在下落状态之外撞击地面造成的伤害值.缺省默认为0.

air.fall = bvalue (布尔型)
设置1如果你想让P2进入"fall"状态,如果hit发生时P2在空中.(P2着地前不恢复控制)
默认和fall的值相同.

forcenofall = bvalue (布尔型)
设置1强制P2解除"fall"状态,如果他在这个状态内.如果P2不在"fall"状态内则此参数无效.
如果"fall"参数是1则此参数被忽略.缺省默认为0.

down.velocity = x_velocity, y_velocity (布尔型, 布尔型)
当P2倒地被攻击时指定给P2的速度.如果y_velocity非0,P2将被打飞.
如果是0,则P2将在地面上向后滑动.缺省默认和"air.velocity"参数值相同.

down.hittime = hit_time (整型)
当P2倒地被攻击时将向后滑动的时间.此参数将被忽略如果"down.velocity"参数中的y_velocity非0.

down.bounce = bvalue (布尔型)
设置为1如果你想让P2在撞击地面后立刻从地面反弹起来.(使用 fall.xvelocity和fall.yvelocity参数值)
如果"down.velocity"中y_velocity参数为0则此参数被忽略.缺省默认为0.(P2撞击地面不反弹)

id = id_number (整型)
hit的识别号,用于招式连击.(连续攻击的招式)
你能使用这个号码稍后检测玩家上一次是否被这个特定的HitDef击中.此号码被称为targetID.
在 TargetBind 控制器或者在 target(ID)重定向 键值中被使用.
有效值是所有大于等于1的整数,缺省默认为0(无ID).不要把TargetID与玩家ID混淆.

chainID = id_number (整型)
主要用于一套连续招式中.
如果P2上一次(最近一次)被P1且此ID的招式击中,则他只能被此chainID号的HitDef击中.你能把这些用于招式连击的下一部分.
注意招式连击在没有使用"id"和"chainid"参数时仍可能有效.有效值是所有大于等于1的整数,缺省默认为-1(连击任何招式).

nochainID = nochain_1, nochain_2 (整型)
nochainID指定2个在此次攻击中不能被连击的hit ID号.
如果他们都是-1(默认值),则连击对任何hit ID号来说没有完全禁用.nochain_2能被省略.
除了-1,指定的值不能与chainID的值吻合.
如果P2被P1上一HitDef和当前HitDef之中的第三方击中则此参数无效.

hitonce = hitonce_flag (布尔型)
如果设置为1,此HitDef只作用于一个对手.如果成功击中,所有其他的目标将丢失.
通常默认为0.异常情况是如果"attr"参数是投掷类型,将使它的默认值变成1.
(也就是说T属性的投掷攻击只能同时击中1个人,除非你用非T属性的投掷攻击)

kill = bvalue (布尔型)
设置此值为0能阻止此次攻击KO对手,当成功击中的时候.默认是1.

guard.kill = bvalue (布尔型)
设置此值为0能阻止此次攻击KO对手,当攻击被防御住的时候.默认是1.(类似kill)

fall.kill = bvalue (布尔型)
设置为0阻止这次攻击KO对手,当他落在地上的时候.(见fall.damage).默认为1.

numhits = hit_count (整型)
hit_count指示此hitdef应该加到combo counter(连击数)上的hits数目(也就是改动连击数).必须大于等于0.默认是1.

getpower = p1power, p1gpower (整型, 整型)
p1power指定给予P1的能量值如果此HitDef成功击中.
p1gpower指定给予P1的能量值如果此HitDef被防住.
如果缺省,p1power默认是hit_damage("damage"中的参数)乘以Default.Attack.LifeToPowerMul(data/mugen.cfg中指定的值).
如果p1gpower缺省,默认值指定为p1power除以2.

givepower = p2power, p2gpower (整型, 整型)
p2power指定给予P2的能量值如果此HitDef成功击中.
p2gpower指定给予P2的能量值如果此HitDef被防住.
如果缺省,p2power默认是hit_damage("damage"中的参数)乘以Default.GetHit.LifeToPowerMul(data/mugen.cfg中指定的值).
如果p2gpower缺省,默认值指定为p2power除以2.

palfx.time = palfx_time (整型)
见下方.

palfx.mul = r1, g1, b1 (整型, 整型, 整型)
见下方.

palfx.add = r2, g2, b2 (整型, 整型, 整型)
如果包含这些参数,将能够实现P2的色表效果,如果成功击中的话.
palfx_time是提供给P2色表效果的时间(游戏帧数表示).palfx_time默认是0.(无效果)
其余的参数和PalFX控制器中一样.

envshake.time = envshake_time (整型)
见下方.

envshake.freq = envshake_freq (浮点型)
见下方.

envshake.ampl = envshake_ampl (整型)
见下方.

envshake.phase = envshake_phase (浮点型)
如果包含这些参数,将在成功击中时使屏幕震动.
envshake_time是屏幕震动的时间.(游戏帧数表示)
其余参数和EnvShake控制器中一样.

fall.envshake.time = envshake_time (整型)
见下方.

fall.envshake.freq = envshake_freq (浮点型)
见下方.

fall.envshake.ampl = envshake_ampl (整型)
见下方.

fall.envshake.phase = envshake_phase (浮点型)
和envshake.*参数相似,只是仅当P2撞击地面时才有效果.

注意:
当在一个[Statedef -2]块中被执行同时此玩家又(执行)另一个玩家的状态和动画数据时HitDef的特征是未定义的.
(比如在[Statedef -2]中执行HitDef同时你进入了对手指定的状态,p2stateno,targetstate这种)

示例:
无


HitFallDamage

当玩家被击中且进入fall状态,提供fall的伤害值(在hitdef中指定的).

必要参数:
无

可选参数:
无

示例:
无


HitFallSet

当玩家被击中,设置玩家的下落变量.

必要参数:
无

可选参数:
value = fallset_flag (整型)
如果fallset_flag是-1,则此控制器不会改变玩家是否将要下落.
如果fallset_flag是0,意味着玩家将不进入下落状态,1表示将进入下落状态.默认值为-1.

xvel = x_velocity (浮点型)
见下方.

yvel = y_velocity (浮点型)
若指定,分别设置玩家的fall.xvel和fall.yvel参数.
详见HitDef对这些参数的描述.

示例:
无

特例:
可作为特殊效果使用,比如对方空中被冰冻着地后再被非fall攻击不会被击飞.
[State 0, HitFallSet]
type = HitFallSet
trigger1 = time = 0
value = 0


HitFallVel

如果玩家被击中且处于下落状态,设置玩家在HitDef中指定的下落速度(中的速度值).(fall.xvel和fall.yvel)

必要参数:
无

可选参数:
无

示例:
无


HitOverride

定义一个hit覆盖.
如果玩家被指定攻击类型击中,他将进入指定的状态号而不是他默认的受击行为.
同一时间能有8个覆盖被激活.

必要参数:
attr = attr_string (字符串型)
标准hit属性字符串指定了要覆盖的hit类型.
见Hitdef中"attr"参数章节.

stateno = value (整型)
指定如果被Hitdef且指定的属性击中后将要进入的状态.

可选参数:
slot = slot_no (整型)
指定放置击中覆盖的一个插槽号(0到7).缺省默认是0.

time = effective_time (整型)
指定此击中覆盖应激活的时间.默认是1(1帧).
设置为-1使得此覆盖一直持续直到被另一个覆盖.

forceair = value (布尔型)
若设置成1,玩家的受击变量将被设置成仿佛击中时进入了空中状态.
用于如果你想强制玩家被任何hit击中便摔倒.

注意:
如果P1有大于等于1个激活的HitOverrides,P1将不会被P2拥有的下列任何特征匹配的HitDef影响：
p1stateno参数值不是-1.
p2getp1state参数值是1.

示例:
无


HitVelSet

不推荐使用此控制器.当玩家被击中,将玩家速度的所需分量设置为适当的受击速度.

必要参数:
无

可选参数:
x = x_flag (整型)
非0的参数意味着把玩家速度的x分量变为受击速度.

y = y_flag (整型)
非0的参数意味着把玩家速度的y分量变为受击速度.

示例:
无

注意:
废弃了.


LifeAdd

指定增加玩家生命值的数量,如果有必要,可以被玩家的防御系数缩放.

必要参数:
value = add_amt (整型)
指定增加到玩家血条上的生命值.

可选参数:
kill = kill_flag (整型)
如果kill_flag是0,则增加量不会使玩家的生命值低于1.默认是1.

absolute = abs_flag (整型)
如果abs_flag是1,则精确的add_amt数值将增加到玩家的生命中(忽略防御系数).默认是0.

示例:
无


LifeSet

把玩家的生命值设置为指定的值.

必要参数:
value = life_amt (整型)
指定执行(lifeset)后玩家将会获得的生命值.

可选参数:
无

示例:
无


MakeDust

不推荐使用此控制器,请使用Explod控制器.
制造尘土效果.

必要参数:
无

可选参数:
pos = x_pos, y_pos (整型)
指定尘土被画出的位置,相对于玩家的坐标轴.默认是0,0.

pos2 = x_pos, y_pos (浮点型)
指定同时画出的第2个尘土的位置.若缺省,则第2个尘土将不会被画出.

spacing = value (整型)
确定绘制尘土的时间间隔.例如,spacing = 3(默认值)将每隔3帧绘制一个新的尘土效果.spacing的值应大于等于1.

示例:
无

注:
此控制器直接调用fightfx内动画号为120的动画.


ModifyExplod

修改现有的Explod的参数.基本语法和Explod相同.然而,此控制器以后可能改动.
依赖于此控制器的任何代码在以后不保证可以正常工作.

注:
对某些explod的参数貌似无效.


MoveHitReset

重置movehit标示到0.就是说,执行了MoveHitReset后,MoveContact, MoveGuarded, MoveHit触发器将都返回0.

必要参数:
无

可选参数:
无

示例:
无


NotHitBy

临时指定无法击中玩家的hit类型.

必要参数:
value = attr_string 或 value2 = attr_string (字符串型)
上面的参数只有1种能被指定.attr_string应是1个标准的hit属性字符串.见详情.

可选参数:
time = effective_time (整型)
指定NotHitBy属性起作用的游戏帧数.默认是1.

详情:
玩家有2个hit属性槽,能用"value"或"value2"的值来设置给NotHitBy控制器.
这些槽也能被HitBy控制器设置.当设置了1个槽,便获得了一个朝0倒记的计时器.(有效时间)
如果计时器还未计时到0,槽被认为是激活的.玩家能被HitDef击中仅当HitDef中的参数出现在所有当前激活的槽中.
使用NotHitBy控制器设置指定的槽来包含所有hit属性,除了那些被指定在NotHitBy属性字符串中的.

NotHitBy同时也与HitDef的attr参数遥相呼应. 请参阅 HitDef

示例:
;所有攻击都不能击中
[State ]
type = NotHitBy
trigger1 = 1
value = SCA

;不被普通攻击和所有飞行道具击中
[State ]
type = NotHitBy
trigger1 = 1
value = , NA, AP
;attr_string 不写就表示SCA

【BUG】注意：
目前来看,这个控制器的BUG还是没有修复.而且通过几次测试,也无法描述出bug的规律.
貌似只有第一组属性槽(SCA)省略,才有效.比如value = ,NA表示对普通攻击免疫,这貌似是准确的.
只要写上SCA就会导致所有攻击都无效.其他还有很多的bug,无法用规律描述出来.比如本人试出来 value = S,NA会导致飞行道具无法击中等等.
总之要实现不让部分招式击中,还是要使用HitBy.


Null

什么也不做.也许用来使其他状态控制器暂时失效,只要简单的吧type改成Null.
(实际中也主要用于调试或者修改的,比如要使一个很多行的控制器失效只要type=null就行了)

必要参数:
无

可选参数:
无

注:
此控制器用法相当灵活.
由于null虽然什么也不做,但他也是一个标准的控制器.
故null中设置的trigger也像其他控制器一样会被执行,同样遵守trigger执行顺序.
另请注意：场景中anim,normal等替换为null之后，画面依然会被显示.


Offset

改变玩家的显示位置.玩家通过此数值移动并绘制于他的坐标轴中.

必要参数:
无

可选参数:
x = x_val (浮点型)
见下方.

y = y_val (浮点型)
分别指定x和y的偏移量.你能指定1或2个可选参数.

示例:
无


PalFX

提供色表的临时效果.这些效果将会同时影响此玩家拥有的explod和helper的色表,除非它们已指定ownpal为非零.

必要参数:
无

可选参数:
time = duration (整型)
指定色表效果将持续的时间.(帧数)
指定-1使色表效果永久持续.指定0停止任何正在起作用的色表效果.

add = add_r, add_g, add_b (整型, 整型, 整型)
见下方.

mul = mul_r, mul_g, mul_b (整型, 整型, 整型)
每部分add参数的分量被加到玩家色表相对应的分量上,结果乘以相对应的mul参数分量除以256.(提供算法)
例如,如果pal_r是人物原色表的红色分量值,则新的红色分量值是(pal_r + add_r) * mul_r / 256.
mul的值必须>=0.3个参数的默认值不变,例如 add = 0,0,0 且 mul = 256,256,256.

sinadd = ampl_r, ampl_g, ampl_b, period (整型, 整型, 整型)
创建一个附加正弦波的色表加成效果.
period指定了正弦波的周期(单位是帧数),amplitude参数控制正弦波每个分量的振幅.
例如,如果t表示从PalFX控制器激活时逝去的帧数,pal_r是人物原色表中红色分量值,则t时间点人物色表红色分量值为(pal_r + add_r + ampl_r * sin(2 * pi * t / period)) * mul_r / 256.

invertall = bvalue (布尔型)
如果bvalue非0,则色表中的颜色会倒置,创建"电影底片"效果.
颜色倒置在add和mul生效前起作用.bvalue默认是0.

color = value (整型)
此参数影响色表的色彩级别(饱和度).如果值为0,色表将会是灰度的.
如果值为256,则色表中的颜色将不改变.0-256之间的值将会有过渡效果.
此参数在invertall,add,mul生效前起作用.值必须在[0,256]范围里.默认值为256.

示例:
无


ParentVarAdd

如果玩家是一个helper,增加玩家父级一个(起作用的)变量(var/fvar)数值.
无论是整型变量还是浮点型变量都能被此控制器增加.
如果此玩家不是helper,则此控制器无效.

必要参数(对应整型变量):
v = var_no (整型)
var_no应该是0-59之中的一个整数.

value = int_expr (整型)
int_expr是加到用var_no标明的(索引号为var_no的)整型变量上的值.

必要参数(对应浮点型变量):
fv = var_no (整型)
var_no应该是0-39之中的一个整数.

value = float_expr (浮点型)
float_expr是加到索引号为var_no的浮点型变量上的值.

可选参数:
上述2种情况都没有.

替代语法:
var(var_no) = int_expr (整型版本)
fvar(var_no) = float_expr (浮点型版本)

注意:
由于历史原因,注意上面列出的VarAdd替代语法,不能在一个表达式内给变量赋值,也不能在一个表达式内增加变量值.
如果你成功击中P2将他置于自定义状态,不要在自定义状态中给变量赋值.否则,你将覆盖P2父级的变量,这将引起对手未知错误.
(也就是说,不要在p2stateno,targetstate指定P2进入的状态里面使用varset,varrangeset,varadd,parentvaradd,parentvarset等等(除非你做整合或者你知道自己在做什么)
否则你设置的其实是P2或者他父级的var/fvar参数,所以将会引起未知错误.)

示例:
无


ParentVarSet

如果玩家是一个helper,设置玩家父级(起作用的)变量(var/fvar)数值.
无论是整型变量还是浮点型变量都能被此控制器设置.
如果此玩家不是helper,则此控制器无效.

必要参数(对应整型变量):
v = var_no (整型)
var_no应该是0-59之中的一个整数.

value = int_expr (整型)
int_expr是赋给用var_no标明的(索引号为var_no的)整型变量的值.

必要参数(对应浮点型变量):
fv = var_no (整型)
var_no应该是0-39之中的一个整数.

value = float_expr (浮点型)
float_expr是赋给索引号为var_no的浮点型变量上的值.

可选参数:
上述2种情况都没有.

替代语法:
var(var_no) = int_expr (整型版本)
fvar(var_no) = float_expr (浮点型版本)

注意:
由于历史原因,注意上面列出的给变量赋值的替代语法,不能在一个表达式内给变量赋值.
如果你成功击中P2将他置于自定义状态,不要在自定义状态中给变量赋值.否则,你将覆盖P2父级的变量,这将引起对手未知错误.
(也就是说,不要在p2stateno,targetstate指定P2进入的状态里面使用varset,varrangeset,varadd,parentvaradd,parentvarset等等(除非你做整合或者你知道自己在做什么)
否则你设置的其实是P2或者他父级的var/fvar参数,所以将会引起未知错误).

示例:
无


Pause

将游戏暂停指定的时间.
在这段时间中,玩家和背景将不会被更新.

必要参数:
time = t (整型)
要暂停的时间帧数.
t的有效值是大于0的正数.

可选参数:
endcmdbuftime = bt (整型)
定义暂停末尾期间的一段时间帧数,在这个时间段里,玩家的招式指令将被缓存起来.
被缓存的指令将在暂停结束后立刻被command触发器检测.
缓存仅提供给在暂停中无法移动的玩家.(见movetime参数)
endcmdbuftime有效值为0-t,t是time的参数值(上面的必要参数).默认是0.

movetime = mt (整型)
定义暂停开始的一段时间帧数,在这个时间段里,玩家被允许移动.
这段时间内将进行碰撞检测,所以有可能击中其他玩家.
mt有效值为0-tt是time的参数值(上面的必要参数).默认是0.

pausebg = p (整型)
如果设置为1,在暂停中背景将停止.如果是0,背景将在暂停中持续更新.默认是1.

注意:
在Pause控制器的暂停时间内执行另一个Pause控制器将取消上一个Pause控制器的效果.
在SuperPause(超级暂停)中执行Pause控制器将延迟暂停效果直到超级暂停结束.

示例:
无


PlayerPush

停止1帧之内玩家的推挤检测.推挤检测用于防止玩家相互重叠.
通过暂时停止推挤检测,dodge(闪避)类型的招式(玩家能穿过另一个人,但是仍然能被击中)能被实现.

必要参数:
value = push_flag (布尔型)
如果push_flag非0,则能够进行推挤检测.如果push_flag是0,则停止推挤检测.

可选参数:
无

示例:
无


PlaySnd

播放一个声音.

必要参数:
value = group_no, sound_no (整型, 整型)
group_no和sound_no对应你在玩家的snd文件中给每个声音指定的一对识别码.
如果要从common.snd中播放声音,在group_no前加上"F".

可选参数:
volumescale = volume_scale (浮点型)
volume_scale控制音量.数值为100表示音量为100%,50为50%,等等.
有效值从0-100.默认为100.

channel = channel_no (整型)
channel_no指定哪个声音通道将播放声音.一个特定通道在同一时间也许只能播放一个声音.
例如,如果你在通道2播放一个声音,然后在第一个声音播放后相同的通道播放任何声音,则默认第一个声音在第二个声音播放时将停止.
通道0是预留给玩家的特殊通道,当玩家被击中时通道0的声音(说话声)将停止.
建议你在通道0播放你人物的(说话声)声音.缺省默认为-1,表示声音将在任何空闲的声道播放.

lowpriority = pr (整型)
此参数仅在通道不是-1的时候有效.如果pr非0,则当前在此通道播放的声音(从上一个PlaySnd中调用)不能被此声音打断.

freqmul = f (浮点型)
声音频率将乘以f.例如.设置f为1.1将造成高分贝的声音.默认为1.0(不改变频率).

loop = loop_flag (整型)
设置loop_flag为非0使得声音样本反复循环.默认是0.

pan = p (整型)
声音(音源)的位置偏移,计量单位是像素.
如果p>0则声音偏移到玩家的前方.如果p<0则声音偏移到玩家的后方.默认为0.
这个参数与abspan是互斥的.
(也就是说如果pan=1000,那么即使你人站在左边脸朝右,你的声音听起来也是从右面播放出来的.)

abspan = p (整型)
和pan一样,只是声音从屏幕中心开始平移,而不是从玩家的位置.
这个参数与pan是互斥的.

示例:
;从玩家的SND文件中播放声音2,0.
type = PlaySnd
value = 2,0

;从fight.snd中播放声音5,2.
type = PlaySnd
value = F5,2

注意:
1.0 RC8 版本之前,volume参数用来取代volumescale.
volume参数不再被使用.


PosAdd

玩家位置的指定偏移量.
X坐标相对于玩家的坐标轴,正值向玩家所朝的方向移动.
Y坐标相对于玩家的坐标轴,负值向上移动.

必要参数:
无

可选参数:
x = x_value (浮点型)
使玩家向前移动x_value像素.默认是0.

y = y_value (浮点型)
使玩家向下移动y_value像素.默认是0.

示例:
无

特例:
此控制器来用来模拟打击停顿时的人物颤动效果:
[State 0, PosAdd]
type = PosAdd
trigger1 = time%2 = 0
x = 1

[State 0, PosAdd]
type = PosAdd
trigger1 = time%2 = 1
x = -1

也能实现不规则颤动效果:

先用有固定效果的控制器固定位置
[State 0, PosSet]
type = PosSet
trigger1 = 1
x = 20
y = 15

添加颤动效果
[State 0, PosAdd]
type = PosAdd
trigger1 = 1
x = -2+Random%5
y = -2+Random%5


PosFreeze

临时冻结玩家的位置.

必要参数:
无

可选参数:
value = freeze_flag (布尔型)
如果freeze_flag非0,则玩家的位置将被冻结,否则不会.默认为1.

示例:
无


PosSet

设置玩家的位置到指定的坐标.
X坐标相对于屏幕中心,正值向右移动.
Y坐标相对于地面,负值向上移动.

注意: x和y的数值为屏幕绝对空间大小,即如果在带有缩放的场景时,需要考虑屏幕缩放带来的位置偏移.
在Helper中使用PosSet时,需要考虑postype和AngleDraw带来的位置偏移.

必要参数:
无

可选参数:
x = x_value (浮点型)
指定玩家新的x方向位置.

y = y_value (浮点型)
指定玩家新的y方向位置.

示例:
无


PowerAdd

增加指定数值给玩家的power(能量/气)值.

必要参数:
value = add_amt (整型)
add_amt是增加到玩家的power上的值.

可选参数:
无

示例:
无


PowerSet

设置玩家拥有的power(能量/气)值.

必要参数:
value = pow_amt (整型)
pow_amt是设置给玩家的新的power值.

可选参数:
无

示例:
无


Projectile

为玩家创建一个飞行道具.
Projectile控制器携带了 HitDef 控制器的所有参数,用来控制飞行道具的HitDef.
此外,Projectile控制器有如下额外的参数.

注:projectile俗称"波""飞弹"等等,这里统一译作"飞行道具".HitDef直译为"击中定义".

必要参数:
无

可选参数:
ProjID = id_no (整型)
给此飞行道具指定ID号.设置为正数.

projanim = anim_no (整型)
指定飞行道具使用的动画动作号.缺省默认是0.

projhitanim = anim_no (整型)
指定飞行道具击中对手时的动画号.缺省默认为-1(不改变原有动画).

projremanim = anim_no (整型)
指定飞行道具被移除时的动画号(由于时间过期或者到达了它的移动边界,等等).
缺省默认为projhitanim的值.

projcancelanim = anim_no (整型)
指定飞行道具被另一个飞行道具削去时的动画.缺省默认为projremanim的值.

projscale = x_scale, y_scale (浮点型, 浮点型)
指定飞行道具的缩放系数.最终飞行道具的缩放效果被此参数和P1cns文件[Size]组中"proj.doscale"共同影响.
缺省默认为1,1(正常尺寸).

projremove = remove_flag (布尔型)
设置非0值使飞行道具在击中后移除,或者设置0阻止这个特征.默认是1.

projremovetime = remove_time (整型)
指定飞行道具在屏幕中将要被移除的时间帧数.(也就是remove_time后飞行道具被移除,相对于生命周期)
如果是-1,飞行道具将不会被移除.默认是-1.

velocity = x_vel, y_vel (浮点型, 浮点型)
指定飞行道具x和y方向的速度初始值.缺省默认是0,0.

remvelocity = x_vel, y_vel (浮点型, 浮点型)
指定当飞行道具被移除时x和y方向的速度.缺省默认为0,0.

accel = x_accel, y_accel (浮点型, 浮点型)
指定飞行道具x和y方向的加速度.缺省默认为0,0.

velmul = x_mul, y_mul (浮点型, 浮点型)
指定x和y方向速度的乘数.飞行道具的速度每帧都会乘以这个乘数.乘数缺省默认为1.

projhits = num_hits (整型)
指定飞行道具在被移除前能给予对手的hit数.默认是1.

projmisstime = miss_time (整型)
如果飞行道具设定了多次hit,miss_time指定了飞行道具hit的时间间隔帧数.默认为0.

projpriority = proj_priority (整型)
指定飞行道具的优先级.(俗称波的等级)
如果飞行道具与另一个相同优先级的飞行道具碰撞,他们将一起被削去.
如果与低优先级的飞行道具碰撞,将会削去低优先级的飞行道具,且那个高优先级的飞行道具,他的优先级将减去1.
默认为1.(与hitdef中攻击优先级定义(priority)不同,飞行道具的优先级没有指定范围)

projsprpriority = priority (整型)
指定飞行道具图像的优先级.高优先级图像会显示在低优先级图像上方.默认是3.

projedgebound = value (整型)
指定飞行道具被自动移除前远离屏幕边缘的距离.单位是像素.
默认为40(240p),80(480p),160(720p).

projstagebound = value (整型)
指定飞行道具被自动移除前远离舞台边缘的最大距离.
默认为40(240p),80(480p),160(720p).

projheightbound = lowbound, highbound (整型, 整型)
指定飞行道具能够到达的y方向坐标最大最小值.如果飞行道具离开这个边界,将会自动移除.
注意:因为减少y值会增加在屏幕上的高度,所以边界值下限实际指定的是飞行道具能到达的最高高度.
边界值下限默认为-240(240p), -480(480p), -960(720p).边界值上限默认是1(240p), 2(480p), 4(720p).

offset = off_x, off_y (整型, 整型)
指定飞行道具被创建时x和y方向的偏移量.缺省默认都为0.
飞行道具创建时的朝向总是和玩家一样.off_x与飞行道具所面对的方向有关.
offset的确切特征取决于postype.

postype = postype_string (字符串型)
postype_string指定了postype(位置类型)--如何解读相关位置的参数.
所有情况下,正的y偏移量表示向下的位移.所有情况下,off_y相对于玩家的位置.

有效的postype_string值如下:

  • p1
    说明了offset相对于p1的坐标轴.正的off_x朝向P1前方.这是postype默认值.
  • p2
    说明了offset相对于p2的坐标轴.正的off_x朝向P2前方.
    如果不存在p2,位置计算和p1有关且会记录一次警告.
  • front
    说明off_x相对于p1面向的屏幕边缘.正的off_x朝向p1前方.
  • back
    说明off_x相对于p1背对的屏幕边缘.正的off_x朝向p1前方.
  • left
    说明off_x相对于左边的屏幕边缘.正的off_x朝向p1前方.
  • right
    说明off_x相对于右边的屏幕边缘.正的off_x朝向p1前方.

projshadow = shadow (整型)
如果shadow非零值,将绘制飞行道具火花的阴影,否则不会.默认是0.

projshadow = shad_r, shad_g, shad_b (整型, 整型, 整型)
指定飞行道具影子的R,G,B数值分量.分量值应是[0,255]之间的整数.
如果shad_r计算出-1,则将使用舞台的影子颜色.
分量值越大,这种颜色在影子中显示的越少.所以纯黑色的影子是255,255,255.
默认为0,0,0.(没影子)

supermovetime = move_time (整型)
指定SuperPause(超级暂停)中飞行道具将不被冻结住的时间帧数.默认为0.

pausemovetime = move_time (整型)
指定Pause(暂停)中飞行道具将不被冻结住的时间帧数.默认为0.

ownpal = ownpal_flag (布尔型)
如果ownpal_flag为0,飞行道具颜色将被随后执行的自身的PalFX和RemapPal控制器影响.通常情况下这是默认值.
如果ownpal_flag为1,飞行道具颜色将不会被随后执行的自身的PalFX和RemapPal控制器影响.如果是从fightfx.air播放动画的,这是默认值.

remappal = dst_pal_grp, dst_pal_item (整型, 整型)
强制色表从飞行道具索引颜色图像重映射到指定的色表.
此参数仅当ownpal_flag为非0.
如果dst_pal_grp是-1,此参数将被忽略.默认-1,0.

afterimage.time = aftimg_time (整型)
见下方.

afterimage.length
见下方.

afterimage....
如果包含这些数值,将实现飞行道具的残影效果.
参数与AfterImage控制器中的一样,只是必须在前面加上"afterimage.".

注意:
helper创建的飞行道具将立刻被他的根级所有.
当在一个[Statedef -2]块中被执行同时此玩家有(执行)另一个玩家的状态和动画数据时飞行道具的HitDef特征是未定义的.

示例:
无


RemapPal

更换玩家的色表.

必要参数:
source = src_pal_grp, src_pal_item
见下方.

dest = dst_pal_grp, dst_pal_item
所有使用source(原始的)色表的玩家图像素材将替代使用dest(目标的)色表绘制.
source和dest色表必须存在于玩家图像素材之内,而且双方都必须有相同的色深.

如果src_pal_grp是-1,所有被索引的图像将被重映射到目标色表.
仅影响相同色深的图像色表.其他存在的任何色表映射将移除.

如果dst_pal_grp是-1,原始色表的映射将移除.
将dest的一对值设置为和source相同将有相同的效果.

source默认值人-1,0.
dest默认值为-1,0.

注意:
色表映射是不可传递的,即,将1,0映射到2,0且2,0映射到3,0将不会造成1,0映射到3,0.

在1.1及以后的版本中,每个玩家将允许同时有8个不同的色表映射.
若source的值未被映射则之后调用RemapPal控制器将失败.

对于给定的一组source值设置dst_pal_grp为-1能移除未使用的映射.

可选参数:
无

示例:
;所有使用(1,1)色表的图像素材将替换使用(1,3)色表来绘制.
type = RemapPal
source = 1,1
dest = 1,3


RemoveExplod

移除玩家所有的explod或者只是指定ID号的explod.

必要参数:
无

可选参数:
ID = remove_id (整型)
remove_id是要移除的explod的ID号.如果缺省,将移除玩家拥有的所有explod.


ReversalDef

定义一个攻击反弹.(攻击倒置)
如果P2的一个Clns1框(红框)与P1的一个Clsn1框(红框)(且此时ReversalDef激活中),则P1将反弹P2的攻击.
与p1stateno(可选p2stateno)一起使用,创建反弹攻击.
ReversalDef携带了HitDef中pausetime, sparkno, hitsound, p1stateno和p2stateno参数,加上:

必要参数:
reversal.attr = attr_string
attr_string指定能被ReversalDef反弹的攻击属性列表.是一个标准的hit属性字符串.
例如,reversal.attr = SA,NA,SA表示 站立+空中, 普通攻击, 特殊攻击.(对手的攻击类型如果包含在列出来的类型内将被反弹)
(另有字符"A",用来表示All(所有的攻击类型),例如,reversal.attr = S,AT表示 站立,所有投掷类攻击)

可选参数:
无

注意:
sparkxy参数被认为是到P2的hitdef的sparkxy的偏移量.
MoveHit触发器能被用来检测如果P1成功反弹了P2招式.

示例:
无

(主要用于格挡技能,例如藤堂香澄的招式,刚体等.只要你的红框有反弹定义且接触到对手的红框,那么对手的招式就会被你反弹.
所以,即使你处于无敌状态(比如使用了nothitby或者压根就没有受蓝色击框),也有可能被对手击中而少血,只要对手配合使用了p2stateno.
当然,此控制器配合p2stateno使用也极易在非整合的MUGEN游戏对战中产生bug,最典型的就是多一个人出来.
主要是由于ReversalDef反弹了对手的helper攻击,配合p2stateno,指定了对手的helper进入了指定状态.
所以使用时一定要注意.)


ScreenBound

指定玩家的运动是否被屏幕约束.
也决定着摄像机是否应该跟随玩家运动.
此控制器产生的结果只在1帧内有效.

必要参数:
无

可选参数:
value = bound_flag (布尔型)
如果bound_flag是0,玩家将被允许离开屏幕.
如果是1,则玩家将被约束在屏幕内.缺省默认是0.

movecamera = move_x_flag, move_y_flag (布尔型, 布尔型)
如果是1,指定摄像机应该跟随玩家分别在x和y方向平移.缺省默认都为0.

示例:
无

实例:
[State 0, ScreenBound]
type = ScreenBound
trigger1 = 1
value = 1
movecamera = 0,0
不允许人物离开屏幕也不允许镜头随人物移动
有时候也可以搭配width使用


SelfState

同ChangeState,只是SelfState使玩家返回他自己状态数据中的状态.
用于下列情况: 当通过一次攻击你已置对手于一个自定义状态,且希望恢复对手到他自己的状态.

注:
此控制器可替换ChangeState,但ChangeState不可替换此控制器.

如果同一个状态(statedef)内有其他ChangeState,建议将SelfState放在此状态内的末尾.


SndPan

调整当前播放声音的相位(平移).此控制器也许能通过持续触发的方式来实现平稳移动一个声音穿过音场或者使声音跟随玩家移动.

必要参数:
channel = chan_no (整型)
指定要移动声音的声道号.

pan = p 或 abspan = p (整型)
这些参数不能同时被指定.p决定声音(音源)的平移量(单位是像素),相对于玩家(pan情况下)或者相对于屏幕中心(abspan情况下).
查看PlaySnd中相关相位参数的描述.

可先参数:
无

示例:
无


SprPriority

改变玩家图像的优先级(也可理解为图层).高优先级的图像绘制在低优先级图像上方.

必要参数:
value = priority_level (整型)
默认值是-5到5.

必要参数:
无

示例:
无


StateTypeSet

更改当前的状态类型和招式类型.用于从地面进入空中的状态,等等...
例如一般的升龙,基本可分为地面起身,空中,落地阶段.从地面起身过渡到空中的时候就可能用到这个控制器.

必要参数:
无

可选参数:
statetype = state_type (字符串型)
state_type(状态的类型)设置为A表示空中,C表示蹲下,S表示站立,L表示躺下.默认不改变.

movetype = move_type (字符串型)
move_type(招式的类型)设置为I表示空闲,H表示受击,A表示攻击.默认不改变.

physics = physics (字符串型)
physics(自身的物理属性)A表示空中(受到重力等),S表示站立(受到摩擦力等),C表示蹲下(受到摩擦力等),N表示无属性(不受任何力,可停留在空中).

示例:
无


StopSnd

停止指定通道所有播放的声音。

必要参数:
channel = chan_no (整型)
停止播放chan_no通道的任何声音。
如果chan_no是-1，则所有声音都将停止播放，包括其他player的声音。

可选参数:
无

示例:
无


SuperPause

冻结游戏,使屏幕变黑.当每个玩家被冻结后,他们的time(状态中的时间)将停止.
用于超级攻击前的突然暂停.

必要参数:
无

可选参数:
SuperPause接受Pause控制器拥有的所有可选参数.另外,SuperPause还拥有如下的参数:
time = pause_time (整型)
指定暂停将持续的时间.默认30帧.(默认速度下的半秒)

anim = anim_no (整型)
指定SuperPause期间播放的指定动画号(从fightx.air中).默认是30,那是一个充电效果.(可能就是超必杀前的那种闪光)如果动画号是-1,则将不播放动画.
如果在anim_no前加上"S",将使用玩家的air文件中动画文件来播放.例如,anim = S10.

sound = snd_grp, snd_no (整型, 整型)
指定SuperPause期间播放的一个声音(从common.snd).默认是-1,表示不播放任何声音.
如果在snd_grp前加上"S",将使用玩家的snd文件中的声音来播放.例如,anim = S10,0.

pos = x_pos, y_pos (浮点型)
指定超级闪光将要显示的位置(相对于玩家的坐标轴).默认0,0.

darken = bvalue (布尔型)
如果是1,则在SuperPause期间屏幕将变黑(半透明的黑色).设置为0无此效果.默认值是1.

p2defmul = def_mul (浮点型)
此数值用来暂时乘以玩家拥有的任何目标的防御值.
使一套连招在超级暂停中拥有较少的伤害值.设置为1不改变玩家的防御值.
0是一个特殊的值,将设置防御值为mugen.cfg中[Rules]中的Super.TargetDefenceMul.
默认值为0,有效值大于等于0.

poweradd = value (整型)
增加给玩家的能量数.默认是0.(一般情况超必杀-1000,max超必杀-2000或者减的更多)

unhittable = bvalue (布尔型)
如果设置为1,玩家在SuperPause期间将无敌.设置为0无此效果.默认是1.

注意:
如果之前执行了Pause控制器,且行动还被暂停中,此时执行SuperPasue控制器将抢占Pause控制器的效果.
在SuperPause期间,剩下的状态时间要等到Pause控制器效果过期才继续计数.

示例:
无


TargetBind

把玩家指定目标绑定到指定的玩家坐标轴相对位置.

必要参数:
无

可选参数:
time = bind_time (整型)
指定绑定起作用的时间帧数.默认是1.

ID = bind_id (整型)
指定要绑定的目标ID号.只有符合此ID号的目标才会被绑定.默认为-1.(绑定所有的目标)
此ID为 HitDef 中定义的ID号.

pos = x_pos, y_pos (浮点型)
指定玩家坐标轴到绑定目标的偏移量.缺省默认是0,0.

注:
TargetBind是把目标绑定到你身上,BindToTarget是把你绑定到目标身上.


TargetDrop

丢弃玩家目标列表中的所有目标,除了像那些有指定ID号的目标.
对仅给某些目标提供效果时有用.

必要参数:
无

可选参数:
excludeID = id_no (整型)
任何ID号不等于id_no的目标将从玩家的目标列表中被丢弃.
默认为-1.(丢弃所有目标)

keepone = keep_flag (布尔型)
如果keep_flag是非0,则至少在玩家目标列表中保留一个目标.
如果有多个目标他们的ID号都等于id_no,将随机保留一个目标其余的都将丢弃.此特征在投掷中有用,用来阻止同时投掷多个对手.
如果keep_flag是0,则此相应ID号的所有目标将被保留.keep_flag默认是1.

示例:
无


TargetFacing

使所有目标都朝向一个相对于玩家的指定方向.

必要参数:
value = facing_val (整型)
如果facing_val是正数,所有目标的朝向都将与玩家相同.
如果facing_val是负数,所有目标的朝向都将与玩家相反.

可选参数:
ID = target_id (整型)
指定要作用的ID号.只有此ID号的目标将被影响.默认为-1.(对所有目标起作用)

示例:
无


TargetLifeAdd

增加目标生命值指定的数量,必要的话此数量会被目标的防御系数缩放.

必要参数:
value = add_amt (整型)
add_amt是增加到每个目标生命值的数量.

可选参数:
ID = target_id (整型)
指定要作用的目标ID号.只有此ID号的目标将被影响.默认为-1.(对所有目标起作用)

kill = kill_flag (布尔型)
如果kill_flag是0,则不会杀死目标,最少保留目标1点血.默认是1.

absolute = abs_flag (布尔型)
如果abs_flag是1,则add_amt将不受缩放影响(比如攻击,防御系数将被忽略).默认为0.

示例:
无


TargetPowerAdd

增加所有目标能量值.

必要参数:
value = add_amt (整型)
增加到每个目标上的能量值.

可选参数:
ID = target_id (整型)
指定要作用的目标ID号.只有此ID号的目标将被影响.默认为-1.(对所有目标起作用)

示例:
无


TargetState

使所有目标进入指定的状态号.

必要参数:
value = state_no (整型)
指定目标要进入的状态号.

可选参数:
ID = target_id (整型)
指定要作用的目标ID号.只有此ID号的目标将被影响.默认为-1.(对所有目标起作用)

示例:
无


TargetVelAdd

增加所有目标速度指定值.
正的x方向速度与目标朝向相同,正的y方向速度指向屏幕下方.

必要参数:
无

可选参数:
x = x_value (浮点型)
目标x方向速度指定的增加值.

y = y_value (浮点型)
目标y方向速度指定的增加值.

ID = target_id (整型)
指定要作用的目标ID号.只有此ID号的目标将被影响.默认为-1.(对所有目标起作用)

示例:
; 将引力常数应用到所有目标上.
type = TargetVelAdd
trigger1 = 1
y = 0.45


TargetVelSet

设置所有目标的速度为指定值.
正的x方向速度与目标朝向相同,正的y方向速度指向屏幕下方.

必要参数:
无

可选参数:
x = x_value (浮点型)
设置目标x方向速度为指定值.

y = y_value (浮点型)
设置目标y方向速度为指定值.

ID = target_id (整型)
指定要作用的目标ID号.只有此ID号的目标将被影响.默认为-1.(对所有目标起作用)a

示例:
无


Trans

覆盖玩家当前游戏帧动画的透明度参数.用于特效中.

必要参数:
trans = trans_type (字符串型)
trans_type必须是以下的一种:
default - 没有效果
none - 禁用透明效果
add - 完全透明叠加效果（alpha值默认为256,256）
addalpha - 自定义透明叠加效果(必须指定alpha参数) （alpha值默认为256,0）（1.1中已废弃）
add1 - alpha在256,128时的透明叠加效果 （1.1中已废弃）
sub - 透明差值效果(以subtractive模式的透明度绘制（alpha值默认为256,256）)

可选参数:
alpha = source_alpha, dest_alpha (整型,整型)
这是addalpha透明类型中alpha的 source(源) 和 destination(目标) 数值.
有效值从0(低)到256(高).缺省默认是256,0.(同air中的ASXXDXX.AS D 就是这个参数的缩写.)

示例:
; 256帧内人物渐入.
type = Trans
trigger1 = time < 256
trans = addalpha
alpha = time, 256-time
(有很多表达式会用到time来实现一些渐变过渡效果,如果实在不明白什么含义,建议依次将几个数值代入time,然后寻找一下规律)


Turn

立即改变玩家的方向.不会播放转身动画.

必要参数:
无

可选参数:
无

示例:
无

特例:
helper锁定和root同一个方向:
[State 0, Turn]
type = Turn
trigger1 = facing != root,facing


VarAdd

增加玩家一个(起作用的)变量(var/fvar)数值.
无论是整型变量还是浮点型变量都能被此控制器增加.

必要参数(对应整型变量):
v = var_no (整型)
var_no指定要影响的变量号.必须是0-59之中的一个整数.

value = int_expr (整型)
int_expr是加到索引号为var_no的整型变量上的值.

必要参数(对应浮点型变量):
fv = var_no (整型)
var_no指定要影响的变量号.必须是0-39之中的一个整数.

value = float_expr (浮点型)
float_expr是加到索引号为var_no的浮点型变量上的值.

可选参数:
上述2种情况都没有.

替代语法:
var(var_no) = int_expr (整型版本)
fvar(var_no) = float_expr (浮点型版本)

注意:
由于历史原因,注意上面列出的VarAdd替代语法,不能在一个表达式内给变量赋值,也不能在一个表达式内增加变量值.
如果你成功击中P2将他置于自定义状态,不要在自定义状态中给变量赋值.否则,你将覆盖P2父级的变量,这将引起对手未知错误.
(也就是说,不要在p2stateno,targetstate指定P2进入的状态里面使用varset,varrangeset,varadd,parentvaradd,parentvarset等等(除非你做整合或者你知道自己在做什么)
否则你设置的其实是P2或者他父级的var/fvar参数,所以将会引起未知错误.)

示例:
无


VarRandom

设定指定整型变量为随机数.浮点型变量不能用此控制器设置.

必要参数:
v = var_no (整型)
var_no是要影响的整型变量索引号.必须是0-59的整数.

可选参数:
range = least_val, greatest_val (整型)
least_val和greatest_val指定此控制器分别指定的最大和最小值.
给变量指定的值是将在这个范围中随机选择的一个整数.
范围默认是[0,1000].如果只指定一个参数,则被认为的指定范围是[0,参数].

注意:
如果你成功击中P2将他置于自定义状态,不要在自定义状态中给变量赋值.否则,你将覆盖P2的变量,这将引起对手未知错误.
(也就是说,不要在p2stateno,targetstate指定P2进入的状态里面使用varset,varrangeset,varadd,parentvaradd,parentvarset等等(除非你做整合或者你知道自己在做什么)
否则你设置的其实是P2或者他父级的var/fvar参数,所以将会引起未知错误.)

示例:
;指定一个0-500之间的随机数给var(5).
type = VarRandom
v = 5
range = 500


VarRangeSet

将玩家一个连续范围内的(起作用的,工作中的)变量设置为相同值.
无论是整型变量还是浮点型变量都能被此控制器设置,但不能同时设置.

必要参数 (对应整型变量):
value = int_expr (整型)
int_expr通过一次性计算指定给所有在此范围中的整型变量的值.

必要参数 (对应浮点型变量):
fvalue = float_expr (浮点型)
float_expr通过一次性计算指定给所有在此范围中的浮点型型变量的值.

可选参数 (两种情况):
first = first_idx (整型)
指定变量设置范围的下限值.默认是0(第一个变量).

last = last_idx (整型)
指定变量设置范围的上限值.整型变量默认是59,浮点型变量默认是39.(这是两种情况最大有效值)

注意:
如果你成功击中P2将他置于自定义状态,不要在自定义状态中给变量赋值.否则,你将覆盖P2的变量,这将引起对手未知错误.
(也就是说,不要在p2stateno,targetstate指定P2进入的状态里面使用varset,varrangeset,varadd,parentvaradd,parentvarset等等(除非你做整合或者你知道自己在做什么)
否则你设置的其实是P2或者他父级的var/fvar参数,所以将会引起未知错误.)

示例:
无


VarSet

设置玩家(起作用的)变量(var/fvar)数值.
无论是整型变量还是浮点型变量都能被此控制器设置,但不能同时设置.

必要参数(对应整型变量):
v = var_no (整型)
var_no指定要影响的变量号.必须是0-59之中的一个整数.

value = int_expr (整型)
int_expr是设置给索引号为var_no的整型变量的值.

必要参数(对应浮点型变量):
fv = var_no (整型)
var_no指定要影响的变量号.必须是0-39之中的一个整数.

value = float_expr (浮点型)
float_expr是设置给索引号为var_no的浮点型变量的值.

可选参数:
上述2种情况都没有.

替代语法:
var(var_no) = int_expr (整型版本)
fvar(var_no) = float_expr (浮点型版本)

注意:
由于历史原因,注意上面列出的给变量赋值的替代语法,不能在一个表达式内给变量赋值.
如果你成功击中P2将他置于自定义状态,不要在自定义状态中给变量赋值.否则,你将覆盖P2的变量,这将引起对手未知错误.
(也就是说,不要在p2stateno,targetstate指定P2进入的状态里面使用varset,varrangeset,varadd,parentvaradd,parentvarset等等(除非你做整合或者你知道自己在做什么)
否则你设置的其实是P2或者他父级的var/fvar参数,所以将会引起未知错误.
这种情况的特例:最典型的就是中毒效果,不断少血.还有就是老版本AI人物(一般AI开关都是var(59)),你可以在自定义状态中设置对手的var(59)=-1000直接关掉对手的AI.- -)

示例:
无


VelAdd

增加玩家速度指定值.
正的x方向速度与玩家朝向相同,正的y方向速度指向屏幕下方.

必要参数:
无

可选参数:
x = x_value (浮点型)
玩家的x方向速度指定的增加值.

y = y_value (浮点型)
玩家的y方向速度指定的增加值.

示例:
; 将引力常数应用到玩家上.
trigger1 = 1
type = VelAdd
y = 0.45


VelMul

将玩家的速度乘以指定的值.
正的x方向速度与玩家朝向相同,正的y方向速度指向屏幕下方.

必要参数:
无

可选参数:
x = x_value (浮点型)
指定乘以玩家x方向速度的值.

y = y_value (浮点型)
指定乘以玩家y方向速度的值.

示例:
; 将摩擦力常量应用到玩家上.
trigger1 = 1
type = VelMul
x = 0.8


VelSet

设置玩家速度为指定值.
正的x方向速度与玩家朝向相同,正的y方向速度指向屏幕下方.

必要参数:
无

可选参数:
x = x_value (浮点型)
设置给玩家的x方向速度的指定值.

y = y_value (浮点型)
设置给玩家的y方向速度的指定值.

示例:
无

注: 在Winmugen中,可以设置z轴,即velset=x,y,z,可是该语法放在mugen1.x中时运行会报错,解决办法是删除z轴参数.


VictoryQuote

从玩家中选择一个胜利引语显示在胜利画面中.

必要参数:
无

可选参数:
value = quote_index (整型)
指定要使用引语的索引.有效值从0到99.如果quote_index为无效的索引,则一个随机的引语将被选择.默认是-1.

注意:
此控制器在比赛中能被任何玩家在任何时间调用.然而,只有获胜的玩家将影响被显示的引语.
此控制器仅影响当前比赛后出现的短暂的胜利画面.helper使用此控制器将无效.
实际的胜利引语是在玩家的cns文件[Quotes]组中指定的.

示例:
无


Width

1帧内暂时改变玩家的宽度尺寸.
当玩家与另一个人接触或与版边接触时用于控制"推挤"的特征.

必要参数:
无

可选参数:
edge = edgewidth_front, edgewidth_back (整型, 整型)
设置玩家前后的edge宽度.edge宽度决定了玩家能有多接近屏幕的边缘.默认值为0,0.

player = playwidth_front, playwidth_back (整型, 整型)
设置玩家前后的player宽度.player宽度决定了玩家能有多接近其他玩家.默认值为0,0.

替代语法:
value = width_front, width_back (整型, 整型)
这是同时设置边缘宽度和玩家宽度的速记语法.这些也许仅被使用在edge和player参数没有指定的时候.

注意:
当显示碰撞块时,设置的edge宽度条显示为橙色,玩家的宽度条显示为黄色.
当它们重叠时,重叠的区域显示为亮黄色.

示例:
无


Zoom

1.1新特性。对游戏进行整体缩放，常用于必杀特写。

必要参数:
无

可选参数:
scale = value (float)
摄像机缩放比例，1为100%，2.5为缩放至原大小的250%，不能小于1，否则会无效。
注意：该比例以当前屏幕缩放(CameraZoom)为基础进行缩放，而不是在CameraZoom=1.0时候。
如当前CameraZoom=0.5，此参数scale=2.5，则最终得到的屏幕缩放比例为：0.5*2.5=1.25，即此时的屏幕大小为125%。
如果人物在不停的上下左右移动，导致CameraZoom数值变化，那么最终的屏幕缩放也会随之变化。
故如果在带有缩放的场景(zoomout zoomin)中使用此缩放时，需要在CameraZoom变化时做相应变化。

pos = x, y(int)
摄像机变焦的位置，该位置相对于场景中心。该位置为绝对屏幕坐标。

lag = value(float)
变焦的速度，大于和等于1会无效(必须大于0，小于1)，数值越小速度越快，数值越大速度越慢。

替代语法:
无

示例1:
[State -2]
type = Zoom
triggerall = !ishelper
trigger1 = win
scale = 1.5
pos = pos x,-15
lag = 0.1

[State -2]
type = Zoom
triggerall = !ishelper
trigger1 = lose
scale = 1.5
pos = (enemy,pos x),-15
lag = 0.1

示例2:
[State -2, 1.5倍缩放,请确保p1在屏幕中央附近]
type = Zoom
triggerall = !ishelper
trigger1 = 1
scale = 1.5/CameraZoom
pos = pos x,pos y
lag = 0.1

示例3:
[State -2, 1.5倍缩放]
type = Zoom
triggerall = !ishelper
trigger1 = 1
scale = 1.5
pos = pos x,pos y
lag = 0.1

[State -2]
type = ScreenBound
triggerall = !ishelper
trigger1 = 1
value = 1


关于控制器

所有状态控制器都有2个可选参数"persistent"和"ignorehitpause",且必须设置成整型常量.
除非另有规定,任何数值型控制器参数都能被指定为算术表达式.
所有情况下,如果用表达式作为参数,请注意表达式不能计算出bottom,此时参数将被设置为0.

AfterImage
AfterImageTime
AllPalFX
AngleAdd
AngleDraw
AngleMul
AngleSet
AppendToClipboard
AssertSpecial
AttackDist
AttackMulSet
BGPalFX
BindToParent
BindToRoot
BindToTarget
ChangeAnim
ChangeAnim2
ChangeState
ClearClipboard
CtrlSet
DefenceMulSet
DestroySelf
DisplayToClipboard
EnvColor
EnvShake
Explod
ExplodBindTime
ForceFeedback
FallEnvShake
GameMakeAnim
Gravity
Helper
HitAdd
HitBy
HitDef
HitFallDamage
HitFallSet
HitFallVel
HitOverride
HitVelSet
LifeAdd
LifeSet
MakeDust
ModifyExplod
MoveHitReset
NotHitBy
Null
Offset
PalFX
ParentVarAdd
ParentVarSet
Pause
PlayerPush
PlaySnd
PosAdd
PosFreeze
PosSet
PowerAdd
PowerSet
Projectile
RemapPal
RemoveExplod
ReversalDef
ScreenBound
SelfState
SprPriority
StateTypeSet
SndPan
StopSnd
SuperPause
TargetBind
TargetDrop
TargetFacing
TargetLifeAdd
TargetPowerAdd
TargetState
TargetVelAdd
TargetVelSet
Trans
Turn
VarAdd
VarRandom
VarRangeSet
VarSet
VelAdd
VelMul
VelSet
VictoryQuote
Width
Zoom


Bound 组

screenleft = min_dist_left
玩家与屏幕左边界允许的最小距离.必须是正值.

screenright = min_dist_right
玩家与屏幕右边界允许的最小距离.必须是正值.

注：这两个数值在不同的localcoord中是不同的,通常在localcoord=320,240情况下,推荐为15--30.
如果是更大的localcoord,一般设置为x轴方向的倍数. 如640,480或640,360情况下,推荐为30--60.
更大的localcoord按照320,240的x轴倍数即可,以此类推.


Camera 组

startx = pos_x
设置摄像机初始x位置.应该被设置成0.

starty = pos_y
设置摄像机初始y位置.应该被设置成0.

boundleft = min_x
这是摄像机能移动到的x坐标最小值.必须是负值.
调整此值可以限制摄像机往左平移多远距离.

注: 该值通常大于[PlayerInfo]组的leftbound.

boundright = max_x
这是摄像机能移动到的x坐标最大值.必须是正值.
调整此值可以限制摄像机往右平移多远距离.

注: 该值通常小于[PlayerInfo]组的rightbound.

boundhigh = min_y
控制摄像机能移动到的y坐标最小值.必须是负值.
调整此值可以限制摄像机往上平移多远距离.

boundlow = max_y
控制摄像机能移动到的y坐标最大值.一般情况必须是0.

tension = h_dist
在摄像机开始跟随玩家(移动)之前玩家能到达版边的水平距离.

tensionhigh = top_dist ; (1.1或更高版本)
通常为正值. 数值越小,摄像机向上跟随玩家的频率和速度越不明显. 反之则反.
摄像机跟随玩家运动前,玩家能到达的距顶部边缘的垂直距离.
使用tensionhigh和tensionlow激活一种(基于1.1版本引进的边界张力)垂直滚动方法.
如果tensionhigh和tensionlow被指定,verticalfollow和floortension将被忽略.

tensionlow = bottom_dist ; (1.1或更高版本)
通常为正值,设置为小于或等于tensionhigh即可.若为0或负值则在屏幕放大之前,屏幕底部优先被移出屏幕显示.
摄像机跟随玩家运动前,玩家能到达的距底部边缘的垂直距离.

verticalfollow = closeness
此值影响摄像机跟随最高点玩家的垂直运动.
此值必须在0到1之间.值为0表示摄像机不会向上运动.值越大使得摄像机追踪玩家越接近.(值越大,位于上方的人物被显示在屏幕内机会更大)
值为1表示摄像机尽可能近的追踪玩家.如果tensionhigh和tensionlow被指定,此值将被忽略.
一般来说,boundhigh(绝对值)越大,verticalfollow也应该越大,反之verticalfollow应该设置较小值.

floortension = v_dist
摄像机跟随玩家向上运动前,最高点玩家能到达的距地面的最小垂直距离(正值形式给出).
此参数仅与verticalfollow一起用于摄像机滚动模式.
如果tensionhigh和tensionlow被指定,此值将被忽略.
数值范围通常在0--boundhigh(绝对值)之间.此数值越高,人物向上运动时摄像机跟随越频繁和灵敏.

overdrawhigh = top_pixels ; (1.0或更高版本)
见下方

overdrawlow = bottom_pixels ; (1.0或更高版本)
屏幕顶部/底部之外被绘制的像素数.envshake期间指定超出绘制多少.
超出绘制的像素也被用于这种情况.(屏幕形状高于舞台形状时)

cuthigh = top_pixels ; (1.0或更高版本)
见下方

cutlow = bottom_pixels ; (1.0或更高版本)
绘制时裁切的屏幕顶部/底部之内的像素数.(屏幕形状低于舞台形状时)
这些只是一个参考值,实际的裁切像素数取决于形状的差异.
如果cuthigh和cutlow被省略,引擎将尝试的给出一个合理值.

startzoom = start_zoom_scale ; (1.1或更高版本)
指定舞台最初的缩放系数.默认是1.

zoomout = zoom_out_scale ; (1.1或更高版本)
指定当摄像机最小缩放时舞台的缩放系数.数值通常介于0.2-1之间.默认为1.

zoomin = zoom_in_scale ; (1.1或更高版本)
指定当摄像机最大缩放时舞台的缩放系数.数值通常大于zoomout,介于0.3-1.x之间.默认为1.

注: 如人物中需要使用ScreenWidth和ScreenHeight来缩放全屏动画的大小,zoomin建议设置为1.


Info 组

name = stage_name
此参数设置舞台名称.必须写在双引号里.

displayname = display_name
此参数设置舞台选择列表中显示的名字.必须写在双引号里.缺省默认为stage_name.

versiondate = version
此参数设置舞台的版本号.能被接受的格式既可以是一个日期(MM,DD,YYYY)也可以使一个x.xx版本号,例如 1.23.
此参数为参考之用,当前不被引擎使用.

mugenversion = mugen_version
此参数设置此舞台用于的MUGEN版本号.有效值是2002,02,14,1.0或1.1.默认2002,02,14.
2002,02,14版本号限制摄像机移动到整个舞台坐标空间单位,而1.0或更高允许摄像机位置设定为分数值.

author = author_name
此参数设置舞台作者名.参数必须写在双引号里.
此参数为参考之用,当前不被引擎使用.


Music 组

bgmusic = bgm_filename ;(可选)
bgm_filename是背景音乐的名字.声音文件一般放置在sound/路径下.
缺省将不播放背景音乐.如果指定的音乐文件不存在,也将不会播放音乐.
若要播放CD音频,写出音轨号然后写上".da".使用音轨号0将随机播放一个音轨.例如,要从CD音乐中播放音轨3,使用bgmusic = 3.da.
缺省默认没有音乐.

bgvolume = volume_offset ;(可选)
此参数调整背景音乐的音量.0是普通,负值变小,正值变大(仅对mp3,mod,cda格式音频起作用).
有效值从-255到255.缺省默认是0.

bgmloop = 1
bgmloopstart = 0
bgmloopend = -1
此3个参数配合可以制作无缝循环BGM.
bgmloop = 1指定此BGM支持循环.
bgmloopstart:此参数指定BGM开始循环的起始位置.在播放一遍BGM之后,便开始从这个位置循环播放.
首先用音频编辑工具打开这段BGM,之后找出这个时间点,以时间形式给出,比如2.234秒这个时间点.
随后用这个时间乘以BGM的采样率,一般都是44100,48000等.上例中2.234*44100=98519.
bgmloopend:与上面参数类似,设置的是循环的结束点,设置-1表示结束点就是BGM播放完的时候.


PlayerInfo 组

p1startx = x_start
设置玩家1初始x位置.

p1starty = y_start
设置玩家1初始y位置.

p2startx = x_start
设置玩家2初始x位置.

p2starty = y_start
设置玩家2初始y位置.

p1facing = facing_flag
控制玩家1初始将面向的方向.设置1面向右,-1面向左.

p2facing = facing_flag
控制玩家2初始将面向的方向.设置1面向右,-1面向左.

leftbound = x_min
设置所有玩家允许到达的最小x位置.

rightbound = x_max
设置所有玩家允许到达的最大x位置.


Reflection 组

reflect = reflect_flag ;(可选)
设置reflect为1使能够反射阴影(俗称倒影效果),0则不能.
反射阴影创建一个"光亮的地板"效果.缺省默认是0.


Shadow 组

intensity = darkness_val ;(可选) (整型)
控制阴影的色深.有效的取值范围是从0(最亮)到256(最暗).缺省默认是128.

color = r,g,b ;(可选) (不推荐用这个参数)
1.1版本开始此参数将被忽略.

yscale = scale_y ;(可选) (浮点型)
阴影的垂直缩放系数.scale_y的值越大使得阴影越长.
你能设置scale_y为负值使影子落在玩家的另一边.缺省默认是0.4.

fade.range = top_y, bot_y ;(可选) (整型,整型)
此参数设置阴影的可见度范围.
用来创建一个阴影可见度渐变效果就像玩家远离地面.
第1个值是上限水平线,第2个是中段水平线.都代表玩家的y坐标.
如果玩家在上限水平线的上方则他的影子将不可见,如果在中段水平线的下方将完全可见.
阴影在两条线之间渐变.缺省默认没有效果(影子总是完全可见).
注意y坐标值是负的,TOP_Y应该小于BOT_Y.

xshear = shear ;(可选) (浮点型)
指定提供给影子的水平切变(变换)数量.正值使影子屏幕朝左边切变.默认是0.


StageInfo 组

zoffset = v_dist
v_dist是地平线与屏幕顶部垂直距离,单位是像素.
zoffset参数是不适当的命名,但为了兼容性所以没改过来.

zoffsetlink = elem_ID
如果指定这个参数,便使得zoffset的值与指定ID号的背景元素y方向位置产生链接.
例如,你能使用sin.y参数链接此值到特定的元素(见其他背景元素类型)使得人物以正弦方式上下摆动.

autoturn = turn_flag
设置为1使得人物自动面向对方.
设为其他值将禁止这种特性.

resetBG = reset_flag
如果设置为1,背景将在每回合之间被重置.如果设置为0,背景将保持上回合状态并继续播放.

localcoord = width, height
舞台坐标空间的尺寸.缺省默认为320,240.

xscale = xscale
偏移量,速度,图片素材和动画 水平方向的缩放系数.

yscale = yscale
偏移量,速度,图片素材和动画 垂直方向的缩放系数.

hires = hi_flag
是Winmugen Plus新添加的选项(兼容mugen 1.x), 使区分低分高分场景成为可能.
hi_flag设置为1时场景缩放系数为0.5倍(即xscale=0.5 yscale=0.5), 设置为0时缩放不变.
注意: 当同时设置了xscale和yscale时, hires会被忽略.


背景控制器

背景控制器操作一个内部计时器.计时器在每回合开始时从0开始计时.每个游戏帧增加1,
当计时器到达控制器起始的时间.则控制器变为激活状态,
当计时器到达控制器结束的时间.则控制器停用,
如果控制器指定了一个正的循环时间.则当循环时间到达时控制器的内部计时器将复位到0,

背景控制器必须以组的形式写在父级BGCtrlDef下,你能使用多个 BGCtrlDef将控制器分成几个组,
每个BGCtrlDef和背景控制器模块可以放置在DEF文件[BGDef]之内的任何位置,
这些模块的一般格式是: (格式类似StateDef)

  • [BGCtrlDef my_controller_name]
    looptime = GLOBAL_LOOPTIME
    ctrlID = DEFAULTID_1, DEFAULTID_2, ...

    [BGCtrl my_controller_1]
    type = CONTROLLER_TYPE
    time = START_TIME, END_TIME, LOOPTIME
    ctrlID = ID_1, ID_2, ...
    (controller-specific parameters here)

    [BGCtrl my_controller_2]
    (等等)

GLOBAL_LOOPTIME指定一个时间帧数.在这个时间之后BGCtrlDef将复位它的内部计时器.以及他包含的所有BGCtrl内部计时器,
要禁止循环时间.设置为-1或者缺省,

DEFAULTID_1, DEFAULTID_2, 等等, 指定将被 没有指定自身ctrlID列表的BGCtrl 影响的 背景元素ID号,
你能为此参数列出最多10个ID号,如果此行缺省.则默认将影响所有背景元素,

START_TIME, END_TIME, LOOPTIME是指定的时间.在这个时间点背景控制器应分别开始激活.停止激活.复位它的内部计时器,
如果LOOPTIME缺省或设置为-1.则背景控制器将不会复位它的计时器,(他的计时器仍然可以被他父级BGCtrlDef复位.只要GLOBAL_LOOPTIME被指定)
背景控制器将在START_TIME和END_TIME中被连续激活,
START_TIME是必要参数.但如果缺省END_TIME则将会默认为和START_TIME的值一样,(因此控制器将仅被触发1帧)

ID_1, ID_2, 等等, 指定此控制器作用于的背景元素ID号,这个列表.如果指定.将覆盖BGCtrlDef中指定的默认列表,
ID最多能指定10个,

下面是BGCtrl类型和它们相关参数的列表:(大多数控制器和状态控制器相似)

  • null
    如其名.此控制器什么也不做,主要用在调试中.当你想短时间使一个控制器无效同时又不想删掉这些代码.就用null.而不必在每行代码前加";",
    把原来的控制器名称换成null同时在原来的名字前加";",此控制器没有其他参数,
  • Visible
    value = visible_flag
    设置元素的可见度状态,激活时.此控制器设置背景元素不可见(=0)或可见(=1),不可见的元素中.计时将不会停止,
    (也就是说.在动画型元素中.即使在不可见的状态.动画仍将持续播放)
  • Enabled
    value = enabled_flag
    设置元素是否被'关闭'(暂时先用这个词吧,,,)
    此控制器要么关闭(禁止)(=0)要么开启(解禁)(=1)背景元素的效果,
    当一个元素被关闭.将是不可见的且它的计时间停止(所以.在动画型元素的情况下.任何动画将停止),
  • VelSet
    x = vel_x
    设置元素x方向速度,
    y = vel_y
    设置元素y方向速度,
    此控制器将设置 被影响的背景元素 x/y方向速度 为指定的值,
    速度单位是 像素/游戏帧,你能在x,y参数中指定1个或2个数值,
    缺省任何一个.元素在此方向的速度将不变,
  • VelAdd
    x = vel_incr_x
    改变元素x方向速度,
    y = vel_incr_y
    改变元素y方向速度,
    此控制器将增加 被影响的背景元素 x/y方向速度 指定的值,
    你能在x,y参数中指定1个或2个数值,
    缺省任何一个.元素在此方向的速度将不变,
  • PosSet
    x = pos_x
    设置元素x方向位置,
    y = pos_y
    设置元素y方向位置,
    此控制器将设置 被影响的背景元素 x/y方向坐标 指定的值,
    你能在x,y参数中指定1个或2个数值,
    缺省任何一个.元素在此坐标方向的位置将不变,
  • PosAdd
    x = x_displacement
    替换元素x方向位置,
    y = y_displacement
    替换元素y方向位置,
    此控制器将替换 被影响的背景元素 x/y方向坐标 指定的值,
    你能在x,y参数中指定1个或2个数值,
    缺省任何一个.元素在此坐标方向的位置将不变,
  • Anim
    value = action_no
    改变 受影响元素 显示的动画到指定动画号,
  • SinX
    value = amplitude, period, offset
    改变受影响元素正弦运动x方向的振幅.周期和相位偏移,
    此参数效果和背景元素参数中的sin.x相同,
  • SinY
    value = amplitude, period, offset
    改变受影响元素正弦运动y方向的振幅.周期和相位偏移,
    此参数效果和背景元素参数中的sin.y相同,


背景元素格式

下面是一个指定静态背景元素的例子:

  • [BG my_element_name]
    type = normal
    spriteno = 0,0
    start = 0,0
    delta = .5, .5
    mask = 0

此例将背景SFF文件中的0,0图像素材显示在0,0这个初始位置上.
摄像机每移动1单位,图像就移动0.5个舞台单位.

每个背景元素由[BG my_element_name]开头的一个组定义.
my_element_name需要用一个顾名思义的名字来替代,报错的时候将会显示这个名字.

下面将定义参数.


背景元素说明

通常一个背景有n个被定义的图像素材组成,定义图像素材就是定义图像的位置,速度,形式(图片形式,动画形式...)等等.(通俗来说背景就是很多元素拼接起来的)

定义舞台的背景元素,你必须首先在DEF文件末尾新建一个BGDef组.格式如下:

  • [BGDef]
    spr = stages/my_stage.sff
    debugbg = 1

把stages/my_stage.sff与包含你舞台图像素材的SFF文件放在一个路径中.
为了确保良好的运行速度,当你舞台完成时记住设置debugbg = 0.

一旦BGDef定义被新建,[BGDef]下面的所有东西都被认为是属于BGDef章节中的.
在BGDef章节中,你应该最少指定1个背景元素.
背景元素按它们出现在DEF文件中的顺序被绘制(后绘制的元素显示在先绘制的元素上方),所以最下方(最下层)的元素应该最先被定义.

(形象思考:如果我要画一幅画,首先我在一张草稿纸上先写上我画画的步骤:
1.绘制树木
2.绘制轿车
3.绘制美女
通过草稿纸上的1.2.3顺序来绘图,先画树木,再画轿车,再画美女.很容易就明白为什么上面说DEF先出现的背景元素绘制在后出现的背景元素下方.
当然,如果你把上述1.2.3每一步都绘制在一张完全透明纸上,即将树木绘制在透明纸上,然后放置在画布上,轿车绘制在另一张透明纸上,美女也是,最终按照这个顺序叠加在一起放置在画布上.
看上去的效果和没有用透明纸时是一样的,但是用了透明纸,我可以随时对每张透明纸进行修改同时不会影响其他透明纸上的东西.
比如我要在轿车上加上法拉利标志,如果没用透明纸,且标志所在的位置被美女挡住了一半,就很难绘制,如果用了透明纸,就能单独把轿车分离出来绘制,绘制完再把透明纸塞到原来的地方,甚至可以改变透明纸叠加的顺序.
背景元素绘制处理方式和透明纸很类似,当然说这些话只是为了有助于对绘制顺序的理解,在其他绘图软件中,透明纸就类似于'图层'.)


动画型背景元素

指定动画型背景元素的格式几乎完全和静态型背景元素相同.
下面将介绍:

  • [BG my_animated_element]
    type = anim
    actionno = 55
    (除了spriteno之外的所有参数都与静态性背景元素相同)

首先,要使元素成为一个动画型,必须指定类型为anim.其次,必须指定动画号(actionno).
这个地方代替了原来静态性元素的spriteno参数.
actionno的值必须是定义在此DEF文件中的一个动画.
在此例中,因为actionno是55,所以55号动作必须以类似下面的方式被定义:

  • [Begin Action 55]
    0,0,0,0,5
    0,1,0,0,5

格式同指定在air文件中的动画是相同的,所以详细过程就省略了.
动作定义可以写在源[BGDef]组下面任何位置.
典型的做法是即可以在他所属的元素下方立即定义,也可以把用到的所有动作都写在一起,位置放在[BGDef]组的开始或者末尾处.

注意动画中使用的每张图片素材都有它自己的坐标.(SFF文件中指定)
当播放动画时,每张图片素材的坐标将被排列,对应背景元素自身的坐标.

tilespacing参数效果对于动画型元素和普通型元素是不同的.
对于普通型元素,此参数的x值指定了第1次平铺的右边缘与第2次平铺的左边缘之间的水平距离.
在任何动画型元素中,x值指定了第1次平铺的左边缘与第2次平铺的左边缘之间的水平距离.
y方向也相似.产生不同的原因在于动画的尺寸未必是常量.(因为图片是静态的,所以尺寸是常量,动画是图片构成的,每张图片尺寸不一定相同)
tilespacing需要动画型元素使用平铺参数的这种特征.

动画型和普通型元素最后一个区别是动画型元素总是有mask = 1.

其他参数请参阅 背景元素高级参数.


概述

注:background-背景,stage-舞台(也俗称背景),background element-背景元素

MUGEN中的背景至少包含一个背景元素,可能含有背景控制器.
这些与舞台设定结合在一起制造出MUGEN中使用的舞台的外观和功能.

舞台设定控制器一般的参数,如:舞台的尺寸,摄像机的运动,人物和摄像机相对于舞台的起始位置,阴影颜色,地面反射(倒影),等等.
大多数格斗游戏在构建的舞台中主要包含这些背景参数的值,尤其是有关舞台尺寸和摄像机运动.

一个背景元素是显示在屏幕上的图像数据的个体单位.所有舞台的可见区域是用背景元素建立的.
每个背景元素都要单独设置图片数据,透明类型,位置,平铺,相对于摄像机的滚动速度,动画(如果适用)
当滚动摄像机时视差型元素增加光栅效果.背景元素可以是任何尺寸,在实际中,背景经常是由几个中等大小尺寸的元素拼接而成的.

背景控制器将在背景元素上执行额外操作,例如改变它的位置或速度,使他可见或不可见等等.
背景控制器的应用包括使人物在背景中来回漫步,使碎片在屏幕上飞溅,或者在设定的时间使背景发生改变(如当人物在船上格斗时进入一个洞穴).
一般来说,背景控制器能允许你给舞台创建更多特效或优化某些动画减少内存消耗,虽然很多舞台没有使用任何控制器也做的非常好.

当创建一个舞台时,你必须确保屏幕可见区域任何时候都被背景元素"覆盖".
如果在背景中遗留空洞将引起那个位置霍氏镜像效应.(如果背景中有区域没有任何图像覆盖,不妨自己试试会是什么效果...)
开启调试参数将使用品红色亮影填满所有的洞,也将帮助你确定位置和填补它们.

除了在舞台中的明显用途,背景对象被用于MUGEN中所有系统画面的背景,如标题画面和人物选择画面,同样也使用在故事背景中.
这些类型的背景("系统背景(俗称画面包)""故事背景")是有区别的.用于舞台的背景对象被称为"舞台背景".
除了它们预期的作用,不同类型的背景实质上没有区别.此文囊括了舞台设定以及背景对象格式.


背景元素高级参数

这些参数能用于任何背景元素. (即 静态型背景元素, 动画型背景元素, 视差型背景元素, 其他背景元素类型.)

trans = trans ; (可选) (字符串型)
指定图形运用的透明混合效果.透明模式为default, none, add, sub.
这些分别表示 默认特征,没有透明效果,颜色叠加,颜色相减.
default和none都会引起非动画型元素没有透明混合效果.
对于动画型背景元素,指定default将使用动画指定的透明混合效果,而其他的透明值将覆盖动画中的透明标示.
如果指定了add,可能需要适用alpha参数来控制混合效果.默认值是default.

注意:如果mugen版本是1.0以下,对动画型元素来说default和none特征相同.

alpha = src_alpha,dst_alpha ; (可选) (整型,整型)
参见trans控制器相关参数.

id = id_number ; (整型)
给背景元素指定一个ID号.不同的元素可以共享相同ID.
ID号作用是允许背景控制器指定要操作哪个元素.缺省默认是0.

positionlink = link_flag ; (布尔型)
设置positionlink为1可以固定此元素的位置到DEF文件中紧挨着它的另一个元素的位置.
如果设置为1,当前元素start参数值被视为是与上一个元素位置的偏移量.
delta参数在此情况下降无效.用于使一大堆元素整齐一致的运动.
如果你编辑positionlink链中的第一个元素的start和delta值,效果将在整个链中的所有元素中都体现出来.
缺省默认为0.

maskwindow = x1,y1,x2,y2 ; (整型,整型,整型,整型) (1.1或以后版本)
给背景元素指定一个遮罩窗口.一个遮罩窗口是屏幕上一个包含此图像的概念矩形.
任何超出这个矩形的图像部分都不会显示出来.
x1,y1指定了窗口的左上角坐标,x2,y2 指定了窗口右下角坐标.此坐标相对于舞台原点中心(屏幕的顶部中心点).
缺省将不执行.

window = x1,y1,x2,y2 ; (整型,整型,整型,整型) (废弃)
此废弃参数仍可用,但不保证在缩放的时候准确性.
指定了一个相对于屏幕右上角坐标的遮罩窗口,端点也包含在内.

windowdelta = window_dx,window_dy ; (浮点型,浮点型)
指定遮罩窗口的delta运动.运行方式和背景元素自身的delta参数差不多.默认为0,0.

scalestart = scale_x, scale_y ; (浮点型,浮点型)
初始缩放值.默认为1,1.

scaledelta = scale_dx, scale_dy ; (浮点型,浮点型)
和delta参数相似,这是摄像机每移动1个单位元素缩放量.默认为0,0.

velocity = vel_x, vel_y ; (浮点型,浮点型)
指定背景元素初始x,y方向速度.(默认为0)
此功能在背景控制器VelSet中也包含.

zoomdelta = dzoom ; (浮点型)
指定摄像机缩放影响元素缩放的量.0表示元素在缩放时不改变尺寸,1表示元素在缩放时和摄像机缩放系数相同.默认为1.

sin.x = amplitude, period, phase ; (浮点型,浮点型,浮点型)
指定元素在x方向的正弦运动.
第1个参数是振幅,第2个参数是运动周期(帧数),第3个参数指定初始正弦运动的相位偏移.(默认是0,例如,元素将正弦范围正中时开始运动)
这参数基本上被SinX背景控制器取代了.

sin.y = amplitude, period, phase ; (浮点型,浮点型,浮点型)
运行方式和sin.x相同,只是y方向.


关于背景和舞台

内容

  • 概述
  • 舞台设定说明
    • Info 组
    • Camera 组
    • PlayerInfo 组
    • Bound 组
    • StageInfo 组
    • Shadow 组
    • Reflection 组
    • Music 组
  • 背景元素说明
    • 背景元素格式
    • 静态型背景元素
    • 动画型背景元素
    • 视差型背景元素
    • 高级参数
    • 其他背景元素类型
  • 背景控制器
  • 简单举例


简单举例

假设我们要创建一个从(-300,0)到(300,0)来回走动的人,正好在主人物的后面.
我们将使用背景控制器来打到目的.

首先定义行走动画.人物的行走图像是从10,0到10,3,朝右.

  • ; Walk right
    [Begin Action 10]
    10,0,0,0,6
    10,1,0,0,6
    10,2,0,0,6
    10,3,0,0,6

    ; Walk left
    [Begin Action 11]
    10,0,0,0,6,H
    10,1,0,0,6,H
    10,2,0,0,6,H
    10,3,0,0,6,H

现在把这个角色放置在他范围的左边缘.

  • [BGDef]
    (...)

    [BG Peregrinator]
    type = anim
    actionno = 10
    id = 10
    start = -300, 0
    delta = 1,1

设置速度为每帧2像素.单程是600像素,所以要用去300帧.所以,一个来回要600帧.
运用这个知识,适当的设置背景控制器:因为每600帧重复这个情况,我们设置全局循环时间为600.

  • [BGCtrlDef Peregrinator]
    ; reset the whole deal every 600 ticks.
    looptime = 600
    ctrlID = 10

    ; Set velocity of 2 pixels/sec rightward at time 0.
    [BGCtrl Walk Right]
    type = VelSet
    time = 0
    x = 2

    ; Set velocity of 2 pixels/sec leftward at time 300.
    [BGCtrl Walk Left]
    type = VelSet
    time = 300
    x = -2

完成!如果能使人物在走到尽头时速度放缓同时显示一个转身的动作那就看起来更好了.这要用到VelAdd和Anim控制器
如果要人物定期停止,启动.你需要创建更多的velset,anim控制器,设置单独的循环时间.


静态型背景元素

type = normal ; (必要) (字符串型)
指定这个背景元素是静态图片素材,既不是动画型也不是视差型. (normal-普通,所以也称普通型)

spriteno = groupno, imageno ; (必要) (整型,整型)
groupno, imageno在背景元素中显示的SFF文件中的图像素材.

layerno = layer ; (可选) (整型)
如果layerno = 0,则此背景元素绘制在人物下方.
如果layerno = 1,则此背景元素绘制在人物上方.
在背景元素层绘制顺序方面,是按照DEF文件中出现的顺序,从底层到顶层绘制.layerno默认为0.

start = x,y ; (可选) (浮点型, 浮点型)
指定背景元素(相对于屏幕顶部中心)初始位置.(正y朝下)
背景元素的坐标原点就在这个地方.缺省默认是0,0.

delta = dx,dy ; (可选) (浮点型, 浮点型)
摄像机水平,垂直方向每移动1像素时背景元素应该移动多少像素.
设置 delta=1,1 将导致背景元素与摄像机移动速度相同.这对于脚下地面来说是合适的.
对于远景中的元素,将delta的值设置的小一点来创建深度错觉.
相同的,前景中的(layerno=1)元素一般设置的delta值大于1.
可以把delta的值设置成负数,但是会有意想不到的效果.缺省默认为1,1.

mask = mask ; (可选) (布尔型)
如果设置为1,图片色表上的0位置颜色将不会绘制出来.用来绘制不规则形状的物体.(也就是色表最后一格颜色会透明)
由于运行速度的关系,当不需要时尽量将mask设置为0.默认为0.

tile = x_tile,y_tile ; (可选) (浮点型, 浮点型)
分别设置背景元素在水平,垂直方向是否被平铺.
0表示不平铺,1表示无限平铺,若tile大于1,比如tile=3,表示元素被平铺3次.
缺省默认不平铺.(主要用于制作无缝背景,以及使背景能平移)

tilespacing = x_spacing,y_spacing ; (可选) (整型,整型)
如果设置了元素可以平铺,此参数分别指定平铺时相邻两张实例图片的水平,垂直间隔.
如果不可以平铺,则此参数无效.tilespacing默认为0,0.

其他参数请参阅 背景元素高级参数.


其他背景元素类型

除了普通型.动画型.视差型背景元素类型.还有一个dummy(虚拟)类型.
人如其名.一个虚拟型背景没有相关的图形.一个虚拟型元素的位置就像被 随便其他什么任何元素类型 影响.
当前.虚拟元素的唯一用途是作为StageInfo组中zoffsetlink参数作用的一个占位符.


视差型背景元素

视差型背景元素给出了元素显示的深度幻觉,看上去像是脸朝上或朝下.
视差型背景元素应由指定spriteno参数的单张图片组成.
在1.1或更高版本中,视差型背景元素也能使用指定actionno参数的动画,就像普通的动画型背景元素.
动画型视差背景元素也许不能使用xscale参数.

格式如下:

  • [BG my_parallax_element];1.1之后
    type = parallax
    spriteno = 10, 0
    width = 300, 600
    scalestart = 1,1
    scaledelta = 0,.001

另一个例子:

  • [BG my_parallax_element];1.1之前
    type = parallax
    spriteno = 10, 0
    xscale = 1,1.5
    yscalestart = 100;废弃
    yscaledelta = 1.2;废弃

width = top_width, bottom_width ; (整型, 整型)
top_width和bottom_width分别指定了这个梯形顶部/底部的宽度,高度和图像的高度是一样的.
图像将通过变形来匹配这个梯形的尺寸.
当摄像机移动时从top_width到bottom_width的变化比例将影响切变量.
如果不想对图像透视变形预处理就使用width.
由于历史原因,SFF中指定的x坐标被忽略了(用图形的水平中心作为中心点).

xscale = top_xscale, bottom_xscale ; (浮点型, 浮点型) (废弃)
top_xscale和bottom_xscale分别缩放背景元素顶部/底部边缘的水平delta效果,创建一个水平切变效果.
delta = .75, .75和xscale = 1, 2指定了摄像机每移动1单位,图像顶部移动.75 * 1 = .75舞台单位,图像底部移动.75 * 2 = 1.5舞台单位.
此例假定图像坐标轴为图像的顶部.

要么指定xscale要么指定width,但不能同时指定.
如果图像已经透视变形预处理了就使用xscale.
硬件加速渲染将在极端切变角上产生视觉假象.

使用xscale参数后动画型视差背景也许会无效.

yscalestart = yscalestart ; (浮点型) (废弃)
此废弃的参数控制着当摄像机垂直移动时元素的垂直缩放变化.
他的功能被多用途的scalestart和scaledelta高级参数替代.

yscalestart是当摄像机在地平线上时图像垂直逆缩放,用百分比表示.
例如,值100对应缩放系数是1,50对应缩放系数为2.默认值是100.

yscaledelta = yscaledelta ; (浮点型) (废弃)
摄像机向下运动每个摄像机单位时,反向缩放系数增加的指定量,体现为百分比.
最终计算出的系数看下面的公式:

  • scale = 1 / (yscalestart/100 + yscaledelta/100 * camera_y)

上面的例子,如果摄像机向上移动1单位,缩放系数将是1 / (1.00 + .012 * -1) = 1.012,如果又移动了1单位,缩放将是1 / (1.00 + .012 * -2) = 1.025等等.

yscalestart和yscaledelta参数非直观的特征是由于历史原因造成的.

注意:
其他静态元素的参数对视差型元素也有效,除了tilespacing.
此外,y_tile强制为0.

在动画型视差背景元素中指定一个角度将导致undefined.

动画型视差背景不支持软件渲染.

其他参数请参阅 背景元素高级参数.


舞台设定说明

舞台设定定义了背景与舞台的关系.舞台设定和背景必须在相同的舞台文件中.
构成舞台设定的是一些组.它们是:

(所有的参数都是必要的,除非指明"可选")


Abs (math)

计算参数的绝对值.

格式:
abs(表达式)

参数:
表达式
需要计算绝对值的表达式:

返回值类型:
和表达式相同的类型.

错误条件:
如果表达式计算出bottom则返回bottom.


Acos (math)

计算指定参数的arccosine(反余弦)(用弧度制表示).

格式:
acos(表达式)

参数:
表达式
需要计算反余弦的表达式(浮点型).

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom则返回bottom.
或者exprn不在反余弦的定义域内(从-1到1即[-1,1]).

示例:
value = acos(1)
计算1的反余弦值,近似值为0.0.(可能会有一些舍入误差)

注:
acos(exprn)的值域是[0,π].


AILevel

返回玩家的AI难度等级.

格式:
AILevel

参数:
无

返回值类型:
整数型

错误条件:
无

详情:
如果玩家开了AI,AILevel的范围是从1(最简单)到8(最难).
如果玩家没开AI,AILevel返回0.

示例:
trigger1 = Random < AILevel * 10
AILevel为1的时候有10%的可能触发.
AILevel为2的时候有20%的可能触发.
等等...

注意事项:
如果当前Player是Helper,返回的是Helper的难度等级而不是人物本体的! 解决办法是加上重定向前缀: root,AILevel


Alive

如果玩家被KO了就返回0,否则返回1.

格式:
Alive

参数:
无

返回值类型:
布尔型整数(1或者0)

错误条件:
无

示例:
trigger1 = Alive = 0
如果玩家被KO了就触发.


Anim

返回玩家当前的动画号.

格式:
Anim

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = Anim = 200
如果玩家当前的动画号是200则触发.


AnimElem(*,***)

获得从当前动画动作指定元素开始逝去的动画时间.
用于动画动作元素的同步事件.
记住:动作元素的起始是1不是0.

AnimElemTime与AnimElem有相似的功能, 但AnimElemTime可以用表达式作为参数.

首先注明:
element按照直译是元素的意思,动画元素就是指组成动画的图片.

格式:
AnimElem = 值1
AnimElem = 值1, [运算符] 值2

参数:
[运算符]
=, !=, <, >, <=, >=

值1 (整型)
检测元素号.

值2 (整型)
用来比较的动画时间值.

返回值类型:
布尔整数型(1或0)

错误条件:
如果这个动作指定元素号不存在(比如太大或者太小)则返回bottom.

详情:
如果玩家的动画在指定值1元素号的起始则格式1为真.
换句话说,如果值1等于n,则该动画的第n个元素首个game-tick(游戏帧)为真.

格式2比较玩家的动画时间到t+值2,这里的t指的是值1指定元素号的起始animation-time(动画时间).

注意:
AnimElem在一个有限循环次数的动画的第二次或者更后面次数循环的首个game-tick不会触发.
(简而言之就是第一次条件合格会触发,然后循环情况下会无视)
例如,"AnimElem=1"在动画改变时的首帧会触发,循环的时候则不会触发.
如想让这种情况下也能触发,你得每次都使用"AnimElem = 1 || AnimTime = 0".

示例:
trigger1 = AnimElem = 2
动画的第2元素首帧为真.也就是:
trigger1 = AnimElem = 2, = 0

trigger1 = AnimElem = 2, = 4
动画的第2元素首帧过后的第4帧为真.

trigger1 = AnimElem = 2, >= 0
trigger1 = AnimElem = 3, < 0
动画的整个第2元素都为真,假设有第3个元素存在.
如果不存在第3个元素,那
trigger1 = AnimElem = 3, < 0
就等同于
trigger1 = AnimTime <= 0

特例:
AnimElem = 2, = 0 相当于AnimElemTime(2) = 0
AnimElem = 2, > 0 相当于AnimElemTime(2) > 0

格式:
Animelem格式写法:
假设一个动画由3张图构成,第1张图有2帧,第2张图有3帧,第3张图有4帧.

第1张图首帧:(帧数都是从0开始的,元素号从1开始)
animelem=1;
animelem=1,0;
animelem=1,=0;

第1张图第2帧:
animelem=1,1;
animelem=1,=1;

表示第2张图开始的帧:
animelem=2,>=0;

表示第3张图之前的帧:
animelem=3,<0;

表示第2张图开始第3张图之前的帧:
animelem=2,>=0&&animelem=3,<0;
animelem=2,[0,2] ;
animelem=2,=[0,2];


AnimElemNo (math)

返回将在指定时间播放的当前动作的动画元素号.
AnimElemNo的参数表示需要检测的时间,这个时间在这里用游戏帧来表示.

首先注明:
element按照直译是元素的意思,动画元素就是指组成动画的图片.

格式:
AnimElemNo(表达式)

参数:
表达式
表达式表示计算出的时间偏移量(整型).

返回值类型:
整型

错误条件:
如果试图检测在当前动画开始前结束的时间则AnimElemNo(表达式)返回bottom.

注意:
如果动作正处于循环部分,且假定已永久循环.
这就是说,无论之前检测了多久,AnimElemNo将总是返回这个动作循环部分中的一个元素号.

示例:
trigger1 = AnimElemNo(0) = 2
当动画元素经过0帧之后是第2个元素则为真.
这等同于:
trigger1 = AnimElem = 2, >= 0
trigger1 = AnimElem = 3, < 0

trigger1 = AnimElemNo(2) = 4
当动画元素经过2帧之后是第4个元素则为真.
这等同于:
trigger1 = AnimElem = 4, >= -2
trigger1 = AnimElem = 5, < -2


AnimElemTime (math)

获得从当前动画动作指定元素开始逝去的动画时间.
用于动画动作元素的同步事件.
记住:动作元素的起始是1不是0.

首先注明:
element按照直译是元素的意思,动画元素就是指组成动画的图片.

格式:
AnimElemTime(表达式)

参数:
表达式
计算出要检测元素号的表达式.(整型)

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.
如果表达式计算出的当前动作元素号不存在则AnimElemTime(表达式)返回bottom.

注意:
AnimElemTime在一个有限循环次数的动画的第二次或者更后面次数循环的首个游戏帧不会触发.
例如,"AnimElemTime(1) = 0"在动画改变时的首帧会触发,循环的时候则不会触发.
如想让这种情况下也能触发,你得每次都使用"AnimElemTime(1) = 0 || AnimTime = 0".

示例:
trigger1 = AnimElemTime(2) = 0
动画的第2元素首帧为真.也就是:
trigger1 = AnimElem = 2

trigger1 = AnimElemTime(2) = 4
动画的第2元素首帧过后的第4帧为真.

trigger1 = AnimElemTime(2) >= 0
trigger1 = AnimElemTime(3) < 0
动画的整个第2元素都为真,假设有第3个元素存在.
如果不存在第3个元素,那第2行也就等价于:
trigger1 = AnimTime <= 0

特例:
AnimElemTime(2) = 0相当于AnimElem = 2, = 0
AnimElemTime(2) > 0相当于AnimElem = 2, > 0

更多详情请查看AnimElem触发器.


AnimExist (math)

如果指定的玩家动作存在则返回1.
如果玩家被成功击中,进入了自定义的状态则这个触发器的结果是"未定义的".
在这种情况下请使用SelfAnimExist.

格式:
AnimExist(表达式)

参数:
表达式
计算出动作号的表达式(整型).

返回值类型:
布尔型整数 (1或0)

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
trigger1 = !AnimExist(200)
如果玩家不存在200号动作则触发.

请参阅: ChangeAnim.


AnimTime

给出了当前动画动作的循环时间与玩家的animation-time(动画时间)的不同.
对了解距动画结束还有多久(何时动画会结束)有帮助.
(animation-time(动画时间)用游戏帧来体现,表示玩家在当前动画中经过的时间).
这名字也许会引起混乱.
尝试把它思考成"距离动画结束的时间".
在这段动画中,AnimTime将总是返回一个非正数.

格式:
AnimTime

参数:
无

返回值类型:
整数型

错误条件:
无

示例:
trigger1 = AnimTime = 0
当动画时间等于动作的循环时间时触发,即动作已结束.


Asin (math)

计算指定参数的反正弦值(用弧度制表示).

格式:
asin(表达式)

参数:
表达式
要计算反正弦的表达式(浮点型).

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom,或者表达式不在反正弦的定义域内(从-1到1即[-1,1])则返回bottom.

示例:
value = asin(1)
设置value的值为1的反正弦,约为π/2.
(可能会有一些舍入误差).

注:
反正弦值域为[-π/2,π/2].


Atan (math)

计算指定参数的反正切(用弧度制表示).

格式:
Atan(表达式)

参数:
表达式
要计算反正切的表达式(浮点型).

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
value = atan(1)
设置value的值为1的反正切,约为π/4.
(可能会有一些舍入误差).

注:
反正切值域为[-π/2,π/2].


AuthorName (*,***)

返回玩家的作者名(在.DEF文件中指定).
这也可能在区分相同名字不同作者的人物上有用.

格式:
AuthorName [运算符] "name"

参数:
[运算符]
=,!= (其他运算符无效)

"name" (字符串型)
要进行比较的名字,必须写在双引号里面.

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = Authorname = "Suika"
如果人物作者的名字是Suika则为真.


BackEdge

BackEdge返回玩家后方屏幕边缘X轴方向位置(背景舞台的绝对坐标).

格式:
BackEdge

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
此触发器与表达式"ifelse(facing = 1, LeftEdge, RightEdge)"相同.

示例:
trigger1 = Pos X + CameraPos X < BackEdge
如果玩家在后方屏幕边缘则左面触发.


BackEdgeBodyDist

BackEdgeBodyDist给出了玩家后方(由他的宽度条后端决定)到后方屏幕的边缘距离.

格式:
BackEdgeBodyDist

参数:
无

返回值类型:
浮点型

错误条件:
无

示例:
trigger1 = BackEdgeBodyDist < 30
如果玩家宽度条末端到屏幕后方的距离在30像素之内(也就是和屏幕后方边缘的距离)则触发.


BackEdgeDist

BackEdgeDist给出了玩家(坐标中心)与他后方屏幕边缘X轴方向的距离.

格式:
BackEdgeDist

参数:
无

返回值类型:
浮点型

错误条件:
无

示例:
trigger1 = BackEdgeDist < 30


BottomEdge

BottomEdge返回屏幕底部边缘y轴位置(绝对舞台坐标).

格式:
BottomEdge

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
此触发器与表达式"Pos Y - ScreenPos Y + GameHeight"相同.

示例:
trigger1 = Pos Y < BottomEdge
如果玩家在屏幕底部边缘上方则触发.
(目测用于检测玩家或者地面是否已在屏幕下方,由于缩放背景,摄像机移动太高等关系)


CameraPos

获得摄像机相对于舞台背景的位置.

格式:
CameraPos [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
无

详情:
摄像机原始位置是0,0
摄像机往右移动的时候"CameraPos X"的值增加.
摄像机向上移动的时候"CameraPos Y"的值减少.
位置的单位用玩家设置的坐标空间表示.

示例:
trigger1 = CameraPos X >= 0
摄像机在舞台背景中心右侧为真.


CameraZoom

获得摄像机缩放系数的值.

该数值介于场景(stage)中定义的zoomin和zoomout之间(这两个值的当前实际值).

格式:
CameraZoom

参数:
无

返回值类型:
浮点型

错误条件:
无

示例:
fvar(1) = ScreenWidth / CameraZoom
将fvar(1)设置为屏幕左右边缘之间的距离.
表达式"ScreenWidth / CameraZoom"与GameWidth触发器返回值相同.即:
GameWidth = ScreenWidth / CameraZoom
GameHeight = ScreenHeight / CameraZoom


CanRecover

当玩家正处于fall(下落)状态中,如果他当前可以recover(恢复,受身)则返回1,否则返回0.
如果玩家不处于fall状态,触发器将显示undefined.

格式:
CanRecover

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无


Ceil (math)

实现"ceiling(向上取整)"函数.
返回大于或等于指定参数的最接近整数.

格式:
ceil(表达式)

参数:
表达式
需要计算向上取整的表达式.

返回值类型:
整型

错误条件:
返回bottom如果表达式计算出bottom.

示例:
1. value = ceil(5.5)
设置value的值为6.
2. value = ceil(-2)
设置value的值为-2.


Command (*,***)

如果玩家输入指定的指令则触发.

格式:
Command [运算符] "指令的名称"

参数:
[运算符]
=,!= (其余运算符无效)

"指令的名称" (字符串型)
指令的名称.指令定义在玩家的CMD文件中,是区分大小写的.
如果CMD中多个指令拥有相同的名称,那么他们中的任何一个都将被执行.
指令的名称必须写在双引号里面.

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = Command = "fireball motion"
如果用户输入的指令正好对应上了"fireball motion"这个指令名称则为真.


Cond (math)

此触发器由3个参数构成.
第1个参数是条件参数.如果条件为真(即非0),Cond计算并返回第2个参数.
如果第1个参数为假,Cond计算并返回第3个参数.
如果条件是bottom,那么Cond返回bottom而不需要计算第2个第3个参数.

在所有情况下,任何未使用的参数就不需要计算了.
因此,Cond可以用来代替ifelse而避免任何由于计算不需要使用的参数而所引起的副作用.
(比如说,给变量赋值或执行一次会产生bottom的计算)

Cond仅支持mugen1.0及以上的版本. 而ifelse支持所有mugen版本.

格式:
Cond(exp_cond,exp_true,exp_false)

参数:
exp_cond
需要测试的表达式

exp_true
如果 exp_cond 为非0则返回此表达式指定的值.

exp_false
如果 exp_cond 为0则返回此表达式指定的值.

返回值类型:
如果 exp_true 被返回,则返回类型和 exp_true 相同.
如果 exp_false 被返回,则返回类型和 exp_false 相同.

错误条件:
返回bottom如果 exp_cond 计算出bottom,
或者 exp_true 或 exp_false (任何一个被使用了) 计算出bottom.

示例:
value = Cond(var(3),1,2)
当var(3)是非0时,value值为1.
当var(3)是0时,value值为2.

特列:
ifelse可以用Cond来代用(反过来也可)
Cond(var(3),1,2)相当于ifelse(var(3),1,2)

两者的区别请查看表达式部分关于bottom中特殊格式的章节.


Const (*)

返回玩家的一些常数.

格式:
Const(参数名)

参数:
参数名
需要检测的常数名.有效参数为:

返回值类型:
取决于指定的打击参数.查看详细信息.

错误条件:
无

详细信息:
下面参数名的值将返回玩家的cns中[Data]组中指定的值.

  • data.life:返回"life(生命值)"参数值. (整型)
  • data.power:返回"power(能量值)"参数值. (整型)
  • data.attack:返回"attack(攻击力)"参数值. (整型)
  • data.defence:返回"defence(防御力)"参数值. (整型)
  • data.fall.defence_mul:返回defence multiplier(防御系数值),公式为 100/(f+100),这里的f指的是"fall.defence_up"参数.(浮点型)
  • data.liedown.time:返回"liedown.time(倒地起身时间)"参数值. (整型)
  • data.airjuggle:返回"airjuggle(控制连击的参数)"参数值. (整型)
  • data.sparkno:返回"sparkno(火花号)"参数值. (整型)
  • data.guard.sparkno:返回"guard.sparkno(防御火花号)"参数值. (整型)
  • data.KO.echo:返回"KO.echo(被KO时有没有回声)"参数值. (整型)
  • data.IntPersistIndex:返回"IntPersistIndex(控制var参数初始化)"参数值. (整型)
  • data.FloatPersistIndex:返回"FloatPersistIndex(控制fvar参数初始化)"参数值. (整型)

下面参数名的值将返回玩家的cns中[Size]组中指定的值.

  • size.xscale:返回"xscale(x方向缩放)"参数值. (浮点型)
  • size.yscale:返回"yscale(y方向缩放)"参数值. (浮点型)
  • size.ground.back:返回"ground.back(后方宽度)"参数值. (整型)
  • size.ground.front:返回"ground.front(前方宽度)"参数值. (整型)
  • size.air.back:返回"aie.back(空中后方宽度)"参数值. (整型)
  • size.air.front:返回"aie.front(空中前方宽度)"参数值. (整型)
  • size.height:返回"height(高度)"参数值. (整型)
  • size.attack.dist:返回"attack.dist(攻击距离,对手超出这个距离无法做出防御动作)"参数值. (整型)
  • size.proj.attack.dist:返回"proj.attack.dist(飞行道具攻击距离)"参数值. (整型)
  • size.proj.doscale:返回"proj.doscale(飞行道具是否受size.xscale和size.yscale影响)"参数值. (整型)
  • size.head.pos.x:返回"head.pos(头部位置)"x方向参数值. (整型)
  • size.head.pos.y:返回"head.pos(头部位置)"y方向参数值. (整型)
  • size.mid.pos.x:返回"mid.pos(身体中部位置)"x方向参数值. (整型)
  • size.mid.pos.y:返回"mid.pos(身体中部位置)"y方向参数值. (整型)
  • size.shadowoffset:返回"shadowoffset(影子偏移)"参数值. (整型)
  • size.draw.offset.x:返回"draw.offset(人物偏移)"x方向参数值. (整型)
  • size.draw.offset.y:返回"draw.offset(人物偏移)"y方向参数值. (整型)

下面参数名的值将返回玩家的cns中[Velocity]组中指定的值.

  • velocity.walk.fwd.x:返回"walk.fwd(向前走速度)"参数值. (浮点型)
  • velocity.walk.back.x:返回"walk.back(向后走速度)"参数值. (浮点型)
  • velocity.run.fwd.x:返回"run.fwd(向前跑)"x方向参数值. (浮点型)
  • velocity.run.fwd.y:返回"run.fwd(向前跑)"y方向参数值. (浮点型)
  • velocity.run.back.x:返回"run.back(向后跑)"x方向参数值. (浮点型)
  • velocity.run.back.y:返回"run.back(向后跑)"y方向参数值. (浮点型)
  • velocity.jump.y:返回"jump.neu(正向上跳)"y方向参数值. 注意: 这不是"velocity.jump.neu.y". 仅仅是"neu"参数取y方向的值. (浮点型)
  • velocity.jump.neu.x:返回"jump.neu(正向上跳)"x方向参数值. (浮点型)
  • velocity.jump.back.x:返回"jump.back(向后跳)"参数值. (浮点型)
  • velocity.jump.fwd.x:返回"jump.fwd(向前跳)"参数值. (浮点型)
  • velocity.runjump.back.x:返回"runjump.back(向后跑跳)"参数值. (浮点型)
  • velocity.runjump.fwd.x:返回"runjump.fwd(向前跑跳)"参数值. (浮点型)
  • velocity.airjump.y:返回"airjump.neu(正向上连跳)"y方向参数值. 注意: 这不是"velocity.airjump.neu.y". (浮点型)
  • velocity.airjump.neu.x:返回"airjump.neu(正向上连跳)"x方向参数值. (浮点型)
  • velocity.airjump.back.x:返回"airjump.back(正向后连跳)"参数值. (浮点型)
  • velocity.airjump.fwd.x:返回"airjump.fwd(正向前连跳)"参数值. (浮点型)
  • velocity.air.gethit.groundrecover.x:返回"air.gethit.groundrecover"x方向参数值. (浮点型)
  • velocity.air.gethit.groundrecover.y:返回"air.gethit.groundrecover"y方向参数值. (浮点型)
  • velocity.air.gethit.airrecover.mul.x:返回"air.gethit.airrecover.mul"x方向参数值. (浮点型)
  • velocity.air.gethit.airrecover.mul.y:返回"air.gethit.airrecover.mul"y方向参数值. (浮点型)
  • velocity.air.gethit.airrecover.add.x:返回"air.gethit.airrecover.add"x方向参数值. (浮点型)
  • velocity.air.gethit.airrecover.add.y:返回"air.gethit.airrecover.add"y方向参数值. (浮点型)
  • velocity.air.gethit.airrecover.back:返回"air.gethit.airrecover.back"参数值. (浮点型)
  • velocity.air.gethit.airrecover.fwd:返回"air.gethit.airrecover.fwd"参数值. (浮点型)
  • velocity.air.gethit.airrecover.up:返回"air.gethit.airrecover.up"参数值. (浮点型)
  • velocity.air.gethit.airrecover.down:返回"air.gethit.airrecover.down"参数值. (浮点型)

下面参数名的值将返回玩家的cns中[Movement]组中指定的值.

  • movement.airjump.num:返回"airjump.num(空中连跳数)"参数值. (整型)
  • movement.airjump.height:返回"airjump.height(空中连跳需要的高度)"参数值. (整型)
  • movement.yaccel:返回"yaccel(下落加速度)"参数值. (浮点型)
  • movement.stand.friction:返回"stand.friction(站立受到的摩擦力)"参数值. (浮点型)
  • movement.crouch.friction:返回"crouch.friction(蹲下受到的摩擦力)"参数值. (浮点型)
  • movement.stand.friction.threshold:返回"stand.friction.threshold(站立摩擦力阈值)"参数值. (浮点型)
  • movement.crouch.friction.threshold:返回"crouch.friction.threshold(蹲下摩擦力阈值)"参数值. (浮点型)
  • movement.jump.changeanim.threshold:返回"jump.changeanim.threshold"参数值. (浮点型)
  • movement.air.gethit.groundlevel:返回"air.gethit.groundlevel"参数值. (浮点型)
  • movement.air.gethit.groundrecover.ground.threshold:返回"air.gethit.groundrecover.ground.threshold"参数值. (浮点型)
  • movement.air.gethit.groundrecover.groundlevel:返回"air.gethit.groundrecover.groundlevel"参数值. (浮点型)
  • movement.air.gethit.airrecover.threshold:返回"air.gethit.airrecover.threshold"参数值. (浮点型)
  • movement.air.gethit.airrecover.yaccel:返回"air.gethit.airrecover.yaccel"参数值. (浮点型)
  • movement.air.gethit.trip.groundlevel:返回"air.gethit.trip.groundlevel"参数值. (浮点型)
  • movement.down.bounce.offset.x:返回"down.bounce.offset"x方向参数值. (浮点型)
  • movement.down.bounce.offset.y:返回"down.bounce.offset"y方向参数值. (浮点型)
  • movement.down.bounce.yaccel:返回"down.bounce.yaccel"参数值. (浮点型)
  • movement.down.bounce.groundlevel:返回"down.bounce.groundlevel"参数值. (浮点型)
  • movement.down.friction.threshold:返回"down.friction.threshold"参数值. (浮点型)

示例:
trigger1 = Const(velocity.walk.fwd.x) > 4
如果向前走的速度大于4则触发.

(关于参数具体含义请查看"cns变量设置")


Const240p

把240p坐标空间转换成玩家的坐标空间.
坐标空间的转换率是他们的宽度比.

格式:
Const240p(表达式)

参数:
表达式
表达式包含了需要转换的值.(浮点型)

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom则返回bottom.

注意:
common1.cns中非0值和速度偏移量值应该使用Const*p触发器中的一个来维护不同坐标空间人物的一致性.

示例:
value = Const240p(3)
设置value的值为3如果玩家拥有 320x240 (240p) 的坐标空间.
设置value的值为6如果玩家拥有 640x480 (480p) 的坐标空间.
设置value的值为12如果玩家拥有 1280x720 (720p) 的坐标空间.


Const480p

把480p坐标空间转换成玩家的坐标空间.
坐标空间的转换率是他们的宽度比.

格式:
Const480p(表达式)

参数:
表达式
表达式包含了需要转换的值.(浮点型)

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom则返回bottom.

注意:
common1.cns中非0值和速度偏移量值应该使用Const*p触发器中的一个来维护不同坐标空间人物的一致性.

示例:
value = Const480p(6)
设置value的值为3如果玩家拥有 320x240 (240p) 的坐标空间.
设置value的值为6如果玩家拥有 640x480 (480p) 的坐标空间.
设置value的值为12如果玩家拥有 1280x720 (720p) 的坐标空间.


Const720p

把720p坐标空间转换成玩家的坐标空间.
坐标空间的转换率是他们的宽度比.

格式:
Const720p(表达式)

参数:
表达式
表达式包含了需要转换的值.(浮点型)

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom则返回bottom.

注意:
common1.cns中非0值和速度偏移量值应该使用Const*p触发器中的一个来维护不同坐标空间人物的一致性.

示例:
value = Const720p(12)
设置value的值为3如果玩家拥有 320x240 (240p) 的坐标空间.
设置value的值为6如果玩家拥有 640x480 (480p) 的坐标空间.
设置value的值为12如果玩家拥有 1280x720 (720p) 的坐标空间.


Cos (math)

计算指定参数的余弦值(用弧度制表示).

格式:
cos(表达式)

参数:
表达式
需要计算余弦值的表达式.(浮点型)

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
value = cos(0)
设置cos(0)的值,约为1.0(可能会有舍入误差)


Ctrl

返回p1的控制flag(标示).

格式:
Ctrl

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = Ctrl
如果玩家受控制则触发.


DrawGame

如果玩家(或者是玩家的队伍,在team mode中)在回合结束后获得平局则返回1,否则返回0.

格式:
DrawGame

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = DrawGame
如果玩家(或队伍)在回合结束后获得平局则触发.


E

返回自然数e的值(2.718281828...)

格式:
e

参数:
无

返回值类型:
浮点型

错误条件:
无


Exp (math)

计算自然数e的参数次幂.
这种计算方式略微比等价的表达式e**(参数)精确些.

格式:
exp(表达式)

参数:
表达式
需要计算幂指数的表达式.(浮点型)

返回值类型:
如果表达式计算出bottom则返回bottom.

示例:
value = exp(4-var(0))
设置value的值为e的 4-var(0) 次幂.

特例:
exp(2) 等价于 e**2.
exp(0.5*ln(var(2))) 等价于 var(2)**0.5.(即给var(2)开根号,e**0.5)


Facing

如果玩家面朝右则返回1,如果面朝左则返回-1.

格式:
Facing

参数:
无

返回值类型:
整型

错误条件:
无

示例:
Trigger = Facing = -1
如果玩家面朝屏幕的左侧则触发.

特例:
facing通常可以用来作为一些特殊效果的修正参数
比如:后方500坐标
[State 0, posset]
type = posset
trigger1 =...
x = -500*facing


Floor (math)

实现floor(向下取整)函数.返回小于等于参数的最大整数.

格式:
floor(表达式)

参数:
表达式
要计算向下取整的表达式.

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
1. value=floor(5.5)
设置value的值为5.
2. value=floor(-2)
设置value的值为-2.


FrontEdge

FrontEdge返回玩家前方屏幕边缘X方向位置(背景舞台的绝对坐标).

格式:
FrontEdge

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
此触发器与表达式"ifelse(facing = 1, RightEdge, LeftEdge)"相同.

示例:
trigger1 = facing * (Pos X + CameraPos X) < facing * (FrontEdge)
如果玩家在前方屏幕边缘后面触发.


FrontEdgeBodyDist

FrontEdgeBodyDist给出了玩家前方(由他的宽度条前端决定)到前方屏幕的边缘距离.

格式:
FrontEdgeBodyDist

参数:
无

返回值类型:
浮点型

错误条件:
无

示例:
trigger1 = FrontEdgeBodyDist < 30
如果玩家宽度条前端到前方的距离在30像素之内(也就是和屏幕前方边缘的距离)则触发.


FrontEdgeDist

FrontEdgeDist给出了玩家(坐标中心)与他前方屏幕边缘X轴方向的距离.

格式:
FrontEdgeDist

参数:
无

返回值类型:
浮点型

错误条件:
无

示例:
trigger1 = FrontEdgeDist < 30
如果玩家与他前方屏幕边缘X轴方向的距离小于30像素则触发.


FVar (math)

此触发器使用强制变量号作为参数.
将返回玩家指定的浮点型变量值.

格式:
FVar(表达式)

参数:
表达式
需要计算参数号的表达式.
目前有效号是0-39.

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom,
或者表达式计算出无效的变量索引则返回bottom.

示例:
trigger1 = FVar(5) = -1.23
如果变量索引为5的浮点数 值为-1.23则触发.

特列:
绝大部分情况下可用Fvar来代替Var

注意:
在设置变量时,变量不能以大写字母开头,例如:
[State ]
type = VarSet
trigger1 = 1
FVar(0) = 0 ;这是错误的写法

[State ]
type = VarSet
trigger1 = 1
fvar(1) = 0 ;这是正确的写法


GameHeight

返回游戏空间(玩家自定坐标空间中的)的高度.
游戏空间被定义为一个空间映射到玩家互动的屏幕可见区域.
直观的,它能够被想象成包含游戏的图形区域.
游戏空间的尺寸由mugen.cfg中的GameWidth和GameHeight指定.
请注意: 在mugen 1.1场景中,mugen.cfg中的GameHeight并不是游戏中的实际变量GameHeight的值,游戏中的GameHeight变量是随着CameraZoom来变化的.通常在CameraZoom=1时,GameHeight=240(4:3游戏屏幕),或者GameHeight=180(16:9游戏屏幕)

格式:
GameHeight

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
GameWidth和GameHeight的缩放与摄像机缩放系数相反.
例如,如果摄像机缩放系数是0.5,GameWidth和GameHeight的返回值将是缩放系数为1时的2倍.

ScreenWidth和ScreenHeight是等价的触发器,将不会被摄像机缩放系数影响.

示例:
trigger1 = ScreenPos Y < GameHeight / 2
如果玩家在屏幕中心上方则触发.


GameTime

返回到目前为止游戏逝去的总帧数.

格式:
GameTime

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = (GameTime % 27) = 0
每隔27个游戏帧触发.


GameWidth

返回游戏空间(玩家自定坐标空间中的)的宽度.
游戏空间被定义为一个空间映射到玩家互动的屏幕可见区域.
直观的,它能够被想象成包含游戏的图形区域.
游戏空间的尺寸由mugen.cfg中的GameWidth和GameHeight指定.
请注意: 在mugen 1.1场景中,mugen.cfg中的GameWidth并不是游戏中的实际变量GameWidth的值,游戏中的GameWidth变量是随着CameraZoom来变化的.通常在CameraZoom=1时,GameWidth=320

格式:
GameWidth

参数:
无

返回值类型:
浮点型

注意:
GameWidth和GameHeight的缩放与摄像机缩放系数相反.
例如,如果摄像机缩放系数是0.5,GameWidth和GameHeight的返回值将是缩放系数为1时的2倍.

ScreenWidth和ScreenHeight是等价的触发器,将不会被摄像机缩放系数影响.

错误条件:
无

示例:
trigger1 = ScreenPos X >= GameWidth / 2
如果玩家在屏幕中心右方则触发.


GetHitVar(*)

当玩家处于gethit(受击状态)状态中,返回指定的hit参数.

格式:
GetHitVar(参数名)

参数:
参数名
有效的可用于检测的参数名有下列:
xveladd, yveladd, type, animtype, airtype, groundtype, damage, hitcount, fallcount, hitshaketime, hittime, slidetime, ctrltime, recovertime, xoff, yoff, zoff, xvel, yvel, yaccel, hitid, chainid, guarded, fall, fall.damage, fall.xvel, fall.yvel, fall.recover, fall.time, fall.recovertime.

返回值类型:
取决于指定的hit参数.查看详情.

错误条件:
无

详情:

  • xveladd: 返回玩家被KO时施加给自身的x方向速度增量.(浮点型)
  • yveladd: 返回玩家被KO时施加给自身的y方向速度增量.(浮点型)
  • type: 返回hit的类型:0-无,1-高,2-低,3-绊倒(在地面时有效)
  • animtype: 返回hit的动画类型:0-轻,1-中,2-重,3-向后,4-向上,5-旋转向上.
  • airtype: 返回Hitdef中空中hit的指定类型.
  • groundtype: 返回Hitdef中地面hit的指定类型.
  • damage: 返回hit的伤害值.(整型)
  • hitcount: 返回玩家在当前连击中产生的连击数.(整型)
  • fallcount: 返回玩家在当前连击中倒地次数.(整型)
  • hitshaketime: 返回玩家在攻击中被"冻结"的时间.此数字每帧减1,到0时停止.(整型)
  • hittime: 返回玩家受控制之前的时间,在受攻击之后返回一个空闲状态.
    只要hitshaketime大于0,则这个数字每帧减1,直到到达-1.(整型)
    "GetHitVar(hittime) < 0" 等价于HitOver被触发.
  • slidetime: 返回玩家被击中后向后滑动(在地面上)的时间.(整型)
  • ctrltime: 返回玩家防御hit之后恢复控制之前的时间.(整型)
  • recovertime: 返回玩家从倒地状态到起身前的时间.此数字在玩家倒地后每帧减1直到0(此时玩家正好起身),如果你在此期间按键,此数字将减少的更快.(整型)
  • xoff: hit时"短暂的"x方向偏移(不推荐)
  • yoff: hit时"短暂的"y方向偏移(不推荐)
  • xvel: 由hit给予的x方向固定的速度.(浮点型)
  • yvel: 由hit给予的y方向固定的速度.(浮点型)
  • yaccel: 由hit设置的y方向加速度.(浮点型)
  • chainid: 由玩家指定的上一次hit中的chainID. (整型)
  • guarded: 如果上一次hit被防御住则返回真,否则返回假.
  • isbound: 如果玩家是攻击者TargetBind控制器的主体则返回真.对防止在抓投状态中被卡住有用处.(整型)
  • fall: 如果处于下落状态则返回真,否则返回假.(整型)
  • fall.damage: 下落状态设定的伤害值.(整型)
  • fall.xvel: 从地面反弹后x方向的速度.(浮点型)
  • fall.yvel: 从地面反弹后y方向的速度.(浮点型)
  • fall.recover: 如果玩家可以recover(恢复)则返回真,否则返回假.
  • fall.recovertime: 玩家可以recover前的时间.(整型)
  • fall.kill: 攻击者hitdef中fall.kill的数值.(整型)
  • fall.envshake.time: 看下面. (整型)
  • fall.envshake.freq: 看下面. (浮点型)
  • fall.envshake.ampl: 看下面. (整型)
  • fall.envshake.phase: 返回攻击者fall.envshake.*参数数值.(浮点型)

示例:
trigger1 = GetHitVar(yvel) < -5.5
hit的指定y速度小于-5.5则触发.


HitCount

返回玩家当前攻击招式击中一个或更多对手的次数.该值仅在单个状态内有效;任何状态改变之后,复位到0.
为了防止它复位到0,请查看StateDef中的hitcountpersist(查看cns文档获得更多详情).HitCount和UniqHitCount触发器不同之处仅在于玩家正攻击1个以上的对手时体现出来.
当玩家正用相同攻击击中2个对手时,HitCount在每次击中时增加1,而UniqHitCount在每次击中时增加2.

格式:
HitCount

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = HitCount > 8
当玩家的攻击招式开始后已完成对对手大于8次连击则触发.


HitDefAttr(*,***)

检测玩家当前活动的 HitDef 中属性参数"attr".
如果玩家当前不处于攻击状态,则没有参数会匹配.
能被用于CMD文件中由弱到强攻击的简单move-interrupts(招式中断).

注意:
HitDefAttr != value1, value2 逻辑上等价于 !(HitDefAttr = value1, value2).

【BUG】注意: "HitDefAttr != "和"!(HitDefAttr = )"都是有BUG的(mugen 1.1.0.650实测)! 请不要使用这两种运算符, 而要直接使用"HitDefAttr = ", 切记!

格式:
HitDefAttr [运算符] 值1, 值2

参数:
[运算符]
=, !=

值1
一个至少由"S"(站立),"C"(蹲下),"A"(空中)3个字母中的一个组成的字符串.
例如:"SA"表示站立和空中.

值2
一组由2字母组成的字符串,用逗号分隔(可以是多组逗号分隔的字符串).
每组2个字母字符串必须符合下面的描述:
第1个字母可以是"N"(普通),"S"(特殊),"H"(超级),"A"(普通+特殊+超级)中的任何一个.
第2个字母必须是"A"(Attack直接攻击),"T"(Throw投掷),"P"(Projectile飞行道具)中任意一个.
例如,"NA,ST"表示普通攻击和特殊抓投.

假设玩家的hitdef控制器"attr"参数是这类格式:
arg1(参数1), arg2(参数2)
则触发条件只有当参数1是值1的子集,且参数2是值2的子集时才确定为真.
请查看 HitDef控制器的"attr"参数获得详细信息.

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = HitDefAttr = A, HA
当玩家处于攻击状态中,当目前的hitdef有如下的属性:
1.是空中的攻击.
2.是超级的攻击.
则触发.

trigger1 = HitDefAttr = SC, NA, SA
当玩家处于攻击状态中,当目前的hitdef有如下的属性:
1.是站立攻击或者蹲下攻击中的任何一种.
2.是普通攻击或者特殊攻击中的任何一种.
则触发.


HitFall

如果玩家当前处于受击状态,则返回hit的fall flag(下落标示).
如果玩家不处于受击状态,则触发器会输出undefined(未定义).
请查看hitdef文档获得fall flag的解释.

格式:
HitFall

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = !HitFall
如果此次攻击未使玩家进入下落状态则触发.a


HitOver

如果玩家处于受击状态,当hittime已经到期则返回1,否则返回0.
请查看hitdef文档获得hittime的解释.

格式:
HitOver

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = HitOver = 1
当玩家的hittime已过期时触发.


HitPauseTime

返回玩家hitpause(打击停顿)过期前的时间.
当玩家的攻击接触到对手时便进入了hitpause状态.
hitpause的初始时间等于玩家的hitdef中pausetime参数的第一个值.
如果不设置ignorehitpause该触发器将总是返回0.

格式:
HitPauseTime

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = HitPauseTime = 0
当玩家在攻击中未停顿则触发.


HitShakeOver

当玩家处于受击状态,如果hit shake(受击震动,当他在一个位置震动的时间)已结束则返回1,否则返回0.

格式:
HitShakeOver

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = HitShakeOver = 0
如果玩家在攻击中仍然处于震动状态则触发.


HitVel

获得攻击中给予玩家速度的值.你必须指定要检测的分量,比如,"HitVel Y"检测垂直方向速度.

格式:
HitVel [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
无

详情:
HitVel Y的正值表示玩家向上运动.
HitVel X的正值表示玩家向后运动.
注意HitVel X与Vel X触发条件相反.

示例:
trigger1 = HitVel X > 0.5
当玩家受击x方向速度大于0.5 像素/帧 则为真.


ID

返回玩家的ID号.在一场比赛中ID号对每个玩家来说是唯一的.
此时创建的任何helper将同样获得它自身唯一的ID号.
此触发器也许对获得对手的ID号有用,之后用"playerID"重定向键值(查看exp文档).
不要把玩家ID和targetID混淆.

玩家1~4本体(即p1,p2,p3,p4)的ID号分别为: 56 57 58 59.

格式:
ID

参数:
无

返回值类型:
整型

错误条件:
无

示例:
value = ID
设置value为当前玩家的ID号.
value = EnemyNear, ID
设置value为最近距离对手的ID号.


IfElse (math)

此触发器由3和参数构成.如果第一个参数非0,ifelse返回第2个参数值,否则,返回第3个参数值.
所有参数在ifelse执行前都将预先计算.特别的,会引起任何由于计算参数(例如给变量赋值或者执行一个会产生警告的运算)所产生的副作用.
如果你想避免产生这些副作用,请使用Cond.

Cond仅支持mugen1.0及以上的版本. 而ifelse支持所有mugen版本.

格式:
IfElse(exp_cond,exp_true,exp_false)

参数:
exp_cond
需要测试的表达式
exp_true
如果 exp_cond 为非0则返回此表达式指定的值.
exp_false
如果 exp_cond 为0则返回此表达式指定的值.

返回值类型:
如果 exp_true 被返回,则返回类型和 exp_true 相同.
如果 exp_false 被返回,则返回类型和 exp_false 相同.

错误条件:
返回bottom如果 exp_cond 计算出bottom,
或者 exp_true 或 exp_false (任何一个被使用了) 计算出bottom.

示例:
value = IfElse(var(3),1,2)
当var(3)是非0时,value值为1.
当var(3)是0时,value值为2.

特列:
ifelse可以用Cond来代用(反过来也可)
Cond(var(3),1,2)相当于ifelse(var(3),1,2)

两者的区别请查看表达式部分关于bottom中特殊格式的章节.


InGuardDist

如果玩家在对手的物理或飞行道具攻击的防御距离之内则返回1.
防御距离是对手hitdef中guard.dist参数值.
如果在防御距离之外或者对手不处于攻击状态则返回0.

格式:
InGuardDist

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
无

【BUG】注意:
若在InGuardDist范围内： 刚开始无攻击判定时，InGuardDist返回假。 判定出现，返回真。 （这个判定包括HitDef、ReversalDef、Projectile全部三类攻击器，比HitDefAttr处理起来方便） 判定结束，打击框消失，依旧返回真。（和HitDefAttr的特性一样）


IsHelper

此触发器拥有一个可选参数-ID号.
1.ID号被省略,如果玩家是一个helper人物则ishelper返回1,否则返回0.
2.包含了ID号,如果玩家是一个指定ID号的helper人物则ishelper返回1,否则返回0.

格式:
1.IsHelper
2.IsHelper(表达式)

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
1. trigger1 = !IsHelper
如果这个玩家不是helper类型人物则触发.
2. trigger1 = IsHelper(1234)
如果这个玩家是ID号为1234的helper类型人物则触发.

特列:
这个条件通常添加在 StateDef -1~-3 里面防止helper误触发 StateDef -1~-3 的控制器.


IsHomeTeam

如果玩家的队伍被认定为"主队"则返回1.
在arcade(街机)模式中,电脑方一般被认为是主队.
在versus(对战)模式中,p1方(左面)是主队.

格式:
IsHomeTeam

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
无


LeftEdge

LeftEdge返回屏幕左边缘X轴方向位置(背景舞台的绝对坐标).

格式:
LeftEdge

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
此触发器与表达式"CameraPos X - GameWidth / 2"相同.

示例:
trigger1 = Pos X + CameraPos X < LeftEdge
如果玩家在屏幕左边缘的左面则触发.


Life

返回玩家的生命值.

格式:
Life

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = life <= 10
如果玩家小于等于10点生命值则触发.


LifeMax

返回玩家能拥有的最大生命值.
这个值通常是玩家变量的[Data]组参数中的"life"值,但有时也许会不同(例如team mode的时候).

格式:
LifeMax

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = life < lifemax / 4
如果玩家的生命值少于最大生命值的四分之一则触发.


Ln (math)

返回参数的自然对数.
产生的结果比等价的log(e,(argument))更为精确.

格式:
ln(表达式)

参数:
表达式
需要计算自然对数的表达式.(浮点型)

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom,或者表达式非正则返回bottom.

示例:
value = ln(time)
设置value的值为玩家状态时间的自然对数.


Log (math)

拥有2个参数a和b,返回以a为底,b的对数.

格式:
Log(表达式1,表达式2)

参数:
表达式1
表达式给出了对数的底数,必须为正.

表达式2
需要计算对数的表达式,必须为正.

返回值类型:
浮点型

错误条件:
如果表达式1和表达式2中任何一个计算出bottom,或者表达式1和表达式2中任何一个非正,则返回bottom.

示例:
value=log(2,64)
设置value的值为以2为底,64的对数,结果为6.0.


Lose

如果玩家(或者在team mode中指的是玩家的队伍)已经输掉了这局则返回1,否则返回0.
能用"KO"或者"Time"的后缀区分仅当此局通过KO或者是时间到了才输掉的而返回1.

格式:
Lose
LoseKO
LoseTime

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
1. trigger1 = Lose
如果玩家(或他的队伍)已输了此局则触发.

2. trigger1 = !LoseKO
如果玩家(或他的队伍)不是通过被KO的方式输了此局则触发.
例如,在玩家的队伍还没有输掉这局,或者由于timeover而输掉的情况下会触发.


MatchNo

返回当前的match number(比赛号,场次号)

格式:
MatchNo

参数:
无

返回值类型:
整型

详情:
在versus模式中当前的比赛号总是1.
在arcade模式或Team Arcade模式中,比赛号从1开始,当新场次比赛开始时加1(续关时不会增加).
如果你结束了arcade模式重新开始游戏,比赛号会恢复到1.

示例:
无


MatchOver

如果比赛结束则返回1.(例如,在三局两胜的比赛中,当其中的一个玩家或者队伍赢了2局将返回真)

格式:
MatchOver

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

详情:
目前情况, 直到玩家做出胜利姿势(state 180)时MatchOver才会返回真.
此特征也许会在未来的版本中改变.

示例:
trigger1 = !matchover
如果比赛没结束则返回真.比如,当前局可能还未结束,或者可能已经结束,但还没给出结果.


MoveContact

此触发器仅当玩家处于攻击状态时有效.
如果p2(p1的对手)被p1击中或者防御住p1的攻击则MoveContact给出一个非0值,否则给出0.
通常情况下与"StateNo"和"Command"触发器一起使用检测CMD文件中的攻击中断(例如A招式击中后可以连接B招式).

格式:
MoveContact

参数:
无

返回值类型:
整型

错误条件:
无

详情:
攻击一接触到(对手),MoveContact便返回1.
接触了之后,在p1没有停顿(p1招式接触到对手后会产生停顿;查看hitdef控制器中pausetime参数)时MoveContact返回的值将每个游戏帧增加1.
MoveGuarded, MoveHit和MoveReversed的值都以相同的方式增长.

注意1: MoveContact, MoveGuarded, MoveHit和MoveReversed是被同时设置的.
例如,一个招式中的HitDef成功击中了对手,MoveHit会返回非0(即MoveHit会产生数值).
如果相同招式中的下一次HitDef被防御住,MoveGuarded会返回非0.
(MoveGuarded和MoveContact 或者 MoveHit和MoveContact 通常情况下会同时出现数值.)

注意2:这4个Move*触发器在状态过渡后会恢复到0并停止增长.
想要知道如何覆盖这种特征,查看StateDefs(CNS文档)中"movehitpersist"参数.

示例:
trigger1 = MoveContact
如果p1对p2的攻击没有出miss则为真.
trigger1 = MoveContact = 1
从p1的攻击接触p2到p1的pausetime正好刚结束这段时间为真.


MoveGuarded

此触发器仅当玩家处于攻击状态时有效.
如果p2正在防御或者已防御住p1的攻击则MoveGuarded给出一个非0值,否则给出0.
通常情况下与"StateNo"和"Command"触发器一起使用检测CMD文件中的攻击中断(例如A招式击中后可以连接B招式).

格式:
MoveGuarded

参数:
无

返回值类型:
整型

错误条件:
无

详情:
查看MoveContact触发器的详情.

示例:
trigger1 = MoveGuarded
如果p1的攻击被p2防御住则为真.


MoveHit

此触发器仅当玩家处于攻击状态时有效.
如果p2已被p1击中MoveHit给出一个非0值,否则给出0.
通常情况下与"StateNo"和"Command"触发器一起使用检测CMD文件中的攻击中断(例如A招式击中后可以连接B招式).

格式:
MoveHit

参数:
无

返回值类型:
整型

错误条件:
无

详情:
查看MoveContact触发器的详情.

示例:
trigger1 = MoveHit
如果p1成功击中p2则为真.


MoveReversed

此触发器仅当玩家处于攻击状态时有效.
如果p1的攻击被p2反弹则MoveReversed给出一个非0值,否则给出0.

格式:
MoveReversed

参数:
无

返回值类型:
整型

错误条件:
无

详情:
查看MoveContact触发器的详情.

示例:
trigger1 = MoveReversed
如果p1的攻击被p2反弹则为真.


MoveType(*,***)

MoveType给出了玩家的move-type(招式类型).
想获得MoveType更多详情,参照CNS文档中StateDef的章节.
检测CMD文件中的攻击中断时有用处.

格式:
MoveType [运算符] 招式类型

参数:
[运算符]
=, != (其他运算符无效)

招式类型(字符型)
A(攻击状态),I(空闲状态),H(受击状态)

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = movetype != H
如果玩家不处于受击状态则触发.


Name(*,***)

返回玩家的名字.(.DEF文件指定的内部名称,也许和显示出来的名字不一样)

格式:
Name [运算符] "名字"

参数:
[运算符]
=, != (其余运算符无效)

"名字"(字符串型)
需要比较的名字.必须写在双引号里面.

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
trigger1 = Name = "Kumquat"
如果玩家的名字是Kumquat则返回真.


NumEnemy

NumEnemy返回存在的对手数量.中立玩家和普通援助不计算在内.

格式:
NumEnemy

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = NumEnemy = 2
trigger1 = enemynear(1), name = "Squash"
如果有2个对手,且第2接近(较远的那个)的对手名字叫Squash则触发.


NumExplod

此触发器拥有一个ID号作为可选参数.如果ID号省略,NumExplod返回玩家拥有的explod(爆炸,闪光,火花)数量.
如果包含了ID号,则NumExplod返回玩家拥有的此ID号的explod数量.ID号必须大于-1.
一个小于等于-1的ID号与省略ID号效果相同.

格式:
NumExplod
NumExplod(表达式)

参数:
表达式
计算出ID号的表达式(整型).

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
1. trigger1 = NumExplod >= 4
如果玩家当前拥有的explod数量大于等于4则触发.
2. trigger1 = NumExplod(1234) >= 4
如果玩家当前拥有ID号为1234的explod数量大于等于4则触发.


NumHelper

此触发器拥有一个ID号作为可选参数.如果ID号省略,NumHelper返回玩家目前拥有的helper(援助)数量.
如果包含了ID号,则NumHelper返回玩家拥有的此ID号的helper数量.ID号必须大于0.
如果ID号小于等于0,则所有helper都会计算在内.

格式:
NumHelper
NumHelper(表达式)

参数:
表达式
计算出ID号的表达式(整型).

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
1. trigger1 = NumHelper < 2
如果玩家当前拥有的helper数量小于2则触发.
2. trigger1 = NumHelper(1234) < 2
如果玩家当前拥有ID号为1234的helper数量小于2则触发.


NumPartner

NumPartner返回存在的partner(同伴)数量.中立的玩家和普通的helper不被认为是partner.

格式:
NumPartner

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = NumPartner = 1
trigger1 = partner, life < 200
如果玩家有1个生命值少于200的partner则触发.


NumProj

返回玩家当前拥有的所有飞行道具数量.

格式:
NumProj

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = NumProj = 0
如果玩家当前没有活动的飞行道具则触发.


NumProjID (math)

此触发器拥有一个必须的参数ID号.
它返回玩家当前拥有的指定ID号的飞行道具数量.

格式:
NumProjID(表达式)

参数:
表达式
计算出ID号的表达式

返回值类型:
整型

错误条件:
如果指定ID号位负数,则ID号默认为0.如果表达式计算出bottom则返回bottom.

示例:
trigger1 = NumProjID(1234) = 1
如果玩家当前仅拥有1个ID号为1234的飞行道具则触发.


NumTarget

此触发器拥有一个ID号作为可选参数.如果ID号省略,NumTarget返回玩家当前拥有的target(目标)数量.
ID号通常在 HitDef 控制器的"ID"参数中指定.
如果包含了ID号,则NumTarget返回玩家拥有的此ID号的target数量.ID号必须大于-1.
一个小于等于-1的ID号与省略ID号效果相同.

格式:
NumTarget
NumTarget(表达式)

参数:
表达式
计算出ID号的表达式(整型).

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
1. trigger1 = NumTarget >= 4
如果玩家当前拥有的target数量大于等于4则触发.
2. trigger1 = NumTarget(1234) >= 4
如果玩家当前拥有ID号为1234的target数量大于等于4则触发.(即敌方被HitDef ID=1234击中或者防御住)


P1Name(*,***)

这是Name触发器的一个别名,请查看 Name.


P2BodyDist

返回P2到P1的距离,这里P1是玩家,P2是他的对手.
这里的距离为: P1自身宽度边缘与P2（距离最近的player，包括对手本体和 player型helper）宽度边缘的距离.
P2BodyDist在CMD中P1的攻击(区别当接近p2的时候)情况下有用.
(是指在CMD出招表中指定某些近身攻击时有效,比如KOF系列人物,一般物理攻击都分近身攻击和远距离攻击,出招条件一般是:
trigger1=p2bodydist x<=15之类的)

格式:
P2BodyDist [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
无

详情:
比较Y方向距离,P2BodyDist给出了玩家的Y坐标上的高度区别.负值表示P2在P1上面.
比较X方向距离,P2BodyDist给出了P2前端到P1前端X方向上的距离.
所以,如果玩家正好彼此相邻的站立,则P2BodyDist是0.
记住你能用"front.width"等等(在玩家变量的[Size]组下面)来设置玩家的宽度.
也请查看 P2Dist 进行比较.
Y轴的P2BodyDist和P2Dist效果一样, 即: P2BodyDist Y = P2Dist Y.

示例:
trigger1 = P2BodyDist X < 30
如果p2前端与p1前端距离小于30像素则触发.


P2Dist

返回P2到P1的距离,P1是玩家,P2是他的对手.
这里的距离为: P1自身坐标原点与P2（距离最近的player，包括对手本体和 player型helper）坐标原点的距离.

格式:
P2Dist [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
无

详情:
比较Y方向距离,P2Dist给出了玩家的Y坐标上的高度区别.负值表示P2在P1上面.

比较X方向距离, P2Dist给出了P2坐标与P1坐标X方向上的距离.
正值表示P2在P1前面.

也请查看 P2BodyDist 进行比较.
Y轴的P2BodyDist和P2Dist效果一样, 即: P2BodyDist Y = P2Dist Y.

示例:
trigger1 = P2Dist Y <= -12
如果P2比P1至少高12像素则为真.


P2Life

与 Life 触发器相同,只是P2Life返回的是对手的生命值.

由于mugen1.1没有P3Life和P4Life, 故需要使用 触发器重定向 partner, enemy(n)或enemyNear(n)或PlayerID(ID)来获取.


P2MoveType

与 MoveType 触发器相同,只是P2MoveType返回的是对手的招式状态.

"对手"包括对手本体和player型helper.
如果只需要对手本体,使用 触发器重定向 enemy或enemyNear.


P2Name(*,***)

与P1Name相同,只是P2Name返回的是"最主要对手"的名字(versus模式中的对手或者是team模式中第一个对手).

"最主要对手"是指的对手本体,不包括对手的helper.

如果没有最主要对手,则无论指定什么名字,p2name = "name"总是返回0.
同样的,无论指定什么名字,p2name != "name"将总是返回1.

请参阅: Name.


P2StateNo

与 StateNo 相同,只是P2StateNo返回的是对手的状态号.

"对手"包括对手本体和player型helper.
如果只需要对手本体,使用 触发器重定向 enemy或enemyNear.

错误条件:
如果p2不存在则返回bottom.(例如,如果已经赢了此局)


P2StateType

与 StateType 相同,只是P2StateType返回的是对手的状态类型.

"对手"包括对手本体和player型helper.
如果只需要对手本体,使用 触发器重定向 enemy或enemyNear.

错误条件:
如果p2不存在则返回bottom.(例如,如果已经赢了此局)


P3Name(*,***)

与P1Name相同,只是P3Name返回的是player队友的名字(如果存在的话).
如果没有队友,则无论指定什么名字,p3name = "name"返回0.
同样的,无论指定什么名字,p3name != "name"返回1.

请参阅: Name.


P4Name(*,***)

与P1Name相同,只是P4Name返回的是第2个对手的名字(如果存在的话).
如果没有第2个对手,则无论指定什么名字,p4name = "name"返回0.
同样的,无论指定什么名字,p4name != "name"返回1.

请参阅: Name.


PalNo

返回player的色表号.(即在人物选择时为人物选择的配色方案)

格式:
PalNo

参数:
无

返回值类型:
整型

错误条件:
无

详情:
调色板序列在人物的def文件中定义.
如果省略,默认的序列是:

A | B | B | X | Y | Z | A2 | B2 | C2 | X2 | Y2 | Z2
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12

示例:
trigger1 = PalNo = 5
如果当前色表号为5则触发.


ParentDist

此触发器仅对helper类型人物有效.ParentDist返回helper与它的父级(上一级)之间距离.运行原理与 P2Dist 相似.

格式:
ParentDist [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
如果玩家没有父级则返回bottom.(比如,父级被销毁了或者被KO了)

详情:
比较Y方向距离,ParentDist给出了玩家的Y坐标上的高度区别.
负值表示父级在子级上面.
比较X方向距离, ParentDist给出了父级坐标与子级坐标X方向上的距离.
正值表示父级在子级前面.

示例:
trigger1 = ParentDist X != 0
如果父级的X坐标与helper人物不完全相同则触发.


Pi

此触发器返回pi的数值(圆周率,圆的周长与直径的比值,表示为π)
(π=3.1415926535 8979323846 2643383279 5028841971 6939937510).

格式:
pi

参数:
无

返回值类型:
浮点型

错误条件:
无

示例:
value = sin(pi/2)
设置value的值为 π/2 的正弦值,约为1.0(可能有舍入误差).


PlayerIDExist (math)

如果指定ID号的玩家存在则返回1,否则返回0.
此ID号通过ID触发器获得(见ID).不要把PlayerID和TargetID搞混.

格式:
PlayerIDExist(ID号)

参数:
ID号
计算出ID号并用来检测的表达式(整型)

返回值类型:
布尔型整数(1或0)

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
trigger1 = PlayerIDExist(var(4))
如果1个ID号等于var(4)的玩家存在则触发.


Pos

给出了玩家位置的数值.你必须指定要测试的分量,例如"Pos Y"用来检测Y轴方向.

格式:
Pos [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
无

详情:
对"Pos X"来说,值是相对于屏幕中心(值为0)而言的.负值向左,正值向右.

由于历史原因,"Pos X"不是返回玩家的绝对位置(即相对于舞台背景中心),绝对位置也许更直观.
要获得玩家的绝对位置,使用"Pos X + CameraPos X".

对"Pos Y"来说,值是相对于地面而言的.负值向上,正值向下.

示例:
trigger1 = Pos Y >= 0
当玩家在地面下方为真.


Power

返回玩家的power(能量)值.

格式:
Power

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = power >= 1000
如果玩家至少有1000power则为真.(1级)


PowerMax

返回玩家能拥有的最大power(能量)数.通常这个值为3000.

格式:
PowerMax

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = power < powermax / 2
如果玩家的power小于最大power值的一半则为真.


PrevStateNo

返回玩家所在的上一个状态号.
此触发器的结果不保证准确.

格式:
PrevStateNo

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = PrevStateNo = [200,650]
如果玩家上一个状态号包含在200到650之间则返回真.


ProjCancelTime (math)

此触发器拥有一个非负的ID号作为必须参数.
如果玩家的最近一个造成任何形式接触的飞行道具被对手的飞行道具取消且拥有指定的ID号,则ProjCancelTime返回从接触发生开始的帧数.
如果指定的ID号为0,则飞行道具的ID将不被检测.如果没有飞行道具符合上述所有条件,则ProjCancelTime返回-1.

格式:
ProjCancelTime(表达式)

参数:
表达式
计算出非负ID号的表达式(整型)

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.如果指定一个负的ID号,则ID默认为0.

示例:
1. trigger1 = ProjCancelTime(1234) = 1
如果一个ID为1234的飞行道具刚被对手的飞行道具取消则触发.
2. trigger1 = ProjCancelTime(0) != -1 && ProjCancelTime(0) < 15
在玩家的任何飞行道具被取消后的15帧内触发.


ProjContact(*,***)

此触发器拥有一个可选ID号作为后缀.
如果ID号省略,则玩家的任何飞行道具只要成功击中对手或者被对手防御住ProjContact都将返回真.
当ID号被指定,则只有当玩家的任何拥有指定ID号的飞行道具成功击中对手或者被防御住ProjContact才会返回真.

格式:
ProjContact[ID] = 值
ProjContact[ID] = 值, [运算符] 值2

参数:
[ID]
可选的ID号

值 (布尔型)
进行比较的值.0表示false(假),1表示true(真).

[运算符]
=, !=, <, >, <=, >=

值2
进行比较的时间.

返回值类型:
布尔型整数

错误条件:
无

详情:
每次飞行道具的打击都将使ProjContact触发一次,所以multi-hit(多段攻击)的飞行道具能多次触发.
上面写出的ProjContact第1种格式仅当飞行道具发生接触1帧后有效而不像MoveContact.
第2种格式,如果飞行道具在n帧前发生接触则ProjContact返回真,这里的n是一个满足关系式"n [运算符] 值2"的非负数.
指定ID号为0和省略ID号(将检测所有的飞行道具)有相同的特征(效果).

示例:
1. trigger1 = ProjContact1234 = 1
如果一个ID号为1234的飞行道具刚与对手接触则触发.
2. trigger1 = ProjContact456 = 0, < 15
如果没有ID号为456的飞行道具在最近的15帧内与对手接触则触发.


ProjContactTime (math)

此触发器拥有一个非负的ID号作为必须参数.
如果玩家的最近一个造成任何形式接触的飞行道具与对手接触了且拥有指定ID号,
则ProjContactTime返回从接触发生开始的帧数.
如果指定的ID号为0,则飞行道具的ID将不被检测.如果没有飞行道具符合上述所有条件,则ProjContactTime返回-1.

格式:
ProjContactTime(表达式)

参数:
表达式
计算非负ID号的表达式(整型)

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.如果指定负的ID号,则ID默认为0.

示例:
1. trigger1 = ProjContactTime(1234) = 1
如果一个ID为1234的飞行道具刚与对手接触则触发.
2. trigger1 = ProjContactTime(0) != -1 && ProjContactTime(0) < 15
如果玩家的任何飞行道具在刚才的15帧之内成功与对手接触则触发.


ProjGuarded(*,***)

此触发器拥有一个可选ID号作为后缀.如果ID号省略,则玩家的任何飞行道具只要被对手防御住ProjGuarded都将返回真.
当ID号被指定,则只有当玩家的任何拥有指定ID号的飞行道具被防御住ProjGuarded才会返回真.

格式:
ProjGuarded[ID] = 值
ProjGuarded[ID] = 值, [运算符] 值2

参数:
[ID]
可选的ID号

值 (布尔型)
进行比较的值.0表示false(假),1表示true(真).

[运算符]
=, !=, <, >, <=, >=

值2
进行比较的时间.

返回值类型:
布尔型整数(1或0)

错误条件:
无

详情:
每次飞行道具的打击都将使ProjGuarded触发一次,所以multi-hit(多段攻击)的飞行道具能多次触发.
上面写出的ProjGuarded第1种格式仅当飞行道具发生接触1帧后有效而不像MoveGuarded.
第2种格式,如果飞行道具在n帧前被防御住则ProjGuarded返回真,这里的n是一个满足关系式"n [运算符] 值2"的非负数.
指定ID号为0和省略ID号(将检测所有的飞行道具)有相同的特征(效果).

示例:
1. trigger1 = ProjGuarded1234 = 1
如果对手刚挡住一个ID号为1234的飞行道具则触发.
2. trigger1 = ProjGuarded = 1, < 15
如果对手在最近的15帧内挡住了任何飞行道具则触发.


ProjGuardedTime (math)

此触发器拥有一个非负的ID号作为必须参数.
如果玩家的最近一个造成任何形式接触的飞行道具被对手防御住且拥有指定ID号,则ProjGuardedTime返回从接触发生开始的帧数.
如果指定的ID号为0,则飞行道具的ID将不被检测.如果没有飞行道具符合上述所有条件,则ProjGuardedTime返回-1.

格式:
ProjGuardedTime(表达式)

参数:
表达式
计算非负ID号的表达式(整型)

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.如果指定负的ID号,则ID默认为0.

示例:
1. trigger1 = ProjGuardedTime(1234) = 1
如果一个ID为1234的飞行道具刚被对手防御住则触发.
2. trigger1 = ProjGuardedTime(0) != -1 && ProjGuardedTime(0) < 15
如果玩家的任何飞行道具在刚才的15帧之内被对手防御住则触发.


ProjHit(*,***)

此触发器拥有一个可选正ID号作为后缀.
如果ID号省略,则玩家的任何飞行道具只要成功击中对手ProjHit都将返回真.
当ID号被指定,则只有当玩家的任何拥有指定ID号的飞行道具成功击中对手ProjHit才会返回真.

格式:
ProjHit[ID] = 值
ProjHit[ID] = 值, [运算符] 值2

参数:
[ID] (整型)
可选的ID号

值 (布尔型)
进行比较的值.0表示false(假),1表示true(真).

[运算符]
=, !=, <, >, <=, >=

值2
进行比较的时间.

返回值类型:
布尔型整数

错误条件:
无

详情:
每次飞行道具的打击都将使ProjHit触发一次,所以multi-hit(多段攻击)的飞行道具能多次触发.
上面写出的ProjHit第1种格式仅当飞行道具击中1帧后有效而不像MoveHit.
第2种格式,如果飞行道具在n帧前击中则ProjHit返回真,这里的n是一个满足关系式"n [运算符] 值2"的非负数.
指定ID号为0和省略ID号(将检测所有的飞行道具)有相同的特征(效果).

示例:
1. trigger1 = ProjHit1234 = 1
如果一个ID号为1234的飞行道具刚成功击中对手则触发.
2. trigger1 = ProjHit1234 = 1, < 15
如果在最近15帧之内玩家的任意飞行道具成功击中对手则触发.


ProjHitTime (math)

此触发器拥有一个非负的ID号作为必须参数.
如果玩家的最近一个造成任何形式接触的飞行道具击中了对手且拥有指定ID号,则ProjHitTime返回从接触发生开始的帧数.
如果指定的ID号为0,则飞行道具的ID将不被检测.如果没有飞行道具符合上述所有条件,则ProjHitTime返回-1.

格式:
ProjHitTime(表达式)

参数:
表达式
计算非负ID号的表达式(整型)

返回值类型:
整型

错误条件:
如果表达式计算出bottom则返回bottom.如果指定负的ID号,则ID默认为0.

示例:
1. trigger1 = ProjHitTime(1234) = 1
如果一个ID为1234的飞行道具刚成功击中对手则触发.
2. trigger1 = ProjHitTime(0) != -1 && ProjHitTime(0) < 15
如果玩家的任何飞行道具在刚才的15帧之内成功击中对手则触发.


Random

返回0到999之间的一个随机数(0和999也包括在内,即[0,999]).

格式:
Random

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = Random <= 249
返回的随机数小于等于249则触发.(可能有25%几率发生)


RightEdge

RightEdge返回屏幕右边缘X轴方向位置(背景舞台的绝对坐标).

格式:
RightEdge

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
此触发器与表达式"CameraPos X + GameWidth / 2"相同.

示例:
trigger1 = Pos X + CameraPos X > RightEdge
如果玩家在屏幕右边缘的右面则触发.


RootDist

此触发器仅对helper类型人物有效.RootDist返回helper与它的根级(最顶级)之间距离.
根级是拥有helper的主玩家角色：
例如,如果你选择Kumquat进行游戏,而Kumquat创建了一个名为Kiwi的helper,Kiwi又顺序创建了一个名为Penguin的helper,则Penguin是Kumquat的一个子孙后代.
运行原理与 P2Dist 相似.

格式:
RootDist [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
如果玩家没有根级则返回bottom.

详情:
比较Y方向距离,RootDist给出了玩家的Y坐标上的高度区别.
负值表示根级在子级上方.
比较X方向距离, RootDist给出了根级坐标与子级坐标X方向上的距离.
正值表示根级在子级前方.

示例:
trigger1 = RootDist X != 0
如果根级的X坐标与helper人物不完全相同则触发.


RoundNo

返回当前的局号.

格式:
RoundNo

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = RoundNo = 3
如果这是比赛第3局则触发.

注意:
生存模式每胜利一次RoundNo增加1


RoundsExisted

返回玩家已经存在过的局数.在第1局,返回0.在Turns模式开场介绍中有用.

格式:
RoundsExisted

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = RoundsExisted = 0
trigger1 = TeamMode = Turns
trigger1 = RoundNo > 0
如果第1局后玩家刚进入Turns模式组队赛则触发.
通过覆盖初始化状态(state 5900),你能结合这个示例与ChangeState控制器配合切换到一个开场介绍状态(intro state).


RoundState

返回当前的局状态号.

格式:
RoundState

参数:
无

返回值类型:
整型

错误条件:
无

详情:
返回值类型:
0: 开场介绍之前 - 屏幕淡入
1: 开场介绍
2: 格斗 - 玩家战斗中
3: 结束之前 - 一局刚赢或刚输
4: 结束 - 做出胜利姿势

示例:
trigger1 = RoundState = 2
如果此局的还在战斗中则触发.


ScreenHeight

返回玩家局部坐标空间中的屏幕高度.

格式:
ScreenHeight

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
ScreenWidth和ScreenHeight不受摄像机缩放系数影响.

示例:
type = Explod
space = screen
pos = 0, ScreenHeight
...
在屏幕右下角创建一个screen空间的explod.


ScreenPos

获得玩家绝对位置(相对屏幕而言).

格式:
ScreenPos [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
无

详情:
对"ScreenPos X"来说,值是相对于屏幕左边来说的(最左端值为0).负值向左,正值向右.
对"ScreenPos Y"来说,值是相对于屏幕顶部来说的.负值向上,正值向下.

示例:
trigger1 = ScreenPos Y >= 0 && ScreenPos Y < GameHeight
当玩家在屏幕的竖直范围内则为真.


ScreenWidth

返回玩家局部坐标空间中的屏幕宽度.

格式:
ScreenWidth

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
ScreenWidth和ScreenHeight不受摄像机缩放系数影响.

示例:
type = Explod
space = screen
pos = ScreenWidth / 2, ScreenHeight / 2
...
在屏幕中心创建一个screen空间的explod.


SelfAnimExist (math)

如同AnimExist,只是SelfAnimExist仅检测P1的动画数据.
如果P1通过一个打击已经给出了P2的动画数据,SelfAnimExist将不会检测P2的动画数据来决定被给出的动作是否存在.
(主要在targetstate和p2stateno这类指定的state中检测动画是否存在).

请参阅: AnimExist, ChangeAnim2.


Sin (math)

计算指定参数正弦值(用弧度制表示)

格式:
sin(表达式)

参数:
表达式
需要计算正弦的表达式(浮点型)

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
value = sin(pi/2)
设置value的值为 π/2 的正弦值,约为1.0(可能有舍入误差)


StageVar(*,***)

返回stage(背景)的信息.支持数量有限的参数.

格式:
StageVar(参数名) [运算符] "字符串"

参数:
参数名
需要检测的stage参数名称.有效值为：
info.name, info.displayname, info.authorname.

[运算符]
=, != (其余运算符无效)

"字符串" (字符串型)
用来比较的字符串,必须写在双引号里.

返回值类型:
布尔型整数(1或0)

错误条件:
如果表达式计算出bottom则返回bottom.

详情:
info.author: 比较[Info]组中"author"参数的值.(布尔型)
info.displayname: 比较[Info]组中"displayname"参数的值.(布尔型)
info.name: 比较[Info]组中"name"参数的值.(布尔型)

版本:
1.0和以后的新版本

示例:
trigger1 = StageVar(info.author) = "Suika"
如果stage作者名字为"Suika"则返回真.


StateNo

返回玩家当前的状态号.在CMD文件"招式中断"中有用.

格式:
StateNo

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = stateno = [200,650]
如果状态号在200到650中为真.(200,650也包括在内)a


StateType

StateType给出了玩家的状态类型.参照CNS文档中StateDef位置获得StateType更多详情.
在CMD文件"招式中断"中有用.

格式:
StateType [运算符] 状态类型

参数:
[运算符]
=, != (其余运算符无效)

状态类型 (字符型)
S, C, A, L
站立,蹲下,空中,倒下 状态类型.

返回值类型:
布尔型整数(1或0)

错误条件:
如果表达式计算出bottom则返回bottom.

示例:
trigger1 = StateType != A
如果玩家不处于空中类型状态则触发.


SysFVar (math)

此触发器使用强制变量号作为参数.将返回玩家指定的系统浮点型变量值.
此触发器不应在普通环境下使用.系统变量为common1.cns中的簿记所预留.

格式:
SysFVar(表达式)

参数:
表达式
一个计算出变量号的表达式.目前的有效号码是0-4.

返回值类型:
浮点型

错误条件:
如果表达式计算出bottom或表达式计算出无效的变了索引则返回bottom.

示例:
trigger1 = SysFVar(0) = -1.23
如果索引为0的系统浮点变量为-1.23则触发.

注意:
SysFvar和Sysvar无法使用":="操作符进行赋值,且每回合开始时强制清零.


SysVar (math)

此触发器使用强制变量号作为参数.将返回玩家指定的系统整型变量值.
此触发器不应在普通环境下使用.系统变量为common1.cns中的簿记所预留.

格式:
SysVar(表达式)

参数:
表达式
一个计算出变量号的表达式.目前的有效号码是0-4.

返回值类型:
整型

错误条件:
如果表达式计算出bottom或表达式计算出无效的变了索引则返回bottom.

示例:
trigger1 = SysVar(0) = -34
如果索引为0的系统整型变量为-34则触发.

注意:
SysFvar和Sysvar无法使用":="操作符进行赋值,且每回合开始时强制清零.


Tan (math)

计算指定参数的正切值(弧度制).

格式:
Tan(表达式)

参数:
表达式
要计算正切值的表达式(浮点型)

返回值类型:
浮点型

错误类型:
如果表达式计算出bottom则返回bottom.

示例:
value = tan(pi/4)
设置value的值为 π/4 的正切值,约为1.0.(可能有一些舍入误差)


TeamMode(*,***)

TeamMode给出了玩家队伍所玩的当前模式.

格式:
TeamMode [运算符] 模式

参数:
[运算符]
=, != (其余运算符无效)

模式(字符串型)
single - 单人
simul - 2人同时
turns - 轮流作战

返回值类型:
布尔型整数(1或0)

错误条件:
无

注意:
在survival(生存)模式中,对敌方来说是TeamMode = turns.

示例:
trigger1 = TeamMode = Single
如果玩家正在玩single play模式则触发.


TeamSide

返回玩家所在的队伍方.1代表P1方(左),2代表P2方(右).

格式:
TeamSide

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = TeamSide = 2
如果玩家在p2方队伍则触发.


TicksPerSecond

返回每秒的帧数.用于计算时间方面.

格式:
TicksPerSecond

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = Time > 10 * TicksPerSecond
10秒之后触发(无论什么样的游戏速度).


Time

返回玩家的state-time(在某个状态内的时间)
(也就是说,直到目前,玩家已在当前state中(停留)的时间).

格式:
Time

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = Time = 2
当玩家的状态时间是2则触发.


TimeMod(*,**,***)

返回玩家的状态时间除以指定值的余数.
运算符"%"包含了TimeMod的功能,所以建议使用"%"来代替TimeMod.

格式:
TimeMod [运算符] 除数, 值1

参数:
[运算符]
=, !=, <, >, <=, >=

除数(整型)
除数是一个正值.

值1 (整型)
进行比较的余数值.

返回值类型:
布尔型整数(1或0)

错误条件:
如果除数是0则返回bottom.

示例:
trigger1 = TimeMod = 4, 3
当状态时间是3,7,11,15...时触发.


TopEdge

TopEdge返回屏幕顶部边缘y轴位置(绝对舞台坐标).

格式:
TopEdge

参数:
无

返回值类型:
浮点型

错误条件:
无

注意:
此触发器与表达式"Pos Y - ScreenPos Y"相同.

示例:
trigger1 = Pos Y > TopEdge
如果玩家在屏幕顶部边缘下方则触发.


UniqHitCount

返回玩家当前攻击招式造成的hit总数(连击数).
该值仅在单个状态内有效;任何状态改变之后,复位到0.
为了防止它复位到0,请查看StateDef中的hitcountpersist(查看cns文档获得更多详情).
HitCount和UniqHitCount触发器不同之处仅在于玩家正攻击1个以上的对手时.
当玩家正用相同攻击击中2个对手时,HitCount在每次击中时增加1,而UniqHitCount在每次击中时增加2.

格式:
UniqHitCount

参数:
无

返回值类型:
整型

错误条件:
无

示例:
trigger1 = UniqHitCount = [4,6]
当玩家的攻击招式开始后已完成4,5或6次连击则触发.


Var (math)

此触发器使用强制变量号作为参数.
将返回玩家指定的整型变量值.

格式:
Var(表达式)

参数:
表达式
需要计算参数号的表达式.
目前有效号是0-59.

返回值类型:
整型

错误条件:
如果表达式计算出bottom,
或者表达式计算出无效的变量索引则返回bottom.

示例:
trigger1 = Var(0) = -34
如果索引为0的整型变量 值为-34则触发.

注意:
在设置变量时,变量不能以大写字母开头,例如:
[State ]
type = VarSet
trigger1 = 1
Var(0) = 0 ;这是错误的写法

[State ]
type = VarSet
trigger1 = 1
var(1) = 0 ;这是正确的写法


Vel

获得玩家的速度值.你必须指定要检测的分量.比如,"Vel Y"检测Y方向速度.

格式:
Vel [分量]

参数:
[分量]
X, Y

返回值类型:
浮点型

错误条件:
无

详情:
对Vel X来说,正值表示玩家向前运动.(此特征与HitVel X相反)
对Vel Y来说,正值表示玩家向下运动.

示例:
trigger1 = Vel Y >= 0
当玩家没有向上运动时为真.


Win

如果玩家(或者玩家的队伍,在组队模式中)已赢得此局,则返回真,否则返回假.
能用"KO","Time"或者"Perfect"的后缀区分仅当此局通过KO或者是时间到了或者是完美胜利获胜的而返回1.

格式:
1. Win
2. WinKO
3. WinTime
4. WinPerfect

参数:
无

返回值类型:
布尔型整数(1或0)

错误条件:
无

示例:
1. trigger1 = Win
如果玩家(或他的队伍)赢了此局则触发.
2. trigger1 = !WinKO
如果玩家(或他的队伍)没有通过KO的方式赢了此局则触发.
例如,如果玩家的队伍还没赢得此局,或者如果他们通过时间终了的方式赢得此局,都将触发.


关于触发器

这是按顺序排列的触发器函数类型列表.要了解使用触发器函数类型的细节,请看下面的文档...
除非另有说明,我们使用P1代表计算触发器的人,P2代表他的对手(通常在teammode时候是最近的对手).

一些触发器是非标准的而且无法用表达式作为他们的参数.这些触发器在索引中用*来标记.

一些触发器不推荐使用,这些触发器在索引中用**来标记,不鼓励使用这些触发器,也许在未来的引擎中将不再支持他们.

旧式触发器,用***标记,仅出现在(触发器)(相关操作符)(值)的形式中.

标有 (math) 的说明该表达式用于数学运算.

对所有触发器而言,若被重新指向一个不存在的目标,或者重定向的ID号算出的结果是bottom,则该触发器会返回bottom.
这些不会在每个触发器的错误条件中列出.

Abs (math)
Acos (math)
AILevel
Alive
Anim
AnimElem
AnimElemNo (math)
AnimElemTime (math)
AnimExist (math)
AnimTime
Asin (math)
Atan (math)
AuthorName (*,***)
BackEdge
BackEdgeBodyDist
BackEdgeDist
BottomEdge
CameraPos
CameraZoom
CanRecover
Ceil (math)
Command (*,***)
Cond (math)
Const (*)
Const240p
Const480p
Const720p
Cos (math)
Ctrl
DrawGame
E
Exp (math)
Facing
Floor (math)
FrontEdge
FrontEdgeBodyDist
FrontEdgeDist
FVar (math)
GameHeight
GameTime
GameWidth
GetHitVar(*)
HitCount
HitDefAttr(*,***)
HitFall
HitOver
HitPauseTime
HitShakeOver
HitVel
ID
IfElse (math)
InGuardDist
IsHelper
IsHomeTeam
LeftEdge
Life
LifeMax
Ln (math)
Log (math)
Lose
MatchNo
MatchOver
MoveContact
MoveGuarded
MoveHit
MoveType(*,***)
MoveReversed
Name(*,***)
NumEnemy
NumExplod
NumHelper
NumPartner
NumProj
NumProjID (math)
NumTarget
P1Name(*,***)
P2BodyDist
P2Dist
P2Life
P2MoveType
P2Name(*,***)
P2StateNo
P2StateType
P3Name(*,***)
P4Name(*,***)
PalNo
ParentDist
Pi
Pos
Power
PowerMax
PlayerIDExist (math)
PrevStateNo
ProjCancelTime (math)
ProjContact(*,***)
ProjContactTime (math)
ProjGuarded(*,***)
ProjGuardedTime (math)
ProjHit(*,***)
ProjHitTime (math)
Random
RightEdge
RootDist
RoundNo
RoundsExisted
RoundState
ScreenPos
ScreenHeight
ScreenWidth
SelfAnimExist (math)
Sin (math)
StateNo
StateType
StageVar(*,***)
SysFVar (math)
SysVar (math)
Tan (math)
TeamMode(*,***)
TeamSide
TicksPerSecond
Time
TimeMod(*,**,***)
TopEdge
UniqHitCount
Var (math)
Vel
Win