跳转到内容
可用

Sell Lemons Script

CLclarkdevlinorg1 次浏览Universal2026年7月26日
分享
Sell Lemons Script

脚本代码

Lua
local config = {
    rebirthMode = 1,
    smooth = 0.3,
    sensitivity = 0.97,
    minRatio = 1,
    fixedGain = 3,
    powerStack = true,
    powerPicker = true,
    reserve = 0.5,
    cashReserve = 0,
    purchasePriority = 1,
    upgradeMaxFraction = 1,
    purchaseMaxFraction = 1,
    permaBuy = false,
    phoneRaises = 0,
    ascendMinEvolution = 0,
    upgradeDelay = 0.06,
    purchaseDelay = 0.1,
    powerDelay = 0.2,
    standDelay = 0.1,
    fruitDelay = 0.05,
    fruitTeleport = true,
    fruitSettle = 0.06,
    fruitAllTycoons = false,
    dropDelay = 0.1,
    phoneDelay = 0.4,
    minimizeKey = Enum.KeyCode.RightBracket,
}

local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local UserInputService = game:GetService("UserInputService")
local RS = game:GetService("ReplicatedStorage")

if not game:IsLoaded() then
    game.Loaded:Wait()
end

local Huge = require(RS.Modules.Huge)
local Config = require(RS.Config)
local Tycoon = require(RS.Modules.Tycoon.Tycoon)
local Entity = require(RS.Core.Entity)
local MessagePhone = nil
pcall(function() MessagePhone = require(RS.Modules.UI.Layers.Phone.UIMessagePhone) end)

local C = RS.Modules.Tycoon.Component
local Balances = require(C.TycoonBalances)
local Analyzer = require(C.TycoonAnalyzer)
local Purchases = require(C.TycoonPurchases)
local Rebirth = require(C.Client.ClientTycoonRebirth)
local Evolution = require(C.Client.ClientTycoonEvolution)
local Ascension = require(C.Client.ClientTycoonAscension)
local Income = require(C.Client.ClientTycoonIncome)
local Powers = require(C.Client.ClientTycoonPowers)
local PhoneOffers = require(C.Client.ClientTycoonPhoneOffers)
local FruitSvc
pcall(function() FruitSvc = require(RS.Modules.Service.ClickFruitService) end)

local genv = getgenv()
if genv.SellLemonsAuto and genv.SellLemonsAuto.stop then
    pcall(genv.SellLemonsAuto.stop)
end

local state = {
    running = true,
    master = true,
    rebirth = false,
    evolution = false,
    ascension = false,
    upgrade = false,
    powers = false,
    purchase = false,
    complete = false,
    clickstand = false,
    cashdrops = false,
    harvest = false,
    clickfruit = false,
    phone = false,
}
genv.SellLemonsAuto = state

local function tryGet(fn)
    local ok, a, b = pcall(fn)
    if ok then return a, b end
    return nil
end

local stats = {
    upgrades = 0, purchases = 0, wakes = 0, harvests = 0, drops = 0,
    rebirths = 0, evolves = 0, ascends = 0, offers = 0, fruits = 0,
    lastAction = 0, lastName = "none", err = nil,
}
local function record(name)
    stats[name] = (stats[name] or 0) + 1
    stats.lastAction = os.clock()
    stats.lastName = name
end

local LOG_DIR = "sellLemons"
local LOG_PATH = LOG_DIR .. "/log.txt"
local SCHEMA = 4
local lz4 = (type(lz4compress) == "function" and lz4compress)
    or (type(crypt) == "table" and crypt.lz4compress) or nil
local b64 = (type(crypt) == "table" and crypt.base64encode)
    or (type(base64encode) == "function" and base64encode) or nil
local fileOk = type(writefile) == "function" and type(appendfile) == "function"
    and type(makefolder) == "function" and type(isfolder) == "function"
    and type(buffer) == "table" and b64 ~= nil

local NAN = 0 / 0
local CAP = 262144
local lbuf = fileOk and buffer.create(CAP) or nil
local lcur = 0
local startClock = os.clock()

