<sect> Interfaçage avec JavaScript

<sect1> Principe du rappel (callbacks).
<p>
Maintenant, depuis le chapitre précédent, nous avons des entités, avec des
propriétés, organisées en hiérarchie de classe. Ce système d'entité est suffisant
pour décrire une scène statique assez complexe. Par contre, dès qu'on veut rajouter
des éléments dynamiques, comme des animaux, ou des personnages non jouables,
on se rend compte qu'il faut pouvoir modifier les entités à postériori, pour les animer,
les faire se déplacer, etc. Il faudrait donc pouvoir définir des morceaux de
programme qui codifient le comportement des entités.

Ce but sera atteint par l'utilisation de fonctions de rappel (callbacks), écrites dans
un langage de script (javascript par défaut). Pourquoi des fonctions "de rappel" ?
Tout simplement parce qu'elles sont appelées par le moteur de jeu lorsqu'un
évènement particulier survient : attaque, collision, réponse à un dialogue, le
but fixé a été atteint, etc. On peut faire une analogie avec le mode de
fonctionnement des êtres vivants : quand ils reçoivent un stimuli (évènement),
une information est envoyé au centre nerveux (la fonction de rappel est appelée),
qui après analyse définit une réaction (modification de l'état de l'entité par la
fonction).

Un ensemble de fonctions de rappels qui prend en compte tous les évèments
possible est appelé un comportement. Chaque jeu peut proposer une liste
de comportements standards ; les quêtes peuvent bien-sûr ajouter leurs propres
comportements.

<sect1> Fonctions définissant un comportement
<p>
Les fonctions de rappel qui doivent être définies sont :
<itemize>
<item> onCreate : elle est appelée lors de la création de l'entité.
<item> onTimer(id) : cette fonction est appelée lorsqu'une alarme se déclenche,
	à la fin d'une période de temps définie. 'id' correspond à l'identifiant qui a
	été donné lors de la création de l'alarme. Les alarmes peuvent servir
	à lancer des actions périodiques (ie. mettre un pain dans le four pour
	un boulanger, etc.), ou à déclencher une action après un compte à
	rebours (ie. explosion d'une bombe).
<item> onTell(from, message) : fonction appelée lorsque quelqu'un s'adresse à
	l'entité (bien sûr cet évènement n'a de sens que pour un PNJ). L'entité
	peut en retour poser une question (dialogues "complexes"), ou bien
	donner un objet, faire une action... 'from' correspond au locuteur, et
	'message' au contenu de sa parole.
<item> onGoalReached() : cet évènement est déclenché lorsque l'entité a atteint
	le but qu'elle s'était fixée. Par exemple, si un boulanger a indiqué au
	moteur qu'il voulait aller au moulin (nous verrons comment plus tard),
	cette fonction sera appelée quand il aura effectivement atteint le moulin.
	Ainsi, on est pas obligé d'utiliser une alarme périodique pour vérifier la
	position, puisque cette fonction est appelée quand qu'on a rejoint
	la position désirée.
<item> Il y a d'autres fonctions (onCollision, onAttack), mais elles n'ont pas
	encore été définies...
</itemize>

Si javascript est le langage de script utilisé, alors la définition d'un comportement
se fait comme suit : on déclare toutes les fonctions de rappel (le nom de la
fonction doit être préfixé du nom du comportement), puis on signale au moteur
la création d'un nouveau comportement à l'aide de la fonction
arkhart_RegisterCallback.

<code>
// Ici, on veut simuler le comportement d'un boulanger. Seules les déclarations
// nécessaire à la création d'un comportement ont été inclues ; pour l'écriture
// de l'IA, on attendra le prochain chapitre :)

// Appelée à la création du boulanger
function boulanger_onCreate ()
{
	// ... Reste à écrire le code ...
}

// Appelée lorsque le but a été atteint.
function boulanger_onGoalReached () {}

// Appelée lorsqu'une alarme s'est déclenchée.
function boulanger_onTimer (id) {}

// Appelée lorsque 'entite' dit 'message' au boulanger.
function boulanger_onTell (entite, message) {}

