--[[ PuckAFK | +1 Fat Per Click | v1.5 Built from: - place 128329680321338 (8 Sep 2026 dump) - supplied client/network capture - PuckUI v3.8.0 Core strategy: * Uses the game's own AutoWinsToggle instead of forcing the win pad. * Auto-clicks the equipped food Tool. * Hybrid mode charges Fat on the best unlocked training table, then lets server Auto Wins clear walls / collect wins while clicks continue. * Auto-rebirths exactly when the level requirement is met. * Buys/equips the strongest food it can legitimately unlock, with a direct remote attempt and a real food-pad fallback when proximity is server-validated. * Uses the highest unlocked world for win runs and the highest effective training table (including owned gamepass tables / live Event Table). * Smart spending reserves wins for the next meaningful food upgrade, but core Fat/Wins boosts may use part of that reserve when their permanent multiplier is mathematically expected to accelerate progression. * Guaranteed pet crafting uses only safe duplicate sets and protects traited pets by default. * Optional permanent progression: upgrades, boosts, auras, pets, titles, daily rewards, free spins, quest-token rewards and group reward. Notes: * This is client-side executor code. Live server rules can change. * Settings are intentionally conservative around consumable win spending. * PuckUI handles profiles/autosave/layout/shared K keybind. ]] if not game:IsLoaded() then game.Loaded:Wait() end local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local MarketplaceService = game:GetService("MarketplaceService") local VirtualUser = game:GetService("VirtualUser") local RunService = game:GetService("RunService") local PathfindingService = game:GetService("PathfindingService") local HttpService = game:GetService("HttpService") local player = Players.LocalPlayer local env = type(getgenv) == "function" and getgenv() or _G local APP_KEY = "__PUCK_FAT_PER_CLICK" if env[APP_KEY] and env[APP_KEY].Stop then pcall(env[APP_KEY].Stop) end local app = { alive = true, connections = {}, tasks = {}, generation = 0, moveLock = false, phase = "Idle", message = "Ready", autoWinsState = nil, nativeAutoClickState = nil, nativeAutoClickScriptOwned = false, chargeBias = 0, winDeniedStreak = 0, lastWinAward = os.clock(), lastWallProgress = os.clock(), forceTrainUntil = 0, wallWorld = 1, wallStage = 0, targetWallStage = 0, spendUntil = 0, eggBudget = 0, lastHatchError = nil, lastHatchSuccess = 0, hatchNeedsProximity = {}, suppressHatchVisualsUntil = 0, navigationRecoveries = 0, navigationFailures = 0, navRecovering = false, wallAction = "restore", boostPlan = "Waiting", boostStateSummary = "Reading boost levels...", } env[APP_KEY] = app local settings = { Farm = false, Mode = "Hybrid", AutoClick = true, ClickDelay = 0.10, NativeAutoClick = true, AutoRebirth = true, AutoFood = true, AutoTable = true, AutoWorld = true, ChargePercent = 82, AutoUpgrades = true, UpgradeClick = true, UpgradeTraining = true, UpgradeWalk = false, AutoBoosts = true, BoostDamage = true, BoostWins = true, BoostLuck = true, AutoAura = true, AutoPets = true, AutoEggs = false, AutoGolden = true, AutoRainbow = true, ProtectTraitedPets = true, Egg = "Smart improvement", EggDelay = 1.2, EggBudgetPercent = 10, HideHatchAnimation = true, AutoTitles = true, RollTitles = false, TitleRollDelay = 0.3, AutoDaily = true, AutoSpin = true, AutoQuestRewards = true, AutoWeeklyFood = true, AutoGroupReward = true, SmartReservePercent = 75, WinsReserve = 0, CoreBoostReserveOverride = true, AntiAFK = true, LowLag = true, SmartNavigation = true, } local telemetry = { clicks = 0, rebirths = 0, winsAwards = 0, winsAwardAmount = 0, foods = 0, hatches = 0, upgrades = 0, startFat = 0, startWins = 0, fatRate = 0, winsRate = 0, } local function connect(signal, fn) local c = signal:Connect(fn) table.insert(app.connections, c) return c end local function worker(fn) local t = task.spawn(fn) table.insert(app.tasks, t) return t end local function say(text) app.message = tostring(text or "") end local function character() local c = player.Character local h = c and c:FindFirstChildOfClass("Humanoid") local r = c and c:FindFirstChild("HumanoidRootPart") if c and h and r and h.Health > 0 then return c, h, r end end local function stopMovement() local _, h, r = character() if h and r then pcall(function() h:MoveTo(r.Position) h:Move(Vector3.zero) end) end end local window function app.Stop() if not app.alive then return end app.alive = false app.generation = app.generation + 1 pcall(function() local r = ReplicatedStorage:FindFirstChild("AutoWinsToggle") if r then r:FireServer(false) end local ac = ReplicatedStorage:FindFirstChild("AutoClickerToggle") if ac and app.nativeAutoClickScriptOwned then ac:FireServer(false) end end) stopMovement() for _, c in ipairs(app.connections) do pcall(function() c:Disconnect() end) end for _, t in ipairs(app.tasks) do if t ~= coroutine.running() then pcall(task.cancel, t) end end pcall(function() local pg = player:FindFirstChildOfClass("PlayerGui") local fx = pg and pg:FindFirstChild("FatClickFX") if fx and fx:IsA("ScreenGui") then fx.Enabled = true end local flash = pg and pg:FindFirstChild("HatchFlash") if flash and flash:IsA("ScreenGui") then flash.Enabled = true end local newGui = pg and pg:FindFirstChild("NewGui") if newGui and newGui:IsA("ScreenGui") then newGui.Enabled = true end end) if window then pcall(function() window:Destroy() end) end if env[APP_KEY] == app then env[APP_KEY] = nil end end local function loadUI() local ok, result = pcall(function() return loadstring(game:HttpGet("https://raw.githubusercontent.com/PuckAFK/Puck-Loader/main/ui/PuckUI.lua"))() end) if not ok or type(result) ~= "table" then error("PuckUI could not load: " .. tostring(result)) end return result end local UI = loadUI() window = UI:CreateWindow({ Name = "PuckAFK | +1 Fat Per Click", Title = "PuckAFK | +1 Fat Per Click v1.4", GuiName = "PuckAFK_FatPerClick", ConfigId = "Fat_Per_Click", Width = 570, Height = 585, }) window.CloseCallback = app.Stop local function safeRequire(instance) if not instance then return nil end local ok, result = pcall(require, instance) return ok and result or nil end local Shared = ReplicatedStorage:FindFirstChild("Shared") local FoodConfig = safeRequire(ReplicatedStorage:FindFirstChild("FoodConfig")) or {} local PetConfig = safeRequire(ReplicatedStorage:FindFirstChild("PetConfig")) or {} local TitleConfig = safeRequire(ReplicatedStorage:FindFirstChild("TitleConfig")) or {} local UpgradeConfig = safeRequire(ReplicatedStorage:FindFirstChild("UpgradeConfig")) or {} local QuestConfig = safeRequire(ReplicatedStorage:FindFirstChild("QuestConfig")) or {} local AuraConfig = safeRequire(ReplicatedStorage:FindFirstChild("AuraConfig")) or {} local TableConfig = safeRequire(Shared and Shared:FindFirstChild("TableConfig")) or {} local Worlds = safeRequire(Shared and Shared:FindFirstChild("Worlds")) or {} local TraitConfig = safeRequire(Shared and Shared:FindFirstChild("TraitConfig")) or {} -- Build one lightweight world-name index instead of calling -- workspace:GetDescendants() separately for every food pad, training table and -- pet machine. Streaming additions/removals update it incrementally. local worldNameIndex = {} local function indexWorldObject(x) if not (x:IsA("BasePart") or x:IsA("Model")) then return end local bucket = worldNameIndex[x.Name] if not bucket then bucket = setmetatable({}, {__mode = "k"}) worldNameIndex[x.Name] = bucket end bucket[x] = true end local function unindexWorldObject(x) local bucket = worldNameIndex[x.Name] if bucket then bucket[x] = nil end end for _, x in ipairs(workspace:GetDescendants()) do indexWorldObject(x) end connect(workspace.DescendantAdded, indexWorldObject) connect(workspace.DescendantRemoving, unindexWorldObject) local function namedWorldObjects(name, className) local out = {} local bucket = worldNameIndex[tostring(name)] if not bucket then return out end for x in pairs(bucket) do if x and x.Parent and (not className or x:IsA(className)) then out[#out + 1] = x end end return out end local function remote(name) local r = ReplicatedStorage:FindFirstChild(name) if r and r:IsA("RemoteEvent") then return r end return nil end local Remotes = {} for _, name in ipairs({ "AutoWinsToggle", "AutoClickerToggle", "DoRebirth", "EquipFood", "HatchEgg", "PetsUpdated", "EquipPet", "UnequipPet", "EquipAllPets", "UnequipAllPets", "RequestPets", "HatchResult", "EquipBestTitle", "RollTitle", "TitleRolled", "BuyBoost", "BuyUpgrade", "UpgradesUpdated", "BuyAuraWins", "EquipAura", "AurasUpdated", "AuraPurchased", "DailyClaim", "DailyState", "RequestSpin", "SpinResult", "QuestState", "RewardBuy", "RewardResult", "WeeklyEquip", "GroupClaim", "GroupRewardResult", "WinPadAward", "WinDenied", "WallFXRE", "TryGoldenPet", "GoldenResult", "TryRainbowPet", "RainbowResult", "AutoEquipHatched" }) do Remotes[name] = remote(name) end local leaderstats = player:WaitForChild("leaderstats", 30) local winsValue = leaderstats and leaderstats:FindFirstChild("Wins") local rebirthsValue = leaderstats and leaderstats:FindFirstChild("Rebirths") local fatValue = player:FindFirstChild("FatValue") or player:WaitForChild("FatValue", 30) local function numberValue(v) return tonumber(v and v.Value) or 0 end local function wins() return numberValue(winsValue) end local function rebirths() return numberValue(rebirthsValue) end local function fat() return numberValue(fatValue) end local function level() local a = tonumber(player:GetAttribute("Level")) if a then return a end if FoodConfig.GetLevelInfo then local ok, l = pcall(FoodConfig.GetLevelInfo, fat()) if ok and l then return tonumber(l) or 1 end end return 1 end local function fmt(n) n = tonumber(n) or 0 local sign = n < 0 and "-" or "" n = math.abs(n) local suffixes = {"", "K", "M", "B", "T", "Qa", "Qi", "Sx", "Sp", "Oc", "No", "Dc"} local i = 1 while n >= 1000 and i < #suffixes do n = n / 1000 i = i + 1 end local s if i == 1 then s = tostring(math.floor(n + 0.5)) elseif n >= 100 then s = string.format("%.0f", n) elseif n >= 10 then s = string.format("%.1f", n) else s = string.format("%.2f", n) end s = s:gsub("%.?0+$", "") return sign .. s .. suffixes[i] end telemetry.startFat = fat() telemetry.startWins = wins() app.eggBudget = math.max(0, wins() * math.clamp((tonumber(settings.EggBudgetPercent) or 10) / 100, 0, 0.30)) local function fire(name, ...) local r = Remotes[name] if not app.alive or not r then return false end local args = table.pack(...) local ok = pcall(function() r:FireServer(table.unpack(args, 1, args.n)) end) return ok end local function setAutoWins(on, force) on = on == true if not force and app.autoWinsState == on then return true end if fire("AutoWinsToggle", on) then app.autoWinsState = on return true end return false end local function setNativeAutoClick(on, force) on = on == true local actual = player:GetAttribute("AutoClicker") == true if not force and app.nativeAutoClickState == on and actual == on then return true end if fire("AutoClickerToggle", on) then app.nativeAutoClickState = on if on then app.nativeAutoClickScriptOwned = true end return true end return false end local function topOf(part, extra) if not part or not part:IsA("BasePart") then return nil end local _, h, r = character() if not h or not r then return nil end local y = part.Size.Y / 2 + h.HipHeight + r.Size.Y / 2 + (extra or 0.35) return part.CFrame * CFrame.new(0, y, 0) end local function teleport(cf) local _, _, r = character() if not r or not cf then return false end pcall(function() r.CFrame = cf r.AssemblyLinearVelocity = Vector3.zero r.AssemblyAngularVelocity = Vector3.zero end) return true end local function withMoveLock(fn) if app.moveLock then return false end app.moveLock = true local ok, result = pcall(fn) app.moveLock = false if not ok then say("Movement action failed: " .. tostring(result)) end return ok, result end -- Lightweight path navigation is only used for collision-sensitive short legs -- and recovery. Long farm travel still uses the faster direct positioning path. -- If a path stops making progress, PuckAFK jumps, tries a clear lateral lane, -- and recomputes around the blocker instead of repeatedly walking into it. local NAV_AGENT = { AgentRadius = 2, AgentHeight = 5, AgentCanJump = true, AgentCanClimb = true, WaypointSpacing = 5, } local function flat(v) return Vector3.new(v.X, 0, v.Z) end local function navigationRayBlocked(fromPos, toPos) local delta = toPos - fromPos if delta.Magnitude < 0.5 then return false end local params = RaycastParams.new() params.FilterType = Enum.RaycastFilterType.Exclude params.IgnoreWater = true local c = player.Character params.FilterDescendantsInstances = c and {c} or {} local hit = workspace:Raycast(fromPos + Vector3.new(0, 2.2, 0), delta, params) return hit and hit.Instance and hit.Instance:IsA("BasePart") and hit.Instance.CanCollide or false end local function jumpAndSidestep(goalPos) local _, h, r = character() if not h or not r then return false end pcall(function() h.Jump = true h:ChangeState(Enum.HumanoidStateType.Jumping) end) local forward = flat(goalPos - r.Position) if forward.Magnitude < 0.1 then forward = flat(r.CFrame.LookVector) end if forward.Magnitude < 0.1 then forward = Vector3.new(0, 0, -1) end forward = forward.Unit local right = Vector3.new(-forward.Z, 0, forward.X) local candidates = { r.Position + right * 7 + forward * 3, r.Position - right * 7 + forward * 3, r.Position + right * 10, r.Position - right * 10, } for _, p in ipairs(candidates) do if not navigationRayBlocked(r.Position, p) then h:MoveTo(p) local start = r.Position local deadline = os.clock() + 0.65 repeat task.wait(0.05) until not app.alive or (flat(r.Position - start).Magnitude > 1.4) or os.clock() >= deadline if flat(r.Position - start).Magnitude > 0.9 then return true end end end return false end local function navigateToPosition(goalPos, arrivalDistance, maxSeconds) if not settings.SmartNavigation then return false end arrivalDistance = tonumber(arrivalDistance) or 4 maxSeconds = tonumber(maxSeconds) or 5 local started = os.clock() local attempts = 0 while app.alive and os.clock() - started < maxSeconds and attempts < 4 do attempts = attempts + 1 local _, h, r = character() if not h or not r then return false end if flat(goalPos - r.Position).Magnitude <= arrivalDistance then return true end local path = PathfindingService:CreatePath(NAV_AGENT) local ok = pcall(function() path:ComputeAsync(r.Position, goalPos) end) local waypoints = ok and path.Status == Enum.PathStatus.Success and path:GetWaypoints() or nil if not waypoints or #waypoints == 0 then h:MoveTo(goalPos) task.wait(0.18) jumpAndSidestep(goalPos) continue end local recompute = false local blockedConnection blockedConnection = path.Blocked:Connect(function() recompute = true end) for i = 2, #waypoints do if not app.alive or recompute then break end local wp = waypoints[i] if wp.Action == Enum.PathWaypointAction.Jump then pcall(function() h.Jump = true h:ChangeState(Enum.HumanoidStateType.Jumping) end) end h:MoveTo(wp.Position) local lastPos = r.Position local lastProgress = os.clock() local segmentDeadline = os.clock() + math.clamp(flat(wp.Position - r.Position).Magnitude / math.max(8, h.WalkSpeed) + 1.1, 0.9, 2.8) while app.alive and not recompute and os.clock() < segmentDeadline do task.wait(0.06) if flat(goalPos - r.Position).Magnitude <= arrivalDistance then if blockedConnection then blockedConnection:Disconnect() end return true end if flat(r.Position - lastPos).Magnitude >= 0.8 then lastPos = r.Position lastProgress = os.clock() elseif os.clock() - lastProgress > 0.72 then app.navigationRecoveries = app.navigationRecoveries + 1 jumpAndSidestep(goalPos) recompute = true break end end end if blockedConnection then blockedConnection:Disconnect() end end app.navigationFailures = app.navigationFailures + 1 return false end local function travelNear(cf, arrivalDistance) local _, _, r = character() if not r or not cf then return false end local distance = flat(cf.Position - r.Position).Magnitude if settings.SmartNavigation and distance <= 85 then if navigateToPosition(cf.Position, arrivalDistance or 4, 5.5) then return true end end -- Far legs and failed local paths keep the farm fast and self-healing. return teleport(cf) end local function worldEntry(worldId) worldId = tonumber(worldId) or 1 if worldId == 1 then return workspace:FindFirstChild("Entry") end for _, def in ipairs(type(Worlds.DEFS) == "table" and Worlds.DEFS or {}) do if tonumber(def.id) == worldId and def.folder then local folder = workspace:FindFirstChild(def.folder) return folder and folder:FindFirstChild("Entry") or nil end end end local function activeWallPart() local worldId = tonumber(app.wallWorld) or 1 if Worlds.idOfPlayer then local ok, current = pcall(Worlds.idOfPlayer, player) if ok and tonumber(current) then worldId = tonumber(current) end end local entry = worldEntry(worldId) if not entry then return nil end local sameTrackedWorld = worldId == (tonumber(app.wallWorld) or worldId) local stage = sameTrackedWorld and math.max(1, tonumber(app.wallStage) or 0) or 1 if sameTrackedWorld and app.wallAction == "break" then stage = stage + 1 end return entry:FindFirstChild("Stage" .. tostring(stage)) or entry:FindFirstChild("Stage1") end local function wallApproachPoint(part, rootPosition) if not part or not part:IsA("BasePart") then return nil end local delta = flat(part.Position - rootPosition) if delta.Magnitude < 0.1 then return rootPosition end local dir = delta.Unit local right = flat(part.CFrame.RightVector) local look = flat(part.CFrame.LookVector) local half = math.abs(dir:Dot(right)) * part.Size.X * 0.5 + math.abs(dir:Dot(look)) * part.Size.Z * 0.5 return part.Position - dir * (half + 2.8) end local function recoverNativeAutoWins() if app.navRecovering or app.moveLock or not settings.SmartNavigation then return false end local _, h, r = character() if not h or not r then return false end app.navRecovering = true local targetWall = activeWallPart() local goal = targetWall and wallApproachPoint(targetWall, r.Position) if not goal then goal = r.Position + flat(r.CFrame.LookVector).Unit * 16 end local ok = withMoveLock(function() setAutoWins(false, true) pcall(function() h.Jump = true h:ChangeState(Enum.HumanoidStateType.Jumping) end) local reached = navigateToPosition(goal, 3.5, 4.5) if not reached then jumpAndSidestep(goal) end if settings.Farm and app.phase == "Wins" then setAutoWins(true, true) end return reached end) app.navRecovering = false return ok end -- --------------------------------------------------------------------------- -- Food progression -- --------------------------------------------------------------------------- local foods = type(FoodConfig.Foods) == "table" and FoodConfig.Foods or {} local function isBought(index, food) if food and player:GetAttribute("EquippedFood") == food.name then return true end if player:GetAttribute("Bought" .. tostring(index)) == true then return true end if food and food.name == "Lobster" and player:GetAttribute("HasLobster") == true then return true end return false end local function standardFood(food) return food and not food.gamepass and not food.dailyReward and not food.questReward and not food.bestMult end local function ownedBestStandardPower() local best = 0 for i, food in ipairs(foods) do if isBought(i, food) and standardFood(food) then best = math.max(best, tonumber(food.fatPerClick) or 0) end end return best end local function foodEffectivePower(index, food) if not food then return 0 end if food.bestMult then return ownedBestStandardPower() * (tonumber(food.bestMult) or 1) end return tonumber(food.fatPerClick) or 0 end local function bestOwnedFood() local bestIndex, bestFood, bestPower = nil, nil, -1 for i, food in ipairs(foods) do if isBought(i, food) then local p = foodEffectivePower(i, food) if p > bestPower then bestIndex, bestFood, bestPower = i, food, p end end end return bestIndex, bestFood, bestPower end local function bestAffordableUnboughtFood() local currentWins = wins() local rb = rebirths() local bestIndex, bestFood, bestPower = nil, nil, -1 for i, food in ipairs(foods) do if not isBought(i, food) and standardFood(food) then local reqWins = tonumber(food.requiredWins) or 0 local reqRb = tonumber(food.requiredRebirths) or 0 if currentWins >= reqWins and rb >= reqRb then local p = tonumber(food.fatPerClick) or 0 if p > bestPower then bestIndex, bestFood, bestPower = i, food, p end end end end return bestIndex, bestFood, bestPower end local function nextFoodGoal() local _, _, ownedPower = bestOwnedFood() ownedPower = math.max(ownedPower or 0, 0) local currentWins = wins() local goalIndex, goalFood, goalReq for i, food in ipairs(foods) do if standardFood(food) and not isBought(i, food) then local p = tonumber(food.fatPerClick) or 0 local req = tonumber(food.requiredWins) or 0 if p > ownedPower and req > currentWins and (not goalReq or req < goalReq) then goalIndex, goalFood, goalReq = i, food, req end end end return goalIndex, goalFood, goalReq end local padCache = {} local function foodPads(index) local key = tostring(index) local cached = padCache[key] if cached then local live = {} for _, p in ipairs(cached) do if p and p.Parent then table.insert(live, p) end end if #live > 0 then padCache[key] = live return live end end local name = index == "Lobster" and "FoodPadLobster" or ("FoodPad" .. tostring(index)) local list = namedWorldObjects(name, "BasePart") padCache[key] = list return list end local function nearestPart(list) local _, _, root = character() if not root then return list[1] end local best, distance for _, p in ipairs(list or {}) do if p and p.Parent then local d = (p.Position - root.Position).Magnitude if not distance or d < distance then best, distance = p, d end end end return best end local lastFoodAttempt = {} local function equipOrBuyFood(index, food) if not food or not Remotes.EquipFood then return false end local name = food.name if player:GetAttribute("EquippedFood") == name then return true end local now = os.clock() if now - (lastFoodAttempt[name] or 0) < 2.0 then return false end lastFoodAttempt[name] = now fire("EquipFood", name) task.wait(0.25) if player:GetAttribute("EquippedFood") == name or isBought(index, food) then telemetry.foods = telemetry.foods + 1 return true end local pads = foodPads(index) local pad = nearestPart(pads) if not pad then return false end return withMoveLock(function() setAutoWins(false, true) travelNear(topOf(pad, 0.15), 3.5) task.wait(0.25) fire("EquipFood", name) local deadline = os.clock() + 1.5 repeat task.wait(0.08) until not app.alive or player:GetAttribute("EquippedFood") == name or isBought(index, food) or os.clock() >= deadline local ok = player:GetAttribute("EquippedFood") == name or isBought(index, food) if ok then telemetry.foods = telemetry.foods + 1 end return ok end) end local function ensureBestFood() if not settings.AutoFood then return end local buyIndex, buyFood = bestAffordableUnboughtFood() if buyFood then say("Unlocking " .. buyFood.name) equipOrBuyFood(buyIndex, buyFood) task.wait(0.15) end local bestIndex, bestFood = bestOwnedFood() if bestFood and player:GetAttribute("EquippedFood") ~= bestFood.name then say("Equipping " .. bestFood.name) equipOrBuyFood(bestIndex, bestFood) end end -- --------------------------------------------------------------------------- -- Tables / worlds -- --------------------------------------------------------------------------- local passOwned = {} local passChecked = {} local function ownsPass(passId) passId = tonumber(passId) if not passId or passId <= 0 then return false end if passOwned[passId] ~= nil then return passOwned[passId] end if not passChecked[passId] then passChecked[passId] = true worker(function() local ok, value = pcall(MarketplaceService.UserOwnsGamePassAsync, MarketplaceService, player.UserId, passId) passOwned[passId] = ok and value == true or false end) end return false end local tableObjectCache = {} local function collectNamedTableObjects(name) local cached = tableObjectCache[name] if cached then local live = {} for _, x in ipairs(cached) do if x and x.Parent then table.insert(live, x) end end if #live > 0 then tableObjectCache[name] = live return live end end local list, seen = {}, {} local wantedInstanceName = name == "Event Table" and "AdminTableEvent" or name for _, x in ipairs(namedWorldObjects(wantedInstanceName)) do if not seen[x] then seen[x] = true table.insert(list, x) end end tableObjectCache[name] = list return list end local function worldOfObject(obj) if Worlds.idOf then local ok, id = pcall(Worlds.idOf, obj) if ok and id then return tonumber(id) or 1 end end local pos if obj:IsA("BasePart") then pos = obj.Position elseif obj:IsA("Model") then local ok, cf = pcall(function() return select(1, obj:GetBoundingBox()) end) if ok and cf then pos = cf.Position end end if pos then if pos.X > 1030 then return 3 end if pos.X > 300 then return 2 end end return 1 end local function tableMult(name, info) if name == (TableConfig.ADMIN_NAME or "Event Table") then local untilAttr = TableConfig.ADMIN_UNTIL_ATTR or "AdminTableUntil" local untilTime = tonumber(ReplicatedStorage:GetAttribute(untilAttr)) or 0 local serverNow = 0 pcall(function() serverNow = workspace:GetServerTimeNow() end) -- AdminTableEvent can remain streamed for a moment after the event ends. -- Do not abandon a permanent table for an expired event object. if untilTime > 0 and serverNow > 0 and untilTime <= serverNow then return 0 end if TableConfig.multOf then local ok, m = pcall(TableConfig.multOf, name) if ok and tonumber(m) then return math.max(0, tonumber(m)) end end return math.max(0, tonumber(ReplicatedStorage:GetAttribute(TableConfig.ADMIN_MULT_ATTR or "AdminTableMult")) or tonumber(info and info.mult) or 1) end return tonumber(info and info.mult) or 1 end local function tableUnlocked(name, info) if type(info) ~= "table" then return false end if info.gate == "open" then return #collectNamedTableObjects(name) > 0 elseif info.gate == "rebirth" then return rebirths() >= (tonumber(info.rebirths) or 0) elseif info.gate == "gamepass" then return ownsPass(info.passId) end return false end local function bestTrainingTable() local tables = type(TableConfig.Tables) == "table" and TableConfig.Tables or {} local bestName, bestInfo, bestMult = nil, nil, 0 for name, info in pairs(tables) do if tableUnlocked(name, info) then local objects = collectNamedTableObjects(name) if #objects > 0 then local m = tableMult(name, info) if m > bestMult then bestName, bestInfo, bestMult = name, info, m end end end end return bestName, bestInfo, bestMult end local tablePartCache = {} local function tableParts(name, obj) local cacheKey = tostring(name) .. "|" .. tostring(obj) local cached = tablePartCache[cacheKey] if cached then local live = {} for _, p in ipairs(cached) do if p and p.Parent then table.insert(live, p) end end if #live > 0 then tablePartCache[cacheKey] = live return live end end local parts = {} if obj:IsA("BasePart") then table.insert(parts, obj) else for _, x in ipairs(obj:GetDescendants()) do if x:IsA("BasePart") then table.insert(parts, x) end end end table.sort(parts, function(a, b) local function score(p) local n = string.lower(p.Name) local bonus = 0 if n:find("training") or n:find("pad") or n:find("top") or n:find("table") or n:find("hitbox") then bonus = 1e9 end return bonus + p.Size.X * p.Size.Z end return score(a) > score(b) end) tablePartCache[cacheKey] = parts return parts end local successfulTablePart = {} local function chooseTableObject(name, info) local objects = collectNamedTableObjects(name) if #objects == 0 then return nil end local desiredWorld = tonumber(info and info.world) local _, _, root = character() local best, bestScore for _, obj in ipairs(objects) do local score = 0 local w = worldOfObject(obj) if desiredWorld and w == desiredWorld then score = score + 1e7 end if root then local pos if obj:IsA("BasePart") then pos = obj.Position else local ok, cf = pcall(function() return select(1, obj:GetBoundingBox()) end) if ok and cf then pos = cf.Position end end if pos then score = score - (pos - root.Position).Magnitude end end if not bestScore or score > bestScore then best, bestScore = obj, score end end return best end local lastTableMove = 0 local function moveToTrainingTable(name, info) if not name then return false end if player:GetAttribute("Training") == name then return true end if os.clock() - lastTableMove < 1.0 then return false end lastTableMove = os.clock() local obj = chooseTableObject(name, info) if not obj then return false end return withMoveLock(function() setAutoWins(false, true) local preferred = successfulTablePart[name] local candidates = {} if preferred and preferred.Parent then table.insert(candidates, preferred) end for _, p in ipairs(tableParts(name, obj)) do if p ~= preferred then table.insert(candidates, p) end end for i = 1, math.min(#candidates, 7) do local p = candidates[i] local cf = topOf(p, 0.05) if cf then travelNear(cf, 3.2) task.wait(0.28) if player:GetAttribute("Training") == name then successfulTablePart[name] = p return true end end end return player:GetAttribute("Training") == name end) end local function highestUnlockedWorld() local count = tonumber(Worlds.COUNT) or 3 local rb = rebirths() local best = 1 for id = 2, count do local req = 0 if Worlds.portalRebirths then local ok, v = pcall(Worlds.portalRebirths, id) if ok then req = tonumber(v) or 0 end elseif type(Worlds.PORTAL_REBIRTHS_BY_WORLD) == "table" then req = tonumber(Worlds.PORTAL_REBIRTHS_BY_WORLD[id]) or 0 end if rb >= req then best = id end end return best end local lastWorldMove = 0 local function ensureWinWorld() if not settings.AutoWorld or not Worlds.idOfPlayer or not Worlds.spawnCFrame then return end local target = highestUnlockedWorld() local ok, current = pcall(Worlds.idOfPlayer, player) current = ok and tonumber(current) or 1 if current >= target then return end if os.clock() - lastWorldMove < 4 then return end lastWorldMove = os.clock() withMoveLock(function() setAutoWins(false, true) local okSpawn, cf = pcall(Worlds.spawnCFrame, target) if okSpawn and cf then teleport(cf) task.wait(0.45) end end) end -- --------------------------------------------------------------------------- -- Clicker / rebirth / smart hybrid state -- --------------------------------------------------------------------------- local cachedFoodTool local function equippedFoodTool() local c, h = character() if not c or not h then cachedFoodTool = nil return nil end if cachedFoodTool and cachedFoodTool.Parent == c and cachedFoodTool:GetAttribute("FatPerClick") ~= nil then return cachedFoodTool end cachedFoodTool = nil for _, x in ipairs(c:GetChildren()) do if x:IsA("Tool") and x:GetAttribute("FatPerClick") ~= nil then cachedFoodTool = x return x end end local backpack = player:FindFirstChildOfClass("Backpack") if backpack then for _, x in ipairs(backpack:GetChildren()) do if x:IsA("Tool") and x:GetAttribute("FatPerClick") ~= nil then cachedFoodTool = x pcall(function() h:EquipTool(x) end) return x end end end end local function clickOnce() local tool = equippedFoodTool() if not tool then return false end local ok = pcall(function() tool:Activate() end) if ok then telemetry.clicks = telemetry.clicks + 1 end return ok end local function rebirthRequirement() local rb = rebirths() if FoodConfig.RebirthLevelReq then local ok, value = pcall(FoodConfig.RebirthLevelReq, rb) if ok and tonumber(value) then return tonumber(value) end end return 10 + rb * 10 end local function rebirthTargetFat() local req = rebirthRequirement() if FoodConfig.FatForLevel then local ok, value = pcall(FoodConfig.FatForLevel, req) if ok and tonumber(value) then return tonumber(value) end end return 0 end local rebirthPending = false local rebirthPendingAt = 0 local function tryRebirth() if not settings.AutoRebirth or not settings.Farm or rebirthPending then return false end local req = rebirthRequirement() if level() < req then return false end rebirthPending = true rebirthPendingAt = os.clock() local before = rebirths() say("Rebirthing at level " .. tostring(level())) setAutoWins(false, true) fire("DoRebirth") worker(function() local deadline = os.clock() + 3 repeat task.wait(0.08) until not app.alive or rebirths() > before or os.clock() >= deadline if rebirths() > before then telemetry.rebirths = telemetry.rebirths + 1 app.generation = app.generation + 1 say("Rebirth " .. tostring(rebirths()) .. " complete") end rebirthPending = false end) return true end local function effectiveChargePercent() local base = math.clamp(tonumber(settings.ChargePercent) or 82, 20, 99) local _, nextFood, nextReq = nextFoodGoal() if nextFood and nextReq and nextReq > 0 and wins() < nextReq then local progress = math.clamp(wins() / nextReq, 0, 1) -- Early in a food target, leave more of the rebirth cycle for win farming. local dynamic = 40 + 42 * progress base = math.min(base, dynamic) end -- Every real WinDenied packet raises the charge target. Successful awards -- slowly relax it again, so Hybrid self-tunes to live server conditions. base = base + math.max(0, tonumber(app.chargeBias) or 0) return math.clamp(base, 30, 97) end local function smartWinTargetFat() local rawTarget = rebirthTargetFat() * (effectiveChargePercent() / 100) local walls = type(FoodConfig.Walls) == "table" and FoodConfig.Walls or {} local bounds = type(walls.EntryBounds) == "table" and walls.EntryBounds or {} if rawTarget <= 0 or #bounds == 0 or not FoodConfig.WorldWallHealth then app.targetWallStage = 0 return rawTarget end local worldId = highestUnlockedWorld() if not settings.AutoWorld and Worlds.idOfPlayer then local ok, currentWorld = pcall(Worlds.idOfPlayer, player) if ok and tonumber(currentWorld) then worldId = tonumber(currentWorld) end end local damageMult = player:GetAttribute("X2Damage") and 2 or 1 local rawDamage = rawTarget * damageMult local chosenStage, chosenHealth for _, stage in ipairs(bounds) do local ok, hp = pcall(FoodConfig.WorldWallHealth, worldId, stage) hp = ok and tonumber(hp) or nil if hp then if not chosenStage then -- Always reach at least the first real win-pad breakpoint. chosenStage, chosenHealth = stage, hp end if hp <= rawDamage then chosenStage, chosenHealth = stage, hp else break end end end app.targetWallStage = tonumber(chosenStage) or 0 if chosenHealth then -- Small safety margin absorbs rounding/server timing without charging -- all the way toward a reward boundary we cannot yet reach. return math.max(0, chosenHealth / damageMult * 1.025) end return rawTarget end local function desiredPhase() if settings.Mode == "Wins" then return "Wins" end if settings.Mode == "Training" then return "Training" end local name, _, mult = bestTrainingTable() if not name or (tonumber(mult) or 1) <= 1 then return "Wins" end if os.clock() < (tonumber(app.forceTrainUntil) or 0) then return "Training" end local threshold = smartWinTargetFat() if threshold <= 0 then return "Wins" end if fat() < threshold then return "Training" end return "Wins" end -- --------------------------------------------------------------------------- -- Smart spending / permanent progression -- --------------------------------------------------------------------------- local function smartReserve() local reserve = math.max(0, tonumber(settings.WinsReserve) or 0) local _, _, req = nextFoodGoal() if req then -- Food unlocks are thresholds rather than a disposable upgrade purchase. -- Protect most of the next threshold so side systems cannot repeatedly -- knock the account backwards just before a major food unlock. reserve = math.max(reserve, req * math.clamp((tonumber(settings.SmartReservePercent) or 75) / 100, 0, 1)) end return reserve end local function spendableWins() return math.max(0, wins() - smartReserve()) end -- Wins purchases share one short gate. Several progression managers run in the -- same side-worker tick, while leaderstats can update a fraction of a second -- after the server accepts a purchase. Without this guard two or three systems -- can all see the same stale balance and collectively dip below the reserve. local function canSpendNow() return os.clock() >= (tonumber(app.spendUntil) or 0) end local function markSpend(delay) app.spendUntil = os.clock() + (tonumber(delay) or 0.8) end -- Eggs get a small independent budget from newly-earned wins. This keeps egg -- automation alive even while the main smart reserve is protecting the next -- food threshold, without allowing eggs to consume the whole progression bank. local function eggSpendableWins() local normal = spendableWins() local absolute = math.max(0, wins() - math.max(0, tonumber(settings.WinsReserve) or 0)) local budgeted = math.min(absolute, math.max(0, tonumber(app.eggBudget) or 0)) -- Let Smart Eggs prove itself immediately with one cheap base hatch when -- possible, even if the food reserve currently consumes every spare Win. local starter = 0 if settings.AutoEggs and telemetry.hatches == 0 and absolute >= 5 then starter = 5 end return math.max(normal, budgeted, starter) end local upgradeLevels = {walkspeed = nil, clickRate = nil, trainingRate = nil} local upgradeBackoff = {walkspeed = 0, clickRate = 0, trainingRate = 0} local function deriveUpgradeLevels() local clickMult = tonumber(player:GetAttribute("ClickRateMult")) local trainMult = tonumber(player:GetAttribute("TrainingRateMult")) if clickMult then upgradeLevels.clickRate = math.max(0, math.floor((clickMult - 1) / 0.1 + 0.5)) end if trainMult then upgradeLevels.trainingRate = math.max(0, math.floor((trainMult - 1) / 0.1 + 0.5)) end if upgradeLevels.walkspeed == nil then local _, h = character() if h then upgradeLevels.walkspeed = math.max(0, math.floor((h.WalkSpeed - 32) / 7 + 0.5)) end end end deriveUpgradeLevels() if Remotes.UpgradesUpdated then connect(Remotes.UpgradesUpdated.OnClientEvent, function(state) if type(state) ~= "table" then return end for key in pairs(upgradeLevels) do local v = tonumber(state[key]) if v then upgradeLevels[key] = v end end end) end local function upgradeCfg(key) if key == "walkspeed" then return UpgradeConfig.Walkspeed end if key == "clickRate" then return UpgradeConfig.ClickRate end if key == "trainingRate" then return UpgradeConfig.TrainingRate end end local function nextUpgradeCost(key) deriveUpgradeLevels() local cfg = upgradeCfg(key) local lvl = tonumber(upgradeLevels[key]) or 0 if type(cfg) ~= "table" or type(cfg.costs) ~= "table" then return nil end return tonumber(cfg.costs[lvl + 1]) end local upgradePending = false local function buyBestUpgrade() if not settings.AutoUpgrades or upgradePending or not canSpendNow() then return end local candidates = {} local enabled = { clickRate = settings.UpgradeClick, trainingRate = settings.UpgradeTraining, walkspeed = settings.UpgradeWalk, } for key, on in pairs(enabled) do if on and os.clock() >= (upgradeBackoff[key] or 0) then local cost = nextUpgradeCost(key) if cost then local lvl = tonumber(upgradeLevels[key]) or 0 local gain if key == "walkspeed" then -- Movement has near-zero farm ROI because PuckAFK uses server -- Auto Wins and targeted teleports for progression actions. gain = 0.000001 else local oldMult = 1 + 0.1 * lvl local newMult = oldMult + 0.1 gain = math.log(newMult / oldMult) if key == "trainingRate" and app.phase ~= "Training" then gain = gain * 0.72 end end table.insert(candidates, {key = key, cost = cost, score = gain / math.max(1, cost)}) end end end table.sort(candidates, function(a, b) if a.score == b.score then local priority = {clickRate = 1, trainingRate = 2, walkspeed = 3} return priority[a.key] < priority[b.key] end return a.score > b.score end) local choice = candidates[1] if not choice or choice.cost > spendableWins() then return end upgradePending = true local before = tonumber(upgradeLevels[choice.key]) or 0 markSpend() fire("BuyUpgrade", choice.key) worker(function() local deadline = os.clock() + 1.3 repeat task.wait(0.08) deriveUpgradeLevels() until not app.alive or (tonumber(upgradeLevels[choice.key]) or 0) > before or os.clock() >= deadline if (tonumber(upgradeLevels[choice.key]) or 0) > before then telemetry.upgrades = telemetry.upgrades + 1 upgradeBackoff[choice.key] = 0 else upgradeBackoff[choice.key] = os.clock() + 20 end upgradePending = false end) end local boostInfo = { {id = "Damage", label = "Fat", attr = "BoostDamage", inc = 0.10}, {id = "Wins", label = "Wins", attr = "BoostWins", inc = 0.10}, {id = "Luck", label = "Luck", attr = "BoostLuck", inc = 0.05}, } local lastBoost = 0 local boostPending = false local boostBackoff = {Damage = 0, Wins = 0, Luck = 0} -- IMPORTANT: BoostsClient stores BoostDamage / BoostWins / BoostLuck as the -- INTEGER UPGRADE LEVEL, not the displayed multiplier. The game's own UI does: -- displayed = 1 + increment * level -- price = floor(5 * 1.5 ^ level) -- Example: BoostDamage == 6 -> x1.60 -> next price 56 Wins. -- v1.4 incorrectly treated the raw level 6 as multiplier x6, inferred level 50, -- and therefore calculated a gigantic price. That is why BuyBoost never fired. local function boostState(b) local raw = tonumber(player:GetAttribute(b.attr)) or 0 local level = math.max(0, math.floor(raw + 0.5)) local mult = 1 + b.inc * level return level, mult, raw end local function boostCost(level) return math.floor(5 * 1.5 ^ math.max(0, math.floor(tonumber(level) or 0))) end local function boostRelativeGain(b, mult) mult = math.max(0.0001, tonumber(mult) or 1) return (mult + b.inc) / mult - 1 end local function boostFarmGain(b, mult) local gain = boostRelativeGain(b, mult) if b.id == "Damage" then -- Fat multiplier speeds clicks, training, wall reach and rebirth setup. local factor = 1.08 if app.phase == "Training" then factor = factor * 1.28 end if (tonumber(app.winDeniedStreak) or 0) > 0 then factor = factor * 1.24 end if (tonumber(app.chargeBias) or 0) >= 8 then factor = factor * 1.12 end return gain * factor elseif b.id == "Wins" then -- Wins multiplier directly shortens every currency target forever. local factor = app.phase == "Wins" and 1.34 or 1.16 local _, _, req = nextFoodGoal() if req and req > wins() then factor = factor * 1.12 end return gain * factor end return settings.AutoEggs and gain * 0.42 or 0 end local function boostCandidateScore(b, level, cost, mult) local relativeGain = math.log((mult + b.inc) / math.max(0.0001, mult)) local weight = 1 if b.id == "Damage" then weight = 1.18 if app.phase == "Training" then weight = weight * 1.34 end if (tonumber(app.winDeniedStreak) or 0) > 0 or (tonumber(app.chargeBias) or 0) >= 8 then weight = weight * 1.22 end elseif b.id == "Wins" then weight = 1.22 if app.phase == "Wins" then weight = weight * 1.38 end local _, _, req = nextFoodGoal() if req and req > wins() then weight = weight * 1.18 end else if not settings.AutoEggs then return -math.huge end weight = 0.38 end return (relativeGain * weight) / math.max(1, cost) end local function refreshBoostSummary() local parts = {} for _, b in ipairs(boostInfo) do local level, mult = boostState(b) parts[#parts + 1] = string.format("%s L%d x%.2f (%s)", b.label, level, mult, fmt(boostCost(level))) end app.boostStateSummary = table.concat(parts, " • ") end -- Decide whether a permanent core boost is worth protecting/buying even when -- the ordinary food reserve would normally hide those Wins from side systems. -- We deliberately use the FULL next-food threshold as the horizon rather than -- only the tiny remaining gap: a permanent multiplier keeps paying after the -- next unlock, and using only the gap caused useful boosts to be skipped near a -- food target. Food that is ALREADY affordable still has first priority. local function coreBoostWorthwhile(candidate) if candidate.def.id ~= "Damage" and candidate.def.id ~= "Wins" then return false end local readyIndex, readyFood = bestAffordableUnboughtFood() if readyIndex and readyFood then return false end local _, _, req = nextFoodGoal() if not req or req <= 0 then return true end local gain = math.max(candidate.farmGain or 0, candidate.relativeGain or 0) local horizon = candidate.def.id == "Wins" and 4.2 or 4.8 local accelerationBudget = req * gain * horizon -- Keep early core boosts from falling absurdly behind progression. At these -- levels their cost is tiny and the permanent gain pays back very quickly. local catchup = candidate.level < 8 and candidate.cost <= req * 0.40 -- If the bank is already large compared with the upgrade, taking the -- permanent multiplier is preferable to sitting on idle currency. local bankEfficient = candidate.cost <= math.max(5, wins() * 0.22) return candidate.cost <= accelerationBudget or catchup or bankEfficient end local function buildBoostCandidates() local candidates = {} for _, b in ipairs(boostInfo) do local enabled = (b.id == "Damage" and settings.BoostDamage) or (b.id == "Wins" and settings.BoostWins) or (b.id == "Luck" and settings.BoostLuck and settings.AutoEggs) if enabled and os.clock() >= (boostBackoff[b.id] or 0) then local level, mult, raw = boostState(b) local cost = boostCost(level) local relativeGain = boostRelativeGain(b, mult) candidates[#candidates + 1] = { def = b, level = level, mult = mult, raw = raw, cost = cost, relativeGain = relativeGain, farmGain = boostFarmGain(b, mult), score = boostCandidateScore(b, level, cost, mult), } end end table.sort(candidates, function(a, b) if a.score == b.score then local p = {Damage = 1, Wins = 2, Luck = 3} return p[a.def.id] < p[b.def.id] end return a.score > b.score end) return candidates end local function waitForBoostLevel(def, beforeLevel, timeout) local deadline = os.clock() + (timeout or 1.6) local level, mult = boostState(def) repeat if level > beforeLevel then return true, level, mult end task.wait(0.07) level, mult = boostState(def) until not app.alive or os.clock() >= deadline return level > beforeLevel, level, mult end -- Returns one of: bought, saving-core, ready-food, none, busy. -- The return value lets the progression worker protect a worthwhile core boost -- from eggs/auras/upgrades while the balance is accumulating. local function buyBestBoost() refreshBoostSummary() if not settings.AutoBoosts then app.boostPlan = "Auto boosts disabled" return "none" end if boostPending then return "busy" end local candidates = buildBoostCandidates() if #candidates == 0 then app.boostPlan = "No enabled boost" return "none" end local readyIndex, readyFood = bestAffordableUnboughtFood() if readyIndex and readyFood then app.boostPlan = "Food ready first • " .. tostring(readyFood.name) return "ready-food" end local absoluteSpare = math.max(0, wins() - math.max(0, tonumber(settings.WinsReserve) or 0)) local normalSpare = spendableWins() local coreSpare = settings.CoreBoostReserveOverride and absoluteSpare or normalSpare local choice = nil local savingCore = nil -- Core Fat/Wins boosts have priority because they permanently increase farm -- speed. They may use the normal smart-food reserve, but NEVER the user's -- explicit Extra wins reserve. If a worthwhile core boost is not affordable -- yet, protect it from lower-priority spending until it is. for _, candidate in ipairs(candidates) do if candidate.def.id == "Damage" or candidate.def.id == "Wins" then if coreBoostWorthwhile(candidate) then if candidate.cost <= coreSpare then choice = candidate break elseif settings.CoreBoostReserveOverride and (not savingCore or candidate.cost < savingCore.cost) then savingCore = candidate end end end end -- Luck is a pet-only side investment. It never steals currency from a core -- boost target and still obeys the normal smart-food reserve. if not choice and not savingCore then for _, candidate in ipairs(candidates) do if candidate.def.id == "Luck" and candidate.cost <= normalSpare then choice = candidate break end end end if not choice then if savingCore then app.boostPlan = string.format( "Saving for %s x%.2f → x%.2f • %s/%s Wins", savingCore.def.label, savingCore.mult, savingCore.mult + savingCore.def.inc, fmt(coreSpare), fmt(savingCore.cost) ) return "saving-core" end local best = candidates[1] app.boostPlan = string.format( "Waiting • %s next x%.2f → x%.2f costs %s Wins", best.def.label, best.mult, best.mult + best.def.inc, fmt(best.cost) ) return "none" end if not canSpendNow() or os.clock() - lastBoost < 0.45 then return "busy" end local arrow = string.format("x%.2f → x%.2f", choice.mult, choice.mult + choice.def.inc) app.boostPlan = choice.def.label .. " " .. arrow .. " • buying for " .. fmt(choice.cost) .. " Wins" lastBoost = os.clock() boostPending = true markSpend(2.2) local beforeLevel = choice.level worker(function() local fired = fire("BuyBoost", choice.def.id) local success, afterLevel, afterMult = false, beforeLevel, choice.mult if fired then success, afterLevel, afterMult = waitForBoostLevel(choice.def, beforeLevel, 1.65) end -- One controlled retry handles a delayed/stale client balance without -- blindly spamming the server. We only retry if the exact server price -- is still affordable above the user's hard reserve. if not success and app.alive then local hardSpare = math.max(0, wins() - math.max(0, tonumber(settings.WinsReserve) or 0)) if hardSpare >= choice.cost then task.wait(0.22) fire("BuyBoost", choice.def.id) success, afterLevel, afterMult = waitForBoostLevel(choice.def, beforeLevel, 1.45) end end if success then boostBackoff[choice.def.id] = 0 app.boostPlan = choice.def.label .. " upgraded to x" .. string.format("%.2f", afterMult) say("Bought " .. choice.def.label .. " boost " .. arrow) else boostBackoff[choice.def.id] = os.clock() + 2.5 local currentLevel, currentMult = boostState(choice.def) app.boostPlan = string.format( "%s purchase rejected/not confirmed • level %d x%.2f • retrying", choice.def.label, currentLevel, currentMult ) end refreshBoostSummary() boostPending = false end) return "bought" end local function ownedAuras() local set = {} for card in string.gmatch(tostring(player:GetAttribute("OwnedAuras") or ""), "[^;]+") do set[card] = true end return set end local lastAuraAction = 0 local function manageAura() if not settings.AutoAura or os.clock() - lastAuraAction < 1.5 then return end local defs = type(AuraConfig.Auras) == "table" and AuraConfig.Auras or {} if #defs == 0 then return end local owned = ownedAuras() local bestOwned, bestMult = nil, 0 for _, a in ipairs(defs) do if owned[a.card] and (tonumber(a.mult) or 0) > bestMult then bestOwned, bestMult = a, tonumber(a.mult) or 0 end end if bestOwned and player:GetAttribute("EquippedAura") ~= bestOwned.card then lastAuraAction = os.clock() fire("EquipAura", bestOwned.card) return end local affordable for _, a in ipairs(defs) do if not owned[a.card] and tonumber(a.wins) and tonumber(a.wins) <= spendableWins() then if not affordable or (tonumber(a.mult) or 0) > (tonumber(affordable.mult) or 0) then affordable = a end end end if affordable and canSpendNow() then lastAuraAction = os.clock() markSpend() fire("BuyAuraWins", affordable.card) end end -- --------------------------------------------------------------------------- -- Pets / eggs -- --------------------------------------------------------------------------- local petState = {pets = {}, equipped = 0, equipLimit = tonumber(PetConfig.EQUIP_LIMIT) or 3, storage = tonumber(PetConfig.STORAGE_LIMIT) or 100} local petManaging = false local lastBestPetScan = 0 local lastGoldenScan = 0 local lastRainbowScan = 0 local hatchPending = false local goldenPending = false local rainbowPending = false local function hatchVisualsShouldBeHidden() return settings.HideHatchAnimation and ( hatchPending or player:GetAttribute("EggHatching") == true or os.clock() < (tonumber(app.suppressHatchVisualsUntil) or 0) ) end local function hideHatchInstance(x) if not x then return end pcall(function() if x:IsA("BasePart") and (x.Name == "HatchDisplay" or x.Name == "LabelAnchor") then -- LocalTransparencyModifier is not touched by EggsClient's reveal -- tweens, so the model stays invisible without destroying objects -- that EggsClient still expects to animate/clean up later. x.LocalTransparencyModifier = 1 elseif x:IsA("BillboardGui") or x:IsA("SurfaceGui") then x.Enabled = false elseif x:IsA("ParticleEmitter") or x:IsA("Trail") or x:IsA("Beam") then x.Enabled = false end end) end local function suppressHatchPresentation() if not settings.HideHatchAnimation then return end app.suppressHatchVisualsUntil = math.max(tonumber(app.suppressHatchVisualsUntil) or 0, os.clock() + 2.1) local pg = player:FindFirstChildOfClass("PlayerGui") local flash = pg and pg:FindFirstChild("HatchFlash") if flash and flash:IsA("ScreenGui") then flash.Enabled = false end local newGui = pg and pg:FindFirstChild("NewGui") if newGui and newGui:IsA("ScreenGui") then newGui.Enabled = true end for _, x in ipairs(workspace:GetChildren()) do if x.Name == "HatchDisplay" or x.Name == "LabelAnchor" then hideHatchInstance(x) for _, d in ipairs(x:GetDescendants()) do hideHatchInstance(d) end end end end -- EggsClient renders reveal models directly in Workspace. Keep its temporary -- objects alive (so its state machine remains healthy) but make every local -- model/label/particle invisible while a hatch is active. connect(workspace.DescendantAdded, function(x) if not hatchVisualsShouldBeHidden() then return end local owner = x while owner and owner ~= workspace do if owner.Name == "HatchDisplay" or owner.Name == "LabelAnchor" then hideHatchInstance(owner) hideHatchInstance(x) task.defer(function() if owner and owner.Parent then hideHatchInstance(owner) for _, d in ipairs(owner:GetDescendants()) do hideHatchInstance(d) end end end) break end owner = owner.Parent end end) connect(player:GetAttributeChangedSignal("EggHatching"), function() if player:GetAttribute("EggHatching") == true and settings.HideHatchAnimation then task.defer(suppressHatchPresentation) end end) local function petMult(p) local m = tonumber(p and p.mult) or 0 if TraitConfig.getTraitMultiplier then local ok, t = pcall(TraitConfig.getTraitMultiplier, p and p.traits) if ok and tonumber(t) then m = m * tonumber(t) end end return m end local function petHasTraits(p) if type(p) ~= "table" or type(p.traits) ~= "table" then return false end if TraitConfig.namesOf then local ok, names = pcall(TraitConfig.namesOf, p.traits) if ok and type(names) == "table" then return #names > 0 end end for _, value in pairs(p.traits) do if value == true or (tonumber(value) and tonumber(value) > 0) then return true end end return false end if Remotes.PetsUpdated then connect(Remotes.PetsUpdated.OnClientEvent, function(pets, equipped, equipLimit, storage) if type(pets) == "table" then petState.pets = pets end petState.equipped = tonumber(equipped) or petState.equipped petState.equipLimit = tonumber(equipLimit) or petState.equipLimit petState.storage = tonumber(storage) or petState.storage end) end if Remotes.HatchResult then connect(Remotes.HatchResult.OnClientEvent, function(results, err) if settings.HideHatchAnimation then task.defer(suppressHatchPresentation) end hatchPending = false app.lastHatchError = err and tostring(err) or nil if type(results) == "table" and #results > 0 and not err then telemetry.hatches = telemetry.hatches + #results app.lastHatchSuccess = os.clock() say("Egg opened • " .. tostring(#results) .. " pet" .. (#results == 1 and "" or "s")) elseif err then say("Egg hatch rejected: " .. tostring(err)) end end) end if Remotes.GoldenResult then connect(Remotes.GoldenResult.OnClientEvent, function(success) goldenPending = false if success then say("Guaranteed Golden craft completed") task.delay(0.25, function() fire("RequestPets") end) end end) end if Remotes.RainbowResult then connect(Remotes.RainbowResult.OnClientEvent, function(success) rainbowPending = false if success then say("Guaranteed Rainbow craft completed") task.delay(0.25, function() fire("RequestPets") end) end end) end local lastPetRequest = 0 local function requestPets() if os.clock() - lastPetRequest >= 8 then lastPetRequest = os.clock() fire("RequestPets") end end local function manageBestPets() if not settings.AutoPets or petManaging or os.clock() - lastBestPetScan < 1.25 then return end lastBestPetScan = os.clock() local pets = petState.pets if type(pets) ~= "table" or #pets == 0 then requestPets() return end local sorted = {} for _, p in ipairs(pets) do table.insert(sorted, p) end table.sort(sorted, function(a, b) local am, bm = petMult(a), petMult(b) if am == bm then return (tonumber(a.id) or 0) < (tonumber(b.id) or 0) end return am > bm end) local limit = math.max(1, tonumber(petState.equipLimit) or 3) local wanted = {} for i = 1, math.min(limit, #sorted) do wanted[sorted[i].id] = true end local actions = {} for _, p in ipairs(pets) do if p.equipped and not wanted[p.id] then table.insert(actions, {kind = "off", id = p.id}) end end for i = 1, math.min(limit, #sorted) do local p = sorted[i] if not p.equipped then table.insert(actions, {kind = "on", id = p.id}) end end if #actions == 0 then return end petManaging = true worker(function() for _, a in ipairs(actions) do if not app.alive then break end if a.kind == "off" then fire("UnequipPet", a.id) else fire("EquipPet", a.id) end task.wait(0.1) end task.wait(0.35) requestPets() petManaging = false end) end local craftMachineCache = {} local function nearestCraftMachine(machineName) local cached = craftMachineCache[machineName] if cached and cached.Parent then return cached end local _, _, root = character() if Worlds.nearestNamed and root then local ok, inst = pcall(function() return Worlds.nearestNamed(machineName, root.Position, true) end) if ok and inst then return inst end end local best, bestDist for _, x in ipairs(namedWorldObjects(machineName)) do local pos = x:IsA("BasePart") and x.Position or x:GetPivot().Position local d = root and (pos - root.Position).Magnitude or 0 if not bestDist or d < bestDist then best, bestDist = x, d end end if best then craftMachineCache[machineName] = best end return best end local function objectTopCFrame(obj, extra) if not obj then return nil end if obj:IsA("BasePart") then return topOf(obj, extra) end if obj:IsA("Model") then local ok, cf, size = pcall(function() local a, b = obj:GetBoundingBox() return a, b end) if ok and cf and size then local _, h, r = character() local y = size.Y / 2 + (h and h.HipHeight or 2) + (r and r.Size.Y / 2 or 1) + (extra or 0.3) return cf * CFrame.new(0, y, 0) end end end local lastGolden = 0 local function manageGoldenPets() if not settings.AutoGolden or goldenPending or os.clock() - lastGolden < 2.5 or os.clock() - lastGoldenScan < 2.0 then return end lastGoldenScan = os.clock() local groups = {} for _, p in ipairs(petState.pets) do local rarity = tostring(p.rarity or "") if not p.equipped and not rarity:match(" Gold$") and not rarity:match(" Rainbow$") and (not settings.ProtectTraitedPets or not petHasTraits(p)) then local key = rarity .. "|" .. tostring(p.pet or "") groups[key] = groups[key] or {} table.insert(groups[key], p) end end local chosen for _, group in pairs(groups) do if #group >= 4 then table.sort(group, function(a, b) return petMult(a) < petMult(b) end) if not chosen or petMult(group[1]) > petMult(chosen[1]) then chosen = group end end end if not chosen then return end local ids = {chosen[1].id, chosen[2].id, chosen[3].id, chosen[4].id} lastGolden = os.clock() goldenPending = true worker(function() withMoveLock(function() setAutoWins(false, true) local pad = nearestCraftMachine("OpenGold") if pad then teleport(objectTopCFrame(pad, 0.2)) task.wait(0.3) end fire("TryGoldenPet", ids) end) local deadline = os.clock() + 3.2 repeat task.wait(0.08) until not app.alive or not goldenPending or os.clock() >= deadline goldenPending = false fire("RequestPets") end) end local lastRainbow = 0 local function manageRainbowPets() if not settings.AutoRainbow or rebirths() < 1 or rainbowPending or os.clock() - lastRainbow < 2.5 or os.clock() - lastRainbowScan < 2.0 then return end lastRainbowScan = os.clock() local groups = {} for _, p in ipairs(petState.pets) do local rarity = tostring(p.rarity or "") if not p.equipped and rarity:match(" Gold$") and (not settings.ProtectTraitedPets or not petHasTraits(p)) then local key = rarity .. "|" .. tostring(p.pet or "") groups[key] = groups[key] or {} table.insert(groups[key], p) end end local chosen for _, group in pairs(groups) do if #group >= 4 then table.sort(group, function(a, b) return petMult(a) < petMult(b) end) if not chosen or petMult(group[1]) > petMult(chosen[1]) then chosen = group end end end if not chosen then return end local ids = {chosen[1].id, chosen[2].id, chosen[3].id, chosen[4].id} lastRainbow = os.clock() rainbowPending = true worker(function() withMoveLock(function() setAutoWins(false, true) local pad = nearestCraftMachine("OpenRainbow") if pad then teleport(objectTopCFrame(pad, 0.2)) task.wait(0.3) end fire("TryRainbowPet", ids) end) local deadline = os.clock() + 3.2 repeat task.wait(0.08) until not app.alive or not rainbowPending or os.clock() >= deadline rainbowPending = false fire("RequestPets") end) end local eggOptions = {"Smart improvement"} local eggDefs = {} for id, egg in pairs(type(PetConfig.EGGS) == "table" and PetConfig.EGGS or {}) do if type(egg) == "table" and type(egg.cost) == "table" and egg.cost.kind == "wins" then eggDefs[id] = egg end end local eggIds = {} for id in pairs(eggDefs) do table.insert(eggIds, id) end table.sort(eggIds, function(a, b) return (tonumber(eggDefs[a].cost.amount) or 0) < (tonumber(eggDefs[b].cost.amount) or 0) end) for _, id in ipairs(eggIds) do table.insert(eggOptions, id) end local function weakestEquippedPetMult() local count, weakest = 0, math.huge for _, p in ipairs(petState.pets) do if p.equipped then count = count + 1 weakest = math.min(weakest, petMult(p)) end end if count < math.max(1, tonumber(petState.equipLimit) or 3) then return 0 end return weakest == math.huge and 0 or weakest end local function eggImprovement(def) if type(def) ~= "table" or not PetConfig.getPets then return nil end local ok, pool = pcall(PetConfig.getPets, def.rarity) if not ok or type(pool) ~= "table" or #pool == 0 then return nil end local threshold = weakestEquippedPetMult() local totalWeight, expectedGain, expectedMult = 0, 0, 0 for _, p in ipairs(pool) do local weight = math.max(0, tonumber(p.chance) or 0) if weight == 0 then weight = 1 end local mult = math.max(0, tonumber(p.mult) or 0) totalWeight = totalWeight + weight expectedMult = expectedMult + weight * mult expectedGain = expectedGain + weight * math.max(0, mult - threshold) end if totalWeight <= 0 then return nil end return expectedGain / totalWeight, expectedMult / totalWeight end local function selectedEgg() if settings.Egg ~= "Smart improvement" then return settings.Egg, eggDefs[settings.Egg] end local spare = eggSpendableWins() local bestId, bestDef, bestScore local fallbackId, fallbackDef for _, candidate in ipairs(eggIds) do local d = eggDefs[candidate] local cost = tonumber(d and d.cost and d.cost.amount) or math.huge if cost <= spare then fallbackId, fallbackDef = candidate, d local gain, expected = eggImprovement(d) if gain then local score = gain / math.max(1, cost) -- When there is an empty equip slot, expected multiplier itself -- is useful even if every candidate is technically an upgrade. if weakestEquippedPetMult() <= 0 then score = expected / math.max(1, cost) end if score > 0 and (not bestScore or score > bestScore) then bestId, bestDef, bestScore = candidate, d, score end end end end return bestId or fallbackId, bestDef or fallbackDef end local lastEgg = 0 local function waitForHatch(timeout) local deadline = os.clock() + (timeout or 1.4) while app.alive and hatchPending and os.clock() < deadline do task.wait(0.06) end return not hatchPending and app.lastHatchError == nil and os.clock() - (tonumber(app.lastHatchSuccess) or 0) < 2 end local function hatchEggSmart() if not settings.AutoEggs or hatchPending or os.clock() - lastEgg < settings.EggDelay or not canSpendNow() then return false end if #petState.pets >= (tonumber(petState.storage) or 100) then say("Eggs paused • pet storage full") return false end local id, def = selectedEgg() if not id or not def then return false end local cost = tonumber(def.cost.amount) or math.huge if cost > eggSpendableWins() then return false end lastEgg = os.clock() markSpend(1.4) app.lastHatchError = nil hatchPending = true if settings.HideHatchAnimation then suppressHatchPresentation() end worker(function() local success = false local function hatchNearSource() local source if PetConfig.eggSource then local ok, part = pcall(PetConfig.eggSource, id) if ok then source = part end end if not (source and source:IsA("BasePart")) then return false end withMoveLock(function() setAutoWins(false, true) local _, _, root = character() if not root or (root.Position - source.Position).Magnitude > 14 then travelNear(topOf(source, 0.35), 4) task.wait(0.16) end app.lastHatchError = nil hatchPending = true if settings.HideHatchAnimation then suppressHatchPresentation() end fire("HatchEgg", id, 1) end) return waitForHatch(1.5) end if app.hatchNeedsProximity[id] then success = hatchNearSource() else -- Direct hatch first. The server uses the same (eggId, count) pair -- as EggsClient. This avoids unnecessary cross-world teleports. if settings.HideHatchAnimation then suppressHatchPresentation() end fire("HatchEgg", id, 1) success = waitForHatch(1.25) if not success and app.alive then local err = string.lower(tostring(app.lastHatchError or "")) local proximityLike = err == "" or err:find("near", 1, true) or err:find("close", 1, true) or err:find("distance", 1, true) or err:find("far", 1, true) if proximityLike then hatchPending = false app.lastHatchError = nil success = hatchNearSource() if success then app.hatchNeedsProximity[id] = true end end end end hatchPending = false if success then app.eggBudget = math.max(0, (tonumber(app.eggBudget) or 0) - cost) -- PetsUpdated already arrives on success. AutoPets will choose the -- actual strongest set; avoid a redundant server auto-equip pass. if not settings.AutoPets then fire("AutoEquipHatched") end elseif not app.lastHatchError then say("Egg hatch timed out • will retry") end end) return true end -- --------------------------------------------------------------------------- -- Titles, daily rewards, spins, quests, group reward -- --------------------------------------------------------------------------- local lastTitleEquip = 0 local lastTitleRoll = 0 local function manageTitles() if not settings.AutoTitles then return end if os.clock() - lastTitleEquip > 4 then lastTitleEquip = os.clock() fire("EquipBestTitle") end if settings.RollTitles and os.clock() - lastTitleRoll >= settings.TitleRollDelay then local cost = tonumber(TitleConfig.RollCost) or 10 if cost <= spendableWins() and canSpendNow() then lastTitleRoll = os.clock() markSpend() fire("RollTitle") end end end local dailyState = {claimed = {}, remaining = math.huge, allReady = false, current = 1} local dailyPending = {} if Remotes.DailyState then connect(Remotes.DailyState.OnClientEvent, function(claimed, remaining, allReady, current) if type(claimed) == "table" then dailyState.claimed = claimed end dailyState.remaining = math.max(0, tonumber(remaining) or 0) dailyState.allReady = allReady == true dailyState.current = math.clamp(tonumber(current) or dailyState.current or 1, 1, 7) for i in pairs(dailyPending) do if dailyState.claimed[i] then dailyPending[i] = nil end end end) end local lastDailyRequest = 0 local function manageDaily() if not settings.AutoDaily then return end if os.clock() - lastDailyRequest > 20 then lastDailyRequest = os.clock() fire("DailyState") end for i = 1, 7 do local claimable = dailyState.allReady or (i == dailyState.current and dailyState.remaining <= 0) if claimable and dailyState.claimed[i] ~= true and not dailyPending[i] then dailyPending[i] = os.clock() fire("DailyClaim", i) task.delay(4, function() dailyPending[i] = nil end) break end end end local lastSpin = 0 local function manageSpin() if not settings.AutoSpin then return end local spins = tonumber(player:GetAttribute("Spins")) or 0 if spins > 0 and os.clock() - lastSpin > 4.8 then lastSpin = os.clock() fire("RequestSpin") end end local questState = {tokens = 0, levels = {}, owned = {}, weekly = {}, monthly = {}} local questPending = false if Remotes.QuestState then connect(Remotes.QuestState.OnClientEvent, function(state) if type(state) ~= "table" then return end questState.tokens = tonumber(state.tokens) or tonumber(player:GetAttribute("QuestTokens")) or 0 questState.levels = type(state.levels) == "table" and state.levels or questState.levels questState.owned = type(state.owned) == "table" and state.owned or questState.owned questState.weekly = type(state.weekly) == "table" and state.weekly or questState.weekly questState.monthly = type(state.monthly) == "table" and state.monthly or questState.monthly end) end if Remotes.RewardResult then connect(Remotes.RewardResult.OnClientEvent, function() questPending = false end) end local lastQuestState = 0 local function rewardDef(id) if type(QuestConfig.REWARD_BY_ID) == "table" then return QuestConfig.REWARD_BY_ID[id] end for _, r in ipairs(type(QuestConfig.REWARDS) == "table" and QuestConfig.REWARDS or {}) do if r.id == id then return r end end end local function rewardPrice(def, lvl) if QuestConfig.rewardPrice then local ok, price = pcall(QuestConfig.rewardPrice, def, lvl) if ok and tonumber(price) then return tonumber(price) end end return tonumber(def and def.price) or math.huge end local function rewardMaxed(def, lvl) if QuestConfig.rewardMaxed then local ok, value = pcall(QuestConfig.rewardMaxed, def, lvl) if ok then return value == true end end local max = tonumber(def and def.maxLevel) return max and max > 0 and lvl >= max or false end local function manageQuestRewards() if not settings.AutoQuestRewards then return end if os.clock() - lastQuestState > 25 then lastQuestState = os.clock() fire("QuestState") end if questPending then return end local tokens = tonumber(player:GetAttribute("QuestTokens")) or tonumber(questState.tokens) or 0 local priorities = settings.AutoEggs and {"fat_125", "wins_125", "luck_125"} or {"fat_125", "wins_125"} local choice, choicePrice for _, id in ipairs(priorities) do local def = rewardDef(id) if def then local lvl = tonumber(questState.levels[id]) or 0 local price = rewardPrice(def, lvl) if not rewardMaxed(def, lvl) and tokens >= price then choice, choicePrice = def, price break end end end if choice and choicePrice then questPending = true fire("RewardBuy", choice.id) task.delay(3.5, function() questPending = false end) end if settings.AutoWeeklyFood and questState.weekly and questState.weekly.unlocked == true then if player:GetAttribute("EquippedFood") ~= "Tacos" then fire("WeeklyEquip") end end end local groupClaimedAttempt = false local function manageGroupReward() if not settings.AutoGroupReward or groupClaimedAttempt then return end groupClaimedAttempt = true worker(function() local inGroup = false pcall(function() inGroup = player:IsInGroup(1081589393) end) if inGroup then fire("GroupClaim") task.wait(3) fire("GroupClaim") end end) end -- --------------------------------------------------------------------------- -- UI -- --------------------------------------------------------------------------- local controls = {} local function toggle(tab, name, key, flagPrefix) local control = tab:CreateToggle({ Name = name, Flag = (flagPrefix or "FPC_") .. key, CurrentValue = settings[key], Callback = function(v) settings[key] = v == true if key == "Farm" and not settings.Farm then setAutoWins(false, true) app.phase = "Idle" say("Stopped") elseif key == "HideHatchAnimation" then local pg = player:FindFirstChildOfClass("PlayerGui") local flash = pg and pg:FindFirstChild("HatchFlash") if settings.HideHatchAnimation then suppressHatchPresentation() elseif flash and flash:IsA("ScreenGui") then flash.Enabled = true end end end, }) controls[key] = control return control end local farmTab = window:CreateTab("Farm") farmTab:CreateSection("Smart farm") toggle(farmTab, "Smart autofarm", "Farm") farmTab:CreateDropdown({ Name = "Farm mode", Flag = "FPC_Mode", Options = {"Hybrid", "Wins", "Training"}, CurrentOption = {settings.Mode}, Callback = function(v) settings.Mode = type(v) == "table" and v[1] or v app.generation = app.generation + 1 end, }) toggle(farmTab, "Auto click food", "AutoClick") toggle(farmTab, "Use native Auto Clicker if gamepass owned", "NativeAutoClick") toggle(farmTab, "Auto rebirth", "AutoRebirth") toggle(farmTab, "Auto best food", "AutoFood") toggle(farmTab, "Use best training table", "AutoTable") toggle(farmTab, "Use highest unlocked world", "AutoWorld") farmTab:CreateSlider({ Name = "Base training charge %", Flag = "FPC_ChargePercent", Range = {30, 95}, Increment = 1, CurrentValue = settings.ChargePercent, Callback = function(v) settings.ChargePercent = tonumber(v) or 82 end, }) farmTab:CreateSlider({ Name = "Click delay", Flag = "FPC_ClickDelay", Range = {0.10, 0.25}, Increment = 0.01, CurrentValue = settings.ClickDelay, Callback = function(v) settings.ClickDelay = math.max(0.10, tonumber(v) or 0.10) end, }) farmTab:CreateLabel("Hybrid dynamically charges less when the next food needs more wins, then returns to the best table before rebirth.") local progressTab = window:CreateTab("Progress") progressTab:CreateSection("Permanent upgrades") toggle(progressTab, "Auto buy upgrades", "AutoUpgrades") toggle(progressTab, "Click-rate upgrade", "UpgradeClick") toggle(progressTab, "Training-rate upgrade", "UpgradeTraining") toggle(progressTab, "Walkspeed upgrade", "UpgradeWalk") progressTab:CreateSection("Boosts & aura") toggle(progressTab, "Smart auto-upgrade boosts by ROI", "AutoBoosts") toggle(progressTab, "Fat boost", "BoostDamage") toggle(progressTab, "Wins boost", "BoostWins") toggle(progressTab, "Luck boost (only while egg farming)", "BoostLuck") toggle(progressTab, "Let core Fat/Wins boosts use reserve when faster", "CoreBoostReserveOverride") progressTab:CreateButton({Name="Run smart boost purchase now", Callback=function() buyBestBoost() end}) progressTab:CreateLabel("Fat/Wins boosts are core farm-speed upgrades. The game stores an integer boost LEVEL: x1.60 Fat = level 6 = 56 Wins next. Core boosts are bought before eggs/auras/upgrades and can use the smart food reserve when their permanent speed gain is worthwhile; the explicit Extra wins reserve is always protected. Luck stays pet-only.") toggle(progressTab, "Auto buy / equip best aura", "AutoAura") progressTab:CreateSection("Wins budget") progressTab:CreateSlider({ Name = "Reserve % of next food goal", Flag = "FPC_SmartReservePercent", Range = {0, 100}, Increment = 5, CurrentValue = settings.SmartReservePercent, Callback = function(v) settings.SmartReservePercent = tonumber(v) or 75 end, }) progressTab:CreateSlider({ Name = "Extra wins reserve", Flag = "FPC_WinsReserve", Range = {0, 1000000000}, Increment = 1000, CurrentValue = settings.WinsReserve, Callback = function(v) settings.WinsReserve = tonumber(v) or 0 end, }) local petsTab = window:CreateTab("Pets") petsTab:CreateSection("Pet automation") toggle(petsTab, "Auto equip strongest pets", "AutoPets") toggle(petsTab, "Auto hatch eggs (spends wins)", "AutoEggs") toggle(petsTab, "Hide egg / pet opening animation", "HideHatchAnimation") toggle(petsTab, "Auto Golden with 4 duplicates (100% only)", "AutoGolden") toggle(petsTab, "Auto Rainbow with 4 Gold duplicates (100% only)", "AutoRainbow") toggle(petsTab, "Protect pets with traits from crafting", "ProtectTraitedPets") petsTab:CreateDropdown({ Name = "Egg", Flag = "FPC_Egg", Options = eggOptions, CurrentOption = {settings.Egg}, Callback = function(v) settings.Egg = type(v) == "table" and v[1] or v end, }) petsTab:CreateSlider({ Name = "Hatch delay", Flag = "FPC_EggDelay", Range = {0.5, 5}, Increment = 0.1, CurrentValue = settings.EggDelay, Callback = function(v) settings.EggDelay = math.max(0.5, tonumber(v) or 1.2) end, }) petsTab:CreateButton({Name = "Refresh pets now", Callback = function() fire("RequestPets") end}) petsTab:CreateSlider({ Name = "Egg budget % of new wins", Flag = "FPC_EggBudgetPercent", Range = {0, 30}, Increment = 1, CurrentValue = settings.EggBudgetPercent, Callback = function(v) settings.EggBudgetPercent = math.clamp(tonumber(v) or 10, 0, 30) end, }) petsTab:CreateLabel("Eggs use surplus wins first, then only the configured slice of newly-earned wins. Direct hatching is tried before any travel.") local rewardsTab = window:CreateTab("Rewards") rewardsTab:CreateSection("Free rewards") toggle(rewardsTab, "Claim daily rewards", "AutoDaily") toggle(rewardsTab, "Use free spins", "AutoSpin") toggle(rewardsTab, "Claim group reward if eligible", "AutoGroupReward") rewardsTab:CreateSection("Titles") toggle(rewardsTab, "Auto equip best title", "AutoTitles") toggle(rewardsTab, "Auto roll titles (spends wins)", "RollTitles") rewardsTab:CreateSlider({ Name = "Title roll delay", Flag = "FPC_TitleRollDelay", Range = {0.15, 2}, Increment = 0.05, CurrentValue = settings.TitleRollDelay, Callback = function(v) settings.TitleRollDelay = math.max(0.15, tonumber(v) or 0.3) end, }) rewardsTab:CreateSection("Quest tokens") toggle(rewardsTab, "Buy permanent quest multipliers", "AutoQuestRewards") toggle(rewardsTab, "Equip weekly Tacos when unlocked", "AutoWeeklyFood") rewardsTab:CreateLabel("Quest tokens prioritize permanent Fat then Wins. Luck is only bought while egg automation is enabled; consumable level/rebirth rewards stay protected.") local statusTab = window:CreateTab("Status") statusTab:CreateSection("Live status") local activityLabel = statusTab:CreateParagraph({Title = "Activity", Content = "Starting...", Height = 72}) local powerLabel = statusTab:CreateParagraph({Title = "Power", Content = "Reading...", Height = 98}) local progressLabel = statusTab:CreateParagraph({Title = "Progression", Content = "Reading...", Height = 84}) local petLabel = statusTab:CreateParagraph({Title = "Pets / rewards", Content = "Reading...", Height = 112}) statusTab:CreateButton({Name = "Force native Auto Wins ON", Callback = function() setAutoWins(true, true) end}) statusTab:CreateButton({Name = "Force native Auto Wins OFF", Callback = function() setAutoWins(false, true) end}) local settingsTab = window:CreateTab("Settings") settingsTab:CreateSection("Session") toggle(settingsTab, "Anti-AFK", "AntiAFK") toggle(settingsTab, "Low-lag mode (hide click FX + slower scanners)", "LowLag") toggle(settingsTab, "Smart pathfinding + anti-stuck jump recovery", "SmartNavigation") settingsTab:CreateButton({Name = "Stop all farm actions", Callback = function() settings.Farm = false if controls.Farm then controls.Farm:Set(false) end setAutoWins(false, true) app.phase = "Idle" say("Stopped") end}) settingsTab:CreateButton({Name = "Unload PuckAFK", Callback = app.Stop}) settingsTab:CreateLabel("PuckUI profiles/autosave and the shared K visibility bind are handled by PuckUI.") -- --------------------------------------------------------------------------- -- Runtime workers -- --------------------------------------------------------------------------- connect(player.CharacterAdded, function() cachedFoodTool = nil craftMachineCache = {} app.generation = app.generation + 1 successfulTablePart = {} app.autoWinsState = nil task.delay(1.2, deriveUpgradeLevels) end) if rebirthsValue then connect(rebirthsValue.Changed, function() app.generation = app.generation + 1 successfulTablePart = {} end) end if Remotes.WinPadAward then connect(Remotes.WinPadAward.OnClientEvent, function(amount) telemetry.winsAwards = telemetry.winsAwards + 1 local gained = tonumber(amount) or 0 telemetry.winsAwardAmount = telemetry.winsAwardAmount + gained app.eggBudget = (tonumber(app.eggBudget) or 0) + gained * math.clamp((tonumber(settings.EggBudgetPercent) or 10) / 100, 0, 0.30) app.lastWinAward = os.clock() app.winDeniedStreak = 0 app.chargeBias = math.max(0, (tonumber(app.chargeBias) or 0) - 2) end) end if Remotes.WinDenied then connect(Remotes.WinDenied.OnClientEvent, function() app.winDeniedStreak = (tonumber(app.winDeniedStreak) or 0) + 1 app.chargeBias = math.min(28, (tonumber(app.chargeBias) or 0) + 6) app.forceTrainUntil = os.clock() + math.min(7, 2.5 + app.winDeniedStreak) setAutoWins(false, true) say("Win denied • adaptive charge +" .. tostring(math.floor(app.chargeBias)) .. "%") end) end if Remotes.WallFXRE then connect(Remotes.WallFXRE.OnClientEvent, function(action, worldId, stage) if action == "break" or action == "hit" then app.wallAction = action app.wallWorld = tonumber(worldId) or app.wallWorld app.wallStage = math.max(tonumber(app.wallStage) or 0, tonumber(stage) or 0) app.lastWallProgress = os.clock() elseif action == "restore" then app.wallAction = "restore" app.wallStage = 0 app.lastWallProgress = os.clock() end end) end connect(player.Idled, function() if not settings.AntiAFK then return end pcall(function() VirtualUser:CaptureController() VirtualUser:Button2Down(Vector2.new(0, 0), workspace.CurrentCamera and workspace.CurrentCamera.CFrame or CFrame.new()) task.wait(0.05) VirtualUser:Button2Up(Vector2.new(0, 0), workspace.CurrentCamera and workspace.CurrentCamera.CFrame or CFrame.new()) end) end) -- Click worker. Native Auto Clicker is used only when the player owns its -- gamepass; otherwise Tool:Activate() runs near the game's own 0.1s cadence. worker(function() local AUTO_CLICK_PASS = 1883741322 local lastNativeRequest = 0 while app.alive do if settings.Farm and settings.AutoClick then local nativeActive = player:GetAttribute("AutoClicker") == true local canNative = settings.NativeAutoClick and ownsPass(AUTO_CLICK_PASS) if canNative then if not nativeActive and os.clock() - lastNativeRequest > 2 then lastNativeRequest = os.clock() setNativeAutoClick(true, true) task.wait(0.15) nativeActive = player:GetAttribute("AutoClicker") == true end elseif app.nativeAutoClickScriptOwned and nativeActive then setNativeAutoClick(false, true) nativeActive = false end if not nativeActive then clickOnce() task.wait(math.max(0.10, tonumber(settings.ClickDelay) or 0.10)) else task.wait(0.1) end else if app.nativeAutoClickScriptOwned and player:GetAttribute("AutoClicker") == true then setNativeAutoClick(false, true) end task.wait(0.12) end end end) -- Main smart farm state machine. worker(function() local lastAutoWinsRefresh = 0 local previousPhase = "Idle" while app.alive do if not settings.Farm then app.phase = "Idle" if app.autoWinsState then setAutoWins(false, true) end task.wait(0.25) continue end if tryRebirth() then task.wait(0.25) continue end if app.moveLock or rebirthPending then task.wait(0.1) continue end local phase = desiredPhase() app.phase = phase if phase ~= previousPhase then previousPhase = phase if phase == "Wins" then app.lastWallProgress = os.clock() app.lastWinAward = os.clock() end end if phase == "Training" then setAutoWins(false) if settings.AutoTable then local name, info, mult = bestTrainingTable() if name then if player:GetAttribute("Training") ~= name then say("Training at " .. name .. " (x" .. tostring(mult) .. ")") moveToTrainingTable(name, info) else say("Charging Fat at " .. name .. " (x" .. tostring(mult) .. ")") end else say("No unlocked training table found; farming wins") app.phase = "Wins" ensureWinWorld() setAutoWins(true, true) end end else ensureWinWorld() local progressClock = math.max(tonumber(app.lastWallProgress) or 0, tonumber(app.lastWinAward) or 0) if settings.Mode == "Hybrid" and os.clock() - progressClock > 12 then app.chargeBias = math.min(28, (tonumber(app.chargeBias) or 0) + 4) app.forceTrainUntil = os.clock() + 4 setAutoWins(false, true) say("Win run stalled • adding charge and returning to table") task.wait(0.2) continue end if os.clock() - lastAutoWinsRefresh > 2.0 or app.autoWinsState ~= true then lastAutoWinsRefresh = os.clock() setAutoWins(true, true) end local worldId = highestUnlockedWorld() say("Native Auto Wins • World " .. tostring(worldId)) end task.wait(0.18) end end) -- Native Auto Wins normally walks the lane itself. If it stops moving and no -- wall packet advances, briefly take movement ownership, jump/repath around the -- blocker, then hand control back to Auto Wins. This runs only on a real stall, -- so PathfindingService does not become a constant CPU cost. worker(function() local lastPos local stagnantSince = os.clock() local lastRecovery = 0 while app.alive do local _, _, r = character() if settings.Farm and settings.SmartNavigation and app.phase == "Wins" and app.autoWinsState == true and not app.moveLock and not rebirthPending and r then if not lastPos or flat(r.Position - lastPos).Magnitude >= 1.0 then lastPos = r.Position stagnantSince = os.clock() end local progressClock = math.max(tonumber(app.lastWallProgress) or 0, tonumber(app.lastWinAward) or 0) local noProgress = os.clock() - progressClock if os.clock() - stagnantSince > 1.7 and noProgress > 1.5 and os.clock() - lastRecovery > 3.5 then lastRecovery = os.clock() say("Auto Wins stuck • jumping and routing around blocker") recoverNativeAutoWins() lastPos = r.Position stagnantSince = os.clock() end else lastPos = r and r.Position or nil stagnantSince = os.clock() end task.wait(settings.LowLag and 0.45 or 0.30) end end) -- Food worker gets priority over side spending. worker(function() while app.alive do if settings.Farm and settings.AutoFood and not app.moveLock and not rebirthPending then ensureBestFood() end task.wait(1.0) end end) -- Permanent progression worker. worker(function() while app.alive do if settings.Farm then -- Do not launch other purchase/movement actions while a hatch is -- waiting for the server. This prevents stale-balance races and -- egg/crafting teleport fights. if not hatchPending then -- Permanent Fat/Wins boosts are evaluated BEFORE consumable egg -- spending and other side purchases. If a worthwhile core boost -- is being saved for, lower-priority spenders wait so they cannot -- keep draining the balance just before the boost becomes affordable. local boostAction = buyBestBoost() local protectCoreBoost = boostAction == "saving-core" or boostAction == "bought" or boostAction == "busy" local hatchStarted = false if not protectCoreBoost then hatchStarted = hatchEggSmart() end if not hatchStarted and not protectCoreBoost then manageAura() buyBestUpgrade() manageTitles() end manageBestPets() manageGoldenPets() manageRainbowPets() manageDaily() manageSpin() manageQuestRewards() manageGroupReward() requestPets() end end task.wait(settings.LowLag and 0.65 or 0.40) end end) -- Low-lag client presentation. FatClickFX is purely cosmetic; disabling the -- ScreenGui removes the expensive stream of popup rendering while keeping all -- server-side clicks, training and rewards intact. worker(function() while app.alive do local pg = player:FindFirstChildOfClass("PlayerGui") local fx = pg and pg:FindFirstChild("FatClickFX") if fx and fx:IsA("ScreenGui") then fx.Enabled = not settings.LowLag end local flash = pg and pg:FindFirstChild("HatchFlash") if flash and flash:IsA("ScreenGui") then flash.Enabled = not settings.HideHatchAnimation end if settings.HideHatchAnimation and hatchVisualsShouldBeHidden() then suppressHatchPresentation() end task.wait(settings.HideHatchAnimation and 0.8 or 2.0) end end) -- Initial state requests are useful even before the user toggles the farm. worker(function() task.wait(0.8) fire("RequestPets") fire("DailyState") fire("QuestState") fire("EquipBestTitle") refreshBoostSummary() end) -- Rate sampler. worker(function() local lastTime = os.clock() local lastFat = fat() local lastWins = wins() while app.alive do task.wait(2) local now = os.clock() local dt = math.max(0.1, now - lastTime) local f, w = fat(), wins() local fr = (f - lastFat) / dt local wr = (w - lastWins) / dt telemetry.fatRate = telemetry.fatRate * 0.65 + fr * 0.35 telemetry.winsRate = telemetry.winsRate * 0.65 + wr * 0.35 lastTime, lastFat, lastWins = now, f, w end end) -- Status renderer. worker(function() while app.alive do local rb = rebirths() local lvl = level() local reqLvl = rebirthRequirement() local targetFat = rebirthTargetFat() local currentFat = fat() local currentWins = wins() local tableName, _, tableMultiplier = bestTrainingTable() local worldId = highestUnlockedWorld() local _, nextFood, nextReq = nextFoodGoal() local equippedFood = tostring(player:GetAttribute("EquippedFood") or "None") local equippedTitle = tostring(player:GetAttribute("EquippedTitle") or "None") local aura = tostring(player:GetAttribute("EquippedAura") or "None") local tokens = tonumber(player:GetAttribute("QuestTokens")) or tonumber(questState.tokens) or 0 local equippedPets = 0 local bestPet = 0 for _, p in ipairs(petState.pets) do if p.equipped then equippedPets = equippedPets + 1 end bestPet = math.max(bestPet, petMult(p)) end pcall(function() activityLabel:Set( "Phase: " .. app.phase .. "\n" .. app.message .. "\n" .. "Clicks: " .. fmt(telemetry.clicks) .. " • Rebirths this run: " .. fmt(telemetry.rebirths) ) powerLabel:Set( "Fat: " .. fmt(currentFat) .. " • Level " .. fmt(lvl) .. "/" .. fmt(reqLvl) .. "\n" .. "Rebirth target Fat: " .. fmt(targetFat) .. " • Smart win Fat: " .. fmt(smartWinTargetFat()) .. "\n" .. "Charge: " .. string.format("%.0f%%", effectiveChargePercent()) .. " • Target wall: " .. tostring(app.targetWallStage or 0) .. " • Bias +" .. tostring(math.floor(app.chargeBias or 0)) .. "%\n" .. "Fat rate: " .. fmt(telemetry.fatRate) .. "/s • Food: " .. equippedFood ) progressLabel:Set( "Wins: " .. fmt(currentWins) .. " • Rate: " .. fmt(telemetry.winsRate * 60) .. "/min\n" .. "Rebirths: " .. fmt(rb) .. " • Best world: " .. tostring(worldId) .. " • Wall: " .. tostring(app.wallStage or 0) .. "\n" .. "Table: " .. tostring(tableName or "None") .. " (x" .. tostring(tableMultiplier or 1) .. ")\n" .. "Next food: " .. (nextFood and (nextFood.name .. " @ " .. fmt(nextReq)) or "all standard foods reached") .. " • Reserve: " .. fmt(smartReserve()) ) petLabel:Set( "Pets: " .. tostring(equippedPets) .. "/" .. tostring(petState.equipLimit) .. " equipped • Best pet x" .. string.format("%.2f", bestPet) .. "\n" .. "Aura: " .. aura .. " • Title: " .. equippedTitle .. "\n" .. "Quest tokens: " .. fmt(tokens) .. " • Spins: " .. fmt(player:GetAttribute("Spins") or 0) .. " • Egg budget: " .. fmt(app.eggBudget or 0) .. " • Native click: " .. ((player:GetAttribute("AutoClicker") == true) and "ON" or "OFF") .. "\n" .. "Boosts: " .. tostring(app.boostStateSummary or "Reading...") .. "\n" .. "Boost plan: " .. tostring(app.boostPlan or "Waiting") .. " • Path recoveries: " .. tostring(app.navigationRecoveries or 0) ) end) task.wait(settings.LowLag and 1.0 or 0.5) end end) UI:Notify({ Title = "+1 Fat Per Click loaded", Content = "v1.5: uses the game's real integer boost levels/prices, protects core boost savings, and buys Fat/Wins before lower-priority spending.", Duration = 6, }) say("Ready • enable Smart autofarm")