""" ====================================================================== COMPLETE DOMINATION ====================================================================== Owner: Evilrage Version: Build 476 Date: 4-10-2026 Server: UO Unchained Guild: Phoenix Rising [PXR] --- SUPPORTED CLASSES & TEMPLATES --- • Tamer • Pure Mage • Dexter / Warrior • Archer • Paladin / Chiv • Bard • Tinker • Lockpicker • Poisoner • Necromancer • Skinner • Combat Healer *(Engine dynamically auto-detects and supports hybrid builds!)* --- INDEX OF MAJOR UPDATES (SINCE v475) --- [+] The Golem Engine: Full Golem auto-repair system using Tinker/Golem kits, wake-up guard commands, and 3-beep low-charge alarms. [+] Anti-Suicide Fix: Violently clears stuck cursors before healing/curing to prevent executing yourself with your own pets. [+] High-Speed Dust Vacuum: Instantly sweeps 36 custom Unchained enhancement IDs directly to the Loot Bag after dusting. [+] Safe Zone Vaulting: Vault Bag is now completely isolated. Enhancements bypass it, and Tomes no longer steal from it. [+] Infinite Loop Fix: Safe-checks destination containers before moving items to eliminate bag-sorting lag. [+] Dead Pet Auto-Recall: Dynamically tracks "IsGhost" and automatically commands dead pets to "follow me" for instant auto-rez. [+] Boss ARPG HUD: Holographic health bar overlay for major Unchained bosses (Shame, Sandstorm, Paragons, etc.). [+] Tome Restocker: Automated GUI for mass-feeding Davies' Locker, Arcane Scrolls, Resource Maps, and custom Dyes. [+] >ignore Command: Custom in-game chat command to permanently whitelist items so the auto-sorter leaves them alone. [+] Streamlined GUI: Completely gutted the heavy PvP, PvE Mage, and Summon Elemental bloat for a lightning-fast PvM experience. [+] Wand of Dust: Renamed GUI toggle and streamlined logic so users can easily swap to a Sewing Kit ID if needed. ====================================================================== """ import sys import Misc import Items import Player import Target import Mobiles import Journal import Gumps import Spells import time import re from System.Collections.Generic import List from System import Byte, Int32 # ========================================================== # >>> PART 1: SYSTEM & CONFIGURATIONS <<< # ========================================================== DRAW_INTERVAL = 1.0 GUMP_ID = 81818 BOSS_GUMP_ID = 6666 BUFF_GUMP_ID = 7777 BOSS_X = 400 BOSS_Y = 50 BOSS_HP_THRESHOLD = 3000 REFRESH_MS = 150 # --- ITEM IDs --- GOLD_ID = 0x0EED BANDAGE_ID = 0x0E21 VET_KIT_ID = 27539 SCISSORS_ID = 3999 HIDES_ID = 0x1079 LEATHER_ID = 0x1081 ARROW_ID = 0x0F3F BOLT_ID = 0x1BFB TOOL_KIT_ID = 0x1EB8 SKULL_ID = 43445 WAND_ID = 20497 REFRESH_POTION_ID = 0x0F0B STR_POTION_ID = 0x0F09 DEX_POTION_ID = 0x0F08 PETAL_ID = 0x1021 ORANGE_PETAL_HUE = 0x002B DISSIDIA_PETAL_HUE = 0x082B MINOC_PETAL_HUE = 0x07C6 MOONGLOW_PETAL_HUE = 0x0B40 STORAGE_SHELF_ID = 44993 ENCHANT_SHELF_ID = 48347 # --- LISTS --- SKINNING_TOOL_IDS = [0x0EC4, 0x0F52, 0x0F51, 0x13F6] INSTRUMENT_IDS = [0x0EB1, 0x0EB2, 0x0EB3, 0x0EB4, 0x0E9C, 0x0E9D, 0x0E9E, 0x2805] POTION_IDS = [0x0F06, 0x0F07, 0x0F08, 0x0F09, 0x0F0A, 0x0F0B, 0x0F0C, 0x0F0D] REAGENT_IDS = [0x0F84, 0x0F85, 0x0F86, 0x0F8D, 0x0F8C, 0x0F7A, 0x0F7B, 0x0F88] IGNORED_ITEM_IDS = [8786, 0x2252, 8787, 0x2253, 10135, 0x0F9E] HIGH_VALUE_IDS = [0x14F0, 0x14EC, 0x2260, 0x0E34, 0x0FF0, 0x14EB, 0x099F, 0x0FA9, 0x0FAB, 0x0F03, 0x5740, 0x097B, 0x2260, 0x63E8, 0x71B0, 43445] BLESSED_ITEM_HUES = List[Int32]([0x08A8]) KNOWN_MASTERIES = ["Fira", "Earth", "Tera", "Aero", "Blood", "Doom", "Lyrical", "Fortune", "Poison", "Shadow", "Holy", "Bulwark", "Death", "Artisan", "Nature", "Druidic", "Void", "Command", "Ranger", "Berserker", "Tinkering", "Alchemy"] MASTERY_PET_NAMES = {"Fira": "Lava Elemental", "Earth": "Tera Guar", "Tera": "Tera Guar", "Aero": "Pixie", "Blood": "Blood Elemental", "Doom": "Shadow Dweller", "Lyrical": "Satyr", "Fortune": "Loot Goblin", "Poison": "Poison Elemental", "Shadow": "Shadow Elemental", "Holy": "Wisp", "Bulwark": "War Boar", "Death": "Lich", "Artisan": "Iron Beetle", "Nature": "Forest Spirit", "Druidic": "Serpent"} PLAYER_BODIES = [400, 401, 605, 606, 666, 667, 746, 747, 748, 749] WHITE_LIST_BY_NAME = ["an energy vortex", "an energy vortext", "a rising colossus", "a dog", "a cat", "bird"] FRIEND_SERIALS = [] SPECIFIC_PET_SERIAL = [] PET_MAPPING = {} SPECIFIC_PET_BODIES = [0x002E, 0x058E, 0x0260, 0x02F0] PET_NAME_OVERRIDES = {"bloody": "Bloody", "draconus": "Draconus"} # --- CACHES & GLOBALS --- MOBILE_PROP_CACHE = {} ITEM_PROP_CACHE = {} PET_DATA_CACHE = {} PET_RECALL_STATES = {} VAULT_ATTEMPT_HISTORY = {} KNOWN_JUNK = [] LOOTED_SERIALS = [] opened_corpses = [] skinned_corpses = [] unlocked_chests = [] MASTERY_DATA = {"Type": "None", "Current": 0, "Max": 0, "Percent": 0.0} ACTIVE_MASTERY = Misc.ReadSharedValue("ACTIVE_MASTERY") if Misc.CheckSharedValue("ACTIVE_MASTERY") else "Waiting..." # --- TARGETING CONFIG --- LOOT_RANGE = 3 GUARD_RANGE = 12 VET_RANGE = 3 # --- TOGGLES --- AUTO_MOVE_GOLD = True AUTO_BANK_GOLD = True USE_SCISSORS = True USE_BLESS = True USE_POTIONS = True USE_ARCH_CURE = True PET_CURE_POISON = True SHOW_HOLOGRAM_HUD = True SHOW_TARGET_OVERHEAD = True TARGET_OVERHEAD_HUE = 33 TARGET_OVERHEAD_MSG = "▼▼ DESTROY ▼▼" HAS_100_LRC = False DISCORD_MODE = "SingleTarget" PEACE_MODE = "Off" BARD_DELAY = 11.0 POTION_COOLDOWN = 10.0 POTION_HEAL_TRIGGER = 60 SELF_HEAL_TRIGGER = 80 SELF_BANDAGE_HP_TRIGGER = 85 SELF_BANDAGE_DELAY = 5.0 VET_DELAY_SECONDS = 4.0 VET_KIT_DELAY = 4.0 RESCUE_HP_TRIGGER = 40 SAFE_TO_VET_HP_TRIGGER = 85 WARN_LOW_AMMO = 100 WARN_LOW_BANDAGES = 25 WARN_AT_WEIGHT = 10 VAULT_SOUND_ID = 0x5B4 # --- REG IDs --- REG_GARLIC = 0x0F84 REG_GINSENG = 0x0F85 REG_MANDRAKE = 0x0F86 REG_SILK = 0x0F8D REG_SHADE = 0x0F88 REG_ASH = 0x0F8C REG_PEARL = 0x0F7A REG_MOSS = 0x0F7B # --- INITIALIZERS --- IS_MEDDING = False MED_GORGET = 0 LAST_EQUIP_TIME = 0 LAST_EMPTY_HANDS_TIME = 0 LAST_CONSECRATE = 0 LAST_DIVINE_FURY = 0 LAST_GOLEM_REPAIR = 0 LAST_PET_SCAN = 0 last_str_pot_time = 0 last_dex_pot_time = 0 last_orange_petal_time = 0 last_dissidia_petal_time = 0 last_minoc_petal_time = 0 last_moonglow_petal_time = 0 last_heal_time = 0 last_cure_time = 0 last_pet_cure_time = 0 last_poison_time = 0 last_magery_buff_time = 0 last_soul_reap_time = 0 last_heal_potion_time = 0 last_cure_potion_time = 0 last_refresh_pot_time = 0 last_wand_time = 0 last_bless_time = 0 last_weight_warn = 0 last_supply_warn = 0 last_bank_check_time = 0 last_vault_scan_time = 0 last_chiv_time = 0 tithing_empty_time = 0 is_recovering_health = False next_allowed_heal_time = 0 next_allowed_vet_time = 0 next_vet_kit_time = 0 vet_cycle_count = 0 pet_rez_timers = {} magery_buff_cooldowns = {} GLOBAL_CORPSE_FILTER = Items.Filter() GLOBAL_CORPSE_FILTER.Enabled = True GLOBAL_CORPSE_FILTER.IsCorpse = True GLOBAL_CHEST_FILTER = Items.Filter() GLOBAL_CHEST_FILTER.Enabled = True GLOBAL_CHEST_FILTER.Graphics = List[Int32]([0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E7C, 0x0E7E, 0x09AA, 0x09AB, 0x0E80, 0x0E7D, 0x0E7F, 3648]) GLOBAL_GOLD_FILTER = Items.Filter() GLOBAL_GOLD_FILTER.Enabled = True GLOBAL_GOLD_FILTER.Graphics = List[Int32]([GOLD_ID]) GLOBAL_GOLD_FILTER.OnGround = True GLOBAL_DANGER_FILTER = Mobiles.Filter() GLOBAL_DANGER_FILTER.Enabled = True GLOBAL_DANGER_FILTER.Notorieties = List[Byte]([Byte(3), Byte(4), Byte(5), Byte(6)]) GLOBAL_FRIEND_FILTER = Mobiles.Filter() GLOBAL_FRIEND_FILTER.Enabled = True GLOBAL_FRIEND_FILTER.IsHuman = True GLOBAL_FRIEND_FILTER.Notorieties = List[Byte]([Byte(1), Byte(2)]) GLOBAL_MOB_FILTER = Mobiles.Filter() GLOBAL_MOB_FILTER.Enabled = True def GetTruePetName(mob_name): if not mob_name: return "Pet" clean = re.sub(r'<[^>]+>', '', mob_name).replace("*", "").strip() for key, true_name in PET_NAME_OVERRIDES.items(): if key in clean.lower(): return true_name caps_words = [w for w in clean.split() if w and w[0].isupper()] if caps_words: return " ".join(caps_words) return clean def InitSavedPets(): global SPECIFIC_PET_SERIAL, PET_MAPPING, SPECIFIC_PET_BODIES if Misc.CheckSharedValue("SAVED_PET_MAP"): val = Misc.ReadSharedValue("SAVED_PET_MAP") if val: pairs = val.split("|") for p in pairs: if ":" in p: s_str, name = p.split(":", 1) if s_str.isdigit(): s = int(s_str) if s not in SPECIFIC_PET_SERIAL: SPECIFIC_PET_SERIAL.append(s) PET_MAPPING[s] = name mob = Mobiles.FindBySerial(s) if mob and int(mob.Body) not in SPECIFIC_PET_BODIES: SPECIFIC_PET_BODIES.append(int(mob.Body)) elif Misc.CheckSharedValue("SAVED_PET_SERIALS"): val = Misc.ReadSharedValue("SAVED_PET_SERIALS") if val: serials = [int(x) for x in val.split(",") if x] for s in serials: if s not in SPECIFIC_PET_SERIAL: SPECIFIC_PET_SERIAL.append(s) mob = Mobiles.FindBySerial(s) if mob: raw_name = mob.Name if mob.Name else "Unknown" PET_MAPPING[s] = GetTruePetName(raw_name) if int(mob.Body) not in SPECIFIC_PET_BODIES: SPECIFIC_PET_BODIES.append(int(mob.Body)) else: PET_MAPPING[s] = "Saved Pet (Out of Range)" save_str = "|".join(["{}:{}".format(x, PET_MAPPING[x]) for x in SPECIFIC_PET_SERIAL]) Misc.SetSharedValue("SAVED_PET_MAP", save_str) # ========================================================== # >>> PART 2: GUI SYSTEM <<< # ========================================================== _core_vars = { 'SCRIPT_RUNNING': False, 'USE_SKINNING': False, 'AUTO_FARM_MODE': True, 'GUI_MINIMIZED': False, 'LOOT_MAGIC_ITEMS': True, 'LOOT_DUSTABLES': False, 'USE_DIVINE_FURY': False, 'USE_MAGERY_BUFFS': True, 'USE_TAUNT': False, 'USE_LOCKPICKING': False, 'USE_CHEST_LOOT': False, 'USE_ENHANCED_HEALING': False, 'USE_AUTO_WAND': True, 'USE_SMART_POISON': False, 'USE_AUTO_BUFFS': False, 'USE_AUTO_PETALS': True, 'PET_HEAL_METHOD': "Both", 'USE_AUTO_SOUL': False, 'USE_ANTI_DISARM': True, 'USE_SELF_HEAL': True, 'USE_PET_HEAL': True, 'USE_AUTO_ENGAGE': False, 'USE_PET_RECALL': True, 'USE_ARPG_HUD': True, 'PLAY_VAULT_SOUND': True, 'CURRENT_ACTION': "Idle", 'LAST_GUI_HASH': 0, 'DRAW_INTERVAL': 1.0, 'LAST_DRAW_TIME': 0, 'last_button_id': 0, 'GUMP_ID': 81818, 'DETECTED_BUILD': "Unknown", 'LOOT_SOURCE_BAG': 0, 'VAULT_BAG_SERIAL': 0, 'SATCHEL_SERIAL': 0, 'PREF_WEP': 0, 'PREF_SHIELD': 0, 'BOSS_GUMP_ID': 6666, 'BOSS_X': 400, 'BOSS_Y': 50, 'BOSS_HP_THRESHOLD': 3000, # ---> THE FIX: Put your private variables back in! <--- 'pvp_mode_enabled': False, 'pve_mage_enabled': False, 'USE_SUMMONS': False, 'PVP_SPELLBOOK_SERIAL': [0x405440DD, 0x4184BE0D], 'PVE_SPELLBOOK_SERIAL': [0x405440DD, 0x4184BE0D] } for _k, _v in _core_vars.items(): if _k not in globals(): globals()[_k] = _v def SmartDetectBuild(): global IS_TAMER, IS_DEXTER, IS_MAGE, IS_BARD, IS_PALADIN, IS_TINKER, IS_CHIV, IS_LOCKPICKER, IS_POISONER, IS_ARCHER, IS_NECRO, IS_SKINNER, DETECTED_BUILD if 'DETECTED_BUILD' not in globals(): globals()['DETECTED_BUILD'] = "Unknown" if 'IS_TAMER' not in globals(): globals()['IS_TAMER'] = False if 'IS_DEXTER' not in globals(): globals()['IS_DEXTER'] = False if 'IS_MAGE' not in globals(): globals()['IS_MAGE'] = False if 'IS_BARD' not in globals(): globals()['IS_BARD'] = False if 'IS_PALADIN' not in globals(): globals()['IS_PALADIN'] = False if 'IS_TINKER' not in globals(): globals()['IS_TINKER'] = False if 'IS_CHIV' not in globals(): globals()['IS_CHIV'] = False if 'IS_LOCKPICKER' not in globals(): globals()['IS_LOCKPICKER'] = False if 'IS_POISONER' not in globals(): globals()['IS_POISONER'] = False if 'IS_ARCHER' not in globals(): globals()['IS_ARCHER'] = False if 'IS_NECRO' not in globals(): globals()['IS_NECRO'] = False if 'IS_SKINNER' not in globals(): globals()['IS_SKINNER'] = False old_build = DETECTED_BUILD taming = Player.GetSkillValue("Animal Taming") magery = Player.GetSkillValue("Magery") peace = Player.GetSkillValue("Peacemaking") discord = Player.GetSkillValue("Discordance") provoke = Player.GetSkillValue("Provocation") healing = Player.GetSkillValue("Healing") chivalry = Player.GetSkillValue("Chivalry") tinkering = Player.GetSkillValue("Tinkering") lockpicking = Player.GetSkillValue("Lockpicking") poisoning = Player.GetSkillValue("Poisoning") archery = Player.GetSkillValue("Archery") necromancy = Player.GetSkillValue("Necromancy") forensics = Player.GetSkillValue("Forensic Evaluation") scavenging = 0 try: scavenging = Player.GetSkillValue("Scavenging") except: try: scavenging = Player.GetSkillValue("Begging") except: pass IS_SKINNER = (forensics >= 50 or scavenging >= 50) IS_DEXTER = (healing > 50) IS_TAMER = (taming > 50) IS_MAGE = (magery > 50) IS_BARD = (peace > 50 or discord > 50 or provoke > 50) IS_PALADIN = (chivalry > 40) IS_CHIV = IS_PALADIN IS_TINKER = (tinkering > 50) IS_LOCKPICKER = (lockpicking > 50) IS_POISONER = (poisoning > 20) IS_ARCHER = (archery > 50) IS_NECRO = (necromancy > 50) build_str = "Newbie" if IS_TAMER: build_str = "Tamer" if IS_MAGE: build_str += "/Mage" if IS_DEXTER: build_str += "/Healer" if IS_BARD: build_str += "/Bard" if IS_CHIV: build_str += "/Chiv" elif IS_BARD: build_str = "Bard" if IS_MAGE: build_str += "/Mage" if IS_DEXTER: build_str += "/Healer" elif IS_MAGE: build_str = "Pure Mage" if IS_DEXTER: build_str += "/Healer" elif IS_DEXTER: build_str = "Dexter/Healer" if IS_ARCHER: if "Dexter" in build_str: build_str = build_str.replace("Dexter", "Archer") elif build_str == "Newbie": build_str = "Archer" else: build_str += "/Archer" if IS_NECRO and "Necro" not in build_str: if build_str == "Newbie": build_str = "Necromancer" else: build_str += "/Necro" if IS_PALADIN and "Paladin" not in build_str: build_str += "+Paladin" if IS_LOCKPICKER: build_str += "/Lockpicker" if IS_POISONER: build_str += "/Poisoner" if IS_TINKER and "Tinker" not in build_str: if build_str == "Newbie": build_str = "Tinker" else: build_str += "/Tinker" DETECTED_BUILD = build_str if old_build != "Unknown" and old_build != DETECTED_BUILD: Player.HeadMessage(63, ">>> TEMPLATE CHANGED: {} <<<".format(DETECTED_BUILD)) Misc.Beep() def SmartDetectMastery(): global ACTIVE_MASTERY, MASTERY_DATA try: mob = Mobiles.FindBySerial(Player.Serial) if mob: Mobiles.WaitForProps(mob, 200) for prop in mob.Properties: p_str = str(prop).lower() clean_prop = re.sub(r'<[^>]+>', '', p_str) if "mastery" in clean_prop and "chivalry" not in clean_prop: for km in KNOWN_MASTERIES: if "{} mastery".format(km.lower()) in clean_prop: if ACTIVE_MASTERY != km: ACTIVE_MASTERY = km MASTERY_DATA["Type"] = ACTIVE_MASTERY Misc.SetSharedValue("ACTIVE_MASTERY", ACTIVE_MASTERY) return except: pass def CheckAndDrawGUI(force=False): global LAST_GUI_HASH global SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_DUSTABLES global LOOT_MAGIC_ITEMS, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING global USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND, USE_SMART_POISON global USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD, USE_AUTO_SOUL, USE_ANTI_DISARM global USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL, USE_ARPG_HUD global PLAY_VAULT_SOUND, CURRENT_ACTION, DETECTED_BUILD, MASTERY_DATA global pvp_mode_enabled, pve_mage_enabled, USE_SUMMONS vars_list = [ SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_MAGIC_ITEMS, LOOT_DUSTABLES, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING, USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND, USE_SMART_POISON, USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD, USE_AUTO_SOUL, USE_ANTI_DISARM, USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL, USE_ARPG_HUD, PLAY_VAULT_SOUND, pvp_mode_enabled, pve_mage_enabled, USE_SUMMONS ] current_state = "_".join(str(v) for v in vars_list) current_state += "_{}_{}_{}".format(MASTERY_DATA["Type"], MASTERY_DATA["Current"], MASTERY_DATA["Percent"]) for s in SPECIFIC_PET_SERIAL: if s in PET_DATA_CACHE: d = PET_DATA_CACHE[s] current_state += "_{}_{}".format(d.get('status',''), d.get('percent',0)) current_state += "_{}_{}".format(CURRENT_ACTION, DETECTED_BUILD) new_hash = hash(current_state) if force or (new_hash != LAST_GUI_HASH): LAST_GUI_HASH = new_hash DrawGUI(force) def DrawGUI(force=False): global last_button_id, LAST_DRAW_TIME, GUMP_ID global SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_DUSTABLES global LOOT_MAGIC_ITEMS, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING global USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND, USE_SMART_POISON global USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD, USE_AUTO_SOUL, USE_ANTI_DISARM global USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL, USE_ARPG_HUD global PLAY_VAULT_SOUND, CURRENT_ACTION, DETECTED_BUILD, MASTERY_DATA global IS_TAMER, IS_TINKER, IS_MAGE, IS_SKINNER, IS_POISONER, IS_CHIV, IS_DEXTER, IS_LOCKPICKER global LOOT_SOURCE_BAG, VAULT_BAG_SERIAL, SATCHEL_SERIAL, SPECIFIC_PET_SERIAL, PET_DATA_CACHE, PET_MAPPING global pvp_mode_enabled, pve_mage_enabled, USE_SUMMONS if not force and (time.time() - LAST_DRAW_TIME < DRAW_INTERVAL): return LAST_DRAW_TIME = time.time() has_pets = (IS_TAMER or IS_TINKER or len(SPECIFIC_PET_SERIAL) > 0) Gumps.CloseGump(GUMP_ID) gd = Gumps.CreateGump() Gumps.AddPage(gd, 0) if MASTERY_DATA["Max"] > 0: pct = float(MASTERY_DATA["Current"]) / float(MASTERY_DATA["Max"]) if pct > 1.0: pct = 1.0 MASTERY_DATA["Percent"] = round(pct * 100, 1) if GUI_MINIMIZED: base_mini_h = 130 pet_mini_h = len(SPECIFIC_PET_SERIAL) * 35 mast_mini_h = 35 if MASTERY_DATA["Type"] != "None" else 0 total_mini_h = base_mini_h + pet_mini_h + mast_mini_h Gumps.AddBackground(gd, 0, 0, 220, total_mini_h, 3500) Gumps.AddImageTiled(gd, 10, 10, 200, total_mini_h - 20, 2624) Gumps.AddAlphaRegion(gd, 10, 10, 200, total_mini_h - 20) btn_start = 101 if SCRIPT_RUNNING else 100 btn_gfx = 2474 if SCRIPT_RUNNING else 2472 Gumps.AddButton(gd, 20, 15, btn_gfx, btn_gfx, btn_start, 1, 0) btn_mode = 105 if AUTO_FARM_MODE else 104 mode_btn = 211 if AUTO_FARM_MODE else 210 Gumps.AddButton(gd, 55, 15, mode_btn, mode_btn, btn_mode, 1, 0) Gumps.AddButton(gd, 185, 15, 2437, 2438, 9999, 1, 0) status_txt = "AUTO" if AUTO_FARM_MODE else "MAN" Gumps.AddLabel(gd, 90, 15, 68, status_txt) y_off = 65 if len(SPECIFIC_PET_SERIAL) > 0: for serial in SPECIFIC_PET_SERIAL: name = PET_MAPPING.get(serial, "Pet") data = PET_DATA_CACHE.get(serial, {'percent': 0.0, 'status': 'Unknown', 'level': '?'}) Gumps.AddImageTiled(gd, 20, y_off, 180, 8, 2624) Gumps.AddAlphaRegion(gd, 20, y_off, 180, 8) p_pct = data.get('percent', 0.0) if data.get('status') == "MAX" or p_pct >= 100.0: Gumps.AddImageTiled(gd, 20, y_off, 180, 8, 2057) elif p_pct > 0: p_fill = int(180 * (p_pct / 100.0)) Gumps.AddImageTiled(gd, 20, y_off, p_fill, 8, 2054) Gumps.AddLabel(gd, 20, y_off - 15, 1152, name) y_off += 35 if MASTERY_DATA["Type"] != "None": y_off += 5 Gumps.AddImageTiled(gd, 20, y_off+15, 180, 8, 2624) Gumps.AddAlphaRegion(gd, 20, y_off+15, 180, 8) fill_m = int(180 * (MASTERY_DATA["Percent"] / 100.0)) if fill_m > 0: Gumps.AddImageTiled(gd, 20, y_off+15, fill_m, 8, 2057) Gumps.AddLabel(gd, 20, y_off, 68, "{} ({:.1f}%)".format(MASTERY_DATA["Type"], MASTERY_DATA["Percent"])) Gumps.SendGump(GUMP_ID, Player.Serial, 0, 0, gd.gumpDefinition, gd.gumpStrings) return y_bar = 110 y_pets = y_bar + 45 pet_block_h = len(SPECIFIC_PET_SERIAL) * 50 y_ctrl = y_pets + pet_block_h + 20 btn_start = 101 if SCRIPT_RUNNING else 100 btn_mode = 105 if AUTO_FARM_MODE else 104 btn_skin = 103 if USE_SKINNING else 102 btn_magic = 107 if LOOT_MAGIC_ITEMS else 106 btn_fury = 109 if USE_DIVINE_FURY else 108 btn_mage = 111 if USE_MAGERY_BUFFS else 110 btn_taunt = 113 if USE_TAUNT else 112 btn_lock = 115 if USE_LOCKPICKING else 114 btn_chest = 177 if USE_CHEST_LOOT else 176 btn_enh = 117 if USE_ENHANCED_HEALING else 116 btn_wand = 129 if USE_AUTO_WAND else 128 btn_poison = 133 if USE_SMART_POISON else 132 btn_buffs = 137 if USE_AUTO_BUFFS else 136 btn_petals = 139 if USE_AUTO_PETALS else 138 btn_soul = 145 if USE_AUTO_SOUL else 144 btn_disarm = 147 if USE_ANTI_DISARM else 146 btn_self_heal = 149 if USE_SELF_HEAL else 148 btn_pet_heal = 151 if USE_PET_HEAL else 150 btn_engage = 153 if USE_AUTO_ENGAGE else 152 btn_recall = 157 if USE_PET_RECALL else 156 btn_dustables = 159 if LOOT_DUSTABLES else 158 btn_hud = 163 if USE_ARPG_HUD else 162 btn_sound = 167 if PLAY_VAULT_SOUND else 166 btn_pvp = 171 if pvp_mode_enabled else 170 btn_pve_mage = 173 if pve_mage_enabled else 172 btn_summons = 175 if USE_SUMMONS else 174 btn_lootbag = 119 if last_button_id == 118 else 118 btn_vault = 121 if last_button_id == 120 else 120 btn_satchel = 127 if last_button_id == 126 else 126 btn_addpet = 123 if last_button_id == 122 else 122 btn_clrpet = 125 if last_button_id == 124 else 124 btn_shelf = 199 if last_button_id == 198 else 198 btn_tome = 197 if last_button_id == 196 else 196 btn_refresh = 165 if last_button_id == 164 else 164 active_toggles = [ ("Mode", btn_mode, AUTO_FARM_MODE, "Auto", "Manual"), ("PvP Mode", btn_pvp, pvp_mode_enabled, "ON", "OFF"), ("PvE Mage", btn_pve_mage, pve_mage_enabled, "ON", "OFF"), ("Auto-Engage", btn_engage, USE_AUTO_ENGAGE, "ON", "OFF"), ("Boss HUD", btn_hud, USE_ARPG_HUD, "ON", "OFF"), ("Self Heal", btn_self_heal, USE_SELF_HEAL, "ON", "OFF") ] if IS_MAGE: if not has_pets: active_toggles.append(("Summon Eles", btn_summons, USE_SUMMONS, "ON", "OFF")) active_toggles.append(("Mage Buffs", btn_mage, USE_MAGERY_BUFFS, "ON", "OFF")) if Player.GetSkillValue("Spirit Speak") > 100: active_toggles.append(("Auto Soul", btn_soul, USE_AUTO_SOUL, "ON", "OFF")) if has_pets: active_toggles.append(("Pet Heal", btn_pet_heal, USE_PET_HEAL, "ON", "OFF")) active_toggles.append(("Pet Recall", btn_recall, USE_PET_RECALL, "ON", "OFF")) if IS_MAGE: active_toggles.append(("Enh. Healing", btn_enh, USE_ENHANCED_HEALING, "ON", "OFF")) if IS_SKINNER: active_toggles.append(("Skin/Scav", btn_skin, USE_SKINNING, "ON", "OFF")) active_toggles.extend([ ("Loot Chests", btn_chest, USE_CHEST_LOOT, "ON", "OFF"), ("Loot Magic", btn_magic, LOOT_MAGIC_ITEMS, "ON", "OFF"), ("Loot Dustables", btn_dustables, LOOT_DUSTABLES, "ON", "OFF"), ("Auto Salvage", btn_wand, USE_AUTO_WAND, "ON", "OFF"), ("Vault Sound", btn_sound, PLAY_VAULT_SOUND, "ON", "OFF"), ("Anti-Disarm", btn_disarm, USE_ANTI_DISARM, "ON", "OFF") ]) if IS_POISONER: active_toggles.append(("Smart Poison", btn_poison, USE_SMART_POISON, "ON", "OFF")) if IS_CHIV: active_toggles.append(("Use D.Fury", btn_fury, USE_DIVINE_FURY, "ON", "OFF")) if Player.GetSkillValue("Parrying") >= 50: active_toggles.append(("Use Taunt", btn_taunt, USE_TAUNT, "ON", "OFF")) if IS_DEXTER: active_toggles.append(("Auto Buffs", btn_buffs, USE_AUTO_BUFFS, "ON", "OFF")) if IS_DEXTER or IS_MAGE: active_toggles.append(("Auto Petals", btn_petals, USE_AUTO_PETALS, "ON", "OFF")) if IS_LOCKPICKER: active_toggles.append(("Auto Lockpick", btn_lock, USE_LOCKPICKING, "ON", "OFF")) toggle_rows = (len(active_toggles) + 1) // 2 y_conf = y_ctrl + 30 + (toggle_rows * 30) + 20 total_h = y_conf + 140 main_w = 350 Gumps.AddBackground(gd, 0, 0, main_w, total_h, 3500) Gumps.AddImageTiled(gd, 10, 10, main_w-20, total_h-20, 2624) Gumps.AddAlphaRegion(gd, 10, 10, main_w-20, total_h-20) Gumps.AddImage(gd, 240, 40, 5549) Gumps.AddButton(gd, 305, 15, 2435, 2436, 9998, 1, 0) Gumps.AddLabel(gd, 20, 15, 63, "COMPLETE DOMINATION (PXR EDITION)") status_color = 63 if SCRIPT_RUNNING else 33 status_text = "RUNNING" if SCRIPT_RUNNING else "PAUSED" Gumps.AddLabel(gd, 20, 40, status_color, "Status: " + status_text) Gumps.AddLabel(gd, 20, 55, 88, "Action: " + CURRENT_ACTION) Gumps.AddLabel(gd, 20, 70, 55, "Build: " + DETECTED_BUILD) Gumps.AddButton(gd, 170, 72, 2117, 2118, btn_refresh, 1, 0) Gumps.AddLabel(gd, 190, 70, 55, "Refresh") m_type = MASTERY_DATA["Type"] display_name = "{} ({})".format(m_type, MASTERY_PET_NAMES[m_type]) if m_type in MASTERY_PET_NAMES else m_type m_label = display_name if m_type != "None" else "Waiting..." Gumps.AddLabel(gd, 20, y_bar, 1152, "Mastery: " + m_label) bar_full_w = 310 Gumps.AddImageTiled(gd, 20, y_bar+20, bar_full_w, 12, 2624) Gumps.AddAlphaRegion(gd, 20, y_bar+20, bar_full_w, 12) full_fill = int(bar_full_w * (MASTERY_DATA["Percent"] / 100.0)) if full_fill > 0: Gumps.AddImageTiled(gd, 20, y_bar+20, full_fill, 12, 2057) stat_text = "MAXED" if MASTERY_DATA["Current"] >= MASTERY_DATA["Max"] and MASTERY_DATA["Max"] > 0 else "{:.1f}%".format(MASTERY_DATA["Percent"]) Gumps.AddLabel(gd, 270, y_bar, 63, stat_text) current_y_pets = y_pets if len(SPECIFIC_PET_SERIAL) > 0: for serial in SPECIFIC_PET_SERIAL: name = PET_MAPPING.get(serial, "Pet") data = PET_DATA_CACHE.get(serial, {'percent': 0.0, 'status': 'Unknown', 'level': '?'}) label_text = name if data.get('status') == "MAX": label_text += " [MAX]" else: if data.get('level') != '?': label_text += " Level " + str(data.get('level')) label_text += " [{:.1f}%]".format(data.get('percent', 0.0)) if PET_RECALL_STATES.get(serial, False): label_text += " << RECALLING >>" Gumps.AddLabel(gd, 20, current_y_pets, 1152 if not PET_RECALL_STATES.get(serial, False) else 33, label_text) Gumps.AddImageTiled(gd, 20, current_y_pets+20, bar_full_w, 12, 2624) Gumps.AddAlphaRegion(gd, 20, current_y_pets+20, bar_full_w, 12) p_pct = data.get('percent', 0.0) if data.get('status') == "MAX" or p_pct >= 100.0: Gumps.AddImageTiled(gd, 20, current_y_pets+20, bar_full_w, 12, 2057) elif p_pct > 0: p_fill = int(bar_full_w * (p_pct / 100.0)) Gumps.AddImageTiled(gd, 20, current_y_pets+20, p_fill, 12, 2054) current_y_pets += 50 btn_gfx = 2474 if SCRIPT_RUNNING else 2472 Gumps.AddButton(gd, 20, y_ctrl, btn_gfx, btn_gfx, btn_start, 1, 0) Gumps.AddLabel(gd, 50, y_ctrl+2, 63 if SCRIPT_RUNNING else 33, "START/STOP") col = 0 row_y = y_ctrl + 30 for label, b_id, state, text_on, text_off in active_toggles: x_btn = 20 if col == 0 else 160 x_lbl = 45 if col == 0 else 185 btn_gfx = 211 if state else 210 lbl_txt = "Mode: " + text_on if (label == "Mode" and state) else "Mode: " + text_off if label == "Mode" else label lbl_color = 63 if state else 999 if label == "Mode": lbl_color = 63 if state else 999 Gumps.AddButton(gd, x_btn, row_y, btn_gfx, btn_gfx, b_id, 1, 0) Gumps.AddLabel(gd, x_lbl, row_y+2, lbl_color, lbl_txt) col += 1 if col > 1: col = 0 row_y += 30 Gumps.AddButton(gd, 20, y_conf+20, 4005, 4007, btn_lootbag, 1, 0) val = "SET" if LOOT_SOURCE_BAG > 0 else "NONE" col = 63 if LOOT_SOURCE_BAG > 0 else 33 Gumps.AddLabel(gd, 55, y_conf+20, col, "Loot Bag: " + val) Gumps.AddButton(gd, 20, y_conf+50, 4005, 4007, btn_vault, 1, 0) val = "SET" if VAULT_BAG_SERIAL > 0 else "NONE" col = 63 if VAULT_BAG_SERIAL > 0 else 33 Gumps.AddLabel(gd, 55, y_conf+50, col, "Vault: " + val) Gumps.AddButton(gd, 160, y_conf+50, 4005, 4007, btn_satchel, 1, 0) val = "SET" if SATCHEL_SERIAL > 0 else "NONE" col = 63 if SATCHEL_SERIAL > 0 else 33 Gumps.AddLabel(gd, 195, y_conf+50, col, "Satchel: " + val) Gumps.AddButton(gd, 20, y_conf+80, 4005, 4007, btn_addpet, 1, 0) Gumps.AddLabel(gd, 55, y_conf+80, 63, "Add Pet") Gumps.AddButton(gd, 120, y_conf+80, 4005, 4007, btn_clrpet, 1, 0) Gumps.AddLabel(gd, 155, y_conf+80, 33, "Clr") btn_heal_method = 141 if last_button_id == 140 else 140 Gumps.AddButton(gd, 190, y_conf+80, 4005, 4007, btn_heal_method, 1, 0) h_col = 63 if PET_HEAL_METHOD == "Both" else 55 if PET_HEAL_METHOD == "Bands" else 88 Gumps.AddLabel(gd, 225, y_conf+80, h_col, "Heal Mode: " + PET_HEAL_METHOD) btn_shelf = 199 if last_button_id == 198 else 198 Gumps.AddButton(gd, 20, y_conf+110, 4005, 4007, btn_shelf, 1, 0) Gumps.AddLabel(gd, 55, y_conf+110, 66, "RESTOCK SHELF") btn_tome = 197 if last_button_id == 196 else 196 Gumps.AddButton(gd, 160, y_conf+110, 4005, 4007, btn_tome, 1, 0) Gumps.AddLabel(gd, 195, y_conf+110, 66, "TOME RESTOCK") Gumps.SendGump(GUMP_ID, Player.Serial, 0, 0, gd.gumpDefinition, gd.gumpStrings) # --- WEAPON SAVING VARIABLES --- stored_pvm_wep = 0 stored_pvm_shield = 0 def poll_buttons(): global last_button_id, SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_DUSTABLES global LOOT_SOURCE_BAG, VAULT_BAG_SERIAL, SATCHEL_SERIAL, SPECIFIC_PET_SERIAL, PET_MAPPING, SPECIFIC_PET_BODIES global LOOT_MAGIC_ITEMS, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING, USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND global USE_SMART_POISON, USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD global USE_AUTO_SOUL, USE_ANTI_DISARM, USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL global USE_ARPG_HUD, PLAY_VAULT_SOUND, pvp_mode_enabled, pve_mage_enabled, USE_SUMMONS global stored_pvm_wep, stored_pvm_shield, PREF_WEP, PREF_SHIELD if 'last_tome_button_id' not in globals(): globals()['last_tome_button_id'] = -1 tome_gd = Gumps.GetGumpData(8888) if tome_gd and getattr(tome_gd, 'buttonid', -1) > 0: t_bid = tome_gd.buttonid if t_bid != globals()['last_tome_button_id']: globals()['last_tome_button_id'] = t_bid Gumps.CloseGump(8888) if t_bid == 8000: perform_tome_sequence("ALL") elif t_bid >= 8001: perform_tome_sequence(t_bid - 8001) CheckAndDrawGUI(force=True) return gd = Gumps.GetGumpData(GUMP_ID) if not gd: return bid = getattr(gd, 'buttonid', 0) if bid <= 0: return if bid == last_button_id: return last_button_id = bid if bid in [164, 165]: Player.HeadMessage(66, ">> Scanning Template & Mastery <<") SmartDetectBuild() SmartDetectMastery() CheckAndDrawGUI(force=True) return if bid in [198, 199]: perform_restock_sequence(); CheckAndDrawGUI(force=True); return if bid in [196, 197]: ShowTomeMenu(); return if bid in [174, 175]: USE_SUMMONS = not USE_SUMMONS Player.HeadMessage(55, "Summon Eles: " + ("ON" if USE_SUMMONS else "OFF")) CheckAndDrawGUI(force=True) return if bid in [170, 171]: pvp_mode_enabled = not pvp_mode_enabled if pvp_mode_enabled: pve_mage_enabled = False Player.HeadMessage(55, "PvP Mode: " + ("ON" if pvp_mode_enabled else "OFF")) if pvp_mode_enabled: Misc.SendMessage(">>> PvP MODE ACTIVATED: Stun Mage Template & Spellbook Equipped. <<<", 38) Target.ClearQueue() Target.Cancel() Player.ChatSay("[Stun Mage]") stored_pvm_wep = PREF_WEP stored_pvm_shield = PREF_SHIELD found_book = False for s in PVP_SPELLBOOK_SERIAL: if Items.FindBySerial(s): Player.EquipItem(s) found_book = True break Misc.Pause(600) if not found_book: Player.HeadMessage(33, "PVP Spellbook not found in bag!") else: Misc.SendMessage(">>> PvM MODE ACTIVATED: Resuming normal operations. <<<", 68) if stored_pvm_wep > 0: wep = Items.FindBySerial(stored_pvm_wep) if wep: Player.EquipItem(wep) Misc.Pause(600) if stored_pvm_shield > 0: sh = Items.FindBySerial(stored_pvm_shield) if sh: Player.EquipItem(sh) CheckAndDrawGUI(force=True) return if bid in [172, 173]: pve_mage_enabled = not pve_mage_enabled if pve_mage_enabled: pvp_mode_enabled = False Player.HeadMessage(55, "PvE Mage Mode: " + ("ON" if pve_mage_enabled else "OFF")) if pve_mage_enabled: Misc.SendMessage(">>> PvE MAGE ACTIVATED: Auto-Nuke Rotation Initiated. <<<", 63) stored_pvm_wep = PREF_WEP stored_pvm_shield = PREF_SHIELD found_book = False for s in PVE_SPELLBOOK_SERIAL: if Items.FindBySerial(s): Player.EquipItem(s) found_book = True break Misc.Pause(600) if not found_book: Player.HeadMessage(33, "PVE Spellbook not found in bag!") else: Misc.SendMessage(">>> PvM MELEE ACTIVATED: Resuming normal weapons. <<<", 68) if stored_pvm_wep > 0: wep = Items.FindBySerial(stored_pvm_wep) if wep: Player.EquipItem(wep) Misc.Pause(600) if stored_pvm_shield > 0: sh = Items.FindBySerial(stored_pvm_shield) if sh: Player.EquipItem(sh) CheckAndDrawGUI(force=True) return if bid in [106, 107]: LOOT_MAGIC_ITEMS = not LOOT_MAGIC_ITEMS; Player.HeadMessage(55, "Magic Loot: " + ("ON" if LOOT_MAGIC_ITEMS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [108, 109]: USE_DIVINE_FURY = not USE_DIVINE_FURY; Player.HeadMessage(55, "Use D.Fury: " + ("ON" if USE_DIVINE_FURY else "OFF")); CheckAndDrawGUI(force=True); return if bid in [110, 111]: USE_MAGERY_BUFFS = not USE_MAGERY_BUFFS; Player.HeadMessage(55, "Mage Buffs: " + ("ON" if USE_MAGERY_BUFFS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [112, 113]: USE_TAUNT = not USE_TAUNT; Player.HeadMessage(55, "Auto Taunt: " + ("ON" if USE_TAUNT else "OFF")); CheckAndDrawGUI(force=True); return if bid in [114, 115]: USE_LOCKPICKING = not USE_LOCKPICKING; Player.HeadMessage(55, "Auto Lockpick: " + ("ON" if USE_LOCKPICKING else "OFF")); CheckAndDrawGUI(force=True); return if bid in [176, 177]: USE_CHEST_LOOT = not USE_CHEST_LOOT; Player.HeadMessage(55, "Loot Chests: " + ("ON" if USE_CHEST_LOOT else "OFF")); CheckAndDrawGUI(force=True); return if bid in [116, 117]: USE_ENHANCED_HEALING = not USE_ENHANCED_HEALING; Player.HeadMessage(55, "Enh. Healing: " + ("ON" if USE_ENHANCED_HEALING else "OFF")); CheckAndDrawGUI(force=True); return if bid in [128, 129]: USE_AUTO_WAND = not USE_AUTO_WAND; Player.HeadMessage(55, "Auto Salvage: " + ("ON" if USE_AUTO_WAND else "OFF")); CheckAndDrawGUI(force=True); return if bid in [132, 133]: USE_SMART_POISON = not USE_SMART_POISON; Player.HeadMessage(55, "Smart Poison: " + ("ON" if USE_SMART_POISON else "OFF")); CheckAndDrawGUI(force=True); return if bid in [136, 137]: USE_AUTO_BUFFS = not USE_AUTO_BUFFS; Player.HeadMessage(55, "Auto Buffs: " + ("ON" if USE_AUTO_BUFFS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [138, 139]: USE_AUTO_PETALS = not USE_AUTO_PETALS; Player.HeadMessage(55, "Auto Petals: " + ("ON" if USE_AUTO_PETALS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [144, 145]: USE_AUTO_SOUL = not USE_AUTO_SOUL; Player.HeadMessage(55, "Auto Soul Reap: " + ("ON" if USE_AUTO_SOUL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [146, 147]: USE_ANTI_DISARM = not USE_ANTI_DISARM; Player.HeadMessage(55, "Anti-Disarm: " + ("ON" if USE_ANTI_DISARM else "OFF")); CheckAndDrawGUI(force=True); return if bid in [148, 149]: USE_SELF_HEAL = not USE_SELF_HEAL; Player.HeadMessage(55, "Self Heal: " + ("ON" if USE_SELF_HEAL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [150, 151]: USE_PET_HEAL = not USE_PET_HEAL; Player.HeadMessage(55, "Pet Heal: " + ("ON" if USE_PET_HEAL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [152, 153]: USE_AUTO_ENGAGE = not USE_AUTO_ENGAGE; Player.HeadMessage(55, "Auto-Engage: " + ("ON" if USE_AUTO_ENGAGE else "OFF")); CheckAndDrawGUI(force=True); return if bid in [156, 157]: USE_PET_RECALL = not USE_PET_RECALL; Player.HeadMessage(55, "Pet Recall: " + ("ON" if USE_PET_RECALL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [158, 159]: LOOT_DUSTABLES = not LOOT_DUSTABLES; Player.HeadMessage(55, "Loot Dustables: " + ("ON" if LOOT_DUSTABLES else "OFF")); CheckAndDrawGUI(force=True); return if bid in [162, 163]: USE_ARPG_HUD = not USE_ARPG_HUD Player.HeadMessage(55, "Boss HUD: " + ("ON" if USE_ARPG_HUD else "OFF")) CheckAndDrawGUI(force=True) return if bid in [166, 167]: PLAY_VAULT_SOUND = not PLAY_VAULT_SOUND Player.HeadMessage(55, "Vault Sound: " + ("ON" if PLAY_VAULT_SOUND else "OFF")) CheckAndDrawGUI(force=True) return if bid in [140, 141]: if PET_HEAL_METHOD == "Both": PET_HEAL_METHOD = "Bands" elif PET_HEAL_METHOD == "Bands": PET_HEAL_METHOD = "Kit" else: PET_HEAL_METHOD = "Both" Misc.SetSharedValue("PET_HEAL_METHOD", PET_HEAL_METHOD) Player.HeadMessage(55, "Pet Heal Mode: " + PET_HEAL_METHOD) CheckAndDrawGUI(force=True) return if bid in [100, 101]: SCRIPT_RUNNING = not SCRIPT_RUNNING Player.HeadMessage(63 if SCRIPT_RUNNING else 33, ">>> DOMINATION " + ("RUNNING" if SCRIPT_RUNNING else "PAUSED") + " <<<") elif bid in [102, 103]: USE_SKINNING = not USE_SKINNING Player.HeadMessage(55, "Skinning: " + ("ON" if USE_SKINNING else "OFF")) elif bid in [104, 105]: AUTO_FARM_MODE = not AUTO_FARM_MODE Player.HeadMessage(66, "Targeting Mode: " + ("AUTO" if AUTO_FARM_MODE else "MANUAL")) elif bid in [9998, 9999]: GUI_MINIMIZED = not GUI_MINIMIZED elif bid in [118, 119]: Misc.SendMessage("Target Loot Bag...", 68) s = Target.PromptTarget("Loot Bag") if s > 0: LOOT_SOURCE_BAG = s Misc.SetSharedValue("LOOT_SOURCE_BAG", s) Player.HeadMessage(63, "Loot Bag Set: " + hex(s)) elif bid in [120, 121]: Misc.SendMessage("Target Vault...", 68) s = Target.PromptTarget("Vault") if s > 0: VAULT_BAG_SERIAL = s Misc.SetSharedValue("VAULT_BAG_SERIAL", s) Player.HeadMessage(63, "Vault Set: " + hex(s)) elif bid in [126, 127]: Misc.SendMessage("Target Satchel...", 68) s = Target.PromptTarget("Satchel") if s > 0: SATCHEL_SERIAL = s Misc.SetSharedValue("SATCHEL_SERIAL", s) Player.HeadMessage(63, "Satchel Set: " + hex(s)) elif bid in [122, 123]: Misc.SendMessage("Target Pet to Add...", 68) s = Target.PromptTarget("Pet") if s > 0: if s == Player.Serial: Player.HeadMessage(33, "Cannot add self.") else: mob = Mobiles.FindBySerial(s) if mob: if s not in SPECIFIC_PET_SERIAL: SPECIFIC_PET_SERIAL.append(s) raw_name = mob.Name if mob.Name else "Unknown" p_name = GetTruePetName(raw_name) PET_MAPPING[s] = p_name if int(mob.Body) not in SPECIFIC_PET_BODIES: SPECIFIC_PET_BODIES.append(int(mob.Body)) save_str = "|".join(["{}:{}".format(x, PET_MAPPING[x]) for x in SPECIFIC_PET_SERIAL]) Misc.SetSharedValue("SAVED_PET_MAP", save_str) Player.HeadMessage(63, "Added & Saved: " + p_name + " (" + hex(s) + ")") else: Player.HeadMessage(44, "Already in list.") else: Player.HeadMessage(33, "Invalid Mobile.") elif bid in [124, 125]: SPECIFIC_PET_SERIAL.clear(); PET_MAPPING.clear(); PET_DATA_CACHE.clear() Misc.SetSharedValue("SAVED_PET_SERIALS", "") Misc.SetSharedValue("SAVED_PET_MAP", "") Player.HeadMessage(33, "Pet List Cleared & Memory Wiped.") CheckAndDrawGUI(force=True) class BossTargetBar: def __init__(self): self.boss_gump_id = BOSS_GUMP_ID self.last_update = 0 self.update_delay = 500 self.hud_filter = Mobiles.Filter() self.hud_filter.Enabled = True self.hud_filter.RangeMax = 15 self.hud_filter.Notorieties = List[Byte]([Byte(3), Byte(4), Byte(5), Byte(6)]) self.last_boss_hash = 0 self.boss_button_map = {} self.last_btn_clicks = {"boss": {"id": 0, "time": 0}} self.active_boss_serial = 0 self.pos_x = BOSS_X self.pos_y = BOSS_Y def draw_stroke_text(self, gump, x, y, color, text): try: ix, iy, ic = int(x), int(y), int(color) st = str(text) Gumps.AddLabel(gump, ix - 1, iy, 1, st) Gumps.AddLabel(gump, ix + 1, iy, 1, st) Gumps.AddLabel(gump, ix, iy - 1, 1, st) Gumps.AddLabel(gump, ix, iy + 1, 1, st) Gumps.AddLabel(gump, ix, iy, ic, st) except: pass def process_targets(self): top_boss = [] if self.active_boss_serial > 0: mob = Mobiles.FindBySerial(self.active_boss_serial) if mob and not getattr(mob, 'IsGhost', False) and int(mob.Hits) > 0 and Player.DistanceTo(mob) <= 18: top_boss.append(mob) else: self.active_boss_serial = 0 if not top_boss: try: mobs = Mobiles.ApplyFilter(self.hud_filter) except: mobs = [] boss_mobs = [] for m in mobs: try: if m.Serial == Player.Serial or getattr(m, 'IsGhost', False) or int(m.Hits) <= 0: continue n_lower = (m.Name or "").lower() props_lower = get_mobile_properties(m).lower() m_hitsmax = int(getattr(m, 'HitsMax', 1)) if m_hitsmax <= 0: m_hitsmax = 1 is_boss = False if m_hitsmax >= BOSS_HP_THRESHOLD: is_boss = True elif any(keyword in n_lower or keyword in props_lower for keyword in [ "boss", "paragon", "champion", "abomination", "plague", "royal wyrm", "runic wyrm", "balerion", "spectral wyrm", "syrax", "cora", "stygian", "shadowlord", "skeleton king", "mephitis", "lizardman overlord", "sandstorm templar", "ancient wyvern", "diablus", "nymphyr", "miasma" ]): is_boss = True if is_boss: boss_mobs.append(m) except: pass if boss_mobs: boss_mobs.sort(key=lambda m: int(Player.DistanceTo(m))) top_boss = boss_mobs[:1] self.active_boss_serial = top_boss[0].Serial boss_state = "".join(["{}_{}".format(m.Serial, m.Hits) for m in top_boss]) b_hash = hash(boss_state) if b_hash != self.last_boss_hash: self.last_boss_hash = b_hash self.render_boss(top_boss) def render_boss(self, bosses): try: gd_read = Gumps.GetGumpData(self.boss_gump_id) if gd_read: cx = getattr(gd_read, 'x', self.pos_x) cy = getattr(gd_read, 'y', self.pos_y) if cx != 0 or cy != 0: self.pos_x = cx self.pos_y = cy gd = Gumps.CreateGump(movable=True) Gumps.AddPage(gd, 0) boss_w = 195 self.boss_button_map.clear() if not bosses: h = 32 Gumps.AddBackground(gd, 0, 0, boss_w, h, 3500) Gumps.AddImageTiled(gd, 5, 5, boss_w - 10, h - 10, 2624) Gumps.AddAlphaRegion(gd, 5, 5, boss_w - 10, h - 10) self.draw_stroke_text(gd, 25, 8, 999, "[ SCANNING FOR BOSS ]") Gumps.SendGump(self.boss_gump_id, Player.Serial, self.pos_x, self.pos_y, gd.gumpDefinition, gd.gumpStrings) return h = 65 Gumps.AddBackground(gd, 0, 0, boss_w, h, 3500) Gumps.AddImageTiled(gd, 5, 5, boss_w - 10, h - 10, 2624) Gumps.AddAlphaRegion(gd, 5, 5, boss_w - 10, h - 10) boss = bosses[0] base_x = 15 name = boss.Name if boss.Name else "Unknown Boss" clean_name = re.sub(r'<[^>]+>', '', name).strip() if len(clean_name) > 13: clean_name = clean_name[:13] + ".." self.draw_stroke_text(gd, base_x + 20, 10, 33, "★ {} ★".format(clean_name)) bar_y = 28 b_hits = int(boss.Hits) if boss.Hits else 0 b_max = int(boss.HitsMax) if getattr(boss, 'HitsMax', 0) > 0 else 1 Gumps.AddImageTiled(gd, base_x + 20, bar_y, 100, 8, 2624) hp_pct = (float(b_hits) / float(b_max)) if hp_pct > 1.0: hp_pct = 1.0 elif hp_pct < 0: hp_pct = 0.0 fill_w = int(100 * hp_pct) if fill_w > 0: Gumps.AddImageTiled(gd, base_x + 20, bar_y, fill_w, 8, 2054) btn_id = 600 self.boss_button_map[btn_id] = boss.Serial Gumps.AddButton(gd, base_x, bar_y - 2, 2117, 2118, btn_id, 1, 0) hp_pct_int = int(hp_pct * 100) self.draw_stroke_text(gd, base_x + 125, bar_y - 3, 2000, "{}%".format(hp_pct_int)) Gumps.SendGump(self.boss_gump_id, Player.Serial, self.pos_x, self.pos_y, gd.gumpDefinition, gd.gumpStrings) except: pass def poll_buttons(self): current_time = time.time() * 1000 bs = Gumps.GetGumpData(self.boss_gump_id) if bs: bid = getattr(bs, 'buttonid', 0) if bid > 0: last_time = self.last_btn_clicks["boss"].get("time", 0) if bid != self.last_btn_clicks["boss"]["id"] or (current_time - last_time) > 1000: self.last_btn_clicks["boss"] = {"id": bid, "time": current_time} if bid in self.boss_button_map: target_serial = self.boss_button_map[bid] boss_mob = Mobiles.FindBySerial(target_serial) if boss_mob: Target.SetLast(target_serial) Player.HeadMessage(63, "-= Target Locked =-") try: Player.Attack(target_serial) except: pass self.last_boss_hash = 0 return try: if not Gumps.HasGump(self.boss_gump_id): self.last_btn_clicks["boss"]["id"] = 0 except: pass def update(self): try: current_time = time.time() * 1000 if (current_time - self.last_update) >= self.update_delay: self.last_update = current_time self.poll_buttons() self.process_targets() except: pass def stop(self): Gumps.CloseGump(self.boss_gump_id) HUD_INSTANCE = None def process_arpg_hud(): global HUD_INSTANCE, USE_ARPG_HUD if USE_ARPG_HUD: if HUD_INSTANCE is None: HUD_INSTANCE = BossTargetBar() HUD_INSTANCE.update() else: if HUD_INSTANCE is not None: HUD_INSTANCE.stop() HUD_INSTANCE = None # --- END OF PART 2 --- # ========================================================== # >>> PART 2: GUI SYSTEM <<< # ========================================================== _core_vars = { 'SCRIPT_RUNNING': False, 'USE_SKINNING': False, 'AUTO_FARM_MODE': True, 'GUI_MINIMIZED': False, 'LOOT_MAGIC_ITEMS': True, 'LOOT_DUSTABLES': False, 'USE_DIVINE_FURY': False, 'USE_MAGERY_BUFFS': True, 'USE_TAUNT': False, 'USE_LOCKPICKING': False, 'USE_CHEST_LOOT': False, 'USE_ENHANCED_HEALING': False, 'USE_AUTO_WAND': True, 'USE_SMART_POISON': False, 'USE_AUTO_BUFFS': False, 'USE_AUTO_PETALS': True, 'PET_HEAL_METHOD': "Both", 'USE_AUTO_SOUL': False, 'USE_ANTI_DISARM': True, 'USE_SELF_HEAL': True, 'USE_PET_HEAL': True, 'USE_AUTO_ENGAGE': False, 'USE_PET_RECALL': True, 'USE_ARPG_HUD': True, 'PLAY_VAULT_SOUND': True, 'CURRENT_ACTION': "Idle", 'LAST_GUI_HASH': 0, 'DRAW_INTERVAL': 1.0, 'LAST_DRAW_TIME': 0, 'last_button_id': 0, 'GUMP_ID': 81818, 'DETECTED_BUILD': "Unknown", 'LOOT_SOURCE_BAG': 0, 'VAULT_BAG_SERIAL': 0, 'SATCHEL_SERIAL': 0, 'PREF_WEP': 0, 'PREF_SHIELD': 0, 'BOSS_GUMP_ID': 6666, 'BOSS_X': 400, 'BOSS_Y': 50, 'BOSS_HP_THRESHOLD': 3000 } for _k, _v in _core_vars.items(): if _k not in globals(): globals()[_k] = _v def SmartDetectBuild(): global IS_TAMER, IS_DEXTER, IS_MAGE, IS_BARD, IS_PALADIN, IS_TINKER, IS_CHIV, IS_LOCKPICKER, IS_POISONER, IS_ARCHER, IS_NECRO, IS_SKINNER, DETECTED_BUILD if 'DETECTED_BUILD' not in globals(): globals()['DETECTED_BUILD'] = "Unknown" if 'IS_TAMER' not in globals(): globals()['IS_TAMER'] = False if 'IS_DEXTER' not in globals(): globals()['IS_DEXTER'] = False if 'IS_MAGE' not in globals(): globals()['IS_MAGE'] = False if 'IS_BARD' not in globals(): globals()['IS_BARD'] = False if 'IS_PALADIN' not in globals(): globals()['IS_PALADIN'] = False if 'IS_TINKER' not in globals(): globals()['IS_TINKER'] = False if 'IS_CHIV' not in globals(): globals()['IS_CHIV'] = False if 'IS_LOCKPICKER' not in globals(): globals()['IS_LOCKPICKER'] = False if 'IS_POISONER' not in globals(): globals()['IS_POISONER'] = False if 'IS_ARCHER' not in globals(): globals()['IS_ARCHER'] = False if 'IS_NECRO' not in globals(): globals()['IS_NECRO'] = False if 'IS_SKINNER' not in globals(): globals()['IS_SKINNER'] = False old_build = DETECTED_BUILD taming = Player.GetSkillValue("Animal Taming") magery = Player.GetSkillValue("Magery") peace = Player.GetSkillValue("Peacemaking") discord = Player.GetSkillValue("Discordance") provoke = Player.GetSkillValue("Provocation") healing = Player.GetSkillValue("Healing") chivalry = Player.GetSkillValue("Chivalry") tinkering = Player.GetSkillValue("Tinkering") lockpicking = Player.GetSkillValue("Lockpicking") poisoning = Player.GetSkillValue("Poisoning") archery = Player.GetSkillValue("Archery") necromancy = Player.GetSkillValue("Necromancy") forensics = Player.GetSkillValue("Forensic Evaluation") scavenging = 0 try: scavenging = Player.GetSkillValue("Scavenging") except: try: scavenging = Player.GetSkillValue("Begging") except: pass IS_SKINNER = (forensics >= 50 or scavenging >= 50) IS_DEXTER = (healing > 50) IS_TAMER = (taming > 50) IS_MAGE = (magery > 50) IS_BARD = (peace > 50 or discord > 50 or provoke > 50) IS_PALADIN = (chivalry > 40) IS_CHIV = IS_PALADIN IS_TINKER = (tinkering > 50) IS_LOCKPICKER = (lockpicking > 50) IS_POISONER = (poisoning > 20) IS_ARCHER = (archery > 50) IS_NECRO = (necromancy > 50) build_str = "Newbie" if IS_TAMER: build_str = "Tamer" if IS_MAGE: build_str += "/Mage" if IS_DEXTER: build_str += "/Healer" if IS_BARD: build_str += "/Bard" if IS_CHIV: build_str += "/Chiv" elif IS_BARD: build_str = "Bard" if IS_MAGE: build_str += "/Mage" if IS_DEXTER: build_str += "/Healer" elif IS_MAGE: build_str = "Pure Mage" if IS_DEXTER: build_str += "/Healer" elif IS_DEXTER: build_str = "Dexter/Healer" if IS_ARCHER: if "Dexter" in build_str: build_str = build_str.replace("Dexter", "Archer") elif build_str == "Newbie": build_str = "Archer" else: build_str += "/Archer" if IS_NECRO and "Necro" not in build_str: if build_str == "Newbie": build_str = "Necromancer" else: build_str += "/Necro" if IS_PALADIN and "Paladin" not in build_str: build_str += "+Paladin" if IS_LOCKPICKER: build_str += "/Lockpicker" if IS_POISONER: build_str += "/Poisoner" if IS_TINKER and "Tinker" not in build_str: if build_str == "Newbie": build_str = "Tinker" else: build_str += "/Tinker" DETECTED_BUILD = build_str if old_build != "Unknown" and old_build != DETECTED_BUILD: Player.HeadMessage(63, ">>> TEMPLATE CHANGED: {} <<<".format(DETECTED_BUILD)) Misc.Beep() def SmartDetectMastery(): global ACTIVE_MASTERY, MASTERY_DATA try: mob = Mobiles.FindBySerial(Player.Serial) if mob: Mobiles.WaitForProps(mob, 200) for prop in mob.Properties: p_str = str(prop).lower() clean_prop = re.sub(r'<[^>]+>', '', p_str) if "mastery" in clean_prop and "chivalry" not in clean_prop: for km in KNOWN_MASTERIES: if "{} mastery".format(km.lower()) in clean_prop: if ACTIVE_MASTERY != km: ACTIVE_MASTERY = km MASTERY_DATA["Type"] = ACTIVE_MASTERY Misc.SetSharedValue("ACTIVE_MASTERY", ACTIVE_MASTERY) return except: pass def CheckAndDrawGUI(force=False): global LAST_GUI_HASH global SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_DUSTABLES global LOOT_MAGIC_ITEMS, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING global USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND, USE_SMART_POISON global USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD, USE_AUTO_SOUL, USE_ANTI_DISARM global USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL, USE_ARPG_HUD global PLAY_VAULT_SOUND, CURRENT_ACTION, DETECTED_BUILD, MASTERY_DATA vars_list = [ SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_MAGIC_ITEMS, LOOT_DUSTABLES, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING, USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND, USE_SMART_POISON, USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD, USE_AUTO_SOUL, USE_ANTI_DISARM, USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL, USE_ARPG_HUD, PLAY_VAULT_SOUND ] current_state = "_".join(str(v) for v in vars_list) current_state += "_{}_{}_{}".format(MASTERY_DATA["Type"], MASTERY_DATA["Current"], MASTERY_DATA["Percent"]) for s in SPECIFIC_PET_SERIAL: if s in PET_DATA_CACHE: d = PET_DATA_CACHE[s] current_state += "_{}_{}".format(d.get('status',''), d.get('percent',0)) current_state += "_{}_{}".format(CURRENT_ACTION, DETECTED_BUILD) new_hash = hash(current_state) if force or (new_hash != LAST_GUI_HASH): LAST_GUI_HASH = new_hash DrawGUI(force) def DrawGUI(force=False): global last_button_id, LAST_DRAW_TIME, GUMP_ID global SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_DUSTABLES global LOOT_MAGIC_ITEMS, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING global USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND, USE_SMART_POISON global USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD, USE_AUTO_SOUL, USE_ANTI_DISARM global USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL, USE_ARPG_HUD global PLAY_VAULT_SOUND, CURRENT_ACTION, DETECTED_BUILD, MASTERY_DATA global IS_TAMER, IS_TINKER, IS_MAGE, IS_SKINNER, IS_POISONER, IS_CHIV, IS_DEXTER, IS_LOCKPICKER global LOOT_SOURCE_BAG, VAULT_BAG_SERIAL, SATCHEL_SERIAL, SPECIFIC_PET_SERIAL, PET_DATA_CACHE, PET_MAPPING if not force and (time.time() - LAST_DRAW_TIME < DRAW_INTERVAL): return LAST_DRAW_TIME = time.time() has_pets = (IS_TAMER or IS_TINKER or len(SPECIFIC_PET_SERIAL) > 0) Gumps.CloseGump(GUMP_ID) gd = Gumps.CreateGump() Gumps.AddPage(gd, 0) if MASTERY_DATA["Max"] > 0: pct = float(MASTERY_DATA["Current"]) / float(MASTERY_DATA["Max"]) if pct > 1.0: pct = 1.0 MASTERY_DATA["Percent"] = round(pct * 100, 1) if GUI_MINIMIZED: base_mini_h = 130 pet_mini_h = len(SPECIFIC_PET_SERIAL) * 35 mast_mini_h = 35 if MASTERY_DATA["Type"] != "None" else 0 total_mini_h = base_mini_h + pet_mini_h + mast_mini_h Gumps.AddBackground(gd, 0, 0, 220, total_mini_h, 3500) Gumps.AddImageTiled(gd, 10, 10, 200, total_mini_h - 20, 2624) Gumps.AddAlphaRegion(gd, 10, 10, 200, total_mini_h - 20) btn_start = 101 if SCRIPT_RUNNING else 100 btn_gfx = 2474 if SCRIPT_RUNNING else 2472 Gumps.AddButton(gd, 20, 15, btn_gfx, btn_gfx, btn_start, 1, 0) btn_mode = 105 if AUTO_FARM_MODE else 104 mode_btn = 211 if AUTO_FARM_MODE else 210 Gumps.AddButton(gd, 55, 15, mode_btn, mode_btn, btn_mode, 1, 0) Gumps.AddButton(gd, 185, 15, 2437, 2438, 9999, 1, 0) status_txt = "AUTO" if AUTO_FARM_MODE else "MAN" Gumps.AddLabel(gd, 90, 15, 68, status_txt) y_off = 65 if len(SPECIFIC_PET_SERIAL) > 0: for serial in SPECIFIC_PET_SERIAL: name = PET_MAPPING.get(serial, "Pet") data = PET_DATA_CACHE.get(serial, {'percent': 0.0, 'status': 'Unknown', 'level': '?'}) Gumps.AddImageTiled(gd, 20, y_off, 180, 8, 2624) Gumps.AddAlphaRegion(gd, 20, y_off, 180, 8) p_pct = data.get('percent', 0.0) if data.get('status') == "MAX" or p_pct >= 100.0: Gumps.AddImageTiled(gd, 20, y_off, 180, 8, 2057) elif p_pct > 0: p_fill = int(180 * (p_pct / 100.0)) Gumps.AddImageTiled(gd, 20, y_off, p_fill, 8, 2054) Gumps.AddLabel(gd, 20, y_off - 15, 1152, name) y_off += 35 if MASTERY_DATA["Type"] != "None": y_off += 5 Gumps.AddImageTiled(gd, 20, y_off+15, 180, 8, 2624) Gumps.AddAlphaRegion(gd, 20, y_off+15, 180, 8) fill_m = int(180 * (MASTERY_DATA["Percent"] / 100.0)) if fill_m > 0: Gumps.AddImageTiled(gd, 20, y_off+15, fill_m, 8, 2057) Gumps.AddLabel(gd, 20, y_off, 68, "{} ({:.1f}%)".format(MASTERY_DATA["Type"], MASTERY_DATA["Percent"])) Gumps.SendGump(GUMP_ID, Player.Serial, 0, 0, gd.gumpDefinition, gd.gumpStrings) return y_bar = 110 y_pets = y_bar + 45 pet_block_h = len(SPECIFIC_PET_SERIAL) * 50 y_ctrl = y_pets + pet_block_h + 20 btn_start = 101 if SCRIPT_RUNNING else 100 btn_mode = 105 if AUTO_FARM_MODE else 104 btn_skin = 103 if USE_SKINNING else 102 btn_magic = 107 if LOOT_MAGIC_ITEMS else 106 btn_fury = 109 if USE_DIVINE_FURY else 108 btn_mage = 111 if USE_MAGERY_BUFFS else 110 btn_taunt = 113 if USE_TAUNT else 112 btn_lock = 115 if USE_LOCKPICKING else 114 btn_chest = 177 if USE_CHEST_LOOT else 176 btn_enh = 117 if USE_ENHANCED_HEALING else 116 btn_wand = 129 if USE_AUTO_WAND else 128 btn_poison = 133 if USE_SMART_POISON else 132 btn_buffs = 137 if USE_AUTO_BUFFS else 136 btn_petals = 139 if USE_AUTO_PETALS else 138 btn_soul = 145 if USE_AUTO_SOUL else 144 btn_disarm = 147 if USE_ANTI_DISARM else 146 btn_self_heal = 149 if USE_SELF_HEAL else 148 btn_pet_heal = 151 if USE_PET_HEAL else 150 btn_engage = 153 if USE_AUTO_ENGAGE else 152 btn_recall = 157 if USE_PET_RECALL else 156 btn_dustables = 159 if LOOT_DUSTABLES else 158 btn_hud = 163 if USE_ARPG_HUD else 162 btn_sound = 167 if PLAY_VAULT_SOUND else 166 btn_lootbag = 119 if last_button_id == 118 else 118 btn_vault = 121 if last_button_id == 120 else 120 btn_satchel = 127 if last_button_id == 126 else 126 btn_addpet = 123 if last_button_id == 122 else 122 btn_clrpet = 125 if last_button_id == 124 else 124 btn_shelf = 199 if last_button_id == 198 else 198 btn_tome = 197 if last_button_id == 196 else 196 btn_refresh = 165 if last_button_id == 164 else 164 active_toggles = [ ("Mode", btn_mode, AUTO_FARM_MODE, "Auto", "Manual"), ("Auto-Engage", btn_engage, USE_AUTO_ENGAGE, "ON", "OFF"), ("Boss HUD", btn_hud, USE_ARPG_HUD, "ON", "OFF"), ("Self Heal", btn_self_heal, USE_SELF_HEAL, "ON", "OFF") ] if IS_MAGE: active_toggles.append(("Mage Buffs", btn_mage, USE_MAGERY_BUFFS, "ON", "OFF")) if Player.GetSkillValue("Spirit Speak") > 100: active_toggles.append(("Auto Soul", btn_soul, USE_AUTO_SOUL, "ON", "OFF")) if has_pets: active_toggles.append(("Pet Heal", btn_pet_heal, USE_PET_HEAL, "ON", "OFF")) active_toggles.append(("Pet Recall", btn_recall, USE_PET_RECALL, "ON", "OFF")) if IS_MAGE: active_toggles.append(("Enh. Healing", btn_enh, USE_ENHANCED_HEALING, "ON", "OFF")) if IS_SKINNER: active_toggles.append(("Skin/Scav", btn_skin, USE_SKINNING, "ON", "OFF")) active_toggles.extend([ ("Loot Chests", btn_chest, USE_CHEST_LOOT, "ON", "OFF"), ("Loot Magic", btn_magic, LOOT_MAGIC_ITEMS, "ON", "OFF"), ("Loot Dustables", btn_dustables, LOOT_DUSTABLES, "ON", "OFF"), ("Wand of Dust", btn_wand, USE_AUTO_WAND, "ON", "OFF"), ("Vault Sound", btn_sound, PLAY_VAULT_SOUND, "ON", "OFF"), ("Anti-Disarm", btn_disarm, USE_ANTI_DISARM, "ON", "OFF") ]) if IS_POISONER: active_toggles.append(("Smart Poison", btn_poison, USE_SMART_POISON, "ON", "OFF")) if IS_CHIV: active_toggles.append(("Use D.Fury", btn_fury, USE_DIVINE_FURY, "ON", "OFF")) if Player.GetSkillValue("Parrying") >= 50: active_toggles.append(("Use Taunt", btn_taunt, USE_TAUNT, "ON", "OFF")) if IS_DEXTER: active_toggles.append(("Auto Buffs", btn_buffs, USE_AUTO_BUFFS, "ON", "OFF")) if IS_DEXTER or IS_MAGE: active_toggles.append(("Auto Petals", btn_petals, USE_AUTO_PETALS, "ON", "OFF")) if IS_LOCKPICKER: active_toggles.append(("Auto Lockpick", btn_lock, USE_LOCKPICKING, "ON", "OFF")) toggle_rows = (len(active_toggles) + 1) // 2 y_conf = y_ctrl + 30 + (toggle_rows * 30) + 20 total_h = y_conf + 140 main_w = 350 Gumps.AddBackground(gd, 0, 0, main_w, total_h, 3500) Gumps.AddImageTiled(gd, 10, 10, main_w-20, total_h-20, 2624) Gumps.AddAlphaRegion(gd, 10, 10, main_w-20, total_h-20) Gumps.AddImage(gd, 240, 40, 5549) Gumps.AddButton(gd, 305, 15, 2435, 2436, 9998, 1, 0) Gumps.AddLabel(gd, 20, 15, 63, "COMPLETE DOMINATION (PXR EDITION)") status_color = 63 if SCRIPT_RUNNING else 33 status_text = "RUNNING" if SCRIPT_RUNNING else "PAUSED" Gumps.AddLabel(gd, 20, 40, status_color, "Status: " + status_text) Gumps.AddLabel(gd, 20, 55, 88, "Action: " + CURRENT_ACTION) Gumps.AddLabel(gd, 20, 70, 55, "Build: " + DETECTED_BUILD) Gumps.AddButton(gd, 170, 72, 2117, 2118, btn_refresh, 1, 0) Gumps.AddLabel(gd, 190, 70, 55, "Refresh") m_type = MASTERY_DATA["Type"] display_name = "{} ({})".format(m_type, MASTERY_PET_NAMES[m_type]) if m_type in MASTERY_PET_NAMES else m_type m_label = display_name if m_type != "None" else "Waiting..." Gumps.AddLabel(gd, 20, y_bar, 1152, "Mastery: " + m_label) bar_full_w = 310 Gumps.AddImageTiled(gd, 20, y_bar+20, bar_full_w, 12, 2624) Gumps.AddAlphaRegion(gd, 20, y_bar+20, bar_full_w, 12) full_fill = int(bar_full_w * (MASTERY_DATA["Percent"] / 100.0)) if full_fill > 0: Gumps.AddImageTiled(gd, 20, y_bar+20, full_fill, 12, 2057) stat_text = "MAXED" if MASTERY_DATA["Current"] >= MASTERY_DATA["Max"] and MASTERY_DATA["Max"] > 0 else "{:.1f}%".format(MASTERY_DATA["Percent"]) Gumps.AddLabel(gd, 270, y_bar, 63, stat_text) current_y_pets = y_pets if len(SPECIFIC_PET_SERIAL) > 0: for serial in SPECIFIC_PET_SERIAL: name = PET_MAPPING.get(serial, "Pet") data = PET_DATA_CACHE.get(serial, {'percent': 0.0, 'status': 'Unknown', 'level': '?'}) label_text = name if data.get('status') == "MAX": label_text += " [MAX]" else: if data.get('level') != '?': label_text += " Level " + str(data.get('level')) label_text += " [{:.1f}%]".format(data.get('percent', 0.0)) if PET_RECALL_STATES.get(serial, False): label_text += " << RECALLING >>" Gumps.AddLabel(gd, 20, current_y_pets, 1152 if not PET_RECALL_STATES.get(serial, False) else 33, label_text) Gumps.AddImageTiled(gd, 20, current_y_pets+20, bar_full_w, 12, 2624) Gumps.AddAlphaRegion(gd, 20, current_y_pets+20, bar_full_w, 12) p_pct = data.get('percent', 0.0) if data.get('status') == "MAX" or p_pct >= 100.0: Gumps.AddImageTiled(gd, 20, current_y_pets+20, bar_full_w, 12, 2057) elif p_pct > 0: p_fill = int(bar_full_w * (p_pct / 100.0)) Gumps.AddImageTiled(gd, 20, current_y_pets+20, p_fill, 12, 2054) current_y_pets += 50 btn_gfx = 2474 if SCRIPT_RUNNING else 2472 Gumps.AddButton(gd, 20, y_ctrl, btn_gfx, btn_gfx, btn_start, 1, 0) Gumps.AddLabel(gd, 50, y_ctrl+2, 63 if SCRIPT_RUNNING else 33, "START/STOP") col = 0 row_y = y_ctrl + 30 for label, b_id, state, text_on, text_off in active_toggles: x_btn = 20 if col == 0 else 160 x_lbl = 45 if col == 0 else 185 btn_gfx = 211 if state else 210 lbl_txt = "Mode: " + text_on if (label == "Mode" and state) else "Mode: " + text_off if label == "Mode" else label lbl_color = 63 if state else 999 if label == "Mode": lbl_color = 63 if state else 999 Gumps.AddButton(gd, x_btn, row_y, btn_gfx, btn_gfx, b_id, 1, 0) Gumps.AddLabel(gd, x_lbl, row_y+2, lbl_color, lbl_txt) col += 1 if col > 1: col = 0 row_y += 30 Gumps.AddButton(gd, 20, y_conf+20, 4005, 4007, btn_lootbag, 1, 0) val = "SET" if LOOT_SOURCE_BAG > 0 else "NONE" col = 63 if LOOT_SOURCE_BAG > 0 else 33 Gumps.AddLabel(gd, 55, y_conf+20, col, "Loot Bag: " + val) Gumps.AddButton(gd, 20, y_conf+50, 4005, 4007, btn_vault, 1, 0) val = "SET" if VAULT_BAG_SERIAL > 0 else "NONE" col = 63 if VAULT_BAG_SERIAL > 0 else 33 Gumps.AddLabel(gd, 55, y_conf+50, col, "Vault: " + val) Gumps.AddButton(gd, 160, y_conf+50, 4005, 4007, btn_satchel, 1, 0) val = "SET" if SATCHEL_SERIAL > 0 else "NONE" col = 63 if SATCHEL_SERIAL > 0 else 33 Gumps.AddLabel(gd, 195, y_conf+50, col, "Satchel: " + val) Gumps.AddButton(gd, 20, y_conf+80, 4005, 4007, btn_addpet, 1, 0) Gumps.AddLabel(gd, 55, y_conf+80, 63, "Add Pet") Gumps.AddButton(gd, 120, y_conf+80, 4005, 4007, btn_clrpet, 1, 0) Gumps.AddLabel(gd, 155, y_conf+80, 33, "Clr") btn_heal_method = 141 if last_button_id == 140 else 140 Gumps.AddButton(gd, 190, y_conf+80, 4005, 4007, btn_heal_method, 1, 0) h_col = 63 if PET_HEAL_METHOD == "Both" else 55 if PET_HEAL_METHOD == "Bands" else 88 Gumps.AddLabel(gd, 225, y_conf+80, h_col, "Heal Mode: " + PET_HEAL_METHOD) btn_shelf = 199 if last_button_id == 198 else 198 Gumps.AddButton(gd, 20, y_conf+110, 4005, 4007, btn_shelf, 1, 0) Gumps.AddLabel(gd, 55, y_conf+110, 66, "RESTOCK SHELF") btn_tome = 197 if last_button_id == 196 else 196 Gumps.AddButton(gd, 160, y_conf+110, 4005, 4007, btn_tome, 1, 0) Gumps.AddLabel(gd, 195, y_conf+110, 66, "TOME RESTOCK") Gumps.SendGump(GUMP_ID, Player.Serial, 0, 0, gd.gumpDefinition, gd.gumpStrings) # --- WEAPON SAVING VARIABLES --- stored_pvm_wep = 0 stored_pvm_shield = 0 def poll_buttons(): global last_button_id, SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_DUSTABLES global LOOT_SOURCE_BAG, VAULT_BAG_SERIAL, SATCHEL_SERIAL, SPECIFIC_PET_SERIAL, PET_MAPPING, SPECIFIC_PET_BODIES global LOOT_MAGIC_ITEMS, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING, USE_CHEST_LOOT, USE_ENHANCED_HEALING, USE_AUTO_WAND global USE_SMART_POISON, USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD global USE_AUTO_SOUL, USE_ANTI_DISARM, USE_SELF_HEAL, USE_PET_HEAL, USE_AUTO_ENGAGE, USE_PET_RECALL global USE_ARPG_HUD, PLAY_VAULT_SOUND global stored_pvm_wep, stored_pvm_shield, PREF_WEP, PREF_SHIELD if 'last_tome_button_id' not in globals(): globals()['last_tome_button_id'] = -1 tome_gd = Gumps.GetGumpData(8888) if tome_gd and getattr(tome_gd, 'buttonid', -1) > 0: t_bid = tome_gd.buttonid if t_bid != globals()['last_tome_button_id']: globals()['last_tome_button_id'] = t_bid Gumps.CloseGump(8888) if t_bid == 8000: perform_tome_sequence("ALL") elif t_bid >= 8001: perform_tome_sequence(t_bid - 8001) CheckAndDrawGUI(force=True) return gd = Gumps.GetGumpData(GUMP_ID) if not gd: return bid = getattr(gd, 'buttonid', 0) if bid <= 0: return if bid == last_button_id: return last_button_id = bid if bid in [164, 165]: Player.HeadMessage(66, ">> Scanning Template & Mastery <<") SmartDetectBuild() SmartDetectMastery() CheckAndDrawGUI(force=True) return if bid in [198, 199]: perform_restock_sequence(); CheckAndDrawGUI(force=True); return if bid in [196, 197]: ShowTomeMenu(); return if bid in [106, 107]: LOOT_MAGIC_ITEMS = not LOOT_MAGIC_ITEMS; Player.HeadMessage(55, "Magic Loot: " + ("ON" if LOOT_MAGIC_ITEMS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [108, 109]: USE_DIVINE_FURY = not USE_DIVINE_FURY; Player.HeadMessage(55, "Use D.Fury: " + ("ON" if USE_DIVINE_FURY else "OFF")); CheckAndDrawGUI(force=True); return if bid in [110, 111]: USE_MAGERY_BUFFS = not USE_MAGERY_BUFFS; Player.HeadMessage(55, "Mage Buffs: " + ("ON" if USE_MAGERY_BUFFS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [112, 113]: USE_TAUNT = not USE_TAUNT; Player.HeadMessage(55, "Auto Taunt: " + ("ON" if USE_TAUNT else "OFF")); CheckAndDrawGUI(force=True); return if bid in [114, 115]: USE_LOCKPICKING = not USE_LOCKPICKING; Player.HeadMessage(55, "Auto Lockpick: " + ("ON" if USE_LOCKPICKING else "OFF")); CheckAndDrawGUI(force=True); return if bid in [176, 177]: USE_CHEST_LOOT = not USE_CHEST_LOOT; Player.HeadMessage(55, "Loot Chests: " + ("ON" if USE_CHEST_LOOT else "OFF")); CheckAndDrawGUI(force=True); return if bid in [116, 117]: USE_ENHANCED_HEALING = not USE_ENHANCED_HEALING; Player.HeadMessage(55, "Enh. Healing: " + ("ON" if USE_ENHANCED_HEALING else "OFF")); CheckAndDrawGUI(force=True); return if bid in [128, 129]: USE_AUTO_WAND = not USE_AUTO_WAND; Player.HeadMessage(55, "Wand of Dust: " + ("ON" if USE_AUTO_WAND else "OFF")); CheckAndDrawGUI(force=True); return if bid in [132, 133]: USE_SMART_POISON = not USE_SMART_POISON; Player.HeadMessage(55, "Smart Poison: " + ("ON" if USE_SMART_POISON else "OFF")); CheckAndDrawGUI(force=True); return if bid in [136, 137]: USE_AUTO_BUFFS = not USE_AUTO_BUFFS; Player.HeadMessage(55, "Auto Buffs: " + ("ON" if USE_AUTO_BUFFS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [138, 139]: USE_AUTO_PETALS = not USE_AUTO_PETALS; Player.HeadMessage(55, "Auto Petals: " + ("ON" if USE_AUTO_PETALS else "OFF")); CheckAndDrawGUI(force=True); return if bid in [144, 145]: USE_AUTO_SOUL = not USE_AUTO_SOUL; Player.HeadMessage(55, "Auto Soul Reap: " + ("ON" if USE_AUTO_SOUL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [146, 147]: USE_ANTI_DISARM = not USE_ANTI_DISARM; Player.HeadMessage(55, "Anti-Disarm: " + ("ON" if USE_ANTI_DISARM else "OFF")); CheckAndDrawGUI(force=True); return if bid in [148, 149]: USE_SELF_HEAL = not USE_SELF_HEAL; Player.HeadMessage(55, "Self Heal: " + ("ON" if USE_SELF_HEAL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [150, 151]: USE_PET_HEAL = not USE_PET_HEAL; Player.HeadMessage(55, "Pet Heal: " + ("ON" if USE_PET_HEAL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [152, 153]: USE_AUTO_ENGAGE = not USE_AUTO_ENGAGE; Player.HeadMessage(55, "Auto-Engage: " + ("ON" if USE_AUTO_ENGAGE else "OFF")); CheckAndDrawGUI(force=True); return if bid in [156, 157]: USE_PET_RECALL = not USE_PET_RECALL; Player.HeadMessage(55, "Pet Recall: " + ("ON" if USE_PET_RECALL else "OFF")); CheckAndDrawGUI(force=True); return if bid in [158, 159]: LOOT_DUSTABLES = not LOOT_DUSTABLES; Player.HeadMessage(55, "Loot Dustables: " + ("ON" if LOOT_DUSTABLES else "OFF")); CheckAndDrawGUI(force=True); return if bid in [162, 163]: USE_ARPG_HUD = not USE_ARPG_HUD Player.HeadMessage(55, "Boss HUD: " + ("ON" if USE_ARPG_HUD else "OFF")) CheckAndDrawGUI(force=True) return if bid in [166, 167]: PLAY_VAULT_SOUND = not PLAY_VAULT_SOUND Player.HeadMessage(55, "Vault Sound: " + ("ON" if PLAY_VAULT_SOUND else "OFF")) CheckAndDrawGUI(force=True) return if bid in [140, 141]: if PET_HEAL_METHOD == "Both": PET_HEAL_METHOD = "Bands" elif PET_HEAL_METHOD == "Bands": PET_HEAL_METHOD = "Kit" else: PET_HEAL_METHOD = "Both" Misc.SetSharedValue("PET_HEAL_METHOD", PET_HEAL_METHOD) Player.HeadMessage(55, "Pet Heal Mode: " + PET_HEAL_METHOD) CheckAndDrawGUI(force=True) return if bid in [100, 101]: SCRIPT_RUNNING = not SCRIPT_RUNNING Player.HeadMessage(63 if SCRIPT_RUNNING else 33, ">>> DOMINATION " + ("RUNNING" if SCRIPT_RUNNING else "PAUSED") + " <<<") elif bid in [102, 103]: USE_SKINNING = not USE_SKINNING Player.HeadMessage(55, "Skinning: " + ("ON" if USE_SKINNING else "OFF")) elif bid in [104, 105]: AUTO_FARM_MODE = not AUTO_FARM_MODE Player.HeadMessage(66, "Targeting Mode: " + ("AUTO" if AUTO_FARM_MODE else "MANUAL")) elif bid in [9998, 9999]: GUI_MINIMIZED = not GUI_MINIMIZED elif bid in [118, 119]: Misc.SendMessage("Target Loot Bag...", 68) s = Target.PromptTarget("Loot Bag") if s > 0: LOOT_SOURCE_BAG = s Misc.SetSharedValue("LOOT_SOURCE_BAG", s) Player.HeadMessage(63, "Loot Bag Set: " + hex(s)) elif bid in [120, 121]: Misc.SendMessage("Target Vault...", 68) s = Target.PromptTarget("Vault") if s > 0: VAULT_BAG_SERIAL = s Misc.SetSharedValue("VAULT_BAG_SERIAL", s) Player.HeadMessage(63, "Vault Set: " + hex(s)) elif bid in [126, 127]: Misc.SendMessage("Target Satchel...", 68) s = Target.PromptTarget("Satchel") if s > 0: SATCHEL_SERIAL = s Misc.SetSharedValue("SATCHEL_SERIAL", s) Player.HeadMessage(63, "Satchel Set: " + hex(s)) elif bid in [122, 123]: Misc.SendMessage("Target Pet to Add...", 68) s = Target.PromptTarget("Pet") if s > 0: if s == Player.Serial: Player.HeadMessage(33, "Cannot add self.") else: mob = Mobiles.FindBySerial(s) if mob: if s not in SPECIFIC_PET_SERIAL: SPECIFIC_PET_SERIAL.append(s) raw_name = mob.Name if mob.Name else "Unknown" p_name = GetTruePetName(raw_name) PET_MAPPING[s] = p_name if int(mob.Body) not in SPECIFIC_PET_BODIES: SPECIFIC_PET_BODIES.append(int(mob.Body)) save_str = "|".join(["{}:{}".format(x, PET_MAPPING[x]) for x in SPECIFIC_PET_SERIAL]) Misc.SetSharedValue("SAVED_PET_MAP", save_str) Player.HeadMessage(63, "Added & Saved: " + p_name + " (" + hex(s) + ")") else: Player.HeadMessage(44, "Already in list.") else: Player.HeadMessage(33, "Invalid Mobile.") elif bid in [124, 125]: SPECIFIC_PET_SERIAL.clear(); PET_MAPPING.clear(); PET_DATA_CACHE.clear() Misc.SetSharedValue("SAVED_PET_SERIALS", "") Misc.SetSharedValue("SAVED_PET_MAP", "") Player.HeadMessage(33, "Pet List Cleared & Memory Wiped.") CheckAndDrawGUI(force=True) class BossTargetBar: def __init__(self): self.boss_gump_id = BOSS_GUMP_ID self.last_update = 0 self.update_delay = 500 self.hud_filter = Mobiles.Filter() self.hud_filter.Enabled = True self.hud_filter.RangeMax = 15 self.hud_filter.Notorieties = List[Byte]([Byte(3), Byte(4), Byte(5), Byte(6)]) self.last_boss_hash = 0 self.boss_button_map = {} self.last_btn_clicks = {"boss": {"id": 0, "time": 0}} self.active_boss_serial = 0 self.pos_x = BOSS_X self.pos_y = BOSS_Y def draw_stroke_text(self, gump, x, y, color, text): try: ix, iy, ic = int(x), int(y), int(color) st = str(text) Gumps.AddLabel(gump, ix - 1, iy, 1, st) Gumps.AddLabel(gump, ix + 1, iy, 1, st) Gumps.AddLabel(gump, ix, iy - 1, 1, st) Gumps.AddLabel(gump, ix, iy + 1, 1, st) Gumps.AddLabel(gump, ix, iy, ic, st) except: pass def process_targets(self): top_boss = [] if self.active_boss_serial > 0: mob = Mobiles.FindBySerial(self.active_boss_serial) if mob and not getattr(mob, 'IsGhost', False) and int(mob.Hits) > 0 and Player.DistanceTo(mob) <= 18: top_boss.append(mob) else: self.active_boss_serial = 0 if not top_boss: try: mobs = Mobiles.ApplyFilter(self.hud_filter) except: mobs = [] boss_mobs = [] for m in mobs: try: if m.Serial == Player.Serial or getattr(m, 'IsGhost', False) or int(m.Hits) <= 0: continue n_lower = (m.Name or "").lower() props_lower = get_mobile_properties(m).lower() m_hitsmax = int(getattr(m, 'HitsMax', 1)) if m_hitsmax <= 0: m_hitsmax = 1 is_boss = False if m_hitsmax >= BOSS_HP_THRESHOLD: is_boss = True elif any(keyword in n_lower or keyword in props_lower for keyword in [ "boss", "paragon", "champion", "abomination", "plague", "royal wyrm", "runic wyrm", "balerion", "spectral wyrm", "syrax", "cora", "stygian", "shadowlord", "skeleton king", "mephitis", "lizardman overlord", "sandstorm templar", "ancient wyvern", "diablus", "nymphyr", "miasma" ]): is_boss = True if is_boss: boss_mobs.append(m) except: pass if boss_mobs: boss_mobs.sort(key=lambda m: int(Player.DistanceTo(m))) top_boss = boss_mobs[:1] self.active_boss_serial = top_boss[0].Serial boss_state = "".join(["{}_{}".format(m.Serial, m.Hits) for m in top_boss]) b_hash = hash(boss_state) if b_hash != self.last_boss_hash: self.last_boss_hash = b_hash self.render_boss(top_boss) def render_boss(self, bosses): try: gd_read = Gumps.GetGumpData(self.boss_gump_id) if gd_read: cx = getattr(gd_read, 'x', self.pos_x) cy = getattr(gd_read, 'y', self.pos_y) if cx != 0 or cy != 0: self.pos_x = cx self.pos_y = cy gd = Gumps.CreateGump(movable=True) Gumps.AddPage(gd, 0) boss_w = 195 self.boss_button_map.clear() if not bosses: h = 32 Gumps.AddBackground(gd, 0, 0, boss_w, h, 3500) Gumps.AddImageTiled(gd, 5, 5, boss_w - 10, h - 10, 2624) Gumps.AddAlphaRegion(gd, 5, 5, boss_w - 10, h - 10) self.draw_stroke_text(gd, 25, 8, 999, "[ SCANNING FOR BOSS ]") Gumps.SendGump(self.boss_gump_id, Player.Serial, self.pos_x, self.pos_y, gd.gumpDefinition, gd.gumpStrings) return h = 65 Gumps.AddBackground(gd, 0, 0, boss_w, h, 3500) Gumps.AddImageTiled(gd, 5, 5, boss_w - 10, h - 10, 2624) Gumps.AddAlphaRegion(gd, 5, 5, boss_w - 10, h - 10) boss = bosses[0] base_x = 15 name = boss.Name if boss.Name else "Unknown Boss" clean_name = re.sub(r'<[^>]+>', '', name).strip() if len(clean_name) > 13: clean_name = clean_name[:13] + ".." self.draw_stroke_text(gd, base_x + 20, 10, 33, "★ {} ★".format(clean_name)) bar_y = 28 b_hits = int(boss.Hits) if boss.Hits else 0 b_max = int(boss.HitsMax) if getattr(boss, 'HitsMax', 0) > 0 else 1 Gumps.AddImageTiled(gd, base_x + 20, bar_y, 100, 8, 2624) hp_pct = (float(b_hits) / float(b_max)) if hp_pct > 1.0: hp_pct = 1.0 elif hp_pct < 0: hp_pct = 0.0 fill_w = int(100 * hp_pct) if fill_w > 0: Gumps.AddImageTiled(gd, base_x + 20, bar_y, fill_w, 8, 2054) btn_id = 600 self.boss_button_map[btn_id] = boss.Serial Gumps.AddButton(gd, base_x, bar_y - 2, 2117, 2118, btn_id, 1, 0) hp_pct_int = int(hp_pct * 100) self.draw_stroke_text(gd, base_x + 125, bar_y - 3, 2000, "{}%".format(hp_pct_int)) Gumps.SendGump(self.boss_gump_id, Player.Serial, self.pos_x, self.pos_y, gd.gumpDefinition, gd.gumpStrings) except: pass def poll_buttons(self): current_time = time.time() * 1000 bs = Gumps.GetGumpData(self.boss_gump_id) if bs: bid = getattr(bs, 'buttonid', 0) if bid > 0: last_time = self.last_btn_clicks["boss"].get("time", 0) if bid != self.last_btn_clicks["boss"]["id"] or (current_time - last_time) > 1000: self.last_btn_clicks["boss"] = {"id": bid, "time": current_time} if bid in self.boss_button_map: target_serial = self.boss_button_map[bid] boss_mob = Mobiles.FindBySerial(target_serial) if boss_mob: Target.SetLast(target_serial) Player.HeadMessage(63, "-= Target Locked =-") try: Player.Attack(target_serial) except: pass self.last_boss_hash = 0 return try: if not Gumps.HasGump(self.boss_gump_id): self.last_btn_clicks["boss"]["id"] = 0 except: pass def update(self): try: current_time = time.time() * 1000 if (current_time - self.last_update) >= self.update_delay: self.last_update = current_time self.poll_buttons() self.process_targets() except: pass def stop(self): Gumps.CloseGump(self.boss_gump_id) HUD_INSTANCE = None def process_arpg_hud(): global HUD_INSTANCE, USE_ARPG_HUD if USE_ARPG_HUD: if HUD_INSTANCE is None: HUD_INSTANCE = BossTargetBar() HUD_INSTANCE.update() else: if HUD_INSTANCE is not None: HUD_INSTANCE.stop() HUD_INSTANCE = None # --- END OF PART 2 --- # ========================================================== # >>> PART 3: MAIN LOOP & UTILITIES <<< # ========================================================== USE_AUTO_BOMBER = False fire_ele_expiry = 0 has_issued_guard_command = False last_attacked_serial = 0 next_bard_time = 0 last_known_hp = 0 last_hud_target_serial = 0 last_attack_packet_time = 0 last_build_check_time = 0 last_chore_time = 0 last_rescue_time = 0 last_pet_recall_time = 0 last_taunt_time = 0 last_pick_time = 0 last_pouch_time = 0 USE_POUCHES = False # ---> NEW ENHANCEMENT VACUUM IDs <--- DUST_RESOURCES = [ 11697, 11698, 11699, 22332, 22338, 22339, 22331, 22328, 22322, 22305, 22327, 3975, 22341, 22310, 22316, 22317, 22329, 22333, 22343, 22345, 9908, 22326, 22340, 22342, 22304, 22321, 22306, 12688, 12689, 12691, 12694, 12695, 12696, 3576, 22344 ] def get_container_count(container): try: if not container or getattr(container, 'Contains', None) is None: return 0 return len(container.Contains) except: return 0 def GetSafeDest(target_serial): if not Player.Backpack: return 0 bp_serial = Player.Backpack.Serial if target_serial <= 0: return bp_serial chk = Items.FindBySerial(target_serial) if chk: if get_container_count(chk) >= 123: return bp_serial return target_serial return bp_serial def WaitForAnyGump(timeout_ms): end = time.time() + (timeout_ms / 1000.0) while time.time() < end: if Gumps.CurrentGump() != 0: return True Misc.Pause(100) return False def bank_gold(): Player.HeadMessage(55, "Scanning for Bank Safe...") safe = None safe_filter = Items.Filter() safe_filter.Enabled = True safe_filter.OnGround = True safe_filter.RangeMax = 3 for item in Items.ApplyFilter(safe_filter): n = (item.Name or "").lower() if "vault" in n or "safe" in n or item.ItemID == 41459: safe = item break if safe: Player.HeadMessage(63, "Opening " + (safe.Name or "Vault") + "...") Items.UseItem(safe) Misc.Pause(2000) found_gold = False for item in Player.Backpack.Contains: if item.ItemID == GOLD_ID: Player.HeadMessage(66, " depositing " + str(item.Amount) + " gold...") Items.Move(item.Serial, safe.Serial, 0) Misc.Pause(500) found_gold = True if not found_gold: Player.HeadMessage(55, "No Gold left in pack.") else: Player.HeadMessage(33, "Bank Safe Not Found! (Stand Closer)") def perform_restock_sequence(): Player.HeadMessage(55, ">>> INITIATING RESTOCK <<<") bank_gold() Misc.Pause(1000) shelf = Items.FindByID(STORAGE_SHELF_ID, -1, -1, True) if shelf: Player.HeadMessage(63, "Using Storage Shelf...") Items.UseItem(shelf) if WaitForAnyGump(3000): curr = Gumps.CurrentGump() Gumps.SendAction(curr, 1790) Misc.Pause(1000) if Target.WaitForTarget(1000, False): Target.Self() Misc.Pause(1000) if WaitForAnyGump(2000): curr = Gumps.CurrentGump() Gumps.SendAction(curr, 4477) Misc.Pause(1000) Gumps.CloseGump(curr) else: Player.HeadMessage(33, "No Storage Shelf Found.") enchant = Items.FindByID(ENCHANT_SHELF_ID, -1, -1, True) if enchant: Player.HeadMessage(63, "Using Enchant Storage...") Items.UseItem(enchant) if WaitForAnyGump(3000): curr = Gumps.CurrentGump() Gumps.SendAction(curr, 73) Misc.Pause(1000) Gumps.CloseGump(curr) Player.HeadMessage(66, "Restock Complete.") def get_tome_list(): return [ (0x4116FE5C, 1, "Davies' Locker"), (0x43023255, 10, "Pet Scrolls"), (0x427A1999, 10, "Arcane Scrolls"), (0x44578FB7, 10, "Enhancement Scrolls"), (0x427A27F7, 10, "Power Scrolls"), (0x427D8F50, 3000, "Resource Maps"), (0x427EF907, 100, "Waterstained Maps"), (0x409AF6BA, 1001, "Rare Cloth"), (0x45720606, 10, "Runic Components"), (0x409CA9F3, 1001, "Beard Dyes"), (0x45BD61E5, 1001, "Spellbook Dyes"), (0x402E09EB, 1001, "Backpack Dyes"), (0x45BC50A7, 1001, "Carpet Dyes"), (0x45BC64E4, 1001, "Runebook Dyes"), (0x409CAB1C, 1001, "Hair Dyes"), (0x45BC5873, 1001, "Furniture Dyes"), (0x40EB2F50, 1001, "Armament Dyes") ] def ShowTomeMenu(): globals()['last_tome_button_id'] = -1 try: Gumps.CloseGump(8888) except: pass gd = Gumps.CreateGump() Gumps.AddPage(gd, 0) master_list = get_tome_list() active_indices = [] for i, (s, b, n) in enumerate(master_list): if Items.FindBySerial(s): active_indices.append(i) if not active_indices: Player.HeadMessage(33, "No tomes found nearby!") return h = 80 + (len(active_indices) * 25) Gumps.AddBackground(gd, 0, 0, 250, h, 3500) Gumps.AddImageTiled(gd, 10, 10, 230, h-20, 2624) Gumps.AddAlphaRegion(gd, 10, 10, 230, h-20) Gumps.AddLabel(gd, 35, 15, 63, "--- SELECT TOME TO FILL ---") Gumps.AddButton(gd, 20, 45, 4005, 4007, 8000, 1, 0) Gumps.AddLabel(gd, 55, 45, 66, "FILL ALL ACTIVE TOMES") y = 75 for i in active_indices: s, b, n = master_list[i] disp_name = n if n == "Dexter Tome": disp_name = "Dexter Tome ({})".format(hex(s)) Gumps.AddButton(gd, 20, y, 4005, 4007, 8001 + i, 1, 0) Gumps.AddLabel(gd, 55, y, 55, disp_name) y += 25 Gumps.SendGump(8888, Player.Serial, 0, 0, gd.gumpDefinition, gd.gumpStrings) def perform_tome_sequence(target_idx="ALL"): global LOOT_SOURCE_BAG master_list = get_tome_list() tomes_to_process = [] if target_idx == "ALL": Player.HeadMessage(55, ">>> SWEEPING BAGS INTO ALL TOMES <<<") tomes_to_process = master_list else: try: tomes_to_process = [master_list[target_idx]] Player.HeadMessage(55, ">>> FILLING SINGLE TOME <<<") except: return bags_to_sweep = [] if LOOT_SOURCE_BAG > 0: bags_to_sweep.append(LOOT_SOURCE_BAG) bags_to_sweep.append(Player.Backpack.Serial) for serial, btn, name in tomes_to_process: if not Items.FindBySerial(serial): continue Player.HeadMessage(68, "Filling {}...".format(name)) for bag in bags_to_sweep: Target.Cancel() Misc.Pause(50) Items.UseItem(serial) if WaitForAnyGump(2000): curr = Gumps.CurrentGump() Gumps.SendAction(curr, btn) if Target.WaitForTarget(2000, False): Target.TargetExecute(bag) Misc.Pause(800) if Target.HasTarget(): Target.Cancel() Misc.Pause(100) Gumps.CloseGump(curr) Misc.Pause(250) Player.HeadMessage(66, "Tome Restock Complete.") def CheckChatCommands(): global SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, ACTIVE_MASTERY, MASTERY_DATA, KNOWN_JUNK if Journal.Search(">start"): Journal.Clear(); SCRIPT_RUNNING = not SCRIPT_RUNNING; CheckAndDrawGUI(force=True) if Journal.Search(">skin"): Journal.Clear(); USE_SKINNING = not USE_SKINNING; CheckAndDrawGUI(force=True) if Journal.Search(">auto"): Journal.Clear(); AUTO_FARM_MODE = not AUTO_FARM_MODE; CheckAndDrawGUI(force=True) if Journal.Search(">ignore"): Journal.Clear() Misc.SendMessage("Target an item to permanently IGNORE (stop auto-sorting):", 55) t = Target.PromptTarget("Ignore Item") if t > 0: if t not in KNOWN_JUNK: KNOWN_JUNK.append(t) Player.HeadMessage(63, "Item Ignored! It will stay where you put it.") else: Player.HeadMessage(44, "Item is already on the ignore list.") if Journal.Search(">mastery"): line = Journal.GetLineText(">mastery") if line: parts = line.split(">mastery") if len(parts) > 1: new_mast = parts[1].strip().title() if new_mast: ACTIVE_MASTERY = new_mast MASTERY_DATA["Type"] = ACTIVE_MASTERY if MASTERY_DATA["Max"] == 0: MASTERY_DATA["Max"] = 62500 MASTERY_DATA["Current"] = 0 MASTERY_DATA["Percent"] = 0.0 CheckAndDrawGUI(force=True) Journal.Clear() def get_mobile_properties(mob): global MOBILE_PROP_CACHE if mob.Serial in MOBILE_PROP_CACHE: return MOBILE_PROP_CACHE[mob.Serial] props_str = "" try: Mobiles.WaitForProps(mob, 50) if mob.Properties: for p in mob.Properties: props_str += str(p).lower() + " " except: pass clean_props = re.sub(r'<[^>]+>', '', props_str).replace('\n', ' ') MOBILE_PROP_CACHE[mob.Serial] = clean_props if len(MOBILE_PROP_CACHE) > 500: MOBILE_PROP_CACHE.clear() return clean_props def check_buff_timers(): global last_orange_petal_time, last_minoc_petal_time, last_moonglow_petal_time, last_dissidia_petal_time, fire_ele_expiry global LAST_BUFF_HASH, last_buff_draw_time, last_buff_x, last_buff_y, last_buff_move_time if 'last_buff_draw_time' not in globals(): globals()['last_buff_draw_time'] = 0 if 'LAST_BUFF_HASH' not in globals(): globals()['LAST_BUFF_HASH'] = 0 if 'last_buff_x' not in globals(): globals()['last_buff_x'] = 0 if 'last_buff_y' not in globals(): globals()['last_buff_y'] = 0 if 'last_buff_move_time' not in globals(): globals()['last_buff_move_time'] = 0 curr = time.time() if curr - globals()['last_buff_draw_time'] < 1.0: return old_gump = Gumps.GetGumpData(BUFF_GUMP_ID) gx, gy = globals()['last_buff_x'], globals()['last_buff_y'] if old_gump: gx = getattr(old_gump, 'x', globals()['last_buff_x']) gy = getattr(old_gump, 'y', globals()['last_buff_y']) if gx != globals()['last_buff_x'] or gy != globals()['last_buff_y']: globals()['last_buff_x'] = gx globals()['last_buff_y'] = gy globals()['last_buff_move_time'] = curr return if curr - globals()['last_buff_move_time'] < 3.0: return active_buffs = [] buff_duration = 300.0 if last_orange_petal_time > 0 and (curr - last_orange_petal_time) < buff_duration: active_buffs.append(("Poison Imm", 63, int(buff_duration - (curr - last_orange_petal_time)))) if last_minoc_petal_time > 0 and (curr - last_minoc_petal_time) < buff_duration: active_buffs.append(("Minoc (+Dex)", 53, int(buff_duration - (curr - last_minoc_petal_time)))) if last_moonglow_petal_time > 0 and (curr - last_moonglow_petal_time) < buff_duration: active_buffs.append(("Moonglow (+Int)", 33, int(buff_duration - (curr - last_moonglow_petal_time)))) if last_dissidia_petal_time > 0 and (curr - last_dissidia_petal_time) < buff_duration: active_buffs.append(("Curse Resist", 44, int(buff_duration - (curr - last_dissidia_petal_time)))) current_state = "".join(["{}_{}".format(b[0], b[2]) for b in active_buffs]) new_hash = hash(current_state) if new_hash == globals()['LAST_BUFF_HASH']: return globals()['LAST_BUFF_HASH'] = new_hash globals()['last_buff_draw_time'] = curr try: Gumps.CloseGump(BUFF_GUMP_ID) except: pass if len(active_buffs) == 0: return gd = Gumps.CreateGump(movable=True) Gumps.AddPage(gd, 0) box_height = 10 + (len(active_buffs) * 20) Gumps.AddBackground(gd, 0, 0, 140, box_height, 3500) Gumps.AddImageTiled(gd, 5, 5, 130, box_height - 10, 2624) Gumps.AddAlphaRegion(gd, 5, 5, 130, box_height - 10) y_offset = 5 for name, color, time_left in active_buffs: Gumps.AddLabel(gd, 10, y_offset, color, "{}: {}s".format(name, time_left)) y_offset += 20 Gumps.SendGump(BUFF_GUMP_ID, Player.Serial, gx, gy, gd.gumpDefinition, gd.gumpStrings) def check_server_captcha(): if Journal.Search("[captcha") or Journal.Search("captcha"): Journal.Clear() Player.HeadMessage(33, "!!! SERVER CAPTCHA DETECTED !!!") Misc.Beep() Misc.Pause(300) Misc.Beep() Player.ChatSay("[captcha") Misc.Pause(5000) def check_auto_soul_reap(): global last_soul_reap_time if not USE_AUTO_SOUL or Player.IsGhost: return False if Player.GetSkillValue("Spirit Speak") < 100: return False if time.time() - last_soul_reap_time < 12.0: return False GLOBAL_CORPSE_FILTER.RangeMax = 6 corpses = Items.ApplyFilter(GLOBAL_CORPSE_FILTER) if corpses: Player.HeadMessage(68, ">> Reaping Souls <<") Player.UseSkill("Spirit Speak") last_soul_reap_time = time.time() return True return False def check_potions(): global last_heal_potion_time, last_cure_potion_time, last_refresh_pot_time if 'last_refresh_pot_time' not in globals(): globals()['last_refresh_pot_time'] = 0 if not USE_POTIONS: return False if not Player or Player.HitsMax == 0: return False curr_time = time.time() if curr_time - last_cure_potion_time >= POTION_COOLDOWN: if Player.Poisoned: cure_pot = Items.FindByID(0x0F07, -1, Player.Backpack.Serial, True) if cure_pot: Player.HeadMessage(63, "!!! POTION: CURE !!!") Items.UseItem(cure_pot) Misc.Pause(500) last_cure_potion_time = curr_time return True if curr_time - last_heal_potion_time >= POTION_COOLDOWN: hp_percent = (Player.Hits * 100) / Player.HitsMax if hp_percent < POTION_HEAL_TRIGGER: heal_pot = Items.FindByID(0x0F0C, -1, Player.Backpack.Serial, True) if heal_pot: Player.HeadMessage(63, "!!! POTION: HEAL !!!") Items.UseItem(heal_pot) Misc.Pause(500) last_heal_potion_time = curr_time return True if curr_time - last_refresh_pot_time >= POTION_COOLDOWN: if Player.WarMode: stam_trigger = (Player.StamMax - 30) if IS_DEXTER else 15 if Player.Stam <= stam_trigger: pot = Items.FindByID(REFRESH_POTION_ID, -1, Player.Backpack.Serial, True) if pot: Player.HeadMessage(63, "!!! POTION: REFRESH !!!") Items.UseItem(pot) Misc.Pause(500) last_refresh_pot_time = curr_time return True return False def check_auto_potions(): global last_str_pot_time, last_dex_pot_time if 'last_str_pot_time' not in globals(): globals()['last_str_pot_time'] = 0 if 'last_dex_pot_time' not in globals(): globals()['last_dex_pot_time'] = 0 if not USE_AUTO_BUFFS or Player.IsGhost: return False curr_time = time.time() is_str_debuffed = Player.BuffsExist("Weaken") or Player.BuffsExist("Curse") is_dex_debuffed = Player.BuffsExist("Clumsy") or Player.BuffsExist("Curse") str_cooldown = 15.0 if is_str_debuffed else 150.0 dex_cooldown = 15.0 if is_dex_debuffed else 150.0 if curr_time - last_str_pot_time > str_cooldown: pot = Items.FindByID(STR_POTION_ID, -1, Player.Backpack.Serial, True) if pot: Player.HeadMessage(63, ">> Chugging Str Pot <<") Items.UseItem(pot) last_str_pot_time = curr_time return True if curr_time - last_dex_pot_time > dex_cooldown: pot = Items.FindByID(DEX_POTION_ID, -1, Player.Backpack.Serial, True) if pot: Player.HeadMessage(63, ">> Chugging Dex Pot <<") Items.UseItem(pot) last_dex_pot_time = curr_time return True return False def check_auto_petals(): global last_orange_petal_time, last_dissidia_petal_time, last_minoc_petal_time, last_moonglow_petal_time if 'last_orange_petal_time' not in globals(): globals()['last_orange_petal_time'] = 0 if 'last_dissidia_petal_time' not in globals(): globals()['last_dissidia_petal_time'] = 0 if 'last_minoc_petal_time' not in globals(): globals()['last_minoc_petal_time'] = 0 if 'last_moonglow_petal_time' not in globals(): globals()['last_moonglow_petal_time'] = 0 if not USE_AUTO_PETALS or Player.IsGhost: return False curr_time = time.time() if curr_time - last_orange_petal_time > 320.0: petals = Items.FindAllByID(PETAL_ID, -1, Player.Backpack.Serial, True) for p in petals: if p.Hue == ORANGE_PETAL_HUE: Player.HeadMessage(55, ">> Eating Orange Petal (Psn Resist) <<") Items.UseItem(p) last_orange_petal_time = curr_time return True if curr_time - last_dissidia_petal_time > 320.0: petals = Items.FindAllByID(PETAL_ID, -1, Player.Backpack.Serial, True) for p in petals: if p.Hue == DISSIDIA_PETAL_HUE: Player.HeadMessage(55, ">> Eating Dissidia Petal (Curse Resist) <<") Items.UseItem(p) last_dissidia_petal_time = curr_time return True if IS_DEXTER: if curr_time - last_minoc_petal_time > 320.0: petals = Items.FindAllByID(PETAL_ID, -1, Player.Backpack.Serial, True) for p in petals: if p.Hue == MINOC_PETAL_HUE: Player.HeadMessage(55, ">> Eating Minoc Petal (+Dex) <<") Items.UseItem(p) last_minoc_petal_time = curr_time return True elif IS_MAGE: if curr_time - last_moonglow_petal_time > 320.0: petals = Items.FindAllByID(PETAL_ID, -1, Player.Backpack.Serial, True) for p in petals: if p.Hue == MOONGLOW_PETAL_HUE: Player.HeadMessage(55, ">> Eating Moonglow Petal (+Int) <<") Items.UseItem(p) last_moonglow_petal_time = curr_time return True return False def check_auto_meditation(): global MED_GORGET, IS_MEDDING, last_med_attempt, med_start_time if Player.IsGhost: return False if Player.GetSkillValue("Meditation") < 10: return False if Player.Mana >= Player.ManaMax: if IS_MEDDING: Journal.Clear() if MED_GORGET > 0: gorget = Items.FindBySerial(MED_GORGET) if gorget: Player.HeadMessage(66, ">> Re-equipping Gorget <<") Player.EquipItem(MED_GORGET) Misc.Pause(400) IS_MEDDING = False MED_GORGET = 0 return False if not IS_MEDDING and (time.time() - last_med_attempt > 4.0): Journal.Clear() Player.UseSkill("Meditation") last_med_attempt = time.time() med_start_time = time.time() IS_MEDDING = True if Journal.Search("penetrate your armor") or Journal.Search("not possible with your equipment") or Journal.Search("Regenerative forces"): Journal.Clear() neck = Player.GetItemOnLayer("Neck") if neck: Player.HeadMessage(63, ">> Stripping Gorget for Meditation <<") MED_GORGET = neck.Serial Items.Move(neck.Serial, Player.Backpack.Serial, 0) Misc.Pause(600) Player.UseSkill("Meditation") last_med_attempt = time.time() med_start_time = time.time() IS_MEDDING = True return False if IS_MEDDING: med_done = False if time.time() - med_start_time > 12.0: med_done = True fail_msgs = [ "You are at peace.", "lose your concentration", "stop meditating", "focus your concentration", "must stand still", "too busy", "cannot meditate" ] for msg in fail_msgs: if Journal.Search(msg): med_done = True break if med_done: Journal.Clear() if MED_GORGET > 0: gorget = Items.FindBySerial(MED_GORGET) if gorget: Player.HeadMessage(66, ">> Re-equipping Gorget <<") Player.EquipItem(MED_GORGET) Misc.Pause(400) IS_MEDDING = False MED_GORGET = 0 last_med_attempt = time.time() return False def track_equipment(): global PREF_WEP, PREF_SHIELD rh = Player.GetItemOnLayer("RightHand") lh = Player.GetItemOnLayer("LeftHand") ignored_ids = [3834, 20497, 0x0EC4, 0x0F52, 0x0F51, 0x13F6] if rh and rh.ItemID not in ignored_ids: curr_rh = rh.Serial if curr_rh != PREF_WEP: PREF_WEP = curr_rh Misc.SetSharedValue("PREF_WEP", curr_rh) if lh and lh.ItemID not in ignored_ids: curr_lh = lh.Serial if curr_lh != PREF_SHIELD: PREF_SHIELD = curr_lh Misc.SetSharedValue("PREF_SHIELD", curr_lh) def check_anti_disarm(): global USE_ANTI_DISARM, PREF_WEP, PREF_SHIELD, LAST_EMPTY_HANDS_TIME if 'LAST_EMPTY_HANDS_TIME' not in globals(): globals()['LAST_EMPTY_HANDS_TIME'] = 0 if not USE_ANTI_DISARM or not Player.WarMode: return False if Player.IsGhost: return False rh = Player.GetItemOnLayer("RightHand") lh = Player.GetItemOnLayer("LeftHand") if (rh and rh.ItemID == 3834) or (lh and lh.ItemID == 3834): return False missing_wep = (not rh and PREF_WEP > 0) missing_shield = (not lh and PREF_SHIELD > 0) if missing_wep or missing_shield: if globals()['LAST_EMPTY_HANDS_TIME'] == 0: globals()['LAST_EMPTY_HANDS_TIME'] = time.time() return False elif time.time() - globals()['LAST_EMPTY_HANDS_TIME'] < 3.5: return False else: globals()['LAST_EMPTY_HANDS_TIME'] = 0 return False equipped_something = False if missing_wep: wep = Items.FindBySerial(PREF_WEP) if wep and (wep.Container == Player.Backpack.Serial or wep.Container == LOOT_SOURCE_BAG): Player.HeadMessage(66, ">> ANTI-DISARM: WEAPON <<") Player.EquipItem(wep.Serial) equipped_something = True if missing_shield: sh = Items.FindBySerial(PREF_SHIELD) if sh and (sh.Container == Player.Backpack.Serial or sh.Container == LOOT_SOURCE_BAG): Player.HeadMessage(66, ">> ANTI-DISARM: BOW/SHIELD <<") Player.EquipItem(sh.Serial) equipped_something = True if equipped_something: globals()['LAST_EMPTY_HANDS_TIME'] = 0 return True return False def check_smart_poison(target): global last_poison_time if not USE_SMART_POISON or not target: return False if Player.IsGhost: return False if time.time() - last_poison_time < 5.0: return False if Player.GetSkillValue("Poisoning") < 20: return False immune_mobs = ["elemental", "wisp", "golem", "undead", "demon", "daemon", "spider", "ooze", "slime", "gate keeper", "plague beast"] t_name = (target.Name or "").lower() if any(imm in t_name for imm in immune_mobs): return False wep = Player.GetItemOnLayer("RightHand") or Player.GetItemOnLayer("LeftHand") if not wep: return False props = get_item_properties(wep) if "poison" not in props.lower(): poison = Items.FindByID(0x0F0A, -1, Player.Backpack.Serial, True) if poison: Player.HeadMessage(63, ">> APPLYING POISON <<") Player.UseSkill("Poisoning") last_poison_time = time.time() if Target.WaitForTarget(3000, False): Target.TargetExecute(poison.Serial) if Target.WaitForTarget(3000, False): Target.TargetExecute(wep.Serial) return True return False def can_cast_spell(spell_name): if HAS_100_LRC: return True if not Player.Backpack: return False regs_needed = [] if spell_name == "Greater Heal": regs_needed = [REG_GARLIC, REG_GINSENG, REG_MANDRAKE, REG_SILK] elif spell_name == "Heal": regs_needed = [REG_GARLIC, REG_GINSENG, REG_SILK] elif spell_name == "Arch Cure": regs_needed = [REG_GARLIC, REG_GINSENG, REG_MANDRAKE] elif spell_name == "Cure": regs_needed = [REG_GARLIC, REG_GINSENG] elif spell_name == "Bless": regs_needed = [REG_GARLIC, REG_MANDRAKE] elif spell_name == "Reactive Armor": regs_needed = [REG_GARLIC, REG_SILK, REG_SHADE] elif spell_name == "Protection": regs_needed = [REG_GARLIC, REG_GINSENG, REG_MANDRAKE] elif spell_name == "Magic Reflection": regs_needed = [REG_GARLIC, REG_MANDRAKE, REG_SILK] elif spell_name == "Explosion": regs_needed = [REG_MANDRAKE, REG_ASH] elif spell_name == "Mind Blast": regs_needed = [REG_PEARL, REG_MANDRAKE, REG_ASH, REG_SHADE] elif spell_name == "Flamestrike": regs_needed = [REG_SILK, REG_ASH] elif spell_name == "Energy Bolt": regs_needed = [REG_PEARL, REG_SHADE] elif spell_name == "Lightning": regs_needed = [REG_MANDRAKE, REG_ASH] elif spell_name == "Chain Lightning": regs_needed = [REG_MANDRAKE, REG_MOSS, REG_PEARL, REG_ASH] elif spell_name == "Fire Elemental": regs_needed = [REG_MOSS, REG_MANDRAKE, REG_SILK, REG_ASH] elif spell_name == "Magic Arrow": regs_needed = [REG_ASH] elif spell_name == "Harm": regs_needed = [REG_SHADE] for r in regs_needed: if Items.BackpackCount(r, -1) < 1: return False return True def auto_lockpick(): global last_pick_time, unlocked_chests, USE_LOCKPICKING if not USE_LOCKPICKING or Player.IsGhost: return False if time.time() - last_pick_time < 4.0: return False GLOBAL_CHEST_FILTER.RangeMax = 2 chests = Items.ApplyFilter(GLOBAL_CHEST_FILTER) target_chest = None for c in chests: if c.Serial not in unlocked_chests: if get_container_count(c) > 0: unlocked_chests.append(c.Serial) if len(unlocked_chests) > 200: unlocked_chests.pop(0) continue target_chest = c break if not target_chest: return False pick = Items.FindByID(5372, -1, Player.Backpack.Serial, True) if not pick: Player.HeadMessage(33, "⚠️ OUT OF LOCKPICKS! Disabling Auto-Pick.") USE_LOCKPICKING = False CheckAndDrawGUI(force=True) return False Player.HeadMessage(55, ">> Picking Chest <<") Journal.Clear() Items.UseItem(pick) last_pick_time = time.time() if Target.WaitForTarget(1500, False): Target.TargetExecute(target_chest.Serial) Misc.Pause(500) if Journal.Search("does not appear to be locked") or Journal.Search("successfully") or Journal.Search("yields") or Journal.Search("That is already unlocked"): unlocked_chests.append(target_chest.Serial) if len(unlocked_chests) > 200: unlocked_chests.pop(0) Player.HeadMessage(63, "Chest Unlocked!") Journal.Clear() return True return False def check_taunt(target): global last_taunt_time if not USE_TAUNT or not target: return False if Player.IsGhost: return False if Player.GetSkillValue("Parrying") < 50: return False if time.time() - last_taunt_time > 15.0: Player.HeadMessage(73, ">> TAUNTING {} <<".format(target.Name)) Player.UseSkill("Taunt") Player.ChatSay("[taunt") last_taunt_time = time.time() if Target.WaitForTarget(500, False): Target.TargetExecute(target.Serial) return True return False def check_magery_buffs(): global last_magery_buff_time, magery_buff_cooldowns if not IS_MAGE: return False if not USE_MAGERY_BUFFS: return False if Player.IsGhost: return False if time.time() - last_magery_buff_time < 3.0: return False if Player.Mana < 20: return False buffs = [ ("Reactive Armor", "Reactive Armor", False, 163), ("Protection", "Protection", False, 163), ("Magic Reflection", "Magic Reflection", False, 163), ("Bless", "Bless", True, 163) ] for buff_icon, spell_name, needs_target, cooldown in buffs: time_since_last_cast = time.time() - magery_buff_cooldowns.get(spell_name, 0) if not Player.BuffsExist(buff_icon) and time_since_last_cast > cooldown: if not can_cast_spell(spell_name): continue Player.HeadMessage(55, ">> Mage Buff: {} <<".format(spell_name)) Spells.Cast(spell_name) magery_buff_cooldowns[spell_name] = time.time() last_magery_buff_time = time.time() if needs_target: if Target.WaitForTarget(3000, False): Target.TargetExecute(Player.Serial) Misc.Pause(150) return True return False def update_mastery_stats(): global MASTERY_DATA, ACTIVE_MASTERY for km in KNOWN_MASTERIES: if Journal.Search(km + " Mastery"): if ACTIVE_MASTERY != km: ACTIVE_MASTERY = km MASTERY_DATA["Type"] = ACTIVE_MASTERY Misc.SetSharedValue("ACTIVE_MASTERY", ACTIVE_MASTERY) CheckAndDrawGUI(force=True) break nums_line = Journal.GetLineText(" / ") if nums_line and "[" not in nums_line and "xp" not in nums_line.lower(): n_match = re.search(r"(\d+)\s*/\s*(\d+)", nums_line) if n_match: curr = int(n_match.group(1)) maxx = int(n_match.group(2)) if maxx > 1000: MASTERY_DATA["Current"] = curr MASTERY_DATA["Max"] = maxx MASTERY_DATA["Type"] = ACTIVE_MASTERY pct = float(curr) / float(maxx) if pct > 1.0: pct = 1.0 MASTERY_DATA["Percent"] = round(pct * 100, 1) CheckAndDrawGUI(force=True) Journal.Clear() def update_pet_levels(): global PET_DATA_CACHE, LAST_PET_SCAN, SPECIFIC_PET_BODIES, PET_MAPPING if not SPECIFIC_PET_SERIAL: return if time.time() - LAST_PET_SCAN < 5.0: return LAST_PET_SCAN = time.time() updated = False for s in SPECIFIC_PET_SERIAL: mob = Mobiles.FindBySerial(s) if s not in PET_DATA_CACHE: PET_DATA_CACHE[s] = {'percent': 0.0, 'status': 'Active', 'level': '?'} if mob: if PET_MAPPING.get(s) == "Saved Pet (Out of Range)" or PET_MAPPING.get(s) == "Unknown": raw_name = mob.Name if mob.Name else "Unknown" PET_MAPPING[s] = GetTruePetName(raw_name) if int(mob.Body) not in SPECIFIC_PET_BODIES: SPECIFIC_PET_BODIES.append(int(mob.Body)) save_str = "|".join(["{}:{}".format(x, PET_MAPPING[x]) for x in SPECIFIC_PET_SERIAL]) Misc.SetSharedValue("SAVED_PET_MAP", save_str) updated = True Mobiles.WaitForProps(mob, 200) for prop in mob.Properties: p_str = str(prop).upper() if "MAX" in p_str: PET_DATA_CACHE[s]['status'] = "MAX" PET_DATA_CACHE[s]['percent'] = 100.0 updated = True break xp_match = re.search(r"(\d+)\s*/\s*(\d+)", p_str) if xp_match: curr = int(xp_match.group(1)) maxx = int(xp_match.group(2)) if maxx > 1000: pct = (float(curr) / float(maxx)) * 100 PET_DATA_CACHE[s]['percent'] = pct PET_DATA_CACHE[s]['status'] = "{:.1f}%".format(pct) updated = True break if "LEVEL" in p_str: match = re.search(r"(?:LEVEL|LVL)[\s:]*(\d+)", p_str) if match: PET_DATA_CACHE[s]['level'] = match.group(1) if PET_DATA_CACHE[s]['status'] == "Active" and PET_DATA_CACHE[s]['percent'] == 0: PET_DATA_CACHE[s]['status'] = "MAX" PET_DATA_CACHE[s]['percent'] = 100.0 updated = True if updated: CheckAndDrawGUI(force=True) def check_pet_recall(): global last_pet_recall_time, PET_RECALL_STATES if not USE_PET_RECALL: return False for s in SPECIFIC_PET_SERIAL: pet = Mobiles.FindBySerial(s) if not pet: continue is_recalled = PET_RECALL_STATES.get(s, False) if getattr(pet, 'IsGhost', False): if not is_recalled and (time.time() - last_pet_recall_time > 2.0): p_name = PET_MAPPING.get(s, "Pet") Player.HeadMessage(33, "!!! {} DIED - CALLING FOR REZ !!!".format(p_name)) Player.ChatSay(33, "{} follow me".format(str(p_name))) Misc.Pause(250) PET_RECALL_STATES[s] = True last_pet_recall_time = time.time() CheckAndDrawGUI(force=True) return True else: if is_recalled: PET_RECALL_STATES[s] = False CheckAndDrawGUI(force=True) return False def check_pouch_popper(): global last_pouch_time if not USE_POUCHES or Player.IsGhost: return if not Player.BuffsExist("Paralyze"): return if time.time() - last_pouch_time < 2.0: return pouches = Items.FindAllByID(0x0E79, -1, Player.Backpack.Serial, True) for p in pouches: if p.Hue in [37, 38, 0x0025]: Player.HeadMessage(63, ">> POPPING POUCH <<") Items.UseItem(p.Serial) last_pouch_time = time.time() Misc.Pause(200) return def get_injured_pet(): global SPECIFIC_PET_SERIAL if not SPECIFIC_PET_SERIAL: return None candidate_pet = None lowest_hp_percent = 100 for serial in SPECIFIC_PET_SERIAL: pet = Mobiles.FindBySerial(serial) if not pet: continue if pet.Body in [0x0260, 0x02F0, 705, 752, 763]: continue if pet.HitsMax == 0: continue if pet.Poisoned or pet.Hits < pet.HitsMax: hp_percent = (pet.Hits * 100) / pet.HitsMax if hp_percent < lowest_hp_percent: lowest_hp_percent = hp_percent candidate_pet = pet if candidate_pet and Player.DistanceTo(candidate_pet) <= VET_RANGE: return candidate_pet return None def check_supplies(): global last_supply_warn if not Player.Backpack: return bandages = Items.BackpackCount(BANDAGE_ID, -1) kits = Items.BackpackCount(VET_KIT_ID, -1) has_kits = kits > 0 has_bandages = bandages > 0 msg = "" if IS_ARCHER: arrows = Items.BackpackCount(ARROW_ID, -1) bolts = Items.BackpackCount(BOLT_ID, -1) quiver = Player.GetItemOnLayer("Cloak") if quiver and getattr(quiver, 'Contains', None): for item in quiver.Contains: if item.ItemID == ARROW_ID: arrows += item.Amount elif item.ItemID == BOLT_ID: bolts += item.Amount total_ammo = arrows + bolts if total_ammo == 0: msg = "⚠️ CRITICAL: OUT OF AMMO! ⚠️" elif total_ammo < WARN_LOW_AMMO: msg = "⚠️ LOW AMMO ({} Left) ⚠️".format(total_ammo) golem_active = False for s in SPECIFIC_PET_SERIAL: mob = Mobiles.FindBySerial(s) if mob and mob.Body in [0x0260, 0x02F0, 705, 752, 763]: golem_active = True break if golem_active: total_golem_kits = 0 total_golem_uses = 0 all_potential_kits = [] res1 = Items.FindAllByID(19218, -1, Player.Backpack.Serial, True) if res1: all_potential_kits.extend(res1) res2 = Items.FindAllByID(TOOL_KIT_ID, -1, Player.Backpack.Serial, True) if res2: all_potential_kits.extend(res2) for kit in all_potential_kits: props = get_item_properties(kit).lower() if "golem" in props or kit.ItemID == 19218: total_golem_kits += 1 match = re.search(r"uses remaining:\s*(\d+)", props) if match: total_golem_uses += int(match.group(1)) else: total_golem_uses += 1 if total_golem_kits == 0 or total_golem_uses == 0: msg = "⚠️ CRITICAL: OUT OF GOLEM KITS! ⚠️" elif total_golem_uses <= 50: msg = "⚠️ LOW GOLEM KITS ({} Kits, {} Charges) ⚠️".format(total_golem_kits, total_golem_uses) if msg == "": if not has_kits and not has_bandages: msg = "⚠️ CRITICAL: NO HEALING SUPPLIES! ⚠️" elif not has_kits and bandages < WARN_LOW_BANDAGES: msg = "⚠️ LOW BANDAGES ({} Left) ⚠️".format(bandages) if msg != "": if time.time() - last_supply_warn > 10.0: Player.HeadMessage(33, msg) if "GOLEM" in msg: Misc.Beep() Misc.Pause(150) Misc.Beep() Misc.Pause(150) Misc.Beep() last_supply_warn = time.time() def check_weight_alarm(): global last_weight_warn, last_bless_time, last_wand_time if not Player or Player.MaxWeight == 0: return False free_stones = Player.MaxWeight - Player.Weight if free_stones <= WARN_AT_WEIGHT: if time.time() - last_weight_warn > 30: Player.HeadMessage(33, "!!! OVERWEIGHT LIMIT (-{} STONES) !!!".format(free_stones)) last_weight_warn = time.time() if USE_AUTO_WAND and LOOT_SOURCE_BAG > 0: if time.time() - last_wand_time > 5.0: wand = Items.FindByID(WAND_ID, -1, Player.Backpack.Serial, True) if wand: Player.HeadMessage(63, ">> DUSTING LOOT BAG <<") Items.UseItem(wand.Serial) if Target.WaitForTarget(1500, False): Target.TargetExecute(LOOT_SOURCE_BAG) last_wand_time = time.time() Misc.Pause(1000) swept = 0 if Player.Backpack: for item in Player.Backpack.Contains: if item.ItemID in DUST_RESOURCES: Items.Move(item.Serial, LOOT_SOURCE_BAG, 0) Misc.Pause(500) swept += 1 if swept > 0: Player.HeadMessage(66, ">> Swept {} enhancements to Loot Bag <<".format(swept)) return True else: if time.time() - last_wand_time > 10.0: Player.HeadMessage(33, "!!! NO MAGIC WAND FOUND !!!") last_wand_time = time.time() if not IS_MAGE or not USE_BLESS: return False if free_stones <= 5: if time.time() - last_bless_time > 30: if Player.Mana > 10: if not can_cast_spell("Bless"): return False Player.HeadMessage(63, "!!! HEAVY - CASTING BLESS !!!") Spells.Cast("Bless") last_bless_time = time.time() if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) return True return False def process_corpse_resources(corpse): global CURRENT_ACTION if not USE_SKINNING: return False if not IS_SKINNER: return False if Player.MaxWeight > 0 and Player.Weight >= Player.MaxWeight: return False if corpse.Serial not in skinned_corpses: skinned_corpses.append(corpse.Serial) if len(skinned_corpses) > 100: skinned_corpses.pop(0) tool = None for tool_id in SKINNING_TOOL_IDS: found = Items.FindByID(tool_id, -1, Player.Backpack.Serial, True) if found: tool = found; break if tool: CURRENT_ACTION = "Skinning" Target.Cancel() Misc.Pause(50) Items.UseItem(tool.Serial) if Target.WaitForTarget(1000, False): Target.TargetExecute(corpse.Serial) Misc.Pause(250) else: Target.Cancel() return True if USE_SCISSORS: hides = Items.FindByID(HIDES_ID, -1, corpse.Serial, False) if not hides: hides = Items.FindByID(0x1078, -1, corpse.Serial, False) if hides: scissors = Items.FindByID(SCISSORS_ID, -1, Player.Backpack.Serial, True) if scissors: CURRENT_ACTION = "Cutting Hides" Target.Cancel() Misc.Pause(50) Items.UseItem(scissors.Serial) if Target.WaitForTarget(1000, False): Target.TargetExecute(hides.Serial) else: Target.Cancel() Misc.Pause(350) return True leather = Items.FindByID(LEATHER_ID, -1, corpse.Serial, False) if not leather: leather = Items.FindByID(0x1082, -1, corpse.Serial, False) if leather: CURRENT_ACTION = "Looting Leather" dest = GetSafeDest(LOOT_SOURCE_BAG) Items.Move(leather.Serial, dest, 0) Misc.Pause(350) return True return False def is_equipment_loot(item, clean_props=""): try: item_id = int(item.ItemID) if item_id in IGNORED_ITEM_IDS: return False ignore_basic = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, 19218, TOOL_KIT_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS if item_id in ignore_basic: return False if item_id in HIGH_VALUE_IDS: return False except: pass if is_blessed_item(item): return False if is_valuable_item(item, clean_props): return False clean_name = re.sub(r'<[^>]+>', '', (item.Name or "")).lower().strip() ignore_names = ["spellbook", "runebook", "tome", "key", "bag", "pouch", "box", "chest", "safe", "vault", "book", "desk", "wand", "scroll", "tools_"] if any(x in clean_name for x in ignore_names): return False if not clean_props: clean_props = get_item_properties(item) keywords = ["intensity", "durability", "weapon damage", "armor", "hit chance", "defense chance", "lower reagent", "spell damage", "faster cast", "damage increase", "swing speed", "resist", "ruin", "might", "force", "power", "defense", "guarding", "hardening", "fortification", "accurate", "surpassingly", "eminently", "exceedingly", "exceptional", "crafted by"] if any(k in clean_props for k in keywords): return True return False def is_dustable_item(item, clean_props=""): try: item_id = int(item.ItemID) if item_id in IGNORED_ITEM_IDS: return False ignore_basic = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, ARROW_ID, BOLT_ID, 19218, TOOL_KIT_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS if item_id in ignore_basic: return False if item_id in HIGH_VALUE_IDS: return False except: pass if is_blessed_item(item): return False if is_valuable_item(item, clean_props): return False clean_name = re.sub(r'<[^>]+>', '', (item.Name or "")).lower().strip() ignore_names = ["spellbook", "runebook", "tome", "key", "bag", "pouch", "box", "chest", "safe", "vault", "book", "desk", "scroll", "map", "potion", "bottle", "bone", "meat", "body", "head", "arm", "leg", "torso", "pelvis", "feather", "shaft", "wand", "tools_"] if any(x in clean_name for x in ignore_names): return False gear_keywords = ["tunic", "sleeves", "leggings", "gorget", "gloves", "cap", "helmet", "helm", "sword", "blade", "mace", "axe", "bow", "crossbow", "shield", "buckler", "kryss", "katana", "spear", "staff", "leather", "studded", "bone armor", "ringmail", "chainmail", "platemail", "plate", "bascinet", "bashing", "slashing", "piercing", "armor"] if any(k in clean_name for k in gear_keywords): return True if not clean_props: clean_props = get_item_properties(item) if "weight" in clean_props or "durability" in clean_props: return True return False def is_valuable_item(item, clean_props=""): try: item_id = int(item.ItemID) if item_id in IGNORED_ITEM_IDS: return False ignore_basic_ids = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, 19218, TOOL_KIT_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS if item_id in ignore_basic_ids: return False if item_id in HIGH_VALUE_IDS: return True except: pass if is_blessed_item(item): return False raw_name = (item.Name or "").lower() clean_name = re.sub(r'<[^>]+>', '', raw_name).strip() ignore_names = ["potion", "eldritch", "wand", "tools_", "codex", "book"] if any(x in clean_name for x in ignore_names): return False if not clean_props: clean_props = get_item_properties(item) instant_rares = ["power scroll", "arcane scroll", "aspect core", "aspect extract", "skill scroll", "mastery chain", "void", "paragon chest", "enhancement core", "enhancement scroll", "map", "rare cloth", "orb", "fira", "artifact", "mastery", "skull", "wraithcaller", "deco", "decoration", "lore page", "turret", "defense token"] if any(r in clean_name for r in instant_rares): return True if any(r in clean_props for r in instant_rares): return True if "paladin spellbook" in clean_name: return False if "spellbook" in clean_name and "paladin" in clean_name: return False return False def check_bag_sorting(): global last_vault_scan_time, VAULT_ATTEMPT_HISTORY, CURRENT_ACTION, KNOWN_JUNK if time.time() - last_vault_scan_time < 0.5: return False last_vault_scan_time = time.time() if not Player.Backpack: return False if Journal.Search("This is a very bad idea"): Journal.Clear() Player.HeadMessage(33, "!!! SERVER BLOCKED BLESSED ITEM MOVE !!!") Misc.Pause(1000) return False vip_moved = False containers_to_sweep = [Player.Backpack] if LOOT_SOURCE_BAG > 0: lb = Items.FindBySerial(LOOT_SOURCE_BAG) if lb and getattr(lb, 'Contains', None): containers_to_sweep.append(lb) for container in containers_to_sweep: for item in container.Contains: safe_gorget = Misc.ReadSharedValue("MED_GORGET") if Misc.CheckSharedValue("MED_GORGET") else 0 safe_wep = Misc.ReadSharedValue("PREF_WEP") if Misc.CheckSharedValue("PREF_WEP") else 0 safe_shield = Misc.ReadSharedValue("PREF_SHIELD") if Misc.CheckSharedValue("PREF_SHIELD") else 0 if item.Serial in [safe_gorget, safe_wep, safe_shield] and item.Serial != 0: continue if item.Serial == VAULT_BAG_SERIAL or item.Serial == LOOT_SOURCE_BAG or item.Serial == SATCHEL_SERIAL: continue if item.Serial in KNOWN_JUNK: continue if "bank check" in (item.Name or "").lower(): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) continue if item.ItemID in DUST_RESOURCES: continue if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5: continue if is_blessed_item(item): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.pop(0) continue try: item_id = int(item.ItemID) ignore_basic = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, 19218, TOOL_KIT_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS + IGNORED_ITEM_IDS if item_id in ignore_basic or "potion" in (item.Name or "").lower() or "tools_" in (item.Name or "").lower(): KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.pop(0) continue if item_id in HIGH_VALUE_IDS: dest_vault = GetSafeDest(VAULT_BAG_SERIAL) if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) disp_name = item.Name or "Epic Item" try: p_list = Items.GetPropStringList(item.Serial) if p_list and len(p_list) > 0: disp_name = str(p_list[0]) except: pass disp_name = re.sub(r'<[^>]+>', '', disp_name).strip() if disp_name.isdigit(): disp_name = "Epic Item" Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(disp_name)) Items.Move(item.Serial, dest_vault, 0) Misc.Pause(600) vip_moved = True continue except: pass props = get_item_properties(item) if is_valuable_item(item, props): dest_vault = GetSafeDest(VAULT_BAG_SERIAL) if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) disp_name = item.Name or "Rare Item" try: p_list = Items.GetPropStringList(item.Serial) if p_list and len(p_list) > 0: disp_name = str(p_list[0]) except: pass disp_name = re.sub(r'<[^>]+>', '', disp_name).strip() if disp_name.isdigit(): disp_name = "Rare Item" Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(disp_name)) Items.Move(item.Serial, dest_vault, 0) Misc.Pause(600) vip_moved = True continue if vip_moved: return True for item in Player.Backpack.Contains: if item.Serial in KNOWN_JUNK: continue if item.ItemID in DUST_RESOURCES: dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True continue if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5: continue if is_blessed_item(item): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) continue props = get_item_properties(item) if LOOT_MAGIC_ITEMS and is_equipment_loot(item, props): dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True elif LOOT_DUSTABLES and is_dustable_item(item, props): dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True else: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() return False def check_bag_sorting(): global last_vault_scan_time, VAULT_ATTEMPT_HISTORY, CURRENT_ACTION, KNOWN_JUNK if time.time() - last_vault_scan_time < 0.5: return False last_vault_scan_time = time.time() if not Player.Backpack: return False if Journal.Search("This is a very bad idea"): Journal.Clear() Player.HeadMessage(33, "!!! SERVER BLOCKED BLESSED ITEM MOVE !!!") Misc.Pause(1000) return False vip_moved = False containers_to_sweep = [Player.Backpack] if LOOT_SOURCE_BAG > 0: lb = Items.FindBySerial(LOOT_SOURCE_BAG) if lb and getattr(lb, 'Contains', None): containers_to_sweep.append(lb) for container in containers_to_sweep: for item in container.Contains: safe_gorget = Misc.ReadSharedValue("MED_GORGET") if Misc.CheckSharedValue("MED_GORGET") else 0 safe_wep = Misc.ReadSharedValue("PREF_WEP") if Misc.CheckSharedValue("PREF_WEP") else 0 safe_shield = Misc.ReadSharedValue("PREF_SHIELD") if Misc.CheckSharedValue("PREF_SHIELD") else 0 if item.Serial in [safe_gorget, safe_wep, safe_shield] and item.Serial != 0: continue if item.Serial == VAULT_BAG_SERIAL or item.Serial == LOOT_SOURCE_BAG or item.Serial == SATCHEL_SERIAL: continue if item.Serial in KNOWN_JUNK: continue if "bank check" in (item.Name or "").lower(): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) continue # ---> FIX: Hides Enhancements AND Void Orbs from the Vault Scanner <--- if item.ItemID in DUST_RESOURCES or "void orb" in (item.Name or "").lower(): continue if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5: continue if is_blessed_item(item): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.pop(0) continue try: item_id = int(item.ItemID) ignore_basic = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, 19218, TOOL_KIT_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS + IGNORED_ITEM_IDS if item_id in ignore_basic or "potion" in (item.Name or "").lower() or "tools_" in (item.Name or "").lower(): KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.pop(0) continue if item_id in HIGH_VALUE_IDS: dest_vault = GetSafeDest(VAULT_BAG_SERIAL) if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) disp_name = item.Name or "Epic Item" try: p_list = Items.GetPropStringList(item.Serial) if p_list and len(p_list) > 0: disp_name = str(p_list[0]) except: pass disp_name = re.sub(r'<[^>]+>', '', disp_name).strip() if disp_name.isdigit(): disp_name = "Epic Item" Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(disp_name)) Items.Move(item.Serial, dest_vault, 0) Misc.Pause(600) vip_moved = True continue except: pass props = get_item_properties(item) if is_valuable_item(item, props): dest_vault = GetSafeDest(VAULT_BAG_SERIAL) if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) disp_name = item.Name or "Rare Item" try: p_list = Items.GetPropStringList(item.Serial) if p_list and len(p_list) > 0: disp_name = str(p_list[0]) except: pass disp_name = re.sub(r'<[^>]+>', '', disp_name).strip() if disp_name.isdigit(): disp_name = "Rare Item" Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(disp_name)) Items.Move(item.Serial, dest_vault, 0) Misc.Pause(600) vip_moved = True continue if vip_moved: return True for item in Player.Backpack.Contains: if item.Serial in KNOWN_JUNK: continue # ---> FIX: Actively vacuum Dust Resources AND Void Orbs from Main Bag to Loot Bag <--- if item.ItemID in DUST_RESOURCES or "void orb" in (item.Name or "").lower(): dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True continue if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5: continue if is_blessed_item(item): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) continue props = get_item_properties(item) if LOOT_MAGIC_ITEMS and is_equipment_loot(item, props): dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True elif LOOT_DUSTABLES and is_dustable_item(item, props): dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True else: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() return False def check_bag_sorting(): global last_vault_scan_time, VAULT_ATTEMPT_HISTORY, CURRENT_ACTION, KNOWN_JUNK if time.time() - last_vault_scan_time < 0.5: return False last_vault_scan_time = time.time() if not Player.Backpack: return False if Journal.Search("This is a very bad idea"): Journal.Clear() Player.HeadMessage(33, "!!! SERVER BLOCKED BLESSED ITEM MOVE !!!") Misc.Pause(1000) return False vip_moved = False containers_to_sweep = [Player.Backpack] if LOOT_SOURCE_BAG > 0: lb = Items.FindBySerial(LOOT_SOURCE_BAG) if lb and getattr(lb, 'Contains', None): containers_to_sweep.append(lb) for container in containers_to_sweep: for item in container.Contains: safe_gorget = Misc.ReadSharedValue("MED_GORGET") if Misc.CheckSharedValue("MED_GORGET") else 0 safe_wep = Misc.ReadSharedValue("PREF_WEP") if Misc.CheckSharedValue("PREF_WEP") else 0 safe_shield = Misc.ReadSharedValue("PREF_SHIELD") if Misc.CheckSharedValue("PREF_SHIELD") else 0 if item.Serial in [safe_gorget, safe_wep, safe_shield] and item.Serial != 0: continue if item.Serial == VAULT_BAG_SERIAL or item.Serial == LOOT_SOURCE_BAG or item.Serial == SATCHEL_SERIAL: continue if item.Serial in KNOWN_JUNK: continue if "bank check" in (item.Name or "").lower(): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) continue if item.ItemID in DUST_RESOURCES: continue # Keeps enhancements out of the Vault scan if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5: continue if is_blessed_item(item): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.pop(0) continue try: item_id = int(item.ItemID) ignore_basic = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, 19218, TOOL_KIT_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS + IGNORED_ITEM_IDS if item_id in ignore_basic or "potion" in (item.Name or "").lower() or "tools_" in (item.Name or "").lower(): KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.pop(0) continue if item_id in HIGH_VALUE_IDS: dest_vault = GetSafeDest(VAULT_BAG_SERIAL) if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) disp_name = item.Name or "Epic Item" try: p_list = Items.GetPropStringList(item.Serial) if p_list and len(p_list) > 0: disp_name = str(p_list[0]) except: pass disp_name = re.sub(r'<[^>]+>', '', disp_name).strip() if disp_name.isdigit(): disp_name = "Epic Item" Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(disp_name)) Items.Move(item.Serial, dest_vault, 0) Misc.Pause(600) vip_moved = True continue except: pass props = get_item_properties(item) if is_valuable_item(item, props): dest_vault = GetSafeDest(VAULT_BAG_SERIAL) if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) disp_name = item.Name or "Rare Item" try: p_list = Items.GetPropStringList(item.Serial) if p_list and len(p_list) > 0: disp_name = str(p_list[0]) except: pass disp_name = re.sub(r'<[^>]+>', '', disp_name).strip() if disp_name.isdigit(): disp_name = "Rare Item" Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(disp_name)) Items.Move(item.Serial, dest_vault, 0) Misc.Pause(600) vip_moved = True continue if vip_moved: return True for item in Player.Backpack.Contains: if item.Serial in KNOWN_JUNK: continue # ---> THE FIX: Actively vacuum Dust Resources from Main Bag to Loot Bag <--- if item.ItemID in DUST_RESOURCES: dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True continue # If it is already sorted, skip the magic item checks if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5: continue if is_blessed_item(item): if item.Serial not in KNOWN_JUNK: KNOWN_JUNK.append(item.Serial) continue props = get_item_properties(item) if LOOT_MAGIC_ITEMS and is_equipment_loot(item, props): dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: # ---> THE FIX: Prevent infinite looping if full <--- VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True elif LOOT_DUSTABLES and is_dustable_item(item, props): dest_loot = GetSafeDest(LOOT_SOURCE_BAG) if item.Container != dest_loot: # ---> THE FIX: Prevent infinite looping if full <--- VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True else: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() return False def autoloot_tick(): if not AUTO_MOVE_GOLD and not USE_SKINNING and not LOOT_MAGIC_ITEMS and not LOOT_DUSTABLES: return False global opened_corpses, LOOTED_SERIALS, KNOWN_JUNK, VAULT_ATTEMPT_HISTORY, last_weight_warn if 'skull_sound_count' not in globals(): globals()['skull_sound_count'] = 0 globals()['last_skull_sound_time'] = 0 if time.time() - globals()['last_skull_sound_time'] > 5.0: globals()['skull_sound_count'] = 0 if Player.Backpack and get_container_count(Player.Backpack) >= 123: global last_supply_warn if time.time() - last_supply_warn > 5.0: Player.HeadMessage(33, "!!! BAG FULL (123/125) - LOOTING SUSPENDED !!!") last_supply_warn = time.time() return False is_overweight = False if Player.MaxWeight > 0 and Player.Weight >= Player.MaxWeight: is_overweight = True if time.time() - last_weight_warn > 5.0: Player.HeadMessage(33, "!!! MAX WEIGHT - IGNORING GEAR & RARES !!!") last_weight_warn = time.time() containers_to_loot = [] GLOBAL_CORPSE_FILTER.RangeMax = LOOT_RANGE for c in Items.ApplyFilter(GLOBAL_CORPSE_FILTER): containers_to_loot.append(c) if USE_CHEST_LOOT: GLOBAL_CHEST_FILTER.RangeMax = LOOT_RANGE for c in Items.ApplyFilter(GLOBAL_CHEST_FILTER): containers_to_loot.append(c) for container in containers_to_loot: if not SCRIPT_RUNNING: return False Misc.Pause(10) if container.Serial in opened_corpses and Player.DistanceTo(container) > LOOT_RANGE: opened_corpses.remove(container.Serial) if container.Serial not in opened_corpses: Items.WaitForContents(container, 300) opened_corpses.append(container.Serial) if len(opened_corpses) > 200: opened_corpses.pop(0) if getattr(container, 'IsCorpse', False): if process_corpse_resources(container): return True if not container.Contains: continue for item in container.Contains: if item.ItemID == SKULL_ID: if item.Serial in VAULT_ATTEMPT_HISTORY and (time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5): continue dest_vault = GetSafeDest(VAULT_BAG_SERIAL) VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND and globals()['skull_sound_count'] < 3: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) globals()['skull_sound_count'] += 1 globals()['last_skull_sound_time'] = time.time() Player.HeadMessage(66, "!!! SKULL SNIPED !!!") Items.Move(item.Serial, dest_vault, 0) Misc.Pause(150) return True for item in container.Contains: if not SCRIPT_RUNNING: return False if item.Serial in KNOWN_JUNK: continue if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 2.5: continue if is_blessed_item(item): KNOWN_JUNK.append(item.Serial) continue item_id = -1 try: item_id = int(item.ItemID) except: pass ignore_basic = [BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, 19218, TOOL_KIT_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS + IGNORED_ITEM_IDS if item_id in ignore_basic or "potion" in (item.Name or "").lower() or "tools_" in (item.Name or "").lower(): KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.pop(0) continue if AUTO_MOVE_GOLD and item_id == GOLD_ID: if item.Serial in LOOTED_SERIALS: continue dest_satchel = GetSafeDest(SATCHEL_SERIAL) LOOTED_SERIALS.append(item.Serial) if len(LOOTED_SERIALS) > 200: LOOTED_SERIALS.pop(0) Items.Move(item.Serial, dest_satchel, 0) Misc.Pause(600) return True props = get_item_properties(item) if item_id in HIGH_VALUE_IDS or is_valuable_item(item, props): if is_overweight: continue dest_vault = GetSafeDest(VAULT_BAG_SERIAL) VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) disp_name = item.Name or "Rare Item" try: plist = Items.GetPropStringList(item.Serial) if plist and len(plist) > 0: disp_name = str(p_list[0]) except: pass disp_name = re.sub(r'<[^>]+>', '', disp_name).strip() if disp_name.isdigit(): disp_name = "Rare Item" Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(disp_name)) Items.Move(item.Serial, dest_vault, 0) Misc.Pause(600) return True if LOOT_MAGIC_ITEMS and is_equipment_loot(item, props): if is_overweight: continue dest_loot = GetSafeDest(LOOT_SOURCE_BAG) VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True if LOOT_DUSTABLES and is_dustable_item(item, props): if is_overweight: continue dest_loot = GetSafeDest(LOOT_SOURCE_BAG) VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() Items.Move(item.Serial, dest_loot, 0) Misc.Pause(600) return True VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if not AUTO_MOVE_GOLD: return False GLOBAL_GOLD_FILTER.RangeMax = LOOT_RANGE gold_list = Items.ApplyFilter(GLOBAL_GOLD_FILTER) for g in gold_list: if not SCRIPT_RUNNING: return False if g.Serial in LOOTED_SERIALS: continue LOOTED_SERIALS.append(g.Serial) if len(LOOTED_SERIALS) > 200: LOOTED_SERIALS.pop(0) try: dest = GetSafeDest(SATCHEL_SERIAL) Items.Move(g.Serial, dest, 0) Misc.Pause(600) return True except: pass return False def check_gold_cleanup(): if not AUTO_MOVE_GOLD: return False if not Player.Backpack: return False if SATCHEL_SERIAL <= 0: return False gold_in_pack = Items.FindAllByID(GOLD_ID, -1, Player.Backpack.Serial, False) for gold in gold_in_pack: if gold.Container == SATCHEL_SERIAL: continue try: dest = GetSafeDest(SATCHEL_SERIAL) Items.Move(gold.Serial, dest, 0) Misc.Pause(150) return True except: pass loot_bag = Items.FindBySerial(LOOT_SOURCE_BAG) if loot_bag: gold_sub = Items.FindAllByID(GOLD_ID, -1, loot_bag.Serial, False) for g in gold_sub: dest = GetSafeDest(SATCHEL_SERIAL) Items.Move(g.Serial, dest, 0) Misc.Pause(150) return True return False def check_bank_deposit(): if not AUTO_BANK_GOLD: return False global last_bank_check_time if time.time() - last_bank_check_time < 15.0: return False last_bank_check_time = time.time() if not Player.Bank: return False gold_in_pack = Items.FindAllByID(GOLD_ID, -1, Player.Backpack.Serial, False) for g in gold_in_pack: Items.Move(g.Serial, Player.Bank.Serial, 0) return True if SATCHEL_SERIAL != 0: satchel_gold = Items.FindAllByID(GOLD_ID, -1, SATCHEL_SERIAL, False) for g in satchel_gold: Items.Move(g.Serial, Player.Bank.Serial, 0) return True return False def check_chivalry_logic(target=None): global LAST_CONSECRATE, LAST_DIVINE_FURY, last_chiv_time if not IS_CHIV or Player.IsGhost: return False if time.time() - last_chiv_time < 2.0: return False if Player.Poisoned: Target.Cancel() Player.HeadMessage(44, ">> Curing Poison <<") Player.ChatSay("[paladin 2") last_chiv_time = time.time() if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) return True if Player.BuffsExist("Curse") or Player.BuffsExist("Clumsy") or Player.BuffsExist("Weaken") or Player.BuffsExist("Feeblemind"): Target.Cancel() Player.HeadMessage(44, ">> Curing Curse <<") Player.ChatSay("[paladin 3") last_chiv_time = time.time() if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) return True if (Player.Hits * 100 / Player.HitsMax) <= 85: if Player.Mana >= 35: Player.ChatSay("[paladin 8") last_chiv_time = time.time() return True if Player.WarMode: if not Player.BuffsExist("Consecrate Weapon") and time.time() - LAST_CONSECRATE > 11.0: if Player.Mana >= 10: Player.HeadMessage(63, ">> Consecrate <<") Player.ChatSay("[paladin 9") last_chiv_time = time.time() LAST_CONSECRATE = time.time() return True if USE_DIVINE_FURY: if not Player.BuffsExist("Divine Fury") and time.time() - LAST_DIVINE_FURY > 16.0: if Player.Mana >= 10: Player.HeadMessage(63, ">> Divine Fury <<") Player.ChatSay("[paladin 7") last_chiv_time = time.time() LAST_DIVINE_FURY = time.time() return True return False def check_golem_repair(): global LAST_GOLEM_REPAIR if time.time() - LAST_GOLEM_REPAIR < 4.0: return False golem = None golem_bodies = [0x0260, 0x02F0, 705, 752, 763] for s in SPECIFIC_PET_SERIAL: mob = Mobiles.FindBySerial(s) if mob and mob.Body in golem_bodies: if mob.Hits < mob.HitsMax: golem = mob break if not golem: GLOBAL_MOB_FILTER.RangeMax = 12 for mob in Mobiles.ApplyFilter(GLOBAL_MOB_FILTER): if mob.Body in golem_bodies and mob.Notoriety == 2: if mob.Hits < mob.HitsMax: golem = mob break if golem and Player.DistanceTo(golem) <= 2: kit = Items.FindByID(19218, -1, Player.Backpack.Serial, True) if not kit: kit = Items.FindByID(TOOL_KIT_ID, -1, Player.Backpack.Serial, True) if kit: if Player.WarMode: if 'golem_cycle' not in globals(): globals()['golem_cycle'] = 0 globals()['golem_cycle'] += 1 if globals()['golem_cycle'] >= 2: Player.HeadMessage(66, ">>> GOLEM WAKE UP: ALL GUARD ME <<<") Player.ChatSay(33, "All Guard Me") Misc.Pause(250) globals()['golem_cycle'] = 0 Target.Cancel() Player.HeadMessage(66, ">> REPAIRING GOLEM <<") Items.UseItem(kit.Serial) LAST_GOLEM_REPAIR = time.time() if Target.WaitForTarget(1500, False): Target.TargetExecute(golem.Serial) return True return False def check_enhanced_pet_healing(): if not USE_ENHANCED_HEALING or not IS_MAGE or not USE_PET_HEAL: return False global last_heal_time if Player.IsGhost: return False self_hp_percent = (Player.Hits * 100) / Player.HitsMax if Player.HitsMax > 0 else 100 if USE_SELF_HEAL and (self_hp_percent < SELF_HEAL_TRIGGER or Player.Poisoned or Player.BuffsExist("Bleed")): return False if time.time() - last_heal_time < 0.5: return False if Player.Mana < 11: return False for serial in SPECIFIC_PET_SERIAL: pet = Mobiles.FindBySerial(serial) if not pet or pet.IsGhost: continue if pet.HitsMax <= 0: continue if pet.Poisoned: continue hp_percent = (pet.Hits * 100) / pet.HitsMax dist = Player.DistanceTo(pet) needs_burst = hp_percent < 40 needs_range = (hp_percent < SAFE_TO_VET_HP_TRIGGER) and (dist > VET_RANGE) and (dist <= 12) if needs_burst or needs_range: if not can_cast_spell("Greater Heal"): return False p_name = PET_MAPPING.get(serial, pet.Name) Player.HeadMessage(63, ">> ENHANCED HEAL: {} <<".format(p_name)) Spells.Cast("Greater Heal") if Target.WaitForTarget(1500, False): Target.TargetExecute(pet.Serial) last_heal_time = time.time() return True return False def decide_healing(): global next_allowed_heal_time, next_allowed_vet_time, next_vet_kit_time, vet_cycle_count global last_attacked_serial, last_rescue_time, pet_rez_timers, PET_HEAL_METHOD if not Player or Player.HitsMax == 0: return False if (IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0) and (Player.Hits * 100 / Player.HitsMax) < RESCUE_HP_TRIGGER: if time.time() - last_rescue_time > 3.0: if IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0: Player.HeadMessage(33, "!!! RESCUE ME !!!") Player.ChatSay(33, "All Guard Me") last_rescue_time = time.time() return True if (IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0) and USE_PET_HEAL: if time.time() >= next_vet_kit_time: pets_hurt = False if PET_HEAL_METHOD in ["Both", "Kit"]: for s in SPECIFIC_PET_SERIAL: pet = Mobiles.FindBySerial(s) if pet and pet.Hits < pet.HitsMax and Player.DistanceTo(pet) <= 2 and pet.Body not in [0x0260, 0x02F0, 705, 752, 763]: pets_hurt = True break if pets_hurt: kit = Items.FindByID(VET_KIT_ID, -1, Player.Backpack.Serial, True) if kit: Player.HeadMessage(55, ">>> VET KIT (AOE) <<<") Items.UseItem(kit.Serial) next_vet_kit_time = time.time() + VET_KIT_DELAY return True for serial in SPECIFIC_PET_SERIAL: p = Mobiles.FindBySerial(serial) if p and p.IsGhost: if time.time() >= pet_rez_timers.get(p.Serial, 0): bandages = Items.FindByID(BANDAGE_ID, -1, Player.Backpack.Serial, True) if bandages: Target.Cancel() p_name = PET_MAPPING.get(p.Serial, p.Name) Player.HeadMessage(33, "!!! RESURRECTING {} !!!".format(p_name)) Items.UseItem(bandages.Serial) pet_rez_timers[p.Serial] = time.time() + 10.0 if Target.WaitForTarget(1500, False): Target.TargetExecute(p.Serial) return True if time.time() >= next_allowed_vet_time and PET_HEAL_METHOD in ["Both", "Bands"]: injured_pet = get_injured_pet() if injured_pet: bandages = Items.FindByID(BANDAGE_ID, -1, Player.Backpack.Serial, True) if bandages: if Player.WarMode: vet_cycle_count += 1 if vet_cycle_count >= 2: if IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0: Player.HeadMessage(66, ">>> WAKE UP TRIGGER: ALL GUARD ME <<<") Player.ChatSay(33, "All Guard Me") Misc.Pause(250) vet_cycle_count = 0 else: vet_cycle_count = 0 Target.Cancel() p_name = injured_pet.Name if injured_pet.Serial in PET_MAPPING: p_name = PET_MAPPING[injured_pet.Serial] Player.HeadMessage(53, "+++ VETTING: {} +++".format(p_name)) Items.UseItem(bandages.Serial) next_allowed_vet_time = time.time() + VET_DELAY_SECONDS if Target.WaitForTarget(1500, False): Target.TargetExecute(injured_pet.Serial) return True has_healing_skill = Player.GetSkillValue("Healing") >= 50 if has_healing_skill and IS_DEXTER and time.time() >= next_allowed_heal_time and USE_SELF_HEAL: hp_percent = (Player.Hits * 100) / Player.HitsMax if Player.HitsMax > 0 else 100 bandage_trigger = SELF_BANDAGE_HP_TRIGGER if (hp_percent < bandage_trigger or Player.Poisoned or Player.BuffsExist("Bleed")): bandages = Items.FindByID(BANDAGE_ID, -1, Player.Backpack.Serial, True) if bandages: Target.Cancel() Player.HeadMessage(63, "+++ BANDAGING SELF +++") Items.UseItem(bandages.Serial) next_allowed_heal_time = time.time() + SELF_BANDAGE_DELAY if Target.WaitForTarget(1500, False): Target.Self() return True return False def check_self_cure(): if not IS_MAGE or not USE_SELF_HEAL: return False global last_cure_time if not Player.Poisoned: return False if not USE_ARCH_CURE: return False if time.time() - last_cure_time > 0.75: if Player.Mana < 15: Player.HeadMessage(33, "!!! OOM - CANNOT CURE !!!") last_cure_time = time.time() return False spell_to_cast = "Arch Cure" if not can_cast_spell(spell_to_cast): Player.HeadMessage(33, "!!! OUT OF REAGENTS FOR CURE !!!") last_cure_time = time.time() + 5.0 return False Player.HeadMessage(55, ">>> SPELL: {} <<<".format(spell_to_cast)) Spells.Cast(spell_to_cast) if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) Misc.Pause(50) last_cure_time = time.time() return True return False def check_self_heal(): if not IS_MAGE or not USE_SELF_HEAL: return False global last_heal_time, is_recovering_health if Player.Poisoned: return False if not Player or Player.HitsMax == 0: return False hp_percent = (Player.Hits * 100) / Player.HitsMax trigger = SELF_HEAL_TRIGGER if hp_percent < trigger: is_recovering_health = True if hp_percent >= 100: is_recovering_health = False if is_recovering_health: spell_to_cast = "Greater Heal" cooldown = 1.0 if hp_percent >= 75: spell_to_cast = "Heal" cooldown = 0.5 if time.time() - last_heal_time > cooldown: mana_cost = 4 if spell_to_cast == "Heal" else 11 if Player.Mana < mana_cost: Player.HeadMessage(33, "!!! OOM - CANNOT HEAL !!!") last_heal_time = time.time() + 1.0 return False if not can_cast_spell(spell_to_cast): Player.HeadMessage(33, "!!! OUT OF REAGENTS FOR HEAL !!!") last_heal_time = time.time() + 5.0 return False Player.HeadMessage(63, "+++ SELF HEALING ({}%) [{}] +++".format(int(hp_percent), spell_to_cast)) Spells.Cast(spell_to_cast) if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) Misc.Pause(50) last_heal_time = time.time() return True return False def check_pet_cure(): if not PET_CURE_POISON or not USE_PET_HEAL: return False if not IS_MAGE: return False if USE_SELF_HEAL and Player.HitsMax > 0 and (Player.Hits * 100) / Player.HitsMax < RESCUE_HP_TRIGGER: return False global last_pet_cure_time if time.time() - last_pet_cure_time < 2.5: return False for serial in SPECIFIC_PET_SERIAL: pet = Mobiles.FindBySerial(serial) if not pet: continue if pet.Poisoned: if not can_cast_spell("Arch Cure"): Player.HeadMessage(33, "!!! OUT OF REAGENTS FOR CURE !!!") last_pet_cure_time = time.time() + 5.0 return False p_name = pet.Name if serial in PET_MAPPING: p_name = PET_MAPPING[serial] Player.HeadMessage(55, "!!! CURING PET: {} !!!".format(p_name)) Spells.Cast("Arch Cure") last_pet_cure_time = time.time() if Target.WaitForTarget(1500, False): Target.TargetExecute(pet.Serial) Misc.Pause(150) return True return False def IsPlayer(mob): if not mob: return False if mob.Serial == Player.Serial: return True props = get_mobile_properties(mob) is_p = False if mob.Body in PLAYER_BODIES: is_p = True if mob.Notoriety == 5: if not any(k in props for k in ["barding level", "difficulty", "type:"]): is_p = True if any(k in props for k in ["barding level", "difficulty", "type:"]): is_p = False return is_p def get_priority_target(): global CURRENT_ACTION, MOBILE_PROP_CACHE t = Target.GetLast() if t and t != Player.Serial: mob = Mobiles.FindBySerial(t) if mob and not getattr(mob, 'IsGhost', False) and mob.Hits > 0: if Player.DistanceTo(mob) <= (GUARD_RANGE + 2): if mob.Serial not in SPECIFIC_PET_SERIAL: if mob.Serial in MOBILE_PROP_CACHE: MOBILE_PROP_CACHE.pop(mob.Serial) props = get_mobile_properties(mob).lower() if "invulnerable" in props: pass elif mob.Notoriety in [1, 2]: pass elif IsPlayer(mob) and mob.Notoriety == 5: return mob elif IsPlayer(mob): pass else: return mob else: Target.SetLast(Player.Serial) if not AUTO_FARM_MODE: return None GLOBAL_DANGER_FILTER.RangeMax = GUARD_RANGE targets = Mobiles.ApplyFilter(GLOBAL_DANGER_FILTER) valid_targets = [] for t in targets: if t.Serial in SPECIFIC_PET_SERIAL: continue if t.Serial in MOBILE_PROP_CACHE: MOBILE_PROP_CACHE.pop(t.Serial) props = get_mobile_properties(t).lower() if "invulnerable" in props: continue if IsPlayer(t): continue t_name = (t.Name or "").lower() is_whitelisted = False for w_name in WHITE_LIST_BY_NAME: if w_name in t_name: is_whitelisted = True break if not is_whitelisted: valid_targets.append(t) if valid_targets: if IS_DEXTER and not IS_ARCHER: for t in valid_targets: if Player.DistanceTo(t) <= 2: Target.SetLast(t.Serial) return t sorted_targets = sorted(valid_targets, key=lambda x: Player.DistanceTo(x)) Target.SetLast(sorted_targets[0].Serial) return sorted_targets[0] return None def do_bard_logic(target): if not IS_BARD or not target: return False if Player.IsGhost: return False global next_bard_time if time.time() < next_bard_time: return False if Player.GetSkillValue("Discordance") >= 80 and Player.GetSkillValue("Musicianship") >= 80: if not Player.BuffsExist("Discordance") and not Player.BuffsExist("Silence"): Player.ChatSay("[DiscordAura") next_bard_time = time.time() + 2.0 return True song_to_cast = "[EternalSonata" song_buff = "Eternal Sonata" if not Player.BuffsExist(song_buff) and not Player.BuffsExist("Silence"): Player.HeadMessage(55, ">> Singing: {} <<".format(song_buff)) Player.ChatSay(song_to_cast) next_bard_time = time.time() + 2.0 return True instrument = None if Player.Backpack: for item in Player.Backpack.Contains: if item.ItemID in INSTRUMENT_IDS: instrument = item break if not instrument: return False if DISCORD_MODE != "Off" and Player.GetSkillValue("Discordance") > 50: if DISCORD_MODE == "SingleTarget": Player.HeadMessage(63, ">> DISCORD: {} <<".format(target.Name)) Player.UseSkill("Discordance") next_bard_time = time.time() + BARD_DELAY if Target.WaitForTarget(1000, False): Target.TargetExecute(target.Serial) return True if PEACE_MODE != "Off" and Player.GetSkillValue("Peacemaking") > 50: if PEACE_MODE == "AoE": Player.HeadMessage(53, ">> PEACE (AOE) <<") Player.UseSkill("Peacemaking") next_bard_time = time.time() + BARD_DELAY if Target.WaitForTarget(1000, False): Target.TargetExecute(Player.Serial) return True elif PEACE_MODE == "SingleTarget": Player.HeadMessage(53, ">> PEACE: {} <<".format(target.Name)) Player.UseSkill("Peacemaking") next_bard_time = time.time() + BARD_DELAY if Target.WaitForTarget(1000, False): Target.TargetExecute(target.Serial) return True return False def check_auto_bomber(target): global last_bomb_time, USE_AUTO_BOMBER if not USE_AUTO_BOMBER: return False if 'last_bomb_time' not in globals(): globals()['last_bomb_time'] = 0 if not target or Player.IsGhost: return False if time.time() - last_bomb_time < 5.0: return False if Player.DistanceTo(target) > 8: return False bomb = Items.FindByID(0x0F0D, -1, Player.Backpack.Serial, True) if bomb: Player.HeadMessage(38, ">> THROWING BOMB <<") Items.UseItem(bomb.Serial) if Target.WaitForTarget(1500, False): Target.TargetExecute(target.Serial) last_bomb_time = time.time() return True return False def update_hologram_hud(target): if not SHOW_HOLOGRAM_HUD: return if not target: return if getattr(target, 'HitsMax', 0) <= 0: return global last_known_hp, last_hud_target_serial hp_percent = int((target.Hits * 100) / target.HitsMax) if (target.Serial == last_hud_target_serial) and (hp_percent == last_known_hp): return last_known_hp = hp_percent last_hud_target_serial = target.Serial hud_color = 63 if hp_percent < 70: hud_color = 53 if hp_percent < 30: hud_color = 33 bars = int(hp_percent / 10) hud_text = "[{}{}] {}%".format("|" * bars, " " * (10 - bars), hp_percent) Mobiles.Message(target.Serial, hud_color, hud_text) def show_fancy_overhead(target): if not SHOW_TARGET_OVERHEAD or not target: return if getattr(target, 'HitsMax', 0) <= 0: return if target.Serial != getattr(sys.modules[__name__], 'last_overhead_serial', 0): Mobiles.Message(target.Serial, TARGET_OVERHEAD_HUE, TARGET_OVERHEAD_MSG) setattr(sys.modules[__name__], 'last_overhead_serial', target.Serial) def get_item_properties(item): global ITEM_PROP_CACHE if item.Serial in ITEM_PROP_CACHE: return ITEM_PROP_CACHE[item.Serial] text = (item.Name or "").lower() + " " try: props = Items.GetPropStringList(item.Serial) if props: for p in props: text += str(p).lower() + " " except: pass clean_text = re.sub(r'<[^>]+>', '', text) clean_text = clean_text.replace('\n', ' ').replace('\r', ' ') ITEM_PROP_CACHE[item.Serial] = clean_text return clean_text def is_blessed_item(item): try: if not item: return False if item.Hue in BLESSED_ITEM_HUES: return True props = get_item_properties(item) p_str = str(props).lower() safe_words = ["blessed", "insured", "insure", "bound", "newbified"] if any(word in p_str for word in safe_words) and "bless deed" not in p_str: return True name = (item.Name or "").lower() safe_names = ["shepherd's crook"] if any(word in name for word in safe_names) or any(word in name for word in safe_words): return True except: pass return False def main(): InitSavedPets() # ---> FIX: Load saved bags from memory on startup <--- global LOOT_SOURCE_BAG, VAULT_BAG_SERIAL, SATCHEL_SERIAL if Misc.CheckSharedValue("LOOT_SOURCE_BAG"): LOOT_SOURCE_BAG = Misc.ReadSharedValue("LOOT_SOURCE_BAG") if Misc.CheckSharedValue("VAULT_BAG_SERIAL"): VAULT_BAG_SERIAL = Misc.ReadSharedValue("VAULT_BAG_SERIAL") if Misc.CheckSharedValue("SATCHEL_SERIAL"): SATCHEL_SERIAL = Misc.ReadSharedValue("SATCHEL_SERIAL") global last_button_id try: gd = Gumps.GetGumpData(GUMP_ID) if gd and getattr(gd, 'buttonid', 0) > 0: last_button_id = gd.buttonid except: pass try: Gumps.CloseGump(8888) tome_gd = Gumps.GetGumpData(8888) if tome_gd and getattr(tome_gd, 'buttonid', -1) > 0: globals()['last_tome_button_id'] = tome_gd.buttonid else: globals()['last_tome_button_id'] = -1 except: globals()['last_tome_button_id'] = -1 SmartDetectBuild() SmartDetectMastery() Player.HeadMessage(90, ">>> DOMINATION GUI LOADED <<<") CheckAndDrawGUI(force=True) global last_scan_msg_time, has_issued_guard_command, last_rescue_time, last_war_mode_state global last_peel_time, last_player_hits, last_build_check_time last_rescue_time = 0 last_peel_time = 0 last_build_check_time = 0 last_player_hits = Player.HitsMax if Player else 0 last_war_mode_state = Player.WarMode if Player else False while True: poll_buttons() CheckChatCommands() check_server_captcha() check_buff_timers() process_arpg_hud() track_equipment() if time.time() - last_build_check_time > 3.0: SmartDetectBuild() SmartDetectMastery() last_build_check_time = time.time() if Player.IsGhost: CURRENT_ACTION = "Dead (Ghost)" CheckAndDrawGUI() Misc.Pause(1000) continue if not SCRIPT_RUNNING: CURRENT_ACTION = "Paused" CheckAndDrawGUI() Misc.Pause(200) continue action_taken = False if not action_taken and check_potions(): action_taken = True if not action_taken and check_self_cure(): action_taken = True if not action_taken and check_pet_cure(): action_taken = True if not action_taken and check_self_heal(): action_taken = True if not action_taken and check_enhanced_pet_healing(): action_taken = True if not action_taken and decide_healing(): action_taken = True if not action_taken and check_chivalry_logic(None): action_taken = True if not action_taken and check_magery_buffs(): action_taken = True if USE_SELF_HEAL and Player.HitsMax > 0 and ((Player.Hits * 100) / Player.HitsMax) < 90: pass if not action_taken and check_golem_repair(): action_taken = True if not action_taken and check_anti_disarm(): action_taken = True check_auto_meditation() check_weight_alarm() check_supplies() if not action_taken and check_auto_potions(): action_taken = True if not action_taken and check_auto_petals(): action_taken = True if not action_taken and auto_lockpick(): action_taken = True if not action_taken and autoloot_tick(): action_taken = True if not action_taken and check_gold_cleanup(): action_taken = True if not action_taken and check_bank_deposit(): action_taken = True if not action_taken and check_bag_sorting(): action_taken = True update_mastery_stats() if time.time() - globals().get('last_chore_time', 0) > 1.0: update_pet_levels() globals()['last_chore_time'] = time.time() if USE_AUTO_ENGAGE and not Player.WarMode and AUTO_FARM_MODE: auto_target = get_priority_target() if auto_target: Player.HeadMessage(33, ">>> AUTO-ENGAGE TRIGGERED <<<") Player.SetWarMode(True) Misc.Pause(100) current_war_mode = Player.WarMode if current_war_mode != last_war_mode_state: last_war_mode_state = current_war_mode if current_war_mode: if IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0: Player.ChatSay(33, "All Guard Me") has_issued_guard_command = True else: if IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0: Player.ChatSay(33, "All Follow Me") has_issued_guard_command = False Misc.Pause(100) if current_war_mode: attack_and_guard() else: CURRENT_ACTION = "Idle / Looting" CheckAndDrawGUI() Misc.Pause(REFRESH_MS) def attack_and_guard(): global has_issued_guard_command, last_attacked_serial, last_attack_packet_time, CURRENT_ACTION global last_chore_time, last_rescue_time if not Player.WarMode: last_attacked_serial = 0 CURRENT_ACTION = "Idle" CheckAndDrawGUI(force=True) return poll_buttons() if not SCRIPT_RUNNING: return target = get_priority_target() if target: CURRENT_ACTION = "Attacking " + target.Name target_serial = target.Serial if (IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0) and not has_issued_guard_command: Player.ChatSay(33, "All Guard Me") has_issued_guard_command = True if last_attacked_serial != target_serial: Player.Attack(target) if IS_TAMER or len(SPECIFIC_PET_SERIAL) > 0: Target.Cancel() Player.HeadMessage(63, ">> COMMANDING PETS TO KILL <<") Player.ChatSay(63, "All Kill") if Target.WaitForTarget(1000, False): Target.TargetExecute(target_serial) Misc.Pause(100) if Target.HasTarget(): Target.Cancel() last_attacked_serial = target_serial last_attack_packet_time = time.time() Player.HeadMessage(44, ">> ENGAGING: {} <<".format(target.Name)) elif time.time() - last_attack_packet_time > 0.5: Player.Attack(target) last_attack_packet_time = time.time() while True: if Player.IsGhost: last_attacked_serial = 0 break poll_buttons() if not SCRIPT_RUNNING: return if not Player.WarMode: last_attacked_serial = 0 break action_taken = False if not action_taken and check_potions(): action_taken = True if not action_taken and check_self_cure(): action_taken = True if not action_taken and check_pet_cure(): action_taken = True if not action_taken and check_self_heal(): action_taken = True if not action_taken and check_enhanced_pet_healing(): action_taken = True if not action_taken and decide_healing(): action_taken = True if not action_taken and check_chivalry_logic(target): action_taken = True if not action_taken and check_magery_buffs(): action_taken = True if USE_SELF_HEAL and Player.HitsMax > 0 and ((Player.Hits * 100) / Player.HitsMax) < 90: pass if not action_taken and do_bard_logic(target): action_taken = True if not action_taken and check_taunt(target): action_taken = True if not action_taken and check_golem_repair(): action_taken = True if not action_taken and check_smart_poison(target): action_taken = True if not action_taken and check_anti_disarm(): action_taken = True if not action_taken and check_pet_recall(): action_taken = True if not action_taken and check_auto_bomber(target): action_taken = True if not action_taken and check_auto_potions(): action_taken = True if not action_taken and check_auto_petals(): action_taken = True check_supplies() check_weight_alarm() check_auto_meditation() check_server_captcha() check_buff_timers() process_arpg_hud() track_equipment() if time.time() - globals().get('last_chore_time', 0) > 1.0: update_pet_levels() globals()['last_chore_time'] = time.time() CheckChatCommands() if not SCRIPT_RUNNING: return show_fancy_overhead(target) update_hologram_hud(target) current_target = Mobiles.FindBySerial(target_serial) target_lost = False is_manual = False try: if Target.GetLast() == target_serial: is_manual = True except: pass allowed_dist = (GUARD_RANGE * 2) if is_manual else GUARD_RANGE if not current_target: target_lost = True elif current_target.Hits <= 0: target_lost = True elif Player.DistanceTo(current_target) > allowed_dist: target_lost = True else: if current_target.Serial in MOBILE_PROP_CACHE: MOBILE_PROP_CACHE.pop(current_target.Serial) c_props = get_mobile_properties(current_target).lower() if "invulnerable" in c_props: target_lost = True if not AUTO_FARM_MODE: new_manual = Target.GetLast() if new_manual and new_manual != target_serial: chk = Mobiles.FindBySerial(new_manual) if chk: if chk.Serial == Player.Serial: pass elif chk.Serial in SPECIFIC_PET_SERIAL: pass elif chk.Notoriety in [1, 2]: pass else: target_lost = True if target_lost: Target.SetLast(Player.Serial) last_attacked_serial = 0 has_issued_guard_command = False Misc.Pause(150) break if current_target and current_target.Hits > 0: if not action_taken and time.time() - last_attack_packet_time > 0.5: Player.Attack(target_serial) last_attack_packet_time = time.time() Misc.Pause(150) else: CURRENT_ACTION = "Scanning" CheckAndDrawGUI() if __name__ == "__main__": main() # --- END OF SCRIPT ---