from phBot import * from threading import Timer import random import QtBind import math import os import json import phBotChat # Definitions pName = 'xFgwStone_Solo' gui = QtBind.init(__name__, pName) current_lang = "TR" evading = False # Dictionary lang = { 'TR': { 'active': 'Eklentiyi Aktif Et', 'pm_notify': 'Bildirimleri PM At', 'target': 'Hedef Canavar:', 'rad': 'Kaçış Menzili (Yatay):', 'delay': 'Kaçış Sonrası Başlama (sn):', 'save': 'Ayarları Kaydet', 'lang_btn': 'Dil / Lang: TR', 'lvl91': '- 91~100 Seviye Seçimi -', 'lvl101': '- 101~110 Seviye Seçimi -', 'err_not_in_game': 'Karakter oyunda değil, kaydedilemedi.', 'saved': 'Ayarlar başarıyla kaydedildi.', 'err_save': 'Ayar kaydetme hatası:', 'loaded': 'Ayarlar yüklendi.', 'err_load': 'Ayar yükleme hatası:', 'wait_start': 'Konuma ulaşıldı. Bot {} saniye sonra başlatılacak.', 'bot_started': 'Bot başarıyla yeniden başlatıldı.', 'random_evade': 'Boss ekranda bulunamadı! Rastgele yatay kaçılıyor.', 'evade_trigger': 'Petrify Tespit! Yörüngeye (X:{}, Y:{}) kaçılıyor...', 'ready': 'Yüklendi. Solo FGW Kaçış Sistemi Hazır.' }, 'EN': { 'active': 'Enable Plugin', 'pm_notify': 'Send PM Notifications', 'target': 'Target Monster:', 'rad': 'Evasion Radius (Horiz):', 'delay': 'Restart Delay (sec):', 'save': 'Save Config', 'lang_btn': 'Lang / Dil: EN', 'lvl91': '- 91~100 Level Selection -', 'lvl101': '- 101~110 Level Selection -', 'err_not_in_game': 'Character not in game, cannot save.', 'saved': 'Settings successfully saved.', 'err_save': 'Error saving config:', 'loaded': 'Settings loaded.', 'err_load': 'Error loading config:', 'wait_start': 'Position reached. Bot will start in {} seconds.', 'bot_started': 'Bot successfully restarted.', 'random_evade': 'Boss not found on screen! Evading randomly.', 'evade_trigger': 'Petrify Detected! Evasion to (X:{}, Y:{})', 'ready': 'Loaded. Solo FGW Evasion System Ready.' } } # GUI cbxActive = QtBind.createCheckBox(gui, 'cbx_active_clicked', '', 15, 15) cbxSendPM = QtBind.createCheckBox(gui, 'cbx_pm_clicked', '', 150, 15) lblTargetMob = QtBind.createLabel(gui, '', 15, 45) tbxTargetMob = QtBind.createLineEdit(gui, 'Ghost Sereness', 150, 43, 110, 16) lblData0 = QtBind.createLabel(gui, 'Data [0]:', 15, 75) tbxData0 = QtBind.createLineEdit(gui, '1', 75, 73, 40, 16) lblData1 = QtBind.createLabel(gui, 'Data [1]:', 135, 75) tbxData1 = QtBind.createLineEdit(gui, '0', 195, 73, 40, 16) lblData3 = QtBind.createLabel(gui, 'Data [3]:', 15, 100) tbxData3 = QtBind.createLineEdit(gui, '82', 75, 98, 40, 16) lblData4 = QtBind.createLabel(gui, 'Data [4]:', 135, 100) tbxData4 = QtBind.createLineEdit(gui, '128', 195, 98, 40, 16) lblRadius = QtBind.createLabel(gui, '', 15, 135) tbxEscapeRadius = QtBind.createLineEdit(gui, '12', 170, 133, 40, 16) lblDelay = QtBind.createLabel(gui, '', 15, 160) tbxRestartDelay = QtBind.createLineEdit(gui, '5.0', 170, 158, 40, 16) btnSaveConfig = QtBind.createButton(gui, 'save_configs', '', 15, 195) btnLang = QtBind.createButton(gui, 'toggle_lang', '', 130, 195) lblLvl91 = QtBind.createLabel(gui, '', 300, 15) rb91_1 = QtBind.createCheckBox(gui, 'rb_clicked_91_1', '91-100 Lvl 1* (Data3: 80)', 300, 35) rb91_2 = QtBind.createCheckBox(gui, 'rb_clicked_91_2', '91-100 Lvl 2* (Data3: 81)', 300, 55) rb91_3 = QtBind.createCheckBox(gui, 'rb_clicked_91_3', '91-100 Lvl 3* (Data3: 82)', 300, 75) rb91_4 = QtBind.createCheckBox(gui, 'rb_clicked_91_4', '91-100 Lvl 4* (Data3: 83)', 300, 95) lblLvl101 = QtBind.createLabel(gui, '', 300, 125) rb101_1 = QtBind.createCheckBox(gui, 'rb_clicked_101_1', '101-110 Lvl 1* (Data3: 84)', 300, 145) rb101_2 = QtBind.createCheckBox(gui, 'rb_clicked_101_2', '101-110 Lvl 2* (Data3: 85)', 300, 165) rb101_3 = QtBind.createCheckBox(gui, 'rb_clicked_101_3', '101-110 Lvl 3* (Data3: 86)', 300, 185) rb101_4 = QtBind.createCheckBox(gui, 'rb_clicked_101_4', '101-110 Lvl 4* (Data3: 87)', 300, 205) radio_buttons = [rb91_1, rb91_2, rb91_3, rb91_4, rb101_1, rb101_2, rb101_3, rb101_4] data3_values = [80, 81, 82, 83, 84, 85, 86, 87] # UI Updates def update_ui(): QtBind.setText(gui, cbxActive, lang[current_lang]['active']) QtBind.setText(gui, cbxSendPM, lang[current_lang]['pm_notify']) QtBind.setText(gui, lblTargetMob, lang[current_lang]['target']) QtBind.setText(gui, lblRadius, lang[current_lang]['rad']) QtBind.setText(gui, lblDelay, lang[current_lang]['delay']) QtBind.setText(gui, btnSaveConfig, lang[current_lang]['save']) QtBind.setText(gui, btnLang, lang[current_lang]['lang_btn']) QtBind.setText(gui, lblLvl91, lang[current_lang]['lvl91']) QtBind.setText(gui, lblLvl101, lang[current_lang]['lvl101']) def toggle_lang(): global current_lang current_lang = "EN" if current_lang == "TR" else "TR" update_ui() save_configs() # Radio Actions def set_radio_exclusive(clicked_rb_index): for i, rb in enumerate(radio_buttons): if i == clicked_rb_index: QtBind.setChecked(gui, rb, True) QtBind.setText(gui, tbxData3, str(data3_values[i])) else: QtBind.setChecked(gui, rb, False) def rb_clicked_91_1(checked): set_radio_exclusive(0) if checked else None def rb_clicked_91_2(checked): set_radio_exclusive(1) if checked else None def rb_clicked_91_3(checked): set_radio_exclusive(2) if checked else None def rb_clicked_91_4(checked): set_radio_exclusive(3) if checked else None def rb_clicked_101_1(checked): set_radio_exclusive(4) if checked else None def rb_clicked_101_2(checked): set_radio_exclusive(5) if checked else None def rb_clicked_101_3(checked): set_radio_exclusive(6) if checked else None def rb_clicked_101_4(checked): set_radio_exclusive(7) if checked else None def cbx_active_clicked(checked): pass def cbx_pm_clicked(checked): pass # Config def get_config_path(): char_data = get_character_data() if char_data and "server" in char_data and "name" in char_data: folder = os.path.join(get_config_dir(), pName) if not os.path.exists(folder): os.makedirs(folder) return os.path.join(folder, f"{char_data['server']}_{char_data['name']}.json") return None def save_configs(): path = get_config_path() if not path: log(f"[{pName}] {lang[current_lang]['err_not_in_game']}") return selected_rb_index = -1 for i, rb in enumerate(radio_buttons): if QtBind.isChecked(gui, rb): selected_rb_index = i data = { "Language": current_lang, "Active": QtBind.isChecked(gui, cbxActive), "SendPM": QtBind.isChecked(gui, cbxSendPM), "TargetMob": QtBind.text(gui, tbxTargetMob), "Data0": QtBind.text(gui, tbxData0), "Data1": QtBind.text(gui, tbxData1), "Data3": QtBind.text(gui, tbxData3), "Data4": QtBind.text(gui, tbxData4), "EscapeRadius": QtBind.text(gui, tbxEscapeRadius), "RestartDelay": QtBind.text(gui, tbxRestartDelay), "SelectedStarIndex": selected_rb_index } try: with open(path, "w", encoding="utf-8") as f: json.dump(data, f, indent=4) log(f"[{pName}] {lang[current_lang]['saved']}") except Exception as e: log(f"[{pName}] {lang[current_lang]['err_save']} {str(e)}") def load_configs(): global current_lang path = get_config_path() if path and os.path.exists(path): try: with open(path, "r", encoding="utf-8") as f: data = json.load(f) current_lang = data.get("Language", "TR") QtBind.setChecked(gui, cbxActive, data.get("Active", False)) QtBind.setChecked(gui, cbxSendPM, data.get("SendPM", False)) QtBind.setText(gui, tbxTargetMob, data.get("TargetMob", "Ghost Sereness")) QtBind.setText(gui, tbxData0, data.get("Data0", "1")) QtBind.setText(gui, tbxData1, data.get("Data1", "0")) QtBind.setText(gui, tbxData3, data.get("Data3", "82")) QtBind.setText(gui, tbxData4, data.get("Data4", "128")) QtBind.setText(gui, tbxEscapeRadius, data.get("EscapeRadius", "12")) QtBind.setText(gui, tbxRestartDelay, data.get("RestartDelay", "5.0")) idx = data.get("SelectedStarIndex", -1) if idx != -1: set_radio_exclusive(idx) log(f"[{pName}] {lang[current_lang]['loaded']}") except Exception as e: log(f"[{pName}] {lang[current_lang]['err_load']} {str(e)}") update_ui() def joined_game(): load_configs() # Notification Engine def notify(msg): """ Hem bot loglarına yazar, hem de tikliyse PM atar """ full_msg = f"[{pName}] {msg}" log(full_msg) if QtBind.isChecked(gui, cbxSendPM): char_data = get_character_data() if char_data and 'name' in char_data and char_data['name']: try: phBotChat.Private(char_data['name'], full_msg) except Exception as e: pass # Evasion Engine def get_boss_position(target_name): name_lower = target_name.lower() for mob in get_monsters().values(): if 'name' in mob and mob['name'].lower() == name_lower: return mob['x'], mob['y'] return None, None def force_move_spam(x, y, z, attempts): if attempts > 0: move_to(x, y, z) Timer(0.2, force_move_spam, [x, y, z, attempts - 1]).start() else: try: delay = float(QtBind.text(gui, tbxRestartDelay)) except: delay = 5.0 notify(lang[current_lang]['wait_start'].format(delay)) Timer(delay, safe_start_bot).start() def safe_start_bot(): global evading evading = False if get_status() != "botting": start_bot() notify(lang[current_lang]['bot_started']) def execute_evasion(): global evading pos = get_position() if not pos: return char_x, char_y, char_z = pos['x'], pos['y'], pos['z'] target_name = QtBind.text(gui, tbxTargetMob).strip() boss_x, boss_y = get_boss_position(target_name) try: radius = float(QtBind.text(gui, tbxEscapeRadius)) except: radius = 12.0 if boss_x is not None and boss_y is not None: dx, dy = boss_x - char_x, boss_y - char_y dist = math.sqrt(dx**2 + dy**2) if dist > 0: ux, uy = dx / dist, dy / dist left_px, left_py = -uy, ux right_px, right_py = uy, -ux choice = random.choice([(left_px, left_py), (right_px, right_py)]) new_x = char_x + (choice[0] * radius) new_y = char_y + (choice[1] * radius) else: new_x = char_x + random.uniform(-radius, radius) new_y = char_y + random.uniform(-radius, radius) else: notify(lang[current_lang]['random_evade']) new_x = char_x + random.uniform(-radius, radius) new_y = char_y + random.uniform(-radius, radius) notify(lang[current_lang]['evade_trigger'].format(int(new_x), int(new_y))) force_move_spam(new_x, new_y, char_z, attempts=6) # Packet Handling def handle_joymax(opcode, data): global evading if opcode == 0xB070 and len(data) >= 5 and QtBind.isChecked(gui, cbxActive): try: d0 = int(QtBind.text(gui, tbxData0)) d1 = int(QtBind.text(gui, tbxData1)) d3 = int(QtBind.text(gui, tbxData3)) d4 = int(QtBind.text(gui, tbxData4)) if data[0] == d0 and data[1] == d1 and data[3] == d3 and data[4] == d4: if evading: return True if get_status() == "botting": evading = True stop_bot() execute_evasion() except ValueError: pass return True # Initialize update_ui() load_configs() log(f"[{pName}] {lang[current_lang]['ready']}")