İçeriğe geç

Metin2 Affect Sistemi: Etkiler, Süreler ve Yeni Etki Ekleme

Hazırlayan: Metin2VIP Editörleri Yayın: 6 dk okuma

Kısaca: Metin2'de iksir, beceri desteği, zehir ya da nesne marketi bonusu gibi her süreli etki bir CAffect kaydıdır: tür, puan, değer, bayrak, süre ve saniyelik SP maliyeti. Oyun çekirdeği oyundaki karakterin etkilerinin süresini saniyede bir azaltır; etki eklendiği anda player veritabanının affect tablosuna yazılır, kalan süre oyundan çıkışta güncellenir. 500-599 arası türler ölümde silinmez, diğerlerinin çoğu silinir.
İçindekiler
  1. Bir etki neyden oluşur?
  2. Tür numaraları hangi aralıkta?
  3. AFF bayrakları ne işe yarar?
  4. Süre nasıl akar?
  5. Kayıt: affect tablosu ve çökme
  6. İksir etkisinin akışı
  7. Beceri etkisinin akışı
  8. Quest'ten verilen etkiler
  9. Yeni etki eklerken dikkat edilecekler

Metin2'de iksir, beceri desteği, zehir, nesne marketi bonusu ya da quest ödülü olan her süreli etki, oyun çekirdeğinde bir affect kaydıdır. Kayıt altı alandan oluşur, karakterin etki listesinde durur, oyundaki karakter için her saniye bir azalır ve sıfıra inince puanı geri alınarak silinir. Etki eklendiği anda player veritabanındaki affect tablosuna yazılır, kalan süre oyundan çıkışta güncellenir.

Bu yazı etkinin kodda nasıl yaşadığını ve yeni bir etki eklerken nelere bakılacağını anlatır; dosya ve fonksiyon adları bu kaynağa göredir, yapı resmî koddan geldiği için sunucuların büyük çoğunluğunda aynıdır. İksirlerin oyuncu tarafı iksirler, zehir ve sersemletme durum etkileri yazısında.

Bir etki neyden oluşur?

game/src/affect.h içindeki CAffect sınıfının altı alanı, affect tablosunun sütunlarıyla bire birdir:

Alan Tablodaki sütun Anlamı
dwType bType (smallint) Etkinin türü; aynı türden etkiler birlikte silinir
bApplyOn bApplyOn (tinyint) Değişen puan, POINT numarası (efsunlardaki APPLY değil)
lApplyValue lApplyValue Puana eklenen değer
dwFlag dwFlag Karakterin görünümünü ya da durumunu değiştiren AFF bayrağı, yoksa 0
lDuration lDuration Kalan süre, saniye
lSPCost lSPCost Her saniye düşülen SP; yetmezse etki biter

Etki eklenince ComputeAffect bayrağı açar ve PointChange(bApplyOn, lApplyValue) çağırır; silinince aynı değeri eksiyle geri alır. Bu yüzden etkinin puanı, PointChange switch'inde dalı olan bir POINT olmalıdır. Puan numarası ile efsun numarası arasındaki fark yeni efsun ekleme yazısında anlatılıyor.

Tür numaraları hangi aralıkta?

Aralık Ne için Ölümde Kayıt
1-199 Beceri desteklerinin türü becerinin numarasıdır; 151-162 lonca becerileri yalnız lonca savaşında çalışır Silinir Kaydedilir
200-227 Sistem ve iksir etkileri: 200 hareket hızı, 201 saldırı hızı, 209 zehir, 210 sersemletme, 211 yavaşlatma, 216 yanma, 221 binek, 223 sohbet yasağı Silinir (215, 222, 223 kalır) 215 ve 222 kaydedilmez
300, 302 Ramazan ve NOG etkinlik eşyaları Silinir Kaydedilir
500-509 Premium süreler (EXP, eşya, depo, otomatik toplama) Kalır Kaydedilmez, süre hesabın bitiş tarihinden hesaplanır
510 Nesne marketi iksirleri (AFFECT_MALL) Kalır Kaydedilir
511-542 Eşya etkileri: 513 beceri kitabı beklemesiz, 514 saç, 515 AFFECT_COLLECT, 519-530 küp, 531 şebnem, 533 binek bonusu, 534-535 otomatik iksir, 540-542 simya Kalır 533 kaydedilmez
1000 affect.add ile quest'ten verilen etki Silinir Kaydedilir

Kural iki makrodadır: IS_NO_CLEAR_ON_DEATH_AFFECT 500-599 arasını ve sohbet yasağını, IS_NO_SAVE_AFFECT savaş bayrağını, dirilme dokunulmazlığını, premium türleri ve binek bonusunu ayırır. Ölünce çalışan ClearAffect(true) ikisine de uyan etkileri yerinde bırakır, geri kalanını siler.

AFF bayrakları ne işe yarar?

dwFlag bir puan değil, karakterin üstündeki görsel ya da durum bitidir: sersemlemişken oynayamamak, görünmezlik, beceri ışıkları. Sunucu bitleri iki DWORD'lük TAffectFlag'te tutar, yani en çok 64 bayrak olur; bu kaynakta AFF_BITS_MAX 46'dır. İstemcideki CInstanceBase enum'u aynı sırayı bir eksiğiyle izler (sunucuda AFF_YMIR 1, istemcide AFFECT_YMIR 0) ve sınırı AFFECT_NUM = 64'tür. Adlar iki tarafta farklı olabilir; önemli olan sıradır. Yeni bayrak iki tarafta da listenin sonuna eklenir, görünecek efekt playersettingmodule.py'de chrmgr.RegisterEffect(chrmgr.EFFECT_AFFECT + sıra, ...) ile bağlanır.

Süre nasıl akar?

Karakterde en az bir etki varken affect_event her saniye UpdateAffect'i, o da ProcessAffect'i çağırır. Her etkinin lDuration'ı bir azalır, lSPCost varsa SP düşülür, süre bitince etki silinir. Olay yalnız oyundaki karakter için çalıştığı için etki süreleri oyundan çıkınca durur. Gerçek zamanlı süreler eşyanın soketinde tutulur; etki sisteminin işi değildir.

  • Süresi 0 verilen etki, syserr'e Character::AddAffect lDuration == 0 yazılıp 1 saniyeye çevrilir.
  • "Süresiz" etkiler büyük bir sayıyla eklenir. INFINITE_AFFECT_DURATION 60 yıllık saniyedir; bazı eşyalar Value3'e 536.870.911 yazar.
  • Premium türlerde süre hesabın bitiş zamanından her saniye yeniden hesaplanır, saç etkisi hair.limit_time quest bayrağına bakar.

Kayıt: affect tablosu ve çökme

AddAffect etkiyi önce listeye koyar, sonra istemciye bildirir ve db'ye REPLACE INTO affect ... gönderir. Silinen etki DELETE ... WHERE dwPID AND bType AND bApplyOn ile tablodan kalkar. Kalan süreler ise yalnız CHARACTER::Disconnect içindeki SaveAffect'te, yani oyundan çıkışta ve ışınlanmada yazılır. Bunun iki sonucu var:

  • Çekirdek çökerse tabloda etkinin eklendiği andaki tam süresi kalır; oyuncu girişte iksirini baştan alır. Bu kaynakta binek bonusu, çökmeden sonra hem tablodan yüklenip hem binekle yeniden eklenerek iki kat olmasın diye kaydedilmeyenler listesine alınmıştır.
  • Tablonun birincil anahtarı dwPID, bType, bApplyOn, lApplyValue'dır. Bellekte aynı tür, puan ve değerden iki etki olabilir, ama tabloda tek satır kalır; bir sonraki girişte bonus yarıya iner. Silme ise değere bakmadan aynı tür ve puandaki bütün satırları siler.

Girişte LoadAffect önce listeyi temizler, satırları yükler ve puanları yeniden hesaplar. Bu kaynakta Muyeong etkisi yüklenmez, arena haritasında iyi etkiler silinir ve karakter ölü değilse HP ile SP en yüksek değere doldurulur. Etkiler yüklenene kadar eşya kullanılamaz, oyuncu "Affects are not loaded yet!" iletisini görür. Tablonun yeri veritabanları yazısında.

İksir etkisinin akışı

İksirler iki farklı alt türle etki verir ve Value sütunlarının sırası ikisinde farklıdır:

Alt tür Value0 Value1 Value2 Value3 Örnek
USE_ABILITY_UP Efsun türü (7 saldırı hızı ...) Süre Değer Yeşil İksir(B): 7, 600, 30
USE_AFFECT Etki türü Efsun türü Değer Süre Kritik İsabet: 510, 15, 20, 600

USE_ABILITY_UP türü kendisi seçer (saldırı hızı için 201) ve yalnız dokuz efsun türünü tanır; diğerlerinde eşya harcanır ama etki gelmez. USE_AFFECT ise türü proto'dan alır, efsun numarasını aApplyInfo ile puana çevirir ve aynı tür ile aynı puandan bir etki varsa "Bu etki zaten çalışıyor." der. Kritik İsabet ile Delici İsabet'in birlikte içilebilmesi bu yüzdendir: ikisi de 510 türündedir ama puanları farklıdır. Value1'e geçerli bir efsun numarası yazılmalıdır, kod bu değerin sınırını denetlemez.

Beceri etkisinin akışı

Destek becerisi kullanılınca etkinin türü becerinin numarasıdır; puan, değer formülü, süre formülü ve bayrak skill_proto'dan gelir, süreye gruptaki destekçinin bonusu eklenir. İkinci puanı olan beceriler aynı türle ikinci bir etki ekler. Sütunların ayrıntısı skill_proto yazısında.

Büyü Çözme gibi iyi etkileri silen beceriler RemoveGoodAffect'i çağırır. Bu fonksiyon sabit bir listeyi siler: hız ve güç iksirlerinin türleri, havai fişek ve oyuncu destek becerileri. Hedefte Büyü Çözme bayrağı varken IsGoodAffect listesindeki destekler yeniden atılamaz. Yeni bir destek etkisi bu iki listeye eklenmezse Büyü Çözme onu silmez.

Quest'ten verilen etkiler

Fonksiyon Tür Not
affect.add(efsun, değer, süre) 1000 Ölümde silinir; aynısı var mı diye bakar ama efsun numarasını puan numarasıyla karşılaştırdığı için denetim çoğu efsunda tutmaz
affect.add_collect(efsun, değer, süre) 515 Ölümde kalır; hiçbir denetim yapmaz, iki kez çağrılırsa bonus bellekte iki kat olur
affect.add_collect_point(puan, değer, süre) 515 Puan numarasını doğrudan alır
affect.remove_collect(efsun, değer) 515 Puanı ve değeri tutan ilk etkiyi siler
affect.remove() quest numarası + 1000 Parametresiz hâli 1000 türünü değil kendi quest numarasına göre bir türü siler; affect.add'in etkisi için affect.remove(1000) yazılır

Bütün quest'lerin affect.add etkileri aynı 1000 türünde durduğu için affect.remove(1000) hepsini birden siler. Bu nedenle quest'te süreli bonus verirken tekrar kullanımı bir bayrakla engellemek gerekir. Fonksiyonların genel kullanımı quest fonksiyonları yazısında.

Yeni etki eklerken dikkat edilecekler

  1. Türü aralığına göre seç. Ölümde kalması gerekiyorsa 500-599 arasında boş bir numara al; kaydedilmemesi gerekiyorsa IS_NO_SAVE_AFFECT'e ekle. affect.h bu aralıkta 542'den sonrasını tanımlamaz, ama varsayılan item_proto bazı USE_AFFECT eşyalarında 570, 574, 583, 584, 587 ve 588'i kullanır; numara seçmeden önce bu eşyaların Value0 sütununa bak. Yeni türü enum'a adıyla yaz.
  2. Üst üste binmeyi kendin engelle. AddAffect aynı türden etki bulunca bOverride true ise onu değiştirir, false ise yanına yenisini ekler. Eklemeden önce FindAffect(tür, puan) ile denetle.
  3. Puanı doğrula. bApplyOn bir POINT'tir; PointChange'te dalı yoksa syserr'e unknown point change type düşer. Yalnız işaret olarak kullanılacak etkilerde POINT_NONE verilir; beceri kitabı beklemesiz etkisi (513) böyle çalışır ve kod yalnız FindAffect ile varlığına bakar.
  4. Silinme listelerini güncelle. Büyü Çözme'nin silmesi isteniyorsa RemoveGoodAffect'e, kötü etkiyse RemoveBadAffect'e ekle. IsGoodAffect parametresini bir bayt olarak aldığı için 255'ten büyük türler bu listeye yazılamaz.
  5. İstemciyi unutma. uiaffectshower.py 500'den küçük türleri yok sayar; 500 ve üstü için AFFECT_DATA_DICT'e tür numarasıyla, 510 türü için 1000 + puan anahtarıyla bir satır (açıklama ve simge yolu) gerekir. İstemcideki NEW_AFFECT_* sabitleri InstanceBase.h'de durur. Varsayılan sözlükte 510 türünden yalnız on bir puanın simgesi var; örneğin saldırı hızı veren nesne marketi iksirinin simgesi yoktur.
  6. GM komutlarıyla dene. /affect_remove <karakter> hedefin etki listesini tür, puan, değer, süre ve bayrak sütunlarıyla yazar; /do_clear_affect GM'in kendi etkilerini ölümdeki gibi temizler. Komutların geri kalanı GM komutları rehberinde.

Sık sorulan sorular

Sunucu çöktükten sonra oyuncuların iksir süreleri neden başa döndü?
Etki, eklendiği anda tam süresiyle affect tablosuna yazılır; kalan süre ise yalnız karakter oyundan düzgün çıkarken güncellenir. Çekirdek çökünce bu güncelleme yapılmaz ve oyuncu bir sonraki girişte etkiyi tablodaki ilk süresiyle geri alır.
affect.add ile verdiğim bonus ölünce gidiyor, affect.add_collect ile verdiğim kalıyor. Neden?
affect.add etkiyi 1000 numaralı türle, affect.add_collect 515 numaralı AFFECT_COLLECT türüyle ekler. Ölümde 500-599 arasındaki türler korunur, 1000 numaralı tür diğer etkilerle birlikte silinir.
Yeni eklediğim etkinin simgesi neden ekranda görünmüyor?
İstemcinin etki penceresi 500'den küçük türleri yok sayar; onların simgesi AFF bayrağından gelir. 500 ve üstü türler için uiaffectshower.py'deki AFFECT_DATA_DICT'te o türün satırı, 510 numaralı nesne marketi türü için ise 1000 + puan numarası satırı olmalıdır.

İlgili sayfalar

Kategori: Server Kurma Kaynak Kod affect etki iksir kaynak kod quest

Bu sayfadaki bilgiler Metin2'nin sunucu yazılımındaki hesaplamalara ve standart oyun dosyalarına dayanır. Oyun dosyalarını değiştiren sunucularda değerler farklı olabilir. İçerikleri nasıl hazırlıyoruz?

Bu sayfa işine yaradı mı?

Giriş yap, oy ver ya da sayfayı kaydet. Okumak için üyelik gerekmez. WhatsApp X'te paylaş
Yanlış ya da eksik bir bilgi mi gördün? Bildir
Neyin yanlış olduğunu, doğrusunun ne olduğunu ve bunu nereden bildiğini yaz. Mesajın editörlere gider; yazı, kontrol edildikten sonra düzeltilir.
Yalnız editör görür.

Tartışma

Kurallar

Henüz yorum yok. Bu konuda bir deneyimin ya da sorun varsa ilk yorumu sen yaz.

Giriş yap ya da kayıt ol, sonra yorum yaz. Metin2VIP üyeliği hiçbir oyun sunucusunun hesabı değildir.