Scripting course

Table of Contents


This course will teach you how to write simple scripts for Planet.

In each 3D object, you can add scripts that run and make the object come alive.

Chapter 1: first script

To create a script:



      // my first script

      event start ()
      {
        say ("Salut les amis !");
        say ("Comment allez-vous ?");
      }


Click on the "Apply" button: the script compiles and runs and displays on the Conversation dialog :

  Salut les amis !
  Comment allez-vous ?

There, you have written your first script!

1.1 explanations

Let's take a closer look at this first program.

  // mon premier script

The first line begins with the // sign, indicating a comment. It is therefore ignored.

  event start ()

The second line is a trigger.

Event means happening, so if something happens, the script wakes up and executes the lines between braces. The start event is triggered automatically when the script starts.

  {
    say ("Salut les amis !");
    say ("Comment allez-vous ?");
  }

The braces { } surround a sequence of instructions to be executed. the say() instruction is used to display text on the chat. Each instruction must end with a semicolon (;).

say is actually a function. To execute it, you simply give its name (here say) and any arguments in brackets (here "Salut les amis !"). If there are no arguments, simply add a pair of empty parentheses ().

1.2 event start

event start() is an event triggered when the script starts. There are many other events, such as event touch(), which is triggered when the object is clicked. Or event collision() when the avatar collides with the object.

Chapter 2: Errors

During the compilation of the script, it is fully checked and verified, which can make syntax errors appear.

For example if you had forgotten the final brace } at the end, you would get an error message at the bottom which tells you exactly where the problem is:

line 5 col 1 : syntax error : '}' expected here

Then just go to line 5 column 1 of your script, correct the text, and click "Apply" again.

Chapter 3: style

To avoid syntax errors and also to facilitate reading it is important to have a clear writing style.

Example :

// my second script

event start ()
{
  string(32) s;
  int        i;

  s = "";
  for (i=0; i<16; i++)
  {
    s = s + chr(0,i);
  }
  say ("icons : " + s);
}

You can see, in the example above, that the lines between braces { } are each time shifted by two blanks to the right. In addition, a curly bracket { is always located vertically above a curly bracket }. This is a habit you should definitely get into, it prevents you from forgetting braces!

The following script also works but is not recommended because it is not understandable!

Example :

// my 3rd script (not recommended)

event start ()
{
string(32) s;
int        i;

s = "";
for (i=0; i<16; i++)
{
s = s + chr(0,i);
}
say ("icons : " + s);
}

When you post a script on a group or a forum, change the font to "Courier New" because with this font because with this font the offsets are preserved.

The importance of comments

Feel free, to clarify a script, to add lots of comment lines anywhere in your script.

It is enough to start a line with //.

These lines are ignored by the compilation.

Example:

// here is my first script
// that I created to animate
// a little bit my room.

// Copyright the scriptwriter

event start ()
{
  // the say command will display a text on the chat !
  say ("Salut les amis !");
}


Chapter 4: integer variables

A variable is a cell in the PC's RAM memory that is given a name.

Each numeric variable contains a value between -2147483648 and +2147483647 (a little over 2 billion).

This value usually changes as the program runs.

To create a numeric variable, it must be 'declared', i.e. reserve memory space for its contents, using an 'int' declaration.

  int compteur;    // I create my counter

To put a value in a variable, we write an 'assignment' that looks like this:

  compteur = 2;   // now, counter has the value 2

To change the value of a variable, you just have to give it a new value:

  compteur = 5;   // now, counter has the value 5

You can also make calculations. In the following example you can see in each line:
. to the left of the = sign, the variable where the result of the calculation will be stored,
. to the right of the = sign, a formula for the value to be calculated.

  compteur = 2 + 5 * 7;    // now, counter has the value 37
  compteur = 5 / 2;        // now, counter has the value 2
  compteur = -45;          // now, counter has the value -45
  compteur = 100 - 101;    // now, counter has the value -1

You have probably guessed that the asterisk is used to multiply. Here is a list of commonly used symbols commonly used: (learn by heart!)

    operation                 symbol
    ----------------------    -------
    addition                     +
    subtraction                  -
    multiplication               *
    division                     /
    remainder of the division    %

If you are paying attention, you may also have been surprised that the previous example gives result 37 and not 49.

  compteur = 2 + 5 * 7;      // now, counter has the value 37

The reason is that, as in mathematics, multiplication and division are done first, while addition and subtraction come next. If you are not sure about the priority of the operations, you can add parentheses to force the order of the calculations, for example like this :

  compteur = (2 + 5) * 7;      // now, counter has the value 49

Also, the previous example must have puzzled you.

  compteur = 5 / 2;        // now, counter has the value 2

Indeed the result of 5 divided by 2 is 2, we ignore the fractional part because counter is of type 'int' and can only store integers.

Let's also mention the "shift" operators:

  compteur = 3 << 3;       // now, counter has the value 24
  compteur = 35 >> 1;      // now, counter has the value 17

