- Katılım
- 22 Mar 2026
- Mesajlar
- 44
- Tepkime puanı
- 5
- Puan
- 8
1) İşlem sırası (özet)
2) Sunucu — cmd.cpp
Adım A1 — Ön bildirim
Ne yapıyoruz: Derleyiciye do_item_gm7 fonksiyonunun varlığını bildiriyoruz.
Ara:
Bulacağın örnek:
Yap:
satırının hemen altına ekle:
Adım A2 — Komut tablosu
Ne yapıyoruz: Sohbette /item7 yazılınca hangi fonksiyon ve GM seviyesi çalışacak, cmd_info[] içine yazıyoruz.
Ara:
Bulacağın örnek:
Yap: item satırının altına ekle:
Not: GM seviyesini kendi sunucuna göre (ör. GM_IMPLEMENTOR) değiştirebilirsin.
3) Sunucu — cmd_gm.cpp
Ne yapıyoruz: /item7 gövdesi: vnum veya isim, adet, ITEM_ATTRIBUTE_MAX_NUM kadar (tip, değer) çifti, ITEM_SOCKET_MAX_NUM kadar socket, CreateItem, SetForceAttribute, SetSocket, AutoGiveItem, log.
Ara:
— klasik GM item komutu (vnum + adet).
Nereye: do_item fonksiyonunun kapatan
ile bir sonraki
satırı arasına aşağıdaki bloğun tamamını yapıştır.
Derleme: cmd_gm.cpp zaten projendeyse ekstra .cpp ekleme; game core’u yeniden derle.
Ek dosya: Birçok sürümde cmd.h içinde ayrıca tanım gerekmez; ön bildirimler cmd.cpp içindeki ACMD(...) satırlarıyla gider.
4) İstemci — uigmitempanel.py
Ne yapıyoruz: Panel mantığı: arama, 7 efsun + 3 taş, açılır liste (alt satır gizleme), /item7 satırını net.SendChatPacket ile gönderme.
Yol:
Yap: Aşağıdaki spoiler içindeki metni uigmitempanel.py dosyasına komple yapıştır (UTF-8 veya cp1254, sunucu diline göre).
5) İstemci — uiscript/gmpanel_item.py
Ne yapıyoruz: Pencere iskeleti (GmItemPanel): başlık, arama, liste, scrollbar, adet, Ekle / İptal. Efsun/taş satırları LoadWindow içinde Python ile eklenir.
Yol:
6) İstemci — interfacemodule.py
B3-1 — Import
Ara: Diğer
satırları.
yoksa ekle.
B3-2 — Oluşturma (Interface.__init__)
Ara:
Hemen altına:
B3-3 — Destroy
Ara:
Altına:
B3-4 — del
Ara:
Altına:
B3-5 — Toggle
Ara:
civarı / Calling Functions bölümü.
Ekle:
B3-6 — Toplu Hide
Çok pencerenin
olduğu yere:
7) İstemci — game.py
Ara:
Örnek altına ekle:
F10 doluysa F11 vb. kullan; önemli olan ToggleItemEditPanel çağrısı.
8) Sohbet formatı (uyum)
Panel Ekle deyince örnek yapı:
7 kez:
— final = değer × yüzde / 100
Sunucu one_argument ile sırayla okur; apply sayısı ITEM_ATTRIBUTE_MAX_NUM, socket ITEM_SOCKET_MAX_NUM.
9) Özet tablo
- Sunucu: cmd.cpp → ön bildirim + cmd_info satırı → cmd_gm.cpp → derle
- İstemci: uigmitempanel.py + gmpanel_item.py → interfacemodule.py → game.py → root paketle
2) Sunucu — cmd.cpp
Adım A1 — Ön bildirim
Ne yapıyoruz: Derleyiciye do_item_gm7 fonksiyonunun varlığını bildiriyoruz.
Ara:
Kod:
ACMD(do_item);
Bulacağın örnek:
Kod:
ACMD(do_item);
ACMD(do_mob);
Yap:
Kod:
ACMD(do_item);
satırının hemen altına ekle:
Kod:
ACMD(do_item_gm7);
Adım A2 — Komut tablosu
Ne yapıyoruz: Sohbette /item7 yazılınca hangi fonksiyon ve GM seviyesi çalışacak, cmd_info[] içine yazıyoruz.
Ara:
Kod:
{ "item", do_item,
Bulacağın örnek:
Kod:
{ "item", do_item, 0, POS_DEAD, GM_GOD },
{ "mob", do_mob, 0, POS_DEAD, GM_HIGH_WIZARD },
Yap: item satırının altına ekle:
Kod:
{ "item7", do_item_gm7, 0, POS_DEAD, GM_GOD },
Not: GM seviyesini kendi sunucuna göre (ör. GM_IMPLEMENTOR) değiştirebilirsin.
3) Sunucu — cmd_gm.cpp
Ne yapıyoruz: /item7 gövdesi: vnum veya isim, adet, ITEM_ATTRIBUTE_MAX_NUM kadar (tip, değer) çifti, ITEM_SOCKET_MAX_NUM kadar socket, CreateItem, SetForceAttribute, SetSocket, AutoGiveItem, log.
Ara:
Kod:
ACMD(do_item)
Nereye: do_item fonksiyonunun kapatan
Kod:
}
ile bir sonraki
Kod:
ACMD(do_...)
satırı arasına aşağıdaki bloğun tamamını yapıştır.
ACMD(do_item_gm7)
{
const char * line = argument;
char arg[256];
line = one_argument(line, arg, sizeof(arg));
if (!*arg)
{
ch->ChatPacket(CHAT_TYPE_INFO, "Usage: item7 <vnum|name> <count> [tip0 val0] x7 [socket0 socket1 socket2] (tas vnum, 0=bos)");
return;
}
DWORD dwVnum = 0;
if (isnhdigit(*arg))
str_to_number(dwVnum, arg);
else if (!ITEM_MANAGER::instance().GetVnum(arg, dwVnum))
{
ch->ChatPacket(CHAT_TYPE_INFO, "Item bulunamadi: %s", arg);
return;
}
line = one_argument(line, arg, sizeof(arg));
int iCount = 1;
if (*arg)
{
str_to_number(iCount, arg);
iCount = MINMAX(1, iCount, g_bItemCountLimit);
}
long attr_type[ITEM_ATTRIBUTE_MAX_NUM];
long attr_val[ITEM_ATTRIBUTE_MAX_NUM];
memset(attr_type, 0, sizeof(attr_type));
memset(attr_val, 0, sizeof(attr_val));
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
{
line = one_argument(line, arg, sizeof(arg));
if (!*arg)
break;
str_to_number(attr_type, arg);
line = one_argument(line, arg, sizeof(arg));
if (!*arg)
break;
str_to_number(attr_val, arg);
}
LPITEM item = ITEM_MANAGER::instance().CreateItem(dwVnum, iCount, 0, true);
if (!item)
{
ch->ChatPacket(CHAT_TYPE_INFO, "item7: #%u olusturulamadi.", dwVnum);
return;
}
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
item->SetForceAttribute(i, (BYTE) attr_type, (short) attr_val);
long socket_val[ITEM_SOCKET_MAX_NUM];
memset(socket_val, 0, sizeof(socket_val));
for (int s = 0; s < ITEM_SOCKET_MAX_NUM; ++s)
{
line = one_argument(line, arg, sizeof(arg));
if (*arg)
str_to_number(socket_val, arg);
}
for (int s = 0; s < ITEM_SOCKET_MAX_NUM; ++s)
item->SetSocket(s, socket_val);
#ifdef __WJ_PICKUP_ITEM_EFFECT__
ch->AutoGiveItem(item, false, true);
#else
ch->AutoGiveItem(item, false);
#endif
LogManager::instance().ItemLog(ch, item, "GM_ITEM7", item->GetName());
ch->ChatPacket(CHAT_TYPE_INFO, "item7: %s verildi.", item->GetName());
}
{
const char * line = argument;
char arg[256];
line = one_argument(line, arg, sizeof(arg));
if (!*arg)
{
ch->ChatPacket(CHAT_TYPE_INFO, "Usage: item7 <vnum|name> <count> [tip0 val0] x7 [socket0 socket1 socket2] (tas vnum, 0=bos)");
return;
}
DWORD dwVnum = 0;
if (isnhdigit(*arg))
str_to_number(dwVnum, arg);
else if (!ITEM_MANAGER::instance().GetVnum(arg, dwVnum))
{
ch->ChatPacket(CHAT_TYPE_INFO, "Item bulunamadi: %s", arg);
return;
}
line = one_argument(line, arg, sizeof(arg));
int iCount = 1;
if (*arg)
{
str_to_number(iCount, arg);
iCount = MINMAX(1, iCount, g_bItemCountLimit);
}
long attr_type[ITEM_ATTRIBUTE_MAX_NUM];
long attr_val[ITEM_ATTRIBUTE_MAX_NUM];
memset(attr_type, 0, sizeof(attr_type));
memset(attr_val, 0, sizeof(attr_val));
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
{
line = one_argument(line, arg, sizeof(arg));
if (!*arg)
break;
str_to_number(attr_type, arg);
line = one_argument(line, arg, sizeof(arg));
if (!*arg)
break;
str_to_number(attr_val, arg);
}
LPITEM item = ITEM_MANAGER::instance().CreateItem(dwVnum, iCount, 0, true);
if (!item)
{
ch->ChatPacket(CHAT_TYPE_INFO, "item7: #%u olusturulamadi.", dwVnum);
return;
}
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
item->SetForceAttribute(i, (BYTE) attr_type, (short) attr_val);
long socket_val[ITEM_SOCKET_MAX_NUM];
memset(socket_val, 0, sizeof(socket_val));
for (int s = 0; s < ITEM_SOCKET_MAX_NUM; ++s)
{
line = one_argument(line, arg, sizeof(arg));
if (*arg)
str_to_number(socket_val, arg);
}
for (int s = 0; s < ITEM_SOCKET_MAX_NUM; ++s)
item->SetSocket(s, socket_val);
#ifdef __WJ_PICKUP_ITEM_EFFECT__
ch->AutoGiveItem(item, false, true);
#else
ch->AutoGiveItem(item, false);
#endif
LogManager::instance().ItemLog(ch, item, "GM_ITEM7", item->GetName());
ch->ChatPacket(CHAT_TYPE_INFO, "item7: %s verildi.", item->GetName());
}
Derleme: cmd_gm.cpp zaten projendeyse ekstra .cpp ekleme; game core’u yeniden derle.
Ek dosya: Birçok sürümde cmd.h içinde ayrıca tanım gerekmez; ön bildirimler cmd.cpp içindeki ACMD(...) satırlarıyla gider.
4) İstemci — uigmitempanel.py
Ne yapıyoruz: Panel mantığı: arama, 7 efsun + 3 taş, açılır liste (alt satır gizleme), /item7 satırını net.SendChatPacket ile gönderme.
Yol:
Kod:
pack/root/uigmitempanel.py
Yap: Aşağıdaki spoiler içindeki metni uigmitempanel.py dosyasına komple yapıştır (UTF-8 veya cp1254, sunucu diline göre).
# -*- coding: utf-8 -*-
import ui
import net
import player
import chr
import chat
import app
import item
import localeInfo
def _wnd_text(s):
"""WndMgr genelde byte string ister; unicode kaynakli 'Nesne' kalmasini onler."""
if s is None:
return ""
if isinstance(s, str):
return s
if isinstance(s, unicode):
try:
return s.encode("cp1254")
except UnicodeEncodeError:
return s.encode("utf-8", "replace")
return str(s)
def _short_label(s):
if not isinstance(s, basestring):
s = str(s)
if len(s) > 52:
return s[:49] + "..."
return s
COMBO_DROP_MAX_H = 240
class GmComboBox(ui.ComboBox):
"""Satirda acilir secilebilir liste (Metin2 ComboBox)."""
MAX_DROP = COMBO_DROP_MAX_H
def __init__(self):
# ComboBox.__init__ listeyi TOP_MOST'ta acar; Board cocuklari UI katmaninda
# sonra cizildigi icin liste gorunurde altta kalir. Liste UI katmaninda olmali.
ui.Window.__init__(self)
self.x = 0
self.y = 0
self.width = 0
self.height = 0
self.isSelected = False
self.isOver = False
self.isListOpened = False
self.event = lambda *arg: None
self.enable = True
self.textLine = ui.MakeTextLine(self)
self.textLine.SetText(localeInfo.UI_ITEM)
self.listBox = ui.ComboBox.ListBoxWithBoard("UI")
self.listBox.SetPickAlways()
self.listBox.SetParent(self)
self.listBox.SetEvent(ui.__mem_func__(self.OnSelectItem))
self.listBox.Hide()
self._gm_z_panel = None
self._gm_z_kind = None
self._gm_z_idx = 0
try:
self.listBox.AddFlag("float")
except Exception:
pass
if app.ENABLE_MOUSEWHEEL_EVENT:
try:
self.listBox.SetMouseWheelScrollEvent(ui.__mem_func__(self._on_combo_list_wheel))
except Exception:
pass
def SetGmDropdownShield(self, panel, kind, index):
"""kind: 'attr' | 'stone' — acilir liste acikken alt satirlar panel tarafindan gizlenir."""
self._gm_z_panel = panel
self._gm_z_kind = kind
self._gm_z_idx = index
def _on_combo_list_wheel(self, mode):
if not self.isListOpened:
return
n = self.listBox.GetItemCount()
v = max(1, self.listBox.GetViewItemCount())
mx = max(0, n - v)
if mx <= 0:
return
bp = getattr(self.listBox, "basePos", 0)
if mode == "UP":
bp = max(0, bp - 1)
else:
bp = min(mx, bp + 1)
self.listBox.SetBasePos(bp)
def CloseListBox(self):
self.isListOpened = False
p = getattr(self, "_gm_z_panel", None)
if p:
try:
p.OnGmComboDropdownClose(self)
except Exception:
pass
if self.listBox:
self.listBox.Hide()
def OnSelectItem(self, index, name):
self.CloseListBox()
self.SetCurrentItem(_wnd_text(_short_label(name)))
self.event(index)
def InsertItem(self, index, name):
self.listBox.InsertItem(index, name)
n = self.listBox.GetItemCount()
step = getattr(self.listBox, "stepSize", 17)
h = min(max(n * step, 17), self.MAX_DROP)
self.listBox.SetSize(self.width, h)
self.listBox._LocateItem()
def OnMouseLeftButtonUp(self):
if not self.enable:
return
self.isSelected = False
if self.isListOpened:
self.CloseListBox()
else:
if self.listBox.GetItemCount() > 0:
p = getattr(self, "_gm_z_panel", None)
if p:
try:
p.OnGmComboDropdownOpen(self)
except Exception:
pass
self.isListOpened = True
self.listBox.Show()
self.__ArrangeListBox()
try:
self.listBox.SetTop()
except Exception:
pass
# --- Ayarlar ---
MAX_ARAMA_SONUC = 50
ATTR_SATIR = 7
TAS_SOCKET_SAYISI = 3
ATTR_ROW_STEP = 26
# Sunucu APPLY tipi (byte) = ilk sütun; isimler sabit TR (uitooltip yerine)
GM_APPLY_OPTIONS = (
(0, u"- Efsun yok -"),
(1, u"Maximum HP"),
(2, u"Maximum MP"),
(3, u"Ya\u015fam Enerjisi"),
(4, u"G\xfc\xe7"),
(5, u"Dayan\u0131kl\u0131l\u0131k"),
(6, u"\xc7eviklik"),
(7, u"Sald\u0131r\u0131 H\u0131z\u0131"),
(8, u"Hareket H\u0131z\u0131"),
(9, u"B\xfcy\xfc H\u0131z\u0131"),
(10, u"Hp \xdcretimi"),
(11, u"MP \xdcretimi"),
(12, u"Zehirlenme De\u011fi\u015fimi"),
(13, u"Sersemletme \u015eans\u0131"),
(14, u"Yava\u015fl\u0131k De\u011fi\u015fimi"),
(15, u"Kritik Vuru\u015f \u015eans\u0131"),
(16, u"Delici Vuru\u015f \u015eans\u0131"),
(17, u"Yar\u0131 \u0130nsana Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(18, u"Hayvanlara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(19, u"Orklara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(20, u"Misiklere Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(21, u"\xd6l\xfcms\xfczlere Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(22, u"\u015eytanlara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(23, u"%? Hasar Hp Taraf\u0131ndan Emilecek"),
(24, u"%? Hasar Mp Taraf\u0131ndan Emilecek"),
(25, u"D\xfc\u015fmandan Sp \xe7alma \u015eans\u0131"),
(26, u"%? Vururken Sp Alma \u015eans\u0131"),
(27, u"Beden Kar\u015f\u0131s\u0131nda Atak Bloklanmas\u0131"),
(28, u"Oklardan Korunma \u015eans\u0131"),
(29, u"K\u0131l\u0131\xe7 Savunmas\u0131"),
(30, u"\xc7ift El Savunma"),
(31, u"Han\xe7er Savunmas\u0131"),
(32, u"\xc7an Savunmas\u0131"),
(33, u"Yelpaze Savunmas\u0131"),
(34, u"Oka Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(35, u"Ate\u015fe Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(36, u"\u015eim\u015fek Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(37, u"B\xfcy\xfcye Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(38, u"R\xfczgara Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(39, u"V\xfccut Darbelerini Yans\u0131tma \u015eans\u0131"),
(40, u"Lanet Yans\u0131tmas\u0131"),
(41, u"Giftwiderstand"),
(42, u"Sp Y\xfcklemesi %? De\u011fi\u015fti"),
(43, u"%? Exp Bonus \u015eans\u0131"),
(44, u"% Kat Yang D\xfc\u015fme \u015eans\u0131"),
(45, u"% Kat E\u015fya d\xfc\u015fme \u015eans\u0131"),
(46, u"\u0130ksir %? Etki G\xf6sterdi"),
(47, u"Hp Y\xfcklemesi %? De\u011fi\u015fti"),
(48, u"Sersemlik Ba\u011f\u0131\u015f\u0131kl\u0131k"),
(49, u"Yava\u015flatma Ba\u011f\u0131\u015f\u0131kl\u0131k"),
(50, u"Yere D\xfc\u015fme Ba\u011f\u0131\u015f\u0131kl\u0131k"),
(51, u"UNKNOW_TYPE[51]"),
(52, u"Yay Menzili +? Metre"),
(53, u"Sald\u0131r\u0131 De\u011feri +"),
(54, u"Savunma +"),
(55, u"B\xfcy\xfcl\xfc Sald\u0131r\u0131 De\u011feri +"),
(56, u"B\xfcy\xfcl\xfc Savunma De\u011feri +"),
(57, u"UNKNOW_TYPE[57]"),
(58, u"Max. Dayan\u0131kl\u0131l\u0131k"),
(59, u"Sava\u015f\xe7\u0131lara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(60, u"Ninjalara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(61, u"Suralara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(62, u"\u015eamanlara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(63, u"Yarat\u0131klara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(64, u"Sald\u0131r\u0131 De\u011feri +?%"),
(65, u"Savunma +?%"),
(66, u"EXP +?%"),
(67, u"Elde Edilen Nesne Kat Say\u0131s\u0131"),
(68, u"Elde Edilen Yang Kat Say\u0131s\u0131"),
(69, u"UNKNOW_TYPE[69]"),
(70, u"UNKNOW_TYPE[70]"),
(71, u"Beceri Hasar\u0131"),
(72, u"Ortalama Zarar"),
(73, u"Tekrarlanan Beceri Hasar\u0131na Kar\u015f\u0131 Koyma"),
(74, u"Ortalama Zarara Direni\u015f"),
(75, u"UNKNOW_TYPE[75]"),
(76, u"\u0130cafe Exp Bonus +?%"),
(77, u"E\u015fya Ele Ge\xe7irme Art\u0131\u015f\u0131 ?/2"),
(78, u"Sava\u015f\xe7\u0131 Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
(79, u"Ninja Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
(80, u"Sura Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
(81, u"\u015eaman Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
)
_itemdesc_cache = None
def _load_itemdesc():
global _itemdesc_cache
if _itemdesc_cache is not None:
return _itemdesc_cache
_itemdesc_cache = {}
path = app.GetLocalePath() + "/itemdesc.txt"
try:
f = open(path, "r")
except IOError:
return _itemdesc_cache
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
parts = line.split("\t")
if len(parts) < 2:
continue
try:
vid = int(parts[0].strip())
name = parts[1].strip()
if name:
_itemdesc_cache[vid] = name
except ValueError:
continue
f.close()
return _itemdesc_cache
def _build_apply_list():
return list(GM_APPLY_OPTIONS)
def _build_metin_list(desc_dict):
out = [(0, "- Tas yok -")]
for vnum, name in sorted(desc_dict.iteritems(), key=lambda x: x[1].lower()):
if item.IsMetin(vnum):
out.append((vnum, "%s (%d)" % (name, vnum)))
return out
def _search_items(desc_dict, needle, limit):
if not needle:
return []
n = needle.lower()
res = []
for vnum, name in desc_dict.iteritems():
if n in name.lower():
res.append((vnum, name))
res.sort(key=lambda x: x[1].lower())
return res[:limit]
class GmItemPanel(ui.ScriptWindow):
def __init__(self):
ui.ScriptWindow.__init__(self)
self.board = None
self.searchEdit = None
self.resultList = None
self.selectedLabel = None
self.countEdit = None
self.spawnBtn = None
self.cancelBtn = None
self.btnSearch = None
self.previewImg = None
self.selectedVnum = 0
self._attr_apply = [0] * ATTR_SATIR
self._stone_vnum = [0] * TAS_SOCKET_SAYISI
self._attr_combos = []
self._attr_val_edits = []
self._attr_pct_edits = []
self._stone_combos = []
self._apply_items = []
self._metin_items = []
self.resultScroll = None
self._dyn = []
self._attr_row_blocks = []
self._stone_row_blocks = []
self._stone_title_line = None
self._gm_footer_btns = []
self._gm_dd_hidden = []
def __del__(self):
ui.ScriptWindow.__del__(self)
def _dyn_add(self, w):
self._dyn.append(w)
def _gm_dd_restore(self):
for w in getattr(self, "_gm_dd_hidden", []):
try:
w.Show()
except Exception:
pass
self._gm_dd_hidden = []
def OnGmComboDropdownClose(self, opener=None):
self._gm_dd_restore()
def OnGmComboDropdownOpen(self, opener):
for cb in self._attr_combos + self._stone_combos:
if cb is not opener and getattr(cb, "isListOpened", False):
try:
cb.CloseListBox()
except Exception:
pass
self._gm_dd_restore()
self._gm_dd_hidden = []
k = getattr(opener, "_gm_z_kind", None)
idx = getattr(opener, "_gm_z_idx", 0)
to_hide = []
if k == "attr":
for j in xrange(idx + 1, ATTR_SATIR):
to_hide.extend(self._attr_row_blocks[j])
if self._stone_title_line:
to_hide.append(self._stone_title_line)
for blk in self._stone_row_blocks:
to_hide.extend(blk)
to_hide.extend(self._gm_footer_btns)
elif k == "stone":
for j in xrange(idx + 1, TAS_SOCKET_SAYISI):
to_hide.extend(self._stone_row_blocks[j])
to_hide.extend(self._gm_footer_btns)
for w in to_hide:
if w is None:
continue
try:
w.Hide()
self._gm_dd_hidden.append(w)
except Exception:
pass
def LoadWindow(self):
try:
py = ui.PythonScriptLoader()
py.LoadScriptFile(self, "uiscript/gmpanel_item.py")
except:
import exception
exception.Abort("GmItemPanel.LoadWindow")
try:
self.board = self.GetChild("Board")
self.searchEdit = self.GetChild("SearchEdit")
self.resultList = self.GetChild("ResultList")
self.selectedLabel = self.GetChild("SelectedLabel")
self.countEdit = self.GetChild("CountValue")
self.spawnBtn = self.GetChild("SpawnButton")
self.cancelBtn = self.GetChild("CancelButton")
self.btnSearch = self.GetChild("SearchButton")
self.btnSearch.SetEvent(ui.__mem_func__(self.OnSearch))
self.resultScroll = self.GetChild("ResultScrollBar")
except:
import exception
exception.Abort("GmItemPanel.Bind")
self.resultScroll.SetScrollBarSize(100)
self.resultScroll.SetScrollEvent(ui.__mem_func__(self._on_result_scroll))
if app.ENABLE_MOUSEWHEEL_EVENT:
self.resultList.SetMouseWheelScrollEvent(ui.__mem_func__(self._on_result_list_wheel))
self.board.SetCloseEvent(ui.__mem_func__(self.Close))
self.spawnBtn.SetEvent(ui.__mem_func__(self.OnSpawn))
self.cancelBtn.SetEvent(ui.__mem_func__(self.Close))
self.searchEdit.SetReturnEvent(ui.__mem_func__(self.OnSearch))
self.searchEdit.SetEscapeEvent(ui.__mem_func__(self.Close))
self.countEdit.SetEscapeEvent(ui.__mem_func__(self.Close))
self.resultList.SetEvent(ui.__mem_func__(self.OnPickResult))
desc = _load_itemdesc()
self._apply_items = _build_apply_list()
self._metin_items = _build_metin_list(desc)
self.previewImg = ui.ImageBox()
self.previewImg.SetParent(self.board)
self.previewImg.SetPosition(300, 168)
try:
self.previewImg.AddFlag("not_pick")
except Exception:
pass
self.previewImg.Hide()
t = ui.TextLine()
t.SetParent(self.board)
t.SetPosition(12, 216)
t.SetText("Efsunlar:")
t.Show()
self._dyn_add(t)
base_y = 232
self._attr_row_blocks = []
for i in xrange(ATTR_SATIR):
row_y = base_y + i * ATTR_ROW_STEP
lb = ui.TextLine()
lb.SetParent(self.board)
lb.SetPosition(12, row_y + 3)
lb.SetText("%d." % (i + 1))
lb.Show()
self._dyn_add(lb)
cb = GmComboBox()
cb.SetParent(self.board)
cb.SetPosition(32, row_y)
cb.SetSize(214, 18)
cb.SetGmDropdownShield(self, "attr", i)
self._fill_gm_combo(cb, self._apply_items)
cb.SetEvent(lambda aid, r=i: self._on_attr_apply(r, aid))
cb.Enable()
cb.Show()
self._attr_combos.append(cb)
sb = ui.SlotBar()
sb.SetParent(self.board)
sb.SetPosition(256, row_y)
sb.SetSize(48, 18)
sb.Show()
self._dyn_add(sb)
ev = ui.EditLine()
ev.SetParent(sb)
ev.SetPosition(3, 3)
ev.SetSize(42, 16)
ev.SetMax(5)
ev.SetNumberMode()
ev.Show()
self._attr_val_edits.append(ev)
self._dyn_add(ev)
sb2 = ui.SlotBar()
sb2.SetParent(self.board)
sb2.SetPosition(310, row_y)
sb2.SetSize(44, 18)
sb2.Show()
self._dyn_add(sb2)
pv = ui.EditLine()
pv.SetParent(sb2)
pv.SetPosition(3, 3)
pv.SetSize(38, 16)
pv.SetMax(4)
pv.SetNumberMode()
pv.SetText("100")
pv.Show()
self._attr_pct_edits.append(pv)
self._dyn_add(pv)
self._attr_row_blocks.append([lb, cb, sb, sb2])
ts = ui.TextLine()
ts.SetParent(self.board)
ts.SetPosition(12, base_y + ATTR_SATIR * ATTR_ROW_STEP + 14)
ts.SetText("Taslar (max %d socket):" % TAS_SOCKET_SAYISI)
ts.Show()
self._dyn_add(ts)
self._stone_title_line = ts
stone_y = base_y + ATTR_SATIR * ATTR_ROW_STEP + 34
self._stone_row_blocks = []
for s in xrange(TAS_SOCKET_SAYISI):
sy = stone_y + s * ATTR_ROW_STEP
lb = ui.TextLine()
lb.SetParent(self.board)
lb.SetPosition(12, sy + 3)
lb.SetText("Tas %d:" % (s + 1))
lb.Show()
self._dyn_add(lb)
cb = GmComboBox()
cb.SetParent(self.board)
cb.SetPosition(52, sy)
cb.SetSize(368, 18)
cb.SetGmDropdownShield(self, "stone", s)
self._fill_gm_combo(cb, self._metin_items)
cb.SetEvent(lambda vid, idx=s: self._on_stone_pick(idx, vid))
cb.Enable()
cb.Show()
self._stone_combos.append(cb)
self._stone_row_blocks.append([lb, cb])
self._gm_footer_btns = [self.spawnBtn, self.cancelBtn]
self._sync_result_scroll()
def _fill_gm_combo(self, combo, pairs):
combo.ClearItem()
for k, t in pairs:
combo.InsertItem(k, _wnd_text(t))
if pairs:
combo.SetCurrentItem(_wnd_text(_short_label(pairs[0][1])))
def _on_attr_apply(self, row, apply_id):
self._attr_apply[row] = apply_id
def _on_stone_pick(self, slot_idx, vnum):
self._stone_vnum[slot_idx] = vnum
def _result_scroll_max(self):
n = self.resultList.GetItemCount()
v = max(1, self.resultList.GetViewItemCount())
return max(0, n - v)
def _on_result_scroll(self):
mx = self._result_scroll_max()
if mx <= 0:
self.resultList.SetBasePos(0)
return
pos = self.resultScroll.GetPos()
bp = int(round(pos * mx))
if bp > mx:
bp = mx
self.resultList.SetBasePos(bp)
def _on_result_list_wheel(self, mode):
mx = self._result_scroll_max()
if mx <= 0:
return
bp = getattr(self.resultList, "basePos", 0)
if mode == "UP":
bp = max(0, bp - 1)
else:
bp = min(mx, bp + 1)
self.resultList.SetBasePos(bp)
self.resultScroll.SetPos(float(bp) / float(mx))
def _sync_result_scroll(self):
n = self.resultList.GetItemCount()
if n == 0:
self.resultScroll.Hide()
self.resultScroll.SetPos(0.0)
self.resultList.SetBasePos(0)
return
mx = self._result_scroll_max()
if mx <= 0:
self.resultScroll.Hide()
self.resultScroll.SetPos(0.0)
self.resultList.SetBasePos(0)
return
self.resultScroll.Show()
v = max(1, self.resultList.GetViewItemCount())
self.resultScroll.SetMiddleBarSize(min(1.0, float(v) / float
))
bp = getattr(self.resultList, "basePos", 0)
if bp > mx:
bp = mx
self.resultList.SetBasePos(bp)
self.resultScroll.SetPos(float(bp) / float(mx))
def OnSearch(self):
desc = _load_itemdesc()
if not desc:
chat.AppendChat(chat.CHAT_TYPE_INFO, "[GM] itemdesc.txt yuklenemedi: %s" % (app.GetLocalePath() + "/itemdesc.txt"))
return
q = self.searchEdit.GetText().strip()
self.resultList.ClearItem()
self.resultList.SetBasePos(0)
self.resultScroll.SetPos(0.0)
found = _search_items(desc, q, MAX_ARAMA_SONUC)
for vnum, name in found:
self.resultList.InsertItem(vnum, "%d | %s" % (vnum, name))
self._sync_result_scroll()
if not found:
chat.AppendChat(chat.CHAT_TYPE_INFO, "[GM] Sonuc yok.")
def OnPickResult(self, vnum, text):
self.selectedVnum = vnum
self.selectedLabel.SetText("Secilen: %s" % text[:60])
self._refresh_preview()
def _refresh_preview(self):
if self.selectedVnum <= 0:
self.previewImg.Hide()
return
item.SelectItem(self.selectedVnum)
fn = item.GetIconImageFileName()
if not fn or fn == "Noname":
self.previewImg.Hide()
return
try:
self.previewImg.LoadImage(fn)
self.previewImg.Show()
except RuntimeError:
self.previewImg.Hide()
def Destroy(self):
if self.board:
self.board.SetCloseEvent(None)
if self.spawnBtn:
self.spawnBtn.SetEvent(None)
if self.cancelBtn:
self.cancelBtn.SetEvent(None)
if self.btnSearch:
self.btnSearch.SetEvent(None)
if self.searchEdit:
self.searchEdit.SetReturnEvent(ui.Window.NoneMethod)
self.searchEdit.SetEscapeEvent(ui.Window.NoneMethod)
if self.countEdit:
self.countEdit.SetEscapeEvent(ui.Window.NoneMethod)
if self.resultList:
self.resultList.SetEvent(None)
if app.ENABLE_MOUSEWHEEL_EVENT:
self.resultList.SetMouseWheelScrollEvent(None)
if self.resultScroll:
self.resultScroll.SetScrollEvent(None)
for cb in self._attr_combos:
try:
cb.CloseListBox()
except Exception:
pass
try:
cb.SetEvent(None)
cb.Destroy()
except Exception:
pass
for cb in self._stone_combos:
try:
cb.CloseListBox()
except Exception:
pass
try:
cb.SetEvent(None)
cb.Destroy()
except Exception:
pass
self._attr_combos = []
self._stone_combos = []
for w in self._dyn:
try:
w.Destroy()
except Exception:
pass
self._dyn = []
if self.previewImg:
try:
self.previewImg.Destroy()
except Exception:
pass
self.previewImg = None
self.ClearDictionary()
self.board = None
self.searchEdit = None
self.resultList = None
self.selectedLabel = None
self.countEdit = None
self.spawnBtn = None
self.cancelBtn = None
self.btnSearch = None
def Open(self):
if not chr.IsGameMaster(player.GetMainCharacterIndex()):
return
self.SetCenterPosition()
self.SetTop()
self.Show()
self.searchEdit.SetFocus()
def Close(self):
self._gm_dd_restore()
for cb in self._attr_combos + self._stone_combos:
try:
cb.CloseListBox()
except Exception:
pass
self.Hide()
return True
def Toggle(self):
if not chr.IsGameMaster(player.GetMainCharacterIndex()):
return
if self.IsShow():
self.Close()
else:
self.Open()
def OnSpawn(self):
if not chr.IsGameMaster(player.GetMainCharacterIndex()):
return
if self.selectedVnum <= 0:
chat.AppendChat(chat.CHAT_TYPE_INFO, "[GM] Once listeden item secin.")
return
c = self.countEdit.GetText().strip()
if not c:
c = "1"
self._refresh_preview()
cmd = "/item7 %d %s" % (self.selectedVnum, c)
for i in xrange(ATTR_SATIR):
t = self._attr_apply
try:
val = int(self._attr_val_edits.GetText() or 0)
except ValueError:
val = 0
try:
pct = int(self._attr_pct_edits.GetText() or 100)
except ValueError:
pct = 100
if pct <= 0:
pct = 100
final = (val * pct) / 100
cmd += " %d %d" % (t, final)
for s in xrange(TAS_SOCKET_SAYISI):
cmd += " %d" % (self._stone_vnum)
net.SendChatPacket(cmd)
def OnPressEscapeKey(self):
for cb in self._attr_combos + self._stone_combos:
try:
if cb.isListOpened:
cb.CloseListBox()
return True
except Exception:
pass
return self.Close()
import ui
import net
import player
import chr
import chat
import app
import item
import localeInfo
def _wnd_text(s):
"""WndMgr genelde byte string ister; unicode kaynakli 'Nesne' kalmasini onler."""
if s is None:
return ""
if isinstance(s, str):
return s
if isinstance(s, unicode):
try:
return s.encode("cp1254")
except UnicodeEncodeError:
return s.encode("utf-8", "replace")
return str(s)
def _short_label(s):
if not isinstance(s, basestring):
s = str(s)
if len(s) > 52:
return s[:49] + "..."
return s
COMBO_DROP_MAX_H = 240
class GmComboBox(ui.ComboBox):
"""Satirda acilir secilebilir liste (Metin2 ComboBox)."""
MAX_DROP = COMBO_DROP_MAX_H
def __init__(self):
# ComboBox.__init__ listeyi TOP_MOST'ta acar; Board cocuklari UI katmaninda
# sonra cizildigi icin liste gorunurde altta kalir. Liste UI katmaninda olmali.
ui.Window.__init__(self)
self.x = 0
self.y = 0
self.width = 0
self.height = 0
self.isSelected = False
self.isOver = False
self.isListOpened = False
self.event = lambda *arg: None
self.enable = True
self.textLine = ui.MakeTextLine(self)
self.textLine.SetText(localeInfo.UI_ITEM)
self.listBox = ui.ComboBox.ListBoxWithBoard("UI")
self.listBox.SetPickAlways()
self.listBox.SetParent(self)
self.listBox.SetEvent(ui.__mem_func__(self.OnSelectItem))
self.listBox.Hide()
self._gm_z_panel = None
self._gm_z_kind = None
self._gm_z_idx = 0
try:
self.listBox.AddFlag("float")
except Exception:
pass
if app.ENABLE_MOUSEWHEEL_EVENT:
try:
self.listBox.SetMouseWheelScrollEvent(ui.__mem_func__(self._on_combo_list_wheel))
except Exception:
pass
def SetGmDropdownShield(self, panel, kind, index):
"""kind: 'attr' | 'stone' — acilir liste acikken alt satirlar panel tarafindan gizlenir."""
self._gm_z_panel = panel
self._gm_z_kind = kind
self._gm_z_idx = index
def _on_combo_list_wheel(self, mode):
if not self.isListOpened:
return
n = self.listBox.GetItemCount()
v = max(1, self.listBox.GetViewItemCount())
mx = max(0, n - v)
if mx <= 0:
return
bp = getattr(self.listBox, "basePos", 0)
if mode == "UP":
bp = max(0, bp - 1)
else:
bp = min(mx, bp + 1)
self.listBox.SetBasePos(bp)
def CloseListBox(self):
self.isListOpened = False
p = getattr(self, "_gm_z_panel", None)
if p:
try:
p.OnGmComboDropdownClose(self)
except Exception:
pass
if self.listBox:
self.listBox.Hide()
def OnSelectItem(self, index, name):
self.CloseListBox()
self.SetCurrentItem(_wnd_text(_short_label(name)))
self.event(index)
def InsertItem(self, index, name):
self.listBox.InsertItem(index, name)
n = self.listBox.GetItemCount()
step = getattr(self.listBox, "stepSize", 17)
h = min(max(n * step, 17), self.MAX_DROP)
self.listBox.SetSize(self.width, h)
self.listBox._LocateItem()
def OnMouseLeftButtonUp(self):
if not self.enable:
return
self.isSelected = False
if self.isListOpened:
self.CloseListBox()
else:
if self.listBox.GetItemCount() > 0:
p = getattr(self, "_gm_z_panel", None)
if p:
try:
p.OnGmComboDropdownOpen(self)
except Exception:
pass
self.isListOpened = True
self.listBox.Show()
self.__ArrangeListBox()
try:
self.listBox.SetTop()
except Exception:
pass
# --- Ayarlar ---
MAX_ARAMA_SONUC = 50
ATTR_SATIR = 7
TAS_SOCKET_SAYISI = 3
ATTR_ROW_STEP = 26
# Sunucu APPLY tipi (byte) = ilk sütun; isimler sabit TR (uitooltip yerine)
GM_APPLY_OPTIONS = (
(0, u"- Efsun yok -"),
(1, u"Maximum HP"),
(2, u"Maximum MP"),
(3, u"Ya\u015fam Enerjisi"),
(4, u"G\xfc\xe7"),
(5, u"Dayan\u0131kl\u0131l\u0131k"),
(6, u"\xc7eviklik"),
(7, u"Sald\u0131r\u0131 H\u0131z\u0131"),
(8, u"Hareket H\u0131z\u0131"),
(9, u"B\xfcy\xfc H\u0131z\u0131"),
(10, u"Hp \xdcretimi"),
(11, u"MP \xdcretimi"),
(12, u"Zehirlenme De\u011fi\u015fimi"),
(13, u"Sersemletme \u015eans\u0131"),
(14, u"Yava\u015fl\u0131k De\u011fi\u015fimi"),
(15, u"Kritik Vuru\u015f \u015eans\u0131"),
(16, u"Delici Vuru\u015f \u015eans\u0131"),
(17, u"Yar\u0131 \u0130nsana Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(18, u"Hayvanlara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(19, u"Orklara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(20, u"Misiklere Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(21, u"\xd6l\xfcms\xfczlere Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(22, u"\u015eytanlara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(23, u"%? Hasar Hp Taraf\u0131ndan Emilecek"),
(24, u"%? Hasar Mp Taraf\u0131ndan Emilecek"),
(25, u"D\xfc\u015fmandan Sp \xe7alma \u015eans\u0131"),
(26, u"%? Vururken Sp Alma \u015eans\u0131"),
(27, u"Beden Kar\u015f\u0131s\u0131nda Atak Bloklanmas\u0131"),
(28, u"Oklardan Korunma \u015eans\u0131"),
(29, u"K\u0131l\u0131\xe7 Savunmas\u0131"),
(30, u"\xc7ift El Savunma"),
(31, u"Han\xe7er Savunmas\u0131"),
(32, u"\xc7an Savunmas\u0131"),
(33, u"Yelpaze Savunmas\u0131"),
(34, u"Oka Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(35, u"Ate\u015fe Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(36, u"\u015eim\u015fek Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(37, u"B\xfcy\xfcye Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(38, u"R\xfczgara Kar\u015f\u0131 Dayan\u0131kl\u0131l\u0131k"),
(39, u"V\xfccut Darbelerini Yans\u0131tma \u015eans\u0131"),
(40, u"Lanet Yans\u0131tmas\u0131"),
(41, u"Giftwiderstand"),
(42, u"Sp Y\xfcklemesi %? De\u011fi\u015fti"),
(43, u"%? Exp Bonus \u015eans\u0131"),
(44, u"% Kat Yang D\xfc\u015fme \u015eans\u0131"),
(45, u"% Kat E\u015fya d\xfc\u015fme \u015eans\u0131"),
(46, u"\u0130ksir %? Etki G\xf6sterdi"),
(47, u"Hp Y\xfcklemesi %? De\u011fi\u015fti"),
(48, u"Sersemlik Ba\u011f\u0131\u015f\u0131kl\u0131k"),
(49, u"Yava\u015flatma Ba\u011f\u0131\u015f\u0131kl\u0131k"),
(50, u"Yere D\xfc\u015fme Ba\u011f\u0131\u015f\u0131kl\u0131k"),
(51, u"UNKNOW_TYPE[51]"),
(52, u"Yay Menzili +? Metre"),
(53, u"Sald\u0131r\u0131 De\u011feri +"),
(54, u"Savunma +"),
(55, u"B\xfcy\xfcl\xfc Sald\u0131r\u0131 De\u011feri +"),
(56, u"B\xfcy\xfcl\xfc Savunma De\u011feri +"),
(57, u"UNKNOW_TYPE[57]"),
(58, u"Max. Dayan\u0131kl\u0131l\u0131k"),
(59, u"Sava\u015f\xe7\u0131lara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(60, u"Ninjalara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(61, u"Suralara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(62, u"\u015eamanlara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(63, u"Yarat\u0131klara Kar\u015f\u0131 G\xfc\xe7l\xfc"),
(64, u"Sald\u0131r\u0131 De\u011feri +?%"),
(65, u"Savunma +?%"),
(66, u"EXP +?%"),
(67, u"Elde Edilen Nesne Kat Say\u0131s\u0131"),
(68, u"Elde Edilen Yang Kat Say\u0131s\u0131"),
(69, u"UNKNOW_TYPE[69]"),
(70, u"UNKNOW_TYPE[70]"),
(71, u"Beceri Hasar\u0131"),
(72, u"Ortalama Zarar"),
(73, u"Tekrarlanan Beceri Hasar\u0131na Kar\u015f\u0131 Koyma"),
(74, u"Ortalama Zarara Direni\u015f"),
(75, u"UNKNOW_TYPE[75]"),
(76, u"\u0130cafe Exp Bonus +?%"),
(77, u"E\u015fya Ele Ge\xe7irme Art\u0131\u015f\u0131 ?/2"),
(78, u"Sava\u015f\xe7\u0131 Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
(79, u"Ninja Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
(80, u"Sura Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
(81, u"\u015eaman Sald\u0131r\u0131lar\u0131na Kar\u015f\u0131 Savunma \u015eans\u0131"),
)
_itemdesc_cache = None
def _load_itemdesc():
global _itemdesc_cache
if _itemdesc_cache is not None:
return _itemdesc_cache
_itemdesc_cache = {}
path = app.GetLocalePath() + "/itemdesc.txt"
try:
f = open(path, "r")
except IOError:
return _itemdesc_cache
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
parts = line.split("\t")
if len(parts) < 2:
continue
try:
vid = int(parts[0].strip())
name = parts[1].strip()
if name:
_itemdesc_cache[vid] = name
except ValueError:
continue
f.close()
return _itemdesc_cache
def _build_apply_list():
return list(GM_APPLY_OPTIONS)
def _build_metin_list(desc_dict):
out = [(0, "- Tas yok -")]
for vnum, name in sorted(desc_dict.iteritems(), key=lambda x: x[1].lower()):
if item.IsMetin(vnum):
out.append((vnum, "%s (%d)" % (name, vnum)))
return out
def _search_items(desc_dict, needle, limit):
if not needle:
return []
n = needle.lower()
res = []
for vnum, name in desc_dict.iteritems():
if n in name.lower():
res.append((vnum, name))
res.sort(key=lambda x: x[1].lower())
return res[:limit]
class GmItemPanel(ui.ScriptWindow):
def __init__(self):
ui.ScriptWindow.__init__(self)
self.board = None
self.searchEdit = None
self.resultList = None
self.selectedLabel = None
self.countEdit = None
self.spawnBtn = None
self.cancelBtn = None
self.btnSearch = None
self.previewImg = None
self.selectedVnum = 0
self._attr_apply = [0] * ATTR_SATIR
self._stone_vnum = [0] * TAS_SOCKET_SAYISI
self._attr_combos = []
self._attr_val_edits = []
self._attr_pct_edits = []
self._stone_combos = []
self._apply_items = []
self._metin_items = []
self.resultScroll = None
self._dyn = []
self._attr_row_blocks = []
self._stone_row_blocks = []
self._stone_title_line = None
self._gm_footer_btns = []
self._gm_dd_hidden = []
def __del__(self):
ui.ScriptWindow.__del__(self)
def _dyn_add(self, w):
self._dyn.append(w)
def _gm_dd_restore(self):
for w in getattr(self, "_gm_dd_hidden", []):
try:
w.Show()
except Exception:
pass
self._gm_dd_hidden = []
def OnGmComboDropdownClose(self, opener=None):
self._gm_dd_restore()
def OnGmComboDropdownOpen(self, opener):
for cb in self._attr_combos + self._stone_combos:
if cb is not opener and getattr(cb, "isListOpened", False):
try:
cb.CloseListBox()
except Exception:
pass
self._gm_dd_restore()
self._gm_dd_hidden = []
k = getattr(opener, "_gm_z_kind", None)
idx = getattr(opener, "_gm_z_idx", 0)
to_hide = []
if k == "attr":
for j in xrange(idx + 1, ATTR_SATIR):
to_hide.extend(self._attr_row_blocks[j])
if self._stone_title_line:
to_hide.append(self._stone_title_line)
for blk in self._stone_row_blocks:
to_hide.extend(blk)
to_hide.extend(self._gm_footer_btns)
elif k == "stone":
for j in xrange(idx + 1, TAS_SOCKET_SAYISI):
to_hide.extend(self._stone_row_blocks[j])
to_hide.extend(self._gm_footer_btns)
for w in to_hide:
if w is None:
continue
try:
w.Hide()
self._gm_dd_hidden.append(w)
except Exception:
pass
def LoadWindow(self):
try:
py = ui.PythonScriptLoader()
py.LoadScriptFile(self, "uiscript/gmpanel_item.py")
except:
import exception
exception.Abort("GmItemPanel.LoadWindow")
try:
self.board = self.GetChild("Board")
self.searchEdit = self.GetChild("SearchEdit")
self.resultList = self.GetChild("ResultList")
self.selectedLabel = self.GetChild("SelectedLabel")
self.countEdit = self.GetChild("CountValue")
self.spawnBtn = self.GetChild("SpawnButton")
self.cancelBtn = self.GetChild("CancelButton")
self.btnSearch = self.GetChild("SearchButton")
self.btnSearch.SetEvent(ui.__mem_func__(self.OnSearch))
self.resultScroll = self.GetChild("ResultScrollBar")
except:
import exception
exception.Abort("GmItemPanel.Bind")
self.resultScroll.SetScrollBarSize(100)
self.resultScroll.SetScrollEvent(ui.__mem_func__(self._on_result_scroll))
if app.ENABLE_MOUSEWHEEL_EVENT:
self.resultList.SetMouseWheelScrollEvent(ui.__mem_func__(self._on_result_list_wheel))
self.board.SetCloseEvent(ui.__mem_func__(self.Close))
self.spawnBtn.SetEvent(ui.__mem_func__(self.OnSpawn))
self.cancelBtn.SetEvent(ui.__mem_func__(self.Close))
self.searchEdit.SetReturnEvent(ui.__mem_func__(self.OnSearch))
self.searchEdit.SetEscapeEvent(ui.__mem_func__(self.Close))
self.countEdit.SetEscapeEvent(ui.__mem_func__(self.Close))
self.resultList.SetEvent(ui.__mem_func__(self.OnPickResult))
desc = _load_itemdesc()
self._apply_items = _build_apply_list()
self._metin_items = _build_metin_list(desc)
self.previewImg = ui.ImageBox()
self.previewImg.SetParent(self.board)
self.previewImg.SetPosition(300, 168)
try:
self.previewImg.AddFlag("not_pick")
except Exception:
pass
self.previewImg.Hide()
t = ui.TextLine()
t.SetParent(self.board)
t.SetPosition(12, 216)
t.SetText("Efsunlar:")
t.Show()
self._dyn_add(t)
base_y = 232
self._attr_row_blocks = []
for i in xrange(ATTR_SATIR):
row_y = base_y + i * ATTR_ROW_STEP
lb = ui.TextLine()
lb.SetParent(self.board)
lb.SetPosition(12, row_y + 3)
lb.SetText("%d." % (i + 1))
lb.Show()
self._dyn_add(lb)
cb = GmComboBox()
cb.SetParent(self.board)
cb.SetPosition(32, row_y)
cb.SetSize(214, 18)
cb.SetGmDropdownShield(self, "attr", i)
self._fill_gm_combo(cb, self._apply_items)
cb.SetEvent(lambda aid, r=i: self._on_attr_apply(r, aid))
cb.Enable()
cb.Show()
self._attr_combos.append(cb)
sb = ui.SlotBar()
sb.SetParent(self.board)
sb.SetPosition(256, row_y)
sb.SetSize(48, 18)
sb.Show()
self._dyn_add(sb)
ev = ui.EditLine()
ev.SetParent(sb)
ev.SetPosition(3, 3)
ev.SetSize(42, 16)
ev.SetMax(5)
ev.SetNumberMode()
ev.Show()
self._attr_val_edits.append(ev)
self._dyn_add(ev)
sb2 = ui.SlotBar()
sb2.SetParent(self.board)
sb2.SetPosition(310, row_y)
sb2.SetSize(44, 18)
sb2.Show()
self._dyn_add(sb2)
pv = ui.EditLine()
pv.SetParent(sb2)
pv.SetPosition(3, 3)
pv.SetSize(38, 16)
pv.SetMax(4)
pv.SetNumberMode()
pv.SetText("100")
pv.Show()
self._attr_pct_edits.append(pv)
self._dyn_add(pv)
self._attr_row_blocks.append([lb, cb, sb, sb2])
ts = ui.TextLine()
ts.SetParent(self.board)
ts.SetPosition(12, base_y + ATTR_SATIR * ATTR_ROW_STEP + 14)
ts.SetText("Taslar (max %d socket):" % TAS_SOCKET_SAYISI)
ts.Show()
self._dyn_add(ts)
self._stone_title_line = ts
stone_y = base_y + ATTR_SATIR * ATTR_ROW_STEP + 34
self._stone_row_blocks = []
for s in xrange(TAS_SOCKET_SAYISI):
sy = stone_y + s * ATTR_ROW_STEP
lb = ui.TextLine()
lb.SetParent(self.board)
lb.SetPosition(12, sy + 3)
lb.SetText("Tas %d:" % (s + 1))
lb.Show()
self._dyn_add(lb)
cb = GmComboBox()
cb.SetParent(self.board)
cb.SetPosition(52, sy)
cb.SetSize(368, 18)
cb.SetGmDropdownShield(self, "stone", s)
self._fill_gm_combo(cb, self._metin_items)
cb.SetEvent(lambda vid, idx=s: self._on_stone_pick(idx, vid))
cb.Enable()
cb.Show()
self._stone_combos.append(cb)
self._stone_row_blocks.append([lb, cb])
self._gm_footer_btns = [self.spawnBtn, self.cancelBtn]
self._sync_result_scroll()
def _fill_gm_combo(self, combo, pairs):
combo.ClearItem()
for k, t in pairs:
combo.InsertItem(k, _wnd_text(t))
if pairs:
combo.SetCurrentItem(_wnd_text(_short_label(pairs[0][1])))
def _on_attr_apply(self, row, apply_id):
self._attr_apply[row] = apply_id
def _on_stone_pick(self, slot_idx, vnum):
self._stone_vnum[slot_idx] = vnum
def _result_scroll_max(self):
n = self.resultList.GetItemCount()
v = max(1, self.resultList.GetViewItemCount())
return max(0, n - v)
def _on_result_scroll(self):
mx = self._result_scroll_max()
if mx <= 0:
self.resultList.SetBasePos(0)
return
pos = self.resultScroll.GetPos()
bp = int(round(pos * mx))
if bp > mx:
bp = mx
self.resultList.SetBasePos(bp)
def _on_result_list_wheel(self, mode):
mx = self._result_scroll_max()
if mx <= 0:
return
bp = getattr(self.resultList, "basePos", 0)
if mode == "UP":
bp = max(0, bp - 1)
else:
bp = min(mx, bp + 1)
self.resultList.SetBasePos(bp)
self.resultScroll.SetPos(float(bp) / float(mx))
def _sync_result_scroll(self):
n = self.resultList.GetItemCount()
if n == 0:
self.resultScroll.Hide()
self.resultScroll.SetPos(0.0)
self.resultList.SetBasePos(0)
return
mx = self._result_scroll_max()
if mx <= 0:
self.resultScroll.Hide()
self.resultScroll.SetPos(0.0)
self.resultList.SetBasePos(0)
return
self.resultScroll.Show()
v = max(1, self.resultList.GetViewItemCount())
self.resultScroll.SetMiddleBarSize(min(1.0, float(v) / float
bp = getattr(self.resultList, "basePos", 0)
if bp > mx:
bp = mx
self.resultList.SetBasePos(bp)
self.resultScroll.SetPos(float(bp) / float(mx))
def OnSearch(self):
desc = _load_itemdesc()
if not desc:
chat.AppendChat(chat.CHAT_TYPE_INFO, "[GM] itemdesc.txt yuklenemedi: %s" % (app.GetLocalePath() + "/itemdesc.txt"))
return
q = self.searchEdit.GetText().strip()
self.resultList.ClearItem()
self.resultList.SetBasePos(0)
self.resultScroll.SetPos(0.0)
found = _search_items(desc, q, MAX_ARAMA_SONUC)
for vnum, name in found:
self.resultList.InsertItem(vnum, "%d | %s" % (vnum, name))
self._sync_result_scroll()
if not found:
chat.AppendChat(chat.CHAT_TYPE_INFO, "[GM] Sonuc yok.")
def OnPickResult(self, vnum, text):
self.selectedVnum = vnum
self.selectedLabel.SetText("Secilen: %s" % text[:60])
self._refresh_preview()
def _refresh_preview(self):
if self.selectedVnum <= 0:
self.previewImg.Hide()
return
item.SelectItem(self.selectedVnum)
fn = item.GetIconImageFileName()
if not fn or fn == "Noname":
self.previewImg.Hide()
return
try:
self.previewImg.LoadImage(fn)
self.previewImg.Show()
except RuntimeError:
self.previewImg.Hide()
def Destroy(self):
if self.board:
self.board.SetCloseEvent(None)
if self.spawnBtn:
self.spawnBtn.SetEvent(None)
if self.cancelBtn:
self.cancelBtn.SetEvent(None)
if self.btnSearch:
self.btnSearch.SetEvent(None)
if self.searchEdit:
self.searchEdit.SetReturnEvent(ui.Window.NoneMethod)
self.searchEdit.SetEscapeEvent(ui.Window.NoneMethod)
if self.countEdit:
self.countEdit.SetEscapeEvent(ui.Window.NoneMethod)
if self.resultList:
self.resultList.SetEvent(None)
if app.ENABLE_MOUSEWHEEL_EVENT:
self.resultList.SetMouseWheelScrollEvent(None)
if self.resultScroll:
self.resultScroll.SetScrollEvent(None)
for cb in self._attr_combos:
try:
cb.CloseListBox()
except Exception:
pass
try:
cb.SetEvent(None)
cb.Destroy()
except Exception:
pass
for cb in self._stone_combos:
try:
cb.CloseListBox()
except Exception:
pass
try:
cb.SetEvent(None)
cb.Destroy()
except Exception:
pass
self._attr_combos = []
self._stone_combos = []
for w in self._dyn:
try:
w.Destroy()
except Exception:
pass
self._dyn = []
if self.previewImg:
try:
self.previewImg.Destroy()
except Exception:
pass
self.previewImg = None
self.ClearDictionary()
self.board = None
self.searchEdit = None
self.resultList = None
self.selectedLabel = None
self.countEdit = None
self.spawnBtn = None
self.cancelBtn = None
self.btnSearch = None
def Open(self):
if not chr.IsGameMaster(player.GetMainCharacterIndex()):
return
self.SetCenterPosition()
self.SetTop()
self.Show()
self.searchEdit.SetFocus()
def Close(self):
self._gm_dd_restore()
for cb in self._attr_combos + self._stone_combos:
try:
cb.CloseListBox()
except Exception:
pass
self.Hide()
return True
def Toggle(self):
if not chr.IsGameMaster(player.GetMainCharacterIndex()):
return
if self.IsShow():
self.Close()
else:
self.Open()
def OnSpawn(self):
if not chr.IsGameMaster(player.GetMainCharacterIndex()):
return
if self.selectedVnum <= 0:
chat.AppendChat(chat.CHAT_TYPE_INFO, "[GM] Once listeden item secin.")
return
c = self.countEdit.GetText().strip()
if not c:
c = "1"
self._refresh_preview()
cmd = "/item7 %d %s" % (self.selectedVnum, c)
for i in xrange(ATTR_SATIR):
t = self._attr_apply
try:
val = int(self._attr_val_edits.GetText() or 0)
except ValueError:
val = 0
try:
pct = int(self._attr_pct_edits.GetText() or 100)
except ValueError:
pct = 100
if pct <= 0:
pct = 100
final = (val * pct) / 100
cmd += " %d %d" % (t, final)
for s in xrange(TAS_SOCKET_SAYISI):
cmd += " %d" % (self._stone_vnum)
net.SendChatPacket(cmd)
def OnPressEscapeKey(self):
for cb in self._attr_combos + self._stone_combos:
try:
if cb.isListOpened:
cb.CloseListBox()
return True
except Exception:
pass
return self.Close()
5) İstemci — uiscript/gmpanel_item.py
Ne yapıyoruz: Pencere iskeleti (GmItemPanel): başlık, arama, liste, scrollbar, adet, Ekle / İptal. Efsun/taş satırları LoadWindow içinde Python ile eklenir.
Yol:
Kod:
pack/root/uiscript/gmpanel_item.py
import uiScriptLocale
W = 440
H = 650
window = {
"name" : "GmItemPanel",
"x" : 0,
"y" : 0,
"style" : ("movable", "float",),
"width" : W,
"height" : H,
"children" :
(
{
"name" : "Board",
"type" : "board_with_titlebar",
"x" : 0,
"y" : 0,
"width" : W,
"height" : H,
"title" : "VezirSOFT - GM Edit Paneli",
"children" :
(
{
"name" : "SearchLabel",
"type" : "text",
"x" : 12,
"y" : 30,
"text" : "Item adi ara:",
},
{
"name" : "SearchSlot",
"type" : "slotbar",
"x" : 12,
"y" : 46,
"width" : 220,
"height" : 18,
"children" :
(
{
"name" : "SearchEdit",
"type" : "editline",
"x" : 3,
"y" : 3,
"width" : 214,
"height" : 18,
"input_limit" : 40,
},
),
},
{
"name" : "SearchButton",
"type" : "button",
"x" : 242,
"y" : 44,
"width" : 70,
"height" : 21,
"text" : "Ara",
"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
},
{
"name" : "ResultList",
"type" : "listbox",
"x" : 12,
"y" : 72,
"width" : 372,
"height" : 100,
},
{
"name" : "ResultScrollBar",
"type" : "scrollbar",
"x" : 388,
"y" : 72,
"size" : 100,
},
{
"name" : "SelectedLabel",
"type" : "text",
"x" : 12,
"y" : 178,
"text" : "Secilen: (liste tikla)",
},
{
"name" : "CountLabel",
"type" : "text",
"x" : 12,
"y" : 196,
"text" : "Adet",
},
{
"name" : "CountSlot",
"type" : "slotbar",
"x" : 52,
"y" : 194,
"width" : 50,
"height" : 18,
"children" :
(
{
"name" : "CountValue",
"type" : "editline",
"x" : 3,
"y" : 3,
"width" : 44,
"height" : 18,
"input_limit" : 4,
"only_number" : 1,
"text" : "1",
},
),
},
{
"name" : "SpawnButton",
"type" : "button",
"x" : -70,
"y" : 612,
"width" : 61,
"height" : 21,
"horizontal_align" : "center",
"text" : "Ekle",
"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
},
{
"name" : "CancelButton",
"type" : "button",
"x" : 70,
"y" : 612,
"width" : 61,
"height" : 21,
"horizontal_align" : "center",
"text" : uiScriptLocale.CANCEL,
"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
},
),
},
),
}
W = 440
H = 650
window = {
"name" : "GmItemPanel",
"x" : 0,
"y" : 0,
"style" : ("movable", "float",),
"width" : W,
"height" : H,
"children" :
(
{
"name" : "Board",
"type" : "board_with_titlebar",
"x" : 0,
"y" : 0,
"width" : W,
"height" : H,
"title" : "VezirSOFT - GM Edit Paneli",
"children" :
(
{
"name" : "SearchLabel",
"type" : "text",
"x" : 12,
"y" : 30,
"text" : "Item adi ara:",
},
{
"name" : "SearchSlot",
"type" : "slotbar",
"x" : 12,
"y" : 46,
"width" : 220,
"height" : 18,
"children" :
(
{
"name" : "SearchEdit",
"type" : "editline",
"x" : 3,
"y" : 3,
"width" : 214,
"height" : 18,
"input_limit" : 40,
},
),
},
{
"name" : "SearchButton",
"type" : "button",
"x" : 242,
"y" : 44,
"width" : 70,
"height" : 21,
"text" : "Ara",
"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
},
{
"name" : "ResultList",
"type" : "listbox",
"x" : 12,
"y" : 72,
"width" : 372,
"height" : 100,
},
{
"name" : "ResultScrollBar",
"type" : "scrollbar",
"x" : 388,
"y" : 72,
"size" : 100,
},
{
"name" : "SelectedLabel",
"type" : "text",
"x" : 12,
"y" : 178,
"text" : "Secilen: (liste tikla)",
},
{
"name" : "CountLabel",
"type" : "text",
"x" : 12,
"y" : 196,
"text" : "Adet",
},
{
"name" : "CountSlot",
"type" : "slotbar",
"x" : 52,
"y" : 194,
"width" : 50,
"height" : 18,
"children" :
(
{
"name" : "CountValue",
"type" : "editline",
"x" : 3,
"y" : 3,
"width" : 44,
"height" : 18,
"input_limit" : 4,
"only_number" : 1,
"text" : "1",
},
),
},
{
"name" : "SpawnButton",
"type" : "button",
"x" : -70,
"y" : 612,
"width" : 61,
"height" : 21,
"horizontal_align" : "center",
"text" : "Ekle",
"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
},
{
"name" : "CancelButton",
"type" : "button",
"x" : 70,
"y" : 612,
"width" : 61,
"height" : 21,
"horizontal_align" : "center",
"text" : uiScriptLocale.CANCEL,
"default_image" : "d:/ymir work/ui/public/middle_button_01.sub",
"over_image" : "d:/ymir work/ui/public/middle_button_02.sub",
"down_image" : "d:/ymir work/ui/public/middle_button_03.sub",
},
),
},
),
}
6) İstemci — interfacemodule.py
B3-1 — Import
Ara: Diğer
Kod:
import
satırları.
Kod:
import uigmitempanel
yoksa ekle.
B3-2 — Oluşturma (Interface.__init__)
Ara:
Kod:
self.dlgPointReset.Hide()
Hemen altına:
Kod:
self.dlgItemEdit = uigmitempanel.GmItemPanel()
self.dlgItemEdit.LoadWindow()
self.dlgItemEdit.Hide()
B3-3 — Destroy
Ara:
Kod:
self.dlgPointReset.Destroy()
Altına:
Kod:
if self.dlgItemEdit:
self.dlgItemEdit.Destroy()
B3-4 — del
Ara:
Kod:
del self.dlgPointReset
Altına:
Kod:
del self.dlgItemEdit
B3-5 — Toggle
Ara:
Kod:
def OpenPointResetDialog(self):
civarı / Calling Functions bölümü.
Ekle:
Kod:
def ToggleItemEditPanel(self):
if self.dlgItemEdit:
self.dlgItemEdit.Toggle()
B3-6 — Toplu Hide
Çok pencerenin
Kod:
.Hide()
olduğu yere:
Kod:
if self.dlgItemEdit:
self.dlgItemEdit.Hide()
7) İstemci — game.py
Ara:
Kod:
onPressKeyDict[app.DIK_F4]
Örnek altına ekle:
Kod:
onPressKeyDict[app.DIK_F10] = lambda : self.interface.ToggleItemEditPanel()
F10 doluysa F11 vb. kullan; önemli olan ToggleItemEditPanel çağrısı.
8) Sohbet formatı (uyum)
Panel Ekle deyince örnek yapı:
Kod:
/item7 <vnum> <adet>
7 kez:
Kod:
<apply_tipi> <final_deger>
— final = değer × yüzde / 100
Kod:
<socket0> <socket1> <socket2>
Sunucu one_argument ile sırayla okur; apply sayısı ITEM_ATTRIBUTE_MAX_NUM, socket ITEM_SOCKET_MAX_NUM.
9) Özet tablo
| Dosya | İş |
| cmd.cpp | ACMD(do_item_gm7); + cmd_info "item7" |
| cmd_gm.cpp | do_item bitişi + ACMD(do_item_gm7) |
| uigmitempanel.py | Üstteki spoiler tam metin |
| gmpanel_item.py | Üstteki uiscript tam metin |
| interfacemodule.py | Import, init, Destroy, del, Toggle, Hide |
| game.py | Tuş → ToggleItemEditPanel |
