Cours de Scripts pour les Quiches. Leçon Quatre.

Introduction
Le but de cette série de leçons, est d'apprendre a se servir des scripts a n'importe qui.

Commençons.
Bon, les plus perspicaces ou acharnés d’entre vous aurons remarqué que notre garde de la leçon trois n’a pas exactement le comportement voulu. A chaque fois que le garde est amical, il salue deux fois. Il faut bien faire attention pour s’en apercevoir, mais quand même, c’est… gênant. De plus, cela me donne la chance d’expliquer une autre concept.

Premièrement, tâchons de comprendre le pourquoi de la chose. Il faut pour cela en venir au fonctionnement du script du « OnPerceive ». Il y a quatre chose qui « appellent » ce script.
 Le npc voit quelque chose.
 Le npc entend quelque chose.
 Le npc s’aperçoit de la disparition de quelqu’un.
 Le npc s’aperçoit du silence de quelqu’un.

Ce qui s’est passé dans notre exemple est que notre garde a vu ET entendu le personnage, ce qui fait que le script a été appelé deux fois. Il y a plusieurs moyen de corriger cela, mettons que nous voulons que le garde ne réagisse qu’a la VUE de l’objet. Ce qui correspond plus a ce que nous cherchons a faire. Il est en effet peu probable qu’il entende l’anneau…

On pourrait faire cela en rajoutant une imbrication dans nos tests. Mais ceux ci étaient déjà un peu compliqués. Ce que nous voulons est que notre script ne soit activé que si l’objet perçu est un personnage, et que cet objet ait été perçu par la vue.

Il suffit donc de modifier la condition en ajoutant l’opérateur « && » qu’il suffit de lire comme un « ET ». Notre condition sera vraie, si et seulement si les deux parties sont vraies.


if (GetIsPC(oSeen))

Changée en


if (
GetIsPC(oSeen) && GetLastPerceptionSeen())

La commande GetLastPerceptionSeen ramène TRUE si la dernière chose perçue a été vue, et FALSE dans les trois autres cas.

Il y a un autre opérateur qui peut être utilisé pour relier deux conditions, c’est le « || » qui peut être lu comme « OU ». La condition se réalise si l’une ou l’autre de ses deux parties est vraie.

Ces opérateurs nous ramènent a Boole… vous vous souvenez de lui ?
Boole a créé ce qu’on appelle aujourd’hui « l’algèbre de Boole ». Et comme dans toute algèbre, il y a des opérateurs et des opérandes.
Si j’insiste sur ce point, c’est parce que c’est un des sujets les plus difficiles a maîtriser pour un développeur. Et que c’est un des plus vitaux.
On parle ici de logique et de mathématique. Cela n’a que peu de rapport avec le français.
A la question : « Est ce un garçon ou une fille ? » N’importe qui répondra « un garçon » ou « une fille »… Un script répondra « VRAI ».

Si cela vous intéresse je vous ferai un vrai cours de logique booléenne. Mais il y a déjà beaucoup de sites très bien fait…

