aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Metin2 Quest Timer: Verwendung und Beispiele

Der Metin2 Quest Timer ist einer der machtigsten — und am haufigsten falsch genutzten — Teile des Quest-Systems: Er erlaubt es, ein Ereignis nicht sofort, sondern nach einer festgelegten Zeit auszulosen. Ob du eine Countdown-Quest willst, eine Warnung, die sich in Intervallen wiederholt, eine Boss-Respawn-Verzogerung oder einen Cooldown wie "du kannst diese Belohnung einmal alle 24 Stunden abholen" — Timer bilden den Kern all dessen. In diesem Artikel gehen wir Schritt fur Schritt die beiden zentralen Timer-Mechanismen der Metin2 Quest-Engine durch: den an den Spieler gebundenen q.start_timer und den globalen server_timer, mit echten, funktionierenden Beispielen.

Was ein Quest Timer ist und wie er funktioniert

Die Quest-Engine ist ereignisgesteuert: when ... begin ... end-Blocke reagieren auf bestimmte Ereignisse (Dialog, Kill, Login). Ein Timer fugt dieser Logik eine "Verzogerung" hinzu. Wenn du einen Timer startest, registriert ihn die Engine, und bei Ablauf erzeugt er ein spezielles Ereignis — das du wieder mit einem when-Block abfangst. Es gibt zwei Arten:

  • An den Spieler gebundener Timer (q.start_timer): Der Timer gehort zu einem bestimmten Charakter. Wenn er auslost, lauft der Block im Kontext dieses Spielers, du kannst also pc.*-Funktionen direkt aufrufen.
  • Globaler Server-Timer (server_timer): Der Timer gehort dem Server, nicht einem Spieler. Ideal fur Aufgaben, die an niemanden gebunden sind, etwa Boss-Respawns oder Map-Events.

Ein an den Spieler gebundener Timer mit q.start_timer

Das ist das haufigste Szenario: Ein Spieler spricht mit einem NPC, und X Sekunden spater passiert etwas. Du startest ihn mit q.start_timer("name", sekunden) und fangst das Ergebnis in einem when name.timer-Block ab.

quest geschenkbox begin
    state start begin
        when 20095.chat."Box oeffnen" begin
            say_title("Haendler:")
            say("Die Box oeffnet sich in 10 Sekunden, warte...")
            q.start_timer("box_oeffnen", 10)
        end

        when box_oeffnen.timer begin
            say("Die Box ist offen! Hier ist deine Belohnung.")
            pc.give_item2(27003, 1)   -- Beispiel-Item-vnum
            pc.give_exp2(5000)
        end
    end
end

Der entscheidende Punkt: Der box_oeffnen.timer-Block lauft bereits im Kontext des richtigen Spielers, weil wir den Timer fur diesen Spieler gestartet haben. Rufst du q.start_timer erneut mit einem bereits vorhandenen Namen auf, wird der alte durch den neuen ersetzt — das verhindert praktischerweise ein versehentliches doppeltes Auslosen.

Globale verzogerte Events mit server_timer

Angenommen, ein Boss soll eine Stunde nach seinem Tod respawnen. Das hat nichts mit einem bestimmten Spieler zu tun, also nutzt du server_timer. Die Signatur lautet server_timer("name", sekunden, arg). Du kannst als dritten Parameter eine VID oder Zahl ubergeben und sie beim Auslosen mit get_server_timer_arg() zuruucklesen.

quest boss_respawn begin
    state start begin
        when 6091.kill begin
            -- Boss tot, nach 1 Stunde respawnen
            local map_index = pc.get_map_index()
            server_timer("boss_zurueck", 60 * 60, map_index)
            notice_all("Der Boss ist gefallen! Er kehrt in 1 Stunde zurueck.")
        end

        when boss_zurueck.server_timer begin
            local map_index = get_server_timer_arg()
            regen_in_map(map_index, "data/boss_regen.txt")
            notice_all("Der Boss ist respawnt!")
        end
    end
end

Innerhalb eines server_timer-Blocks gibt es keinen Standard-Spielerkontext. Musst du auf einen bestimmten Spieler einwirken, trage seine PID uber das Argument mit und nutze das Muster q.begin_other_pc_block(pid) ... q.end_other_pc_block().

Das Cooldown-Muster

Timer sind fur Dinge, die "bald" auslosen, aber ein dauerhafter Cooldown wie "diese Belohnung einmal alle 24 Stunden abholen" muss sogar einen Serverneustart uberleben. Der richtige Weg ist kein Timer, sondern das Schreiben eines Zeitstempels in ein Spieler-Flag. get_global_time() liefert die aktuelle Serverzeit in Sekunden; du speicherst sie mit pc.setqf und vergleichst spater.

