{{outdated}}
Scripts control all NPCs, warps, mob spawns, shops, and quests you will find
in the game--and nearly everything else! Clearly they play a large part in
customizing a server, but learning isn't very hard.
Scripts are built up of predefined script commands, all of which can be found
in {{git|doc/script_commands.txt}} (for explanations, see
:Category:Script_Command). Every line should begin with a
command and the argument it takes, and must end in a semicolon (or you'll get
mapserver errors!). Arguments are usually separated by commas, and are
sometimes contained in parentheses () or curly brackets {}. Tabs and proper
indentation are standard scripting measures.
Scripts are saved as text (*.txt) files, so all code can be written in
Notepad. There are also a lot of scripting programs to use: the most recent
and comprehensive one is Vince's
eNPC. All defined
functions are highlighted, with an autocomplete feature included, and pressing
"F1" will display the corresponding explanation for any command.
A Script NPC will look something like the following:
prontera,156,145,4 <tab> script <tab> Test NPC <tab> 1_M_MERCHANT,{
The first section is the map location of the NPC, followed by its coordinates
in x,y and the direction the NPC will face. Direction numbers are counted
counterclockwise in 45º increments, with 0 being the center:
After the first tab, the type of script is defined. For our purposes, it'll
stay "script" for now, but can also be function, shop, or cashshop, for
starters.
The name of the NPC is next. You can use up to 24 characters, so make it
unique! Any duplicates will cause warnings or errors, and the NPC will just be
automatically renamed anyway.
The last number is for the sprite (Ai4rei's sprite list can be found
here). It's followed by a comma and open
curly bracket, marking the beginning of the script contents. Of course, the
script must also end in a curly bracket.
A Function script will look almost identical to:
function <tab> script <tab> Function Name <tab> {
The words "function" and "script" won't change; the name must also be unique.
All functions can be called using the "callfunc" command.
A Shop starts like a normal script:
prontera,156,145,4 <tab> shop <tab> Fruit Store <tab> 1_M_MERCHANT,512:-1,513:1000
The first section defines the map, coordinates, and direction. The word "shop"
replaces "script" (alternately, "cashshop" will use Cashpoints instead of
Zeny). The name and sprite ID follow, then a comma.
Items in the shop are defined in an ID:Price format. A price of -1 uses the
default price in item_db.txt. Be sure the price is not too low, or a you will
open a Zeny exploit in your server!
You can always look up commands that you need--even the best scripters don't
have everything memorized. There are a few fundamentals that you should know
by heart, though, since they are so commonly used.
*mes "<string>";
This is the most basic command. Start the line with the word mes, then enter
the message in quotes (don't forget the semicolon at the end!).
To add color, simply add ^ and the hex code anywhere in the message. A list
can be found here.
As an example:
mes "[^FF0000Test NPC^000000]";
mes "Hello!";
Will display:
[Test NPC]
Hello!
To create a label, type a label name and a colon at the start of a line. If
the label does not end with an "end;" command, everything following the label
will be read, so don't forget it between labels!
To go to a label, use the simple "goto" command:
*goto <label>;
Note that there are "special" labels that trigger whenever a specific event
occurs. The name usually makes it obvious, but you can find explanations in
script_commands.txt. Here is a brief sampling:
OnClock<hour><minute>:
OnInit:
OnAgitStart:
OnAgitEnd:
OnTouch:
OnPCLoginEvent:
OnPCLogoutEvent:
OnPCBaseLvUpEvent:
OnPCJobLvUpEvent:
OnPCDieEvent:
OnPCKillEvent:
OnNPCKillEvent:
OnPCLoadMapEvent:
{{EntirePage|Menus}}
*menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
*close;
*next;
Menus create a set of options, which trigger labels when selected. The text in
quotes is what will be displayed, followed by its respective label. Enter as
many choices as you want, and end the last one with a semicolon instead of a
comma.
"Close" will close any message window that is open (from "mes" commands).
"Next" will clear the message window, bringing up a fresh screen.
For example:
mes "[Test NPC]";
mes "How are you doing today?";
menu "I am doing okay!",doingokay,"Not doing too well",bad;
doingokay:
mes "Glad to hear it!";
close;
end;
bad:
mes "Aww, I'm sorry about that.";
close;
end;
{{EntirePage|Variables}}
*if(condition) {<script>;}
*else {<script>;}
Conditional statements "if" and "else" are the same as anywhere else. Multiple
conditions can be specified: || means or , while && means and. == is
equal , != is not equal. Inequalities can be used as well (
The "else" can be omitted, and the brackets aren't necessary unless multiple
commands follow a conditional statement.
The type of variable used is defined in the name. There are permanent and
temporary variables, as well as scope (temporary NPC), character, global, and
global account. The default type is an integer, and adding $ as a suffix
creates a string.
Here are some example types, taken from script_commands.txt:
name - permanent character integer variable
name$ - permanent character string variable
@name - temporary character integer variable
@name$ - temporary character string variable
$name - permanent global integer variable
$name$ - permanent global string variable
$@name - temporary global integer variable
$@name$ - temporary global string variable
.name - NPC integer variable
.name$ - NPC string variable
.@name - scope integer variable
.@name$ - scope string variable
#name - permanent local account integer variable
#name$ - permanent local account string variable
##name - permanent global account integer variable
##name$ - permanent global account string variable
The "set" command is used to give a value (or string) to a variable:
*set <variable>,<expression>;
The following script will pick a random number, store it as the temporary
scope variable .@random, and display two different messages depending on the
result:
set .@random, rand(1,2);
if (.@random == 1) { mes "I like you! :D"; }
else { mes "I don't like you. Get out of here!"; }
close;
It would be a huge waste of time and space to code the same NPC over and over
again. By duplication, an NPC can be created in multiple locations.
Take a look at our old Test NPC:
prontera,156,145,4 <tab> script <tab> Test NPC <tab> 1_M_MERCHANT,{
To be able to duplicate this, we will change the heading to this:
- <tab> script <tab> Test NPC#01::testnpc <tab> 1_M_MERCHANT,{
The location doesn't need to be defined in the NPC, since it will be in the
duplicates.
The displayed name remains "Test NPC". But since NPC names must be unique,
adding #01 separates this one from the rest, which will be #02, #03, etc.
Lastly, ::testnpc is the reference name used for duplicating NPCs; this part
is not displayed on the screen.
After creating the base NPC, duplicates can be added anywhere to any file, so
long as you use the same NPC name:
spl_fild03,150,150,7 <tab> duplicate(testnpc) <tab> Test NPC <tab> 1_M_MERCHANT
niflheim,50,50,2 <tab> duplicate(testnpc) <tab> Test NPC <tab> 1_M_MERCHANT
tha_scene01,140,190,4 <tab> duplicate(testnpc) <tab> Test NPC <tab> 1_M_MERCHANT
The first part is map,x,y,direction , as you're probably used to by now.
To define a duplicate, the word "duplicate" followed by the NPC, in
parentheses, is needed. The last two parameters are the display name and NPC
view constant (actual name of the npc sprite, yes, you can change these,
too!).
Here is an example using the features explained above:
prontera,156,145,4 script Test NPC::test 4_WHIKEBAIN,{
mes "Hello, how are you?";
mes "I am fine, how are you?";
menu "I am doing okay!",-,"Not doing too good",bad;
mes "That's good, I'm glad to hear that";
close;
bad:
mes "Awww, that makes me a bit ^FF0000sad^000000. Sorry to hear that.";
next;
mes "Would you like some zeny to help yourself feel better?";
next;
menu "Sure, give it to me!",L_zeny,"Naw, No zeny for me",-;
close;
L_Zeny:
mes "I can only give you zeny if you have 10,000 or less.";
if (Zeny > 10000) goto toomuch;
mes "You have 10,000 zeny or less, I see.";
set Zeny,Zeny+10000;
next;
mes "Hope you feel better!";
close;
toomuch:
mes "You have over 10,000 zeny, you must feel really good about yourself!";
close;
}
lhz_dun01,157,285,4 duplicate(test) Test NPC 4_F_AGENTKAFRA
hu_fild05,186,210,4 duplicate(test) Test NPC 4_F_AGENTKAFRA
yuno_fild07,221,179,4 duplicate(test) Test NPC 4_F_AGENTKAFRA
tha_scene01,139,194,1 duplicate(test) Test NPC 4_F_AGENTKAFRA
{{EntirePage|Adding a Script}} For an NPC to be loaded, it needs to be added
to a .conf file. This is typically npc/scripts_custom.conf.
Add a line, and enter your NPC file in the following format:
npc: npc/path/to/script.txt
That's it! You're finished!
Reference Manuals for scriping commands
Sprite lists
Color Charts
Support, Request and Release