Worldedit
  Worldedit
Le site sur l'éditeur de warcraft 3 !
 
  FAQFAQ   RechercherRechercher   Liste des MembresListe des Membres    Groupes d'utilisateursGroupes d'utilisateurs   medals.php?sid=656bef2951e03391c5c269318f946518Médailles   S'enregistrerS'enregistrer 
 ProfilProfil   Se connecter pour vérifier ses messages privésSe connecter pour vérifier ses messages privés   ConnexionConnexion 
  FAQFAQ World Editor   UploadUploader une map ou une image    UploadAjouter sa map à l'annuaire   UploadConsulter l'annuaire

Introduction au vJass
Aller à la page 1, 2, 3, 4, 5, 6  Suivante
 
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Tutoriels
Voir le sujet précédent :: Voir le sujet suivant  
Auteur Message
 Sapeur-Goblin
Floodeur prématuré


Inscrit le: 14 Oct 2009
Messages: 719
Sujets: 40
Spécialité en worldedit: Les bugs
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 19/05/12 10:15    Sujet du message: Introduction au vJass Citer

J'ai remarqué qu'il n'y avait aucun tutoriel pour le vJass sur ce forum, j'ai donc décidé d'en faire un, d'une part parce qu'il y a plusieurs demandes, d'autre part parce que c'est toujours plus agréable que d'aller sur un forum anglais. Ce tutoriel expliquera les bases du vJass, des globals jusqu'aux structures.

Il n'est pas indispensable de tout connaître du Jass, on peut directement passer du Gui au vJass, mais il est vivement recommandé d'avoir quelques notions.

I/ Le vJass, c'est quoi?

a) Explications

Le vJass est tout simplement une extension du Jass, permettant de le manipuler beaucoup plus facilement. Il faut cependant garder à l'esprit que du vJass restera du Jass une fois compilé. Il a donc les même limitations et les mêmes capacités, bien qu'il soit plus facile d'utilisation, offrant entre autre une interface orientée objet. Le moyen le plus simple de s'en servir est d'utiliser le Jass NewGen Pack que vous pourrez télécharger ici. Ce programme peut être considéré comme un virus par votre ordinateur, mais ça n'en est pas un. Si vous rencontrez des problèmes, mettez le sur la liste d'exception de votre anti-virus.

En plus de donner la possibilité de coder en vJass, cet outil offre aussi de nouvelles fonctionnalités assez intéressantes :
- Création de cartes plus grandes qu'avec l'éditeur officiel;
- Édition des textures sol;
- Possibilité de choisir soit même l'identifiant d'un objet;
- Activation du mode sans limite permettant de placer autant de destructibles sur la carte que l'on veut entre autre.

b) Mise à jour du JassHelper

Avant d'utiliser du vJass, il est préférable de se servir de la dernière version du JassHelper. Une fois le Jass NewGen Pack téléchargé, extrayez-le puis téléchargez ce fichier. Extrayez-le puis ouvrez-le, et ouvrez le sous-dossier executable. Copiez les trois fichiers et collez-les dans le dossier jasshelper du dossier jassnewgenpack que vous avez extrait tout à l'heure. Confirmez pour remplacer les fichiers déjà existants.
Le JassHelper étant souvent amélioré, je poste ici le lien pour le tenir à jour.

Voilà, votre JassHelper est mis à jour. Notez que si vous utilisez du vJass, il faut enregistrer la carte avant de pouvoir la tester.

II/ La déclaration de variables globales

Au lieu de passer par la petite boîte de dialogue habituelle pour créer des variables globales (qui n'est d'ailleurs pas pratique du tout), le vJass permet de les déclarer à l'intérieur même du code. Au début vous trouverez sûrement cette possibilité assez inutile, mais cela va devenir intéressant lorsque nous utiliseront l'encapsulation (qui fera l'objet de notre quatrième partie).

Mais pour l'instant nous n'allons que nous attarder sur la déclaration en elle même de ces variables. Pour ce faire, il suffit de préciser le type de variable, suivi de son nom, et d'une éventuelle valeur par défaut, le tout dans un bloc globals :
Jass:
globals
    unit Heros = null
endglobals


Vous pouvez bien-sûr déclarer plusieurs variables dans le même bloc de cette manière :
Jass:
globals
    unit Heros = null
    integer level = 1
endglobals


Pour des variables à déploiement, c'est le même principe :
Jass:
globals
    unit array Heros
endglobals


Il est aussi possible de déclarer des variables ayant un déploiement supérieur à 8191 ou en deux dimension :
Jass:
globals
    unit array Heros1[15000]
    unit array Heros2[50][50]
endglobals


Soyez cependant vigilant avec ces types de variable : si le déploiement dépasse 8191, plusieurs variables seront créées lors de la compilation, et le code sera moins performant, utilisant une fonction pour se référer à la bonne variable.

Ces variables seront donc accessibles dans toutes les fonctions de la carte, mais en plus de cela, nous n'avons plus besoin de préciser le mot-clef udg_.
Ainsi cette fonction est tout à fait correcte, pourtant la variable Heros n'est pas précédée de udg_ :
Jass:
function KillHeros takes nothing returns nothing
    call KillUnit(Heros)
endfunction


Notez aussi que les variables globales peuvent être constantes, et ne seront donc pas modifiables au cours du jeu. Cela peut être utile pour paramétrer plus facilement un sort ou un système, sans avoir à chercher toutes les valeurs dans le code :
Jass:
globals
    constant real TIMEOUT = 0.03
endglobals


III/ Les bibliothèques et les scopes

Les bibliothèques (library en anglais) et les scopes permettent chacune de classer le code, et de le rendre plus réutilisable.

a) Les bibliothèques

Il n'est pas toujours pratique d'utiliser le script personnalisé de la carte pour déclarer de nouvelle fonctions : lorsque l'on en a plus d'une vingtaine, et que certaines en requièrent d'autres qui doivent être placées plus haut, cela devient très vite difficile de tout classer correctement.