Confession.
Jusqu'à présent, je vous ai toujours dit que je vous proposais des scripts comme je les aurai écrit. Je doit maintenant vous avouer que c’est faux. Jamais je n’aurai écrit les scripts comme cela.
Le problème vient du fait de tous ces scripts par défaut que l’on a effacés pour mettre les nôtres. Vous vous en souvenez ? Maintenant, notre garde fait ce qu’on lui demande, mais il ne répond plus a aucun autre stimulus. Essayez par exemple de l’attaquer… il ne se défendra même pas ;(
La question qui se pose donc est, comment ajouter un comportement, tout en gardant tous les comportements par défaut. Et la réponse est : En utilisant les « User defined » scripts. Ce qui est l’objet de ce cours. Avouez que cela tombe bien non ?

Retravaillons donc notre garde.
- Ouvrez votre module de Test.
- Supprimez le garde.
- Créez un autre npc a sa place, de façon a récupérer tous les scripts par défaut.
- Changez son tag en « GARDE ».
- Vérifiez dans l’onglet « Advanced » que sa faction soit bien « Commoner ».
- Activez l’onglet « Scripts ».
- Editez le script du « OnSpawn ». Il y a beaucoup de choses ici, nous allons en ignorer la plupart. Mais vers la fin du script, il y a une ligne qui nous intéresse.

//SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1002

- Supprimez les // au début de cette ligne.
- Sauvegardez le script en tm_garde_os
- Fermez la fenêtre de scripts et allez sur le « OnUserDefined »
- Choisissez le script tm_garde_op
- Editez le, sauvegardez le en tm_guard_ud
- Changez éventuellement les commentaires pour refléter le fait qu’il aie changé de place.
- Sauvegardez le tout et lancez votre module.

Maintenant le garde réagit beaucoup plus normalement, et en plus, il fait toujours ce que l’on veut.
Bien, qu’avons nous fait ? En enlevant les commentaires « // » dans le script de « OnSpawn », nous avons dit au script que nous voulions que ce bout de code optionnel prévu par Bioware soit exécuté.
De façon schématique nous lui avons demandé. Quand tu fait ton script de « OnPerceive », fait en plus le nôtre.

Bien sur les plus malins d’entre vous demanderons… Et si je veux ajouter plusieurs comportement spéciaux, sur le « OnPerceive » et sur le « OnHeartbeat » par exemple ?
C’est toujours faisable, même si cela demande un tout petit peu plus de travail.
Si par exemple nous voulions que notre garde dise toutes les six secondes « Je m’ennuie » .
- Retournez dans le script de « OnSpawn » de votre garde et enlevez le commentaire devant le « OnHeartbeat ».
- Remarquez que les lignes « OnPerceive » et « OnHeartbeat » ont chacune un numéro d’associé. 1002 pour le « OnPerception » et 1001 pour le « OnHeartbeat ».
- Sauvegardez votre script en tm_ennui_os.
- Modifiez votre script de « OnUserDefined » comme suit et sauvegardez le en tm_ennui_ud.

// « OnUserDefined » Script : tm_bored_ud

// Appele par les scripts OnHeartbeat et OnPerception
//
// Le npc se plaint de s’ennuyer toutes les six secondes
//  et salue un pc des qu’il le voit.
//
int nAppelePar GetUserDefinedEventNumber();
void main()
{
 switch(
nAppelePar)
 {
   case 
1001:  // Appele par OnHeartbeat
     
ActionSpeakString("Je m’ennui.");
     break;
    
//
   
case 1002:  // Appele par OnPerception
     
object oSeen GetLastPerceived();
     if (
GetIsPC(oSeen) && GetLastPerceptionSeen())
       
ActionPlayAnimation(ANIMATION_FIREFORGET_BOW);
     break;
  }
}


Questions / Réponses…

Qu’est ce que le GetUserDefinedEventNumber?
C’est exactement le nombre auquel je vous ai demandé de prêter attention un peu plus haut. Bioware a bien fait les choses. Non seulement chaque événement peut appeler le script « UserDefined » mais en plus, chacun lui passe un paramètre différent.

Et la commande « switch » ?
Je pourrai vous en parler pendant des pages et des pages… qu’il suffise de dire que cette commande prend une constante en paramètre et fait « sauter » le script jusqu'à ce nombre. Le script continue alors de s’exécuter jusqu'à ce qu’il rencontre la commande « break ».
Donc si notre nAppelePar vaut 1001, le script va rechercher la ligne « Case 1001: »

Quand j’écris des scripts « UserDefined » je me sert toujours de la commande « switch ». Même si j’en ai qu’un seul. Cela me permet plus tard, d’en rajouter de façon simple et rapide.

Ehhh tu as oublié des { et des } avec ton if ?
Euhh… non
Quand il n’y a qu’une seule commande attachée au « if », les { et les } ne sont pas obligatoires. Dans ce cas, le script est plus propre sans.

Voilà pour aujourd’hui…
__________________
Amaranthe.
Thoerel, un monde semi-persistant pour Neverwinter Nights.