Le Metin2 quest timer est l'une des parties les plus puissantes — et les plus souvent mal utilisees — du systeme de quetes : il permet de declencher un evenement non pas instantanement, mais apres un delai defini. Que vous vouliez une quete a compte a rebours, un avertissement qui se repete a intervalles, un delai de reapparition de boss, ou un cooldown du type "vous pouvez reclamer cette recompense une fois toutes les 24 heures", les minuteurs sont au coeur de tout cela. Dans cet article, nous allons parcourir pas a pas les deux mecanismes principaux du moteur de quetes Metin2 — le q.start_timer lie au joueur et le server_timer global — avec des exemples reels et fonctionnels.
Qu'est-ce qu'un quest timer et comment fonctionne-t-il ?
Le moteur de quetes est evenementiel : les blocs when ... begin ... end reagissent a des evenements precis (dialogue, kill, connexion). Un minuteur ajoute un "delai" a cette logique. Quand vous demarrez un minuteur, le moteur l'enregistre, et a son expiration il leve un evenement special — que vous attrapez a nouveau avec un bloc when. Il en existe deux types :
- Minuteur lie au joueur (
q.start_timer) : le minuteur appartient a un personnage precis. Quand il se declenche, le bloc s'execute dans le contexte de ce joueur, vous pouvez donc appeler directement les fonctionspc.*. - Minuteur serveur global (
server_timer) : le minuteur appartient au serveur, pas a un joueur. Il est ideal pour des taches non liees a quelqu'un, comme les reapparitions de boss ou les evenements de carte.
Un minuteur lie au joueur avec q.start_timer
C'est le scenario le plus courant : un joueur parle a un PNJ, et X secondes plus tard quelque chose se produit. Vous le demarrez avec q.start_timer("nom", secondes) et attrapez le resultat dans un bloc when nom.timer.
quest boite_cadeau begin
state start begin
when 20095.chat."Ouvrir la boite" begin
say_title("Marchand :")
say("La boite s'ouvrira dans 10 secondes, attends...")
q.start_timer("ouvrir_boite", 10)
end
when ouvrir_boite.timer begin
say("La boite s'est ouverte ! Voici ta recompense.")
pc.give_item2(27003, 1) -- vnum d'item d'exemple
pc.give_exp2(5000)
end
end
end
Le point cle : le bloc ouvrir_boite.timer s'execute deja dans le contexte du bon joueur, car nous avons demarre le minuteur pour ce joueur. Si vous rappelez q.start_timer avec un nom deja existant, l'ancien est remplace par le nouveau, ce qui evite commodement un double declenchement accidentel.
Evenements differes globaux avec server_timer
Supposons que vous vouliez qu'un boss reapparaisse une heure apres sa mort. Cela n'a rien a voir avec un joueur precis, vous utilisez donc server_timer. La signature est server_timer("nom", secondes, arg). Vous pouvez passer un VID ou un nombre en troisieme parametre et le relire avec get_server_timer_arg() au declenchement.
quest reapparition_boss begin
state start begin
when 6091.kill begin
-- Le boss est mort, reapparition dans 1 heure
local map_index = pc.get_map_index()
server_timer("retour_boss", 60 * 60, map_index)
notice_all("Le boss est tombe ! Il reviendra dans 1 heure.")
end
when retour_boss.server_timer begin
local map_index = get_server_timer_arg()
regen_in_map(map_index, "data/boss_regen.txt")
notice_all("Le boss est reapparu !")
end
end
end
A l'interieur d'un bloc server_timer, il n'y a pas de contexte joueur par defaut. Si vous devez agir sur un joueur precis, transportez son PID via l'argument et utilisez le motif q.begin_other_pc_block(pid) ... q.end_other_pc_block().
Le motif de cooldown
Les minuteurs sont faits pour des choses qui se declencheront "bientot", mais un cooldown persistant du type "reclamer cette recompense une fois toutes les 24 heures" doit survivre meme a un redemarrage du serveur. La bonne methode n'est pas un minuteur, mais l'ecriture d'un horodatage dans un flag du joueur. get_global_time() renvoie l'heure actuelle du serveur en secondes ; vous la stockez avec pc.setqf et comparez plus tard.
quest recompense_quotidienne begin
state start begin
when 20095.chat."Recompense quotidienne" begin
local now = get_global_time()
local last = pc.getqf("derniere_recompense")
local cooldown = 24 * 60 * 60 -- 24 heures
if now - last < cooldown then
local reste = cooldown - (now - last)
say("Attends encore " .. math.floor(reste / 3600) .. " heures pour la prochaine recompense.")
return
end
pc.setqf("derniere_recompense", now)
pc.give_item2(50300, 1)
say("Ta recompense quotidienne est prete !")
end
end
end
La difference est cruciale : q.start_timer est perdu au redemarrage du serveur, mais l'horodatage ecrit dans un flag reste dans la base de donnees. Pour des cooldowns persistants, preferez toujours ce motif.
Minuteurs repetitifs et annulation
Pour une tache qui se repete a intervalles (par exemple un avertissement toutes les 30 secondes), vous re-armez le minuteur dans son propre bloc. Quand vous voulez l'arreter, vous brisez la boucle avec un flag de quete — car si vous ne le redemarrez tout simplement pas, la boucle s'arrete d'elle-meme.
quest compteur begin
state start begin
when login begin
pc.setqf("tour", 0)
q.start_timer("tic", 30)
end
when tic.timer begin
local tour = pc.getqf("tour") + 1
pc.setqf("tour", tour)
chat("Tour : " .. tour)
if tour < 5 then
q.start_timer("tic", 30) -- re-armer = continuer
else
chat("Compteur termine.") -- ne pas re-armer = arreter
end
end
end
end
Si vous devez annuler tot un minuteur lie au joueur, q.clear_timer() efface les minuteurs en cours. Pour un minuteur global, utilisez q.clear_server_timer("nom", arg).
Erreurs courantes et astuces
- Le nom du minuteur ne correspond pas au bloc when : si vous avez demarre
q.start_timer("ouvrir_boite", 10), le bloc doit etrewhen ouvrir_boite.timer. Les noms doivent etre strictement identiques. - Utiliser un minuteur pour un cooldown persistant : le minuteur est efface au redemarrage du serveur. Pour des durees longues et persistantes, utilisez le motif
get_global_time()+ flag. - Appeler pc.* dans server_timer : il n'y a pas de joueur dans le contexte global ; transportez le PID via l'argument et entrez dans un bloc
q.begin_other_pc_block. - Intervalles tres courts : evitez le travail en dessous de la seconde ; le moteur de quetes fonctionne a la resolution de la seconde, et des minuteurs trop frequents nuisent aux performances.
- Verifiez syserr : si un minuteur ne se declenche pas comme prevu, regardez d'abord
syserr.txt— les erreurs Lua y apparaissent generalement.
Questions frequentes
Quelle est la difference entre q.start_timer et server_timer ?
q.start_timer appartient a un joueur precis et le bloc s'execute dans son contexte ; il tombe si le personnage se deconnecte. server_timer appartient au serveur, n'est lie a personne et sert aux evenements globaux comme les reapparitions de boss.
Qu'arrive-t-il aux minuteurs si le serveur redemarre ?
Les minuteurs en memoire sont perdus. C'est pourquoi vous devez gerer les attentes de plusieurs heures ou jours non pas avec un minuteur, mais en ecrivant get_global_time() dans un flag du joueur ; le flag persiste en base de donnees.
Puis-je lancer plusieurs minuteurs en meme temps ?
Oui, donnez simplement un nom different a chacun. Demarrer un nouveau minuteur avec le meme nom annule l'ancien et arme le nouveau, ce qui est parfois utilise volontairement comme mecanisme de "reinitialisation".
Bloque sur le systeme de quetes ? Si vous avez besoin d'aide pour le developpement de quetes Metin2 — quetes basees sur des minuteurs, logique de donjon ou systemes d'evenements personnalises — contactez-moi et resolvons votre projet ensemble.