<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://graalonline.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Twinny</id>
	<title>Graal Bible - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://graalonline.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Twinny"/>
	<link rel="alternate" type="text/html" href="https://graalonline.net/Special:Contributions/Twinny"/>
	<updated>2026-04-09T22:57:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>https://graalonline.net/index.php?title=Template:Playerworld_Administration_Team&amp;diff=17731</id>
		<title>Template:Playerworld Administration Team</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Template:Playerworld_Administration_Team&amp;diff=17731"/>
		<updated>2011-01-04T01:17:18Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Administration]][[Category:Global Staff]]&lt;br /&gt;
* [[User:Tigairius|Tig]]&lt;br /&gt;
**[http://forums.graalonline.com/forums/private.php?do=newpm&amp;amp;u=5380 Forum PM: Tigairius]&lt;br /&gt;
** AIM: Tigairius&lt;br /&gt;
** E-mail: [mailto:Tig@graalonline.com Tig@graalonline.com]&lt;br /&gt;
* [[User:Xor|Xor]]&lt;br /&gt;
**[http://forums.graalonline.com/forums/private.php?do=newpm&amp;amp;u=6109 Forum PM: Xor]&lt;br /&gt;
** E-mail: [mailto:xor@graalonline.com xor@graalonline.com]&lt;br /&gt;
* [[User:benpoke103|Ben]]&lt;br /&gt;
**[http://forums.graalonline.com/forums/private.php?do=newpm&amp;amp;u=1901 Forum PM: benpoke103]&lt;br /&gt;
** E-mail: [mailto:ben@graalonline.com ben@graalonline.com]&lt;br /&gt;
* [[User:Twinny|Twinny]]&lt;br /&gt;
**[http://forums.graalonline.com/forums/private.php?do=newpm&amp;amp;u=4853 Forum PM: Twinny]&lt;br /&gt;
** E-mail: [mailto:twinny@graalonline.com twinny@graalonline.com]&lt;br /&gt;
&lt;br /&gt;
You can also contact the Playerworld Administration Team via [mailto:accounts@graalonline.com accounts@graalonline.com] and [mailto:support@graalonline.com support@graalonline.com].&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Excalibur%27s_scripting_guide&amp;diff=8941</id>
		<title>Creation/Dev/Excalibur's scripting guide</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Excalibur%27s_scripting_guide&amp;diff=8941"/>
		<updated>2007-07-01T07:56:24Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''Excalibur's Scripting Guide''' ==&lt;br /&gt;
I'm hoping this allows people to learn how to script a bit easier, I believe all staff should know some scripting basics, and I find other GS2 guides hard to follow. This should help you get started out. I'm afraid it isn't complete and there are a few typos in it. I'm working on it. &lt;br /&gt;
&lt;br /&gt;
Starting:&lt;br /&gt;
&lt;br /&gt;
Level NPCs:&lt;br /&gt;
&lt;br /&gt;
A level NPC is an npc that functions in a specific level. These are the most common on most servers. They are also a very important part of developement.&lt;br /&gt;
&lt;br /&gt;
A script:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//this is a note&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
this is also a note, these help make scripts more clear&lt;br /&gt;
this type of note can go on as longe as it's inclosed&lt;br /&gt;
*/&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
//This tells the computer that the following&lt;br /&gt;
//script will be on the players client, &lt;br /&gt;
//as opposed to the server, this is very important.&lt;br /&gt;
function onPlayerTouchsMe()&lt;br /&gt;
//this checks if the player has touched the NPC&lt;br /&gt;
{ // starting bracket&lt;br /&gt;
  this.chat = &amp;quot;Hey!&amp;quot;; //displays a message above the NPC&lt;br /&gt;
}//closing bracket&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The above script checks to see if the event, playertouchsme is true, then acts on what is in the bracket. It is important to include this clientside, because too many serverside scripts can cause problems for an NPC server, however they are more secure. If you wanted to do the last script serverside, you would omit the //#CLIENTSIDE , and add the shape to the NPC:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape(1,32,32);&lt;br /&gt;
  setimg(&amp;quot;block.png&amp;quot;);&lt;br /&gt;
//img can also be done in the box above the script&lt;br /&gt;
}&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  this.chat = &amp;quot;You made a serverside script!&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This takes a bit longer than clientside commands, and it takes up serverside script time, however, for secure actions, it may be necessary.&lt;br /&gt;
A secure script example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.account=&amp;quot;Excaliber7388&amp;quot;;&lt;br /&gt;
  setshape(1,32,32);&lt;br /&gt;
  this.chat=&amp;quot;Excaliber's Chest&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  if(player.account==this.account)&lt;br /&gt;
  {&lt;br /&gt;
    this.chat=&amp;quot;This is a secure message!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
First, I would like to quickly point out the 'if' statement. Some guides go into this a lot, but it's actually quite simple. The if statement is a very important part of scripting. It's what allows the NPC to make choices. The code withing the brackets of an if statement will only execute if the statement is true. Also, there is a catchall statement you can use, else. If the if statement is not true, the else will exectue it's script, other wise it is ignored. &lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.a=1;&lt;br /&gt;
}&lt;br /&gt;
if(this.a==1) &lt;br /&gt;
//always use '==' for comparasons, NEVER just '=' as '=' is for assignments&lt;br /&gt;
{&lt;br /&gt;
  this.b=2;&lt;br /&gt;
}&lt;br /&gt;
else if(this.a==2) //will only execute if first is false, AND this.a==2&lt;br /&gt;
{&lt;br /&gt;
  this.b=3;&lt;br /&gt;
}&lt;br /&gt;
else //catch all if above 2 statements are false&lt;br /&gt;
{&lt;br /&gt;
  this.b=4;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, in the above example, this.b will always be 2, however, it's the format that's important.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(statement)&lt;br /&gt;
else if(statement)&lt;br /&gt;
else if(statement //may be used many times&lt;br /&gt;
else //catch all&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, back to serverside and clientside scripts:&lt;br /&gt;
By putting the checks on serverside, you disable a hackers ability to send an action from their client. So, this script is much more secure, and can only be accessed by the specified account (Excaliber7388 in this case). Most playerworlds and classic servers do these checks serverside as well, but we also apply a different method, to avoid having too much serverside script time:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.account=&amp;quot;Excaliber7388&amp;quot;;&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
  this.chat=&amp;quot;Excaliber's Chest&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
function onActiontouched()&lt;br /&gt;
{&lt;br /&gt;
  if(player.account==this.account)&lt;br /&gt;
  {&lt;br /&gt;
    this.chat=&amp;quot;Yup, this is still secure, yay!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  triggeraction(x,y,&amp;quot;Touched&amp;quot;,&amp;quot;Touched&amp;quot;);//no params needed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This script will take up more time, but the playertouchsme check is clientside. Would this help much? Probably not, in fact, sending the action in this case would probably create more lag than having the script serverside. However, if a large portion of the script is serverside, and can be moved to clientside without risking security, it may be a good idea. &lt;br /&gt;
Serverisde timeouts=bad idea.&lt;br /&gt;
You shouldn't send to many actions to serverside, especially if you do so quickly. You should always limit the serverside timeouts, and the amount of time between actions to the server from client should be spaced out. Also, you should never have a timeout shorter than .05 on serverside, though it is possible, please do not do it. Many playerworlds have expierenced problems from serverside timeouts which can lead to NPC server crashing or lagging.&lt;br /&gt;
&lt;br /&gt;
Here are two examples of serverside scripts, the first is [b]VERY[/b] bad, the second is more productive:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActiontime()&lt;br /&gt;
{&lt;br /&gt;
  for(server.i=0;server.i&amp;lt;5;server.i++)&lt;br /&gt;
 //WHY use server for this???&lt;br /&gt;
 //for loops, use this. it works only for this NPC&lt;br /&gt;
  {&lt;br /&gt;
    sleep(.01); &lt;br /&gt;
//WAY to short of a sleep time for the server&lt;br /&gt;
   }   &lt;br /&gt;
    server.time+=.1;&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(.05); //minimum clientside timeout&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  trigegraction(x,y,&amp;quot;time&amp;quot;,&amp;quot;time&amp;quot;);&lt;br /&gt;
  settimer(.05);&lt;br /&gt;
//Will cause a loop through the timeout, sending action &lt;br /&gt;
//to serverside TOO quickly, AND while the server is &lt;br /&gt;
//still working on the last action. This WILL cause the &lt;br /&gt;
//server to crash.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you put the above script on a server, say goodbye to your NPC server, because it will crach pretty quickly!&lt;br /&gt;
A better version:&lt;br /&gt;
&amp;lt;pre&amp;gt;function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
  //setshape is needed for all level NPCs triggeractions&lt;br /&gt;
  //this sets it to a square of tiles 32x32 pixels.&lt;br /&gt;
}&lt;br /&gt;
function onActiontime()&lt;br /&gt;
{&lt;br /&gt;
  server.time++;&lt;br /&gt;
  //no need for incredible accuracy&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  triggeraction(x,y,&amp;quot;time&amp;quot;,&amp;quot;time&amp;quot;);&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will execute the script less often, however, it still is an unlimited loop. Don't have too many of these NPCs, or you could have problems!&lt;br /&gt;
&lt;br /&gt;
Now, you may have noticed this line in the bad script:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for(server.i=0;server.i&amp;lt;5;server.i++)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a 'for' loop. There are many types of loops, however the for loop isn't the easiest to learn first. Therefore, I will show you the 'while loop' first.&lt;br /&gt;
The while loop executes whatever is held within it's brackets as long as the statement within it is true. The while loop is just like an if statement, but you cannot use else with a with statement.&lt;br /&gt;
format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
while(statments)&lt;br /&gt;
{&lt;br /&gt;
  //commands&lt;br /&gt;
}&lt;br /&gt;
//if statment is still true, it will loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
here's a script example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.size=10;&lt;br /&gt;
}&lt;br /&gt;
while(this.size&amp;lt;=20) //while this.size is less than or equal to 20&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  //as the story is retold....&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
  this.size=this.size+1;&lt;br /&gt;
  //increment the size&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The above script will run through the loop until this.size is equal or greater than 20.&lt;br /&gt;
Some important things to know:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(a==b) means if a is equal to b&lt;br /&gt;
if(a&amp;lt;b) means if a is less than b&lt;br /&gt;
if(a&amp;gt;b) means if a is greater than b&lt;br /&gt;
if(a&amp;lt;=b) means if a is less than or equal to be&lt;br /&gt;
if(a&amp;gt;=b) means if a is greater than or equal to be&lt;br /&gt;
a++      is the same as a=a+1&lt;br /&gt;
a--      is the same as a=a-1&lt;br /&gt;
a+=b    means a=a+b&lt;br /&gt;
a-=b    means a=a-b&lt;br /&gt;
a*=b    means a=a*b (multiplied by b)&lt;br /&gt;
a/=b    means a=a/b&lt;br /&gt;
++a     is just like a, but it will add to a before anything else in the line, &lt;br /&gt;
         this is not important to know now&lt;br /&gt;
--a     just like ++a, but with subtraction&lt;br /&gt;
a%b     Modulus, basically, its a/b and th remainder is the output &lt;br /&gt;
        for example 10%3=1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These may be helpfull in loops, or in any other rational expressions you may use. (Well, it's important for all scripting!)&lt;br /&gt;
Now, recall this line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The output for this is: The fish was (size here) centimeters long!&lt;br /&gt;
The script NEEDS to know where a variable is, so if you want to put it in between a string you surround it with the '@' symbol. Or if it's at the end, you only put the '@' at the beggining of the variable. The variable and the '@' do NOT go in the quotes. Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;Well hi there, &amp;quot; @player.account@ &amp;quot; I like your sword, &amp;quot; @player.swordimg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This would display the player's account, and sword image.&lt;br /&gt;
&lt;br /&gt;
Now, back to the 'for' loop.&lt;br /&gt;
This a very interesting loop it's format is as follows:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for(command;expression;command)&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here's an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  for(this.i=0;this.i&amp;lt;10;this.i++)&lt;br /&gt;
  {&lt;br /&gt;
    this.chat=&amp;quot;Loops: &amp;quot; @this.i;&lt;br /&gt;
    sleep(.5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This loop would be activated when the player touchs it.&lt;br /&gt;
It would go through 10 loops, displaying the count, and taking .5 seconds for each loop (due to the sleep() command)&lt;br /&gt;
Now remember this while loop?&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.size=10;&lt;br /&gt;
}&lt;br /&gt;
while(this.size&amp;lt;=20)&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  //as the story is retold....&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
  this.size=this.size+1;&lt;br /&gt;
  //increment the size&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There's an easier way of doing it with a for loop, in fact all loops done with while can be replaced by for.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for(this.size=10;this.size&amp;lt;=20;this.size++)&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See? Much shorter and easier to use!&lt;br /&gt;
Once you know the format of a for loop, you can make longer and more complex loops as well, and they'll take less time to script, which is always a bonus.&lt;br /&gt;
&lt;br /&gt;
Some more detail on actions:&lt;br /&gt;
An action is an effective way to use a portion of script more than once, have one script act on another script, more script to serverside from clientside (and the other way) and more.&lt;br /&gt;
So how do you use them? Here's the format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
triggeraction(x,y,&amp;quot;params[0]&amp;quot;,&amp;quot;params[1]&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You must have two parameters, but you can have as many as you want a quick example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActiontrigger()&lt;br /&gt;
{&lt;br /&gt;
  player.chat=&amp;quot;Account: &amp;quot; @params[1]@ &amp;quot; Sword &amp;quot; @params[2]@ &amp;quot; head: &amp;quot; @params[3];&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayerchats()&lt;br /&gt;
{&lt;br /&gt;
  if(player.chat==&amp;quot;Who am I?&amp;quot;) //amnesia? multiple identities?&lt;br /&gt;
  {&lt;br /&gt;
    triggeraction(x,y,&amp;quot;trigger&amp;quot;,player.account,player.swordimg,player.headimg);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See? You can make more than one parameter.&lt;br /&gt;
Now, there are a few differences between a level NPC with a triggeraction, and a weapon with a triggeraction. Weapons need their location (serverside or clientside) as the first parameter, params[0] is the one after it. Here, you can have just one parameter, and the x and y is always 0 (because the npc server is at 0,0), and you need to include the name of the weapon in the action.&lt;br /&gt;
here's an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//weapon script with a triggeraction &lt;br /&gt;
//Weapon name: Fire Ball&lt;br /&gt;
function onActionserverside()&lt;br /&gt;
{&lt;br /&gt;
  if(params[0]==&amp;quot;mp&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    playermp-=10&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onWeaponfired()&lt;br /&gt;
{&lt;br /&gt;
  if(playermp&amp;gt;=10)&lt;br /&gt;
  {&lt;br /&gt;
    shootfireball(playerdir);&lt;br /&gt;
    triggeraction(0,0,&amp;quot;serverside&amp;quot;,&amp;quot;Fireball&amp;quot;,&amp;quot;mp&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    player.chat=&amp;quot;Not enough mp!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This nifty little weapon will cost 10 mp per use, and fires a fireball in the direction the player is facing. Hopefully, you can learn to make many weapons of your own!&lt;br /&gt;
Triggeractions can be used in shops as well (and these are the scripts people ask for the most).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//a shop script, yay!&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActionbuy()&lt;br /&gt;
{&lt;br /&gt;
  if(playerrupees&amp;gt;=100)&lt;br /&gt;
  {&lt;br /&gt;
    addweapon Fire Ball;&lt;br /&gt;
    playerrupees-=100;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayerchats()&lt;br /&gt;
{&lt;br /&gt;
  if(player.chat==&amp;quot;buy fire ball&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    triggeraction(x,y,&amp;quot;buy&amp;quot;,&amp;quot;buy&amp;quot;); &lt;br /&gt;
    //the level npc triggeraction type&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There, now you can make a little shop that sells a Fire Ball weapon. Have fun with it, search the commands, there's plenty of easy weapons you can make, and the weapon script is easy to follow and modify as well. Hopefully, you know enough about parameters to make more than one weapon for sale in the same NPC, just make the weapon name part of the action, then check for that parameter before they can buy. &lt;br /&gt;
 Now there are other types of loops. One I commonly see is a timeout loop. You should understand why. Back with GS1, it was a bit easier to tell what was happening in the script. In GS1 the script for function onTimeout() would be displayed as if(timeout). It was a bit easier to tell that when a timeout was done, it set a flag that if(timeout) would check. function onTimeout does the same thing, however, for new users this may be harder to tell. here's an example of an NPC that uses a timeout loop:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  player.chat=&amp;quot;Counter: &amp;quot; @this.time;&lt;br /&gt;
  this.time++;&lt;br /&gt;
  settimer(1); &lt;br /&gt;
//after 1 second, the timeout loop will restart&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This would cause the player to count up every second.&lt;br /&gt;
You may have noticed that the variables often start of with client. or this. There are actually a few prefixes, each does a different thing:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
client. variable is saved to the client, it can be modified on the clientside or serverside, and read from either.&lt;br /&gt;
clientr. variables can be rad from server or clientside, but only written from serverside. This is more secure, but only if you use it right.&lt;br /&gt;
server. variables are saved to the server, can only be written on the serverside, read on either side&lt;br /&gt;
serverr. more secure version of server. read only on clientside&lt;br /&gt;
this. is a variable that only functions in the NPC it is in. This prevents NPCs from morifying each others variables&lt;br /&gt;
temp. only exists in between the brackets of a function&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To use scripts effectivly, you should know how to use each of these.&lt;br /&gt;
I will add more over time.&lt;br /&gt;
&lt;br /&gt;
Some important commands can be found here:&lt;br /&gt;
page:http://wiki.graal.net/index.php/Creation/Dev/Script/Starting_Guide#Introduction&lt;br /&gt;
Which is also helpful for learning how to script. Enjoy!&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Vectors&amp;diff=8940</id>
		<title>Vectors</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Vectors&amp;diff=8940"/>
		<updated>2007-07-01T07:56:00Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Vectors''' are mathematical representations of any thing that has a length, or magnitude, and direction. Positions are also described using vectors which start at the origin of the coordinate system (0,0,0).&lt;br /&gt;
&lt;br /&gt;
== Definition ==&lt;br /&gt;
In GraalScript, a vector is limited to three dimensions, however, mathematics allows for analyses of vectors in n-dimensions. Vectors do not have positions. Two vectors are said to be parallel if they have the same direction (u || v), and are said to be equal if they are parallel and have the same magnitude (u = v). Vectors are generally described by their terminal points with respect to the origin (0,0,0).&lt;br /&gt;
&lt;br /&gt;
The basic format of a vector in GraalScript is {x,y,z} where x, y, and z are all floating points in reference to the axis to which they correspond. Built into GraalScript are several functions which can be used to analyze these vectors.&lt;br /&gt;
&lt;br /&gt;
In mathematics, vectors are often written&lt;br /&gt;
 v = &amp;amp;lt;v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,v&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;&amp;amp;gt;&lt;br /&gt;
for a vector in three dimensions. They can also be written as the sum of unit vectors, &amp;lt;b&amp;gt;i&amp;lt;/b&amp;gt; = &amp;amp;lt;1,0,0&amp;amp;gt;, &amp;lt;b&amp;gt;j&amp;lt;/b&amp;gt; = &amp;amp;lt;0,1,0&amp;amp;gt;, and &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; = &amp;amp;lt;0,0,1&amp;amp;gt; on the x, y, and z axes, respectively. In this case, the vector would be written as&lt;br /&gt;
 v = v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;&amp;lt;b&amp;gt;i&amp;lt;/b&amp;gt; + v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;&amp;lt;b&amp;gt;j&amp;lt;/b&amp;gt; + v&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;&amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
where the values of v are treated as scalars (numerical multipliers) of the unit vectors.&lt;br /&gt;
&lt;br /&gt;
To denote the difference between a scalar and a vector, vectors are often written with a directional arrow above them, which looks like the top half of an arrow pointing right. In GraalScript, a scalar and a vector are impossible to confuse: a scalar is a floating point whereas a vector is a string.&lt;br /&gt;
&lt;br /&gt;
=== Vector Length (Magnitude) ===&lt;br /&gt;
Being as vectors are merely written by terminal point coordinates, there is no immediate way to determine the magnitude of the vector. Mathematically, the terminal point lies on a sphere that has the same radius as the vector's magnitude. Thus, we can use the equation of a sphere to calculate the magnitude.&amp;lt;br /&amp;gt;&lt;br /&gt;
 r&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; = x&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; + y&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; + z&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
 r = &amp;amp;radic;(x&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; + y&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; + z&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;)&lt;br /&gt;
where r is the magnitude. Generally, the magnitude is denoted as |v| or ||v||. This was chosen, because absolute value refers to distance from the origin, thus  the marks were suitable. In GraalScript, however, the magnitude of any vector can be calculated simply by plugging a vector string into the '''vectorlen({{graycourier|v}})''' function.&lt;br /&gt;
&lt;br /&gt;
=== Unit Length ===&lt;br /&gt;
A vector is said to have &amp;quot;unit length&amp;quot; when it's magnitude is one. '''i''', '''j''', and '''k''' are each unit vectors because their magnitudes are each one. To make a vector of unit length, the vector must merely be divided by it's magnitude.&lt;br /&gt;
Let v be a vector and u be the direction (unit vector) of v.&lt;br /&gt;
 v = &amp;lt;1,7,1&amp;gt;&lt;br /&gt;
 |v| = &amp;amp;radic;(1&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; + 7&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; + 1&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) = &amp;amp;radic;51&lt;br /&gt;
 u = v/|v| = &amp;lt;1/&amp;amp;radic;51,7/&amp;amp;radic;51,1/&amp;amp;radic;51&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Graalscript has a built-in function, '''vectornormalize({{graycourier|1=v}})''',to perform such a calculation.&lt;br /&gt;
&lt;br /&gt;
== Vector Modification ==&lt;br /&gt;
Along with vectorlen are a plethora of functions built into GraalScript all for the purpose of modifying vectors.&lt;br /&gt;
&lt;br /&gt;
=== Vector Addition ===&lt;br /&gt;
[[Image:Vectors-addition.png|thumb|right|Vector addition]]&lt;br /&gt;
Given the vectors u and v, we could create a third vector that has the magnitude of u and v, were the two vectors to be placed tip-to-end. This is called vector addition and can be done with the function '''vectoradd({{graycourier|u}},{{graycourier|v}})'''. This takes the terminal coordinates and adds them together. to make a new vector: &amp;lt;br /&amp;gt;&lt;br /&gt;
 w = &amp;amp;lt;u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;+v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;, u&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;+v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;, u&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;+v&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;&amp;amp;gt;. &lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vector-Scalar Multiplication ===&lt;br /&gt;
[[Image:Vectors-scalar-multiplication.png|thumb|left|Vector-scalar multiplication]]&lt;br /&gt;
With a vector, v, and a scalar, s, we could make a new vector that is s times larger than v. This can be accomplished in GraalScript with the function '''vectorscale({{graycourier|v}},{{graycourier|s}})'''. The vector is thus extended in the following manner: &amp;lt;br /&amp;gt;&lt;br /&gt;
 s&amp;amp;#183;v = s&amp;amp;#183;&amp;amp;lt;v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,v&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;&amp;amp;gt; = &amp;amp;lt;s&amp;amp;#183;v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,s&amp;amp;#183;v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,s&amp;amp;#183;v&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;&amp;amp;gt;.&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vector Subtraction ===&lt;br /&gt;
[[Image:Vectors-subtraction.png|thumb|right|Vector subtraction]]&lt;br /&gt;
With these two properties, we find that vector subtraction is possible, and no longer a new idea. This is done in GraalScript with the use of the '''vectorsub({{graycourier|u}},{{graycourier|v}})''' function. &amp;lt;br /&amp;gt;&lt;br /&gt;
 u-v = u + (-v) = u + (-1)&amp;amp;#183;v&lt;br /&gt;
You can imagine this as the two vectors placed tip-to-end, but the second is facing the opposite direction.&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Distance Between Terminal Points ===&lt;br /&gt;
Without creating a third vector, it is simple in GraalScript to find the distance between the two points at which two vectors end. This function is '''vectordist({{graycourier|u}},{{graycourier|v}})'''. &amp;lt;br /&amp;gt;&lt;br /&gt;
The return value would be&lt;br /&gt;
 &amp;amp;radic;((u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;-v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;)&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;+(u&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;-v&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;)&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;+(u&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;-v&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;)&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;)&lt;br /&gt;
The mathematical operation is the pythagorean theorem (or a combination of two). As may be evident, the distance is the magnitude of '''u'''-'''v'''.&lt;br /&gt;
&lt;br /&gt;
== Other functions ==&lt;br /&gt;
vectordot({{graycourier|u}},{{graycourier|v}}): see [[Dot Product]].&amp;lt;br /&amp;gt;&lt;br /&gt;
vectorcross({{graycourier|u}},{{graycourier|v}}): see [[Cross Product]].&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/GScript/Understanding_GUI_Profiles&amp;diff=8939</id>
		<title>Creation/Dev/GScript/Understanding GUI Profiles</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/GScript/Understanding_GUI_Profiles&amp;diff=8939"/>
		<updated>2007-07-01T07:55:37Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
GUI profiles are a set of characteristics that define how a GUI control looks. By default when you create a GUI control, it will be using the default profile for the control type; for example, &amp;quot;GuiButtonControl&amp;quot; by default uses &amp;quot;GuiButtonProfile&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This profile tells the program that this button needs to be red with a golden border and have orange text. It can define various things such as font face, size, colour, background colour, borders, images, etc.&lt;br /&gt;
&lt;br /&gt;
A GUI profile is created in a similar way to a GUI control itself.&lt;br /&gt;
&amp;lt;pre&amp;gt;new GuiControlProfile(&amp;quot;ProfileName&amp;quot;)&lt;br /&gt;
{&lt;br /&gt;
  attr = value;&lt;br /&gt;
  attr = value;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can then be applied to a control like so:&lt;br /&gt;
&amp;lt;pre&amp;gt;new GuiControl(&amp;quot;ControlName&amp;quot;)&lt;br /&gt;
{&lt;br /&gt;
  profile = &amp;quot;ProfileName&amp;quot;;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The control will then be formatted as is directed by the GUI profile.&lt;br /&gt;
&lt;br /&gt;
An example profile looks like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;new GuiControlProfile(&amp;quot;MyProfile&amp;quot;)&lt;br /&gt;
{&lt;br /&gt;
  fillColor = {255, 0, 0};&lt;br /&gt;
  fontColor = {255, 255, 255};&lt;br /&gt;
&lt;br /&gt;
  bitmap = &amp;quot;myEvilImage.png&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  opaque = false;&lt;br /&gt;
  transparency = 0.5;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can copy existing profiles to create a new one. Instead of creating a &amp;quot;GuiControlProfile&amp;quot; just use the name of the existing profile which you want to copy:&lt;br /&gt;
&amp;lt;pre&amp;gt;new GuiButtonProfile(&amp;quot;MyButtonProfile&amp;quot;) {&lt;br /&gt;
  fontsize = 20;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Available Attributes ==&lt;br /&gt;
&lt;br /&gt;
See [[Creation/Dev/Script/Client/GuiControlProfile|GuiControlProfile]].&lt;br /&gt;
&lt;br /&gt;
== Editing control-specific profile information ==&lt;br /&gt;
You can also edit the profile attributes of a single control. This is using the &amp;quot;profile&amp;quot; object of each GUI control.&lt;br /&gt;
&lt;br /&gt;
The profile object contains members exactly the same as a normal GUI profile (i.e. &amp;quot;transparency&amp;quot; =&amp;gt; &amp;quot;controlname.profile.transparency&amp;quot;. This provides a way to edit the profile.&lt;br /&gt;
&lt;br /&gt;
However! You must be careful. A variable, &amp;quot;useOwnProfile&amp;quot;, plays an important role here. useOwnProfile tells the control not to share any changes made to the profile.&lt;br /&gt;
&lt;br /&gt;
For example, if you did the following:&lt;br /&gt;
&amp;lt;pre&amp;gt;profile = &amp;quot;MyProfile&amp;quot;;&lt;br /&gt;
profile.transparency = 1;&amp;lt;/pre&amp;gt;&lt;br /&gt;
... then every control using the profile &amp;quot;MyProfile&amp;quot; would set transparency to 1.&lt;br /&gt;
&lt;br /&gt;
useOwnProfile stops this happening:&lt;br /&gt;
&amp;lt;pre&amp;gt;profile = &amp;quot;MyProfile&amp;quot;;&lt;br /&gt;
useOwnProfile = true;&lt;br /&gt;
profile.transparency = 1;&amp;lt;/pre&amp;gt;&lt;br /&gt;
... causes only the current control to have transparency set to 1.&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Local_Database_NPC_Communication&amp;diff=8937</id>
		<title>Creation/Dev/Local Database NPC Communication</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Local_Database_NPC_Communication&amp;diff=8937"/>
		<updated>2007-07-01T07:54:01Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8867 by Special:Contributions/Anti-up (User talk:Anti-up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
What exactly is the purpose of database communication? You might have seen the telephone scripts on Era, where anyone can talk to anyone else on another phone on the server. The method that these phones use to transfer messages is database communication. Database communication is really useful for passing data between database instances of NPCs on a server, while at the same time, giving them a friendlier ID. But first, you must understand a couple of things about database NPCs.&lt;br /&gt;
&lt;br /&gt;
Note: This article '''expects''' a certain degree of knowledge of new engine scripting, using classes and database NPCs, etc.&lt;br /&gt;
&lt;br /&gt;
=== What are Database NPCs? ===&lt;br /&gt;
There are two major types of DB NPC: these are DB NPCs created using [[NC]], and putnpc2()-style NPCs created using scripting, and having your script joined to them using join(). In this tutorial, we will be using both putnpc2()-style NPCs, and DB NPCs. We'll be giving each putnpc2()-style NPC we create a nice friendly identifier.&lt;br /&gt;
&lt;br /&gt;
=== Important concepts ===&lt;br /&gt;
DB NPCs each have a unique identifier.&lt;br /&gt;
&lt;br /&gt;
[[Image:rc_classlist_normal.png]] NPCs created using putnpc2() each have a unique identifier, which is dynamically generated when the NPC is created. An example of one of these IDs is &amp;quot;localnpc_era_present_32673165_8&amp;quot;. Don't worry about remembering these - we will write methods to save these identifiers automatically.&lt;br /&gt;
&lt;br /&gt;
[[Image:rc_localnpcs_normal.png]] NPCs created using NC have a specified identifier that you assign. Again, these must be unique. An example of one of these might be &amp;quot;DB_Phones&amp;quot;, or &amp;quot;SkyldTest&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In either a database NPC or a putnpc2() NPC, the ID can be found with the '''this.name''' variable.&lt;br /&gt;
&lt;br /&gt;
= Objective =&lt;br /&gt;
The objective for this tutorial is to create a system where NPCs created using putnpc2() can communicate with each other. So, let's start by designing the system.&lt;br /&gt;
&lt;br /&gt;
You will want:&lt;br /&gt;
* One Database NPC with a sensible and easy name. For example, if you are creating a system for phones, a suitable name may be &amp;quot;DB_Phones&amp;quot;. Try to avoid using &amp;quot;-&amp;quot; in names, since this makes it harder to link to them.&lt;br /&gt;
* One script class with your scripting in. In the example of creating phones, you will want to have your phone scripting in here.&lt;br /&gt;
* A weapon to place putnpc2() instances of your script class with.&lt;br /&gt;
&lt;br /&gt;
=== Database NPC ===&lt;br /&gt;
The Database NPC will be one of the core parts of your system. As we've said already, each putnpc2() we have will be assigned a friendly ID, like a phone number. The Database NPC is where these identifiers will be stored, where any NPC can access them. In this case, it's important that our putnpc2() NPCs can read them!&lt;br /&gt;
&lt;br /&gt;
Create a Database NPC. For this example, we'll use &amp;quot;DB_Identifiers&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Script classes ===&lt;br /&gt;
The majority of your scripting will be in these script classes. However, there are a few fundamental things that must be inside this class before you can begin.&lt;br /&gt;
&lt;br /&gt;
==== Saving the ID of the class ====&lt;br /&gt;
When the NPC is placed, it must save it's ID into the database so that we can later access it. In this case, we will generate a random four digit number which will identify the NPC, and then save it to DB_Identifiers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  while (this.number == NULL)&lt;br /&gt;
  {&lt;br /&gt;
    temp.try = int(random(1000, 9999);&lt;br /&gt;
&lt;br /&gt;
    if (DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.try) == NULL)&lt;br /&gt;
    { // Okay, the number is free, let's save it&lt;br /&gt;
      DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.try) = this.name;&lt;br /&gt;
     &lt;br /&gt;
      // Now save the number locally so we know it&lt;br /&gt;
      this.number = temp.try;&lt;br /&gt;
      &lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating a method to find the NPCs by their new ID ====&lt;br /&gt;
&lt;br /&gt;
So far, the NPC will assign itself a four digit number and save that number into the database. But there are still a few complications. You need a way to find the ID of a class by just it's four digit number. So, we write a function to retrieve a number if it's available. We'll call it findClass().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function findClass(temp.number)&lt;br /&gt;
{&lt;br /&gt;
  // Perform a little sanity check on the number&lt;br /&gt;
  if (!(temp.number &amp;gt;= 1000 &amp;amp;&amp;amp; temp.number &amp;lt;= 9999))&lt;br /&gt;
  {&lt;br /&gt;
    return -1; // Invalid number, so stop!&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Make sure the number is an integer&lt;br /&gt;
  temp.number = int(temp.number);&lt;br /&gt;
  &lt;br /&gt;
  // Check if the database has the number saved&lt;br /&gt;
  if (DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.number) != NULL)&lt;br /&gt;
  { // Database has got this identifier, let's return the object ID&lt;br /&gt;
    return DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.number);&lt;br /&gt;
  }&lt;br /&gt;
    else&lt;br /&gt;
  { // Database hasn't got the ID, no such NPC?&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, from inside your class, you can see if there is a class on the server with your ID just by using findClass(). &lt;br /&gt;
&lt;br /&gt;
To better explain, say you created two NPCs. The first NPC named itself with the number 3209. The second NPC named itself with 5563. If you wanted to find the object for the first NPC, you would use:&lt;br /&gt;
&amp;lt;pre&amp;gt;with (findClass(3209))&lt;br /&gt;
{ &lt;br /&gt;
  // code&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
... And likewise for the second NPC:&lt;br /&gt;
&amp;lt;pre&amp;gt;with (findClass(5563))&lt;br /&gt;
{ &lt;br /&gt;
  // code&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is exactly how we will make the NPCs communicate.&lt;br /&gt;
&lt;br /&gt;
==== Creating a function to be run remotely ====&lt;br /&gt;
Now, to give the NPC an entry point from other NPCs, we'll create a public function. Public functions can be run by any NPC on the same side (serverside or clientside).&lt;br /&gt;
&lt;br /&gt;
So, let's define a public function called entryPoint(). This is where instances of your class will send data to other instances. This is also where the commands will be interpreted to do something useful.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public function entryPoint(temp.data)&lt;br /&gt;
{&lt;br /&gt;
  // Code&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, the creation of this function means that you can do this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;findClass(5563).entryPoint(&amp;quot;I am sending this data!&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, does this help you? Well, this has given you a foundation to allow your classes to communicate. Hold on, though. There are still some complications.&lt;br /&gt;
&lt;br /&gt;
==== Destroying class instances correctly ====&lt;br /&gt;
If you just this.destroy() an instance of your class without first removing the identifier, the identifier will stay there until someone removes it. So, let's make sure that your routine clears out the identifier properly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function destroyInstance()&lt;br /&gt;
{&lt;br /&gt;
  DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.number) = NULL;&lt;br /&gt;
  this.destroy();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now you can use destroyInstance() to correctly remove your NPC '''and''' it's identifier.&lt;br /&gt;
&lt;br /&gt;
==== An example use of what you've created ====&lt;br /&gt;
Here's an example of something you might want to put in your class to test if it works.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  while (this.number == NULL)&lt;br /&gt;
  {&lt;br /&gt;
    temp.try = int(random(1000, 9999);&lt;br /&gt;
&lt;br /&gt;
    if (DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.try) == NULL)&lt;br /&gt;
    { // Okay, the number is free, let's save it&lt;br /&gt;
      DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.try) = this.name;&lt;br /&gt;
     &lt;br /&gt;
      // Now save the number locally so we know it&lt;br /&gt;
      this.number = temp.try;&lt;br /&gt;
      &lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function findClass(temp.number)&lt;br /&gt;
{&lt;br /&gt;
  // Perform a little sanity check on the number&lt;br /&gt;
  if (!(temp.number &amp;gt;= 1000 &amp;amp;&amp;amp; temp.number &amp;lt;= 9999))&lt;br /&gt;
  {&lt;br /&gt;
    return -1; // Invalid number, so stop!&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Make sure the number is an integer&lt;br /&gt;
  temp.number = int(temp.number);&lt;br /&gt;
  &lt;br /&gt;
  // Check if the database has the number saved&lt;br /&gt;
  if (DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.number) != NULL)&lt;br /&gt;
  { // Database has got this identifier, let's return the object ID&lt;br /&gt;
    return DB_Identifiers.(&amp;quot;class_&amp;quot; @ temp.number);&lt;br /&gt;
  }&lt;br /&gt;
    else&lt;br /&gt;
  { // Database hasn't got the ID, no such NPC?&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public function entryPoint(temp.data)&lt;br /&gt;
{&lt;br /&gt;
  if (temp.data == &amp;quot;explode&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    putexplosion(2, this.x, this.y);&lt;br /&gt;
    return 1; // Let's let the other NPC know that the command was received&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function onPlayerChats()&lt;br /&gt;
{&lt;br /&gt;
  temp.tok = player.chat.tokenize();&lt;br /&gt;
&lt;br /&gt;
  if (temp.tok[0] == &amp;quot;explode&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    if (findClass(temp.tok[1]).entryPoint(&amp;quot;explode&amp;quot;) == 1)&lt;br /&gt;
    {&lt;br /&gt;
      player.say2(&amp;quot;You successfully exploded the NPC!&amp;quot;);&lt;br /&gt;
    } &lt;br /&gt;
      else&lt;br /&gt;
    {&lt;br /&gt;
      player.say2(&amp;quot;Maybe the NPC doesn't exist?&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You could then say &amp;quot;explode 5563&amp;quot; from any other NPC of your instance, and cause it to explode!&lt;br /&gt;
&lt;br /&gt;
=== Weapon to place your instances ===&lt;br /&gt;
Let's actually create a method to place your NPCs now. For this, you'll need a weapon. The name of the weapon isn't really important. The code for this is simple.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function onActionserverside()&lt;br /&gt;
{&lt;br /&gt;
  if (params[0] == &amp;quot;place&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    putnpc2(player.x, player.y, &amp;quot;join yourclassname;&amp;quot;); &lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
&lt;br /&gt;
function onPlayerChats()&lt;br /&gt;
{&lt;br /&gt;
  if (player.chat == &amp;quot;drop&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    triggeraction(0, 0, &amp;quot;serverside&amp;quot;, &amp;quot;yourweaponname&amp;quot;, &amp;quot;place&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Conclusion =&lt;br /&gt;
So, you've got your framework. You could easily now create your system on a framework of these functions by giving each of your NPCs a friendly name. The reason we used four digit numbers here is because they are easy to work with. You might decide to make it 7 digit numbers to resemble phone numbers, or even email addresses!&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/GScript/Constants&amp;diff=8936</id>
		<title>Creation/Dev/GScript/Constants</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/GScript/Constants&amp;diff=8936"/>
		<updated>2007-07-01T07:53:52Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8675 by Special:Contributions/Anti-Up (User talk:Anti-Up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As one might be able to deduce, a '''constant''' has a single value and will retain that value as long as that constant exists. A constant is ''not'' a variable for one very important reason: it's value is not variable!&lt;br /&gt;
&lt;br /&gt;
 const intVar = 3;&lt;br /&gt;
 intVar = 4; // will not work&lt;br /&gt;
 player.chat = intVar; // displays 3&lt;br /&gt;
&lt;br /&gt;
The value of the constant cannot change even in conjunction with the use of the &amp;quot;=&amp;quot; operator. This is the power of a constant. However, player.variables cannot be defined as a constant (client(r).variables, too, possibly).&lt;br /&gt;
&lt;br /&gt;
A constant may be used most likely to keep a variable that is available to any script from changing its value due to any foreign script interfering. It can also be used to give some cryptic value an easy to understand name, and by putting the const definition at the beginning of the script it can easily be configured.&lt;br /&gt;
&lt;br /&gt;
A constant is only accessible in the script where you have defined it, they&lt;br /&gt;
are not shared between the server-side and client-side parts either.&lt;br /&gt;
&lt;br /&gt;
A special type of constants are enumerators:&lt;br /&gt;
&lt;br /&gt;
 enum {&lt;br /&gt;
   enum0,&lt;br /&gt;
   enum1,&lt;br /&gt;
   enum2&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
When you put names in an enumerator list, then it is automatically generating constants by enumarating the names - enum0 will be zero, enum1 will be 1, enum2 will be 2.&lt;br /&gt;
&lt;br /&gt;
 enum modes {&lt;br /&gt;
   IDLE,&lt;br /&gt;
   WALK&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
By giving a name to the enumerator list you can group enumerations - you can access the constants by modes.IDLE and modes.WALK. &lt;br /&gt;
&lt;br /&gt;
 enum {&lt;br /&gt;
   enum10 = 10,&lt;br /&gt;
   enum11,&lt;br /&gt;
   enumstr = &amp;quot;string&amp;quot;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
You can assign values to the constants like you do for normal constants. It will automatically enumerate the following entries by adding one to the last value, so enum11 will be 11. You can also assign a sring value.&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Using_Classes_Effectively&amp;diff=8935</id>
		<title>Creation/Dev/Using Classes Effectively</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Using_Classes_Effectively&amp;diff=8935"/>
		<updated>2007-07-01T07:53:48Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8674 by Special:Contributions/Anti-Up (User talk:Anti-Up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Note: Code examples in this article use new engine scripting.&lt;br /&gt;
= Why classes? =&lt;br /&gt;
Classes are a very useful concept in Gscript. They allow many instances of the same code to be run and even dynamically placed. They are also an effective means of sharing functions between scripts. You can attach them to the player, too, where the player is treated as the current object.&lt;br /&gt;
&lt;br /&gt;
= Using classes as standalone NPCs =&lt;br /&gt;
Objects, including NPCs from levels or database NPCs, can join a class. That class is then controlling the behaviour of the object. The class can so act either as level NPC, when being joined from a level NPC, or as database NPC, when joined from a database NPC. Many objects can join the same class, which is useful e.g. for ATMs.&lt;br /&gt;
&lt;br /&gt;
=== Joining from a level ===&lt;br /&gt;
To let a level NPC join a class, simply create an NPC and put:&lt;br /&gt;
&amp;lt;pre&amp;gt;this.join(&amp;quot;classname&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
The NPC will then join the class once created. When updating a class with RC that is joined by level NPCs, you may have to update the level in order to see the update.&lt;br /&gt;
=== Joining using putnpc2 ===&lt;br /&gt;
To create a databased NPC, you can use the function putnpc2() on serverside:&lt;br /&gt;
&amp;lt;pre&amp;gt;putnpc2(x, y, &amp;quot;join(\&amp;quot;classname\&amp;quot;);&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
... replacing x and y with coordinate values, or variable names containing these values. A putnpc2() NPC is called a &amp;quot;database NPC&amp;quot;, being that it is databased in the NPC-Server, and does not belong to a specific level. Database NPCs usually receive updates when the script is updated with RC immediately. They can also warp to other levels.&lt;br /&gt;
=== About database NPCs (including putnpc2 NPCs) ===&lt;br /&gt;
When you are finished with a DB NPC and want to destroy it, you should use this.destroy(); serverside. The NPC will then be totally removed from memory. Note that the class will of course still remain on the server.&lt;br /&gt;
&lt;br /&gt;
DB NPCs have unique identifiers, which can be read using this.name. This identifier can be used to locate the NPC on the serverside, like shown:&lt;br /&gt;
&amp;lt;pre&amp;gt;with (findnpc(identifier))&lt;br /&gt;
{&lt;br /&gt;
  // foo&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;findnpc(identifier).foo();&amp;lt;/pre&amp;gt;&lt;br /&gt;
This allows other scripts to interact with the database NPCs that you have placed. With the new scripting engine you can also access those npcs directly by using identifier.foo.&lt;br /&gt;
&lt;br /&gt;
Like mentioned previously, database NPCs are not specific to one level, and such you can use the warpto() command to move the NPC into a new level:&lt;br /&gt;
&amp;lt;pre&amp;gt;this.warpto(&amp;quot;levelname&amp;quot;, x, y);&amp;lt;/pre&amp;gt;&lt;br /&gt;
This enables great portability.&lt;br /&gt;
&lt;br /&gt;
= Using classes to share functions =&lt;br /&gt;
If you write a set of functions that you wish to use in more than one NPC, then you can define them in a class, and let each npc join the class instead of copying the functions into each. It also means that you can update your functions across all your scripts, too.&lt;br /&gt;
=== Define your functions ===&lt;br /&gt;
Open up your class, and define your functions like you normally would!&lt;br /&gt;
&amp;lt;pre&amp;gt;function funcName(parameters)&lt;br /&gt;
{&lt;br /&gt;
  // code&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then save your class. This will provide these functions to any NPC that joins the class, and will allow you to easily update functions between several NPCs.&lt;br /&gt;
=== Using your functions ===&lt;br /&gt;
Now, before you can use the functions in your other scripts, you must let the current NPC join the class. Like a level NPC, you use the following command:&lt;br /&gt;
&amp;lt;pre&amp;gt;this.join(&amp;quot;classname&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then, you can use your functions.&lt;br /&gt;
&lt;br /&gt;
You can easily let an NPC join more than one class, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;this.join(&amp;quot;classone&amp;quot;);&lt;br /&gt;
this.join(&amp;quot;classtwo&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
However, this can cause problems where there is more than one function with the same name. You can specify which class you want to use the function from by using the :: operator. The :: tells the scripting engine to look in that specific class, like so:&lt;br /&gt;
&amp;lt;pre&amp;gt;classtwo::myFunction();&amp;lt;/pre&amp;gt;&lt;br /&gt;
This means that you do not have to worry about using the same function name more than once. If function names are colliding, then the first function found will be used, which means either from the script of the npc itself or of the class joined first.&lt;br /&gt;
&lt;br /&gt;
= Using &amp;quot;player classes&amp;quot; =&lt;br /&gt;
Player classes are classes joined by players. A player-joined class treats the player as the current object (this.). Also, you can create functions available to other scripts through the player object, for example, creating a function that damages the player called doDamage() and then calling it from any script using:&lt;br /&gt;
&amp;lt;pre&amp;gt;player.doDamage();&amp;lt;/pre&amp;gt;&lt;br /&gt;
This allows the player to be treated easier using different functions.&lt;br /&gt;
&lt;br /&gt;
=== Join the class ===&lt;br /&gt;
You can let the player join the class on serverside like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;player.join(&amp;quot;classname&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
You could do this in your Control-NPC to, say, join the classes whenever the player logs onto the game server.&lt;br /&gt;
&lt;br /&gt;
Player classes are no different to ordinary classes - you should edit them in RC the same way as you do with normal classes.&lt;br /&gt;
&lt;br /&gt;
=== Define your functions ===&lt;br /&gt;
For functions to be useable by other NPCs, they must be public:&lt;br /&gt;
&amp;lt;pre&amp;gt;public function funcName(parameters)&lt;br /&gt;
{&lt;br /&gt;
  // code&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
This means that other NPCs can run the function, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;player.funcName(1, &amp;quot;Hello!&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
Non-public functions will not be useable from outside the current script, so you can define normal functions to create a function that you don't want to be called externally, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;function funcName()&lt;br /&gt;
{&lt;br /&gt;
  // code&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using your functions ===&lt;br /&gt;
If your functions are public, then other scripts can easily call the functions that you have defined in your class, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;player.funcName();&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== this. object ===&lt;br /&gt;
Player classes work in a different focus, where the current object (that's the '''this.''' object) becomes the player. So, if you wanted to change the player's chat text in a player joined class, you would use the following:&lt;br /&gt;
&amp;lt;pre&amp;gt;this.chat = &amp;quot;Chat text!&amp;quot;;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Calling functions using this. will also call functions from player joined classes, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;player.join(&amp;quot;classname&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;this.playerFunction();&lt;br /&gt;
this.anotherFunction();&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Output_Methods&amp;diff=8934</id>
		<title>Creation/Dev/Output Methods</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Output_Methods&amp;diff=8934"/>
		<updated>2007-07-01T07:51:19Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
With the addition of the [[GScript|new scripting engine]], there are a number of new methods in which you can create output from an NPC. In this article, I will discuss a couple of ways.&lt;br /&gt;
&lt;br /&gt;
== Useful Things To Know ==&lt;br /&gt;
If you've played with the new engine for a while, you're probably aware of the string concationation operators. If not, here they are.&lt;br /&gt;
&amp;lt;pre&amp;gt;String Concatenation     a @ b&lt;br /&gt;
    with space            a SPC b&lt;br /&gt;
    with newline          a NL b&lt;br /&gt;
    with tabulator        a TAB b&amp;lt;/pre&amp;gt;&lt;br /&gt;
What these operators do is join values together to form one value.&lt;br /&gt;
&lt;br /&gt;
An example of using @ would be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Hello, &amp;quot; @ player.account&amp;lt;/pre&amp;gt;&lt;br /&gt;
... which would produce &amp;quot;Hello, accountnamehere&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The SPC, NL and TAB operators work using the same principal - except that they insert a Space, New Line or Tab Space respectively.&lt;br /&gt;
&lt;br /&gt;
If you don't put a space at the end of the first value or at the beginning of the second value when using @, you don't get a visible space, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Hello&amp;quot; @ &amp;quot;World&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
... will produce &amp;quot;HelloWorld&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
However! If you use SPC, you'll get a space in place of the operator:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Hello&amp;quot; SPC &amp;quot;World&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
... producing &amp;quot;Hello World&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You can use these operators just about anywhere that a variable is requested, i.e. setting a variable, or sending to a function.&lt;br /&gt;
&lt;br /&gt;
== format() function ==&lt;br /&gt;
Or, if you aren't so interested in using the concationation operators, you can use the ''format()'' function.&lt;br /&gt;
&lt;br /&gt;
What this function does, is that it takes a sort of template from the first parameter you give it, and replaces % codes with other parameters you give it.&lt;br /&gt;
&lt;br /&gt;
Now, the template format primarily uses the following % characters:&lt;br /&gt;
&amp;lt;pre&amp;gt;%d %i - Integer&lt;br /&gt;
%f - Float (number with decimal)&lt;br /&gt;
%s - String&lt;br /&gt;
%c - Single character&lt;br /&gt;
%% - Literal &amp;quot;%&amp;quot; character&lt;br /&gt;
%x %X - Print an integer as a hexadecimal&amp;lt;/pre&amp;gt;&lt;br /&gt;
There are more, since the function is made to be compatible with C's ''printf()'' function.&lt;br /&gt;
&lt;br /&gt;
In the template, every % code will be replaced with the respective parameter.&lt;br /&gt;
&lt;br /&gt;
Say you want to produce &amp;quot;Hello, '''Mr. Skyld'''. You ate '''4''' apples today!&amp;quot; using format(). First, your format would be this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;quot;Hello, %s. You ate %i apples today!&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
... and you must not forget to give the parameters containing the values:&lt;br /&gt;
&amp;lt;pre&amp;gt;format(&amp;quot;Hello, %s. You ate %i apples today!&amp;quot;, &amp;quot;Mr. Skyld&amp;quot;, 4);&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can give the format() functions as many parameters as necessary to build up your value. If you use a % code and a value isn't present for it, a 0 (zero) will appear in it's place.&lt;br /&gt;
&lt;br /&gt;
You can also use ''format2()'', which acts just like format() with the exception that instead of passing variables as separate parameters, they are sent as an array to the 2nd parameter.&lt;br /&gt;
The example above would become&lt;br /&gt;
&amp;lt;pre&amp;gt;format2(&amp;quot;Hello, %s. You ate %i apples today!&amp;quot;, {&amp;quot;Mr. Skyld&amp;quot;, 4});&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Along with format2() came the indexing of the parameters. This method will work with both format() and format2() functions. It allows us to choose which parameter to place in which position in the format string. The problem of parameters being placed in the wrong order will not exist if each parameter has a different data type, however.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;format2(&amp;quot;Hello, %2$s. You ate %1$s apples today!&amp;quot;, {&amp;quot;four&amp;quot;,&amp;quot;Mr. Skyld&amp;quot;});&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the example, both parameters are strings, so it would be necessary to give them an index when trying to insert them in a different order than they were passed. ''%1$s'' refers to the 1&amp;lt;sup&amp;gt;st&amp;lt;/sup&amp;gt; object in the array inserted as a string. ''%n$T'' is general; the n&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; parameter inserted with datatype of ''T''.&lt;br /&gt;
&lt;br /&gt;
Now, let's continue on various ways of outputting data.&lt;br /&gt;
&lt;br /&gt;
== Outputs ==&lt;br /&gt;
=== Direct Output ===&lt;br /&gt;
Direct Output is sending an output directly to the game client, or to RC/NC. There are a number of functions for these tasks.&lt;br /&gt;
&lt;br /&gt;
==== echo() ====&lt;br /&gt;
The echo() function will, on the serverside, send data to NC, so RC users who have the NPC-Control right will see the message in RC chat, and on the clientside, sends the message to the F2 window. It expects one parameter, and that's the message you're sending. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;echo(&amp;quot;This is a message!&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
The message &amp;quot;This is a message!&amp;quot; will appear either in RC or the F2 window using this example.&lt;br /&gt;
&lt;br /&gt;
==== sendtorc() ====&lt;br /&gt;
The sendtorc() function works in the same way that the echo() function does, however, it only usually works on the serverside. It will appear to all RC users. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;sendtorc(&amp;quot;This is a message!&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
... will send &amp;quot;NPC-Server (Server): This is a message!&amp;quot; to RC.&lt;br /&gt;
&lt;br /&gt;
'''Note''' that this function can only be used on the clientside when Client-RC is active.&lt;br /&gt;
&lt;br /&gt;
==== sendtonc() ====&lt;br /&gt;
The sendtonc() function works in exactly the same way as echo() does serverside.&lt;br /&gt;
&lt;br /&gt;
==== sendrpgmessage() ====&lt;br /&gt;
The sendrpgmessage() works much the same as echo() does clientside. It will result in a message appearing in the player's F2 log window. For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;sendrpgmessage(&amp;quot;This is a message!&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
... will send &amp;quot;This is a message!&amp;quot; to the player's F2 window.&lt;br /&gt;
&lt;br /&gt;
=== Working with Files ===&lt;br /&gt;
==== loadstring() ====&lt;br /&gt;
loadstring() is an object function which loads the contents of a given file.&lt;br /&gt;
&lt;br /&gt;
Say that the file &amp;quot;levels/file.txt&amp;quot; contains the message &amp;quot;HELLO WORLD&amp;quot;. If you want to load that value into a variable called &amp;quot;myVar&amp;quot;, you should use this function:&lt;br /&gt;
&amp;lt;pre&amp;gt;myVar.loadstring(&amp;quot;levels/file.txt&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can easily check the contents of the file:&lt;br /&gt;
&amp;lt;pre&amp;gt;echo(myVar);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== savestring() ====&lt;br /&gt;
savestring() is another object function, however, instead of loading the contents of a file, it writes the contents instead.&lt;br /&gt;
&lt;br /&gt;
Consider this with the previous example:&lt;br /&gt;
&amp;lt;pre&amp;gt;myVar = &amp;quot;HELLO PLANET&amp;quot;;&lt;br /&gt;
myVar.savestring(&amp;quot;levels/file.txt&amp;quot;, 0);&amp;lt;/pre&amp;gt;&lt;br /&gt;
... would write &amp;quot;HELLO PLANET&amp;quot; to &amp;quot;levels/file.txt&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The second operator, which is 0 (zero) in that example, is the '''Append''' function, and decides whether the file should be overwritten with the new value, or whether the new value should be added onto the end of the file. If you specify '''1''', then the value will be appended, if not, it will overwrite the file.&lt;br /&gt;
&lt;br /&gt;
==== savevars() ====&lt;br /&gt;
savevars() is an object function which saves the variables of an object into a file. Consider this example:&lt;br /&gt;
&amp;lt;pre&amp;gt;myVar = new TStaticVar(); // Create a TStaticVar&lt;br /&gt;
myVar.variable = &amp;quot;Hello&amp;quot;;&lt;br /&gt;
myVar.secondvariable = &amp;quot;World&amp;quot;;&lt;br /&gt;
myVar.saveVars(&amp;quot;levels/test.txt&amp;quot;, 0);&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will save the variables inside the &amp;quot;myVar&amp;quot; object into &amp;quot;levels/test.txt&amp;quot;. You can then recall these variables using loadvars();&lt;br /&gt;
&lt;br /&gt;
Like savelines(), the second parameter controls whether the variables are to be appended to the file. '''0''' will overwrite the file, and '''1''' will append to the file.&lt;br /&gt;
&lt;br /&gt;
==== loadvars() ====&lt;br /&gt;
loadvars() is another object function which loads savevars()-style variables from a file into an object. Let's say you used the previous example from savevars(), then you could restore these values using the following:&lt;br /&gt;
&amp;lt;pre&amp;gt;myNewVar.loadvars(&amp;quot;levels/test.txt&amp;quot;);&lt;br /&gt;
echo(myNewVar.secondvariable);&amp;lt;/pre&amp;gt;&lt;br /&gt;
... which will output &amp;quot;World&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Private Messages (PMs) ===&lt;br /&gt;
From the serverside, you can send PMs to players. They appear from the NPC-Server.&lt;br /&gt;
&lt;br /&gt;
If you wanted to send a PM to the player &amp;quot;Skyld&amp;quot; (if the player is online), the you would use the following example:&lt;br /&gt;
&amp;lt;pre&amp;gt;findPlayer(&amp;quot;Skyld&amp;quot;).sendPM(&amp;quot;This is a PM&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
... and then the specified player, in this case Skyld, would receive the PM &amp;quot;This is a PM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you want to send a PM to the current player, you would simply use:&lt;br /&gt;
&amp;lt;pre&amp;gt;player.sendPM(&amp;quot;This is a PM&amp;quot;);&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Troubleshooting_Graal_v4_IRC&amp;diff=8933</id>
		<title>Creation/Dev/Troubleshooting Graal v4 IRC</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Troubleshooting_Graal_v4_IRC&amp;diff=8933"/>
		<updated>2007-07-01T07:50:14Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8679 by Special:Contributions/Anti-Up (User talk:Anti-Up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Written by [[Skyld]], 28/08/2005.&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
After a rising number of people are having problems using the IRC and events system in their scripting, I have decided to write this document to assist in troubleshooting problems.&lt;br /&gt;
&lt;br /&gt;
== No IRC server connection ==&lt;br /&gt;
If you are finding that commands like:&lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;login&amp;quot;, &amp;quot;EventsBot&amp;quot;);&lt;br /&gt;
sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {&amp;quot;IRCBot&amp;quot;, &amp;quot;!resetevents&amp;quot;});&amp;lt;/pre&amp;gt;&lt;br /&gt;
... in your events bots are not returning any responses, then your server might not be GScript2-enabled. You will need to use the old style scripting as described in [[Creation/Dev/Graal_v4_IRC#IRCBots_for_Old_Scripting|Bots using old scripting]].&lt;br /&gt;
&lt;br /&gt;
== IRC Bot appears to be online but does not receive data ==&lt;br /&gt;
If your IRC Bot is logging in and joining channels properly but not returning any information, the most simple problem is that you have made a spelling error. &lt;br /&gt;
&amp;lt;pre&amp;gt;function onRecieveText(texttype, textoptions, textlines)&amp;lt;/pre&amp;gt;&lt;br /&gt;
This won't work because onReceiveText is spelt wrong. Ensure that it is spelt correctly.&lt;br /&gt;
&amp;lt;pre&amp;gt;function onReceiveText(texttype, textoptions, textlines)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== EventsBot will not register ==&lt;br /&gt;
If you used the EventsBot start script from the [[Creation/Dev/Graal_v4_IRC|Graal 4 IRC]] Wiki page, then you may encounter a problem where the EventsBot will not login correctly.&lt;br /&gt;
This is simply fixed, by replacing this:&lt;br /&gt;
&amp;lt;pre&amp;gt;textlines[1] == &amp;quot;!eventsbotlogin&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
With this:&lt;br /&gt;
&amp;lt;pre&amp;gt;textlines[2] == &amp;quot;!eventsbotlogin&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Thanks to napo_p2p for discovering this this and [http://forums.graalonline.com/forums/showpost.php?p=1103844&amp;amp;postcount=20 posting the error].&lt;br /&gt;
&lt;br /&gt;
== EventsBot is registered, but no admin control is available in the serverlist ==&lt;br /&gt;
When you receive a '''PRIVMSG''' from '''IRCBot''' saying &amp;quot;!eventsbotlogin&amp;quot;, you must provide two important details about your setup.&lt;br /&gt;
* Send the account names of those who should have admin access: &amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {&amp;quot;IRCBot&amp;quot;, {&amp;quot;!eventadmins&amp;quot;, &amp;quot;AccountName&amp;quot;, &amp;quot;AccountName2&amp;quot;}});&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Send the discussion channel for your events: &amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {&amp;quot;IRCBot&amp;quot;, {&amp;quot;!eventchannel&amp;quot;, &amp;quot;#ChannelName&amp;quot;}});&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the EventsBot logs in, after sending the above data, the listed account names should have access to the Admin tab for events when they log onto the game server.&lt;br /&gt;
&lt;br /&gt;
== My IRC bot occasionally disappears and does not reappear until script update ==&lt;br /&gt;
This could be for a couple of reasons:&lt;br /&gt;
* The IRC server was reloaded and connections were reset&lt;br /&gt;
* The IRC server fails or a problem arises&lt;br /&gt;
* The gserver/npcserver has been restarted&lt;br /&gt;
To ensure that the IRC bot always restores it's connection, you should put your connect routine in a seperate function, and use something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;function onCreated() IRCConnect();&lt;br /&gt;
function onInitialized() IRCConnect();&lt;br /&gt;
function onServerListerConnect() IRCConnect();&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also, ensure that the IRC bot is correctly resetting it's connection by logging out in your connect routine:&lt;br /&gt;
&amp;lt;pre&amp;gt;// Logout first&lt;br /&gt;
sendtext(&amp;quot;irc&amp;quot;, &amp;quot;logout&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
// Then login and do stuff&lt;br /&gt;
sendtext(&amp;quot;irc&amp;quot;, &amp;quot;login&amp;quot;, &amp;quot;Nickname&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== My IRC bot does not accept name changes properly on script update ==&lt;br /&gt;
This occurs because you have tried to use a new name without freeing your previous one. Just logging in again with a new name will not work.&lt;br /&gt;
Instead, you have to log out and '''then''' log in using the new name.&lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;logout&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
sendtext(&amp;quot;irc&amp;quot;, &amp;quot;login&amp;quot;, &amp;quot;Nickname&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
In fact, it's probably a good idea to make your IRC bot log out and in again on every connection.&lt;br /&gt;
&lt;br /&gt;
== Randomly, my IRC bot reports everyone in the channel joining again ==&lt;br /&gt;
'''ADDCHANNELUSER''' is sent to IRC scripts every time a user joins a channel that you or your IRC bot is also in. This allows making of a user list for that channel, or simply monitoring who joins and leaves.&lt;br /&gt;
It has been known for this to occasionally occur, listing everyone in the channel at once. This could happen for a number of reasons:&lt;br /&gt;
* You have reset your connection to the IRC server, maybe by a script update, and the IRC server is telling you again who is in the channel&lt;br /&gt;
* The IRC server has been reloaded, and as a result, connections have been dropped&lt;br /&gt;
This is not a problem as such, but if this is a problem for you specifically, consider removing any messages that occur on this event, or if you are listing users, make sure your list does not show any user more than once.&lt;br /&gt;
&lt;br /&gt;
== My IRC bot is not setting it's name correctly ==&lt;br /&gt;
You may find that in an attempt to set your IRC bot's name, it may be named IRCBot_N instead. There is a simple reason for this.&lt;br /&gt;
IRC connections from the serverside demand the nickname to begin with the following:&lt;br /&gt;
* IRCBot_&lt;br /&gt;
* EventsBot_&lt;br /&gt;
* Graal_&lt;br /&gt;
Any other nicknames will not be accepted.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' This is not the case with IRC connections from the clientside.&lt;br /&gt;
&lt;br /&gt;
== Other problems ==&lt;br /&gt;
If you are having a problem that is not listed here, [[Skyld]] may be able to help you. Contact details are available on [[Skyld|Skyld's user page]], and may be able to help solve the problem. New problems will also be added here when found.&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Graal_IRC&amp;diff=8932</id>
		<title>Creation/Dev/Graal IRC</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Graal_IRC&amp;diff=8932"/>
		<updated>2007-07-01T07:49:46Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Written by [[User:Skyld|Skyld]], 26/07/2005. Edits made by [[User:Stefan|Stefan]] since. Hooray for [[User:Stefan|Stefan]]!&lt;br /&gt;
= IRC Information =&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Graal 4 comes with a built-in form of IRC to allow people to chat between servers in rooms. Like IRC. But not, if you get my point. Now, there are ways in which you can use this IRC system to your advantage. Perhaps you want to script some kind of client for your players to use, or perhaps you want to script some kind of bot. Either way, the communication is simple.&lt;br /&gt;
&lt;br /&gt;
=== Links===&lt;br /&gt;
* [http://forums.graalonline.com/forums/showthread.php?t=60809 Graal v4 IRC Problem Information Thread]&lt;br /&gt;
* [[Creation/Dev/Troubleshooting Graal v4 IRC|Troubleshooting Graal v4 IRC]]&lt;br /&gt;
&lt;br /&gt;
== Logging In ==&lt;br /&gt;
To use the IRC, you just need to have basic knowledge of sendtext() and onReceiveText(). The fundamentals are that you have three parameters for each outgoing and incoming message. If you have used onReceiveText() before, you are likely to know &lt;br /&gt;
it has a structure like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;function onReceiveText(texttype, textoptions, textlines)&amp;lt;/pre&amp;gt;&lt;br /&gt;
The texttype will always equal &amp;quot;irc&amp;quot; if it is an IRC command. This helps to filter out unwanted commands from, say, the scripted RC. The textoptions will always equal the command that you've sent, and the textlines will equal any parameters necessary for that command. &lt;br /&gt;
&lt;br /&gt;
An important thing to note is that the IRC server will not throw any errors at you if you make a mistake with a command, so you should ensure throughly that your requests are correct. &lt;br /&gt;
&lt;br /&gt;
You send requests like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;command&amp;quot;, &amp;quot;params&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like any other IRC server, you need to log in before you can use it. &lt;br /&gt;
This is quite simply done. From your NPC, use the following command: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;login&amp;quot;, &amp;quot;nickname&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The nickname behaviour is different on the serverside. If you are logging in from the serverside, your nickname MUST begin with Graal, EventsBot or IRCBot. If you do not provide a valid nickname, then a suitable name (like IRCBot_2) will be automatically assigned and your nickname ignored. &lt;br /&gt;
Now, with any luck, you will have been logged in successfully!&amp;lt;br&amp;gt;&lt;br /&gt;
'''NOTE2:''' There is also the command requesttext(texttype,textoption), but it is not used for irc communication since most irc commands require additional data.&lt;br /&gt;
&lt;br /&gt;
== Joining a Channel ==&lt;br /&gt;
Now, you could probably get away with not joining a channel if you felt it necessary, but that would make communicating with you hard. So, why not join a channel? Joining and leaving channels is much like, again, in normal IRC. You sendtext(&amp;quot;irc&amp;quot;, &amp;quot;join&amp;quot;, &amp;quot;#channame&amp;quot;) to join a channel, and you sendtext(&amp;quot;irc&amp;quot;, &amp;quot;part&amp;quot;, &amp;quot;#channame&amp;quot;) to leave one. &lt;br /&gt;
&lt;br /&gt;
You can be in multiple channels, however, if you are writing a bot, you should probably make sure that you are always replying to the correct channel. I suppose the same applies to if you are writing a client - make sure you are sending to the right channel! &lt;br /&gt;
&lt;br /&gt;
== Receiving Information ==&lt;br /&gt;
Information from the IRC server comes to you in the form of onReceiveText(),providing you have logged into the server first. So, you will want to make sure that your script is receiving the information, or you might as well talk to a nice stone. I am not sure that it will help you, however. &lt;br /&gt;
&lt;br /&gt;
Now, earlier in the document, I said about the onReceiveText structure. &lt;br /&gt;
Just for reference, it looks like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;function onReceiveText(texttype, textoptions, textlines)&amp;lt;/pre&amp;gt;&lt;br /&gt;
To ensure that you are only receiving information from the IRC server, you should put an if check to check that the texttype is always &amp;quot;irc&amp;quot;: &lt;br /&gt;
&amp;lt;pre&amp;gt;if (texttype == &amp;quot;irc&amp;quot;)&lt;br /&gt;
{&lt;br /&gt;
 // Let's do this if we get IRC data&lt;br /&gt;
} &lt;br /&gt;
  else&lt;br /&gt;
{&lt;br /&gt;
  echo(&amp;quot;I am receiving non-IRC data!&amp;quot;);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''NOTE:''' Commands like &amp;quot;privmsg&amp;quot; will be broadcasted to the whole channel, and will be sent back to you in the process. &amp;quot;join&amp;quot; and &amp;quot;part&amp;quot; are also sent to you to confirm that you have joined a channel, but can also be used for kicking.&lt;br /&gt;
&lt;br /&gt;
The textoptions will equal the command type, such as &amp;quot;join&amp;quot;, &amp;quot;part&amp;quot; or whatever. &lt;br /&gt;
&lt;br /&gt;
So, you will want next to check what kind of information is being sent to you: &lt;br /&gt;
&amp;lt;pre&amp;gt;if (textoptions == &amp;quot;join&amp;quot;) echo(&amp;quot;You joined the channel successfully!&amp;quot;);&lt;br /&gt;
if (textoptions == &amp;quot;part&amp;quot;) echo(&amp;quot;You left successfully&amp;quot;);&lt;br /&gt;
if (textoptions == &amp;quot;privmsg&amp;quot;) echo(&amp;quot;Message!&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;quot;privmsg&amp;quot; differs here - it contains messages from anyone, not just yourself. I'll explain about &amp;quot;privmsg&amp;quot; in a second. To know who is joining or leaving your channel you need to handle the &amp;quot;addchanneluser&amp;quot; and &amp;quot;deletechanneluser&amp;quot; types.&lt;br /&gt;
&lt;br /&gt;
You may also receive information of the &amp;quot;notice&amp;quot; or &amp;quot;topic&amp;quot; types. These aren't so important yet and will be explained later.&lt;br /&gt;
&lt;br /&gt;
== Working With Messages Specifically ==&lt;br /&gt;
The type you will most likely be interested in receiving is the &amp;quot;privmsg&amp;quot; command. This is the most complicated, as if it isn't used correctly, you'll end up no further forward then you were at the beginning of this section. &lt;br /&gt;
* When you send a &amp;quot;privmsg&amp;quot;, you send the destination and the message.&lt;br /&gt;
* When you receive a &amp;quot;privmsg&amp;quot;, you receive the source, destination and message.&lt;br /&gt;
&lt;br /&gt;
So, let's assume that you've joined the channel #test. If you want to send a message to #test, you would use the following command:&lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {&amp;quot;#test&amp;quot;, &amp;quot;THIS IS MY MESSAGE&amp;quot;});&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A sensible idea would be to create a function that makes that mildly less tedious, so let's use this for example: &lt;br /&gt;
&amp;lt;pre&amp;gt;function send(dest, msg)&lt;br /&gt;
{&lt;br /&gt;
  sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {dest, msg});&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, you can just use send(&amp;quot;#test&amp;quot;, &amp;quot;lolmsg&amp;quot;); to send a message to a channel or user. &lt;br /&gt;
&lt;br /&gt;
However! Like I said before with &amp;quot;privmsg&amp;quot;, what you get back will not be the same! &lt;br /&gt;
&lt;br /&gt;
Instead of receiving {&amp;quot;destination&amp;quot;,&amp;quot;message&amp;quot;}, you will get {&amp;quot;source&amp;quot;,&amp;quot;destination&amp;quot;,&amp;quot;message&amp;quot;}, where source is the nickname that you logged in with. This allows you to find out who sent a message in the case that you are writing a client script, or for using people's names as an identity, say, with a bot. &lt;br /&gt;
&lt;br /&gt;
So, what about parsing an incoming privmsg? &lt;br /&gt;
&amp;lt;pre&amp;gt;function onReceiveText(texttype, textoptions, textlines)&lt;br /&gt;
{&lt;br /&gt;
 if (texttype == &amp;quot;irc&amp;quot;)&lt;br /&gt;
 {&lt;br /&gt;
   if (textoptions == &amp;quot;privmsg&amp;quot;)&lt;br /&gt;
   {&lt;br /&gt;
     // Do some stuff here&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the function, you can read who sent the message with textlines[0], where it was directed to with textlines[1] (say, #test) and the actual message with textlines[2].&lt;br /&gt;
&lt;br /&gt;
== Logging Out ==&lt;br /&gt;
If you are writing a client, or a bot that might have a reason to log out of the IRC server, you send a &amp;quot;logout&amp;quot; command like this: &lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;logout&amp;quot;, &amp;quot;&amp;quot;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
'''NOTE:''' The third parameter is ignored in this case.&lt;br /&gt;
&lt;br /&gt;
== Other IRC Commands ==&lt;br /&gt;
There are a couple of other IRC commands, such as ''TOPIC'' and ''NOTICE''. &lt;br /&gt;
&lt;br /&gt;
=== topic (Channel Topic) ===&lt;br /&gt;
''TOPIC'' commands are used to set the topic of a channel. This might be useful for you if you are writing a client, and simply uses this format: &lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, &amp;quot;topic&amp;quot;, {&amp;quot;#channel&amp;quot;, &amp;quot;Topic goes here&amp;quot;});&amp;lt;/pre&amp;gt;&lt;br /&gt;
You should also receive any ''TOPIC'' commands in the same format.&lt;br /&gt;
&lt;br /&gt;
=== notice (Notices) ===&lt;br /&gt;
''NOTICE'' is similar to ''PRIVMSG'', but is considered less important, and while ''PRIVMSG'' to a single player is automatically converted into a regular [[PM]], ''NOTICE'' is not, and can so be used for sending information back to the user. The events bot is using ''NOTICE'' commands for event management.&lt;br /&gt;
&lt;br /&gt;
=== addchanneluser (Channel Join Notifications) ===&lt;br /&gt;
''ADDCHANNELUSER'' is received when a new user joins a channel. The received data contains the channel name, irc nick, [[Server|Graal server]] and account name of the new user.&lt;br /&gt;
&lt;br /&gt;
=== deletechanneluser (Channel Part Notifications) ===&lt;br /&gt;
''DELETECHANNELUSER'' is received when a user leaves a channel. Only the channel name and the irc nick of the leaving user are received.&lt;br /&gt;
&lt;br /&gt;
== Multiple bots on one machine ==&lt;br /&gt;
It is possible to have more than one irc bot per machine - on the client you need to use two different weapon scripts which both login to the irc, on serverside you must use two independent database npcs or weapon scripts which both login to the irc and possibly use different nicknames.&lt;br /&gt;
&lt;br /&gt;
= Extra Information =&lt;br /&gt;
== Events Bots ==&lt;br /&gt;
For making it possible that events from your [[server]] are displayed on the global events list of [[Graal4]], the server needs to have an '''EventsBot'''. That is an irc bot with a name starting with EventsBot. That [[NPC|npc]] or weapon npc automatically gets information about when events should be started. It needs to login to the irc and then wait for instructions using '''onReceiveText'''. If there is no EventsBot for the server, then events will not work for it. The EventsBot also needs to send some information to the IRCBot about who is [[Events Team|Events Admin]] on the server, and which channel should be used for talking about the events. That must be done as answer to a &amp;quot;!eventsbotlogin&amp;quot; message from the IRC Bot:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated() doConnect();&lt;br /&gt;
function onInitialized() doConnect();&lt;br /&gt;
function onServerListerConnect() doConnect();&lt;br /&gt;
&lt;br /&gt;
function doConnect()&lt;br /&gt;
{&lt;br /&gt;
  sendtext(&amp;quot;irc&amp;quot;, &amp;quot;login&amp;quot;, &amp;quot;EventsBot&amp;quot;);&lt;br /&gt;
  sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {&amp;quot;IRCBot&amp;quot;, &amp;quot;!resetevents&amp;quot;});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function onReceiveText(texttype,textoption,textlines)&lt;br /&gt;
{&lt;br /&gt;
  if (texttype == &amp;quot;irc&amp;quot; &amp;amp;&amp;amp; textoption == &amp;quot;privmsg&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
  textlines[0] == &amp;quot;IRCBot&amp;quot; &amp;amp;&amp;amp; textlines[2] == &amp;quot;!eventsbotlogin&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {&amp;quot;IRCBot&amp;quot;, {&amp;quot;!eventadmins&amp;quot;, &amp;quot;AccountName&amp;quot;, &amp;quot;AccountName2&amp;quot;}});&lt;br /&gt;
    sendtext(&amp;quot;irc&amp;quot;, &amp;quot;privmsg&amp;quot;, {&amp;quot;IRCBot&amp;quot;, {&amp;quot;!eventchannel&amp;quot;, &amp;quot;#ChannelName&amp;quot;}});&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The EventsBot will also need to start events on the server, and tell the IRCbot about the status of the events.&lt;br /&gt;
&lt;br /&gt;
== Quick Reference ==&lt;br /&gt;
Here are some quick reference notes.&lt;br /&gt;
&lt;br /&gt;
=== Outgoing data ===&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;sendtext(&amp;quot;irc&amp;quot;, command, parameters)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Format:&lt;br /&gt;
* '''command:''' ''parameters'' - description&lt;br /&gt;
Outgoing data:&lt;br /&gt;
* '''login:''' ''name'' - Connects to the IRC using name as the connection's nickname&lt;br /&gt;
* '''logout:''' ''&amp;quot;&amp;quot;'' - Disconnects from the IRC&lt;br /&gt;
* '''privmsg:''' ''{destination, message}'' - Sends a message to a channel or user&lt;br /&gt;
* '''notice:''' ''{destination, message}'' - Sends a &amp;quot;notice&amp;quot; message to a channel or user&lt;br /&gt;
* '''join:''' ''channelname'' - Join channelname&lt;br /&gt;
* '''part:''' ''channelname'' - Leave channelname&lt;br /&gt;
* '''topic:''' ''{channel, topic}'' - Set the topic for the channel&lt;br /&gt;
&lt;br /&gt;
=== Incoming data ===&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;function onReceiveText(texttype, textoptions, textlines)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Format:&lt;br /&gt;
* '''textoptions:''' ''textlines'' - description&lt;br /&gt;
Note:&lt;br /&gt;
''The texttype will always be &amp;quot;irc&amp;quot; when information is sent from the IRC server.''&lt;br /&gt;
Incoming data:&lt;br /&gt;
* '''privmsg:''' ''{source, destination, message}'' - Sends the ''source'' of a message, where the message was directed to (''destination'') and the message&lt;br /&gt;
* '''notice:''' ''{source, destination, message}'' - Sends the ''source'' of a notice, where the notice was directed to (''destination'') and the notice&lt;br /&gt;
* '''addchanneluser:''' ''{channel, name, (servername), (account)}'' - Mechanism used to alert IRC scripts when users have joined the current channel, and lists users in the channel upon join. Shows the ''channel'' that ''name'' joined.&lt;br /&gt;
* '''deletechanneluser:''' ''{channel, name}'' - Mechanism used to alert IRC scripts when users have left the current channel&lt;br /&gt;
* '''join:''' ''{channel}'' - Mechanism used to confirm that you have joined ''channel''&lt;br /&gt;
* '''part:''' ''{channel}'' - Mechanism used to confirm that you have left ''channel''&lt;br /&gt;
&lt;br /&gt;
=== Nickname Rules ===&lt;br /&gt;
If you are connecting from the serverside, you must start your nickname with one of the following:&lt;br /&gt;
* IRCBot_&lt;br /&gt;
* EventsBot_&lt;br /&gt;
* Graal_&lt;br /&gt;
If an invalid nickname is provided from the serverside, you will automatically be assigned with an IRCBot_'''n''' nickname.&lt;br /&gt;
&lt;br /&gt;
Nicknames should not contain spaces.&lt;br /&gt;
&lt;br /&gt;
== IRCBots for Old Scripting ==&lt;br /&gt;
It is now possible for servers using the old scripting engine to do IRCBots using the commands sendtext, requesttext, and the &amp;quot;if (receivetext)&amp;quot; event. A script example for a simple EventsBot:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (created || initialized || serverlisterconnect) {&lt;br /&gt;
  doConnect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function doConnect() {&lt;br /&gt;
  sendtext irc,logout,;&lt;br /&gt;
  sendtext irc,login,EventsBot_OldScript;&lt;br /&gt;
  setstring this.options,;&lt;br /&gt;
  addstring this.options,IRCBot;&lt;br /&gt;
  addstring this.options,!resetevents;&lt;br /&gt;
  sendtext irc,privmsg,#s(this.options);&lt;br /&gt;
  sendtext irc,join,#OldScriptTest;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (receivetext) {&lt;br /&gt;
  sendtonc irc: #p(0) - #p(1) - #p(2) - #p(3) - #p(4) - #p(5) - #p(6) - #p(7);&lt;br /&gt;
  if (strequals(#p(0),irc) &amp;amp;&amp;amp; strequals(#p(1),privmsg) &amp;amp;&amp;amp;&lt;br /&gt;
      strequals(#p(2),IRCBot)) {&lt;br /&gt;
    if (strequals(#p(4),!eventsbotlogin)) {&lt;br /&gt;
      setstring this.options,;&lt;br /&gt;
      addstring this.options,IRCBot;&lt;br /&gt;
        setstring this.options2,;&lt;br /&gt;
        addstring this.options2,!eventadmins;&lt;br /&gt;
        addstring this.options2,Stefan;&lt;br /&gt;
        addstring this.options2,Spark910;&lt;br /&gt;
      addstring this.options,#s(this.options2);&lt;br /&gt;
      sendtext irc,privmsg,#s(this.options);&lt;br /&gt;
&lt;br /&gt;
      setstring this.options,;&lt;br /&gt;
      addstring this.options,IRCBot;&lt;br /&gt;
        setstring this.options2,;&lt;br /&gt;
        addstring this.options2,!eventchannel;&lt;br /&gt;
        addstring this.options2,#OldScriptTest;&lt;br /&gt;
      addstring this.options,#s(this.options2);&lt;br /&gt;
      sendtext irc,privmsg,#s(this.options);&lt;br /&gt;
    } else if (strequals(#p(4),!startevent)) {&lt;br /&gt;
    } else if (strequals(#p(4),!resetevent)) {&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You also need to add a few script lines to the Control-NPC because in old scripting only the Control-NPC gets an event if the serverlister (=irc server) is reconnecting:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (serverlisterconnect) {&lt;br /&gt;
  with (getnpc(EventsBot)) {&lt;br /&gt;
    // Forwarding the event to the Events Bot&lt;br /&gt;
    callnpc -1,serverlisterconnect;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Particle_Engine&amp;diff=8931</id>
		<title>Particle Engine</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Particle_Engine&amp;diff=8931"/>
		<updated>2007-07-01T07:49:13Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8678 by Special:Contributions/Anti-Up (User talk:Anti-Up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
&lt;br /&gt;
The particle engine in Graal v4 is an extension of the SHOWIMG feature. With the command &amp;quot;showimg&amp;quot; scripts can display graphics, text, polygons and even animations on the screen. That command is mainly meant for client-side effects, but can also partially used on the serverside, and they can also be made visible on other player's screens. Graphics or texts displayed using this command will be called SHOWIMGs in this paper.&lt;br /&gt;
&lt;br /&gt;
Each SHOWIMG can be used as emitter for particles. That way all kind of scripts can use the new particle engine - just display a SHOWIMG and set the attributes of the SHOWIMG so that the particle emitter is activated and is emitting particles. A particle can be seen as an independent graphic object that is put at the position of the emitter once it is emitted, then travelling over the screen, and disappearing once its lifetime is over or it is outside the allowed screen bounds. Actually a particle is itself a SHOWIMG and can so be used for any kind of graphical effect, and can theoretically even be used as emitter for other particles.&lt;br /&gt;
&lt;br /&gt;
The reason for using a particle engine is speed: theoretically all graphical effects could be done by using scripts which call commands to display graphics or text. But often such effects contain several hundreds or even thousands of graphics, which must be moved and animated several times each second. If there are many objects using scripted particle effects that can slow down the game quite a lot. That's why it is possible in Graal v4 to use a built-in particle engine with many possible options to influence the look and behaviour of the particles so that most graphics effects can be displayed using that engine.&lt;br /&gt;
&lt;br /&gt;
==Create a SHOWIMG==&lt;br /&gt;
&lt;br /&gt;
To use the particle engine, you first need a SHOWIMG as emitter:&lt;br /&gt;
&lt;br /&gt;
  with (findimg(200)) {&lt;br /&gt;
    x = player.x;&lt;br /&gt;
    y = player.y;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
The function findimg(index) is searching for an existing SHOWIMG with the index of 200 and then using that for setting the other attributes, otherwise it is automatically creating a new SHOWIMG with index 200 for the current object (npc, or player if its a weapon/gui-script). Afterwards it is setting the position of the SHOWIMG to position of the player.&lt;br /&gt;
&lt;br /&gt;
==Configure emitter and particle==&lt;br /&gt;
&lt;br /&gt;
Once the SHOWIMG is setup, you need to configure the emitter and the default attributes of the particle that should be emitted:&lt;br /&gt;
&lt;br /&gt;
  with (findimg(200)) {&lt;br /&gt;
    x = player.x;&lt;br /&gt;
    y = player.y;&lt;br /&gt;
    emitter.attribute = value;&lt;br /&gt;
    emitter.particle.attribute = value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Possible attribute names are&lt;br /&gt;
(you can run &amp;quot;Graal4.exe -listscriptfunctions&amp;quot; to get the latest list of script functions):&lt;br /&gt;
&lt;br /&gt;
  TParticleEmitter (TGraalVar):&lt;br /&gt;
    attachposition - boolean - says if the particle is moved with the emitter (true), or can fly freely (false)&lt;br /&gt;
    autorotation - boolean - for making the particle heading into the direction it flies (rotation=angle)&lt;br /&gt;
    checkbelowterrain - boolean - destroys the particles if they are below the terrain height (or zero on flat maps)&lt;br /&gt;
    clippingbox - {xd1,yd1,zd1, xd2,yd2,zd2} - defines a box, if particles leave this box then they are destroyed&lt;br /&gt;
    cliptoscreen - boolean - automatically resizes the clipping box to the visible area&lt;br /&gt;
    delaymin - float - minimum delay till the next automatic emission (&amp;gt;= 0.05 seconds)&lt;br /&gt;
    delaymax - float - maximum delay till the next automatic emission&lt;br /&gt;
    emissionoffset - {xd,yd,zd} - by default {0,0,0}, says at which position the particles should be emitted, relative to the current emitter position&lt;br /&gt;
    emitautomatically - boolean - enables or disabled the automatic emission of particles after delaymin/delaymax time&lt;br /&gt;
    firstinfront - boolean - says if the first emitted particle should be displayed in front (true by default)&lt;br /&gt;
    maxparticles - integer - can be used to limit the total particle count&lt;br /&gt;
    nrofparticles - integer - specifies how many particles are emitted at once&lt;br /&gt;
    particle - object (read only) - defines the default attributes of the next emitted particle&lt;br /&gt;
    wraptoclippingbox - boolean - if a particle leaves on one side, it appears on the other side (use with &amp;quot;cliptoscreen&amp;quot; option)&lt;br /&gt;
&lt;br /&gt;
  TParticle (TGraalVar):&lt;br /&gt;
    angle - float - the movement angle of the particle (horizontally on the (x,y) plane)&lt;br /&gt;
    lifetime - float - in seconds, the particle will be destroyed when the lifetime is over&lt;br /&gt;
    movementvector - string - says in which direction the particles moves, this is a combination of angle and zangle&lt;br /&gt;
    speed - float - tiles per second&lt;br /&gt;
    spin - float - automatic rotation of the particle (radiants each second)&lt;br /&gt;
    zangle - float - the vertical movement angle - says if the particles goes up or down&lt;br /&gt;
&lt;br /&gt;
    Particle attributes that are the same like for a SHOWIMG:&lt;br /&gt;
    alpha - float - transparency&lt;br /&gt;
    ani - string - a gani file (use &amp;quot;projectile.actor&amp;quot; for changing the attributes)&lt;br /&gt;
    blue - float - blue color value (0-1)&lt;br /&gt;
    code - string - the old representation as 'font@style@text'&lt;br /&gt;
    dimension - integer - polygon dimension (2 or 3)&lt;br /&gt;
    dir - integer - animation direction&lt;br /&gt;
    emitter - object (read only) - for specifying the attributes of a sub-emitter&lt;br /&gt;
    font - string - text font name&lt;br /&gt;
    green - float - green color value (0-1)&lt;br /&gt;
    image - string - image filename&lt;br /&gt;
    layer - integer - 4 or higher for particle which move in screen coordinates, below 4 for level coordinates&lt;br /&gt;
    mode - integer - the image drawing mode (0 - add, 1 - transparent, 2 - subtract, 3 - daynight)&lt;br /&gt;
    playerlook - boolean - if the animation should take it's head, body, sword, shield and attr[] from the owner (playerlook), set this to false if you want to set the images yourself by changing showimg.actor.head etc.&lt;br /&gt;
    polygon - object - array of coordinates for displaying a 2 or 3 dimensional polygon&lt;br /&gt;
    red - float - red color value (0-1)&lt;br /&gt;
    rotation - float - defines in which direction the particle graphics is facing&lt;br /&gt;
    stretchx - float - horizontal particle graphics stretch factor (default 1)&lt;br /&gt;
    stretchy - float - vertical particle graphics stretch factor (default 1)&lt;br /&gt;
    style - string - text style (e.g. &amp;quot;b&amp;quot; for bold text)&lt;br /&gt;
    text - string - a text that should be displayed on the SHOWIMG position&lt;br /&gt;
    zoom - float - zoom factor of the particle graphics or text&lt;br /&gt;
&lt;br /&gt;
==Add particle modifiers==&lt;br /&gt;
&lt;br /&gt;
Once you have setup the SHOWIMG and specified the attributes of the emitter and default particle, you can also specify particle modifiers so that the particles are not always flying into the same direction and look the same. There are 3 different functions, for modifying the default particle addemitmodifier(), for modifying all existing particles addglobalmodifier(), and for modifying the attributes for each particle individually addlocalmodifier(). The local modifiers are the most often used modifier.&lt;br /&gt;
Parameters are:&lt;br /&gt;
  modifier type - once,impulse or range - modifies the particle one time, periodically or only in the given time range&lt;br /&gt;
  rangemin - seconds, minimum delay until first modification or start of modification range (if modifier is &amp;quot;range&amp;quot;)&lt;br /&gt;
  rangemax - seconds, maximum delay until first modification or end of modification range (if modifier is &amp;quot;range&amp;quot;)&lt;br /&gt;
  variable - x,y,z,movex,movey,movez,angle,zangle,speed,rotation,spin,stretchx,stretchy,red,green,blue,alpha or zoom&lt;br /&gt;
  variable modification type - replace,add or multiply (if modifier type is &amp;quot;range&amp;quot; then only &amp;quot;replace&amp;quot; and &amp;quot;add&amp;quot; are valid)&lt;br /&gt;
  valuemin - range start of the random value or first value to set/add (if modifier is &amp;quot;range&amp;quot;)&lt;br /&gt;
  valuemax - range end of the random value or last value to set/add (if modifier is &amp;quot;range&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Those 3 functions addemitmodifier(), addglobalmodifier() and addlocalmodifier() are returning a modifier object which can be used to attach more variable modifications to the same impulse:&lt;br /&gt;
&lt;br /&gt;
  with (addlocalmodifier(&amp;quot;impulse&amp;quot;,1,2,&amp;quot;angle&amp;quot;,&amp;quot;replace&amp;quot;,0,pi)) {&lt;br /&gt;
    addmod(&amp;quot;zoom&amp;quot;,&amp;quot;add&amp;quot;,0.1,0.2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
This example is modifying the angle each 1-2 seconds, and at the same time it is zooming the particle so that it grows bigger. If you don't need to have the two modifiers act at the same moment, then you could have called addlocalmodifier(&amp;quot;impulse&amp;quot;,1,2,&amp;quot;zoom&amp;quot;,&amp;quot;add&amp;quot;,0.1,0.2) which looks quite the same, but is not guaranteed to happen at the same moment like the first modifier. Most of the time you don't need the addmod-function though.&lt;br /&gt;
&lt;br /&gt;
==Manually emitting particles==&lt;br /&gt;
&lt;br /&gt;
If you have done the things mentioned in the previous steps, then the particle emitter is automatically emitting particles after the time specified with delaymin and delaymax. If you don't want that particles are automatically emitted, then set emitautomatically to false and call emitter.emit() directly.&lt;br /&gt;
&lt;br /&gt;
==Controlling the particle emitter==&lt;br /&gt;
&lt;br /&gt;
You can modify the particle emitter at any time by using the &amp;quot;with (findimg(index))&amp;quot; construct again as mentioned in &amp;quot;Create a SHOWIMG&amp;quot; chapter. To change the position where the particles are emitted you can just change the position of the SHOWIMG, e.g. moving it to the player position so that the particles are always emitted where the player stands.&lt;br /&gt;
&lt;br /&gt;
It can also be interesting to watch the number of particles that the emitter has emitted, you can read the variables &amp;quot;currentparticlecount&amp;quot; and &amp;quot;emittedparticles&amp;quot; for that:&lt;br /&gt;
&lt;br /&gt;
  TParticleEmitter (TGraalVar):&lt;br /&gt;
    currentparticlecount - integer (read only) - for watching how many particles exist&lt;br /&gt;
    emittedparticles - integer (read only) - for seeing how many particles have been emitted in total&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Reference==&lt;br /&gt;
&lt;br /&gt;
  emitter&lt;br /&gt;
    attachposition - Tells whether or not x/y position of particles is relative to the position of the emitter. Also tells if particles should move when the emitter is moved.&lt;br /&gt;
    autorotation - Must be ture for making the particle heading into the direction it flies (rotation=angle)&lt;br /&gt;
    checkbelowterrain - If true, the particle will be destroyed if it falls below the terrain height (0 for flat GMaps)&lt;br /&gt;
    clippingbox - Format of {x1,y1,z1,x2,y2,z2}, particles that leave this box will be destroyed&lt;br /&gt;
    cliptoscreen - boolean - automatically resizes the clipping box to the visible area&lt;br /&gt;
    currentparticlecount - Current number of particles that exist&lt;br /&gt;
    delaymin - Minimum time before another particle is emitted&lt;br /&gt;
    delaymax - Maximum time before another particle is emitted&lt;br /&gt;
    emissionoffset - How far away from the emitter (or the level if attachposition=false) to emit particles. Format: {x,y,z}&lt;br /&gt;
    emittedparticles - Total number of particles that have been emitted&lt;br /&gt;
    firstinfront - Tells whether particles drawn after the first particle should draw on top or below the first&lt;br /&gt;
    maxparticles - Maximum number of particles that can exist at once&lt;br /&gt;
    nrofparticles - Number of particles to release at once&lt;br /&gt;
    isfrozen - Boolean, stops all particles if true&lt;br /&gt;
    wraptoclippingbox - boolean - if a particle leaves on one side, it appears on the other side (use with &amp;quot;cliptoscreen&amp;quot; option)&lt;br /&gt;
    particle&lt;br /&gt;
      lifetime - Time (in seconds) before a particle is destroyed&lt;br /&gt;
      image - Image to use for the particle&lt;br /&gt;
      mode - Drawing mode of the image. (0 = add, 1 = replace, 2 = subtract, 3 = daynight) See changeimgmode&lt;br /&gt;
      alpha - Alpha transparency of a particle (0 = invisible, 1 = opaque)&lt;br /&gt;
      zoom - Zoomfactor of a particle&lt;br /&gt;
      angle - Movement angle for the particle (for x/y)&lt;br /&gt;
      zangle - Up/down movement angle for the particle&lt;br /&gt;
      speed - How many tiles or pixels the particle should move (depends on if its in a level or on the GUI)&lt;br /&gt;
      rotation - Angle for rotating the image (set autorotation=true to automatically set rotation=angle)&lt;br /&gt;
      spin - How much the image should be rotated each second, can be postive and negative&lt;br /&gt;
      stretchx - How much to stretch the particle image horizontally&lt;br /&gt;
      stretchy - How much to stretch the particle image vertically&lt;br /&gt;
      red, green, blue - Used to change color of particle&lt;br /&gt;
      dimension - Polygon dimension (2 or 3)&lt;br /&gt;
      movementvector - Format is {float,float,float}, a combination of x, y and z&lt;br /&gt;
&lt;br /&gt;
    Emitter functions:&lt;br /&gt;
    addlocalmodifier(&amp;quot;string&amp;quot;,float,float,&amp;quot;string&amp;quot;,&amp;quot;string&amp;quot;,float,float)&lt;br /&gt;
      Parameters:&lt;br /&gt;
      First - Tells when to do an action&lt;br /&gt;
        once - Do it once&lt;br /&gt;
        range - Do the action during the range of time param2-param3&lt;br /&gt;
        impulse - Do it randomly&lt;br /&gt;
      Second - Tells the minimum time to wait before doing an action (except for 'range')&lt;br /&gt;
      Third - Tells the maximum time to wait before doing an action (except for 'range')&lt;br /&gt;
      Fourth - Tells what action to perform&lt;br /&gt;
        Everything under &amp;quot;particle&amp;quot; except for the following can be changed: image , text, ani, font, movementvector, style&lt;br /&gt;
        x - x position of the particle&lt;br /&gt;
        y - y position of the particle&lt;br /&gt;
        z - z position of the particle&lt;br /&gt;
        movex - How far the particle should move horizontally in its lifetime&lt;br /&gt;
        movey - How far the particle should move vertically in its lifetime&lt;br /&gt;
        movez - How far the particle should move above the ground in its lifetime&lt;br /&gt;
      Fifth - Tells what to do with parameters 6 and 7&lt;br /&gt;
        add - Add the amount (use negatives to subtract)&lt;br /&gt;
        replace - Set a new amount&lt;br /&gt;
        multiply - Multiply the amount (use negatives to divide)&lt;br /&gt;
      Sixth - Minimum amount&lt;br /&gt;
      Seventh - Maximum amount&lt;br /&gt;
    addglobalmodifier() - Same as addlocalmodifier, except it affects all particles at once&lt;br /&gt;
    addemitmodifier() - Same as addlocalmodifier, except it only affects emitter.particle&lt;br /&gt;
    addmod() - Used in conjunction with addlocalmodifier, same parameters except no parameters 1-3&lt;br /&gt;
    emit() - Do one emission&lt;br /&gt;
    removemodifiers() - Remove modifiers set&lt;br /&gt;
    removeparticles() - Remove particles&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/GS1_To_GS2&amp;diff=8930</id>
		<title>Creation/Dev/GS1 To GS2</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/GS1_To_GS2&amp;diff=8930"/>
		<updated>2007-07-01T07:49:10Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8677 by Special:Contributions/Anti-Up (User talk:Anti-Up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introducing the new scripting engine ==&lt;br /&gt;
&lt;br /&gt;
This document is describing some problems and solutions&lt;br /&gt;
when switching from the old Graal scripting engine (GS1) to&lt;br /&gt;
the new engine (GS2). The new scripting engine has been&lt;br /&gt;
designed to on the one hand be compatible to the old&lt;br /&gt;
engine, and on the other hand provide new functionality&lt;br /&gt;
to make it easier to write Graal scripts and do more&lt;br /&gt;
interesting things with it. Those new things include&lt;br /&gt;
a windowing system (GUI), a particle engine, multi-dimensional&lt;br /&gt;
arrays, function parameter passing, true object orientation.&lt;br /&gt;
&lt;br /&gt;
Since the old engine has been designed 7 years ago, a lot&lt;br /&gt;
of functionality has been added to that engine while the basic&lt;br /&gt;
design has not been changed, so a lot of modifications can be&lt;br /&gt;
more seen as a &amp;quot;hack&amp;quot; and are not very easy to use. For example&lt;br /&gt;
numeric variables and string variables must be accessed&lt;br /&gt;
in a different way, even more complex operations need to be&lt;br /&gt;
used to access numeric arrays and string lists.&lt;br /&gt;
The new scripting engine tries to stay compatible with the old&lt;br /&gt;
functions, but also add easier ways to access the variables.&lt;br /&gt;
Numeric and string variables can now be accessed the same way,&lt;br /&gt;
as well as numeric arrays and string lists.&lt;br /&gt;
&lt;br /&gt;
To make the new functionality easy to use, some old &amp;quot;hacky&amp;quot; ways of&lt;br /&gt;
accessing variables are not supported anymore. If scripts are&lt;br /&gt;
written correctly without using those methods, then they will work&lt;br /&gt;
fine in the new engine. If not, then they need to be fixed manually.&lt;br /&gt;
In generally there are not a lot of scripts using those problematic&lt;br /&gt;
ways of accessing variables, but sometime scripters just use&lt;br /&gt;
copy &amp;amp; paste and so also copy the error to a lot of scripts. Then&lt;br /&gt;
the only solution will be to edit those scripts manually, copying&lt;br /&gt;
the fixed code part to the other affected scripts, or directly use&lt;br /&gt;
classes and the ''join'' function.&lt;br /&gt;
&lt;br /&gt;
== Using the correct syntax ==&lt;br /&gt;
&lt;br /&gt;
The new scripting engine finally reports syntax errors, when&lt;br /&gt;
modifying scripts you see the error output on RC chat (RC is&lt;br /&gt;
short for [[RC|RemoteControl]], an admin tool for Graal). If there&lt;br /&gt;
are errors while the npcserver is starting up, then the errors&lt;br /&gt;
are written in to logs/syntaxerrors.txt.&lt;br /&gt;
The new engine also reports errors while running the scripts,&lt;br /&gt;
including endless loops (loops are limited to 10000 cycles)&lt;br /&gt;
and call of non-existing functions. On clientside those&lt;br /&gt;
errors are output into the F2 window, on serverside they&lt;br /&gt;
are displayed on RC chat, but can also be redirected to&lt;br /&gt;
file using the [[server options|server option]] ''logscripterrorstofile=true'',&lt;br /&gt;
the errors will then appear in logs/scripterrors.txt.&lt;br /&gt;
&lt;br /&gt;
While some people might get headache when seeing a lot of&lt;br /&gt;
script errors, that error reporting is actually giving you&lt;br /&gt;
the possibility to track errors easily. While the new engine&lt;br /&gt;
is not accepting as many syntax hacks as the old engine,&lt;br /&gt;
it is actually easier now to fix them.&lt;br /&gt;
&lt;br /&gt;
=== Closing brackets ===&lt;br /&gt;
&lt;br /&gt;
An error that often happens is a missing opening bracket or&lt;br /&gt;
missing closing bracket. The best way to not accidently do&lt;br /&gt;
that error is to follow a constant and ordered scripting&lt;br /&gt;
style, indenting scripting lines, using spaces between&lt;br /&gt;
operators. Each time you open a '''{''' bracket you indent the&lt;br /&gt;
following lines by 2 spaces. You can also use 4 spaces, that&lt;br /&gt;
doesn't matter as long as you keep the same number of spaces&lt;br /&gt;
in the whole script. Tabulators are not recommended since&lt;br /&gt;
special characters are automatically removed by the engine.&lt;br /&gt;
When you afterwards use a '''}''', then you stop the indenting.&lt;br /&gt;
That way you can check the correct number of opening and closing&lt;br /&gt;
brackets by just watching if the last closing bracket appears&lt;br /&gt;
at the very beginning of a line.&lt;br /&gt;
The Graal script compiler doesn't require that indenting, but it&lt;br /&gt;
is still recommended.&lt;br /&gt;
&lt;br /&gt;
=== Semicolon ===&lt;br /&gt;
&lt;br /&gt;
A thing that is quite simple to keep care of but is often&lt;br /&gt;
done wrong is to add semicolons behind commands. That must&lt;br /&gt;
be done to separate the commands from each other.&lt;br /&gt;
In the old scripting engine it was possible to forget the&lt;br /&gt;
semicolon if the next character was a closing bracket '''}'''.&lt;br /&gt;
The bracket was automatically finishing the last command.&lt;br /&gt;
In the new engine that it possible too as long as the last&lt;br /&gt;
command is a function call, it's not working if the last&lt;br /&gt;
command is an assignment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bad:  if (playerenters) {x=3}&lt;br /&gt;
Good: if (playerenters) {x=3;}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scripters also often think that a closing bracket '''}'''&lt;br /&gt;
never needs a semicolon behind it, although the semicolon is&lt;br /&gt;
required if the brackets are used for defining an array or&lt;br /&gt;
subscript:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bad:  setshape2 2,2,{0,0,0,0}&lt;br /&gt;
Good: setshape2 2,2,{0,0,0,0};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That mainly affects the function calls ''setshape2'', ''showpoly''&lt;br /&gt;
and ''putnpc2''. Those always require a semicolon at the end,&lt;br /&gt;
no matter if the function parameters are finishing with a&lt;br /&gt;
closing bracket '''}'''.&lt;br /&gt;
&lt;br /&gt;
=== Syntax incompatibilities ===&lt;br /&gt;
&lt;br /&gt;
While most old scripts compile fine when having no syntax&lt;br /&gt;
error, there is one exception when a correct old script&lt;br /&gt;
is not working with the new scripting engine: the&lt;br /&gt;
in-operator is different:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Works in GS1:  i = (playerx,playery in &amp;lt;20,40&amp;gt;);&lt;br /&gt;
Works in both: i = (playerx in &amp;lt;20,40&amp;gt; &amp;amp;&amp;amp; playery in &amp;lt;20,40&amp;gt;);&lt;br /&gt;
Works in GS2:  i = ({playerx,playery} in &amp;lt;20,40&amp;gt;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variable lookup ==&lt;br /&gt;
&lt;br /&gt;
As described in chapter one, the variable lookup has been&lt;br /&gt;
changed in the new scripting engine. Lookup means the&lt;br /&gt;
behaviour how variable names are translated into actual&lt;br /&gt;
object attributes, or to be more close to the hardware,&lt;br /&gt;
lookup is the translation into memory addresses.&lt;br /&gt;
That means that a variable that was formerly connected&lt;br /&gt;
to one value, is now connected to another value, and&lt;br /&gt;
eventually having different behaviour when modifying it,&lt;br /&gt;
and is so changing the logic of the script or even&lt;br /&gt;
mess it up.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
&lt;br /&gt;
Several scripts were using the variable ''this.x'' to store&lt;br /&gt;
temporary data, or just as for-loop variable.&lt;br /&gt;
While in the old engine ''this.x'' was just a numeric scripting&lt;br /&gt;
variable, it is now redirecting to the ''x'' value of the&lt;br /&gt;
current script object (''this''). So if you modify it, then&lt;br /&gt;
the npc is magically starting to move, which was&lt;br /&gt;
probably not the intention of the scripter.&lt;br /&gt;
In that case the variable name must be modified to something&lt;br /&gt;
like ''i'' or ''temp.i''.&lt;br /&gt;
&lt;br /&gt;
=== Variable types in the new scripting engine ===&lt;br /&gt;
&lt;br /&gt;
The new scripting engine (GS2) has basicly 3 types of variables:&lt;br /&gt;
&lt;br /&gt;
* Object variables: objectname.variablename &amp;lt;br&amp;gt; Object can be ''this'' for the current object, or ''player'' or an NPC name like ''DB_Items''. The variable will then access the attributes of the object if there is a built-in attribute with that name (e.g. ''this.x''), or a script variable belonging to that object (e.g. ''this.i'')&lt;br /&gt;
&lt;br /&gt;
* Attributes of the active object: attributename &amp;lt;br&amp;gt; If there is no leading, then the attributes of the current script object (for which the script is executed) are accessed, if there is an attribute with that name, e.g. ''x''.&lt;br /&gt;
&lt;br /&gt;
* Global variables: variablename &amp;lt;br&amp;gt; If the variable name has no leading and is not matching a built-in attribute of the current script object, then it is taken from the global variable pool. This is different to most other scripting languages where variables without leading are seen as local variables, but this behaviour is required to be compatible with the old scripting engine. Also it is a simple way to share data between scripts - you can set a flag in one script and read the flag in another script without needing to know where it is stored. Global variables are not saved, so they are not persistent and disappear after a server restart.&lt;br /&gt;
&lt;br /&gt;
There are a few exceptions to this lookup scheme, e.g.&lt;br /&gt;
function parameters can be accessed without a leading in&lt;br /&gt;
front of the variable name. Also the ''with'' operator can&lt;br /&gt;
temporary modify the current script object (''this'').&lt;br /&gt;
In generally you don't need to care about those exceptions,&lt;br /&gt;
to be sure that everything is working fine you should&lt;br /&gt;
prefer to add a leading in front of variable names&lt;br /&gt;
though.&lt;br /&gt;
&lt;br /&gt;
=== Change of variable lookup ===&lt;br /&gt;
&lt;br /&gt;
==== Attributes of the current object ====&lt;br /&gt;
&lt;br /&gt;
As described in chapter 3.1., the built-in attributes of the&lt;br /&gt;
current object can be accessed by ''this.x'', ''this.y'' etc. now.&lt;br /&gt;
In the old scripting engine that was not possible, those&lt;br /&gt;
variable names were used for normal variables. That means&lt;br /&gt;
if your scripts are using such variables, make sure that it is&lt;br /&gt;
used for the correct thing. That includes numeric variables&lt;br /&gt;
(''this.x = 3;'') as well as string variables (''setstring this.x,3;'');&lt;br /&gt;
&lt;br /&gt;
Most common variables that need to be changed:&lt;br /&gt;
* ''this.x'', ''this.y'', ''this.dir'', ''this.hp'', ''this.ap''&lt;br /&gt;
* ''this.hp'' on serverside&lt;br /&gt;
* ''this.width'', ''this.height'', ''this.image''&lt;br /&gt;
&lt;br /&gt;
==== Global variables ====&lt;br /&gt;
&lt;br /&gt;
Variables without leading are global now. While on clientside&lt;br /&gt;
that was already the case in the old scripting engine, on&lt;br /&gt;
serverside those variables were formerly only accessible in the&lt;br /&gt;
current script. If you are using such variables, don't trust&lt;br /&gt;
that other scripts are not modifying it. Eventually rename&lt;br /&gt;
those variables, or use ''this.variables'' which are only working&lt;br /&gt;
for the current object, or ''temp.variables'' which are only working&lt;br /&gt;
in the current function body.&lt;br /&gt;
&lt;br /&gt;
==== With-Operator ====&lt;br /&gt;
&lt;br /&gt;
The ''with'' operator is temporary changing the current&lt;br /&gt;
script object (''this''): all ''this.'' variables inside the&lt;br /&gt;
opening and closing bracket are redirected to the&lt;br /&gt;
with-object instead of the executing script object.&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.myvar = 3;&lt;br /&gt;
with (findplayer(&amp;quot;Max&amp;quot;)) {&lt;br /&gt;
  this.myvar = 5;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After executing that code, ''myvar'' of the npc has&lt;br /&gt;
the value 3, while ''myvar'' of the player &amp;quot;Max&amp;quot; has 5.&lt;br /&gt;
The player &amp;quot;Max&amp;quot; is the with-object in this case.&lt;br /&gt;
While both variables are accessed using the same&lt;br /&gt;
variable name, they are directing to different&lt;br /&gt;
variables.&lt;br /&gt;
In the old scripting engine ''this'' was only modified&lt;br /&gt;
when the with-object is another npc. In the new&lt;br /&gt;
engine any script object can overwrite ''this''.&lt;br /&gt;
&lt;br /&gt;
Another thing that you need to keep care of is that you&lt;br /&gt;
can also access the built-in variables of the with-object&lt;br /&gt;
without using the ''this'' leading:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
x = 20;&lt;br /&gt;
with (findnpc(&amp;quot;Turret&amp;quot;)) {&lt;br /&gt;
  x = 30;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this case the ''x'' position of the current npc will&lt;br /&gt;
be changed to 20, while the ''x'' position of the Turret&lt;br /&gt;
will be changed to 30.&lt;br /&gt;
The only exceptions for this behaviour are the variables&lt;br /&gt;
''x'', ''y'', ''dir'' and ''ap'' when using a player as&lt;br /&gt;
with-object: an ''x'' without leading will never direct&lt;br /&gt;
to the ''player.x'' variable, it will always take the&lt;br /&gt;
npc for which the script is executed, or the npc that is&lt;br /&gt;
positioned highest in the ''with''-stack when using several&lt;br /&gt;
''with''-operations inside each other.&lt;br /&gt;
&lt;br /&gt;
=== Numeric variables, string variables and array using the same name ===&lt;br /&gt;
&lt;br /&gt;
One major improvement in the new scripting engine is that&lt;br /&gt;
you can easier access string variables and arrays. One&lt;br /&gt;
drawback is that if you have used numeric variables, arrays or&lt;br /&gt;
string variables with the same name, those are now directing to&lt;br /&gt;
the same variable. So you will need to modify the variable&lt;br /&gt;
names if they are supposed to hold different data:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bad:&lt;br /&gt;
  this.myvar = 1;&lt;br /&gt;
  setstring this.myvar,2;&lt;br /&gt;
  this.myvar = {1,2,3};&lt;br /&gt;
&lt;br /&gt;
Good:&lt;br /&gt;
  this.mynumericvar = 1;&lt;br /&gt;
  this.mystringvar = &amp;quot;2&amp;quot;;&lt;br /&gt;
  this.myarrayvar = {1,2,3};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Easier access to string variables ==&lt;br /&gt;
&lt;br /&gt;
You only need to read this chapter if you want to use the&lt;br /&gt;
new way of accessing string variables, it is not&lt;br /&gt;
required to make old scripts compatible.&lt;br /&gt;
&lt;br /&gt;
String variables can be accessed easier now:&amp;lt;br&amp;gt;&lt;br /&gt;
Writing string variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Old: setstring this.myvar,text;&lt;br /&gt;
New: this.myvar = &amp;quot;text&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Reading string variables:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Old: #s(this.mvyar)&lt;br /&gt;
New: this.myvar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see that string variables can now be accessed&lt;br /&gt;
similar to numeric variables. Sometimes the variable&lt;br /&gt;
name must have a different leading though to access&lt;br /&gt;
the same variable:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Old: setstring varwithoutleading,text;&lt;br /&gt;
New: player.varwithoutleading = &amp;quot;text&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also constructing dynamic variable names for string&lt;br /&gt;
variables is different now, you need to use the&lt;br /&gt;
new syntax. This documentation is not for explaining&lt;br /&gt;
the complete syntax, but it might help to lead you&lt;br /&gt;
to the correct path:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Old: setstring this.item#v(itemnumber),apple;&lt;br /&gt;
New: this.(&amp;quot;item&amp;quot; @ itemnumber) = &amp;quot;apple&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need to keep care on following things:&lt;br /&gt;
* you concat strings using @&lt;br /&gt;
* if you want to concat a string to another variable, don't forget to put &amp;quot;&amp;quot; around it to mark it as string&lt;br /&gt;
* never put a dot inside the dynamic variable name:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bad:  (&amp;quot;this.item&amp;quot; @ itemnumber)&lt;br /&gt;
Good: this.(&amp;quot;item&amp;quot; @ itemnumber)&lt;br /&gt;
Good: (&amp;quot;Party&amp;quot; @ partynumber).name&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* never use array brackets in the dynamic variable name:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Bad:  this.(&amp;quot;item[&amp;quot; @ index @ &amp;quot;]&amp;quot;)&lt;br /&gt;
Good: this.item[index]&lt;br /&gt;
Good: this.(&amp;quot;itemstats_&amp;quot; @ itemnumber)[index]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Server-side and client-side ==&lt;br /&gt;
&lt;br /&gt;
The new scripting engine is reporting the calls of&lt;br /&gt;
non-existing functions. As described in chapter 2,&lt;br /&gt;
you can redirect those error reports to file using&lt;br /&gt;
[[server options|server option]] ''logscripterrorstofile=true'', or you&lt;br /&gt;
set the variable ''this.scriptlogmissingfunctions'' to&lt;br /&gt;
false in case a script wants to call functions of&lt;br /&gt;
unknown objects and doesn't want to flood the&lt;br /&gt;
RC chat.&lt;br /&gt;
Still it is not good to call non-existing functions,&lt;br /&gt;
most of the time that function call actually&lt;br /&gt;
was meant to have a purpose and is causing problems&lt;br /&gt;
if it's not executed. In some cases the object&lt;br /&gt;
might have disappeared or was accessed using a&lt;br /&gt;
bad name.&lt;br /&gt;
It might also be possible that the function&lt;br /&gt;
actually doesn't exist: on many servers scripts&lt;br /&gt;
are executed on server-side which are meant for&lt;br /&gt;
client-side, and vice-versa. There are lists of&lt;br /&gt;
available scripting functions, check those if&lt;br /&gt;
you are not sure if the function is existing &lt;br /&gt;
([[Creation/Dev/Script Functions: NPC Server|Script Functions: NPC Server]], [[Creation/Dev/Script/Client|Script Functions: Client]]).&lt;br /&gt;
&lt;br /&gt;
You can add a line ''//#CLIENTSIDE'' in front of a&lt;br /&gt;
script if it's meant for clientside execution,&lt;br /&gt;
or remove that line if its meant for serverside&lt;br /&gt;
executing. If you call the non-existing function&lt;br /&gt;
on the bad side but rely on executing that function,&lt;br /&gt;
then you will need to send a trigger to the other&lt;br /&gt;
side or modify a variable, which can be read on&lt;br /&gt;
the other side and reacted probably.&lt;br /&gt;
&lt;br /&gt;
Common functions that are client-side only:&lt;br /&gt;
* '''play'''(soundfile);&lt;br /&gt;
* '''hurt'''(hurtpower);&lt;br /&gt;
* '''addtiledef'''(image,levelstart,tilestype)&lt;br /&gt;
* '''addtiledef2'''(image,levelstart,x,y)&lt;br /&gt;
* '''showtext'''(index,x,y,font,style,text); &amp;lt;br&amp;gt; also ''showani'', ''showpoly'' etc. &amp;lt;br&amp;gt; those might be added soon to serverside though, currently only ''showimg'' and ''changeimgcolors'' etc. is available on serverside&lt;br /&gt;
&lt;br /&gt;
Common functions that are server-side only:&lt;br /&gt;
* '''setlevel2'''(levelname,newx,newy);&lt;br /&gt;
* '''putnpc2'''(newx,newy,script);&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Script/Client&amp;diff=8929</id>
		<title>Creation/Dev/Script/Client</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Script/Client&amp;diff=8929"/>
		<updated>2007-07-01T07:49:05Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Client Supported Script Features=&lt;br /&gt;
&lt;br /&gt;
==Settings==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot;&lt;br /&gt;
| '''Name'''&lt;br /&gt;
| '''Type'''&lt;br /&gt;
| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| $camera::movementspeed&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::choosenvoicecodec&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::microactivatebyvolume&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::microactivationlevel&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::microinputdevice&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::microon&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::microvolumefactor&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::midivolume&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::mp3volume&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::radiovolume&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::reversestereo&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::sfxvolume&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::audio::voicevolume&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::allowglobalpms&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::automapping&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::defaultfontsize&lt;br /&gt;
| integer&lt;br /&gt;
| Change showtext zoom: $pref::graal::defaultfontsize/24&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::dontconnectlevels&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::dontloadlistheads&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::dontsavepasswords&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::dontsavepms&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::fixedport&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::fixedudpport&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::language&lt;br /&gt;
| string&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::limitnicknames&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::loadbuddylistfromserver&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::nicknamelimit&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::nomassmessages&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::notoalls&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::noudp&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::graal::showyourselfonbuddylists&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::input::mousesensitivity&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::interior::lockarrays&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::terrain::enabledetails&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::video::detailfactor&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::video::fogdistance&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::video::fullscreenmode&lt;br /&gt;
| string&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::video::screenshotformat&lt;br /&gt;
| string&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::video::visibledistance&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $pref::video::windowmode&lt;br /&gt;
| string&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| $scenelighting::lightingprogress&lt;br /&gt;
| float (read only)&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Variables==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot;&lt;br /&gt;
| '''Name'''&lt;br /&gt;
| '''Type'''&lt;br /&gt;
| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| allfeatures&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| for use with enablefeatures(), it's the default unless it is changed.&lt;br /&gt;
|-&lt;br /&gt;
| allplayerscount&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| The size of the allplayers array.&lt;br /&gt;
|-&lt;br /&gt;
| allrenderobjecttypes&lt;br /&gt;
| integer (read only)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| allstats&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| A bitflag of all stats currently enabled&lt;br /&gt;
|-&lt;br /&gt;
| canspin&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the player has spin attack&lt;br /&gt;
|-&lt;br /&gt;
| carriesblackstone&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the player is carrying a black stone&lt;br /&gt;
|-&lt;br /&gt;
| carriesbush&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the player is carrying a bush&lt;br /&gt;
|-&lt;br /&gt;
| carriesnpc&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the player is carrying an NPC.&lt;br /&gt;
|-&lt;br /&gt;
| carriessign&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if a player is carrying a sign.&lt;br /&gt;
|-&lt;br /&gt;
| carriesstone&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if a player is carrying a stone.&lt;br /&gt;
|-&lt;br /&gt;
| carriesvase&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if a player is carrying a vase.&lt;br /&gt;
|-&lt;br /&gt;
| downloadfile&lt;br /&gt;
| string (read only)&lt;br /&gt;
| Name of the file currently being downloaded&lt;br /&gt;
|-&lt;br /&gt;
| downloadpos&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| Amount of download file already downloaded&lt;br /&gt;
|-&lt;br /&gt;
| downloadsize&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| Size of the file being downloaded&lt;br /&gt;
|-&lt;br /&gt;
| editingmission&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| emoticonchar&lt;br /&gt;
| string (read only)&lt;br /&gt;
| The letter of the emoticon being displayed by the player&lt;br /&gt;
|-&lt;br /&gt;
| focusx&lt;br /&gt;
| float (read only)&lt;br /&gt;
| X coordinate of the center of playing screen in the level, offset -1.5&lt;br /&gt;
|-&lt;br /&gt;
| focusy&lt;br /&gt;
| float (read only)&lt;br /&gt;
| Y coordinate of the center of playing screen in the level, offset -2&lt;br /&gt;
|-&lt;br /&gt;
| graalversion&lt;br /&gt;
| float (read only)&lt;br /&gt;
| Graal version&lt;br /&gt;
|-&lt;br /&gt;
| gravity&lt;br /&gt;
| float&lt;br /&gt;
| Downward acceleration for projectiles ejected with the shoot() function.&lt;br /&gt;
|-&lt;br /&gt;
| iscarrying&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the player is carrying anything&lt;br /&gt;
|-&lt;br /&gt;
| isfocused&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| isgraal3d&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if you are running graal 3D&lt;br /&gt;
|-&lt;br /&gt;
| isleader&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| signifies that the player is the first person in the level&lt;br /&gt;
|-&lt;br /&gt;
| isonmap&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| signifies that the player is on a map&lt;br /&gt;
|-&lt;br /&gt;
| jpegquality&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| lastdownloadfile&lt;br /&gt;
| string (read only)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| leftmousebutton&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the left mouse button is down&lt;br /&gt;
|-&lt;br /&gt;
| levelorgx&lt;br /&gt;
| float (read only)&lt;br /&gt;
| The x-value of the levels' origin (may deviate with attachplayertoobj)&lt;br /&gt;
|-&lt;br /&gt;
| levelorgy&lt;br /&gt;
| float (read only)&lt;br /&gt;
| The y-value of the levels' origin (may deviate with attachplayertoobj)&lt;br /&gt;
|-&lt;br /&gt;
| lighteffectsenabled&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| signifies that the player has enabled light effects&lt;br /&gt;
|-&lt;br /&gt;
| weathereffectsenabled&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| signifies that the player has enabled weather effects&lt;br /&gt;
|-&lt;br /&gt;
| particleeffectsenabled&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| signifies that the player has enabled particle effects&lt;br /&gt;
|-&lt;br /&gt;
| middlemousebutton&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the middle mouse button is down&lt;br /&gt;
|-&lt;br /&gt;
| mousebuttons&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| Counts the amount of mousebuttons pressed&lt;br /&gt;
|-&lt;br /&gt;
| mousescreenx&lt;br /&gt;
| integer&lt;br /&gt;
| X coordinate of the mouse on the GUI layer&lt;br /&gt;
|-&lt;br /&gt;
| mousescreeny&lt;br /&gt;
| integer&lt;br /&gt;
| Y coordinate of the mouse on the GUI layer&lt;br /&gt;
|-&lt;br /&gt;
| mousewheeldelta&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| Amount that the mouse scroll wheel was scrolled [(-) is up, (+) is down]&lt;br /&gt;
|-&lt;br /&gt;
| mousex&lt;br /&gt;
| float&lt;br /&gt;
| X coordinate of the mouse on the tile layer&lt;br /&gt;
|-&lt;br /&gt;
| mousey&lt;br /&gt;
| float&lt;br /&gt;
| Y coordinate of the mouse on the tile layer&lt;br /&gt;
|-&lt;br /&gt;
| musiclen&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| The duration of the playing sound file&lt;br /&gt;
|-&lt;br /&gt;
| musicpos&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| The position in the file at which the sound file is&lt;br /&gt;
|-&lt;br /&gt;
| rightmousebutton&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the right mouse button is down&lt;br /&gt;
|-&lt;br /&gt;
| screenheight&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| Height of the Graal window&lt;br /&gt;
|-&lt;br /&gt;
| screenwidth&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| Width of the Graal window&lt;br /&gt;
|-&lt;br /&gt;
| scriptedcontrols&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| scriptedplayerlist&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| selectedlistplayers&lt;br /&gt;
| object&lt;br /&gt;
| an array of players highlighted on the playerlist&lt;br /&gt;
|-&lt;br /&gt;
| selectedsword&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| selectedweapon&lt;br /&gt;
| integer&lt;br /&gt;
| Index of player.weapons that references the player's current weapon&lt;br /&gt;
|-&lt;br /&gt;
| servername&lt;br /&gt;
| string (read only)&lt;br /&gt;
| Name of the current server&lt;br /&gt;
|-&lt;br /&gt;
| serverstartconnect&lt;br /&gt;
| string&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| serverstartparams&lt;br /&gt;
| string&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| shotbybaddy&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the player was shot by a baddy&lt;br /&gt;
|-&lt;br /&gt;
| shotbyplayer&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
| True if the player was shot by another player&lt;br /&gt;
|-&lt;br /&gt;
| showterraingrid&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| timevar&lt;br /&gt;
| integer (read only)&lt;br /&gt;
| A timer which is increased each 5 seconds and is snychronized between server and clients; The timer started exactly on 2001-02-01 at 18:33:34 Paris time (opening of Graal2001); on serverside the unixtime (timevar2) is around 981048814 + timevar*5&lt;br /&gt;
|-&lt;br /&gt;
| timevar2&lt;br /&gt;
| float (read only)&lt;br /&gt;
| Unix-time with a very high precision, not synchronized between server and client&lt;br /&gt;
|-&lt;br /&gt;
| timevar3 &lt;br /&gt;
| float (read only)&lt;br /&gt;
| synchronized time which works on both server- and client-side, precision is milliseconds, only available for Graal3D right now&lt;br /&gt;
|-&lt;br /&gt;
| wasshooted&lt;br /&gt;
| boolean (read only)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| waterheight&lt;br /&gt;
| float&lt;br /&gt;
| The height of water at the player's (x,y) on a terrain&lt;br /&gt;
|-&lt;br /&gt;
| weapons&lt;br /&gt;
| object (read only)&lt;br /&gt;
| An array of weapon objects&lt;br /&gt;
|-&lt;br /&gt;
| weaponsenabled&lt;br /&gt;
| boolean&lt;br /&gt;
| Are weapons enabled? (Player can trigger onWeaponFired...)&lt;br /&gt;
|-&lt;br /&gt;
| worldclockstopped&lt;br /&gt;
| boolean&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| worldhour&lt;br /&gt;
| integer&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| worldminute&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| worldminutesofday&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| worldrealsecondsperday&lt;br /&gt;
| float&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Variable Prefixes==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot;&lt;br /&gt;
| '''Prefix'''&lt;br /&gt;
| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| object.var&lt;br /&gt;
| accesses the variables of the object. The object can be retrieved by using the case-sensitive name of the object or a variable pointing to the object.&lt;br /&gt;
|-&lt;br /&gt;
| this.var&lt;br /&gt;
| variables that belong to the current script object, on the server-side they are saved to file when the object is a database npc&lt;br /&gt;
|-&lt;br /&gt;
| thiso.var&lt;br /&gt;
| refer to the this. variables of the executing npc ('o' stands for original) when you use the with () command: with (findnpc(&amp;quot;npc2&amp;quot;)) thiso.temp = this.temp; will copy 'this.temp' from npc2 to the current npc&lt;br /&gt;
|-&lt;br /&gt;
| temp.var&lt;br /&gt;
| variables that belong to the current function. They can be used anywhere in the function even when referencing another object. Function parameters are declared as temp variables if they do not have a prefix. Temp variables will be destroyed at the end of the function.&lt;br /&gt;
|-&lt;br /&gt;
| player.var&lt;br /&gt;
| variables of the current player object, when the event was invoked by a player (e.g. playertouchsme), or you do with (findplayer(accountname))&lt;br /&gt;
|-&lt;br /&gt;
| playero.var&lt;br /&gt;
| variables of the original player object, in generally the player who has invoked the event (e.g. playertouchsme)&lt;br /&gt;
|-&lt;br /&gt;
| client.var&lt;br /&gt;
| short for player.client.var, variables that can be changed on server-side and client-side&lt;br /&gt;
|-&lt;br /&gt;
| clientr.var&lt;br /&gt;
| short for player.clientr.var, variables that can only be changed on server-side but can be read on client-side&lt;br /&gt;
|-&lt;br /&gt;
| server.var&lt;br /&gt;
| variables that only exists on server-side and can be accessed by all npcs&lt;br /&gt;
|-&lt;br /&gt;
| serverr.var&lt;br /&gt;
| variables that can only be changed on server-side and is server wide, but can also be read by all clients, so it can be used for storing the state of global activities that need client-side actions like displaying weather; like server. vars they can also be changed with remotecontrol.exe by administrators that have the right to change server. variables&lt;br /&gt;
|-&lt;br /&gt;
| level.var&lt;br /&gt;
| variables of the current level, which is the level the executing npc stands in (on server-side) or the player is in (on client-side)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
''Note: Currently this doesn't list the functions which are optimized at compile time, see [[Creation/Dev/Script/Starting_Guide#Standard_functions|Starting Guide: Standard functions]] for those.''&lt;br /&gt;
&lt;br /&gt;
===Common===&lt;br /&gt;
* aindexof(float, array) - returns integer, better use array.index(float) instead&lt;br /&gt;
* echo(str text) - prints text in the F2 window (clientside) or RC chat (serverside)&lt;br /&gt;
* getbasepackage() - returns [[Creation/Dev/Script/Client/TUpdatePackage|TUpdatePackage]] object&lt;br /&gt;
* getdownloadedupdatepackagesize() - returns integer&lt;br /&gt;
* getdownloadingpackage() - returns [[Creation/Dev/Script/Client/TUpdatePackage|TUpdatePackage]] object&lt;br /&gt;
* getdownloadingpackagescount() - returns integer&lt;br /&gt;
* gethttprequest(str, int, str) - returns [[Creation/Dev/Script/Client/THTTPRequest|THTTPRequest]] object&lt;br /&gt;
* getkeycode(str keyname) - returns integer&lt;br /&gt;
* getpackagesdownloadcomplete() - returns boolean&lt;br /&gt;
* getpackagesdownloaded() - returns boolean&lt;br /&gt;
* getplatform() - returns string&lt;br /&gt;
* getservername() - returns string&lt;br /&gt;
* gettotalupdatepackagesize() - returns integer&lt;br /&gt;
* getupdatepackage(str) - returns object&lt;br /&gt;
* isadminguild(str guildname) - returns boolean&lt;br /&gt;
* isobject(str objectname) - returns boolean, checks if an object is existing&lt;br /&gt;
* keydown(int keynumber) - returns if the specified key is pressed (0..10: up, left, down, right, S, A, D, M, tab, Q, P)&lt;br /&gt;
* keydown2(int keycode, bool ignorecase) - returns boolean&lt;br /&gt;
* keyname(int keycode) - returns string&lt;br /&gt;
* opengraalurl(str url) - opens a website of www.graalonline.com and automatically lets the player login to it (e.g. for the upgrade page or screenshot section)&lt;br /&gt;
* openurl(str url)&lt;br /&gt;
* openurl2(str url, int width, int height) - deprecated, width and height are ignored&lt;br /&gt;
* requesthttp(str, int, str) - returns [[Creation/Dev/Script/Client/THTTPRequest|THTTPRequest]] object&lt;br /&gt;
* requesttext(str type, str option)&lt;br /&gt;
* requesturl(str url) - returns [[Creation/Dev/Script/Client/THTTPRequest|THTTPRequest]] object&lt;br /&gt;
* savelog(str text)&lt;br /&gt;
* savelog2(str filename, str text) - adds a log entry to &amp;quot;logs/filename&amp;quot;&lt;br /&gt;
* sendrpgmessage(str text) - adds text to the F2 window&lt;br /&gt;
* sendtext(str type, str option, params...)&lt;br /&gt;
* sendtorc(str text) - serverside only, displays text on the RC chat&lt;br /&gt;
* serverwarp(str servername) - the name can either be the internal name (graal2002) or part of the server name on the serverlist&lt;br /&gt;
&lt;br /&gt;
====Files====&lt;br /&gt;
* extractfilebase(str filepath) - returns string, '/an/example/path/and/file' would return '/an/example/path/and/'&lt;br /&gt;
* extractfileext(str filepath) - returns string, 'filename.ext' would return '.ext'&lt;br /&gt;
* extractfilename(str filepath) - returns string, '/an/example/path/and/file' would return 'file'&lt;br /&gt;
* extractfilepath(str filepath) - returns string, '/an/example/path/and/file' would return '/an/example/path/and/'&lt;br /&gt;
* fileexists(str filepath) - returns boolean, checks if a file exists&lt;br /&gt;
* filesize(str filepath) - returns integer, returns the size of a file&lt;br /&gt;
* fileupdate(str filepath) - returns boolean, checks if a file is existing and requests an update from the server if it has not been checked yet&lt;br /&gt;
* findfiles(str filenamepattern, flags) - returns array of strings, flags can be either 1 for recursive search or 0 for non-recursive&lt;br /&gt;
* freefileresources(str)&lt;br /&gt;
* getextension(str filepath) - returns string, 'filename.ext' would return '.ext'&lt;br /&gt;
* requestfiledeletion(str filepath), requests a file to be deleted on the server&lt;br /&gt;
* requestfilerename(str filepath, str newfilepath), requests a file to be renamed on the server&lt;br /&gt;
* requestfilesmove(str filepath, str newfilepath), requests a file to be moved on the server&lt;br /&gt;
* selectfilefordownload(str filter)&lt;br /&gt;
* selectfileforupload()&lt;br /&gt;
&lt;br /&gt;
''Watch the [[Creation/Dev/Script/Client/TGraalVar|TGraalVar]] object for loading and saving of files (loadlines etc.)''&lt;br /&gt;
&lt;br /&gt;
''See more information about input/output at [[Creation/Dev/Output Methods|Output methods]]''&lt;br /&gt;
&lt;br /&gt;
====Math====&lt;br /&gt;
* degtorad(float value) - returns float&lt;br /&gt;
* radtodeg(float value) - returns float&lt;br /&gt;
&lt;br /&gt;
=====Matrices=====&lt;br /&gt;
GraalScript [[Matrix|matricies]] are arrays of seven elements: three describing translation (position), three describing the rotation axis, and one describing the angle.&lt;br /&gt;
* [[Matrix#matrixcreate()|matrixcreate]](str vector, str rotation) - returns matrix string&lt;br /&gt;
* matrixcreatefromeuler(str eulerrotation) - returns matrix string&lt;br /&gt;
* matrixmulpoint(str, str) - returns string&lt;br /&gt;
* matrixmultiply(str matrix, str matrix) - returns matrix string&lt;br /&gt;
* matrixmulvector(str matrix, str vector) - returns vector string&lt;br /&gt;
&lt;br /&gt;
=====Vectors=====&lt;br /&gt;
Each [[Vectors|vector]] is basicly an array of format {x,y,z} but is passed as string for simplicity. Click on the function names to see more information about the vector operations.&lt;br /&gt;
* [[Vectors#Vector_Addition|vectoradd]](vector, vector) - returns vector&lt;br /&gt;
* [[Cross Product|vectorcross]](vector, vector) - returns vector&lt;br /&gt;
* [[Vectors#Distance_Between_Terminal_Points|vectordist]](vector, vector) - returns float&lt;br /&gt;
* [[Dot Product|vectordot]](vector, vector) - returns float&lt;br /&gt;
* [[Vectors#Vector_Length_.28Magnitude.29|vectorlen]](vector) - returns float&lt;br /&gt;
* [[Vectors#Unit_Length|vectornormalize]](vector) - returns vector, scales the vector to length 1&lt;br /&gt;
* vectororthobasis(vector) - returns vector&lt;br /&gt;
* [[Vectors#Vector-Scalar_Multiplication|vectorscale]](vector, float) - returns vector&lt;br /&gt;
* [[Vectors#Vector_Subtraction|vectorsub]](vector, vector) - returns vector&lt;br /&gt;
&lt;br /&gt;
====Strings====&lt;br /&gt;
* base64decode(str text) - returns decoded string&lt;br /&gt;
* base64encode(str text) - returns encoded string&lt;br /&gt;
* checksum(str text) - returns checksum float&lt;br /&gt;
* contains(str haystack, str needle) - returns boolean, you should probably do haystack.contains(needle) instead&lt;br /&gt;
* getascii(str character) - returns ascii value integer&lt;br /&gt;
* getstringkeys(str leading) - searchs for variables which start with the specified string and returns and array of their ending&lt;br /&gt;
* lowercase(str text) - returns lowercased string, it is recommended to use string.lower() though&lt;br /&gt;
* md5(str text) - returns md5 hash string&lt;br /&gt;
* randomstring(array of strings) - returns string&lt;br /&gt;
* strcmp(str text1, str text2) - returns integer&lt;br /&gt;
* strequals(str text1, str text2) - returns boolean, you probably should do text1.equals(text2) instead&lt;br /&gt;
* uppercase(str text) - returns uppercased string, it is recommended to use string.upper() though&lt;br /&gt;
&lt;br /&gt;
===GUI===&lt;br /&gt;
* addcontrol(obj) - adds a GUI control or a 3D-object to the scene&lt;br /&gt;
* cursoroff()&lt;br /&gt;
* cursoron()&lt;br /&gt;
* iscursoron() - returns boolean&lt;br /&gt;
* popdialog() - removes the top dialog control&lt;br /&gt;
* pushdialog(obj) - displays a control on top of all other controls, this control gains all focus until it is removed again&lt;br /&gt;
* setcontentcontrol(obj) - replaces the current content control (usually named GUIContainer) with another one&lt;br /&gt;
&lt;br /&gt;
===Graal 2D===&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot;&lt;br /&gt;
| '''Name'''&lt;br /&gt;
| '''Type'''&lt;br /&gt;
| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| addtiledef(str tilesetimage, str prefix, int tilesettype)&lt;br /&gt;
|&lt;br /&gt;
| Sets the tileset image for levels beginning with the specified prefix.&lt;br /&gt;
Tileset type 0 is for pics1.png style tilesets.&lt;br /&gt;
Tileset type 1 is for the new tileset format (Era's tiles for example)&lt;br /&gt;
|-&lt;br /&gt;
| addtiledef2(str tilesetimage, str prefix, int x, int y)&lt;br /&gt;
|&lt;br /&gt;
| Replaces a section of the tileset (x, y) image for levels beginning with the specified prefix.&lt;br /&gt;
|-&lt;br /&gt;
| attachplayertoobj(int objtype, int id)&lt;br /&gt;
|&lt;br /&gt;
| Attaches a player to the specified object. Using attachpayertoobj(0, id); the player will be attached to the current NPC.&lt;br /&gt;
|-&lt;br /&gt;
| callnpc(int npcindex, params...)&lt;br /&gt;
|&lt;br /&gt;
| Invokes an event on an npc, better use npcs[npcindex].trigger(event, params) instead; you can only trigger objects this way that are on your side of clientside/serverside&lt;br /&gt;
|-&lt;br /&gt;
| callweapon(int weaponindex, params...)&lt;br /&gt;
|&lt;br /&gt;
| Invokes a trigger on a weapon, better use weapons[weaponindex].trigger(event, params) instead&lt;br /&gt;
|-&lt;br /&gt;
| detachplayer()&lt;br /&gt;
|&lt;br /&gt;
| Puts the player back on the level (after using attachplayertoobj).&lt;br /&gt;
|-&lt;br /&gt;
| disabledefmovement()&lt;br /&gt;
|&lt;br /&gt;
| Disables the default movement.&lt;br /&gt;
|-&lt;br /&gt;
| disablemap()&lt;br /&gt;
|&lt;br /&gt;
| Disables the default map&lt;br /&gt;
|-&lt;br /&gt;
| disablepause()&lt;br /&gt;
|&lt;br /&gt;
| Disables pausing.&lt;br /&gt;
|-&lt;br /&gt;
| disableselectweapons()&lt;br /&gt;
|&lt;br /&gt;
| Disables the default Q menu.&lt;br /&gt;
|-&lt;br /&gt;
| disableweapons()&lt;br /&gt;
|&lt;br /&gt;
| Disables weapons.&lt;br /&gt;
|-&lt;br /&gt;
| enabledefmovement()&lt;br /&gt;
|&lt;br /&gt;
| Enables default movement&lt;br /&gt;
|-&lt;br /&gt;
| enablefeatures(int flags)&lt;br /&gt;
| &lt;br /&gt;
| Enable/disable client features&lt;br /&gt;
&lt;br /&gt;
Flags can consist of:&lt;br /&gt;
  {| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot;&lt;br /&gt;
  | '''Value'''&lt;br /&gt;
  | '''Description'''&lt;br /&gt;
  |-&lt;br /&gt;
  | 1&lt;br /&gt;
  | M key (map)&lt;br /&gt;
  |-&lt;br /&gt;
  | 2&lt;br /&gt;
  | P key (pause)&lt;br /&gt;
  |-&lt;br /&gt;
  | 4&lt;br /&gt;
  | Q key (weapon select)&lt;br /&gt;
  |-&lt;br /&gt;
  | 8&lt;br /&gt;
  | R key (show ratings)&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x10&lt;br /&gt;
  | S+A key combination for dropping items&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x20&lt;br /&gt;
  | S+D key combination for switching weapons&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x40&lt;br /&gt;
  | TAB key (if disabled then you cannot switch to the chat field with TAB)&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x80&lt;br /&gt;
  | Display of chat text&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x100&lt;br /&gt;
  | Display of the hearts over player heads&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x200&lt;br /&gt;
  | Display of nicknames&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x400&lt;br /&gt;
  | Toall/PM-icons on the minimap&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x800&lt;br /&gt;
  | Right-click on players opens their profile&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x1000&lt;br /&gt;
  | Emoticons (disable it if you want to do other stuff with control+keys)&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x2000&lt;br /&gt;
  | Alt+5 for making snapshots  ''(deprecated)''&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x4000&lt;br /&gt;
  | Alt+8/9 for zooming ''(deprecated)''&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x8000&lt;br /&gt;
  | Allows F2 output (savelog()/echo())&lt;br /&gt;
  |-&lt;br /&gt;
  | allfeatures&lt;br /&gt;
  | All of the previously stated feature flags enabled&lt;br /&gt;
  |}&lt;br /&gt;
|-&lt;br /&gt;
| enablemap()&lt;br /&gt;
|&lt;br /&gt;
| Enables default map.&lt;br /&gt;
|-&lt;br /&gt;
| enablepause()&lt;br /&gt;
|&lt;br /&gt;
| Enables pausing.&lt;br /&gt;
|-&lt;br /&gt;
| enableselectweapons()&lt;br /&gt;
|&lt;br /&gt;
| Enables default Q menu.&lt;br /&gt;
|-&lt;br /&gt;
| enableweapons()&lt;br /&gt;
|&lt;br /&gt;
| Enables weapons.&lt;br /&gt;
|-&lt;br /&gt;
| explodebomb(int bombindex)&lt;br /&gt;
|&lt;br /&gt;
| Explodes a bomb with the specified index.&lt;br /&gt;
|-&lt;br /&gt;
| findani(str)&lt;br /&gt;
| [[Creation/Dev/Script/Client/TGraalAni|TGraalAni]] object&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| findlevel(str levelfilename)&lt;br /&gt;
| [[Creation/Dev/Script/Client/TServerLevel|TServerLevel]] object&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| findplayer(str accountname)&lt;br /&gt;
| [[Creation/Dev/Script/Client/TServerPlayer|TServerPlayer]] object&lt;br /&gt;
| Returns player object of Account specified. Player must be online.&lt;br /&gt;
|-&lt;br /&gt;
| findplayerbyid(int playerid)&lt;br /&gt;
| [[Creation/Dev/Script/Client/TServerPlayer|TServerPlayer]] object&lt;br /&gt;
| Returns player object of id specified. If id isn't available, returns false.&lt;br /&gt;
|-&lt;br /&gt;
| findweapon(str weaponname)&lt;br /&gt;
| [[Creation/Dev/Script/Client/TServerWeapon|TServerWeapon]] object&lt;br /&gt;
| Returns weapon object of the specified name if the player has that weapon.&lt;br /&gt;
|-&lt;br /&gt;
| findweaponnpc(str weaponname)&lt;br /&gt;
| [[Creation/Dev/Script/Client/TServerWeapon|TServerWeapon]] object&lt;br /&gt;
| Returns weapon object if it exits on the server, only works on server-side. You can normally also access weapons by just typing their name though (e.g. MyWeapon.functionname() instead of findweaponnpc(&amp;quot;MyWeapon&amp;quot;).functionname())&lt;br /&gt;
|-&lt;br /&gt;
| freezeplayer(float seconds)&lt;br /&gt;
|&lt;br /&gt;
| Freezes player for a specific amount of time.&lt;br /&gt;
|-&lt;br /&gt;
| getimgheight(str imagefilename)&lt;br /&gt;
| integer&lt;br /&gt;
| Returns the height (in pixels) of an image.&lt;br /&gt;
|-&lt;br /&gt;
| getimgwidth(str imagefilename)&lt;br /&gt;
| integer&lt;br /&gt;
| Returns the width (in pixels) of an image.&lt;br /&gt;
|-&lt;br /&gt;
| getmapx(str levelname)&lt;br /&gt;
| integer&lt;br /&gt;
| X coordinate of the level on a map (top-left level is 0)&lt;br /&gt;
|-&lt;br /&gt;
| getmapy(str levelname)&lt;br /&gt;
| integer&lt;br /&gt;
| Y coordinate of the level on a map (top-left level is 0)&lt;br /&gt;
|-&lt;br /&gt;
| gettextheight(float, str, str)&lt;br /&gt;
| integer&lt;br /&gt;
| Returns the height of the font. Format:&lt;br /&gt;
  gettextheight(zoom, font, style)&lt;br /&gt;
|-&lt;br /&gt;
| gettextwidth(float, str, str, str)&lt;br /&gt;
| integer&lt;br /&gt;
| Returns the width of a specified text in a certain font. Format:&lt;br /&gt;
  gettextwidth(zoom, font, style, text)&lt;br /&gt;
|-&lt;br /&gt;
| getz(float x, float y)&lt;br /&gt;
| float&lt;br /&gt;
| Returns the z value of a terrain at (x,y).&lt;br /&gt;
|-&lt;br /&gt;
| graalcontrolhasfocus(bool) &lt;br /&gt;
| boolean &lt;br /&gt;
| parameter says if it should also check if the chat bar has the focus&lt;br /&gt;
|-&lt;br /&gt;
| hideplayer(float seconds)&lt;br /&gt;
|&lt;br /&gt;
| Hides the player for ''seconds'' seconds.&lt;br /&gt;
|-&lt;br /&gt;
| hidesword(float seconds)&lt;br /&gt;
|&lt;br /&gt;
| Hides the player's sword for ''seconds'' seconds.&lt;br /&gt;
|-&lt;br /&gt;
| hitnpc(int, float, float, float)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| hitobjects(float, float, float)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| hitplayer(int, float, float, float)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| lay2(str extraname, float x, float y)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| loadmap(str mapfilename)&lt;br /&gt;
|&lt;br /&gt;
| Preloads a gmap on clientside, speeds up entering of new maps but is not required.&lt;br /&gt;
|-&lt;br /&gt;
| noplayerkilling()&lt;br /&gt;
|&lt;br /&gt;
| Disables killing of other players. This also lets players walk through other players (players are not blocking anymore).&lt;br /&gt;
|-&lt;br /&gt;
| onwall(float x, float y)&lt;br /&gt;
| boolean&lt;br /&gt;
| Returns true if the specified x and y is a blocking tile.&lt;br /&gt;
|-&lt;br /&gt;
| onwall2(float x, float y, float width, float height)&lt;br /&gt;
| boolean&lt;br /&gt;
| Returns true if a blocking tile exists in the specified area.&lt;br /&gt;
|-&lt;br /&gt;
| onwater(float x, float y)&lt;br /&gt;
| boolean&lt;br /&gt;
| Returns true if the specified x and y is water.&lt;br /&gt;
|-&lt;br /&gt;
| onwater2(float x, float y, float width, float height)&lt;br /&gt;
| boolean&lt;br /&gt;
| Returns true if water exists in the specified area.&lt;br /&gt;
|-&lt;br /&gt;
| play(str soundfilename)&lt;br /&gt;
|&lt;br /&gt;
| Plays the specified sound file.&lt;br /&gt;
|-&lt;br /&gt;
| play2(str soundfilename, float x, float y, float volume)&lt;br /&gt;
|&lt;br /&gt;
| Plays the specified sound file at location x, y with the specified volume. Volume should be between 0 and 1, if volume is set to 1 default volume is used (depending on how far away the player is).&lt;br /&gt;
|-&lt;br /&gt;
| playlooped(str soundfilename)&lt;br /&gt;
|&lt;br /&gt;
| Plays the specified sound file in a loop until stopsound() is called.&lt;br /&gt;
|-&lt;br /&gt;
| playlooped2(str soundfile, float x, float y, float volume)&lt;br /&gt;
|&lt;br /&gt;
| Plays the specified sound file at location x, y with the specified volume in a loop until stopsound() is called. Volume should be between 0 and 1, if volume is set to 1 default volume is used (depending on how far away the player is).&lt;br /&gt;
|-&lt;br /&gt;
| putleaps(int leapstype, float x, float y)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| removetiledefs(str prefix)&lt;br /&gt;
|&lt;br /&gt;
| Remove tile definitions set by addtiledef and addtiledef2 for the specified prefix.&lt;br /&gt;
|-&lt;br /&gt;
| replaceani(str defaultaniname, str newaniname)&lt;br /&gt;
|&lt;br /&gt;
| replaces the player's default ani with the new ani.&lt;br /&gt;
|-&lt;br /&gt;
| resetfocus()&lt;br /&gt;
|&lt;br /&gt;
| Sets the screen focus to the player (default focus behaviour).&lt;br /&gt;
|-&lt;br /&gt;
| say(int signindex)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| say2(str text)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| screenx(float x, float y)&lt;br /&gt;
| integer&lt;br /&gt;
| returns the x of the screen layer for a location on the tiles layer.&lt;br /&gt;
|-&lt;br /&gt;
| screeny(float x, float y)&lt;br /&gt;
| integer&lt;br /&gt;
| returns the y of the screen layer for a location on the tiles layer.&lt;br /&gt;
|-&lt;br /&gt;
| worldx(float x, float y)&lt;br /&gt;
| float&lt;br /&gt;
| returns the x of the tiles layer for a location on the screen layer.&lt;br /&gt;
|-&lt;br /&gt;
| worldy(float x, float y)&lt;br /&gt;
| float&lt;br /&gt;
| returns the y of the tiles layer for a location on the screen layer.&lt;br /&gt;
|-&lt;br /&gt;
| setani(str aniname, str aniparams)&lt;br /&gt;
|&lt;br /&gt;
| Sets the gani of a player.&lt;br /&gt;
|-&lt;br /&gt;
| setbeltcolor(str color)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setcoatcolor(str color)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| seteffect(float red, float green, float blue, float alpha)&lt;br /&gt;
|&lt;br /&gt;
| Displays a 'day-night' effect on top of the game. Default value is (0,0,0,0). Change alpha to make the screen darker. You can reach the same effect if you use a polygon (showpoly()) and set the mode to 3. To manipulate the color of a single npc, see setcoloreffect() for [[Creation/Dev/Script/Client/TServerNPC|TServerNPC]].&lt;br /&gt;
|-&lt;br /&gt;
| setfocus(float x, float y)&lt;br /&gt;
|&lt;br /&gt;
| Sets the screen focus to the specified x and y. Use resetfocus() to switch back to the default focus behaviour.&lt;br /&gt;
|-&lt;br /&gt;
| setgender(str gendername)&lt;br /&gt;
|&lt;br /&gt;
| Sets the gender of a player.&lt;br /&gt;
|-&lt;br /&gt;
| sethead(str imagefilename)&lt;br /&gt;
|&lt;br /&gt;
| Sets the head of a player&lt;br /&gt;
|-&lt;br /&gt;
| setletters(str imagefilename)&lt;br /&gt;
|&lt;br /&gt;
| Sets the image to use for sign background and text.&lt;br /&gt;
|-&lt;br /&gt;
| setmap(str, str, float, float)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setminimap(str, str, float, float)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setmusicvolume(float, float)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setplayerdir(str)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setshield(str imagefilename, int shieldpower)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setshoecolor(str color)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setshootparams(str params)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setskincolor(str color)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setsleevecolor(str color)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| setsword(str imagefilename, int swordpower)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| showstats(int statsflag)&lt;br /&gt;
|&lt;br /&gt;
| With this you can show/hide parts of the status bar / game&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Shows all&lt;br /&gt;
showstats(allstats);&lt;br /&gt;
&lt;br /&gt;
// Enable everything except minimap&lt;br /&gt;
showstats(allstats &amp;amp; ~0x100);&lt;br /&gt;
&lt;br /&gt;
// Enable everything except AP and MP bars&lt;br /&gt;
showstats(allstats &amp;amp; ~(0x40 | 0x80));&lt;br /&gt;
&lt;br /&gt;
// Enable only players and right-click profile&lt;br /&gt;
showstats(0x400 | 0x800);&lt;br /&gt;
&lt;br /&gt;
// Hides all&lt;br /&gt;
showstats(0);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Flags can consist of:&lt;br /&gt;
  {| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot;&lt;br /&gt;
  | '''Value'''&lt;br /&gt;
  | '''Description'''&lt;br /&gt;
  |-&lt;br /&gt;
  | 1&lt;br /&gt;
  | ASD&lt;br /&gt;
  |-&lt;br /&gt;
  | 2&lt;br /&gt;
  | Icons (for rupees, bombs, arrows)&lt;br /&gt;
  |-&lt;br /&gt;
  | 4&lt;br /&gt;
  | Rupees count&lt;br /&gt;
  |-&lt;br /&gt;
  | 8&lt;br /&gt;
  | Bombs count&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x10&lt;br /&gt;
  | Arrows count&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x20&lt;br /&gt;
  | Hearts&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x40&lt;br /&gt;
  | Alignment (ap) bar&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x80&lt;br /&gt;
  | Magic points (mp) bar&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x100&lt;br /&gt;
  | Minimap (you can only hide it, you can't show it when the player pressed Alt+3)&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x200&lt;br /&gt;
  | Inventory NPCs&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x400&lt;br /&gt;
  | Players&lt;br /&gt;
  |-&lt;br /&gt;
  | 0x800&lt;br /&gt;
  | Right-click on players opens their profile&lt;br /&gt;
  |-&lt;br /&gt;
  | allstats&lt;br /&gt;
  | All of the previously stated stats flags enabled&lt;br /&gt;
  |}&lt;br /&gt;
|-&lt;br /&gt;
| spyfire(int length, int power)&lt;br /&gt;
|&lt;br /&gt;
| Shoots a line of fire in the direction of the player with the specified tile length, and fire power (1 - bomb, 2 - super bomb, 3 - jolt bomb).&lt;br /&gt;
|-&lt;br /&gt;
| stopmidi()&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| stopsound(str soundfilename)&lt;br /&gt;
|&lt;br /&gt;
| Stop playing a sound started by playlooped&lt;br /&gt;
|-&lt;br /&gt;
| takeplayercarry()&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| takeplayerhorse()&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| testplayer(float x, float y)&lt;br /&gt;
| integer&lt;br /&gt;
| checks if there is a player on that position and returns the index of the player in players[], or -1 if there is none&lt;br /&gt;
|-&lt;br /&gt;
| triggeraction(float x, float y, str eventname, params...)&lt;br /&gt;
|&lt;br /&gt;
| Invokes an &amp;quot;onActionEventname&amp;quot; event on objects at the specified position, can be used to invoke events on objects from clientside to serverside and vice versa. &lt;br /&gt;
Special eventnames are &amp;quot;serverEventname&amp;quot; which will invoke an event on the Control-NPC (onActionEventname), or &amp;quot;serverside&amp;quot; which will invoke an onActionServerSide event on the weapon script specified by the first following parameter (the fourth parameter). It is recommended to use triggerserver() for that though.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
triggeraction(30, 30, &amp;quot;explode&amp;quot;, 5);&lt;br /&gt;
triggeraction(0, 0, &amp;quot;serverchat&amp;quot;, player.chat);&lt;br /&gt;
triggeraction(0, 0, &amp;quot;serverside&amp;quot;, &amp;quot;PlasmaGun&amp;quot;, &amp;quot;activate&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| triggerserver(str objecttype, str objectname, str params)&lt;br /&gt;
|&lt;br /&gt;
| Invokes an event on a serverside object, currently objecttype can only be &amp;quot;gui&amp;quot; or &amp;quot;weapon&amp;quot; (which is the same), objectname is the name of the weapon script, the invoked event will be &amp;quot;onActionServerSide&amp;quot;.&lt;br /&gt;
On Graal3D the event will be &amp;quot;onActionParam0&amp;quot; instead.&lt;br /&gt;
For invoking events on the clientside use player.triggerclient(objecttype,objectname,params) instead.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
triggerserver(&amp;quot;weapon&amp;quot;, &amp;quot;PlasmaGun&amp;quot;, &amp;quot;activate&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| updateboard(int x, int y, int width, int height)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| updateratings(obj)&lt;br /&gt;
| object&lt;br /&gt;
| Updates an array of {rating1,ratingdeviation1, rating2,ratingdeviation2, ...}, init them at 1500 and 350.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
newratings = updateratings({winner.rating,winner.ratingd,loser.rating,loser.ratingd});&lt;br /&gt;
winner.rating = newratings[0];&lt;br /&gt;
winner.ratingd = newratings[1];&lt;br /&gt;
loser.rating = newratings[2];&lt;br /&gt;
loser.ratingd = newratings[3];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| wraptext(int fontsize, str format, str text)&lt;br /&gt;
| array of strings&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| wraptext2(int pixelwidth, float zoom, str delimiters, str text)&lt;br /&gt;
| array of strings&lt;br /&gt;
| wraps the text so that it fits in the specified number of pixels and returns an array of text lines &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Graal 3D===&lt;br /&gt;
* getboxcenter(str box) - returns string&lt;br /&gt;
* get3dobjectat(float x, float y, bool doboxcollision) - returns object - gets the 3d object at the specified screen position, third parameter says if it should do box collision&lt;br /&gt;
* get3dobjectatmouse(bool doboxcollision) - returns object - gets the 3d object at the mouse, specify if it should do box collision (true)&lt;br /&gt;
* get3dobjectbyray(str vector, str vector) - returns object&lt;br /&gt;
* lightscene() - returns boolean&lt;br /&gt;
* setfogcolors(array)&lt;br /&gt;
* setinteriorrendermode(int)&lt;br /&gt;
* setskybandcolors(array)&lt;br /&gt;
* setskybandsizes(array)&lt;br /&gt;
* setsuncolors(array)&lt;br /&gt;
* setterrainrendermode(int)&lt;br /&gt;
* synctimeofday(float hour, float minute)&lt;br /&gt;
* updateterrain()&lt;br /&gt;
* updatevisibledistance()&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* adventure_installgraal(str, bool, bool)&lt;br /&gt;
* adventure_openexternaloptions() - returns boolean&lt;br /&gt;
* adventure_openexternalpm(obj) - returns boolean&lt;br /&gt;
* adventure_openserverlist()&lt;br /&gt;
* adventure_quit()&lt;br /&gt;
* adventure_reconnect()&lt;br /&gt;
* adventure_savegraaloptions()&lt;br /&gt;
* adventure_selectpath(str) - returns object&lt;br /&gt;
* adventure_setaccountname(str)&lt;br /&gt;
* adventure_setchat(str)&lt;br /&gt;
* adventure_setnickname(str)&lt;br /&gt;
* adventure_setpassword(str)&lt;br /&gt;
* adventure_startofflinemode()&lt;br /&gt;
* adventure_updateaccountfield()&lt;br /&gt;
* adventure_updatemicroactivationlevel()&lt;br /&gt;
* adventure_updatemidivolume()&lt;br /&gt;
* adventure_updatemp3volume()&lt;br /&gt;
* adventure_updateplayermuted()&lt;br /&gt;
* adventure_updateplayerprofile(bool, str, str, int, str, str, str, str, str, str)&lt;br /&gt;
* adventure_updateradiovolume()&lt;br /&gt;
&lt;br /&gt;
''(these functions are only available to privileged scripts from the Login server)''&lt;br /&gt;
&lt;br /&gt;
==Classes / Object Types==&lt;br /&gt;
* [[Creation/Dev/Script/Client/TGraalVar|TGraalVar]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/ActionMap|ActionMap]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/DTSAniThread|DTSAniThread]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GameMovementInterpolate|GameMovementInterpolate]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GameMovementRigid|GameMovementRigid]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GameMovementList|GameMovementList]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GameShape|GameShape]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GameShape3DS|GameShape3DS]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GameShapeDIF|GameShapeDIF]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GameShapeDTS|GameShapeDTS]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GameShapeFT|GameShapeFT]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GuiControl|GuiControl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiArrayCtrl|GuiArrayCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiTextListCtrl|GuiTextListCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiTreeViewCtrl|GuiTreeViewCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiBitmapButtonCtrl|GuiBitmapButtonCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiBitmapCtrl|GuiBitmapCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiMapOverviewCtrl|GuiMapOverviewCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiButtonBaseCtrl|GuiButtonBaseCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiButtonCtrl|GuiButtonCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiCheckBoxCtrl|GuiCheckBoxCtrl]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/GuiRadioCtrl|GuiRadioCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiChunkedBitmapCtrl|GuiChunkedBitmapCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiContextMenuCtrl|GuiContextMenuCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiDrawingPanel|GuiDrawingPanel]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiFlash|GuiFlash]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiFrameSetCtrl|GuiFrameSetCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiGraal3DCtrl|GuiGraal3DCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiGraalCtrl|GuiGraalCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiMenuCtrl|GuiMenuCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiMLTextCtrl|GuiMLTextCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiMLTextEditCtrl|GuiMLTextEditCtrl]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/GuiPMEditCtrl|GuiPMEditCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiPMCtrl|GuiPMCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiPMHistoryCtrl|GuiPMHistoryCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiPlayerView|GuiPlayerView]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiProgressCtrl|GuiProgressCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiScrollCtrl|GuiScrollCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiShapeNameHud|GuiShapeNameHud]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiShowImgCtrl|GuiShowImgCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiSliderCtrl|GuiSliderCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiStretchCtrl|GuiStretchCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiTabCtrl|GuiTabCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/GuiTextCtrl|GuiTextCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiPopUpEditCtrl|GuiPopUpEditCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiPopUpMenuCtrl|GuiPopUpMenuCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiTextEditCtrl|GuiTextEditCtrl]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/GuiTextEditSliderCtrl|GuiTextEditSliderCtrl]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GuiWindowCtrl|GuiWindowCtrl]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TerrainEditor|TerrainEditor]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/WorldEditor|WorldEditor]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GuiControlProfile|GuiControlProfile]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GuiCursor|GuiCursor]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GuiTabCtrlEntry|GuiTabCtrlEntry]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GuiTextListEntry|GuiTextListEntry]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/GuiTreeViewNode|GuiTreeViewNode]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/MRandomGenerator|MRandomGenerator]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/MRandomLCG|MRandomLCG]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/MRandomR250|MRandomR250]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/SimObject|SimObject]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/SceneObject|SceneObject]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/fxSunLight|fxSunLight]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GameObject|GameObject]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/Camera|Camera]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/DynamicShapeReplicator|DynamicShapeReplicator]]&lt;br /&gt;
****** [[Creation/Dev/Script/Client/DynamicGrass|DynamicGrass]]&lt;br /&gt;
****** [[Creation/Dev/Script/Client/DynamicGrassReplicator|DynamicGrassReplicator]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/Sky|Sky]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TerrainBlock|TerrainBlock]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/twSurfaceReference|twSurfaceReference]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/WaterBlock|WaterBlock]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/SimGroup|SimGroup]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/GameConnection|GameConnection]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/Sun|Sun]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TDrawableObject|TDrawableObject]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TBaddy|TBaddy]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TLevelObject|TLevelObject]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TExplosion|TExplosion]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TGaniObject|TGaniObject]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/TProjectile|TProjectile]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/TServerHorse|TServerHorse]]&lt;br /&gt;
***** [[Creation/Dev/Script/Client/TServerPlayer|TServerPlayer]]&lt;br /&gt;
****** [[Creation/Dev/Script/Client/TPlayer|TPlayer]]&lt;br /&gt;
****** [[Creation/Dev/Script/Client/TServerNPC|TServerNPC]]&lt;br /&gt;
******* [[Creation/Dev/Script/Client/TServerWeapon|TServerWeapon]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TServerBomb|TServerBomb]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TServerCarry|TServerCarry]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TServerChest|TServerChest]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TServerExtra|TServerExtra]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TServerFlying|TServerFlying]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TServerLeap|TServerLeap]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TServerSign|TServerSign]]&lt;br /&gt;
**** [[Creation/Dev/Script/Client/TShowImg|TShowImg]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TDrawingPanel|TDrawingPanel]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/Terraformer|Terraformer]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TFrameDetail|TFrameDetail]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TGaniParam|TGaniParam]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TGraalAni|TGraalAni]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TGraalAniPart|TGraalAniPart]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TGraalAniSound|TGraalAniSound]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TGraalAniSprite|TGraalAniSprite]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TGraalAniStep|TGraalAniStep]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TGraalSpriteAttachment|TGraalSpriteAttachment]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/THTTPRequest|THTTPRequest]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TMovementRigid|TMovementRigid]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TParticle|TParticle]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TParticleEmitter|TParticleEmitter]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TParticleModifier|TParticleModifier]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TServerLevel|TServerLevel]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TServerLevelLink|TServerLevelLink]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TShapeMaterial|TShapeMaterial]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TShowImg_Values|TShowImg_Values]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TShowImg_Flash|TShowImg_Flash]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TShowImg_Gani|TShowImg_Gani]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TShowImg_Image|TShowImg_Image]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TShowImg_Shape|TShowImg_Shape]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TShowImg_Poly|TShowImg_Poly]]&lt;br /&gt;
*** [[Creation/Dev/Script/Client/TShowImg_Text|TShowImg_Text]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TStaticVar|TStaticVar]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TTilesLayer|TTilesLayer]]&lt;br /&gt;
** [[Creation/Dev/Script/Client/TUpdatePackage|TUpdatePackage]]&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Script/Starting_Guide&amp;diff=8928</id>
		<title>Creation/Dev/Script/Starting Guide</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Script/Starting_Guide&amp;diff=8928"/>
		<updated>2007-07-01T07:47:42Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