local function flushChunk()
    if not fileOk or lcur == 0 then return end
    local raw = buffer.readstring(lbuf, 0, lcur)
    lcur = 0
    local flag, payload = "R", raw
    if lz4 then
        local ok, c = pcall(lz4, raw)
        if ok and type(c) == "string" and #c < #raw then flag, payload = "L", c end
    end
    local ok, enc = pcall(b64, payload)
    if ok and enc then
        pcall(function() appendfile(LOG_PATH, flag .. "\t" .. #raw .. "\t" .. enc .. "\n") end)
    end
end

local function ensure(n) if lcur + n > CAP then flushChunk() end end
local function wu8(v) buffer.writeu8(lbuf, lcur, math.floor(type(v) == "number" and v or 0) % 256); lcur = lcur + 1 end
local function wu16(v) buffer.writeu16(lbuf, lcur, math.floor(type(v) == "number" and v or 0) % 65536); lcur = lcur + 2 end
local function wu32(v) buffer.writeu32(lbuf, lcur, math.floor(type(v) == "number" and v or 0) % 4294967296); lcur = lcur + 4 end
local function wi16(v) buffer.writei16(lbuf, lcur, math.clamp(math.floor(type(v) == "number" and v or -1), -32768, 32767)); lcur = lcur + 2 end
local function wf32(v) buffer.writef32(lbuf, lcur, type(v) == "number" and v or NAN); lcur = lcur + 4 end
local function wf64(v) buffer.writef64(lbuf, lcur, type(v) == "number" and v or NAN); lcur = lcur + 8 end
local function wstr(s)
    s = tostring(s or "")
    local n = math.min(#s, 255)
    buffer.writeu8(lbuf, lcur, n); lcur = lcur + 1
    if n > 0 then buffer.writestring(lbuf, lcur, s, n); lcur = lcur + n end
end
local function rel() return os.clock() - startClock end

local VIA = { none = 0, firesignal = 1, proximity = 2, useasync = 3, failed = 4,
    ["no-character"] = 5, ["no-position"] = 6, ["no-vine"] = 7 }

local function logPoll(elapsed, ratio, smooth, peak, rate, inv, pot, cash, cashspent, income, flags)
    if not fileOk then return end
    ensure(48)
    wu8(1); wf32(rel()); wf32(elapsed); wf32(ratio); wf32(smooth); wf32(peak); wf32(rate)
    wf32(inv); wf32(pot); wf32(cash); wf32(cashspent); wf32(income); wu8(flags)
end
local function logSnap(cash, cashspent, inv, pot, income, gain, earners, purchases, vines, s)
    if not fileOk then return end
    ensure(60)
    wu8(2); wf32(rel()); wf32(cash); wf32(cashspent); wf32(inv); wf32(pot); wf32(income); wf32(gain)
    wu16(earners); wu16(purchases); wu16(vines)
    wu32(s.upgrades); wu32(s.purchases); wu32(s.wakes); wu32(s.harvests); wu32(s.drops)
    wu16(s.rebirths); wu16(s.evolves); wu16(s.ascends); wu32(s.offers); wu32(s.fruits)
end
local function logRebirth(ratio, elapsed, invB, invA, potB, ok)
    if not fileOk then return end
    ensure(28)
    wu8(3); wf32(rel()); wf32(ratio); wf32(elapsed); wf32(invB); wf32(invA); wf32(potB); wu8(ok and 1 or 0)
end
local function logEvolve(before, after, ok)
    if not fileOk then return end
    ensure(12)
    wu8(4); wf32(rel()); wi16(before); wi16(after); wu8(ok and 1 or 0)
end
local function logAscend(ascB, ascA, evoB, ok)
    if not fileOk then return end
    ensure(14)
    wu8(5); wf32(rel()); wi16(ascB); wi16(ascA); wi16(evoB); wu8(ok and 1 or 0)
end
local function logHarvest(sub, via, avail, server, dist)
    if not fileOk then return end
    ensure(24)
    wu8(6); wf32(rel()); wu8(sub); wu8(VIA[via] or 0); wf64(avail); wf64(server); wf32(dist)
end
local function logEnv(comp, earners, purchases, vines, cash, cashspent, inv, pot, evo, asc, vineArr)
    if not fileOk then return end
    ensure(40 + 280)
    wu8(7); wf32(rel()); wu16(comp); wu16(earners); wu16(purchases); wu16(vines)
    wf32(cash); wf32(cashspent); wf32(inv); wf32(pot); wi16(evo); wi16(asc)
    local vc = math.min(#vineArr, 16)
    wu8(vc)
    for i = 1, vc do
        local v = vineArr[i]
        wf64(v.avail or 0)
        wu8((v.hasPrompt and 1 or 0) + (v.enabled and 2 or 0))
        wf32(v.maxDist or 0)
        wstr(v.name)
    end
end
local function logErr(code, msg)
    if not fileOk then return end
    ensure(8 + 260)
    wu8(8); wf32(rel()); wstr(code); wstr(msg)
end
local function logEnd(s)
    if not fileOk then return end
    ensure(32)
    wu8(9); wf32(rel())
    wu32(s.upgrades); wu32(s.purchases); wu32(s.wakes); wu32(s.harvests); wu32(s.drops)
    wu16(s.rebirths); wu16(s.evolves); wu16(s.ascends); wu32(s.offers); wu32(s.fruits)
end
if fileOk then
    pcall(function()
        if not isfolder(LOG_DIR) then makefolder(LOG_DIR) end
    end)
    local exec, ver = "unknown", "?"
    pcall(function() local a, b = identifyexecutor(); if a then exec, ver = a, b end end)
    local header = table.concat({
        "SLOGB", tostring(SCHEMA), lz4 and "lz4" or "raw", tostring(os.time()),
        tostring(game.PlaceId), tostring(game.JobId), tostring(exec), tostring(ver),
    }, "\t") .. "\n"
    pcall(function() writefile(LOG_PATH, header) end)
end

local function resolve()
    local ok, t = pcall(function() return Tycoon.getLocal() end)
    if not ok or not t then return nil end
    local model = t.Instance or (t.Remotes and t.Remotes.Parent)
    local bal = tryGet(function() return t:GetComponent(Balances) end)
    local reb = tryGet(function() return t:GetComponent(Rebirth) end)
    if not (model and bal and reb) then return nil end
    return {
        tycoon = t,
        model = model,
        balances = bal,
        rebirth = reb,
        evolution = tryGet(function() return t:GetComponent(Evolution) end),
        ascension = tryGet(function() return t:GetComponent(Ascension) end),
        income = tryGet(function() return t:GetComponent(Income) end),
        powers = tryGet(function() return t:GetComponent(Powers) end),
        phoneoffers = tryGet(function() return t:GetComponent(PhoneOffers) end),
        analyzer = tryGet(function() return t:GetComponent(Analyzer) end),
        purchases = tryGet(function() return t:GetComponent(Purchases) end),
    }
end

local function taggedUnder(model, tag)
    local out = {}
    for _, inst in CollectionService:GetTagged(tag) do
        if inst:IsDescendantOf(model) then
            table.insert(out, inst)
        end
    end
    return out
end

local function log10(x)
    return math.log(x) / math.log(10)
end

local function spendBudget(c, maxFraction)
    local cash = c.balances:GetCash()
    local b = cash
    if config.cashReserve > 0 then b = b + log10(1 - config.cashReserve) end
    if maxFraction and maxFraction > 0 and maxFraction < 1 then
        b = math.min(b, cash + log10(maxFraction))
    end
    return b
end

local rb = { t0 = 0, peak = 0, smooth = 0, lastRun = nil, lastInv = nil }

local function rebirthShouldFire(now, c)
    local cashLog = c.balances:GetCash()
    local spentLog = c.balances:GetCashSpent()
    local invLog = c.balances:GetInvestors()
    local potLog = c.rebirth:GetPotentialInvestors()
    local runLog = Huge.add(cashLog, spentLog)
    if (rb.lastRun and runLog < rb.lastRun - 3) or (rb.lastInv and math.abs(invLog - rb.lastInv) > 1e-3) then
        rb.t0, rb.peak, rb.smooth = now, 0, 0
    end
    rb.lastRun = runLog
    rb.lastInv = invLog
    if rb.t0 == 0 then rb.t0 = now end
    local elapsed = now - rb.t0
    local ratio = 10 ^ (potLog - math.max(invLog, 2))
    rb.ratio = ratio
    if config.rebirthMode == 2 then
        return ratio >= config.fixedGain
    end
    if elapsed <= 0 then return false end
    local stale = (rb.sPot ~= nil) and (potLog == rb.sPot) and (invLog == rb.sInv)
    rb.sPot, rb.sInv = potLog, invLog
    if stale then return false end
    local avg = math.log(1 + ratio) / elapsed
    rb.rate = avg
    rb.smooth = rb.smooth + config.smooth * (avg - rb.smooth)
    if rb.smooth > rb.peak then rb.peak = rb.smooth end
    return ratio >= config.minRatio and rb.peak > 0 and rb.smooth < rb.peak * config.sensitivity
end

local function progressReady(comp, fn)
    if not comp then return false end
    local ok, p = pcall(fn)
    return ok and p and p >= 1
end

local function earnersByValue(c)
    local list = {}
    for _, inst in taggedUnder(c.model, "Tycoon.Earner") do
        local e = Entity.getUnsafe(inst)
        if e then
            local v = tryGet(function() return e:GetRealValue() end) or -math.huge
            table.insert(list, { e = e, v = v })
        end
    end
    table.sort(list, function(a, b) return a.v > b.v end)
    local out = {}
    for _, item in list do
        out[#out + 1] = item.e
    end
    return out
end

local function entitiesUnder(model, tag)
    local out = {}
    for _, inst in taggedUnder(model, tag) do
        local e = Entity.getUnsafe(inst)
        if e then table.insert(out, e) end
    end
    return out
end

local function entitiesTagged(tag)
    local out = {}
    for _, inst in CollectionService:GetTagged(tag) do
        local e = Entity.getUnsafe(inst)
        if e then table.insert(out, e) end
    end
    return out
end

local function spawnGuarded(inflight, key, fn)
    if inflight[key] then return end
    inflight[key] = true
    task.spawn(function()
        pcall(fn)
        inflight[key] = false
    end)
end

local throttleSlots = {}
local function throttle(key, delay)
    if not delay or delay <= 0 then return end
    local now = os.clock()
    local slot = math.max(now, throttleSlots[key] or 0)
    throttleSlots[key] = slot + delay
    local wait = slot - now
    if wait > 0 then task.wait(wait) end
end

local lastPowerDiag = 0
local function upgradePowerTo(c, name, code, reserveFrac, maxIters)
    local function cap()
        return c.balances:GetInvestors() + (reserveFrac > 0 and log10(1 - reserveFrac) or 0)
    end
    for _ = 1, maxIters do
        local lvl = tryGet(function() return c.powers:GetLevel(name) end) or 0
        local maxLvl = tryGet(function() return c.powers:GetMaxLevel(name) end)
        if maxLvl and lvl >= maxLvl then return end
        local ok, price = pcall(function() return c.powers:GetUpgradePrice(name) end)
        if not ok then logErr("power.price", tostring(price)); return end
        if not price or price > cap() then return end
        throttle("power", config.powerDelay)
        if price > cap() then return end
        local okU, errU = pcall(function() c.powers:UpgradeAsync(name) end)
        if not okU then logErr(code, tostring(errU)); return end
        record("upgrades")
    end
end

local function buyPowers(c)
    if not c.powers then return end
    if config.powerStack then
        upgradePowerTo(c, "UpgradeStack", "power.stack", 0, 8)
        local lvl = tryGet(function() return c.powers:GetLevel("UpgradeStack") end)
        if lvl and lvl > 0 then
            local sel = tryGet(function() return c.powers:GetSelectedLevel("UpgradeStack") end)
            if sel ~= lvl then pcall(function() c.powers:SelectLevel("UpgradeStack", lvl) end) end
        end
    end
    if config.powerPicker and state.clickfruit then
        upgradePowerTo(c, "ClickFruitValue", "power.picker", config.reserve, 1)
    end
    if os.clock() - lastPowerDiag >= 20 then
        lastPowerDiag = os.clock()
        local function info(name)
            local lvl = tryGet(function() return c.powers:GetLevel(name) end) or -1
            local maxL = tryGet(function() return c.powers:GetMaxLevel(name) end) or -1
            local pr = tryGet(function() return c.powers:GetUpgradePrice(name) end)
            return string.format("%s L%d/%d next=%s", name, lvl, maxL, pr and string.format("%.2f", pr) or "MAX")
        end
        logErr("power.diag", string.format("inv=%.2f reserve=%.2f stack_on=%s picker_on=%s clickfruit=%s | %s | %s",
            c.balances:GetInvestors(), config.reserve, tostring(config.powerStack), tostring(config.powerPicker),
            tostring(state.clickfruit), info("UpgradeStack"), info("ClickFruitValue")))
    end
end

local function buildPurchases(c)
    local list = {}
    for _, inst in taggedUnder(c.model, "Tycoon.Purchase") do
        local e = Entity.getUnsafe(inst)
        if e then
            local info = c.analyzer and tryGet(function() return c.analyzer:GetPurchaseInfo(e.Name) end) or nil
            local rank = 1
            if info and (info.Multiplier or info.Automator) then
                rank = 3
            elseif info and info.Earner then
                rank = 2
            end
            table.insert(list, { e = e, info = info, rank = rank })
        end
    end
    if config.purchasePriority == 1 then
        table.sort(list, function(a, b) return a.rank > b.rank end)
    end
    return list
end

local function characterRoot()
    local char = Players.LocalPlayer.Character
    return char and char:FindFirstChild("HumanoidRootPart")
end

local function grabDrop(part)
    if not firetouchinterest then return end
    local hrp = characterRoot()
    if not (hrp and part and part:IsA("BasePart")) then return end
    throttle("drop", config.dropDelay)
    local ok = pcall(function()
        firetouchinterest(part, hrp, true)
        firetouchinterest(part, hrp, false)
    end)
    if ok then record("drops") end
end

task.spawn(function()
    local folder = workspace:WaitForChild("CashDrops", 60)
    if not folder then return end
    if not firetouchinterest then
        warn("[SellLemons] firetouchinterest unavailable; cash drop collection disabled")
        return
    end
    state.dropConn = folder.ChildAdded:Connect(function(part)
        if state.cashdrops then
            task.wait(0.15)
            grabDrop(part)
        end
    end)
    while state.running do
        if state.cashdrops then
            for _, part in folder:GetChildren() do
                grabDrop(part)
            end
        end
        task.wait(1)
    end
end)

local updateStatus = function(_) end

local ctx = nil
local earnerList = nil
local vineList = nil
local purchaseList = nil
local fruitList = nil

local SAFETY = 2

local upInflight = {}
local buyInflight = {}
local engineConns = {}

local function clearConns()
    for _, conn in engineConns do
        pcall(function() conn:Disconnect() end)
    end
    table.clear(engineConns)
end

local function track(conn)
    table.insert(engineConns, conn)
    return conn
end

local phoneRaiseCount = 0
local phoneUIReady = false
task.spawn(function()
    if not MessagePhone then return end
    local ok, phone = pcall(function() return MessagePhone:get() end)
    local container = ok and phone and phone.Gui and tryGet(function() return phone.Gui.Screen.Footer.Container end)
    if not (container and phone._OptionSelected) then return end
    local pending = false
    container.ChildAdded:Connect(function(child)
        if not (state.master and state.phone) then return end
        if not string.match(child.Name, "^Option%d") then return end
        if pending then return end
        pending = true
        task.defer(function()
            pending = false
            local index
            if phoneRaiseCount < config.phoneRaises then
                index = 2
                phoneRaiseCount = phoneRaiseCount + 1
            else
                index = 1
            end
            throttle("phone", config.phoneDelay)
            if pcall(function() phone._OptionSelected:Fire(index) end) then record("offers") end
        end)
    end)
    phoneUIReady = true
end)

local fruitBaseline = nil
local function refreshFruitCount()
    if not FruitSvc then return end
    local n = tryGet(function() return FruitSvc:GetFruitsClicked() end)
    if type(n) ~= "number" then return end
    if fruitBaseline == nil or n < fruitBaseline then fruitBaseline = n end
    stats.fruits = math.max(0, n - fruitBaseline)
end

local lastStat = 0
local function refreshStats()
    local now = os.clock()
    if now - lastStat < 0.2 then return end
    lastStat = now
    refreshFruitCount()
    updateStatus(ctx)
end

local STAND_TIER = {
    LemonStand = 1, LemonDash = 2, LemonDepot = 3, LemonTrading = 4,
    LemonLabs = 5, LemonRobotics = 6, LemonRepublic = 7, LemonX = 8,
}

local function permaAllowance(c)
    if not (c and c.ascension) then return 0 end
    local n = tryGet(function() return c.ascension:GetAscensionPermanentPurchasesRemaining() end)
    return (type(n) == "number" and n) or 0
end

local function isPermanent(c, name)
    if not (c and c.purchases) then return false end
    local ok, _, perm = pcall(function() return c.purchases:IsPurchased(name) end)
    return ok and perm == true
end

local function permaTarget(c)
    local best, bestTier = nil, 0
    for _, item in (purchaseList or {}) do
        local tier = STAND_TIER[item.e.Name]
        if tier and tier > bestTier and not isPermanent(c, item.e.Name) then
            best, bestTier = item.e, tier
        end
    end
    return best
end

local function runEconomy()
    if not (state.master and ctx) then return end
    local c = ctx
    if state.upgrade and earnerList then
        local budget = spendBudget(c, config.upgradeMaxFraction)
        local selLvl = (c.powers and tryGet(function() return c.powers:GetSelectedLevel("UpgradeStack") end)) or 0
        local bonus = Config.Powers.UpgradeStack.Bonuses[selLvl] or 1
        local cap = math.min(bonus, 100000)
        for _, e in earnerList do
            if not upInflight[e] then
                local ok, price, affordable = pcall(function() return e:GetUpgradePrice(nil, cap, budget) end)
                if ok and affordable and affordable > 0 and price and price <= budget then
                    spawnGuarded(upInflight, e, function()
                        throttle("upgrade", config.upgradeDelay)
                        if pcall(function() e:Upgrade(affordable, false) end) then record("upgrades") end
                    end)
                end
            end
        end
    end
    if (state.purchase or state.complete) and purchaseList then
        local includeDecor = state.complete
        local pTarget = nil
        if config.permaBuy and c.purchases and c.ascension and permaAllowance(c) > 0 then
            pTarget = permaTarget(c)
            if pTarget and not buyInflight[pTarget] then
                local budget = spendBudget(c, config.purchaseMaxFraction)
                local ok, price = pcall(function() return pTarget:GetPrice() end)
                if ok and price and price <= budget then
                    spawnGuarded(buyInflight, pTarget, function()
                        throttle("purchase", config.purchaseDelay)
                        local okB, errB = pcall(function() pTarget.PurchaseRemote:InvokeServer(true) end)
                        if okB then record("purchases") else logErr("perma.buy", tostring(errB)) end
                    end)
                end
            end
        end
        for _, item in purchaseList do
            if item.e ~= pTarget and not buyInflight[item.e] then
                local inst = item.e.Instance
                if inst and inst:GetAttribute("Shown") then
                    local budget = spendBudget(c, config.purchaseMaxFraction)
                    local ok, price = pcall(function() return item.e:GetPrice() end)
                    if ok and price and price <= budget then
                        local buy
                        if includeDecor or not c.analyzer then
                            buy = true
                        elseif item.info then
                            buy = (item.info.Earner or item.info.Multiplier or item.info.Automator) and true or false
                        else
                            buy = false
                        end
                        if buy then
                            spawnGuarded(buyInflight, item.e, function()
                                throttle("purchase", config.purchaseDelay)
                                if pcall(function() item.e:TryPurchaseAsync(false) end) then record("purchases") end
                            end)
                        end
                    end
                end
            end
        end
    end
end

local function ascendReady(c)
    return state.ascension and c and c.ascension
        and progressReady(c.ascension, function() return c.ascension:GetAscensionProgress() end)
        and (tryGet(function() return c.evolution and c.evolution:GetEvolution() or 0 end) or 0) >= config.ascendMinEvolution
end

local function tryAscend(c)
    c = c or ctx
    if not (state.master and ascendReady(c)) then return end
    local before = tryGet(function() return c.ascension:GetAscension() end)
    local evo = c.evolution and tryGet(function() return c.evolution:GetEvolution() end) or nil
    local ok = pcall(function() c.ascension:AscendAsync() end)
    if ok then record("ascends") end
    logAscend(before, tryGet(function() return c.ascension:GetAscension() end), evo, ok)
end

local function tryEvolve(c)
    c = c or ctx
    if not (state.master and state.evolution and c and c.evolution) then return end
    if ascendReady(c) then return end
    if progressReady(c.evolution, function() return c.evolution:GetEvolutionProgress() end) then
        local before = tryGet(function() return c.evolution:GetEvolution() end)
        local ok = pcall(function() c.evolution:EvolveAsync() end)
        if ok then record("evolves") end
        logEvolve(before, tryGet(function() return c.evolution:GetEvolution() end), ok)
    end
end

local econPending = false
local function onCash()
    if not state.master then return end
    if not econPending then
        econPending = true
        task.defer(function()
            econPending = false
            runEconomy()
        end)
    end
    refreshStats()
end

local function onInvestors()
    if not state.master then return end
    if state.powers and ctx then pcall(buyPowers, ctx) end
    tryEvolve(ctx)
    tryAscend(ctx)
    refreshStats()
end

local rebuild

local function connectEngine(c)
    clearConns()
    if not c then return end
    if c.balances then
        track(c.balances.CashChanged:Connect(onCash))
        track(c.balances.InvestorsChanged:Connect(onInvestors))
    end
    if c.evolution and c.evolution.EvolveAvailable then
        track(c.evolution.EvolveAvailable:Connect(function() tryEvolve(c) end))
    end
    if c.ascension and c.ascension.AscensionAvailable then
        track(c.ascension.AscensionAvailable:Connect(function() tryAscend(c) end))
    end
    if c.tycoon and c.tycoon.Rebirthed then
        track(c.tycoon.Rebirthed:Connect(function() task.defer(rebuild) end))
    end
    if c.phoneoffers then
        local comp = c.phoneoffers
        local function fallback()
            if phoneUIReady then return end
            if not (state.master and state.phone) then return end
            if phoneRaiseCount < config.phoneRaises then
                phoneRaiseCount = phoneRaiseCount + 1
                if pcall(function() comp:RaiseOffer() end) then record("offers") end
            else
                if pcall(function() comp:AcceptOffer() end) then record("offers") end
            end
        end
        track(comp.OfferStarted:Connect(function()
            phoneRaiseCount = 0
            fallback()
        end))
        track(comp.OfferUpdated:Connect(fallback))
        local cur = tryGet(function() return comp:GetCurrentOffer() end)
        if cur then
            phoneRaiseCount = 0
            fallback()
        end
    end
    onInvestors()
    onCash()
end

local function buildFruits(c)
    local out = {}
    local function addFrom(trees)
        if not trees then return end
        for _, d in trees:GetDescendants() do
            if d:IsA("ClickDetector") then table.insert(out, d) end
        end
    end
    if config.fruitAllTycoons then
        for _, f in workspace:GetChildren() do
            local constant = f:FindFirstChild("Constant")
            addFrom(constant and constant:FindFirstChild("Trees"))
        end
    else
        local model = c and c.model
        local constant = model and model:FindFirstChild("Constant")
        addFrom(constant and constant:FindFirstChild("Trees"))
    end
    return out
end

local function refreshLists(c)
    earnerList = earnersByValue(c)
    vineList = entitiesTagged("CashVine")
    purchaseList = buildPurchases(c)
    fruitList = buildFruits(c)
end

rebuild = function()
    local ok, c = pcall(resolve)
    if not ok then c = nil end
    if not c then
        if ctx then
            ctx = nil
            pcall(clearConns)
            earnerList, vineList, purchaseList, fruitList = nil, nil, nil, nil
        end
        return
    end
    local changed = (not ctx) or ctx.balances ~= c.balances or ctx.tycoon ~= c.tycoon
    ctx = c
    pcall(refreshLists, c)
    if changed then
        pcall(connectEngine, c)
        pcall(function()
            local vines = {}
            for _, e in vineList or {} do
                local inst = e.Instance
                local prompt = inst and inst:FindFirstChildWhichIsA("ProximityPrompt", true)
                table.insert(vines, {
                    name = inst and inst.Name or "?",
                    avail = tryGet(function() return e:GetAvailableTime() end),
                    hasPrompt = prompt ~= nil,
                    maxDist = prompt and prompt.MaxActivationDistance or nil,
                    enabled = prompt and prompt.Enabled or nil,
                })
            end
            local comp = (c.balances and 1 or 0) + (c.rebirth and 2 or 0) + (c.evolution and 4 or 0)
                + (c.ascension and 8 or 0) + (c.income and 16 or 0) + (c.powers and 32 or 0)
                + (c.phoneoffers and 64 or 0) + (c.analyzer and 128 or 0)
            logEnv(comp, #(earnerList or {}), #(purchaseList or {}), #(vineList or {}),
                c.balances:GetCash(), c.balances:GetCashSpent(), c.balances:GetInvestors(),
                tryGet(function() return c.rebirth:GetPotentialInvestors() end),
                c.evolution and tryGet(function() return c.evolution:GetEvolution() end) or -1,
                c.ascension and tryGet(function() return c.ascension:GetAscension() end) or -1,
                vines)
        end)
    end
end

task.spawn(function()
    for _, tag in { "Tycoon.Earner", "Tycoon.Purchase", "CashVine" } do
        CollectionService:GetInstanceAddedSignal(tag):Connect(function() task.defer(rebuild) end)
        CollectionService:GetInstanceRemovedSignal(tag):Connect(function() task.defer(rebuild) end)
    end
    while state.running do
        pcall(rebuild)
        if ctx and state.master then
            pcall(runEconomy)
            if state.powers then pcall(buyPowers, ctx) end
            pcall(tryEvolve, ctx)
            pcall(tryAscend, ctx)
        end
        pcall(refreshStats)
        task.wait(SAFETY)
    end
end)

task.spawn(function()
    while state.running do
        if state.master and ctx and ctx.rebirth and ctx.balances then
            local fire = false
            pcall(function() fire = rebirthShouldFire(os.clock(), ctx) end)
            local c = ctx
            local elapsed = rb.t0 > 0 and (os.clock() - rb.t0) or 0
            local income = c.income and tryGet(function() return c.income:GetAverageStreamIncome() end) or nil
            local flags = (state.rebirth and 1 or 0) + (fire and 2 or 0) + (state.master and 4 or 0)
                + (state.harvest and 8 or 0) + (state.upgrade and 16 or 0)
            logPoll(elapsed, rb.ratio, rb.smooth, rb.peak, rb.rate, c.balances:GetInvestors(),
                tryGet(function() return c.rebirth:GetPotentialInvestors() end),
                c.balances:GetCash(), c.balances:GetCashSpent(), income, flags)
            if fire and state.rebirth then
                local invBefore = c.balances:GetInvestors()
                local potBefore = tryGet(function() return c.rebirth:GetPotentialInvestors() end)
                local ratioAt = rb.ratio
                local elapsedAt = elapsed
                local ok = pcall(function() return c.rebirth:RebirthAsync() end)
                if ok then record("rebirths") else logErr("rebirth", "RebirthAsync failed") end
                task.wait(0.5)
                logRebirth(ratioAt, elapsedAt, invBefore, c.balances:GetInvestors(), potBefore, ok)
            end
        end
        task.wait(0.5)
    end
end)

task.spawn(function()
    while state.running do
        local wait = 1
        if state.master and state.clickstand and ctx and ctx.income and earnerList then
            local c = ctx
            local soonest = math.huge
            for _, e in earnerList do
                local name = e.Name
                local autoOk, auto = pcall(function() return c.income:IsStreamAutomatic(name) end)
                if autoOk and not auto then
                    local untilNext = tryGet(function() return c.income:GetStreamEstimatedNextEarnTime(name) end)
                    if untilNext == nil or untilNext <= 0 then
                        throttle("stand", config.standDelay)
                        if pcall(function() e:WakeAsync() end) then record("wakes") end
                        if soonest > 0.5 then soonest = 0.5 end
                    elseif untilNext < soonest then
                        soonest = untilNext
                    end
                end
            end
            if soonest ~= math.huge then
                wait = math.clamp(soonest, 0.1, 30)
            end
        end
        task.wait(wait)
    end
end)

local function harvestPrompt(e)
    local inst = e.Instance
    if not inst then return nil end
    local prompt = inst:FindFirstChildWhichIsA("ProximityPrompt", true)
    if prompt then
        pcall(function()
            prompt.MaxActivationDistance = math.huge
            prompt.RequiresLineOfSight = false
            prompt.Enabled = true
        end)
    end
    return prompt
end

local function harvestAt(e)
    local prompt = harvestPrompt(e)
    if prompt and type(firesignal) == "function" then
        if pcall(function() firesignal(prompt.Triggered, Players.LocalPlayer) end) then return "firesignal", 0 end
    end
    if prompt and type(fireproximityprompt) == "function" then
        if pcall(function() fireproximityprompt(prompt) end) then return "proximity", 0 end
    end
    if pcall(function() e:UseAsync() end) then return "useasync", 0 end
    return "failed", 0
end

task.spawn(function()
    local lastAvail = nil
    local firedAt = nil
    local busy = false
    while state.running do
        local wait = 1
        if state.master and state.harvest and ctx and vineList and vineList[1] and not busy then
            local server = workspace:GetServerTimeNow()
            local avail = tryGet(function() return vineList[1]:GetAvailableTime() end) or 0
            if lastAvail and avail > lastAvail + 0.05 and avail > server then
                record("harvests")
                logHarvest(1, "none", avail, server, 0)
                firedAt = nil
            end
            lastAvail = avail
            if avail <= server then
                if not firedAt or (os.clock() - firedAt) > 6 then
                    busy = true
                    firedAt = os.clock()
                    local snapshotVines = vineList
                    task.spawn(function()
                        local via, dist = "no-vine", 0
                        for _, e in snapshotVines do
                            via, dist = harvestAt(e)
                            if via ~= "no-position" then break end
                        end
                        logHarvest(0, via, avail, server, dist)
                        busy = false
                    end)
                end
                wait = 1.5
            else
                firedAt = nil
                wait = math.clamp(avail - server, 0.5, 30)
            end
            if firedAt and (os.clock() - firedAt) > 12 and avail <= server then
                logHarvest(2, "none", avail, server, 0)
                firedAt = nil
            end
        end
        task.wait(wait)
    end
end)

local fruitHome = nil
local fruitMoved = false

local function fruitPos(cd)
    local p = cd.Parent
    while p and p ~= workspace do
        if p:IsA("BasePart") then return p.Position end
        p = p.Parent
    end
    return nil
end

task.spawn(function()
    while state.running do
        if state.master and state.clickfruit and fruitList and fruitList[1]
            and type(fireclickdetector) == "function" then
            if config.fruitTeleport then
                local hrp = characterRoot()
                if hrp and not fruitMoved then
                    fruitHome = hrp.CFrame
                    fruitMoved = true
                end
                for _, cd in fruitList do
                    if not (state.running and state.master and state.clickfruit) then break end
                    hrp = characterRoot()
                    local pos = hrp and fruitPos(cd)
                    if pos then
                        pcall(function() hrp.CFrame = CFrame.new(pos + Vector3.new(0, 3, 0)) end)
                        if config.fruitSettle > 0 then task.wait(config.fruitSettle) end
                        pcall(function() fireclickdetector(cd, 0) end)
                    end
                    if config.fruitDelay > 0 then task.wait(config.fruitDelay) end
                end
            else
                for _, cd in fruitList do
                    if not (state.running and state.master and state.clickfruit) then break end
                    pcall(function() fireclickdetector(cd, 0) end)
                    task.wait(config.fruitDelay)
                end
            end
        else
            if fruitMoved and fruitHome then
                local hrp = characterRoot()
                if hrp then pcall(function() hrp.CFrame = fruitHome end) end
            end
            fruitMoved = false
            task.wait(0.5)
        end
    end
end)

task.spawn(function()
    while state.running do
        if fileOk and ctx and ctx.balances then
            local c = ctx
            local pot = tryGet(function() return c.rebirth:GetPotentialInvestors() end)
            local inv = c.balances:GetInvestors()
            logSnap(c.balances:GetCash(), c.balances:GetCashSpent(), inv, pot,
                c.income and tryGet(function() return c.income:GetAverageStreamIncome() end) or nil,
                (pot and inv) and 10 ^ (pot - math.max(inv, 2)) or nil,
                #(earnerList or {}), #(purchaseList or {}), #(vineList or {}), stats)
        end
        task.wait(5)
    end
end)

task.spawn(function()
    while state.running do
        flushChunk()
        task.wait(1)
    end
    flushChunk()
end)

local CASCADE_URL = "https://github.com/cascadeui/Cascade/releases/latest/download/dist.luau"
local CASCADE_CACHE = "sellLemons/cascade_dist.luau"

local function compileCascade(source)
    if type(source) ~= "string" or #source < 1000 then return nil end
    local chunk = loadstring(source, "cascade_dist")
    if type(chunk) ~= "function" then return nil end
    local ran, lib = pcall(chunk)
    if ran and type(lib) == "table" and type(lib.New) == "function" then return lib end
    return nil
end

local function loadCascade()
    if type(isfile) == "function" and isfile(CASCADE_CACHE) then
        local okR, cached = pcall(readfile, CASCADE_CACHE)
        if okR then
            local lib = compileCascade(cached)
            if lib then return lib end
        end
    end
    for attempt = 1, 4 do
        local okH, body = pcall(function() return game:HttpGetAsync(CASCADE_URL) end)
        if okH then
            local lib = compileCascade(body)
            if lib then
                if type(writefile) == "function" then
                    if type(isfolder) == "function" and type(makefolder) == "function" and not isfolder("sellLemons") then
                        pcall(makefolder, "sellLemons")
                    end
                    pcall(writefile, CASCADE_CACHE, body)
                end
                return lib
            end
        end
        task.wait(0.4 * attempt)
    end
    return nil
end

local cascade = loadCascade()
if not cascade then
    warn("[SellLemons] could not load Cascade UI: network is unstable and no usable cached copy exists. Run again on a stable connection.")
    return
end

local app = cascade.New({ Theme = cascade.Themes.Dark, Accent = cascade.Accents.Yellow })
state.app = app

local parented, parentErr = pcall(function()
    app.__instance.Parent = Players.LocalPlayer:WaitForChild("PlayerGui")
end)
if not parented then
    warn("[SellLemons] could not move UI to PlayerGui: " .. tostring(parentErr))
end

local window = app:Window({
    Title = "Sell Lemons",
    Subtitle = "Automation",
    Size = UDim2.fromOffset(560, 470),
})
local section = window:Section({ Title = "Sell Lemons" })

local function ctrlRow(form, title, subtitle)
    local r = form:Row({ SearchIndex = title })
    r:Left():TitleStack({ Title = title, Subtitle = subtitle })
    return r
end

local function toggleRow(form, title, subtitle, tbl, key)
    ctrlRow(form, title, subtitle):Right():Toggle({
        Value = tbl[key],
        ValueChanged = function(_, on) tbl[key] = on end,
    })
end

local function stepperRow(form, title, subtitle, min, max, step, key)
    ctrlRow(form, title, subtitle):Right():Stepper({
        Minimum = min,
        Maximum = max,
        Step = step,
        Fielded = true,
        Value = config[key],
        ValueChanged = function(_, v) config[key] = v end,
    })
end

local statusTab = section:Tab({ Title = "Status", Selected = true })

local L = {}
local function infoRow(form, key, text)
    local _, inst = form:Row({}):Left():Label({ Text = text })
    L[key] = inst
end

local balForm = statusTab:PageSection({ Title = "Balances" }):Form()
infoRow(balForm, "cash", "Cash: --")
infoRow(balForm, "income", "Income: --")
infoRow(balForm, "investors", "Investors: --")
infoRow(balForm, "potential", "Next rebirth: --")

local presForm = statusTab:PageSection({ Title = "Prestige" }):Form()
infoRow(presForm, "evolution", "Evolution: --")
infoRow(presForm, "ascension", "Ascension: --")
infoRow(presForm, "perma", "Permanent stands: --")
infoRow(presForm, "ratio", "Rebirth gain: --")
infoRow(presForm, "ready", "Rebirth rate: --")

local engForm = statusTab:PageSection({ Title = "Engine" }):Form()
infoRow(engForm, "engine", "Status: starting...")
infoRow(engForm, "counts", "Earners --")
infoRow(engForm, "harvest", "Next harvest: --")
infoRow(engForm, "stack", "Upgrade batch: --")

local sessForm = statusTab:PageSection({ Title = "Session" }):Form()
infoRow(sessForm, "session", "Actions: --")
infoRow(sessForm, "prestige", "Prestige: --")
infoRow(sessForm, "last", "Last action: none")

local function fmt(v, prefix)
    if not v then return "--" end
    local ok, s = pcall(function() return Huge.formatAbbreviated(v, prefix or "", 2) end)
    return ok and s or "--"
end
local function setL(key, text)
    if L[key] then L[key].Text = text end
end

updateStatus = function(c)
    if not c then
        setL("engine", "Status: waiting for tycoon...")
        setL("cash", "Cash: --")
        setL("income", "Income: --")
        setL("investors", "Investors: --")
        setL("potential", "Next rebirth: --")
        return
    end
    local cash = tryGet(function() return c.balances:GetCash() end)
    local inc = c.income and tryGet(function() return c.income:GetAverageStreamIncome() end) or nil
    local inv = tryGet(function() return c.balances:GetInvestors() end)
    local pot = c.rebirth and tryGet(function() return c.rebirth:GetPotentialInvestors() end) or nil
    local evo = (c.evolution and tryGet(function() return c.evolution:GetEvolution() end)) or 0
    local evoP = (c.evolution and tryGet(function() return c.evolution:GetEvolutionProgress() end)) or 0
    local asc = (c.ascension and tryGet(function() return c.ascension:GetAscension() end)) or 0
    local ascP = (c.ascension and tryGet(function() return c.ascension:GetAscensionProgress() end)) or 0
    local selLvl = (c.powers and tryGet(function() return c.powers:GetSelectedLevel("UpgradeStack") end)) or 0
    local bonus = Config.Powers.UpgradeStack.Bonuses[selLvl] or 1
    local ratio = (pot and inv) and (10 ^ (pot - math.max(inv, 2))) or 0
    local ready = (rb.peak and rb.peak > 0) and (rb.smooth / rb.peak) or 0

    setL("cash", "Cash: " .. fmt(cash, "$"))
    setL("income", "Income: " .. (inc and (fmt(inc, "$") .. "/s") or "--"))
    setL("investors", "Investors: " .. fmt(inv, ""))
    setL("potential", "Next rebirth: +" .. fmt(pot, "") .. " investors")
    setL("evolution", string.format("Evolution: %d  (%d%%)", evo, math.floor(evoP * 100)))
    setL("ascension", string.format("Ascension: %d  (%d%%)", asc, math.floor(ascP * 100)))
    local permaCount = 0
    for name in pairs(STAND_TIER) do
        if isPermanent(c, name) then permaCount = permaCount + 1 end
    end
    local permaLeft = permaAllowance(c)
    local nextStr = "--"
    if config.permaBuy and permaLeft > 0 then
        local t = permaTarget(c)
        nextStr = t and t.Name or "all owned"
    end
    setL("perma", string.format("Permanent: %d/8  (%d left, next: %s)", permaCount, permaLeft, nextStr))
    setL("ratio", string.format("Rebirth gain: x%.2f", ratio))
    if config.rebirthMode == 2 then
        setL("ready", string.format("Rebirth at: x%.2f (fixed)", config.fixedGain))
    else
        setL("ready", string.format("Rebirth rate: %d%% of peak", math.floor(ready * 100)))
    end
    setL("engine", "Status: connected")
    setL("counts", string.format("Earners %d   Purchases %d   Vines %d   Fruit trees %d",
        #(earnerList or {}), #(purchaseList or {}), #(vineList or {}), #(fruitList or {})))
    if vineList and vineList[1] then
        local avail = tryGet(function() return vineList[1]:GetAvailableTime() end) or 0
        local remain = avail - workspace:GetServerTimeNow()
        if remain > 0 then
            setL("harvest", string.format("Next harvest: %d:%02d", math.floor(remain / 60), math.floor(remain % 60)))
        else
            setL("harvest", "Next harvest: ready")
        end
    else
        setL("harvest", "Next harvest: no tree")
    end
    setL("stack", "Upgrade batch: +" .. (bonus == math.huge and "inf" or tostring(bonus)))
    setL("session", string.format("Up %d  Buy %d  Wake %d  Harvest %d  Drop %d  Pick %d  Phone %d",
        stats.upgrades, stats.purchases, stats.wakes, stats.harvests, stats.drops, stats.fruits, stats.offers))
    setL("prestige", string.format("Rebirths %d  Evolves %d  Ascends %d", stats.rebirths, stats.evolves, stats.ascends))
    if stats.lastAction > 0 then
        setL("last", string.format("Last action: %s (%ds ago)", stats.lastName, math.floor(os.clock() - stats.lastAction)))
    else
        setL("last", "Last action: none")
    end
end

local prestige = section:Tab({ Title = "Prestige" })
local pf = prestige:Form()
toggleRow(pf, "Master Auto", "Master switch for every automation", state, "master")
toggleRow(pf, "Auto Rebirth", "Rebirth at the growth-rate peak (~99% optimal)", state, "rebirth")
toggleRow(pf, "Auto Evolution", "Evolve at the gate for permanent x42 income", state, "evolution")
toggleRow(pf, "Auto Ascension", "Ascend at 453 purchases (wipes evolutions)", state, "ascension")

local econ = section:Tab({ Title = "Economy" })
local ef = econ:Form()
toggleRow(ef, "Auto Upgrade", "Spend cash upgrading earners, biggest first, in bulk", state, "upgrade")
toggleRow(ef, "Auto Buy Powers", "Max Stack Upgrade (bulk upgrades) and the picker power", state, "powers")
toggleRow(ef, "Auto Purchase", "Buy revealed, affordable income sources", state, "purchase")
toggleRow(ef, "Auto Permanent Buy", "Forever-buy the top stands (LemonX first, then down) the moment a run can afford each", config, "permaBuy")
toggleRow(ef, "Auto Complete Tycoon", "Buy everything revealed, including decor", state, "complete")

local collect = section:Tab({ Title = "Collection" })
local cf = collect:Form()
toggleRow(cf, "Auto Click Stand", "Wake every manual income stream", state, "clickstand")
toggleRow(cf, "Auto Collect Cash Drops", "Touch cash drops the instant they spawn", state, "cashdrops")
toggleRow(cf, "Auto Harvest Vine Tree", "Collect the cash vine when ready (Potassium bypass, no teleport)", state, "harvest")
toggleRow(cf, "Auto Pick Fruit Trees", "Pick fruit for cash (teleports to each tree so the server registers it)", state, "clickfruit")
toggleRow(cf, "Teleport to fruit", "Teleport onto each fruit before picking (off = click in place, server may reject)", config, "fruitTeleport")
toggleRow(cf, "Pick from all tycoons", "Pick fruit on every tycoon's trees, not just yours", config, "fruitAllTycoons")
toggleRow(cf, "Auto Phone Offers", "Respond to incoming phone cash offers", state, "phone")
ctrlRow(cf, "Phone strategy", "Raising risks losing the offer for a higher payout"):Right():PopUpButton({
    Options = { "Accept now", "Raise once", "Raise twice" },
    Maximum = 1,
    Value = config.phoneRaises + 1,
    ValueChanged = function(_, i) config.phoneRaises = i - 1 end,
})

local settings = section:Tab({ Title = "Settings" })

local rebirthForm = settings:PageSection({ Title = "Rebirth" }):Form()
ctrlRow(rebirthForm, "Mode", "Dynamic finds the optimum; Fixed fires at a set gain"):Right():PopUpButton({
    Options = { "Dynamic peak", "Fixed gain" },
    Maximum = 1,
    Value = config.rebirthMode,
    ValueChanged = function(_, i) config.rebirthMode = i end,
})
stepperRow(rebirthForm, "Smoothing", "Higher absorbs more rate noise (dynamic)", 0.05, 0.5, 0.01, "smooth")
stepperRow(rebirthForm, "Min gain ratio", "Never rebirth unless potential investors >= this x your current (1 = must at least double)", 0.5, 10, 0.25, "minRatio")
stepperRow(rebirthForm, "Sensitivity", "Lower waits longer past the peak (bigger gain)", 0.9, 0.999, 0.001, "sensitivity")
stepperRow(rebirthForm, "Fixed target", "Rebirth at this gain ratio (fixed mode)", 0.25, 10, 0.25, "fixedGain")
stepperRow(rebirthForm, "Min evolution", "Won't auto-ascend (resets investors + evolutions) until this evolution level", 0, 50, 1, "ascendMinEvolution")

local upgradeForm = settings:PageSection({ Title = "Upgrades & Purchases" }):Form()
stepperRow(upgradeForm, "Cash reserve", "Keep at least this fraction of cash unspent", 0, 0.9, 0.05, "cashReserve")
stepperRow(upgradeForm, "Max per upgrade", "Skip an upgrade costing more than this fraction of cash", 0.05, 1, 0.05, "upgradeMaxFraction")
stepperRow(upgradeForm, "Max per purchase", "Skip a purchase costing more than this fraction of cash", 0.05, 1, 0.05, "purchaseMaxFraction")
stepperRow(upgradeForm, "Upgrade delay", "Seconds between upgrade actions", 0, 5, 0.01, "upgradeDelay")
stepperRow(upgradeForm, "Purchase delay", "Seconds between purchase actions", 0, 5, 0.01, "purchaseDelay")
ctrlRow(upgradeForm, "Purchase priority", "What to buy first when purchasing"):Right():PopUpButton({
    Options = { "Multipliers first", "Listed order" },
    Maximum = 1,
    Value = config.purchasePriority,
    ValueChanged = function(_, i) config.purchasePriority = i end,
})

local powerForm = settings:PageSection({ Title = "Powers" }):Form()
toggleRow(powerForm, "Stack Upgrade", "Buy bulk-upgrade levels ASAP (ignores reserve)", config, "powerStack")
toggleRow(powerForm, "Expert Picker", "Multiply fruit-pick cash (only while Auto Pick is on)", config, "powerPicker")
stepperRow(powerForm, "Investor reserve", "Investors kept unspent (applies to Expert Picker)", 0, 0.9, 0.05, "reserve")
stepperRow(powerForm, "Power delay", "Seconds between power purchases", 0, 5, 0.01, "powerDelay")

local collectForm = settings:PageSection({ Title = "Collection" }):Form()
stepperRow(collectForm, "Stand delay", "Seconds between stand wakes", 0, 5, 0.01, "standDelay")
stepperRow(collectForm, "Cash drop delay", "Seconds between cash-drop pickups", 0, 5, 0.01, "dropDelay")
stepperRow(collectForm, "Fruit click delay", "Seconds between fruit clicks", 0, 1, 0.01, "fruitDelay")
stepperRow(collectForm, "Fruit settle", "Seconds to wait after teleport so the server sees you in range", 0, 0.5, 0.01, "fruitSettle")
stepperRow(collectForm, "Phone delay", "Seconds between phone replies", 0, 5, 0.01, "phoneDelay")

local generalForm = settings:PageSection({ Title = "General" }):Form()
ctrlRow(generalForm, "Minimize key", "Hide or show this window"):Right():KeybindField({
    Value = config.minimizeKey,
    ValueChanged = function(_, key) config.minimizeKey = key end,
})

local accentNames = { "Yellow", "Blue", "Green", "Orange", "Red", "Pink", "Purple" }
ctrlRow(generalForm, "Accent", "Window accent colour"):Right():PopUpButton({
    Options = accentNames,
    Maximum = 1,
    Value = 1,
    ValueChanged = function(_, i)
        local accent = cascade.Accents[accentNames[i]]
        if accent then pcall(function() app.Accent = accent end) end
    end,
})
local minimized = false
state.inputConn = UserInputService.InputBegan:Connect(function(input, gpe)
    if gpe then return end
    if input.KeyCode == config.minimizeKey then
        minimized = not minimized
        window.Minimized = minimized
    end
end)

state.stop = function()
    state.running = false
    if fruitMoved and fruitHome then
        local hrp = Players.LocalPlayer.Character and Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
        if hrp then pcall(function() hrp.CFrame = fruitHome end) end
    end
    logEnd(stats)
    pcall(flushChunk)
    pcall(clearConns)
    if state.dropConn then pcall(function() state.dropConn:Disconnect() end) end
    if state.inputConn then pcall(function() state.inputConn:Disconnect() end) end
    if state.app and state.app.__instance then pcall(function() state.app.__instance:Destroy() end) end
end

描述

stupid game, deserves to die

评论 (0)

登录以参与讨论

  • 成为第一个评论的人。

常见问题

如何使用 Sell Lemons Script 脚本?
复制上方的脚本代码,打开你的 Roblox 执行器,粘贴代码,然后在游戏中点击执行。脚本运行后功能会立即激活。
Sell Lemons Script 脚本免费吗?
是的。此脚本免费复制和使用。如果使用密钥系统,请通过「获取密钥」链接免费解锁。
使用 Sell Lemons Script 脚本安全吗?
完整源代码显示在此页面上,让你在运行前准确了解其功能。请始终使用可信的执行器,并记住使用脚本违反 Roblox 服务条款,风险自负。
哪个执行器兼容 Sell Lemons Script?
此脚本兼容大多数热门 Roblox 执行器。查看我们的执行器页面,为你的设备找到可信的免费或付费执行器。
Sell Lemons Script | BloxScripter