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

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

Les Sources.

Je reçois de plus en plus de demandes d'aide ces temps ci. Lorsque j'ai le temps d'aider, je ne demande pas mieux, mais je ne peux pas toujours me permettre le luxe d'expliquer en détail et de commenter chacune de mes réponses comme je le voudrais. Je me propose donc d'investir ici un peu de temps pour vous montrer comment trouver les réponses par vous même. Honnêtement, je n'ai pas la science infuse, et je ne connais pas toutes les fonctions par cœur. De plus, la plupart du temps, les réponses aux questions posées existent déjà ailleurs. Dites vous bien que malgré votre géni, si vous osez poser une question, il y en a douze qui se posent la même et un ou deux qui ont la réponse.

Il y a quatre endroits ou vous devez tout d'abord chercher les réponses, et dans cet ordre.
* Les " sticky topics " de ce forum.
* Les différents posts de ce forum.
* La campagne officielle.
* Le Toolset en lui même.

Je ne parle volontairement pas des ressources dans la langue de Shakespeare

Détaillons un peu.

La FAQ.
Pour rappel, cela veut dire "frequently asked questions" et ce n'est pas pour rien. Les discussions qui ont été compilées regroupent les questions les plus fréquemment posées. Il est généralement utile d'y jeter un coup d'œil. Il n'y a pas forcément la réponse a votre question, mais peut être quelque chose qui s'en rapproche de très près. De plus, même si cela ne répond pas a votre question, cela peut vous donner des idées pour contourner le problème.

Le Forum.
Tout le monde y pose ses questions, et certains se spécialisent dans les réponses. Encore une fois, il est de bon ton de faire une petite recherche avant de reposer sa question pour la dixième fois. Le forum est équipé d'outils de recherche perfectionné, n'hésitez pas a en user et en abuser. Lorsque je ne trouve pas ce que je veux par la recherche, je regarde quand même les derniers entêtes de discussions, des fois que ma question ait été posée récemment.
Si je ne trouve rien se rapportant a mon problème alors seulement je fait un nouveau post pour demander de l'aide. Sachez quand même, que plus vous vous investissez sur votre problème, plus les gens auront envie de vous aider.
Prenons un exemple. ( Toute ressemblance avec un ou plusieurs fils de discussion est voulue ! Par contre, il n'est nullement dans mon intention de tourner les auteurs de ces demandes en ridicule, d'une quelconque manière que ce soit ).
Un nouveau message, et une seule question. " Comment faire un levier qui ferme une porte ? "
Une autre poste le même genre de question mais explique de façon détaillée son script, les tags qu'elle utilise et pourquoi. Elle explique qu'elle a cherché a attacher le script sur le " OnActivate " de levier, explique les variables locales qu'elle utilise...
Je ne sais pas pour vous, mais pour ma part, j'ai beaucoup plus envie de répondre a la seconde personne et de lui montrer la ou elle a pu faire une erreur. Je ne parle même pas ici de ma répulsion vis a vis des orthographes approximatives. Mais on sent au moins que cette personne s'est investie dans son script, peut être qu'elle a déjà passé des dizaines de minutes a essayer de la faire fonctionner. Alors que je ressent la première question comme : " J'ai pas envie de faire des efforts, pouvez vous en faire pour moi ? ".
Et, encore autre chose au sujet de l'aide apportée sur les forums, il est poli, même si cela n'est pas strictement nécessaire, de remercier les gens qui nous ont aidé pour un script. Juste un petit quelque chose comme ça :
// OnUserDefined Script : tm_garde_ud
// Fait en sorte que le garde grogne s'il voit quelqu'un avec une arme sortie.
// Dernière mise a jour le 11/07/02
// Ecris par Gatsby le magnifique.
// avec l'aide de Celowin.
// Traduis par Amaranthe.
Les gens qui joueront votre module ne verrons jamais ces remerciements, mais ceux qui " piquerons " votre code, oui.
Même si vous ne connaissez pas le nom de la personne, son pseudonyme fera l'affaire.

