-- [[ Rscripts Risk Notice ]] -- This script is not verified by rscripts.net. Deal with caution. -- -- Stay safe: -- • Never log in on unofficial Roblox sites or lookalike domains. -- • Real Roblox links use roblox.com (check the .com ending). -- • Treat fake Roblox login / "claim reward" pages as phishing. -- [[ End Rscripts Risk Notice ]] local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local RunService = game:GetService("RunService") local VirtualInputManager = game:GetService("VirtualInputManager") local UserInputService = game:GetService("UserInputService") local TweenService = game:GetService("TweenService") local player = Players.LocalPlayer -- CONFIG local CLICK_INTERVAL = 0.01 local SAFETY_CHECK_INTERVAL = 0.1 local REFRESH_INTERVAL = 0.5 local FULL_RESCAN_INTERVAL = 5.0 -- how often to re-scan getgc from scratch local TOGGLE_KEY = Enum.KeyCode.F -- State local enabled = false local gameState = nil local oldNewIndex = nil local mt = nil local skillTest = nil local selectionLine = nil -- ============================================================ -- GUI (no blocking waits) -- ============================================================ local gui = Instance.new("ScreenGui") gui.Name = "SkillBotPro" gui.ResetOnSpawn = false gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling gui.Parent = player.PlayerGui local window = Instance.new("Frame") window.Name = "MainWindow" window.Size = UDim2.new(0, 220, 0, 145) window.Position = UDim2.new(0, 50, 0, 300) window.BackgroundColor3 = Color3.fromRGB(35, 35, 40) window.BorderSizePixel = 0 window.ZIndex = 10000 window.Parent = gui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 12) corner.Parent = window local shadow = Instance.new("Frame") shadow.Size = UDim2.new(1, 0, 1, 0) shadow.Position = UDim2.new(0, 0, 0, 4) shadow.BackgroundColor3 = Color3.fromRGB(20, 20, 25) shadow.BorderSizePixel = 0 shadow.ZIndex = 9999 shadow.Parent = window local shadowCorner = corner:Clone() shadowCorner.Parent = shadow local titleBar = Instance.new("Frame") titleBar.Size = UDim2.new(1, 0, 0, 36) titleBar.BackgroundColor3 = Color3.fromRGB(45, 45, 55) titleBar.BorderSizePixel = 0 titleBar.ZIndex = 10001 titleBar.Parent = window local titleCorner = Instance.new("UICorner") titleCorner.CornerRadius = UDim.new(0, 12) titleCorner.Parent = titleBar local title = Instance.new("TextLabel") title.Size = UDim2.new(1, -40, 1, 0) title.Position = UDim2.new(0, 15, 0, 0) title.BackgroundTransparency = 1 title.Text = "Skill Bot Pro" title.TextColor3 = Color3.fromRGB(255, 255, 255) title.TextSize = 16 title.Font = Enum.Font.GothamBold title.ZIndex = 10002 title.Parent = titleBar local statusDot = Instance.new("Frame") statusDot.Size = UDim2.new(0, 8, 0, 8) statusDot.Position = UDim2.new(1, -20, 0.5, -4) statusDot.BackgroundColor3 = Color3.fromRGB(255, 50, 50) statusDot.BorderSizePixel = 0 statusDot.ZIndex = 10002 statusDot.Parent = titleBar local dotCorner = Instance.new("UICorner") dotCorner.CornerRadius = UDim.new(1, 0) dotCorner.Parent = statusDot local toggleBtn = Instance.new("TextButton") toggleBtn.Size = UDim2.new(0, 180, 0, 45) toggleBtn.Position = UDim2.new(0.5, -90, 0, 55) toggleBtn.BackgroundColor3 = Color3.fromRGB(200, 50, 50) toggleBtn.Text = "OFF" toggleBtn.TextColor3 = Color3.fromRGB(255, 255, 255) toggleBtn.TextSize = 20 toggleBtn.Font = Enum.Font.GothamBold toggleBtn.ZIndex = 10001 toggleBtn.Parent = window local btnCorner = Instance.new("UICorner") btnCorner.CornerRadius = UDim.new(0, 10) btnCorner.Parent = toggleBtn local hotkeyHint = Instance.new("TextLabel") hotkeyHint.Size = UDim2.new(1, -20, 0, 16) hotkeyHint.Position = UDim2.new(0, 10, 0, 104) hotkeyHint.BackgroundTransparency = 1 hotkeyHint.Text = "[F] to toggle" hotkeyHint.TextColor3 = Color3.fromRGB(200, 200, 120) hotkeyHint.TextSize = 11 hotkeyHint.Font = Enum.Font.Gotham hotkeyHint.ZIndex = 10001 hotkeyHint.Parent = window local infoLabel = Instance.new("TextLabel") infoLabel.Size = UDim2.new(1, -20, 0, 20) infoLabel.Position = UDim2.new(0, 10, 1, -25) infoLabel.BackgroundTransparency = 1 infoLabel.Text = "Waiting for grading screen..." infoLabel.TextColor3 = Color3.fromRGB(150, 150, 150) infoLabel.TextSize = 11 infoLabel.Font = Enum.Font.Gotham infoLabel.ZIndex = 10001 infoLabel.Parent = window -- Drag local dragging, dragStart, startPos = false, nil, nil titleBar.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then dragging = true dragStart = input.Position startPos = window.Position end end) UserInputService.InputChanged:Connect(function(input) if dragging and input.UserInputType == Enum.UserInputType.MouseMovement then local delta = input.Position - dragStart window.Position = UDim2.new( startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y ) end end) UserInputService.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then dragging = false end end) -- ============================================================ -- GAME STATE DISCOVERY -- ============================================================ local candidateFunctions = {} local lastFullScan = 0 local function fullScan() local found = {} for _, func in pairs(getgc()) do if type(func) == "function" then local info = getinfo(func) if info and info.source and info.source:find("SkillTestServiceClient") then table.insert(found, func) end end end candidateFunctions = found lastFullScan = tick() end -- Score candidates: prefer phase == "lock", then any with a phase set, -- then any with hearts > 0, so stale tables don't win. local function findGameState() if tick() - lastFullScan > FULL_RESCAN_INTERVAL then fullScan() end local best, bestScore = nil, -1 for _, func in ipairs(candidateFunctions) do if type(func) == "function" then local ups = getupvalues(func) for _, v in pairs(ups) do if type(v) == "table" and rawget(v, "areaRotation") ~= nil and rawget(v, "speed") ~= nil then local score = 0 local phase = rawget(v, "phase") local hearts = rawget(v, "hearts") if phase == "lock" then score = score + 200 elseif phase ~= nil and phase ~= "done" and phase ~= "idle" then score = score + 50 end if type(hearts) == "number" and hearts > 0 then score = score + 30 end if score > bestScore then best, bestScore = v, score end end end end end return best end -- ============================================================ -- METATABLE HOOK -- ============================================================ local function ensureHook() if not selectionLine then return end local currentMt = getrawmetatable(selectionLine) -- Same metatable & we still have our hook -> nothing to do if currentMt == mt and oldNewIndex ~= nil then return end -- Restore any previous hook first (in case it was a stale metatable) if mt and oldNewIndex then pcall(function() setreadonly(mt, false) mt.__newindex = oldNewIndex end) end mt = currentMt setreadonly(mt, false) oldNewIndex = mt.__newindex mt.__newindex = function(self, key, value) if key == "Rotation" and enabled and gameState then value = gameState.areaRotation or value end return oldNewIndex(self, key, value) end end -- ============================================================ -- TARGET REFRESH -- ============================================================ local function refreshTargets() local frames = player.PlayerGui:FindFirstChild("Frames") local mainInv = frames and frames:FindFirstChild("MainInventory") local armor = mainInv and mainInv:FindFirstChild("ArmorGradingSkillFrame") local st = armor and armor:FindFirstChild("SkillTest") local sl = st and st:FindFirstChild("selectionLine") if st and sl then local screenChanged = (skillTest ~= st) or (selectionLine ~= sl) skillTest = st selectionLine = sl ensureHook() -- ALWAYS re-scan for the live state. This is the fix: -- the game reuses the same SkillTest frame, so `skillTest ~= st` -- never triggers on re-entry, and we were stuck on the old state. local newState = findGameState() if newState and newState ~= gameState then gameState = newState end else -- Screen is gone -> clear everything if skillTest then if enabled then disableBot() end skillTest = nil selectionLine = nil gameState = nil end end end -- ============================================================ -- BOT LOGIC -- ============================================================ local function isSafeToClick() if not gameState then return false end if not skillTest or not skillTest.Visible then return false end if gameState.phase ~= "lock" then return false end if type(gameState.hearts) == "number" and gameState.hearts <= 0 then return false end return true end local function enableBot() if not gameState then -- Try a fresh lookup right now gameState = findGameState() end if not gameState then infoLabel.Text = "Error: Not on grading screen" return end enabled = true toggleBtn.Text = "ON" toggleBtn.BackgroundColor3 = Color3.fromRGB(50, 200, 50) statusDot.BackgroundColor3 = Color3.fromRGB(50, 255, 50) TweenService:Create(statusDot, TweenInfo.new(0.3), {Size = UDim2.new(0, 10, 0, 10)}):Play() ensureHook() gameState.speed = 0 gameState.direction = 0 gameState.areaHalfWidth = 360 gameState.areaPerfect = 360 infoLabel.Text = "Bot Active" end local function disableBot() enabled = false toggleBtn.Text = "OFF" toggleBtn.BackgroundColor3 = Color3.fromRGB(200, 50, 50) statusDot.BackgroundColor3 = Color3.fromRGB(255, 50, 50) TweenService:Create(statusDot, TweenInfo.new(0.3), {Size = UDim2.new(0, 8, 0, 8)}):Play() if gameState then gameState.speed = 90 gameState.direction = 1 end infoLabel.Text = "Bot Disabled" end local function toggleBot() if enabled then disableBot() else enableBot() end end toggleBtn.MouseButton1Click:Connect(toggleBot) UserInputService.InputBegan:Connect(function(input, gameProcessed) if gameProcessed then return end if input.KeyCode == TOGGLE_KEY then toggleBot() end end) -- ============================================================ -- LOOPS -- ============================================================ -- Initial full scan fullScan() -- Refresh loop (handles entering / leaving / re-entering the minigame) task.spawn(function() while true do task.wait(REFRESH_INTERVAL) refreshTargets() end end) -- Fast clicker task.spawn(function() while true do task.wait(CLICK_INTERVAL) if enabled and isSafeToClick() then VirtualInputManager:SendMouseButtonEvent(0, 0, 0, true, game, 0) VirtualInputManager:SendMouseButtonEvent(0, 0, 0, false, game, 0) end end end) -- Keep line locked at target RunService.RenderStepped:Connect(function() if enabled and gameState and gameState.areaRotation and selectionLine then selectionLine.Rotation = gameState.areaRotation end end) -- Status label task.spawn(function() while true do task.wait(SAFETY_CHECK_INTERVAL) if not skillTest then infoLabel.Text = "Waiting for grading screen..." elseif enabled then if not isSafeToClick() then local phase = gameState and tostring(gameState.phase) or "?" infoLabel.Text = "Paused (phase: "..phase..")" else infoLabel.Text = "Clicking..." end end end end) player.CharacterRemoving:Connect(function() gui:Destroy() end) print("[SkillBot Pro] Loaded - Press F or click the button to toggle")