Les librairies permettent justement de classer notre code, et de le placer dans le bon ordre dans le script personnalisé lors de la compilation.
Voici la syntaxe à suivre pour déclarer un librairie :
Jass:
library MaLibrairie
endlibrary


Il suffit ensuite de placer nos fonctions à l'intérieur pour être certain qu'elles soient ensuite utilisables par toutes les autres fonctions :
Jass:
library KillHeros
function KillHeros takes nothing returns nothing
    call KillUnit(Heros)
endfunction
endlibrary


Il est aussi possible de déclarer des globals à l'intérieur même d'une librairie :
Jass:
library KillHeros

globals
    unit Heros = CreateUnit(Player(0), 'Hpal', 0, 0, 0)
endglobals

function KillHeros takes nothing returns nothing
    call KillUnit(Heros)
endfunction

endlibrary


Si une librairie en nécessite une autre, et donc que cette dernière doit être placée plus haut dans le script personnalisé de la carte, il faut utiliser les attributs needs, uses, ou encore requires :
Jass:
library MaLibrairie uses Heros
endlibrary

library Heros
endlibrary

Attention cependant aux boucles : si la librairie Heros nécessitait aussi la librairie MaLibrairie, cela déclencherait une erreur.

Les librairies permettent aussi de déclarer des initializers, qui sont des fonctions appelées à l'initialisation de la carte :
Jass:
library Heros initializer onInit

globals
    unit Heros
endglobals

function onInit takes nothing returns nothing
    set Heros = CreateUnit(Player(0), 'Hpal', 0, 0, 0)
endfunction

endlibrary


b) Les scopes

Les scopes reposent sur le même principe que les librairies : elles regroupent le code. Elles ne le placent cependant pas au début du script personnalisé de la carte, il ne sera donc pas utilisable par toutes les fonctions, mais pourra toutes les utiliser (du moins celles faisant partie de librairies).
Jass:
scope MySpell initializer onInit

function Action takes nothing returns nothing
    call KillUnit(GetSpellTargetUnit())
endfunction

function onInit takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddAction(t, function Action)
endfunction

endscope


IV/ L'encapsulation

Une des choses les plus intéressantes du vJass reste l'encapsulation. Cela permet de rendre une donnée, comme une variable ou une fonction, privée, la rendant inaccessible pour d'autres blocs. On pourra ainsi déclarer plusieurs fois la fonction onInit, en faisant attention de la privatiser, sans risque d'erreur. De même que si vous récupérer du code créé par une autre personne, vous ne risquerez pas de modifier des données qui ne devraient pas l'être.

Pour encapsuler une donnée, il est nécessaire qu'elle appartienne à un bloc, que ce soit une librairie, une scope, ou une structure (que nous étudierons dans notre cinquième partie) : seules les fonctions à l'intérieur de ce bloc pourront y accéder. Pour ce faire, il suffit qu'elle soit précédée de l'attribut private.

Une petite mise en pratique :
Jass:
library Heros

globals
    private unit Heros = CreateUnit(Player(0), 'Hpal', 0, 0, 0)
endglobals

endlibrary

library KillHeros

function KillHeros takes nothing returns nothing
    call KillUnit(Heros)
endfunction

endlibrary

Ce code déclenchera une erreur : la variable Heros étant privée, il est impossible que la fonction KillHeros puisse y accéder n'appartenant pas au même bloc.

Jass:
scope MySpell1 initializer onInit

private function onInit takes nothing returns nothing
    //Initialisation du sort
endfunction

endscope

scope MySpell2 initializer onInit

private function onInit takes nothing returns nothing
    //Inititalisation du sort
endfunction

endscope

De même que ce code ne sera pas source d'erreur : les deux fonction onInit étant privées, il est possible de les déclarer deux fois. Pour que cela soit possible, le compilateur vJass rajoutera tout simplement les préfixes MySpell1_ et MySpell2_ pour que chacunes des fonctions aient des noms différents.

Notez qu'il existe aussi l'attribut public, qui lui, rend la donnée accessible dans toute la carte. Il n'est cependant pas nécessaire de l'utiliser, toutes les données étant publiques par défaut.

V/ Les structures

a) Notion de structure

Une structure est un regroupement d'éléments caractéristiques à un objet. Tout objet peut donc être considéré comme une structure, qu'il soit concret (une maison), ou abstrait (un point). Une fois déclaré, cet objet peut être utilisé comme une variable : les structures permettent de créer nos propres types de variables.
Dans l'exemple du point, une structure le définissant contiendrait trois données, trois réels, chacun caractérisant une coordonnée.

En vJass, on peut donc s'en servir pour toute sorte de choses, mais elles se limitent le plus souvent à une sauvegarde de données. On les déclare de cette manière :
Jass:
struct MaStruct
endstruct


b) Les attributs d'une structure

Pour mieux expliquer comment fonctionne une structure, nous utiliserons l'exemple d'un héros. Nous ne considèrerons que cinq de ses attributs : l'unité en elle-même, le niveau du héros, sa force, son agilité, et pour finir son intelligence.

Les attributs de la structure se déclarent un peu de la même manière que les globals :
Jass:
struct Heros
    unit whichUnit
    integer level
    integer strenght
    integer agility
    integer intelligence
endstruct


Il est aussi possible de leur donner une valeur par défaut.
Voilà notre structure déclarée, nous allons pouvoir nous en servir. Pour créer une instance de structure, on utilise la fonction create précédée d'un point et du type de structure :
Jass:
struct Heros
    unit whichUnit
    integer level
    integer strenght
    integer agility
    integer intelligence
endstruct

function CreateHeros takes nothing returns nothing
    local Heros h = Heros.create()
endfunction


