Program a bot using a script



The 'script' language is available to program the bot; to achieve this,
you must create and put a file SCRIPT.TXT like the one below in the
bot's directory.

--------------------------------------------------------------------------------

// Here's a simple script that says Hello to all newcomers in the room 

proc event (session_key, userid$, sex$, has_photo, age, is_away,
            admin, cam_on, is_bot, toc_capab, signature$, suffix$, profile_life,
            action, is_myself, line$)
{
  if (action == 128)   // action 128 indicates a new arrival in the room
  {
    // the print command is used to display a line on the chat
    print ("Welcome in the room " + userid$ + " :p");
  }
}

--------------------------------------------------------------------------------

notes:
1 - if you modify the script, press the F5 key to reload it.
2 - you can put several files having the ending "SCRIPT.TXT"
    in the bot's directory (for ex: SCRAB-SCRIPT.TXT, ROBOT-SCRIPT.TXT),
    they will then be executed in alphabetical order.


On this script example, you see a procedure "event" that is executed
each time an event occurs in the room.

This procedure "event" receives the following information about
the chatter concerned with the event :


session_key: number associated with the chatter's arrival in the room
             and that will be provided for all its events until
             he leaves the room; the session_key is used, among other things,
             to designated the chatter to be kicked out of the room.
userid$    : name of the chatter
sex$       : kind of the chatter ("M", "F" or "C")
has_photo  : indicates if there's a photo in the profile (0=no, 1=yes)
age        : age of the chatter
is_away    : indicates if he's away (in cup) (0=no, 1=yes)
admin      : indicates if he has currently taken his toc (0=no toc, 1=brown, 2=gold)
cam_on     : indicates if his cam is turned on (0=no, 1=yes, 2=yes and cam was verified by an anim)
is_bot     : indicates if it's a bot (0=no, 1=yes)
toc_capab  : indicates if he's capable of taking his toc (0=no, 1=brown, 2=gold)
signature$ : signature of the chatter, example "1234567890ABCDEF"
suffix$    : signature suffix (after the colon), example : "FAB2"
profile_life : number of days since the profile creation day
action     : event type, see the list below
is_myself  : indicates if the chatter is this bot (thus myself) (0=no, 1=yes)
line$      : contains the text line written by the chatter, see below


possible actions
----------------
Here's a list of all events, with their action number :

action  event
------  -----
    0   chatter writes a normal line of text
    1   chatter writes a line of text with a balloon
    2   chatter goes away (in cup) or comes back
   16   chatter takes or drops the toc
  127   chatter was already in room before this bot entered room
  128   a new chatter enters the room
  129   chatter leaves the room in a normal way / or is teleported to another room
  130   chatter is disconnected
  200   chatter whispers to the bot
  204   the chatter's whisper was blocked with the crossed telephone (line$ contains the blocker's pseudo)
  240   toc-owner gives a temporary toc (line$ contains the 10-digit session_key and the userid of the receiver)
  241   same as 240 but for removing the toc
  256   chatter is kicked out of the room
  300   chatter has clicked on text zone - see chr$(3,a,b,c) below
  400   chatter posted a new message on the group
             (with pannel nr (9 digits), message nr (9 digits), and message subject in line$)
  512   chatter speaks on the microphone
  550   chatter turns his webcam on or off
  601-609 chatter clicked on a chat menu button (see commands to create a button)
  912   chatteur klicked on a 3D actor (line$ contains actor's session_key in 10 digits)
  915   chatter has clicked on a clickable 3D object (line$ contains the 3D-object's number in 1-to-6 digits)


text line line$
---------------
The text line line$ contains printables characters (ascii codes 32 to 255)
but it contains also special 4- or 8-character sequences that begin
with a character between chr$(0) and chr$(9), for example :

chr$(0,n%256,n/256,0)    : emoticon N
chr$(1,red,green,blue)   : color (red green and blue are values between 0 and 255)
chr$(2,font,style,0)     : font or style change (see chapter macros)
chr$(3,a,b,c)            : text zone marker - chr$(3,0,0,0) indicates end-marker
chr$(4,a,b,c)            : (not used for now)
chr$(5,a,b,c)            : (not used for now)
chr$(6,a,b,c,d,e,f,g)    : image jpeg/gif/bmp/png
chr$(7,a,b,c,d,e,f,g)    : son wav
chr$(8,a,b,c,d,e,f,g)    : (not used for now)
chr$(9,a,b,c,d,e,f,g)    : (not used for now)


For example, if you write "Hello" on the chat, userid$ and line$ could contain the following characters :

userid$=[0,11,1,0,6,16,156,56,39,33,252,127,65,0,4,0,0]
line$=[0,50,0,0,0,11,1,0,6,16,156,56,39,33,252,127,65,0,4,0,0,32,58,32,1,12,94,254,2,2,0,0,72,101,108,108,111]


Here's the detail of line$ :

0 50 0 0                  : emoticon 50  ":M"
0 11 1 0                  : emoticon 267 (11 + 1*256) "$nr"
6 16 156 56 39 33 252 127 : image (banner of the chatter)
65                        : character A uppercase
0 4 0 0                   : emoticon 4 ";)"
32                        : a space
58                        : character ':' between pseudo and text line
32                        : a space
1 12 94 254               : a color code (red=12,green=94,blue=254)
2 2 0 0                   : a font code (2=Arial)
72 101 108 108 111        : "Hello" in ascii

More generally, when action==0, line$ has always the following structure :

- an emoticon (or an image if the room owner has drawn its own icons)
- the content of userid$, so the chatter's pseudo, which can contain several
  text, emoticon or image sequences,
- the sequence : space, character ':', space
- then the text line, that can contain any sequence including font and color codes.


The following test script allows you to make tests to understand better the content of line$ :


proc event (session_key, userid$, sex$, has_photo, age, is_away,
            admin, cam_on, is_bot, toc_capab, signature$, suffix$, profile_life,
            action, is_myself, line$)
{
  var i, s$, u$;
  if (!is_myself)
  {
    for (i=1; i<=len(line$); i++)
    {
      if (i > 1)
        s$ = s$ + ",";
      s$ = s$ + str$(asc(line$,i));
    }
    for (i=1; i<=len(userid$); i++)
    {
      if (i > 1)
        u$ = u$ + ",";
      u$ = u$ + str$(asc(userid$,i));
    }
    print ("action=" + str$(action) + " userid$=[" + u$ + "] line$=[" + s$ + "]");
  }
}



Elements of the script language
===============================

Data
====

The script language manipulates two types of data :

1) integer numbers :

        9  -62  136  0xFFD2

Values must be between -2147483647 et +2147483647
The number 0xFFD2 is in hexadecimal format (base 16 instead of the usual base 10).


2) character strings :

       ""   "Bonjour"  "Oui:p"

