Bienvenue sur JeuxOnLine - MMO, MMORPG et MOBA !
Les sites de JeuxOnLine...
 
NWN 2 - JOL

NWScript - pour niveau 3

Vous êtes bien accroché ? Les choses sérieuses ne font qu'arriver.

Pendant ce niveau 3, vous aborderez la manière d'incrémenter et décrémenter une variable. Vous apprendrez ensuite à tourner en rond grace aux boucles, et surtout à résister au mal de mer ! Viendra enfin la sélection programmée. N'oubliez pas votre fil d'Ariane, car ce labyrinthe de codes demandera beaucoup de patience pour en sortir. Heureusement, certaines commandes vous tendront la main pour trouver la sortie.

Respirez un grand coup, et plongez dans ce nouvel océan.



NWScript - Page générale


NWScript - pour niveau 1
- Bases et notions de programmation -

NWScript - pour niveau 2
- Conditions if/else et opérateurs ET / OU -

NWScript - pour niveau 3
- Boucles while/for et sélection switch/case -

NWScript - pour niveau 4
- Constantes, fonctions, et bibliothèques -

NWScript - pour niveau 5
- Variables persistantes et exécution de scripts -

Les boucles (while / for), incrémenter/décrémenter une variable

Une boucle est une instruction qui va tourner... en boucle ! Celle-ci dépend d'une condition à remplir pour permettre à la boucle de poursuivre son cycle. Tout comme l'instruction conditionnelle, il peut y avoir des comparaisons multiples. De plus, elle contient également une portion de code qui sera répétée tant que la condition est remplie.

Il est nécessaire de faire évoluer l'un des termes de la comparaison. Sans cela, une boucle se répéterait à l'infini et gèlerait le jeu au moment où elle se mettrait à tourner.

Les deux boucles évoquées ici seront "while" et "for". La boucle "while" pourrait être traduite par "tant que". La boucle "for" serait traduite par "en considérant que".

Il y a plusieurs façons de faire évoluer un élément de comparaison, qui dépendent du type de variable utilisé. La plus simple est d'utiliser un nombre entier et de l'augmenter (ou le diminuer) à chaque passage. afin qu'il ne vérifie plus la condition de la boucle.

Faire évoluer une variable de type "int" ou "float" fonctionne ainsi :

// je crée une variable avec
// une valeur de départ :

int nVariable = 0;
// nVariable est égale à 0

// J'augmente maintenant sa valeur de 1 :

nVariable = nVariable + 1;
// nVariable est donc égale à 1

// Je réduis maintenant sa valeur de 2 :

nVariable = nVariable - 2;
// nVariable est donc égale à -1

J'ai donc "incrémenté" nVariable de 1 (augmenté sa valeur de 1), puis j'ai "décrémenté" nVariable de 2 (diminué sa valeur de 2).

Il y a plusieurs méthodes pour incrémenter / décrémenter une variable. Voici différentes manières :

nVariable = nVariable + 2;
// peut aussi s'écrire :
nVariable += 2;

nVariable = nVariable - 3;
// peut aussi s'écrire :
nVariable -= 3;

Il existe une autre façon d'incrémenter / décrémenter une variable "int" de 1. Notez bien que cette méthode n'est valable QUE pour les variables de type "int" :

nVariable = nVariable + 1;
// peut aussi s'écrire :
nVariable += 1;
// mais encore :
nVariable++;

nVariable = nVariable - 1;
// peut aussi s'écrire :
nVariable -= 1;
// mais aussi :
nVariable--;

La modification d'une variable de type "string", quant à elle, demandera un peu plus d'attention. D'une part, il est possible d'ajouter des caractères avant ou après la chaîne existante. D'autre part, une variable de type "string" ne pourra jamais se "décrémenter" :

// Je crée une variable de type "string"
string sVariable = "C";

// Je rajoute un caractère après ma chaîne :
sVariable = sVariable + "D";
// la valeur de sVariable est donc "CD"