On crée donc ici une instance de la structure et on l'assigne à une variable : comme je vous l'ai dit tout à l'heure, une structure est un type de variable. Maintenant que cela est fait, on va pouvoir modifier les attributs de notre héros : on va ainsi créer l'unité, lui ajouter un niveau, de la force, de l'agilité et de l'intelligence. Pour se référer à un attribut d'une instance de structure, on utilise un point suivi du nom de l'attribut :
Jass:
struct Heros
    unit whichUnit
    integer level
    integer strenght
    integer agility
    integer intelligence
endstruct

function CreateHeros takes nothing returns nothing
    local Heros h = Heros.create()
    set h.whichUnit = CreateUnit(Player(0), 'H000', 0, 0, 0)
    set h.level = 1
    set h.strenght = 16
    set h.agility = 14
    set h.intelligence = 20
endfunction


Les membres whichUnit, level, strenght, agility, et intelligence ne seront donc que modifiés pour l'instance de structure en question, h.

c) Les fonctions propres à une structure

Dans le cas de notre héros, certaines fonctions comme lui faire gagner un niveau seraient utiles : ce sont des fonctions propres à la structure, que l'on appelle des methods. Une méthode fonctionne de la même manière qu'une fonction : elle peut prendre des arguments, et peut retourner une valeur. De même que pour l'appeler, on utilise aussi call mais étant un attribut de la structure, on s'y réfère de la même manière que pour les données, à savoir avec un point suivi du nom de la méthode.

Nous allons donc créer une méthode augmentant le niveau du héros :
Jass:
struct Heros
    unit whichUnit
    integer level
    integer strenght
    integer agility
    integer intelligence

    method LevelUp takes nothing returns nothing
        set this.level = this.level + 1
        set this.strenght = this.strenght + 4
        set this.agility = this.agility + 3
        set this.intelligence = this.intelligence + 5
        call DestroyEffect(AddSpecialEffectTarget(this.whichUnit, "Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.mdl", "origin"))
    endmethod
endstruct

function CreateHeros takes nothing returns nothing
    local Heros h = Heros.create()
    set h.whichUnit = CreateUnit(Player(0), 'H000', 0, 0, 0)
    set h.level = 1
    set h.strenght = 16
    set h.agility = 14
    set h.intelligence = 20
    call h.LevelUp()
endfunction


Cela demande quelques explications tout de même. La méthode LevelUp n'est appelée que pour l'instance de structure en question : les autres Heros ne verront pas leur niveau augmenter.
L'attribut this à l'intérieur de la méthode permet donc de se référer à l'instance de structure pour laquelle elle a été appelée.

d) Les membres statiques

Comme nous l'avons vu, les membres de notre structure n'appartiennent qu'à une instance de celle-ci. Or il peut être utile d'avoir des données qui sont communes à toutes les instances de cette structure, comme par exemple le nombre de héros créés. Au lieu d'utiliser un bloc globals, on peut se servir des membres statiques. On utilise l'attribut static pour les définir :
Jass:
struct Heros
    static integer count = 0
    unit whichUnit
    integer level
    integer strenght
    integer agility
    integer intelligence
endstruct

function CreateHeros takes nothing returns nothing
    local Heros h = Heros.create()
    set h.whichUnit = CreateUnit(Player(0), 'H000', 0, 0, 0)
    set h.level = 1
    set h.strenght = 16
    set h.agility = 14
    set h.intelligence = 20
    set h.count = h.count + 1
endfunction


Vous remarquerez que l'on utilise h.count mais il est aussi possible de se servir de Heros.count pour s'y référer, count étant un attribut propre à la structure elle-même et non à l'instance h.

Les méthodes peuvent aussi être statiques ;
Jass:
struct Heros
    static integer count = 0
    unit whichUnit
    integer level
    integer strenght
    integer agility
    integer intelligence

    static method CountUp takes nothing returns nothing
        set Heros.count = Heros.count + 1
    endmethod
endstruct

function CreateHeros takes nothing returns nothing
    local Heros h = Heros.create()
    set h.whichUnit = CreateUnit(Player(0), 'H000', 0, 0, 0)
    set h.level = 1
    set h.strenght = 16
    set h.agility = 14
    set h.intelligence = 20
    call h.CountUp()
endfunction


De même qu'à la place de h.CountUp(), Heros.CountUp() aurait pu fonctionner.

Faîtes cependant attention à une chose : dans la méthode CountUp, nous avons utilisé Heros.count. Il aurait été possible de n'écrire que count, les membres statiques étant considéré comme des variables globales à l'intérieur de la structure. De même pour les méthodes, à l'intérieur de la structure, il est possible de s'y référer en n'écrivant que le nom. Mais cette méthode est à éviter : le code est plus clair en précisant le nom de la structure.
Il faut aussi savoir qu'il existe un mot-clef, thistype (ce type en anglais), renvoyant au type de structure dans laquelle on travaille (il n'est utilisable qu'à l'intérieur d'une structure). Il aurait donc aussi été possible d'écrire thistype.count, thistype étant le type Heros à l'intérieur de cette structure. C'est une convention : plutôt que d'écrire le type de structure, il vaut mieux utiliser thistype.

e) Les constructeurs

Vous aurez peut-être remarqué que nous utilisons la méthode create que nous n'avons pourtant pas déclarée. Cette méthode ainsi que la méthode destroy sont automatiquement créées lorsque vous définissez une structure. Mais il est possible de les modifier en les déclarant nous même. Dans l'exemple de notre héros, il serait préférable de regrouper la fonction CreateHeros avec notre structure, étant elle aussi un membre qui lui est propre :
Jass:
struct Heros
    unit whichUnit
    integer level
    integer strenght
    integer agility
    integer intelligence

    static method create takes player p, integer id, real x, real y, real a returns thistype
        local thistype this = thistype.allocate()
        set this.whichUnit = CreateUnit(p, id, x, y, a)
        set this.level = 1
        set this.strenght = 16
        set this.agility = 14
        set this.intelligence = 20
        return this
    endmethod
endstruct


