
Metin2 dünyası, 20 yılı aşkın süredir hem oyuncular hem de oyun geliştiricileri için bitmek bilmeyen bir macera sunuyor. 2026 yılına geldiğimizde, oyunun temel mekanikleri korunsa da, sunucu sahiplerinin ve geliştiricilerin oyunculara sunduğu içerik kalitesi hiç olmadığı kadar önem kazanmış durumda. Bir sunucunun kimliğini belirleyen en önemli unsurlardan biri, oyuncuların etkileşime girdiği özgün görevlerdir. Quest (görev) yazımı, sadece birkaç satır kod yazmaktan ibaret değildir; bu, oyuncunun hikayesini şekillendirmek, oyun içi ekonomiyi dengelemek ve kullanıcıyı sürekli bir amaç doğrultusunda tutmak için kullanılan sanatsal bir araçtır.
Bir sunucu yöneticisi veya geliştiricisi olarak, standart “10 yabani köpek öldür” görevlerinin ötesine geçmeniz gerekir. Modern Metin2 altyapılarında, Lua tabanlı bu sistemler artık daha karmaşık algoritmaları, çok dilli destekleri ve gelişmiş zindan (dungeon) mekaniklerini desteklemektedir. Bu rehberde, temel seviyeden uzmanlık seviyesine kadar bir görevin nasıl kurgulandığını, kodlandığını ve optimize edildiğini derinlemesine inceleyeceğiz. Kendi özgün senaryolarınızı oluşturmak ve Metin2 PvP serverler dünyasında fark yaratmak için ihtiyacınız olan teknik donanımı bu yazıda bulacaksınız.
Önemli: Quest yazımına başlamadan önce, dosya formatınızın mutlaka ANSI değil, UTF-8 (BOM’suz) olduğundan emin olmalısınız. Aksi takdirde oyun içerisinde Türkçe karakter hataları ile karşılaşırsınız.
Quest Yapısının Temelleri ve Mantıksal Hiyerarşi
Metin2’de bir görev dosyası .quest veya .lua uzantısına sahiptir. Bu dosyalar, oyunun çekirdek mekanizması tarafından okunabilmesi için bir derleyici (genellikle qc dosyası) aracılığıyla işlenir. Bir görev dosyasının mimarisi, belirli bir hiyerarşiye dayanır. En üstte görev ismi yer alır, ardından görev durumları (states) ve son olarak bu durumları tetikleyen olaylar (triggers) gelir.
Görev Bloklarının Tanımlanması
Her görev, quest görev_adı begin ifadesiyle başlar ve end ile son bulur. Bu blok, dosyanın genel sınırlarını çizer. Bir görev dosyasının içinde birden fazla durum (state) olabilir. Ancak her görev mutlaka bir start durumuna sahip olmalıdır. Oyuncu bir göreve başladığında sistem otomatik olarak bu başlangıç durumuna bakar.
quest ilk_gorevim begin
state start begin
when login or levelup with pc.get_level() >= 30 begin
set_state(bilgi_al)
end
end
end
Yukarıdaki basit örnekte, oyuncu 30. seviyeye ulaştığında veya bu seviyedeyken oyuna girdiğinde görev tetiklenir ve set_state komutu ile görev bir sonraki aşamaya aktarılır. Bu yapı, Metin2’nin görev mantığının temelidir.
Tetikleyiciler (When Blokları)
Tetikleyiciler, bir eylemin ne zaman gerçekleşeceğini belirler. Metin2 Lua motoru onlarca farklı tetikleyiciyi tanır:
when login: Oyuncu oyuna girdiğinde.when kill: Bir canavar veya oyuncu öldürüldüğünde.when click: Bir NPC’ye tıklandığında.when use: Bir eşya kullanıldığında (örneğin bir yüzük veya binek).when levelup: Seviye atlandığında.when chat: NPC menüsünde bir seçenek göründüğünde.pc.setf("gorev_adı", "durum", deger): Veri kaydeder.pc.getf("gorev_adı", "durum"): Kaydedilen veriyi okur.
Tetikleyicilerin verimli kullanılması, sunucu performansını doğrudan etkiler. Örneğin, her saniye çalışan bir tetikleyici yerine, sadece gerektiğinde (event-driven) çalışan tetikleyiciler tercih edilmelidir.
Lua Dilinin Metin2’deki Rolü ve Temel Fonksiyonlar
Metin2 görev sistemi, Lua programlama dilinin basitleştirilmiş bir versiyonunu kullanır. Karmaşık matematiksel hesaplamalar yapabilir, oyuncu verilerini (flag) saklayabilir ve oyun dünyasına müdahale edebilirsiniz. 2026 yılındaki güncel sunucu yapılarında, Lua fonksiyonları artık daha geniş bir kütüphaneye sahiptir.
Değişkenler ve Flag Kullanımı
Bir oyuncunun görevde hangi aşamada olduğunu veya bir görevi daha önce yapıp yapmadığını anlamak için “flag” sistemini kullanırız. pc.setf ve pc.getf fonksiyonları, oyuncunun karakterine özel kalıcı veriler kaydetmenizi sağlar.
Örneğin, bir oyuncunun günde sadece bir kez girebileceği bir zindan yapmak istiyorsanız, oyuncunun en son girdiği zamanı get_global_time() ile bir flag içine kaydedebilir ve her girişte bu süreyi kontrol edebilirsiniz.
Temel Çıktı ve Etkileşim Fonksiyonları
Oyuncuyla iletişim kurmak için en sık kullanılan fonksiyon say() fonksiyonudur. Ancak modern tasarımlarda say_item(), say_reward() ve say_title() gibi görseli zenginleştiren yardımcı fonksiyonlar da mevcuttur.
say_title("Demirci:")
say("Merhaba evlat, bana 10 adet Bakır Cevheri")
say("getirirsen sana özel bir ödül verebilirim.")
local secim = select("Kabul Ediyorum", "Vazgeç")
Buradaki select() fonksiyonu, oyuncuya seçenek sunar ve oyuncunun tıkladığı butonun indeksini döndürür. Bu, görev dallanmaları için hayati önem taşır.
Önemli:
sayfonksiyonu içerisinde çok uzun metinler kullanmak, pencerenin taşmasına veya oyuncunun ekranının donmasına neden olabilir. Her zaman metinlerinizi makul uzunlukta tutun.
Gelişmiş Görev Senaryoları ve Zindan Kodlama
2026 yılı Metin2 PvP dünyasında standart görevlerden ziyade “Dungeon” (Zindan) görevleri revaçtadır. Bir zindan yazmak, normal bir görev yazmaktan daha karmaşıktır çünkü grup (party) kontrolü, harita indeksleri ve canavar doğurma (spawn) koordinatlarını yönetmeniz gerekir.
Zindan Başlatma Mantığı
Bir zindanı başlatmak için d.new_jump veya d.new_jump_all fonksiyonları kullanılır. Bu fonksiyonlar oyuncuyu veya grubu izole edilmiş (instance) bir haritaya ışınlar.
Zindan içerisinde kullanılan bazı özel fonksiyonlar şunlardır:
d.notice(): Zindandaki herkese duyuru geçer.d.spawn_mob(): Belirli bir koordinata canavar çağırır.d.setf(): Sadece o zindan oturumuna (instance) özel veri saklar.d.kill_all(): Haritadaki tüm canavarları temizler.Zindan tasarlarken en sık yapılan hata, timer (zamanlayıcı) kullanımında yaşanır. timer yerine server_timer veya loop_timer kullanmak, sunucu taraflı senkronizasyonu artırır ve oyuncuların zindandan düşmesi (kick) durumunda görevin askıda kalmasını engeller.
Ödüllendirme ve Eşya Kontrolü
Görevlerin sonunda oyuncuya eşya vermek için pc.give_item2() fonksiyonu kullanılır. Bu fonksiyon, envanter doluysa eşyayı yere atmaz, sistem üzerinden bir uyarı verir. Eşya kontrolü yaparken ise pc.count_item() fonksiyonu ile oyuncunun elinde yeterli malzeme olup olmadığı denetlenmelidir.
| Fonksiyon Adı | Amacı | Örnek Kullanım |
|---|---|---|
pc.give_item2 |
Oyuncuya eşya verir | pc.give_item2(19, 1) |
pc.remove_item |
Oyuncudan eşya siler | pc.remove_item(30006, 5) |
pc.get_job |
Oyuncunun karakter sınıfını döner | if pc.get_job() == 0 then |
pc.warp |
Oyuncuyu ışınlar | pc.warp(x_koordinat, y_koordinat) |
mob.spawn |
Canavar oluşturur | mob.spawn(101, x, y, adet) |
Quest Yazımında Performans ve Güvenlik
Büyük oyuncu kitlesine sahip sunucularda hatalı yazılmış bir quest, CPU kullanımını %100’e çıkarabilir veya oyun veritabanında (db) açıklar yaratabilir. Bu nedenle kod yazarken “temiz kod” prensiplerine uymak zorunludur.
Performans Optimizasyonu
- Döngülerden Kaçının: Görev içerisinde çok büyük
forveyawhiledöngüleri kullanmak oyunun anlık takılmasına (lag) neden olabilir. Eğer bir liste üzerinde işlem yapacaksanız, bunu küçük parçalara bölün. - Sorgu Sayısını Azaltın:
pc.getfgibi fonksiyonlar veritabanı ile doğrudan etkileşime girmese de, sürekli çağrılmaları bellek yükünü artırır. Değişkenleri bir yerel değişkene (local) atayıp oradan kullanmak daha hızlıdır. - Gereksiz Tetikleyicileri Kapatın: Kullanılmayan bir görevi
qcile derleyip aktif bırakmak, her oyuncu girişinde sistemin o görevi kontrol etmesine neden olur. - Oyuncu NPC’nin yanında mı? (
pc.get_distance) - Oyuncu gerekli seviyede mi?
- Oyuncunun envanterinde yer var mı?
- Oyuncu bu ödülü daha önce aldı mı?
- Dosyayı sunucunuzun
/usr/game/share/locale/turkey/questdizinine yükleyin. quest_list(veya bazı filestardalocale_list) dosyasına yazdığınız dosyanın adını ekleyin.- SSH (Putty) üzerinden ilgili dizine giderek
./qc dosya_adi.questkomutunu çalıştırın. - Oyun içerisinden yönetici (GM) karakteriyle
/reload qkomutunu verin veya sunucuyu yeniden başlatın.
Güvenlik Önlemleri
Bir oyuncunun görevi suistimal etmesini (exploit) önlemek için her zaman kontrollerinizi çift taraflı yapın. Örneğin, bir NPC’den ödül alınacaksa:
Bu kontrolleri yapmadan verilen ödüller, hile kullanan oyuncuların görevi uzaktan tetikleyerek sonsuz eşya almasına neden olabilir.
Quest Derleme ve Sunucuya Entegre Etme

Yazdığınız .quest dosyasını oyuna dahil etmek için şu adımları izlemelisiniz:
Önemli:
/reload qkomutu büyük sunucularda anlık donmaya neden olabilir. Canlı sunucularda bu komutu kullanırken dikkatli olmalısınız.
Örnek Bir Senaryo: Günlük Hediye Görevi
Aşağıda, 2026 yılı standartlarına uygun, hata payı düşük ve optimize edilmiş bir günlük giriş ödülü görevi örneği bulunmaktadır. Bu kod bloğunu inceleyerek mantığı kavrayabilirsiniz.
quest gunluk_odul begin
state start begin
when 20095.chat."Günlük Hediyeni Al" begin
local son_alim = pc.getf("gunluk_odul", "son_zaman")
local su anki_zaman = get_global_time() if su_anki_zaman < son_alim + 86400 then
say_title("Sistem:")
say("Henüz 24 saat geçmemiş.")
say("Tekrar gelmek için beklemen gereken süre:")
say_reward(string.format("%d saat.", (son_alim + 86400 - su_anki_zaman) / 3600))
else
say_title("Sistem:")
say("Harika! Bugünün hediyesini hak ettin.")
pc.give_item2(71084, 10) -- Efsun Nesnesi
pc.setf("gunluk_odul", "son_zaman", su_anki_zaman)
say_reward("10x Efsun Nesnesi kazandın.")
end
end
end
end
Bu örnekte get_global_time() fonksiyonu ile Unix zaman damgası alınmış ve 24 saatlik (86400 saniye) kontrol mekanizması kurulmuştur. Bu, modern sunucularda en sağlıklı çalışma yöntemidir.
Sonuç
Metin2 quest yazımı, teknik bilgi ile yaratıcılığın buluştuğu bir noktadır. İyi bir geliştirici, sadece kod yazan değil, aynı zamanda yazdığı kodun oyuncu üzerindeki etkisini ve sunucu üzerindeki yükünü hesaplayan kişidir. 2026 yılında, oyuncu toplulukları artık daha bilinçli ve kaliteli içerik bekliyor. Bu rehberde öğrendiğiniz temeller üzerine kendi özgün sistemlerinizi inşa ederek, oyun dünyasında kalıcı bir iz bırakabilirsiniz. Unutmayın ki en iyi görev, oyuncuyu sıkmayan, ona bir hikaye sunan ve adil bir ödül sistemiyle çalışan görevdir.
Yasal Uyarı: Bu rehberdeki bilgiler eğitim amaçlıdır. Uygulama sırasında oluşabilecek veri kayıplarından veya sunucu hatalarından geliştiricinin kendisi sorumludur. Her zaman yedek alarak çalışınız.
Sıkça Sorulan Sorular
Quest dosyasını derlerken "Segmentation Fault" hatası alıyorum, ne yapmalıyım?
Bu hata genellikle Lua kodundaki yazım yanlışlarından (eksik end, parantez hatası vb.) kaynaklanır. Kodunuzu satır satır kontrol edin ve blokların doğru kapandığından emin olun. Ayrıca dosya sonuna bir boş satır bırakmak bazen bu sorunu çözebilir.
Bir görevi sadece belirli bir krallığa özel nasıl yapabilirim?
pc.get_empire() fonksiyonunu kullanarak kontrol sağlayabilirsiniz. Örneğin; if pc.get_empire() == 1 then kontrolü, görevin sadece Kırmızı Krallık (Shinsoo) oyuncuları tarafından yapılmasını sağlar.
Quest dosyalarındaki Türkçe karakterler neden "?" olarak görünüyor?
Bu durum tamamen dosya kodlaması ile ilgilidir. Notepad++ gibi bir editör kullanarak "Kodlama" menüsünden "UTF-8 (BOM'suz)" seçeneğini işaretleyip dosyayı kaydedin ve sunucuya tekrar yükleyip derleyin.
Quest ile oyun içi "Sistem" (C++ tabanlı) arasındaki fark nedir?
Questler Lua dilini kullanır ve yorumlanarak çalışır; esnektirler ancak çok yoğun işlemlerde performansı etkileyebilirler. Sistemler (source tarafı) C++ ile yazılır, çekirdeğe gömülüdür ve çok daha hızlı çalışırlar. Karmaşık mantıklar için quest, temel mekanikler için C++ tercih edilir.
Yazdığım görev oyunda görünmüyor, sebebi ne olabilir?
Bunun birkaç sebebi olabilir: qc ile derlenmemiş olabilir, quest_list dosyasına eklenmemiş olabilir, NPC kodu yanlış yazılmış olabilir veya görevdeki seviye/krallık şartlarını karşılamıyor olabilirsiniz.
Birden fazla NPC'ye aynı görevi nasıl atayabilirim?
when 20011.chat."Görev" or 20012.chat."Görev" begin şeklinde or (veya) bağlacını kullanarak birden fazla NPC kodunu aynı tetikleyiciye bağlayabilirsiniz.
Timer (zamanlayıcı) kullanırken server kapanırsa ne olur?
Standart timer fonksiyonları bellek üzerinde tutulur ve sunucu (veya kanal) kapandığında sıfırlanır. Eğer kalıcı bir süre takibi istiyorsanız (örneğin 1 hafta sürecek bir görev), veritabanına kayıt yapan pc.setf ve get_global_time ikilisini kullanmalısınız.

Bir yanıt bırakın