İçeriğe geç

Metin2 Yeni Efsun (Bonus) Ekleme: Sunucu ve İstemci

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

Kısaca: Metin2'de bir efsun iki numarayla çalışır: eşyada yazan APPLY türü ve karakterde tutulan POINT değeri. Yeni efsun için sunucuda APPLY ve POINT sabitleri, ikisini eşleyen aApplyInfo satırı, ApplyPoint ve PointChange dalları ve değerin okunduğu hesap eklenir; db'de item_proto ad listesi ve item_attr ENUM'u, istemcide sabit, ipucu satırı ve locale_game.txt metni değişir. Numara her listede aynı sırada olmalı ve bu yapıda 127'yi geçmemelidir.
İçindekiler
  1. APPLY ve POINT neden ayrı?
  2. Sunucuda sabitler
  3. Değer karaktere nasıl eklenir?
  4. Hesapta nerede okunur?
  5. item_proto ve item_attr
  6. İstemci: sabit, ipucu ve metin
  7. Bu kaynakta yarım kalmış bir örnek
  8. Sıra, numara ve sık yapılan hatalar

Metin2'de bir efsun iki numarayla çalışır. Eşyada, item_proto'da ve item_attr tablosunda yazan numara APPLY türüdür; karakterin üzerinde tutulan ve hasar hesabının okuduğu değer ise POINT'tir. Eşya giyilince oyun çekirdeği her APPLY'yi bir tablo üzerinden POINT'e çevirip karaktere ekler. Yeni bir efsun eklemek, bu zincirin her halkasına aynı numarayla bir satır yazmak demektir: sunucuda sabitler, karaktere uygulama ve hesap; db'de proto ve efsun tablosu; istemcide sabit, ipucu ve metin.

Aşağıdaki 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ı yerlerdedir. Örnek olarak bu kaynakta bulunmayan "Patronlara karşı güç" efsunu eklenir: APPLY_ATTBONUS_BOSS 107, POINT_ATTBONUS_BOSS 152. Efsunun oyuncu tarafı efsun sistemi, mevcut efsunların listesi efsun listesi sayfasında.

APPLY ve POINT neden ayrı?

APPLY, "eşya ne veriyor" sorusunun cevabıdır; POINT, "karakterde ne birikiyor" sorusunun. İkisi çoğu zaman bire birdir, ama her zaman değil: APPLY_CON tek bir APPLY olduğu hâlde ApplyPoint içinde hem POINT_HT'yi hem en yüksek HP'yi hem dayanıklılığı değiştirir. Bu kaynağın sayıları şöyledir:

Sabit Değer Nerede
MAX_APPLY_NUM 107 (APPLY 0-106) common/length.h, EApplyTypes
En büyük POINT 151 (POINT_RESIST_HUMAN) game/src/char.h, EPointTypes
POINT_MAX_NUM 255, sabit common/length.h
İstemcinin kendi puanları 200-204 (POINT_MIN_WEP ...) UserInterface/Packet.h

POINT_MAX_NUM sabit olduğu için yeni bir POINT, karakter puanlarının istemciye giden paket boyunu değiştirmez. Bazı POINT'lerin ise hiç APPLY karşılığı yoktur: böceklere, ateş, buz ve çöl canavarlarına, ağaçlara karşı güç puanları CalcAttBonus içinde okunur ama bunları dolduran bir efsun ya da PointChange dalı yoktur. Bunlardan birini efsun yapmak isteyen için hesap kısmı zaten hazırdır.

Sunucuda sabitler

Önce iki enum'a birer değer eklenir. Değeri elle yazmak iyi bir alışkanlıktır: bu kaynakta 92-106 arası elle yazılmıştır, bu sayede Lycan ya da kuşak bayrağı kapatıldığında sonraki numaralar kaymaz.

// common/length.h, EApplyTypes
	APPLY_RESIST_HUMAN = 105,
	APPLY_MOUNT = 106,
	APPLY_ATTBONUS_BOSS = 107,
	MAX_APPLY_NUM,

// game/src/char.h, EPointTypes
	POINT_RESIST_HUMAN = 151,
	POINT_ATTBONUS_BOSS = 152,

