--// Services
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local Workspace = game:GetService("Workspace")
local VirtualUser = game:GetService("VirtualUser")
--// Runtime cleanup
local RUNTIME_KEY = "__SellLemonsRuntime"
local previousRuntime = getgenv()[RUNTIME_KEY]
if previousRuntime and previousRuntime.stop then
previousRuntime.stop()
end
local Runtime = {
alive = true,
connections = {},
lemonConnections = {},
tasks = {},
}
getgenv()[RUNTIME_KEY] = Runtime
local function isAlive()
return Runtime.alive and getgenv()[RUNTIME_KEY] == Runtime
end
local function trackConnection(connection)
table.insert(Runtime.connections, connection)
return connection
end
local function trackTask(thread)
if thread then
table.insert(Runtime.tasks, thread)
end
return thread
end
local function spawnTracked(callback, ...)
local args = { ... }
return trackTask(task.spawn(function()
if isAlive() then
callback(table.unpack(args))
end
end))
end
local function delayTracked(seconds, callback, ...)
local args = { ... }
return trackTask(task.delay(seconds, function()
if isAlive() then
callback(table.unpack(args))
end
end))
end
function Runtime.stop()
if not Runtime.alive then
return
end
Runtime.alive = false
getgenv().autobuyButtons = false
getgenv().autoUpgrade = false
getgenv().autoCashDrops = false
getgenv().autoAcceptPhoneOffers = false
getgenv().autoBigLemons = false
getgenv().antiAFK = false
getgenv().buttonsBuying = 0
getgenv().upgradesBuying = 0
for _, connection in ipairs(Runtime.connections) do
pcall(function()
connection:Disconnect()
end)
end
for _, connection in pairs(Runtime.lemonConnections) do
pcall(function()
connection:Disconnect()
end)
end
for _, thread in ipairs(Runtime.tasks) do
pcall(function()
task.cancel(thread)
end)
end
table.clear(Runtime.connections)
table.clear(Runtime.lemonConnections)
table.clear(Runtime.tasks)
end
-- UserInputService is loaded by the original script's environment.
-- Keeping the reference avoids changing executor-side assumptions.
local _UIS = UserInputService
--// Player
local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")
--// UI Library
local CalmLib = loadstring(game:HttpGet("https://raw.githubusercontent.com/ICantAffordSynapse/calmlib/refs/heads/main/src.lua"))()
--// Configuration
local DEFAULTS = {
autobuyButtonsInterval = 2000,
buyButtonsThreshold = 1,
autobuyButtons = false,
autoUpgradeInterval = 2000,
upgradeThreshold = 1,
upgradeAmount = 1,
autoUpgrade = false,
autoBigLemons = false,
autoCashDrops = false,
autoAcceptPhoneOffers = false,
antiAFK = false,
maxSimulatenousPurchases = 1,
buttonsBuying = 0,
upgradesBuying = 0,
}
for key, value in pairs(DEFAULTS) do
if getgenv()[key] == nil then
getgenv()[key] = value
end
end
local function global(key)
return getgenv()[key]
end
local function setGlobal(key, value)
getgenv()[key] = value
end
--// Number parsing
local SUFFIXES = {
k = 1e3, m = 1e6, b = 1e9, t = 1e12,
qd = 1e15, qn = 1e18, sx = 1e21, sp = 1e24, oc = 1e27, no = 1e30,
dc = 1e33, ud = 1e36, dd = 1e39, td = 1e42, qtd = 1e45, qnd = 1e48,
sxd = 1e51, spd = 1e54, ocd = 1e57, nod = 1e60,
vg = 1e63, uvg = 1e66, dvg = 1e69, tvg = 1e72, qtvg = 1e75, qnvg = 1e78,
sxvg = 1e81, spvg = 1e84, ocvg = 1e87, novg = 1e90,
tg = 1e93, utg = 1e96, dtg = 1e99, ttg = 1e102, qttg = 1e105, qntg = 1e108,
sxtg = 1e111, sptg = 1e114, octg = 1e117, notg = 1e120,
qdg = 1e123, uqdg = 1e126, dqdg = 1e129, tqdg = 1e132, qtqdg = 1e135,
qnqdg = 1e138, sxqdg = 1e141, spqdg = 1e144, ocqdg = 1e147, noqdg = 1e150,
qng = 1e153, uqng = 1e156, dqng = 1e159, tqng = 1e162, qtqng = 1e165,
qnqng = 1e168, sxqng = 1e171, spqng = 1e174, ocqng = 1e177, noqng = 1e180,
sxg = 1e183, usxg = 1e186, dsxg = 1e189, tsxg = 1e192, qtsxg = 1e195,
qnsxg = 1e198, sxsxg = 1e201, spsxg = 1e204, ocsxg = 1e207, nosxg = 1e210,
spg = 1e213, uspg = 1e216, dspg = 1e219, tspg = 1e222, qtspg = 1e225,
qnspg = 1e228, sxspg = 1e231, spspg = 1e234, ocspg = 1e237, nospg = 1e240,
ocg = 1e243, uocg = 1e246, docg = 1e249, tocg = 1e252, qtocg = 1e255,
qnocg = 1e258, sxocg = 1e261, spocg = 1e264, ococg = 1e267, noocg = 1e270,
nog = 1e273, unog = 1e276, dnog = 1e279, tnog = 1e282, qtnog = 1e285,
qnnog = 1e288, sxnog = 1e291, spnog = 1e294, ocnog = 1e297, nonog = 1e300,
ce = 1e303,
}
local WORDS = {
hundred = 1e2,
thousand = 1e3,
million = 1e6,
billion = 1e9,
trillion = 1e12,
quadrillion = 1e15,
quintillion = 1e18,
sextillion = 1e21,
septillion = 1e24,
octillion = 1e27,
nonillion = 1e30,
decillion = 1e33,
undecillion = 1e36,
duodecillion = 1e39,
tredecillion = 1e42,
quattuordecillion = 1e45,
quindecillion = 1e48,
sexdecillion = 1e51,
septendecillion = 1e54,
octodecillion = 1e57,
novemdecillion = 1e60,
vigintillion = 1e63,
unvigintillion = 1e66,
duovigintillion = 1e69,
tresvigintillion = 1e72,
quattuorvigintillion = 1e75,
quinvigintillion = 1e78,
sexvigintillion = 1e81,
septenvigintillion = 1e84,
octovigintillion = 1e87,
novemvigintillion = 1e90,
trigintillion = 1e93,
untrigintillion = 1e96,
duotrigintillion = 1e99,
trestrigintillion = 1e102,
quattuortrigintillion = 1e105,
quintrigintillion = 1e108,
sextrigintillion = 1e111,
septentrigintillion = 1e114,
octotrigintillion = 1e117,
novemtrigintillion = 1e120,
quadragintillion = 1e123,
unquadragintillion = 1e126,
duoquadragintillion = 1e129,
tresquadragintillion = 1e132,
quattuorquadragintillion = 1e135,
quinquadragintillion = 1e138,
sexquadragintillion = 1e141,
septenquadragintillion = 1e144,
octoquadragintillion = 1e147,
novemquadragintillion = 1e150,
quinquagintillion = 1e153,
unquinquagintillion = 1e156,
duoquinquagintillion = 1e159,
tresquinquagintillion = 1e162,
quattuorquinquagintillion = 1e165,
quinquinquagintillion = 1e168,
sexquinquagintillion = 1e171,
septenquinquagintillion = 1e174,
octoquinquagintillion = 1e177,
novemquinquagintillion = 1e180,
sexagintillion = 1e183,
unsexagintillion = 1e186,
duosexagintillion = 1e189,
tressexagintillion = 1e192,
quattuorsexagintillion = 1e195,
quinsexagintillion = 1e198,
sexsexagintillion = 1e201,
septensexagintillion = 1e204,
octosexagintillion = 1e207,
novemsexagintillion = 1e210,
septuagintillion = 1e213,
unseptuagintillion = 1e216,
duoseptuagintillion = 1e219,
tresseptuagintillion = 1e222,
quattuorseptuagintillion = 1e225,
quinseptuagintillion = 1e228,
sexseptuagintillion = 1e231,
septenseptuagintillion = 1e234,
octoseptuagintillion = 1e237,
novemseptuagintillion = 1e240,
octogintillion = 1e243,
unoctogintillion = 1e246,
duooctogintillion = 1e249,
tresoctogintillion = 1e252,
quattuoroctogintillion = 1e255,
quinoctogintillion = 1e258,
sexoctogintillion = 1e261,
septenoctogintillion = 1e264,
octooctogintillion = 1e267,
novemoctogintillion = 1e270,
nonagintillion = 1e273,
unnonagintillion = 1e276,
duononagintillion = 1e279,
tresnonagintillion = 1e282,
quattuornonagintillion = 1e285,
quinnonagintillion = 1e288,
sexnonagintillion = 1e291,
septennonagintillion = 1e294,
octononagintillion = 1e297,
novemnonagintillion = 1e300,
centillion = 1e303
}
local function getMultiplier(token, customSuffixes)
token = token:lower()
return (customSuffixes and customSuffixes[token]) or SUFFIXES[token] or WORDS[token]
end
local function decodeValue(value, customSuffixes)
if typeof(value) ~= "string" then
return tonumber(value)
end
local cleaned = value:lower():gsub(",", ""):gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
local amount, suffix = cleaned:match("^([%d%.%-]+)%s*([%a]+)$")
if amount and suffix then
local multiplier = getMultiplier(suffix, customSuffixes)
if not multiplier then
error(suffix .. " not in suffix tables!")
end
local numericAmount = tonumber(amount)
return numericAmount and numericAmount * multiplier or nil
end
return tonumber(cleaned)
end
local function safeDecode(value)
local ok, result = pcall(decodeValue, value)
if not ok then
warn("safeDecode() was not ok: ", result)
end
return ok and result or nil
end
--// Character helpers
local function getCharacter()
return LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
end
local function getRootPart()
return getCharacter():WaitForChild("HumanoidRootPart")
end
--// Tycoon helpers
local function findTycoon()
for _, instance in ipairs(Workspace:GetChildren()) do
local owner = instance:FindFirstChild("Owner")
if owner and owner.Value == LocalPlayer then
return instance
end
end
return nil
end
local Tycoon = findTycoon()
if not Tycoon then
warn("Tycoon not found for player.")
return
end
local CashDropsFolder = Workspace:WaitForChild("CashDrops")
local TycoonRemotes = Tycoon:WaitForChild("Remotes")
local PhoneOfferEvent = TycoonRemotes:WaitForChild("PhoneOffer")
local function getPurchasesFolder()
return Tycoon:FindFirstChild("Purchases")
end
local function getIncomeSource(category)
local source = category:FindFirstChild(category.Name)
return source and source:FindFirstChild(source.Name) or nil
end
--// Interaction helpers
local primingUpgradeUis = false
local function primeUpgradeUis()
if primingUpgradeUis then
return
end
primingUpgradeUis = true
local purchases = getPurchasesFolder()
if purchases then
for _, category in ipairs(purchases:GetChildren()) do
local incomeSource = getIncomeSource(category)
if incomeSource and incomeSource:IsA("BasePart") then
local originalCFrame = incomeSource.CFrame
incomeSource.CFrame = getRootPart().CFrame
task.wait(0.21)
incomeSource.CFrame = originalCFrame
end
end
end
primingUpgradeUis = false
end
local function remoteTouchInterest(part)
local root = getRootPart()
local originalCanCollide = part.CanCollide
local originalCFrame = part.CFrame
part.CanCollide = false
part:PivotTo(root.CFrame)
task.wait()
task.wait()
if part.Parent then
part:PivotTo(originalCFrame)
part.CanCollide = originalCanCollide
end
end
--// Price helpers
local function stripCurrency(text)
return text:match("%d.*") or ""
end
local function getCurrentCash()
local leaderstats = LocalPlayer:FindFirstChild("leaderstats")
local cash = leaderstats and leaderstats:FindFirstChild("Cash")
return cash and safeDecode(stripCurrency(cash.Value)) or nil
end
local function getButtonPrice(button)
local buttonPart = button:FindFirstChild("Button")
local gui = buttonPart and buttonPart:FindFirstChild("Gui")
local priceLabel = gui and gui:FindFirstChild("Price")
local priceMagnitudeLabel = gui and gui:FindFirstChild("PriceMag")
if priceLabel and priceMagnitudeLabel then
return safeDecode(stripCurrency(priceLabel.Text) .. priceMagnitudeLabel.Text)
end
return nil
end
local function getUpgradePrice(upgradeEvent)
local source = upgradeEvent.Parent
local sourceUi = source and PlayerGui:FindFirstChild(source.Name:gsub(" ", ""))
local upgradeUi = sourceUi and sourceUi:FindFirstChild("Upgrade")
local priceLabel = upgradeUi and upgradeUi:FindFirstChild("Price")
return priceLabel and safeDecode(stripCurrency(priceLabel.Text)) or nil
end
local function canBuyButton(button)
local cash = getCurrentCash()
local price = getButtonPrice(button)
if not cash or not price then
warn(not cash and "Invalid cash (from buy button)" or ("Invalid button price for " .. button.Name))
return false
end
return (cash * global("buyButtonsThreshold") / 110) > price
end
local function canBuyUpgrade(upgradeEvent)
local cash = getCurrentCash()
local price = getUpgradePrice(upgradeEvent)
if not cash or not price then
local sourceName = upgradeEvent.Parent and (" for " .. upgradeEvent.Parent.Name) or ""
warn(not cash and "Invalid cash (from buy upgrade)" or ("Invalid upgrade price" .. sourceName))
return false
end
local adjustedCash = cash * global("upgradeThreshold") / 100
adjustedCash /= 1.2 ^ global("upgradeAmount")
return adjustedCash > price
end
--// Collection helpers
local function isValidButton(instance)
return instance:IsA("Model") and instance:FindFirstChild("Button") ~= nil
end
local function collectButtons()
local buttons = {}
local purchases = getPurchasesFolder()
if not purchases then
return buttons
end
for _, category in ipairs(purchases:GetChildren()) do
local buttonsFolder = category:FindFirstChild("Buttons")
if not buttonsFolder then
continue
end
for _, group in ipairs(buttonsFolder:GetChildren()) do
if isValidButton(group) then
table.insert(buttons, group)
continue
end
for _, button in ipairs(group:GetChildren()) do
if isValidButton(button) then
table.insert(buttons, button)
end
end
end
end
return buttons
end
local function collectUpgradeEvents()
local upgradeEvents = {}
local purchases = getPurchasesFolder()
if not purchases then
return upgradeEvents
end
for _, category in ipairs(purchases:GetChildren()) do
local incomeSource = getIncomeSource(category)
local upgrade = incomeSource and incomeSource:FindFirstChild("Upgrade")
if upgrade then
table.insert(upgradeEvents, upgrade)
end
end
return upgradeEvents
end
local function collectTrees()
local trees = {}
for _, loopTycoon in ipairs(Workspace:GetChildren()) do
if not loopTycoon.Name:find("Tycoon") then
continue
end
local empty = loopTycoon:FindFirstChild("Empty")
if empty then
for _, tree in ipairs(empty:GetChildren()) do
if tree.Name == "LemonTree" then
table.insert(trees, tree)
end
end
end
local constantTrees = loopTycoon:FindFirstChild("Constant")
constantTrees = constantTrees and constantTrees:FindFirstChild("Trees")
if constantTrees then
for _, tree in ipairs(constantTrees:GetChildren()) do
table.insert(trees, tree)
end
end
local purchases = loopTycoon:FindFirstChild("Purchases")
if purchases then
local hills = purchases:FindFirstChild("Hills")
if hills then
for i = 1, 3, 1 do
local hill = hills:FindFirstChild("Hill " .. i)
if hill then
for _, tree in ipairs(hill:GetChildren()) do
if tree.Name == "LemonTree" then
table.insert(trees, tree)
end
end
end
end
end
end
for _, tree in workspace:GetChildren() do
if tree.Name == "LemonTree" then
table.insert(trees, tree)
end
end
end
return trees
end
local function collectLemons(trees)
local lemons = {}
for _, tree in ipairs(trees or collectTrees()) do
for _, child in ipairs(tree:GetChildren()) do
if child.Name == "Fruit" then
table.insert(lemons, child)
end
end
end
return lemons
end
--// Purchase actions
local function activePurchases()
return global("buttonsBuying") + global("upgradesBuying")
end
local function waitForPurchaseSlot()
while isAlive() and activePurchases() >= global("maxSimulatenousPurchases") do
task.wait()
end
end
local function runButtonPurchase(button)
if not canBuyButton(button) then
return
end
waitForPurchaseSlot()
setGlobal("buttonsBuying", global("buttonsBuying") + 1)
local ok, err = pcall(function()
if canBuyButton(button) then
local buttonPart = button:FindFirstChild("Button")
if buttonPart and buttonPart:IsA("BasePart") then
remoteTouchInterest(buttonPart)
end
end
end)
if not ok then
warn(err)
end
setGlobal("buttonsBuying", math.max(0, global("buttonsBuying") - 1))
end
local function buyButtons()
for _, button in ipairs(collectButtons()) do
if not isAlive() then
break
end
spawnTracked(runButtonPurchase, button)
task.wait(1 / 30)
end
end
local function runUpgradePurchase(upgradeEvent)
if not canBuyUpgrade(upgradeEvent) then
return
end
waitForPurchaseSlot()
setGlobal("upgradesBuying", global("upgradesBuying") + 1)
local ok, err = pcall(function()
if canBuyUpgrade(upgradeEvent) then
upgradeEvent:InvokeServer(global("upgradeAmount"))
end
end)
if not ok then
warn(err)
end
setGlobal("upgradesBuying", math.max(0, global("upgradesBuying") - 1))
end
local function upgradeEverything()
for _, upgradeEvent in ipairs(collectUpgradeEvents()) do
if not isAlive() then
break
end
spawnTracked(runUpgradePurchase, upgradeEvent)
task.wait(1 / 30)
end
end
--// Lemon automation
local lemonConnections = Runtime.lemonConnections
local lemons = collectLemons()
local function tryClickLemon(lemon)
if not lemon then return end
lemon.CanQuery = false
lemon.CanCollide = false
lemon.CanTouch = false
lemon.Size = Vector3.new(
10,
10,
10
)
for _, descendant in ipairs(lemon:GetDescendants()) do
if descendant.Name == "ClickPart" then
descendant.Size = Vector3.new(
15,
15,
15
)
descendant.Position = lemon.Position
end
if descendant:IsA("ClickDetector") then
descendant.MaxActivationDistance = 123456
end
end
end
local function refreshLemonConnections()
for index, connection in pairs(lemonConnections) do
connection:Disconnect()
lemonConnections[index] = nil
end
lemons = collectLemons()
for _, lemon in ipairs(lemons) do
lemonConnections[lemon] = lemon.ChildAdded:Connect(function(child)
if global("autoBigLemons") and child.Name == "ClickPart" then
spawnTracked(tryClickLemon, lemon)
end
end)
end
end
spawnTracked(function()
while isAlive() and task.wait(10) do
if global("autoBigLemons") then
refreshLemonConnections()
for _, lemon in ipairs(lemons) do
tryClickLemon(lemon)
end
end
end
end)
--// UI
local window = CalmLib:win("sell lemons")
local infoTab = window:tab("info", "rbxassetid://109121102062195")
infoTab:label("// // // TIP")
infoTab:label("- Do not confuse buttons with upgrades.")
infoTab:label("- Buttons are purchase pads.")
infoTab:label("- Upgrades are for income sources, such as the lemon stand.")
infoTab:label("// // // PROBLEMS")
infoTab:label("// // Buying upgrades not working:")
infoTab:label("- You need to see the upgrade UI inside your tycoon at least once.")
infoTab:label("- The script uses that UI to read upgrade prices.")
infoTab:button("Upgrades Quick Fix", primeUpgradeUis)
local farmTab = window:tab("farm", "rbxassetid://109121102062195")
farmTab:label("// // // SETTINGS")
farmTab:slider("Autobuy Buttons Interval (ms)", 200, 2000, global("autobuyButtonsInterval"), function(value)
setGlobal("autobuyButtonsInterval", value)
end)
farmTab:slider("Auto Upgrade Interval (ms)", 200, 2000, global("autoUpgradeInterval"), function(value)
setGlobal("autoUpgradeInterval", value)
end)
farmTab:slider("Buy Buttons Threshold (%)", 1, 100, global("buyButtonsThreshold"), function(value)
setGlobal("buyButtonsThreshold", value)
end)
farmTab:slider("Upgrade Threshold (%)", 1, 100, global("upgradeThreshold"), function(value)
setGlobal("upgradeThreshold", value)
end)
farmTab:slider("Maximum Simultaneous Purchases", 1, 50, global("maxSimulatenousPurchases"), function(value)
setGlobal("maxSimulatenousPurchases", value)
end)
farmTab:slider("Upgrade Amount", 1, 100, global("upgradeAmount"), function(value)
setGlobal("upgradeAmount", value)
end)
farmTab:label("WARNING: Larger upgrade amounts can make price estimates inaccurate.")
farmTab:label("The script exaggerates prices because the exact formulas are unknown.")
farmTab:label("// // // MANUAL")
farmTab:button("Buy Buttons", buyButtons)
farmTab:button("Upgrade Everything", upgradeEverything)
farmTab:label("// // // AUTOMATIC")
farmTab:toggle("Autobuy Buttons", global("autobuyButtons"), function(enabled)
setGlobal("autobuyButtons", enabled)
if not enabled then
return
end
spawnTracked(function()
while isAlive() and global("autobuyButtons") do
task.wait(global("autobuyButtonsInterval") / 1000)
pcall(buyButtons)
end
end)
end)
farmTab:toggle("Auto Upgrade Everything", global("autoUpgrade"), function(enabled)
setGlobal("autoUpgrade", enabled)
if not enabled then
return
end
spawnTracked(function()
while isAlive() and global("autoUpgrade") do
task.wait(global("autoUpgradeInterval") / 1000)
pcall(upgradeEverything)
end
end)
end)
trackConnection(CashDropsFolder.ChildAdded:Connect(function(drop)
if global("autoCashDrops") and drop:IsA("BasePart") then
remoteTouchInterest(drop)
end
end))
farmTab:toggle("Auto Cash Drops", global("autoCashDrops"), function(enabled)
setGlobal("autoCashDrops", enabled)
if not enabled then
return
end
for _, drop in ipairs(CashDropsFolder:GetChildren()) do
if not global("autoCashDrops") then
break
end
if drop:IsA("BasePart") then
remoteTouchInterest(drop)
end
end
end)
trackConnection(PhoneOfferEvent.OnClientEvent:Connect(function()
if global("autoAcceptPhoneOffers") then
PhoneOfferEvent:FireServer("Accept")
end
end))
farmTab:toggle("Auto Accept Phone Offers", global("autoAcceptPhoneOffers"), function(enabled)
setGlobal("autoAcceptPhoneOffers", enabled)
end)
farmTab:toggle("Auto Big Lemons", global("autoBigLemons"), function(enabled)
setGlobal("autoBigLemons", enabled)
if not enabled then
return
end
refreshLemonConnections()
for _, lemon in ipairs(lemons) do
if not global("autoBigLemons") then
break
end
spawnTracked(tryClickLemon, lemon)
task.wait()
end
end)
local miscTab = window:tab("misc", "rbxassetid://109121102062195")
trackConnection(LocalPlayer.Idled:Connect(function()
if not global("antiAFK") then
return
end
VirtualUser:Button2Down(Vector2.new(0, 0), Workspace.CurrentCamera.CFrame)
task.wait()
VirtualUser:Button2Up(Vector2.new(0, 0), Workspace.CurrentCamera.CFrame)
end))
miscTab:toggle("Anti AFK", global("antiAFK"), function(enabled)
setGlobal("antiAFK", enabled)
end)