Un dialogue PNJ Metin2 commence dès qu'un joueur ouvre la fenêtre de discussion avec un PNJ, et bien conçu, il ressemble à une petite histoire. Afficher une seule ligne de texte est facile ; le vrai travail consiste à proposer des choix au joueur et à ramifier la conversation selon la décision qu'il prend. Dans cet article, je détaille pas à pas la création de menus à choix multiples avec select, de fenêtres oui/non avec confirm, et la façon de les combiner dans une quête Lua propre et fonctionnelle.
Le squelette de base d'un dialogue
Chaque conversation avec un PNJ s'ouvre avec un déclencheur chat. Tu indiques le vnum du PNJ, tu donnes un titre à la fenêtre et tu déroules le texte ligne par ligne avec les fonctions say.
quest dialogue_villageois begin
state start begin
when 9003.chat."Parler au villageois" begin
say_title("Vieux villageois")
say("Bienvenue, voyageur.")
say("")
say("Qu'est-ce qui t'amène ici ?")
end
end
end
Ici, 9003 est le vnum du PNJ, say_title est l'en-tête de la fenêtre de dialogue, et say est le corps du texte. Un say("") vide sert à laisser une ligne blanche. Ce bloc est à sens unique : le joueur se contente de lire et clique sur « Fermer ». Pour ajouter de l'interaction, il faut passer aux mécanismes de sélection.
Menus à choix multiples avec select
select affiche au joueur une liste de boutons et renvoie l'indice de l'option choisie (à partir de 1). Tu récupères la valeur renvoyée dans une variable et tu ramifies avec if / elseif.
when 9003.chat."Parler au villageois" begin
say_title("Vieux villageois")
say("Comment puis-je t'aider ?")
say("")
local choix = select("Donne-moi une quête", "Acheter des biens", "Raconte ton histoire", "Laisse tomber")
if choix == 1 then
say("Alors écoute : débarrasse la forêt des loups.")
elseif choix == 2 then
say("Hélas, il ne me reste rien à vendre.")
elseif choix == 3 then
say("Il y a des années, ce village était bien différent...")
else
say("Bon voyage.")
end
end
Quelques points à surveiller : en pratique, select reste confortable jusqu'à 6-7 options ; au-delà, elles ne tiennent plus dans la fenêtre de dialogue. Faire de la dernière option une sortie « Laisse tomber » est une bonne habitude, pour que le joueur ne reste jamais coincé dans le menu. Stocke toujours la valeur renvoyée dans une variable local, car si tu appelles un second select, la valeur précédente est perdue.
Confirmation oui/non avec confirm
Avant une action irréversible (supprimer un objet, se téléporter, dépenser des yang), tu veux demander confirmation au joueur. confirm("texte") sert exactement à cela : il ouvre une fenêtre « Oui / Non » au joueur et renvoie true s'il accepte et false s'il refuse.
when 9003.chat."Se téléporter en ville" begin
say_title("Vieux villageois")
say("Veux-tu que je t'envoie en ville ?")
say("Cela coûte 50 000 yang.")
say("")
if confirm("Veux-tu te téléporter en ville ?") then
if pc.get_money() >= 50000 then
pc.change_money(-50000)
pc.warp(469000, 964000)
else
say("Tu n'as pas assez de yang.")
end
else
say("Une autre fois peut-être.")
end
end
confirm peut être utilisé directement dans une condition if puisqu'il renvoie un booléen. Certaines versions proposent aussi confirm_with_button("question", "Libellé oui", "Libellé non") pour un texte de bouton personnalisé ; cependant, comme sa disponibilité dépend de ta source, reste sur le confirm standard si tu veux préserver la portabilité.
Enchaîner select et confirm
La vraie puissance apparaît quand tu imbriques les deux. Le joueur choisit d'abord dans un menu select, puis valide sa décision finale avec confirm à l'étape critique. Voici un exemple de PNJ coffre à récompenses :
when 9003.chat."Coffre à récompenses" begin
say_title("Coffre mystérieux")
say("Choisis une récompense à l'intérieur, mais sois prudent.")
say("Aucun retour en arrière après ton choix.")
say("")
local recompense = select("Épée", "Armure", "Yang", "Plus tard")
if recompense == 4 then
say("Le coffre s'est refermé.")
return
end
if not confirm("Es-tu sûr de ton choix ?") then
say("Tu as hésité un instant devant le coffre.")
return
end
if recompense == 1 then
pc.give_item2(11209, 1)
say("Tu as gagné une épée tranchante !")
elseif recompense == 2 then
pc.give_item2(11949, 1)
say("Tu as gagné une armure solide !")
elseif recompense == 3 then
pc.change_money(500000)
say("Tu as gagné 500 000 yang !")
end
end
Trois techniques fonctionnent ensemble ici : select détermine la branche, un return anticipé gère proprement le cas « plus tard », et confirm place une dernière barrière de sécurité avant de remettre la récompense irréversible. Utiliser return évite les imbrications profondes de if et garde le code lisible.
Rendre le texte dynamique
Le texte statique devient vite ennuyeux. Pour insérer le nom du joueur, son niveau ou le nombre d'objets dans le texte, utilise la concaténation de chaînes à l'intérieur de say. En Lua, l'opérateur de concaténation est deux points (..).
when 9003.chat."Saluer" begin
say_title("Vieux villageois")
say("Bonjour "..pc.get_name()..", content de te voir.")
say("Tu es niveau "..pc.get_level()..", tu as progressé vite.")
end
Ainsi, le même dialogue paraît personnel à chaque joueur. Quand tu insères des valeurs numériques (pc.get_level()) dans le texte, Lua les convertit automatiquement, tu n'as même pas besoin d'appeler tostring().
Erreurs courantes et astuces
- Oublier de vérifier le résultat de select : le joueur peut fermer la fenêtre avec ÉCHAP ; définis une branche pour chaque option plus une sortie « laisse tomber ».
- Écrire confirm comme un simple if et oublier les parenthèses :
confirm(...)a toujours besoin d'un argument texte, ne le laisse pas vide. - Chaînes de say trop longues : après 4-5 lignes, affiche un bouton « Continuer » avec
wait(); sinon la fenêtre de texte déborde. - Caractères spéciaux : enregistre les fichiers de quête dans l'encodage attendu par le serveur (généralement UTF-8 ou la locale correspondante) ; un mauvais encodage apparaît comme des caractères corrompus dans le dialogue.
- N'oublie pas de compiler et de recharger la quête après une modification ; sinon le game core continue d'afficher l'ancien texte.
Questions fréquentes
Combien d'options select prend-il en charge ?
Il n'y a pas de limite technique stricte, mais en pratique 6-7 options tiennent confortablement dans la fenêtre de dialogue. Si tu en as besoin de plus, répartis les options en catégories : affiche les groupes dans le premier menu, puis ouvre un second select selon le groupe choisi. C'est plus propre et reste lisible.
Puis-je changer le texte des boutons de la fenêtre confirm ?
Le confirm standard utilise des boutons « Oui/Non » fixes. Certaines sources incluent une version étendue qui permet de définir un texte de bouton personnalisé, mais cela dépend de ta version. Pour la portabilité, le plus sûr est de formuler clairement la vraie question avec say et de garder confirm simple.
Puis-je utiliser le résultat de select directement dans un if ?
Tu peux, mais ce n'est pas recommandé. select affiche le menu et renvoie la valeur ; si tu répètes le même appel dans deux branches if, le menu s'ouvre deux fois. Récupère plutôt le résultat dans une variable local, puis compare cette variable.
Bloqué sur les dialogues PNJ ? Si tu as besoin d'aide pour des chaînes de quêtes ramifiées, des systèmes de dialogue à plusieurs étapes ou la conception de menus pour ton serveur, contacte-moi — construisons-le ensemble.