Vous remarquerez d'abord que cette méthode est static. Toutes les méthodes créant une instance de structure doivent être statiques puisque ce ne sont pas des fonctions propres à une instance, mais bien à l'ensemble de la structure. De même que cette méthode retourne thistype, ce qui permet de le stocker dans une variable. Notez aussi que notre variable s'appelle this. Dans les méthodes statiques, cette variable étant libre (elle n'est pas utilisée pour se référer à l'instance de structure comme dans les méthodes non statiques), c'est une convention de l'utiliser.
Mais le plus important réside dans le thistype.allocate(). La méthode allocate est créée directement lorsque vous déclarez une structure. Elle permet de renvoyer une nouvelle instance de structure. Lorsque vous ne modifiez pas la méthode create, elle ne ressemble qu'à cela :
Jass:
static method create takes nothing returns thistype
    return thistype.allocate()
endmethod


De même qu'il serait utile de modifier la méthode destroy pour exécuter du code lorsqu'elle est appelée. A l'inverse de la méthode create, la méthode destroy n'est pas statique : elle est propre à une instance de structure :
Jass:
method destroy takes nothing returns nothing
    call this.deallocate()
endmethod

Vous remarquerez la méthode deallocate, qui à l'inverse de la méthode allocate permet de libérer une instance de structure.
Nous allons donc modifier cette méthode de cette manière :
Jass:
method destroy takes nothing returns nothing
    call KillUnit(this.whichUnit)
    set this.whichUnit = null
    call this.deallocate()
endmethod


Les structures étant limitées à 8190 instances simultanées, la méthode destroy est importante : elle libère une instance de structure.

f) Quelques précisions

- Une structure ainsi que ses membres (variables et méthodes) peuvent être privés.

- Il faut savoir qu'une instance de structure n'est en fait rien d'autre qu'un entier. Lors de la compilation en Jass, les attributs de la structure deviendront des variables à déploiement. La méthode allocate renvoie donc un entier pour lequel le déploiement des variables est libre, d'où la limite de 8190 instances.

- Les membres de la structure devenant des variables à déploiement, on comprend bien que nous rencontrerons des problème à déclarer un membre à déploiement dans une structure. Le vJass permet cependant de le faire, mais il faut préciser le nombre de déploiement :
Jass:
struct MaStruct
    unit array whichUnit[5]
endstruct


Si vous pouvez ne pas le faire, évitez de déclarer un membre à déploiement : ici le nombre d'instances simultanées possibles de MaStruct seront divisées par 5, soit 1638. Pour les membres statiques, vous ne rencontrerez aucun problème étant des variables normales.

- Si jamais vous avez besoin de plus de 8190 instances de structures, c'est possible de le faire de cette manière :
Jass:
struct MaStruct[15000]
endstruct


Encore une fois, c'est à éviter, le code devenant moins performant : plusieurs variables à déploiement sont créées, et pour se référer à une de ces variables, une fonction doit être appelée pour savoir laquelle est la bonne.

- Il existe la méthode onInit (qui doit être statique) se déclenchant à l'initialisation de la carte, sans avoir besoin de préciser un initializer comme pour les librairies ou les scopes. De même que la méthode onDestroy (qui ne doit pas être statique se référant à une instance) se déclenche à la destruction d'une instance. Elle est cependant à éviter : c'est un appel de fonction inutile, la méthode destroy pouvant servir à éxecuter du code.

- Les méthode allocate et deallocate sont créées automatiquement pour faciliter l'utilisation des structures. Il existe cependant un moyen de tout gérer soit même :
Jass:
struct MaStruct extends array
endstruct


Dans cette structure, aucune méthode ne sera créée par défaut : c'est à vous de tout définir. Cela est cependant à éviter. Bien qu'il y ait une légère optimisation du code (on n'appelle plus la méthode allocate pour créer une instance), cela complique les choses, pouvant être source d'erreurs.

g) Les methods operators

Pour l'instant, pour augmenter le niveau de notre héros, on utilise ça :
Jass:
method LevelUp takes nothing returns nothing
        set this.level = this.level + 1
        set this.strenght = this.strenght + 4
        set this.agility = this.agility + 3
        set this.intelligence = this.intelligence + 5
        call DestroyEffect(AddSpecialEffectTarget(this.whichUnit, "Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.mdl", "origin"))
endmethod


Mais si on veux augmenter plus d'une fois le niveau du héros, ça devient embêtant.
On aimerais bien pouvoir faire quelque chose dans le genre :
Jass:
set monHeros.level = monHeros.level + 2


Mais si on laisse à l'utilisateur la possibilité de faire ça (en mettant le membre level en public), lorsqu'il augmenterait le niveau de son héros, ces actions ne se déclencheraient plus :
Jass:
set this.strenght = this.strenght + 4
        set this.agility = this.agility + 3
        set this.intelligence = this.intelligence + 5
        call DestroyEffect(AddSpecialEffectTarget(this.whichUnit, "Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.mdl", "origin"))


