--[[
Grow a Garden 2 ā Stock & Fruit Price Monitor
Monitors SeedShop, GearShop stock + fruit sell price multipliers.
Sends Discord webhook on stock arrival and fruit price spikes.
Made by Zr3 // Discord - https://discord.gg/Gj9bnxa5Kz
]]
local CONFIG = {
enabled = true,
webhookURL = "YOUR_WEBHOOK",
checkInterval = 0.01,
monitorSeeds = true,
monitorGears = true,
monitorFruitPrices = true,
notifyOnStock = true,
notifyOnOutOfStock = false,
cooldown = 250,
fruitCooldown = 600,
fruitThreshold = 2,
pingHere = true,
}
local monitoredSeeds = {
["Dragon's Breath"] = true, --seeds to be monitored
["Moon Bloom"] = true,
["Hypno Bloom"] = true,
["Venom Spitter"] = true,
}
local monitoredGears = {
["Super Sprinkler"] = true, -- gears to be monitored
["Super Watering Can"] = true,
["Legendary Sprinkler"] = true,
}
local monitoredFruits = {
["Dragon's Breath"] = true, -- fruits to monitor for 2x and more price
["Moon Bloom"] = true,
["Ghost Pepper"] = true,
["Venom Spitter"] = true,
}
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")
local LP = Players.LocalPlayer
local stockStatus = { seeds = {}, gears = {} }
local lastNotification = { seeds = {}, gears = {} }
local lastFruitAlert = {}
local isRunning = false
local monitorConnection = nil
local hasSentPing = false
local function sendWebhook(content, embeds)
if not CONFIG.webhookURL or CONFIG.webhookURL:find("YOUR_WEBHOOK") then
warn("[Monitor] Webhook URL not configured!")
return false
end
local data = { content = content or "", embeds = embeds or {} }
local ok, err = pcall(function()
local json = HttpService:JSONEncode(data)
local reqFn = (syn and syn.request) or (http and http.request) or request
if reqFn then
reqFn({
Url = CONFIG.webhookURL,
Method = "POST",
Headers = { ["Content-Type"] = "application/json" },
Body = json,
})
else
HttpService:PostAsync(CONFIG.webhookURL, json, Enum.HttpContentType.ApplicationJson)
end
end)
if not ok then warn("[Monitor] Webhook error: "..tostring(err)) end
return ok
end
local function embed(title, desc, color, fields)
return {
title = title,
description = desc or "",
color = color or 0x7ED957,
fields = fields or {},
footer = { text = "Made by Zr3 ⢠" .. os.date("%H:%M:%S") },
}
end
local function stockFolder(shop)
local sv = ReplicatedStorage:FindFirstChild("StockValues")
local sh = sv and sv:FindFirstChild(shop)
return sh and sh:FindFirstChild("Items")
end
local function getAllStock(shop)
local folder = stockFolder(shop)
if not folder then return {} end
local out = {}
for _, v in ipairs(folder:GetChildren()) do
if v:IsA("ValueBase") then out[v.Name] = v.Value or 0 end
end
return out
end
local function checkStock()
if not CONFIG.enabled then return end
local seedStock = CONFIG.monitorSeeds and getAllStock("SeedShop") or {}
local gearStock = CONFIG.monitorGears and getAllStock("GearShop") or {}
local alerts = {}
local now = os.time()
local hasInStock = false
local function scanCategory(monitorTable, stockData, statusTable, notifTable, catKey)
for name, _ in pairs(monitorTable) do
local stock = stockData[name] or 0
local wasInStock = statusTable[name] or false
local inStock = stock > 0
local lastN = notifTable[name] or 0
local canNotify = (now - lastN) >= CONFIG.cooldown
if CONFIG.notifyOnStock and inStock and not wasInStock and canNotify then
alerts[#alerts+1] = { cat=catKey, name=name, stock=stock, status="in_stock" }
notifTable[name] = now
hasInStock = true
elseif CONFIG.notifyOnOutOfStock and not inStock and wasInStock and canNotify then
alerts[#alerts+1] = { cat=catKey, name=name, stock=stock, status="out_of_stock" }
notifTable[name] = now
end
statusTable[name] = inStock
end
end
scanCategory(monitoredSeeds, seedStock, stockStatus.seeds, lastNotification.seeds, "seed")
scanCategory(monitoredGears, gearStock, stockStatus.gears, lastNotification.gears, "gear")
if #alerts == 0 then return end
local fields = {}
local allOut = true
for _, a in ipairs(alerts) do
local icon = a.cat == "seed" and "š±" or "š§"
local sIcon = a.status == "in_stock" and "ā
" or "ā"
local sText = a.status == "in_stock" and "IN STOCK" or "OUT OF STOCK"
fields[#fields+1] = {
name = icon .. " " .. a.name,
value = string.format("**Status:** %s %s\n**Qty:** %d\n**Time:** %s", sIcon, sText, a.stock, os.date("%H:%M:%S")),
inline = true,
}
if a.status == "in_stock" then allOut = false end
end
if not hasInStock then hasSentPing = false end
local content = nil
if CONFIG.pingHere and hasInStock then
content = "@here"
hasSentPing = true
end
sendWebhook(content, {
embed(
"š¦ Stock Notifications ā Made by Zr3",
"",
allOut and 0xFF4444 or 0x7ED957,
fields
)
})
end
local function parseMult(txt)
if not txt then return nil end
local n = txt:match("x?(%d+%.?%d*)")
return n and tonumber(n) or nil
end
local function checkFruitPrices()
if not CONFIG.monitorFruitPrices then return end
pcall(function()
local sf = LP.PlayerGui
:FindFirstChild("FruitStockPrice")
and LP.PlayerGui.FruitStockPrice:FindFirstChild("Frame")
and LP.PlayerGui.FruitStockPrice.Frame:FindFirstChild("ScrollingFrame")
if not sf then return end
local now = os.time()
local alerts = {}
local maxMultiplier = 0
for _, card in ipairs(sf:GetChildren()) do
if card.Name == "FruitCard" then
local fruitName = card:GetAttribute("SeedToolTip")
if fruitName and monitoredFruits[fruitName] then
local mFrame = card:FindFirstChild("Frame")
local mLabel = mFrame and mFrame:FindFirstChild("Multiplier")
if mLabel then
local mult = parseMult(mLabel.Text)
if mult and mult >= CONFIG.fruitThreshold then
local last = lastFruitAlert[fruitName] or 0
if (now - last) >= CONFIG.fruitCooldown then
lastFruitAlert[fruitName] = now
alerts[#alerts+1] = {
name = fruitName,
mult = mult
}
if mult > maxMultiplier then
maxMultiplier = mult
end
end
end
end
end
end
end
if #alerts == 0 then return end
table.sort(alerts, function(a, b) return a.mult > b.mult end)
local fields = {}
for _, a in ipairs(alerts) do
local stars = ""
if a.mult >= 4 then
stars = " āāāā"
elseif a.mult >= 3 then
stars = " āāā"
elseif a.mult >= 2.5 then
stars = " āā"
elseif a.mult >= 2 then
stars = " ā"
end
fields[#fields+1] = {
name = "š " .. a.name .. stars,
value = string.format("**Price Multiplier:** x%.1f\n**Time:** %s", a.mult, os.date("%H:%M:%S")),
inline = true,
}
end
local description = string.format(
"Found **%d** fruit(s) with multiplier ā„ x%.0f\n",
#alerts,
CONFIG.fruitThreshold
)
sendWebhook("@here", {
embed(
"š° Fruit Price Increase!",
description,
0xFFD700,
fields
)
})
end)
end
local stockTimer = 0
local fruitTimer = 0
local FRUIT_INTERVAL = 3
local function startMonitor()
if isRunning then return end
isRunning = true
CONFIG.enabled = true
hasSentPing = false
task.spawn(function() task.wait(2); checkStock() end)
monitorConnection = RunService.Heartbeat:Connect(function(dt)
if not CONFIG.enabled then return end
if not LP or not LP.Parent then return end
stockTimer = stockTimer + dt
if stockTimer >= CONFIG.checkInterval then
stockTimer = 0
task.spawn(checkStock)
end
if CONFIG.monitorFruitPrices then
fruitTimer = fruitTimer + dt
if fruitTimer >= FRUIT_INTERVAL then
fruitTimer = 0
task.spawn(checkFruitPrices)
end
end
end)
print("[Monitor] Started. Stock check every "..CONFIG.checkInterval.."s, fruit prices every "..FRUIT_INTERVAL.."s.")
end
local function stopMonitor()
if monitorConnection then monitorConnection:Disconnect(); monitorConnection=nil end
isRunning = false
CONFIG.enabled = false
hasSentPing = false
print("[Monitor] Stopped.")
end
task.wait(5)
startMonitor()
game:GetService("StarterGui"):SetCore("SendNotification", {
Title = "GAG2 Monitor Loaded!",
Text = "Made by Zr3 ⢠https://discord.gg/Gj9bnxa5Kz",
Duration = 5,
})
print("[Monitor] Loaded!")
print("Notifier Made by Zr3 ⢠https://discord.gg/Gj9bnxa5Kz")