game/src/constants.cpp içindeki aApplyInfo dizisi APPLY'yi POINT'e çevirir ve sıra sayısıyla okunur; yeni satır tam 107. sırada, APPLY_MOUNT satırının altında olmalıdır. Aynı dosyadaki c_aApplyTypeNames tablosu ise öneksiz kısa adları sayıya çevirir. Bu tabloyu blend.txt (şebnemler), dragon_soul_table.txt ve special_item_group'taki attr grupları kullanır. Bulunamayan ad blend.txt'de hata vermeden 0'a, yani "efsun yok"a döner; diğer iki okuyucu syserr'e yazıp dosyayı reddeder.

	{ POINT_NONE,			}, //APPLY_MOUNT,106
	{ POINT_ATTBONUS_BOSS,	}, //APPLY_ATTBONUS_BOSS,107
};
...
	{ "ATTBONUS_BOSS",	APPLY_ATTBONUS_BOSS },
	{ NULL,		0			}

Değer karaktere nasıl eklenir?

Eşya giyilince CItem::ModifyPoints dört sabit efsunu ve eşyadaki efsun yuvalarını tek tek CHARACTER::ApplyPoint'e yollar. ApplyPoint büyük bir switch'tir; yeni APPLY, değeri doğrudan POINT'e ekleyen gruba yazılır:

	case APPLY_RESIST_MAGIC_REDUCTION:	//98
#endif
	case APPLY_ATTBONUS_BOSS:
		PointChange(aApplyInfo[bApplyType].bPointType, iVal);
		break;

Dal yoksa değer karaktere hiç eklenmez ve syserr'e Unknown apply type 107 name <karakter> yazılır. İkinci switch CHARACTER::PointChange içindedir; yeni POINT, SetPoint(type, GetPoint(type) + amount) yapan gruba (POINT_RESIST_HUMAN'ın yanına) eklenir. Unutulursa syserr'e unknown point change type 152 düşer. ComputePoints bütün anlık puanları sıfırlayıp eşyaları ve etkileri yeniden uyguladığı için ona dokunmak gerekmez.

Hesapta nerede okunur?

Puanın bir işe yaraması için onu bir formülün okuması gerekir. Irk ve sınıf bonusları game/src/battle.cpp içindeki CalcAttBonus'ta toplanır. Bu fonksiyon düz vuruşta, okta, büyü becerilerinde ve becerilerin atk değerini veren yakın dövüş hesabında çağrıldığı için tek bir satır hepsini kapsar:

	if (pkVictim->IsNPC())
	{
		...
		iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_MONSTER)) / 100;

		if (!pkVictim->IsStone() && pkVictim->GetMobRank() >= MOB_RANK_BOSS)
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_BOSS)) / 100;
	}

IsStone denetimi bilerek konuldu: varsayılan mob_proto'daki 147 metin taşının hepsi BOSS ya da KING rütbesindedir, denetim olmadan efsun metinlere de işler. Savunma türü bir efsun aynı fonksiyonun ikinci yarısına, saldıranın sınıfına göre iAtk -= ... yapan bloğun yanına yazılır. Mevcut formüllerin sırası ve sınırları hasar hesaplama ve ırk bonusları yazılarında. Test için /state <ad> GM komutu karakterin bonuslarını yazar; yeni puanı do_state çıktısına eklemek denemeyi kolaylaştırır.

item_proto ve item_attr

db, item_proto.txt'deki ApplyType sütunlarını ProtoReader.cpp içindeki get_Item_ApplyType_Value ile sayıya çevirir. Fonksiyon bir ad dizisinde arama yapar ve adın dizideki sırasını numara olarak döndürür. Bu yüzden "APPLY_ATTBONUS_BOSS" tam 107. sıraya, "APPLY_MOUNT"'un altına yazılmalıdır; dizi şu an 107 ad içerir. Tanınmayan ad db'yi ItemProto Reading Failed : Invalid value iletisiyle kapatır. Sütunların geri kalanı item_proto yazısında.