C'est là que les méthods operators interviennent. Elles permettent une écriture plus intuitive (set monHeros.level = x), tout en exécutant des actions quand on les appelle. Il existe plusieurs types de methods operators :
    • Il est parfois utile de simuler l'existence d'un membre dans la structure. Par exemple, pour notre structure héros, on pourrait imaginer un membre speed qui renvoie la vitesse de l'unité. Cela permet à l'utilisateur d'obtenir le speed avec
    Jass:
    monHeros.speed
    plutôt que
    Jass:
    GetUnitSpeed(monHeros.whichUnit)
    . Voici comment déclarer ce type de méthods operators :
    Jass:
    method operator nomDuMembre takes nothing returns valeurDeRetour
        //code
        //return valeur
    endmethod
    Il est important que la méthode ne prenne aucun argument et renvoie quelque chose (ça n'aurait pas de sens sinon). Dans le cas de notre héros, ça donne :
    Jass:
    method operator speed takes nothing returns real
        return GetUnitSpeed(this.whichUnit)
    endmethod

    • Si on peut simuler des membres, il est alors nécessaire de pouvoir simuler une attribution de valeur à ces membres inexistants (c'est le cas pour set monHeros.level = 2 par exemple). On les déclare de cette manière :
    Jass:
    method operator level= takes integer l returns nothing
            set this.le = l
            set this.strenght = this.strenght + 4
            set this.agility = this.agility + 3
            set this.intelligence = this.intelligence + 5
            call DestroyEffect(AddSpecialEffectTarget(this.whichUnit, "Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.mdl", "origin"))
    endmethod

    Elle ne prend qu'un argument (on va pas s'amuser à faire des set struct.membre = x, y, z) et ne retourne rien. Notez que j'ai changé le membre level stockant le niveau du héros en le. En effet, level doit être un membre private pour éviter les problèmes décrits plus haut. Mais on veut pouvoir y accéder simplement avec des methods operators. Il fallait donc changer son nom pour ne pas avoir de redéclaration de membre (level le membre et level la méthode operator).
    • Il est aussi possible de faire comme si une instance d'une structure était un tableau, c'est à dire :
    Jass:
    local MaStruct instance = MaStruct.create()
        set instance[5] = 2
        call BJDebugMsg(I2S(instance[5]))
    Pour déclarer la lecture d'un tel tableau :
    Jass:
    method operator [] takes unTypeQuelconque i returns unTypeQuelconque
        //code
        return uneValeur
    endmethod
    Ici, i correspond à l'index utilisé. Et pour un attribuer une valeur au tableau :
    Jass:
    method operator []= takes unTypeQuelconque i, unTypeQuelconque j returns nothing
        //code
    endmethod
    L'index utilisé correspond à i, et la valeur assignée correspond à j.
    • Dernière catégorie d'opérateurs : les comparaisons '<' et '>'. Voici la syntaxe générale :
    Jass:
    method operator < takes unTypeQuelconque a returns boolean
        return true
    endmethod
    Cela permet de faire des trucs du style :
    Jass:
    local Heros h1 = Heros.create()
    local Heros h2 = Heros.create()
    if h1 > h2 then //Qui est le plus fort?
        //code
    endif



Voilà pour les opérateurs, rendant le code plus lisible par rapport à de simples méthodes. Notez que les opérateurs [] et []= peuvent aussi être statiques.

VI/ Les textmacros

a) Explications théoriques

Les textmacros sont des instructions qui seront éxecutées lors de la compilation en Jass. Ils permettent d'une manière générale de rajouter des segments de code, et donc d'éviter des répétitions.

Il faut avant tout déclarer le textmacro ainsi que le code qu'il contient pour l'utiliser :
Jass:
//! textmacro BJDebugMsg
    call BJDebugMsg("test")
//! endtextmacro


Une fois déclaré, on peut l'utiliser dans toute autre fonction :
Jass:
function Test takes nothing returns nothing
    //! runtextmacro BJDebugMsg()
endfunction


Une fois compilée, la fonction Test ressemblera à cela :
Jass:
function Test takes nothing returns nothing
    call BJDebugMsg("test")
endfunction


Vous remarquerez qu'il faut ajouter des parenthèses à BJDebugMsg dans //! run textmacro BJDebugMsg(). Cela vient du fait que les textmacros peuvent prendre des arguments, comme une fonction. Ces arguments sont cependant un peu spéciaux : il ne s'agit pas de réels, ou d'entiers, mais de bouts de code :
Jass:
//! textmacro BJDebugMsg takes MESSAGE
    call BJDebugMsg("$MESSAGE$")
//! endtextmacro


Notez que pour se référer à l'argument MESSAGE, il est nécessaire de le placer entre des $, sinon ce textmacro n'affichera que MESSAGE et non l'argument qu'on lui transmet.
On peut maintenant l'utiliser, sachant que lorsque l'on appel le textmacro, les arguments doivent être placés entre des guillemets. :
Jass:
function Test takes nothing returns nothing
    //! runtextmacro BJDebugMsg("test")
endfunction


Un autre exemple de textmacro permettant de réaliser des opérations sur deux nombres :
Jass:
//! textmacro CALCUL takes VARIABLE, N1, N2, OPERATION
    set $VARIABLE$ = $N1$ $OPERATION$ $N2$
//! endtextmacro


On va l'utiliser pour faire un calcul et mettre le résultat dans une variable :
Jass:
function Test takes nothing returns nothing
    local integer i
    //! runtextmacro CALCUL("i", "4", "5", "*")
    call BJDebugMsg(I2S(i))
endfunction


On obtiendra 20 à la sortie.

b) Une petite mise en pratique

Dans une carte avec beaucoup de héros, il pourrait être très utile de créer un textmacro initialisant leurs sorts pour nous.
De manière habituelle, on utiliserait cette méthode :
Jass:
scope MonSort initializer onInit

globals
    private integer SpellId = 'A000'
endglobals

private function Action takes nothing returns nothing
    // Le sort
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == SpellId
endfunction

private function onInit takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t, Filter(function Conditions))
    call TriggerAddAction(t, function Action)
endfunction

endscope


On va donc créer un textmacro qui va faire tout cela à notre place.
Il aura besoin du nom de l'initialisateur, de la condition, de l'action et de l'identifiant du sort :
Jass:
//! textmacro InitSpell takes INITIALIZER, CONDITION, ACTION, SPELLID

    private function $CONDITION$ takes nothing returns boolean
        return GetSpellAbilityId() == $SPELLID$
    endfunction

    private function $INITIALIZER$ takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Filter(function $CONDITION$))
        call TriggerAddAction(t, function $ACTION$)
    endfunction

//! endtextmacro


Cela nous permet maintenant d'initialiser notre sort beaucoup plus facilement :
Jass:
scope MonSort initializer onInit

private function Action takes nothing returns nothing
    // Le sort
endfunction

//! runtextmacro InitSpell("onInit", "Conditions", "Action", "'A000'")

endscope