the first character string here above is an empty string.
the maximum length of a string is 8192 characters.


Variables
=========

A variable is a memory cell of the PC that has received a name;
this memory cell contains a value that can change as the program runs.

Two types of variables exist :

- those that contain an integer number (example: count, i, player)

- those that contain a character string (example: fruit$, user$)
  (those always end with a dollar sign '$')


Before using a variable, you need to 'declare' it, this means to reserve
memory space for its content, using the command 'var'.

example:

  var count;       // will contain a counter
  var user$, t$;   // two string variables
  var fruit$[3];   // a table of 3 strings : fruit$[1], fruit$[2] and fruit$[3]

Variables can be declared,
- either at the beginning of the script,
- or at the beginning of a function or procedure.

If they are declared at the top of the script, they keep their value
between two events; otherwise, they are deleted each time.

By default, numeric variables receive the value zero, and string variables
receive an empty string.



Procedures and Functions
========================

A procedure is a command that can be given parameters, for example 'print'
that can receive the string "Welcome !" which results in :

  print ("Welcome !");

A function looks like a procedure, but it furthermore computes a result,
for example 'len' that computes the length of a string :

  length = len ("abc");


The following standard procedures/functions exist :

bot commands
------------
print ("Welcome !");             // bot sends a text line on the chat
bubble ("thinks he's right :p"); // bot sends a thought (with bubble icon)
away ();                         // bot goes away (in cup) or comes back
toc ();                          // bot takes or drops its toc
kick (session_key, "go to bed"); // bot kicks the chatter having the give session number


Menu button creation commands
-----------------------------
To create a button in the menu that will generate an action 601 to 609
when clicked :

  create_button (session_key, 601, "{lock01}");  // with icon
  create_button (session_key, 602, ":)");        // with smiley
  create_button (session_key, 603, "T");         // with texte

The action 601 to 609 will contain in line$ the chatter's session_key who clicked (in 10 digits),
followed by the text typed on the chat line.

To delete the button :

  delete_button (session_key, 601);


teleportation commands
----------------------
To teleport a chatter in another room (bot must have a Toc) :

    teleport (session_key, x, y, z, dir);            // to simply change 3D coordinates
    teleport (session_key, x, y, z, dir, port);      // IP not necessary if same router or PC
    teleport (session_key, x, y, z, dir, port, ip$);


calendar
--------
d$ = now$ ();           // function that compute today's date
                        // example: now$() == "2007/01/17 12:23:12"

