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

Metin2 Quest Timer: Kullanımı ve Örnekleri

Metin2 quest timer, görev sisteminin en güçlü ama en çok yanlış kullanılan parçalarından biridir: bir olayı anında değil, belirli bir süre sonra tetiklemenize olanak tanır. Geri sayım yapan bir görev, belirli aralıkla tekrar eden bir uyarı, boss yeniden doğma süresi veya "bu ödülü 24 saatte bir alabilirsin" şeklinde bir bekleme süresi (cooldown) kurmak istiyorsanız, hepsinin temelinde zamanlayıcılar yatar. Bu yazıda Metin2 quest motorundaki iki ana zamanlayıcı mekanizmasını — oyuncuya bağlı q.start_timer ve global server_timer — gerçek, çalışan örneklerle adım adım inceleyeceğiz.

Quest timer nedir, nasıl çalışır?

Quest motoru olay tabanlıdır: when ... begin ... end blokları belirli olaylara (sohbet, öldürme, giriş) tepki verir. Zamanlayıcı ise bu mantığa "gecikme" ekler. Bir timer kurduğunuzda motor onu kaydeder ve süresi dolduğunda özel bir olay üretir; siz de bu olayı yine bir when bloğuyla yakalarsınız. İki tür timer vardır:

  • Oyuncuya bağlı timer (q.start_timer): zamanlayıcı belirli bir karaktere aittir. Süre dolduğunda blok o oyuncunun bağlamında çalışır; yani pc.* fonksiyonlarına doğrudan erişebilirsiniz.
  • Global server timer (server_timer): zamanlayıcı bir oyuncuya değil, sunucuya aittir. Boss doğma, harita olayları gibi kimseye bağlı olmayan işler için idealdir.

Bu ayrımı baştan doğru kurmak önemlidir, çünkü iki tür timer farklı bağlamlarda çalışır ve birini diğerinin yerine kullanmak en sık karşılaşılan hatalardandır. Aşağıdaki bölümlerde her ikisini de tek tek ele alacağız.

q.start_timer ile oyuncuya bağlı zamanlayıcı

En sık ihtiyaç duyulan senaryo budur: oyuncu bir NPC ile konuşur, X saniye sonra bir şey olur. q.start_timer("isim", saniye) ile başlatırsınız, sonucu when isim.timer bloğunda yakalarsınız.

quest hediye_kutusu begin
    state start begin
        when 20095.chat."Kutuyu ac" begin
            say_title("Tuccar:")
            say("Kutu 10 saniye sonra acilacak, bekle...")
            q.start_timer("kutu_ac", 10)
        end

        when kutu_ac.timer begin
            say("Kutu acildi! Iste odulun.")
            pc.give_item2(27003, 1)   -- ornek item vnum
            pc.give_exp2(5000)
        end
    end
end

Burada dikkat edilecek nokta: kutu_ac.timer bloğu zaten doğru oyuncunun bağlamında çalışır, çünkü timer'ı o oyuncu için başlattık. Aynı isimle bir timer zaten varken yeniden q.start_timer çağırırsanız eskisi yenisiyle değişir, bu da istemeden çift tetiklemeyi önler.

server_timer ile global gecikmeli olaylar

Bir bossun ölümünden bir saat sonra yeniden doğmasını istediğinizi düşünün. Bu işin belirli bir oyuncuyla ilgisi yoktur, dolayısıyla server_timer kullanılır. İmza şudur: server_timer("isim", saniye, arg). Üçüncü parametre olarak bir VID veya sayı geçirebilir, tetiklendiğinde get_server_timer_arg() ile geri okuyabilirsiniz.

quest boss_dogus begin
    state start begin
        when 6091.kill begin
            -- Boss oldu, 1 saat sonra yeniden dogsun
            local map_index = pc.get_map_index()
            server_timer("boss_respawn", 60 * 60, map_index)
            notice_all("Boss oldu! 1 saat sonra geri donecek.")
        end

        when boss_respawn.server_timer begin
            local map_index = get_server_timer_arg()
            regen_in_map(map_index, "data/boss_regen.txt")
            notice_all("Boss yeniden dogdu!")
        end
    end
end

server_timer bloğunun içinde varsayılan bir oyuncu bağlamı yoktur. Belirli bir oyuncuya iş yaptırmanız gerekirse, argümanla taşıdığınız PID üzerinden q.begin_other_pc_block(pid) ... q.end_other_pc_block() kalıbını kullanmalısınız.

Bekleme süresi (cooldown) deseni

Timer'lar "şu an dolacak" işler içindir; ama "bu ödülü 24 saatte bir al" gibi kalıcı bir cooldown, sunucu yeniden başlasa bile saklanmalıdır. Bunun doğru yolu timer değil, bir zaman damgasını oyuncu flag'ine yazmaktır. get_global_time() sunucunun anlık zamanını saniye cinsinden verir; bunu pc.setqf ile saklar ve sonra karşılaştırırsınız.

