
Key Required

local _setIdent
do
local names = { "setthreadidentity", "set_thread_identity", "setidentity",
"setcontext", "setthreadcontext" }
for _, n in ipairs(names) do
local f = rawget(getfenv(), n)
if typeof(f) == "function" then _setIdent = f; break end
end
end
local function elevate()
if _setIdent then
if pcall(_setIdent, 8) then return end
if pcall(_setIdent, 7) then return end
pcall(_setIdent, 2)
end
end
elevate()
local _firesignal = rawget(getfenv(), "firesignal") or firesignal
local _getconnections = rawget(getfenv(), "getconnections") or getconnections
local function fireSignalSafely(sig, ...)
if typeof(_firesignal) == "function" then
pcall(_firesignal, sig, ...)
end
if typeof(_getconnections) == "function" then
local ok, conns = pcall(_getconnections, sig)
if ok and type(conns) == "table" then
for _, conn in ipairs(conns) do
if type(conn.Fire) == "function" then
pcall(conn.Fire, conn, ...)
end
if type(conn.Function) == "function" then
pcall(conn.Function, ...)
end
end
end
end
end
local function fireClick(btn)
fireSignalSafely(btn.MouseButton1Down, 0, 0)
fireSignalSafely(btn.MouseButton1Up, 0, 0)
fireSignalSafely(btn.MouseButton1Click)
fireSignalSafely(btn.Activated, nil, 1)
end
local function findScreenFrame()
local objects = workspace:FindFirstChild("objects")
if not objects then return nil, "workspace.objects not found" end
local puzzle = objects:FindFirstChild("puzzle")
if not puzzle then return nil, "puzzle not found" end
local screen = puzzle:FindFirstChild("Screen", true)
if not screen then return nil, "Screen part not found" end
local sg = screen:FindFirstChildOfClass("SurfaceGui")
if not sg then return nil, "SurfaceGui not found" end
local sf = sg:FindFirstChild("ScreenFrame")
if not sf then return nil, "ScreenFrame not found" end
return sf
end
local function findButtonsContainer()
local sf, err = findScreenFrame()
if not sf then return nil, err end
local b = sf:FindFirstChild("Buttons")
if not b then return nil, "Buttons not found" end
return b
end
local function findFormulaFrame(sf)
for _, d in ipairs(sf:GetDescendants()) do
if d.Name == "FormulaFrame" then return d end
end
end
local function getFormulaText(ff)
if not ff then return "" end
for _, d in ipairs(ff:GetDescendants()) do
if d:IsA("TextLabel") then
local t = d.Text
if t and t ~= "" and t ~= "Label" then return t end
end
end
return ""
end
local function findPlayButton()
local sf = findScreenFrame()
if not sf then return nil end
for _, d in ipairs(sf:GetDescendants()) do
if d:IsA("TextButton") and (d.Name == "PlayButton" or d.Text == "START") then
return d
end
end
end
local function findRegenerateBtn()
local objects = workspace:FindFirstChild("objects")
if not objects then return nil end
local puzzle = objects:FindFirstChild("puzzle")
if not puzzle then return nil end
for _, d in ipairs(puzzle:GetDescendants()) do
if (d:IsA("ImageButton") or d:IsA("TextButton"))
and d.Name == "RegenerateStage" then
return d
end
end
end
local function isVisibleChain(g)
local cur = g
while cur and cur:IsA("GuiObject") do
if not cur.Visible then return false end
cur = cur.Parent
end
return true
end
local function splitTopLevelCommas(s)
local parts, depth, cur = {}, 0, ""
for i = 1, #s do
local ch = s:sub(i, i)
if ch == "(" or ch == "[" or ch == "{" then depth = depth + 1; cur = cur .. ch
elseif ch == ")" or ch == "]" or ch == "}" then depth = depth - 1; cur = cur .. ch
elseif ch == "," and depth == 0 then parts[#parts + 1] = cur; cur = ""
else cur = cur .. ch end
end
if cur:match("%S") then parts[#parts + 1] = cur end
return parts
end
local function normalizeExpr(t)
t = t:gsub("π", "math.pi")
t = t:gsub("\226\136\146", "-")
t = t:gsub("\226\128\147", "-")
t = t:gsub("\226\128\148", "-")
t = t:gsub("%)%s*%(", ")*(")
t = t:gsub("(%d)%s*%(", "%1*(")
t = t:gsub("%)%s*(%d)", ")*%1")
return t
end
local function evaluateMath(text)
if type(text) ~= "string" or text:match("^%s*$") then return nil end
local expr = normalizeExpr(text)
local hasAssign = expr:find("=") ~= nil
local hasEqEq = expr:find("==") ~= nil
local hasNeq = expr:find("~=") ~= nil
local code
if hasAssign and not hasEqEq and not hasNeq then
local pieces, lastVar = {}, nil
for _, p in ipairs(splitTopLevelCommas(expr)) do
p = p:match("^%s*(.-)%s*$")
local var = p:match("^([%a_][%w_]*)%s*=[^=]") or p:match("^([%a_][%w_]*)%s*=$")
if not var then return nil end
pieces[#pieces + 1] = "local " .. p
lastVar = var
end
if not lastVar then return nil end
code = table.concat(pieces, "; ") .. "; return " .. lastVar
else
code = "return " .. expr
end
local loader = loadstring or load
if type(loader) ~= "function" then return nil end
local fn = loader(code)
if not fn then return nil end
local ok, res = pcall(fn)
if not ok or type(res) ~= "number" or res ~= res then return nil end
return res
end
local SHIFT_MAP = {
["!"]="1",["@"]="2",["#"]="3",["$"]="4",["%"]="5",
["^"]="6",["&"]="7",["*"]="8",["("]="9",[")"]="0",
}
local function decodeShift(text)
if type(text) ~= "string" then return nil end
local digs = {}
for i = 1, #text do
local ch = text:sub(i, i)
if ch ~= " " and ch ~= "\t" and ch ~= "\n" and ch ~= "\r" then
local d = SHIFT_MAP[ch]
if not d then return nil end
digs[#digs + 1] = d
end
end
if #digs == 0 then return nil end
return tonumber(table.concat(digs))
end
local function parseBased(text)
if type(text) ~= "string" then return nil end
local sign, digits, base = text:match("^%s*(%-?)%s*([%w]+)%s*%(%s*(%d+)%s*%)%s*$")
if not digits then return nil end
base = tonumber(base)
if not base or base < 2 or base > 36 then return nil end
local n = tonumber(digits, base)
if not n then return nil end
if sign == "-" then n = -n end
return n
end
local CLICK_DELAY = 0.15
local function sortedClick(entries, status)
table.sort(entries, function(a, b) return a.value < b.value end)
status(("clicking %d cells ascending"):format(#entries))
for i, e in ipairs(entries) do
fireClick(e.btn)
status(("%d/%d -> %s"):format(i, #entries, tostring(e.value)))
task.wait(CLICK_DELAY)
end
end
local function hoverObject(obj)
if not obj then return end
local x, y = 0, 0
pcall(function()
local p, s = obj.AbsolutePosition, obj.AbsoluteSize
x = math.floor(p.X + s.X / 2)
y = math.floor(p.Y + s.Y / 2)
end)
fireSignalSafely(obj.MouseEnter, x, y)
fireSignalSafely(obj.MouseMoved, x, y)
fireSignalSafely(obj.InputBegan)
fireSignalSafely(obj.InputChanged)
end
local function unhoverObject(obj)
if not obj then return end
fireSignalSafely(obj.MouseLeave, 0, 0)
end
local function hoverCell(c)
if c.slot then
hoverObject(c.slot)
for _, ch in ipairs(c.slot:GetChildren()) do
if ch:IsA("GuiObject") then hoverObject(ch) end
end
else
hoverObject(c.mtb); hoverObject(c.btn)
end
end
local function unhoverCell(c)
if c.slot then
for _, ch in ipairs(c.slot:GetChildren()) do
if ch:IsA("GuiObject") then unhoverObject(ch) end
end
unhoverObject(c.slot)
else
unhoverObject(c.mtb); unhoverObject(c.btn)
end
end
local function focusBox(tb)
pcall(function() tb:CaptureFocus() end)
fireSignalSafely(tb.Focused)
end
local function submitBox(tb, value)
tb.Text = tostring(value)
fireSignalSafely(tb.FocusLost, true)
pcall(function() tb:ReleaseFocus(true) end)
end
local function cancelBox(tb)
fireSignalSafely(tb.FocusLost, false)
pcall(function() tb:ReleaseFocus(false) end)
end
local function waitForFormula(ff, prev, timeout)
local deadline = os.clock() + (timeout or 0.4)
while os.clock() < deadline do
local cur = getFormulaText(ff)
if cur ~= "" and cur ~= prev then return cur end
task.wait(0.03)
end
return getFormulaText(ff)
end
local function waitCellSolved(c, timeout)
local deadline = os.clock() + (timeout or 1.5)
while os.clock() < deadline do
if c.btn.Visible and not c.mtb.Visible then return true end
task.wait(0.05)
end
return false
end
local function solveL1(status)
local container, err = findButtonsContainer()
if not container then return false, err end
local list = {}
for _, slot in ipairs(container:GetChildren()) do
if slot:IsA("Frame") then
local btn = slot:FindFirstChildOfClass("TextButton")
local lbl = slot:FindFirstChildOfClass("TextLabel")
if btn and btn.Visible and (not lbl or not lbl.Visible) then
local n = tonumber(btn.Text)
if n then list[#list + 1] = { btn = btn, value = n } end
end
end
end
if #list == 0 then return false, "no L1 buttons" end
sortedClick(list, status)
return true
end
local function solveL2(status)
local container, err = findButtonsContainer()
if not container then return false, err end
local list = {}
for _, slot in ipairs(container:GetChildren()) do
if slot:IsA("Frame") then
local btn = slot:FindFirstChildOfClass("TextButton")
if btn and btn.Visible then
local v = decodeShift(btn.Text)
if v then list[#list + 1] = { btn = btn, value = v } end
end
end
end
if #list == 0 then return false, "no L2 shift symbols" end
sortedClick(list, status)
return true
end
local function solveL3(status)
local container, err = findButtonsContainer()
if not container then return false, err end
local list = {}
for _, slot in ipairs(container:GetChildren()) do
if slot:IsA("Frame") then
local btn = slot:FindFirstChildOfClass("TextButton")
if btn and btn.Visible then
local v = parseBased(btn.Text)
if v then list[#list + 1] = { btn = btn, value = v } end
end
end
end
if #list == 0 then return false, "no L3 base format" end
sortedClick(list, status)
return true
end
local function solveL4(status)
if type(loadstring) ~= "function" and type(load) ~= "function" then
return false, "no loadstring"
end
local sf, err = findScreenFrame()
if not sf then return false, err end
local container = sf:FindFirstChild("Buttons")
if not container then return false, "Buttons not found" end
local ff = findFormulaFrame(sf)
if not ff then return false, "FormulaFrame not found" end
local cells = {}
for _, slot in ipairs(container:GetChildren()) do
if slot:IsA("Frame") then
local mtb = slot:FindFirstChild("MathTextBox")
local btn = slot:FindFirstChildOfClass("TextButton")
if mtb and btn then
cells[#cells + 1] = { slot = slot, mtb = mtb, btn = btn }
end
end
end
if #cells == 0 then return false, "no MathTextBox cells" end
local lastHovered
local function isPending(c) return c.mtb.Visible and not c.btn.Visible end
local function countPending()
local n = 0
for _, c in ipairs(cells) do if isPending(c) then n = n + 1 end end
return n
end
local function resetHover()
if lastHovered then unhoverCell(lastHovered); lastHovered = nil end
hoverObject(sf); unhoverObject(sf)
task.wait(0.05)
end
local function readFormulaForCell(c)
if lastHovered and lastHovered ~= c then
unhoverCell(lastHovered)
task.wait(0.06)
end
for attempt = 1, 4 do
if attempt == 3 then resetHover() end
hoverCell(c)
lastHovered = c
local deadline = os.clock() + 0.5
local f = ""
while os.clock() < deadline do
f = getFormulaText(ff)
if f ~= "" then break end
task.wait(0.04)
end
if f ~= "" then return f end
unhoverCell(c)
task.wait(0.06)
end
return getFormulaText(ff)
end
local function processCell(i, c)
if not isPending(c) then return false, "already solved" end
local formula = readFormulaForCell(c)
if formula == "" then return false, "no formula" end
local ans = evaluateMath(formula)
if not ans then return false, "compute failed: " .. formula end
local txt = (math.floor(ans) == ans) and string.format("%d", ans) or tostring(ans)
status(("[L4] %d/%d %s = %s"):format(i, #cells, formula, txt))
focusBox(c.mtb)
task.wait(0.10)
submitBox(c.mtb, txt)
local ok = waitCellSolved(c, 1.8)
task.wait(0.25)
if ok then return true end
return false, ("rejected: %s = %s"):format(formula, txt)
end
local MAX_PASSES = 8
local solved = 0
local lastFails = {}
for pass = 1, MAX_PASSES do
if countPending() == 0 then break end
local progressed = false
for i, c in ipairs(cells) do
if isPending(c) then
local ok, reason = processCell(i, c)
if ok then
solved = solved + 1
progressed = true
lastFails[i] = nil
else
lastFails[i] = reason
cancelBox(c.mtb)
if lastHovered then unhoverCell(lastHovered); lastHovered = nil end
resetHover()
end
end
end
local left = countPending()
status(("[L4] pass %d/%d solved %d/%d left %d")
:format(pass, MAX_PASSES, solved, #cells, left))
if left == 0 then break end
if not progressed then resetHover(); task.wait(0.25) else task.wait(0.10) end
end
if lastHovered then unhoverCell(lastHovered) end
local left = countPending()
if left > 0 then
local msgs = {}
for i, c in ipairs(cells) do
if isPending(c) then
msgs[#msgs + 1] = ("#%d:%s"):format(i, lastFails[i] or "?")
end
end
return false, ("phase 1 incomplete %d/%d unsolved (%s)")
:format(left, #cells, table.concat(msgs, ";"))
end
status(("[L4] phase 1: %d/%d, settling"):format(solved, #cells))
task.wait(0.6)
local readyDeadline = os.clock() + 3
while os.clock() < readyDeadline do
local ready = true
for _, c in ipairs(cells) do
if not (c.btn.Visible and tonumber(c.btn.Text)) then ready = false; break end
end
if ready then break end
task.wait(0.1)
end
local list = {}
for _, c in ipairs(cells) do
if c.btn.Visible then
local n = tonumber(c.btn.Text)
if n then list[#list + 1] = { btn = c.btn, value = n } end
end
end
if #list ~= #cells then
return false, ("phase 2: only %d/%d buttons ready"):format(#list, #cells)
end
status("[L4] phase 2: clicking")
sortedClick(list, status)
return true
end
local function detectLevel()
local container = findButtonsContainer()
if not container then return nil end
local hasMtb, hasShift, hasBased, hasNum = false, false, false, false
for _, slot in ipairs(container:GetChildren()) do
if slot:IsA("Frame") then
local mtb = slot:FindFirstChild("MathTextBox")
local btn = slot:FindFirstChildOfClass("TextButton")
if mtb and mtb.Visible then hasMtb = true end
if btn and btn.Visible then
local t = btn.Text
if decodeShift(t) then hasShift = true
elseif parseBased(t) then hasBased = true
elseif tonumber(t) then hasNum = true end
end
end
end
if hasMtb then return "L4" end
if hasBased then return "L3" end
if hasShift then return "L2" end
if hasNum then return "L1" end
return nil
end
local SOLVERS = { L1 = solveL1, L2 = solveL2, L3 = solveL3, L4 = solveL4 }
local function getGuiParent()
local lp = game:GetService("Players").LocalPlayer
if lp then
local pg = lp:FindFirstChildOfClass("PlayerGui")
if pg then return pg end
end
local h = rawget(getfenv(), "gethui")
if typeof(h) == "function" then
local ok, r = pcall(h)
if ok and r then return r end
end
return game:GetService("CoreGui")
end
local guiParent = getGuiParent()
local existing = guiParent:FindFirstChild("HarryPuzzleSolverGui")
if existing then existing:Destroy() end
local screenGui = Instance.new("ScreenGui")
screenGui.Name = "HarryPuzzleSolverGui"
screenGui.ResetOnSpawn = false
screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
screenGui.IgnoreGuiInset = true
screenGui.Parent = guiParent
local C = {
headerBg = Color3.fromRGB(142, 201, 252),
border1 = Color3.fromRGB(142, 201, 252),
border2 = Color3.fromRGB(121, 171, 214),
panelBg = Color3.fromRGB(255, 255, 255),
titleTx = Color3.fromRGB(12, 50, 85),
btnBg = Color3.fromRGB(244, 244, 244),
btnBgHover = Color3.fromRGB(232, 240, 252),
btnBorder = Color3.fromRGB(228, 228, 228),
btnTx = Color3.fromRGB(0, 0, 0),
statusBg = Color3.fromRGB(252, 252, 252),
statusTx = Color3.fromRGB(40, 50, 60),
hideBg = Color3.fromRGB(252, 234, 160),
closeBg = Color3.fromRGB(252, 118, 118),
autoOnBg = Color3.fromRGB(177, 232, 184),
autoOffBg = Color3.fromRGB(244, 244, 244),
stopBg = Color3.fromRGB(252, 200, 200),
}
local FONT = Enum.Font.SourceSansSemibold
local FONT_REG = Enum.Font.SourceSans
local W, BAR, BODYH = 350, 25, 230
local drag = Instance.new("Frame")
drag.Name = "drag"
drag.BackgroundColor3 = C.headerBg
drag.BorderSizePixel = 0
drag.Size = UDim2.fromOffset(W, BAR)
drag.Position = UDim2.new(0.5, -W/2, 0.4, -(BAR + BODYH)/2)
drag.Active = true
drag.ZIndex = 4
drag.Parent = screenGui
local bg1 = Instance.new("Frame")
bg1.Parent = drag
bg1.BorderSizePixel = 4
bg1.BorderColor3 = C.border1
bg1.BackgroundColor3 = C.panelBg
bg1.Size = UDim2.fromOffset(W, BODYH + 21)
bg1.Position = UDim2.fromOffset(0, 4)
bg1.ZIndex = 0
local bg2 = Instance.new("Frame")
bg2.Parent = bg1
bg2.BorderSizePixel = 5
bg2.BorderColor3 = C.border2
bg2.BackgroundColor3 = C.panelBg
bg2.Size = UDim2.new(1, 0, 1, 0)
bg2.ZIndex = 0
local main = Instance.new("Frame")
main.Parent = drag
main.BackgroundColor3 = C.panelBg
main.BorderSizePixel = 1
main.BorderColor3 = C.border2
main.Size = UDim2.fromOffset(W, BODYH)
main.Position = UDim2.fromOffset(0, BAR)
main.ZIndex = 2
local title = Instance.new("TextLabel")
title.Parent = drag
title.BackgroundTransparency = 1
title.Position = UDim2.fromOffset(8, 0)
title.Size = UDim2.new(1, -90, 1, 0)
title.Font = FONT_REG
title.TextSize = 17
title.TextColor3 = C.titleTx
title.TextXAlignment = Enum.TextXAlignment.Left
title.Text = "HARRY AUTO-SOLVER"
title.ZIndex = 5
local function makeCornerBtn(name, txt, color, x)
local b = Instance.new("TextButton")
b.Name = name
b.Parent = drag
b.AutoButtonColor = true
b.BackgroundColor3 = color
b.BorderSizePixel = 1
b.BorderColor3 = C.btnBorder
b.Size = UDim2.fromOffset(35, 20)
b.Position = UDim2.fromOffset(x, 2)
b.Font = FONT_REG
b.TextSize = 14
b.TextColor3 = C.btnTx
b.Text = txt
b.ZIndex = 5
return b
end
local hideBtn = makeCornerBtn("hib", "Hide", C.hideBg, W - 35 - 35 - 2)
local closeBtn = makeCornerBtn("deb", "Del", C.closeBg, W - 35 - 2)
local row1 = Instance.new("Frame")
row1.Parent = main
row1.BackgroundTransparency = 1
row1.Size = UDim2.new(1, 0, 0, 30)
row1.Position = UDim2.fromOffset(0, 4)
local row1L = Instance.new("UIListLayout", row1)
row1L.FillDirection = Enum.FillDirection.Horizontal
row1L.HorizontalAlignment = Enum.HorizontalAlignment.Center
row1L.VerticalAlignment = Enum.VerticalAlignment.Center
row1L.Padding = UDim.new(0, 4)
row1L.SortOrder = Enum.SortOrder.LayoutOrder
local function makeTabBtn(parent, label, w, order, bg)
local b = Instance.new("TextButton")
b.Parent = parent
b.LayoutOrder = order
b.AutoButtonColor = true
b.BackgroundColor3 = bg or C.btnBg
b.BorderSizePixel = 1
b.BorderColor3 = C.btnBorder
b.Size = UDim2.fromOffset(w, 22)
b.Font = FONT
b.TextSize = 14
b.TextColor3 = C.btnTx
b.Text = label
return b
end
local btnL1 = makeTabBtn(row1, "L1", 50, 1)
local btnL2 = makeTabBtn(row1, "L2", 50, 2)
local btnL3 = makeTabBtn(row1, "L3", 50, 3)
local btnL4 = makeTabBtn(row1, "L4", 50, 4)
local btnDetect = makeTabBtn(row1, "DETECT", 66, 5)
local btnRefresh = makeTabBtn(row1, "REFRESH", 66, 6)
local row2 = Instance.new("Frame")
row2.Parent = main
row2.BackgroundTransparency = 1
row2.Size = UDim2.new(1, 0, 0, 30)
row2.Position = UDim2.fromOffset(0, 38)
local row2L = Instance.new("UIListLayout", row2)
row2L.FillDirection = Enum.FillDirection.Horizontal
row2L.HorizontalAlignment = Enum.HorizontalAlignment.Center
row2L.VerticalAlignment = Enum.VerticalAlignment.Center
row2L.Padding = UDim.new(0, 4)
row2L.SortOrder = Enum.SortOrder.LayoutOrder
local btnAuto = makeTabBtn(row2, "AUTO OFF", 160, 1, C.autoOffBg)
local btnStop = makeTabBtn(row2, "STOP", 160, 2, C.stopBg)
local statusBox = Instance.new("Frame")
statusBox.Parent = main
statusBox.BackgroundColor3 = C.statusBg
statusBox.BorderSizePixel = 1
statusBox.BorderColor3 = C.btnBorder
statusBox.Size = UDim2.new(1, -16, 0, 130)
statusBox.Position = UDim2.fromOffset(8, 74)
local statusHdr = Instance.new("TextLabel")
statusHdr.Parent = statusBox
statusHdr.BackgroundTransparency = 1
statusHdr.Position = UDim2.fromOffset(6, 2)
statusHdr.Size = UDim2.new(1, -12, 0, 14)
statusHdr.Font = FONT
statusHdr.TextSize = 12
statusHdr.TextColor3 = C.titleTx
statusHdr.TextXAlignment = Enum.TextXAlignment.Left
statusHdr.Text = "STATUS"
local statusLbl = Instance.new("TextLabel")
statusLbl.Parent = statusBox
statusLbl.BackgroundTransparency = 1
statusLbl.Position = UDim2.fromOffset(6, 18)
statusLbl.Size = UDim2.new(1, -12, 1, -22)
statusLbl.Font = FONT_REG
statusLbl.TextSize = 13
statusLbl.TextColor3 = C.statusTx
statusLbl.TextXAlignment = Enum.TextXAlignment.Left
statusLbl.TextYAlignment = Enum.TextYAlignment.Top
statusLbl.TextWrapped = true
statusLbl.Text = "ready"
local function setStatus(s) statusLbl.Text = tostring(s) end
local UIS = game:GetService("UserInputService")
do
local dragging, dragStart, startPos
drag.InputBegan:Connect(function(input)
elevate()
if input.UserInputType == Enum.UserInputType.MouseButton1
or input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragStart = input.Position
startPos = drag.Position
input.Changed:Connect(function()
if input.UserInputState == Enum.UserInputState.End then
dragging = false
end
end)
end
end)
UIS.InputChanged:Connect(function(input)
if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement
or input.UserInputType == Enum.UserInputType.Touch) then
elevate()
local delta = input.Position - dragStart
drag.Position = UDim2.new(
startPos.X.Scale, startPos.X.Offset + delta.X,
startPos.Y.Scale, startPos.Y.Offset + delta.Y
)
end
end)
end
closeBtn.MouseButton1Click:Connect(function() elevate(); screenGui:Destroy() end)
local minimized = false
hideBtn.MouseButton1Click:Connect(function()
elevate()
minimized = not minimized
if minimized then
main.Visible = false; bg1.Visible = false; hideBtn.Text = "Show"
else
main.Visible = true; bg1.Visible = true; hideBtn.Text = "Hide"
end
end)
local running = false
local autoMode = false
local autoThread
local function setAutoBtn(state)
if state then
btnAuto.Text = "AUTO ON"
btnAuto.BackgroundColor3 = C.autoOnBg
else
btnAuto.Text = "AUTO OFF"
btnAuto.BackgroundColor3 = C.autoOffBg
end
end
local function runOnce(name, fn)
elevate()
if running then setStatus("busy"); return false end
running = true
setStatus(name .. ": start")
local ok, err, msg = pcall(fn, setStatus)
running = false
if not ok then
setStatus(name .. " error: " .. tostring(err))
return false
elseif err == false then
setStatus(name .. " failed: " .. tostring(msg))
return false
else
setStatus(name .. " done")
return true
end
end
local function waitForPlayButton(timeout)
local deadline = os.clock() + (timeout or 8)
while os.clock() < deadline do
if not autoMode then return nil end
local pb = findPlayButton()
if pb and isVisibleChain(pb) then return pb end
task.wait(0.15)
end
return findPlayButton()
end
local function waitForLevelReady(timeout)
local deadline = os.clock() + (timeout or 8)
while os.clock() < deadline do
if not autoMode then return nil end
local lvl = detectLevel()
if lvl then return lvl end
task.wait(0.15)
end
return detectLevel()
end
local function waitForTransition(prevLvl, timeout)
local deadline = os.clock() + (timeout or 6)
while autoMode and os.clock() < deadline do
local pb = findPlayButton()
if pb and isVisibleChain(pb) then return "start" end
local lvl = detectLevel()
if lvl and lvl ~= prevLvl then return "level", lvl end
task.wait(0.15)
end
return "timeout"
end
local function autoLoop()
setStatus("auto: scanning")
local lastLvl
local blockedLvl, blockedUntil = nil, 0
while autoMode do
local pb = findPlayButton()
if pb and isVisibleChain(pb) then
elevate()
fireClick(pb)
setStatus("auto: START clicked, waiting load")
lastLvl = nil
blockedLvl = nil
local t0 = os.clock()
while autoMode and os.clock() - t0 < 3.0 do
local pb2 = findPlayButton()
if not (pb2 and isVisibleChain(pb2)) then break end
task.wait(0.1)
end
task.wait(1.5)
local kind, newLvl = waitForTransition(nil, 8)
if kind == "level" then
setStatus("auto: " .. newLvl .. " loaded")
task.wait(0.5)
end
else
local lvl = detectLevel()
local now = os.clock()
local isBlocked = lvl and lvl == blockedLvl and now < blockedUntil
if lvl and lvl ~= lastLvl and not isBlocked then
elevate()
running = true
setStatus("auto: solving " .. lvl)
local fn = SOLVERS[lvl]
local ok, err, msg = pcall(fn, setStatus)
running = false
if not ok then
setStatus("auto: " .. lvl .. " error: " .. tostring(err))
local rb = findRegenerateBtn()
if rb then
fireClick(rb)
setStatus("auto: REFRESH after error")
task.wait(1.5)
else
blockedLvl = lvl
blockedUntil = os.clock() + 5
task.wait(2)
end
elseif err == false then
setStatus("auto: " .. lvl .. " failed: " .. tostring(msg))
local rb = findRegenerateBtn()
if rb then
fireClick(rb)
setStatus("auto: REFRESH after fail")
task.wait(1.5)
else
blockedLvl = lvl
blockedUntil = os.clock() + 5
task.wait(2)
end
else
setStatus("auto: " .. lvl .. " done")
lastLvl = lvl
blockedLvl = nil
if not autoMode then break end
local kind, newLvl = waitForTransition(lvl, 8)
if kind == "level" then
setStatus("auto: " .. newLvl .. " loaded")
lastLvl = nil
elseif kind == "start" then
setStatus("auto: round done, START visible")
lastLvl = nil
else
setStatus("auto: transition timeout")
lastLvl = nil
end
end
else
if isBlocked then
setStatus(("auto: %s blocked, waiting"):format(lvl))
elseif lastLvl then
setStatus("auto: waiting for next level")
else
setStatus("auto: idle")
end
task.wait(0.4)
end
end
end
setStatus("auto: stopped")
end
btnL1.MouseButton1Click:Connect(function() elevate(); runOnce("L1", solveL1) end)
btnL2.MouseButton1Click:Connect(function() elevate(); runOnce("L2", solveL2) end)
btnL3.MouseButton1Click:Connect(function() elevate(); runOnce("L3", solveL3) end)
btnL4.MouseButton1Click:Connect(function() elevate(); runOnce("L4", solveL4) end)
btnDetect.MouseButton1Click:Connect(function()
elevate()
local lvl = detectLevel()
if lvl then
runOnce(lvl, SOLVERS[lvl])
else
setStatus("DETECT: no level")
end
end)
btnRefresh.MouseButton1Click:Connect(function()
elevate()
local rb = findRegenerateBtn()
if rb then
fireClick(rb)
setStatus("REFRESH: clicked")
else
setStatus("REFRESH: button not found")
end
end)
btnAuto.MouseButton1Click:Connect(function()
elevate()
if autoMode then
autoMode = false
setAutoBtn(false)
else
autoMode = true
setAutoBtn(true)
autoThread = task.spawn(autoLoop)
end
end)
btnStop.MouseButton1Click:Connect(function()
elevate()
autoMode = false
setAutoBtn(false)
setStatus("stopped")
end)
setStatus("ready - pick a level or AUTO")No comments yet for this script.