La campagne officielle.
Je vais le dire et le redire, mais cela m'énerve de voir des gens poser cette question : " Comment je fais pour faire ceci ou cela comme dans la campagne a tel endroit ? "
* Dans le répertoire NeverWinter Nights, il y a un sous répertoire nommé " nwn ". Vous trouverez dans ce sous répertoire les modules de la campagne officielle.
* Copiez les fichiers qui vous intéressent dans le répertoire " modules ".
* Changez leur extension, de " .nwn " en " .mod ".
* Click droit, propriétés, enlevez le " Read Only ".
* Maintenant ce fichier peut être ouvert dans le Toolset.
Vous pouvez apprendre énormément, en regardant comme Bioware a codé telle ou telle chose.
Vous cherchez a savoir comment un Npc peut commencer une conversation ? Regardez le script de Pavel dans le prélude !
Vous voulez savoir comment conjurer des créatures qui attaquent les pcs ? Regardez le script de conversation d'Aribeth dans le prélude !
Vous voulez un npc qui vous suive jusqu'à ce qu'il rencontre un autre npc, puis s'en aille ? Regardez donc dans le chapitre 1...
Il y a plein de petits trucs dans la campagne... apprenez a vous en servir.
Bien sur, des fois, le code est un peu ardu a lire, surtout pour les choses compliquées, mais vous commencez a vous débrouiller en script non ? Sinon, c'est peut être que vous vous attaquez a un trop gros morceau.
Ce qui m'amène a un point que je voulais aborder depuis longtemps. Il est normal quand on veut faire un module, d'essayer de suite de scripter le truc particulier qui va faire de son module, celui dont on sera fier. Hors, au début, c'est souvent une mauvaise idée. Commencez a vous faire la main sur de petits scripts, qui prêtent moins a conséquence, et qui vous découragerons moins vite surtout. Vous devez apprendre a marcher avant de courir.

Le Toolset.
Ne soyez pas étonnés, il y a beaucoup a apprendre du Toolset. C'est la dedans que j'ai appris la plupart de ce que je sais. Une fois que vous connaissez les bases de script, et vous les connaissez n'est ce pas ?, il y a beaucoup a apprendre de la documentation du Toolset, aussi minimale soit elle.
Vous avez sans doutes noté que quand vous éditez un script, toutes les fonctions étaient regroupées dans une fenêtre a votre droite. Vous pouvez cliquer sur chacune d'elle et avoir quelques informations dans l'écran du bas.
De plus le nom des fonctions est souvent assez explicite, utilisez donc la recherche et regardez ce que chaque fonction fait. Vous ne devriez pas tarder a trouver celle qu'il vous faut.
Prenons donc un exemple qui concerne le script écrit plus bas. Je souhaites téléporter un pc d'un endroit a un autre. Je ne sais pas comment faire, donc je commence a regarder les fonctions. Il semblerait que la fonction " ActionMoveToLocation " corresponde plutôt bien. Cependant, j'ai déjà utiliser les commandes " Move " et je sais que cela veut dire marcher. Je continue ma rechercher et je vous " ActionJumpToLocation ". Voyons donc ça de plus près. Je clique dessus et cela me dit.


// The subject will jump to lLocation instantly (even between areas).
// If lLocation is invalid, nothing will happen.
void ActionJumpToLocation(location lLocation)

Les deux premières lignes sont des commentaires. La première nous apprends que la fonction correspond bien a ce que l'on veut. La deuxième nous explique comment elle se comporte dans certains cas.
La troisième ligne nous explique comment mettre en œuvre la fonction. Si vous ne comprenez pas, alors relisez donc la leçon 1
Reprenons notre recherche dans la liste...
Cette commande est une commande de type " Action ". Il va donc probablement que nous placions notre téléport dans la file des actions. Si nous voulons qu'il opère immédiatement, il va nous falloir trouver quelque chose... Et si on utilisait juste " JumpToLocation " ?
Le problème suivant est, comment récupérer une " Location " a passer en argument a la fonction ? La plupart des fonctions ramenant une réponse commencent par " Get ", regardons donc celles ci. Il y a bien une fonction " GetLocation ".
Hmmmm... la commande " JumpToLocation " ne prend pas en argument ce que vous voulez bouger. C'est un petit peu plus compliqué a trouver, mais je vous laisse chercher par vous même
Vous voyez qu'avec un peu de persévérance, et un peu d'intuition, on en apprends beaucoup... et vous verrez qu'au fil du temps, cela viendra de plus en plus facilement.
Apprenez a connaître les fonctions, vous en trouverez des usages peut être inventifs.

