?
| Nos forums | NwN2.fr | Lyncya | Notre channel IRC |
La Bibliothéque de Neverwinter Nights
La Bibliothéque de Neverwinter Nights
 
 
 
 
 
Bienvenue, connectez vous ou créez votre compte. Changer d'interface
 
Se connecter:
Login:

Password:


 
Neverwinter Nights 2
  Compendium NWN/NWN2
Classe, Warlock
Classes de Base
Classes de Prestige
Forum Joueur NWN2
Forum Concepteur NWN2
Bestiaire (Créatures)
Races
Tests
 - Collector Chaotique Mauvais (bbnwn, 4 nov 2006)
 - Mask of the Betrayer
 - Storm of Zehir
 - Mysteries of Westgate
Mondes
 - Les Artisans du Mitan
 - Les Légendes de Luiren
 - LanceDragon
 - La Bataille pour Cormanthor
 - Man O'War
 - Sendarie Nouvel Âge
Preview
 - 29 Mars 2006 (BBNWN)
 - 2 mai 2006 (Gamespot)
 - 17 Mai 2006 (WarCry)
 - 19 Mai 2006 (NWVault)
 - Designer Diary #1 (Gamespot, 1er Juin 2006)
Interview
 - Dorian Richard (20/02/2006)
 - Ferret Baudoin (22/02/2006)
 - Feargus Urquhart (2 mai 2006)
 - La Lettre Ouverte de Papermonk
 - Chris Avellone (Total Video Games)
Logs IRC
 - Warcry (27/01/2006)
 - NWVault / NWC (3 Juin 2006)
 - NWN2News.net (30 Juin 2006)
Faciliter la diffusion et l'installation de vos créations

 
Communauté
  Forums
Channel #nwnights-fr
Guide IRC
Liens
CEP

 
Fichier
  Tileset
Module
Hakpak
Objets
Portraits
Créatures
Scripts
Tutoriaux
Autres
Wallpapers

 
Editeur
  Tutorial Editeur
Cinématiques
Musiques
Textures
Tutoriaux NWScripts
Scripts

 
Le jeu
  Solution
Sorts
Classes
Dons (feat)
Aptitudes (skill)
Bestiaire
Règles 3e Edition
Jouer en multiplayer

 
Hordes of the Underdark
  Informations Générales
Solution [forum]

 
Shadows of Undrentide
  Preview
Informations générales
Classes de Prestige
'Lisez Moi.txt' de la Démo
FAQ
Nouveaux tilesets
Solution [forum]

 
Divers
  Traductions Logs Irc
Guides divers

 
Présentation
  Généralités
Configuration minimale
Serveur Dédié
Traduction FAQ
Historique (nwn et bioware)
Contrats de Bioware (vf)

 
Site
  Copyrights
Webmasters

 
     
 
Dîtes non aux inutiles protections contre la copie dans les jeux (SecuROM, StarForce, etc) !!
HADOPI - Le Net en France : black-out

Masteriser Neverwinter Nights (mnwn)

Prélude



Navigation dans la série :

Table des matières :

Vue du Module

Voir agrandi


1. Quartiers des Vétérans : le premier coffre

Mastering NWN Les "Quartiers des Vétérans" sont la zone où tout commence. Et la première chose intéressante se trouve juste à côté de votre point de départ, dans un coffre qui ressemble à n'importe quel autre. Ce coffre n'est pas vérrouillé, ni piégé, mais il possède le script "m1q0_feat" attaché aux évènements OnOpen et OnDeath. regardons ce script : (ok, j'ai coupé un paquet de sections qui se ressemblent énormément les unes les autres, puisque vous pouvez ouvrir ce script vous même et l'examiner, mais j'ai laissé toutes les lignes dont nous avons besoin pour comprendre cela).

Euh... bon, une suggestion : commencez par la fonction principale ! Nous avons l'ouvreur du conteneur, et le conteneur. Maintenant, regardons la variable "NW_L_OPENONCE" du conteneur. si la variable est > 0, ou si l'ouvreur n'est pas un objet valide, on s'arrête là. Autrement, on commence un petit parcours. Tout d'abord, on initialise la variable NW_L_OPENONCE à 1 pour indiquer que le conteneur a été ouvert une première fois (si on ne le fait pas, on pourrait obtenir un objet à chaque ouverture du coffre... c'est comme ça que vous pouvez faire rapidement une boîte magique, si vous le désirez). Ensuite, on signale autour que l'on a été dérangé, si jamais quelqu'un s'y intéresse.

Maintenant nous avons un gros block de commandes si-alors, vérifiant toutes la fonction Prefers. La fonction Prefers est définie dans le même script. Comme le disent les commentaires, elle contient deux paramètres : un FeatWeaponType, et un objet d'aventurier. Prefers se contente de vérifier si l'aventurier a le don correspondant à ce type d'arme, à l'aide de la fonction GetHasFeat. Voici l'aide pour GetHasFeat :

