×

Langue

Fermer
Atelier 801
  • Forums
  • Dev Tracker
  • Connexion
    • English Français
      Português do Brasil Español
      Türkçe Polski
      Magyar Română
      العربية Skandinavisk
      Nederlands Deutsch
      Bahasa Indonesia Русский
      中文 Filipino
      Lietuvių kalba 日本語
      Suomi עברית
      Italiano Česky
      Hrvatski Slovensky
      Български Latviešu
      Estonian
  • Langue
  • Forums
  • /
  • Transformice
  • /
  • Modules
  • /
  • [Tutoriel] Syntaxe lua et exemple de module
1 / 6 › »
[Tutoriel] Syntaxe lua et exemple de module
Podoko
« Citoyen »
1413725760000
    • Podoko#0000
    • Profil
    • Derniers messages
    • Tribu
#1
  15
  • Sommaire
  • Avant de commencer
  • Les variables
  • Les opérateurs
  • Les structures de contrôle
  • Les fonctions

Syntaxe lua
et exemple de module



Ce topic sert à apprendre comment créer des modules en maison de tribu sur Transformice. Les bases du langage ainsi que quelques points complexes y sont expliqués.
N'oubliez pas que le seul meilleur moyen d'apprendre à coder est la pratique, lire ce tutoriel n'est pas suffisant pour savoir créer des modules. Essayer de créer des modules simples en vous aidant de l'api, faites des erreurs (beaucoup) pour vous améliorer et ne laissez pas tomber si vous n'arrivez pas à résoudre un problème, demandez de l'aide sur ce topic ou celui-là.