Continuons.
Bon assez parlé méthode, faisons un peu de script
Tout ce que nous avons appris dans les leçons précédentes concernait les nps, passons a quelque chose de différent.
En règle générale, que l’on scripte un npc, un objet ou un « trigger », la démarche est la même. Il suffit souvent de faire attention a ce a quoi fait référence le OBJECT_SELF, mais la structure et les commandes sont les mêmes.
Dans notre module de test, si vous avez suivi mes instructions, nous avons deux zones qui ne sont en rien connectées entre elles. Nous avons juste placé notre point d’entrée comme nous en avions besoin. Même si c’est utile pour les tests, c’est un peu gênant. On pourrait placer une zone de transition entre les deux mais ce serait… inintéressant. Faisons donc quelque chose de plus sympa.

Voici ce que je vous propose, dans une des zones, nous allons placer deux leviers, tous les deux en position « off » par défaut. Quand les deux leviers sont abaissés, ils provoquent l’apparition d’un portail qui permet la téléportation dans l’autre zone.
Voici comment faire pas a pas.

 Ouvrez le Toolset, choisissez votre module, choisissez une des zones. A priori la plus grande des deux.
 Placez deux leviers. "Placeable Objects", "Containers and Levers" « Floor Lever ».
 Donnez au premier le tag « LEVIER1 » et au deuxième le tag « LEVIER2 ».
 La ou vous voulez faire apparaître le portail de téléportation, placez un « WayPoint », donnez lui le tag « TM_INWP ».
 Dessinez un « trigger » autour de ce « WayPoint ». Donnez lui le tag « PORTTRIG ».
 Mettez ce script dans le « OnUsed » de chacun des leviers. Editez le une fois en tant que tm_levier_ou et mettez le sur les deux leviers.


// OnUsed script: tm_levier_ou 

//
// Ce script active les leviers nommés LEVIER1 et LEVIER2.
// Les deux sont levés par défaut.
// Lorsque les deux sont baissés, un portail est activé au WayPoint « TM_INWP »
// Et le trigger « PORTTRIG » est activé.
//
// Ecrit par Celowin
// Le 12 Juillet 02
//
void main() 

   
int nUsed1 GetLocalInt(OBJECT_SELF"ETAT_LEVIER") ; 
   
int nUsed2 
   
//
   // nUsed1 et nUsed2 renseignent de manière temporaire l’état des leviers.
   // 0 pour « Off », 1 pour « On »
   // Chaque levier a son propre « ETAT_LEVIER ».
   //
   
if (nUsed1 == 1
   
// Si le levier est a « On » alors le placer a « Off »
      
SetLocalInt(OBJECT_SELF"ETAT_LEVIER"0); 
   else 
   
// Si le levier est a « Off » alors le placer a « On »
      
SetLocalInt(OBJECT_SELF"ETAT_LEVIER"1); 
      
nUsed1 GetLocalInt(GetObjectByTag("LEVIER1"), "ETAT_LEVIER"); 
      
nUsed2 GetLocalInt(GetObjectByTag("LEVIER2"), "ETAT_LEVIER"); 
      if ((
nUsed1==1) && (nUsed2==1)) 
      
// Est ce que les deux leviers sont a « On » ?
      

         
// Alors créer le portail et le trigger.
         
object oPortalSpot=GetWaypointByTag("TM_INWP");
         
CreateObject(OBJECT_TYPE_PLACEABLE,"plc_portal",
            
GetLocation(oPortalSpot), TRUE);
         
SetLocalInt(GetObjectByTag("PORTTRIG"), "READY"1); 
      } 
}


