from phBot import * ; from datetime import datetime, timedelta
import QtBind, phBotChat, threading, time, struct, os, json, math, webbrowser
pName = 'xNsyL-HWT-FGW'
pVersion = 'HollyGame-1'
# Ayarlar eski klasorden okunmaya devam etsin (xNsyLDungeon ayarlarin kaybolmasin)
pConfigName = 'xNsyLDungeon'
# ______________________________ ' Initializing ' ______________________________ #
# Graphic user interface
gui = QtBind.init(__name__,pName)
FIXSOUNDPATH = "c:\\Windows\\Media\\chimes.wav"
Remaining = AdvancedL = IntermediateL = BeginnerL = Return = MembersReturn = WaitMaster = Done = Move = x = y = last_trace_stop_time = 0
Advanced_remaining = Intermediate_remaining = Beginner_remaining = 4
Finished_HWT = ReturnCommand = DodgeAttackBool = CheckPoint = start_bot_in_town = stop_bot_in_town = dead = check_data = inside_hwt = trace_log = stop_checking_trace_status = False
HWT_Entrance = unsucces_fgw = pm_requested = pm_received = dont_move = Alert = False
is_in_dungeon = previous_dungeon = dungeon_location = status = resurrection_name = current_profile = remember_last_status = ResetCountActivatedDate = new_profile = ''
waiting_thread = converted_time1 = converted_time2 = start_time_entrance = None
set_profile_in_town, disconnect_from_fgw, client_disconnect_from_fgw = (False, ''), ('null',0,0), ('null',0,0)
last_trace_time, trace_cooldown , dead_time = 0, 3, 0
resurrection_list, disconnect_list, checkbox_states = [], [], {}
waitpartymembers_command = movement = True
log_message = True # log her zaman acik (arayuzden kaldirildi)
# --- Ghost Sereness kacis tekillestirme -------------------------------------
# Sorun: boss'un telegraf paketini partideki HER uye goruyor, her biri partiye
# "dodge Sereness" yaziyor, o duyuruyu alan her uye tekrar kacis tetikliyordu.
# 8 kisilik partide tek olay 8 kez tetikleniyor, her tetikleme yonu ters cevirip
# ayri bir move_to thread'i aciyordu. Karakter sag-sol emri alip yerinde titriyordu.
DODGE_COOLDOWN = 6.0 # saniye: bu sure icinde gelen tekrar tetiklemeler yutulur
_dodge_lock = threading.Lock()
_dodge_last_ts = 0.0
_dodge_epoch = 0 # her yeni kacista artar; eski move_to dongusu kendini iptal eder
# --- HWT zamanlayici --------------------------------------------------------
# Girilen saat geldiginde: botu durdur -> HWT profiline gec -> return scroll.
# Her gun tekrarlar. Ayni gun icinde bir kez tetiklenir.
_timer_target = None # datetime.time | None = kapali/gecersiz
_timer_fired_date = '' # 'YYYY-MM-DD' - o gun tetiklendi mi
_timer_last_shown = '' # arayuzdeki geri sayimi bosuna guncellememek icin
# ===========================================================================
# YERLESIM
# Sutunlar : SOL 10-270 | ORTA 285-478 | SAG 492-716
# Kural : satir araligi 20-22 px, sayi kutulari sutun sonunda ayni hizada,
# bolum basliklari sade renkli metin (cizgi yok - tasiyordu).
# Not : arka plan icin createList kullanilmiyor; etiketleri kendi icine
# cekip yerlerinden oynatiyordu.
# ===========================================================================
# ---------------------------------------------------------------------------
# ===========================================================================
# DIL (TR / EN)
# Arayuz phBot acilisinda BIR KEZ kuruluyor, karakter config'i ise oyuna
# girildikten sonra okunuyor. Bu yuzden dil tercihi ayri bir dosyada tutulur
# ve import aninda okunur.
# ===========================================================================
def _lang_file():
try:
return get_config_dir() + pConfigName + "\\language.txt"
except Exception:
return ''
def _lang_read():
try:
p = _lang_file()
if p and os.path.exists(p):
v = open(p, 'r', encoding='utf-8').read().strip().upper()
if v in ('TR', 'EN'):
return v
except Exception:
pass
return 'TR'
def _lang_write(v):
try:
p = _lang_file()
if not p:
return
os.makedirs(os.path.dirname(p), exist_ok=True)
open(p, 'w', encoding='utf-8').write(v)
except Exception as e:
log(f'Plugin: Dil tercihi kaydedilemedi: {e}')
LANG = _lang_read()
# key : (turkce, english)
S = {
'settings' : ('AYARLAR', 'SETTINGS'),
'conditions' : ('KOŞULLAR', 'CONDITIONS'),
'general' : ('GENEL', 'GENERAL'),
'timer' : ('ZAMANLAYICI', 'TIMER'),
'hwtEntrance': ('Holy Water Temple girişi', 'Holy Water Temple Entrance'),
'waitParty' : ('Parti üyesi bekle', 'Wait for party members'),
'floorOrder' : ('Kat sırası', 'Floor order'),
'atkRadius' : ('Saldırı yarıçapı', 'Attack radius'),
'sphinxRefl' : ('Sphinx Reflect sayacı', 'Sphinx Reflect counter'),
'ignoreSph' : ('Beginner Sphinx\'i yoksay', 'Ignore Beginner Sphinx'),
'dodgeBridge': ('Köprüden kaçın', 'Dodge bridge'),
'dodgeSer' : ('Ghost Sereness kaçışı', 'Dodge Ghost Sereness'),
'returnDead' : ('Trace master ölünce şehre dön', 'Return town if trace master dies'),
'stopTrace' : ('Işınlanma sonrası takibi durdur', 'Stop trace after teleport'),
'traceMaster': ('Trace master', 'Trace master'),
'partyMaster': ('Party master', 'Party master'),
'profileName': ('Profil adı', 'Profile name'),
'condOn' : ('Koşullar aktif', 'Conditions on'),
'pluginOn' : ('Eklenti aktif', 'Plugin on'),
'traceParty' : ('Parti master takip', 'Trace party master'),
'range' : ('Menzil', 'Range'),
'startTown' : ('Şehirde botu başlat', 'Start bot in town'),
'autoEntr' : ('HWT girişini otomatik aç', 'Auto activate HWT entrance'),
'afterHWT' : ('HWT bitince geç', 'After HWT switch to'),
'afterFGW' : ('FGW bitince geç', 'After FGW switch to'),
'slotToHwt' : ('SLOT → HWT geçişi', 'SLOT → HWT switch'),
'active' : ('Aktif', 'On'),
'clock' : ('Saat', 'Time'),
'save' : (' Kaydet ', ' Save '),
'promo1' : ('Botun artık cebinde', 'Your bot is in your pocket'),
'promo2' : ('Nerede olursan ol, kontrol sende', 'Wherever you are, you are in control'),
'tmrOff' : ('kapalı', 'off'),
'tmrNoTime' : ('saat gir', 'set time'),
'tmrDone' : ('bugün çalıştı', 'ran today'),
}
def t(key):
v = S.get(key)
if not v:
return key
return v[1] if LANG == 'EN' else v[0]
# (widget, key) ciftleri: dil degisince anlik yeniden etiketleme denenir
_lang_widgets = []
def _reg(widget, key):
_lang_widgets.append((widget, key))
return widget
lbl = _reg(QtBind.createLabel(gui,''+t('settings')+'',10,8),'settings')
lbl = _reg(QtBind.createLabel(gui,''+t('conditions')+'',492,8),'conditions')
btnLang = QtBind.createButton(gui,'toggle_language',' EN ' if LANG=='TR' else ' TR ',664,5)
# =========================== SOL SUTUN ===================================
cbxHolyMolyEntrance = _reg(QtBind.createCheckBox(gui,'HolyWaterTemple_Entrance_checked',t('hwtEntrance'),10,26),'hwtEntrance')
lbl = _reg(QtBind.createLabel(gui,t('waitParty'),10,48),'waitParty')
txtPartyMembers = QtBind.createLineEdit(gui,"8",235,45,32,19)
lbl = _reg(QtBind.createLabel(gui,t('floorOrder'),10,70),'floorOrder')
cmbRoute = QtBind.createCombobox(gui,80,67,187,20)
lbl = QtBind.createLabel(gui,'HWT',10,94)
cbxSafeWay = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('atkRadius'),10,112),'atkRadius')
txtRange = QtBind.createLineEdit(gui,"35",235,110,32,19)
cbxspinixref = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('sphinxRefl'),10,130),'sphinxRefl')
txtRangeSphinx = QtBind.createLineEdit(gui,"40",235,128,32,19)
cbxIgnoreSphnix = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('ignoreSph'),10,148),'ignoreSph')
lbl = QtBind.createLabel(gui,'FGW',10,172)
cbxSafeWay2 = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('dodgeBridge'),10,190),'dodgeBridge')
txtRange2 = QtBind.createLineEdit(gui,"45",235,188,32,19)
cbxDodgeSereness = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('dodgeSer'),10,208),'dodgeSer')
lineedit_range = QtBind.createLineEdit(gui,"20",235,206,32,19)
cbxReturn = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('returnDead'),10,226),'returnDead')
lbl = _reg(QtBind.createLabel(gui,''+t('general')+'',10,250),'general')
cbxNotrace = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('stopTrace'),10,268),'stopTrace')
# =========================== ORTA SUTUN ==================================
lblStages = QtBind.createLabel(gui,'Adv 4 · Int 4 · Beg 4',285,8)
lbl = QtBind.createLabel(gui,'HWT',285,34)
lbl = _reg(QtBind.createLabel(gui,t('traceMaster'),290,54),'traceMaster')
txtHWTMASTER = QtBind.createLineEdit(gui,'',375,52,103,19)
lbl = _reg(QtBind.createLabel(gui,t('profileName'),290,74),'profileName')
txtHWTPROFILE = QtBind.createLineEdit(gui,'HWT',375,72,103,19)
lbl = QtBind.createLabel(gui,'FGW',285,98)
lbl = _reg(QtBind.createLabel(gui,t('traceMaster'),290,118),'traceMaster')
txtFGWMASTER = QtBind.createLineEdit(gui,'',375,116,103,19)
lbl = _reg(QtBind.createLabel(gui,t('profileName'),290,138),'profileName')
txtFGWPROFILE = QtBind.createLineEdit(gui,'FGW',375,136,103,19)
lbl = QtBind.createLabel(gui,'SLOT',285,162)
lbl = _reg(QtBind.createLabel(gui,t('partyMaster'),290,182),'partyMaster')
txtSLOTMASTER = QtBind.createLineEdit(gui,'',375,180,103,19)
lbl = _reg(QtBind.createLabel(gui,t('profileName'),290,202),'profileName')
txtSLOTPROFILE = QtBind.createLineEdit(gui,'SLOT',375,200,103,19)
# --- NsyL Companion tanitimi ----------------------------------------------
lbl = QtBind.createLabel(gui,'NsyL Companion',285,232)
lbl = _reg(QtBind.createLabel(gui,''+t('promo1')+'',285,252),'promo1')
lbl = _reg(QtBind.createLabel(gui,''+t('promo2')+'',285,270),'promo2')
btnNsyLSite = QtBind.createButton(gui,'open_nsyl_site',' nsylcompanion.com ',285,290)
# =========================== SAG SUTUN ===================================
cbxEnabledConditions = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('condOn'),500,26),'condOn')
cbxEnabledEventLoop = _reg(QtBind.createCheckBox(gui,'Enabled_checked',t('pluginOn'),612,26),'pluginOn')
cbxTrace = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('traceParty'),500,48),'traceParty')
lbl = _reg(QtBind.createLabel(gui,t('range'),618,50),'range')
txtMinDistance = QtBind.createLineEdit(gui,'10',658,47,28,19)
lbl = QtBind.createLabel(gui,'–',690,50)
txtMaxDistance = QtBind.createLineEdit(gui,'70',698,47,28,19)
cbxStart = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('startTown'),500,70),'startTown')
cbxEntranceON = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('autoEntr'),500,90),'autoEntr')
lbl = _reg(QtBind.createLabel(gui,t('afterHWT'),500,114),'afterHWT')
cmbAfterHWT = QtBind.createCombobox(gui,606,112,120,20)
lbl = _reg(QtBind.createLabel(gui,t('afterFGW'),500,138),'afterFGW')
cmbAfterFGW = QtBind.createCombobox(gui,606,136,120,20)
cbxChangeProfile2 = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('slotToHwt'),500,162),'slotToHwt')
lbl = _reg(QtBind.createLabel(gui,''+t('timer')+'',492,186),'timer')
cbxTimer = _reg(QtBind.createCheckBox(gui,'checkbox_changed',t('active'),500,206),'active')
lbl = _reg(QtBind.createLabel(gui,t('clock'),558,208),'clock')
txtTimerHWT = QtBind.createLineEdit(gui,'',592,205,44,19)
lblTimerNext = QtBind.createLabel(gui,'bugün çalıştı',642,208)
cbxEnter1 = QtBind.createButton(gui,'ManuelEntrance1_clicked','Beginner',492,232)
cbxEnter2 = QtBind.createButton(gui,'ManuelEntrance2_clicked','Intermediate',568,232)
cbxEnter3 = QtBind.createButton(gui,'ManuelEntrance3_clicked','Advanced',648,232)
txtBuildList = QtBind.createCombobox(gui,492,260,140,20)
cbResetCheckboxes = _reg(QtBind.createButton(gui,'reset_checkboxes',t('save'),640,259),'save')
#----------------------------------------------Load Configs------------------------------------------------#
#---------------------------------------------- Kat sirasi ------------------------------------------------#
# Eskiden 6 ayri onay kutusuydu ve hepsi birbirini kapatiyordu (tek secim).
# Tek acilir listeye indirildi. Kayitli secim, liste doldurulurken BASA konur;
# boylece QtBind.setText combobox'ta calismasa bile ayar geri gelir.
# Acilir liste secenekleri dile bagli. Config'e METIN degil ANAHTAR yazilir,
# yoksa dil degisince kayitli secim eslesmez.
ROUTE_KEYS = ['first','second','third','only_beginner','only_intermediate','only_advanced']
ROUTE_LABELS = {
'TR': [
'Beginner → Intermediate → Advanced',
'Intermediate → Advanced → Beginner',
'Advanced → Intermediate → Beginner',
'Sadece Beginner',
'Sadece Intermediate',
'Sadece Advanced',
],
'EN': [
'Beginner → Intermediate → Advanced',
'Intermediate → Advanced → Beginner',
'Advanced → Intermediate → Beginner',
'Beginner only',
'Intermediate only',
'Advanced only',
],
}
_route_filled = False
AFTER_HWT_KEYS = ['', 'fgw', 'slot']
AFTER_FGW_KEYS = ['', 'hwt', 'slot']
NONE_LABEL = {'TR': 'Hiçbiri', 'EN': 'None'}
_after_hwt_filled = False
_after_fgw_filled = False
def _route_labels():
return ROUTE_LABELS.get(LANG, ROUTE_LABELS['TR'])
def _after_labels(keys):
return [NONE_LABEL.get(LANG, 'Hiçbiri') if k == '' else k.upper() for k in keys]
def _key_from_combo(widget, keys, labels):
try:
v = (QtBind.text(gui, widget) or '').strip()
except Exception:
return ''
if v in labels:
return keys[labels.index(v)]
return ''
def route_key():
"""Secili kat sirasi anahtari: first/second/third/only_* veya ''."""
return _key_from_combo(cmbRoute, ROUTE_KEYS, _route_labels())
def after_hwt_key():
"""HWT bitince: 'fgw' | 'slot' | ''"""
return _key_from_combo(cmbAfterHWT, AFTER_HWT_KEYS, _after_labels(AFTER_HWT_KEYS))
def after_fgw_key():
"""FGW bitince: 'hwt' | 'slot' | ''"""
return _key_from_combo(cmbAfterFGW, AFTER_FGW_KEYS, _after_labels(AFTER_FGW_KEYS))
def _fill_combo(widget, labels, sel_label, ad):
"""Secili secenek BASA konur; QtBind.setText combobox'ta calismasa bile
ilk oge secili geldigi icin ayar geri gelir."""
order = list(labels)
if sel_label in order:
order.remove(sel_label)
order.insert(0, sel_label)
for opt in order:
try:
QtBind.append(gui, widget, opt)
except Exception as e:
log(f'Plugin: "{ad}" listesi doldurulamadi: {e}')
return
if sel_label:
try:
QtBind.setText(gui, widget, sel_label)
except Exception:
pass
def route_fill(selected_key=''):
global _route_filled
if _route_filled:
return
_route_filled = True
labels = _route_labels()
sel = labels[ROUTE_KEYS.index(selected_key)] if selected_key in ROUTE_KEYS else ''
_fill_combo(cmbRoute, labels, sel, 'Kat sirasi')
def after_hwt_fill(selected_key=''):
global _after_hwt_filled
if _after_hwt_filled:
return
_after_hwt_filled = True
labels = _after_labels(AFTER_HWT_KEYS)
sel = labels[AFTER_HWT_KEYS.index(selected_key)] if selected_key in AFTER_HWT_KEYS else ''
_fill_combo(cmbAfterHWT, labels, sel, 'HWT bitince')
def after_fgw_fill(selected_key=''):
global _after_fgw_filled
if _after_fgw_filled:
return
_after_fgw_filled = True
labels = _after_labels(AFTER_FGW_KEYS)
sel = labels[AFTER_FGW_KEYS.index(selected_key)] if selected_key in AFTER_FGW_KEYS else ''
_fill_combo(cmbAfterFGW, labels, sel, 'FGW bitince')
def update_stage_label():
"""Uc kat sayacini tek satirda gosterir: 'Adv 4 · Int 4 · Beg 4'.
Kalan 0 ise o kat '✔' olur."""
def g(v):
return '✔' if v <= 0 else str(v)
try:
QtBind.setText(gui, lblStages,
f'Adv {g(Advanced_remaining)} · Int {g(Intermediate_remaining)} · Beg {g(Beginner_remaining)}')
except Exception:
pass
def profile_for(key):
"""Anahtardan gercek profil adini bul: 'hwt'/'fgw'/'slot' -> kutudaki isim."""
if key == 'hwt':
return QtBind.text(gui, txtHWTPROFILE).strip() or "HWT"
if key == 'fgw':
return QtBind.text(gui, txtFGWPROFILE).strip() or "FGW"
if key == 'slot':
return QtBind.text(gui, txtSLOTPROFILE).strip() or "SLOT"
return ''
def switch_profile_and_return(key, nereden=''):
"""Zindan bitisinde: partiye duyur, profili degistir, sehre don, botu baslat.
start_bot_in_town bayragi sehre varista botu baslatir."""
global start_bot_in_town
yeni = profile_for(key)
if not yeni:
return False
if (get_profile() or '') == yeni:
return False
st = get_status() or ''
if st == "botting":
stop_bot()
elif st == "tracing":
stop_trace()
start_bot_in_town = True
phBotChat.Party(f"change profile {yeni.lower()}")
set_profile(yeni)
log(f'Plugin: {nereden} bitti — [ {yeni} ] profiline geçiliyor, şehre dönülüyor.')
threading.Timer(1.0, return_town).start()
return True
#---------------------------------------------- Zamanlayici -----------------------------------------------#
def timer_parse():
"""Arayuzdeki saati oku. Gecerliyse datetime.time, degilse None."""
global _timer_target
txt = (QtBind.text(gui, txtTimerHWT) or '').strip()
if not txt:
_timer_target = None
return None
try:
_timer_target = datetime.strptime(txt, "%H:%M").time()
except ValueError:
_timer_target = None
log(f'Plugin: Zamanlayici saati gecersiz: "{txt}" — SS:DD yazin (orn. 16:30).')
return _timer_target
def timer_seconds_left():
"""Hedef saate kalan saniye. Saat gectiyse yarinki ayni saate gore hesaplar."""
if not _timer_target:
return None
now = datetime.now()
target = datetime.combine(now.date(), _timer_target)
if target <= now:
target += timedelta(days=1)
return int((target - now).total_seconds())
def timer_update_label():
"""Arayuzdeki 'sonraki tetikleme' satirini tazeler. Saniyede bir cagrilir."""
global _timer_last_shown
if not QtBind.isChecked(gui, cbxTimer):
text = '' + t('tmrOff') + ''
elif not _timer_target:
text = '' + t('tmrNoTime') + ''
else:
kalan = timer_seconds_left()
if _timer_fired_date == datetime.now().strftime("%Y-%m-%d"):
text = '' + t('tmrDone') + ''
else:
s, dk = divmod(kalan // 60, 60)
text = f'{s}sa {dk}dk'
if text != _timer_last_shown:
_timer_last_shown = text
QtBind.setText(gui, lblTimerNext, text)
def timer_check():
"""event_loop'tan saniyede bir cagrilir. Saat geldiyse HWT'ye gecisi baslatir."""
global _timer_fired_date
if not QtBind.isChecked(gui, cbxTimer) or not _timer_target:
return
now = datetime.now()
today = now.strftime("%Y-%m-%d")
if _timer_fired_date == today:
return
if now.time() < _timer_target:
return
# Saatin cok gerisinde bir anda (orn. gece acilista) tetiklenmesin: 10 dk pencere
gecen = (now - datetime.combine(now.date(), _timer_target)).total_seconds()
if gecen > 600:
_timer_fired_date = today
return
_timer_fired_date = today
threading.Timer(0.1, timer_go_hwt).start()
def timer_go_hwt():
"""Zamanlayici eylemi: botu durdur, HWT profiline gec, sehre don."""
try:
profile_hwt = (QtBind.text(gui, txtHWTPROFILE) or '').strip() or "HWT"
current = get_profile() or ''
if current == profile_hwt:
log(f'Plugin: Zamanlayici — zaten [ {profile_hwt} ] profilindesin, islem yapilmadi.')
return
log(f'Plugin: Zamanlayici saati geldi. [ {profile_hwt} ] profiline geciliyor.')
st = get_status() or ''
if st == "botting":
stop_bot()
elif st == "tracing":
stop_trace()
set_profile(profile_hwt)
threading.Timer(1.0, return_town).start()
except Exception as e:
log(f'Plugin: Zamanlayici hatasi: {e}')
def toggle_language():
"""TR <-> EN. Tercihi dosyaya yazar ve arayuzu anlik guncellemeyi dener.
QtBind bazi bilesenlerin metnini sonradan degistiremiyorsa, tercih yine de
kaydedildigi icin bir sonraki acilista tam olarak uygulanir."""
global LANG
LANG = 'EN' if LANG == 'TR' else 'TR'
_lang_write(LANG)
degisen = 0
for widget, key in _lang_widgets:
try:
metin = t(key)
# renkli/kalin olanlar ayni bicimle yeniden kurulur
if key in ('settings', 'conditions'):
metin = '' + metin + ''
elif key == 'general':
metin = '' + metin + ''
elif key == 'timer':
metin = '' + metin + ''
elif key == 'promo1':
metin = '' + metin + ''
elif key == 'promo2':
metin = '' + metin + ''
QtBind.setText(gui, widget, metin)
degisen += 1
except Exception:
pass
try:
QtBind.setText(gui, btnLang, ' EN ' if LANG == 'TR' else ' TR ')
except Exception:
pass
# Uyari, gecilen dilde yazilir - okuyan kisi o dili kullaniyor.
if LANG == 'EN':
log(f'Plugin: Language changed to English. ({degisen} labels updated)')
log('Plugin: Reload the plugin to apply the language to the drop-down lists and all remaining texts.')
else:
log(f'Plugin: Dil Türkçe olarak değiştirildi. ({degisen} etiket güncellendi)')
log('Plugin: Açılır listelerin ve kalan tüm metinlerin değişmesi için eklentiyi yeniden yükleyin.')
def open_nsyl_site():
"""Tanitim butonu: web sitesini varsayilan tarayicida acar."""
url = 'https://nsylcompanion.com'
try:
webbrowser.open(url)
log(f'Plugin: {url} tarayicida aciliyor.')
except Exception as e:
log(f'Plugin: Site acilamadi ({e}). Adres: {url}')
def HolyWaterTemple_Entrance_checked(checked) :
global HWT_Entrance
HWT_Entrance = QtBind.isChecked(gui, cbxHolyMolyEntrance)
def checkbox_changed(checked):
saveConfigs()
def safe_int(text, default):
try:
return int(text.strip())
except (ValueError, AttributeError):
return default
def Config_Builds():
Config_Builds_List = [
"Auto Detect",
"Wizard / Spear (Attack)",
"Warrior",
"Cleric / Force",
"Bard / Warlock",
"Personal Configuration",
"Clear Settings"
]
if 'QtBind' in globals() and 'gui' in globals() and 'txtBuildList' in globals():
for config in Config_Builds_List:
QtBind.append(gui, txtBuildList, config)
else:
log("Plugin: GUI bileşenleri tanımlı değil.")
return Config_Builds_List
Config_Builds()
def reset_checkboxes():
global HWT_Entrance
build = QtBind.text(gui, txtBuildList)
checkboxes = [
cbxHolyMolyEntrance,
cbxspinixref, cbxSafeWay,
cbxSafeWay2, cbxIgnoreSphnix, cbxNotrace,
cbxEnabledConditions, cbxTrace, cbxStart, cbxEntranceON, cbxReturn,
cbxDodgeSereness, cbxChangeProfile2, cbxEnabledEventLoop
]
for checkbox in checkboxes:
if not build == "Personal Configuration":
QtBind.setChecked(gui, checkbox, False)
# Otomatik build algılama
if build == "Auto Detect":
try:
Master = get_party_info().get('leader_name','')
if Master != "null" :
QtBind.setText(gui, txtHWTMASTER, Master)
QtBind.setText(gui, txtFGWMASTER, Master)
QtBind.setText(gui, txtSLOTMASTER, Master)
inventory = get_inventory()
if inventory and 'items' in inventory and len(inventory['items']) >= 7:
item = inventory['items'][6]
name = item.get('name')
if isinstance(name, str):
item_info = get_item_string(name)
tid3 = item_info.get('tid3', None)
if isinstance(tid3, int):
if tid3 in {2, 3, 4, 5, 6, 11, 12, 13}:
build = "Wizard / Spear (Attack)"
elif tid3 in {7, 8, 9}:
build = "Warrior"
elif tid3 in {10, 14}:
build = "Bard / Warlock"
else:
build = "Cleric / Force"
else :
log(f'Plugin: Yapılandırma başarısız. Birincil Silah tespit edilemedi.')
except Exception as e:
log(f"Build algılama hatası: {e}")
# Build yapılandırmaları
if build == "Wizard / Spear (Attack)":
Config = [
cbxSafeWay2, cbxspinixref, cbxSafeWay, cbxNotrace,
cbxIgnoreSphnix, cbxEnabledConditions, cbxTrace,
cbxStart, cbxEntranceON, cbxReturn, cbxDodgeSereness, cbxEnabledEventLoop
]
for checkbox in Config:
QtBind.setChecked(gui, checkbox, True)
log("Plugin: xDungeonSupporteRx'ın Ayarları [ Wizard / Spear (Attack) ] için düzenlendi.")
elif build == "Warrior":
Config = [
cbxSafeWay2, cbxspinixref, cbxSafeWay, cbxNotrace,
cbxIgnoreSphnix, cbxEnabledConditions, cbxTrace, cbxStart,
cbxEntranceON, cbxReturn, cbxDodgeSereness, cbxEnabledEventLoop
]
for checkbox in Config:
QtBind.setChecked(gui, checkbox, True)
log("Plugin: xDungeonSupporteRx'ın Ayarları [ Warrior ] için düzenlendi.")
elif build == "Cleric / Force":
Config = [
cbxIgnoreSphnix, cbxSafeWay,
cbxEnabledConditions, cbxStart,
cbxEntranceON, cbxDodgeSereness, cbxEnabledEventLoop
]
for checkbox in Config:
QtBind.setChecked(gui, checkbox, True)
log("Plugin: xDungeonSupporteRx'ın Ayarları [ Cleric / Force ] için düzenlendi.")
elif build == "Bard / Warlock":
Config = [
cbxSafeWay2, cbxSafeWay, cbxNotrace, cbxIgnoreSphnix,
cbxEnabledConditions, cbxTrace, cbxStart,
cbxEntranceON, cbxReturn, cbxDodgeSereness, cbxEnabledEventLoop
]
for checkbox in Config:
QtBind.setChecked(gui, checkbox, True)
log("Plugin: xDungeonSupporteRx'ın Ayarları [ Bard / Warlock ] için düzenlendi.")
elif build == "Clear Settings":
QtBind.setText(gui, txtHWTMASTER, "")
QtBind.setText(gui, txtFGWMASTER, "")
QtBind.setText(gui, txtSLOTMASTER, "")
log("Plugin: Ayarlarınız Sıfırlandı.")
else:
if build == "Personal Configuration" :
log("Plugin: Kişisel Ayarlarınız Kaydedildi.")
HWT_Entrance = QtBind.isChecked(gui, cbxHolyMolyEntrance)
threading.Timer(0.1, saveConfigs).start()
def saveConfigs():
try:
if not isJoined():
return
# Kaydet'e her basildiginda saat yeniden okunur
timer_parse()
global checkbox_states, converted_time1, converted_time2, disconnect_from_fgw
checkbox_states = {} # önce sıfırla
data = {}
# Checkbox ve Text alanları (sade gruplandırma)
checkboxes = {
'notrace': cbxNotrace,
'reflect': cbxspinixref,
'ignoresph': cbxIgnoreSphnix,
'ignoreNav': cbxSafeWay,
'ignoreNav2': cbxSafeWay2,
'returntown': cbxReturn,
'changeprofile2': cbxChangeProfile2,
'disabledplugin': cbxEnabledEventLoop,
'Enabled': cbxEnabledConditions,
'trace': cbxTrace,
'start': cbxStart,
'EntranceON': cbxEntranceON,
'usedodgeskills': cbxDodgeSereness,
'timer': cbxTimer
}
textfields = {
'PartyMembers': txtPartyMembers,
'RangeSphinx': txtRangeSphinx,
'Range': txtRange,
'Range2': txtRange2,
'hwtmaster': txtHWTMASTER,
'fgwmaster': txtFGWMASTER,
'slotmaster': txtSLOTMASTER,
'hwtprofile': txtHWTPROFILE,
'fgwprofile': txtFGWPROFILE,
'slotprofile': txtSLOTPROFILE,
'minDistance': txtMinDistance,
'maxDistance': txtMaxDistance,
'radius': lineedit_range,
'timerHWT': txtTimerHWT
}
for key, checkbox in checkboxes.items():
checked = QtBind.isChecked(gui, checkbox)
data[key] = checked
checkbox_states[key] = checked
for key, field in textfields.items():
text = QtBind.text(gui, field)
data[key] = text
data['route'] = route_key()
data['afterhwt'] = after_hwt_key()
data['afterfgw'] = after_fgw_key()
data['disconnect_from_where'] = disconnect_from_fgw
# Dosyaya yaz
with open(getConfig(), "w") as f:
json.dump(data, f, indent=4, sort_keys=True)
except Exception as e:
log(f"{pName}: Ayarlar kaydedilirken bir hata oluştu: {e}")
def getPath():
return get_config_dir()+pConfigName+"\\"
def connected():
global inGame
inGame = None
def getConfig():
return getPath()+inGame['server'] + "_" + inGame['name'] + ".json"
def resurrection():
global resurrection_name, resurrection_list
data = get_character_data() or {}
resurrection_name = data.get('name', '').lower()
if resurrection_name:
if resurrection_name not in resurrection_list:
resurrection_list.append(resurrection_name)
else:
# 3 saniye sonra tekrar dene
threading.Timer(3.0, resurrection).start()
def isJoined():
global inGame,check_data
inGame = get_character_data() or {}
if not check_data and inGame :
check_data = True
if not (inGame and "name" in inGame and inGame["name"]):
inGame = None
return inGame
def loadConfigs():
try:
if isJoined():
if not resurrection_list:
resurrection()
if os.path.exists(getConfig()):
with open(getConfig(), "r") as f:
data = json.load(f)
global checkbox_states, converted_time1, converted_time2, disconnect_from_fgw
checkbox_states = {}
# Checkbox haritası (anahtar: config adı, değer: QtBind nesnesi)
checkboxes = {
'notrace': cbxNotrace,
'reflect': cbxspinixref,
'ignoresph': cbxIgnoreSphnix,
'ignoreNav': cbxSafeWay,
'ignoreNav2': cbxSafeWay2,
'returntown': cbxReturn,
'changeprofile2': cbxChangeProfile2,
'disabledplugin': cbxEnabledEventLoop,
'Enabled': cbxEnabledConditions,
'trace': cbxTrace,
'start': cbxStart,
'EntranceON': cbxEntranceON,
'usedodgeskills': cbxDodgeSereness,
'timer': cbxTimer
}
textfields = {
'PartyMembers': txtPartyMembers,
'RangeSphinx': txtRangeSphinx,
'Range': txtRange,
'Range2': txtRange2,
'hwtmaster': txtHWTMASTER,
'fgwmaster': txtFGWMASTER,
'slotmaster': txtSLOTMASTER,
'hwtprofile': txtHWTPROFILE,
'fgwprofile': txtFGWPROFILE,
'slotprofile': txtSLOTPROFILE,
'minDistance': txtMinDistance,
'maxDistance': txtMaxDistance,
'radius': lineedit_range,
'timerHWT': txtTimerHWT
}
# Checkbox'ları yükle ve checkbox_states içine ata
for key, checkbox in checkboxes.items():
checked = data.get(key, False)
QtBind.setChecked(gui, checkbox, checked)
checkbox_states[key] = checked
# Text alanlarını yükle
for key, field in textfields.items():
if key in data:
QtBind.setText(gui, field, str(data[key]))
route_fill(str(data.get('route','')).strip())
after_hwt_fill(str(data.get('afterhwt','')).strip())
after_fgw_fill(str(data.get('afterfgw','')).strip())
if 'disconnect_from_where' in data:
disconnect_from_fgw = data.get("disconnect_from_where", "")
timer_parse()
if _timer_target :
log(f'Plugin: Zamanlayici yuklendi — HWT saati {_timer_target.strftime("%H:%M")}.')
log(f"Plugin Configs : {pName}: Ayarlar başarıyla yüklendi. ✔️ ")
else :
route_fill()
after_hwt_fill()
after_fgw_fill()
log(f"Plugin Configs : {pName}: Henüz bir yapılandırmaya sahip değil. ❌ ")
except Exception as e:
route_fill() # hata olsa bile listeler bos kalmasin
after_hwt_fill()
after_fgw_fill()
log(f"{pName}: Ayarlar yüklenirken bir hata oluştu: {e} ⚠️ ")
#----------------------------------------------Load Configs------------------------------------------------#
def End():
party_info = get_party_info() or {}
finished = party_info.get('area','') == "TOWN"
in_end_area = 17409 < x < 17540 and 3761 < y < 3885
return finished and in_end_area
def change_profile(args):
profile = args[1]
msg = f'change profile {profile}'
phBotChat.Party(msg)
return 0
def GetUnique():
gtmonsters = get_monsters() or {}
if not gtmonsters:
return False
unique_names = {"MOB_SD_OSIRIS_3", "Ghost Sereness",}
return any(monster['servername'] in unique_names or monster['name'] in unique_names for monster in gtmonsters.values())
def set_dungeon(new_dungeon):
global is_in_dungeon, previous_dungeon
if is_in_dungeon != new_dungeon:
previous_dungeon = is_in_dungeon
is_in_dungeon = new_dungeon
def CheckInDungeon():
#start_time = time.time() if log_message else None
global is_in_dungeon, dungeon_location, status, current_profile, dead, x, y, remember_last_status, dead_time
if resurrection_name in resurrection_list :
char_data = get_character_data() or {}
dungeon_name = char_data.get('zone_name', '').lower()
x, y = char_data.get('x',0), char_data.get('y',0)
current_profile = get_profile() or ''
slot_profile = QtBind.text(gui, txtSLOTPROFILE) or "SLOT"
dead = char_data.get('dead','')
current_time = time.time()
if dead :
dead_time = current_time
if status != "nothing" :
remember_last_status = status
else :
if remember_last_status != status :
if current_time - dead_time >= 15 :
remember_last_status = status
status = get_status() or "nothing"
if dungeon_name in {'constantinople', 'jangan', 'western china donwhang', 'hotan krallığı', 'alexandria', 'hotan kingdom', 'batı çin donwhang', 'samarkand'} :
set_dungeon("TOWN")
elif dungeon_name in {'gemi enkazı içinde', 'gemi enkazı dışında', 'inside of the shipwreck', 'outside of the shipwreck'} :
set_dungeon("FGW")
if checkbox_states.get('ignoreNav2') :
B1 = 18028 < x < 18158 and 3845 < y < 3918
B2 = 17873 < x < 17964 and 3956 < y < 4135
B3 = 18016 < x < 18186 and 4196 < y < 4252
B4 = 18265 < x < 18424 and 4252 < y < 4299
B5 = 18467 < x < 18520 and 3893 < y < 4089
B6 = 18654 < x < 18680 and 3529 < y < 3769
B7 = 18323 < x < 18556 and 3242 < y < 3401
B8 = 18081 < x < 18189 and 3317 < y < 3473
B9 = 17939 < x < 18103 and 4350 < y < 4474
B10 = 17572 < x < 17755 and 4419 < y < 4453
B11 = 17246 < x < 17421 and 4247 < y < 4357
B12 = 17218 < x < 17274 and 3839 < y < 4069
B13 = 17113 < x < 17167 and 3414 < y < 3674
B14 = 17303 < x < 17452 and 3163 < y < 3288
B15 = 17625 < x < 17794 and 3153 < y < 3177
B16 = 17546 < x < 17577 and 3237 < y < 3396
B17 = 17714 < x < 17825 and 3471 < y < 3689
B18 = 17570 < x < 17718 and 3684 < y < 3790
B19 = 17910 < x < 18005 and 3704 < y < 3833
if B1 or B2 or B3 or B4 or B5 or B6 or B7 or B8 or B9 or B10 or B11 or B12 or B13 or B14 or B15 or B16 or B17 or B18 or B19:
if dungeon_location != "OFF_FGW" :
dungeon_location = "OFF_FGW"
else:
if dungeon_location != "ON_FGW" :
dungeon_location = "ON_FGW"
elif dungeon_name in {'pharaoh mezarı', 'pharaoh tomb'} :
set_dungeon("HWT")
if checkbox_states.get('ignoreNav') :
#-------------------------Advanced--------------------------------------#
NephthysOFF = 8547 < x < 8712 and 5656 < y < 5801
SekhmetOFF = 8547 < x < 8712 and 6070 < y < 6219
HorusOFF = 8998 < x < 9118 and 5896 < y < 6063
#----------------------Intermediate-------------------------------------#
NephthysOFF2 = 11043 < x < 11208 and 5658 < y < 5804
SekhmetOFF2 = 11043 < x < 11208 and 6072 < y < 6219
HorusOFF2 = 11494 < x < 11618 and 5897 < y < 6065
#----------------------Beginner-----------------------------------------#
SphinxOFF3 = 10875 < x < 11113 and 4566 < y < 4620
NephthysOFF3 = 11042 < x < 11213 and 4313 < y < 4460
SekhmetOFF3 = 11042 < x < 11213 and 4728 < y < 4876
HorusOFF3 = 11496 < x < 11624 and 4553 < y < 4719
#----------------------Sphinx--------------------------------#
Sphinx3 = 10875 < x < 11042 and 4523 < y < 4664
Sphinx2 = 10875 < x < 11042 and 5865 < y < 6009
Sphinx = 8377 < x < 8545 and 5865 < y < 6009
if NephthysOFF or SekhmetOFF or HorusOFF or NephthysOFF2 or SekhmetOFF2 or HorusOFF2 or NephthysOFF3 or SekhmetOFF3 or HorusOFF3 or (checkbox_states.get('ignoresph') and SphinxOFF3):
if dungeon_location != "OFF_HWT" :
dungeon_location = "OFF_HWT"
elif Sphinx or Sphinx2 or Sphinx3 :
if dungeon_location != "PASS" :
dungeon_location = "PASS"
else :
if dungeon_location != "ON_HWT" :
dungeon_location = "ON_HWT"
elif -11455 < x < -11327 and -3296 < y < -3261:
set_dungeon("GATE")
elif current_profile == slot_profile :
if get_distance_to_training_area() :
set_dungeon("SLOT")
else :
set_dungeon("OUTSLOT")
else :
set_dungeon("UNKNOWN")
if dungeon_location != "PASS" :
dungeon_location = "PASS"
CheckResetTime()
#end_time = time.time() if log_message else None # Bitiş zamanı
#elapsed = round((end_time - start_time) * 1000, 2) if log_message else None # ms cinsinden
#log(f"[CheckInDungeon] çalışması {elapsed} ms sürdü.") if log_message else None
def get_distance_to_training_area():
training_area = get_training_area() or {}
training_x = training_area.get('x', 0)
training_y = training_area.get('y', 0)
training_radius = training_area.get('radius', 50)
distance = ( ((x - training_x) ** 2 + (y - training_y) ** 2) ** 0.5 )
return distance <= training_radius
def CheckResetTime():
now = datetime.now()
if now.hour == 0 and now.minute == 1:
if ResetCountDelay():
ResetCount()
def DodgeAttack():
global DodgeAttackBool, CheckPoint
if DodgeAttackBool :
return
DodgeAttackBool = True
while DodgeAttackBool :
AttackRadius= safe_int(QtBind.text(gui,txtRange),35)
AttackRadius2 = safe_int(QtBind.text(gui,txtRange2),45)
training_area = get_training_area() or {}
radius = training_area.get('radius', 0)
if is_in_dungeon in {"FGW","HWT"} :
if dungeon_location in {"ON_HWT","OFF_HWT"} :
if dungeon_location == "ON_HWT" and radius < AttackRadius :
CheckPoint = True
set_training_radius(AttackRadius)
if log_message :
log(f'Plugin: Training radius set to "{AttackRadius}" m. [ HWT ] ')
elif dungeon_location == "OFF_HWT" and radius > 0 :
CheckPoint = False
set_training_radius(0)
if log_message :
log('Plugin: Training radius set to "0" m. [HWT] ')
elif dungeon_location in {"ON_FGW","OFF_FGW"} :
if dungeon_location == "ON_FGW" and radius < AttackRadius2 :
set_training_radius(AttackRadius2)
if log_message :
log(f'Plugin: Training radius set to "{AttackRadius2}" m. [ FGW ] ')
elif dungeon_location == "OFF_FGW" and radius > 0 :
set_training_radius(0)
if log_message :
log('Plugin: Training radius set to "0" m. [ FGW ] ')
elif is_in_dungeon not in {"FGW","HWT"} :
DodgeAttackBool = False
break
time.sleep(0.5)
def get_party_info():
party = get_party() or {}
if not party:
return {
'leader_name': "null",
'is_me': False,
'area': "null",
'total_members': 0,
'nearby_count': 1,
'leader_pos': (0,0)
}
character_data = get_character_data() or {}
my_name = character_data.get('name', '')
total_members = len(party)
nearby_count = 1
for member in party.values():
if member.get('leader'):
leader_name = member['name']
is_me = (leader_name == my_name)
leader_pos = (member['x'], member['y'])
r = member['region']
for other_member in party.values():
if other_member != member:
other_pos = (other_member['x'], other_member['y'])
distance = math.dist(leader_pos, other_pos)
if distance < 25:
nearby_count += 1
# Bölge belirleme
x, y = leader_pos
if 7301 <= x <= 9603 and 5385 <= y <= 6540:
area = "Advanced"
elif 9790 <= x <= 12095 and 5375 <= y <= 6530:
area = "Intermediate"
elif 10560 <= x <= 12100 and 4030 <= y <= 5180:
area = "Beginner"
elif 16317 < x < 19388 and 2298 < y < 4991:
area = "FGW"
elif r in {23088, 23687, 23603, 25000, 26265, 27244, 26959}:
area = "TOWN"
elif r == 19019:
area = "GATE"
else:
area = "UNKNOWN"
return {
'leader_name': leader_name,
'is_me': is_me,
'area': area,
'total_members': total_members,
'nearby_count': nearby_count,
'leader_pos': leader_pos
}
return {
'leader_name': "null",
'is_me': False,
'area': "null",
'total_members': 0,
'nearby_count': 1,
'leader_pos': (0,0)
}
def Entrance():
global Beginner_remaining,Intermediate_remaining,Advanced_remaining,WaitMaster,MembersReturn,Return,ReturnCommand,Finished_HWT,Remaining,Done,inside_hwt
party_info_list = get_party_info() or {}
lider_durumu = party_info_list.get('is_me',False)
lider_konum = party_info_list.get('area','')
count = party_info_list.get('total_members',0)
nearby_count = party_info_list.get('nearby_count',1)
PartyMembers = safe_int(QtBind.text(gui,txtPartyMembers),0)
if not ReturnCommand and resurrection_name in resurrection_list :
if lider_durumu and nearby_count >= PartyMembers :
if route_key() == 'third':
if Advanced_remaining > 0 :
Advanced()
inside_hwt = True
if Advanced_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Advanced_remaining -=1
update_stage_label()
elif Intermediate_remaining > 0 :
Intermediate()
inside_hwt = True
if Intermediate_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Intermediate_remaining -=1
update_stage_label()
elif Beginner_remaining > 0 :
Beginner()
inside_hwt = True
if Beginner_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Beginner_remaining -=1
update_stage_label()
else :
if Advanced_remaining == 0 and Intermediate_remaining == 0 and Beginner_remaining == 0 :
if Remaining == 0 :
Done = 3
Finished_HWT = True
HWTOFF()
elif route_key() == 'second':
if Intermediate_remaining > 0 :
Intermediate()
inside_hwt = True
if Intermediate_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Intermediate_remaining -=1
update_stage_label()
elif Advanced_remaining > 0 :
Advanced()
inside_hwt = True
if Advanced_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Advanced_remaining -=1
update_stage_label()
elif Beginner_remaining > 0 :
Beginner()
inside_hwt = True
if Beginner_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Beginner_remaining -=1
update_stage_label()
else :
if Advanced_remaining == 0 and Intermediate_remaining == 0 and Beginner_remaining == 0 :
if Remaining == 0 :
Done = 3
Finished_HWT = True
HWTOFF()
elif route_key() == 'first':
if Beginner_remaining > 0 :
Beginner()
inside_hwt = True
if Beginner_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Beginner_remaining -=1
update_stage_label()
elif Intermediate_remaining > 0 :
Intermediate()
inside_hwt = True
if Intermediate_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Intermediate_remaining -=1
update_stage_label()
elif Advanced_remaining > 0 :
Advanced()
inside_hwt = True
if Advanced_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Advanced_remaining -=1
update_stage_label()
else :
if Advanced_remaining == 0 and Intermediate_remaining == 0 and Beginner_remaining == 0 :
if Remaining == 0 :
Done = 3
Finished_HWT = True
HWTOFF()
elif not lider_durumu and count >= 2:
if lider_konum == "Advanced" :
Advanced()
if Advanced_remaining == 0 :
update_stage_label()
elif Advanced_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Advanced_remaining -=1
update_stage_label()
elif lider_konum == "Intermediate" :
Intermediate()
if Intermediate_remaining == 0 :
update_stage_label()
elif Intermediate_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Intermediate_remaining -=1
update_stage_label()
elif lider_konum == "Beginner" :
Beginner()
if Beginner_remaining == 0 :
update_stage_label()
elif Beginner_remaining > 0 :
if Remaining == 0 :
Remaining += 1
Beginner_remaining -=1
update_stage_label()
elif lider_konum == "TOWN" :
if MembersReturn == 0 :
MembersReturn += 1
ReturnCommand = True
return_town()
log('Plugin: Party Lideri Şehirde, Şehre dönülüyor.')
elif lider_konum == "GATE" :
if WaitMaster == 0 :
WaitMaster += 1
log('Plugin: Party Liderinin giriş yapması bekleniyor...')
else :
pass
def Gate():
npcs = get_npcs() or {}
return any(npc['servername'] == "GATE_TOMB_GATE_IN" for npc in npcs.values()) if npcs else False
def FGW_Gate():
npcs = get_npcs() or {}
return any(npc['servername'] == "NPC_FWORLD_RECALL_PARTY" for npc in npcs.values()) if npcs else False
def IfCancelSpeed():
npcs = get_npcs() or {}
if not npcs:
return False
target_npcs = {
"NPC_FWORLD_RECALL_PARTY",
"GATE_TOMB_GATE_IN",
"GATE_TOMB_GATE_OUT_1",
"GATE_TOMB_GATE_OUT_2",
"GATE_TOMB_GATE_OUT_3"
}
result = any(npc['servername'] in target_npcs for npc in npcs.values())
return result
def event_loop():
# Zamanlayici, eklentinin geri kalanindan bagimsiz calisir:
# "Eklenti aktif" kapali olsa bile saat gelince profili degistirir.
try:
timer_check()
timer_update_label()
except Exception as e:
log(f'Plugin: Zamanlayici dongu hatasi: {e}')
if checkbox_states.get('disabledplugin') and resurrection_name in resurrection_list and check_data :
global ReturnCommand, Finished_HWT, CheckPoint, start_bot_in_town, last_trace_stop_time, start_time_entrance
CheckInDungeon()
if is_in_dungeon in { "FGW" , "HWT" } :
if is_in_dungeon == "HWT" :
if checkbox_states.get('ignoreNav') and not DodgeAttackBool :
if status in { "tracing", "botting" }:
threading.Timer(0.1, DodgeAttack).start()
elif is_in_dungeon == "FGW" :
if checkbox_states.get('ignoreNav2') and not DodgeAttackBool :
if status in { "tracing", "botting" }:
threading.Timer(0.1, DodgeAttack).start()
elif checkbox_states.get('returntown') :
party_info = get_party_info() or {}
if party_info.get('area','') == "TOWN" :
if not End() and not ReturnCommand:
ReturnCommand = True
return_town()
elif is_in_dungeon == "GATE" :
if HWT_Entrance and ReturnCommand == False and Finished_HWT == False:
if status == "botting" and Gate() :
if start_time_entrance is None:
start_time_entrance = time.time()
elif time.time() - start_time_entrance >= 30:
stop_bot()
else:
start_time_entrance = None
Entrance()
elif Finished_HWT and after_hwt_key() and start_bot_in_town == False :
hwt_profile = QtBind.text(gui, txtHWTPROFILE) or "HWT"
if current_profile == hwt_profile:
Finished_HWT = False
switch_profile_and_return(after_hwt_key(), 'HWT')
if checkbox_states.get('Enabled'):
if is_in_dungeon in { "FGW" , "HWT" } and checkbox_states.get('trace') :
party_info = get_party_info() or {}
lider_durumu = party_info.get('is_me',False)
if not lider_durumu and not stop_checking_trace_status :
start_trace_for_dungeon()
elif is_in_dungeon == "TOWN" :
hwt_profile = QtBind.text(gui, txtHWTPROFILE) or "HWT"
# FGW bitisi: FGW'den sehre donuldu ve bir hedef secilmis.
# Profil degistigi an kosul kendiliginden kapanir, tekrar tetiklenmez.
fgw_profile_ = QtBind.text(gui, txtFGWPROFILE).strip() or "FGW"
if after_fgw_key() and previous_dungeon == "FGW" and current_profile == fgw_profile_ :
switch_profile_and_return(after_fgw_key(), 'FGW')
elif checkbox_states.get('changeprofile2') and waitpartymembers_command and current_profile == "FAKE_SLOT" :
threading.Timer(0.1,waitpartymembers).start()
elif current_profile == hwt_profile and checkbox_states.get('start') :
current_time = time.time()
if last_trace_stop_time > 0 and (current_time - last_trace_stop_time) < 0.6:
return
elif status is not None and status not in { 'tracing', 'botting' }:
start_bot()
log(f'Plugin: Şehirde Holy Water Temple için botu başlattık.')
elif status == "tracing":
stop_trace()
log(f'Plugin: Şehirde botu başlatmak için takibi durdurduk.')
last_trace_stop_time = time.time()
elif current_profile != hwt_profile and HWT_Entrance and checkbox_states.get('EntranceON') :
HWTOFF()
elif is_in_dungeon == "GATE" :
if not HWT_Entrance :
hwt_profile = QtBind.text(gui, txtHWTPROFILE) or "HWT"
if current_profile == hwt_profile:
if checkbox_states.get('EntranceON'):
party_info = get_party_info() or {}
lider_durumu = party_info.get('is_me',False)
if lider_durumu and Done < 3:
HWTON()
elif not lider_durumu:
HWTON()
elif is_in_dungeon == "SLOT" :
profile_slot = QtBind.text(gui, txtSLOTPROFILE).strip() or "SLOT"
if checkbox_states.get('changeprofile2') and waitpartymembers_command and current_profile == profile_slot :
threading.Timer(0.1,waitpartymembers).start()
def send_pm_to_dc_chars(args):
if disconnect_list :
slot_profile = QtBind.text(gui, txtSLOTPROFILE).strip() or "SLOT"
pm_message = f"change profile {slot_profile.lower()}"
for name in disconnect_list[:]:
try:
result = phBotChat.Private(name, pm_message)
if result:
log(f"Plugin: {name} adlı kişiye mesaj gönderildi.")
disconnect_list.remove(name)
else:
log(f"Plugin: {name} adlı kişiye mesaj gönderilemedi.")
except Exception as e:
log(f"Plugin: {name} için hata oluştu: {e}")
if disconnect_list :
log(f"Kalanlar: {', '.join(disconnect_list)}")
else :
log(f'Plugin: Herkese mesaj gönderildi.')
time.sleep(1.5) # Flood yememek için bekleme
else :
log(f'Plugin: Liste temiz.')
return 0
target_positions = [
(["alexandria"], [(-16638, -329), (-16117, 54)]),
(["hotan krallığı", "hotan kingdom"], (-11454, -3262)),
(["jangan"], (6432, 1098)),
(["constantinople"], (-10656, 2604)),
(["western china donwhang", "batı çin donwhang"], (3551, 2070)),
(["samarkand"], (-5155, 2830)),
]
def check_positions():
char_data = get_character_data() or {}
map_location = char_data.get('zone_name', '').lower()
char_pos = (char_data.get('x', 0), char_data.get('y', 0))
for town_names, coords in target_positions:
if map_location in [name.lower() for name in town_names]:
# Alexandria veya diğerleri
if isinstance(coords, list):
# Tüm koordinatlar için kontrol
all_far = True
for x, y in coords:
target_range = int(math.dist(char_pos, (x, y)))
log(f'{map_location} -> {x},{y} -> Range: {target_range}')
if target_range < 10: # biri 30'dan küçükse başarısız
all_far = False
break
if all_far: # hepsi 30 veya daha uzaksa
return True
else:
x, y = coords
target_range = int(math.dist(char_pos, (x, y)))
log(f'{map_location} -> {x},{y} -> Range: {target_range}')
if target_range >= 10:
return True
return False
def handle_chat(t, player, msg) :
if not player.lower() == resurrection_name :
if t in { 2 , 4 } :
if msg.startswith("change profile "):
global pm_received, start_bot_in_town, stop_bot_in_town, set_profile_in_town, unsucces_fgw, dont_move, stop_checking_trace_status
FGWProfile = QtBind.text(gui, txtFGWPROFILE).strip() or "FGW"
HWTProfile = QtBind.text(gui, txtHWTPROFILE).strip() or "HWT"
SLOTProfile = QtBind.text(gui, txtSLOTPROFILE).strip() or "SLOT"
if not pm_received :
pm_received = True
if not dont_move :
dont_move = True
new_profile = msg[len("change profile "):].strip() or ''
master_name = QtBind.text(gui, txtSLOTMASTER).strip() or ''
if new_profile == FGWProfile.lower() and master_name == player : #change profile fgw
if status in { "tracing" , "botting" } :
if status == "tracing" :
stop_trace()
elif status == "botting" :
if is_in_dungeon == "TOWN" :
stop_bot()
else :
stop_bot_in_town = True
if is_in_dungeon == "TOWN" :
if current_profile.lower() != new_profile.lower() :
set_profile(FGWProfile)
else :
if current_profile.lower() != new_profile.lower() :
set_profile_in_town = (True,FGWProfile)
return_town()
if unsucces_fgw :
unsucces_fgw = False
log(f'Plugin: [ {FGWProfile} ] profiline geçiş kontrolü yapılıyor. ')
log(f'Plugin: Durum: {status}, Lokasyon: {is_in_dungeon}, ')
log(f'Plugin: Aktif profil: "{current_profile}", Master: {master_name}, ')
log(f'Plugin: Profil değiştirilecek mi: {"Evet" if current_profile.lower() != new_profile.lower() else "Hayır"}')
elif new_profile == "dc_fgw" and master_name == player : #change profile dc_fgw
if status in { "tracing" , "botting" } :
if status == "tracing" :
stop_trace()
elif status == "botting" :
if is_in_dungeon == "TOWN" :
stop_bot()
else :
stop_bot_in_town = True
if is_in_dungeon == "TOWN" :
if current_profile.lower() != new_profile.lower() :
set_profile(FGWProfile)
else :
if current_profile.lower() != new_profile.lower() :
set_profile_in_town = (True,FGWProfile)
return_town()
log(f'Plugin: [ {FGWProfile }] profiline geçiş kontrolü yapılıyor. ')
log(f'Plugin: Durum: {status}, Lokasyon: {is_in_dungeon}, ')
log(f'Plugin: Aktif profil: "{current_profile}", Master: {master_name}, ')
log(f'Plugin: Profil değiştirilecek mi: {"Evet" if current_profile.lower() != FGWProfile.lower() else "Hayır"}')
elif new_profile == HWTProfile.lower() and master_name == player : # change profile hwt
if status == "tracing" :
stop_trace()
if Gate() :
if current_profile.lower() != new_profile :
set_profile(HWTProfile)
else:
log(f'Plugin: Zaten "{HWTProfile}" profili aktif. Değişiklik yapılmadı.')
if status == "botting" :
stop_bot()
else :
if current_profile.lower() != new_profile :
set_profile_in_town = (True,HWTProfile)
else:
log(f'Plugin: Zaten "{HWTProfile}" profili aktif. Değişiklik yapılmadı.')
if status == "botting" :
stop_bot_in_town = True
return_town()
log(f'Plugin: [ {HWTProfile} ] profiline geçiş kontrolü yapılıyor. ')
log(f'Plugin: Durum: {status}, Lokasyon: {is_in_dungeon}, ')
log(f'Plugin: Aktif profil: "{current_profile}", Master: {master_name}, ')
log(f'Plugin: Profil değiştirilecek mi: {"Evet" if current_profile.lower() != new_profile.lower() else "Hayır"}')
elif new_profile == SLOTProfile.lower() and master_name == player : # change profile slot
if status == "tracing" :
stop_trace()
if current_profile.lower() != new_profile :
set_profile(SLOTProfile)
if get_distance_to_training_area() :
if status != "botting" :
start_bot()
else :
start_bot_in_town = True
return_town()
log(f'Plugin: [ {SLOTProfile} ] profiline geçiş kontrolü yapılıyor. ')
log(f'Plugin: Durum: {status}, Lokasyon: {is_in_dungeon}, ')
log(f'Plugin: Aktif profil: "{current_profile}", Master: {master_name}, ')
log(f'Plugin: Profil değiştirilecek mi: {"Evet" if current_profile.lower() != new_profile.lower() else "Hayır"}')
elif new_profile == "rpr" and master_name == player : # change profile rpr
if is_in_dungeon == "FGW" :
stop_checking_trace_status = True
return_town()
if status == "tracing" :
stop_trace()
if current_profile.lower() == FGWProfile.lower() :
set_profile(new_profile.upper())
else:
log(f'Plugin: Profil zaten " {new_profile.upper()} " olarak ayarlı. Değişiklik yapılmadı.')
elif new_profile == "fake_slot" and master_name == player :
if status == "tracing" :
stop_trace()
if unsucces_fgw :
unsucces_fgw = False
set_profile("RPR")
else :
profile_fgw = FGWProfile.upper()
if current_profile.upper() != profile_fgw :
set_profile(profile_fgw)
if status == "botting" :
stop_bot_in_town = True
return_town()
log(f'Plugin: [ {SLOTProfile} ] profiline geçiş kontrolü yapılıyor. ')
log(f'Plugin: Durum: {status}, Lokasyon: {is_in_dungeon}, ')
log(f'Plugin: Aktif profil: "{current_profile}", Master: {master_name}, ')
log(f'Plugin: Profil değiştirilecek mi: {"Evet" if current_profile.lower() != new_profile.lower() else "Hayır"}')
else :
Master = get_party_info().get('leader_name','') == player
if new_profile.lower() not in {'fgw','dc_fgw','hwt','slot','rpr','fake_slot'} and Master :
set_profile(new_profile.upper())
elif msg.startswith("dodge "):
if is_in_dungeon in { "FGW" , "HWT" } :
command = msg[len("dodge "):].strip()
if is_in_dungeon == "FGW" and checkbox_states.get('usedodgeskills') :
if command == "Sereness":
# Kendi paketimizden zaten tetiklendiyse bu cagri yutulur.
request_dodge_sereness('parti duyurusu')
elif is_in_dungeon == "HWT" and checkbox_states.get('reflect') :
if command == "Sphinx Beginner":
SpinixReflectCounterStop()
threading.Timer(16.0,SpinixReflectCounterStart).start()
if log_message :
log('Plugin: Beginner Sphinx Reflect Counter')
elif command == "Sphinx Intermediate":
SpinixReflectCounterStop()
threading.Timer(21.0,SpinixReflectCounterStart).start()
if log_message :
log('Plugin: Intermediate Sphinx Reflect Counter')
elif command == "Sphinx Advanced":
SpinixReflectCounterStop()
threading.Timer(26.0,SpinixReflectCounterStart).start()
if log_message :
log('Plugin: Advanced Spinix Reflect Counter')
elif msg.startswith("give me profile"):
if checkbox_states.get('disabledplugin') :
if is_in_dungeon == "FGW" :
if player not in disconnect_list :
disconnect_list.append(player)
if disconnect_from_fgw[0] == "FGW" and False :
return
elif current_profile == "FAKE_SLOT" :
phBotChat.Private(player, f'change profile fake_slot')
else :
profile = current_profile.lower()
phBotChat.Private(player, f'change profile {profile}')
else :
phBotChat.Private(player, f'Plugin: Plugin is Disabled. [ Cannot assign a profile name ] ')
def is_close_trace_master(trace_name):
char_data = get_character_data() or {}
party_members = get_party() or {}
char_pos = (char_data.get('x', 0), char_data.get('y', 0))
Range = 299
for member in party_members.values():
if member['name'] == trace_name:
member_pos = (member['x'], member['y'])
distance = int(math.dist(char_pos, member_pos))
Range = min(Range, distance)
return Range if Range != 299 else -1
def start_trace_for_dungeon():
global last_trace_time, trace_log, trace_cooldown
party_info = get_party_info() or {}
leader_name = party_info.get('leader_name','')
if is_in_dungeon == "FGW":
trace_name = QtBind.text(gui, txtFGWMASTER) or leader_name
elif is_in_dungeon == "HWT":
trace_name = QtBind.text(gui, txtHWTMASTER) or leader_name
else:
return
distance = is_close_trace_master(trace_name)
if distance >= 0:
min_distance = safe_int(QtBind.text(gui, txtMinDistance), 10)
max_distance = safe_int(QtBind.text(gui, txtMaxDistance), 70)
if distance <= min_distance:
if status == "tracing" and trace_log :
trace_log = False
log(f'Plugin: Trace Master: {trace_name} ({distance} birim uzaklıkta) takip başlatılıyor...')
elif status is not None and status not in { "tracing" , "botting" } and not dead and remember_last_status not in { "tracing" , "botting" }:
current_time = time.time()
if current_time - last_trace_time >= trace_cooldown:
last_trace_time = current_time
start_trace(trace_name)
trace_log = True
elif status == "botting":
stop_bot()
leader_pos = party_info.get('leader_pos','')
if leader_pos[0] != 0 and leader_pos[1] != 0 :
move_to(leader_pos[0], leader_pos[1], 0)
if trace_log :
trace_log = False
elif distance >= max_distance:
file_path = get_training_area().get('path', '')
if status is not None and status not in { "tracing" , "botting" } and not dead :
set_training_script(file_path)
threading.Timer(0.5,start_bot).start()
log(f'Plugin: Trace Master: {trace_name} ({distance} birim uzaklıkta) bot başlatılıyor...')
if trace_log :
trace_log = False
elif status == "tracing":
set_training_script(file_path)
stop_trace()
if trace_log :
trace_log = False
def handle_joymax(opcode, data) :
global AdvancedL,IntermediateL,BeginnerL,Done
if opcode == 0xB05A and resurrection_name in resurrection_list:
if data[:3] == bytes( [ 0x02, 0x27, 0x1C ] ) :
if route_key() == 'third':
if AdvancedL < 5:
AdvancedL = 5
elif IntermediateL < 5 :
IntermediateL = 5
elif BeginnerL < 5 :
BeginnerL = 5
elif route_key() == 'second':
if IntermediateL < 5 :
IntermediateL = 5
elif AdvancedL < 5:
AdvancedL = 5
elif BeginnerL < 5 :
BeginnerL = 5
elif route_key() == 'first':
if BeginnerL < 5 :
BeginnerL = 5
elif IntermediateL < 5 :
IntermediateL = 5
elif AdvancedL < 5:
AdvancedL = 5
elif route_key() == 'only_advanced' :
if AdvancedL < 5:
AdvancedL = 5
elif route_key() == 'only_intermediate' :
if IntermediateL < 5 :
IntermediateL = 5
elif route_key() == 'only_beginner' :
if BeginnerL < 5 :
BeginnerL = 5
Done += 1
elif opcode == 0xB070 and resurrection_name in resurrection_list:
if is_in_dungeon in { "FGW" , "HWT" } :
if is_in_dungeon == "FGW" :
if data[:5] == bytes( [ 0x01, 0x00, 0x30, 0x51, 0x80 ] ) :
sereness_cast_detected()
elif is_in_dungeon == "HWT" :
if data[:5] == bytes( [ 0x01, 0x00, 0x30, 0x9D, 0x7A ] ) :
phBotChat.Party("dodge Sphinx Beginner")
if checkbox_states.get('reflect') :
SpinixReflectCounterStop()
threading.Timer(16.0,SpinixReflectCounterStart).start()
if log_message :
log('Plugin: Beginner Sphinx Reflect Counter')
elif data[:5] == bytes( [ 0x01, 0x00, 0x30, 0xA4, 0x7A ] ) :
phBotChat.Party("dodge Sphinx Intermediate")
if checkbox_states.get('reflect') :
SpinixReflectCounterStop()
threading.Timer(21.0,SpinixReflectCounterStart).start()
if log_message :
log('Plugin: Intermediate Spinix Reflect Counter')
elif data[:5] == bytes( [ 0x01, 0x00, 0x30, 0xAB, 0x7A ] ) :
phBotChat.Party("dodge Sphinx Advanced")
if checkbox_states.get('reflect') :
SpinixReflectCounterStop()
threading.Timer(26.0,SpinixReflectCounterStart).start()
if log_message :
log('Plugin: Advanced Sphinx Reflect Counter')
return True
def pm_party_master_for_profile_loop():
global pm_requested, pm_received
master_name = QtBind.text(gui, txtSLOTMASTER).strip() or ''
if pm_received :
return
if master_name == '' :
log("Plugin: Party master ismi boş.")
return
if pm_requested and not pm_received:
log(f"Plugin: PM gönderiliyor → {master_name}")
phBotChat.Private(master_name, "give me profile")
threading.Timer(30.0,pm_party_master_for_profile_loop).start()
def sereness_cast_detected():
"""Boss'un telegraf paketi goruldu. Duyuruyu SADECE parti lideri yapar;
boylece 8 uyenin ayni anda partiye yazip birbirini tetiklemesi biter."""
started = False
if checkbox_states.get('usedodgeskills'):
started = request_dodge_sereness('paket')
try:
if started and get_party_info().get('is_me', False):
phBotChat.Party("dodge Sereness")
except Exception as e:
log(f'Plugin: Sereness duyurusu gonderilemedi: {e}')
def request_dodge_sereness(source=''):
"""Tek olay = tek kacis. Tekrar eden tetiklemeleri yutar.
Donen deger: bu cagri gercekten yeni bir kacis baslatti mi."""
global _dodge_last_ts, _dodge_epoch
with _dodge_lock:
now = time.time()
if now - _dodge_last_ts < DODGE_COOLDOWN:
return False
_dodge_last_ts = now
_dodge_epoch += 1
epoch = _dodge_epoch
if log_message and source:
log(f'Plugin: Kacis tetiklendi [ kaynak: {source} ]')
Trigger_Dodge_Sereness(epoch)
return True
def Trigger_Dodge_Sereness(epoch=None):
if epoch is None:
# Disaridan dogrudan cagrildiysa tekillestirmeden gecir
request_dodge_sereness('direct')
return
monsters = get_monsters() or {}
x_canavar = y_canavar = None
if monsters:
unique_name = "Ghost Sereness"
for mob in monsters.values():
if mob['name'].strip() == unique_name.strip():
x_canavar, y_canavar = mob['x'], mob['y']
break
else:
log(f'Plugin: Yakınlarda [ {unique_name} ] bulunamadı.')
return
else:
log("Plugin: Yakınlarda Canavar bulunamadı.")
return
if x_canavar is not None and y_canavar is not None:
global movement
movement = not movement
position = get_position() or {}
x_karakter = position.get('x', 0)
y_karakter = position.get('y', 0)
yaricap = safe_int(QtBind.text(gui, lineedit_range), 20)
dx = x_karakter - x_canavar
dy = y_karakter - y_canavar
mesafe = math.hypot(dx, dy) # sqrt(dx**2 + dy**2) yerine daha okunabilir
if mesafe != 0:
target_angle = math.atan2(dy, dx)
delta_angle = math.radians(20) if movement else math.radians(-20)
target_angle += delta_angle
x_yeni = x_canavar + yaricap * math.cos(target_angle)
y_yeni = y_canavar + yaricap * math.sin(target_angle)
else:
x_yeni = x_canavar
y_yeni = y_canavar
if status == "botting" :
set_training_position(0, x_yeni, y_yeni, 0)
if log_message :
log(f"Plugin: Ghost Sereness ' ten kaçılıyor... [ {x_karakter:.0f},{y_karakter:.0f} -> {x_yeni:.0f},{y_yeni:.0f} ]")
threading.Timer(0.1, Dodge_Sereness, [x_yeni, y_yeni, 0, epoch]).start()
def Dodge_Sereness(x, y, z, epoch=None):
for i in range(10):
# Daha yeni bir kacis basladiysa bu dongu kendini iptal eder;
# boylece iki zit hedefe ayni anda move_to gonderilmez.
if epoch is not None and epoch != _dodge_epoch:
return
move_to(x, y, z)
time.sleep(0.2)
if log_message :
p = get_position() or {}
log(f"Plugin: Kacis bitti. Son konum: [ {p.get('x',0):.0f},{p.get('y',0):.0f} ]")
def HWTON():
global HWT_Entrance
if not HWT_Entrance :
QtBind.setChecked(gui,cbxHolyMolyEntrance,True)
HWT_Entrance = QtBind.isChecked(gui, cbxHolyMolyEntrance)
if log_message :
log('Plugin: Active Holy Water Temple (Entrance)')
def HWTOFF():
global HWT_Entrance
if HWT_Entrance:
QtBind.setChecked(gui,cbxHolyMolyEntrance,False)
HWT_Entrance = QtBind.isChecked(gui, cbxHolyMolyEntrance)
if log_message :
log('Plugin: Passive Holy Water Temple (Entrance)')
def Beginner(): # 165, 166, 167
npcs = get_npcs() or {}
if npcs :
for key , npc in npcs.items() :
if npc.get('servername', 'GATE_TOMB_GATE_IN') == "GATE_TOMB_GATE_IN" or npc.get('name', 'Krallar Vadisi') == "Krallar Vadisi" or npc.get('name', 'Kings Valley') == "Kings Valley" :
eng = get_teleport_data(npc['name'], "Pharaoh tomb (beginner)")
tr = get_teleport_data(npc['name'], "Pharaoh'nun mezarı (düşük)")
if eng :
inject_joymax(0x705A,struct.pack('= 2 :
try:
if round(float(args[1])) <= 8 :
memberCount = round(float(args[1]))
else :
log(f"Plugin: Geçersiz sayı girdisi, Yakındaki oyuncu sayısı için varsayılan {memberCount} kullanılacak.")
except ValueError:
log(f"Plugin: Geçersiz sayı girdisi, Yakındaki oyuncu sayısı için varsayılan {memberCount} kullanılacak.")
if len(args) >= 3 :
try:
if round(float(args[2])) :
max_range = round(float(args[2]))
else :
log(f"Plugin: Geçersiz sayı girdisi, Kontrol mesafesi için varsayılan {max_range} kullanılacak.")
except ValueError:
log(f"Plugin: Geçersiz sayı girdisi, Kontrol mesafesi için varsayılan {max_range} kullanılacak.")
current_count, missing_players = GetPartyMembersCount(max_range)
if current_count < memberCount:
stop_bot()
if not waiting_thread or not waiting_thread.is_alive():
waiting_thread = threading.Thread(target=WaitPartyTask, args=(memberCount,max_range))
waiting_thread.start()
if missing_players:
log('Plugin: Yakında olmayan üyeler: ' + ', '.join(missing_players) + ' bekleniyor...')
else :
if memberCount > 8 :
memberCount = 8
if current_count < memberCount :
logged_missing_player = memberCount - current_count
log(f'Plugin: Partyde {logged_missing_player} kişi eksik, bekleniyor... ')
else :
log(f'Plugin: WaitParty script komutu zaten aktif.')
return 0
def GetPartyMembersCount(check_range):
_, missing_players, _ = everybodyhere()
nearby_count = 0
player_data = get_party() or {}
if player_data:
leader = next((m for m in player_data.values() if m.get('leader')), None)
if leader:
nearby_count = 1 # lider dahil
leader_pos = (leader['x'], leader['y'])
for member in player_data.values():
if not member.get('leader'):
member_pos = (member['x'], member['y'])
dist = math.dist(member_pos, leader_pos)
if dist < check_range:
nearby_count += 1
if member['name'] in missing_players:
missing_players.remove(member['name'])
return nearby_count, missing_players
def WaitPartyTask(MemberCount,max_range):
previous_missing_count = 0
while True:
try:
result = GetPartyMembersCount(max_range)
if result is None or not isinstance(result, tuple) or len(result) != 2:
log("Plugin: Grup verisi alınamadı veya hatalı formatta. Beklenmedik sonuç.")
time.sleep(1)
continue
count, missing_players = result
if missing_players and len(missing_players) < previous_missing_count:
log('Plugin: Bir oyuncu daha geldi! Şu anda beklenen üyeler: ' + ', '.join(missing_players))
previous_missing_count = len(missing_players)
if count >= MemberCount:
break
time.sleep(0.5)
except Exception as e:
log(f"Plugin: WaitPartyTask hata verdi: {str(e)}")
break
log('Plugin: Bekleme tamamlandı, herkes hazır!')
start_bot()
def teleported():
if checkbox_states.get('disabledplugin') :
global WaitMaster,MembersReturn,ReturnCommand,Remaining,start_bot_in_town,stop_bot_in_town,movement,set_profile_in_town,dont_move,stop_checking_trace_status
party_info = get_party_info() or {}
lider_durumu = party_info.get('is_me', False)
if set_profile_in_town[0]:
set_profile(set_profile_in_town[1])
set_profile_in_town = (False, '')
if start_bot_in_town or stop_bot_in_town:
if start_bot_in_town :
start_bot()
start_bot_in_town = False
elif stop_bot_in_town :
stop_bot()
stop_bot_in_town = False
if stop_checking_trace_status :
stop_checking_trace_status = False
if ReturnCommand :
ReturnCommand = False
if movement == False :
movement = True
if Remaining > 0 :
Remaining = 0
if WaitMaster > 0 :
WaitMaster = 0
if MembersReturn > 0 :
MembersReturn = 0
if checkbox_states.get('notrace') :
if dont_move :
dont_move = False
inject_joymax(0x7074,b'\x02',False)
p = get_position()
if p :
region, x, y, z = p.get('region', 0), p.get('x', 0), p.get('y', 0), p.get('z', 0)
if region in {23088, 23687, 23603, 25000, 26265, 27244, 26959}:
def force_movemont(x,y,z):
for i in range(3):
move_to(x, y, z)
time.sleep(0.334)
threading.Timer(0.1, force_movemont,[x,y,z]).start()
threading.Timer(1.0,stop_trace_if_checked).start()
if HWT_Entrance and lider_durumu :
threading.Timer(1.0,start_bot_in_hwt).start()
def stop_trace_if_checked():
if previous_dungeon in ("FGW", "HWT", "GATE" ):
global unsucces_fgw
start_time = time.time()
while True:
if time.time() - start_time > 20.0:
break
if status in { "tracing" , "botting" } :
if is_in_dungeon == "TOWN":
if status == "tracing" :
stop_trace()
log("Plugin: Şehre dönüş yapıldı, takip durduruldu.")
if False and previous_dungeon == "FGW" :
if not unsucces_fgw :
unsucces_fgw = True
give_me_profile_name()
break
else :
break
elif is_in_dungeon == "GATE":
if status == "tracing" :
stop_trace()
log("Plugin: Holy Water Temple girişindesin, takip durduruldu.")
elif status == "botting" :
stop_bot()
log("Plugin: Holy Water Temple girişindesin, bot durduruldu.")
break
time.sleep(0.5)
def start_bot_in_hwt():
global inside_hwt
start_time = time.time()
while True:
if time.time() - start_time > 1.0:
break
if inside_hwt:
if is_in_dungeon == "HWT":
if status != "botting":
start_bot()
elif status == "botting":
stop_bot()
threading.Timer(1, start_bot).start()
inside_hwt = False
break
else:
if is_in_dungeon == "GATE" and status == "botting":
stop_bot()
break
time.sleep(0.5)
def OutCheck():
start_time = time.time()
server_name = ''
while True:
if time.time() - start_time > 1.0:
break
npcs = get_npcs() or {}
training_area = get_training_area() or {}
radius = training_area.get('radius', 0)
attack_radius = safe_int(QtBind.text(gui, txtRange), 35)
attack_radius2 = safe_int(QtBind.text(gui, txtRange2), 45)
if not npcs:
continue
for key, npc in npcs.items():
server_name = npc.get('servername', '')
if server_name in ["GATE_TOMB_GATE_OUT_2", "GATE_TOMB_GATE_OUT_3"] and radius < attack_radius:
set_training_radius(attack_radius)
if log_message:
log(f'Plugin: Saldırı Menzilin [ {attack_radius} ] ile değiştirildi. [ HWT ] ')
break
elif server_name == "GATE_TOMB_GATE_OUT_1" and radius < attack_radius:
if not checkbox_states.get('ignoresph') :
set_training_radius(attack_radius)
if log_message:
log(f'Plugin: Saldırı Menzilin [ {attack_radius} ] ile değiştirildi. [ HWT ] ')
break
elif server_name == "NPC_FWORLD_RECALL_PARTY" and radius < attack_radius2:
set_training_radius(attack_radius2)
if log_message:
log(f'Plugin: Saldırı Menzilin [ {attack_radius2} ] ile değiştirildi. [ FGW ] ')
break
if server_name in {'NPC_FWORLD_RECALL_PARTY','GATE_TOMB_GATE_OUT_1','GATE_TOMB_GATE_OUT_2','GATE_TOMB_GATE_OUT_3'}:
break
time.sleep(0.5)
def go_hwt():
# Eskiden sabit "hwt" gonderiliyordu; profil adi "HWT-1" oldugu icin
# alicida eslesme tutmuyordu. Artik profil adinin kendisi gonderiliyor.
hwt_profile = QtBind.text(gui, txtHWTPROFILE).strip() or "HWT"
log(f'Plugin: [ {hwt_profile} ] için Profil değiştiriliyor. [ {pName} ]' )
phBotChat.Party(f"change profile {hwt_profile.lower()}")
threading.Timer(10.0,self_change_profile_hwt).start()
def self_change_profile_hwt():
global waitpartymembers_command
profile_hwt = QtBind.text(gui, txtHWTPROFILE).strip() or "HWT"
if status == "botting" :
stop_bot()
set_profile(profile_hwt)
waitpartymembers_command = True
return_town()
def everybodyhere():
path = get_config_dir() or ''
CharData = get_character_data() or {}
profile = get_profile() or ''
ConfigFile = f"{CharData['server']}_{CharData['name']}.{profile}.json" if profile else f"{CharData['server']}_{CharData['name']}.json"
cleaned_list = []
party_invite_type = 0
limited_list = 1
full_path = path + ConfigFile
if os.path.exists(full_path):
with open(full_path, "r", encoding='utf-8') as f:
Configdata = json.load(f)
party_data = Configdata.get("Party", {})
invite_list = party_data.get("InviteList", [])
limited_list += len(invite_list[:7])
cleaned_list = [item[:-1] if item.endswith('$') else item for item in invite_list]
party_invite_type = party_data.get("PartyInviteType", 0)
return limited_list, cleaned_list, party_invite_type
def fgw_party_list():
path = get_config_dir() or ''
CharData = get_character_data() or {}
profile_fgw = QtBind.text(gui, txtFGWPROFILE).strip() or "FGW"
ConfigFile = f"{CharData['server']}_{CharData['name']}.{profile_fgw}.json" if profile_fgw else f"{CharData['server']}_{CharData['name']}.json"
full_path = path + ConfigFile
cleaned_list = []
if os.path.exists(full_path):
with open(full_path, "r", encoding='utf-8') as f:
Configdata = json.load(f)
if "Party" in Configdata and "InviteList" in Configdata["Party"]:
invite_list = Configdata["Party"]["InviteList"]
cleaned_list = [item[:-1] if item.endswith('$') else item for item in invite_list]
return cleaned_list
def disconnected():
if False :
global disconnect_from_fgw,client_disconnect_from_fgw
if is_in_dungeon == "FGW" and disconnect_from_fgw[0] == 'null' :
disconnect_from_fgw = (is_in_dungeon,x,y)
client_disconnect_from_fgw = disconnect_from_fgw
saveConfigs()
def send_message_from_dc():
fgw_players = fgw_party_list()
profile_fgw = QtBind.text(gui, txtFGWPROFILE).strip() or "FGW"
global start_bot_in_town
if fgw_players :
pm_message = "change profile dc_fgw"
log(f"PM LIST: {', '.join(fgw_players)}")
for name in fgw_players[:]:
try:
result = phBotChat.Private(name, pm_message)
if result:
log(f"Plugin: {name} adlı kişiye mesaj gönderildi.")
fgw_players.remove(name)
else:
log(f"Plugin: {name} adlı kişiye mesaj gönderilemedi.")
except Exception as e:
log(f"Plugin: {name} için hata oluştu: {e}")
if fgw_players :
log(f"Kalanlar: {', '.join(fgw_players)}")
else :
log(f'Plugin: Herkese mesaj gönderildi.')
threading.Timer(0.5,change_rotation).start()
if status == "botting" :
stop_bot()
start_bot_in_town = True
return_town()
if status == "botting" :
stop_bot()
if current_profile != profile_fgw :
set_profile(profile_fgw)
time.sleep(1.5) # Flood yememek için bekleme
else :
log(f'Plugin: [ {profile_fgw} ] Profilindeki invite listesinde kimse bulunamadı.')
return 0
def change_rotation():
x, y = client_disconnect_from_fgw[1], client_disconnect_from_fgw[2]
training_area = get_training_area() or {}
if is_inside_big_area(x, y):
if is_inside_inner_area(x, y):
if training_area.get('name','') != 'FGW3' :
log(f"Plugin: Ghost Sereness buz dağında dc oldunuz. Komut ona göre düzenlendi.")
set_training_area('FGW3')
else:
log(f'Plugin: İlk gemi rotasyonunda dc tespit edildi. Komut değiştirilmedi.')
else:
if training_area.get('name','') != 'FGW2' :
log(f'Plugin: ikinci gemi rotasyonunda dc tespit edildi. Komut ona göre düzenlendi.')
set_training_area('FGW2')
def is_inside_big_area(x, y):
center_x, center_y = 18618, 3774
radius = 905
dx = x - center_x
dy = y - center_y
distance_squared = dx**2 + dy**2
return distance_squared <= radius**2
def is_inside_inner_area(x, y):
center_x, center_y = 17844, 3754
radius = 120
dx = x - center_x
dy = y - center_y
distance_squared = dx**2 + dy**2
return distance_squared <= radius**2
def waitpartymembers():
global waitpartymembers_command
if waitpartymembers_command :
waitpartymembers_command = False
party_info = get_party_info() or {}
expected_count, _, _ = everybodyhere()
current_count = party_info.get('total_members', 0)
if current_count >= expected_count:
go_hwt()
return
timeout = time_diff_in_seconds()
timeout = timeout if timeout is not None else 7200
start_time = time.time()
while current_count < expected_count:
profile_slot = QtBind.text(gui, txtSLOTPROFILE).strip() or "SLOT"
if current_profile != profile_slot :
threading.Timer(5.0, waitpartymembers_command_t).start()
break
party_info = get_party_info() or {}
current_count = party_info.get('total_members', 0)
if current_count >= expected_count:
go_hwt()
break
if time.time() - start_time > timeout:
log("Plugin: Süre doldu. Beklenen Party üye sayısına ulaşılamadı.")
threading.Timer(5.0, waitpartymembers_command_t).start()
break
time.sleep(0.5)
def waitpartymembers_command_t():
global waitpartymembers_command
waitpartymembers_command = True
def time_diff_in_seconds():
if not (converted_time1 and converted_time2):
return None # Saatler tanımlı değilse
today = datetime.today().date()
dt1 = datetime.combine(today, converted_time1)
dt2 = datetime.combine(today, converted_time2)
diff = (dt2 - dt1).total_seconds()
if diff < 0:
diff += 24 * 3600 # gece yarısını geçiyorsa
return int(diff)
def information_dungeon(args):
if len(args) == 1 :
if is_in_dungeon in {"FGW", "HWT"}:
radius = 50
if is_in_dungeon == "FGW":
objects = {
"First Treasure Box": (17832, 3195),
"Ghost Sereness": (17930, 3735),
"Done Forgotten World": (17475, 3825),
}
elif is_in_dungeon == "HWT":
objects = {
"Done Beginner": (11765, 4327),
"Done Intermediate": (11764, 5700),
"Done Advanced": (9268, 5690),
}
for name, (obj_x, obj_y) in objects.items():
distance = ((x - obj_x) ** 2 + (y - obj_y) ** 2) ** 0.5
if distance <= radius:
if is_in_dungeon == "FGW":
if name == "First Treasure Box":
log("Congratulations, the first Treasure Box has been destroyed.")
elif name == "Ghost Sereness":
log("Congratulations, Ghost Sereness has been defeated.")
elif name == "Done Forgotten World":
log("Congratulations, you have successfully completed Forgotten World.")
elif is_in_dungeon == "HWT":
if name == "Done Beginner":
log("Congratulations, you have successfully completed Holy Water Temple - Beginner.")
elif name == "Done Intermediate":
log("Congratulations, you have successfully completed Holy Water Temple - Intermediate.")
elif name == "Done Advanced":
log("Congratulations, you have successfully completed Holy Water Temple - Advanced.")
else:
log("Custom Notice: " + ' '.join(args[1:]))
return 0
def give_me_profile_name():
if isJoined() :
if False :
global pm_requested, pm_received
master_name = QtBind.text(gui, txtSLOTMASTER).strip() or ''
if master_name.lower() == resurrection_name.lower():
return
pm_requested = True
pm_received = False
if previous_dungeon == 'FGW' and unsucces_fgw :
log("Plugin: Forgotten World bitirilemedi. Party master'dan profil bilgisi istenecek.")
else :
threading.Timer( 1, lambda: log("Plugin: Profil bilgisi isteme açık. Party master'dan profil bilgisi istenecek.") ).start()
threading.Timer(5.0, pm_party_master_for_profile_loop).start()
elif False :
global disconnect_from_fgw
if disconnect_from_fgw[0] == "FGW" :
disconnect_from_fgw = ('null',0,0)
saveConfigs()
log("Plugin: Profil bilgisi verme açık. Party üyelerine profil bilgisi verilecek.")
threading.Timer(5.0, send_message_from_dc).start()
else :
threading.Timer(5.0, give_me_profile_name).start()
def return_town():
return_scroll_list = [
"Instant Return Scroll", # Anında
"Special Return Scroll", # Özel
"Return Scroll", # Normal Return
]
def get_item(name):
items = get_inventory()['items']
for slot, item in enumerate(items):
if item and item.get('name') == name:
item['slot'] = slot
return item
return None
def use_item(item):
if not item:
return False
ItemInfo = get_item_string(item['name'])
tid1, tid2, tid3, slot = ItemInfo['tid1'], ItemInfo['tid2'], ItemInfo['tid3'], item['slot']
p = struct.pack('