Si vous voyez des erreurs ou si certains points ne sont pas clairs, signalez-le ;)
(ça compte aussi pour les erreurs d'orthographe)


Sommaire

  • Avant de commencer ★
    • Liens utiles
    • Environnement de travail
      • Notepad++
    • Lancer un module ★★
    • Les commentaires ★
  • Les variables ★
    • Qu'est-ce qu'une variable ★
    • Déclarer une variable ★
    • Nommer ses variables ★
    • Conventions ★
  • Les opérateurs ★
    • Opérateurs arithmétiques ★
    • Opérateurs de comparaison ★
    • Opérateurs logiques ★★
    • Autres opérateurs ★
    • Ordre de priorité ★★
  • Les structures de contrôle ★★
    • Condition : if ★
    • Boucle : while ★
    • Boucle : repeat ★
    • Boucle : for (numérique) ★★
  • Les fonctions ★★
    • Qu'est-ce qu'une fonction ? ★
    • Utiliser sa première fonction : print ★
    • Créer des fonctions ★★
    • Variable globale, variable locale ★
  • Manipulation de tables ★★
    • Qu'est-ce qu'une table ★
    • Accéder et modifier les élément d'une table ★
    • Choses à savoir sur les tables ★★
      • L'opérateur # ★
      • Copie de table ★★
      • Parcourir tous les éléments d'une table ★★
  • Fonctions sur les string ★★
    • Rappels ★
    • Prendre une sous-chaine de caractères #1 ★
    • Patterns (prendre une sous-chaine de caractères #2) ★★★
  • Exemple de module
    • Étape N°1 : Sortir un papier et un crayon
    • Étape N°2 : Rotation de cartes
    • Étape N°3 : Lancer les esprits
    • Étape N°4 : modification de l'offset
Avant de commencer


Liens utiles

  • [Tutoriel] Comment utiliser un module ?
  • [Aide] Demandes de codes et d'explications

  • L'API Lua de Transformice
  • Anglais - [Module API] Errors
  • Anglais - Function Library
  • Transformice wiki - Énumération

  • [Discussion] Le coin des développeurs LUA !





Environnement de travail


La fenêtre de Transformice pour lancer un module (/lua) n'est pas pratique pour coder, c'est à peut-près aussi utile qu'un bloc, il vaut donc mieux utiliser des éditeurs de textes tels que Kobra pour coder à plusieurs ou Notepad++.
Voyez par exemple le même script affiché sur Notepad++, Sublime Text et Transformice. C'est normal si vous ne comprenez pas ce qui est écrit, regardez juste celui sur lequel vous voudriez travailler.


http://i.imgur.com/qYmLJxU.jpg
Affichage Notepad++

http://i.imgur.com/phIyBUsl.png
Affichage Sublime Text

http://i.imgur.com/fw2q9l3.jpg
Affichage Transformice






Notepad++


Notepad++ est un éditeur de texte / de code source qui prends en charge le langage Lua et beaucoup d'autres ( C, C++, PHP, HTML, Java, etc). Il est fiable, utilise peu de ressources et sans danger.

Site officiel
Notepad++ V6.6.8 - téléchargement direct


Une fois un nouveau fichier créé, allez dans l'onglet Langage > L puis sélectionnez Lua pour activer la coloration des mots clés.
Les mots clés propres au langage lua seront ainsi automatiquement coloré d'une couleur différente du reste de texte pour rendre votre code plus simple à lire.

http://i.imgur.com/gg8uxFs.png
Activer la syntaxe lua






Lancer un module


Pour lancer un module en maison de tribu,
  • Sélectionnez l'ensemble du texte et copiez-le dans votre presse papier (ctrl+c ou clic droit > copier)
  • Allez ensuite sur Transformice dans votre maison de tribu et tapez /lua dans le tchat, une fenêtre doit normalement s'ouvrir.
  • Effacez tout le texte dans cette fenêtre s'il y en a, puis collez-y le module que vous venez de copier (ctrl+v ou clic droit > coller)
  • Cliquez ensuite sur valider pour lancer le module. Le message suivant doit normalement s'afficher dans votre tchat pour vous signaler que le module s'est bien lancé : "[11:01] [Lua] # Lua script loaded in 1 ms (4000 max)", si vous recevez un autre message différent c'est que le code comporte une erreur et doit être modifié.

http://i.imgur.com/t8sbgFR.jpg
Fenêtre Lua dans Transformice


Essayez de lancer ce module dans votre maison de tribu, une fenêtre avec écrit "Le module a été lancé avec succès" doit apparaitre.


Les commentaires


Les commentaires sont des morceaux de code que le jeu ne lit pas, ils sont généralement utilisés pour expliquer ce que fait le code ou pour mettre une portion de code qui ne fonctionne pas entre parenthèses sans avoir à l'effacer.
Vous pouvez écrire ce que vous voulez dans un commentaire, ça il ne modifie en rien l'exécution du module.

Pour indiquer qu'un morceau de code est un commentaire vous pouvez le mettre après deux tirets -- pour un commentaire sur une ligne ou entre --[[ et ]] pour un commentaire sur plusieurs lignes.

Exemple de commentaire a dit :
Ceci est un morceau de code -- Et ceci est un commentaire
Ceci est de nouveau du code
--[[ Et ceci est un autre commentaire
Je suis encore un commentaire ]]

Je suis de nouveau un bout de code

Les variables


Qu'est-ce qu'une variable ?

Une variable est un emplacement dans la mémoire de votre module, elle permet de sauvegarder des informations afin de ne pas les perdre et pour les réutiliser plus tard.
Vous pouvez mettre toutes sortes d'informations dans une variable :
- des nombres (number)
- des mots ou des phrases (string)
- des "booléens" qui sont en fait les valeurs vrai et faux (boolean)
- des fonctions (function)
- des listes qui permettent de contenir d'autres variables (table)
- nil qui représente en fait l'absence de valeur (nil)


Déclarer une variable

Vous pouvez déclarer une nouvelle variable à n'importe quel moment de votre programme.
Une variable se déclare de la façon suivante :

nom_de_la_variable = valeur

Par exemple :


nombre = 5 -- On met la valeur 5 dans la variable nombre
chaine = "Ceci est une phrase." -- On met la chaine de caractères "Ceci est une phrase" dans la variable chaine
vrai = true -- On met la valeur true dans la variable vrai
faux = false -- On met la valeur false dans la variable faux
uneListe = {1, 2, 3, 4, 5} -- On met les valeurs 1, 2, 3, 4 et 5 dans la liste uneListe
vide = nil -- On dis que la variable vide ne contient rien



Il est possible de mettre la valeur d'une variable dans une autre variable comme ceci :

nombre1 = 5
nombre2 = nombre1 -- On met la valeur de nombre1 dans la variable nombre2
-- Ansi nombre2 a la valeur 5 et je peux modifier nombre1 sans changer la valeur de nombre2.

nombre1 = 5 -- On met le chiffre 5 dans la variable nombre1
nombre2 = nombre1 -- nombre2 prend la valeur de nombre1 (5) et nombre1 vaut toujours 5
nombre1 = 7 -- nombre1 vaut 7 et nombre2 vaut encore 5


On peut aussi déclarer plusieurs variables à la fois de cette manière :

unMot, unNombre = "Peluche", 7 -- On met le mot "Peluche" dans la variable unMot et le nombre 7 dans
-- la variable unNombre
-- Les virgules sont indispensables




Nommer ses variables.

Un nom de variable ne peut être composé que de lettres minuscules ou majuscules sans accent, des chiffres et du caractère _ , il doit obligatoirement commencer par une lettre.

Important : Le lua est un langage sensible à la casse, c'est à dire qu'il fait la différence entre les lettre majuscules et les lettres minuscules, ainsi les noms vAriaBle et VAriabLe ne représentent pas la même variable.


Certains mots ont une signification spéciale en lua et vous ne pouvez donc pas les utiliser comme nom de variable, En voici la liste :
and break do else elseif end false for if
in local nil not repeat then return true or
until while function




Conventions

Pour faciliter la lecture d'un script, il est indispensable de nommer intelligemment ses variables. Le nom d'une variable doit décrire son utilité. Par exemple une variable qui doit contenir le pseudo d'un joueur devrait s'appeler pseudo (pseudo = "Podoko") tandis qu'une variable devant contenir un score devrait s'appeler score (score = 117)
Si plusieurs mots sont nécessaires pour décrire une variable, la plupart des codeurs mettent une majuscule au début de chaque mot sauf le premier. Par exemple une variable devant contenir le meilleur score d'une partie devrait s'appeler meilleurScore
Les opérateurs


Les opérateurs arithmétiques

Les opérateurs de arithmétiques permettent de faire des opérations telles que la somme, la soustraction, la multiplication. Voici comment les utiliser.


n1, n2 = 6, 3
n3 = n1 + n2 -- + La somme, on met le résultat de 6+3 dans la variable n3
n4 = n2 - n1 -- - La soustraction
n5 = n1 * n2 -- * La multiplication
n6 = n1 / n2 -- / La division
n7 = n1 ^ n2 -- ^ La puissance ( équivalent à n7 = 6 * 6 * 6 )
n8 = n1 % n2 -- % Le modulo, renvoie le reste de la division euclidienne de n1 par n2 (0 en l'occurrence)

On peut aussi bien mettre des nombres que des variables dans l'expression de droite :

n8 = n1 + 7 -- Cette expression est parfaitement valable.

De la même façon, la variable dans laquelle vous voulez mettre votre résultat peut apparaitre dans l'expression de droite :

n9 = 8
n9 = n9 + 5 -- Cette expression aussi est valable, elle est équivalente à n9 = 8 + 5 ou
-- à "j'ajoute 5 à la valeur actuelle de n9"



Vous ne pouvez utiliser ces opérateurs que sur des nombre, en effet ça n'aurait aucun sens d'écrire res = "Peluche" - "Ratatouille"



Opérateurs de comparaison
(ou opérateurs booléens)


Ces opérateurs servent à vérifier des égalités et renvoient un booléen (true ou false)
Voici comment les utiliser :

n1, n2 = 5, 13
test1 = n1 == n2 -- == équivaut à est-ce que n1 est égal à n2 ? Le résultat est false et va dans test1
test2 = n1 ~= n2 -- ~= équivaut à est-ce que n1 est différent de n2 ? Le résultat est true et va dans test2
test3 = n1 < n2 -- < équivaut à est-ce que n1 est plus petit que n2 ?
test4 = n1 > n2 -- < équivaut à est-ce que n1 est plus grand que n2 ?
test5 = n1 <= 5 -- <= équivaut à est-ce que n1 est plus petit ou égal à 5 ?
test6 = ni >= 6 -- >= équivaut à est-ce que n1 est plus grand ou égal à 6 ?

Note : les opérateurs == et ~= fonctionnent aussi sur les autres types de variables tels que les string et les boolean.




Les opérateurs logiques

Les opérateurs logiques permettent de vérifier plusieurs propositions à la fois, on en compte trois : not, or, and

L'opérateur or renvoie le premier argument s'il est différent de false ou de nil, sinon il renvoie le second argument. Il signifie "ou" en français.
L'opérateur and renvoie le premier argument si sa valeur est false ou nil, sinon il renvoie le second argument. Il signifie "et" en français.
L'opérateur not renvoie false si son argument est différent de nil ou de false et renvoie true sinon. C'est l'opérateur qui renvoie le contraire de son argument


Quelques exemples avec les résultats

-- or
test1 = true or false -- true
test2 = false or true -- true
test3 = false or false -- false
test4 = false or nil -- nil
test5 = nil or 5 -- 5
test6 = "Peluche" or "Ratatouille" -- "Peluche"

-- and
test1 = true and false -- false
test2 = false and true -- false
test3 = true and nil -- nil
test4 = 5 and true -- true
test5 = nil and false -- nil
test6 = "Peluche" and "Ratatouille" -- "Ratatouille"

-- not
test1 = not true -- false
test2 = not false -- true
test3 = not nil -- true
test4 = not 5 -- false
test5 = not "Peluche" -- false




Autres opérateurs

L'opérateur # permet de connaitre le nombre d'élément que contient un tableau ou une chaine de caractères, il renvoie toujours un nombre positif.

monTableau = {5, 9, "chaine", true}
tailleTableau = #monTableau -- tailleTableau vaut maintenant 4 comme il y a 4 éléments dans monTableau

maChaine = "Je suis une peluche"
tailleChaine = #maChaine -- tailleChaine vaut maintenant 19 comme il y a 19 caractères dans maChaine
-- l'opérateur # compte tous les caractères, même les espaces



L'opérateur .. (deux points à la suite) permet de créer une chaine de caractères à partir de deux autres, c'est ce qu'on appelle la concaténation.

phraseDebut = "Bonjour, je suis "
phraseFin = "une peluche"

phrase = phraseDebut .. phraseFin -- phrase contient maintenant la chaine "Bonjour, je suis une peluche"




Ordre de priorité

Si vous faites des expressions un peu compliquées qui mélangent plusieurs opérateurs, les opérateurs prioritaires s'exécuteront avant ceux de priorité inférieure.
Voici la liste des opérateurs par ordre décroissant de priorité :
^
not # -
(pour dire -5 ou -13)
* / %
+ -
..
< > <= >= == ~=
and
or


Vous pouvez modifier l'ordre dans lequel se font les opérations avec des parenthèses () comme en mathématiques

Ainsi :

5 * 6 + 15 / 3 est équivalent à ( 5 * 6 ) + ( 15 / 3 )
13 + 15 / 5 < 7 est équivalent à ( 13 + ( 15 / 5 )) < 7
false and 5 or true est équivalent à ( false and 5 ) or true

Les structures de contrôle

La condition : if


La structure de contrôle if permet de n’exécuter un bloc d'instructions que si une certaine condition est vérifiée. La condition est considérée comme vérifiée si son résultat est différent de nil ou de false.
Voici comment se construit une boucle if :
Structure if a dit :
if condition then
   instructions
end

si la condition n'est pas vérifiée vous pouvez faire une nouveau test pour exécuter d'autres instructions :

if condition then
   instructions
elseif condition2 then
   instructions2
elseif condition3 then
   instructions3
end

Vous pouvez mettre autant de elseif que vous voulez à la suite, si une des conditions est vérifiée, le programme ne testera pas les conditions restantes (concrètement, si la condition 2 est vérifiée, les conditions 3, 4, etc ne seront pas testées)


Vous pouvez rajouter un else pour le cas où aucune des conditions n'a été validée :

if condition then
   instructions
else
   autresInstruction
end

Le cas else se place toujours en dernière position dans une boucle if.



nb1 = 5
nb2 = 9

if nb1 == nb2 then -- Cette condition est fausse
   nb3 = nb1 -- Cette ligne ne s’exécute pas
elseif nb1 < nb2 then -- Cette condition est vraie
   nb3 = 8 -- Cette ligne s'exécute
elseif nb1 == 5 then -- Cette condition est vraie mais une des conditions précédentes l'était déjà
   nb3 = 10 -- Cette ligne ne s'exécute pas
else -- Une des conditions plus haut était vraie
   nb3 = nb2 -- donc cette ligne ne s'exécute pas
end

-- À la fin du programme, nb3 vaut 8


Note :
if nb1 == nb2 then
   bool1 = true
elseif nb1 < nb2 then
   bool1 = false
end
-- est équivalent à
if nb1 == nb2 then
   bool1 = true
else
   if nb1 < nb2 then
       bool1 = false
   end
end




la boucle while


La structure de contrôle while permet de répéter la même série d'instructions tant qu'une condition est vérifiée. De même que pour le if, la condition est considérée comme vérifiée si son résultat est différent de false ou de nil.
Voici comment se construit une boucle while :
Structure while a dit :
while condition do
   instructions
end

On peut le traduire par "Tant que ... tu fais ..."
Par exemple :

nb1 = 0

while nb1 < 6 do -- Tant que nb1 est inférieur à 6
   nb1 = nb1 + 1 -- On ajoute 1 à nb1
end

-- À la fin de l'exécution, nb1 vaut 6

Important : Il faut faire attention avec ce genre de structure pour éviter qu'elles ne tournent à l'infini, sinon votre module plante forcement.
par exemple :

nb1 = 1
while nb1 ~= 0 do
   nb1 = nb1 + 1
end

Comme nb1 ne sera jamais égal à 0, votre module ne cessera pas d'ajouter 1 et plantera.




La boucle repeat


La structure de contrôle repeat est similaire au while, elle permet de répéter une suite d'instructions tant qu'une condition n'est pas vérifiée. Comme pour if et while, la condition est considérée comme vérifiée si son résultat est différent de false ou de nil.
Voici comment se forme une boucle repeat :
Structure repeat a dit :
repeat
   instructions
until condition

On peut le traduire par : "Fais ... jusqu'à ce que ..."
Par exemple :

nb1 = 0
repeat
   nb1 = nb1 + 1 -- Ajoute 1 à nb1
until nb1 == 5 -- Jusqu'à ce que nb1 vaille 5

Important : Comme la condition est énoncée à la fin de la boucle, les instructions s'exécutent toujours au moins une fois.
Important² : Comme pour la boucle while, il faut faire attention à ce que la condition de la boucle repeat se vérifie bien à un moment sinon votre module plantera.




La boucle for (numérique)


Le for numérique permet d'exécuter une suite d'instructions un nombre prédéfini de fois.
Voici comment se forme une boucle for :
Structure for numerique a dit :
for nb = n1, n2, n3 do
   instructions
end

Avec n1, n2, n3 qui sont des nombres. (ou des variables contenant des nombres, c'est la même chose)
nb est un compteur qui commence à n1.
n2 est la borne de fin, la boucle for se termine une fois que nb est égal à n2.
n3 est le pas, après chaque exécution des instructions on ajoute n3 à nb

C'est équivalent à "pour nb allant de n1 à n2 par pas de n3, faire ..."
Par exemple :

for i=0, 10, 2 do -- Pour i allant de 0 à 10 par pas de 2, tu dois
   instructions -- faire ce qui est écrit
end

par défaut n3 est égal à 1, donc
for i=1, 10 do -- signifie : pour i allant de 1 à 10 par pas de 1

Important : Comme pour les boucle while et repeat, il faut faire attention à ce que la le compteur soit bien égal à la borne de fin à un moment, sinon votre module va planter. ("for i=1, 10, 2" fera planter votre module puisque i ne sera jamais égal à 10, il passera de 9 à 11)
Important² : Vous ne pouvez pas modifier vous-même le compteur, la borne de fin ni le pas quand vous êtes dans la boucle for.

Important³ : Il existe un autre type de boucle for : le for générique, c'est une notion trop compliquée à expliquer à ce point du tutoriel mais des exemples d'utilisations sont donnés dans les parties sur les manipulations de tables et les patterns.
Les fonctions

Qu'est-ce qu'une fonction ?

Une fonction est un morceau de votre module qui contient une série d'instructions à exécuter lorsqu'elle est appelée. Elle peut appeler d'autres fonctions, modifier des variables,renvoyer un ou plusieurs résultats.
Une fonction peut recevoir des paramètres à partir desquels elle travaille pour renvoyer un résultat ou modifier le jeu.


Utiliser sa première fonction : print

print est une fonction qui prend un paramètre de n'importe quel type (number, string, boolean, etc) et affiche son contenu dans le tchat de celui qui lance le module.

Par exemple :
print("Hello world!") -- affiche Hello world! dans le tchat
print(true) -- affiche true dans le tchat
print(var1) -- affiche le contenu de la variable var1 dans le tchat




Créer des fonctions


Pour déclarer une fonction, on commence toujours par le mot clé function suivit par le nom de la nouvelle fonction, puis par la liste des paramètres/arguments entre parenthèses. chaque paramètre étant séparé des autres par une virgule.
On écrit ensuite les instruction de la fonction dans les lignes qui suivent et on ferme la fonction avec un end

Comme ceci :

function nomDeLaFonction ( param1, param2, param3 ) -- Une fonction qui prend trois arguments
   instructions
end


Si la fonction n'a pas besoin de paramètres, les parenthèses doivent quand même être mises :

function nomDeLaFonction () -- Aucun argument
   instructions
end



Une fonction peut ou non renvoyer un ou plusieurs résultats grâce au mot clé return. Cette valeur retournée peut ensuite être sauvegardée dans une variable.
Une fois le résultat renvoyé, la fonction se termine même si des instructions sont écrites après.
En voici un exemple :

function renvoi2 () -- Cette fonction ne demande pas de paramètre et renvoie 2
   return 2
end

nb = renvoi2() -- On met le résultat de renvoi2 dans la variable nb
print( renvoi2() ) -- On affiche le résultat de renvoi2 dans le tchat



Pour écrire une fonction qui fait la somme de deux nombres on peut écrire
function somme( nb1, nb2 )
   resultat = nb1 + nb2
   return resultat
end

ou bien
function somme (nb1, nb2)
   return nb1+nb2
end


Par conséquent on peut directement renvoyer le résultat d'une expression plutôt que de passer par un résultat intermédiaire.
Une seule fonction peut également renvoyer plusieurs résultats à la fois en les séparant par une virgule :
function sommeProduit (nb1, nb2)
   som = nb1 + nb2
   prod = nb1 * nb2
   return som, prod -- on renvoie la somme et le produit des deux nombres reçus en argument
end

resSom, resPro = sommeProduit ( 2, 5 ) -- On met 7 dans resSom et 10 dans resPro
resSom2 = sommeProduit ( 3, 7 ) -- On met la somme de 3 et 7 dans resSom2 et le produit n'est pas sauvegardé.


On peut également appeler de nouvelles fonctions directement avec le résultat d'une autre.

print ( somme(5, 7) ) -- On affiche le résultat de la somme de 5 et 7
print ( somme( sommeProduit(4,3) ) ) -- On affiche le résultat de la somme de la somme et du produit de 4 et 3 (donc (4+3) + (4*3))

Dernière modification le 1604046480000
Podoko
« Citoyen »
1413725820000
    • Podoko#0000
    • Profil
    • Derniers messages
    • Tribu
#2
  11
  • Manipulation de tables
  • Fonctions sur les strings
  • Exemple de module
Manipulation de tables


Qu'est-ce qu'une table ?


Les tables sont des variables particulières dans lesquelles ont peut mettre plusieurs variables, des nombres, des booléens, des chaines de caractères, d'autres tables.
Si on voit les variables comme des tiroirs dans lesquelles on met des valeurs, alors on peut se représenter les tables comme de grandes armoires avec plusieurs tiroirs.

On se sert la plupart du temps des tables pour ranger au même endroit des informations similaires comme par exemple la liste des joueurs d'un salon, une liste de records, etc.

Une table se déclare de la façon suivante :

Declaration table a dit :
maTable = {}

Accéder et modifier les élément d'une table


Pour modifier un élément d'une table, il y a plusieurs solutions, la première est la suivante :

nomDeMaTable[ nomDuTiroir ] = valeur

Par exemple :

maTable = {} -- Ne surtout pas oublier de déclarer la table, sinon le module plante
maTable[1] = "val" -- On me la valeur "val" dans le premier tiroir de maTable
maTable["case"] = 56 -- On met le nombre 56 dans le tiroir "case" de maTable
maTable["1"] = true -- On met la valeur true dans le tiroir "1" de maTable (maTable[1] et maTable["1"] sont deux tiroirs différents)

Vous pouvez ensuite utiliser les variables du tableau comme n'importe quelle autre variable :

print( maTable["case"] )
print( maTable[1] )
print( maTable["1"] )
-- Avec les deux dernières lignes vous pouvez confirmer que maTable[1] et maTable["1"] sont bien deux tiroirs différents


Vous pouvez également mettre une table dans une autre :

maTable = {} -- On déclare la table
maTable[1] = {} -- Le premier tiroir de maTable contient une table
maTable[1]["case"] = "coucou" -- On met la valeur "coucou" dans le "sous-tiroir" du premier tiroir de maTable


On peut également modifier un élément d'une table de la façon suivante :

nomDeMaTable.nomDuTiroir = valeur
-- Un point entre le nom de la table et le nom du tiroir


par exemple :

maTable = {}
maTable.case = "Peluche" -- Équivalent à maTable["case"] = "Peluche"

maTable.sousTable = {}
maTable.sousTable.sousTiroir = "Ratatouille"
-- Équivalent à maTable["sousTable"]["sousTiroir"] = "Ratatouille
-- Équivalent à maTable["sousTable"].sousTiroir = "Ratatouille
-- Équivalent à maTable.sousTable["sousTiroir"] = "Ratatouille



Les avantages de la première méthode sur la deuxième sont les suivants :
On ne peut pas accéder aux tiroirs numérotés avec la deuxième méthode.
maTable = {}
maTable.1 = "valeur" -- Cette ligne fera planter le module, le nom de "tiroir" doit respecter les même règles que celui d'une
-- variable comme commencer par une lettre


On peut mémoriser le nom d'un tiroir avec la première méthode
maTable = {}
adresse = "case"
maTable[adresse] = "Peluche" -- On met "Peluche" dans le tiroir "case" de maTable




Une troisième méthode permet d'ajouter les éléments au tableau dès sa déclaration :

maTable = { "Peluche", 56, true, "Ratatouille" }
--[[ Cette ligne est équivalente à

maTable = {}
maTable[1] = "Peluche" -- Notez que le compte commence à 1 et pas à 0 comme dans d'autres langages, c'est important
maTable[2] = 56
maTable[3] = true
maTable[4] = "Ratatouille"
]]


On peut aussi faire comme ceci :

maTable = { case="coucou", autre = "Peluche" }
--[[ C'est équivalent à

maTable = {}
maTable.case = "coucou"
maTable.autre = "Peluche"
]]




La dernière solution est d'utiliser une fonction : table.insert
Note : Si vous suivez un peut vous remarquez que cette fonction est dans une table. On peut donc bien mettre une fonction dans une table.

Cette fonction, comme son nom l'indique insère un élément dans une table à la suite des autres éléments. Elle prend deux arguments : le nom de la table et l'élément à insérer.
par exemple :

maTable = { "test", 56, true, "Peluche" }
table.insert (maTable, "Ratatouille") -- On rajoute "Ratatouille à la fin de la table
-- À la fin, maTable[5] vaut "Ratatouille"


Vous pouvez également indiquer à quel numéro vous voulez insérer l'élément, dans ce cas l'élément au numéro indiqué et tous les suivants seront déplacés vers la case d'après :

table.insert (nomDeLaTable, numero, valeur)

par exemple :

maTable = { "test", 56, true, "Peluche" }

table.insert ( maTable, 3, "Ratatouille" )
--[[ Revient à faire
maTable[5] = maTable[4]
maTable[4] = maTable[3]
maTable[3] = "Ratatouille"
]]


La fonction inverse à table.insert est table.remove qui retire un élément à une table :

table.remove (nomDeLaTable, numero)

maTable = { "test", 56, "Peluche", "Ratatouille" }

table.remove (maTable, 2)
--[[ Revient à faire
maTable[2] = maTable[3]
maTable[3] = maTable[4]
maTable[4] = nil
]]





Choses à savoir sur les tables


L'opérateur #


Cet opérateur, comme c'est indiqué au début du tutoriel, sert à connaitre la taille d'une table ou d'un string. C'est en réalité un peu différent, il regarde le premier élément de la table, puis le second, le troisième, ... jusqu'à tomber sur un élément qui vaille nil pour trouver la taille du tableau, par conséquent il ne compte pas les éléments qui n'ont pas de numéro.
Un exemple vaut mieux que des explications vagues :

maTable = { "test", 56, "Peluche" }
print(#maTable) -- Affichera 3

maTable["test"] = "Ratatouille"
print(#maTable) -- Affichera encore 3

maTable[4] = "Souris"
print(#maTable) -- Affichera 4

maTable[6] = "Fromage"
print(#maTable) -- Affichera toujours 4

maTable[5] = "Chamane"
print(#maTable) -- Affichera 6




Copie de table


Le tutoriel dit au début qu'on peut copier la valeur d'une variable dans une autre variable avec le symbole = et qu'on peut ensuite manipuler chacune des variables sans affecter l'autre

nb1 = 5
nb2 = nb1 -- On copie nb1 et on le met dans nb2
nb1 = 3 -- On modifie la valeur de nb1 mais nb2 ne change pas
print(nb1)
print(nb2)


Avec les tables, ce n'est pas vrai.
Par exemple :

tab1 = { "test", 56, true, "Peluche" }
tab2 = tab1 -- On copie tab1 dans tab2

tab1[2] = "Ratatouille" -- On change la valeur de tab1[2]
print(tab2[2]) -- On devrait afficher 56 mais pourtant c'est "Ratatouille" qui s'affiche.


Donc les deux noms de variables permettent de manipuler la même table. Si vous voulez vraiment copier la table et ses éléments dans une nouvelle variable vous devez créer une fonction pour ça. (pas donnée dans ce tutoriel car peut vite manger des ressources pour les grandes tables et parce que c'est un bon entrainement à chercher)

Note : Si vous savez ce qu'est un pointeur, en réalité ce n'est pas le tableau lui-même que contient la variable mais le pointeur vers ce tableau. On copie donc le pointeur et pas le tableau, c'est de là que vient ce "problème".




Parcourir tous les éléments d'une table


Il arrive souvent d'avoir besoin d'exécuter les mêmes instructions sur tous les éléments d'une table, pour cela on utilise la boucle for générique de la façon suivante :

tab = { "test", "Peluche", "Ratatouille" }
tab.fromage = "Souris"

for key, val in ipairs(tab) do
instructions
end


ou bien :

for key, val in pairs(tab) do
instructions
end

--[[ key est "le nom du tiroir" dans la table et val sa valeur

La différence entre les fonctions pairs et ipairs est que pairs permet de parcourir vraiment tous les éléments de la table qui sont différents de nil comme tab.fromage alors que ipairs ne parcourt que les éléments de 1 à #tab (donc tab[1], tab[2], etc jusqu'à ce que la valeur soit nil)

]]


Note : si la valeur ne vous intéresse pas, vous pouvez très bien écrire "for key in pairs(tab)" ou for "key in ipairs(tab)", ça ne pose pas de problème.
Fonctions sur les strings


Rappels

Les strings sont des variables qui contiennent des chaines de caractères, c'est à dire des mots, des phrases, tu texte, etc.
Il existe plusieurs façons de déclarer un nouveau string :

str1 = "Texte" -- entre " et "
str2 = 'Texte' -- entre ' et '
str3 = [[Texte]] -- entre [[ et ]]


Avec l'opérateur # vous pouvez connaitre le nombre de caractères que contient une variable :

str1 = "Je suis une peluche"
print(#str1) -- Affiche la longueur de la chaine : 19


Vous pouvez réunir deux chaines de caractères en une seule grâce à l'opérateur ..

str1 = "Bonjour, "
str2 = "je suis une peluche"
str3 = str1..str2.. " et j'aime la ratatouille."
print(str3) -- "Bonjour, je suis une peluche et j'aime la ratatouille."


Enfin, vous pouvez comparer deux chaines de caractères avec les opérateurs <, >, <= et >=
Ceci peut permettre par exemple de ranger des mots par ordre alphabétique :

"Peluche" < "Ratatouille" -- true puisque P vient avant R dans l'alphabet.





Prendre un morceau d'un string (première version)


Le langage lua possède beaucoup de fonctions pour manipuler les chaines de caractères. Il permet entre autres de récupérer un bout de cette chaine grâce à la fonction string.sub
Cette fonction prend trois arguments : la chaine de caractères, l'emplacement de la première lettre à récupérer et l'emplacement de la dernière lettre à récupérer.
Si le troisième argument n'est pas donné (la dernière lettre à prendre), alors la fonction renvoie la fin de la chaine.

str = "Je suis une peluche"

str1 = string.sub(str, 1, 7) -- "Je suis"
str2 = string.sub(str, 13) -- "peluche"
str3 = string.sub("Ratatouille", 1, 3) -- "Rat"


Il est aussi possible d'appeler cette fonction en mettant le nom de la variable contenant le string suivit de :sub(debut, fin)
Par exemple :

str = "Je suis une peluche"
str1 = str:sub(13, 19) -- "peluche" (équivalent à string.sub(str, 13, 19))



Cette fonction string.sub est très utile pour créer des commandes qui prennent des paramètres grâce à la fonction eventChatCommand
Voici par exemple une fonction qui permet de donner le fromage à un joueur grâce à la commande "!cheese nom_du_joueur" :

function eventChatCommand(name, command)
if command:sub(1,6) == "cheese" then -- Si les 6 premières lettres forment "cheese" alors
tfm.exec.giveCheese( command:sub(8) ) -- on donne le fromage au joueur dont le nom est donné
end
end






Avancé : Les patterns
Prendre un morceau d'un string (seconde version)



Il peut parfois arriver d'avoir besoin de traiter de façon plus complexe une chaine de caractères, ça peut être le cas si vous voulez créer une commande dans le tchat qui demande de donner deux informations ou plus. Par exemple une commande "!addPoint [name] [nbPoints]" qui servirait à donner un certain nombre de points ("[nbPoints]") à un joueur ("[name]") au score d'un joueur. Par exemple : "!addPoints Peluche 15" donnerait 15 points au joueur Peluche.
On ne peut pas créer ce genre de fonction si l'on a que string.sub à disposition puisque le nom du joueur peut être plus long que ce qu'on a initialement prévu.

Une méthode utile est donc de récupérer tous les mots dans une chaine de caractère avant de faire ses test.
Voici le code qui permet de mettre tous les mots d'une chaine de caractères dans un tableau :

local monString = "Je suis une peluche avec une moustache !" -- On crée notre chaine de caractères à analyser
local listeMots = {} -- On crée la table qui va contenir la liste des mots

for word in string.gmatch ( monString, '%S+' ) do -- Pour chaque mot dans monString...
table.insert ( listeMots, word ) -- Ajouter le mot à la liste des mots déjà trouvés.
end

Vous pouvez ensuite afficher tous les éléments de la table pour voir le résultat.

for _, word in ipairs(listMots) do
print(word)
end

--[[ Résultat :
Je
suis
une
peluche
avec
une
moustache
!
]]


Avec cette méthode il est très simple de créer la commande !addPoint :

function eventChatCommand(name, command)

local listeMots = {}
for word in command:gmatch( '%S+' ) do -- On liste les mots de la commande
table.insert(listeMots, word)
end

if listeMots[1] == 'addPoint' then -- Si le premier mot de la commande est 'addPoint' alors
tfm.exec.setPlayerScore(listeMots[2], listeMots[3], true) -- On ajoute listeMots[3] (le nombre de points) à listeMots[2] (le nom du joueur)
end
end




Regardons de plus près la ligne suivante : for word in string.gmatch( monString, '%S+' ) do
et plus précisément '%S+' , sans en avoir l'air, cette simple chaine de caractères a énormément de sens. C'est un pattern qui représente "une suite de caractères différents d'un espace la plus longue possible"

Par exemple, dans "Je suis une peluche !", "Je" correspond à ce pattern, "une" aussi. Même "!" y correspond puisque ce n'est pas un espace
Attention, "pelu" ne correspond pas puisque le caractère suivant dans la chaine n'est pas un espace, "peluche" quand à lui, correspond.


"%S" représente une classe de caractères : tous les caractères différents d'un espace (" ")
le "+" est un opérateur de répétition, en étant lié au "%S" il permet d'indiquer qu'on cherche une suite de caractères aussi longue que possible, c'est donc lui qui fait que "pelu" ne correspond pas au pattern "%S+" mais que "peluche" oui.





Les classes de caractères.

Il existe plusieurs classes de caractères comme %S qui servent chacune à trouver des caractères différents :

Les principaux
  • %s : représente les caractères espace
  • %d : représente les chiffres décimaux (0 1 2 3 4 5 6 7 8 9)
  • %x : représente les chiffres hexadécimaux (0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F)
  • %l : représente toutes les minuscules ( de a à z )
  • %u : représente toutes les majuscules ( de A à Z )
  • %a : représente toutes les lettres, %l et %u à la fois
  • %w : représente tous les caractères alphanumériques, %d, %l et %u à la fois
  • . (sans %) : représente tous les caractères.
  • x (sans % et x n'étant un des caractères suivant : ^$()%.[]*+-?) : représente le caractère x lui-même.


D'autres classes
  • %c : représente les caractères de contrôle par exemple "\t" (tabulation) ou "\n" (retour à la ligne)
  • %g : représente tous les caractères imprimables sauf espace
  • %p : représente tous les caractères de ponctuation ( ! § , ; etc...
  • %x (avec x n'étant pas un caractère alphanumérique) : représente le caractère lui même (utile pour représenter le "+" par exemple : "%+")


Important : remplacer le caractère représentant une classe par sa majuscule représente le contraire de cette classe. Par exemple %S représente tous les caractères sauf les espaces, %D représente tous les caractères sauf 0 1 2 3 4 5 6 7 8 9.



Créer sa classe de caratères

Grâce aux crochets [] vous pouvez définir vos propres classes de caractères, il suffit de lister les caractères entre les crochets comme ceci :

[abcdef] -- Représente les caractères a b c d e et f minuscules
Si vous cherchez toutes les lettres correspondant à cette nouvelle classe vous aurez une chose comme ceci :

str = "J'ai caliné une peluche"
for car in str:gmatch('[abcdef]') do
print(car)
end
-- Vous obtiendrez a c a e e c e
-- NB : le é n'a pas été affiché, c'est normal puisque e et é sont des caractères différents
-- si vous voulez avoir le é, votre classe de caractères doit être [abcdefé]


Un raccourcis : plutôt que d'écrire [abcdef] il possible d'écrire [a-f] qui veut dire "tous les caractères de a jusqu'à f"
Vous pouvez également inclure une des classes prédéfinies dans vos propres classes comme ceci :

[a-fA-F%d] -- cette classe représente les lettres de a à f, de A à F et les caractères décimaux : 0 1 2 3 4 5 6 7 8 9
-- Elle est donc équivalente à la classe %x (les caractères hexadécimaux)





Les modificateurs


Les modificateurs permettent de récupérer plusieurs caractères à la fois plutôt qu'un seul. Ils se mettent après une classe de caractères pour récupérer plusieurs lettres correspondantes à cette classe à la fois.
Il existe quatre modificateurs :

+ Permet de récupérer une série de un ou plusieurs caractères
* Permet de récupérer une série de 0 ou plusieurs caractères
- Pareil que pour *, mais récupère la chaine la plus courte posible
? Permet Permet de récupérer une ou zéro répétitions du caractère


Quelques exemple :

'%S+' signifie une chaine de un ou plusieurs caractères différents d'un espace, c'est à dire un mot

phrase = "Je suis une peluche."
for str in phrase:gmatch('%S+') do
print(str)
end
-- "Je" "suis" "une" "peluche."

' .* ' signife une chaine de caractères correspondante à un espace suivit d'un ou plusieurs caractères puis d'un autre espace

phrase = "Je suis une peluche."
for str in phrase:gmatch(' .* ') do
print(str)
end
-- " suis une "


' .- ' signife une chaine de caractères correspondante à un espace suivit d'un ou plusieurs caractères la plus courte possible puis d'un autre espace

phrase = "Je suis une peluche."
for str in phrase:gmatch(' .- ') do
print(str)
end
-- " suis "


'-?%d+' signifie un ou aucun caractère - suivit d'un ou plusieurs chiffres

phrase = "négatif : -13 positif : 42"
for str in phrase:gmatch('-?%d+') do
print(str)
end
-- "-13" "42"




Exercices :

Essayez de créer les patterns permettant de trouver les chaines de caractères suivantes :

un nombre à virgule (positif)
%d+,%d+ -- Virgule obligatoire ( 42 n'est pas pris en compte)
%d+,?[%d+]? -- Virgule facultative (42 est pris en compte)

un nombre à virgule (positif ou négatif)
-?%d+,%d+ -- Virgule obligatoire ( 42 n'est pas pris en compte)
-?%d+,?[%d+]? -- Virgule facultative (42 est pris en compte)

une date ( jj/mm/aaaa )
%d%d/%d%d/%d%d%d%d

un mot
%S+

un mot suivit d'une date ( blabla jj/mm/aaaa )
%S+ %d%d/%d%d/%d%d%d%d

"pseudo : " suivit d'un nom
pseudo : %S+

une série de caractères avec des 0 aux extrémités
0.-0 -- Ne peut pas contenir des 0
0.*0 -- Peut contenir des 0
Exemple de module


Dans cet exemple nous allons créer un mini-jeu sans chamane dans lequel chaque joueur sera capable de lancer des esprits pour atteindre le fromage puis rentrer au trou. Nous allons devoir décider des règles et du fonctionnement du jeu puis le coder.



Étape N°1 : Sortir un papier et un crayon


Avant de commencer à coder il faut bien décider de ce que vous allez coder et ne pas foncer tête en bille sans savoir où vous allez, prenez le temps de réfléchir aux fonctions que vous allez devoir mettre en place, celles dont vous aurez besoin et celles


Les joueurs ne pourront lancer d'esprit que toutes les secondes
Il pourront choisir où l'esprit sera invoqué par rapport à eux dans un carré de 30*30 autour d'eux (offset)
L'esprit se lancera en se baissant
Il faudra désactiver le changement automatique de cartes pour mettre ses propres cartes.
Par conséquent il faudra savoir quand changer de carte : temps à 0 ou plus de souris sur la carte.


Nous avons donc besoin :

D'une table personnalisée par joueur pour sauvegarder l'offset et le moment où il a lancé un esprit pour la dernière fois
D'une table où sauvegarder la liste des cartes

D'activer l'écoute pour les touches bas et S (pour lancer l'esprit)
De désactiver le changement automatique de carte
De désactiver la sélection automatique d'une chamane

De la fonction eventLoop pour savoir si la carte doit être changée
Des fonction eventPlayerWon et eventPlayerDied pour activer la fonction précédente
De la fonction eventKeyboard pour permettre aux joueurs de lancer des esprits


D'une fonction pour compter le nombre de joueurs restant quand un joueur rentre ou meurt
De la fonction os.time() pour obtenir l'heure à laquelle un joueur essaie de lancer un esprit




Étape N°2 : Rotation de cartes


Comme nous créons un mini-jeu sur plusieurs cartes, il faut s'occuper de savoir quand passer à la suivante et quelle carte passer.
Commençons par désactiver le changement automatique de carte, la fonction pour le faire est tfm.exec.disableAutoNewGame et prend un argument booléen pour savoir s'il faut activer ou désactiver le changement de carte.

a dit :
tfm.exec.disableAutoNewGame(true) -- Désactivation de changement automatique de carte.

Comme il s'agit d'un fonction qu'on va utiliser uniquement au lancement du module, on peut y mettre dans une fonction qu'on appellera lors du lancement du module et qui servira à faire toutes les actions du début de jeu :

a dit :
function main() -- Fonction principale appelée au lancement du module
   tfm.exec.disableAutoNewGame(true)
   tfm.exec.disableAutoShaman(true) -- Tant qu'on y est on empêche la sélection d'une chamane sur les cartes.

end

main()

Il nous faut également une liste des cartes que jouera le module, on peut la mettre dans un tableau qu'on appelle mapList

a dit :
function main()
   tfm.exec.disableAutoNewGame(true)
   tfm.exec.disableAutoShaman(true)
   mapList = { 0, 15, 42, 17, 14, 33, 104 } -- Liste des cartes du module.

end

Maintenant qu'on a une liste de cartes et qu'on sait que le jeu ne va pas changer de carte tout seul, on peut décider de quand charger une nouvelle carte.
De toutes évidence c'est quand il n'y a plus aucun joueur ou quand le temps est arrivé à zéro.

Commençons par gérer le cas où tous les joueurs sont rentrés ou morts :

On va compter le nombre de joueurs vivants chaque fois qu'un joueur meurt ou rentre avec le fromage. Il va nous falloir une nouvelle fonction pour ça :

a dit :
function playerLeft ()
   local i = 0 -- Le compteur de souris vivantes
   for _, prop in pairs(tfm.get.room.playerList) do -- pour chaque joueur du salon ...
       if not prop.isDead then -- Si le joueur n'est pas mort/rentré (donc s'il est vivant et sur la carte)
           i = i+1 -- On ajoute 1 au compteur de souris
       end
   end
   return i -- On renvoie le nombre de souris vivantes
end

Une fois qu'on a cette fonction on peut l'appeler quand un joueur meurt ou rentre dans le trou. Deux fonctions se déclenchent lorsqu'un joueur meurt ou rentre : eventPlayerWon pour une souris qui rentre et eventPlayerDied pour une qui meurt.

a dit :
function eventPlayerDied(name)
   if playerLeft() == 0 then -- S'il n'y a plus de joueurs sur la carte ....
       tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une carte au hasard dans la liste
   end
end

function eventPlayerWon(name, timeBegin, timeRes)
   if playerLeft() == 0 then -- Pareil que pour eventPlayerDied
       tfm.exec.newGame( mapList[math.random(#mapList)] ) --
   end
end

Nous devons également changer la carte lorsque le temps restant tombe à zéro. On peut voir le temps restant avec la fonction eventLoop(tempsPasse, tempsRestant) qui se déclenche automatiquement toutes les demie-secondes

a dit :
function eventLoop(timePast, timeLeft) -- timePast et timeLeft sont en millisecondes
   if timeLeft <= 0 then -- S'il reste moins de 0 millisecondes ...
       tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une nouvelle carte de la liste
   end
end

Désormais notre code doit ressembler à ceci :


a dit :
function main() -- Fonction de lancement du module
   tfm.exec.disableAutoNewGame(true) -- Désactivation du changement de cartes
   tfm.exec.disableAutoShaman(true) -- Désactivation des chamanes sur les cartes

   mapList = { 0, 15, 42, 17, 14, 33, 104 } -- Création de la liste de cartes

end



function eventLoop(timePast, timeLeft)
   if timeLeft <= 0 then -- S'il reste moins de 0 millisecondes
       tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une carte de la liste
   end
end

function eventPlayerDied(name)
   if playerLeft() == 0 then -- S'il n'y a plus de joueurs sur la carte ...
       tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une carte de la liste
   end
end

function eventPlayerWon(name, timeBegin, timeRes)
   if playerLeft() == 0 then -- Comme pour eventPlayerDied
       tfm.exec.newGame( mapList[math.random(#mapList)] )
   end
end


function playerLeft()
   local i = 0 -- Compteur de souris
   for _, prop in pairs(tfm.get.room.playerList) do
       if not prop.isDead then -- Si le joueur est encore sur la carte ...
           i = i+1 -- On ajoute 1 au compteur
       end
   end
   return i -- On renvoie le nombre de souris vivantes
end




main() -- On appelle main pour mettre en place les paramètres du jeu.

Vous pouvez déjà lancer ce code en maison de tribu pour vérifier qu'il fonctionne, vous verrez que la carte change toute seule, c'est un code utilisé dans beaucoup de modules qui utilise une rotation de cartes donc vous pouvez vous en resservir pour d'autres mini-jeux.




Étape N°3 : Lancer les esprits


Maintenant que nous pouvons changer les cartes automatiquement on peut s'occuper de permettre aux joueurs de lancer des esprits :)
Les joueurs pourront lancer les esprits en se baissant, il faut donc que l'on soit au courant quand un joueur appuie sur les touches pour se baisser :

On active l'écoute d'une touche avec la fonction tfm.exec.bindKeyboard



a dit :
function eventNewPlayer(name) -- Se déclenche automatiquement quand un joueur entre dans le salon
   tfm.exec.bindKeyboard(name, 39, true, true) -- On écoute la touche 39 (flèche bas)
   tfm.exec.bindKeyboard(name, 83, true, true) -- On écoute la touche 38 (S)

end

for name in pairs(tfm.get.room.playerList) do -- Pour tous les joueurs déjà dans le salon
   eventNewPlayer(name) -- On fait comme s'ils venaient d'entrer pour activer l'écoute des touches du clavier
end

Comme la boucle for de ce code est utilisée uniquement au lancement du module, on peut y rajouter à la fonction main()


a dit :
function main() -- Fonction de lancement du module
   tfm.exec.disableAutoNewGame(true) -- Désactivation du changement de cartes
   tfm.exec.disableAutoShaman(true) -- Désactivation des chamanes sur les cartes

   mapList = { 0, 15, 42, 17, 14, 33, 104 } -- Création de la liste de cartes

   for name in pairs(tfm.get.room.playerList) do -- Pour tous les joueurs déjà dans le salon
       eventNewPlayer(name) -- On fait comme s'ils venaient d'entrer pour activer l'écoute des touches du clavier
   end


end

Dans le "cahier des charges" du jeu, on a dit que le joueur devait pouvoir choisir l'offset de son esprit, il faut donc une table où sauvegarder ces offset et les initialiser en même temps qu'on active l'écoute des touches du clavier :


a dit :
function main() -- Fonction de lancement du module
   tfm.exec.disableAutoNewGame(true) -- Désactivation du changement de cartes
   tfm.exec.disableAutoShaman(true) -- Désactivation des chamanes sur les cartes

   mapList = { 0, 15, 42, 17, 14, 33, 104 } -- Création de la liste de cartes
   offsets = {} -- Création de la table qui contiendra les offsets de chaque joueur.


   for name in pairs(tfm.get.room.playerList) do -- Pour tous les joueurs déjà dans le salon
       eventNewPlayer(name) -- On fait comme s'ils venaient d'entrer pour activer l'écoute des touches du clavier
   end

end


function eventNewPlayer(name) -- Se déclenche automatiquement quand un joueur entre dans le salon
   tfm.exec.bindKeyboard(name, 40, true, true) -- On écoute la touche 39 (flèche bas)
   tfm.exec.bindKeyboard(name, 83, true, true) -- On écoute la touche 38 (S)

   offsets[name] = {x=0, y=10} -- On ajoute l'offset du joueur dans la liste
end

Maintenant qu'on a activé l'écoute des touches, on peut attaquer la mise de l'esprit lorsqu'un joueur se baisse.
Lorsqu'un joueur appuie sur une touche don on a activé l'écoute il active la fonction eventKeyboard, c'est dans celle-ci qu'on va travailler désormais.


Lorsque la fonction eventKeyboard est activé on doit placer un esprit en fonction de son offset, mais seulement s'il est vivant et si la touche qu'il active est bien la flèche du bas ou S :

a dit :
function eventKeyboard(name, key, down, x, y)
   if key==40 or key==83 then -- Si la touche est bien bas ou S
       if not tfm.get.room.playerList[name].isDead then -- Si le joueur est bien vivant
           tfm.exec.addshamanobject(24, x+offsets[name].x, y+offsets[name].y, 0, 0, 0, false) -- On met l'esprit
       end
   end
end

Si vous êtes à l'aise avec les expressions booléennes, vous pouvez réunir les deux boucles if en une seule :

a dit :
function eventKeyboard(name, key, down, x, y)
   if (key==40 or key==83) and not tfm.get.room.playerList[name].isDead then
       tfm.exec.addShamanObject(24, x+offsets[name].x, y+offsets[name].y, 0, 0, 0, false) -- On met l'esprit
   end
end

Il nous manque une dernière chose pour terminer l'étape des esprits. Si vous essayez de lancer le module tel qu'il est pour le moment vous allez vite vous rendre compte que vous n'avez pas besoin d'attendre une seconde pour lancer plusieurs esprits, c'est quelque chose à corriger.


Premièrement on va créer une nouvelle table qui servira à sauvegarder le dernier moment où un joueur a lancé un esprit, puis initialiser cette table pour chaque joueur grâce aux fonctions main et eventNewPlayer :


a dit :
function main() -- Fonction de lancement du module
   tfm.exec.disableAutoNewGame(true) -- Désactivation du changement de cartes
   tfm.exec.disableAutoShaman(true) -- Désactivation des chamanes sur les cartes

   mapList = { 0, 15, 42, 17, 14, 33, 104 } -- Création de la liste de cartes
   offsets = {} -- Création de la table qui contiendra les offsets de chaque joueur.
   lastSpirit = {} -- Création de la table qui contiendra l'heure à laquel chaque joueur a lancé un esprit

   for name in pairs(tfm.get.room.playerList) do -- Pour tous les joueurs déjà dans le salon
       eventNewPlayer(name) -- On fait comme s'ils venaient d'entrer pour activer l'écoute des touches du clavier
   end

end


function eventNewPlayer(name) -- Se déclenche automatiquement quand un joueur entre dans le salon
   tfm.exec.bindKeyboard(name, 40, true, true) -- On écoute la touche 39 (flèche bas)
   tfm.exec.bindKeyboard(name, 83, true, true) -- On écoute la touche 38 (S)

   offsets[name] = {x=0, y=10} -- On ajoute l'offset du joueur dans la liste
   lastSpirit[name] = os.time() -- renvoie l'heure au moment de l'appel en millisecondes.
end

On peut maintenant ajouter une condition au lancement d'un esprit dans la fonction eventKeyboard : le dernier esprit qu'a lancé le joueur doit dater d'au moins une seconde.



a dit :
function eventKeyboard(name, key, down, x, y)
   if (key==40 or key==83) and not tfm.get.room.playerList[name].isDead and os.time()-lastSpirit[name]>=1000 then
       tfm.exec.addShamanObject(24, x+offsets[name].x, y+offsets[name].y, 0, 0, 0, false) -- On met l'esprit
       lastSpirit[name] = os.time() -- On sauvegarde l'heure où on lance l'esprit
   end
end

Le code du module est maintenant :





a dit :
function main() -- Fonction de lancement du module
   tfm.exec.disableAutoNewGame(true) -- Désactivation du changement de cartes
   tfm.exec.disableAutoShaman(true) -- Désactivation des chamanes sur les cartes

   mapList = { 0, 15, 42, 17, 14, 33, 104 } -- Création de la liste de cartes
   offsets = {} -- Création de la table qui contiendra les offsets de chaque joueur.
   lastSpirit = {} -- Création de la table qui contiendra l'heure à laquel chaque joueur a lancé un esprit

   for name in pairs(tfm.get.room.playerList) do -- Pour tous les joueurs déjà dans le salon
       eventNewPlayer(name) -- On fait comme s'ils venaient d'entrer pour activer l'écoute des touches du clavier
   end

end


function eventNewPlayer(name) -- Se déclenche automatiquement quand un joueur entre dans le salon
   tfm.exec.bindKeyboard(name, 40, true, true) -- On écoute la touche 39 (flèche bas)
   tfm.exec.bindKeyboard(name, 83, true, true) -- On écoute la touche 38 (S)

   offsets[name] = {x=0, y=10} -- On ajoute l'offset du joueur dans la liste
   lastSpirit[name] = os.time() -- renvoie l'heure au moment de l'appel en millisecondes.
end


function eventKeyboard(name, key, down, x, y)
   if (key==40 or key==83) and not tfm.get.room.playerList[name].isDead and os.time()-lastSpirit[name]>=1000 then
       tfm.exec.addShamanObject(24, x+offsets[name].x, y+offsets[name].y, 0, 0, 0, false) -- On met l'esprit
       lastSpirit[name] = os.time() -- On sauvegarde l'heure où on lance l'esprit
   end
end


function eventLoop(timePast, timeLeft)
   if timeLeft <= 0 then -- S'il reste moins de 0 millisecondes
       tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une carte de la liste
   end
end

function eventPlayerDied(name)
   if playerLeft() == 0 then -- S'il n'y a plus de joueurs sur la carte ...
       tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une carte de la liste
   end
end

function eventPlayerWon(name, timeBegin, timeRes)
   if playerLeft() == 0 then -- Comme pour eventPlayerDied
       tfm.exec.newGame( mapList[math.random(#mapList)] )
   end
end


function playerLeft()
   local i = 0 -- Compteur de souris
   for _, prop in pairs(tfm.get.room.playerList) do
       if not prop.isDead then -- Si le joueur est encore sur la carte ...
           i = i+1 -- On ajoute 1 au compteur
       end
   end
   return i -- On renvoie le nombre de souris vivantes
end


main()

Vous pouvez déjà utiliser ce code, il contient la majorité des fonctionnalités qu'on voulait. Il ne manque plus que la possibilité pour le joueur de changer l'offset de leur esprit.




Étape N°4 : modification de l'offset


Il y a plusieurs moyen pour qu'un joueur modifie sont offset, le plus simple est de passer pas une commande du tchat grace à la fonction eventChatCommand qui s'active lorsqu'un joueur tape un message qui commence par '!' comme !Peluche ou !coucou
la commande devrait être "!offset x y" avec x et y les coordonnées de l'offset (!offset -5 10 par exemple)



Pour pouvoir reconnaitre la commande on va utiliser la fonction string.gmatch(texte, pattern), je vous invite à lire le chapitre sur les strings pour comprendre ce qu'on va faire.

a dit :
function eventChatCommand(name, command) -- Se déclenche à chaque message commençant par '!'
   local nextWord = string.gmatch(command, '%S+') -- on sauvegarde la fonction qui renverra les mots de command
   local word1 = nextWord()
   if word1 == "offset" then -- si le premier mot est la commande "offset"
       local a, b = tonumber(nextWord()), tonumber(nextWord()) -- on sauvegarde l'x et l'y du nouvel offset sous forme de nombre
       offsets[name] = { x = a and math.abs(a)<30 and a or offsets[name].x, y = b and math.abs(b)<30 and b or offsets[name].y }
   end
end

Si vous avez eu du mal avec cette ligne :
offsets[name] = { x = a and math.abs(a)<30 and a or offsets[name].x, y = b and math.abs(b)<30 and b or offsets[name].y }
c'est normal, elle fait beaucoup de choses à la fois et il faut la lire attentivement pour bien comprendre ce qu'elle fait.

x = a and math.abs(a)<30 and a or offsets[name].x
Cette petite ligne est l'équivalent de :

a dit :
if a ~= nil then -- si 'a' a une valeur
   if math.abs(a) < 30 then -- si a est entre -30 et 30
       x = a -- alors on met la valeur de a dans x
   else
       x = x -- sinon on ne change pas la valeur de x
   end
else
   x = x -- sinon on ne change pas la valeur de x
end

De même pour l'expression "y = b and math.abs(b)<30 and b or offsets[name].y"
Avec ces expressions réduites, on exploite efficacement les opérateurs and et or


Voila, il ne reste plus qu'à ajouter cette fonction la suite du code pour que le module soit terminé

a dit :
function main() -- Fonction de lancement du module
    tfm.exec.disableAutoNewGame(true) -- Désactivation du changement de cartes
    tfm.exec.disableAutoShaman(true) -- Désactivation des chamanes sur les cartes

    mapList = { 0, 15, 42, 17, 14, 33, 104 } -- Création de la liste de cartes
    offsets = {} -- Création de la table qui contiendra les offsets de chaque joueur.
    lastSpirit = {} -- Création de la table qui contiendra l'heure à laquel chaque joueur a lancé un esprit

    for name in pairs(tfm.get.room.playerList) do -- Pour tous les joueurs déjà dans le salon
            eventNewPlayer(name)    -- On fait comme s'ils venaient d'entrer pour activer l'écoute des touches du clavier
    end

end


function eventNewPlayer(name) -- Se déclenche automatiquement quand un joueur entre dans le salon
    tfm.exec.bindKeyboard(name, 40, true, true) -- On écoute la touche 39 (flèche bas)
    tfm.exec.bindKeyboard(name, 83, true, true) -- On écoute la touche 38 (S)

    offsets[name] = {x=0, y=10} -- On ajoute l'offset du joueur dans la liste
    lastSpirit[name] = os.time() -- renvoie l'heure au moment de l'appel en millisecondes.
end


function eventKeyboard(name, key, down, x, y)
    if (key==40 or key==83) and not tfm.get.room.playerList[name].isDead and os.time()-lastSpirit[name]>=1000 then
            tfm.exec.addShamanObject(24, x+offsets[name].x, y+offsets[name].y, 0, 0, 0, false) -- On met l'esprit
            lastSpirit[name] = os.time() -- On sauvegarde l'heure où on lance l'esprit
    end
end


function eventLoop(timePast, timeLeft)
    if timeLeft <= 0 then -- S'il reste moins de 0 millisecondes
            tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une carte de la liste
    end
end

function eventPlayerDied(name)
    if playerLeft() == 0 then -- S'il n'y a plus de joueurs sur la carte ...
            tfm.exec.newGame( mapList[math.random(#mapList)] ) -- On lance une carte de la liste
    end
end

function eventPlayerWon(name, timeBegin, timeRes)
    if playerLeft() == 0 then -- Comme pour eventPlayerDied
            tfm.exec.newGame( mapList[math.random(#mapList)] )
    end
end


function playerLeft()
    local i = 0 -- Compteur de souris
    for _, prop in pairs(tfm.get.room.playerList) do
            if not prop.isDead then -- Si le joueur est encore sur la carte ...
                    i = i+1 -- On ajoute 1 au compteur
            end
    end
    return i -- On renvoie le nombre de souris vivantes
end


function eventChatCommand(name, command) -- Se déclenche à chaque message commençant par '!'
local nextWord = string.gmatch(command, '%S+') -- on sauvegarde la fonction qui renverra les mots de command
local word1 = nextWord()
if word1 == "offset" then -- si le premier mot est la commande "offset"
    local a, b = tonumber(nextWord()), tonumber(nextWord()) -- on sauvegarde l'x et l'y du nouvel offset sous forme de nombre
    offsets[name] = { x = a and math.abs(a)<30 and a or offsets[name].x, y = b and math.abs(b)<30 and b or offsets[name].y }
end
end


main()

Dernière modification le 1605371760000
Elyolucas
« Consul »
1414938900000
    • Elyolucas#0000
    • Profil
    • Derniers messages
#3
  1
Pour le moment, je suis un peu trop débutant en LUA, je me consacrerais au Module plus tard.

En tout cas ça à l'air d'être compliqué et très long à apprendre, j'espère y arriver un jour ! ^^
Un topic très bien présenter tout de même, je n'est pas eu le courage de tout lire, mais un ptit peu quand même, j'espère que ce sera utile pour les autres personnes. ^^
Ski
« Censeur »
1415036220000
    • Ski#5535
    • Profil
    • Derniers messages
#4
  1
Bof Notepad++..

Autant faire télécharger Sublime Text, il est plus joli et on s'y repère beaucoup mieux dans un long code..

Sinon gg le topic

Dernière modification le 1415036280000
Ausecourr
« Citoyen »
1415045700000
    • Ausecourr#0000
    • Profil
    • Derniers messages
#5
  0
Bien joué le topic! Si tu as le temps d'expliquer un peu comment tu fais pour faire une interface graphique comme pour ton snake ça m'intéresserait beaucoup :)
Meeyo
« Citoyen »
1415132520000
    • Meeyo#0095
    • Profil
    • Derniers messages
    • Tribu
#6
  0
Bravo pour ce sujet !
Elyolucas
« Consul »
1415133840000
    • Elyolucas#0000
    • Profil
    • Derniers messages
#7
  0
C'est dommage qu'il ne soit pas plus actif, il aurait peut-être plus être épinglé, qui sais.
Arkuo
« Citoyen »
1415175600000
    • Arkuo#9521
    • Profil
    • Derniers messages
    • Tribu
#8
  0
Bravo ! J'demande a ce qui soit épingle hein !
Meeyo
« Citoyen »
1415181120000
    • Meeyo#0095
    • Profil
    • Derniers messages
    • Tribu
#9
  0
Bathchaboom a dit :
Bravo ! J'demande a ce qui soit épingle hein !

Voeu exaucé :)

Bravo Podoko pour ce très bon travail !

Dernière modification le 1415182560000
Arkuo
« Citoyen »
1415184840000
    • Arkuo#9521
    • Profil
    • Derniers messages
    • Tribu
#10
  0
Ouiii !
Elyolucas
« Consul »
1415188860000
    • Elyolucas#0000
    • Profil
    • Derniers messages
#11
  0
EPINGLER EPINGLER !
Podoko
« Citoyen »
1415262780000
    • Podoko#0000
    • Profil
    • Derniers messages
    • Tribu
#12
  0
Owi un topic épinglé ! Merci à tous \o/

Pour le choix Notepad++/Sublime_Text, les deux se valent à mes yeux mais j'ai l'habitude de travailler sur Notepad++ et il est facile à mettre en français. (en soit prendre l'un ou l'autre fait de grande différence)
Pour le Snake, je verrai si j'ai le temps d'écrire comment il est fait, c'est juste une série de textArea bien placés avec un fond transparent. ^^'
Redstarz
« Censeur »
1415292660000
    • Redstarz#0000
    • Profil
    • Derniers messages
#13
  0
Dans la catégorie "Opérateurs", il y a une petite faute à "nombre que tu as écrit sans -s (juste avant les Opérateurs de comparaison )
Je suis en train de lire, ça m'intéresse vraiment et tu explique super bien :D
Linkaito
« Consul »
1415305380000
    • Linkaito#0095
    • Profil
    • Derniers messages
    • Tribu
#14
  1
Oh j'avais pas vu le topic, bravo ! Il me servira certainement \o/
Ski
« Censeur »
1415306580000
    • Ski#5535
    • Profil
    • Derniers messages
#15
  0
podoko a dit :
Owi un topic épinglé ! Merci à tous \o/

Pour le choix Notepad++/Sublime_Text, les deux se valent à mes yeux mais j'ai l'habitude de travailler sur Notepad++ et il est facile à mettre en français. (en soit prendre l'un ou l'autre fait de grande différence)
Pour le Snake, je verrai si j'ai le temps d'écrire comment il est fait, c'est juste une série de textArea bien placés avec un fond transparent. ^^'

Il y a un plugin LUA Transformice pour sublime text qui permet de coder plus vite et de ne pas tout apprendre par coeur.
Pourquoi mettre Sublime text en français ? C'est inutile !

Sachant que sur sublime on s'y retrouve beaucoup mieux :s
Mcfloy
« Citoyen »
1415390880000
    • Mcfloy#0000
    • Profil
    • Derniers messages
    • Tribu
#16
  0
Un beau tutoriel, félicitations pour le travail fourni.

Simple et complet, c'est exactement ce genre de topic qu'il manquait. :-)
Elyolucas
« Consul »
1415392140000
    • Elyolucas#0000
    • Profil
    • Derniers messages
#17
  0
mcfloy a dit :
Un beau tutoriel, félicitations pour le travail fourni.

Simple et complet, c'est exactement ce genre de topic qu'il manquait. :-)

Totalement d'accord, cependant, malgré qu'il soit bien expliquer, le Lua reste assez compliqué pour les vraiment débutants. Il faudrait peut-être des personnes attitrées pour apprendre le lua au personnes postulants, je sais pas trop. :')
Nicolasledu
« Citoyen »
1415450280000
    • Nicolasledu#0000
    • Profil
    • Derniers messages
    • Tribu
#18
  0
elyolucas a dit :
mcfloy a dit :
Un beau tutoriel, félicitations pour le travail fourni.

Simple et complet, c'est exactement ce genre de topic qu'il manquait. :-)

Totalement d'accord, cependant, malgré qu'il soit bien expliquer, le Lua reste assez compliqué pour les vraiment débutants. Il faudrait peut-être des personnes attitrées pour apprendre le lua au personnes postulants, je sais pas trop. :')

Le lua est quand même un des langages les plus faciles :/
Elyolucas
« Consul »
1415465460000
    • Elyolucas#0000
    • Profil
    • Derniers messages
#19
  0
C'est pour le comprendre que j'ai du mal.

Toutes les directives à employer (Du moins, je l'appel comme ça) sont assez longues et compliquées quand on a personne pour nous aidés, c'est pourquoi, même avec ce topic, cela reste compliqué dans aide d'une personne en jeu, ou extérieur.
Arkuo
« Citoyen »
1415475360000
    • Arkuo#9521
    • Profil
    • Derniers messages
    • Tribu
#20
  0
Elyolucas, je peux t'aider si tu le souhaites.

@Nicolasledu Non, c'est loin d'être le plus facile, c'est le HTML qui est a porté de tous.
  • Forums
  • /
  • Transformice
  • /
  • Modules
  • /
  • [Tutoriel] Syntaxe lua et exemple de module
1 / 6 › »
© Atelier801 2018

Equipe Conditions Générales d'Utilisation Politique de Confidentialité Contact

Version 1.27