Efsun nesneleriyle gelen efsunlar item_attr ve item_attr_rare tablolarından okunur. db burada adı değil ENUM'daki sırayı kullanır (SELECT apply, apply+0 ...). Paketin şeması ENUM'u RESIST_PENETRATE'te (91), güncelleme dosyası RESIST_CLAW'da (96) bitirir. 107 numaralı efsun için arada 97-106'yı karşılayan on ad gerekir:

ALTER TABLE item_attr MODIFY COLUMN apply ENUM(
  'MAX_HP', 'MAX_SP', ..., 'RESIST_WOLFMAN', 'RESIST_CLAW',
  'ACCEDRAIN_RATE', 'RESIST_MAGIC_REDUCTION', 'ENCHANT_ELECT', 'ENCHANT_FIRE',
  'ENCHANT_ICE', 'ENCHANT_WIND', 'ENCHANT_EARTH', 'ENCHANT_DARK',
  'RESIST_HUMAN', 'MOUNT', 'ATTBONUS_BOSS'
) NOT NULL DEFAULT 'MAX_HP';

Mevcut adlar yerinde kalır, yeni adlar yalnız sona eklenir; araya eklenen bir ad sonraki bütün satırların numarasını kaydırır. item_attr_rare için aynı komut tekrarlanır. Sonra efsunun satırı eklenir; sütunların anlamı ve olasılıklar item_attr yazısında. Oyun çekirdeği açılışta db'den gelen her satırı syslog'a ITEM_ATTR[107]: ATTBONUS_BOSS ... diye yazar; köşeli parantezdeki sayı 107 değilse ENUM sırası yanlıştır. MAX_APPLY_NUM ve üstündeki numaralar sessizce atlanır.

İstemci: sabit, ipucu ve metin

İstemcide dört dosya değişir:

  1. GameLib/ItemData.h: CItemData içindeki enum'a APPLY_ATTBONUS_BOSS = 107.
  2. UserInterface/PythonItemModule.cpp: Python'a sabit açılır.
  3. root/uitooltip.py: AFFECT_DICT sözlüğüne satır eklenir. Aynı sözlük hem proto efsunlarını hem efsun yuvalarını yazar.
  4. locale_game.txt: ipucu metni.
	PyModule_AddIntConstant(poModule, "APPLY_ATTBONUS_BOSS", CItemData::APPLY_ATTBONUS_BOSS);
	AFFECT_DICT.update({
		item.APPLY_ATTBONUS_BOSS : localeInfo.TOOLTIP_APPLY_ATTBONUS_BOSS,
	})
TOOLTIP_APPLY_ATTBONUS_BOSS	Patronlara karşı güçlü +%%%d	SA

locale satırı sekmeyle ayrılmış üç alandır. Üçüncü alan SA, metni değeri alan bir fonksiyona çevirir; %% yüzde işaretini, %d değeri yazar ve ipucunda "+%10" görünür. SA unutulursa sözlükteki değer düz metin kalır ve ipucunda UNKNOWN_VALUE[107] 10 çıkar; sözlükte satır hiç yoksa UNKNOWN_TYPE[107] 10. AFFECT_DICT sınıf gövdesinde kurulduğu için item.APPLY_ATTBONUS_BOSS ya da localeInfo.TOOLTIP_... adlarından biri tanımsızsa uitooltip.py ilk içe aktarıldığı anda, yani karakter oluşturma ya da yükleme ekranına geçilirken istemci AttributeError ile kapanır. Dosyaların yeri ve kodlaması client locale dosyaları yazısında.

İstemcinin item_proto'sunu üreten dump_proto'nun ItemCSVReader.cpp dosyasında da aynı sırayla çalışan bir ad dizisi (arIATVApplyType) vardır; yeni ad buraya da 107. sıraya eklenir ve araç yeniden derlenir. Araçların ayrıntısı proto araçları, derleme source derleme yazısında.

Quest tarafı için questlib.lua'daki apply tablosu da güncellenir; bu tablo bu pakette yalnız 74'e kadar ad içerir: ["ATTBONUS_BOSS"] = 107, satırıyla quest'ler affect.add_collect(apply.ATTBONUS_BOSS, 10, 600) yazabilir.

Bu kaynakta yarım kalmış bir örnek