Notez que l'argument CONDITION n'est pas indispensable, mais il permet tout de même d'éviter la déclaration de deux fonctions ayant le même nom (si jamais on voulait réserver la fonction Conditions pour autre chose).

VII/ Considérer les fonctions en tant qu'objets

a) Les fonctions execute et evaluate

Le vJass offre la possibilité de considérer les fonctions comme des objets à l'aide des fonctions execute et evaluate. Cela permet entre autre de faire des appels de fonctions à partir d'un code au-dessus de sa déclaration :
Jass:
function A takes nothing returns nothing
    call B.evaluate(5)
endfunction

function B takes real x returns nothing
    call BJDebugMsg(R2S(x))
endfunction


Un simple appel de fonction aurait ici déclenché une erreur.

La fonction evaluate : Elle permet de faire un appel de fonction à partir d'un code au-dessus de sa déclaration. Elle n'ouvre cependant pas un nouveau thread, ce qui empêche l'utilisation de Wait. Elle est plus lente qu'un appel normal.

La fonction execute : Même rôle que la fonction evaluate, mais ouvre un nouveau thread. Elle est plus rapide que ExecuteFunc().

L'attribut .name d'une telle fonction renvoie le nom de la fonction une fois compilée.

b) Les fonctions interfaces

Il est possible de déclarer des fonctions interfaces. Celles-ci peuvent alors être sauvegardées dans des variables, envoyées en tant qu'arguments à une fonction et être exécutées à l'aide des fonctions execute et evaluate.
Jass:
function interface f takes nothing returns nothing


Elle peut aussi prendre des arguments et renvoyer une valeur.
Cela permet ainsi de créer des codes exécutant des fonctions pouvant être choisies par l'utilisateur :
Jass:
function interface Action takes nothing returns nothing

function Action1 takes nothing returns nothing
    // Action 1
endfunction

function Action2 takes nothing returns nothing
    // Action 2
endfunction

function executeAction takes Action func returns nothing
    call func.evaluate()
endfunction


Bien-sûr, cet exemple n'a pas vraiment de sens, mais le principe est là.
Notez que les fonctions que l'on envoie en argument à la fonction executeAction sont calquées sur la fonction interface Action, sans quoi ce ne serait pas possible.

VIII/ Pour aller plus loin

Ce qui a été dit dans ce tutoriel suffira à coder quoi que ce soit en vJass. Il existe cependant d'autres fonctionnalités et subtilités comme l'héritage que vous pourrez découvrir en lisant la documentation du vJass (en anglais).

Je rajoute aussi deux liens qui permettront de pratiquer un peu (en anglais) :
- Création d'un sort;
- Création d'effets dans le temps.

****************************************

Voilà, c'est fini pour ce tutoriel. J'espère que ça vous a été utile.
_________________


Dernière édition par Sapeur-Goblin le 16/02/13 15:44; édité 8 fois
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Sapeur-Goblin
Floodeur prématuré


Inscrit le: 14 Oct 2009
Messages: 719
Sujets: 40
Spécialité en worldedit: Les bugs
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 19/05/12 12:48    Sujet du message: Citer

@Tirlititi : Non, je n'essaie pas de te surcharger de boulot Wink.

@Troll-Brain : J'attends tes critiques.

La notion de structure est assez compliquée à expliquer. C'est pourquoi j'aimerais qu'on me dise si à un endroit ce n'est pas très clair.
J'avais pensé à mettre une sixième partie avec une mise en pratique de tout ce qui a été dit pour mieux expliquer. Est-ce nécessaire?
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Tirlititi



Inscrit le: 21 Fév 2010
Messages: 1785
Sujets: 22
Spécialité en worldedit: La modestie
Médailles: 1 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1)

MessagePosté le: 19/05/12 13:10    Sujet du message: Citer

C'est pas grave, je vais me contenter de faire des critiques et laisser TB décider de s'il faut l'approuver ou pas Idea .

Quelques erreurs déjà (très peu nombreuses, faut bien l'avouer) :

Jass:
call h.LevelUp

->
Jass:
call h.LevelUp()

(la même erreur est refaite à chaque duplicata.)

Citation:
Si vous pouvez ne pas le faire, évitez de déclarer un membre à déploiement : ici le nombre d'instances simultanées possibles de MaStruct seront divisées par 5, soit 1638.

- Si jamais vous avez besoin de plus de 8191 instances de structures, c'est possible de le faire de cette manière :


Sinon, ça m'a parut très bien expliqué, les structs, et de façon assez exhaustive. Je crois pas qu'il soit nécessaire de rajouter une partie pour synthétiser.
Par contre, tu peux parler des textmacros, des arrays 2D et des actions .execute/.evaluate, qui sont assez basiques.

Très bon tuto. Bravo Wink .
_________________
Warcraft III, c'était mieux avant. Y'avait des purs chefs-d'oeuvres du mapping !
Road Of Glory (par moi)
Casse-briques (par moi)
Temple de Glace (par moi)
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Ectelion
Membre reconnu


Inscrit le: 12 Nov 2011
Messages: 1062
Sujets: 107
Spécialité en worldedit: Inactif(Enfin presque)
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 19/05/12 13:13    Sujet du message: Citer

Bon tuto Very Happy(depuis le temps que je cherchais un tuto fr sur le vjass)

Juste une question:
le h.strenght/h.agility correspond à local Heros h.strenght/h.agility mais si il y a deux unités:
Jass:
local Heros h = Heros.create()
local Units h = Units.create()

il ya deux "h" donc que va faire le compilateur les renommés en "h_1" et "h_2"
_________________
Inactif(Enfn presque)
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7143
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1) Grand mage créateur de sort (Quantité : 1)

MessagePosté le: 19/05/12 13:23    Sujet du message: Re: Introduction au vJass Citer

Citation:
Le vJass est tout simplement une extension du Jass, permettant de le manipuler beaucoup plus facilement