The operators << and >> multiply or divide by a power of 2. Thus (a << b) is equivalent in mathematics to    a . ( 2 b )   and (a >> b) is equivalent to    a / ( 2 b )

Here is how to increase the value of a variable by 1:

  compteur = compteur + 1;     // computes compteur + 1 and stores the result in compteur

However, there is an abbreviated way to do the same thing, the incrementing :

  compteur++;     // increases compteur by 1

In the same way, to decrease a variable by 1, we do a decrement.

  compteur--;     // decreases compteur by 1

Here is how to increase the value of a variable by 10:

  compteur = compteur + 10;     // calculates compteur + 10 and stores the result in compteur

However, there is an abbreviated way of doing the same thing, the assignment with addition:

  compteur += 10;     // increases compteur by 10

In the same way, to decrease a variable by 10 :

  compteur -= 10;     // decreases compteur by 10

To multiply a variable by 3 :

  compteur *= 3;     // multiplies compteur by 3

There is an operation that stops the script with an error, it is to divide by zero, it is prohibited!

  compteur = 3 / 0;     // error
  compteur = 3 % 0;     // error

Chapter 5 : floating-point variables

After having studied the 'int' type in the previous chapter, we will now see the 'float' type which is used to store fractional numerical variables.

Example:

  float f;
  f = 15.2476;
  f = 67.762 + 87.126;
  f *= 1.2;

You will notice that with the 'float' type, the numbers always have a mandatory dot, even if there is no part after the comma. For example to specify the value 12 you would write 12.0

A variable of type 'float' can store very large numbers, up to 38 digits. However, it takes the same space in RAM as a variable of type 'int'. How is this possible?

In fact a 'float' variable only stores the 6 or 7 most significant digits of the value, as well as an exponent which indicates how many zeros to add.

  f = 3.12345678901234567890;  // will be stored as 3.12345600000000000
  f = 3.12e8;                  // f equals 3.12 x 10_exponent_8, so 31200000.0
  f = 0.5;                     // f equals a half
  f = 5.0e-1;                  // f equals a half too

On Planet, the 'float' type is widely used, to store distances in meters, rotation angles or times in seconds.

Type 'float' allows the following operations :

    operation                 symbol
    ----------------------    -------
    addition                     +
    subtraction                  -
    multiplication               *
    division                     /

Furthermore, the following functions are available :

  float     fabs  (float value);        // absolute value

  float     sin   (float angle);        // sin, with angle in degrees
  float     cos   (float angle);        // cos, with angle in degrees
  float     atan2 (float y, float x);   // arc tangent, calculates an angle in degrees

  float     sqrt  (float angle);        // square root    
  float     trunc (float angle);        // remove the fractional part by truncating
  float     round (float angle);        // remove the fractional part by rounding

  string ftos (float  value, int width=0, int decimals = 3);   // convert a float to a string

Example:

  event start()
  {
    float n = sin(34.0);
    say ("sin(34) = " + ftos(n));
  }

  // which will display : sin(34) = 0.55919

Chapter 6: string variables

There is a 3rd kind of variable : string variables.

These do not contain numbers but strings of characters (letters, numbers, punctuation, etc ...).

Example:

  string(100) nom;        // I create a string variable of maximum 100 characters

To change the value of a string variable, we perform an 'assignment which looks like this:

  nom = "Bonjour";     // now, name has the value "Bonjour"

Note that the value is enclosed in quotation marks.

To change the value of the variable, simply give it a new value:

  nom = "Bonsoir";      // now, name has the value "Bonsoir"

You can paste several strings together with the "+" operator.

  nom = "Bon" + "soir";      // now, name has the value "Bonsoir"
  nom = nom + " mes amis";   // now, name has the value "Bonsoir mes amis"

Warning: the length of a string variable cannot exceed 1024 characters.

To delete a string variable, you can assign an empty string to it.

  nom = "";       // now, nom is empty

Le type 'string' permet les opérations suivantes :

  int    len   (string value);                          // calcule la longueur de la chaine
  string chr   (int c1, int c2, int c3, ..., int c16);  // convert ascii codes to string
  int    asc   (string value, int index=1);             // convert the nth character of the string into ascii code
  string left  (string value, int count);               // take the first N characters
  string right (string value, int count);               // take the last N characters
  string mid   (string value, int index, int count=);   // take the N characters starting at the ith
  int    pos   (string phrase, string word);            // find the position of a string in another
  string dup   (string value, int count);               // duplicate a string N times
  string upper (string value);                          // removes accents and converts to uppercase
  string lower (string value);                          // removes accents and converts to lower case
  string trim  (string value);                          // removes spaces before and after
  string ltrim (string value);                          // removes spaces before
  string rtrim (string value);                          // removes spaces after

Chapter 7: Conversions

We can convert a numerical variable into a string variable using the itos() function. This name actually means i to s, so int to string.

Example:

  int        compteur;
  string(32) nom;

  compteur = 12;

  nom = itos(compteur);    // now, nom is "12"

  nom = "compteur = " + itos(compteur);    // now, nom is "compteur = 12"

