""" ================================================================== SCRIPT: COMPLETE DOMINATION (OFFICIAL MASTER RELEASE) AUTHOR: Evilrage WEBSITE: unchainedscripts.com ================================================================== THE ULTIMATE ALL-IN-ONE COMBAT & UTILITY ENGINE FOR UO UNCHAINED. FEATURES: - 🧠 SMART TEMPLATE DETECTION: Auto-swaps UI based on your active skills. - 🛡️ CRASH-PROOF MEMORY CORE: Remembers your bags and settings across reboots. - ⚔️ BULLETPROOF ANTI-DISARM: Instantly re-equips weapons & shields. - 🧘 AUTO-MEDITATION: Strips non-medable armor, meditates, and re-equips. - 🧪 THE ALCHEMIST: Auto-chugs stats/refresh pots and eats colored petals. - 🐾 BEASTMASTER UI: Dynamic pet status, mastery tracking, and 3-way healing. - 🎒 AUTO-LOOT & SORT: Intelligently routes gold, rares, and magic gear. ================================================================== """ import sys import Misc import Items import Player import Target import Mobiles import Journal import Spells import Gumps import time import re from System.Collections.Generic import List from System import Byte, Int32 # ========================================================== # >>> BUFF & PETAL IDs <<< # ========================================================== STR_POTION_ID = 0x0F09 DEX_POTION_ID = 0x0F08 REFRESH_POTION_ID = 0x0F0B PETAL_ID = 0x1021 ORANGE_PETAL_HUE = 0x002B DISSIDIA_PETAL_HUE = 0x082B MINOC_PETAL_HUE = 0x07C6 MOONGLOW_PETAL_HUE = 0x0B40 # ========================================================== # >>> MASTERY DICTIONARIES <<< # ========================================================== MASTERY_PET_NAMES = { "Fira": "Lava Elemental", "Earth": "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 Ox" } KNOWN_MASTERIES = [ "Fira", "Earth", "Aero", "Blood", "Doom", "Lyrical", "Fortune", "Poison", "Shadow", "Holy", "Bulwark", "Void", "Command", "Ranger", "Berserker", "Druidic", "Tinkering", "Alchemy" ] # ========================================================== # >>> GLOBAL DEFINITIONS <<< # ========================================================== MIN_MANA_CHIV = 10 IS_CHIV = True PLAYER_BODIES = [400, 401, 605, 606, 666, 667] # ========================================================== # >>> STICKY MEMORY CONFIGURATION <<< # ========================================================== SPECIFIC_PET_SERIAL = [] PET_MAPPING = {} SPECIFIC_PET_BODIES = [0x002E, 0x058E, 0x0260, 0x02F0] PET_DATA_CACHE = {} SATCHEL_SERIAL = Misc.ReadSharedValue("SATCHEL_SERIAL") if Misc.CheckSharedValue("SATCHEL_SERIAL") else 0 VAULT_BAG_SERIAL = Misc.ReadSharedValue("VAULT_BAG_SERIAL") if Misc.CheckSharedValue("VAULT_BAG_SERIAL") else 0 LOOT_SOURCE_BAG = Misc.ReadSharedValue("LOOT_SOURCE_BAG") if Misc.CheckSharedValue("LOOT_SOURCE_BAG") else 0 ACTIVE_MASTERY = Misc.ReadSharedValue("ACTIVE_MASTERY") if Misc.CheckSharedValue("ACTIVE_MASTERY") else "Waiting..." PET_HEAL_METHOD = Misc.ReadSharedValue("PET_HEAL_METHOD") if Misc.CheckSharedValue("PET_HEAL_METHOD") else "Both" FRIEND_SERIALS = [] NAME_OVERRIDES = { 0x5C3EF: "Draconus", 0x88171: "Bloody" } # ========================================================== # SETTINGS # ========================================================== SCRIPT_RUNNING = False USE_SKINNING = False USE_SCISSORS = True USE_BLESS = True USE_POTIONS = True AUTO_FARM_MODE = True AUTO_BANK_GOLD = True AUTO_MOVE_GOLD = True LOOT_MAGIC_ITEMS = True USE_DIVINE_FURY = False USE_MAGERY_BUFFS = False USE_TAUNT = False USE_LOCKPICKING = False USE_ENHANCED_HEALING = False USE_PARTY_HEAL = False USE_AUTO_WAND = False USE_POUCHES = False USE_SMART_POISON = False USE_AUTO_BUFFS = False USE_AUTO_PETALS = False USE_ARCH_CURE = True USE_SELF_HEAL = True PET_CURE_POISON = True HAS_100_LRC = False # --- CLASS SETTINGS --- USE_CHIVALRY = True MIN_MARKS_BUFF = 80 MIN_MARKS_CURE = 10 REPAIR_GOLEM_AT_HP = 60 RESCUE_HP_TRIGGER = 60 PEACE_MODE = "AoE" DISCORD_MODE = "SingleTarget" BARD_DELAY = 10 SELF_BANDAGE_HP_TRIGGER = 90 SAFE_TO_VET_HP_TRIGGER = 85 SELF_HEAL_TRIGGER = 85 POTION_HEAL_TRIGGER = 40 SELF_HEAL_SPELL = "Greater Heal" # --- TOOLS --- SKINNING_TOOL_IDS = [0x0EC4, 0x0F52, 0x0F51, 0x13F6] SCISSORS_ID = 3999 BANDAGE_ID = 0x0E21 VET_KIT_ID = 27539 TOOL_KIT_ID = 0x1EB8 GOLD_ID = 0x0EED HIDES_ID = 0x1079 LEATHER_ID = 0x1081 INSTRUMENT_IDS = [0x0EB1, 0x0EB2, 0x0EB3, 0x0EB4, 0x0E9C, 0x0E9D, 0x0E9E, 0x2805] WAND_ID = 20497 # REAGENT IDS REG_GARLIC = 0x0F84 REG_GINSENG = 0x0F85 REG_MANDRAKE = 0x0F86 REG_SILK = 0x0F8D REG_ASH = 0x0F8C REG_PEARL = 0x0F7A REG_MOSS = 0x0F7B REG_SHADE = 0x0F88 REAGENT_IDS = [REG_GARLIC, REG_GINSENG, REG_MANDRAKE, REG_SILK, REG_ASH, REG_PEARL, REG_MOSS, REG_SHADE] POTION_IDS = [0x0F06, 0x0F07, 0x0F08, 0x0F09, 0x0F0A, 0x0F0B, 0x0F0C, 0x0F0D] IGNORED_ITEM_IDS = [8786, 0x2252, 8787, 0x2253, 10135, 0x0F9E] # SHELF CONFIG STORAGE_SHELF_ID = 44993 ENCHANT_SHELF_ID = 48347 SAFE_GRAPHICS = [0x280B, 0x280C, 0x0E40] # Known graphics for Maps, Scrolls, Orbs, Dyes, and Skulls T_MAP_ID = 0x63E8 DYE_ID = 0x71B0 SKULL_ID = 43445 HIGH_VALUE_IDS = [0x14F0, 0x14EC, 0x2260, 0x0E34, 0x0FF0, 0x14EB, 0x099F, 0x0FA9, 0x0FAB, 0x0F03, 0x5740, 0x097B, 0x2260, T_MAP_ID, DYE_ID, SKULL_ID] VAULT_TARGET_IDS = [ 0x13EC, 0x1415, 0x1411, 0x1414, 0x1413, 0x2779, 0x140A, 0x140C, 0x140E, 0x1408, 0x1412, 0x1C04, 0x1410, 0x13BF, 0x13BE, 0x13BB, 0x13C0, 0x13C3, 0x13C4, 0x13F0, 0x1B72, 0x1B7B, 0x1B73, 0x144E, 0x1B7A, 0x1B79, 0x1450, 0x1452, 0x144F, 0x1451, 0x1F0B, 0x13C0, 0x13C3, 0x13C4, 0x13EE, 0x13F0, 0x13EB, 0x13C7, 0x13DB, 0x13D4, 0x13DA, 0x13D6, 0x279D, 0x13D5, 0x13DC, 0x1C0C, 0x1C02, 0x13CD, 0x13CB, 0x13CC, 0x13C6, 0x1DB9, 0x1C08, 0x1C06, 0x277A, 0x1C00, 0x1C0A, 0x0F49, 0x0F47, 0x0F4B, 0x0F45, 0x0F43, 0x13FB, 0x1443, 0x13B0, 0x0F5E, 0x1441, 0x13FF, 0x0F61, 0x13B6, 0x13B9, 0x13B4, 0x143D, 0x0F5C, 0x143B, 0x1439, 0x1407, 0x0DF0, 0x13F8, 0x0E89, 0x0EC3, 0x0EC4, 0x13F6, 0x0F52, 0x0F62, 0x1403, 0x1405, 0x1401, 0x13B2, 0x13B1, 0x26C2, 0x0F50, 0x13FD, 0x26C3, 0x2D1F, 0x1B72, 0x1B73, 0x1B74, 0x1B75, 0x1B76, 0x1B77, 0x1B78, 0x1B79, 0x1B7A, 0x1B7B, 0x1BC3, 0x1BC4, 0x48B2, 0x48B4, 0x48B0, 0x48C6, 0x48B6, 0x48AE, 0x0902, 0x48D0, 0x48B8, 0x48BA, 0x48BC, 0x48CA, 0x48C2, 0x48C8, 0x48C4, 0x0908, 0x48CE, 0x48CC, 0x48C0 ] # --- SYSTEM VARIABLES --- GUARD_RANGE = 12 LOOT_RANGE = 3 VET_RANGE = 3 WARN_AT_WEIGHT = 10 WARN_LOW_BANDAGES = 25 WARN_LOW_REAGENTS = 20 SELF_BANDAGE_DELAY = 5 VET_DELAY_SECONDS = 4 POTION_COOLDOWN = 10 VET_KIT_DELAY = 8 IS_TAMER = False IS_DEXTER = False IS_MAGE = False IS_BARD = False IS_PALADIN = False IS_TINKER = False IS_LOCKPICKER = False IS_POISONER = False CURRENT_ACTION = "Idle" DETECTED_BUILD = "Unknown" GUMP_ID = 589431 REFRESH_MS = 200 SESSION_GOLD_LOOTED = 0 GUI_MINIMIZED = False LAST_GUI_HASH = 0 LAST_DRAW_TIME = 0 DRAW_INTERVAL = 0.5 last_button_id = 0 LOOTED_SERIALS = [] MASTERY_DATA = { "Type": ACTIVE_MASTERY, "Current": 0, "Max": 0, "Percent": 0.0 } SHOW_HOLOGRAM_HUD = True SHOW_TARGET_OVERHEAD = True TARGET_OVERHEAD_MSG = "▼▼ DESTROY ▼▼" TARGET_OVERHEAD_HUE = 33 PLAY_VAULT_SOUND = True VAULT_SOUND_ID = 0x5B4 next_allowed_heal_time = 0 next_allowed_vet_time = 0 next_vet_kit_time = 0 next_bard_time = 0 last_cure_time = 0 last_heal_time = 0 last_pet_cure_time = 0 last_bank_check_time = 0 last_bless_time = 0 last_scan_msg_time = 0 last_weight_warn = 0 last_supply_warn = 0 last_overhead_time = 0 last_attack_time = 0 last_heal_potion_time = 0 last_cure_potion_time = 0 last_reg_check_time = 0 last_chiv_time = 0 last_repair_time = 0 last_magery_buff_time = 0 last_taunt_time = 0 last_wand_time = 0 last_pouch_time = 0 last_poison_time = 0 last_build_check_time = 0 # Buff Engine Variables last_str_pot_time = 0 last_dex_pot_time = 0 last_refresh_pot_time = 0 last_orange_petal_time = 0 last_dissidia_petal_time = 0 last_minoc_petal_time = 0 last_moonglow_petal_time = 0 is_recovering_health = False has_issued_guard_command = False last_attacked_serial = 0 # --- MEMORY LISTS --- skinned_corpses = [] opened_corpses = [] vet_cycle_count = 0 pet_rez_timers = {} KNOWN_JUNK = [] last_vault_scan_time = 0 last_hud_update_time = 0 last_known_hp = -1 last_hud_target_serial = 0 last_attack_packet_time = 0 last_chore_time = 0 last_rescue_time = 0 LAST_PET_SCAN = 0 LAST_CONSECRATE = 0 LAST_DIVINE_FURY = 0 LAST_EOO = 0 LAST_GOLEM_REPAIR = 0 VAULT_ATTEMPT_HISTORY = {} magery_buff_cooldowns = { "Reactive Armor": 0, "Protection": 0, "Magic Reflection": 0, "Bless": 0 } last_pick_time = 0 unlocked_chests = [] # ========================================================== # GUI SYSTEM & BUILD DETECTION # ========================================================== def SmartDetectBuild(): global IS_TAMER, IS_DEXTER, IS_MAGE, IS_BARD, IS_PALADIN, IS_TINKER, IS_CHIV, IS_LOCKPICKER, IS_POISONER, 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") 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) 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_PALADIN and "Paladin" not in build_str: build_str += "+Paladin" if IS_LOCKPICKER: build_str += "/Lockpicker" if IS_POISONER: build_str += "/Poisoner" DETECTED_BUILD = build_str def SmartDetectMastery(): """Dynamically reads Mastery name directly from the Player's Profile Tooltip.""" 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) match = re.search(r"([A-Za-z]+)\s+Mastery:", p_str, re.IGNORECASE) if match: found_mastery = match.group(1).strip().title() if found_mastery.lower() != "chivalry" and ACTIVE_MASTERY != found_mastery: ACTIVE_MASTERY = found_mastery MASTERY_DATA["Type"] = ACTIVE_MASTERY Misc.SetSharedValue("ACTIVE_MASTERY", ACTIVE_MASTERY) CheckAndDrawGUI(force=True) return except: pass def get_gold_count(): return 0 def GetActualBackpackGold(): return 0 def UpdateGoldLedger(): pass def WaitForMobileData(serial): for i in range(10): mob = Mobiles.FindBySerial(serial) if mob and mob.Name: return mob Misc.Pause(100) return Mobiles.FindBySerial(serial) def CheckAndDrawGUI(force=False): global LAST_GUI_HASH current_state = "{}_{}_{}_{}_{}_{}_{}_{}_{}_{}_{}_{}_{}_{}_{}_{}_{}".format( SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED, LOOT_MAGIC_ITEMS, USE_DIVINE_FURY, USE_MAGERY_BUFFS, USE_TAUNT, USE_LOCKPICKING, USE_ENHANCED_HEALING, USE_AUTO_WAND, USE_POUCHES, USE_SMART_POISON, USE_PARTY_HEAL, USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD ) 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['status'], d['percent']) current_state += "_{}".format(CURRENT_ACTION) current_state += "_{}".format(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 if not force and (time.time() - LAST_DRAW_TIME < DRAW_INTERVAL): return LAST_DRAW_TIME = time.time() try: 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 if IS_TAMER else 0 total_mini_h = base_mini_h + pet_mini_h Gumps.AddBackground(gd, 0, 0, 220, total_mini_h, 9200) 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, 20, 15, mode_btn, mode_btn, btn_mode, 1, 0) Gumps.AddButton(gd, 185, 15, 2437, 2438, 9999, 1, 0) status_color = 63 if SCRIPT_RUNNING else 33 status_txt = "AUTO" if AUTO_FARM_MODE else "MAN" Gumps.AddLabel(gd, 90, 15, 68, status_txt) Gumps.AddLabel(gd, 20, 40, 44, "0 gp") y_off = 65 if IS_TAMER: for serial in SPECIFIC_PET_SERIAL: name = PET_MAPPING.get(serial, "Pet") data = PET_DATA_CACHE.get(serial, {'percent': 0.0, 'status': 'Unknown'}) Gumps.AddImageTiled(gd, 20, y_off, 180, 8, 2624) Gumps.AddAlphaRegion(gd, 20, y_off, 180, 8) p_pct = data['percent'] if data['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 = 125 y_pets = y_bar + 45 pet_block_h = len(SPECIFIC_PET_SERIAL) * 50 if IS_TAMER else 0 y_ctrl = y_pets + pet_block_h + 20 # --- DYNAMIC PING-PONG IDs GENERATION --- 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_enh = 117 if USE_ENHANCED_HEALING else 116 btn_wand = 129 if USE_AUTO_WAND else 128 btn_pouch = 131 if USE_POUCHES else 130 btn_poison = 133 if USE_SMART_POISON else 132 btn_party = 135 if USE_PARTY_HEAL else 134 btn_buffs = 137 if USE_AUTO_BUFFS else 136 btn_petals = 139 if USE_AUTO_PETALS else 138 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 active_toggles = [ ("Mode", btn_mode, AUTO_FARM_MODE, "Auto", "Manual"), ("Skinning", btn_skin, USE_SKINNING, "ON", "OFF"), ("Loot Magic", btn_magic, LOOT_MAGIC_ITEMS, "ON", "OFF"), ("Pouch Popper", btn_pouch, USE_POUCHES, "ON", "OFF"), ("Auto Wand", btn_wand, USE_AUTO_WAND, "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 IS_MAGE: active_toggles.append(("Mage Buffs", btn_mage, USE_MAGERY_BUFFS, "ON", "OFF")) active_toggles.append(("Party Heal", btn_party, USE_PARTY_HEAL, "ON", "OFF")) if Player.GetSkillValue("Parrying") >= 50 or IS_DEXTER: 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")) if IS_TAMER and IS_MAGE: active_toggles.append(("Enh. Healing", btn_enh, USE_ENHANCED_HEALING, "ON", "OFF")) toggle_rows = (len(active_toggles) + 1) // 2 y_conf = y_ctrl + 30 + (toggle_rows * 30) + 20 total_h = y_conf + 170 main_w = 350 Gumps.AddBackground(gd, 0, 0, main_w, total_h, 9200) Gumps.AddAlphaRegion(gd, 10, 10, main_w-20, total_h-20) Gumps.AddImage(gd, 240, 40, 5549) Gumps.AddButton(gd, 305, 15, 2435, 2436, 9999, 1, 0) Gumps.AddLabel(gd, 20, 15, 63, "COMPLETE DOMINATION (MASTER EDITION)") status_color = 63 if SCRIPT_RUNNING else 33 status_text = "RUNNING" if SCRIPT_RUNNING else "PAUSED" Gumps.AddLabel(gd, 20, 40, 1152, "Status:") Gumps.AddLabel(gd, 80, 40, status_color, status_text) Gumps.AddLabel(gd, 20, 60, 1152, "Action:") Gumps.AddLabel(gd, 80, 60, 88, CURRENT_ACTION) Gumps.AddLabel(gd, 20, 80, 1152, "Build:") Gumps.AddLabel(gd, 80, 80, 55, DETECTED_BUILD) Gumps.AddLabel(gd, 20, 100, 1152, "Session:") Gumps.AddLabel(gd, 80, 100, 44, "0 gp") # Dynamic Pet Name Injection for Main GUI m_type = MASTERY_DATA["Type"] display_name = m_type if m_type in MASTERY_PET_NAMES: display_name = "{} ({})".format(m_type, MASTERY_PET_NAMES[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 IS_TAMER: 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['status'] == "MAX": label_text += " [MAX]" else: if data['level'] != '?': label_text += " Level " + data['level'] label_text += " [{:.1f}%]".format(data['percent']) Gumps.AddLabel(gd, 20, current_y_pets, 1152, 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['percent'] if data['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 = f"Mode: {text_on}" if (label == "Mode" and state) else f"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.AddLabel(gd, 20, y_conf, 1152, "--- CONFIGURATION ---") Gumps.AddButton(gd, 20, y_conf+20, 4005, 4007, btn_lootbag, 1, 0) Gumps.AddLabel(gd, 55, y_conf+20, 55, "Loot Bag") val = "SET" if LOOT_SOURCE_BAG > 0 else "NONE" col = 63 if LOOT_SOURCE_BAG > 0 else 33 Gumps.AddLabel(gd, 115, y_conf+20, col, val) Gumps.AddButton(gd, 20, y_conf+50, 4005, 4007, btn_vault, 1, 0) Gumps.AddLabel(gd, 55, y_conf+50, 66, "Vault") val = "SET" if VAULT_BAG_SERIAL > 0 else "NONE" col = 63 if VAULT_BAG_SERIAL > 0 else 33 Gumps.AddLabel(gd, 115, y_conf+50, col, val) Gumps.AddButton(gd, 20, y_conf+80, 4005, 4007, btn_satchel, 1, 0) Gumps.AddLabel(gd, 55, y_conf+80, 66, "Satchel") val = "SET" if SATCHEL_SERIAL > 0 else "NONE" col = 63 if SATCHEL_SERIAL > 0 else 33 Gumps.AddLabel(gd, 115, y_conf+80, col, val) Gumps.AddButton(gd, 20, y_conf+140, 4005, 4007, btn_shelf, 1, 0) Gumps.AddLabel(gd, 55, y_conf+140, 66, "RESTOCK SHELF") Gumps.AddButton(gd, 160, y_conf+140, 4005, 4007, btn_tome, 1, 0) Gumps.AddLabel(gd, 195, y_conf+140, 66, "TOME RESTOCK") if IS_TAMER: Gumps.AddButton(gd, 20, y_conf+110, 4005, 4007, btn_addpet, 1, 0) Gumps.AddLabel(gd, 55, y_conf+110, 63, "Add Pet") Gumps.AddButton(gd, 120, y_conf+110, 4005, 4007, btn_clrpet, 1, 0) Gumps.AddLabel(gd, 155, y_conf+110, 33, "Clear") btn_heal_method = 141 if last_button_id == 140 else 140 Gumps.AddButton(gd, 210, y_conf+110, 4005, 4007, btn_heal_method, 1, 0) # Ensures colors look perfect on the new spaced-out layout h_col = 63 if PET_HEAL_METHOD == "Both" else 55 if PET_HEAL_METHOD == "Bands" else 88 Gumps.AddLabel(gd, 245, y_conf+110, h_col, "Heal: " + PET_HEAL_METHOD) Gumps.SendGump(GUMP_ID, Player.Serial, 0, 0, gd.gumpDefinition, gd.gumpStrings) except: pass 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 # ========================================================== # RESTOCK & BUTTON LOGIC # ========================================================== def bank_gold(): Player.HeadMessage(55, "Scanning for Bank Safe...") safe = None filter = Items.Filter() filter.RangeMax = 3 filter.OnGround = True for item in Items.ApplyFilter(filter): n = item.Name.lower() if item.Name else "" if "vault" in n or "safe" in n: safe = item break if safe: Player.HeadMessage(63, "Opening " + safe.Name + "...") Items.UseItem(safe) Misc.Pause(2000) gold_ids = [0x0EED] found_gold = False for item in Player.Backpack.Contains: if item.ItemID in gold_ids: 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 perform_tome_sequence(): global VAULT_BAG_SERIAL, LOOT_SOURCE_BAG Player.HeadMessage(55, ">>> SWEEPING ALL BAGS INTO TOMES <<<") bags_to_sweep = [] if VAULT_BAG_SERIAL > 0: bags_to_sweep.append(VAULT_BAG_SERIAL) if LOOT_SOURCE_BAG > 0: bags_to_sweep.append(LOOT_SOURCE_BAG) bags_to_sweep.append(Player.Backpack.Serial) tomes = [ (0x427A1999, 10), (0x44578FB7, 10), (0x427EF907, 100), (0x427D8F50, 3000), (0x400C309B, 1), (0x410D5A6A, 1), (0x427A27F7, 10), (0x45720606, 10) ] for serial, btn in tomes: 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) while Gumps.CurrentGump() != 0: Gumps.CloseGump(Gumps.CurrentGump()) Misc.Pause(50) Player.HeadMessage(66, "Tome Restock Complete.") def poll_buttons(): global last_button_id, SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, GUI_MINIMIZED 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_ENHANCED_HEALING, USE_AUTO_WAND global USE_POUCHES, USE_SMART_POISON, USE_PARTY_HEAL, USE_AUTO_BUFFS, USE_AUTO_PETALS, PET_HEAL_METHOD gd = Gumps.GetGumpData(GUMP_ID) if not gd: return bid = gd.buttonid if not bid or bid == 0: return if bid == last_button_id: return last_button_id = bid # Instantly clear Gump to prevent Razor input lag Gumps.CloseGump(GUMP_ID) if bid in [198, 199]: perform_restock_sequence(); CheckAndDrawGUI(force=True); return if bid in [196, 197]: perform_tome_sequence(); 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 [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 Wand: " + ("ON" if USE_AUTO_WAND else "OFF")); CheckAndDrawGUI(force=True); return if bid in [130, 131]: USE_POUCHES = not USE_POUCHES; Player.HeadMessage(55, "Pouch Popper: " + ("ON" if USE_POUCHES 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 [134, 135]: USE_PARTY_HEAL = not USE_PARTY_HEAL; Player.HeadMessage(55, "Party Heal: " + ("ON" if USE_PARTY_HEAL 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 [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")) if USE_SKINNING and SCRIPT_RUNNING: autoloot_tick() 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 == 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]: if IS_TAMER: 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 = NAME_OVERRIDES.get(s, raw_name.replace("*", "")) PET_MAPPING[s] = p_name Player.HeadMessage(63, "Added: " + p_name + " (" + hex(s) + ")") if int(mob.Body) not in SPECIFIC_PET_BODIES: SPECIFIC_PET_BODIES.append(int(mob.Body)) 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() Player.HeadMessage(33, "Pet List Cleared.") CheckAndDrawGUI(force=True) def CheckChatCommands(): global SCRIPT_RUNNING, USE_SKINNING, AUTO_FARM_MODE, ACTIVE_MASTERY, MASTERY_DATA 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) # Manual Override for Mastery Type (Forces GUI Refresh) 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() # ========================================================== # CORE LOGIC # ========================================================== def check_auto_potions(): global last_str_pot_time, last_dex_pot_time, last_refresh_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 'last_refresh_pot_time' not in globals(): globals()['last_refresh_pot_time'] = 0 if not USE_AUTO_BUFFS or Player.IsGhost: return if check_priority_tasks(): return curr_time = time.time() # 1. Emergency Stamina Refresh (Under 80 Stamina) if Player.Stam < 80 and (curr_time - last_refresh_pot_time > 2.0): pot = Items.FindByID(REFRESH_POTION_ID, -1, Player.Backpack.Serial, True) if pot: Player.HeadMessage(63, ">> Chugging Refresh Pot <<") Items.UseItem(pot) last_refresh_pot_time = curr_time Misc.Pause(500) return # 2. Timed Buffs (2 Min 30 Sec) if curr_time - last_str_pot_time > 150.0: 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 Misc.Pause(500) return if curr_time - last_dex_pot_time > 150.0: 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 Misc.Pause(500) return 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 if check_priority_tasks(): return 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 Misc.Pause(500) return 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 Misc.Pause(500) return 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 Misc.Pause(500) return 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 Misc.Pause(500) return def check_auto_meditation(): """ 100% crash-proof shared memory logic. Strips non-medable armor, recasts Meditation, and auto-equips. """ if not Misc.CheckSharedValue("MED_GORGET"): Misc.SetSharedValue("MED_GORGET", 0) if not Misc.CheckSharedValue("IS_MEDDING"): Misc.SetSharedValue("IS_MEDDING", False) med_gorget = Misc.ReadSharedValue("MED_GORGET") is_medding = Misc.ReadSharedValue("IS_MEDDING") 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 <<") Misc.SetSharedValue("MED_GORGET", neck.Serial) Items.Move(neck.Serial, Player.Backpack.Serial, 0) Misc.Pause(600) Player.UseSkill("Meditation") Misc.SetSharedValue("IS_MEDDING", True) return if is_medding: if Journal.Search("You are at peace.") or Journal.Search("lose your concentration") or Journal.Search("stop meditating") or Journal.Search("-Actively Meditating"): 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) Misc.SetSharedValue("IS_MEDDING", False) Misc.SetSharedValue("MED_GORGET", 0) def track_equipment(): # Initializes memory if it doesn't exist if not Misc.CheckSharedValue("PREF_WEP"): Misc.SetSharedValue("PREF_WEP", 0) if not Misc.CheckSharedValue("PREF_SHIELD"): Misc.SetSharedValue("PREF_SHIELD", 0) rh = Player.GetItemOnLayer("RightHand") lh = Player.GetItemOnLayer("LeftHand") # Only updates memory IF you are holding something. # This prevents the script from saving "0" when you get disarmed! if rh: Misc.SetSharedValue("PREF_WEP", rh.Serial) if lh: Misc.SetSharedValue("PREF_SHIELD", lh.Serial) def check_anti_disarm(): """ 100% crash-proof shared memory logic for anti-disarm. """ if not Misc.CheckSharedValue("LAST_EQUIP_TIME"): Misc.SetSharedValue("LAST_EQUIP_TIME", 0.0) if not Misc.CheckSharedValue("PREF_WEP"): Misc.SetSharedValue("PREF_WEP", 0) if not Misc.CheckSharedValue("PREF_SHIELD"): Misc.SetSharedValue("PREF_SHIELD", 0) last_eq = Misc.ReadSharedValue("LAST_EQUIP_TIME") if time.time() - last_eq < 3.0: return if Player.IsGhost: return pref_wep = Misc.ReadSharedValue("PREF_WEP") pref_sh = Misc.ReadSharedValue("PREF_SHIELD") rh = Player.GetItemOnLayer("RightHand") lh = Player.GetItemOnLayer("LeftHand") equipped_something = False if not rh and pref_wep > 0: wep = Items.FindBySerial(pref_wep) if wep and wep.Container == Player.Backpack.Serial: Player.HeadMessage(66, ">> ANTI-DISARM: WEAPON <<") Player.EquipItem(wep.Serial) equipped_something = True if not lh and pref_sh > 0: sh = Items.FindBySerial(pref_sh) if sh and sh.Container == Player.Backpack.Serial: Player.HeadMessage(66, ">> ANTI-DISARM: SHIELD <<") Player.EquipItem(sh.Serial) equipped_something = True if equipped_something: Misc.SetSharedValue("LAST_EQUIP_TIME", time.time()) Misc.Pause(400) 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 check_smart_poison(target): global last_poison_time if not USE_SMART_POISON or not target: return if Player.IsGhost: return if time.time() - last_poison_time < 5.0: return if Player.GetSkillValue("Poisoning") < 20: return 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 wep = Player.GetItemOnLayer("RightHand") or Player.GetItemOnLayer("LeftHand") if not wep: return 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") if Target.WaitForTarget(1500, False): Target.TargetExecute(poison.Serial) if Target.WaitForTarget(1500, False): Target.TargetExecute(wep.Serial) last_poison_time = time.time() Misc.Pause(500) def check_priority_tasks(): if Player.IsGhost: return False global next_allowed_heal_time, next_allowed_vet_time global last_cure_potion_time, last_heal_potion_time hp_percent = (Player.Hits * 100) / Player.HitsMax if Player.HitsMax > 0 else 100 if USE_POTIONS: if Player.Poisoned and time.time() - last_cure_potion_time >= POTION_COOLDOWN: return True if hp_percent < POTION_HEAL_TRIGGER and time.time() - last_heal_potion_time >= POTION_COOLDOWN: return True if IS_DEXTER: if hp_percent < SELF_BANDAGE_HP_TRIGGER or Player.Poisoned or Player.BuffsExist("Bleed"): if time.time() >= next_allowed_heal_time: return True else: if hp_percent < SELF_HEAL_TRIGGER or Player.Poisoned or Player.BuffsExist("Bleed"): return True if IS_TAMER: for s in SPECIFIC_PET_SERIAL: pet = Mobiles.FindBySerial(s) if pet and not pet.IsGhost: p_hp = (pet.Hits * 100) / pet.HitsMax if pet.HitsMax > 0 else 100 if pet.Poisoned or p_hp < SAFE_TO_VET_HP_TRIGGER: if time.time() >= next_allowed_vet_time: return True return False def smart_pause(ms): end = time.time() + (ms / 1000.0) while time.time() < end: if check_priority_tasks(): return False Misc.Pause(10) return True 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 == "Arch Cure": regs_needed = [REG_GARLIC, REG_GINSENG, REG_MANDRAKE] 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] 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 if time.time() - last_pick_time < 4.0: return chest_ids = [0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E7C, 0x0E7E, 0x09AA, 0x09AB, 0x0E80, 0x0E7D, 0x0E7F, 3648] fil = Items.Filter() fil.OnGround = True fil.RangeMax = 2 fil.Graphics = List[Int32](chest_ids) chests = Items.ApplyFilter(fil) target_chest = None for c in chests: if c.Serial not in unlocked_chests: target_chest = c break if not target_chest: return 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 Player.HeadMessage(55, ">> Picking Chest <<") Journal.Clear() Items.UseItem(pick) if Target.WaitForTarget(1500, False): Target.TargetExecute(target_chest.Serial) last_pick_time = time.time() Misc.Pause(500) if Journal.Search("does not appear to be locked") or Journal.Search("successfully") or Journal.Search("yields"): unlocked_chests.append(target_chest.Serial) if len(unlocked_chests) > 200: unlocked_chests.clear() Player.HeadMessage(63, "Chest Unlocked!") Journal.Clear() def check_taunt(target): global last_taunt_time if not USE_TAUNT or not target: return if Player.IsGhost: return if check_priority_tasks(): return if Player.GetSkillValue("Parrying") < 50: return if time.time() - last_taunt_time > 15.0: Player.HeadMessage(73, ">> TAUNTING {} <<".format(target.Name)) Player.UseSkill("Taunt") Player.ChatSay("[taunt") if Target.WaitForTarget(500, False): Target.TargetExecute(target.Serial) last_taunt_time = time.time() Misc.Pause(200) def check_magery_buffs(): global last_magery_buff_time, magery_buff_cooldowns if not USE_MAGERY_BUFFS: return if Player.IsGhost: return if check_priority_tasks(): return if time.time() - last_magery_buff_time < 3.0: return if Player.Mana < 20: return 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) if needs_target: if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) else: Misc.Pause(500) magery_buff_cooldowns[spell_name] = time.time() last_magery_buff_time = time.time() return def update_mastery_stats(): global MASTERY_DATA, ACTIVE_MASTERY # 1. BRUTE FORCE NAME SCANNER # Searches raw text without brackets to completely bypass regex bugs for km in KNOWN_MASTERIES: if Journal.Search(km + " Mastery"): if ACTIVE_MASTERY != km: ACTIVE_MASTERY = km MASTERY_DATA["Type"] = ACTIVE_MASTERY CheckAndDrawGUI(force=True) break # 2. NUMBERS SCANNER 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 if not IS_TAMER or not SPECIFIC_PET_SERIAL: return scan_delay = 0.5 if Player.WarMode else 2.0 if time.time() - LAST_PET_SCAN < scan_delay: 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: 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 get_priority_target(): global CURRENT_ACTION if not AUTO_FARM_MODE: t = Target.GetLast() if t: mob = Mobiles.FindBySerial(t) if mob: if mob.Serial != Player.Serial and mob.Serial not in SPECIFIC_PET_SERIAL: update_hologram_hud(mob) return mob return None mob_filter = Mobiles.Filter() mob_filter.RangeMax = GUARD_RANGE mob_filter.Enabled = True mob_filter.Notorieties = List[Byte]([Byte(3), Byte(4), Byte(6)]) targets = Mobiles.ApplyFilter(mob_filter) valid_targets = [] for t in targets: if t.Serial in SPECIFIC_PET_SERIAL: continue if t.Body in PLAYER_BODIES: continue if "bird" not in t.Name.lower(): valid_targets.append(t) if valid_targets: if IS_DEXTER: for t in valid_targets: if Player.DistanceTo(t) <= 2: return t sorted_targets = sorted(valid_targets, key=lambda x: Player.DistanceTo(x)) return sorted_targets[0] return None def get_injured_pet(): if not IS_TAMER: return None global SPECIFIC_PET_SERIAL candidate_pet = None lowest_hp_percent = 100 for serial in SPECIFIC_PET_SERIAL: pet = Mobiles.FindBySerial(serial) if not pet: 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 get_instrument(): if not Player.Backpack: return None for item in Player.Backpack.Contains: if item.ItemID in INSTRUMENT_IDS: return item return None def do_bard_logic(target): if not IS_BARD or not target: return if Player.IsGhost: return if check_priority_tasks(): return global next_bard_time if time.time() < next_bard_time: return instrument = get_instrument() if not instrument: return if DISCORD_MODE != "Off" and Player.GetSkillValue("Discordance") > 50: if DISCORD_MODE == "SingleTarget": Player.HeadMessage(63, ">> DISCORD: {} <<".format(target.Name)) Player.UseSkill("Discordance") Target.WaitForTarget(100, False) Target.TargetExecute(target.Serial) next_bard_time = time.time() + BARD_DELAY return if PEACE_MODE != "Off" and Player.GetSkillValue("Peacemaking") > 50: if PEACE_MODE == "AoE": Player.HeadMessage(53, ">> PEACE (AOE) <<") Player.UseSkill("Peacemaking") Target.WaitForTarget(100, False) Target.TargetExecute(Player.Serial) next_bard_time = time.time() + BARD_DELAY return elif PEACE_MODE == "SingleTarget": Player.HeadMessage(53, ">> PEACE: {} <<".format(target.Name)) Player.UseSkill("Peacemaking") Target.WaitForTarget(100, False) Target.TargetExecute(target.Serial) next_bard_time = time.time() + BARD_DELAY return def update_hologram_hud(target): if not SHOW_HOLOGRAM_HUD: return if not target: return if target.HitsMax == 0: return global last_hud_update_time, last_known_hp, last_hud_target_serial hp_percent = (target.Hits * 100) / target.HitsMax if (target.Serial == last_hud_target_serial) and (hp_percent == last_known_hp) and (time.time() - last_hud_update_time < 1.0): return last_known_hp = hp_percent last_hud_update_time = time.time() 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): global last_overhead_time if not SHOW_TARGET_OVERHEAD or not target: return if time.time() - last_overhead_time > 5.0: Mobiles.Message(target.Serial, TARGET_OVERHEAD_HUE, TARGET_OVERHEAD_MSG) last_overhead_time = time.time() def get_item_properties(item): 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) return clean_text.replace('\n', ' ').replace('\r', ' ') def is_equipment_loot(item, clean_props=""): """Catches magic equipment (weapons/armor) to be routed to the LOOT BAG.""" 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, WAND_ID] + SKINNING_TOOL_IDS + INSTRUMENT_IDS + POTION_IDS + REAGENT_IDS if item_id in ignore_basic: return False except: pass clean_name = re.sub(r'<[^>]+>', '', (item.Name or "")).lower().strip() ignore_names = ["spellbook", "runebook", "tome", "key", "bag", "pouch", "box", "chest", "safe", "vault", "book", "desk"] 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_valuable_item(item, clean_props=""): """Catches purely Unchained Rares to route strictly to the VAULT BAG.""" 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] + 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 raw_name = (item.Name or "").lower() clean_name = re.sub(r'<[^>]+>', '', raw_name).strip() if "paladin spellbook" in clean_name: return False if "spellbook" in clean_name and "paladin" in clean_name: return False if any(x in clean_name for x in ["potion", "eldritch", "scroll of"]): return False # Highly targeted Unchained keyword phrases instant_rares = [ "power scroll", "arcane scroll", "aspect core", "aspect extract", "skill scroll", "mastery chain", "void", "paragon chest", "enhancement core", "map", "rare cloth", "orb", "fira", "artifact", "mastery", "skull" ] if any(r in clean_name for r in instant_rares): return True if not clean_props: clean_props = get_item_properties(item) if any(r in clean_props for r in instant_rares): return True return False def check_bag_sorting(): if check_priority_tasks(): return global last_vault_scan_time, VAULT_ATTEMPT_HISTORY, CURRENT_ACTION, KNOWN_JUNK if time.time() - last_vault_scan_time < 0.5: return last_vault_scan_time = time.time() if not Player.Backpack: return for item in Player.Backpack.Contains: if check_priority_tasks(): return # --- THE VIP EXCEPTION --- 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 in KNOWN_JUNK: continue if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 1.0: continue try: item_id = int(item.ItemID) ignore_basic = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, WAND_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(): KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.clear() continue if item_id in HIGH_VALUE_IDS: dest_vault = VAULT_BAG_SERIAL if VAULT_BAG_SERIAL > 0 else Player.Backpack.Serial if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() + 60.0 if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(item.Name or "Rare Item")) Items.Move(item.Serial, dest_vault, 0) if not smart_pause(200): return continue except: pass props = get_item_properties(item) if "blessed" in props: KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.clear() continue if is_valuable_item(item, props): dest_vault = VAULT_BAG_SERIAL if VAULT_BAG_SERIAL > 0 else Player.Backpack.Serial if item.Container != dest_vault: CURRENT_ACTION = "Vaulting" VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() + 60.0 if PLAY_VAULT_SOUND: Misc.PlaySound(VAULT_SOUND_ID, Player.Position.X, Player.Position.Y, Player.Position.Z) Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(item.Name or "Rare Item")) Items.Move(item.Serial, dest_vault, 0) if not smart_pause(200): return continue elif LOOT_MAGIC_ITEMS and is_equipment_loot(item, props): if LOOT_SOURCE_BAG > 0 and item.Container != LOOT_SOURCE_BAG: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() + 60.0 Items.Move(item.Serial, LOOT_SOURCE_BAG, 0) if not smart_pause(200): return continue else: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() 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 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: Player.HeadMessage(33, msg) 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 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) if Target.WaitForTarget(1500, False): Target.TargetExecute(LOOT_SOURCE_BAG) last_wand_time = time.time() Misc.Pause(500) 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 if free_stones <= 5: if time.time() - last_bless_time > 30: if Player.Mana > 10: if check_priority_tasks(): return if not can_cast_spell("Bless"): return Player.HeadMessage(63, "!!! HEAVY - CASTING BLESS !!!") Spells.Cast("Bless") if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) last_bless_time = time.time() def process_corpse_resources(corpse): global CURRENT_ACTION if check_priority_tasks(): return if not USE_SKINNING: return if corpse.Serial in skinned_corpses: return 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" Items.UseItem(tool) Target.WaitForTarget(1000, False) Target.TargetExecute(corpse.Serial) skinned_corpses.append(corpse.Serial) if len(skinned_corpses) > 100: skinned_corpses.clear() if not smart_pause(800): return if USE_SCISSORS: scissors = Items.FindByID(SCISSORS_ID, -1, Player.Backpack.Serial, True) if scissors: hides = Items.FindByID(HIDES_ID, -1, corpse.Serial, False) if not hides: hides = Items.FindByID(0x1078, -1, corpse.Serial, False) if hides: Items.UseItem(scissors) Target.WaitForTarget(1000, False) Target.TargetExecute(hides.Serial) if not smart_pause(600): return leather = Items.FindByID(LEATHER_ID, -1, corpse.Serial, False) if not leather: leather = Items.FindByID(0x1082, -1, corpse.Serial, False) if leather: dest = Player.Backpack.Serial if Items.FindBySerial(LOOT_SOURCE_BAG): dest = LOOT_SOURCE_BAG Items.Move(leather.Serial, dest, 0) if not smart_pause(500): return def loot_gold_from_corpses(): global SESSION_GOLD_LOOTED, opened_corpses, LOOTED_SERIALS, KNOWN_JUNK corpses = Items.Filter() corpses.Enabled = True corpses.OnGround = True corpses.IsCorpse = True corpses.RangeMax = LOOT_RANGE corpse_list = Items.ApplyFilter(corpses) for corpse in corpse_list: if not SCRIPT_RUNNING: return if check_priority_tasks(): return if corpse.Serial not in opened_corpses: Items.WaitForContents(corpse, 300) opened_corpses.append(corpse.Serial) if len(opened_corpses) > 200: opened_corpses.clear() process_corpse_resources(corpse) if not corpse.Contains: continue for item in corpse.Contains: if item.Serial in KNOWN_JUNK: continue if item.Serial in VAULT_ATTEMPT_HISTORY: if time.time() - VAULT_ATTEMPT_HISTORY[item.Serial] < 1.0: continue try: item_id = int(item.ItemID) ignore_basic = [GOLD_ID, BANDAGE_ID, VET_KIT_ID, SCISSORS_ID, HIDES_ID, LEATHER_ID, WAND_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(): KNOWN_JUNK.append(item.Serial) if len(KNOWN_JUNK) > 1000: KNOWN_JUNK.clear() continue if item_id in HIGH_VALUE_IDS: dest_vault = VAULT_BAG_SERIAL if VAULT_BAG_SERIAL > 0 else Player.Backpack.Serial VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() + 60.0 Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(item.Name or "Epic Item")) Misc.Beep() Items.Move(item.Serial, dest_vault, 0) if not smart_pause(200): return continue except: pass props = get_item_properties(item) if is_valuable_item(item, props): dest_vault = VAULT_BAG_SERIAL if VAULT_BAG_SERIAL > 0 else Player.Backpack.Serial VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() + 60.0 Player.HeadMessage(66, "!!! VAULTING: {} !!!".format(item.Name or "Rare Item")) Misc.Beep() Items.Move(item.Serial, dest_vault, 0) if not smart_pause(200): return continue elif LOOT_MAGIC_ITEMS and is_equipment_loot(item, props): dest = Player.Backpack.Serial if LOOT_SOURCE_BAG > 0: dest = LOOT_SOURCE_BAG VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() + 60.0 Items.Move(item.Serial, dest, 0) if not smart_pause(200): return continue else: VAULT_ATTEMPT_HISTORY[item.Serial] = time.time() if not AUTO_MOVE_GOLD: continue for item in corpse.Contains: if check_priority_tasks(): return if item.ItemID == GOLD_ID: if item.Serial in LOOTED_SERIALS: continue LOOTED_SERIALS.append(item.Serial) if len(LOOTED_SERIALS) > 200: LOOTED_SERIALS.clear() try: dest = Player.Backpack.Serial if SATCHEL_SERIAL > 0 and Items.FindBySerial(SATCHEL_SERIAL): dest = SATCHEL_SERIAL Items.Move(item.Serial, dest, 0) UpdateGoldLedger() CheckAndDrawGUI(force=True) if not smart_pause(500): return except: pass Misc.Pause(100) def loot_gold_from_ground(): global SESSION_GOLD_LOOTED, LOOTED_SERIALS golds = Items.Filter() golds.Enabled = True golds.OnGround = True golds.Movable = True golds.RangeMax = LOOT_RANGE golds.Graphics = List[Int32]([GOLD_ID]) gold_list = Items.ApplyFilter(golds) for g in gold_list: if not SCRIPT_RUNNING: return if check_priority_tasks(): return if g.Serial in LOOTED_SERIALS: continue LOOTED_SERIALS.append(g.Serial) if len(LOOTED_SERIALS) > 200: LOOTED_SERIALS.clear() try: dest = Player.Backpack.Serial if SATCHEL_SERIAL > 0 and Items.FindBySerial(SATCHEL_SERIAL): dest = SATCHEL_SERIAL Items.Move(g.Serial, dest, 0) UpdateGoldLedger() CheckAndDrawGUI(force=True) if not smart_pause(500): return except: pass def autoloot_tick(): if check_priority_tasks(): return if not AUTO_MOVE_GOLD and not USE_SKINNING and not LOOT_MAGIC_ITEMS: return loot_gold_from_corpses() loot_gold_from_ground() def check_gold_cleanup(): if not AUTO_MOVE_GOLD: return if not Player.Backpack: return if SATCHEL_SERIAL <= 0: return 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: Items.Move(gold.Serial, SATCHEL_SERIAL, 0) if not smart_pause(500): return 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: Items.Move(g.Serial, SATCHEL_SERIAL, 0) if not smart_pause(500): return def check_bank_deposit(): if check_priority_tasks(): return if not AUTO_BANK_GOLD: return global last_bank_check_time if time.time() - last_bank_check_time < 15.0: return last_bank_check_time = time.time() if not Player.Bank: return gold_moved = 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) Misc.Pause(50) if not Items.FindBySerial(g.Serial) or Items.FindBySerial(g.Serial).Container != Player.Backpack.Serial: gold_moved = 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) Misc.Pause(50) if not Items.FindBySerial(g.Serial) or Items.FindBySerial(g.Serial).Container != SATCHEL_SERIAL: gold_moved = True def check_potions(): global last_heal_potion_time, last_cure_potion_time if not USE_POTIONS: return if not Player or Player.HitsMax == 0: return if time.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) last_cure_potion_time = time.time() Misc.Pause(1000) if time.time() - last_heal_potion_time < POTION_COOLDOWN: return 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) last_heal_potion_time = time.time() def check_chivalry_logic(): global LAST_CONSECRATE, LAST_DIVINE_FURY if not IS_CHIV or Player.IsGhost: return if check_priority_tasks(): return if Player.Poisoned: Player.HeadMessage(44, ">> Curing Poison <<") Player.ChatSay("[paladin 2") Target.WaitForTarget(2000, False) Target.TargetExecute(Player.Serial) Misc.Pause(500) return if Player.BuffsExist("Curse") or Player.BuffsExist("Clumsy") or Player.BuffsExist("Weaken") or Player.BuffsExist("Feeblemind"): Player.HeadMessage(44, ">> Curing Curse <<") Player.ChatSay("[paladin 3") Target.WaitForTarget(2000, False) Target.TargetExecute(Player.Serial) Misc.Pause(500) return if (Player.Hits * 100 / Player.HitsMax) <= 85: if Player.Mana >= 35: Player.ChatSay("[paladin 8") Misc.Pause(200) return if Player.WarMode: if not USE_DIVINE_FURY: if not Player.BuffsExist("Consecrate Weapon") and time.time() - LAST_CONSECRATE > 10: if Player.Mana >= 10: Player.HeadMessage(63, ">> Consecrate <<") Player.ChatSay("[paladin 9") LAST_CONSECRATE = time.time() Misc.Pause(200) return else: if Player.GetItemOnLayer("RightHand"): if not Player.BuffsExist("Divine Fury") and time.time() - LAST_DIVINE_FURY > 15: if Player.Mana >= 10: Player.HeadMessage(63, ">> Divine Fury <<") Player.ChatSay("[paladin 7") LAST_DIVINE_FURY = time.time() Misc.Pause(200) return elif Player.GetItemOnLayer("LeftHand"): if not Player.BuffsExist("Consecrate Weapon") and time.time() - LAST_CONSECRATE > 10: if Player.Mana >= 10: Player.HeadMessage(63, ">> Consecrate <<") Player.ChatSay("[paladin 9") LAST_CONSECRATE = time.time() Misc.Pause(200) return def check_golem_repair(): global LAST_GOLEM_REPAIR if not IS_TINKER: return if time.time() - LAST_GOLEM_REPAIR < 5: return golem = None for mob in Mobiles.ApplyFilter(Mobiles.Filter()): if mob.Body in [0x0260, 0x02F0] and mob.Notoriety == 2: golem = mob break if golem and golem.Hits * 100 / golem.HitsMax < REPAIR_GOLEM_AT_HP: kit = Items.FindByID(TOOL_KIT_ID, -1, Player.Backpack.Serial) if kit: Player.HeadMessage(66, ">> REPAIRING GOLEM <<") Items.UseItem(kit) Target.WaitForTarget(100, False) Target.TargetExecute(golem.Serial) LAST_GOLEM_REPAIR = time.time() def check_party_heal(): """[v408.0] Smart Party/Guild Field Medic Engine""" global last_heal_time if not USE_PARTY_HEAL or not IS_MAGE: return if Player.IsGhost or Player.Poisoned: return # Self-preservation check if (Player.Hits * 100 / Player.HitsMax) < 80: return if time.time() - last_heal_time < 1.2: return # 1. Find friends/party members friend_filter = Mobiles.Filter() friend_filter.Enabled = True friend_filter.RangeMax = 12 friend_filter.IsHuman = True friend_filter.IsGhost = False friend_filter.Notorieties = List[Byte]([Byte(1), Byte(2)]) # Blue or Green friends = Mobiles.ApplyFilter(friend_filter) target_to_heal = None lowest_hp = 100 for friend in friends: if friend.Serial == Player.Serial: continue # Only heal if explicitly listed as a friend OR actively green (party/guild) if friend.Serial in FRIEND_SERIALS or friend.Notoriety == 2: if friend.Poisoned: continue hp_pct = (friend.Hits * 100) / friend.HitsMax if friend.HitsMax > 0 else 100 if hp_pct < 85 and hp_pct < lowest_hp: lowest_hp = hp_pct target_to_heal = friend if target_to_heal: # 2. Threat Assessment danger_filter = Mobiles.Filter() danger_filter.Enabled = True danger_filter.RangeMax = 5 danger_filter.Notorieties = List[Byte]([Byte(3), Byte(4), Byte(5), Byte(6)]) enemies = Mobiles.ApplyFilter(danger_filter) is_danger = len(enemies) > 0 spell_to_cast = "Greater Heal" # If in immediate danger but friend isn't critically dying, use fast heal if (is_danger and lowest_hp > 40) or (lowest_hp >= 70): spell_to_cast = "Heal" # Mana checks if Player.Mana < 11 and spell_to_cast == "Greater Heal": if Player.Mana >= 4: spell_to_cast = "Heal" else: return elif Player.Mana < 4: return if not can_cast_spell(spell_to_cast): return Player.HeadMessage(63, ">> {} on {} <<".format(spell_to_cast, target_to_heal.Name)) Spells.Cast(spell_to_cast) if Target.WaitForTarget(1500, False): Target.TargetExecute(target_to_heal.Serial) last_heal_time = time.time() def check_enhanced_pet_healing(): global last_heal_time if not USE_ENHANCED_HEALING or not IS_MAGE or not IS_TAMER: return if Player.IsGhost: return self_hp_percent = (Player.Hits * 100) / Player.HitsMax if Player.HitsMax > 0 else 100 if self_hp_percent < SELF_HEAL_TRIGGER or Player.Poisoned or Player.BuffsExist("Bleed"): return if time.time() - last_heal_time < 1.2: return if Player.Mana < 11: return 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"): Player.HeadMessage(33, "!!! OUT OF REAGENTS FOR PET HEAL !!!") last_heal_time = time.time() + 5.0 return 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 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 if IS_TAMER and (Player.Hits * 100 / Player.HitsMax) < RESCUE_HP_TRIGGER: if time.time() - last_rescue_time > 3.0: Player.HeadMessage(33, "!!! ☠️ RESCUE ME ☠️ !!!") Player.ChatSay(33, "All Guard Me") Misc.Beep() last_rescue_time = time.time() if time.time() >= next_vet_kit_time: hp_pct = (Player.Hits * 100) / Player.HitsMax pets_hurt = False if IS_TAMER and 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: 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) next_vet_kit_time = time.time() + VET_KIT_DELAY next_allowed_vet_time = time.time() + VET_DELAY_SECONDS return if time.time() < next_allowed_heal_time: return hp_percent = (Player.Hits * 100) / Player.HitsMax if IS_TAMER: 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): continue 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) if Target.WaitForTarget(1000, False): Target.TargetExecute(p.Serial) pet_rez_timers[p.Serial] = time.time() + 10.0 return 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: Player.HeadMessage(66, ">>> WAKE UP TRIGGER: ALL GUARD ME <<<") Player.ChatSay("All Guard Me") 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) Target.WaitForTarget(1500, False) Target.TargetExecute(injured_pet.Serial) next_allowed_vet_time = time.time() + VET_DELAY_SECONDS return if IS_DEXTER and (hp_percent < SELF_BANDAGE_HP_TRIGGER or Player.Poisoned or Player.BuffsExist("Bleed")): bandages = Items.FindByID(BANDAGE_ID, -1, Player.Backpack.Serial, True) if bandages: Player.HeadMessage(63, "+++ BANDAGING SELF +++") Items.UseItem(bandages) Target.WaitForTarget(1500, False) Target.Self() next_allowed_heal_time = time.time() + SELF_BANDAGE_DELAY return def check_self_cure(): if not IS_MAGE or not USE_ARCH_CURE: return global last_cure_time if not Player.Poisoned: return if time.time() - last_cure_time > 1.0: if Player.Mana < 15: Player.HeadMessage(33, "!!! OOM - CANNOT CURE !!!") last_cure_time = time.time() return if not can_cast_spell("Arch Cure"): Player.HeadMessage(33, "!!! OUT OF REAGENTS FOR CURE !!!") last_cure_time = time.time() + 5.0 return Player.HeadMessage(55, ">>> SPELL: ARCH CURE <<<") Spells.Cast("Arch Cure") if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) last_cure_time = time.time() def check_self_heal(): if not IS_MAGE or not USE_SELF_HEAL: return global last_heal_time, is_recovering_health if Player.Poisoned: return if not Player or Player.HitsMax == 0: return hp_percent = (Player.Hits * 100) / Player.HitsMax if hp_percent < SELF_HEAL_TRIGGER: is_recovering_health = True if hp_percent >= 100: is_recovering_health = False if is_recovering_health: if time.time() - last_heal_time > 1.2: if Player.Mana < 11: Player.HeadMessage(33, "!!! OOM - CANNOT HEAL !!!") last_heal_time = time.time() + 2 return if not can_cast_spell(SELF_HEAL_SPELL): Player.HeadMessage(33, "!!! OUT OF REAGENTS FOR HEAL !!!") last_heal_time = time.time() + 5.0 return Player.HeadMessage(63, "+++ SELF HEALING ({}%) +++".format(hp_percent)) Spells.Cast(SELF_HEAL_SPELL) if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) last_heal_time = time.time() def check_pet_cure(): if not PET_CURE_POISON: return if not IS_MAGE: return if (Player.Hits * 100) / Player.HitsMax < RESCUE_HP_TRIGGER: return global last_pet_cure_time if time.time() - last_pet_cure_time < 1.0: return 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 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") if Target.WaitForTarget(1500, False): Target.TargetExecute(pet.Serial) last_pet_cure_time = time.time() return def attack_and_guard(): global has_issued_guard_command, last_attacked_serial, last_attack_time, CURRENT_ACTION global last_chore_time, last_attack_packet_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 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) 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 if time.time() - last_chore_time > 1.0: update_pet_levels() CheckChatCommands() if not SCRIPT_RUNNING: return show_fancy_overhead(target) update_hologram_hud(target) check_auto_meditation() check_weight_alarm() check_supplies() check_potions() check_auto_potions() check_auto_petals() decide_healing() check_self_cure() check_self_heal() check_pet_cure() check_enhanced_pet_healing() check_party_heal() do_bard_logic(target) check_taunt(target) check_chivalry_logic() check_magery_buffs() check_golem_repair() check_pouch_popper() check_smart_poison(target) if time.time() - last_chore_time > 0.5: auto_lockpick() autoloot_tick() update_mastery_stats() check_gold_cleanup() check_bank_deposit() check_bag_sorting() last_chore_time = time.time() current_target = Mobiles.FindBySerial(target_serial) if not current_target: break if current_target.Hits <= 0: break if Player.DistanceTo(current_target) > GUARD_RANGE: break if time.time() - last_attack_packet_time > 0.5: Player.Attack(target) last_attack_packet_time = time.time() 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 else: break Misc.Pause(50) else: CURRENT_ACTION = "Scanning" CheckAndDrawGUI() def main(): SmartDetectBuild() Player.HeadMessage(90, ">>> DOMINATION GUI LOADED <<<") CheckAndDrawGUI(force=True) global last_scan_msg_time, has_issued_guard_command, last_button_id, last_rescue_time, last_war_mode_state global last_build_check_time last_rescue_time = 0 last_war_mode_state = Player.WarMode while True: poll_buttons() CheckChatCommands() 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 track_equipment() check_anti_disarm() check_pouch_popper() check_auto_meditation() check_weight_alarm() check_supplies() check_potions() check_auto_potions() check_auto_petals() decide_healing() check_self_cure() check_self_heal() check_pet_cure() check_enhanced_pet_healing() check_party_heal() auto_lockpick() autoloot_tick() check_gold_cleanup() check_bank_deposit() check_bag_sorting() check_chivalry_logic() check_magery_buffs() check_golem_repair() update_mastery_stats() if time.time() % 2 < 0.2: update_pet_levels() 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: Player.ChatSay(33, "All Guard Me") has_issued_guard_command = True else: if IS_TAMER: 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) if __name__ == "__main__": main()