d  = weekday (d$);      // returns the day of the week (1=monday, 7=sunday) corresponding to the date
                        // example: weekday("2007/01/17 12:23:12") == 2

d$ = add_date$ (d$,n);  // returns the date made older by n seconds
                        // example: add_date$("2007/01/17 12:23:12", 3600) == "2007/01/17 13:23:12"

n = nb_days_since_1901 (d$);  // returns the number of days between 1/1/1901 and the provided date,
                              // which can be used to compute the number of days between two dates:
                              // nb_days_since_1901 (date2$) - nb_days_since_1901 (date1$)

numeric
-------
n = random (a,b);       // returns a random number between a and b
                        // example: random(1,50) == 12

n = abs (n);            // returns the absolute value of n
                        // example: abs(-2) == 2

n = sin (angle, M);     // computes the sinus(angle), multiplied by M

n = cos (angle, M);     // computes the cosinus(angle), multiplied by M

angle = atan2 (Y, X);   // compute the angle corresponding to the arc-tangent of (Y / X)

n = sqrt (n, M);        // compute the square root of n, multiplied by M


string
------
n  = len(s$);           // returns the length of string s$
                        // example: len("abc") == 3

s$ = dup$(s$,N);        // returns the string s$ duplicated N times (with N >= 0)
                        // example: dup$("ab",3) == "ababab"

s$ = chr$(N1,N2,N3,..); // returns a string built by concatenating the ascii characters N1,N2,..
                        // example: chr$(65,66,67) == "ABC"

c  = asc(s$[,N]);       // returns the ascii number of the Nth character of string s$ (N=1 by default)
                        // example: asc("A") == 65
                        // example: asc("ABC",2) == 66

s$ = str$(N);           // returns a string representing the number N
                        // example: str$(23) == "23"

n  = val(s$);           // returns the number represented by the string s$ (reverse of str$)
                        // example: val("23") == 23

s$ = left$(s$,N);       // returns the N left characters of s$
                        // example: left$("ABCD",2) == "AB"

s$ = right$(s$,N);      // returns the N right characters of s$
                        // example: right$("ABCD",2) == "CD"

s$ = mid$(s$,a,N);      // returns N characters of s$ starting at the 'a'th
                        // example: mid$("ABCDEF",2,3) == "BCD"

i  = pos(s1$,s2$);      // returns the position of the string s2$ in s1$, or 0 if not found
                        // example: pos("ABCDEF","CD") == 3
                        // example: pos("ABCDEF","X") == 0

input/output
------------
n = count_lines ("quizz.txt");     // returns the number of lines of the file present in the bot's directory
                                   // example: count_lines ("quizz.txt") == 120

l$ = read_line$ ("quizz.txt", i);  // returns the ith line of the file
                                   // example: read_line$ ("quizz.txt", 3) == "Question 3 : now ..."

i$ = image$("a.jpg");              // returns the image or sound of a file present in the bot's directory
i$ = sound$("a.wav");              // example: print ("a cow : " + image$("images/cow.jpg"));

s = selected_user_session_key();   // returns the session_key of the chatter selected in the right-hand list
                                   // on the bot's screen, or zero if no chatter is selected.


database
--------
store (tiroir$, valeur$);   // store valeur$ in the drawer tiroir$ of database chat.db
                            // example: store ("GAME-1", "1 35 16 32 89 12");
                            // length of tiroir$ must not exceed 100.

a$ = fetch$ (tiroir$);      // returns the value contains in drawer tiroir$ of the database
                            // example: fetch$ ("GAME-1") == "1 35 16 32 89 12"

timer
-----
set_timer (n);     // call the procedure timer() in n seconds (or cancel if n==0)



In addition to the existing procedures and functions described hereabove,
you can write new ones; here are three examples :

// a function that computes the double of n
func double (n)
{
  var result;
  result = n * 2;
  return result;
}

// a function that returns a string of N minus signs
func tiret$ (n)
{
  return dup$("-", n);
}

// a procedure that prints N minus signs
proc print_tiret (n)
{
  print (tiret$(n));
}


Operators
=========

Operators are used to perform computations, for example:

    2 + 3 * 4

Each operator has a priority, for example * has a higher priority than
+, which means that the computation above is equivalent to :

    2 + (3 * 4)

and not to :

    (2 + 3) * 4

If this last computation is desired, one should use parentheses.


Here are the available operators, ordered by decreasing priority :

