--[[ Auto Auction / Auto Sell / Pathfinder - Storage Hunters: Open World Uses WindUI for the interface. - Auction tab: monitors the bidding minigame and auto-bids when cursor is in the zone. - Sell tab: monitors Quick Sell rate + vehicle load weight and auto-sells. - Pathfinder tab: state machine automates the full auction loop (walk → trigger → bid → collect). ]] -- Load WindUI from the dist URL directly local WindUI = loadstring(game:HttpGet("https://raw.githubusercontent.com/Footagesus/WindUI/main/dist/main.lua"))() local Players = game:GetService("Players") local RunService = game:GetService("RunService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local PathfindingService = game:GetService("PathfindingService") local LocalPlayer = Players.LocalPlayer local PlayerGui = LocalPlayer:WaitForChild("PlayerGui") -- Remote references local AuctionEvents = ReplicatedStorage:WaitForChild("Events"):WaitForChild("Auction") local BidRemote = AuctionEvents:WaitForChild("Bid") local LeaveAuctionRemote = AuctionEvents:WaitForChild("LeaveAuction") local Pawn = ReplicatedStorage:WaitForChild("Events"):WaitForChild("Pawn") local GetPawnState = Pawn:WaitForChild("GetPawnState") local GetSellableItems = Pawn:WaitForChild("GetSellableItems") local SellItems = Pawn:WaitForChild("SellItems") local RateChanged = Pawn:WaitForChild("RateChanged") local UIEvents = ReplicatedStorage:WaitForChild("Events"):WaitForChild("UI") local VehicleWeightUpdate = UIEvents:WaitForChild("VehicleWeightUpdate") -- Items module — used to look up category for trophy/accessory filtering -- Loaded via decompile to avoid "Cannot require a RobloxScript module from a non RobloxScript context" errors local ItemsModule = (function() local ok, result = pcall(function() return loadstring(decompile(ReplicatedStorage.Modules.Items))() end) if ok then return result end return {} end)() -- ── Area-to-garage mapping for pathfinder toggles ── local AREA_GARAGES = { ["Junk Yard"] = { "Scrap Garage" }, ["Back Alley"] = { "Shop Front" }, ["Farmyard"] = { "Stable Garage", "Barn Garage" }, ["Shipyard"] = { "Small Container Garage", "Large Container Garage", "Warehouse Garage" }, } -- ── State via getgenv() so re-running cleans up old state ── getgenv().AutoAuction = getgenv().AutoAuction or {} local State = getgenv().AutoAuction -- Auction state State.BidEnabled = false -- Sell state State.SellEnabled = false State.MinSellRate = -15 -- minimum rate percentage (slider: -50..+50) State.MinWeight = 0 -- minimum weight in kg (slider: 0..100) State.CurrentWeight = 0 -- current vehicle load weight State.CurrentRate = 1.0 -- current pawn rate multiplier State.SellCooldown = 0 -- cooldown timer to avoid spam State.SellSyncing = false -- guard against overlapping sell cycles State.SaveTrophies = true -- exclude Trophy-category items from auto-sell State.SaveAccessories = true -- exclude Accessories-category items from auto-sell -- Pathfinder state State.PathfinderEnabled = false State.AreaToggles = State.AreaToggles or {} for area in pairs(AREA_GARAGES) do if State.AreaToggles[area] == nil then State.AreaToggles[area] = true end end State.PathfinderStatus = "Idle" State.PathfinderPhase = "Idle" State._pathfinderRunning = false -- ── Helper: format rate as percentage string ── local function formatRate(rate) local pct = math.floor((rate - 1) * 100 + 0.5) if pct >= 0 then return "+" .. pct .. "%" end return pct .. "%" end -- ── Helper: get rate as integer percent ── local function ratePercent(rate) return math.floor((rate - 1) * 100 + 0.5) end -- ── Helper: get character root position ── local function getRoot() local char = LocalPlayer.Character if not char then return nil end local root = char:FindFirstChild("HumanoidRootPart") if not root then return nil end return root end -- ── Helper: get humanoid ── local function getHumanoid() local char = LocalPlayer.Character if not char then return nil end return char:FindFirstChildOfClass("Humanoid") end -- ── Helper: find nearest EnterAuction prompt matching enabled areas ── local function findNearestAuction() local root = getRoot() if not root then return nil end local rootPos = root.Position local bestDist = math.huge local bestPrompt = nil for _, prompt in ipairs(workspace:GetDescendants()) do if not (prompt:IsA("ProximityPrompt") and prompt.Name == "EnterAuction") then continue end local garageType = prompt.ObjectText -- Check if this garage type belongs to an enabled area local areaMatch = false local areaName = nil for area, garages in pairs(AREA_GARAGES) do if State.AreaToggles[area] then for _, g in ipairs(garages) do if g == garageType then areaMatch = true areaName = area break end end end if areaMatch then break end end if not areaMatch then continue end local promptPart = prompt.Parent if not promptPart then continue end local dist = (promptPart.Position - rootPos).Magnitude if dist < bestDist then bestDist = dist bestPrompt = { prompt = prompt, promptPart = promptPart, position = promptPart.Position, garageType = garageType, areaName = areaName, distance = dist, } end end return bestPrompt end -- ── Helper: pathfind and walk to a target position ── local function walkTo(targetPos, timeoutSeconds) local hum = getHumanoid() local root = getRoot() if not hum or not root then task.wait(1) return false end local startTime = tick() while tick() - startTime < (timeoutSeconds or 30) do root = getRoot() hum = getHumanoid() if not root or not hum then return false end local dist = (root.Position - targetPos).Magnitude if dist < 5 then hum:MoveTo(targetPos) return true end -- Compute a path local pathParams = { AgentRadius = 2, AgentHeight = 5, AgentCanJump = true, AgentMaxSlope = 45, WaypointSpacing = 4, } local ok, path = pcall(function() return PathfindingService:CreatePath(pathParams):ComputeAsync(root.Position, targetPos) end) if ok and path and path.Status == Enum.PathStatus.Success then local waypoints = path:GetWaypoints() hum:MoveTo(waypoints[#waypoints].Position) -- Walk along the path for i, wp in ipairs(waypoints) do if tick() - startTime >= (timeoutSeconds or 30) then hum:MoveTo(root.Position) return false end if wp.Action == Enum.PathWaypointAction.Jump then hum.Jump = true end -- Move to next waypoint hum:MoveTo(wp.Position) repeat task.wait(0.1) root = getRoot() if not root then hum:MoveTo(root and root.Position or Vector3.new()) return false end until (root.Position - wp.Position).Magnitude < 5 or not hum end else -- Direct approach as fallback hum:MoveTo(targetPos) task.wait(1) end -- Re-check distance root = getRoot() if root and (root.Position - targetPos).Magnitude < 5 then hum:MoveTo(targetPos) return true end end return false end -- ── Helper: find prompts by name near a position (e.g. PickupPrompt or OpenBoxPrompt) ── local function findPromptsNear(centerPos, radius, promptName) local results = {} for _, desc in ipairs(workspace:GetDescendants()) do if desc:IsA("ProximityPrompt") and desc.Name == promptName then local parentPart = desc.Parent if parentPart and parentPart:IsA("BasePart") then local dist = (parentPart.Position - centerPos).Magnitude if dist <= radius then table.insert(results, { prompt = desc, part = parentPart, position = parentPart.Position, distance = dist, }) end end end end table.sort(results, function(a, b) return a.distance < b.distance end) return results end -- ── Helper: trigger a ProximityPrompt instantly using the executor-native function ── local function triggerPrompt(prompt) local ok = pcall(function() fireproximityprompt(prompt) end) task.wait(0.1) return ok end -- ── Disconnect old connections if re-running ── local function disconnectAll() if State.BidHeartbeat then State.BidHeartbeat:Disconnect() State.BidHeartbeat = nil end if State.SellHeartbeat then State.SellHeartbeat:Disconnect() State.SellHeartbeat = nil end if State.WeightConnection then State.WeightConnection:Disconnect() State.WeightConnection = nil end if State.RateConnection then State.RateConnection:Disconnect() State.RateConnection = nil end if State.PickupConnection then State.PickupConnection:Disconnect() State.PickupConnection = nil end end disconnectAll() -- ── Vehicle weight tracking ── State.CurrentWeight = 0 State.WeightConnection = VehicleWeightUpdate.OnClientEvent:Connect(function(currentKg, maxKg) State.CurrentWeight = tonumber(currentKg) or 0 end) -- ── Pawn rate tracking ── State.RateConnection = RateChanged.OnClientEvent:Connect(function(data) if type(data) == "table" and data.rate then State.CurrentRate = data.rate end end) -- ── Auction Bid Heartbeat ── State.BidHeartbeat = RunService.Heartbeat:Connect(function() if not State.BidEnabled then return end local gui = PlayerGui:FindFirstChild("UIControllerGui") if not gui then return end local container = gui:FindFirstChild("AuctionBiddingContainer") if not container or not container.Visible then return end local now = tick() if State.LastBidTime and now - State.LastBidTime < 0.35 then return end local barRow = container:FindFirstChild("BidBarRow") if not barRow or not barRow.Visible then return end local track = barRow:FindFirstChild("Track") if not track then return end local cursor = track:FindFirstChild("Cursor") local bidZone = track:FindFirstChild("BidZone") if not cursor or not bidZone then return end local cPos = cursor.Position.X.Scale local zPos = bidZone.Position.X.Scale local zWidth = bidZone.Size.X.Scale local tolerance = 0.0075 if zPos <= cPos + tolerance and cPos - tolerance <= zPos + zWidth then local ok = pcall(function() BidRemote:FireServer() end) if not ok then warn("[AutoAuction] Bid failed") end State.LastBidTime = tick() end end) -- ── Sell Heartbeat ── State.SellHeartbeat = RunService.Heartbeat:Connect(function() if not State.SellEnabled then return end if State.SellSyncing then return end if tick() < State.SellCooldown then return end local pct = ratePercent(State.CurrentRate) if pct < State.MinSellRate then return end local weight = State.CurrentWeight if weight < State.MinWeight then return end -- All conditions met — attempt to sell State.SellSyncing = true task.spawn(function() local ok, items = pcall(function() return GetSellableItems:InvokeServer() end) if not ok or type(items) ~= "table" then State.SellSyncing = false return end -- Collect GUIDs of non-favorited items, respecting filters local toSell = {} for guid, info in pairs(items) do if not info.Favorited then local itemDef = ItemsModule[info.ItemId] local skip = false if itemDef then if State.SaveTrophies and itemDef.Category == "Trophy" then skip = true end if State.SaveAccessories and itemDef.Category == "Accessories" then skip = true end end if not skip then table.insert(toSell, guid) end end end if #toSell == 0 then State.SellSyncing = false return end local ok2, result = pcall(function() return SellItems:InvokeServer(toSell) end) if ok2 then -- Reset cooldown: 15 seconds before checking again State.SellCooldown = tick() + 15 end State.SellSyncing = false end) end) -- ── Auction pickup event (fires when items spawn after winning) ── State._itemsAvailable = false State.PickupConnection = AuctionEvents:WaitForChild("AuctionPickupStart").OnClientEvent:Connect(function(bidAmount, totalValue) State._itemsAvailable = true end) AuctionEvents:WaitForChild("AuctionPickupEnd").OnClientEvent:Connect(function() State._itemsAvailable = false end) -- ── Pathfinder state machine runner ── local function pathfinderLoop() while State.PathfinderEnabled and State._pathfinderRunning do -- STATE 1: FIND AUCTION State.PathfinderPhase = "Finding Auction" local target = findNearestAuction() if not target then State.PathfinderStatus = "No eligible auctions found, waiting..." task.wait(5) continue end State.PathfinderStatus = "Walking to " .. target.garageType .. " (" .. target.areaName .. ")" -- STATE 2: WALK TO AUCTION State.PathfinderPhase = "Walking to Auction" local walked = walkTo(target.position, 45) if not walked then State.PathfinderStatus = "Failed to reach auction, retrying..." task.wait(3) continue end -- STATE 3: TRIGGER AUCTION State.PathfinderPhase = "Triggering Auction" State.PathfinderStatus = "Starting auction..." -- Walk closer (within 6 studs for the 7-stud prompt range) walkTo(target.position, 5) -- Trigger the EnterAuction prompt instantly via the native executor function triggerPrompt(target.prompt) task.wait(1) -- Check if bidding window opened local gui = PlayerGui:FindFirstChild("UIControllerGui") local container = gui and gui:FindFirstChild("AuctionBiddingContainer") if not (container and container.Visible) then -- Try once more triggerPrompt(target.prompt) task.wait(1) end -- STATE 4: WAIT FOR BIDDING TO FINISH State.PathfinderPhase = "Waiting for Bidding" State.PathfinderStatus = "Auction in progress, waiting for result..." -- Wait for the auction to resolve (bidding UI closes AND we either win or lose) State._itemsAvailable = false local biddingEndTime = tick() local inAuction = true while inAuction and State.PathfinderEnabled do task.wait(0.5) gui = PlayerGui:FindFirstChild("UIControllerGui") container = gui and gui:FindFirstChild("AuctionBiddingContainer") -- If the bidding UI is gone, the auction resolved if not (container and container.Visible) then -- Double-check: if we won, items should be spawning if State._itemsAvailable then inAuction = false else -- Wait a bit more to see if items appear (winning) or it was just a loss if tick() - biddingEndTime > 8 then inAuction = false end end else biddingEndTime = tick() end -- Safety: max wait of 3 minutes for an auction if tick() - biddingEndTime > 180 then inAuction = false end end -- STATE 5: COLLECT ITEMS (if we won) — with verification loop if State._itemsAvailable then State.PathfinderPhase = "Collecting Items" State.PathfinderStatus = "Auction won! Collecting items..." task.wait(1) -- Helper: find the garage model in workspace matching the won auction local function findGarageModel() for _, model in ipairs(workspace:GetChildren()) do local name = model.Name if name == target.garageType or name:find(target.garageType) then return model end end return nil end local garageModel = findGarageModel() local garagePos = garageModel and garageModel:GetPivot().Position or target.position -- Blacklist for glitched/unreachable objects local blacklist = {} local function isBlacklisted(key) return blacklist[key] and blacklist[key].attempts >= 3 end local function recordAttempt(key) blacklist[key] = blacklist[key] or { attempts = 0 } blacklist[key].attempts = blacklist[key].attempts + 1 end -- Verification loop: repeat until garage is fully cleared or timeout local garageLoopStart = tick() local garageCleared = false while not garageCleared and State.PathfinderEnabled do -- Safety: if we've been in this garage > 20 seconds, bail out if tick() - garageLoopStart > 20 then State.PathfinderStatus = "Garage timeout (20s), moving on" task.wait(0.5) break end -- PHASE A: OPEN BOXES/CRATES State.PathfinderStatus = "Opening boxes in garage..." local boxes = findPromptsNear(garagePos, 80, "OpenBoxPrompt") for i, box in ipairs(boxes) do if not State.PathfinderEnabled then break end local key = tostring(box.prompt) if isBlacklisted(key) then continue end State.PathfinderStatus = "Opening box " .. i .. "/" .. #boxes local arrived = walkTo(box.position, 15) if arrived then triggerPrompt(box.prompt) task.wait(0.3) else recordAttempt(key) end end -- PHASE B: COLLECT ALL ITEMS State.PathfinderStatus = "Collecting items..." -- Find all PickupPrompt instances near the garage area local pickups = findPromptsNear(target.position, 60, "PickupPrompt") if #pickups == 0 then -- Try at the garage model position if garageModel then pickups = findPromptsNear(garagePos, 80, "PickupPrompt") end end if #pickups == 0 then -- Last resort: search the entire workspace for pickup prompts for _, desc in ipairs(workspace:GetDescendants()) do if desc:IsA("ProximityPrompt") and desc.Name == "PickupPrompt" then local parent = desc.Parent if parent and parent:IsA("BasePart") then table.insert(pickups, { prompt = desc, part = parent, position = parent.Position, distance = 0, }) end end end table.sort(pickups, function(a, b) return a.distance < b.distance end) end -- Walk to each pickup and collect using fireproximityprompt for i, pickup in ipairs(pickups) do if not State.PathfinderEnabled then break end local key = tostring(pickup.prompt) if isBlacklisted(key) then continue end State.PathfinderStatus = "Collecting item " .. i .. "/" .. #pickups local arrived = walkTo(pickup.position, 15) if arrived then triggerPrompt(pickup.prompt) task.wait(0.3) else recordAttempt(key) end end -- VERIFICATION: check if anything remains task.wait(0.3) local remainingBoxes = findPromptsNear(garagePos, 80, "OpenBoxPrompt") local remainingItems = findPromptsNear(garagePos, 80, "PickupPrompt") if #remainingBoxes == 0 and #remainingItems == 0 then garageCleared = true State.PathfinderStatus = "Garage cleared!" else State.PathfinderStatus = "Verification: " .. #remainingBoxes .. " boxes, " .. #remainingItems .. " items remain" end task.wait(0.3) end -- ── EXIT GARAGE: walk back to the auction board ── State.PathfinderPhase = "Exiting Garage" State.PathfinderStatus = "Exiting garage, returning to auction board..." walkTo(target.position, 20) -- Ensure we're safely outside before transitioning back to State 1 local exitStart = tick() local root = getRoot() while root and (root.Position - target.position).Magnitude >= 6 and State.PathfinderEnabled do if tick() - exitStart > 15 then break end root = getRoot() if root then local hum = getHumanoid() if hum then hum:MoveTo(target.position) end end task.wait(0.5) end else State.PathfinderStatus = "Auction lost or no items to collect" task.wait(2) end State.PathfinderStatus = "Cycle complete, searching for next auction..." task.wait(1) end State.PathfinderPhase = "Idle" if not State.PathfinderEnabled then State.PathfinderStatus = "Disabled" else State.PathfinderStatus = "Stopped" end State._pathfinderRunning = false end -- ── Start/stop pathfinder ── local function setPathfinderEnabled(value) State.PathfinderEnabled = value if value and not State._pathfinderRunning then State._pathfinderRunning = true State.PathfinderStatus = "Starting..." task.spawn(pathfinderLoop) elseif not value then State.PathfinderStatus = "Disabled" end end -- ═══════════════════════════════════════════════════════════════ -- WindUI -- ═══════════════════════════════════════════════════════════════ local Window = WindUI:CreateWindow({ Title = "Auto Auction", Folder = "AutoAuction", Icon = "solar:cursor-square-bold-duotone", NewElements = true, HideSearchBar = true, Topbar = { Height = 38, ButtonsType = "Mac", }, }) -- ═══════════════════════════════════════════════════════════════ -- Auction Tab -- ═══════════════════════════════════════════════════════════════ local AuctionTab = Window:Tab({ Title = "Auction", Desc = "Auto bidding controls", Icon = "solar:cursor-square-bold-duotone", }) AuctionTab:Toggle({ Title = "Auto Bid", Desc = "Automatically bid when the cursor is in the green zone", Value = State.BidEnabled, Callback = function(value) State.BidEnabled = value end, }) AuctionTab:Space() AuctionTab:Paragraph({ Title = "How it works", Desc = "Monitors the bidding bar during garage auctions and automatically fires a bid when the moving cursor overlaps the green target zone.", }) AuctionTab:Space() AuctionTab:Button({ Title = "Leave Auction", Icon = "solar:logout-2-bold", Callback = function() local ok, result = pcall(function() return LeaveAuctionRemote:InvokeServer() end) if ok and result then local UIController = require(ReplicatedStorage.Modules.UIController) UIController:Close("AuctionBidding") UIController:Close("AuctionPowers") UIController:Close("AuctionWinningBid") end end, }) -- ═══════════════════════════════════════════════════════════════ -- Auto Sell Tab -- ═══════════════════════════════════════════════════════════════ local SellTab = Window:Tab({ Title = "Auto Sell", Desc = "Auto quick-sell controls", Icon = "solar:wallet-bold-duotone", }) -- Master Toggle SellTab:Toggle({ Title = "Master Toggle", Desc = "Enable auto-selling when conditions are met", Value = State.SellEnabled, Callback = function(value) State.SellEnabled = value end, }) SellTab:Space() -- Min Sell Rate slider (range -50% to +50%) local RateSlider RateSlider = SellTab:Slider({ Title = "Sell Rate", Desc = "Minimum quick-sell rate (%) to trigger a sale", IsTooltip = true, IsTextbox = true, Width = 200, Step = 1, Value = { Min = -50, Max = 50, Default = -15, }, Callback = function(value) State.MinSellRate = value end, }) State.MinSellRate = -15 SellTab:Space() -- Min Load Weight slider local WeightSlider WeightSlider = SellTab:Slider({ Title = "Load Weight", Desc = "Minimum vehicle load weight (kg) to trigger a sale", IsTooltip = true, IsTextbox = true, Width = 200, Step = 1, Value = { Min = 0, Max = 100, Default = 20, }, Callback = function(value) State.MinWeight = value end, }) State.MinWeight = 20 SellTab:Space() -- Save Trophies toggle SellTab:Toggle({ Title = "Save Trophies", Desc = "Don't auto-sell items with the Trophy category (e.g. Gavel Trophy)", Value = State.SaveTrophies, Callback = function(value) State.SaveTrophies = value end, }) SellTab:Space() -- Save Accessories toggle SellTab:Toggle({ Title = "Save Accessories", Desc = "Don't auto-sell items with the Accessories category", Value = State.SaveAccessories, Callback = function(value) State.SaveAccessories = value end, }) SellTab:Space() -- Live status readout local StatusSection = SellTab:Section({ Title = "Status", }) local RateLabel local WeightLabel local StatusLabel -- Build a small live-status group local StatusGroup = SellTab:Group({}) RateLabel = StatusGroup:Paragraph({ Title = "Current Rate", Desc = "Waiting for data...", }) WeightLabel = StatusGroup:Paragraph({ Title = "Vehicle Load", Desc = "Waiting for data...", }) StatusLabel = StatusGroup:Paragraph({ Title = "Auto Sell Status", Desc = "Inactive", }) -- ── Live status updater ── if State.StatusUpdater then State.StatusUpdater:Disconnect() end State.StatusUpdater = RunService.Heartbeat:Connect(function() if not RateLabel or not WeightLabel or not StatusLabel then return end local pct = ratePercent(State.CurrentRate) RateLabel:SetDesc("Rate: " .. formatRate(State.CurrentRate)) WeightLabel:SetDesc("Weight: " .. math.floor(State.CurrentWeight) .. " kg") if not State.SellEnabled then StatusLabel:SetDesc("Disabled — toggle Master Toggle on") return end if pct < State.MinSellRate then StatusLabel:SetDesc("Waiting for rate (" .. pct .. "% < " .. State.MinSellRate .. "%)") return end if State.CurrentWeight < State.MinWeight then StatusLabel:SetDesc("Waiting for weight (" .. math.floor(State.CurrentWeight) .. "kg < " .. State.MinWeight .. "kg)") return end if State.SellSyncing then StatusLabel:SetDesc("Selling in progress...") return end if tick() < State.SellCooldown then local remaining = math.floor(State.SellCooldown - tick()) StatusLabel:SetDesc("Cooldown (" .. remaining .. "s)") return end StatusLabel:SetDesc("Conditions met — ready to sell") end) -- Manual refresh button SellTab:Space() SellTab:Button({ Title = "Refresh Now", Icon = "solar:refresh-bold", Callback = function() task.spawn(function() local ok, state = pcall(function() return GetPawnState:InvokeServer() end) if ok and type(state) == "table" and state.rate then State.CurrentRate = state.rate end end) end, }) -- ═══════════════════════════════════════════════════════════════ -- Pathfinder Tab -- ═══════════════════════════════════════════════════════════════ local PathfinderTab = Window:Tab({ Title = "Pathfinder", Desc = "Auto auction loop", Icon = "solar:map-arrow-right-bold-duotone", }) -- Master Pathfinder Toggle PathfinderTab:Toggle({ Title = "Master Pathfinder", Desc = "Enable the full auto-auction loop (walk → trigger → bid → collect)", Value = State.PathfinderEnabled, Callback = function(value) setPathfinderEnabled(value) end, }) PathfinderTab:Space() -- Section label for area toggles PathfinderTab:Section({ Title = "Target Areas", TextSize = 16, }) -- Area toggle for each garage tier for _, area in ipairs({ "Junk Yard", "Back Alley", "Farmyard", "Shipyard" }) do PathfinderTab:Toggle({ Title = area, Desc = "Target " .. area .. " auctions", Value = State.AreaToggles[area], Callback = function(value) State.AreaToggles[area] = value end, }) PathfinderTab:Space() end -- Status readout PathfinderTab:Section({ Title = "Status", }) local PFGroup = PathfinderTab:Group({}) local PhaseLabel = PFGroup:Paragraph({ Title = "Current Phase", Desc = "Idle", }) local StateLabel = PFGroup:Paragraph({ Title = "State", Desc = "Waiting for activation", }) -- ── Pathfinder status updater ── if State.PFStatusUpdater then State.PFStatusUpdater:Disconnect() end State.PFStatusUpdater = RunService.Heartbeat:Connect(function() if PhaseLabel then PhaseLabel:SetDesc(State.PathfinderPhase or "Idle") end if StateLabel then StateLabel:SetDesc(State.PathfinderStatus or "Waiting for activation") end end) print("[AutoAuction] Loaded successfully")