// Je rajoute deux caractères avant ma chaîne :
sVariable = "AB" + sVariable;
// la valeur de sVariable est donc "ABCD"


// Cette façon d'incrémenter une variable "string"
sVariable += "EFGH";

// Correspondra toujours à :
sVariable = sVariable + "EFGH";

Bien qu'impossible à décrémenter, une variable "string" peut être analysée grâce à des fonctions précises. Elles permettent entre autres de sélectionner une partie de la chaîne de caractères.


A présent, voyons comment fonctionne une boucle de type "while". Je vais utiliser une condition "évolutive" simple, en me servant de ma variable de type "int". Je ferai évoluer cette variable de 0 vers 10 en augmentant de 1 à chaque fois que la boucle accomplira un cycle. Si la valeur de la variable dépasse 10, je veux que ma boucle se termine. On pourrait dire que "while" raisonne de la manière suivante :

"J'agis, tant que ma comparaison est vérifiée".

Mon support sera le plaçable utilisable habituel :

void main()
{
    object oJoueur = GetLastUsedBy()

    // Je déclare ma variable en lui donnant
    // sa valeur de départ (0)

    int nVariable = 0;

    // Et "tant que" nVariable est inférieur ou égal à 10...
    while ( nVariable <= 10 )
    {
        // ...j'envoie le message "cycle" au joueur
        SendMessageToPC(oJoueur, "Cycle");

        // puis j'incrémente ma variable de 1
        nVariable++;
    }
}

Notez que, tout comme pour une instruction conditionnelle, les termes de la comparaison sont entre parenthèses, et la portion de code à répéter est entre accolades.

La fonction "for" peut nous permettre de réaliser la même chose. Mais la manière de raisonner est légèrement différente. On pourrait traduire "for" par :

"Je répète mes instructions, en considérant que nous avons ces termes à analyser et à faire évoluer".

Notre fonction "while" pourrait s'écrire de cette manière, en utilisant "for" :

void main()
{
    object oJoueur = GetLastUsedBy()

    // Je veux utiliser une variable de départ de type "int" égale à 0,
    // que cette variable doit être inférieure ou égale à 10,
    // et qu'elle s'incrémente de 1 à chaque passage.

    int nVariable;
    for ( nVariable = 0 ; nVariable <= 10 ; nVariable++ )
    {
        // j'envoie le message "cycle" au joueur
        SendMessageToPC(oJoueur, "Cycle");
    }
}

L'instruction "for" est régie par ces trois paramètres : l'instruction initiale, la condition, et l'instruction incrémentale. Ces paramètres sont séparés par des points-virgules. Dans l'ordre, "for" agit de la manière suivante :

1 - l'instruction initiale est exécutée.
2 - la condition est vérifiée. Si la condition n'est pas remplie la boucle se termine.
3 - la portion de code entre accolades est exécutée.
4 - l'instruction incrémentale est exécutée, puis on retourne à l'étape 2.

On peut donc comprendre que "for" est capable de contenir des instructions particulièrement complexes.

Interrompre un script, une boucle

Il existe des commandes afin de couper court à une portion de code. Certaines sont utilisable dans la globalité d'un script, d'autres sont spécifiques à une instruction :

Commande Utilisation
break interrompt une instruction while / for / switch
return interrompt le script
continue Passe directement au prochain cycle d'une instruction while / for

"break" & "return" :

Ces commandes représentent généralement une sortie de secours pour un programmeur. Elle lui permettent par exemple de terminer une boucle dont les conditions seraient trop floues pour s'en sortir simplement. "break" représente un aiguillage pour quitter une boucle. "return" est quant à lui la porte de sortie directe mettant fin à un script.

Par exemple, je vais faire constamment incrémenter une variable. Si elle atteint la valeur maximum que j'aurai choisie, je veux que la boucle s'arrête grace à "break".

Je conçois que le code suivant peut paraître inutile, mais ici c'est le principe qui importe :