numeric operators
-----------------
 !     logical NOT
 *     multiplied by
 /     divided by
 %     rest of division
 &     bitwise and
 |     bitwise or
 +     add
 -     subtract
 <=    smaller than or equal to
 >=    larger than or equal to
 ==    equal to
 !=    not equal to
 <     smaller than
 >     larger than
 &&    logical AND
 ||    logical OR

string operators
----------------
 +     concatenate 2 strings
 <=    smaller than or equal to (lexicographic order = dictionnary)
 >=    larger than or equal to
 ==    equal to
 !=    not equal to
 <     smaller than
 >     larger than


example:

  if ("ab" < "abc")
    print ("ab comes before abc in the dictionnary");



Instructions
============

assignation
-----------
The assignation instruction is used to perform a computation (on the right)
and then store the result in the variable (on the left).

  result = a * b + c;          // compute '(a * b) + c' and store in variable 'result'
  line$ = "Hello" + userid$;   // concatenate "Hello" and userid$ and store in line$
  fruit$[2] = "pomme";         // store string "pomme" in cell 2 of table fruit$
  ligne$ = "i contains the value " + str$(i);
  length = len(s$) + 1;

Assignation with incrementation allows to add or subtract
a value to the left-side variable.

  i += 72;             // adds 72 to i
  j -= (b + c);

Simple incrementation allows to add or subtract 1 to a variable:

  i++;       // add 1 to i
  j--;       // subtract 1 from i



If instruction
--------------

The IF instruction allows to execute a group of instructions
only if a condition is fulfilled.


  // if with single instruction

  if (i < 10)
    print ("i too small");   // execute print only if i is smaller than 10



  // if with several instructions
  // note: { } are mandatory in case of several instructions

  if (i < 10)
  {
    print ("i too small");
    print ("try again");
  }



  // "if" with "else" clause

  if (i < 10)     // if i smaller than 10
  {
    print ("i too small");
    print ("try again");
  }
  else           // otherwise
  {
    print ("i equal or larger than 10 !");
  }



  // "if" with several parts

  if (i < 10)                // if i smaller than 10
  {
    print ("i too small");
    print ("try again");
  }
  else if (i == 10)          // else if i equal to 10
  {
    print ("i equals 10 !");
  }
  else                       // else (i larger than 10)
  {
    print ("i larger than 10 !");
  }



  // if with complex expressions

  if (i < 10 && j == 3 && a$ == "hello")    // if i < 10 AND j == 3 AND a$ == "Hello"
    print ("yes");

  if (i < 10 || j == 3 || a$ == "hello")    // if i < 10 OR j == 3 OR a$ == "Hello"
    print ("yes");



  // if with empty instruction

  if (i < 10)
    ;          // do nothing
  else
  {
    print ("yes");
  }



FOR instruction
---------------

The FOR instruction allows to repeat execution of a group of instructions
between { } by increasing the value of a variable at each execution.

examples:


  // to print the numbers from 1 to 5 :

  for (i=1; i<=5; i++)
  {
    print (str$(i));
  }

  prints:
    1
    2
    3
    4
    5


  // to print the numbers from 5 to 1 :

  for (i=5; i>=1; i--)
  {
    print (str$(i));
  }

  prints:
    5
    4
    3
    2
    1


WHILE instruction
-----------------

The WHILE instruction allows repeating a group of
instructions while a given condition is true.

  // while i <= 10,
  // repeat the instructions between { }

  i = 1;
  while (i <= 10)
  {
    print ("Hello");
    i++;
  }


  // loop on table tab[]
  // until finding a value 6

  var tab[512];

  .......

  i = 0;
  while (i <= 512 && tab[i] != 6)   // while i <= 512 and tab[i] not equal to 6, increment i
  {
    i++;
  }



break and continue
------------------

  // the 'break' instruction ends the repetition immediately

  for (i=1; i<=6; i++)
  {
    if (i == 3)
      break;
    print (str$(i));
  }

  prints:
    1
    2



  // the 'continue' instruction skips to next repetition

  for (i=1; i<=6; i++)
  {
    if (i == 3 || i == 5)   // if i equals 3 or 5, go to next i
      continue;
    print (str$(i));
  }

  prints:
    1
    2
    4
    6



timer procedure
===============

If you add a "timer" procedure in your script,
it'll be executed first once you enter the room.

Next, using the procedure set_timer(N), you can make it execute again
after N seconds. If N == 0, this new execution is cancelled.

example
-------

proc timer ()
{
  print ("this message is displayed each 30 seconds");

  if (mid$(now$(),12,5) == "12:00")
    print ("it is 12 o'clock !");

  if (mid$(now$(),12,5) == "13:00")
    print ("it is 13 o'clock !");

  set_timer (30);   // execute timer() again in 30 seconds
}