// Ajoute le comportement 'boulanger' à la liste des comportements.
arkhart_RegisterCallback ("boulanger");
</code>


Finalement, pour indiquer au moteur quel comportement doit utiliser l'entité,
on assigne au membre 'callback' de celle-ci le nom du comportement. Par
exemple, si on veut ajouter un boulanger dans une quête :

<code>
implements Personne, uses Humain
{
	model = "{models}/boulanger.mdl";
	position = {128.0, 0.0, 128.0};

	// Signale que cette entité va avoir le comportement 'boulanger'.
	callback = "boulanger";
}
</code>

<sect1> Objet de comportement
<p>
Maintenant survient un autre problème (éh oui, encore un!) : comment fournir
des données spécifiques au comportement pour une entité. Par exemple, pour un
boulanger, comment lui indiquer quelle est sa boulangerie, où il peut acheter
de la farine, etc.

La réponse simple serait de rajouter de créer une classe Boulanger,
dérivée de la classe Humain. Ca n'est pas acceptable, tout simplement parce
qu'un boulanger peut-être un Daphy, par exemple : il faudrait créer une classe
DaphyBoulanger, HumainBoulanger, et ainsi de suite pour toutes les classes
qui peuvent devenir boulanger. Ce serait ingérable.

Le problème vient du fait que le comportement d'un personnage n'est aucunement
lié à sa classe ; Pour chaque entité, il est donc nécessaire d'associer deux
objets distincs. Un Objet de Caractéristique, qui contient une liste de
propriétés inhérentes à cette entité (c'est ce dont nous avons traité dans
le chapitre précédent), et un Objet de Comportement, qui contient une liste
de propriétés liées au comportement de cette entité. La distinction est de
taille.

Le premier Objet reste presque inchangé au cours de la vie de l'entité, il
correspond aux caractéristiques immuables, le deuxième donne des informations
sur l'action / le comportement actuel de l'entité. On comprend encore plus
l'importance de séparer les deux : en procédant de la sorte on on rend possible
un changement de comportement au milieu de la vie de l'entité. Par exemple
le boulanger (toujours lui!) peut passer d'un comportement d'artisan la journée
à un comportement de père de famille la nuit.

<p>
Passons à la partie technique : comment spécifie-t'on les Objets de
comportement ? La réponse est simple : exactement de la même manière que l'on
fait pour les Objets de caractéristique.

<itemize>
<item> La définition des classes et des modèles de comportement se fait dans
       les fichier <em>{game}/scripts/callbacks.def</em> et
       <em>{game}/scripts/callbacks.def</em> respectivement.
<item> La déclaration d'objets de comportement attachés à une entité 
       se fait dans un fichier <em>callbacks.lst</em> dans le même répertoire
       que le fichier <em>entities.lst</em>.
</itemize>

Par exemple : 
<code>
// {game}/scripts/callbacks.def

// ...
Callback
{
        // Remarque : ce champ est indispensable. Contrairement à ce que
        // son nom pourrait laisser croire, "name" ne contient pas le nom de
        // l'entité à laquelle le comportement s'applique, mais son
        // nom-identifiant (shortname), qui est forcément unique.
        STRING name
        {
                desc = "[entity] Entité à laquelle ce comportement s'applique";
                default = "None";
        }
}

Boulanger inherits Callback
{
        STRING boulangerie
        {
               desc = "[entity] Boulangerie dans laquelle travaille ce brave "
                      "homme";
               default = "None";
        }
}
// ...
</code>

<code>
// entities.lst

// ...
implements Personne, uses Humain
{
        shortname = "Boulanger0";
        name = "Marcel le Boulanger";
	model = "{models}/boulanger.mdl";
	position = {128.0, 0.0, 128.0};

	// Signale que cette entité va avoir le comportement 'boulanger'.
	callback = "boulanger";
}

// ...
</code>


<code>
// callbacks.lst

// ...
implements Boulanger
{
    name = "Boulanger0";
    boulangerie = "Snattalang_Boulangerie18";
}
// ...

</code>