Il faudrait préciser que le vJass n'apporte que du candy eye stuff, c'est à dire que le vJass reste du jass à la fin.
Autrement dit on ne peut pas s'affranchir des limitations inhérentes du jass, ce n'est pas un nouveau langage en soi.
Tout ce qui est possible en vJass est aussi possible en jass, certes d'une façon plus contraignante, et parfois on devrait éditer le script de la map (comme la déclaration de variables globales autre que celle que peut fournir l'éditeur de variable, mais c'est une limite de l'éditeur officiel, pas du jass)

Citation:
b) Mise à jour du JassHelper


Il serait bien de donner aussi le lien du "nouveau" jasshelper par Cohadar.

Citation:
Les librairies permettent justement de classer notre code, et en le plaçant au début du script personnalisé automatiquement.


C'est confus et ne veut pas dire grand chose, il faudrait plutôt simplement parler du script de la map.

Citation:
Faîtes cependant attention à une chose : dans la méthode CountUp, nous avons utilisé Heros.count. Il aurait été possible de n'écrire que count, les membres statiques étant considéré comme des variables globales à l'intérieur de la structure. De même pour les méthodes, à l'intérieur de la structure, il est possible de s'y référer en n'écrivant que le nom. Faîtes cependant attention : si une autre fonction porte le même nom, il vaut mieux le préciser pour éviter les confusions.


Omettre le this. est une très mauvaise pratique, de plus il me semble que l'on peut changer le comportement de jasshelper pour les this. implicites ou non avec un tag dans le fichier jasshelper.conf.

Citation:
La méthode allocate renvoie donc un entier pour lequel le déploiement des variables est libre, d'où la limite de 8191 instances.


C'est 8190, l'index 0 n'étant pas utilisé -> struct "null".
Et l'index 8191 non plus à cause de ce bug.

Citation:
- Il existe la méthode onInit (qui doit être statique) se déclenchant à l'initialisation de la carte, sans avoir besoin de préciser un initializer comme pour les librairies ou les scopes. De même que la méthode onDestroy (qui ne doit pas être statique se référant à une instance) se déclenche à la destruction d'une instance. Elle est cependant à éviter : c'est un appel de fonction inutile, la méthode destroy pouvant servir à éxecuter du code.


C'est vrai la plupart du temps, sauf si tu utilises des struct qui extend d'autres structs, dans ce cas l'emploi des method onDestroy/onCreate est impératif.

Faudrait aussi mentionner la documentation de jasshelper fournie avec jasshelper.
Consulter le code jass généré à partir du vJass, fichier outputwar3map.j, ou output_war3map.j (selon le jasshelper utilisé) présent dans le sous dossier logs est utile pour savoir comment est compilé le vJass.

Surtout éviter d'appeler une method qui se situe au dessus de celle qui l'appelle, sous peine de se retrouver avec un ugly TriggerEvaluate au lieu d'un simple call de function.
L'utilisateur n'en sera même pas averti ...
Ce comportement peut être changé en définissant le tag [forcemethodevaluate] dans le fichier jasshelper.conf situé dans le dossier du JNGP, (et non le sous dossier jasshelper).
Je recommande vivement de le faire d'ailleurs.

Tirlititi a écrit:
C'est pas grave, je vais me contenter de faire des critiques et laisser TB décider de s'il faut l'approuver ou pas .


Euh, je ne suis pas modérateur de cette section.
_________________


Dernière édition par Troll-Brain le 19/05/12 13:27; édité 2 fois
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Crowolf
Animateur


Inscrit le: 21 Avr 2008
Messages: 1607
Sujets: 81
Spécialité en worldedit: Utiliser le travail des autres
Médailles: 3 (En savoir plus...)
Grand décorateur (Quantité : 2) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 19/05/12 13:25    Sujet du message: Citer

Merci.
Sinon, comme Tirlititi, manque les textmacros et aussi les fonctions "implement" peut-être?

Pour la mise en pratique, tu n'as qu'à renvoyer vers des tutos anglais.
http://www.hiveworkshop.com/forums/jass-ai-scripts-tutorials-280/making-spell-vjass-practice-session-1-a-114519/#7
http://www.wc3c.net/showthread.php?t=100953
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Sapeur-Goblin
Floodeur prématuré


Inscrit le: 14 Oct 2009
Messages: 719
Sujets: 40
Spécialité en worldedit: Les bugs
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 19/05/12 15:09    Sujet du message: Citer

J'ai édité mon premier poste pour corriger toutes les fautes et rajouter quelques précision (notamment celles de Troll-Brain).
Pour les déploiement 2D, c'est fait.
Je parlerai des actions .execute et .evaluate mais aussi des fonction interfaces non?
Sinon les textmacros, je veux bien mais je ne trouve pas ça très utile.
Quand tu parles des fonctions implement, tu veux dire les modules que l'ont ajoute à une structure?

@Lord_Demon_X : Euh, je n'ai pas très bien compris ton problème, mais ton code ne fonctionnera pas : tu déclare deux fois le même nom de variable.

@Troll-Brain : Le lien que j'ai donné renvoie au JassHelper de Cohadar. J'ai quand même rajouté un lien vers la page à cause des probables mises à jour.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Ectelion
Membre reconnu


Inscrit le: 12 Nov 2011
Messages: 1062
Sujets: 107
Spécialité en worldedit: Inactif(Enfin presque)
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 19/05/12 17:04    Sujet du message: Citer

Y'avait pas de problème je voulais juste savoir si ça fonctionnait ou pas.
merci
_________________
Inactif(Enfn presque)
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Ayane
Bot administrateur


Inscrit le: 17 Sep 2007
Messages: 2009
Sujets: 49

Médailles: 2 (En savoir plus...)
Rédacteur de tuto #1 (Quantité : 1) Ayane (Quantité : 1)

MessagePosté le: 19/05/12 17:46    Sujet du message: Citer

http://www.wc3c.net/vexorian/jasshelpermanual.html
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger
 Wareditor