quest taegliche_belohnung begin
    state start begin
        when 20095.chat."Taegliche Belohnung" begin
            local now = get_global_time()
            local last = pc.getqf("letzte_belohnung")
            local cooldown = 24 * 60 * 60   -- 24 Stunden

            if now - last < cooldown then
                local rest = cooldown - (now - last)
                say("Warte noch " .. math.floor(rest / 3600) .. " Stunden auf die naechste Belohnung.")
                return
            end

            pc.setqf("letzte_belohnung", now)
            pc.give_item2(50300, 1)
            say("Deine taegliche Belohnung ist bereit!")
        end
    end
end

Der Unterschied ist entscheidend: q.start_timer geht beim Serverneustart verloren, aber der in ein Flag geschriebene Zeitstempel bleibt in der Datenbank. Bevorzuge fur dauerhafte Cooldowns immer dieses Muster.

Wiederholende Timer und ihr Abbrechen

Fur eine Aufgabe, die sich in Intervallen wiederholt (etwa eine Warnung alle 30 Sekunden), bewaffnest du den Timer innerhalb seines eigenen Blocks erneut. Willst du stoppen, durchbrichst du die Schleife mit einem Quest-Flag — denn wenn du ihn einfach nicht neu startest, stoppt die Schleife von selbst.

quest zaehler begin
    state start begin
        when login begin
            pc.setqf("runde", 0)
            q.start_timer("tick", 30)
        end

        when tick.timer begin
            local runde = pc.getqf("runde") + 1
            pc.setqf("runde", runde)
            chat("Runde: " .. runde)

            if runde < 5 then
                q.start_timer("tick", 30)   -- neu bewaffnen = weiter
            else
                chat("Zaehler beendet.")     -- nicht neu bewaffnen = stopp
            end
        end
    end
end

Musst du einen an den Spieler gebundenen Timer fruh abbrechen, loscht q.clear_timer() die laufenden Timer. Fur einen globalen Timer nutze q.clear_server_timer("name", arg).

Haufige Fehler und Tipps

  • Timer-Name passt nicht zum when-Block: Hast du q.start_timer("box_oeffnen", 10) gestartet, muss der Block when box_oeffnen.timer sein. Die Namen mussen exakt ubereinstimmen.
  • Einen Timer fur einen dauerhaften Cooldown nutzen: Der Timer wird beim Serverneustart geloscht. Nutze fur lange, dauerhafte Zeitraume das Muster get_global_time() + Flag.
  • pc.* innerhalb von server_timer aufrufen: Im globalen Kontext gibt es keinen Spieler; trage die PID uber das Argument mit und betritt einen q.begin_other_pc_block-Block.
  • Sehr kurze Intervalle: Vermeide Arbeit unter einer Sekunde; die Quest-Engine lauft mit Sekundenauflosung, und zu haufig auslosende Timer schaden der Leistung.
  • syserr prufen: Lost ein Timer nicht wie erwartet aus, sieh zuerst in syserr.txt nach — Lua-Fehler erscheinen meist dort.

Haufig gestellte Fragen

Was ist der Unterschied zwischen q.start_timer und server_timer?

q.start_timer gehort zu einem bestimmten Spieler und der Block lauft in dessen Kontext; er fallt weg, wenn sich der Charakter ausloggt. server_timer gehort dem Server, ist an niemanden gebunden und wird fur globale Events wie Boss-Respawns genutzt.

Was passiert mit Timern, wenn der Server neu startet?

Timer im Speicher gehen verloren. Deshalb solltest du Wartezeiten von Stunden oder Tagen nicht mit einem Timer verwalten, sondern indem du get_global_time() in ein Spieler-Flag schreibst; das Flag bleibt in der Datenbank erhalten.

Kann ich mehrere Timer gleichzeitig laufen lassen?

Ja, gib jedem einfach einen anderen Namen. Einen neuen Timer mit demselben Namen zu starten bricht den alten ab und bewaffnet den neuen, was manchmal bewusst als "Reset"-Mechanismus genutzt wird.

Beim Quest-System festgefahren? Brauchst du Hilfe bei der Metin2 Quest-Entwicklung — timerbasierte Quests, Dungeon-Logik oder eigene Event-Systeme — melde dich und lass uns dein Projekt gemeinsam losen.

Bu kategorideki tüm yazılar →

Devamı için