Display the CAM icon next to the room name
==========================================

The CAM icon appears automatically next to the room name
when a bot is present in the room and configurated using bot.txt
to make webcams mandatory.

Alternatively, if you have your own script to impose webcams,
you can force the display the CAM icon using the following command
to be placed in chatserv.ini :

  [settings]
  cams = oblig   ; cams obligatory


Make a text zone cliquable
==========================

By enveloping a text zone with markers, you can make it cliquable
which means that if a user clicks on the zone with the mouse,
an action will be sent to the bot with line$ containing the marker code.

A marker always begins with code 3. The end-marker is always chr$(3,0,0,0).

Marker chr$(3,255,a,b) are reserved for the bot's mine game.

exemples:

  print (chr$(3,0,0,1) + image$("logo.gif") + chr$(3,0,0,0));

  print (chr$(3,0,0,1) + image$("logo1.gif") +
         chr$(3,0,0,2) + image$("logo2.gif") +
         chr$(3,0,0,0));

  print ("Logo 1 : " + chr$(3,0,0,1) + image$("logo1.gif") + chr$(3,0,0,0) +
         "Logo 2 : " + chr$(3,0,0,2) + image$("logo2.gif") + chr$(3,0,0,0) +
         "Logo 3 : " + chr$(3,0,0,3) + image$("logo3.gif") + chr$(3,0,0,0));

...

  if (action == 300)
    print ("you clicked on logo " + str$(asc(line$,4)));



Errors
======

The following errors can appear when a script is executed :

  1 "array index out of range"   : index of the table [] is out of limits
  2 "division by zero"           : division by zero not allowed
  3 "string too long"            : string long cannot exceed 8192 characters
  4 "out of string space"        : too many strings, memory is full
  5 "bad argument"               : bad value for standard function
  6 "application hangs"          : the application has already executed 100 million instructions
                                   and seems running in a loop
  7 "missing return in function" : function without "return" instruction
  8 "expression too complex"     : too many parameters or nested calls
  9 "callstack full"             : too many parameters or nested calls

Errors 10 to 15 indicate a problem with the chat software :

 10 "arithmetic stack empty"
 11 "unknown pcode",
 12 "outside code range"
 13 "outside var range"
 14 "ret outside range"
 15 "astack corrupt"



Sample Scripts
==============


////////////////////////////////////////////////////////////////////////////////


//  Example 1 : Clock

proc event (session_key, userid$, sex$, has_photo, age, is_away,
            admin, cam_on, is_bot, toc_capab, signature$, suffix$, profile_life,
            action, is_myself, line$)
{
  var heure, phrase$, phrase2$;

  if (action == 128)
  {
    heure = val (mid$(now$(),12,2));

    if (heure >= 12 && heure <= 13)
      phrase$ = "Bon Appétit$mi ";
    else if (heure >= 0 && heure <= 4)
      phrase$ = "Agréable Nuit(s) ";
    else if (heure >= 6 && heure <= 19)
      phrase$ = "Bonjour:) ";
    else
      phrase$ = "Bonsoir;) ";

    if (sex$ == "F")
      phrase2$ = " (f)";
    else
      phrase2$ = " (y)";


    print (phrase$ + userid$ + phrase2$
            + ", it is " + right$(now$(),8)  + "(o)");
  }
}


////////////////////////////////////////////////////////////////////////////////


//  Exemple 2 : Puissance 4 game

var jeu;         // 1 = jeu actif
var tab[35];     // 5 lignes de 7 colonnes
var joueur;


proc effacer_table ()
{
  var i;
  for (i=0; i<35; i++)
    tab[i] = 0;
}


proc afficher_table ()
{
  var line, col, line$, i;

  i = 0;

  for (line=0; line<5; line++)
  {
    line$ = "   ";

    for (col=0; col<7; col++)
    {
      if (tab[i] == 0)
        line$ = line$ + chr$(1,0,0,0) + ".";
      else if (tab[i] == 1)
        line$ = line$ + chr$(1,0,0,255) + "X";
      else
        line$ = line$ + chr$(1,255,0,0) + "O";
      i++;
    }

    print (chr$(2,5,4,0) + line$);  // courier new + gras
  }

  print (chr$(2,5,4,0) + chr$(1,0,0,0) + "  >" + "1234567<");
}


func score (col, line)
{
  var x, y, c, i, j, count;

  // 4 cases consecutives horizontales

  j     = 0;
  count = 0;

  for (x=0; x<7; x++)
  {
    c = tab[x+line*7];

    if (c == 0 || c != j)
    {
      count = 1;
      j = c;
    }
    else
    {
      count++;
      if (count == 4)
        return j;
    }
  }


  // 4 cases consecutives verticales

  j     = 0;
  count = 0;

  for (y=0; y<5; y++)
  {
    c = tab[col+y*7];

    if (c == 0 || c != j)
    {
      count = 1;
      j = c;
    }
    else
    {
      count++;
      if (count == 4)
        return j;
    }
  }


  // 4 cases consecutives obliques \

  j     = tab[col+line*7];
  count = 1;

  for (i=1; i<=3; i++)
  {
    if (col-i < 0 || line-i < 0 || tab[col-i + (line-i)*7] != j)
      break;
    count++;
  }

  for (i=1; i<=3; i++)
  {
    if (col+i >= 7 || line+i >= 5 || tab[col+i + (line+i)*7] != j)
      break;
    count++;
  }

  if (count >= 4)
    return j;


  // 4 cases consecutives obliques /

  j     = tab[col+line*7];
  count = 1;

  for (i=1; i<=3; i++)
  {
    if (col-i < 0 || line+i >= 5 || tab[col-i + (line+i)*7] != j)
      break;
    count++;
  }

  for (i=1; i<=3; i++)
  {
    if (col+i >= 7 || line-i < 0 || tab[col+i + (line-i)*7] != j)
      break;
    count++;
  }

  if (count >= 4)
    return j;

  return 0;
}


// col de 1 a 7
// joueur 1 ou 2

func ajouter (col, joueur)
{
  var line;

  col--;

  if (col < 0 || col >= 7)
    return -1;

  if (tab[col] != 0)
    return -1;

  for (line=0; line<4; line++)
  {
    if (tab[col+line*7+7] != 0)
      break;
  }

  tab[col+line*7] = joueur;

  return score (col, line);
}


proc event (session_key, userid$, sex$, has_photo, age, is_away, admin,
            cam_on, is_bot, toc_capab, signature$, suffix$, profile_life,
            action, is_myself, line$)
{
  var c$, col, r;

  if (action == 128)
  {
    print ("Welcome in the room, type !p4 to play puissance 4.");
  }

  if (action == 0)
  {
    if (len(line$) >= 3 && right$(line$,3) == "!p4")
    {
      jeu = 1;
      afficher_table();
    }
    else if (jeu == 1)
    {
      if (len(line$) >= 1)
      {
        c$ = right$(line$, 1);
        if (c$ >= "1" && c$ <= "7")
        {
          col = val (c$);

          if (joueur == 1)
            joueur = 2;
          else
            joueur = 1;

          r = ajouter (col, joueur);

          if (r >= 0)
          {
            afficher_table();

            if (r > 0)
            {
              if (r == 1)
              {
                print (chr$(1,0,0,0) + "Bravo ! " + chr$(1,0,0,255) + "X"
                        + chr$(1,0,0,0) + " a gagne");
              }
              else if (r == 2)
              {
                print (chr$(1,0,0,0) + "Bravo ! " + chr$(1,255,0,0) + "O"
                        + chr$(1,0,0,0) + " a gagne");
              }

              effacer_table ();
              jeu = 0;
            }
          }
        }
      }
    }
  }
}


////////////////////////////////////////////////////////////////////////////////


// Example 3 : kick cups after 30 seconds

var session[256];     // enregistre le session_key des chatteurs en tasse
var expire$[256];     // date et heure à laquelle on kicke le chatteur
var nb_session;       // nombre d'éléments dans les 2 tableaux


// ajoute une session_key dans les 2 tableaux

proc ajouter_dans_table (session_key)
{
  var i;

  for (i=0; i < nb_session; i++)
  {
    if (session_key == session[i])    // trouvé
      break;
  }

  if (i == nb_session)   // pas trouvé, donc agrandir table
    nb_session++;

  session[i] = session_key;
  expire$[i] = add_date$ (now$(), 30);
}


proc supprimer_de_table (session_key)
{
  var i;

  for (i=0; i < nb_session; i++)
  {
    if (session_key == session[i])   // trouvé
      break;
  }

  if (i < nb_session)   // trouvé
  {
    session[i] = session[nb_session-1];
    expire$[i] = expire$[nb_session-1];
    nb_session--;
  }
}


proc timer ()
{
  var i;

  for (i=0; i < nb_session; i++)
  {
    if (now$() > expire$[i])   // a expiré
    {
      kick (session[i], "it's not a parking here !");
      supprimer_de_table (session[i]);
    }
  }

  set_timer (1);    // rappeler timer() toutes les secondes
}


proc event (session_key, userid$, sex$, has_photo, age, is_away,
            admin, cam_on, is_bot, toc_capab, signature$, suffix$, profile_life,
            action, is_myself, line$)
{

  if (!is_myself)  // pas moi-même
  {
    if (action == 2)
    {
      if (is_away)   // chatteur va en tasse
      {
        print ("Attention " + userid$ + " : you'll be kicked after 30 seconds away !");
        ajouter_dans_table (session_key);
      }
      else           // reviens de tasse
      {
        supprimer_de_table (session_key);
      }
    }

    if (action == 129 || action == 130 || action == 256)
    {
      supprimer_de_table (session_key);
    }
  }

}

////////////////////////////////////////////////////////////////////////////////
 
// Example 4 : multi-functions robot

var nombre;              // nombre a deviner (pour le jeu devine)
var jeu_score[50], jeu_pseudo$[50];

var nombre_de_lignes;    // compte le nombre de lignes reçues

var fruit$[3];           // tableau de 3 fruits


func fq$ ()    // changer la couleur et le style d'écriture
{
  return chr$(1,0,0,128)  // couleur bleue claire (voir chapitre macros)
       + chr$(2,5,4,0);   // font "Courier New", style gras
}

func red$ ()
{
  return chr$(1,255,0,0);   // couleur rouge
}

func green$ ()
{
  return chr$(1,0,255,0);
}

func blue$ ()
{
  return chr$(1,0,0,255);
}


proc demarre_devine ()
{
  print ("devine un nombre de 1 à 99");
  nombre = random (1,99);
}


// ajoute des points dans le tableau jeu_score[]

proc ajoute_points (userid$)
{
  var i, j, u$;

  // cherche le userid$ dans le tableau jeu_pseudo$[]
  // ou bien cherche une case vide dans le tableau

  for (i=0; i<50; i++)
  {
    if (jeu_pseudo$[i] == userid$ || jeu_pseudo$[i] == "")
      break;
  }


  // remplir la case et augmenter le score

  jeu_pseudo$[i] = userid$;
  jeu_score[i]++;            // ajouter 1 point au score


  // remonter le joueur dans le tableau des scores
  // s'il a dépassé des joueurs avant lui

  while (i > 0 && jeu_score[i] > jeu_score[i-1])
  {
    j = jeu_score[i];
    jeu_score[i] = jeu_score[i-1];
    jeu_score[i-1] = j;

    u$ = jeu_pseudo$[i];
    jeu_pseudo$[i] = jeu_pseudo$[i-1];
    jeu_pseudo$[i-1] = u$;

    i--;
  }
}


// imprime les 9 premiers scores du tableau
// ainsi que le userid$ même s'il est après les 9 premiers

proc affiche_scores (userid$)
{
  var i, score$;

  print (fq$() + "SCORES");
  print (fq$() + "======");

  for (i=0; i<50; i++)
  {
    if (jeu_pseudo$[i] == "")
      break;
    if (i < 9 || userid$ == jeu_pseudo$[i])
    {
      score$ = str$(jeu_score[i]);
      if (len(score$) < 4)
        score$ = dup$(" ",4-len(score$)) + score$;
      print (fq$() + str$(i+1) + ". " + score$ + "  " + jeu_pseudo$[i]);
    }
  }
  print("");
}


proc joue_devine (word$,userid$)
{
  var last, first, n;

  // enlève les blancs à la fin
  last = len(word$);
  while (last >= 1 && asc(word$,last) == 32)
    last--;

  // collecte tous les chiffres à la fin
  first = last;
  while (first >= 1 && asc(word$,first) >= 48 && asc(word$,first) <= 57)
    first--;

  if (first == last)   // pas de chiffres
    return;

  n = val (mid$(word$,first+1,last-first));

  if (n < nombre)
    print ("ha non, trop petit !");
  else if (n > nombre)
    print ("hé non, trop grand !");
  else
  {
    print ("Bravo, c'était bien " + str$(nombre));
    ajoute_points (userid$);
    affiche_scores (userid$);
    nombre = 0;
  }
}


proc print_fruits ()
{
  if (fruit$[1] == "")   // tableau pas encore rempli
  {
    fruit$[1] = "Pommes";
    fruit$[2] = "Poires";
    fruit$[3] = "Bananes";
  }
  print ("Saluuuut :d  tu aimes les " + fruit$[random(1,3)] + " ? ");
}



// nettoye la ligne line$ en remplaçant toutes les icones par des blancs,
// en convertissant tous les mots en minuscules,
// et en entourant tous les mots par des blancs.

