-- Kasumi Hub for Plants vs. Brainrot - FINAL FIX -- Game validation first local PLANTS_VS_BRAINROT_ID = 127742093697776 if game.PlaceId ~= PLANTS_VS_BRAINROT_ID then game:GetService("StarterGui"):SetCore("SendNotification", { Title = "Wrong Game!"; Text = "This script only works in Plants vs. Brainrot"; Duration = 5; }) return end local WindUI = loadstring(game:HttpGet("https://github.com/Footagesus/WindUI/releases/latest/download/main.lua"))() local Players = game:GetService("Players") local Workspace = game:GetService("Workspace") local ReplicatedStorage = game:GetService("ReplicatedStorage") local UserInputService = game:GetService("UserInputService") local TeleportService = game:GetService("TeleportService") local NetworkClient = game:GetService("NetworkClient") local localPlayer = Players.LocalPlayer -- Script Version local SCRIPT_VERSION = "v1.1" -- Configuration system - SEPARATE FOLDER: KasumiHubPVB local CONFIG_FILE = "KasumiHubPVB/PlantsBrainrot_Config.json" local SETTINGS_FILE = "KasumiHubPVB/PlantsBrainrot_Settings.json" local defaultConfig = { selectedSeeds = {}, selectedGears = {}, equipInterval = 20, theme = "Dark", autoBuySeedsEnabled = false, autoBuyGearsEnabled = false, autoEquipEnabled = false, autoBuyAllSeedsEnabled = false, autoBuyAllGearsEnabled = false, antiAFKEnabled = false, autoReconnectEnabled = false } local defaultSettings = { autoLoadConfig = "None", autoLoadEnabled = false } local currentConfig = {} local currentSettings = {} -- Variables local autoBuySeedsEnabled = false local autoBuyGearsEnabled = false local autoEquipEnabled = false local autoBuyAllSeedsEnabled = false local autoBuyAllGearsEnabled = false local antiAFKEnabled = false local autoReconnectEnabled = false local selectedSeeds = {} local selectedGears = {} local equipInterval = 20 local Window = nil -- UNIFIED TIMING SYSTEM local ITEMS_PER_ROUND = 10 local PURCHASE_DELAY = 200 local CYCLE_INTERVAL = 3000 local currentItemIndex = 1 local purchaseCount = 0 local isAlternatingSeed = true -- EXACT GAME REMOTES FROM SIGMA SPY local BuyItemRemote = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("BuyItem") local BuyGearRemote = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("BuyGear") local OpenUIRemote = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("OpenUI") local EquipBestRemote = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("EquipBest") local ItemSellRemote = ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("ItemSell") -- UI References local seedShopUI = localPlayer.PlayerGui.Main.Seeds local gearShopUI = localPlayer.PlayerGui.Main.Gears -- Available items lists local availableSeeds = { "Cactus Seed", "Strawberry Seed", "Pumpkin Seed", "Sunflower Seed", "Dragon Fruit Seed", "Eggplant Seed", "Watermelon Seed", "Grape Seed", "Cocotank Seed", "Carnivorous Plant Seed", "Mr Carrot Seed", "Tomatrio Seed", "Shroombino Seed", "Mango Seed" } local availableGears = { "Water Bucket", "Frost Grenade", "Banana Gun", "Frost Blower", "Carrot Launcher" } -- UI References for keybinds and dropdowns local autoBuyToggleSeeds = nil local autoBuyToggleGears = nil local autoEquipToggle = nil local autoBuyAllSeedsToggle = nil local autoBuyAllGearsToggle = nil local equipIntervalInput = nil local seedDropdown = nil local gearDropdown = nil local themeDropdown = nil local autoLoadDropdown = nil local autoLoadToggle = nil local ConfigNameInput = nil local antiAFKToggle = nil local autoReconnectToggle = nil -- Control flags local canChangeTheme = true local canChangeDropdown = true -- EXTENDED AUTO-RECONNECT SYSTEM (3 MINUTES DURATION) local reconnectAttempts = 0 local MAX_RECONNECT_ATTEMPTS = 30 -- ✅ Increased to 30 attempts local RECONNECT_INTERVAL = 6 -- ✅ 6 seconds between attempts (30 × 6 = 180 seconds = 3 minutes) local lastDisconnectTime = 0 local lastPingTime = tick() local consecutiveTimeouts = 0 local function setupAutoReconnect() print("🌐 Initializing 3-minute auto-reconnect with network monitoring...") -- Method 1: Detect Roblox error prompts pcall(function() local RobloxPromptGui = game:GetService("CoreGui"):FindFirstChild("RobloxPromptGui") if RobloxPromptGui then local promptOverlay = RobloxPromptGui:FindFirstChild("promptOverlay") if promptOverlay then promptOverlay.ChildAdded:Connect(function(child) if child.Name == "ErrorPrompt" and autoReconnectEnabled then task.wait(0.5) local errorMessage = child:FindFirstChild("MessageArea") if errorMessage then local messageText = errorMessage:FindFirstChild("ErrorMessage") if messageText then local text = messageText.Text:lower() if string.find(text, "disconnect") or string.find(text, "connection") or string.find(text, "lost") or string.find(text, "error") or string.find(text, "kicked") or string.find(text, "unable") or string.find(text, "timeout") or string.find(text, "network") or string.find(text, "failed") or string.find(text, "id=17") then reconnectAttempts = reconnectAttempts + 1 if reconnectAttempts <= MAX_RECONNECT_ATTEMPTS then local timeRemaining = (MAX_RECONNECT_ATTEMPTS - reconnectAttempts) * RECONNECT_INTERVAL print(string.format("🔄 Network issue - reconnecting (attempt %d/%d, %ds remaining)", reconnectAttempts, MAX_RECONNECT_ATTEMPTS, timeRemaining)) task.wait(RECONNECT_INTERVAL) local success = pcall(function() TeleportService:TeleportToPlaceInstance(game.PlaceId, game.JobId, localPlayer) end) if not success then pcall(function() TeleportService:Teleport(game.PlaceId, localPlayer) end) end else print("❌ Max reconnect attempts reached (3 minutes elapsed)") WindUI:Notify({ Title = "Auto-Reconnect Failed", Content = string.format("Could not reconnect after 3 minutes (%d attempts)", MAX_RECONNECT_ATTEMPTS), Duration = 5 }) end end end end end end) end end end) -- Method 2: NetworkClient disconnection detection pcall(function() NetworkClient.ChildRemoved:Connect(function() if autoReconnectEnabled then local currentTime = tick() if currentTime - lastDisconnectTime > 5 then lastDisconnectTime = currentTime reconnectAttempts = reconnectAttempts + 1 if reconnectAttempts <= MAX_RECONNECT_ATTEMPTS then local timeRemaining = (MAX_RECONNECT_ATTEMPTS - reconnectAttempts) * RECONNECT_INTERVAL print(string.format("🔄 NetworkClient disconnect (attempt %d/%d, %ds left)", reconnectAttempts, MAX_RECONNECT_ATTEMPTS, timeRemaining)) task.wait(RECONNECT_INTERVAL) pcall(function() TeleportService:Teleport(game.PlaceId, localPlayer) end) end end end end) end) -- Method 3: Active ping monitoring (checks every 8 seconds) task.spawn(function() while true do task.wait(8) if autoReconnectEnabled then local pingStart = tick() local pingSuccess = pcall(function() local test = game:GetService("Players"):GetPlayers() return test ~= nil end) local pingTime = tick() - pingStart if not pingSuccess or pingTime > 4 then consecutiveTimeouts = consecutiveTimeouts + 1 print(string.format("⚠️ Poor connection detected (timeout %d/4)", consecutiveTimeouts)) if consecutiveTimeouts >= 4 then print("🔴 Connection lost - poor network quality") reconnectAttempts = reconnectAttempts + 1 if reconnectAttempts <= MAX_RECONNECT_ATTEMPTS then local timeRemaining = (MAX_RECONNECT_ATTEMPTS - reconnectAttempts) * RECONNECT_INTERVAL print(string.format("🔄 Reconnecting (attempt %d/%d, %ds remaining)", reconnectAttempts, MAX_RECONNECT_ATTEMPTS, timeRemaining)) task.wait(RECONNECT_INTERVAL) pcall(function() TeleportService:Teleport(game.PlaceId, localPlayer) end) end consecutiveTimeouts = 0 end else consecutiveTimeouts = 0 end lastPingTime = tick() end end end) -- Method 4: Monitor ReplicatedFirst pcall(function() game:GetService("ReplicatedFirst"):GetPropertyChangedSignal("FinishedReplicating"):Connect(function() if not game:GetService("ReplicatedFirst").FinishedReplicating and autoReconnectEnabled then print("🔄 Replication interrupted") reconnectAttempts = reconnectAttempts + 1 if reconnectAttempts <= MAX_RECONNECT_ATTEMPTS then task.wait(RECONNECT_INTERVAL) pcall(function() TeleportService:Teleport(game.PlaceId, localPlayer) end) end end end) end) -- Method 5: GuiService error monitoring pcall(function() local GuiService = game:GetService("GuiService") GuiService.ErrorMessageChanged:Connect(function() if autoReconnectEnabled then local errorMessage = GuiService:GetErrorMessage() if errorMessage and errorMessage ~= "" then print("🔴 GuiService error:", errorMessage) reconnectAttempts = reconnectAttempts + 1 if reconnectAttempts <= MAX_RECONNECT_ATTEMPTS then task.wait(RECONNECT_INTERVAL) pcall(function() TeleportService:Teleport(game.PlaceId, localPlayer) end) end end end end) end) -- Method 6: Heartbeat freeze detection (15 seconds threshold) local lastHeartbeat = tick() pcall(function() game:GetService("RunService").Heartbeat:Connect(function() if autoReconnectEnabled then local currentTime = tick() local timeSinceLastBeat = currentTime - lastHeartbeat if timeSinceLastBeat > 15 then print("🔴 Connection frozen - no heartbeat for " .. math.floor(timeSinceLastBeat) .. " seconds") reconnectAttempts = reconnectAttempts + 1 if reconnectAttempts <= MAX_RECONNECT_ATTEMPTS then task.wait(RECONNECT_INTERVAL) pcall(function() TeleportService:Teleport(game.PlaceId, localPlayer) end) end end lastHeartbeat = currentTime end end) end) print("✅ 3-minute auto-reconnect initialized (30 attempts × 6 seconds)") end -- ANTI-AFK SYSTEM local idledConnection = nil local antiAFKLoop = nil local function startAntiAFK() local VirtualUser = game:GetService("VirtualUser") if not idledConnection then idledConnection = localPlayer.Idled:Connect(function() if antiAFKEnabled then VirtualUser:CaptureController() VirtualUser:ClickButton2(Vector2.new()) print("🛡️ Anti-AFK: Prevented idle kick") end end) end if not antiAFKLoop then antiAFKLoop = task.spawn(function() while true do if antiAFKEnabled then VirtualUser:CaptureController() VirtualUser:Button1Down(Vector2.new(0, 0)) task.wait(0.1) VirtualUser:Button1Up(Vector2.new(0, 0)) print("🛡️ Anti-AFK: Activity simulated") end task.wait(600) end end) end end -- KEYBIND SYSTEM local function setupKeybinds() UserInputService.InputBegan:Connect(function(input, gameProcessed) if gameProcessed then return end local isCtrlPressed = UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or UserInputService:IsKeyDown(Enum.KeyCode.RightControl) if isCtrlPressed then if input.KeyCode == Enum.KeyCode.B then autoBuySeedsEnabled = not autoBuySeedsEnabled if autoBuyToggleSeeds then pcall(function() autoBuyToggleSeeds.Value = autoBuySeedsEnabled if autoBuyToggleSeeds.Callback then autoBuyToggleSeeds.Callback(autoBuySeedsEnabled) end end) end WindUI:Notify({ Title = "Auto Buy Seeds " .. (autoBuySeedsEnabled and "Started" or "Stopped") .. " [Ctrl+B]", Content = autoBuySeedsEnabled and string.format("Now purchasing %d selected seeds automatically", #selectedSeeds) or "Seed purchasing stopped", Duration = 3 }) elseif input.KeyCode == Enum.KeyCode.N then autoBuyGearsEnabled = not autoBuyGearsEnabled if autoBuyToggleGears then pcall(function() autoBuyToggleGears.Value = autoBuyGearsEnabled if autoBuyToggleGears.Callback then autoBuyToggleGears.Callback(autoBuyGearsEnabled) end end) end WindUI:Notify({ Title = "Auto Buy Gears " .. (autoBuyGearsEnabled and "Started" or "Stopped") .. " [Ctrl+N]", Content = autoBuyGearsEnabled and string.format("Now purchasing %d selected gears automatically", #selectedGears) or "Gear purchasing stopped", Duration = 3 }) elseif input.KeyCode == Enum.KeyCode.E then autoEquipEnabled = not autoEquipEnabled if autoEquipToggle then pcall(function() autoEquipToggle.Value = autoEquipEnabled if autoEquipToggle.Callback then autoEquipToggle.Callback(autoEquipEnabled) end end) end if autoEquipEnabled then startEquipLoop() end WindUI:Notify({ Title = "Auto Equip " .. (autoEquipEnabled and "Started" or "Stopped") .. " [Ctrl+E]", Content = autoEquipEnabled and string.format("Now auto-equipping best brainrot every %d seconds", equipInterval) or "Auto equip stopped", Duration = 3 }) end end end) end -- BUYING FUNCTIONS local function buySeed(seedName) if not BuyItemRemote then return false end return pcall(function() BuyItemRemote:FireServer(seedName) end) end local function buyGear(gearName) if not BuyGearRemote then return false end return pcall(function() BuyGearRemote:FireServer(gearName) end) end -- SELLING FUNCTIONS local function sellAllBrainrots() if not ItemSellRemote then return false end return pcall(function() ItemSellRemote:FireServer() end) end local function sellAllPlants() if not ItemSellRemote then return false end return pcall(function() ItemSellRemote:FireServer(unpack({[2] = true}, 1, table.maxn({[2] = true}))) end) end -- SHOP OPENING FUNCTIONS local function openSeedShop() if not OpenUIRemote or not seedShopUI then return false end return pcall(function() OpenUIRemote:Fire(seedShopUI, true) end) end local function openGearShop() if not OpenUIRemote or not gearShopUI then return false end return pcall(function() OpenUIRemote:Fire(gearShopUI, true) end) end -- EQUIP BEST FUNCTION local function equipBest() if not EquipBestRemote then return false end return pcall(function() EquipBestRemote:Fire() end) end local function startEquipLoop() task.spawn(function() while autoEquipEnabled do equipBest() task.wait(equipInterval) end end) end -- Apply equip interval function local function applyEquipInterval() if equipIntervalInput then local value = "" if equipIntervalInput.Get then value = equipIntervalInput:Get() elseif equipIntervalInput.Value then value = equipIntervalInput.Value else value = "20" end local num = tonumber(value) if num and num > 0 then equipInterval = num WindUI:Notify({ Title = "Equip Interval Updated", Content = "Auto-equip now runs every " .. num .. " seconds", Duration = 2 }) return true else WindUI:Notify({ Title = "Invalid Number", Content = "Please enter a valid positive number for the interval", Duration = 3 }) end end return false end -- SETTINGS MANAGEMENT local function saveSettings() local settings = { autoLoadConfig = currentSettings.autoLoadConfig or defaultSettings.autoLoadConfig, autoLoadEnabled = currentSettings.autoLoadEnabled or defaultSettings.autoLoadEnabled } if not isfolder("KasumiHubPVB") then makefolder("KasumiHubPVB") end local success = pcall(function() writefile(SETTINGS_FILE, game:GetService("HttpService"):JSONEncode(settings)) end) return success end local function loadSettings() local success, result = pcall(function() if isfile(SETTINGS_FILE) then local data = readfile(SETTINGS_FILE) return game:GetService("HttpService"):JSONDecode(data) end return nil end) if success and result then currentSettings = result else currentSettings = table.clone(defaultSettings) saveSettings() end return currentSettings end -- Get available config files local function getAvailableConfigs() local configs = {"None"} pcall(function() if isfolder("KasumiHubPVB") then local files = listfiles("KasumiHubPVB") for _, file in pairs(files) do if file:match("%.json$") and not file:match("Settings") then local fileName = file:match("KasumiHubPVB/(.+)%.json$") or file:match("([^/\\]+)%.json$") if fileName and fileName ~= "PlantsBrainrot_Settings" then if not table.find(configs, fileName) then table.insert(configs, fileName) end end end end end end) return configs end -- Save config function (saves all toggles) local function saveConfig(customName) if not isfolder("KasumiHubPVB") then makefolder("KasumiHubPVB") end local fileName = customName and ("KasumiHubPVB/" .. customName .. ".json") or CONFIG_FILE local equipInt = equipInterval if equipIntervalInput then local equipValue = "" if equipIntervalInput.Get then equipValue = equipIntervalInput:Get() elseif equipIntervalInput.Value then equipValue = equipIntervalInput.Value end equipInt = tonumber(equipValue) or 20 end currentConfig = { selectedSeeds = selectedSeeds, selectedGears = selectedGears, equipInterval = equipInt, theme = WindUI:GetCurrentTheme() or "Dark", autoBuySeedsEnabled = autoBuySeedsEnabled, autoBuyGearsEnabled = autoBuyGearsEnabled, autoEquipEnabled = autoEquipEnabled, autoBuyAllSeedsEnabled = autoBuyAllSeedsEnabled, autoBuyAllGearsEnabled = autoBuyAllGearsEnabled, antiAFKEnabled = antiAFKEnabled, autoReconnectEnabled = autoReconnectEnabled } local success = pcall(function() writefile(fileName, game:GetService("HttpService"):JSONEncode(currentConfig)) end) if success then print("✅ Config saved to:", fileName) WindUI:Notify({ Title = "Settings Saved", Content = "Your preferences have been saved as: " .. (customName or "PlantsBrainrot_Config"), Duration = 3 }) else WindUI:Notify({ Title = "Save Failed", Content = "Could not save your settings. Please try again.", Duration = 3 }) end return success end -- Dropdown update functions local function updateSeedDropdownProperly() if seedDropdown then task.spawn(function() task.wait(0.3) pcall(function() if seedDropdown.Set then seedDropdown:Set(selectedSeeds) end if seedDropdown.Value ~= nil then seedDropdown.Value = selectedSeeds end if Window and Window.Flags and Window.Flags.SeedSelection ~= nil then Window.Flags.SeedSelection = selectedSeeds end task.wait(0.1) if seedDropdown.Refresh then seedDropdown:Refresh(availableSeeds, selectedSeeds) end end) end) end end local function updateGearDropdownProperly() if gearDropdown then task.spawn(function() task.wait(0.3) pcall(function() if gearDropdown.Set then gearDropdown:Set(selectedGears) end if gearDropdown.Value ~= nil then gearDropdown.Value = selectedGears end if Window and Window.Flags and Window.Flags.GearSelection ~= nil then Window.Flags.GearSelection = selectedGears end task.wait(0.1) if gearDropdown.Refresh then gearDropdown:Refresh(availableGears, selectedGears) end end) end) end end local function updateAllUI() task.spawn(function() task.wait(0.3) updateSeedDropdownProperly() updateGearDropdownProperly() if equipIntervalInput and equipIntervalInput.Set then pcall(function() equipIntervalInput:Set(tostring(equipInterval)) end) end if currentConfig.theme then pcall(function() WindUI:SetTheme(currentConfig.theme) if themeDropdown and themeDropdown.Set then themeDropdown:Set(currentConfig.theme) end end) end end) end local function resetToDefault() selectedSeeds = {} selectedGears = {} equipInterval = defaultConfig.equipInterval task.spawn(function() task.wait(0.2) updateSeedDropdownProperly() updateGearDropdownProperly() updateAllUI() end) WindUI:Notify({ Title = "Settings Reset", Content = "All preferences have been reset to their default values", Duration = 3 }) end -- ✅ CRITICAL FIX: Load settings AND config BEFORE creating UI loadSettings() -- If autoload is enabled, load the config NOW (before UI creation) if currentSettings.autoLoadEnabled and currentSettings.autoLoadConfig ~= "None" then local configName = currentSettings.autoLoadConfig local filesToTry = { "KasumiHubPVB/" .. configName .. ".json", configName .. ".json" } for _, file in pairs(filesToTry) do if file and isfile(file) then local success, result = pcall(function() local data = readfile(file) return game:GetService("HttpService"):JSONDecode(data) end) if success and result then currentConfig = result selectedSeeds = currentConfig.selectedSeeds or {} selectedGears = currentConfig.selectedGears or {} equipInterval = currentConfig.equipInterval or 20 autoBuySeedsEnabled = currentConfig.autoBuySeedsEnabled or false autoBuyGearsEnabled = currentConfig.autoBuyGearsEnabled or false autoEquipEnabled = currentConfig.autoEquipEnabled or false autoBuyAllSeedsEnabled = currentConfig.autoBuyAllSeedsEnabled or false autoBuyAllGearsEnabled = currentConfig.autoBuyAllGearsEnabled or false antiAFKEnabled = currentConfig.antiAFKEnabled or false autoReconnectEnabled = currentConfig.autoReconnectEnabled or false -- Start systems immediately if antiAFKEnabled then startAntiAFK() end if autoReconnectEnabled then setupAutoReconnect() end if autoEquipEnabled then startEquipLoop() end print("✅ Pre-loaded config before UI:", configName) break end end end end -- Set theme to default WindUI:SetTheme(currentConfig.theme or defaultConfig.theme) Window = WindUI:CreateWindow({ Title = "Kasumi Hub", Icon = "zap", Author = "@kasumichwan", Folder = "KasumiHubPVB", Size = UDim2.fromOffset(580, 490), Theme = currentConfig.theme or defaultConfig.theme, SideBarWidth = 180, }) Window:SetToggleKey(Enum.KeyCode.G) Window:Tag({ Title = SCRIPT_VERSION .. " ", Color = Color3.fromHex("#00ff88") }) Window:CreateTopbarButton("theme-switcher", "moon", function() local newTheme = WindUI:GetCurrentTheme() == "Dark" and "Light" or "Dark" WindUI:SetTheme(newTheme) if canChangeTheme and themeDropdown then themeDropdown:Set(newTheme) end WindUI:Notify({ Title = "Theme Changed", Content = "Interface theme changed to: " .. newTheme, Duration = 2 }) end, 990) Window:EditOpenButton({ Title = "Open Kasumi Hub", Icon = "zap", CornerRadius = UDim.new(0,12), StrokeThickness = 2, Color = ColorSequence.new( Color3.fromHex("FF0F7B"), Color3.fromHex("F89B29") ), OnlyMobile = true, Enabled = true, Draggable = true, }) -- Create tabs local InformationTab = Window:Tab({ Title = "Information", Icon = "info", Locked = false }) local AutoBuyTab = Window:Tab({ Title = "Auto Buy", Icon = "shopping-cart", Locked = false }) local SellTab = Window:Tab({ Title = "Sell", Icon = "dollar-sign", Locked = false }) local AutoEquipTab = Window:Tab({ Title = "Auto Equip", Icon = "zap", Locked = false }) local SettingsTab = Window:Tab({ Title = "Settings", Icon = "settings", Locked = false }) Window:SelectTab(1) -- Information Tab InformationTab:Paragraph({ Title = "Kasumi Hub for Plants vs. Brainrot", Desc = [[Key will auto load and work forever until I changed it so if it ask for key it means I changed it but you can get the key always. FEATURES: • Auto buy seeds • Auto buy gears • Sell all brainrot and Plants (Favorite not included) • Auto equip your best brainrot and auto collects all money • Anti-AFK protection (NEW) • Auto-reconnect on disconnect (NEW) • Save and load config • Auto-load your preferred setup on startup • Multiple theme options for personalization CONTROLS: • G = Show/Hide Interface • Ctrl + B = Toggle Seed Auto-Buy • Ctrl + N = Toggle Gear Auto-Buy • Ctrl + E = Toggle Auto Equipment + Auto Collect Money CHANGELOGS: v1.1 • Added Anti-AFK system • Added Auto-reconnect feature • Improved config save/load Made for you with love <3]] }) -- Auto Buy Tab AutoBuyTab:Button({ Title = "Open Seed Shop", Icon = "plant", Variant = "Primary", Callback = function() local success = openSeedShop() WindUI:Notify({ Title = success and "Seed Shop Opened" or "Shop Access Failed", Content = success and "You can now browse and purchase seeds" or "Unable to access the seed shop", Duration = 3 }) end }) AutoBuyTab:Button({ Title = "Open Gear Shop", Icon = "wrench", Variant = "Secondary", Callback = function() local success = openGearShop() WindUI:Notify({ Title = success and "Gear Shop Opened" or "Shop Access Failed", Content = success and "You can now browse and purchase gears" or "Unable to access the gear shop", Duration = 3 }) end }) AutoBuyTab:Divider() seedDropdown = AutoBuyTab:Dropdown({ Title = "Select Seeds", Values = availableSeeds, Value = selectedSeeds, SearchBarEnabled = true, MenuWidth = 400, Multi = true, Flag = "SeedSelection", Callback = function(value) selectedSeeds = value end }) -- ✅ FIXED: Use loaded config value as initial state autoBuyToggleSeeds = AutoBuyTab:Toggle({ Title = "Enable Auto Buy Seeds", Desc = "Automatically buy your selected seeds (Use Ctrl+B to toggle quickly)", Value = autoBuySeedsEnabled, -- ← FIXED: Now uses loaded value Callback = function(enabled) autoBuySeedsEnabled = enabled if enabled then WindUI:Notify({ Title = "Seed Auto Buy Started", Content = string.format("Now automatically purchasing %d seed types", #selectedSeeds), Duration = 3 }) else WindUI:Notify({ Title = "Seed Auto Buy Stopped", Content = "Automatic seed purchasing has been disabled", Duration = 2 }) end end }) autoBuyAllSeedsToggle = AutoBuyTab:Toggle({ Title = "Auto Buy All Seeds", Desc = "Purchase all 14 available seed types automatically", Value = autoBuyAllSeedsEnabled, -- ← FIXED Callback = function(enabled) autoBuyAllSeedsEnabled = enabled if enabled then WindUI:Notify({ Title = "Buying All Seeds", Content = string.format("Now purchasing all %d seed types automatically", #availableSeeds), Duration = 3 }) else WindUI:Notify({ Title = "Stopped Buying All Seeds", Content = "Switched back to your selected seeds only", Duration = 2 }) end end }) AutoBuyTab:Divider() gearDropdown = AutoBuyTab:Dropdown({ Title = "Select Gears", Values = availableGears, Value = selectedGears, SearchBarEnabled = true, MenuWidth = 400, Multi = true, Flag = "GearSelection", Callback = function(value) selectedGears = value end }) autoBuyToggleGears = AutoBuyTab:Toggle({ Title = "Enable Auto Buy Gears", Desc = "Automatically buy your selected gears (Use Ctrl+N to toggle quickly)", Value = autoBuyGearsEnabled, -- ← FIXED Callback = function(enabled) autoBuyGearsEnabled = enabled if enabled then WindUI:Notify({ Title = "Gear Auto Buy Started", Content = string.format("Now automatically purchasing %d gear types", #selectedGears), Duration = 3 }) else WindUI:Notify({ Title = "Gear Auto Buy Stopped", Content = "Automatic gear purchasing has been disabled", Duration = 2 }) end end }) autoBuyAllGearsToggle = AutoBuyTab:Toggle({ Title = "Auto Buy All Gears", Desc = "Purchase all 5 available gear types automatically", Value = autoBuyAllGearsEnabled, -- ← FIXED Callback = function(enabled) autoBuyAllGearsEnabled = enabled if enabled then WindUI:Notify({ Title = "Buying ALL Gears", Content = string.format("Now purchasing all %d gear types automatically", #availableGears), Duration = 3 }) else WindUI:Notify({ Title = "Stopped Buying All Gears", Content = "Switched back to your selected gears only", Duration = 2 }) end end }) -- Sell Tab SellTab:Paragraph({ Title = "Note:", Desc = "Your favorited brainrots are not included when you sell all.", Image = "dollar-sign", ImageSize = 20, Color = "White" }) SellTab:Button({ Title = "Sell All Brainrots", Icon = "brain-circuit", Variant = "Primary", Callback = function() local success = sellAllBrainrots() WindUI:Notify({ Title = success and "Brainrots Sold" or "Sale Failed", Content = success and "All brainrots in your inventory have been sold" or "Unable to sell brainrots right now", Duration = 3 }) end }) SellTab:Button({ Title = "Sell All Plants", Icon = "leaf", Variant = "Secondary", Callback = function() local success = sellAllPlants() WindUI:Notify({ Title = success and "Plants Sold" or "Sale Failed", Content = success and "All plants in your inventory have been sold" or "Unable to sell plants right now", Duration = 3 }) end }) SellTab:Button({ Title = "Sell Everything", Icon = "trash-2", Variant = "Destructive", Callback = function() local brainrotSuccess = sellAllBrainrots() task.wait(0.5) local plantSuccess = sellAllPlants() local bothSuccess = brainrotSuccess and plantSuccess WindUI:Notify({ Title = bothSuccess and "Everything Sold" or "Partial Sale", Content = bothSuccess and "Your entire inventory has been cleared" or "Some items couldn't be sold", Duration = 3 }) end }) -- Auto Equip Tab AutoEquipTab:Paragraph({ Title = "Auto Equip Brainrots + Collect All Money", Desc = "Useful when you need to collect all money from your brainrots", Image = "zap", ImageSize = 20, Color = "White" }) equipIntervalInput = AutoEquipTab:Input({ Title = "Auto Equip Interval (seconds)", Desc = "How often to automatically equip your best brainrots (default: 20 seconds)", Value = tostring(equipInterval) }) AutoEquipTab:Button({ Title = "Apply Interval", Icon = "clock", Variant = "Secondary", Callback = function() applyEquipInterval() end }) autoEquipToggle = AutoEquipTab:Toggle({ Title = "Enable Auto Equip + Collect All Money", Desc = "Automatically equip your best brainrot and collects all money from your brainrots (Use Ctrl+E to toggle quickly)", Value = autoEquipEnabled, -- ← FIXED Callback = function(enabled) autoEquipEnabled = enabled if enabled then startEquipLoop() WindUI:Notify({ Title = "Auto Equipment Started", Content = string.format("Now auto-equipping best brainrot every %d seconds", equipInterval), Duration = 3 }) else WindUI:Notify({ Title = "Auto Equipment Stopped", Content = "Automatic equipment has been disabled", Duration = 2 }) end end }) AutoEquipTab:Button({ Title = "Equip Best Brainrots", Icon = "zap", Variant = "Primary", Callback = function() local success = equipBest() WindUI:Notify({ Title = success and "Equip Success" or "Equip Failed", Content = success and "Your best brainrots has been equipped" or "Unable to update equipment right now", Duration = 3 }) end }) -- Settings Tab SettingsTab:Paragraph({ Title = "Personalization & Data Management", Desc = "Customize your interface and manage your saved configurations for quick setup across sessions.", Image = "palette", ImageSize = 20, Color = "White" }) local themes = {} for themeName, _ in pairs(WindUI:GetThemes()) do table.insert(themes, themeName) end table.sort(themes) themeDropdown = SettingsTab:Dropdown({ Title = "Interface Theme", Values = themes, SearchBarEnabled = true, MenuWidth = 280, Value = WindUI:GetCurrentTheme(), Callback = function(theme) canChangeDropdown = false WindUI:SetTheme(theme) WindUI:Notify({ Title = "Theme Applied", Content = "Interface changed to " .. theme .. " theme", Icon = "palette", Duration = 2 }) canChangeDropdown = true end }) SettingsTab:Divider() SettingsTab:Paragraph({ Title = "Connection & Activity", Desc = "Manage anti-AFK and auto-reconnect features for uninterrupted gameplay.", Image = "wifi", ImageSize = 20, Color = "White" }) autoReconnectToggle = SettingsTab:Toggle({ Title = "Enable Auto-Reconnect", Desc = "Automatically rejoin the game if disconnected due to network issues", Value = autoReconnectEnabled, -- ← FIXED Callback = function(enabled) autoReconnectEnabled = enabled reconnectAttempts = 0 if enabled then setupAutoReconnect() WindUI:Notify({ Title = "Auto-Reconnect Enabled", Content = string.format("Will attempt to reconnect up to %d times if disconnected", MAX_RECONNECT_ATTEMPTS), Duration = 3 }) else WindUI:Notify({ Title = "Auto-Reconnect Disabled", Content = "Manual reconnection required if disconnected", Duration = 2 }) end end }) antiAFKToggle = SettingsTab:Toggle({ Title = "Enable Anti-AFK Protection", Desc = "Prevents Roblox from kicking you for inactivity", Value = antiAFKEnabled, -- ← FIXED Callback = function(enabled) antiAFKEnabled = enabled if enabled then startAntiAFK() WindUI:Notify({ Title = "Anti-AFK Enabled", Content = "You will no longer be kicked for inactivity", Duration = 3 }) else WindUI:Notify({ Title = "Anti-AFK Disabled", Content = "Inactivity kick protection has been turned off", Duration = 2 }) end end }) SettingsTab:Divider() SettingsTab:Paragraph({ Title = "Startup Configuration", Desc = "Choose a saved configuration to automatically load when you start the script.", Image = "settings-2", ImageSize = 20, Color = "White" }) autoLoadToggle = SettingsTab:Toggle({ Title = "Enable Auto-Load", Desc = "Automatically load your chosen configuration when the script starts", Value = currentSettings.autoLoadEnabled or false, Callback = function(state) currentSettings.autoLoadEnabled = state saveSettings() WindUI:Notify({ Title = "Auto-Load " .. (state and "Enabled" or "Disabled"), Content = "Startup configuration " .. (state and "will now load automatically" or "disabled"), Duration = 2 }) end }) local availableConfigs = getAvailableConfigs() autoLoadDropdown = SettingsTab:Dropdown({ Title = "Startup Configuration", Values = availableConfigs, Value = currentSettings.autoLoadConfig or "None", SearchBarEnabled = true, MenuWidth = 280, Callback = function(config) currentSettings.autoLoadConfig = config saveSettings() WindUI:Notify({ Title = "Startup Config Set", Content = "Will auto-load: " .. config, Duration = 2 }) end }) SettingsTab:Button({ Title = "Refresh Configuration List", Icon = "refresh-cw", Callback = function() local newConfigs = getAvailableConfigs() if autoLoadDropdown and autoLoadDropdown.Refresh then autoLoadDropdown:Refresh(newConfigs) end WindUI:Notify({ Title = "List Updated", Content = "Found " .. math.max(0, #newConfigs - 1) .. " saved configurations", Duration = 2 }) end }) SettingsTab:Divider() SettingsTab:Paragraph({ Title = "Save & Load Configurations", Desc = "Save your current preferences or load previously saved configurations for quick setup.", Image = "save", ImageSize = 20, Color = "White" }) local configName = "kasumi-hub-pvb" ConfigNameInput = SettingsTab:Input({ Title = "Configuration Name", Value = configName, Callback = function(value) configName = value or "kasumi-hub-pvb" end }) SettingsTab:Button({ Title = "Save Current Settings", Icon = "save", Variant = "Primary", Callback = function() local name = configName if ConfigNameInput and ConfigNameInput.Get then name = ConfigNameInput:Get() or configName end saveConfig(name) end }) SettingsTab:Button({ Title = "Load Saved Settings", Icon = "folder-open", Variant = "Secondary", Callback = function() local name = configName if ConfigNameInput and ConfigNameInput.Get then name = ConfigNameInput:Get() or configName end local filesToTry = {"KasumiHubPVB/" .. name .. ".json", name .. ".json"} local loaded = false for _, file in pairs(filesToTry) do if file and isfile(file) then local success, result = pcall(function() return game:GetService("HttpService"):JSONDecode(readfile(file)) end) if success and result then currentConfig = result selectedSeeds = result.selectedSeeds or {} selectedGears = result.selectedGears or {} equipInterval = result.equipInterval or 20 autoBuySeedsEnabled = result.autoBuySeedsEnabled or false autoBuyGearsEnabled = result.autoBuyGearsEnabled or false autoEquipEnabled = result.autoEquipEnabled or false autoBuyAllSeedsEnabled = result.autoBuyAllSeedsEnabled or false autoBuyAllGearsEnabled = result.autoBuyAllGearsEnabled or false antiAFKEnabled = result.antiAFKEnabled or false autoReconnectEnabled = result.autoReconnectEnabled or false -- Start systems if antiAFKEnabled then startAntiAFK() end if autoReconnectEnabled then setupAutoReconnect() end if autoEquipEnabled then startEquipLoop() end -- Update toggles if autoBuyToggleSeeds then autoBuyToggleSeeds.Value = autoBuySeedsEnabled end if autoBuyToggleGears then autoBuyToggleGears.Value = autoBuyGearsEnabled end if autoEquipToggle then autoEquipToggle.Value = autoEquipEnabled end if autoBuyAllSeedsToggle then autoBuyAllSeedsToggle.Value = autoBuyAllSeedsEnabled end if autoBuyAllGearsToggle then autoBuyAllGearsToggle.Value = autoBuyAllGearsEnabled end if antiAFKToggle then antiAFKToggle.Value = antiAFKEnabled end if autoReconnectToggle then autoReconnectToggle.Value = autoReconnectEnabled end updateAllUI() loaded = true WindUI:Notify({ Title = "Settings Loaded", Content = name .. " loaded - Seeds: " .. #selectedSeeds .. ", Gears: " .. #selectedGears, Duration = 3 }) break end end end if not loaded then WindUI:Notify({ Title = "Load Failed", Content = "Could not find: " .. name, Duration = 3 }) end end }) SettingsTab:Button({ Title = "Reset All Settings", Icon = "rotate-ccw", Variant = "Destructive", Callback = function() resetToDefault() end }) -- Initialize keybinds setupKeybinds() -- UNIFIED AUTO-BUY LOOP task.spawn(function() while true do local shouldBuySeeds = (autoBuySeedsEnabled and #selectedSeeds > 0) or autoBuyAllSeedsEnabled local shouldBuyGears = (autoBuyGearsEnabled and #selectedGears > 0) or autoBuyAllGearsEnabled if shouldBuySeeds or shouldBuyGears then local purchased = false if shouldBuySeeds and shouldBuyGears then if isAlternatingSeed then local seedList = autoBuyAllSeedsEnabled and availableSeeds or selectedSeeds if #seedList > 0 then local seedIndex = ((currentItemIndex - 1) % #seedList) + 1 local seedName = seedList[seedIndex] local success = buySeed(seedName) if success then purchased = true end end isAlternatingSeed = false else local gearList = autoBuyAllGearsEnabled and availableGears or selectedGears if #gearList > 0 then local gearIndex = ((currentItemIndex - 1) % #gearList) + 1 local gearName = gearList[gearIndex] local success = buyGear(gearName) if success then purchased = true end end isAlternatingSeed = true end elseif shouldBuySeeds then local seedList = autoBuyAllSeedsEnabled and availableSeeds or selectedSeeds if #seedList > 0 then local seedIndex = ((currentItemIndex - 1) % #seedList) + 1 local seedName = seedList[seedIndex] local success = buySeed(seedName) if success then purchased = true end end elseif shouldBuyGears then local gearList = autoBuyAllGearsEnabled and availableGears or selectedGears if #gearList > 0 then local gearIndex = ((currentItemIndex - 1) % #gearList) + 1 local gearName = gearList[gearIndex] local success = buyGear(gearName) if success then purchased = true end end end if purchased then purchaseCount = purchaseCount + 1 if purchaseCount >= ITEMS_PER_ROUND then purchaseCount = 0 currentItemIndex = currentItemIndex + 1 local totalItems = 0 if shouldBuySeeds and shouldBuyGears then totalItems = math.max( autoBuyAllSeedsEnabled and #availableSeeds or #selectedSeeds, autoBuyAllGearsEnabled and #availableGears or #selectedGears ) elseif shouldBuySeeds then totalItems = autoBuyAllSeedsEnabled and #availableSeeds or #selectedSeeds elseif shouldBuyGears then totalItems = autoBuyAllGearsEnabled and #availableGears or #selectedGears end if currentItemIndex > totalItems then currentItemIndex = 1 task.wait(CYCLE_INTERVAL / 1000) end end end task.wait(PURCHASE_DELAY / 1000) else task.wait(2) end end end) -- Startup notification task.spawn(function() task.wait(1) WindUI:Notify({ Title = "Kasumi Hub " .. SCRIPT_VERSION .. " Ready", Content = string.format("Welcome! %s\nSeeds: %d | Gears: %d | Interval: %ds\n\nPress G to toggle interface", currentSettings.autoLoadEnabled and currentSettings.autoLoadConfig ~= "None" and ("Auto-loaded: " .. currentSettings.autoLoadConfig) or "Enjoy using my scripts!", #selectedSeeds, #selectedGears, equipInterval), Duration = 8 }) end) task.spawn(function() while task.wait(0.1) do end end)