Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- SERVICES & MODULES
- local Players = game:GetService("Players")
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local UserInputService = game:GetService("UserInputService")
- local player = Players.LocalPlayer
- local GetFarm = require(ReplicatedStorage.Modules.GetFarm)
- local MutationHandler = require(ReplicatedStorage.Modules:WaitForChild("MutationHandler"))
- -- ✅ FRUIT LOG SYSTEM
- local fruitLog = {}
- local maxLogEntries = 200
- local lastKnownFruits = {} -- Track existing fruits to detect spawns/deletions
- local logGui = nil
- -- Helper function for mutation priority
- local function getMutationPriority(mutation)
- local priorityMap = {
- ["Moonlit"] = 6,
- ["Choc"] = 5,
- ["Shocked"] = 4,
- ["Frozen"] = 3,
- ["Chilled"] = 2,
- ["Wet"] = 1,
- ["None"] = 0
- }
- -- Count mutations and assign a priority
- if mutation == "None" then
- return 0
- end
- -- If it contains multiple mutations, count them
- local count = 0
- for w in mutation:gmatch("([^•]+)") do -- Changed to match bullet separator
- count = count + 1
- end
- -- Multiple mutations always have highest priority
- if count > 1 then
- return 100 + count
- end
- -- Single mutation - look up its priority
- for mutName, priority in pairs(priorityMap) do
- if mutation:find(mutName) then
- return priority
- end
- end
- return 0
- end
- -- Helper function for variant priority
- local function getVariantPriority(variant)
- local priorityMap = {
- ["Rainbow"] = 3,
- ["Gold"] = 2,
- ["Normal"] = 1
- }
- return priorityMap[variant] or 0
- end
- -- GUI SETUP
- local playerGui = player:WaitForChild("PlayerGui")
- -- Check if GUI already exists and remove it
- local existingGui = playerGui:FindFirstChild("FruitListGui")
- if existingGui then
- existingGui:Destroy()
- end
- -- State variables
- local currentSortColumn = "Fruit Name" -- Default sort by name
- local currentSortDir = "asc" -- Default ascending
- local allFruitsData = {} -- Will store all fruits data for sorting
- local isMinimized = false -- Track minimize state
- local originalSize -- Store original size when minimizing
- local fruitListGui = Instance.new("ScreenGui")
- fruitListGui.Name = "FruitListGui"
- fruitListGui.ResetOnSpawn = false
- fruitListGui.Parent = playerGui
- local mainFrame = Instance.new("Frame")
- mainFrame.Size = UDim2.new(0, 500, 0, 400)
- mainFrame.Position = UDim2.new(0.5, -250, 0.5, -200)
- mainFrame.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
- mainFrame.BackgroundTransparency = 0.1
- mainFrame.Parent = fruitListGui
- mainFrame.Active = true
- -- Store original size for minimizing
- originalSize = mainFrame.Size
- -- Add rounded corners to main frame
- local mainCorner = Instance.new("UICorner")
- mainCorner.CornerRadius = UDim.new(0, 8)
- mainCorner.Parent = mainFrame
- -- Title bar
- local titleBar = Instance.new("Frame")
- titleBar.Name = "TitleBar"
- titleBar.Size = UDim2.new(1, 0, 0, 30)
- titleBar.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
- titleBar.BorderSizePixel = 0
- titleBar.Parent = mainFrame
- -- Add rounded corners to title bar (top corners only)
- local titleCorner = Instance.new("UICorner")
- titleCorner.CornerRadius = UDim.new(0, 8)
- titleCorner.Parent = titleBar
- -- Make sure the title bar only rounds the top corners
- local bottomFrame = Instance.new("Frame")
- bottomFrame.Size = UDim2.new(1, 0, 0.5, 0)
- bottomFrame.Position = UDim2.new(0, 0, 0.5, 0)
- bottomFrame.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
- bottomFrame.BorderSizePixel = 0
- bottomFrame.Parent = titleBar
- local titleText = Instance.new("TextLabel")
- titleText.Name = "Title"
- titleText.Size = UDim2.new(1, -60, 1, 0)
- titleText.BackgroundTransparency = 1
- titleText.Text = "Farm Fruit List"
- titleText.Font = Enum.Font.SourceSansBold
- titleText.TextColor3 = Color3.fromRGB(255, 255, 255)
- titleText.TextSize = 18
- titleText.Parent = titleBar
- -- Close button
- local closeButton = Instance.new("TextButton")
- closeButton.Name = "CloseButton"
- closeButton.Size = UDim2.new(0, 30, 0, 30)
- closeButton.Position = UDim2.new(1, -30, 0, 0)
- closeButton.BackgroundColor3 = Color3.fromRGB(200, 60, 60)
- closeButton.Text = "X"
- closeButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- closeButton.TextSize = 18
- closeButton.Font = Enum.Font.SourceSansBold
- closeButton.Parent = titleBar
- -- Add rounded corners to close button
- local closeCorner = Instance.new("UICorner")
- closeCorner.CornerRadius = UDim.new(0, 6)
- closeCorner.Parent = closeButton
- -- Minimize button
- local minimizeButton = Instance.new("TextButton")
- minimizeButton.Name = "MinimizeButton"
- minimizeButton.Size = UDim2.new(0, 30, 0, 30)
- minimizeButton.Position = UDim2.new(1, -65, 0, 0)
- minimizeButton.BackgroundColor3 = Color3.fromRGB(60, 60, 200)
- minimizeButton.Text = "-"
- minimizeButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- minimizeButton.TextSize = 22
- minimizeButton.Font = Enum.Font.SourceSansBold
- minimizeButton.Parent = titleBar
- -- Add rounded corners to minimize button
- local minimizeCorner = Instance.new("UICorner")
- minimizeCorner.CornerRadius = UDim.new(0, 6)
- minimizeCorner.Parent = minimizeButton
- -- Function to toggle minimize state
- local function toggleMinimize()
- isMinimized = not isMinimized
- if isMinimized then
- -- Store current size before minimizing
- originalSize = mainFrame.Size
- -- Minimize GUI - just show title bar
- mainFrame.Size = UDim2.new(0, 300, 0, 30)
- minimizeButton.Text = "+"
- -- Hide content
- if mainFrame:FindFirstChild("HeaderFrame") then
- mainFrame.HeaderFrame.Visible = false
- end
- if mainFrame:FindFirstChild("ScrollingFrame") then
- mainFrame.ScrollingFrame.Visible = false
- end
- if mainFrame:FindFirstChild("ResizeHandle") then
- mainFrame.ResizeHandle.Visible = false
- end
- else
- -- Restore GUI to original size
- mainFrame.Size = originalSize
- minimizeButton.Text = "-"
- -- Show content
- if mainFrame:FindFirstChild("HeaderFrame") then
- mainFrame.HeaderFrame.Visible = true
- end
- if mainFrame:FindFirstChild("ScrollingFrame") then
- mainFrame.ScrollingFrame.Visible = true
- end
- if mainFrame:FindFirstChild("ResizeHandle") then
- mainFrame.ResizeHandle.Visible = true
- end
- end
- end
- -- Connect minimize button
- minimizeButton.MouseButton1Click:Connect(toggleMinimize)
- -- Add keyboard shortcut (Left Ctrl) to toggle minimize
- UserInputService.InputBegan:Connect(function(input)
- if input.KeyCode == Enum.KeyCode.LeftControl then
- toggleMinimize()
- end
- end)
- -- Resize Handle
- local resizeHandle = Instance.new("Frame")
- resizeHandle.Size = UDim2.new(0, 24, 0, 24)
- resizeHandle.Position = UDim2.new(1, -24, 1, -24)
- resizeHandle.BackgroundColor3 = Color3.fromRGB(80, 80, 80)
- resizeHandle.BorderSizePixel = 0
- resizeHandle.Parent = mainFrame
- resizeHandle.Name = "ResizeHandle"
- resizeHandle.ZIndex = 10
- local resizeCorner = Instance.new("UICorner")
- resizeCorner.CornerRadius = UDim.new(0, 8)
- resizeCorner.Parent = resizeHandle
- -- IMPROVED DRAGGING IMPLEMENTATION
- local dragging = false
- local dragInput
- local dragStart
- local startPos
- local lastMousePos
- local lastGoalPos
- local function updateDrag(input)
- if dragging then
- local delta = input.Position - dragStart
- local position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X,
- startPos.Y.Scale, startPos.Y.Offset + delta.Y)
- -- Use a smoother movement with lerping
- game:GetService("RunService").RenderStepped:Wait()
- mainFrame.Position = position
- end
- end
- titleBar.InputBegan:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 or
- input.UserInputType == Enum.UserInputType.Touch then
- dragging = true
- dragStart = input.Position
- startPos = mainFrame.Position
- lastMousePos = Vector2.new(input.Position.X, input.Position.Y)
- -- Continue tracking even if mouse leaves the titleBar
- input.Changed:Connect(function()
- if input.UserInputState == Enum.UserInputState.End then
- dragging = false
- end
- end)
- end
- end)
- titleBar.InputChanged:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseMovement or
- input.UserInputType == Enum.UserInputType.Touch then
- dragInput = input
- end
- end)
- UserInputService.InputChanged:Connect(function(input)
- if input == dragInput and dragging then
- updateDrag(input)
- end
- end)
- -- Resize Script
- local draggingResize = false
- local resizeStart
- local startSize
- resizeHandle.InputBegan:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 or
- input.UserInputType == Enum.UserInputType.Touch then
- draggingResize = true
- resizeStart = input.Position
- startSize = mainFrame.Size
- -- Track input end even outside the resize handle
- input.Changed:Connect(function()
- if input.UserInputState == Enum.UserInputState.End then
- draggingResize = false
- end
- end)
- end
- end)
- UserInputService.InputChanged:Connect(function(input)
- if draggingResize and (input.UserInputType == Enum.UserInputType.MouseMovement or
- input.UserInputType == Enum.UserInputType.Touch) then
- local delta = input.Position - resizeStart
- local newWidth = math.max(400, startSize.X.Offset + delta.X)
- local newHeight = math.max(300, startSize.Y.Offset + delta.Y)
- mainFrame.Size = UDim2.new(0, newWidth, 0, newHeight)
- -- Store new size for when un-minimizing
- originalSize = mainFrame.Size
- -- Recalculate scrolling frame size when resizing
- local headerHeight = 30 -- title bar height
- if mainFrame:FindFirstChild("HeaderFrame") and mainFrame:FindFirstChild("ScrollingFrame") then
- mainFrame.ScrollingFrame.Size = UDim2.new(1, -20, 1, -(headerHeight + mainFrame.HeaderFrame.Size.Y.Offset + 20))
- end
- end
- end)
- -- Close button logic
- closeButton.MouseButton1Click:Connect(function()
- fruitListGui:Destroy()
- end)
- -- Header Frame for column titles
- local headerFrame = Instance.new("Frame")
- headerFrame.Name = "HeaderFrame"
- headerFrame.Size = UDim2.new(1, -20, 0, 35)
- headerFrame.Position = UDim2.new(0, 10, 0, 40)
- headerFrame.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
- headerFrame.BackgroundTransparency = 0.5
- headerFrame.Parent = mainFrame
- -- Add rounded corners to header frame
- local headerCorner = Instance.new("UICorner")
- headerCorner.CornerRadius = UDim.new(0, 6)
- headerCorner.Parent = headerFrame
- -- Column Headers - SIMPLIFIED: only 4 columns now
- local columns = {"Fruit Name", "Variant", "Weight (kg)", "Mutations"}
- local columnWidths = {0.22, 0.18, 0.18, 0.42} -- Give more space to mutations column
- local sortButtons = {}
- -- Scrolling Frame for fruit list
- local scrollingFrame = Instance.new("ScrollingFrame")
- scrollingFrame.Name = "ScrollingFrame"
- scrollingFrame.Size = UDim2.new(1, -20, 1, -85)
- scrollingFrame.Position = UDim2.new(0, 10, 0, 85)
- scrollingFrame.BackgroundTransparency = 0.9
- scrollingFrame.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
- scrollingFrame.BorderSizePixel = 0
- scrollingFrame.ScrollBarThickness = 8
- scrollingFrame.Parent = mainFrame
- -- Refresh Button
- local refreshButton = Instance.new("TextButton")
- refreshButton.Name = "RefreshButton"
- refreshButton.Size = UDim2.new(0, 100, 0, 25)
- refreshButton.Position = UDim2.new(0, 10, 0, 3)
- refreshButton.BackgroundColor3 = Color3.fromRGB(60, 120, 60)
- refreshButton.Text = "Refresh"
- refreshButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- refreshButton.TextSize = 16
- refreshButton.Font = Enum.Font.SourceSansBold
- refreshButton.Parent = titleBar
- -- Create a UICorner for the refresh button
- local refreshCorner = Instance.new("UICorner")
- refreshCorner.CornerRadius = UDim.new(0, 4)
- refreshCorner.Parent = refreshButton
- -- Status label (for minimize tooltip)
- local statusLabel = Instance.new("TextLabel")
- statusLabel.Name = "StatusLabel"
- statusLabel.Size = UDim2.new(0, 200, 0, 20)
- statusLabel.Position = UDim2.new(0.5, -100, 0, -25)
- statusLabel.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
- statusLabel.BackgroundTransparency = 0.2
- statusLabel.Text = "Press Left Ctrl to minimize"
- statusLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
- statusLabel.TextSize = 14
- statusLabel.Font = Enum.Font.SourceSans
- statusLabel.Visible = false
- statusLabel.Parent = mainFrame
- -- Add rounded corners to status label
- local statusCorner = Instance.new("UICorner")
- statusCorner.CornerRadius = UDim.new(0, 4)
- statusCorner.Parent = statusLabel
- -- Show tooltip when hovering minimize button
- minimizeButton.MouseEnter:Connect(function()
- statusLabel.Visible = true
- end)
- minimizeButton.MouseLeave:Connect(function()
- statusLabel.Visible = false
- end)
- -- Function declaration for refreshFruitList (will be defined later)
- local refreshFruitList
- -- Function to create sorted fruit list
- local function createSortedFruitList()
- -- Clear existing list
- for _, child in pairs(scrollingFrame:GetChildren()) do
- if child:IsA("Frame") then
- child:Destroy()
- end
- end
- -- Sort the fruits data based on current sort column and direction
- table.sort(allFruitsData, function(a, b)
- local aValue, bValue
- if currentSortColumn == "Fruit Name" then
- aValue = a.name:lower()
- bValue = b.name:lower()
- elseif currentSortColumn == "Variant" then
- -- Sort by variant priority
- aValue = getVariantPriority(a.variant)
- bValue = getVariantPriority(b.variant)
- elseif currentSortColumn == "Mutations" then
- -- Sort by mutation priority
- aValue = getMutationPriority(a.mutations)
- bValue = getMutationPriority(b.mutations)
- elseif currentSortColumn == "Weight (kg)" then
- -- Use the raw numeric weight value instead of the string
- aValue = a.weightNum or 0
- bValue = b.weightNum or 0
- else
- return false
- end
- if currentSortDir == "asc" then
- return aValue < bValue
- else
- return aValue > bValue
- end
- end)
- -- Update sort button appearance
- for colName, button in pairs(sortButtons) do
- if colName == currentSortColumn then
- button.Text = currentSortDir == "asc" and "▲" or "▼"
- button.TextColor3 = Color3.fromRGB(255, 255, 100) -- Highlight active sort
- else
- button.Text = "◆"
- button.TextColor3 = Color3.fromRGB(150, 150, 150) -- Dim inactive sorts
- end
- end
- -- Remote for collecting fruit
- local PickupEvent = ReplicatedStorage:WaitForChild("GameEvents"):WaitForChild("Pickup")
- local rowHeight = 50 -- Increased height for better mutation display
- for i, fruitData in ipairs(allFruitsData) do
- -- Create row frame
- local rowFrame = Instance.new("Frame")
- rowFrame.Name = "Row_" .. i
- rowFrame.Size = UDim2.new(1, 0, 0, rowHeight)
- rowFrame.Position = UDim2.new(0, 0, 0, (i-1) * rowHeight)
- rowFrame.BackgroundColor3 = i % 2 == 0 and Color3.fromRGB(40, 40, 40) or Color3.fromRGB(35, 35, 35)
- rowFrame.BackgroundTransparency = 0.3
- rowFrame.Parent = scrollingFrame
- -- Add hover effect
- rowFrame.InputBegan:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseMovement then
- rowFrame.BackgroundTransparency = 0.1
- end
- end)
- rowFrame.InputEnded:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseMovement then
- rowFrame.BackgroundTransparency = 0.3
- end
- end)
- -- Create columns in the row
- local currentX = 0
- local columnValues = {fruitData.name, fruitData.variant, fruitData.weight, fruitData.mutations}
- -- Add collect button
- local collectButton = Instance.new("TextButton")
- collectButton.Name = "CollectButton"
- collectButton.Size = UDim2.new(0, 70, 0, 25)
- collectButton.Position = UDim2.new(1, -75, 0, 12.5) -- Right side of row, centered vertically
- collectButton.BackgroundColor3 = Color3.fromRGB(60, 180, 80) -- Green
- collectButton.Text = "Collect"
- collectButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- collectButton.TextSize = 14
- collectButton.Font = Enum.Font.SourceSansBold
- collectButton.Parent = rowFrame
- -- Add rounded corners to collect button
- local collectCorner = Instance.new("UICorner")
- collectCorner.CornerRadius = UDim.new(0, 4)
- collectCorner.Parent = collectButton
- -- Store the fruit model in the button for reference
- collectButton:SetAttribute("FruitModel", fruitData.model:GetFullName())
- -- Collect button click handler
- collectButton.MouseButton1Click:Connect(function()
- -- Show collecting status
- local originalText = collectButton.Text
- local originalColor = collectButton.BackgroundColor3
- collectButton.Text = "..."
- collectButton.BackgroundColor3 = Color3.fromRGB(150, 150, 150)
- -- Fire the remote to collect the fruit
- local success, error = pcall(function()
- if fruitData.model and fruitData.model:IsA("Model") then
- -- Fire the pickup event to collect the fruit
- PickupEvent:FireServer(fruitData.model)
- task.wait(0.1) -- Small delay
- -- Track whether collection was successful
- local startTime = tick()
- local collected = false
- -- Check if fruit still exists after a brief delay
- task.wait(0.3)
- if not fruitData.model or not fruitData.model.Parent then
- -- Successfully collected
- collectButton.Text = "✓"
- collectButton.BackgroundColor3 = Color3.fromRGB(40, 180, 40)
- addToFruitLog("COLLECTED", fruitData.name, fruitData.variant, fruitData.weight, fruitData.mutations, fruitData.treeName)
- -- Disable the button
- collectButton.AutoButtonColor = false
- collectButton.Active = false
- else
- -- Failed to collect
- collectButton.Text = "Retry"
- collectButton.BackgroundColor3 = Color3.fromRGB(180, 100, 100)
- end
- else
- -- Fruit no longer exists
- collectButton.Text = "Gone"
- collectButton.BackgroundColor3 = Color3.fromRGB(150, 150, 150)
- collectButton.AutoButtonColor = false
- end
- end)
- if not success then
- -- Error occurred
- collectButton.Text = "Error"
- collectButton.BackgroundColor3 = Color3.fromRGB(180, 60, 60)
- print("❌ Failed to collect fruit:", error)
- -- Reset after delay
- task.delay(1.5, function()
- collectButton.Text = originalText
- collectButton.BackgroundColor3 = originalColor
- end)
- end
- end)
- -- Add hover effect to collect button
- collectButton.MouseEnter:Connect(function()
- if collectButton.Active ~= false then
- collectButton.BackgroundColor3 = Color3.fromRGB(80, 200, 100)
- end
- end)
- collectButton.MouseLeave:Connect(function()
- if collectButton.Active ~= false then
- collectButton.BackgroundColor3 = Color3.fromRGB(60, 180, 80)
- end
- end)
- for j, columnValue in ipairs(columnValues) do
- local cell = Instance.new("TextLabel")
- cell.Name = "Column" .. j
- cell.Size = UDim2.new(columnWidths[j], -10, 1, 0)
- cell.Position = UDim2.new(currentX, 5, 0, 0)
- cell.BackgroundTransparency = 1
- cell.Font = Enum.Font.SourceSans
- cell.TextColor3 = Color3.fromRGB(255, 255, 255)
- cell.Text = tostring(columnValue)
- cell.TextXAlignment = Enum.TextXAlignment.Left
- cell.TextWrapped = true
- cell.TextYAlignment = Enum.TextYAlignment.Top
- -- Special handling for mutations column (column 4)
- if j == 4 then
- cell.TextSize = 14 -- Slightly smaller for more text
- cell.Font = Enum.Font.SourceSans
- -- Make sure mutations are fully visible
- if #tostring(columnValue) > 20 then
- cell.TextScaled = false -- Don't scale down, just wrap
- end
- -- Make room for collect button
- cell.Size = UDim2.new(columnWidths[j] - 0.15, -10, 1, 0)
- else
- cell.TextSize = 16
- cell.TextYAlignment = Enum.TextYAlignment.Center
- end
- cell.Parent = rowFrame
- currentX = currentX + columnWidths[j]
- end
- end
- -- Update scrolling frame content size
- scrollingFrame.CanvasSize = UDim2.new(0, 0, 0, #allFruitsData * rowHeight)
- -- Update counter
- titleText.Text = "Farm Fruit List - " .. #allFruitsData .. " Fruits"
- end
- -- Column Headers
- local currentX = 0
- for i, columnName in ipairs(columns) do
- local headerContainer = Instance.new("Frame")
- headerContainer.Name = columnName:gsub(" ", "") .. "HeaderContainer"
- headerContainer.Size = UDim2.new(columnWidths[i], 0, 1, 0)
- headerContainer.Position = UDim2.new(currentX, 0, 0, 0)
- headerContainer.BackgroundTransparency = 1
- headerContainer.Parent = headerFrame
- local columnHeader = Instance.new("TextLabel")
- columnHeader.Name = columnName:gsub(" ", "") .. "Header"
- columnHeader.Size = UDim2.new(1, -25, 1, 0) -- Make room for sort button
- columnHeader.Position = UDim2.new(0, 5, 0, 0)
- columnHeader.BackgroundTransparency = 1
- columnHeader.Font = Enum.Font.SourceSansBold
- columnHeader.TextColor3 = Color3.fromRGB(255, 255, 255)
- columnHeader.TextSize = 18
- columnHeader.Text = columnName
- columnHeader.TextXAlignment = Enum.TextXAlignment.Left
- columnHeader.Parent = headerContainer
- -- Add sort button
- local sortButton = Instance.new("TextButton")
- sortButton.Name = "SortButton"
- sortButton.Size = UDim2.new(0, 20, 0, 20)
- sortButton.Position = UDim2.new(1, -25, 0.5, -10)
- sortButton.BackgroundTransparency = 0.8
- sortButton.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
- sortButton.Text = columnName == currentSortColumn and "▲" or "◆" -- Triangle up for current sort, diamond for others
- sortButton.TextColor3 = columnName == currentSortColumn
- and Color3.fromRGB(255, 255, 100)
- or Color3.fromRGB(150, 150, 150)
- sortButton.TextSize = 14
- sortButton.Font = Enum.Font.SourceSansBold
- sortButton.Parent = headerContainer
- -- Add rounded corners to sort button
- local sortCorner = Instance.new("UICorner")
- sortCorner.CornerRadius = UDim.new(0, 4)
- sortCorner.Parent = sortButton
- -- Store the sort button for later reference
- sortButtons[columnName] = sortButton
- -- Sort button click handler
- sortButton.MouseButton1Click:Connect(function()
- if currentSortColumn == columnName then
- -- Toggle direction if same column
- currentSortDir = currentSortDir == "asc" and "desc" or "asc"
- else
- -- New column, default directions
- currentSortColumn = columnName
- -- Special case: weight should default to descending (high to low)
- if columnName == "Weight (kg)" then
- currentSortDir = "desc"
- else
- -- Variant and mutation have special logic so desc is actually "best first"
- if columnName == "Variant" or columnName == "Mutations" then
- currentSortDir = "desc" -- Rainbow/Multiple mutations first
- else
- currentSortDir = "asc" -- A-Z for regular text
- end
- end
- end
- createSortedFruitList()
- end)
- -- Add hover effect to sort button
- sortButton.MouseEnter:Connect(function()
- sortButton.BackgroundTransparency = 0.5
- end)
- sortButton.MouseLeave:Connect(function()
- sortButton.BackgroundTransparency = 0.8
- end)
- currentX = currentX + columnWidths[i]
- end
- -- Function to refresh the fruit list
- refreshFruitList = function()
- -- Clear all fruit data
- allFruitsData = {}
- -- Get player farm
- local farm = GetFarm(player)
- if not farm or not farm:FindFirstChild("Important") or not farm.Important:FindFirstChild("Plants_Physical") then
- local errorLabel = Instance.new("TextLabel")
- errorLabel.Size = UDim2.new(1, 0, 0, 30)
- errorLabel.Position = UDim2.new(0, 0, 0, 0)
- errorLabel.BackgroundTransparency = 1
- errorLabel.TextColor3 = Color3.fromRGB(255, 100, 100)
- errorLabel.Text = "Farm not found!"
- errorLabel.Font = Enum.Font.SourceSansSemibold
- errorLabel.TextSize = 18
- errorLabel.Parent = scrollingFrame
- return
- end
- local plantsPhysical = farm.Important.Plants_Physical
- -- Loop through all tree types
- for _, treeType in pairs(plantsPhysical:GetChildren()) do
- local fruitsFolder = treeType:FindFirstChild("Fruits")
- if fruitsFolder then
- for _, fruitModel in pairs(fruitsFolder:GetChildren()) do
- if fruitModel:IsA("Model") then
- -- Get fruit attributes and properties
- local fruitName = fruitModel.Name
- -- Get variant (typically stored as a child)
- local variant = fruitModel:FindFirstChild("Variant")
- local variantText = variant and variant.Value or "Normal"
- -- Get weight
- local weight = fruitModel:FindFirstChild("Weight")
- local weightNum = weight and weight.Value or 0
- local weightValue = weight and string.format("%.2f kg", weightNum) or "? kg"
- -- Get mutations from attributes (using MutationHandler if available)
- local mutations = ""
- local success, mutationString = pcall(function()
- return MutationHandler:GetMutationsAsString(fruitModel) or ""
- end)
- if not success or mutationString == "" then
- -- Try checking attributes directly
- local mutationList = {}
- for attrName, value in pairs(fruitModel:GetAttributes()) do
- if value == true and typeof(value) == "boolean" then
- -- Check only known mutation attributes
- if attrName == "Shocked" or
- attrName == "Frozen" or
- attrName == "Wet" or
- attrName == "Chilled" or
- attrName == "Twisted" or
- attrName == "Choc" or
- attrName == "Burnt" or
- attrName == "Moonlit" then
- table.insert(mutationList, attrName)
- end
- end
- end
- if #mutationList > 0 then
- -- Sort mutations for consistent display
- table.sort(mutationList)
- mutations = table.concat(mutationList, " • ") -- Use bullet separator for better readability
- else
- mutations = "None"
- end
- else
- -- Format the mutation string for better readability
- if mutationString ~= "" then
- -- Replace commas with bullet points for better visual separation
- mutations = mutationString:gsub(", ", " • ")
- else
- mutations = "None"
- end
- end
- -- Store fruit data for sorting
- table.insert(allFruitsData, {
- name = fruitName,
- variant = variantText,
- mutations = mutations,
- weight = weightValue,
- weightNum = weightNum, -- Store raw number for sorting
- model = fruitModel,
- treeName = treeType.Name
- })
- end
- end
- end
- end
- -- Display sorted fruit list
- createSortedFruitList()
- end
- -- Connect the refresh button
- refreshButton.MouseButton1Click:Connect(refreshFruitList)
- -- Handle refresh on unhide
- minimizeButton.MouseButton1Click:Connect(function()
- if isMinimized then
- -- Will refresh data when un-minimizing
- task.delay(0.1, function()
- refreshFruitList()
- end)
- end
- end)
- -- ✅ FRUIT LOG FUNCTIONS
- local function addToFruitLog(action, fruitName, variant, weight, mutations, treeName)
- local timestamp = os.date("%H:%M:%S")
- local logEntry = {
- time = timestamp,
- action = action, -- "SPAWNED" or "DELETED"
- fruit = fruitName or "Unknown",
- variant = variant or "Normal",
- weight = weight or "Unknown",
- mutations = mutations or "None",
- tree = treeName or "Unknown"
- }
- table.insert(fruitLog, 1, logEntry) -- Add to beginning
- -- Keep only last entries
- if #fruitLog > maxLogEntries then
- table.remove(fruitLog, maxLogEntries + 1)
- end
- local actionEmoji = action == "SPAWNED" and "🌟" or "🗑️"
- local mutText = mutations ~= "None" and " (" .. mutations .. ")" or ""
- print(string.format("%s [%s] %s: %s - %s %s%s on %s", actionEmoji, timestamp, action, fruitName, weight, variant, mutText, treeName))
- -- Update log GUI if exists
- if logGui then
- updateFruitLogDisplay()
- end
- end
- -- ✅ MONITOR FRUIT CHANGES
- local function checkFruitChanges()
- local currentFruits = {}
- -- Get current fruits on farm
- local farm = GetFarm(player)
- if farm and farm:FindFirstChild("Important") and farm.Important:FindFirstChild("Plants_Physical") then
- local plantsPhysical = farm.Important.Plants_Physical
- -- Loop through all tree types
- for _, treeType in pairs(plantsPhysical:GetChildren()) do
- if treeType:IsA("Folder") or treeType:IsA("Model") then
- -- Check for Fruits folder in each tree type
- local fruitsFolder = treeType:FindFirstChild("Fruits")
- if fruitsFolder then
- for _, fruitModel in pairs(fruitsFolder:GetChildren()) do
- if fruitModel:IsA("Model") and fruitModel.Name ~= "Fruits" then
- -- Use a more reliable unique identifier
- local fruitId = treeType.Name .. "_" .. fruitModel.Name .. "_" .. tostring(fruitModel)
- -- Get fruit data
- local fruitName = fruitModel.Name
- local variant = fruitModel:FindFirstChild("Variant")
- local variantText = variant and variant.Value or "Normal"
- local weight = fruitModel:FindFirstChild("Weight")
- local weightValue = weight and string.format("%.2f kg", weight.Value) or "? kg"
- -- Get mutations using same method as main GUI
- local mutations = "None"
- local success, mutationString = pcall(function()
- return MutationHandler:GetMutationsAsString(fruitModel) or ""
- end)
- if success and mutationString ~= "" then
- mutations = mutationString:gsub(", ", " • ")
- else
- -- Check attributes directly
- local mutationList = {}
- for attrName, value in pairs(fruitModel:GetAttributes()) do
- if value == true and typeof(value) == "boolean" then
- if attrName == "Shocked" or attrName == "Frozen" or
- attrName == "Wet" or attrName == "Chilled" or
- attrName == "Twisted" or attrName == "Choc" or
- attrName == "Burnt" or attrName == "Moonlit" then
- table.insert(mutationList, attrName)
- end
- end
- end
- if #mutationList > 0 then
- table.sort(mutationList)
- mutations = table.concat(mutationList, " • ")
- end
- end
- currentFruits[fruitId] = {
- name = fruitName,
- variant = variantText,
- weight = weightValue,
- mutations = mutations,
- tree = treeType.Name
- }
- end
- end
- end
- end
- end
- end
- -- Compare with last known fruits to detect changes
- -- Check for new fruits (spawned)
- for fruitId, fruitData in pairs(currentFruits) do
- if not lastKnownFruits[fruitId] then
- addToFruitLog("SPAWNED", fruitData.name, fruitData.variant, fruitData.weight, fruitData.mutations, fruitData.tree)
- end
- end
- -- Check for deleted fruits
- for fruitId, fruitData in pairs(lastKnownFruits) do
- if not currentFruits[fruitId] then
- addToFruitLog("DELETED", fruitData.name, fruitData.variant, fruitData.weight, fruitData.mutations, fruitData.tree)
- end
- end
- -- Update known fruits
- lastKnownFruits = currentFruits
- end
- -- ✅ FRUIT LOG GUI
- local function createFruitLogGui()
- local playerGui = player:WaitForChild("PlayerGui")
- -- Remove existing log GUI
- if logGui then
- logGui:Destroy()
- end
- local screenGui = Instance.new("ScreenGui")
- screenGui.Name = "FruitLogGui"
- screenGui.ResetOnSpawn = false
- screenGui.Parent = playerGui
- local frame = Instance.new("Frame")
- frame.Size = UDim2.new(0, 600, 0, 400)
- frame.Position = UDim2.new(0.5, -300, 0.5, -200)
- frame.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
- frame.BackgroundTransparency = 0.1
- frame.Parent = screenGui
- frame.Active = true
- -- Add rounded corners
- local frameCorner = Instance.new("UICorner")
- frameCorner.CornerRadius = UDim.new(0, 8)
- frameCorner.Parent = frame
- -- Title bar
- local titleBar = Instance.new("Frame")
- titleBar.Size = UDim2.new(1, 0, 0, 30)
- titleBar.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
- titleBar.BorderSizePixel = 0
- titleBar.Parent = frame
- local titleCorner = Instance.new("UICorner")
- titleCorner.CornerRadius = UDim.new(0, 8)
- titleCorner.Parent = titleBar
- -- Bottom frame for title bar
- local bottomFrame = Instance.new("Frame")
- bottomFrame.Size = UDim2.new(1, 0, 0.5, 0)
- bottomFrame.Position = UDim2.new(0, 0, 0.5, 0)
- bottomFrame.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
- bottomFrame.BorderSizePixel = 0
- bottomFrame.Parent = titleBar
- local titleText = Instance.new("TextLabel")
- titleText.Size = UDim2.new(1, -60, 1, 0)
- titleText.BackgroundTransparency = 1
- titleText.Text = "🍎 Fruit Spawn/Delete Log"
- titleText.Font = Enum.Font.SourceSansBold
- titleText.TextColor3 = Color3.fromRGB(255, 255, 255)
- titleText.TextSize = 18
- titleText.Parent = titleBar
- -- Close button
- local closeButton = Instance.new("TextButton")
- closeButton.Size = UDim2.new(0, 30, 0, 30)
- closeButton.Position = UDim2.new(1, -30, 0, 0)
- closeButton.BackgroundColor3 = Color3.fromRGB(200, 60, 60)
- closeButton.Text = "X"
- closeButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- closeButton.TextSize = 18
- closeButton.Font = Enum.Font.SourceSansBold
- closeButton.Parent = titleBar
- local closeCorner = Instance.new("UICorner")
- closeCorner.CornerRadius = UDim.new(0, 6)
- closeCorner.Parent = closeButton
- closeButton.MouseButton1Click:Connect(function()
- screenGui:Destroy()
- logGui = nil
- end)
- -- Clear button
- local clearButton = Instance.new("TextButton")
- clearButton.Size = UDim2.new(0, 80, 0, 25)
- clearButton.Position = UDim2.new(0, 10, 0, 40)
- clearButton.BackgroundColor3 = Color3.fromRGB(100, 100, 100)
- clearButton.Text = "Clear Log"
- clearButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- clearButton.TextSize = 12
- clearButton.Font = Enum.Font.SourceSans
- clearButton.Parent = frame
- local clearCorner = Instance.new("UICorner")
- clearCorner.CornerRadius = UDim.new(0, 4)
- clearCorner.Parent = clearButton
- clearButton.MouseButton1Click:Connect(function()
- fruitLog = {}
- updateFruitLogDisplay()
- end)
- -- Scroll frame
- local scrollFrame = Instance.new("ScrollingFrame")
- scrollFrame.Name = "LogScrollFrame"
- scrollFrame.Size = UDim2.new(1, -20, 1, -75)
- scrollFrame.Position = UDim2.new(0, 10, 0, 70)
- scrollFrame.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
- scrollFrame.BackgroundTransparency = 0.2
- scrollFrame.ScrollBarThickness = 8
- scrollFrame.Parent = frame
- local scrollCorner = Instance.new("UICorner")
- scrollCorner.CornerRadius = UDim.new(0, 6)
- scrollCorner.Parent = scrollFrame
- logGui = screenGui
- return screenGui
- end
- -- ✅ UPDATE LOG DISPLAY
- function updateFruitLogDisplay()
- if not logGui then return end
- local success, err = pcall(function()
- local scrollFrame = logGui.FruitLogGui.LogScrollFrame
- -- Clear existing entries
- for _, child in ipairs(scrollFrame:GetChildren()) do
- if child:IsA("Frame") then
- child:Destroy()
- end
- end
- -- Update title with count
- local titleLabel = logGui.FruitLogGui.Frame.Frame.TextLabel
- if titleLabel then
- titleLabel.Text = "🍎 Fruit Log (" .. #fruitLog .. " entries)"
- end
- -- Add log entries
- local yOffset = 0
- for i, entry in ipairs(fruitLog) do
- local entryFrame = Instance.new("Frame")
- entryFrame.Size = UDim2.new(1, -10, 0, 30)
- entryFrame.Position = UDim2.new(0, 5, 0, yOffset)
- entryFrame.BackgroundColor3 = entry.action == "SPAWNED"
- and Color3.fromRGB(40, 60, 40)
- or Color3.fromRGB(60, 40, 40)
- entryFrame.BackgroundTransparency = 0.3
- entryFrame.Parent = scrollFrame
- local entryCorner = Instance.new("UICorner")
- entryCorner.CornerRadius = UDim.new(0, 4)
- entryCorner.Parent = entryFrame
- local entryLabel = Instance.new("TextLabel")
- entryLabel.Size = UDim2.new(1, -10, 1, 0)
- entryLabel.Position = UDim2.new(0, 5, 0, 0)
- entryLabel.BackgroundTransparency = 1
- entryLabel.Font = Enum.Font.SourceSans
- entryLabel.TextSize = 11
- entryLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
- entryLabel.TextXAlignment = Enum.TextXAlignment.Left
- entryLabel.TextYAlignment = Enum.TextYAlignment.Center
- entryLabel.TextWrapped = true
- local actionEmoji = entry.action == "SPAWNED" and "🌟" or "🗑️"
- local mutText = entry.mutations ~= "None" and " (" .. entry.mutations .. ")" or ""
- entryLabel.Text = string.format("%s [%s] %s: %s - %s %s%s on %s",
- actionEmoji, entry.time, entry.action, entry.fruit, entry.weight, entry.variant, mutText, entry.tree)
- entryLabel.Parent = entryFrame
- yOffset = yOffset + 35
- end
- scrollFrame.CanvasSize = UDim2.new(0, 0, 0, yOffset)
- -- Auto-scroll to bottom to see latest entries
- scrollFrame.CanvasPosition = Vector2.new(0, math.max(0, yOffset - scrollFrame.AbsoluteSize.Y))
- end)
- if not success then
- print("❌ Error updating fruit log display:", err)
- end
- end
- -- ✅ LOG BUTTON (Position next to refresh button)
- local logButton = Instance.new("TextButton")
- logButton.Name = "LogButton"
- logButton.Size = UDim2.new(0, 80, 0, 25)
- logButton.Position = UDim2.new(0, 115, 0, 3) -- Next to refresh button
- logButton.BackgroundColor3 = Color3.fromRGB(60, 120, 60)
- logButton.Text = "🍎 Log"
- logButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- logButton.TextSize = 14
- logButton.Font = Enum.Font.SourceSansBold
- logButton.Parent = titleBar
- local logCorner = Instance.new("UICorner")
- logCorner.CornerRadius = UDim.new(0, 4)
- logCorner.Parent = logButton
- logButton.MouseButton1Click:Connect(function()
- if not logGui then
- createFruitLogGui()
- updateFruitLogDisplay()
- else
- logGui:Destroy()
- logGui = nil
- end
- end)
- -- ✅ START FRUIT MONITORING
- spawn(function()
- -- Initial setup - populate known fruits to avoid spam on first run
- task.wait(3) -- Wait for GUI to load
- pcall(checkFruitChanges) -- First scan to populate baseline
- print("🍎 Fruit monitoring started!")
- while true do
- task.wait(3) -- Check every 3 seconds
- local success, error = pcall(checkFruitChanges)
- if not success then
- print("❌ Fruit monitoring error:", error)
- end
- end
- end)
- -- Initial refresh
- refreshFruitList()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement