public class 0100_Basic_Commands extends Object
======================== |0100.- Basic commands.| ========================
| 构造器和说明 |
|---|
0100_Basic_Commands() |
| 限定符和类型 | 方法和说明 |
|---|---|
void |
callfunc()
callfunc "<function>"{,<argument>,...
|
void |
callsub()
callsub <label>{,<argument>,...
|
void |
clear()
clear;
This command will clear the dialog text and continue the script without player interaction.
|
void |
cleararray()
cleararray <array name>[<first value to alter>],<value>,<number of values to set>;
This command will change many array values at the same time to the same value.
|
void |
close()
close;
This command will create a 'close' button in the message window for the invoking
character.
|
void |
close2()
close2;
This command will create a 'close' button in the message window for the invoking
character.
|
void |
copyarray()
copyarray <destination array>[<first value>],<source array>[<first value>],<amount of data to copy>;
This command lets you quickly shuffle a lot of data between arrays, which is in
some cases invaluable.
|
void |
countinarray()
countinarray <array name>{[<start index>]},<array name>{[<start index>]};
This command will check for matches between the array values and return the number of matches.
|
void |
deletearray()
deletearray <array name>[<first value>],<how much to delete>;
This command will delete a specified number of array elements totally from an
array, shifting all the elements beyond this towards the beginning.
// This will delete array element 0, and move all the other array elements
// up one place.
|
void |
do()
do { <statement>; } while (<condition>);
The 'do...while' is the only post-test loop structure available in this script
language.
|
void |
end()
end;
This command will stop the execution for this particular script.
|
void |
for()
for (<variable initialization>; <condition>; <variable update>) <statement>;
Another pretest looping structure is the 'for' statement.
|
void |
freeloop()
freeloop({<toggle>})
Toggling this to enabled (1) allows the script instance to bypass the infinite loop
protection, allowing your script to loop as much as it may need.
|
void |
function()
function <function name>;
<function name>{(<argument>,...
|
void |
getarg()
getarg(<index>{,<default_value>})
This function is used when you use the 'callsub' or 'callfunc' commands.
|
void |
getargcount()
getargcount()
This function is used when you use the 'callsub' or 'callfunc' commands.
|
void |
getd()
getd("<variable name>")
Returns a reference to a variable, the name can be constructed dynamically.
|
void |
getvar()
getvar <variable>,<char_id>;
Get variable value from the specified player.
|
void |
getvariableofnpc()
getvariableofnpc(<variable>,"<npc name>")
Returns a reference to a NPC variable (. prefix) from the target NPC.
|
void |
goto()
goto <label>;
This command will make the script jump to a label, usually used in conjunction
with other command, such as "if", but often used on its own.
...
|
void |
if()
if (<condition>) <statement>;
This is the basic conditional statement command, and just about the only one
available in this scripting language.
|
void |
inarray()
inarray <array name>,<value>;
This command returns the index of the first matching value found in the array.
|
void |
input()
input(<variable>{,<min>{,<max>}})
This command will make an input box pop up on the client connected to the
invoking character, to allow entering of a number or a string.
|
void |
is_function()
is_function("<function name>")
This command checks whether a function exists.
|
void |
jump_zero()
jump_zero (<condition>),<label>;
This command works kinda like an 'if'+'goto' combination in one go.
|
void |
menu()
menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
This command will create a selectable menu for the invoking character.
|
void |
mes()
mes "<string>"{,"<string>"{,...}};
This command will display a box on the screen for the invoking character, if no
such box is displayed already, and will print the string specified into that
box.
|
void |
next()
next;
This command will display a 'next' button in the message window for the
invoking character.
|
void |
return()
return {<value>};
This command causes the script execution to leave previously called function
with callfunc or script with callsub and return to the location, where the call
originated from.
|
void |
select()
select("<option>"{,"<option>",...})
|
void |
set()
set <variable>,<expression>{,<char_id>};
set(<variable>,<expression>{,<char id>});
This command will set a variable to the value that the expression results in.
|
void |
setarray()
setarray <array name>[<first value>],<value>{,<value>...
|
void |
setd()
setd "<variable name>",<value>{,<char_id>};
Works almost identically as set, except the variable name is identified as a string
and can thus be constructed dynamically.
|
void |
switch()
switch (expression);
The switch statement is similar to a series of if statements on the same expression.
|
void |
while()
while (<condition>) <statement>;
This is probably the simplest and most frequently used loop structure.
|
mes "<string>"{,"<string>"{,...}};
This command will display a box on the screen for the invoking character, if no
such box is displayed already, and will print the string specified into that
box. There is normally no 'close' or 'next' button on this box, unless you
create one with 'close' or 'next', and while it's open the player can't do much
else, so it's important to create a button later. If the string is empty, it
will show up as an empty line.
mes "Text that will appear in the box";
Colors
------
Inside the string you may put color codes, which will alter the color of the
text printed after them. The color codes are all '^<R><G><B>' and contain three
hexadecimal numbers representing colors as if they were HTML colors - ^FF0000 is
bright red, ^00FF00 is bright green, ^0000FF is bright blue, ^000000 is black.
^FF00FF is a pure magenta, but it's also a color that is considered transparent
whenever the client is drawing windows on screen, so printing text in that color
will have kind of a weird effect. Once you've set a text's color to something,
you have to set it back to black unless you want all the rest of the text be in
that color:
mes "This is ^FF0000 red ^000000 and this is ^00FF00 green, ^000000 so.";
Notice that the text coloring is handled purely by the client. If you use non-
English characters, the color codes might get screwed if they stick to letters
with no intervening space. Separating them with spaces from the letters on
either side solves the problem.
Multiple Lines
--------------
To display multiple lines of message while only using a single 'mes' command,
use the script command in the following format:
mes "Line 1", "Line 2", "Line 3";
This will display 3 different lines while only consuming a single line in
the relevant script file.
Navigation
----------
For clients dated 2011-10-10aRagexe onwards, you can generate navigation links
using HTML-like labels:
<NAVI>Display Name<INFO>mapname,x,y,0,000,flag</INFO></NAVI>
The "flag" parameter can be:
0: Do not open Navigation Window (default).
1: Open Navigation Window.
The example below will make the [Tool Shop] text clickable and begin navigation
to alberta (98,154) when clicked.
mes "Have you checked out the <NAVI>[Tool Shop]<INFO>alberta,98,154,0,000,0</INFO></NAVI>?";
See also 'navigateto', which can be used for certain NPC events.
Items
-----
You can refer to items by using HTML-like links to certain items:
<ITEMLINK>Display Name<INFO>Item ID</INFO></ITEMLINK>
Where <Display Name> is the name that will be displayed for your link and
<Item ID> being the ID of the item you want to link to when clicked.
In 2015 the tag name was changed to <ITEM> resulting in the following syntax:
<ITEM>Display Name<INFO>Item ID</INFO></ITEM>
The following sample will open a preview window for Red Potion:
mes "Did you ever consume a <ITEMLINK>Red Potion<INFO>501</INFO></ITEMLINK>?";
// Or in 2015:
mes "Did you ever consume a <ITEM>Red Potion<INFO>501</INFO></ITEM>?";
NOTE: Be aware that item links are rendered incorrectly in 2015+ clients at the moment.
URLs
----
Similarly, you can create links to websites that launch in a new window:
<URL>Display Name<INFO>http://www.example.com/</INFO></URL>";
next;
This command will display a 'next' button in the message window for the
invoking character. Clicking on it will cause the window to clear and display
a new one. Used to segment NPC-talking, next is often used in combination with
'mes' and 'close'.
If no window is currently on screen, one will be created, but once the invoking
character clicks on it, a warning is thrown on the server console and the script
will terminate.
mes "[Woman]";
mes "This would appear on the page";
next;
// This is needed since it is a new page and the top will now be blank
mes "[Woman]";
mes "This would appear on the 2nd page";
clear;
用于清空 NPC 等对话框的文本内容,该命令不会阻塞脚本执行,会继续往下执行无交互的脚本。
示例:
mes "This is how the 'clear' script command works.";
sleep2 3000;
clear; // This will clear the dialog and continue to the next one.
mes "I will show you again.";
sleep2 3000;
clear;
mes "Bye!";
close;
close;
This command will create a 'close' button in the message window for the invoking
character. If no window is currently on screen, the script execution will end. This is one
of the ways to end a speech from an NPC. Once the button is clicked, the NPC
script execution will end, and the message box will disappear.
mes "[Woman]";
mes "I am finished talking to you. Click the close button.";
close;
mes "This command will not run at all, since the script has ended.";
close2;
This command will create a 'close' button in the message window for the invoking
character. WARNING: If no window is currently on screen, the script execution will halt
indefinitely! See 'close'. There is one important difference, though - even though
the message box will have closed, the script execution will not stop, and commands after
'close2' will still run, meaning an 'end' has to be used to stop the script, unless you
make it stop in some other manner.
mes "[Woman]";
mes "I will warp you now.";
close2;
warp "place",50,50;
end;
Don't expect things to run smoothly if you don't make your scripts 'end'.
end;
This command will stop the execution for this particular script. The two
versions are perfectly equivalent. It is the normal way to end a script which
does not use 'mes'.
if (BaseLevel <= 10)
npctalk "Look at that you are still a n00b";
else if (BaseLevel <= 20)
npctalk "Look at that you are getting better, but still a n00b";
else if (BaseLevel <= 30)
npctalk "Look at that you are getting there, you are almost 2nd profession now right???";
else if (BaseLevel <= 40)
npctalk "Look at that you are almost 2nd profession";
end;
Without the use of 'end' it would travel through the labels until the end of the
script. If you were lvl 10 or less, you would see all the speech lines, the use
of 'end' stops this, and ends the script.
set <variable>,<expression>{,<char_id>};
set(<variable>,<expression>{,<char id>})
This command will set a variable to the value that the expression results in.
Variables may either be set through this command or directly, much like any
other programming language (refer to the "Assigning variables" section).
This is the most basic script command and is used a lot whenever you try to do
anything more advanced than just printing text into a message box.
set @x,100;
will make @x equal 100.
set @x,1+5/8+9;
will compute 1+5/8+9 (which is, surprisingly, 10 - remember, all numbers are
integer in this language) and make @x equal it.
Returns the variable reference (since trunk r12870).
setd "<variable name>",<value>{,<char_id>};
Works almost identically as set, except the variable name is identified as a string
and can thus be constructed dynamically.
This command is equivalent to:
set getd("variable name"),<value>;
Examples:
setd ".@var$", "Poporing";
mes .@var$; // Displays "Poporing".
setd ".@" + .@var$ + "123$", "Poporing is cool";
mes .@Poporing123$; // Displays "Poporing is cool".
NOTE:
'char_id' only works for non-server variables.
Player with Character ID 'char_id' must be online.
getd("<variable name>")
Returns a reference to a variable, the name can be constructed dynamically.
Refer to 'setd' for usage.
This can also be used to set an array dynamically:
setarray getd(".array[0]"), 1, 2, 3, 4, 5;
Examples:
set getd("$varRefence"), 1;
set @i, getd("$" + "pikachu");
getvariableofnpc(<variable>,"<npc name>")
Returns a reference to a NPC variable (. prefix) from the target NPC.
This can only be used to get . variables.
Examples:
//This will return the value of .var, note that this can't be used, since the value isn't caught.
getvariableofnpc(.var,"TargetNPC");
//This will set the .v variable to the value of the TargetNPC's .var variable.
set .v, getvariableofnpc(.var,"TargetNPC");
//This will set the .var variable of TargetNPC to 1.
set getvariableofnpc(.var,"TargetNPC"), 1;
Note: even though function objects can have .variables,
getvariableofnpc will not work on them.
getvar <variable>,<char_id>;
Get variable value from the specified player. Only player/account variables
are allowed to be used (temporary character variable "@", permanent
character "", permanent local account "#", and permanent global account "##").
goto <label>;
This command will make the script jump to a label, usually used in conjunction
with other command, such as "if", but often used on its own.
...
goto Label;
mes "This will not be seen";
end;
Label:
mes "This will be seen";
end;
This command should be avoided and only used if there is no other option.
menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
This command will create a selectable menu for the invoking character. Only one
menu can be on screen at the same time.
Depending on what the player picks from the menu, the script execution will
continue from the corresponding label. (it's string-label pairs, not label-
string)
Options can be grouped together, separated by the character ':'.
menu "A:B",L_Wrong,"C",L_Right;
It also sets a special temporary character variable @menu, which contains the
number of option the player picked. (Numbering of options starts at 1.)
This number is consistent with empty options and grouped options.
menu "A::B",L_Wrong,"",L_Impossible,"C",L_Right;
L_Wrong:
// If they click "A" or "B" they will end up here
// @menu == 1 if "A"
// @menu == 2 will never happen because the option is empty
// @menu == 3 if "B"
L_Impossible:
// Empty options are not displayed and therefore can't be selected
// this label will never be reached from the menu command
L_Right:
// If they click "C" they will end up here
// @menu == 5
If a label is '-', the script execution will continue right after the menu
command if that option is selected, this can be used to save you time, and
optimize big scripts.
menu "A::B:",-,"C",L_Right;
// If they click "A" or "B" they will end up here
// @menu == 1 if "A"
// @menu == 3 if "B"
L_Right:
// If they click "C" they will end up here
// @menu == 5
Both these examples will perform the exact same task.
If you give an empty string as a menu item, the item will not display. This
can effectively be used to script dynamic menus by using empty string for
entries that should be unavailable at that time.
You can do it by using arrays, but watch carefully - this trick isn't high
wizardry, but minor magic at least. You can't expect to easily duplicate it
until you understand how it works.
Create a temporary array of strings to contain your menu items, and populate it
with the strings that should go into the menu at this execution, making sure not
to leave any gaps. Normally, you do it with a loop and an extra counter, like
this:
setarray @possiblemenuitems$[0],<list of potential menu items>;
select("<option>"{,"<option>",...});
prompt("<option>"{,"<option>",...});
This function is a handy replacement for 'menu' for some specific cases where
you don't want a complex label structure - like, for example, asking simple yes-
no questions. It will return the number of menu option picked, starting with 1.
Like 'menu', it will also set the variable @menu to contain the option the user
picked.
if (select("Yes:No" ) == 1)
mes "You said yes, I know.";
And like 'menu', the selected option is consistent with grouped options
and empty options.
'prompt' works almost the same as select, except that when a character clicks
the Cancel button, this function will return 255 instead.
input(<variable>{,<min>{,<max>}})
This command will make an input box pop up on the client connected to the
invoking character, to allow entering of a number or a string. This has many
uses, one example would be a guessing game, also making use of the 'rand'
function:
mes "[Woman]";
mes "Try and guess the number I am thinking of.";
mes "The number will be between 1 and 10.";
next;
.@number = rand(1,10);
input .@guess;
if (.@guess == .@number) {
mes "[Woman]";
mes "Well done, that was the number I was thinking of!";
close;
} else {
mes "[Woman]";
mes "Sorry, that wasn't the number I was thinking of.";
close;
}
If you give the input command a string variable to put the input in, it will
allow the player to enter text. Otherwise, only numbers will be allowed.
mes "[Woman]";
mes "Please say HELLO";
next;
input .@var$;
if (.@var$ == "HELLO") {
mes "[Woman]";
mes "Well done, you typed it correctly.";
close;
} else {
mes "[Woman]";
mes "Sorry, you got it wrong.";
close;
}
Normally you may not input a negative number with this command.
This is done to prevent exploits in badly written scripts, which would
let people, for example, put negative amounts of Zeny into a bank script and
receive free Zeny as a result.
Since trunk r12192 the command has two optional arguments and a return value.
The default value of 'min' and 'max' can be set with 'input_min_value' and
'input_max_value' in script_athena.conf.
For numeric inputs the value is capped to the range [min,max]. Returns 1 if
the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
For string inputs it returns 1 if the string was longer than 'max', -1 is
shorter than 'min' and 0 otherwise.
callfunc "<function>"{,<argument>,...<argument>};
callfunc("<function>"{,<argument>,...<argument>});
This command lets you call up a function NPC. A function NPC can be called from
any script on any map server. Using the 'return' command it will come back to
the place that called it.
place,50,50,6%TAB%script%TAB%Woman%TAB%115,{
mes "[Woman]"
mes "Let's see if you win...";
callfunc "funcNPC";
mes "Well done, you have won!";
close;
}
function%TAB%script%TAB%funcNPC%TAB%{
.@win = rand(2);
if (.@win == 0)
return;
mes "Sorry, you lost.";
close;
}
You can pass arguments to your function - values telling it what exactly to do -
which will be available there with getarg() (see 'getarg')
Notice that returning is not mandatory, you can end execution right there.
If you want to return a real value from inside your function NPC, it is better
to write it in the function form, which will also work and will make the script
generally cleaner:
place,50,50,6%TAB%script%TAB%Man%TAB%115,{
mes "[Man]"
mes "Gimme a number!";
next;
input @number;
if (callfunc("OddFunc",@number)) mes "It's Odd!";
close;
}
function%TAB%script%TAB%OddFunc%TAB%{
if (getarg(0)%2 == 0)
return 0;// it's even
return 1;// it's odd
}
Alternately, as of rAthena revision 15979 and 15981, user-defined functions
may be called directly without the use of the 'callfunc' script command.
function<tab>script<tab>SayHello<tab>{
mes "Hello " + getarg(0);
return 0;
}
place,50,50,6<tab>script<tab>Man<tab>115,{
mes "[Man]";
SayHello strcharinfo(0);
close;
}
Note:
!! A user-defined function must be declared /before/ a script attempts to
!! call it. That is to say, any functions should be placed above scripts or NPCs
!! (or loaded in a separate file first) before attempting to call them directly.
callsub <label>{,<argument>,...<argument>};
callsub(<label>{,<argument>,...<argument>});
This command will go to a specified label within the current script (do NOT use
quotes around it) coming in as if it were a 'callfunc' call, and pass it
arguments given, if any, which can be recovered there with 'getarg'. When done
there, you should use the 'return' command to go back to the point from where
this label was called. This is used when there is a specific thing the script
will do over and over, this lets you use the same bit of code as many times as
you like, to save space and time, without creating extra NPC objects which are
needed with 'callfunc'. A label is not callable in this manner from another
script.
Example 1: callsub for checking (if checks pass, return to script)
callsub S_CheckFull, "guild_vs2",50;
switch( rand(4) ) {
case 0: warp "guild_vs2",9,50; end;
case 1: warp "guild_vs2",49,90; end;
case 2: warp "guild_vs2",90,50; end;
case 3: warp "guild_vs2",49,9; end;
}
...
S_CheckFull:
if (getmapusers(getarg(0)) >= getarg(1)) {
mes "I'm sorry, this arena is full. Please try again later.";
close;
}
return;
Example 2: callsub used repeatedly, with different arguments
// notice how the Zeny check/delete is reused, instead of copy-pasting for every warp
switch(select("Abyss Lake:Amatsu Dungeon:Anthell:Ayothaya Dungeon:Beacon Island, Pharos") {
case 1: callsub S_DunWarp,"hu_fild05",192,207;
case 2: callsub S_DunWarp,"ama_in02",119,181;
case 3: callsub S_DunWarp,"moc_fild20",164,145;
case 4: callsub S_DunWarp,"ayo_fild02",279,150;
case 5: callsub S_DunWarp,"cmd_fild07",132,125;
// etc
}
...
S_DunWarp:
// getarg(0) = "map name"
// getarg(1) = x
// getarg(2) = y
if (Zeny >= 100) {
Zeny -= 100;
warp getarg(0),getarg(1),getarg(2);
} else {
mes "Dungeon warp costs 100 Zeny.";
}
close;
getarg(<index>{,<default_value>})
This function is used when you use the 'callsub' or 'callfunc' commands. In the
call you can specify variables that will make that call different from another
one. This function will return an argument the function or subroutine was
called with, and is the normal way to get them.
This is another thing that can let you use the same code more than once.
Argument numbering starts with 0, i.e. the first argument you gave is number 0.
If no such argument was given, a zero is returned.
place,50,50,6%TAB%script%TAB%Woman1%TAB%115,{
mes "[Woman]";
mes "Let's see if you win...";
callfunc "funcNPC",2;
mes "Well done, you have won!";
close;
}
place,52,50,6%TAB%script%TAB%Woman2%TAB%115,{
mes "[Woman]";
mes "Let's see if you win...";
callfunc "funcNPC",5;
mes "Well done, you have won!";
close;
}
function%TAB%script%TAB%funcNPC%TAB%{
.@win = rand(getarg(0));
if (.@win == 0) return;
mes "Sorry, you lost.";
close;
|
"woman1" NPC object calls the funcNPC. The argument it gives in this call is
stated as 2, so when the random number is generated by the 'rand' function, it
can only be 0 or 1. Whereas "woman2" gives 5 as the argument number 0 when
calling the function, so the random number could be 0, 1, 2, 3 or 4, this makes
"woman2" less likely to say the player won.
You can pass multiple arguments in a function call:
callfunc "funcNPC",5,4,3;
getarg(0) would be 5, getarg(1) would be 4 and getarg(2) would be 3.
'getarg' has an optional argument since trunk r10773 and stable r10958.
If the target argument exists, it is returned.
Otherwise, if <default_value> is present it is returned instead,
if not the script terminates immediately.
In the previous example getarg(2,-1) would be 3 and getarg(3,-1) would be -1.
getargcount()
This function is used when you use the 'callsub' or 'callfunc' commands. In the
call you can specify arguments. This function will return the number of arguments
provided.
Example:
callfunc "funcNPC",5,4,3;
...
function%TAB%script%TAB%funcNPC%TAB%{
.@count = getargcount(); // 3
...
}
return {<value>};
This command causes the script execution to leave previously called function
with callfunc or script with callsub and return to the location, where the call
originated from. Optionally a return value can be supplied, when the call was
done using the function form.
Using this command outside of functions or scripts referenced by callsub will
result in error and termination of the script.
callfunc "<your function>";// when nothing is returned
set <variable>,callfunc("<your function>");// when a value is being returned
function <function name>;
<function name>{(<argument>,...<argument>)};
function <function name> {
<code>
}
This works like callfunc, and is used for cleaner and faster scripting. The function
must be defined and used within a script, and works like a label with arguments.
Note that the name may only contain alphanumeric characters and underscore.
Usage:
1. Declare the function.
function <function name>;
2. Call the function anywhere within the script.
It can also return a value when used with parentheses.
<function name>;
3. Define the function within the script.
<function name> {<code>}
Example:
prontera,154,189,4 script Item Seller 767,{
// Function declaration
function SF_Selling;
if (Zeny > 50) {
mes "Welcome!";
// Function call
SF_Selling;
}
else mes "You need 50z, sorry!";
close;
// Function definition
function SF_Selling {
mes "Would you like to buy a phracon for 50z?";
next;
if (select("Yes","No, thanks") == 1) {
Zeny -= Zeny;
getitem 1010,1;
mes "Thank you!";
}
return;
}
}
Example with parameters and return value:
prontera,150,150,0 script TestNPC 123,{
// Function declaration
function MyAdd;
mes "Enter two numbers.";
next;
input .@a;
input .@b;
// Function call
mes .@a + " + " + .@b + " = " + MyAdd(.@a,.@b);
close;
// Function definition
function MyAdd {
return getarg(0)+getarg(1);
}
}
is_function("<function name>")
This command checks whether a function exists.
It returns 1 if function is found, or 0 if it isn't.
Example:
function script try {
dothat;
}
- script test -1,{
.@try = is_function("try"); // 1
.@not = is_function("not"); // 0
}
if (<condition>) <statement>;
This is the basic conditional statement command, and just about the only one
available in this scripting language.
The condition can be any expression. All expressions resulting in a non-zero
value will be considered True, including negative values. All expressions
resulting in a zero are false.
If the expression results in True, the statement will be executed. If it isn't
true, nothing happens and we move on to the next line of the script.
if (1) mes "This will always print.";
if (0) mes "And this will never print.";
if (5) mes "This will also always print.";
if (-1) mes "Funny as it is, this will also print just fine.";
For more information on conditional operators see the operators section above.
Anything that is returned by a function can be used in a condition check without
bothering to store it in a specific variable:
if (strcharinfo(0) == "Daniel Jackson") mes "It is true, you are Daniel!";
More examples of using the 'if' command in the real world:
Example 1:
.@answer = 1;
input .@input;
if (.@input == .@answer)
close;
mes "Sorry, your answer is incorrect.";
close;
Example 2:
.@answer = 1;
input .@input;
if (.@input != .@answer)
mes "Sorry, your answer is incorrect.";
close;
Notice that examples 1 and 2 have the same effect.
Example 3:
jump_zero (<condition>),<label>;
This command works kinda like an 'if'+'goto' combination in one go. (See 'if').
If the condition is false (equal to zero) this command will immediately jump to
the specified label like in 'goto'. While 'if' is more generally useful, for
some cases this could be an optimization.
The main reason for this command is that other control statements, like
'switch', 'for' or 'while', are disassembled into simple expressions together
with this command when a script is parsed.
switch (expression);
The switch statement is similar to a series of if statements on the same expression.
In many occasions, you may want to compare the same variable (or expression)
with many different values, and execute a different piece of code depending
on which value it equals to. This is exactly what the switch statement is for.
It is important to understand how the switch statement is executed in order
to avoid mistakes. The switch statement executes line by line (actually, statement by statement).
In the beginning, no code is executed. Only when a case statement is found
with a value that matches the value of the switch expression the case statement(s)
will to executed. The parser continues to execute the statements until the end
of the switch block, or the first time it sees a break statement. If you don't
write a break statement at the end of a case's statement list, the parser will
go on executing the statements of the following case (fall-through).
Example 1:
switch(select("Yes:No")) {
case 1:
mes "You said yes!";
break;
case 2:
mes "Aww, why?";
break;
}
close;
The example above would work like a menu and would go to the first case if
the user selects option, otherwise, would go to the second one.
Example 2:
switch(getgroupid()) {
case 1:
mes "Wow, you're super!";
break;
case 2:
mes "A helping hand!";
break;
case 3:
mes "10001010010011";
break;
case 4:
mes "Yes, milord?";
break;
default:
mes "Hello there!";
break;
}
The example above would print a message depending on the player's groupid.
If there is no statement declared for the corresponding groupid, the script
would use the 'default' statement that applies to rest of possible values,
similar to 'else' in the if-else statement.
while (<condition>) <statement>;
This is probably the simplest and most frequently used loop structure. The 'while'
statement can be interpreted as "while <condition> is true, perform <statement>".
It is a pretest loop, meaning the conditional expression is tested before any of the
statements in the body of the loop are performed. If the condition evaluates to
false, the statement(s) in the body of the loop is/are never executed. If the
condition evaluates to true, the statement(s) are executed, then control transfers
back to the conditional expression, which is reevaluated and the cycle continues.
Multiple statements can be grouped with { }, curly braces, just like with the 'if' statement.
Example 1:
while (switch(select("Yes:No") == 2 ))
mes "You picked no.";
close;
Example 2: multiple statements
while (switch(select("Yes:No") == 2 )) {
mes "Why did you pick no?";
mes "You should pick yes instead!";
}
close;
Example 3: counter-controlled loop
.@i = 1;
while (.@i <= 5) {
mes "This line will print 5 times.";
.@i += 1;
}
close;
Example 4: sentinel-controlled loop
mes "Input 0 to stop";
input .@num;
while (.@num != 0) {
mes "You entered " + .@num;
input .@num;
}
close;
for (<variable initialization>; <condition>; <variable update>) <statement>;
Another pretest looping structure is the 'for' statement. It is considered a
specialized form of the 'while' statement, and is usually associated with counter-
controlled loops. Here are the steps of the 'for' statement: the initialize
statement is executed first and only once. The condition test is performed.
When the condition evaluates to false, the rest of the for statement is skipped.
When the condition evaluates to true, the body of the loop is executed, then the
update statement is executed (this usually involves incrementing a variable).
Then the condition is reevaluated and the cycle continues.
Example 1:
for( .@i = 1; .@i <= 5; .@i++ )
mes "This line will print 5 times.";
Example 2:
mes "This will print the numbers 1 - 5.";
for( .@i = 1; .@i <= 5; .@i++ )
mes "Number: " + .@i;
do { <statement>; } while (<condition>);
The 'do...while' is the only post-test loop structure available in this script
language. With a post-test, the statements are executed once before the condition
is tested. When the condition is true, the statement(s) are repeated. When the
condition is false, control is transferred to the statement following the
'do...while' loop expression.
Example 1: sentinel-controlled loop
mes "This menu will keep appearing until you pick Cancel";
do {
.@menu = select("One:Two:Three:Cancel");
} while (.@menu != 4);
Example 2: counter-controlled loop
mes "This will countdown from 10 to 1.";
.@i = 10;
do {
mes .@i;
.@i -= 1;
} while (.@i > 0);
freeloop({<toggle>})
Toggling this to enabled (1) allows the script instance to bypass the infinite loop
protection, allowing your script to loop as much as it may need. Disabling (0) will
warn you if an infinite loop is detected.
The command will return the state of freeloop for the attached script, even if no
argument is provided.
Example:
freeloop(1); // enable script to loop freely
// be careful with what you do here
for ( .@i = 0; .@i < .@bigloop; .@i++ ) {
dothis;
// will sleep the script for 1ms when detect an infinity loop to
// let rAthena do what it needs to do (socket, timer, process, etc.)
}
freeloop(0); // disable freeloop
for ( .@i = 0; .@i < .@bigloop; .@i++ ) {
dothis;
// throw an infinity loop error
}
setarray <array name>[<first value>],<value>{,<value>...<value>};
This command will allow you to quickly fill up an array in one go. Check the
Kafra scripts in the distribution to see this used a lot.
setarray @array[0], 100, 200, 300, 400, 500, 600;
First value is the index of the first element of the array to alter. For
example:
setarray @array[0],200,200,200;
setarray @array[1],300,150;
will produce:
cleararray <array name>[<first value to alter>],<value>,<number of values to set>;
This command will change many array values at the same time to the same value.
setarray @array[0], 100, 200, 300, 400, 500, 600;
// This will make all 6 values 0
cleararray @array[0],0,6;
// This will make array element 0 change to 245
cleararray @array[0],245,1;
// This will make elements 1 and 2 change to 345
cleararray @array[1],345,2;
See 'setarray'.
copyarray <destination array>[<first value>],<source array>[<first value>],<amount of data to copy>;
This command lets you quickly shuffle a lot of data between arrays, which is in
some cases invaluable.
setarray @array[0], 100, 200, 300, 400, 500, 600;
// So we have made @array[]
copyarray @array2[0],@array[2],2;
// Now, @array2[0] will be equal to @array[2] (300) and
// @array2[1] will be equal to @array[3].
So using the examples above:
deletearray <array name>[<first value>],<how much to delete>;
This command will delete a specified number of array elements totally from an
array, shifting all the elements beyond this towards the beginning.
// This will delete array element 0, and move all the other array elements
// up one place.
deletearray @array[0],1
// This would delete array elements numbered 1, 2 and 3, leave element 0 in its
// place, and move the other elements ups, so there are no gaps.
deletearray @array[1],3
inarray <array name>,<value>;
This command returns the index of the first matching value found in the array.
It will return -1 if the value is not found.
setarray .@array[0], 100, 200, 300, 400, 500, 600, 100;
inarray(.@array[0], 200);
//return 1 because 200 is in index 1
//another way to say it that .@array[1] == 200
.@index = inarray(.@array[0], 600);
//.@index is now 5 because .@array[5] == 600
inarray(.@array[0], 100);
//while index 6 is also 100, the command will return the first instance it finds
//return 0 because .@array[0] == 100
inarray(.@array[0], 800);
//return -1 because 800 is not an element of the array .@array
For more details, see the sample in 'doc/sample/inarray.txt'.
countinarray <array name>{[<start index>]},<array name>{[<start index>]};
This command will check for matches between the array values and return the number of matches.
While being optional, if [<start index>] is supplied, the search will begin from the given index value.
setarray .@array[0], 100, 200, 300, 400, 500, 600;
.@variable = 100;
if(countinarray(.@array[0], .@variable))
mes "The number 100 was found in the array @array";
countinarray(.@array[0], .@variable);
//return 1 because the number 100 is an element of the array .@array
setarray .@array2[0],100,500;
countinarray(.@array[0], .@array2[0]);
//return 2 because the numbers 100 and 500 are elements of the array .@array
setarray .@array3[0],100,700;
countinarray(.@array[0], .@array3[0]);
//return 1 because the number 100 is an element of the array .@array
//but the number 700 is not an element of the array .@array
//also you can change the position between the arrays in the command
if(countinarray(.@array[0], .@array3[0]) == countinarray(.@array3[0], .@array[0]))
//This is true
For more details, see the sample in 'doc/sample/inarray.txt'.
Copyright © 工程的初始时间(可选)–2019. All rights reserved.