void main()
{
    object oJoueur = GetLastUsedBy()

    int nVariable = 0;
    // Je crée ici une boucle infinie
    while ( nVariable >= 0 )
    {
        // Si la valeur de la variable atteint 20
        if ( nVariable == 20 )
        {
            // J'envoie mon message au joueur
            SendMessageToPC(oJoueur, "20 !");

            // et je quitte la boucle
            break;
        }

        // Sinon c'est que la variable n'est pas
        // encore égale à 20, et je continue
        // donc de l'incrémenter.

        else
        {
            Variable++;
        }
    }

    // J'envoie un deuxième message au joueur.
    SendMessageToPC(oJoueur, "Test terminé");
}

En remplaçant "break" par "return", j'aurais directement mis fin au script. Le message "Test terminé" n'aurait donc pas pu être envoyé.

Mais si l'utilisation de "break" est limitée" aux boucles, "return" peut être utilisé à n'importe quelle sauce. Par exemple, je vais déterminer si mon personnage a plus de 13 en intelligence. Si ce n'est pas le cas, je coupe le script. Sinon, j'envois mon message :

void main()
{
    object oJoueur = GetLastUsedBy()
    int nIntelligence = GetAbilityScore(oJoueur, ABILITY_INTELLIGENCE);

    // Si l'intelligence du personnage est
    // inférieure ou égale à 13

    if ( nIntelligence <= 13 )
    {
    // Je mets fin au script
        return;
    }
    // Sinon je lui envoie le message
    else
    {
        SendMessageToPC(oJoueur, "Vous avez plus de 13 en intelligence");
    }
}

"return" sert également à renvoyer une valeur. Nous verrons cela lorsque nous créerons nos propres fonctions.


"continue" :

Il s'agit d'une commande permettant de sauter un cycle d'une boucle, sans pour autant y mettre fin. Tout ce qui se trouvera après "continue" sera ignoré, et la boucle passera directement à un nouveau cycle. Il s'agit donc d'utiliser "continue" avec précaution, car elle pourra parfois être la cause d'une boucle infinie.

Voyons comment "continue" se comporte, et comment une boucle infinie peut apparaître. Je décide donc que :

- Ma variable augmente de 1 à chaque cycle
- Que cette variable s'arrête à 20
- Que la valeur 15 soit sautée

Voici le malheureux exemple d'une boucle infinie.

void main()
{
    object oJoueur = GetLastUsedBy();

    int nVariable = 0;
    while ( nVariable <= 20 )
    {
        // Si ma variable est égale à 15, je saute un cycle.
        if ( nVariable == 15 )
        {
            continue;
        }

        // Sinon j'annonce la valeur de la variable
        else
        {
            // La fonction "IntToString(...)" permet de
            // traduire une valeur "int" en valeur "string".
            // Cette fonction est de type "string".

            SendMessageToPC(oJoueur, IntToString(nVariable));

            // Puis j'incrémente la variable.
            nVariable++;
        }
    }
}

En effet, quand ma variable aura atteint 15, "continue" agira et passera directement à un nouveau cycle. La variable n'aura donc pas pu s'incrémenter. Elle aura toujours la valeur 15 au prochain cycle, et "continue" agira à nouveau, à l'infini.

Il suffit donc de prendre une précaution supplémentaire, en incrémentant la variable avant "continue".

void main()
{
    object oJoueur = GetLastUsedBy();

    int nVariable = 0;
    while ( nVariable <= 20 )
    {
        // Si ma variable est égale à 15, je l'incrémente
        // et je saute le cycle.

        if ( nVariable == 15 )
        {
            nVariable++;
            continue;
        }

        // Sinon je poursuis mon cycle normal
        else
        {
            SendMessageToPC(oJoueur, IntToString(nVariable));
            nVariable++;
        }
    }
}

La fonction suivante m'a permis de récupérer la valeur "int" d'une variable, et de la convertir en valeur de type "string".

string IntToString(int nInteger)

- Etant une fonction de type "string", elle renverra une valeur de type "string".
- nInteger est la valeur de type "int" devant être traduite en valeur de type "string".


Une fois la boucle corrigée, le joueur verra donc les nombres apparaître un à un, de 0 à 20, à l'exception du nombre 15.