Il y a quelques petites choses a expliquer dans ce script, mais pour la plupart, j’espère que les commentaires sont suffisants.

 Prenez maintenant le trigger que vous avez dessiné.
 Placez ce script sur le « OnEnter ». Sauvegardez le en « tm_portail_en ».


// « OnEnter » script: tm_portal_en
//
// Si le portail est « On » et qu’un Pc entre dedans,
// alors téléporter le Pc au WayPoint « TM_OUTWP ».
//
// Ecrit par Celowin
// Le 12 Juillet 02.
//
void main() 

// Initialisation de nos variables
//
object oPC GetEnteringObject(); 
object oDest GetWaypointByTag("TM_OUTWP"); 
int nReady GetLocalInt(OBJECT_SELF"READY"); 
//
// Vérifie si c’est un Pc et si le portail est « On » ?
// Dans ce cas, téléporter le Pc.
if ((nReady==1) && (GetIsPC(oPC))) 
AssignCommand(oPCJumpToLocation(GetLocation(oDest))); 
}


 On a presque terminé, sortez du trigger.
 Prenez votre zone de destination.
 Dessinez un « WayPoint ». Donnez lui le tag « TM_OUTWP ».
 Sauvegardez le tout et sortez de l’éditeur.
 Testez.

Ces scripts sont relativement linéaires. La seule chose qui mérite d’être précisée a mon sens est le « AssignCommand ». C’est une de ces commandes qui nous font nous demander comment on a pu vivre sans. Elle sert simplement a faire effectuer une action a quelqu’un d’autre. Nous voulons que le joueur se téléporte, donc nous lui demandons de le faire.
Un petit mot encore au sujet des variables renseignant l’état des leviers. J’utilise nUsed1 deux fois. Une fois pour chaque levier. En fait, c’est l ‘état du levier sur lequel on est. Hors plus tard, je dit que nUsed1 est l’état du LEVIER1.
Il y aura sans doutes des programmeurs qui ne trouveront pas ça très propre. Alors pourquoi l’ai je fait ? Par soucis de simplicité. Le script est suffisamment court. Il n’y a pas de besoin de rajouter une autre variable. Sur un script plus long ou plus compliqué, je l’aurai sans doutes fait.
Une autre chose a préciser est la commande « CreateObject » et pour ce faire, il faut expliquer la différence entre un tag et une référence de bluePrint.
Les objets qui sont dans le jeu ont des Tags. Il est donc possible de retrouver tout objet, déjà crée par son tag. Mais un objet qui n’a pas encore été crée n’en a pas… encore. A la place, nous utilisons un « BluePrint », une sorte de schémas de l’objet, avec toutes les instructions permettant de le créer. C’est exactement cela, le « plc_portal », la référence du « BluePrint » de l’objet Portail. Notez que pour trouver la référence du « BluePrint », j’ai juste dessiné un portail. En regardant dans l’ongle propriétés, j’ai noté sa référence.

Exercices complémentaires.
Apres le cours, les devoirs a la maison… et j’aimerai beaucoup que vous les fassiez. Je ne peux en aucun cas vous y contraindre, mais je peux vous assurer qu’ils sont nécessaires afin d’assimiler ces leçons.
Essayez donc de faire ceci.
A l’heure actuelle, abaisser les deux leviers active le portail. Mais une fois activé, le portail reste en place quelque soit ce qu’on fait aux leviers. Il faudrait que le portail disparaisse des que l’on relève l’un OU l’autre des leviers. Et bien sur, qu’il réapparaisse des que les deux sont baissés.
Une autre idée…
Essayez de faire un portail qui marche dans les deux sens…
Je pense que le premier exercice est moyennement difficile, le second étant assez facile.
Quoiqu’il en soit, bon courage et a bientôt pour une nouvelle leçon.

__________________
Amaranthe.
Thoerel, un monde semi-persistant pour Neverwinter Nights.