The Master of Nothing


Inscrit le: 22 Déc 2008
Messages: 1638
Sujets: 88
Spécialité en worldedit: Effacer


MessagePosté le: 19/05/12 17:50    Sujet du message: Citer

Ayane a écrit:
http://www.wc3c.net/vexorian/jasshelpermanual.html


Existe il une traduction en français ou un projet de traduction ?
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7143
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 19/05/12 18:07    Sujet du message: Citer

Pour les sized array (2d ou non) c'est la même chose, il faut utiliser une taille < 8191 (8190 ou moins), sinon autant de variables que nécessaire seront utilisés pour simuler cette variable array.

Il faut comprendre qu'utiliser une taille > 8190 générera plusieurs variables en jass (autant que nécessaire, avec une limite que je ne connais pas mais qui générera une erreur à la compilation si franchie).
Chaque lecture/écriture de cette variable en vJass se traduira une suite de if/then/elseif en jass.
Faut vraiment en avoir besoin et avoir conscience du code que cela génère.
Perso, j'en ai jamais eu besoin, et c'est devenu plus ou moins obsolète avec l'apparition du type hashtable.

EDIT :

Haha je savais que j'aurais du utiliser le conditionnel.
J'ai pas testé, mais en y réfléchissant pour les sized array, la limite devrait être en effet 8191, car contrairement à une struct où l'index 0 n'est pas utilisé (considéré comme une instance "null"), l'index 0 d'une variable array peut tout à fait être utilisé, on exclue toujours l'index 8191 pour la même raison, mais de 0 à 8190 inclus, ca fait bien une taille de 8191.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 kungfu-sheep
Anomalie floodiforme


Inscrit le: 14 Avr 2011
Messages: 1846
Sujets: 119
Spécialité en worldedit: fonctions paramétriques, équation de mouvement.


MessagePosté le: 20/05/12 16:55    Sujet du message: Citer

super sapeur c'est excellent ! je cherchais depuis longtemps moi aussi un tuto vf sur le vjass bien fait.
_________________
22:27:43<Seiraw> Bah y a deux genre de personnes
22:27:57<Seiraw> les soumis et les soumises
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé Envoyer l'e-mail
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7143
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 20/05/12 20:27    Sujet du message: Citer

C'est runtextmacro et non run textmacro (toujours tester ses codes avant de poster :p)

Ah un truc que j'ai oublié de dire aussi, je ne suis pas certain que tes exemples avec les utilisations de globals fonctionnent, tout dépend comment la fonction main gère leur valeur "initiale" (autrement dit comment le vJass gère la définition des variables globales), je ne m'en rappelle plus.

Jass:
library Heros initializer onInit

globals
    unit Heros
endglobals

function onInit takes nothing returns nothing
    set Heros = gg_unit_Hpal_0001
endfunction

endlibrary


Je ne suis pas certain que l'unité soit créée quand Heros est définie. (il faut vérifier le code jass compilé)

Jass:
library Heros

globals
    private unit Heros = gg_unit_Hpal_0001
endglobals

endlibrary

library KillHeros

function KillHeros takes nothing returns nothing
    call KillUnit(Heros)
endfunction

endlibrary


Ne devrait pas fonctionner du tout car au moment de la définition de Heros, l'unité Paladin préplacé ne devrait pas être créé (les variables des unités préplacés sont définies dans une fonction, peut être directement dans main)
Oui je sais c'était juste pour montrer une erreur, mais pas la peine d'en rajouter Laughing
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Sapeur-Goblin
Floodeur prématuré


Inscrit le: 14 Oct 2009
Messages: 719
Sujets: 40
Spécialité en worldedit: Les bugs
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 20/05/12 20:33    Sujet du message: Citer

Ah oui c'est vrai j'avais déjà rencontré des problèmes pour attribuer à une variable une unité pré placée sur la carte.
Mais bon, c'était juste pour donner un exemple Rolling Eyes.
Je modifierai tout ça demain, et je rajouterai une partie sur les fonctions .execute/.evaluate et sur les fonctions interfaces.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Tirlititi



Inscrit le: 21 Fév 2010
Messages: 1785
Sujets: 22
Spécialité en worldedit: La modestie
Médailles: 1 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1)

MessagePosté le: 20/05/12 21:39    Sujet du message: Citer

C'est bon, le code compilé met les fonctions dans cet ordre :
Secret:

Jass:
    // Initialisation des objets préplacés
    call CreateRegions()
    call CreateCameras()
    call CreateAllDestructables()
    call CreateAllUnits()
    call InitBlizzard()

    // Pour certaines features du vJass, comme les fonctions interface
    call ExecuteFunc("jasshelper__initstructs22630203")
    // Appel des initializers librairies/scopes/structures
    call ExecuteFunc("LIBRARIES__initFunction")
    // etc...

    // Initialisation des globales (la valeur par défaut que l'on met dans l'éditeur de variables)
    call InitGlobals()
    // Initialisation des triggers GUI
    call InitCustomTriggers()
    // Lancement des triggers "Map Initialization"
    call RunInitializationTriggers()


Les globales "gg_" sont donc initialisées avant le moindre code vJass.

Pour le 2ème, par contre, c'est vrai que ça risque pas de marcher ^^.

Je crois qu'il est question de mettre InitGlobals() avant dans le jasshelper de Cohadar.
_________________
Warcraft III, c'était mieux avant. Y'avait des purs chefs-d'oeuvres du mapping !
Road Of Glory (par moi)
Casse-briques (par moi)
Temple de Glace (par moi)
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
Montrer les messages depuis:   
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Tutoriels Toutes les heures sont au format GMT + 1 Heure
Aller à la page 1, 2, 3, 4, 5, 6  Suivante
Page 1 sur 6

 
Sauter vers:  
Vous ne pouvez pas poster de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas voter dans les sondages de ce forum


Powered by phpBB © 2001, 2005 phpBB Group
Traduction par : phpBB-fr.com