quest gunluk_odul begin
    state start begin
        when 20095.chat."Gunluk odul" begin
            local now = get_global_time()
            local last = pc.getqf("son_odul")
            local bekleme = 24 * 60 * 60   -- 24 saat

            if now - last < bekleme then
                local kalan = bekleme - (now - last)
                say("Bir sonraki odul icin " .. math.floor(kalan / 3600) .. " saat bekle.")
                return
            end

            pc.setqf("son_odul", now)
            pc.give_item2(50300, 1)
            say("Gunluk odulun hazir!")
        end
    end
end

Buradaki fark kritiktir: q.start_timer sunucu yeniden başlatıldığında kaybolur, ama flag'e yazılan zaman damgası veritabanında kalır. Kalıcı bekleme süreleri için her zaman bu deseni tercih edin. Aynı mantık günlük giriş ödülleri, saatlik avlanma sınırı veya boss çağırma taşı gibi kullanım sıklığı sınırlı tüm sistemler için geçerlidir; süreyi timer ile değil, zaman damgasıyla yönetmek hem güvenli hem de restart'a dayanıklıdır.

Tekrarlı timer ve iptal etme

Belirli aralıkla tekrar eden bir görev (örneğin her 30 saniyede bir uyarı) için timer'ı kendi bloğunun içinde yeniden kurarsınız. Süreyi durdurmak istediğinizde ise bir quest flag'iyle döngüyü kırarsınız — çünkü bittiğinde yeniden başlatmazsanız döngü kendiliğinden durur.

quest sayac begin
    state start begin
        when login begin
            pc.setqf("tur", 0)
            q.start_timer("tik", 30)
        end

        when tik.timer begin
            local tur = pc.getqf("tur") + 1
            pc.setqf("tur", tur)
            chat("Tur: " .. tur)

            if tur < 5 then
                q.start_timer("tik", 30)   -- yeniden kur = devam
            else
                chat("Sayac bitti.")       -- yeniden kurma = dur
            end
        end
    end
end

Bir oyuncuya bağlı timer'ı erken iptal etmeniz gerekirse q.clear_timer() çalışan timer'ları temizler. Global timer için ise q.clear_server_timer("isim", arg) kullanılır.

Yaygın hatalar ve ipuçları

  • Timer ismi ile when bloğu eşleşmiyor: q.start_timer("kutu_ac", 10) başlattıysanız blok mutlaka when kutu_ac.timer olmalı. İsimler birebir aynı olmalıdır.
  • Kalıcı cooldown için timer kullanmak: sunucu restart'ında timer silinir. Uzun ve kalıcı süreler için get_global_time() + flag desenini kullanın.
  • server_timer içinde pc.* çağırmak: global bağlamda oyuncu yoktur; PID'yi argümanla taşıyıp q.begin_other_pc_block bloğuna girin.
  • Çok kısa süreler: 1 saniyenin altında işlerden kaçının; quest motoru saniye çözünürlüğünde çalışır ve çok sık tetiklenen timer'lar performansı düşürür.
  • syserr kontrolü: timer beklediğiniz gibi tetiklenmiyorsa önce syserr.txt dosyasına bakın; Lua hataları çoğu zaman orada belirir.

Sık Sorulan Sorular

q.start_timer ile server_timer arasındaki fark nedir?

q.start_timer belirli bir oyuncuya aittir ve blok o oyuncunun bağlamında çalışır; karakterden çıkış yapılırsa düşer. server_timer ise sunucuya aittir, kimseye bağlı değildir ve boss doğma gibi global olaylar için kullanılır.

Sunucu yeniden başlarsa timer'lar ne olur?

Bellekte tutulan timer'lar kaybolur. Bu yüzden saatler veya günler süren bekleme sürelerini timer ile değil, get_global_time() değerini bir oyuncu flag'ine yazarak yönetmelisiniz; flag veritabanında kalıcıdır.

Aynı anda birden fazla timer çalıştırabilir miyim?

Evet, sadece her birine farklı bir isim verin. Aynı isimle yeni bir timer başlatmak eskisini iptal edip yenisini kurar, bu da bazen kasıtlı olarak "sıfırla" mantığı için kullanılır.

Quest sisteminde takıldınız mı? Zamanlayıcı tabanlı görevler, dungeon mantığı veya özel event sistemleri için Metin2 quest geliştirmesi konusunda yardıma ihtiyacınız varsa benimle iletişime geçin — projenizi birlikte çözelim.

Bu kategorideki tüm yazılar →

Devamı için