=== Why scripts ===&lt;br /&gt;
&lt;br /&gt;
Scripts bring life into objects and make it easy to &lt;br /&gt;
customize the game. Instead of just placing a stone&lt;br /&gt;
into your world, you can make it so that the stone&lt;br /&gt;
can be lifted or kicked. Instead of being limited to&lt;br /&gt;
some fixed player movement you can rescript it&lt;br /&gt;
to let the player jump, strafe and duck. To let the &lt;br /&gt;
player inspect and organize his/her items you can&lt;br /&gt;
create some dialogs and display those by script,&lt;br /&gt;
e.g. when the player presses a special key.&lt;br /&gt;
&lt;br /&gt;
In Graal the scripting is done in 'Graal Script',&lt;br /&gt;
it's looking like Java/C++, but brings some &lt;br /&gt;
additional features for making things easier&lt;br /&gt;
for game creators, while on the other hand&lt;br /&gt;
running in a sandbox and limiting access to&lt;br /&gt;
game-related stuff only.&lt;br /&gt;
&lt;br /&gt;
Graal Script is almost fully compatible to &lt;br /&gt;
the 'old' Graal script used in Graal v1.0 - 3.0,&lt;br /&gt;
and is partially compatible to Torque script. &lt;br /&gt;
&lt;br /&gt;
=== NPCs and 'weapons' ===&lt;br /&gt;
&lt;br /&gt;
There are generally two types of objects in Graal&lt;br /&gt;
which have scripts: The first type are the &lt;br /&gt;
non-player-characters (NPCs). The name 'NPC' is&lt;br /&gt;
actually used for all visible objects in the game: &lt;br /&gt;
monsters, stones, bushes, houses, ships, plants etc.&lt;br /&gt;
Scripts for npcs are most of the time containing&lt;br /&gt;
code for moving the npc or for reacting to &lt;br /&gt;
activities of the player, e.g. giving money to&lt;br /&gt;
the player when he/she grabs the npc.&lt;br /&gt;
The other type of script-holding objects are the&lt;br /&gt;
'weapons'. Those are items in the inventory of&lt;br /&gt;
the player, not necessary being weapons. Most of&lt;br /&gt;
the time they are actually just scripts which&lt;br /&gt;
control the movement of the player, display weapon&lt;br /&gt;
graphics, or display menus.&lt;br /&gt;
&lt;br /&gt;
So there are objects in the game which have &lt;br /&gt;
their own script, and players which have a set&lt;br /&gt;
of scripts in their invisible backpack.&lt;br /&gt;
&lt;br /&gt;
=== Server-side and client-side ===&lt;br /&gt;
&lt;br /&gt;
Graal is an online game, and there are differences&lt;br /&gt;
to standard scripting in offline games.&lt;br /&gt;
In offline programs you have access to everything,&lt;br /&gt;
anytime. In online games everything is divided&lt;br /&gt;
into two parts: the server-side which controls&lt;br /&gt;
most things in the game, and the client-side which&lt;br /&gt;
displays the game to the player.&lt;br /&gt;
Since the client only displays things, it is not&lt;br /&gt;
possible to cheat by hacking the client. On client-side&lt;br /&gt;
you mainly have code for displaying special effects,&lt;br /&gt;
for displaying the GUI (windows, status bars, item menus),&lt;br /&gt;
playing sound effects and music. Also the player &lt;br /&gt;
movement is done on client-side.&lt;br /&gt;
On the server-side scripts are used to do the more&lt;br /&gt;
secure parts of the game engine,&lt;br /&gt;
and things that are the same for all players -&lt;br /&gt;
npcs are added, moved, npcs interact with players,&lt;br /&gt;
the stats of the players are calculated, the&lt;br /&gt;
communication between players is handled.&lt;br /&gt;
&lt;br /&gt;
All scripts for npcs and weapons can contain&lt;br /&gt;
server-side code and client-side code. The server-side&lt;br /&gt;
code is executed directly on the server, the&lt;br /&gt;
client-side code is sent to the client when he/she&lt;br /&gt;
logins and executed separately for each player on&lt;br /&gt;
their own computer. Usually the two parts of the script&lt;br /&gt;
are divided by a line that only contains &amp;quot;//#CLIENTSIDE&amp;quot;,&lt;br /&gt;
like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Server-side part which is setting the image&lt;br /&gt;
// of the npc when it is created&lt;br /&gt;
function onCreated() {&lt;br /&gt;
  setimg(&amp;quot;door.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
&lt;br /&gt;
// Here follows the client-side part,&lt;br /&gt;
// which plays a sound effect when the player&lt;br /&gt;
// touchs the npc&lt;br /&gt;
function onPlayerTouchsme() {&lt;br /&gt;
  play(&amp;quot;chest.wav&amp;quot;);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
&lt;br /&gt;
In general scripts are made for reacting to &lt;br /&gt;
events - when the npc is created then the script&lt;br /&gt;
initializes the attributes of the npc,&lt;br /&gt;
when the player says something then the npc is&lt;br /&gt;
moving to the player, when the player grabs the&lt;br /&gt;
npc then the npc is giving the player some money etc.&lt;br /&gt;
So the script is basicly a collection of actions&lt;br /&gt;
that are done when special events are happening.&lt;br /&gt;
Events can e.g. be the &amp;quot;created&amp;quot; event when the npc&lt;br /&gt;
is created, the &amp;quot;playertouchsme&amp;quot; event when the &lt;br /&gt;
player touchs the npc, or the &amp;quot;playerchats&amp;quot; event&lt;br /&gt;
when the player says something. To write code that reacts&lt;br /&gt;
to one of those event, you define an event&lt;br /&gt;
function like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function onEVENTNAME() {&lt;br /&gt;
  // actions&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the event is happening, then Graal executes&lt;br /&gt;
that scripting function and all commands you &lt;br /&gt;
have added there.&lt;br /&gt;
Sometimes the event gives some parameters to the &lt;br /&gt;
event function, then change your function to:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function onEVENTNAME(parameter1, parameter2, ...) {&lt;br /&gt;
  // actions&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By accessing 'parameter1' etc. (you can name&lt;br /&gt;
them differently) you can react to the event more&lt;br /&gt;
exactly. &lt;br /&gt;
&lt;br /&gt;
Instead of reacting to events, the npcs and&lt;br /&gt;
weapons can also invoke new events. That way &lt;br /&gt;
you can let other npcs doing things. You also&lt;br /&gt;
need that if you want to coninuously doing things -&lt;br /&gt;
use timeout events for that.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;function onCreated() {&lt;br /&gt;
  setTimer(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function onTimeout() {&lt;br /&gt;
  // actions&lt;br /&gt;
  setTimer(1);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the onCreated event function the script is&lt;br /&gt;
setting the timer to 1 second. When that second is&lt;br /&gt;
over, then the &amp;quot;timeout&amp;quot; event is invoked on the&lt;br /&gt;
npc and the onTimeout event function is executed.&lt;br /&gt;
Because it is setting the timer to 1 second&lt;br /&gt;
again, the onTimeout event will occur again after&lt;br /&gt;
one second, and so on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Compatibility note:&lt;br /&gt;
In older Graal scripts you will also find the&lt;br /&gt;
deprecated way of receiving events:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if (EVENTNAME) {&lt;br /&gt;
  // actions&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That is an if-command outside of any brackets. If&lt;br /&gt;
Graal sees that you use such an if-command, then&lt;br /&gt;
it will execute the whole script so that the actions&lt;br /&gt;
you have written inside the if-command will be&lt;br /&gt;
executed too.&lt;br /&gt;
&lt;br /&gt;
== Basics ==&lt;br /&gt;
&lt;br /&gt;
=== Accessing variables ===&lt;br /&gt;
&lt;br /&gt;
Graal Script variables are 'variant', that means they are objects&lt;br /&gt;
that hold values of different types.&lt;br /&gt;
When you assign a value to the variable then it automatically&lt;br /&gt;
switches to the right type:&lt;br /&gt;
&lt;br /&gt;
Numeric (floating point):&lt;br /&gt;
  var = 1;&lt;br /&gt;
String (text):&lt;br /&gt;
  var = &amp;quot;hello&amp;quot;;&lt;br /&gt;
Object link:&lt;br /&gt;
  var = player;&lt;br /&gt;
Array (list of objects):&lt;br /&gt;
  var = {1,2,3};&lt;br /&gt;
&lt;br /&gt;
You can check the current type with the&lt;br /&gt;
type()-function - obj.type() returns&lt;br /&gt;
0,1,2,3 for numeric, string, object or array.&lt;br /&gt;
&lt;br /&gt;
=== Operators ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Addition                  a + b&lt;br /&gt;
Substraction              a - b&lt;br /&gt;
Mulitplication            a * b&lt;br /&gt;
Division                  a / b&lt;br /&gt;
Modulus                   a % b&lt;br /&gt;
Power                     a ^ b&lt;br /&gt;
String Concationation     a @ b&lt;br /&gt;
    with space            a SPC b&lt;br /&gt;
    with newline          a NL b&lt;br /&gt;
    with tabulator        a TAB b&lt;br /&gt;
Bool-And                  a &amp;amp;&amp;amp; b&lt;br /&gt;
Bool-Or                   a || b&lt;br /&gt;
Bool-Not                  !a&lt;br /&gt;
Negative                  -a&lt;br /&gt;
Equal                     a == b&lt;br /&gt;
Not-Equal                 a != b&lt;br /&gt;
Less                      a &amp;lt; b&lt;br /&gt;
Greater                   a &amp;gt; b&lt;br /&gt;
Less-Equal                a &amp;lt;= b,  a =&amp;lt; b&lt;br /&gt;
Greater-Equal             a &amp;gt;= b,  a =&amp;gt; b&lt;br /&gt;
In-Range                  a in &amp;lt;b,c&amp;gt;, a in |b,c&amp;gt;, a in &amp;lt;b,c|, a in |b,c|&lt;br /&gt;
In-Array                  a in {b,c,...}, {a,b,...} in {c,d,...}&lt;br /&gt;
Bitwise-Or                a | b&lt;br /&gt;
Bitwise-And               a &amp;amp; b&lt;br /&gt;
Bitwise-Shift left        a &amp;lt;&amp;lt; b&lt;br /&gt;
Bitwise-Shift right       a &amp;gt;&amp;gt; b&lt;br /&gt;
Bitwise-Invert            ~a&lt;br /&gt;
Bitwise-Xor               a xor b (operator ^ already used for power)&lt;br /&gt;
Array-Constructor         {a,b,...}&lt;br /&gt;
Empty Array               new [count], new[countdim1][countdim2]...&lt;br /&gt;
Array Member              a[index]&lt;br /&gt;
Function call             a(), a(b,c,...)&lt;br /&gt;
Object Attribute          a.b, a.(b)&lt;br /&gt;
Post Increment            a++&lt;br /&gt;
Post Decrement            a--&lt;br /&gt;
Pre Increment             ++a&lt;br /&gt;
Pre Decrement             --a&lt;br /&gt;
Old String Function       #a&lt;br /&gt;
Conditional               a? b : c&lt;br /&gt;
Assignment                a = b, a := b&lt;br /&gt;
Additive Assignment       a += b&lt;br /&gt;
Substractive Assignment   a -= b&lt;br /&gt;
Multiplicative Assignment a *= b&lt;br /&gt;
Division Assignment       a /= b&lt;br /&gt;
Modulus Assignment        a %= b&lt;br /&gt;
Power Assignment          a ^= b&lt;br /&gt;
Bitwise-Or Assignment     a |= b&lt;br /&gt;
Bitwise-And Assignment    a &amp;amp;= b&lt;br /&gt;
Shift Left Assignment     a &amp;lt;&amp;lt;= b&lt;br /&gt;
Shift Right Assignment    a &amp;gt;&amp;gt;= b&lt;br /&gt;
String Append             a @= b&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Standard object functions ===&lt;br /&gt;
&lt;br /&gt;
Here only some of the built-in functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
obj.type()  - gets the type of the var (float 0, string 1, object 2, array 3)&lt;br /&gt;
obj.length() - string length&lt;br /&gt;
obj.trim() - removes spaces from the front and back of a string&lt;br /&gt;
obj.lower() - converts a string to lower case&lt;br /&gt;
obj.upper() - converts a string to upper case&lt;br /&gt;
obj.tokenize([delimiters])&lt;br /&gt;
obj.charat(pos)&lt;br /&gt;
obj.pos(substring)&lt;br /&gt;
obj.positions(substring)&lt;br /&gt;
obj.starts(string)&lt;br /&gt;
obj.ends(string)&lt;br /&gt;
obj.substring(index[,length])&lt;br /&gt;
obj.size() - array length&lt;br /&gt;
obj.add(obj2)&lt;br /&gt;
obj.delete(index)&lt;br /&gt;
obj.remove(obj2)&lt;br /&gt;
obj.replace(index,obj2)&lt;br /&gt;
obj.insert(index,obj2)&lt;br /&gt;
obj.clear()&lt;br /&gt;
obj.subarray(index[,length])&lt;br /&gt;
obj.addarray(obj2)&lt;br /&gt;
obj.insertarray(index,obj2)&lt;br /&gt;
obj.index(obj2) - position of obj2 in the array&lt;br /&gt;
obj.indices(obj2) - positions of obj2 in the array&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also see [[Creation/Dev/Script/Client/TGraalVar|TGraalVar]] for more functions for objects.&lt;br /&gt;
&lt;br /&gt;
=== Standard functions ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
_(string) - translates a text on serverside &lt;br /&gt;
  to the language of the current player, &lt;br /&gt;
  if translations are enabled&lt;br /&gt;
abs(float)&lt;br /&gt;
arctan(float) - arcus tangens&lt;br /&gt;
char(ascii) - gets the character for an ascii code (char(65) returns 'A')&lt;br /&gt;
cos(angle) - cosinus of a radiant angle&lt;br /&gt;
exp(float)&lt;br /&gt;
float(string) - for explicitely converting a string &lt;br /&gt;
  to number (normally done automatically though&lt;br /&gt;
  when accessing a string with numeric operators)&lt;br /&gt;
format(format,parameters,...) - formats a &amp;quot;%s %d&amp;quot; string, &lt;br /&gt;
  inserts the parameters, and returns a string&lt;br /&gt;
getangle(delta x,delta y)&lt;br /&gt;
getdir(delta x,delta y) - returns 0 for up, 1 for left, &lt;br /&gt;
  2 for down, 3 for right&lt;br /&gt;
int(a) - gets the integer part of a floating point number&lt;br /&gt;
log(base,a)&lt;br /&gt;
max(a,b)&lt;br /&gt;
min(a,b)&lt;br /&gt;
printf(format,parameters,...) - same as &lt;br /&gt;
  echo(format(format,parameters,...))&lt;br /&gt;
random(rangestart,rangeend)&lt;br /&gt;
sin(angle) - sinus of a radiant angle&lt;br /&gt;
sleep(time) - suspends the current script for some time&lt;br /&gt;
vecx(direction 0..3)&lt;br /&gt;
vecy(direction 0..3)&lt;br /&gt;
waitfor(objectname,event[,timeout]) - suspends the current script&lt;br /&gt;
  and waits until an event is invoked on the specified object,&lt;br /&gt;
  returns false when the parameters are wrong or the event&lt;br /&gt;
  was not received before the timeout;&lt;br /&gt;
  only available in the latest versions of npcserver&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also see [[Creation/Dev/Script/Client#Functions|Client Functions]] for more functions.&lt;br /&gt;
&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
The events for GUI controls are listed in the description of the different object types: &lt;br /&gt;
[[Creation/Dev/Script/Client#Classes_.2F_Object_Types|Object types]]&lt;br /&gt;
&lt;br /&gt;
== Old script compatibility ==&lt;br /&gt;
&lt;br /&gt;
=== Removed functionality ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
- toinventory&lt;br /&gt;
- followplayer&lt;br /&gt;
- playersays()&lt;br /&gt;
- setbackpal&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Supported old scripting commands and their mapping to new script ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
addstring oldstring, oldstring;&lt;br /&gt;
                                list.add(string);&lt;br /&gt;
addtiledef oldstring, oldstring, float;&lt;br /&gt;
                                addtiledef(string,string,float);&lt;br /&gt;
addtiledef2 oldstring, oldstring, float, float;&lt;br /&gt;
                                addtiledef2(string,string,float,float);&lt;br /&gt;
attachplayertoobj float, float;&lt;br /&gt;
                                attachplayertoobj(float,float);&lt;br /&gt;
blockagain;&lt;br /&gt;
                                blockagain();&lt;br /&gt;
blockagainlocal;&lt;br /&gt;
                                blockagainlocal();&lt;br /&gt;
callnpc float, oldstring;&lt;br /&gt;
                                callnpc(float,string);&lt;br /&gt;
callweapon float, oldstring;&lt;br /&gt;
                                callweapon(float,string);&lt;br /&gt;
canbecarried;&lt;br /&gt;
                                canbecarried();&lt;br /&gt;
canbepulled;&lt;br /&gt;
                                canbepulled();&lt;br /&gt;
canbepushed;&lt;br /&gt;
                                canbepushed();&lt;br /&gt;
cannotbecarried;&lt;br /&gt;
                                cannotbecarried();&lt;br /&gt;
cannotbepulled;&lt;br /&gt;
                                cannotbepulled();&lt;br /&gt;
cannotbepushed;&lt;br /&gt;
                                cannotbepushed();&lt;br /&gt;
canwarp;&lt;br /&gt;
                                canwarp();&lt;br /&gt;
canwarp2;&lt;br /&gt;
                                canwarp2();&lt;br /&gt;
carryobject oldstring;&lt;br /&gt;
                                carryobject(string);&lt;br /&gt;
changeimgcolors float, float, float, float, float;&lt;br /&gt;
                                changeimgcolors(float,float,float,float,float);&lt;br /&gt;
changeimgmode float, float;&lt;br /&gt;
                                changeimgmode(float,float);&lt;br /&gt;
changeimgpart float, float, float, float, float;&lt;br /&gt;
                                changeimgpart(float,float,float,float,float);&lt;br /&gt;
changeimgvis float, float;&lt;br /&gt;
                                changeimgvis(float,float);&lt;br /&gt;
changeimgzoom float, float;&lt;br /&gt;
                                changeimgzoom(float,float);&lt;br /&gt;
deletestring oldstring, float;&lt;br /&gt;
                                deletestring(string,float);&lt;br /&gt;
destroy;&lt;br /&gt;
                                destroy();&lt;br /&gt;
detachplayer;&lt;br /&gt;
                                detachplayer();&lt;br /&gt;
disabledefmovement;&lt;br /&gt;
                                disabledefmovement();&lt;br /&gt;
disablemap;&lt;br /&gt;
                                disablemap();&lt;br /&gt;
disablepause;&lt;br /&gt;
                                disablepause();&lt;br /&gt;
disableselectweapons;&lt;br /&gt;
                                disableselectweapons();&lt;br /&gt;
disableweapons;&lt;br /&gt;
                                disableweapons();&lt;br /&gt;
dontblock;&lt;br /&gt;
                                dontblock();&lt;br /&gt;
dontblocklocal;&lt;br /&gt;
                                dontblocklocal();&lt;br /&gt;
drawaslight;&lt;br /&gt;
                                drawaslight();&lt;br /&gt;
drawoverplayer;&lt;br /&gt;
                                drawoverplayer();&lt;br /&gt;
drawunderplayer;&lt;br /&gt;
                                drawunderplayer();&lt;br /&gt;
enabledefmovement;&lt;br /&gt;
                                enabledefmovement();&lt;br /&gt;
enablefeatures float;&lt;br /&gt;
                                enablefeatures(float);&lt;br /&gt;
enablemap;&lt;br /&gt;
                                enablemap();&lt;br /&gt;
enablepause;&lt;br /&gt;
                                enablepause();&lt;br /&gt;
enableselectweapons;&lt;br /&gt;
                                enableselectweapons();&lt;br /&gt;
enableweapons;&lt;br /&gt;
                                enableweapons();&lt;br /&gt;
explodebomb float;&lt;br /&gt;
                                explodebomb(float);&lt;br /&gt;
followplayer;&lt;br /&gt;
                                followplayer();&lt;br /&gt;
freezeplayer float;&lt;br /&gt;
                                freezeplayer(float);&lt;br /&gt;
freezeplayer2;&lt;br /&gt;
                                freezeplayer2();&lt;br /&gt;
hide;&lt;br /&gt;
                                hide();&lt;br /&gt;
hideimg float;&lt;br /&gt;
                                hideimg(float);&lt;br /&gt;
hideimgs float, float;&lt;br /&gt;
                                hideimgs(float,float);&lt;br /&gt;
hidelocal;&lt;br /&gt;
                                hidelocal();&lt;br /&gt;
&lt;br /&gt;
hitcompu float, float, float, float;&lt;br /&gt;
                                hitcompu(float,float,float,float);&lt;br /&gt;
hitnpc float, float, float, float;&lt;br /&gt;
                                hitnpc(float,float,float,float);&lt;br /&gt;
hitobjects float, float, float;&lt;br /&gt;
                                hitobjects(float,float,float);&lt;br /&gt;
hideplayer float;&lt;br /&gt;
                                hideplayer(float);&lt;br /&gt;
hidesword float;&lt;br /&gt;
                                hidesword(float);&lt;br /&gt;
hitplayer float, float, float, float;&lt;br /&gt;
                                hitplayer(float,float,float,float);&lt;br /&gt;
hurt float;&lt;br /&gt;
                                hurt(float);&lt;br /&gt;
insertstring oldstring, float, oldstring;&lt;br /&gt;
                                insertstring(string,float,string);&lt;br /&gt;
join oldstring;&lt;br /&gt;
                                join(string);&lt;br /&gt;
lay oldstring;&lt;br /&gt;
                                lay(string);&lt;br /&gt;
lay2 oldstring, float, float;&lt;br /&gt;
                                lay2(string,float,float);&lt;br /&gt;
loadmap oldstring;&lt;br /&gt;
                                loadmap(string);&lt;br /&gt;
message oldstring;&lt;br /&gt;
                                message(string);&lt;br /&gt;
move float, float, float, float;&lt;br /&gt;
                                move(float,float,float,float);&lt;br /&gt;
noplayerkilling;&lt;br /&gt;
                                noplayerkilling();&lt;br /&gt;
openurl oldstring;&lt;br /&gt;
                                openurl(string);&lt;br /&gt;
openurl2 oldstring, float, float;&lt;br /&gt;
                                openurl2(string,float,float);&lt;br /&gt;
play oldstring;&lt;br /&gt;
                                play(string);&lt;br /&gt;
play2 oldstring, float, float, float;&lt;br /&gt;
                                play2(string,float,float,float);&lt;br /&gt;
playlooped oldstring;&lt;br /&gt;
                                playlooped(string);&lt;br /&gt;
putbomb float, float, float;&lt;br /&gt;
                                putbomb(float,float,float);&lt;br /&gt;
putcomp oldstring, float, float;&lt;br /&gt;
                                putcomp(string,float,float);&lt;br /&gt;
putexplosion float, float, float;&lt;br /&gt;
                                putexplosion(float,float,float);&lt;br /&gt;
putexplosion2 float, float, float, float;&lt;br /&gt;
                                putexplosion2(float,float,float,float);&lt;br /&gt;
puthorse oldstring, float, float;&lt;br /&gt;
                                puthorse(string,float,float);&lt;br /&gt;
putleaps float, float, float;&lt;br /&gt;
                                putleaps(float,float,float);&lt;br /&gt;
putnewcomp oldstring, float, float, oldstring, float;&lt;br /&gt;
                                putnewcomp(string,float,float,string,float);&lt;br /&gt;
putnpc oldstring, oldstring, float, float;&lt;br /&gt;
                                putnpc(string,string,float,float);&lt;br /&gt;
putnpc2 float, float, oldstring;&lt;br /&gt;
                                putnpc2(float,float,string);&lt;br /&gt;
reflectarrow float;&lt;br /&gt;
                                reflectarrow(float);&lt;br /&gt;
removearrow float;&lt;br /&gt;
                                removearrow(float);&lt;br /&gt;
removebomb float;&lt;br /&gt;
                                removebomb(float);&lt;br /&gt;
removecompus;&lt;br /&gt;
                                removecompus();&lt;br /&gt;
removeexplo float;&lt;br /&gt;
                                removeexplo(float);&lt;br /&gt;
removehorse float;&lt;br /&gt;
                                removehorse(float);&lt;br /&gt;
rmeoveitem float;&lt;br /&gt;
                                removeitem(float)&lt;br /&gt;
removestring oldstring, oldstring;&lt;br /&gt;
                                removestring(string,string);&lt;br /&gt;
removetiledefs oldstring;&lt;br /&gt;
                                removetiledefs(string);&lt;br /&gt;
replaceani oldstring, oldstring;&lt;br /&gt;
                                replaceani(string,string);&lt;br /&gt;
replacestring oldstring, float, oldstring;&lt;br /&gt;
                                replacestring(string,float,string);&lt;br /&gt;
resetfocus;&lt;br /&gt;
                                resetfocus();&lt;br /&gt;
savelog oldstring;&lt;br /&gt;
                                savelog(string);&lt;br /&gt;
savelog2 oldstring, oldstring;&lt;br /&gt;
                                savelog2(string,string);&lt;br /&gt;
say float;&lt;br /&gt;
                                say(float);&lt;br /&gt;
say2 oldstring;&lt;br /&gt;
                                say2(string);&lt;br /&gt;
sendrpgmessage oldstring;&lt;br /&gt;
                                sendrpgmessage(string);&lt;br /&gt;
sendpm oldstring;&lt;br /&gt;
                                sendpm(string);&lt;br /&gt;
sendtonc oldstring;&lt;br /&gt;
                                sendtonc(string);&lt;br /&gt;
sendtorc oldstring;&lt;br /&gt;
                                sendtorc(string);&lt;br /&gt;
serverwarp oldstring;&lt;br /&gt;
                                serverwarp(string);&lt;br /&gt;
set oldstring;&lt;br /&gt;
                                set(string);&lt;br /&gt;
setani oldstring, oldstring;&lt;br /&gt;
                                setani(string,string);&lt;br /&gt;
setarray float, float;&lt;br /&gt;
                                setarray(var,float);&lt;br /&gt;
setbeltcolor oldstring;&lt;br /&gt;
                                setbeltcolor(string);&lt;br /&gt;
setbow oldstring;&lt;br /&gt;
                                setbow(string);&lt;br /&gt;
setcharani oldstring, oldstring;&lt;br /&gt;
                                setcharani(string,string);&lt;br /&gt;
setchargender oldstring;&lt;br /&gt;
                                setchargender(string);&lt;br /&gt;
setcharprop oldstring, oldstring;&lt;br /&gt;
                                string = string;&lt;br /&gt;
setcoatcolor oldstring;&lt;br /&gt;
                                setcoatcolor(string);&lt;br /&gt;
setcoloreffect float, float, float, float;&lt;br /&gt;
                                setcoloreffect(float,float,float,float);&lt;br /&gt;
setcursor float;&lt;br /&gt;
                                setcursor(float);&lt;br /&gt;
setcurcor2 oldstring;&lt;br /&gt;
                                setcursor2(string);&lt;br /&gt;
seteffect float, float, float, float;&lt;br /&gt;
                                seteffect(float,float,float,float);&lt;br /&gt;
seteffectmode float;&lt;br /&gt;
                                seteffectmode(float);&lt;br /&gt;
setfocus float, float;&lt;br /&gt;
                                setfocus(float,float);&lt;br /&gt;
setgender oldstring;&lt;br /&gt;
                                setgender(string);&lt;br /&gt;
sethead oldstring;&lt;br /&gt;
                                sethead(string);&lt;br /&gt;
setlevel oldstring;&lt;br /&gt;
                                setlevel(string);&lt;br /&gt;
setlevel2 oldstring, float, float;&lt;br /&gt;
                                setlevel2(string,float,float);&lt;br /&gt;
setmap oldstring, oldstring, float, float;&lt;br /&gt;
                                setmap(string,string,float,float);&lt;br /&gt;
setminimap oldstring, oldstring, float, float;&lt;br /&gt;
                                setminimap(string,string,float,float);&lt;br /&gt;
setmusicvolume float, float;&lt;br /&gt;
                                setmusicvolume(float,float);&lt;br /&gt;
setimg oldstring;&lt;br /&gt;
                                setimg(string);&lt;br /&gt;
setimgpart oldstring, float, float, float, float;&lt;br /&gt;
                                setimgpart(string,float,float,float,float);&lt;br /&gt;
setletters oldstring;&lt;br /&gt;
                                setletters(string);&lt;br /&gt;
setplayerdir oldstring;&lt;br /&gt;
                                setplayerdir(string);&lt;br /&gt;
setplayerprop oldstring, oldstring;&lt;br /&gt;
                                string = string;&lt;br /&gt;
setpm oldstring;&lt;br /&gt;
                                setpm(string);&lt;br /&gt;
setshape float, float, float;&lt;br /&gt;
                                setshape(float,float,float);&lt;br /&gt;
setshape2 float, float, float;&lt;br /&gt;
                                setshape2(float,float,float);&lt;br /&gt;
setshield oldstring, float;&lt;br /&gt;
                                setshield(string,float);&lt;br /&gt;
setshoecolor oldstring;&lt;br /&gt;
                                setshoecolor(string);&lt;br /&gt;
setshootparams oldstring;&lt;br /&gt;
                                setshootparams(string);&lt;br /&gt;
setskincolor oldstring;&lt;br /&gt;
                                setskincolor(string);&lt;br /&gt;
setsleevecolor oldstring;&lt;br /&gt;
                                setsleevecolor(string);&lt;br /&gt;
setstring oldstring, oldstring;&lt;br /&gt;
                                setstring(string,string);&lt;br /&gt;
setsword oldstring, float;&lt;br /&gt;
                                setsword(string,float);&lt;br /&gt;
seturllevel oldstring;&lt;br /&gt;
                                seturllevel(string);&lt;br /&gt;
setz float, float, float, float, float, float, float, float;&lt;br /&gt;
                                setz(float,float,float,float,float,float,float,float);&lt;br /&gt;
setzoomeffect float;&lt;br /&gt;
                                setzoomeffect(float);&lt;br /&gt;
shoot float, float, float, float, float, float, oldstring, oldstring;&lt;br /&gt;
                                shoot(float,float,float,float,float,float,string,string);&lt;br /&gt;
shootarrow float;&lt;br /&gt;
                                shootarrow(float);&lt;br /&gt;
shootball;&lt;br /&gt;
                                shootball();&lt;br /&gt;
shootfireball float;&lt;br /&gt;
                                shootfireball(float);&lt;br /&gt;
shootfireblast float;&lt;br /&gt;
                                shootfireblast(float);&lt;br /&gt;
shootnuke float;&lt;br /&gt;
                                shootnuke(float);&lt;br /&gt;
show;&lt;br /&gt;
                                show();&lt;br /&gt;
showani float, float, float, float, oldstring;&lt;br /&gt;
                                showani(float,float,float,float,string);&lt;br /&gt;
showani2 float, float, float, float, float, oldstring;&lt;br /&gt;
                                showani2(float,float,float,float,float,string);&lt;br /&gt;
showcharacter;&lt;br /&gt;
                                showcharacter();&lt;br /&gt;
showfile oldstring;&lt;br /&gt;
                                showfile(string);&lt;br /&gt;
showimg float, oldstring, float, float;&lt;br /&gt;
                                showimg(float,string,float,float);&lt;br /&gt;
showimg2 float, oldstring, float, float, float;&lt;br /&gt;
                                showimg2(float,string,float,float,float);&lt;br /&gt;
showlocal;&lt;br /&gt;
                                showlocal();&lt;br /&gt;
&lt;br /&gt;
showpoly float, float;&lt;br /&gt;
                                showpoly(float,array);&lt;br /&gt;
showpoly2 float, float;&lt;br /&gt;
                                showpoly2(float,array);&lt;br /&gt;
showstats float;&lt;br /&gt;
                                showstats(float);&lt;br /&gt;
showtext float, float, float, oldstring, oldstring, oldstring;&lt;br /&gt;
                                showtext(float,float,float,string,string,string);&lt;br /&gt;
showtext2 float, float, float, float, oldstring, oldstring, oldstring;&lt;br /&gt;
                                showtext2(float,float,float,float,string,string,string);&lt;br /&gt;
sleep float;&lt;br /&gt;
                                sleep(float);&lt;br /&gt;
spyfire float, float;&lt;br /&gt;
                                spyfire(float,float);&lt;br /&gt;
stopmidi;&lt;br /&gt;
                                stopmidi();&lt;br /&gt;
stopsound oldstring;&lt;br /&gt;
                                stopsound(string);&lt;br /&gt;
take oldstring;&lt;br /&gt;
                                take(string);&lt;br /&gt;
take2 float;&lt;br /&gt;
                                take2(float);&lt;br /&gt;
takehorse float;&lt;br /&gt;
                                takehorse(float);&lt;br /&gt;
takeplayercarry;&lt;br /&gt;
                                takeplayercarry();&lt;br /&gt;
takeplayerhorse;&lt;br /&gt;
                                takeplayerhorse();&lt;br /&gt;
throwcarry;&lt;br /&gt;
                                throwcarry();&lt;br /&gt;
timereverywhere;&lt;br /&gt;
                                timereverywhere();&lt;br /&gt;
timershow;&lt;br /&gt;
                                timershow();&lt;br /&gt;
toinventory oldstring;&lt;br /&gt;
                                toinventory(string);&lt;br /&gt;
tokenize oldstring;&lt;br /&gt;
                                tokens = string.tokenize();&lt;br /&gt;
tokenize2 oldstring, oldstring;&lt;br /&gt;
                                tokens = string.tokenize(&amp;quot; ,&amp;quot; @ string);&lt;br /&gt;
toweapons oldstring;&lt;br /&gt;
                                toweapons(string);&lt;br /&gt;
triggeraction float, float, oldstring, oldstring;&lt;br /&gt;
                                triggeraction(float,float,string,string);&lt;br /&gt;
unfreezeplayer;&lt;br /&gt;
                                unfreezeplayer();&lt;br /&gt;
unset oldstring;&lt;br /&gt;
                                unset(string);&lt;br /&gt;
updateboard float, float, float, float;&lt;br /&gt;
                                updateboard(float,float,float,float);&lt;br /&gt;
updateterrain;&lt;br /&gt;
                                updateterrain();&lt;br /&gt;
wraptext float, oldstring, oldstring;&lt;br /&gt;
                                tokens = wraptext(float,&amp;quot; ,&amp;quot; @ string,string);&lt;br /&gt;
wraptext2 float, float, oldstring, oldstring;&lt;br /&gt;
                                tokens = wraptext2(float,float,&amp;quot; ,&amp;quot; @ string,string);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Supported old string operations ===&lt;br /&gt;
These old string operators can be used in string parameters&lt;br /&gt;
for the old commands, also you can use them directly as operators, e.g.&lt;br /&gt;
  #c = &amp;quot;hello&amp;quot;&lt;br /&gt;
is actually doing&lt;br /&gt;
  player.chat = &amp;quot;hello&amp;quot;&lt;br /&gt;
It is recommended to use the new scripting style though.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#a            player.account&lt;br /&gt;
#a(float)     players[float].account&lt;br /&gt;
#m            player.ani&lt;br /&gt;
              ani&lt;br /&gt;
#m(float)     players[float].ani&lt;br /&gt;
#K(float)     char(float)&lt;br /&gt;
#8            player.bodyimg&lt;br /&gt;
              bodyimg&lt;br /&gt;
#8(float)     players[float].bodyimg&lt;br /&gt;
#c            player.chat&lt;br /&gt;
              chat&lt;br /&gt;
#c(float)     players[float].chat&lt;br /&gt;
#C0           player.colors[0]&lt;br /&gt;
              colors[0]&lt;br /&gt;
#C0(float)    players[float].colors[0]&lt;br /&gt;
#C1           player.colors[1]&lt;br /&gt;
              colors[1]&lt;br /&gt;
#C1(float)    players[float].colors[1]&lt;br /&gt;
#C2           player.colors[2]&lt;br /&gt;
              colors[2]&lt;br /&gt;
#C2(float)    players[float].colors[2]&lt;br /&gt;
#C3           player.colors[3]&lt;br /&gt;
              colors[3]&lt;br /&gt;
#C3(float)    players[float].colors[3]&lt;br /&gt;
#C4           player.colors[4]&lt;br /&gt;
              colors[4]&lt;br /&gt;
#C4(float)    players[float].colors[4]&lt;br /&gt;
#C5           player.colors[5]&lt;br /&gt;
              colors[5]&lt;br /&gt;
#C5(float)    players[float].colors[5]&lt;br /&gt;
#D            downloadfile()&lt;br /&gt;
#E            emoticonchar()&lt;br /&gt;
#e(float,float,oldstring)&lt;br /&gt;
              string.substring(float,float)&lt;br /&gt;
#g            player.guild&lt;br /&gt;
              guild&lt;br /&gt;
#g(float)     players[float].guild&lt;br /&gt;
#3            player.headimg&lt;br /&gt;
              headimg&lt;br /&gt;
#3(float)     players[float].headimg&lt;br /&gt;
#5            player.horseimg&lt;br /&gt;
              horseimg&lt;br /&gt;
#5(float)     players[float].horseimg&lt;br /&gt;
#k(float)     keyname(float)&lt;br /&gt;
#L            player.level&lt;br /&gt;
#I(oldstring,float)&lt;br /&gt;
              getstring(string)[float]&lt;br /&gt;
#n            player.nick&lt;br /&gt;
              nick&lt;br /&gt;
#n(float)     players[float].nick&lt;br /&gt;
#f            image&lt;br /&gt;
#f(float)     npcs[float].image&lt;br /&gt;
#F            level&lt;br /&gt;
#p(float)     params[float]&lt;br /&gt;
#P(float)     player.attr[float]&lt;br /&gt;
              attr[float]&lt;br /&gt;
#P(float_1,float_2)&lt;br /&gt;
              players[float_2].attr[float_1]&lt;br /&gt;
#P1           player.attr[1]&lt;br /&gt;
              attr[1]&lt;br /&gt;
#P1(float)    players[float].attr[1]&lt;br /&gt;
#P2           player.attr[2]&lt;br /&gt;
              attr[2]&lt;br /&gt;
#P2(float)    players[float].attr[2]&lt;br /&gt;
#P3           player.attr[3]&lt;br /&gt;
              attr[3]&lt;br /&gt;
#P3(float)    players[float].attr[3]&lt;br /&gt;
#P4           player.attr[4]&lt;br /&gt;
              attr[4]&lt;br /&gt;
#P4(float)    players[float].attr[4]&lt;br /&gt;
#P5           player.attr[5]&lt;br /&gt;
              attr[5]&lt;br /&gt;
#P5(float)    players[float].attr[5]&lt;br /&gt;
#P6           player.attr[6]&lt;br /&gt;
              attr[6]&lt;br /&gt;
#P6(float)    players[float].attr[6]&lt;br /&gt;
#P7           player.attr[7]&lt;br /&gt;
              attr[7]&lt;br /&gt;
#P7(float)    players[float].attr[7]&lt;br /&gt;
#P8           player.attr[8]&lt;br /&gt;
              attr[8]&lt;br /&gt;
#P8(float)    players[float].attr[8]&lt;br /&gt;
#P9           player.attr[9]&lt;br /&gt;
              attr[9]&lt;br /&gt;
#P9(float)    players[float].attr[9]&lt;br /&gt;
#R(oldstring) string.random()&lt;br /&gt;
#2            player.shieldimg&lt;br /&gt;
              shieldimg&lt;br /&gt;
#2(float)     players[float].shieldimg&lt;br /&gt;
#s(oldstring) getstring(string)&lt;br /&gt;
#1            player.swordimg&lt;br /&gt;
              swordimg&lt;br /&gt;
#1(float)     players[float].swordimg&lt;br /&gt;
#S            player.sword.script&lt;br /&gt;
#t(float)     tokens[float]&lt;br /&gt;
#T(oldstring) string.trim()&lt;br /&gt;
#v(float)     float&lt;br /&gt;
#W            player.weapon.image&lt;br /&gt;
#W(float)     weapons[float].image&lt;br /&gt;
#w            player.weapon.name&lt;br /&gt;
#w(float)     weapons[float].name&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Compatibility note:&lt;br /&gt;
When you use the command setcharprop then the first parameter&lt;br /&gt;
is handled differently: instead of changing 'player.chat' it&lt;br /&gt;
is changing 'chat', the chat text of the npc. So 'setcharprop #c,hello'&lt;br /&gt;
would be translated into&lt;br /&gt;
chat = &amp;quot;hello&amp;quot;&lt;br /&gt;
while 'setplayerprop #c,hello' is translated into&lt;br /&gt;
player.chat = &amp;quot;hello&amp;quot;&lt;br /&gt;
In the list above both possibilities are listed.&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Script/Client/GuiControls_List&amp;diff=8926</id>
		<title>Creation/Dev/Script/Client/GuiControls List</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Script/Client/GuiControls_List&amp;diff=8926"/>
		<updated>2007-07-01T07:46:42Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8676 by Special:Contributions/Anti-Up (User talk:Anti-Up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
Click on the name below the image of the GUI control to see a description and the script for displaying it. Also check out the page about [[Creation/Dev/GScript/Understanding_GUI_Profiles|GUI profiles]]. &lt;br /&gt;
The full list of GUI controls is available at [[Creation/Dev/Script/Client#Classes_.2F_Object_Types|Client Object Types]].&lt;br /&gt;
&lt;br /&gt;
==GUI Containers==&lt;br /&gt;
[[Image:Guicontrol_panel.png|thumb|left|[[Creation/Dev/Script/Client/GuiControl|GuiControl]]]]&lt;br /&gt;
[[Image:Guicontrol_window.png|thumb|left|[[Creation/Dev/Script/Client/GuiWindowCtrl|GuiWindowCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_bitmapborder.png|thumb|none|[[Creation/Dev/Script/Client/GuiBitmapBorderCtrl|GuiBitmapBorderCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Guicontrol_scroll.png|thumb|left|[[Creation/Dev/Script/Client/GuiScrollCtrl|GuiScrollCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_stretch.png|thumb|left|[[Creation/Dev/Script/Client/GuiStretchCtrl|GuiStretchCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_frames.png|thumb|none|[[Creation/Dev/Script/Client/GuiFrameSetCtrl|GuiFrameSetCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
==Text and Edit fields==&lt;br /&gt;
[[Image:Guicontrol_text.png|thumb|left|100px|[[Creation/Dev/Script/Client/GuiTextCtrl|GuiTextCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_edit.png|thumb|none|[[Creation/Dev/Script/Client/GuiTextEditCtrl|GuiTextEditCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_editslider.png|thumb|none|[[Creation/Dev/Script/Client/GuiTextEditSliderCtrl|GuiTextEditSliderCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Guicontrol_multiline.png|thumb|left|100px|[[Creation/Dev/Script/Client/GuiMLTextCtrl|GuiMLTextCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_multilineedit.png|thumb|none|[[Creation/Dev/Script/Client/GuiMLTextEditCtrl|GuiMLTextEditCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Buttons==&lt;br /&gt;
[[Image:Guicontrol_button.png|thumb|left|[[Creation/Dev/Script/Client/GuiButtonCtrl|GuiButtonCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_check.png|thumb|left|120px|[[Creation/Dev/Script/Client/GuiCheckBoxCtrl|GuiCheckBoxCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_radio.png|thumb|left|[[Creation/Dev/Script/Client/GuiRadioCtrl|GuiRadioCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_tab.png|thumb|none|[[Creation/Dev/Script/Client/GuiTabCtrl|GuiTabCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Guicontrol_bitmapbutton.png|thumb|none|120px|[[Creation/Dev/Script/Client/GuiBitmapButtonCtrl|GuiBitmapButtonCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
==Menus==&lt;br /&gt;
[[Image:Guicontrol_menu.png|thumb|left|[[Creation/Dev/Script/Client/GuiMenuCtrl|GuiMenuCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_combobox.png|thumb|left|[[Creation/Dev/Script/Client/GuiPopUpMenuCtrl|GuiPopUpMenuCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_comboedit.png|thumb|none|[[Creation/Dev/Script/Client/GuiPopUpEditCtrl|GuiPopUpEditCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==TextList and TreeView==&lt;br /&gt;
[[Image:Guicontrol_textlist.png|thumb|left|[[Creation/Dev/Script/Client/GuiTextListCtrl|GuiTextListCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_treeview.png|thumb|none|[[Creation/Dev/Script/Client/GuiTreeViewCtrl|GuiTreeViewCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Special==&lt;br /&gt;
[[Image:Guicontrol_showimg.png|thumb|left|100px|[[Creation/Dev/Script/Client/GuiShowImgCtrl|GuiShowImgCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_drawingpanel.png|thumb|left|120px|[[Creation/Dev/Script/Client/GuiDrawingPanel|GuiDrawingPanel]]]]&lt;br /&gt;
[[Image:Guicontrol_bitmap.png|thumb|none|[[Creation/Dev/Script/Client/GuiBitmapCtrl|GuiBitmapCtrl]]]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Guicontrol_progress.png|thumb|left|[[Creation/Dev/Script/Client/GuiProgressCtrl|GuiProgressCtrl]]]]&lt;br /&gt;
[[Image:Guicontrol_slider.png|thumb|none|[[Creation/Dev/Script/Client/GuiSliderCtrl|GuiSliderCtrl]]]]&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/GScript&amp;diff=8923</id>
		<title>Creation/Dev/GScript</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/GScript&amp;diff=8923"/>
		<updated>2007-07-01T07:42:09Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8680 by Special:Contributions/Anti-Up (User talk:Anti-Up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''GScript''' is [[Graal]]'s scripting language.&lt;br /&gt;
&lt;br /&gt;
Its syntax and some of its semantics might seem familiar to those who program in [[WikiPedia:C (Programming Language) |C]] or [[WikiPedia:Java_programming_language|Java]]. In some ways it is more dynamic, e.g. supporting dynamicly joining and leaving of classes, and brings support for easy management of online game content.&lt;br /&gt;
&lt;br /&gt;
GScript started as a very limited language ([[Creation/Dev/Old GScript|Old GScript]]) and has since kept up with improvements to the game engine and can now be used for pretty sophisticated scripts that greatly customise the gaming experience.&lt;br /&gt;
&lt;br /&gt;
It is used, with minor differences, for [[Clientside]] tasks like [[GUI | GUI programming]], special effects with nifty 3d lighting and custom [[NPC weapon|NPC Weapons]] or &amp;amp;quot;engines&amp;amp;quot;, and [[Serverside]] systems like player housing, complex baddies or pets.&lt;br /&gt;
&lt;br /&gt;
GScript can be discussed in the non-official [[GScript IRC channel]].&lt;br /&gt;
&lt;br /&gt;
'''If you would like to contribute to the GraalBible's GScript documentation, you might want to [[Creation/Dev/GScript/Contribute|read this article]].'''&lt;br /&gt;
&lt;br /&gt;
In your scripting quest, you may find the following articles to be of use:&lt;br /&gt;
&lt;br /&gt;
'''Basic information'''&lt;br /&gt;
* [[Creation/Dev/Script/Starting Guide|Starting Guide]]&lt;br /&gt;
* [[Creation/Dev/Script/Client|Functions, variables and objects (clientside)]] &lt;br /&gt;
* [[Creation/Dev/Script/Client/GuiControls_List|GUI Controls]]&lt;br /&gt;
&lt;br /&gt;
'''Specific Features'''&lt;br /&gt;
* [[Creation/Dev/GS1_To_GS2|GS1 To GS2: Guide for fixing scripts to work with the new engine]]&lt;br /&gt;
* [[Particle Engine|Particle Engine]]&lt;br /&gt;
* [[Creation/Dev/Graal v4 IRC|Graal IRC Scripting: Graal IRC Scripting Reference]]&lt;br /&gt;
* [[Creation/Dev/Troubleshooting Graal v4 IRC|Graal IRC Scripting: Troubleshooting Scripting Reference]]&lt;br /&gt;
* [[Creation/Dev/Output Methods|Output methods]]&lt;br /&gt;
* [[Creation/Dev/Using Classes Effectively|Use of classes]]&lt;br /&gt;
* [[Creation/Dev/GScript/Understanding GUI Profiles|GUI Features: Understanding GUI profiles]]&lt;br /&gt;
* [[Creation/Dev/GScript/Constants|Constants]]&lt;br /&gt;
* [[Vectors]] (3D)&lt;br /&gt;
&lt;br /&gt;
'''Tutorials'''&lt;br /&gt;
* [[Creation/Dev/Creating Tabbed Window Panes|Creating Tabbed Window Panes]]&lt;br /&gt;
* [[Creation/Dev/Database_Communication|Indexed Database Communication]]&lt;br /&gt;
* [[Creation/Dev/Excalibur's scripting guide|Excalibur's Scripting Guide]]&lt;br /&gt;
* [http://twinny.vip.graal.net Twinny's Scripting Page]&lt;br /&gt;
'''Script Functions'''&lt;br /&gt;
&lt;br /&gt;
These are frequently updated, to get the latest list run Graal with the -listscriptfunctions option:&lt;br /&gt;
* [[Creation/Dev/Script/Clientside_Functions|Client side]]&lt;br /&gt;
* [[Creation/Dev/Script Functions: NPC Server|Server side]]&lt;br /&gt;
&lt;br /&gt;
[[Creation/Dev/Script/Index |Related Artices]]&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation&amp;diff=8922</id>
		<title>Creation</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation&amp;diff=8922"/>
		<updated>2007-07-01T07:40:56Z</updated>

		<summary type="html">&lt;p&gt;Twinny: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Something that makes Graal very interesting is that you can create your own online game. You can become staff at a server and upload your own graphics, maps, add monsters or even create a new style of game. To make it possible for everyone to participate we created the possibility to rent your own playerworld space. &lt;br /&gt;
Follow those links to find more documentation about server managment and the development tools:&lt;br /&gt;
&lt;br /&gt;
[[Creation/Playerworld Renting|Rent a Playerworld]]&lt;br /&gt;
&lt;br /&gt;
Management&lt;br /&gt;
* [[Creation/Management/Playerworld_Guide|Playerworld Guide]]&lt;br /&gt;
* [[Server options|Server Options]]&lt;br /&gt;
* [[Creation/Management/Contacts|Staff Contacts]]&lt;br /&gt;
* [[Creation/Dev/Basics_of_NPC-Control|NPC-Control]]&lt;br /&gt;
&lt;br /&gt;
Development&lt;br /&gt;
* [[Creation/Dev/GScript|Scripting]]&lt;br /&gt;
* Tools:&lt;br /&gt;
** [[Creation/Dev/Level editor|Level Editor]]&lt;br /&gt;
** [[Creation/Dev/Gani|Gani Editor]]&lt;br /&gt;
* Help pages:&lt;br /&gt;
** [[Creation/Dev/Tileset|Information on Tilesets]]&lt;br /&gt;
** [[Creation/Dev/Player|Information on Player Looks]]&lt;br /&gt;
** [[Creation/Dev/Update Packages|Update Packages]]&lt;br /&gt;
* [[Creation/Dev/Client_Releases|Client Changelog]]&lt;br /&gt;
&lt;br /&gt;
Inspection&lt;br /&gt;
* [[Creation/Inspection/Playerworld_Scripting|Playerworld Scripting]]&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Script/Client/WheeledVehicleData&amp;diff=8921</id>
		<title>Creation/Dev/Script/Client/WheeledVehicleData</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Script/Client/WheeledVehicleData&amp;diff=8921"/>
		<updated>2007-07-01T07:38:50Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8915 by Special:Contributions/Anti-up (User talk:Anti-up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Inherits [[Creation/Dev/Script/Client/VehicleData|VehicleData]].&lt;br /&gt;
&lt;br /&gt;
=Variables=&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot;&lt;br /&gt;
| '''Name'''&lt;br /&gt;
| '''Type'''&lt;br /&gt;
| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| enginesound&lt;br /&gt;
| object&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| jetsound&lt;br /&gt;
| object&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| squealsound&lt;br /&gt;
| object&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| tireemitter&lt;br /&gt;
| object&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| wheelimpactsound&lt;br /&gt;
| object&lt;br /&gt;
|&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Local_Staff_Positions&amp;diff=8920</id>
		<title>Local Staff Positions</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Local_Staff_Positions&amp;diff=8920"/>
		<updated>2007-07-01T07:38:31Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8917 by Special:Contributions/Anti-up (User talk:Anti-up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;There are four common local staff positions:&lt;br /&gt;
&lt;br /&gt;
*'''GP''' ''(Graal Police)'' - in charge of enforcing the rules and maintaining order in the server.&lt;br /&gt;
&lt;br /&gt;
*'''LAT''' ''(Levels Administration Team)'' - the development team, contains tilers, scripters and graphics makers.&lt;br /&gt;
&lt;br /&gt;
*'''FAQ''' ''(Frequently Asked Questions)'' - the server's source of knowledge, in charge of anwering players' questions.&lt;br /&gt;
&lt;br /&gt;
*'''Events Team''' - in charge of hosting events to entertain the players.  Known as Game Coordinator on Classic.&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Script/Client/GuiCursor&amp;diff=8919</id>
		<title>Creation/Dev/Script/Client/GuiCursor</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Script/Client/GuiCursor&amp;diff=8919"/>
		<updated>2007-07-01T07:38:22Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Undo revision 8918 by Special:Contributions/Anti-up (User talk:Anti-up)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Inherits [[Creation/Dev/Script/Client/TGraalVar|TGraalVar]].&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/GScript&amp;diff=8369</id>
		<title>Creation/Dev/GScript</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/GScript&amp;diff=8369"/>
		<updated>2007-06-10T09:24:05Z</updated>

		<summary type="html">&lt;p&gt;Twinny: Added a link to my 'learn gs2' website :D&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''GScript''' is [[Graal]]'s scripting language.&lt;br /&gt;
&lt;br /&gt;
Its syntax and some of its semantics might seem familiar to those who program in [[WikiPedia:C (Programming Language) |C]] or [[WikiPedia:Java_programming_language|Java]]. In some ways it is more dynamic, e.g. supporting dynamicly joining and leaving of classes, and brings support for easy management of online game content.&lt;br /&gt;
&lt;br /&gt;
GScript started as a very limited language ([[Creation/Dev/Old GScript|Old GScript]]) and has since kept up with improvements to the game engine and can now be used for pretty sophisticated scripts that greatly customise the gaming experience.&lt;br /&gt;
&lt;br /&gt;
It is used, with minor differences, for [[Clientside]] tasks like [[GUI | GUI programming]], special effects with nifty 3d lighting and custom [[NPC weapon|NPC Weapons]] or &amp;amp;quot;engines&amp;amp;quot;, and [[Serverside]] systems like player housing, complex baddies or pets.&lt;br /&gt;
&lt;br /&gt;
GScript can be discussed in the non-official [[GScript IRC channel]].&lt;br /&gt;
&lt;br /&gt;
'''If you would like to contribute to the GraalBible's GScript documentation, you might want to [[Creation/Dev/GScript/Contribute|read this article]].'''&lt;br /&gt;
&lt;br /&gt;
In your scripting quest, you may find the following articles to be of use:&lt;br /&gt;
&lt;br /&gt;
'''Basic information'''&lt;br /&gt;
* [[Creation/Dev/Script/Starting Guide|Starting Guide]]&lt;br /&gt;
* [[Creation/Dev/Script/Client|Functions, variables and objects (clientside)]] &lt;br /&gt;
* [[Creation/Dev/Script/Client/GuiControls_List|GUI Controls]]&lt;br /&gt;
&lt;br /&gt;
'''Specific Features'''&lt;br /&gt;
* [[Creation/Dev/GS1_To_GS2|GS1 To GS2: Guide for fixing scripts to work with the new engine]]&lt;br /&gt;
* [[Particle Engine|Particle Engine]]&lt;br /&gt;
* [[Creation/Dev/Graal v4 IRC|Graal IRC Scripting: Graal IRC Scripting Reference]]&lt;br /&gt;
* [[Creation/Dev/Troubleshooting Graal v4 IRC|Graal IRC Scripting: Troubleshooting Scripting Reference]]&lt;br /&gt;
* [[Creation/Dev/Output Methods|Output methods]]&lt;br /&gt;
* [[Creation/Dev/Using Classes Effectively|Use of classes]]&lt;br /&gt;
* [[Creation/Dev/GScript/Understanding GUI Profiles|GUI Features: Understanding GUI profiles]]&lt;br /&gt;
* [[Creation/Dev/GScript/Constants|Constants]]&lt;br /&gt;
* [[Vectors]] (3D)&lt;br /&gt;
&lt;br /&gt;
'''Tutorials'''&lt;br /&gt;
* [[Creation/Dev/Creating Tabbed Window Panes|Creating Tabbed Window Panes]]&lt;br /&gt;
* [[Creation/Dev/Database_Communication|Indexed Database Communication]]&lt;br /&gt;
* [[Creation/Dev/Excalibur's scripting guide|Excalibur's Scripting Guide]]&lt;br /&gt;
* [http://twinny.vip.graal.net Twinny's Scripting Page]&lt;br /&gt;
'''Script Functions'''&lt;br /&gt;
&lt;br /&gt;
These are frequently updated, to get the latest list run Graal with the -listscriptfunctions option:&lt;br /&gt;
* [[Creation/Dev/Script/Clientside_Functions|Client side]]&lt;br /&gt;
* [[Creation/Dev/Script Functions: NPC Server|Server side]]&lt;br /&gt;
&lt;br /&gt;
[[Creation/Dev/Script/Index |Related Artices]]&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Excalibur%27s_scripting_guide&amp;diff=7579</id>
		<title>Creation/Dev/Excalibur's scripting guide</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Excalibur%27s_scripting_guide&amp;diff=7579"/>
		<updated>2006-11-17T00:12:59Z</updated>

		<summary type="html">&lt;p&gt;Twinny: /* '''Excalibur's Scripting Guide''' */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''Excalibur's Scripting Guide''' ==&lt;br /&gt;
I'm hoping this allows people to learn how to script a bit easier, I believe all staff should know some scripting basics, and I find other GS2 guides hard to follow. This should help you get started out. I'm afraid it isn't complete and there are a few typos in it. I'm working on it. &lt;br /&gt;
&lt;br /&gt;
Starting:&lt;br /&gt;
&lt;br /&gt;
Level NPCs:&lt;br /&gt;
&lt;br /&gt;
A level NPC is an npc that functions in a specific level. These are the most common on most servers. They are also a very important part of developement.&lt;br /&gt;
&lt;br /&gt;
A script:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//this is a note&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
this is also a note, these help make scripts more clear&lt;br /&gt;
this type of note can go on as longe as it's inclosed&lt;br /&gt;
*/&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
//This tells the computer that the following&lt;br /&gt;
//script will be on the players client, &lt;br /&gt;
//as opposed to the server, this is very important.&lt;br /&gt;
function onPlayertouchesme()&lt;br /&gt;
//this checks if the player has touched the NPC&lt;br /&gt;
{ // starting bracket&lt;br /&gt;
  this.message(&amp;quot;Hey!&amp;quot;); //displays a message above the NPC&lt;br /&gt;
}//closing bracket&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The above script checks to see if the event, playertouchsme is true, then acts on what is in the bracket. It is important to include this clientside, because too many serverside scripts can cause problems for an NPC server, however they are more secure. If you wanted to do the last script serverside, you would omit the //#CLIENTSIDE , and add the shape to the NPC:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape(1,32,32);&lt;br /&gt;
  setimg(&amp;quot;block.png&amp;quot;);&lt;br /&gt;
//img can also be done in the box above the script&lt;br /&gt;
}&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  this.message(&amp;quot;You made a serverside script!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This takes a bit longer than clientside commands, and it takes up serverside script time, however, for secure actions, it may be necessary.&lt;br /&gt;
A secure script example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.account=&amp;quot;Excaliber7388&amp;quot;;&lt;br /&gt;
  setshape(1,32,32);&lt;br /&gt;
  this.chat=&amp;quot;Excaliber's Chest&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  if(player.account==this.account)&lt;br /&gt;
  {&lt;br /&gt;
    this.chat=&amp;quot;This is a secure message!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
First, I would like to quickly point out the 'if' statement. Some guides go into this a lot, but it's actually quite simple. The if statement is a very important part of scripting. It's what allows the NPC to make choices. The code withing the brackets of an if statement will only execute if the statement is true. Also, there is a catchall statement you can use, else. If the if statement is not true, the else will exectue it's script, other wise it is ignored. &lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.a=1;&lt;br /&gt;
}&lt;br /&gt;
if(this.a==1) &lt;br /&gt;
//always use '==' for comparasons, NEVER just '=' as '=' is for assignments&lt;br /&gt;
{&lt;br /&gt;
  this.b=2;&lt;br /&gt;
}&lt;br /&gt;
else if(this.a==2) //will only execute if first is false, AND this.a==2&lt;br /&gt;
{&lt;br /&gt;
  this.b=3;&lt;br /&gt;
}&lt;br /&gt;
else //catch all if above 2 statements are false&lt;br /&gt;
{&lt;br /&gt;
  this.b=4;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, in the above example, this.b will always be 2, however, it's the format that's important.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(statement)&lt;br /&gt;
else if(statement)&lt;br /&gt;
else if(statement //may be used many times&lt;br /&gt;
else //catch all&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, back to serverside and clientside scripts:&lt;br /&gt;
By putting the checks on serverside, you disable a hackers ability to send an action from their client. So, this script is much more secure, and can only be accessed by the specified account (Excaliber7388 in this case). Most playerworlds and classic servers do these checks serverside as well, but we also apply a different method, to avoid having too much serverside script time:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.account=&amp;quot;Excaliber7388&amp;quot;;&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
  this.chat=&amp;quot;Excaliber's Chest&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
function onActiontouched()&lt;br /&gt;
{&lt;br /&gt;
  if(player.account==this.account)&lt;br /&gt;
  {&lt;br /&gt;
    this.chat=&amp;quot;Yup, this is still secure, yay!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  triggeraction(x,y,&amp;quot;Touched&amp;quot;,&amp;quot;Touched&amp;quot;);//no params needed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This script will take up more time, but the playertouchsme check is clientside. Would this help much? Probably not, in fact, sending the action in this case would probably create more lag than having the script serverside. However, if a large portion of the script is serverside, and can be moved to clientside without risking security, it may be a good idea. &lt;br /&gt;
Serverisde timeouts=bad idea.&lt;br /&gt;
You shouldn't send to many actions to serverside, especially if you do so quickly. You should always limit the serverside timeouts, and the amount of time between actions to the server from client should be spaced out. Also, you should never have a timeout shorter than .05 on serverside, though it is possible, please do not do it. Many playerworlds have expierenced problems from serverside timeouts which can lead to NPC server crashing or lagging.&lt;br /&gt;
&lt;br /&gt;
Here are two examples of serverside scripts, the first is [b]VERY[/b] bad, the second is more productive:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActiontime()&lt;br /&gt;
{&lt;br /&gt;
  for(server.i=0;server.i&amp;lt;5;server.i++)&lt;br /&gt;
 //WHY use server for this???&lt;br /&gt;
 //for loops, use this. it works only for this NPC&lt;br /&gt;
  {&lt;br /&gt;
    sleep(.01); &lt;br /&gt;
//WAY to short of a sleep time for the server&lt;br /&gt;
   }   &lt;br /&gt;
    server.time+=.1;&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(.05); //minimum clientside timeout&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  trigegraction(x,y,&amp;quot;time&amp;quot;,&amp;quot;time&amp;quot;);&lt;br /&gt;
  settimer(.05);&lt;br /&gt;
//Will cause a loop through the timeout, sending action &lt;br /&gt;
//to serverside TOO quickly, AND while the server is &lt;br /&gt;
//still working on the last action. This WILL cause the &lt;br /&gt;
//server to crash.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you put the above script on a server, say goodbye to your NPC server, because it will crach pretty quickly!&lt;br /&gt;
A better version:&lt;br /&gt;
&amp;lt;pre&amp;gt;function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
  //setshape is needed for all level NPCs triggeractions&lt;br /&gt;
  //this sets it to a square of tiles 32x32 pixels.&lt;br /&gt;
}&lt;br /&gt;
function onActiontime()&lt;br /&gt;
{&lt;br /&gt;
  server.time++;&lt;br /&gt;
  //no need for incredible accuracy&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  triggeraction(x,y,&amp;quot;time&amp;quot;,&amp;quot;time&amp;quot;);&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will execute the script less often, however, it still is an unlimited loop. Don't have too many of these NPCs, or you could have problems!&lt;br /&gt;
&lt;br /&gt;
Now, you may have noticed this line in the bad script:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for(server.i=0;server.i&amp;lt;5;server.i++)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a 'for' loop. There are many types of loops, however the for loop isn't the easiest to learn first. Therefore, I will show you the 'while loop' first.&lt;br /&gt;
The while loop executes whatever is held within it's brackets as long as the statement within it is true. The while loop is just like an if statement, but you cannot use else with a with statement.&lt;br /&gt;
format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
while(statments)&lt;br /&gt;
{&lt;br /&gt;
  //commands&lt;br /&gt;
}&lt;br /&gt;
//if statment is still true, it will loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
here's a script example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.size=10;&lt;br /&gt;
}&lt;br /&gt;
while(this.size&amp;lt;=20) //while this.size is less than or equal to 20&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  //as the story is retold....&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
  this.size=this.size+1;&lt;br /&gt;
  //increment the size&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The above script will run through the loop until this.size is equal or greater than 20.&lt;br /&gt;
Some important things to know:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(a==b) means if a is equal to b&lt;br /&gt;
if(a&amp;lt;b) means if a is less than b&lt;br /&gt;
if(a&amp;gt;b) means if a is greater than b&lt;br /&gt;
if(a&amp;lt;=b) means if a is less than or equal to be&lt;br /&gt;
if(a&amp;gt;=b) means if a is greater than or equal to be&lt;br /&gt;
a++      is the same as a=a+1&lt;br /&gt;
a--      is the same as a=a-1&lt;br /&gt;
a+=b    means a=a+b&lt;br /&gt;
a-=b    means a=a-b&lt;br /&gt;
a*=b    means a=a*b (multiplied by b)&lt;br /&gt;
a/=b    means a=a/b&lt;br /&gt;
++a     is just like a, but it will add to a before anything else in the line, &lt;br /&gt;
         this is not important to know now&lt;br /&gt;
--a     just like ++a, but with subtraction&lt;br /&gt;
a%b     Modulus, basically, its a/b and th remainder is the output &lt;br /&gt;
        for example 10%3=1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These may be helpfull in loops, or in any other rational expressions you may use. (Well, it's important for all scripting!)&lt;br /&gt;
Now, recall this line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The output for this is: The fish was (size here) centimeters long!&lt;br /&gt;
The script NEEDS to know where a variable is, so if you want to put it in between a string you surround it with the '@' symbol. Or if it's at the end, you only put the '@' at the beggining of the variable. The variable and the '@' do NOT go in the quotes. Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;Well hi there, &amp;quot; @player.account@ &amp;quot; I like your sword, &amp;quot; @player.swordimg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This would display the player's account, and sword image.&lt;br /&gt;
&lt;br /&gt;
Now, back to the 'for' loop.&lt;br /&gt;
This a very interesting loop it's format is as follows:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for(command;expression;command)&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here's an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  for(this.i=0;this.i&amp;lt;10;this.i++)&lt;br /&gt;
  {&lt;br /&gt;
    this.chat=&amp;quot;Loops: &amp;quot; @this.i;&lt;br /&gt;
    sleep(.5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This loop would be activated when the player touchs it.&lt;br /&gt;
It would go through 10 loops, displaying the count, and taking .5 seconds for each loop (due to the sleep() command)&lt;br /&gt;
Now remember this while loop?&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.size=10;&lt;br /&gt;
}&lt;br /&gt;
while(this.size&amp;lt;=20)&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  //as the story is retold....&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
  this.size=this.size+1;&lt;br /&gt;
  //increment the size&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There's an easier way of doing it with a for loop, in fact all loops done with while can be replaced by for.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for(this.size=10;this.size&amp;lt;=20;this.size++)&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See? Much shorter and easier to use!&lt;br /&gt;
Once you know the format of a for loop, you can make longer and more complex loops as well, and they'll take less time to script, which is always a bonus.&lt;br /&gt;
&lt;br /&gt;
Some more detail on actions:&lt;br /&gt;
An action is an effective way to use a portion of script more than once, have one script act on another script, more script to serverside from clientside (and the other way) and more.&lt;br /&gt;
So how do you use them? Here's the format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
triggeraction(x,y,&amp;quot;params[0]&amp;quot;,&amp;quot;params[1]&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You must have two parameters, but you can have as many as you want a quick example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActiontrigger()&lt;br /&gt;
{&lt;br /&gt;
  player.chat=&amp;quot;Account: &amp;quot; @params[1]@ &amp;quot; Sword &amp;quot; @params[2]@ &amp;quot; head: &amp;quot; @params[3];&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayerchats()&lt;br /&gt;
{&lt;br /&gt;
  if(player.chat==&amp;quot;Who am I?&amp;quot;) //amnesia? multiple identities?&lt;br /&gt;
  {&lt;br /&gt;
    triggeraction(x,y,&amp;quot;trigger&amp;quot;,player.account,player.swordimg,player.headimg);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See? You can make more than one parameter.&lt;br /&gt;
Now, there are a few differences between a level NPC with a triggeraction, and a weapon with a triggeraction. Weapons need their location (serverside or clientside) as the first parameter, params[0] is the one after it. Here, you can have just one parameter, and the x and y is always 0 (because the npc server is at 0,0), and you need to include the name of the weapon in the action.&lt;br /&gt;
here's an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//weapon script with a triggeraction &lt;br /&gt;
//Weapon name: Fire Ball&lt;br /&gt;
function onActionserverside()&lt;br /&gt;
{&lt;br /&gt;
  if(params[0]==&amp;quot;mp&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    playermp-=10&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onWeaponfired()&lt;br /&gt;
{&lt;br /&gt;
  if(playermp&amp;gt;=10)&lt;br /&gt;
  {&lt;br /&gt;
    shootfireball(playerdir);&lt;br /&gt;
    triggeraction(0,0,&amp;quot;serverside&amp;quot;,&amp;quot;Fireball&amp;quot;,&amp;quot;mp&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    player.chat=&amp;quot;Not enough mp!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This nifty little weapon will cost 10 mp per use, and fires a fireball in the direction the player is facing. Hopefully, you can learn to make many weapons of your own!&lt;br /&gt;
Triggeractions can be used in shops as well (and these are the scripts people ask for the most).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//a shop script, yay!&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActionbuy()&lt;br /&gt;
{&lt;br /&gt;
  if(playerrupees&amp;gt;=100)&lt;br /&gt;
  {&lt;br /&gt;
    addweapon Fire Ball;&lt;br /&gt;
    playerrupees-=100;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayerchats()&lt;br /&gt;
{&lt;br /&gt;
  if(player.chat==&amp;quot;buy fire ball&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    triggeraction(x,y,&amp;quot;buy&amp;quot;,&amp;quot;buy&amp;quot;); &lt;br /&gt;
    //the level npc triggeraction type&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There, now you can make a little shop that sells a Fire Ball weapon. Have fun with it, search the commands, there's plenty of easy weapons you can make, and the weapon script is easy to follow and modify as well. Hopefully, you know enough about parameters to make more than one weapon for sale in the same NPC, just make the weapon name part of the action, then check for that parameter before they can buy. &lt;br /&gt;
 Now there are other types of loops. One I commonly see is a timeout loop. You should understand why. Back with GS1, it was a bit easier to tell what was happening in the script. In GS1 the script for function onTimeout() would be displayed as if(timeout). It was a bit easier to tell that when a timeout was done, it set a flag that if(timeout) would check. function onTimeout does the same thing, however, for new users this may be harder to tell. here's an example of an NPC that uses a timeout loop:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  player.chat=&amp;quot;Counter: &amp;quot; @this.time;&lt;br /&gt;
  this.time++;&lt;br /&gt;
  settimer(1); &lt;br /&gt;
//after 1 second, the timeout loop will restart&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This would cause the player to count up every second.&lt;br /&gt;
You may have noticed that the variables often start of with client. or this. There are actually a few prefixes, each does a different thing:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
client. variable is saved to the client, it can be modified on the clientside or serverside, and read from either.&lt;br /&gt;
clientr. variables can be rad from server or clientside, but only written from serverside. This is more secure, but only if you use it right.&lt;br /&gt;
server. variables are saved to the server, can only be written on the serverside, read on either side&lt;br /&gt;
serverr. more secure version of server. read only on clientside&lt;br /&gt;
this. is a variable that only functions in the NPC it is in. This prevents NPCs from morifying each others variables&lt;br /&gt;
temp. only exists in between the brackets of a function&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To use scripts effectivly, you should know how to use each of these.&lt;br /&gt;
I will add more over time.&lt;br /&gt;
&lt;br /&gt;
Some important commands can be found here:&lt;br /&gt;
page:http://wiki.graal.net/index.php/Creation/Dev/Script/Starting_Guide#Introduction&lt;br /&gt;
Which is also helpful for learning how to script. Enjoy!&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
	<entry>
		<id>https://graalonline.net/index.php?title=Creation/Dev/Excalibur%27s_scripting_guide&amp;diff=7578</id>
		<title>Creation/Dev/Excalibur's scripting guide</title>
		<link rel="alternate" type="text/html" href="https://graalonline.net/index.php?title=Creation/Dev/Excalibur%27s_scripting_guide&amp;diff=7578"/>
		<updated>2006-11-17T00:06:26Z</updated>

		<summary type="html">&lt;p&gt;Twinny: /* '''Excalibur's Scripting Guide''' */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''Excalibur's Scripting Guide''' ==&lt;br /&gt;
I'm hoping this allows people to learn how to script a bit easier, I believe all staff should know some scripting basics, and I find other GS2 guides hard to follow. This should help you get started out. I'm afraid it isn't complete and there are a few typos in it. I'm working on it. &lt;br /&gt;
&lt;br /&gt;
Starting:&lt;br /&gt;
&lt;br /&gt;
Level NPCs:&lt;br /&gt;
&lt;br /&gt;
A level NPC is an npc that functions in a specific level. These are the most common on most servers. They are also a very important part of developement.&lt;br /&gt;
&lt;br /&gt;
A script:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//this is a note&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
this is also a note, these help make scripts more clear&lt;br /&gt;
this type of note can go on as longe as it's inclosed&lt;br /&gt;
*/&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
//This tells the computer that the following&lt;br /&gt;
//script will be on the players client, &lt;br /&gt;
//as opposed to the server, this is very important.&lt;br /&gt;
function onPlayertouchesme()&lt;br /&gt;
//this checks if the player has touched the NPC&lt;br /&gt;
{ // starting bracket&lt;br /&gt;
  message(&amp;quot;Hey!&amp;quot;); //displays a message above the NPC&lt;br /&gt;
}//closing bracket&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The above script checks to see if the event, playertouchsme is true, then acts on what is in the bracket. It is important to include this clientside, because too many serverside scripts can cause problems for an NPC server, however they are more secure. If you wanted to do the last script serverside, you would omit the //#CLIENTSIDE , and add the shape to the NPC:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape(1,32,32);&lt;br /&gt;
  setimg(&amp;quot;block.png&amp;quot;);&lt;br /&gt;
//img can also be done in the box above the script&lt;br /&gt;
}&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  message(&amp;quot;You made a serverside script!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This takes a bit longer than clientside commands, and it takes up serverside script time, however, for secure actions, it may be necessary.&lt;br /&gt;
A secure script example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.account=&amp;quot;Excaliber7388&amp;quot;;&lt;br /&gt;
  setshape(1,32,32);&lt;br /&gt;
  chat=&amp;quot;Excaliber's Chest&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  if(player.account==this.account)&lt;br /&gt;
  {&lt;br /&gt;
    chat=&amp;quot;This is a secure message!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
First, I would like to quickly point out the 'if' statement. Some guides go into this a lot, but it's actually quite simple. The if statement is a very important part of scripting. It's what allows the NPC to make choices. The code withing the brackets of an if statement will only execute if the statement is true. Also, there is a catchall statement you can use, else. If the if statement is not true, the else will exectue it's script, other wise it is ignored. &lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.a=1;&lt;br /&gt;
}&lt;br /&gt;
if(this.a==1) &lt;br /&gt;
//always use '==' for comparasons, NEVER just '=' as '=' is for assignments&lt;br /&gt;
{&lt;br /&gt;
  this.b=2;&lt;br /&gt;
}&lt;br /&gt;
else if(this.a==2) //will only execute if first is false, AND this.a==2&lt;br /&gt;
{&lt;br /&gt;
  this.b=3;&lt;br /&gt;
}&lt;br /&gt;
else //catch all if above 2 statements are false&lt;br /&gt;
{&lt;br /&gt;
  this.b=4;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, in the above example, this.b will always be 2, however, it's the format that's important.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(statement)&lt;br /&gt;
else if(statement)&lt;br /&gt;
else if(statement //may be used many times&lt;br /&gt;
else //catch all&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now, back to serverside and clientside scripts:&lt;br /&gt;
By putting the checks on serverside, you disable a hackers ability to send an action from their client. So, this script is much more secure, and can only be accessed by the specified account (Excaliber7388 in this case). Most playerworlds and classic servers do these checks serverside as well, but we also apply a different method, to avoid having too much serverside script time:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.account=&amp;quot;Excaliber7388&amp;quot;;&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
  chat=&amp;quot;Excaliber's Chest&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
function onActiontouched()&lt;br /&gt;
{&lt;br /&gt;
  if(player.account==this.account)&lt;br /&gt;
  {&lt;br /&gt;
    chat=&amp;quot;Yup, this is still secure, yay!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  triggeraction(x,y,&amp;quot;Touched&amp;quot;,&amp;quot;Touched&amp;quot;);//no params needed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This script will take up more time, but the playertouchsme check is clientside. Would this help much? Probably not, in fact, sending the action in this case would probably create more lag than having the script serverside. However, if a large portion of the script is serverside, and can be moved to clientside without risking security, it may be a good idea. &lt;br /&gt;
Serverisde timeouts=bad idea.&lt;br /&gt;
You shouldn't send to many actions to serverside, especially if you do so quickly. You should always limit the serverside timeouts, and the amount of time between actions to the server from client should be spaced out. Also, you should never have a timeout shorter than .05 on serverside, though it is possible, please do not do it. Many playerworlds have expierenced problems from serverside timeouts which can lead to NPC server crashing or lagging.&lt;br /&gt;
&lt;br /&gt;
Here are two examples of serverside scripts, the first is [b]VERY[/b] bad, the second is more productive:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActiontime()&lt;br /&gt;
{&lt;br /&gt;
  for(server.i=0;server.i&amp;lt;5;server.i++)&lt;br /&gt;
 //WHY use server for this???&lt;br /&gt;
 //for loops, use this. it works only for this NPC&lt;br /&gt;
  {&lt;br /&gt;
    sleep(.01); &lt;br /&gt;
//WAY to short of a sleep time for the server&lt;br /&gt;
   }   &lt;br /&gt;
    server.time+=.1;&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(.05); //minimum clientside timeout&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  trigegraction(x,y,&amp;quot;time&amp;quot;,&amp;quot;time&amp;quot;);&lt;br /&gt;
  settimer(.05);&lt;br /&gt;
//Will cause a loop through the timeout, sending action &lt;br /&gt;
//to serverside TOO quickly, AND while the server is &lt;br /&gt;
//still working on the last action. This WILL cause the &lt;br /&gt;
//server to crash.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you put the above script on a server, say goodbye to your NPC server, because it will crach pretty quickly!&lt;br /&gt;
A better version:&lt;br /&gt;
&amp;lt;pre&amp;gt;function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
  //setshape is needed for all level NPCs triggeractions&lt;br /&gt;
  //this sets it to a square of tiles 32x32 pixels.&lt;br /&gt;
}&lt;br /&gt;
function onActiontime()&lt;br /&gt;
{&lt;br /&gt;
  server.time++;&lt;br /&gt;
  //no need for incredible accuracy&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  triggeraction(x,y,&amp;quot;time&amp;quot;,&amp;quot;time&amp;quot;);&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will execute the script less often, however, it still is an unlimited loop. Don't have too many of these NPCs, or you could have problems!&lt;br /&gt;
&lt;br /&gt;
Now, you may have noticed this line in the bad script:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for(server.i=0;server.i&amp;lt;5;server.i++)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a 'for' loop. There are many types of loops, however the for loop isn't the easiest to learn first. Therefore, I will show you the 'while loop' first.&lt;br /&gt;
The while loop executes whatever is held within it's brackets as long as the statement within it is true. The while loop is just like an if statement, but you cannot use else with a with statement.&lt;br /&gt;
format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
while(statments)&lt;br /&gt;
{&lt;br /&gt;
  //commands&lt;br /&gt;
}&lt;br /&gt;
//if statment is still true, it will loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
here's a script example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.size=10;&lt;br /&gt;
}&lt;br /&gt;
while(this.size&amp;lt;=20) //while this.size is less than or equal to 20&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  //as the story is retold....&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
  this.size=this.size+1;&lt;br /&gt;
  //increment the size&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The above script will run through the loop until this.size is equal or greater than 20.&lt;br /&gt;
Some important things to know:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(a==b) means if a is equal to b&lt;br /&gt;
if(a&amp;lt;b) means if a is less than b&lt;br /&gt;
if(a&amp;gt;b) means if a is greater than b&lt;br /&gt;
if(a&amp;lt;=b) means if a is less than or equal to be&lt;br /&gt;
if(a&amp;gt;=b) means if a is greater than or equal to be&lt;br /&gt;
a++      is the same as a=a+1&lt;br /&gt;
a--      is the same as a=a-1&lt;br /&gt;
a+=b    means a=a+b&lt;br /&gt;
a-=b    means a=a-b&lt;br /&gt;
a*=b    means a=a*b (multiplied by b)&lt;br /&gt;
a/=b    means a=a/b&lt;br /&gt;
++a     is just like a, but it will add to a before anything else in the line, &lt;br /&gt;
         this is not important to know now&lt;br /&gt;
--a     just like ++a, but with subtraction&lt;br /&gt;
a%b     Modulus, basically, its a/b and th remainder is the output &lt;br /&gt;
        for example 10%3=1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
These may be helpfull in loops, or in any other rational expressions you may use. (Well, it's important for all scripting!)&lt;br /&gt;
Now, recall this line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The output for this is: The fish was (size here) centimeters long!&lt;br /&gt;
The script NEEDS to know where a variable is, so if you want to put it in between a string you surround it with the '@' symbol. Or if it's at the end, you only put the '@' at the beggining of the variable. The variable and the '@' do NOT go in the quotes. Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  this.chat=&amp;quot;Well hi there, &amp;quot; @player.account@ &amp;quot; I like your sword, &amp;quot; @player.swordimg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This would display the player's account, and sword image.&lt;br /&gt;
&lt;br /&gt;
Now, back to the 'for' loop.&lt;br /&gt;
This a very interesting loop it's format is as follows:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for(command;expression;command)&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here's an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayertouchsme()&lt;br /&gt;
{&lt;br /&gt;
  for(this.i=0;this.i&amp;lt;10;this.i++)&lt;br /&gt;
  {&lt;br /&gt;
    chat=&amp;quot;Loops: &amp;quot; @this.i;&lt;br /&gt;
    sleep(.5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This loop would be activated when the player touchs it.&lt;br /&gt;
It would go through 10 loops, displaying the count, and taking .5 seconds for each loop (due to the sleep() command)&lt;br /&gt;
Now remember this while loop?&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  this.size=10;&lt;br /&gt;
}&lt;br /&gt;
while(this.size&amp;lt;=20)&lt;br /&gt;
{&lt;br /&gt;
  chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  //as the story is retold....&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
  this.size=this.size+1;&lt;br /&gt;
  //increment the size&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There's an easier way of doing it with a for loop, in fact all loops done with while can be replaced by for.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for(this.size=10;this.size&amp;lt;=20;this.size++)&lt;br /&gt;
{&lt;br /&gt;
  chat=&amp;quot;The fish was &amp;quot; @this.size@ &amp;quot; centimeters long!&amp;quot;;&lt;br /&gt;
  sleep(.5);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See? Much shorter and easier to use!&lt;br /&gt;
Once you know the format of a for loop, you can make longer and more complex loops as well, and they'll take less time to script, which is always a bonus.&lt;br /&gt;
&lt;br /&gt;
Some more detail on actions:&lt;br /&gt;
An action is an effective way to use a portion of script more than once, have one script act on another script, more script to serverside from clientside (and the other way) and more.&lt;br /&gt;
So how do you use them? Here's the format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
triggeraction(x,y,&amp;quot;params[0]&amp;quot;,&amp;quot;params[1]&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You must have two parameters, but you can have as many as you want a quick example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActiontrigger()&lt;br /&gt;
{&lt;br /&gt;
  player.chat=&amp;quot;Account: &amp;quot; @params[1]@ &amp;quot; Sword &amp;quot; @params[2]@ &amp;quot; head: &amp;quot; @params[3];&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayerchats()&lt;br /&gt;
{&lt;br /&gt;
  if(player.chat==&amp;quot;Who am I?&amp;quot;) //amnesia? multiple identities?&lt;br /&gt;
  {&lt;br /&gt;
    triggeraction(x,y,&amp;quot;trigger&amp;quot;,player.account,player.swordimg,player.headimg);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See? You can make more than one parameter.&lt;br /&gt;
Now, there are a few differences between a level NPC with a triggeraction, and a weapon with a triggeraction. Weapons need their location (serverside or clientside) as the first parameter, params[0] is the one after it. Here, you can have just one parameter, and the x and y is always 0 (because the npc server is at 0,0), and you need to include the name of the weapon in the action.&lt;br /&gt;
here's an example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//weapon script with a triggeraction &lt;br /&gt;
//Weapon name: Fire Ball&lt;br /&gt;
function onActionserverside()&lt;br /&gt;
{&lt;br /&gt;
  if(params[0]==&amp;quot;mp&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    playermp-=10&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onWeaponfired()&lt;br /&gt;
{&lt;br /&gt;
  if(playermp&amp;gt;=10)&lt;br /&gt;
  {&lt;br /&gt;
    shootfireball(playerdir);&lt;br /&gt;
    triggeraction(0,0,&amp;quot;serverside&amp;quot;,&amp;quot;Fireball&amp;quot;,&amp;quot;mp&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    player.chat=&amp;quot;Not enough mp!&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This nifty little weapon will cost 10 mp per use, and fires a fireball in the direction the player is facing. Hopefully, you can learn to make many weapons of your own!&lt;br /&gt;
Triggeractions can be used in shops as well (and these are the scripts people ask for the most).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//a shop script, yay!&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  setshape 1,32,32;&lt;br /&gt;
}&lt;br /&gt;
function onActionbuy()&lt;br /&gt;
{&lt;br /&gt;
  if(playerrupees&amp;gt;=100)&lt;br /&gt;
  {&lt;br /&gt;
    addweapon Fire Ball;&lt;br /&gt;
    playerrupees-=100;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onPlayerchats()&lt;br /&gt;
{&lt;br /&gt;
  if(player.chat==&amp;quot;buy fire ball&amp;quot;)&lt;br /&gt;
  {&lt;br /&gt;
    triggeraction(x,y,&amp;quot;buy&amp;quot;,&amp;quot;buy&amp;quot;); &lt;br /&gt;
    //the level npc triggeraction type&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There, now you can make a little shop that sells a Fire Ball weapon. Have fun with it, search the commands, there's plenty of easy weapons you can make, and the weapon script is easy to follow and modify as well. Hopefully, you know enough about parameters to make more than one weapon for sale in the same NPC, just make the weapon name part of the action, then check for that parameter before they can buy. &lt;br /&gt;
 Now there are other types of loops. One I commonly see is a timeout loop. You should understand why. Back with GS1, it was a bit easier to tell what was happening in the script. In GS1 the script for function onTimeout() would be displayed as if(timeout). It was a bit easier to tell that when a timeout was done, it set a flag that if(timeout) would check. function onTimeout does the same thing, however, for new users this may be harder to tell. here's an example of an NPC that uses a timeout loop:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//#CLIENTSIDE&lt;br /&gt;
function onCreated()&lt;br /&gt;
{&lt;br /&gt;
  settimer(1);&lt;br /&gt;
}&lt;br /&gt;
function onTimeout()&lt;br /&gt;
{&lt;br /&gt;
  player.chat=&amp;quot;Counter: &amp;quot; @this.time;&lt;br /&gt;
  this.time++;&lt;br /&gt;
  settimer(1); &lt;br /&gt;
//after 1 second, the timeout loop will restart&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This would cause the player to count up every second.&lt;br /&gt;
You may have noticed that the variables often start of with client. or this. There are actually a few prefixes, each does a different thing:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
client. variable is saved to the client, it can be modified on the clientside or serverside, and read from either.&lt;br /&gt;
clientr. variables can be rad from server or clientside, but only written from serverside. This is more secure, but only if you use it right.&lt;br /&gt;
server. variables are saved to the server, can only be written on the serverside, read on either side&lt;br /&gt;
serverr. more secure version of server. read only on clientside&lt;br /&gt;
this. is a variable that only functions in the NPC it is in. This prevents NPCs from morifying each others variables&lt;br /&gt;
temp. only exists in between the brackets of a function&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To use scripts effectivly, you should know how to use each of these.&lt;br /&gt;
I will add more over time.&lt;br /&gt;
&lt;br /&gt;
Some important commands can be found here:&lt;br /&gt;
page:http://wiki.graal.net/index.php/Creation/Dev/Script/Starting_Guide#Introduction&lt;br /&gt;
Which is also helpful for learning how to script. Enjoy!&lt;/div&gt;</summary>
		<author><name>Twinny</name></author>
	</entry>
</feed>