APPLY_RESIST_HUMAN (105) ve altı APPLY_ENCHANT_* efsunu (99-104) bu kaynağa sonradan eklenmiş ama tamamlanmamıştır. Enum değerleri, aApplyInfo satırları, db'nin ad dizisi, PointChange dalları ve istemcideki ipucu metinleri vardır; ApplyPoint'te dal yoktur ve hiçbir hesap bu puanları okumaz. Varsayılan item_proto'da 50 satır APPLY_RESIST_HUMAN taşır; bunların hepsi Kyanit Zırh, Kyanit Giysi, Kyanit Plaka Zırhı, Kyanit Kıyafet ve Kyanit Cebe serilerinin +0-+9 satırlarıdır. ENCHANT türleri 1.214 satırda geçer.

Bu yüzden oyuncu ipucunda "Yarı insanlara karşı direnç" satırını görür, ama değer karaktere eklenmez ve karakterin puanları her hesaplandığında, eşyayı giyip çıkarırken de, syserr'e Unknown apply type 105 düşer. Bu efsunları çalıştırmak isteyen sunucu sahibi yukarıdaki iki adımı yapar: ApplyPoint'e dal ve CalcAttBonus'a okuma satırı.

Sıra, numara ve sık yapılan hatalar

Sınır Nedeni
APPLY en çok 127 player.item.attrtype0-6 ve MySQL'deki item_proto.applytype0-3 işaretli tinyint(4)
APPLY en çok 255 Kodda APPLY türleri bir bayttır (TItemApply, TPlayerItemAttribute, quest'teki affect.add)
POINT 200'den küçük İstemci 200-204'ü kendi hesapladığı silah ve isabet puanlarına ayırır
ad dizileri = enum sırası db ve dump_proto adı dizideki sırasıyla sayıya çevirir
item_attr ENUM = enum sırası db apply+0 okur
  • Bir numarayı atlamak ya da enum'un ortasına değer eklemek: ad dizileri ve aApplyInfo sırayla okunduğu için sonraki bütün efsunlar kayar. Kayma eşyada başka bir efsun adı olarak görünür; ayrıntısı sistem ekleme hataları yazısındaki enum bölümünde.
  • Yalnız game'i derlemek: common/length.h iki çekirdeğin ortak dosyasıdır, db de yeniden derlenmelidir.
  • Sunucu numarasını değiştirip istemci item_proto'sunu yeniden üretmemek: ipucu eski numaraya göre yazılır.
  • Başka bir kaynaktan sistem taşırken numarayı denetlememek: o sistem 107'yi başka bir efsuna vermiş olabilir.
  • Değeri efsun yuvasına sığdırmamak: yuva değeri short'tur, 32.767'yi geçemez.

Sık sorulan sorular

Yeni efsunu ekledim, eşyada görünüyor ama hasara etkisi yok. Neden?
İstemci ipucunu yalnız APPLY numarasına bakarak yazar; değerin işlemesi sunucudaki ApplyPoint dalına ve değerin bir hesapta okunmasına bağlıdır. ApplyPoint'te dal yoksa syserr'e Unknown apply type satırı düşer, hesap yoksa değer karakterde durur ama hiçbir şeyi değiştirmez.
item_attr tablosuna yeni efsunu ekledim, ama efsun nesnesi başka bir efsun basıyor. Neden?
db çekirdeği apply sütununu ENUM'daki sırasıyla, apply+0 diye okur. Yeni adın ENUM'daki sırası APPLY numarasıyla aynı değilse çekirdek o satırı başka bir efsun sanır. Bu yapıda ENUM 96'da biter; 107 numaralı bir efsun için arada 97-106 arasını dolduran on ad gerekir.
Efsun numarası en çok kaç olabilir?
Kodun kendisi bir bayt, yani 255'e kadar izin verir, ama player.item tablosundaki attrtype sütunları ve MySQL'deki item_proto tablosunun applytype sütunları işaretli tinyint'tir. Bu yüzden bu yapıda yeni efsun numarası 127'yi geçmemelidir.

İlgili sayfalar

Kategori: Server Kurma Kaynak Kod efsun kaynak kod bonus item_attr apply

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.