# ======================================================================================= # == ALL-IN-ONE GATHERER SUITE == # ======================================================================================= # AUTHOR: Evilrage # WEBSITE: unchainedscripts.com # # DESCRIPTION: # - THE PERFECT MERGE: Restored the flawless Pack Animal & Lumber logic from v41. # - Mining Suite: Rapid swing looping, auto-smelting, and ghost-ore bypass. # - Cotton Suite: Auto-scans, walks to, and harvests local ripe Cotton/Flax plants. # * Automatically sweeps the ground to pick up harvested bales! # - Weaver Suite: Automatically converts bales to thread, and thread to cloth bolts. # - Auto-Crafting: Automatically crafts replacement pickaxes and hatchets on the fly. # - Anti-Macro Alarm: Built-in Windows audio alert and visual warning for AFK gumps. # - Auto-Hide: Automatically keeps your character hidden while gathering. # ======================================================================================= import Misc import Player import Items import Target import Mobiles import Gumps import Journal import Spells import PathFinding import time import System from System import Int32, Byte from System.Collections.Generic import List from math import sqrt # =========================================================== # 1. CONFIGURATION & CONSTANTS # =========================================================== # COMPLETELY NEW GUMP ID GUMP_ID = 0x1A2B3C4D REFRESH_MS = 200 GUMP_X, GUMP_Y = 500, 300 # --- ANTI-MACRO GUMP ALARM --- ALERT_GUMP_ID = 0x00000000 # TIMING MINING_WAIT_MS = 2500 LUMBER_WAIT_MS = 2200 PAGE_MINING = 0 PAGE_LUMBER = 1 PAGE_COTTON = 2 PAGE_SETTINGS = 3 PAGE_NAMES = ["Mining", "Lumberjack", "Cotton", "Settings"] # Keys (PXR GUILD BRANDED) SV_PACK_CREW = "pxr_pack_crew_list_v2" SV_SATCHEL = "pxr_resource_satchel" SV_AUTO_HIDE = "pxr_auto_hide" # IDs LOG_ID = 0x1BDD BOARD_ID = 0x1BD7 INGOT_ID = 0x1BF2 # COTTON & WEAVING IDs COTTON_PLANT_ID = [0x0C4F, 0x0C50, 0x0C51, 0x0C52, 0x0C53, 0x0C54] FLAX_PLANT_ID = [0x1A4C, 0x1A4D, 0x1A4E, 0x1A4F] RIPE_PLANTS = COTTON_PLANT_ID + FLAX_PLANT_ID BALE_OF_COTTON = 0x0DF9 BUNDLE_OF_FLAX = 0x1A53 HARVESTED_IDS = [BALE_OF_COTTON, BUNDLE_OF_FLAX] SPINNING_WHEEL_IDS = [0x1015, 0x1019] # Decimal: 4117, 4121 LOOM_IDS = [0x105F, 0x1062] # Decimal: 4191, 4194 SPOOL_OF_THREAD_ID = 0x0FA0 # Decimal: 4000 # ARRAYS ORE_IDS = [0x19B7, 0x19B8, 0x19B9, 0x19BA, 0x19B2, 0x19B3, 0x19B4, 0x19B5, 0x19B6, 0x19B1, 0x19B0] GEM_IDS = [0x0F0F, 0x0F10, 0x0F11, 0x0F12, 0x0F13, 0x0F14, 0x0F15, 0x0F16, 0x0F17, 0x0F18, 0x0F19, 0x0F20, 0x0F21, 0x0F22, 0x0F23, 0x0F24, 0x0F25, 0x0F26, 0x0F27, 0x0F28, 0x0F29, 0x0F2A, 0x0F2B, 0x0F2C, 0x0F2D, 0x0F2E, 0x0F2F, 0x0F30, 0x3192, 0x3193, 0x3194, 0x3195, 0x3196, 0x3197, 0x3198, 0x1EA7] FIRE_BEETLE_IDS = [0x031A, 0x00A9] TINKER_TOOL_IDS = [0x1EB8, 0x1EBC] miningTools = [0x0E86, 0x0E85, 0x0FB4, 0x0F39] AXE_TYPES = [0x0F43, 0x0F45, 0x0F47, 0x0F49, 0x0F4B, 0x13FA, 0x1443] TREE_IDS = [0x0C95, 0x0C96, 0x0C99, 0x0C9B, 0x0C9C, 0x0C9D, 0x0C8A, 0x0CA6, 0x0CA8, 0x0CAA, 0x0CAB, 0x0CC3, 0x0CC4, 0x0CC8, 0x0CC9, 0x0CCA, 0x0CCB, 0x0CCC, 0x0CCD, 0x0CD0, 0x0CD3, 0x0CD6, 0x0CDB, 0X0CDA, 0X0CD7, 0x0CE1, 0x0CE0, 0x0CE7, 0x0CE6, 0x0CF6, 0x0CD1, 0x0CDE, 0x0CDD, 0x33A3, 0x0CE4, 0x0CE3, 0x0D2F] ORE_HUES = { 'Iron': 0x0000, 'Dull': 0x0973, 'Shadow': 0x0966, 'Copper': 0x096D, 'Bronze': 0x0972, 'Gold': 0x08A5, 'Agapite': 0x0979, 'Verite': 0x089F, 'Val': 0x08AB } DISPLAY_HUES = { 'Iron': 1152, 'Dull': 2419, 'Shadow': 1109, 'Copper': 1259, 'Bronze': 1260, 'Gold': 53, 'Agapite': 33, 'Verite': 68, 'Val': 1156 } WOOD_HUES = { 'Log': 0x0000, 'Oak': 0x07DA, 'Ash': 0x04A7, 'Yew': 0x04A8, 'Heart': 0x04A9, 'Blood': 0x04AA, 'Frost': 0x047F } WOOD_DISPLAY_HUES = { 'Log': 1152, 'Oak': 1260, 'Ash': 1150, 'Yew': 53, 'Heart': 1161, 'Blood': 33, 'Frost': 1151 } _ore_counts = {k: 0 for k in ORE_HUES} _wood_counts = {k: 0 for k in WOOD_HUES} # =========================================================== # 2. GLOBAL STATE # =========================================================== _running = True _current_page = PAGE_MINING _status_msg = "Idle." _runtime_mining = False _runtime_lumber = False _runtime_cotton = False _runtime_weaver = False _pack_crew = [] _satchel_serial = 0 _auto_hide_enabled = False _last_hide_attempt = 0 _start_time = time.time() _total_items_gained = 0 _lumber_mode = 2 _lumber_trees = [] _lumber_tree_idx = 0 _lumber_visited = [] _lumber_fails = 0 _mining_mode = 1 _current_pet_index = 0 _cotton_mode = 1 LAST_GUI_HASH = 0 last_button_id = 0 BTN_CLOSE = 9000 BTN_PAGE_NEXT = 9001 BTN_PAGE_PREV = 9002 BTN_RUN_MINING = 9100 BTN_MINING_MODE_SELF = 9101 BTN_MINING_MODE_STRIP = 9102 BTN_MINING_MODE_RECALL = 9103 BTN_RUN_LUMBER = 9200 BTN_LUMBER_MODE_SELF = 9201 BTN_LUMBER_MODE_AUTO = 9202 BTN_LUMBER_MODE_SEMI = 9203 BTN_COTTON_RUN = 9300 BTN_RUN_WEAVER = 9304 BTN_ADD_PET = 9400 BTN_CLR_CREW = 9401 BTN_SET_SATCHEL = 9402 BTN_CLR_SATCHEL = 9403 BTN_AUTO_HIDE = 9404 # =========================================================== # 3. HELPER FUNCTIONS # =========================================================== def get_dist_to_mob(mob): if not mob: return 999 return max(abs(Player.Position.X - mob.Position.X), abs(Player.Position.Y - mob.Position.Y)) def get_dist_to_pos(x, y): return max(abs(Player.Position.X - x), abs(Player.Position.Y - y)) def save_pack_crew(): if not _pack_crew: if Misc.CheckSharedValue(SV_PACK_CREW): Misc.RemoveSharedValue(SV_PACK_CREW) else: val = "|".join(str(x) for x in _pack_crew) Misc.SetSharedValue(SV_PACK_CREW, val) def load_settings(): global _pack_crew, _satchel_serial, _auto_hide_enabled if Misc.CheckSharedValue(SV_PACK_CREW): raw = Misc.ReadSharedValue(SV_PACK_CREW) if raw: try: _pack_crew = [int(x) for x in raw.split('|') if x and x.lstrip('-').isdigit()] except: _pack_crew = [] else: _pack_crew = [] if Misc.CheckSharedValue(SV_SATCHEL): _satchel_serial = int(Misc.ReadSharedValue(SV_SATCHEL)) if Misc.CheckSharedValue(SV_AUTO_HIDE): _auto_hide_enabled = bool(int(Misc.ReadSharedValue(SV_AUTO_HIDE))) def get_current_bag_serial(): global _current_pet_index if not _pack_crew: return None if _current_pet_index >= len(_pack_crew): _current_pet_index = 0 s = _pack_crew[_current_pet_index] if not isinstance(s, int) or s <= 0: return None # Check if Mobile (Pet) FIRST mob = Mobiles.FindBySerial(s) if mob: if mob.Backpack: return mob.Backpack.Serial # Check if Item (Bag/Box) item = Items.FindBySerial(s) if item: return s return s def deposit_items(item_list): global _status_msg, _current_pet_index if not item_list: return Player.HeadMessage(68, "Unloading items...") for item in item_list: check_stop() failures = 0 while True: check_stop() current_s = 0 if _current_pet_index < len(_pack_crew): current_s = _pack_crew[_current_pet_index] mob_check = Mobiles.FindBySerial(current_s) if mob_check: if get_dist_to_mob(mob_check) > 2: Player.HeadMessage(55, "Waiting for {}...".format(mob_check.Name)) SmartPause(1000) continue if failures >= 5: Player.HeadMessage(38, "Bag Full. Switching...") _current_pet_index += 1 failures = 0 if _current_pet_index >= len(_pack_crew): _current_pet_index = 0 return target_serial = get_current_bag_serial() if target_serial is None: return if item.Container == target_serial: break try: Items.Move(item, target_serial, 0) SmartPause(1000) except: failures += 1 continue if Items.FindBySerial(item.Serial) and item.Container != target_serial: failures += 1 else: break def get_hatchet(): for layer in ['LeftHand', 'RightHand']: item = Player.GetItemOnLayer(layer) if item and item.ItemID in AXE_TYPES: return item for axe_id in AXE_TYPES: found = Items.FindByID(axe_id, -1, Player.Backpack.Serial) if found: return found return None def craft_tool(tool_type): global _status_msg tinker_tool = None for tid in TINKER_TOOL_IDS: found = Items.FindByID(tid, -1, Player.Backpack.Serial) if found: tinker_tool = found break if not tinker_tool: Player.HeadMessage(33, "No Tinker Tool!") return if Items.BackpackCount(INGOT_ID, -1) < 4: Player.HeadMessage(33, "Need Ingots!") return _status_msg = "Crafting " + tool_type + "..." Player.HeadMessage(68, "Crafting " + tool_type) if tinker_tool.Serial > 0: Items.UseItem(tinker_tool.Serial) if not Gumps.WaitForGump(CRAFT_GUMP_ID, 2000): return Gumps.SendAction(CRAFT_GUMP_ID, BTN_TOOLS_TAB) if not Gumps.WaitForGump(CRAFT_GUMP_ID, 2000): return if tool_type == "pickaxe": Gumps.SendAction(CRAFT_GUMP_ID, BTN_MAKE_PICK) elif tool_type == "hatchet": Gumps.SendAction(CRAFT_GUMP_ID, BTN_MAKE_AXE) Misc.Pause(1000) Gumps.CloseGump(CRAFT_GUMP_ID) def check_and_craft_tools(): if _runtime_mining: lh = Player.GetItemOnLayer('LeftHand') rh = Player.GetItemOnLayer('RightHand') if lh and lh.ItemID in miningTools: return if rh and rh.ItemID in miningTools: return has_tool = False for t in miningTools: if Items.FindByID(t, -1, Player.Backpack.Serial): has_tool = True break if not has_tool: craft_tool("pickaxe") if _runtime_lumber: lh = Player.GetItemOnLayer('LeftHand') rh = Player.GetItemOnLayer('RightHand') if lh and lh.ItemID in AXE_TYPES: return if rh and rh.ItemID in AXE_TYPES: return has_tool = False for t in AXE_TYPES: if Items.FindByID(t, -1, Player.Backpack.Serial): has_tool = True break if not has_tool: craft_tool("hatchet") def cut_tree_self(): hatchet = get_hatchet() if not hatchet: check_and_craft_tools() hatchet = get_hatchet() if not hatchet: return False if not Player.GetItemOnLayer('LeftHand') and not Player.GetItemOnLayer('RightHand'): Player.EquipItem(hatchet) Misc.Pause(600) Items.UseItem(hatchet) if not Target.WaitForTarget(1200, False): return False Target.TargetExecute(Player.Serial) Misc.Pause(600) return True def count_resources(): global _ore_counts, _wood_counts tmp_ore = {k: 0 for k in ORE_HUES} tmp_wood = {k: 0 for k in WOOD_HUES} containers = [Player.Backpack.Serial] if _satchel_serial: containers.append(_satchel_serial) for s in _pack_crew: item = Items.FindBySerial(s) if item: containers.append(s) else: mob = Mobiles.FindBySerial(s) if mob and mob.Backpack: containers.append(mob.Backpack.Serial) for c_serial in containers: cont = Items.FindBySerial(c_serial) if not cont: continue for item in cont.Contains: if item.ItemID in ORE_IDS or item.ItemID == INGOT_ID: found = False for name, hue in ORE_HUES.items(): if item.Hue == hue: tmp_ore[name] += item.Amount found = True break if not found: tmp_ore['Iron'] += item.Amount if item.ItemID == LOG_ID or item.ItemID == BOARD_ID: found = False for name, hue in WOOD_HUES.items(): if item.Hue == hue: tmp_wood[name] += item.Amount found = True break if not found: tmp_wood['Log'] += item.Amount _ore_counts = tmp_ore _wood_counts = tmp_wood def poll_buttons(): global last_button_id if Gumps.HasGump(ALERT_GUMP_ID): try: System.Media.SystemSounds.Exclamation.Play() except: pass Player.HeadMessage(33, "!!! GUMP DETECTED - WAKE UP !!!") 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 handle_button(bid) CheckAndDrawGUI(force=True) def CheckAndDrawGUI(force=False): global LAST_GUI_HASH current_state = "{}_{}_{}_{}_{}_{}_{}_{}_{}".format( _current_page, _status_msg, _runtime_mining, _runtime_lumber, _runtime_cotton, _mining_mode, _lumber_mode, _auto_hide_enabled, _runtime_weaver ) for k in _ore_counts: current_state += str(_ore_counts[k]) for k in _wood_counts: current_state += str(_wood_counts[k]) new_hash = hash(current_state) if force or (new_hash != LAST_GUI_HASH): LAST_GUI_HASH = new_hash render_gui() def SmartPause(ms): steps = int(ms / 50) for i in range(steps): if not _running: raise Exception("STOPPED") poll_buttons() if (_runtime_mining or _runtime_lumber or _runtime_cotton or _runtime_weaver) and not _running: raise Exception("STOPPED") Misc.Pause(50) rem = ms % 50 if rem > 0: Misc.Pause(rem) def check_stop(): if not _running: raise Exception("STOPPED") if not _runtime_mining and not _runtime_lumber and not _runtime_cotton and not _runtime_weaver: raise Exception("STOPPED") def cut_logs_to_boards(): global _status_msg while True: check_stop() logs = [i for i in Player.Backpack.Contains if i.ItemID == LOG_ID] if not logs: return True _status_msg = "Cutting logs..." hatchet = get_hatchet() if not hatchet: check_and_craft_tools() hatchet = get_hatchet() if not hatchet: return False if not Player.GetItemOnLayer('LeftHand') and not Player.GetItemOnLayer('RightHand'): if hatchet.Container == Player.Backpack.Serial: pass else: Player.EquipItem(hatchet) SmartPause(600) for log in logs: check_stop() if not Items.FindBySerial(log.Serial): continue Items.UseItem(hatchet) if Target.WaitForTarget(1000, False): Target.TargetExecute(log.Serial) SmartPause(600) SmartPause(200) def smelt_ore(): beetle = None f = Mobiles.Filter() f.RangeMax = 3 f.Bodies = List[Int32]([Int32(x) for x in FIRE_BEETLE_IDS]) mobs = Mobiles.ApplyFilter(f) if mobs: beetle = mobs[0] if not beetle: return ignored_ores = [] ore_attempts = {} while True: check_stop() ore_to_smelt = None for item in Player.Backpack.Contains: if item.ItemID in ORE_IDS and item.Serial not in ignored_ores: ore_to_smelt = item break if not ore_to_smelt: break s = ore_to_smelt.Serial ore_attempts[s] = ore_attempts.get(s, 0) + 1 if ore_attempts[s] > 3: ignored_ores.append(s) continue Journal.Clear() Items.UseItem(ore_to_smelt) Target.WaitForTarget(1000, False) Target.TargetExecute(beetle.Serial) SmartPause(600) if Journal.Search("not enough metal-bearing") or Journal.Search("combine it") or Journal.Search("You cannot smelt that"): ignored_ores.append(s) # =========================================================== # 6. MAIN LOOPS # =========================================================== def wait_for_depletion_or_threshold(): Journal.Clear() consecutive_fails = 0 while not Journal.Search("not enough wood"): check_stop() if Player.Weight >= Player.MaxWeight: break if Journal.Search("You can't use an axe on that"): Misc.SendMessage("Invalid target/Ground. Skipping.", 33) break if Journal.Search("far away"): Misc.SendMessage("Too far. Skipping.", 33) break cut_tree_self() SmartPause(900) if Journal.Search("You put"): consecutive_fails = 0 Journal.Clear() else: consecutive_fails += 1 if consecutive_fails >= 6: Misc.SendMessage("Ghost Tree detected (No logs). Moving on.", 38) break Journal.Clear() def scan_trees(range_val): global _lumber_trees, _lumber_tree_idx _lumber_trees = [] px = Player.Position.X py = Player.Position.Y for x in range(px - range_val, px + range_val + 1): for y in range(py - range_val, py + range_val + 1): statics = Statics.GetStaticsTileInfo(x, y, 0) for tile in statics: if tile.StaticID in TREE_IDS: found = False for t in _lumber_trees: if t[0] == x and t[1] == y: found = True break if not found: _lumber_trees.append((x, y, tile.StaticZ, tile.StaticID)) _lumber_trees.sort(key=lambda t: sqrt((t[0]-px)**2 + (t[1]-py)**2)) _lumber_tree_idx = 0 def move_to_tree_spot(tx, ty): global _status_msg offsets = [(0, 1), (1, 0), (-1, 0), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)] px = Player.Position.X py = Player.Position.Y offsets.sort(key=lambda o: abs((tx+o[0])-px) + abs((ty+o[1])-py)) for off in offsets: check_stop() dest_x = tx + off[0] dest_y = ty + off[1] route = PathFinding.Route() route.X = dest_x route.Y = dest_y route.MaxRetry = 3 route.StopIfStuck = False if PathFinding.Go(route): _status_msg = "Moving..." SmartPause(200) timeout = 0 while get_dist_to_pos(dest_x, dest_y) > 0 and timeout < 30: check_stop() SmartPause(50) timeout += 1 return True return False def run_lumber(): global _status_msg, _runtime_lumber, _lumber_trees, _lumber_tree_idx check_stop() cut_logs_to_boards() check_and_craft_tools() to_move = [i for i in Player.Backpack.Contains if i.ItemID == BOARD_ID or i.ItemID == LOG_ID or i.ItemID in GEM_IDS] if to_move: deposit_items(to_move) check_stop() if Player.Weight >= Player.MaxWeight: _status_msg = "FULL! Stopped." _runtime_lumber = False return hatchet = get_hatchet() if not hatchet: check_and_craft_tools() hatchet = get_hatchet() if not hatchet: _status_msg = "No Axe!" _runtime_lumber = False return if not Player.GetItemOnLayer('LeftHand') and not Player.GetItemOnLayer('RightHand'): Player.EquipItem(hatchet) SmartPause(600) if _lumber_mode == 2: # AUTO if not _lumber_trees or _lumber_tree_idx >= len(_lumber_trees): scan_trees(20) if not _lumber_trees: _status_msg = "No trees found!" _runtime_lumber = False return tree = _lumber_trees[_lumber_tree_idx] if get_dist_to_pos(tree[0], tree[1]) > 1: if not move_to_tree_spot(tree[0], tree[1]): _status_msg = "Can't reach tree, skipping." _lumber_tree_idx += 1 return _status_msg = "Chopping..." check_stop() Items.UseItem(hatchet) if Target.WaitForTarget(1000, False): Target.TargetExecute(tree[0], tree[1], tree[2], tree[3]) SmartPause(LUMBER_WAIT_MS) wait_for_depletion_or_threshold() _lumber_tree_idx += 1 elif _lumber_mode == 1: # SELF if not _lumber_trees or _lumber_tree_idx >= len(_lumber_trees): scan_trees(2) if not _lumber_trees: _status_msg = "No trees nearby." _runtime_lumber = False return tree = _lumber_trees[_lumber_tree_idx] _status_msg = "Chopping..." check_stop() Items.UseItem(hatchet) if Target.WaitForTarget(1000, False): Target.TargetExecute(tree[0], tree[1], tree[2], tree[3]) SmartPause(LUMBER_WAIT_MS) if Journal.Search("not enough wood"): _lumber_tree_idx += 1 elif _lumber_mode == 3: # SEMI _status_msg = "Chopping (Semi)..." check_stop() Items.UseItem(hatchet) if Target.WaitForTarget(1000, False): Target.TargetExecute(Player.Serial) SmartPause(LUMBER_WAIT_MS) count_resources() def run_mining(): global _status_msg, _runtime_mining check_stop() smelt_ore() check_and_craft_tools() to_move = [i for i in Player.Backpack.Contains if i.ItemID == INGOT_ID or i.ItemID in GEM_IDS] if to_move: deposit_items(to_move) check_stop() if Player.Weight >= Player.MaxWeight: _status_msg = "FULL! Stopped." _runtime_mining = False return tool = None lh = Player.GetItemOnLayer('LeftHand') rh = Player.GetItemOnLayer('RightHand') if lh and lh.ItemID in miningTools: tool = lh if rh and rh.ItemID in miningTools: tool = rh if not tool: for t in miningTools: tool = Items.FindByID(t, -1, Player.Backpack.Serial) if tool: break if not tool: check_and_craft_tools() tool = Items.FindByID(0xE86, -1, Player.Backpack.Serial) if not tool: _status_msg = "No Tool!" _runtime_mining = False return if not Player.GetItemOnLayer('LeftHand') and not Player.GetItemOnLayer('RightHand'): Player.EquipItem(tool) SmartPause(600) _status_msg = "Digging..." check_stop() swing_count = 0 while _running and _runtime_mining and swing_count < 10: check_stop() if Player.Weight >= Player.MaxWeight: break Target.Cancel() Misc.Pause(100) Journal.Clear() if tool.Serial > 0: Items.UseItem(tool.Serial) if Target.WaitForTarget(1500, False): Target.TargetExecute(Player.Serial) SmartPause(MINING_WAIT_MS) else: break if Journal.Search("no metal") or Journal.Search("mined there") or Journal.Search("far away") or Journal.Search("cannot be seen"): Player.HeadMessage(68, "Vein Empty. Move on.") break swing_count += 1 count_resources() CheckAndDrawGUI() def run_cotton(): global _status_msg, _runtime_cotton check_stop() item_list = [] for hid in HARVESTED_IDS: found = Items.FindAllByID(hid, -1, Player.Backpack.Serial, -1, False) if found: item_list.extend(found) if item_list: deposit_items(item_list) check_stop() if Player.Weight >= Player.MaxWeight: _status_msg = "FULL! Stopped." _runtime_cotton = False return f_ground = Items.Filter() f_ground.Enabled = True f_ground.OnGround = True f_ground.RangeMax = 2 f_ground.Graphics = List[Int32]([Int32(x) for x in HARVESTED_IDS]) ground_items = Items.ApplyFilter(f_ground) if ground_items: _status_msg = "Looting ground..." for gi in ground_items: check_stop() Items.Move(gi, Player.Backpack.Serial, 0) SmartPause(600) return _status_msg = "Scanning Cotton..." f = Items.Filter() f.Enabled = True f.OnGround = True f.RangeMax = 12 f.Graphics = List[Int32]([Int32(x) for x in RIPE_PLANTS]) plants = Items.ApplyFilter(f) if not plants: _status_msg = "No plants nearby." SmartPause(1000) return python_plants = [p for p in plants] python_plants.sort(key=lambda p: get_dist_to_pos(p.Position.X, p.Position.Y)) target_plant = python_plants[0] if get_dist_to_pos(target_plant.Position.X, target_plant.Position.Y) > 1: _status_msg = "Walking to plant..." route = PathFinding.Route() route.X = target_plant.Position.X route.Y = target_plant.Position.Y route.MaxRetry = 3 route.StopIfStuck = False if PathFinding.Go(route): timeout = 0 while get_dist_to_pos(target_plant.Position.X, target_plant.Position.Y) > 1 and timeout < 30: check_stop() SmartPause(100) timeout += 1 if get_dist_to_pos(target_plant.Position.X, target_plant.Position.Y) <= 2: _status_msg = "Picking..." check_stop() Items.UseItem(target_plant.Serial) SmartPause(800) ground_items2 = Items.ApplyFilter(f_ground) if ground_items2: _status_msg = "Looting bale..." for gi in ground_items2: check_stop() Items.Move(gi, Player.Backpack.Serial, 0) SmartPause(600) def run_weaver(): global _status_msg, _runtime_weaver check_stop() raw_mats = [] for hid in HARVESTED_IDS: found = Items.FindAllByID(hid, -1, Player.Backpack.Serial, -1, False) if found: raw_mats.extend(found) if raw_mats: f = Items.Filter() f.Enabled = True f.OnGround = True f.RangeMax = 3 f.Graphics = List[Int32]([Int32(x) for x in SPINNING_WHEEL_IDS]) wheels = Items.ApplyFilter(f) if not wheels: _status_msg = "No Spinning Wheel nearby!" SmartPause(1000) return py_wheels = [w for w in wheels] py_wheels.sort(key=lambda w: get_dist_to_pos(w.Position.X, w.Position.Y)) wheel = py_wheels[0] _status_msg = "Spinning thread..." for mat in raw_mats: check_stop() Items.UseItem(mat.Serial) Target.WaitForTarget(1000, False) Target.TargetExecute(wheel.Serial) SmartPause(4000) return threads = Items.FindAllByID(SPOOL_OF_THREAD_ID, -1, Player.Backpack.Serial, -1, False) if threads: f = Items.Filter() f.Enabled = True f.OnGround = True f.RangeMax = 3 f.Graphics = List[Int32]([Int32(x) for x in LOOM_IDS]) looms = Items.ApplyFilter(f) if not looms: _status_msg = "No Loom nearby!" SmartPause(1000) return py_looms = [l for l in looms] py_looms.sort(key=lambda l: get_dist_to_pos(l.Position.X, l.Position.Y)) loom = py_looms[0] _status_msg = "Weaving cloth..." for thread in threads: check_stop() Items.UseItem(thread.Serial) Target.WaitForTarget(1000, False) Target.TargetExecute(loom.Serial) SmartPause(500) return _status_msg = "Out of materials. Stopped." _runtime_weaver = False Player.HeadMessage(68, "Finished weaving cloth!") # =========================================================== # 7. GUI RENDERING # =========================================================== def mining_mode_label(): if _mining_mode == 1: return "Self Pilot" if _mining_mode == 2: return "Strip Mine" if _mining_mode == 3: return "Recall Mining" return "Unknown" def lumber_mode_label(): if _lumber_mode == 1: return "Self Pilot" if _lumber_mode == 2: return "Auto Pilot" if _lumber_mode == 3: return "Semi Manual" return "Unknown" def draw_counters(gd, x_start, y_start, data_dict, hues_dict): keys = list(data_dict.keys()) half = (len(keys) // 2) + 1 col_1 = keys[:half] col_2 = keys[half:] y = y_start for k in col_1: qty = data_dict.get(k, 0) hue = hues_dict.get(k, 1152) Gumps.AddLabel(gd, x_start, y, hue, "{0}: {1}".format(k, qty)) y += 20 y = y_start for k in col_2: qty = data_dict.get(k, 0) hue = hues_dict.get(k, 1152) Gumps.AddLabel(gd, x_start + 110, y, hue, "{0}: {1}".format(k, qty)) y += 20 def render_mining_page(gd): mode_lbl = mining_mode_label() run_lbl = "ON" if _runtime_mining else "OFF" Gumps.AddLabel(gd, 15, 40, 68, "Mining Suite") Gumps.AddLabel(gd, 15, 60, 81, "Mode: {0}".format(mode_lbl)) Gumps.AddLabel(gd, 15, 80, 81, "Run: {0}".format(run_lbl)) col1 = 68 if _mining_mode == 1 else 33 col2 = 68 if _mining_mode == 2 else 33 col3 = 68 if _mining_mode == 3 else 33 Gumps.AddButton(gd, 15, 110, 4017, 4018, BTN_MINING_MODE_SELF, 1, 0) Gumps.AddLabel(gd, 45, 112, col1, "Self Pilot") Gumps.AddButton(gd, 15, 140, 4017, 4018, BTN_MINING_MODE_STRIP, 1, 0) Gumps.AddLabel(gd, 45, 142, col2, "Strip Mine") Gumps.AddButton(gd, 15, 170, 4017, 4018, BTN_MINING_MODE_RECALL, 1, 0) Gumps.AddLabel(gd, 45, 172, col3, "Recall Mining") Gumps.AddButton(gd, 300, 40, 4017, 4018, BTN_RUN_MINING, 1, 0) Gumps.AddLabel(gd, 330, 42, 68 if _runtime_mining else 33, "Start/Stop") Gumps.AddLabel(gd, 200, 100, 88, "-- Ore Counts --") draw_counters(gd, 200, 120, _ore_counts, DISPLAY_HUES) def render_lumber_page(gd): mode_lbl = lumber_mode_label() run_lbl = "ON" if _runtime_lumber else "OFF" Gumps.AddLabel(gd, 15, 40, 68, "Lumberjack Suite") Gumps.AddLabel(gd, 15, 60, 81, "Mode: {0}".format(mode_lbl)) Gumps.AddLabel(gd, 15, 80, 81, "Run: {0}".format(run_lbl)) col1 = 68 if _lumber_mode == 1 else 33 col2 = 68 if _lumber_mode == 2 else 33 col3 = 68 if _lumber_mode == 3 else 33 Gumps.AddButton(gd, 15, 110, 4017, 4018, BTN_LUMBER_MODE_SELF, 1, 0) Gumps.AddLabel(gd, 45, 112, col1, "Self Pilot") Gumps.AddButton(gd, 15, 140, 4017, 4018, BTN_LUMBER_MODE_AUTO, 1, 0) Gumps.AddLabel(gd, 45, 142, col2, "Auto Pilot") Gumps.AddButton(gd, 15, 170, 4017, 4018, BTN_LUMBER_MODE_SEMI, 1, 0) Gumps.AddLabel(gd, 45, 172, col3, "Semi Manual") Gumps.AddButton(gd, 300, 40, 4017, 4018, BTN_RUN_LUMBER, 1, 0) Gumps.AddLabel(gd, 330, 42, 68 if _runtime_lumber else 33, "Start/Stop") Gumps.AddLabel(gd, 200, 100, 88, "-- Wood Counts --") draw_counters(gd, 200, 120, _wood_counts, WOOD_DISPLAY_HUES) def render_cotton_page(gd): run_lbl = "ON" if _runtime_cotton else "OFF" weave_lbl = "ON" if _runtime_weaver else "OFF" Gumps.AddLabel(gd, 15, 40, 68, "Cotton & Flax Suite") Gumps.AddLabel(gd, 15, 60, 81, "Mode: Auto-Picker & Stasher") Gumps.AddLabel(gd, 15, 80, 81, "Run Picker: {0}".format(run_lbl)) Gumps.AddButton(gd, 300, 40, 4017, 4018, BTN_COTTON_RUN, 1, 0) Gumps.AddLabel(gd, 330, 42, 68 if _runtime_cotton else 33, "Start Picker") Gumps.AddLabel(gd, 15, 120, 68, "Weaver Suite (Cloth Bolts)") Gumps.AddLabel(gd, 15, 140, 81, "Run Weaver: {0}".format(weave_lbl)) Gumps.AddButton(gd, 300, 120, 4017, 4018, BTN_RUN_WEAVER, 1, 0) Gumps.AddLabel(gd, 330, 122, 68 if _runtime_weaver else 33, "Create Cloth") def render_settings_page(gd): Gumps.AddLabel(gd, 15, 40, 68, "Settings") Gumps.AddButton(gd, 20, 70, 4008, 4010, BTN_ADD_PET, 1, 0) Gumps.AddLabel(gd, 55, 72, 68, "Add Bag to Crew (+)") Gumps.AddButton(gd, 20, 95, 4017, 4019, BTN_CLR_CREW, 1, 0) Gumps.AddLabel(gd, 55, 97, 33, "Clear Crew") Gumps.AddLabel(gd, 220, 50, 88, "Bag List:") y_list = 70 if not _pack_crew: Gumps.AddLabel(gd, 220, y_list, 33, "No bags set.") else: for i, s in enumerate(_pack_crew): if i > 5: break item = Items.FindBySerial(s) mob = Mobiles.FindBySerial(s) name = "Unknown" if mob: name = mob.Name elif item: name = item.Name if item.Name else "Bag" Gumps.AddLabel(gd, 220, y_list, 68 if i==0 else 88, "#{0}: {1}".format(i+1, name)) y_list += 20 col = 68 if _auto_hide_enabled else 33 Gumps.AddButton(gd, 20, 235, 4008, 4010, BTN_AUTO_HIDE, 1, 0) Gumps.AddLabel(gd, 55, 237, col, "Auto Hide") def render_gui(): gd = Gumps.CreateGump(movable=True) Gumps.AddPage(gd, 0) w, h = 430, 420 Gumps.AddBackground(gd, 0, 0, w, h, 9270) Gumps.AddAlphaRegion(gd, 0, 0, w, h) Gumps.AddLabel(gd, 110, 5, 68, "All-In-One Gatherer (Domination)") Gumps.AddButton(gd, w-35, 8, 4017, 4018, BTN_CLOSE, 1, 0) if _current_page == PAGE_MINING: render_mining_page(gd) elif _current_page == PAGE_LUMBER: render_lumber_page(gd) elif _current_page == PAGE_COTTON: render_cotton_page(gd) elif _current_page == PAGE_SETTINGS: render_settings_page(gd) Gumps.AddButton(gd, 15, h-35, 4014, 4016, BTN_PAGE_PREV, 1, 0) Gumps.AddButton(gd, w-80, h-35, 4005, 4007, BTN_PAGE_NEXT, 1, 0) Gumps.AddLabel(gd, 110, h-33, 81, "Status: {0}".format(_status_msg[:40])) Gumps.SendGump(GUMP_ID, Player.Serial, GUMP_X, GUMP_Y, gd.gumpDefinition, gd.gumpStrings) def handle_button(btn): try: global _running, _current_page, _runtime_mining, _runtime_lumber, _runtime_cotton, _runtime_weaver, _status_msg global _mining_mode, _lumber_mode, _cotton_mode, _auto_hide_enabled, _pack_crew if btn == BTN_CLOSE: _running = False return if btn == BTN_PAGE_NEXT: _current_page = (_current_page + 1) % len(PAGE_NAMES) return if btn == BTN_PAGE_PREV: _current_page = (_current_page - 1) % len(PAGE_NAMES) return if btn == BTN_RUN_MINING: _runtime_mining = not _runtime_mining _runtime_lumber = False _runtime_cotton = False _runtime_weaver = False _status_msg = "Mining " + ("ON" if _runtime_mining else "OFF") if btn == BTN_RUN_LUMBER: _runtime_lumber = not _runtime_lumber _runtime_mining = False _runtime_cotton = False _runtime_weaver = False _status_msg = "Lumber " + ("ON" if _runtime_lumber else "OFF") if btn == BTN_COTTON_RUN: _runtime_cotton = not _runtime_cotton _runtime_mining = False _runtime_lumber = False _runtime_weaver = False _status_msg = "Cotton " + ("ON" if _runtime_cotton else "OFF") if btn == BTN_RUN_WEAVER: _runtime_weaver = not _runtime_weaver _runtime_mining = False _runtime_lumber = False _runtime_cotton = False _status_msg = "Weaver " + ("ON" if _runtime_weaver else "OFF") if btn == BTN_LUMBER_MODE_SELF: _lumber_mode = 1 if btn == BTN_LUMBER_MODE_AUTO: _lumber_mode = 2 if btn == BTN_LUMBER_MODE_SEMI: _lumber_mode = 3 if btn == BTN_MINING_MODE_SELF: _mining_mode = 1 if btn == BTN_ADD_PET: s = Target.PromptTarget("Add Bag") if s > 0 and s not in _pack_crew: _pack_crew.append(s) save_pack_crew() if btn == BTN_CLR_CREW: _pack_crew = [] save_pack_crew() if btn == BTN_AUTO_HIDE: _auto_hide_enabled = not _auto_hide_enabled Misc.SetSharedValue(SV_AUTO_HIDE, 1 if _auto_hide_enabled else 0) except Exception as e: Misc.SendMessage("Config Error: " + str(e), 33) finally: CheckAndDrawGUI(force=True) # =========================================================== # 8. MAIN EXECUTION # =========================================================== load_settings() CheckAndDrawGUI(force=True) last_btn = 0 _count_timer = time.time() while _running: try: poll_buttons() if (time.time() - _count_timer) > 0.5: count_resources() _count_timer = time.time() if not _runtime_mining and not _runtime_lumber and not _runtime_cotton and not _runtime_weaver: CheckAndDrawGUI() if _runtime_mining: run_mining() CheckAndDrawGUI() elif _runtime_lumber: run_lumber() CheckAndDrawGUI() elif _runtime_cotton: run_cotton() CheckAndDrawGUI() elif _runtime_weaver: run_weaver() CheckAndDrawGUI() if _auto_hide_enabled and not Player.IsGhost and Player.Visible: if (time.time() - _last_hide_attempt) > 6: Player.UseSkill("Hiding") _last_hide_attempt = time.time() except Exception as e: err_str = str(e) if "STOPPED" in err_str or "ThreadAbortException" in err_str: _status_msg = "Stopped." CheckAndDrawGUI(force=True) else: Misc.SendMessage("Error: " + err_str, 33) Misc.Pause(REFRESH_MS) Gumps.CloseGump(GUMP_ID)