// Determine whether oCreature has nFeat, and nFeat is useable.
// - nFeat: FEAT_*
// - oCreature
int GetHasFeat(int nFeat, object oCreature=OBJECT_SELF)

Vous pouvez l'utiliser avec n'importe quelle constante FEAT_*, et vous avez à disposition une constante pour chaque don du jeu. GetHasFeat renvoie à Prefers soit TRUE soit FALSE (ah, ces bons vieux entiers passant pour des booléens... ça fait penser à des C++, hein ?), qui lui même renvoie la même chose à notre fonction principale originale. Donc, par exemple, la première vérification dans la fonction principale est :

if (Prefers( FEAT_WEAPON_FOCUS_BASTARD_SWORD, oLastOpener) == TRUE)
{
CreateBastardSword( oContainer, oLastOpener);
}

Si le PJ (parce que bon, on suppose que c'est un PJ non ?) a le don correspondant à l'épée bâtarde, alors la fonction principale appelle CreateBastardSword (devinez ce que ça fait). Sinon il fait la vérification suivante. Tôt ou tard, l'une des vérifications renverra Vrai et l'on créera l'objet approprié. Si tout le reste rate, on créera un gourdin, juste pour le fun. Maintenant, regardons une ou deux de ces fonctions Create<n'importe quoi>...

Par exemple, CreatBastardSword, puisque nous l'avons déjà mentionnée. Elle accepte deux paramètres : l'objet correspondant au conteneur, et l'objet correspondant à l'aventurier. La fonction récupère les Dés de Vie (DV si vous permettez) de l'aventurier. Ensuite elle utilise GetRange pour... attendez un instant ! GetRange ?? Cherchons dans le fichier... hummm.... non. Cherchons dans tous les fichiers du module... hmmm... rien... cherchons dans toutes les ressources... ah, voilà, bien sûr, dans le fichier NW_02_CONINCLUDE (qui incluse le fichier m1q0_feat). Hummm... NW_02_COINCLUDE, que contient ce fichier ? Le commentaire de Bioware dit (avec quelques coupures) :

/*
This include file handles the random treasure
distribution for treasure from creatures and containers

[ ] Documented
*/

// April 23 2002: Removed animal parts. They were silly.
// May 6 2002: Added Undead to the EXCLUSION treasure list (they drop
// nothing now)
// - redistributed treasure (to lessen amount of armor and increase
// 'class specific treasure'
// - Rangers with heavy armor prof. will be treated as Fighters else
// as Barbarians
// - Gave wizards, druids and monk their own function
// MAY 29 2002: Removed the heal potion from treasure
// Moved nymph cloak +4 to treasure bracket 6
// Added Monk Enhancement items to random treasure

Ainsi, les "Animal Parts" étaient stupides, et les mort-vivants ne lâchent plus de trésor (bon sang !), bon... Revenons à GetRange. Voilà le commentaire de Bioware à ce sujet :

/*
Returns true if nHD matches the correct
level range for the indicated nCategory.
(i.e., First to Fourth level characters
are considered Range1)
*/

Avec cet en-tête : int GetRange (int nCategoty, int nHD). Donc, étant connus les DVs du personnage, ça retourne en gros la gamme de niveau dans laquelle se situe le personnage. Par exemple, notre fonction CreateBastardSword utilise GetRange ainsi :

if (GetRange(1, nHD)) // * 800
{
/* ... */
}
else if (GetRange(2, nHD)) // * 200 - 2500

et ainsi de suite. Le premier appel regarde si le PJ est dans la première game de niveau des personages (avec des DVs compris entre RANGE_1_MIN et RANGE_1_MAX, soit entre 0 et 5). Cool. Donc qu'arrive-t-il si le PJ est dans cette game de niveau de DV ? Ben CreateBastardSword exécute le code suivant :

int nRandom = Random(1) + 1;
switch (nRandom)
{
case 1: sItem = "nw_wswbs001"; break;
}

euh... hmmm... ça crée un nombre aléatoire entre 0 et (1-1) (i.e. 0 sauf si Bioware utilise un système mathématique ésotérique)... ça ajoute 1 à ce nombre (hmmm... ça fait 1 chez moi), et si le résultat est 1 (oh !), ça met la variable sItem à "nw_wswbs001". Si notre PJ rentre dans une autre gamme de niveau de DV, on peut éentuellement finir avec différentes chaînes de caractères dans sItem. Quoi qu'il en soit, à la fin de ce bloc si-alors fondé sur le niveau de DV du PJ, on appelle :

dbCreateItemOnObject(sItem, oTarget, 1);

Hein ? Je m'attendais à un bête CreateItemOnObject... hmmm... ce préfixe db... cherchons... oh, c'est dans le fichier nw_02_include ! Sans rentrer dans les détails de ce qui est visiblement une fonction de débuggage, dbCreateItemOnObject crée l'objet dans/sur l'objet (fabriquant un emplacement si nécessaire) par l'intermédiaire du CreatItemOnObject, ce qu'on attendait de notre CreateBastardSword.

C'est assez clair non ?

2. Quartiers des Vétérans : Pavel

Dès que vous passez la porte de la pièce où vous commencez l'aventure, vous trouvez Pavel qui vous attend. Le comportement de Pavel est en gros défini par son script OnSpawn (tous ses autres scripts évènements sont vides) et son dialogue. Tout d'abord, le script :

^^^^^^^^^^^^^^^^^^^^
Script: m1_initdlg_9
^^^^^^^^^^^^^^^^^^^^
//Laves the object Id of the NPC
//this is used in the trigger onExit script
void main()
{
SetLocalObject( GetArea( OBJECT_SELF ), "NW_G_" +
GetTag( OBJECT_SELF),OBJECT_SELF);
}
^^^^^^^^^^^^^^^^^^^^

Alors, dès que Pavel apparaît, ce script mettra un objet local dans la zone, appelé NW_G_...lt;Tag de Pavel...gt; (soit simplement NW_G_M1Q0APavel), à la valeur OBJECT_SELF (soit en d'autres termes, une référence à Pavel lui-même). Le script dit que cet objet sera utilisé dans le script OnExit. Donc on va aller regarder ça. Autrement dit, on va aller regarder le script OnExot de la zone. Sélectionnez "Area Properties", puis l'onglet "Scripts", puis le script2 dans la liste d'évènements OnExit... cliquez sur Edit et eh bien ! On en est là : le script est introuvable... hmmm... Les scripts du module n'aident pas beaucoup pour ça.

A la fin de cette section sur Pavel, vous verrez que Pavel est en fait positionné dans un Trigger (déclencheur), et que l'évènement OnExit mentionné ici est en fait l'évènement OnExit du Trigger. Pour voir comment cette référence à Pavel est utilisée, lisez la fin de cette section, où l'on examine le Trigger. Cependant, nous n'avons pas encore trouvé le "Script2" pour la zone.

A la place, regardons le dialogue de Pavel : dialogue m0q01a01pave. A partir de la racine, nous avons 4 branches principales.

La première ramification contient un unique noeud : "Protect the Waterdhavian creatures! Don't let the attackers get them!"

Elle apparaît lorsque l'entier local "NW_PROLOGUE_PLOT" (sur le module) prend la valeur 99, et un son lui est attaché. Si vous regardez le dernier onglet, vous pouvez voir les scripts qui s'exécuteront lorsque la conversation se terminera normalement et quand elle sera interrompue prématurément. Si la conversation se termine normalement, le script m1q0apaveend fait bouger Pavel à l'objet portant le tag "WP_return_<Tag de Pavel>" le plus proche. La même chose se produit après une discussion interrompue. Si on regarde la zone, on s'aperçoit que Pavel débute le jeu juste sur un waypoint portant ce même tag.

La deuxième ramification du dialogue de Pavel commence avec le noeud : "Finally, you're up. I was afraid you were going to sleep all day. I guess the instructors work you pretty hard here at the Academy."

Elle apparaît lorsque la variable locale NW_L_TALKTIMER (définie sur Pavel) vaut 0, et elle mène alors à un lien vers la quatrième ramification de l'arbre du dialogue (voir ci-dessous). Pendant ce temps, le dialogue définit une variable locale sur le PJ, nommée "NW_L_Init<Tag de Pavel>" et initialisée à TRUE.

La troisième ramification du dialogue de Pavel commence avec le noeud : "Hello again, <Firstname>. I'm surprised you're still here - I thought you'd be anxious to go see Olgerd in the next room so you can finish your training."

Elle apparaît lorsque la variable locale (sur Pavel) "NW_L_TALKLEVEL" est supérieure ou égale à 1. Ce noeud mène à 3 noeuds pour la réponse du PJ :

"I want to ask you some more questions.", pour un PJ d'intelligence normale. (eh-ehm... je pense que Bioware considère une "intelligence normale" comme étant supérieure ou égale à 9, vous pouvez vérifier la fonction CheckIntelligenceNormal dans le fichier "nw_io_plot"... Curieusement, il y a deux prototypes listés pour cette fonction... quelqu'un a du faire CTRL + V une fois de trop).
"Me want ask questions.", pour un PJ avec une intelligence faible.
"Goodbye.", pour quiconque veut interrompre le dialogue.

Cette dernière branche mène à l'attribution à la variable "NW_L_Init<Tag de Pavel>", sur le PJ, de la valeur TRUE, et éventuellement à la fin de la conversation. La seconde branche mène à un lien vers le noeud suivant dans la première de ces branches. Voilà le noeud en question :

"I don't know how much I can tell you, <Firstname>, but I'll do my best to help. We're all going to have to work together if want to survive the Wailing Death... unless those rumors about a cure turn out to be true."

Ce noeud mène à une série de noeuds que le PJ peut sélectionner. Il y a en gros 3 possibilités de question pour le PJ, mais chaque question est présente en deux versions, l'une pour les PJs d'intelligence normale, l'autre pour ceux mentalement déficient. Chaque noeud de l'option faible intelligence mène à un lien pour le noeud suivant la question équivalente pour les PJs d'intelligence normale. Pour chaque sous-branche, vous pouvez obtenir des informations sur la Wailing Death, les rumeurs concernant le remède concernant le fléau, ou ‘n'importe quoi d'autre', et éventuellement vous pourrez cliquez sur le noeud "Goodbye" pour mettre fin à la conversation.

Finalement, la quatrième ramification du dialogue de Pavel commence avec le noeud :

"My name's Pavel, I'm one of the new recruits. I just arrived here at the Academy this morning. You're <FullName>, aren't you?"

Passer par ce noeud incrémentera simplement la variable "NW_L_TALKTIMER" sur Pavel. De ce noeud partent deux branches : "Yes, I am ...<FullName>", et "No, I think you have me confused with someone else.", ainsi que leurs equivalents pour les mentalement déficients. La seconde option conduit Pavel à afficher un entier et tester votre bluff, et rapidement ramène le dialogue dans l'autre branche.

Après avoir effectué cela, un objet local nommé "NW_L_CurrentPC" est défini sur Pavel pour définir le PJ qui est en train de lui parler. En parallèle des textes saupoudrés et des options d'intelligence, cette ligne de dialogue amène Pavel à mentionner Bim (son frère), et incrémente la variable locale "NW_L_TALKLEVEL" sur Pavel (quelque fois, ça dépend de vos choix). Au bout d'un moment vous terminerez votre discussion avec Pavel de toute façon.

Est-ce là tout ce qu'il y a autour de Pavel ? Bien, Pavel vous attend en fait au milieu d'un gros Trigger le seul de la zone. Le trigger a deux scripts associés : OnEnter, le script m1q0atrig_2, et OnExit, le script m1q0atrig_3. Jetons-y un coup d'Sil :

^^^^^^^^^^^^^^^^^^^
Script: m1q0atrig_2
^^^^^^^^^^^^^^^^^^^
// this is the on enter script if a trigger that encompasses the NPC who will be
//initiating dialouge. Make sure to replace the value of sTag with the tag of
//the NPC in question.
void main()
{
    string sTag = "M1Q0APavel";
    object oNPC = GetLocalObject( GetArea( OBJECT_SELF ), "NW_G_" + sTag);
    object oPC = GetEnteringObject();
    if(GetIsPC(oPC) ......
      GetLocalInt(oPC,"NW_L_Init" + GetTag(oNPC)) == FALSE ......
      IsInConversation(oNPC) == FALSE)
    {
      AssignCommand( oPC, ClearAllActions());
      AssignCommand( oNPC, ClearAllActions());
      AssignCommand( oNPC, ActionMoveToObject(oPC));
      AssignCommand( oNPC, ActionStartConversation(oPC));
    }
}
^^^^^^^^^^^^^^^^^^^

Hmmm... alors, si l'objet entrant dans le trigger est un PJ, si la variable "NW_L_Init<Tag de Pavel>" sur le PJ est à FALSE, et si Pavel n'est pas dans une conversation (notez que la référence à Pavel est obtenue par l'objet local de la zone appelé "NW_G_<Tag de Pavel>"), alors on annule les actions du PJ, du PNJ (Pavel, au cas où vous seriez perdu), on fait avancer Pavel vers le PJ, et on le fait commencer la conversation.

Pourquoi ne pas utiliser l'évènement OnPerceive de Pavel ou son onUserDefined avec l'Evènement Perception activé ? <ton académique>Choix esthétique</ton académique>. L'autre script du trigger concerne l'évènement onExit.

^^^^^^^^^^^^^^^^^^^
Script: m1q0atrig_3
^^^^^^^^^^^^^^^^^^^
//This will return the NPC to a starting position if he attempts to
//leave the
//trigger. You must replace the value of sTag with the tag of the NPC
//in
//question. you must also have a waypoint with the tag "WP_Return_" +
//NPC's Tag.
//This should be placed in the spot the NPC starts at.
void main()
{
    string sTag = "M1Q0APavel";
    object oExit = GetExitingObject();
    if(GetTag(oExit) == sTag)
    {
      AssignCommand( oExit, ClearAllActions() );
      AssignCommand( oExit, ActionMoveToObject( GetNearestObjectByTag("WP_Return_" + sTag) ) );
    }
}
^^^^^^^^^^^^^^^^^^^

En gros, c'est là uniquement pour s'assurer que Pavel ne quitte pas la zone de ce trigger, et reste à prowimité de son waypoint WP_return_. Si vous voulez, c'est le coût de l'utilisation d'un trigger à la place de l'évènement onPerceived de Pavel. En fait, onPerceived marcherait où que soit Pavel, mais la conversation trigger-triggered (déclencheur-déclenché) (mais qu'est-ce que c'est que cette récursion ?) ne marche que si les PJs entrent dans la zone du trigger.

3. Quartiers des Vétérans : Bim

Bim se trouve dans la même pièce que Pavel. Je trouve Bim assez marrant, à première vue. Peut-être est-ce parce que quand vous cliquez sur son onglet "Scripts ", vous trouvez les scripts suivants :

• OnHeartbeat :          m1q0apavel_1
• OnPerception :         m1q0apavel_2
• OnPhysicalAttacked : m1q0apavel_4

Eh-ehm... Les scripts de Pavel sur Bim ? C'est sûr ils sont frères, mais que se passe-t-il exactement avec ça ? Bah ! on verra bien... Les autres scripts de Bim sont vides, donc, par exemple, on n'a pas à regarder le onspawn... Commençons par l'évènement OnHeartBeat, ça vous va ?

^^^^^^^^^^^^^^^^^^^^
Script: m1q0apavel_1
^^^^^^^^^^^^^^^^^^^^
void main()
{
    object oPC = GetNearestCreature( CREATURE_TYPE_PLAYER_CHAR,
    PLAYER_CHAR_IS_PC,
    OBJECT_SELF,
    1,
    CREATURE_TYPE_PERCEPTION,
    PERCEPTION_SEEN);
    if( GetLocalInt( OBJECT_SELF, "NW_L_CallingOut" ) ......
      GetIsObjectValid(oPC) ......
      IsInConversation(oPC) == FALSE ......
      GetLocalInt( GetModule(), "NW_PROLOGUE_PLOT") < 99 )
    {
      if( GetLocalInt( OBJECT_SELF, "NW_L_HBCount" ) > 2 )
      {
        SpeakOneLinerConversation();
        SetLocalInt(OBJECT_SELF,"NW_L_HBCount",0);
      }
      else
      {
        SetLocalInt(OBJECT_SELF,"NW_L_HBCount",GetLocalInt
        (OBJECT_SELF,"NW_L_HBCount") + 1);
      }
    }
}
^^^^^^^^^^^^^^^^^^^^

Ainsi, pour chaque heartbeat, Bim reçoit une référence à la plus proche créature qui est un PJ et visible. Ensuite il vérifie la variable locale “NW_L_CallingOut” (placée sur lui-même). Si cette variable est à 0 (équivalent à FALSE), il ne fait rien. S'il ne voit pas de PJ, il ne fait rien. Si le PJ qu'il voit est en conversation, il ne fait rien. Si la variable “NW_PROLOGUE_PLOT” est supérieure ou égale à 99 il ne fait rien. Si toutes ces vérifications renvoient TRUE, alors Bim vérifie la variable “NW_L_HBCount” placée sur lui-même. Si cette variable est à 3 ou plus, alors il dit la première ligne de sa conversation (ok, pas seulement ‘la première ligne', mais plutôt la première ligne qu'il dirait si le PJ essayait de lui parler et y arrivait… on se plongera dans la conversation de Bim très bientôt), et met à 0 la variable NW_L_HBCount sur lui-même. Si NW_L_HBCount était inférieure ou égale à 2, Bim se contente de l'incrémenter. En gros cela empêche Bim de dire sa ligne à chaque heartbeat (ce qui pourrait en effet être ennuyeux !).

Voilà le script onPerception de Bim :

^^^^^^^^^^^^^^^^^^^^
Script: m1q0apavel_2
^^^^^^^^^^^^^^^^^^^^
void main()
{
  if(GetIsPC(GetLastPerceived()) &&
    GetLocalInt(GetModule(), "NW_PROLOGUE_PLOT") < 99)
  {
    SetLocalInt(OBJECT_SELF,"NW_L_CallingOut",TRUE);
  }
}
^^^^^^^^^^^^^^^^^^^^^

En bref, si Bim aperçoit un PJ, et si la variable “NW_PROLOGUE_PLOT” est inférieure à 99, il donne alors la valeur TRUE à la variable “NW_L_CallingOut” sur lui-même (qui , ensuite, sera vérifiée par le script m1q0apavel_1 pour l'évènement onHeartbeat, comme expliqué plus haut). Finalement, le script onPhysicalAttack de Bim est le suivant :

^^^^^^^^^^^^^^^^^^^^
Script: m1q0apavel_4
^^^^^^^^^^^^^^^^^^^^
void main()
{
  if(GetLocalInt(OBJECT_SELF, "NW_L_TALKLEVEL") == 1)
  {
    SetLocalInt(OBJECT_SELF, "NW_L_TALKLEVEL",2);
    SetLocalInt(OBJECT_SELF, "NW_L_CallingOut",TRUE);
    AssignCommand(GetLastAttacker(),ClearAllActions());
    SpeakOneLinerConversation();
  }
}
^^^^^^^^^^^^^^^^^^^^^

Bon, si NW_L_TALKLEVEL (définie sur Bim lui-même) ne vaut pas 1, rien ne se produit. Autrement, NW_L_TALKLEVEL sur Bim est mise à 2, NW_L_CallingOut est mise à TRUE, les actions de Bim sont annulées, et il dit la première ligne (encore une fois, celle qu'il aurait dite si un dialogue avait été engagé avec lui à ce moment là) de son arbre de dialogue. En gros c'est un juke-box : frappez le et il chantera !

Bon maintenant, ouvrons le dialogue de Bim : m0q01a0bim. 12 (douze !) branches à partir de la racine, et les six premières n'ont pas de nœud-fils… hmmm… notez également que les champs “Normal” et “Aborted” de l'onglet “Current File” de Bim sont vides. On dirait que chaque fois que vous arrêter de parler avec Bim, il restera planté là et gardera la même attitude.

Noeud#1 : “Protect the Waterdhavian creatures ! Don't let the attackers get them !”, apparaît lorsque NW_PROLOGUE_PLOT vaut 99.

Noeud#2 : “Hey there, I want to talk to you”, apparaît lorsque Bim parle à un PJ (souvenez vous, cet arbre de dialogue peut être appelé par le script onHeartbeat de Bim, et comme il est dans la même pièce que Pavel, il pourrait apercevoir Pavel !).

Noeud#3 : “Right-click on me to bring up the menu, then select the attack icon on the right of the menu to punch me.”, apparaît lorsque NW_L_TALKLEVEL vaut 1 ; n'est-ce pas une belle façon de débuter une conversation ? Bien, considérons que toutes les variables sont initialisées à 0 au début du module… il devrait être clair pour tout le monde que pour que NW_L_TALKLEVEL (sur Bim) prenne la valeur 1 il faut qu'il se passe quelquechose. Cette situation sera probablement amenée par une ligne dans la conversation, et Bim est prêt à “prendre un pour tous” pour ainsi dire.

Noeud#4 : “I want to talk to you again”, apparaît lorsque Bim aperçoit le PJ, et que NW_L_TALKLEVEL vaut 2.

Noeud#5 : “Speak to me again before you leave the room”, apparaît lorsque Bim aperçoit (vous l'aviez deviné) un PJ, et que NW_L_TALKLEVEL vaut 3.

Noeud#6 : “Speak to me after you've rested. In order to rest, just left-click on the rest button below your portrait in the upper right corner of the screen”, apparaît lorsque… oh, regardez ça ! C'est le script conditionnel de ce noeud :

^^^^^^^^^^^^^^^^^^^^^^^
Script: m0q01a01bimsck9
^^^^^^^^^^^^^^^^^^^^^^^
int StartingConditional()
{
  object oPC = GetLocalObject(OBJECT_SELF,"NW_L_CurrentPC");
  int bCondition = GetLocalInt(OBJECT_SELF, "NW_L_TALKLEVEL") == 4 &&
  GetLocalInt(GetPCSpeaker(),"NW_L_M1Q0Rested")
  == FALSE;
  return bCondition;
}
^^^^^^^^^^^^^^^^^^^^^^^

Vous ne remarquez rien de bizarre (*ici, jeux de mot inside en anglais , à vous de comprendre*) ?En gros, ce nœud apparaîtra si NW_L_TALKLEVEL sur Bim vaut 4, et si la variable NW_L_M1Q0Rested sur le PJ qui parle à Bim vaut FALSE. Bon, alors, que dire de la première ligne ? Elle acquiert une référence à un objet, stocké sur Bim, nommé NW_L_CurrentPC. Mais, elle n'en fait rien … Elle ne vérifie même pas si l'appel à GetLocalObject renvoie un OBJECT_INVALID ou non. A moins que j'ai raté quelquechose, c'est une ligne redondante (peut-être laissée là depuis une version précédente, où le comportement de Bim dépendait de cette référence locale…).

Noeud#7 : “Okay, you've had a chance to test out the Top Down Camera mode. Now we'll let you try the Chase Camera mode.”, apparaît lorsque la variable “Camera Test” sur Bim vaut 1. Arriver à ce nœud provoque l'exécution de la ligne suivante :

SetCameraMode( GetPCSpeaker(),CAMERA_MODE_CHASE_CAMERA);

Devinez ce que ça fait. Oui, exactement, ça met votre camera en Chase Mode. Je n'entrerai pas plus dans les détails concernant les nœuds suivants puisqu'ils concernent tous le tutorial de la Camera, utilisent en gros les variables SetCameraMode et CameraTest pour vous guider à travers les options.

Noeud#8 : “Okay, you've had a chance to test out the Chase Camera mode. Now we'll let you try the Driving Camera mode.”, apparaît pour CameraTest égal 2 (en supposant qu'on arrive après la branche du Node#7 ci-dessus).

Noeud#9 : “Okay, <Firstname>, you've had a chance to try all three camera modes now. You can choose between them by selecting “Controls” dans le menu “Options”.”, apparaît pour CameraTest égal 3.

Noeud#10 : “You're <FullName>, right ? I saw you talking to my brother, Pavel. My name is Bim. If you want, I can give you a short tutorial on adventuring.”, apparaît pour NW_L_TALKLEVEL (sur Bim) égal 0, et attribue à NW_L_CallingOut la valeur FALSE. Ainsi, ça provoquera sûrement l'appel de la première branche (puisque tant qu'elle n'est pas modifiée, la variable NW_L_TALKLEVEL sur Bim vaut 0 par défaut), et assurera que Bim arrête de vous appeler. Cette branche mène au tutorial de Bim sur les modes de la camera, et utilise la variable CameraTest lorsqu'il est nécessaire de garder une trace de là où vous êtes, durant ce tutorial, pour que vous puissiez cesser la discussion avec Bim, vous déplacer alentour avec le mode de camera courrant, et recommencer là où vous vous êtes arrêté.

Noeud#11 : “Okay, seems like you've got the menu figured out. Remember, right-click on objects to bring up the menu. You can even right-click on yourself to access skills, feats and other special abilities.”, apparaît pour NW_L_TALKLEVEL égal 2 ou 3. La sélection de ce noeud mène à l'attribution de la valeur FALSE à la variable NW_L_CallingOut, et au tutorial de Bim sur le menu radial et d'autres petits aspects sympas de l'interface de NWN. Il y a une variable appelée SkipTutorial qui est vérifiée pour savoir si vous avez choisi de sauter le tutorial (par une option de dialogue), la variable NW_L_TALKLEVEL qui garde une trace de l'endroit que vous avez atteint dans le dialogue, la variable NW_L_M1Q0Rested pour voir si vous vous êtes reposé ou non (ça fait partie du tutorial), et vous pouvez finalement atteindre la fin de cette branche, qui est, bien sûr, un lien vers le dernier nœud de l'arbre.

Noeud#12 : “Well, looks like you're ready to go and complete your training. Just head on through the door and you'll find Olgerd waiting for you.”, n'a aucune condition attachée (c'est le cas de base, si vous préférez). Ca mène à l'exécution du script suivant :

^^^^^^^^^^^^^^^^^^^^^^
Script: m0q01a0bimelc1
^^^^^^^^^^^^^^^^^^^^^^
void main()
{
  SetLocalInt(GetPCSpeaker(),"SkipTutorial",99);
  SetLocalInt(OBJECT_SELF,"NW_L_TALKLEVEL",5);
  SetLocalInt(GetPCSpeaker(),"NW_L_M1Q0Rested",TRUE);
  SetLocalInt(OBJECT_SELF,"CameraTest",0);
  object oDoor = GetNearestObjectByTag("M1Q0A_M1Q0B");
  SetLocked(oDoor,FALSE);
  AssignCommand(oDoor,ActionOpenDoor(oDoor));
}
^^^^^^^^^^^^^^^^^^^^^^^

En bref, lorsque vous arrivez à la fin du dialogue complet avec Bim, votre variable SkipTutorial est mise à 99 (i.e. Je suis passé par là, ou j'ai dit que je ne voulais pas l'entendre), NW_L_TALKLEVEL sur Bim est mise à 5 (i.e. on a causé de tout ce que vous deviez entendre), NW_L_M1Q0Rested est mise à TRUE (i.e. on est passé par là, ou j'ai choisi de sauter le tutorial sur la façon de se reposer), CameraTest est mise à 0 (i.e. fait), et la porte avec le tag M1Q0A_M1Q0B est déverrouillée pour vous (et ouverte également !) vous laissant supposer que vous devriez avancer vers d'autres choses plus intéressantes.

Si vous vous demander pourquoi ce script est exécuté deux fois dans cette petite branche du dialogue (dans le nœud#12 et dans sont petit-fils), c'est parce que certaines des autres branches mènent directement au nœud petit-fils, et ça assure que le script est exécuté dans ce cas. Pourquoi, alors, ne pas avoir mis le script uniquement dans le nœud petit-fils ? Parce que vous pouvez interrompre le dialogue avec Bim à tout moment et vous en aller… ainsi l'équipe Bioware a pensé que, si vous atteignez le nœud#12, c'était suffisant et que vous pouviez vous en aller et passer à la suite (ce qui vous épargne deux nœuds de dialogue…).

4. Quartiers des Vétérans : la première porte

Bon, il semble approprié de consacrer quelques lignes à la première porte que vous rencontrez au cours de votre aventure dans NWN. La porte a le tag “M1Q0A_M1Q0B”, et est prévue pour être une porte “indestructible” (i.e. quelquechose du type “vous pouvez me taper mais vous ne pouvez pas réellement me détruire”), et verrouillée. Notez qu'elle nécessite une clef pour être déverrouillée, mais le tag de la clef n'est pas spécifié (façon amusante de s'assurer que personne ne sera capable de crocheter cette serrure !). Elle n'est pas piégée, et elle est liée au tag de destination “M1Q0B_M1Q0A” (dans la zone “Training Halls”). Enfin, elle a un script associé à son évènement onFailToOpen : nw_od_feedback8.

^^^^^^^^^^^^^^^^^^^^^^^
Script: nw_od_feedback8
^^^^^^^^^^^^^^^^^^^^^^^
void main()
{
  SetLocalInt(OBJECT_SELF, "NW_L_FEEDBACK",8) ;
  SpeakOneLinerConversation();
  ActionDoCommand(SetLocalInt(OBJECT_SELF, "NW_L_FEEDBACK",0));
}
^^^^^^^^^^^^^^^^^^^^^^^

Le script, bien sûr, met la variable NW_L_FEEDBACK de la porte à 8, et dit une ligne tirée de son arbre de conversation, puis met NW_L_FEEDBACK à 0. Notez l'utilisation de SetLocalInt(), puis de ActionDoCommand(SetLocalInt()) pour s'assurer de la bonne synchronisation du dialogue uniligne et de la mise en place/l'enlèvement de la variable NW_L_FEEDBACK.

Attendez une minute ? Dialogue ? Ce n'est pas d'une porte dont nous parlions ? Oui, bien sûr… si les dragons peuvent venir foutre le bordel dans notre village, alors *au moins* on devrait laisser les portes dire ce qu'elles pensent, vous ne pensez pas ? Je veux dire qu'elles sont principalement faites de bois… elles sont donc facilement brûlées lorsqu'un dragon détruit un village… il semble juste que nous les laissions se plaindre à tout moment, non ?

Quoiqu'il en soit, le fichier conversation de cette porte est nwn_all_feedback (et notez que non, vous ne pouvez pas interrompre cette porte quand elle parle !). Ce dialogue contient **beaucoup** de choses pour un simple dialogue de porte (et la porte ne dit que des phrases d'une ligne !). Le fait est que ce dialogue est utilisé par toutes les portes indestructibles, et la variable NW_L_FEEDBACK est définie juste avant que l'uniligne ne soit dite pour déterminer quel nœud de cet arbre de dialogue il faut énoncer.

Donc, dans ce cas, avant d'appeler la SpeakOneLinerConversation, on a mis NW_L_FEEDBACK à 8, et ça nous mène au nœud suivant :
“This door is presently barred from the other side but shows signs of recent use. Perhaps it will be open later.”

Nous examinerons les autres noeuds de ce dialogue lorsque nous les rencontrerons dans la campagne, d'accord ?




A. Législation

"Neverwinter Nights" est développé par Bioware Corp., produit et vendu par Infogrames, Inc., New York, NY. Bioware et le Bioware Aurora Engine sont des marques déposées de Bioware Corp. Tous les autres copyrights et marques déposées sont la propriété de leurs ayant-droits respectifs.


B. Contact

L'article "Masteriser Neverwinter Nights : Prélude" a été écrit par Frank "Olorin" Rizzi. Vous pouvez me contacter (l'auteur) par e-mail fkh1000@yahoo.com. Tout commentaire, suggestion, et même critique, sera bienvenu et apprécié. Ceci est le premier de ce qui pourrait être une série d'articles, donc il y a de la marge pour améliorer cet article, ainsi que ceux encore à venir.

J'espère que vous apprécierez la lecture de mnwn : Prélude, et qu'elle vous inspirera et vous aider pour la création de modules encore meilleurs avec le toolset Aurora et Neverwinter Nights. Je tiens à remercier BioWare pour avoir développer un aussi bon produit.

Cette traduction à été effectuée par Gorkk. Vous pouvez me contacter (le traducteur) par e-mail gorkk@bbnwn.eu. Toute suggestion pour améliorer la traduction sera la bienvenue. J'espère vous faciliter la lecture et la compréhension de cette très intéressante série d'articles.
Vous pouvez (et je vous le recommande) consulter la version originale à cette adresse.


 
 
Revenir à la page d'accueil du site Ajouter la Bibliothéque de Neverwinter dans vos favoris Afficher une version imprimable de la page
  NeverList - Liste ...
Lyncya 3 - La Gue ...
Sarmates!
Le dernier des fi ...
Bonne année
Joyeux Noël 2010
The Witcher 2 en ...

Archives
Rechercher
 
 
Le Site



NwN 2 - Support des Modules Solos


Groupes
Archives
 

:: design by ghaxir :: coding by baldurien :: la bibliothèque de neverwinter :: tous droits réservés ::