-
Notifications
You must be signed in to change notification settings - Fork 132
ZSS (Zantei State Script) is a state description format new to IKEMEN GO that can be used instead of CNS. The basic structure is the same as CNS, but the grammar is significantly different.
Almost all CNS descriptions can be replaced with ZSS, with new features such as local variables and functions. ZSS could be useful for people that:
- Feels that the CNS format is redundant.
- Wants to compress or reuse code.
- Doesn't like to describe complicated processes many times.
- Has programming experience.
common1.cns.zss can be used as a sample. Comparing it to the original common1.cns may help you understand how to use it properly.
If you're using Notepad++, consider installing ZSS syntax highlighter.
Here is a brief manual for those who understand MUGEN CNS.
Specify the ZSS file like any other file in the character DEF's [Files] section. Additionally, characters can mix CNS and ZSS code, as long as they are in separate files.
The file extension describing ZSS is fixed with .zss.
Example:
st1 = kfm.zss
It's also possible to load a ZSS file if the referenced file is missing, but the same file name with additional .zss extension is present.
Example: File name
common1.cns.zss
Example: Description in DEF file. (under [Files])
stcommon = common1.cns
ZSS is composed of a collection of Statedefs much like CNS. All it's options (parameters) are written inside square/box brackets.
Example: CNS
[Statedef 0]
type = S
physics = S
sprpriority = 0
Example: ZSS
[StateDef 0; type: S; physics: S; sprPriority: 0;]
To specify a value, write :
instead of =
.
Separating parameters is done using ;
. All of these in the Statedef bracket always end using this.
Above example can be also written like this (whitespace doesn't matter):
[StateDef 0;
type: S;
physics: S;
sprPriority: 0;]
Write state code under Statedefs.
Format:
State controller name {parameter name: value}
State controllers in ZSS are written in a similar format to CNS, but triggers are not part of SCTRL definition.
Example: CNS
[State Sample]
type = PosAdd
trigger1 = 1
x = 10
Example: ZSS
posAdd{x: 10}
When writing multiple parameters, use ;
to separate them, just like in Statedefs.
Example: CNS
[State Sample]
type = PosAdd
trigger1 = 1
x = 10
y = -10
Example: ZSS
posAdd{x: 10; y: -10}
Example: With whitespace
posAdd{
x: 10;
y: -10;
}
On state controllers without parameters, leave the brace brackets inside empty.
Example:
turn{}
In the examples so far, nothing is written in the surrounding area, so that the Statedef is executed every frame (like writing "1" as the trigger of any SCTRL in CNS).
ZSS uses if
statements instead of CNS triggers.
Usage is roughly the same to the "if" sentences in a typical programming language.
Format:
"if" conditional statement {code to be executed}
Example: CNS
[State Sample]
type = PosAdd
trigger1 = time = 0
x = 10
Example: ZSS
if time = 0 {
posAdd{x: 10}
}
if
uses the same conditional statement as CNS triggers.
If code is added after the conditional statement, and is enclosed in {}
. The code within it is executed only while the if
condition is satisfied.
When you want to put more than one condition, you can write it like this:
Example: CNS
[State Sample]
type = PosAdd
triggerall = time = 0
trigger1 = stateType = S
trigger2 = stateType = C
trigger3 = stateType = L
x = 10
Example: ZSS
if time = 0 {
if stateType = S || stateType = C || stateType = L {
posAdd{x: 10}
}
}
You can write ifs inside another ifs to write more complex conditions.
An if
statement tests it's condition and executes it's {
-part or it's else
-part accordingly. The else-part is optional.
When you write nested ifs, you can also combine both if
and else
in the same line (the so called else if
statement in programming languages).
Example: CNS
[State Sample]
type = PosAdd
triggerall = time = 0
trigger1 = stateType = S
y = -50
[State Sample]
type = VelAdd
triggerall = time = 0
trigger1 = stateType = A
y = 0.1
[State Sample]
type = PosSet
triggerall = time = 0
trigger1 = stateType != S
trigger1 = stateType != A
y = -20
Example: ZSS
if time = 0 {
if stateType = S {
posAdd{y: -50}
} else if stateType = A {
velAdd{y: 0.1}
} else {
posSet{y: -20}
}
}
As an alternative to if/else, switch
statement can be used to produce tidier, more understandable code. Cases are defined inside the statement, where multiple cases can trigger the same code block (separating them by using ;
), and a default block can be defined in case all the other cases fail to trigger.
Example: If statement
if stateNo = 0 {
playSnd{value: 2,1}
} else if stateNo = 10 || stateNo = 20 {
playSnd{value: 2,2}
} else {
playSnd{value: 2,0}
}
Example: Switch statement
switch stateNo {
case 0:
playSnd{value: 2,1}
case 10; 20:
playSnd{value: 2,2}
default:
playSnd{value: 2,0}
}
Use ignoreHitPause
for ignoring hit pauses.
Use persistent
for specifying the interval between execution frames.
Code that should be affected by IgnoreHitPause and Persistent needs to be enclosed in {} (also affects nested blocks).
They can be used individually, or as part of if
statement (typed before if
).
Unlike IgnoreHitPause from CNS, it's not a separate SCTRL parameter (except Explod, which allows setting this parameter arbitrarily).
Example: CNS
[State Sample]
type = PosAdd
trigger1 = 1
x = 10
ignorehitpause = 1
Example: ZSS
ignoreHitPause {
posAdd{x: 10}
}
Example: CNS
[State Sample]
type = PosAdd
trigger1 = 1
x = 10
persistent = 5
Example: ZSS
persistent(5) {
posAdd{x: 10}
}
Both IgnoreHitPause and Persistent can be specified at the same time. If you specify more than one, bring the if
statement at the end.
Example: CNS
[State Sample]
type = PosAdd
trigger1 = Time = 0
x = 10
ignorehitpause = 1
persistent = 5
Example: ZSS
ignoreHitPause persistent(5) if time = 0 {
posAdd{x: 10}
}
In ZSS, simple variable operations such as VarSet/MapSet are obsolete.
Instead, manipulate variables using :=
.
It looks like an assignment expression that can be written with CNS trigger.
Example: CNS
[State Sample]
type = VarSet
trigger1 = 1
Var(59) = 1
Example: ZSS
var(59) := 1;
Example: CNS
[State Sample]
type = MapAdd
trigger1 = 1
Map(collection) = 1
Example: ZSS
map(collection) := map(collection) + 1;
Add ;
at the end of each assignment expression.
If you want to assign a variable to another character, specify the redirect to that character/helper as usual.
Example: CNS
[State Sample]
type = ParentVarSet
trigger1 = 1
Var(59) = 1
Example: ZSS
parent,var(59) := 1;
In ZSS, use #
to comment lines of code instead of ;
.
A variable that can only be used within a defined state and doesn't affect other states. Up to 256 can be set. Used primarily for passing disposable variables in the state or for passing functions numerically.
Format:
let < variable name > = value;
Put a ;
at the end.
Example:
let randomValue100 = Random%100;
If you want to change this value later, write it in exactly the same way.
Remember that all the descriptions for putting values into local variables are in this format.
Use: $ Variable name
To refer to the variable declared in the above example.
$randomValue100
For
iterates code inside a strict range. Statement header accepts three expressions, where exp1
and exp2
are the range of the loop, in integers, and exp3
is an optional incremental expression that can be positive or negative (a negative increment value will perform looping from a greater number to a lower one).
Example 1:
for 0; 10 {
map(collection) := map(collection) + 1;
}
Additionally, a control variable can be declared in the first expression of the header. Value from this local variable will persist after the loop has ended.
Example 2:
for i = 20; 10; -1 {
map(collection) := map(collection) + $i%4;
}
While
will iterate a state block indefinitely until the header expression returns false.
Example:
while var(20) < 40 {
var(20) := var(20) + 1;
}
Break/continue statements are useful to control the flow of the loop blocks. They're expected to be inside a loop block and must end with a ;
. Changing states inside loops will also break them.
Example:
let i = 0;
while $i < 10 {
if $i = 8 {
break;
}
let i = $i + 1;
if $i > 5 {
continue;
}
map(collector) := map(collector) + 1;
}
For safety and performance reasons, loops will be automatically broken after 2500 iterations. (nightly build only)
A function is a group of processes that allows you to call and execute the work you have written previously in a separate location.
Instead of writing a process to be used many times, it is possible to abstract the process in the form of a function and only write the call statement in a Statedef itself.
In CNS, the more complicated the functions to be implemented, the more complicated the code becomes. However, in ZSS, this can be solved to some extent by using functions.
Use: [Function FunctionName()]
Example: Function that plays voice during KO.
[Function PlayKOSound()]
playSnd{value: 11,0}
You can also write arguments and return values if you need them.
[Function FunctionName(argumentName) return valueName]
Write in the format of:
call FunctionName();
Only the functions written above the calling state can be called, so pay attention to the order of calls.
Example: Calling the PlayKOSound() function written above:
call PlayKOSound ();
You can also include arguments by using:
call FunctionName(argumentName);
See below for details.
A function can receive arguments and process it. This could be used to write processes that differ in input.
Arguments are listed within the parentheses, and are separated by commas.
To call the argument inside the function, use $
.
Example: Play a sound in the volume specified in the argument.
[Function PlayKOSound(VoiceVolume)]
playSnd{
value: 11,0;
volumescale: $VoiceVolume;
}
- The received argument is treated as a local variable by the function.
To call it we use:call PlayKOSound(200);
orcall PlayKOSound(50);
Multiple arguments could be used. Example: The function above but with the capacity of also setting the frequency.
[Function PlayKOSound(VoiceVolume, Frequency)]
PlaySnd{
value: 11,0;
volumeScale: $VoiceVolume;
freqMul: $Frequency;
}
And to call it we use:
call PlayKOSound(200, 0.5);
Functions can return values to the caller. The value can be specified by writing it after the function definition. The returned value can be assigned to a variable.
A example of a Function with return argument:
[Function IsHelperID() ret]
let ret = 0;
if isHelper(1) {
let ret = 1;
} else if isHelper(2) {
let ret = 2;
} else if isHelper(3) {
let ret = 3;
} else if isHelper(4) {
let ret = 4;
} else if isHelper(5) {
let ret = 5;
}
In this case the return value was specified as ret
in [Function IsHelperID () ret]
As an example, you can retrieve the value like this:
let helperIdValue = call IsHelperID();