Un système d'arène Metin2 est un contenu PvP personnalisé où les joueurs s'affrontent en duels 1v1 sûrs et équitables, avec un vainqueur désigné à la fin. Dans ce guide, je montre comment construire une arène de duel de zéro avec le moteur de quêtes Lua : apparier les joueurs, téléporter la paire dans une carte isolée, activer le PvP uniquement entre ces deux-là, détecter le vainqueur et — si tu le souhaites — relier le tout à un arbre de tournoi. Le but n'est pas de coller du code fini, mais de comprendre les rouages pour adapter le système à ton propre serveur.
Comment fonctionne une arène ?
Une arène de duel est essentiellement une machine à états qui répond à trois questions : qui combat qui, où ils combattent et qui a gagné. Dans Metin2, la solution la plus propre est de sortir le combat de la carte commune et de le jouer dans sa propre instance de carte. Ainsi les deux adversaires sont protégés de toute interférence extérieure, aucun autre joueur ne peut perturber le match, et la téléportation de victoire/défaite reste nette.
- Un PNJ ou un objet d'inscription — le joueur interagit avec lui pour rejoindre la file/l'appariement.
- Une file d'attente — la liste des joueurs en attente d'appariement ; au plus simple, une paire de flags globaux.
- Un index de carte d'arène — le numéro de la carte vide, défini dans le fichier
index, où se joue le duel. - Des flags d'état — qui est en file, qui est en match et qui a gagné, stockés avec
pc.setqfet le globalset_quest_flag.
La distinction clé : les données par joueur (ce joueur est-il en match, quel est l'id de l'adversaire) vont dans pc.setqf ; les données globales du serveur (y a-t-il quelqu'un en file) vont dans set_quest_flag. Metin2 possède bien une fonction de duel (challenge) intégrée, mais c'est un affrontement à ciel ouvert ; pour une arène isolée, contrôlée et prête pour les tournois, construire ton propre système basé sur les quêtes est bien plus souple.
Apparier les joueurs (matchmaking)
La première partie de l'arène est la file. Quand un joueur parle au PNJ d'inscription, il est apparié avec celui qui attend déjà ; s'il n'y a personne, il entre lui-même dans la file. L'appariement le plus simple utilise un unique flag global qui contient « l'id du joueur en attente » :
quest arena_inscription begin
state start begin
when 20399.chat."Rejoindre l'arene" begin
local mon_id = pc.get_player_id()
local en_attente = get_quest_flag("arena.en_attente_pid")
if en_attente == 0 then
-- file vide : mettre ce joueur en attente
set_quest_flag("arena.en_attente_pid", mon_id)
pc.setqf("arena_etat", 1) -- 1 = en file
say("Attends pendant qu'on cherche un adversaire...")
return
end
if en_attente == mon_id then
say("Tu es deja dans la file.")
return
end
-- adversaire trouve : vider la file et lancer le combat
set_quest_flag("arena.en_attente_pid", 0)
arena_demarrer(en_attente, mon_id)
end
end
end
Ici get_player_id() renvoie l'id unique du joueur ; il reste identique même quand le joueur change de carte, c'est donc une clé sûre pour apparier les adversaires. arena_demarrer est notre propre fonction d'aide qui prend les deux id et met en place le combat. Sur un vrai serveur, tu ajouterais aussi une restriction de niveau/équipement à la file, ou une vérification que le joueur en attente est toujours en ligne.
Téléporter dans une carte d'arène isolée
Une fois l'appariement trouvé, on déplace les deux joueurs dans une instance d'arène toute neuve. d.new_jump_all crée une nouvelle instance de carte et y téléporte le joueur appelant ; pour faire entrer le second joueur dans la même instance, on cible son pid et on le téléporte vers le même index de carte. Un court compte à rebours avant le match laisse aux deux joueurs un instant pour se préparer :
function arena_demarrer(pid1, pid2)
-- ecrire l'adversaire et l'etat sur les deux joueurs
pc.select_pc(pid1)
pc.setqf("arena_etat", 2) -- 2 = en match
pc.setqf("arena_adversaire", pid2)
-- methode pratique : instance partagee + deux teleports :
-- d'abord creer la nouvelle instance avec un joueur, puis
-- teleporter l'autre vers la meme carte via son pid.
end
En pratique, la méthode la plus robuste est : appeler d.new_jump_all(ARENA_MAP_INDEX, x, y) avec un joueur pour créer l'instance, puis sélectionner le second joueur avec pc.select_pc(pid2) et le téléporter au second point d'apparition de cette même instance. N'oublie pas que les coordonnées sont les coordonnées locales de la carte — place les deux joueurs aux coins opposés pour que le combat démarre équitablement. Un petit compte à rebours « 3... 2... 1... Combat ! » via server_timer après le téléport améliore nettement l'expérience.
Activer le PvP entre ces deux-là uniquement
Le point crucial de l'arène est que le combat se déroule uniquement entre les deux joueurs appariés. La méthode la plus fiable est de configurer l'arène comme une carte PvP libre : dans les réglages de carte, tu marques ce map_index comme PvP activé, ainsi tout le monde dans l'arène peut attaquer — et tu garantis l'isolement en ne laissant entrer que deux joueurs par instance. Côté quête, tu t'assures que les joueurs peuvent frapper sans être bloqués par les flags de guilde / guerre de guilde qui régissent les cartes ouvertes.
-- quand un joueur entre dans la carte d'arene
when <ARENA_MAP_INDEX>.enter begin
pc.setqf("arena_etat", 2)
-- bloquer la fuite : verrouiller les objets de teleport / protections
pc.remove_affect(...) -- retirer les effets de protection indesirables
syschat("Tu es dans l'arene 1v1. Bonne chance !")
end
Si tu as accès à la source, la solution la plus propre est d'ajuster une vérification comme CHARACTER::IsAttackableMap pour ouvrir le map_index de l'arène et de désactiver les règles de zone de paix à l'intérieur. Sans toucher à la source, tu peux quand même gérer cela avec une approche purement quête en marquant la carte comme PvP libre et en t'appuyant sur l'isolement ; pour les petits et moyens serveurs, c'est largement suffisant.
Détecter le vainqueur
Un duel se termine quand un camp meurt. Dans le moteur de quêtes Metin2, le déclencheur when dead s'exécute dans le contexte du joueur qui est mort ; c'est là que tu marques ce joueur comme « perdant » et son adversaire comme « vainqueur ». Grâce à l'id de l'adversaire stocké dans pc.setqf("arena_adversaire"), on connaît directement le vainqueur :
when dead with pc.getqf("arena_etat") == 2 begin
local perdant = pc.get_player_id()
local vainqueur = pc.getqf("arena_adversaire")
-- nettoyer le perdant et le teleporter dehors
pc.setqf("arena_etat", 0)
pc.setqf("arena_adversaire", 0)
pc.warp(VILLE_X * 100, VILLE_Y * 100)
-- selectionner le vainqueur, recompenser et teleporter dehors
if pc.select_pc(vainqueur) then
pc.setqf("arena_etat", 0)
pc.setqf("arena_adversaire", 0)
notice_all(pc.get_name() .. " a gagne l'arene !")
pc.give_item2(50300, 1) -- recompense ex. : un trophee/objet
pc.warp(VILLE_X * 100, VILLE_Y * 100)
end
end
Attention : pc.warp attend des coordonnées de monde multipliées par 100 (coordonnée de case en jeu × 100), tandis que la téléportation en instance utilise des coordonnées locales — confondre les deux est l'erreur la plus fréquente des débutants. Par ailleurs, pour qu'une déconnexion ne soit pas une échappatoire, ajoute une règle « si tu es en match, ton adversaire gagne » dans when logout ; sinon les joueurs sur le point de perdre peuvent débrancher pour effacer le résultat.
Relier à un arbre de tournoi
Une fois le duel unique fonctionnel, un tournoi n'est que la même logique répétée : les vainqueurs passent au tour suivant, les perdants sont éliminés. Tu gardes les id des participants dans des flags séquentiels (arena.tour1_0, arena.tour1_1, ...), tu écris le vainqueur de chaque match dans la liste du tour suivant à sa fin, et tu reconstruis les appariements quand le tour est complet.
- Fenêtre d'inscription : accepte les inscriptions pendant une durée définie avant le début du tournoi ; fige la liste à la fermeture.
- Nombre impair (bye) : si le nombre d'inscrits est impair, donne à l'un un passage automatique (bye) ; calcule-le en construisant la liste.
- Matchs séquentiels : tu peux jouer un seul match à la fois et garder l'arène occupée, ou ouvrir plusieurs instances et jouer les tours en parallèle.
- Récompense finale : donne un costume, un titre ou un prix en yang spécial uniquement au vainqueur du dernier match.
En pilotant le tournoi avec un server_timer, tu peux lui donner un rythme du type « construire les appariements du tour toutes les 5 minutes ». Comme la logique est identique à celle d'un duel unique, une fois un solide noyau 1v1 en place, le tournoi n'est qu'une coquille tissée autour de ce noyau.
Erreurs fréquentes
- Confusion de coordonnées : case × 100 pour
pc.warp, coordonnées locales pour les téléports en instance. Les confondre fait tomber le joueur hors de la carte. - Exploit de déconnexion : sans règle
when logout, un joueur sur le point de perdre peut se déconnecter pour effacer le résultat. Traite la déconnexion comme « l'adversaire gagne ». - Fuite d'instances : si les deux joueurs ne quittent pas à la fin du match, des instances d'arène vides s'accumulent. Ferme les chemins de mort et de sortie avec
warp. - Nettoyage des flags : si tu ne réinitialises pas les flags
arena_etatetarena_adversaireà la fin d'un match, le joueur entre dans son match suivant dans un état « inachevé » et le système casse.
Questions fréquentes
Le système de duel intégré de Metin2 ne suffit-il pas ?
Le challenge intégré est un combat sur la carte ouverte, au vu de tous et exposé aux interférences. Si tu veux une arène isolée, un départ équitable, une récompense au vainqueur et surtout un tournoi, ta propre arène basée sur les quêtes est bien plus contrôlée et souple. Tu peux aussi proposer les deux côte à côte.
Peut-on construire une arène sans toucher à la source ?
Oui, dans la plupart des cas. Si tu marques la carte d'arène comme PvP libre et ne laisses entrer que deux joueurs par instance, tu obtiens un système 1v1 qui tourne sur une logique purement quête. Pour des règles PvP très fines (par ex. retirer de force certains affects), l'accès à la source facilite les choses, mais ce n'est pas obligatoire.
Combien de matchs peuvent tourner en même temps ?
Comme chaque match tourne dans sa propre instance de carte, la limite théorique est ton matériel ; chaque instance consomme mémoire et CPU. Sur des serveurs petits à moyens, des dizaines de matchs simultanés ne posent aucun problème. Lors de tournois très chargés, il est plus sûr de plafonner le nombre d'instances et de mettre les matchs en file.
Tu veux une arène équitable, isolée et à l'épreuve des abus pour ton serveur ? De la file d'appariement à la carte de duel isolée, de la détection du vainqueur à un arbre de tournoi complet, je peux construire et tester tout le système. Pour parler de ton projet, contacte-moi.