Conversely, a string variable can be converted into a numeric variable using the stoi() function.

  int        compteur;
  string(32) nom;

  nom = "12";

  compteur = stoi (nom);      // now, nom is 12

  compteur = stoi ("13");     //  now, nom is 13

  compteur = stoi ("ab");     //  this will give an error that stops the script,
                              //  because "ab" cannot be converted to a numerical value!

Chapter 8: Screen display

The display in the Conversation window is done with the say() procedure

Example:

  say ("Bonjour !");
  say (nom);

It is not allowed to give say() a numeric variable, for example this will not work:

  say (compteur);         // error

To display the counter value, you must first convert it into a string:

  say (itos(compteur));

This can be combined by pasting several strings together:

  say ("la valeur de compteur égale " + itos(compteur));

Chapter 9: the IF statement

Conditions are used to "test" variables.

We can for example say "If the variable is equal to 50, do this"...

But it would be a shame to be able to test only the equality!

It should also be possible to test if the variable is less than 50, less than or equal to 50, greater than, greater than or equal to...

Don't worry, the scripting language has foreseen everything (but you didn't doubt it)

Before you see how to write an "if... else" condition, you need to know 2-3 basic symbols. These symbols are essential to create conditions.

Here is a small table of symbols to know by heart:

  Symbol  Meaning
  ======= =============
     ==    Is equal to
     >     Is greater than
     <     Is less than
     >=    Is greater than or equal to
     <=    Is less than or equal to
     !=    Is different from

Be very careful, there are 2 symbols "==" to test the equality. A common mistake that beginners make is to put only one = symbol. I'll talk about this a little further down.

A simple if

Now let's get started without further ado. We'll do a simple test, which will tell the computer:

IF the variable is this
THEN do this

For example, we could test a variable "age" which contains your age. Here, to practice, we will test if you are of age, i.e. if your age is higher or equal to 18 :

Example:

  if (age >= 18)
  {
    say ("You are of age!");
  }

The symbol >= means "Greater than or equal to", as seen in the table earlier.

If there is only one statement between the braces, then they become optional.
So you can write :

  if (age >= 18)
    say ("You are of age!");

If you want to test the previous codes to see how the if works, you have to place the if inside a start event and don't forget to declare a variable age to which we will give the value of our choice.

It may seem obvious to some, but apparently it wasn't to everyone so I added this example:

  // Example:

  event start ()
  {
    int age;

    age = 20;

    if (age >= 18)
      say ("You are of age!");
  }

Here, the age variable is 20, so the "You are of age!" will be displayed.

Try changing the initial value of the variable to see. Put for example 15 : the condition will be false, and so "You are of age !" will not be displayed this time.

Use this base code to test the next examples in the chapter.

A matter of cleanliness

It doesn't matter how you place the braces, your program will work just as well if you write everything on one line.

For example :

  if (age >= 18) {  say ("You are of age!"); }

However, even if it is possible to write like that, it is not recommended ! Indeed, writing everything on the same line makes your code difficult to read.

If you don't get into the habit of airing out your code now later on when you write bigger programs you won't find your way around!

So try to present your source code the same way I do: a brace on one line, then your instructions (preceded by two blanks to "shift them to the right"), then the closing brace on one line.

There are several good ways to present your source code.

It doesn't change the way the final program works, but it's a matter of "computer style" if you will. If you see someone else's code presented a little differently, they are coding with a different style.

The main thing is that its code remains clean and readable.

The "else" to say "otherwise"