func clean$ (line$)
{
  var last, r$, i, c;

  i = 1;
  last = len(line$);

  while (i <= last)
  {
    c = asc (line$,i);
    if (c <= 9)  // séquence spéciale
    {
      i += 4;    // passer 4 caractères
      if (c > 5)
        i += 4;
      c = 32;  // remplacer par un blanc
    }
    else   // caractère normal
    {
      if (c >= 65 && c <= 90)  // si entre A et Z
        c += 32;    // convertir en minuscules
      i++;
    }
    r$ = r$ + chr$(c);
  }

  return r$ + " ";
}



proc timer ()
{
  if (mid$(now$(),12,5) == "12:00")
    print ("il est 12 heures !");

  if (mid$(now$(),12,5) == "13:00")
    print ("il est 13 heures !");

  set_timer (55);  // rappeler toutes les 55 secondes,
}                  // donc 1 appel par minute est garanti



proc event (session_key, userid$, sex$, has_photo, age, is_away,
            admin, cam_on, is_bot, toc_capab, signature$, suffix$, profile_life,
            action, is_myself, line$)
{
  var word$, w$, heure, i;

  word$ = clean$(line$);   // nettoye la ligne pour pouvoir y chercher des mots

  if (action == 127)   // afficher les gens déjà présents en salle
  {
    print ("Déjà en salle : " + userid$ + "  (session_key=" + str$(session_key) + ")");
  }

  if (action == 128)   // arrivée en salle
  {
    if (is_myself)    // c'est moi-même
      toc();          // je prend le toc !

    w$ = blue$();

    heure = val (mid$(now$(),12,2));

    if (heure >= 12 && heure <= 13)
      w$ = w$ + "Bon Appétit$mi ";
    else if (heure >= 0 && heure <= 4)
      w$ = "Agréable Nuit(s) ";
    else if (heure >= 6 && heure <= 19)
      w$ = w$ + "Bonjour:) ";
    else
      w$ = w$ + "Bonsoir;) ";

    w$ = w$ + userid$;

    if (sex$ == "F")
      w$ = w$ + " (f)";
    else
      w$ = w$ + " (y)";

    w$ = w$ + ", il est " + right$(now$(),8)  + "(o)";

    print (w$);

//    print ("Votre signature est : " + signature$);

    print (blue$() + "tape " + red$() + "!devine" + blue$() + " pour le jeu devine");
  }

  if (action == 0)    // ligne de texte normale
  {
    if (!is_myself)    // ce n'est pas moi-même
    {
      if (pos (word$, " !devine "))    // contient !devine (avec 2 blancs autour, attention !)
        demarre_devine ();

      if (nombre > 0)  // le jeu devine est actif
        joue_devine (word$, userid$);


      // kicker quelqu'un s'il dit cochon

      if (pos (word$, " cochon "))
        kick (session_key, userid$ + ":@ malpoli !!");


      // Afficher l'heure

      if (pos (word$, " heure "))
        print ("Horloge parlante : " + now$());


      // afficher le fichier bienvenue.txt, ligne par ligne

      if (pos (word$, " bien "))
      {
        for (i=1; i<=count_lines("bienvenue.txt"); i++)
          print (read_line$("bienvenue.txt", i));
      }


      // Afficher une image de porte

      if (pos (word$, " porte ") > 0)
        print ("-> " + image$("kitchen02.jpg") + "quelle porte ? :p");


      // retenir une phrase en la stockant dans la database chat.db

      if (pos (word$, " retiens ") > 0)
      {
        store ("Retiens " + signature$, line$);
        print ("phrase retenue, dis 'quoi' pour la revoir !");
      }

      // redire la phrase stockée

      if (pos (word$, " quoi ") > 0)
      {
        print ("ta phrase était : "+ fetch$("Retiens " + signature$));
      }


      nombre_de_lignes++;    // augmenter le nombre de lignes de 1


      // toutes les 200 lignes, annoncer le nombre de lignes déjà parlées en salle

      if ((nombre_de_lignes % 200) == 0)
        print ("Déjà " + str$(nombre_de_lignes) + " lignes parlées sur ce chat :p");


      // toutes les 100 lignes, demander si on aime un fruit

      if ((nombre_de_lignes % 100) == 0)
        print_fruits ();
    }
  }


  if (action == 2 && is_away)   // aller en tasse
  {
    print ("Et alors là " + userid$ + " ?  on se cache ?");
  }

  if (action == 2 && !is_away)  // revenir de tasse
  {
    print ("Ben heureusement que tu reviens " + userid$ + " $si");
  }

  if (action == 1)       // ligne de texte envoyé avec la bulle
  {
    print ("Alors on rêvasse " + userid$ + " :d");
  }
}

////////////////////////////////////////////////////////////////////////////////

revenir à la page précédente