Notez que la variable ne s'incrémentera pas deux fois d'affilée pendant un même cycle. Tant que la valeur de la variable n'est pas égale à 15, le code contenu dans la condition "if" n'est pas exécuté. Lorsque cette valeur est égale à 15, "continue" passe directement au cycle suivant, et ce qui se trouve hors de la condition "if" n'est pas exécuté.

La sélection (switch / case)

Cette instruction nous permet d'analyser une situation et d'offrir plusieurs solutions selon le cas présenté. Il n'est pas obligatoire de présenter tous les cas possible. Il existe pour cela une instruction nous permettant de définir un cas "par défaut" pour les solutions n'étant pas analysées en particulier.

Dans les portions de code de chaque cas, on peut utiliser les commandes "break" et "return". "break" sera utilisé pour terminer la partie de code exécutée lorsqu'un cas est rencontré, et pour éviter d'exécuter la partie de code du cas suivant. "return" aura toujours la fonction de terminer l'exécution du script si cette commande est exécutée.

Selon la manière d'étudier les différentes solutions de "switch/case", il n'est pas forcément nécessaire de séparer chaque cas en les terminant avec "break" ou "return". Si deux cas se suivent, et qu'ils ont le même code à exécuter, on ne les séparera pas par "break". On laissera le premier cas vide, et on le fera suivre directement du second cas.

Par exemple, je vais analyser la caractéristique sagesse d'une créature, et exécuter une commande selon les différentes valeurs. Je peux estimer que rien de particulier ne se passera par défaut, et qu'un message apparaîtra si la caractéristique de sagesse est de 15, si elle est de 16, ou si elle est de 17. Je veux également rassembler deux cas et faire apparaître un même message si elle est de 18 ou de 19 :

void main()
{
    object oJoueur = GetLastUsedBy()
    int nSagesse = GetAbilityScore(oJoueur, ABILITY_WISDOM);

    // J'analyse la variable nSagesse
    switch ( nSagesse )
    {
        // Dans le cas où elle est égale à 15
        case 15 :
        {
            // J'envoie ce message
            SendMessageToPlayer(oJoueur, "Votre sagesse est de 15");
            break;
        }

        // Dans le cas où elle est égale à 16
        case 16 :
        {
            SendMessageToPlayer(oJoueur, "Votre sagesse est de 16");
            break;
        }

        // Dans le cas où elle est égale à 17
        case 17 :
        {
            SendMessageToPlayer(oJoueur, "Votre sagesse est de 17");
            break;
        }

        // Dans le cas où elle est égale à 18,
        // et dans le cas où elle est égale à 19

        case 18 :
        case 19 :
        {
            // J'envoie ce message
            SendMessageToPlayer(oJoueur, "Votre sagesse est de 18 ou 19");
            break;
        }

        // Sinon, par défaut, je ne fais rien
        // à part quitter l'instruction "switch"

        default :
        {
            break;
        }
    }
}

Vous avez gagné un niveau !

A ce stade il est maintenant possible de créer des scripts relativement complexes. Il faudra toutefois garder en mémoire que les données ne seront traitées que pour un même script. Les variables ne navigueront pas d'un script à un autre, et les lignes de codes ne s'exécuteront que dans l'enceinte d'un seul script. En contrepartie, vous pourrez utiliser les mêmes noms de variables dans plusieurs scripts, ils ne se disputeront pas pour si peu.



NWScript - Page générale


NWScript - pour niveau 1
- Bases et notions de programmation -

NWScript - pour niveau 2
- Conditions if/else et opérateurs ET / OU -

NWScript - pour niveau 3
- Boucles while/for et sélection switch/case -

NWScript - pour niveau 4
- Constantes, fonctions, et bibliothèques -

NWScript - pour niveau 5
- Variables persistantes et exécution de scripts -

Rédigé par Deyonara
article mis en ligne le 17 mai 2007 à 15:20,
dernière mise à jour : 17 octobre 2007 à 19:10.
Haut de page