Now that we know how to do a simple test, let's go a step further: if the test didn't work (it's false), we'll tell the computer to execute other instructions.

In English, we will write something like this:

IF the variable is this
THEN do this
ELSE do this

Just add the word else after the closing brace of the if.

Small example :

  if (age >= 18) // If age is greater than or equal to 18
  {
    say ("You are of age!");
  }
  else   // Else ...
  {
    say ("Oh it's silly, you are a minor!");
  }

Things are quite simple: if the age variable is greater than or equal to 18, we display the message "You are of age!", otherwise we display "You are a minor".

The "else if" to say "otherwise if"

We have seen how to make an "if" and an "else". It is also possible to make an "else if".

In this case we say to the computer:

IF the variable is this THEN do this
ELSE IF the variable is this THEN do this
THEN do that

Translation:

  if (age >= 18)       // If age is greater than or equal to 18
  {
    say ("You are of age!");
  }
  else if (age > 4)    // Otherwise, if the age is at least 4
  {
    say ("Well, you're not too young after all...");
  }
  else                 // otherwise...
  {
    say ("Aga gaa aga gaaa gaaa");   // Language Baby, you can't understand ;o)
  }

The computer runs the tests in order:

First it tests the first if : if the condition is true, then it executes what is between the first braces.

If not, it goes to the "else if" and tests again: if this test is true, then it executes the corresponding statements between the braces.

Finally, if none of the previous tests worked, it executes the "else" instructions.

The "else" and the "else if" are not mandatory. To make a condition, you just need at least one "if" (logical, you might say, otherwise there is no condition!)

Note that you can put as many "else if" as you want. So we can write :

IF the variable is this THEN do this
ELSE IF the variable is this THEN do this
ELSE IF the variable is this THEN do this
ELSE IF the variable is this THEN do this
THEN do that

Several conditions at once

It may also be useful to run several tests at once in your yew.

For example, you would want to test if the age is greater than 18 AND if the age is less than 25.

To do this, you'll need to use some new symbols:

  Symbol   Meaning
  ======= =============
    &&       AND
    ||       OR
    !        NOT

AND Test

If we want to do the test I mentioned above, we have to write :

  if (age > 18 && age < 25)

The two symbols "&&" stand for AND.

Our condition would be said in English:

"If age is over 18 AND age is under 25"

OR Test

To make an OR, we use the 2 signs ||. I must admit that this sign is not easily accessible on our keyboards. To type it on a French AZERTY keyboard, you have to press Alt Gr + 6. On a Belgian keyboard, you have to press Alt Gr + &.

Let's imagine a stupid program that decides if a person has the right to open a bank account. It is well known that to open a bank account, it is better not to be too young (we will say arbitrarily that you have to be at least 30 years old) or to have a lot of money (because even at 10 years old you will be accepted with open arms)

Our test to see if the client has the right to open a bank account could be :

  if (age > 30 || argent > 100000)
  {
    say ("Welcome to Scrooge Bank!");
  }
  else
  {
    say ("Get out of my sight, you wretch!");
  }

This test is only valid if the person is over 30 years old or has more than 100,000 euros.

NOT Test

The last symbol we have left to test is the exclamation mark.

In computer science, the exclamation point means "No".

You must put this sign before your condition to say "If this is not true":

Example:

  if (!(age < 18))

This could be translated as "If the person is not a minor".

If the "!" had been removed in front, it would have meant the opposite: "If the person is a minor".

Some common beginner's mistakes

Do not forget the 2 signs ==

If you want to test if the person is just 18 years old, you should write :

  if (age == 18)
  {
    say ("You just came of age!");
  }

Don't forget to put 2 "equal" signs in an if, like this : ==

The semicolon too much

Another common beginner's mistake: you sometimes put a semicolon at the end of the line of an if. However, an if is a condition, and you only put a semicolon at the end of a statement, not a condition.

The following code will not work as expected because there is a semi-colon at the end of the if :

  if (age == 18); // Note the semicolon here that should NOT be there
    say ("You've just come of age");

The computer will interpret the above erroneous example as follows:

  if (age == 18)
    ; // Note the semicolon here that should NOT be there
  say ("You've just come of age");

This means that the say() will always be executed, regardless of the result of the if!

Booleans, the heart of the conditions

We will now go into more detail on how an if... else condition works.

Indeed, the conditions involve something called Booleans in computer science.

This is a very important concept, so open your ears (or rather your eyes)

Some small tests to understand

In Physics and Chemistry class, my teacher used to make us start with some small experiments before introducing a new concept. I'm going to imitate him a little today.

Here is a very simple source code that I ask you to test:

  if (true)
  {
    say ("It's true");
  }
  else
  {
    say ("It's false");
  }

Result:

  It's true

But ??? We didn't put a condition in the if, just true. What does that mean that it doesn't make sense?

Yes, it does, you will understand.

Do another test now by replacing the true with a false :

  if (false)
  {
    say ("It's true");
  }
  else
  {
    say ("It's false");
  }

Result:

  It's false

Explanations are needed

In fact, every time you do a test in an if, that test returns true if it is true, and false if it is false.

For example :

  if (age >= 18)

Here, the test you are doing is "age >= 18".

Suppose that age is 23. Then the test is true, and the computer somehow "replaces" "age >= 18" with true.

Then the computer gets (in its head) an "if (true)".

When the value is true, as we have seen, the computer says that the condition is true, so it displays "This is true"!

In the same way, if the condition is false, it replaces age >= 18 by false, and so the condition is false: the computer will read the "else" instructions.

A test with one variable

Now try another trick: send the result of your condition to a variable, as if it were an operation (because for the computer, it is an operation!).

Example:

  int  age;
  bool majeur;

  age = 20;

  majeur = age >= 18;

  if (majeur)
    say ("adult");
  else
    say ("minor");

As you can see, the condition age >= 18 has returned true because it is true. Therefore, our majeur variable is true.

Do the same test by setting age = 10 for example. This time, majeur will be false.

This "majeur" variable is a boolean! You can see that we declared it with :

  bool majeur;

Remember this: We say that a variable which is given the values false and true is a boolean.

Booleans in conditions

Often, we will do an "if" test on a boolean variable:

  bool majeur;

  majeur = true;

  if (majeur)
  {
    say ("You are of age !");
  }
  else
  {
    say ("You are a minor");
  }

As majeur is true, the condition is true, so we display "You are of age !"

What is very convenient is that the condition is easily read by a human being.

We see "if (majeur)", which can be translated as "If you are majeur".

Tests on booleans are therefore easy to read and understand, as long as you have given clear names to your variables.

Here's another imaginary test:

  if (majeur && garcon)

This test means "If you are of age AND you are a boy".

garcon is here another boolean variable which is true if you are a boy, and false if you are... a girl! Congratulations, you've understood everything!

Booleans are therefore used to express whether something is true or false.

This is very useful, and what I have just explained will help you understand a lot of things later.


The "if... else" condition we just saw is the most commonly used condition type.

In fact, there are not 36 ways to make a condition. The "if... else" handles all cases.

Example:

  if (age == 2)
  {
    say ("Hi baby !");
  }
  else if (age == 6)
  {
    say ("Hi kid !");
  }
  else if (age == 12)
  {
    say ("Hello young person !");
  }
  else if (age == 16)
  {
    say ("Hi teenager !");
  }
  else if (age == 18)
  {
    say ("Hi adult !");
  }
  else if (age == 68)
  {
    say ("Hi Grandpa !");
  }
  else
  {
    say ("I have no sentence ready for your age ");
  }

The switch statement

If you need to test a sequence of equalities as in the example above, there is also the 'switch' instruction which allows you to rewrite this more cleanly:

  switch (age)
  {
    case 2:
      say ("Hi baby !");
      break;
  
    case 6;
      say ("Hi kid !");
      break;

    case 12:
      say ("Hello young person !");
      break;
      
    case 16:
      say ("Hi teenager !");
      break;
      
    case 18:
      say ("Hi adult !");
      break;

    case 68:
      say ("Hi Grandpa !");
      break;
      
    default:
      say ("I have no sentence ready for your age ");
      break;
  }

Tests with other types

Conditions can also be applied to 'float' and 'string' types.

For example we will write (f >= 1.0 && f <= 2.0) to test if f is between 1 and 2.

In the same way (name >= "TREE" && name <= "CROCO") will test if name is between TREE and CROCO in lexicographical order (dictionary order).

Chapter 10: Loops

What is a loop?

It is a technique that allows you to repeat the same instructions several times.

As with conditions, there are many ways to make loops.

In the end, it all boils down to doing the same thing: repeating the same instructions a certain number of times.

In all cases, the pattern is the same:

        <----------
  Instructions     ^
  Instructions     ^
  Instructions     ^
  Instructions     ^
        -----------^

Here is what happens in order:

The computer reads the instructions from top to bottom (as usual)

Then, when it reaches the end of the loop, it starts again at the first instruction

It then starts reading the instructions again from top to bottom...

... And it goes back to the beginning of the loop.

The problem in this system is that if you don't stop it, the computer is able to repeat the instructions ad infinitum!

It is not the kind of computer to complain, you know, it does what it is told to do.

And that's where we find... conditions! When we create a loop, we always indicate a condition.

This condition will mean "Repeat the loop as long as this condition is true".

There are several ways to do this as I said. Let's see without further ado how to make a "while" loop.

The while loop

Here is how to build a while loop:

  while ( Condition )
  {
      // Instructions to repeat
  }

It's as simple as that. While means "As long as".

So we tell the computer "As long as the condition is true: repeat the instructions between braces".

We want our loop to repeat a certain number of times.

To do this, we will create a "counter" variable which will be 0 at the beginning of the program and that we will increment as we go along.

Do you remember the incrementation? It consists in adding 1 to the variable by doing "variable++;".

Look carefully at this piece of code and, above all, try to understand it:

  int compteur;

  compteur = 0;

  while (compteur < 5)
  {
    say ("Salut !");
    compteur++;
  }

Result :

  Salut !
  Salut !
  Salut !
  Salut !
  Salut !

This code repeats the "Salut!" display 5 times.

How does it work exactly ?

At the beginning, we have a counter variable initialized to 0. It is therefore 0 at the beginning of the program.

The while loop orders the repetition AS LONG AS the counter is lower than 5.

As the counter is 0 at the beginning, we enter the loop.

We display the sentence "Salut!" via a say.

We increase the value of the variable counter, thanks to the instruction "counter++;".

compteur was worth 0, it is now worth 1.

We arrive at the end of the loop (closing brace), we thus start again at the beginning, at the level of the while.

We redo the test of the while: "Is the counter always lower than 5?

Well yes, compteur is 1 So we start again the instructions of the loop.

And so on... compteur will be progressively 0, 1, 2, 3, 4, 5.

When compteur is 5, the condition "compteur < 5" is false.

As the instruction is false, we leave the loop.

We can see that the compteur variable increases as we go along in the loop, by displaying it with a say :

  int compteur;

  compteur = 0;

  while (compteur < 5)
  {
    say ("the counter variable is " + itos(compteur));
    compteur++;
  }

This will display:

the counter variable is 0
the counter variable is 1
the counter variable is 2
the counter variable is 3
the counter variable is 4

There, if you understood that, you've got it. You can have fun increasing the limit of the number of loops ("< 10" instead of "< 5").

Beware of infinite loops

When you create a loop, always make sure that it can stop at some point! If the condition is always true, your program will never stop!

Here is an example of an infinite loop:

  while (true)
  {
    say ("infinite loop");
  }

Remember booleans. Here, the condition is always true, so this program will display "infinite loop" all the time!

So be very careful : avoid at all costs to fall in an infinite loop.

The for loop

In theory, the while loop allows you to make all the loops you want.

However, in some cases it is useful to have another loop system that is more "condensed" and faster to write.

For loops are very much used in programming.

I don't have any statistics at hand, but you will probably use as many for loops as while loops, so you will have to know how to handle these two types of loops.

As I said, for loops are just another way of doing a while loop.

Here is a while loop beispiel that we saw earlier:

  int compteur;

  compteur = 0;

  while (compteur < 10)
  {
    say ("Salut !");
    compteur++;
  }

Here is the equivalent in a for loop:

  int compteur;

  for (compteur = 0 ; compteur < 10 ; compteur++)
  {
    say ("Salut !");
  }

What are the differences?

There are many things between the parenthesis after the for (we will detail this later)

There is no more counter++; in the loop.

Let's look at what is between the parentheses, because that's where all the interest of the for loop lies. There are 3 condensed instructions, each separated by a semicolon:

The first one is the initialization: this first instruction is used to prepare our counter variable. In our case, we initialize the variable to 0.

The second one is the condition: as for the while loop, it is the condition that says if the loop must be repeated or not. As long as the condition is true, the for loop continues.

Finally, there is the increment: this last instruction is executed at the end of each loop to update the counter variable.

Almost all the time we will do an increment, but we can also do a decrement (variable--;) or any other operation (variable += 2; to advance from 2 to 2 for example).

In short, as you can see the for loop is nothing more than a condensed version of the while loop. Know how to use it, you will need it more than once!

the break instruction

The break instruction is used to abandon and leave a loop.

  for (i=0; i<5; i++)
  {
    if (i == 3)
      break;       // exit here
    say (itos(i));
  }

will display

0
1
2

the continue instruction

The continue instruction is used to go straight to the next loop.

  for (i=0; i<5; i++)
  {
    if (i == 1 || i == 3)
      continue;
    say (itos(i));
  }

will display

0
2
4

Chapter 11: Events

In the previous chapters, you were able to write scripts that ran by themselves and completely ignored the avatars.

Now we'll move on to another kind of script: those that interact with avatars and respond to them!

Indeed, avatars cause actions, for example :
- they click on the object
- they write lines of text
etc ...

Each time an action occurs, the corresponding event is executed.

Example :

  // react with a message when the chatter touches the object
  event touch()
  {
    say ("Bienvenue " + avatar_name(touched_avatar()));
  }

In the event, we have access to a whole bunch of parameters about the action: for example touched_avatar() returns a key about the avatar that touched. We can pass this key to the avatar_name() function to get the name of the touched avatar.

Global variables

You should know that 99% of the time, a script does nothing, it sleeps!

But as soon as an avatar causes an action, the script wakes up!

It then executes the few instructions contained in an event (for example it displays a message), and when it is finished, the script goes back to sleep waiting for the next action.

Between two actions, so while it sleeps, the script has completely lost its memory, i.e. all variables are reset to zero!

There is only one exception to this rule, and that is the global variables (those declared at the top of the script). These are very useful because they keep their value as long as the script is running!

However, you should know that global variables increase the cost of the script, while those declared at the bottom of the script cost nothing. So you should only use global variables if their value must be kept between 2 events.

The following script tells each avatar how many avatars have touched the object before him. To do this, it uses a variable declared at the top of the script.

  // a script that counts the chatters

  int g_compteur = 0;

  event touch()
  {
    say ("Bienvenue " + avatar_name(touched_avatar()));
    g_compteur++;
    say ("you are the " + itos(g_compteur) + " person who touches me since my script is running");
  }

Often, variables declared at the very top of the script start with g_ to indicate global. This is not mandatory but is a convention among computer scientists.

Chapter 12: Arrays

Instead of reserving a single variable, you can also reserve a whole array of variables.

Example:

  int[100] compteur;       // I create 100 counters

In fact, the above example creates the following 100 counters:

  compteur[0]
  compteur[1]
  compteur[2]
  compteur[3]
  ...
  compteur[99]

To clear the whole table at once (set all counters to zero), we use the clear instruction :

  clear compteur;

You can store values in these counters, like this:

  compteur[5] = 12;    // store 12 in counter number 5

  compteur[5]++;       // increase counter 5 by 1

  compteur[i] = 13;    // store 13 in the counter i

The last example above will give a script error if the variable "i" does not have a value between 0 and 99.

Chapter 13: Structures

Structures are another mechanism to declare several variables, but of a different type. For example here we will create an INFO structure composed of two fields : name and cost :

struct INFO
{
  string(32) name;
  int        cost;
}

Once the structure is created, we can declare variables of it, for example :

INFO info;

and it can be assigned values:

  info = {name => "Marc", cost => 10};

To access only one field of the structure, a dot is used followed by the name of the field. Example:

  say (info.name);

We can combine structure and array, for example we can declare an array of 100 INFO structures:

  INFO[100] table;

To delete a large variable at once, the clear instruction is convenient:

  clear table;

To write the value 2 in the cost field of the 5th element of the table, we will write :

  table[5].cost = 2;

Chapter 14: Functions

What is a function? Well, for example "atan2()", which allows you to calculate the arc-tangent.

  float f = atan2 (30.0, 40.0);

You also know "say()", which allows to display a text on the screen.

  say ("hello");

These two functions are declared with the following formalism:

  float atan2 (float y, float x);
  void say (string s);
This formalism indicates that :

In fact a function that starts with void is a command, while a function without void calculates a result. Apart from that, the two are very similar.

Let's look at some common functions to see how they work:

date_time now ();        // function that calculates the current date

int rnd (int a,int b);   // returns a random number between a and b

The now() function is simple: it has no parameters and calculates the date and time of the PC. For example we can write :

event start()
{
  date_time  ma_date;

  ma_date = now();   // put the date in my_date

  say (itos(ma_date.day, 2, "0")
        + "/"
        + itos(ma_date.month, 2, "0")
        + "/"
        + itos(ma_date.year, 2, "0"));
}

which will print for example:

  02/12/2020

The rnd() function allows to draw a random number, which is very useful for games.

Example:

event touch()
{
  int i;
  i = rnd (1, 100);   // choose a number from 1 to 100 to put in i
  say ("on choisit " + itos(i));
}  

In the documentation of the script language, you will find lists of all the predefined procedures and functions.

Create your own functions

You can also create your own functions. For example, if we wanted to create a function tan() that calculates the tangeant, we could write this:

float tan (float a)
{
  float t = sin (a) / cos (a);
  return t;
}

You can see that we declared the function with the formalism (but without a semicolon at the end), then between braces we put a sequence of statements to calculate the value, and finally we end the function with the statement "return" which terminates the function and specifies the value of the result.

Here is another function that says hello:

void say_hello (key k)
{
  say ("Hello " + avatar_name (k));
}

event touch()
{
  say_hello (k => touched_avatar());
}

The event touch will call the say_hello function by giving an avatar key as parameter, and this function will display on the screen Hello and the name of this avatar.

If you want to end a void function, you can simply write "return;"


// say hello to women only

void say_hello_to_female (key k)
{
  if (avatar_gender (k) != 1)
    return;
  say ("Hello " + avatar_name (k));
}

event touch()
{
  say_hello_to_female (k => touched_avatar());
}

Here the function tests the gender of the avatar. If it's not a woman the function ends immediately with the return without displaying anything. Otherwise we continue to display the hello.


Chapter 15: Constants

When you use the same value several times in a long script, you can declare this value at the top of the script by a constant. If you change the value, you only have to change it in one place and you can find it easily.

Example: numerical and string constants

const int NOMBRE_DE_PLACES = 4;
const float SECONDES = 30.0;
const string ACCUEIL_1 = "Bonjour, j'ai ";
const string ACCUEIL_2 = " places";

say (ACCUEIL_1 + itos(NOMBRE_DE_PLACES) + ACCUEIL_2);

Often constants are written in capital letters, this is a convention among computer scientists.


Example: array constants

const string(23)[3] MENU1 = {"Jeu contre l'ordinateur", "Play against computer", "Spiel gegen Computer"};


Example: constants of arrays of structures

struct BOISSON
{
  string(16) name;
}

const int MAX_OBJECTS = 5;

const BOISSON G_BOISSON[MAX_OBJECTS] =
{
  {name => "Bière"},
  {name => "Soda coca"},
  {name => "Soda orange"},
  {name => "Becher Kaffee"},
  {name => "Becher Tee"},
};


Chapter 16: the text that repeats itself

Here is a script that repeats a text every 10 seconds.

event start()
{
  start_timer (0, 10.0);
}

event timer (int nr)
{
  say ("Salut les amis !");
  say ("J'espère que vous allez bien :p");

  start_timer (0, 10.0);
}

The procedure start_timer(0, 10.0); means: "start timer number 0 in 10 seconds".

When event timer is executed, it writes the text, and the start_timer retriggers it for in 10 seconds, etc... and it loops!

Chapter 17: The procedure say

The say() procedure allows you to display a text, for example :

  say ("Bonjour !");

You can paste several pieces of text together using the + (plus) operator, for example:

  say ("Bonjour "    +    "Chers Amis !");

well, in this case, we could also have written :

  say ("Bonjour Chers Amis !");

But here is a more interesting case:

  say ("Bonjour "   +   userid   +   " !");

here, we paste the hello and the name of the chatter together.

Note that if you write :

    say (count);

you will get an error because say() only accepts string variables!

To display a value, you must first convert it into text with the itos() function.

Example :

    say ("tu es la " + itos(count) + " personne qui me touche depuis que mon script tourne");

Chapter 18: Writing in Different Fonts and Colors

To write in different styles, you can use these functions :

    color (0xFFFFFF)                                          : changer de couleur
    font (5)                                                  : numéro de font
    style (underlined => true, italic => true, bold => true)  : changer de style souligné italique ou gras

Example:

  // welcome message

  string font(int f)                                     { return chr(1, f); }
  string style(bool underlined, bool italic, bool bold)  { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4;  return chr(2, s); }
  string color(int col)                                  { return chr(4, col & 0xFFFF, col>>16); }

  event touch ()
  {
    say ("big "
       + color(0x8080FF)
       + "kiss"
       + font(9)
       + color(0x00FF00)
       + style(underlined => true, italic => true, bold => true)
       + " from Didi");
  }

This example displays the welcome message in red!

But well, if you display a lot of red text it is not practical.

Because the day you want to change the color, you have to change all the color(0x8080FF) in your program.

What you can do is to write your own color change function.

Example:

  // message d'accueil

  string font(int f)                                     { return chr(1, f); }
  string style(bool underlined, bool italic, bool bold)  { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4;  return chr(2, s); }
  string color(int col)                                  { return chr(4, col & 0xFFFF, col>>16); }

  string ftitle ()
  {
    return color(0x8080FF) + font(8);  // couleur rouge + font Impact
  }

  event touch ()
  {
    say (ftitle() + "Bonjour !");
  }

So if you want to change the colors or the font, you just have to modify the ftitle function.

Here is another example that shows that you can put a whole text in function :

Example:

  // message d'accueil

  string font(int f)                                     { return chr(1, f); }
  string style(bool underlined, bool italic, bool bold)  { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4;  return chr(2, s); }
  string color(int col)                                  { return chr(4, col & 0xFFFF, col>>16); }

  string red ()
  {
    return color(0x8080FF);
  }

  string Impact ()
  {
    return font(8);
  }

  string Bienvenue (string userid)
  {
    return red() + Impact() + "Bienvenue " + userid + " !";
  }

  event touch ()
  {
    say (Bienvenue (avatar_name(touched_avatar())));
  }

Notice in the example above that the userid parameter was passed to the Bienvenue() function because it needed it!

Another solution would have been to use a procedure instead of a function. The difference between the two is very small: a function returns a value or a text, a procedure returns nothing ! (so void)

Example:

  // message d'accueil

  string font(int f)                                     { return chr(1, f); }
  string style(bool underlined, bool italic, bool bold)  { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4;  return chr(2, s); }
  string color(int col)                                  { return chr(4, col & 0xFFFF, col>>16); }

  string red ()
  {
    return color(0x8080FF);
  }

  string Impact ()
  {
    return font(8);
  }

  void Bienvenue (string userid)
  {
    say (red() + Impact() + "Bienvenue " + userid + " !");
  }

  event touch ()
  {
    Bienvenue (avatar_name(touched_avatar()));
  }

Above, you can notice that the say() procedure is no longer in the touch event, but in the procedure Bienvenue.

Chapter 19: Drawing a Random Number

How to display a random welcome message?

Using the rnd() function !

Example:

  // random welcome message

  event touch ()
  {
    int n;

    n = rnd (1, 3);   // draws a random number between 1 and 3

    if (n == 1)
      say ("salut, ça va ?");
    else if (n == 2)
      say ("oula, toi je ne t'aime pas !");
    else
      say ("reviens plus tard, j'suis pas là :p");
  }

Notice here that the variable 'n' has not been declared at the top of the script but in the procedure: it therefore loses its value between two actions while the script is sleeping, this is ok since we do not want to keep it.

Chapter 20: Reading a File

LThe following script will choose a random welcome text from a file you have placed in the script folder of the object :

  // random welcome text

  event touch ()
  {
    // counts the number of lines in the bienvenue.txt file
    int count = count_lines ("bienvenue.txt");

    // draws a random number between 1 and count
    int n = rnd (1, count);

    // extracts the selected line from the file
    string(128) s = read_line ("bienvenue.txt", n);

    // displays the line
    say (s);
  }

Chapter 21: Storing Information on the Server

You know that the variables declared at the top of the script keep their value between two actions. But what happens when the script is changed? They are obviously deleted .

What we need is a way to keep data permanently, on the hard disk ...

We use for that the functions store and fetch which allow to write information on the Planet server then to read them again later.

store (tiroir, valeur);   // stores the value in the server drawer
                          // Example: store ("JEU-DEVINE", "1 35 16 32 89 12");

s = fetch (tiroir);       // returns the value contained in the drawer
                          // Example: fetch ("JEU-DEVINE") == "1 35 16 32 89 12"

How does it work?

Imagine you are in a large library with a wall of drawers in front of you.

On each drawer is written a name.

When you open a drawer you can put a value in it and close it. Later, you can open the drawer again and retrieve the value you put in it.

This is exactly how store and fetch work.

Of course you are free to put whatever value you want in the drawer. This can be a score, points, the number of times a chatter has entered the room, the date and time of his last visit, or any other info.