local HttpService = game:GetService("HttpService")
local CoreGui = game:GetService("CoreGui")
local Players = game:GetService("Players")
local RbxAnalyticsService = game:GetService("RbxAnalyticsService")
local cloneref = cloneref or function(o) return o end
local gethui = gethui or function() return CoreGui end
local CoreGui = cloneref(game:GetService("CoreGui"))
local Players = cloneref(game:GetService("Players"))
local VirtualInputManager = cloneref(game:GetService("VirtualInputManager"))
local UserInputService = cloneref(game:GetService("UserInputService"))
local RunService = cloneref(game:GetService("RunService"))
local TweenService = cloneref(game:GetService("TweenService"))
local LogService = cloneref(game:GetService("LogService"))
local GuiService = cloneref(game:GetService("GuiService"))
local request = (syn and syn.request) or (http and http.request) or http_request or (fluxus and fluxus.request) or request
local TOGGLE_KEY = Enum.KeyCode.RightControl
local MIN_CPM = 50
local MAX_CPM_LEGIT = 1500
local MAX_CPM_BLATANT = 3000
math.randomseed(os.time())
local THEME = {
Background = Color3.fromRGB(20, 20, 24),
ItemBG = Color3.fromRGB(32, 32, 38),
Accent = Color3.fromRGB(114, 100, 255),
Text = Color3.fromRGB(240, 240, 240),
SubText = Color3.fromRGB(150, 150, 160),
Success = Color3.fromRGB(100, 255, 140),
Warning = Color3.fromRGB(255, 200, 80),
Slider = Color3.fromRGB(60, 60, 70)
}
local function ColorToRGB(c)
return string.format("%d,%d,%d", math.floor(c.R * 255), math.floor(c.G * 255), math.floor(c.B * 255))
end
local ConfigFile = "WordHelper_Longest_Config.json" -- Changed filename to not overwrite original
local Config = {
CPM = 450, -- Lowered slightly as longer words take longer
Blatant = false,
Humanize = true,
FingerModel = true,
SortMode = "Longest", -- CHANGED TO LONGEST DEFAULT
SuffixMode = "",
LengthMode = 0,
AutoPlay = false,
AutoJoin = false,
AutoJoinSettings = {
_1v1 = true,
_4p = true,
_8p = true
},
PanicMode = true,
ShowKeyboard = false,
ErrorRate = 5,
ThinkDelay = 0.8,
RiskyMistakes = false,
CustomWords = {},
MinTypeSpeed = 50,
MaxTypeSpeed = 3000,
KeyboardLayout = "QWERTY"
}
local function SaveConfig()
if writefile then
writefile(ConfigFile, HttpService:JSONEncode(Config))
end
end
local function LoadConfig()
if isfile and isfile(ConfigFile) then
local success, decoded = pcall(function() return HttpService:JSONDecode(readfile(ConfigFile)) end)
if success and decoded then
for k, v in pairs(decoded) do Config[k] = v end
end
end
end
LoadConfig()
-- Ensure Longest on start
Config.SortMode = "Longest"
local currentCPM = Config.CPM
local isBlatant = Config.Blatant
local useHumanization = Config.Humanize
local useFingerModel = Config.FingerModel
local sortMode = Config.SortMode
local suffixMode = Config.SuffixMode or ""
local lengthMode = Config.LengthMode or 0
local autoPlay = Config.AutoPlay
local autoJoin = Config.AutoJoin
local panicMode = Config.PanicMode
local showKeyboard = Config.ShowKeyboard
local errorRate = Config.ErrorRate
local thinkDelayCurrent = Config.ThinkDelay
local riskyMistakes = Config.RiskyMistakes
local keyboardLayout = Config.KeyboardLayout or "QWERTY"
local isTyping = false
local isAutoPlayScheduled = false
local lastTypingStart = 0
local runConn = nil
local inputConn = nil
local logConn = nil
local unloaded = false
local isMyTurnLogDetected = false
local logRequiredLetters = ""
local turnExpiryTime = 0
local Blacklist = {}
local UsedWords = {}
local RandomOrderCache = {}
local RandomPriority = {}
local lastDetected = "---"
local lastLogicUpdate = 0
local lastAutoJoinCheck = 0
local lastWordCheck = 0
local cachedDetected = ""
local cachedCensored = false
local LOGIC_RATE = 0.1
local AUTO_JOIN_RATE = 0.5
local UpdateList
local ButtonCache = {}
local ButtonData = {}
local JoinDebounce = {}
local thinkDelayMin = 0.4
local thinkDelayMax = 1.2
local listUpdatePending = false
local forceUpdateList = false
local lastInputTime = 0
local LIST_DEBOUNCE = 0.05
local currentBestMatch = nil
if logConn then logConn:Disconnect() end
logConn = LogService.MessageOut:Connect(function(message, type)
local wordPart, timePart = message:match("Word:%s*([A-Za-z]+)%s+Time to respond:%s*(%d+)")
if wordPart and timePart then
isMyTurnLogDetected = true
logRequiredLetters = wordPart
turnExpiryTime = tick() + tonumber(timePart)
end
end)
local url = "https://raw.githubusercontent.com/skrylor/english-words/refs/heads/main/merged_english.txt"
local fileName = "ultimate_words_v4.txt"
-- Temporary Loading UI
local LoadingGui = Instance.new("ScreenGui")
LoadingGui.Name = "WordHelperLoading"
local success, parent = pcall(function() return gethui() end)
if not success or not parent then parent = game:GetService("CoreGui") end
LoadingGui.Parent = parent
LoadingGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
local LoadingFrame = Instance.new("Frame", LoadingGui)
LoadingFrame.Size = UDim2.new(0, 300, 0, 100)
LoadingFrame.Position = UDim2.new(0.5, -150, 0.4, 0)
LoadingFrame.BackgroundColor3 = THEME.Background
LoadingFrame.BorderSizePixel = 0
Instance.new("UICorner", LoadingFrame).CornerRadius = UDim.new(0, 10)
local LStroke = Instance.new("UIStroke", LoadingFrame)
LStroke.Color = THEME.Accent
LStroke.Transparency = 0.5
LStroke.Thickness = 2
local LoadingTitle = Instance.new("TextLabel", LoadingFrame)
LoadingTitle.Size = UDim2.new(1, 0, 0, 40)
LoadingTitle.BackgroundTransparency = 1
LoadingTitle.Text = "WordHelper Longest V4"
LoadingTitle.TextColor3 = THEME.Accent
LoadingTitle.Font = Enum.Font.GothamBold
LoadingTitle.TextSize = 18
local LoadingStatus = Instance.new("TextLabel", LoadingFrame)
LoadingStatus.Size = UDim2.new(1, -20, 0, 30)
LoadingStatus.Position = UDim2.new(0, 10, 0, 50)
LoadingStatus.BackgroundTransparency = 1
LoadingStatus.Text = "Initializing..."
LoadingStatus.TextColor3 = THEME.Text
LoadingStatus.Font = Enum.Font.Gotham
LoadingStatus.TextSize = 14
local function UpdateStatus(text, color)
LoadingStatus.Text = text
if color then LoadingStatus.TextColor3 = color end
game:GetService("RunService").RenderStepped:Wait()
end
-- Startup: Always fetch fresh word list
local function FetchWords()
UpdateStatus("Fetching latest word list...", THEME.Warning)
local success, res = pcall(function()
return request({Url = url, Method = "GET"})
end)
if success and res and res.Body then
writefile(fileName, res.Body)
UpdateStatus("Fetched successfully!", THEME.Success)
else
UpdateStatus("Fetch failed! Using cached.", Color3.fromRGB(255, 80, 80))
end
task.wait(0.5)
end
FetchWords()
local Words = {}
local SeenWords = {}
local function LoadList(fname)
UpdateStatus("Parsing word list...", THEME.Warning)
if isfile(fname) then
local content = readfile(fname)
for w in content:gmatch("[^\r\n]+") do
local clean = w:gsub("[%s%c]+", ""):lower()
if #clean > 0 and not SeenWords[clean] then
SeenWords[clean] = true
table.insert(Words, clean)
end
end
UpdateStatus("Loaded " .. #Words .. " words!", THEME.Success)
else
UpdateStatus("No word list found!", Color3.fromRGB(255, 80, 80))
end
task.wait(1)
end
LoadList(fileName)
if LoadingGui then LoadingGui:Destroy() end
table.sort(Words)
Buckets = {}
for _, w in ipairs(Words) do
local c = w:sub(1,1) or ""
if c == "" then c = "#" end
Buckets[c] = Buckets[c] or {}
table.insert(Buckets[c], w)
end
if Config.CustomWords then
for _, w in ipairs(Config.CustomWords) do
local clean = w:gsub("[%s%c]+", ""):lower()
if #clean > 0 and not SeenWords[clean] then
SeenWords[clean] = true
table.insert(Words, clean)
local c = clean:sub(1,1) or ""
if c == "" then c = "#" end
Buckets[c] = Buckets[c] or {}
table.insert(Buckets[c], clean)
end
end
end
-- Clear memory
SeenWords = nil
local function shuffleTable(t)
local n = #t
for i = n, 2, -1 do
local j = math.random(i)
t[i], t[j] = t[j], t[i]
end
return t
end
local HardLetterScores = {
x = 10, z = 9, q = 9, j = 8, v = 6, k = 5, b = 4, f = 3, w = 3,
y = 2, g = 2, p = 2
}
local function GetKillerScore(word)
local lastChar = word:sub(-1)
return HardLetterScores[lastChar] or 0
end
local function Tween(obj, props, time)
TweenService:Create(obj, TweenInfo.new(time or 0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), props):Play()
end
local function GetCurrentGameWord(providedFrame)
local frame = providedFrame
if not frame then
local player = Players.LocalPlayer
local gui = player and player:FindFirstChild("PlayerGui")
local inGame = gui and gui:FindFirstChild("InGame")
frame = inGame and inGame:FindFirstChild("Frame")
end
local container = frame and frame:FindFirstChild("CurrentWord")
if not container then return "", false end
local detected = ""
local censored = false
local children = container:GetChildren()
local letterData = {}
for _, c in ipairs(children) do
if c:IsA("GuiObject") and c.Visible then
local txt = c:FindFirstChild("Letter")
if txt and txt:IsA("TextLabel") and txt.TextTransparency < 1 then
table.insert(letterData, {
Obj = c,
Txt = txt,
X = c.AbsolutePosition.X,
Id = tonumber(c.Name) or 0
})
end
end
end
table.sort(letterData, function(a,b)
if math.abs(a.X - b.X) > 2 then
return a.X < b.X
end
return a.Id < b.Id
end)
for _, data in ipairs(letterData) do
local t = tostring(data.Txt.Text)
if t:find("#") or t:find("%*") then censored = true end
detected = detected .. t
end
return detected:lower():gsub(" ", ""), censored
end
local function GetTurnInfo(providedFrame)
if isMyTurnLogDetected then
if tick() < turnExpiryTime then
return true, logRequiredLetters
else
isMyTurnLogDetected = false
end
end
local frame = providedFrame
if not frame then
local player = Players.LocalPlayer
local gui = player and player:FindFirstChild("PlayerGui")
local inGame = gui and gui:FindFirstChild("InGame")
frame = inGame and inGame:FindFirstChild("Frame")
end
local typeLbl = frame and frame:FindFirstChild("Type")
if typeLbl and typeLbl:IsA("TextLabel") then
local text = typeLbl.Text
local player = Players.LocalPlayer
if text:sub(1, #player.Name) == player.Name or text:sub(1, #player.DisplayName) == player.DisplayName then
local char = text:match("starting with:%s*([A-Za-z])")
return true, char
end
end
return false, nil
end
local function GetSecureParent()
local success, result = pcall(function()
return gethui()
end)
if success and result then return result end
success, result = pcall(function()
return CoreGui
end)
if success and result then return result end
return Players.LocalPlayer.PlayerGui
end
local ParentTarget = GetSecureParent()
local GuiName = tostring(math.random(1000000, 9999999))
local env = (getgenv and getgenv()) or _G
if env.WordHelperInstance and env.WordHelperInstance.Parent then
env.WordHelperInstance:Destroy()
end
local ScreenGui = Instance.new("ScreenGui")
ScreenGui.Name = GuiName
ScreenGui.Parent = ParentTarget
ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
env.WordHelperInstance = ScreenGui
local ToastContainer = Instance.new("Frame", ScreenGui)
ToastContainer.Name = "ToastContainer"
ToastContainer.Size = UDim2.new(0, 300, 1, 0)
ToastContainer.Position = UDim2.new(1, -320, 0, 20)
ToastContainer.BackgroundTransparency = 1
ToastContainer.ZIndex = 100
local function ShowToast(message, type)
local toast = Instance.new("Frame")
toast.Size = UDim2.new(1, 0, 0, 40)
toast.BackgroundColor3 = THEME.ItemBG
toast.BorderSizePixel = 0
toast.BackgroundTransparency = 1
toast.Parent = ToastContainer
local stroke = Instance.new("UIStroke", toast)
stroke.Thickness = 1.5
stroke.Transparency = 1
local color = THEME.Text
if type == "success" then color = THEME.Success
elseif type == "warning" then color = THEME.Warning
elseif type == "error" then color = Color3.fromRGB(255, 80, 80)
end
stroke.Color = color
Instance.new("UICorner", toast).CornerRadius = UDim.new(0, 6)
local lbl = Instance.new("TextLabel", toast)
lbl.Size = UDim2.new(1, -20, 1, 0)
lbl.Position = UDim2.new(0, 10, 0, 0)
lbl.BackgroundTransparency = 1
lbl.Text = message
lbl.TextColor3 = color
lbl.Font = Enum.Font.GothamMedium
lbl.TextSize = 14
lbl.TextWrapped = true
lbl.TextTransparency = 1
Tween(toast, {BackgroundTransparency = 0.1}, 0.3)
Tween(lbl, {TextTransparency = 0}, 0.3)
Tween(stroke, {Transparency = 0.2}, 0.3)
task.delay(3, function()
if toast and toast.Parent then
Tween(toast, {BackgroundTransparency = 1}, 0.5)
Tween(lbl, {TextTransparency = 1}, 0.5)
Tween(stroke, {Transparency = 1}, 0.5)
task.wait(0.5)
toast:Destroy()
end
end)
end
local MainFrame = Instance.new("Frame")
MainFrame.Name = "MainFrame"
MainFrame.Size = UDim2.new(0, 300, 0, 500)
MainFrame.Position = UDim2.new(0.8, -50, 0.4, 0)
MainFrame.BackgroundColor3 = THEME.Background
MainFrame.BorderSizePixel = 0
MainFrame.Active = true
MainFrame.ClipsDescendants = true
MainFrame.Parent = ScreenGui
local function EnableDragging(frame)
local dragging, dragInput, dragStart, startPos
local function Update(input)
local delta = input.Position - dragStart
frame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
end
frame.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragStart = input.Position
startPos = frame.Position
input.Changed:Connect(function()
if input.UserInputState == Enum.UserInputState.End then
dragging = false
end
end)
end
end)
frame.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
Update(input)
end
end)
end
EnableDragging(MainFrame)
Instance.new("UICorner", MainFrame).CornerRadius = UDim.new(0, 10)
local Stroke = Instance.new("UIStroke", MainFrame)
Stroke.Color = THEME.Accent
Stroke.Transparency = 0.5
Stroke.Thickness = 2
local Header = Instance.new("Frame", MainFrame)
Header.Size = UDim2.new(1, 0, 0, 45)
Header.BackgroundColor3 = THEME.ItemBG
Header.BorderSizePixel = 0
local Title = Instance.new("TextLabel", Header)
Title.Text = "WordLongest V4"
Title.RichText = true
Title.Font = Enum.Font.GothamBold
Title.TextSize = 18
Title.TextColor3 = THEME.Text
Title.Size = UDim2.new(1, -50, 1, 0)
Title.Position = UDim2.new(0, 15, 0, 0)
Title.BackgroundTransparency = 1
Title.TextXAlignment = Enum.TextXAlignment.Left
local MinBtn = Instance.new("TextButton", Header)
MinBtn.Text = "-"
MinBtn.Font = Enum.Font.GothamBold
MinBtn.TextSize = 24
MinBtn.TextColor3 = THEME.SubText
MinBtn.Size = UDim2.new(0, 45, 1, 0)
MinBtn.Position = UDim2.new(1, -90, 0, 0)
MinBtn.BackgroundTransparency = 1
local CloseBtn = Instance.new("TextButton", Header)
CloseBtn.Text = "X"
CloseBtn.Font = Enum.Font.GothamBold
CloseBtn.TextSize = 18
CloseBtn.TextColor3 = Color3.fromRGB(255, 80, 80)
CloseBtn.Size = UDim2.new(0, 45, 1, 0)
CloseBtn.Position = UDim2.new(1, -45, 0, 0)
CloseBtn.BackgroundTransparency = 1
CloseBtn.MouseButton1Click:Connect(function()
unloaded = true
if runConn then runConn:Disconnect() runConn = nil end
if inputConn then inputConn:Disconnect() inputConn = nil end
if logConn then logConn:Disconnect() logConn = nil end
for _, btn in ipairs(ButtonCache) do btn:Destroy() end
table.clear(ButtonCache)
if ScreenGui and ScreenGui.Parent then ScreenGui:Destroy() end
end)
local StatusFrame = Instance.new("Frame", MainFrame)
StatusFrame.Size = UDim2.new(1, -30, 0, 24)
StatusFrame.Position = UDim2.new(0, 15, 0, 55)
StatusFrame.BackgroundTransparency = 1
local StatusDot = Instance.new("Frame", StatusFrame)
StatusDot.Size = UDim2.new(0, 8, 0, 8)
StatusDot.Position = UDim2.new(0, 0, 0.5, -4)
StatusDot.BackgroundColor3 = THEME.SubText
Instance.new("UICorner", StatusDot).CornerRadius = UDim.new(1, 0)
local StatusText = Instance.new("TextLabel", StatusFrame)
StatusText.Text = "Idle..."
StatusText.RichText = true
StatusText.Font = Enum.Font.Gotham
StatusText.TextSize = 12
StatusText.TextColor3 = THEME.SubText
StatusText.Size = UDim2.new(1, -15, 1, 0)
StatusText.Position = UDim2.new(0, 15, 0, 0)
StatusText.BackgroundTransparency = 1
StatusText.TextXAlignment = Enum.TextXAlignment.Left
local SearchFrame = Instance.new("Frame", MainFrame)
SearchFrame.Size = UDim2.new(1, -10, 0, 26)
SearchFrame.Position = UDim2.new(0, 5, 0, 82)
SearchFrame.BackgroundColor3 = THEME.ItemBG
Instance.new("UICorner", SearchFrame).CornerRadius = UDim.new(0, 6)
local SearchBox = Instance.new("TextBox", SearchFrame)
SearchBox.Size = UDim2.new(1, -20, 1, 0)
SearchBox.Position = UDim2.new(0, 10, 0, 0)
SearchBox.BackgroundTransparency = 1
SearchBox.Font = Enum.Font.Gotham
SearchBox.TextSize = 14
SearchBox.TextColor3 = THEME.Text
SearchBox.PlaceholderText = "Search words..."
SearchBox.PlaceholderColor3 = THEME.SubText
SearchBox.Text = ""
SearchBox.TextXAlignment = Enum.TextXAlignment.Left
SearchBox:GetPropertyChangedSignal("Text"):Connect(function()
if UpdateList then
UpdateList(lastDetected, lastRequiredLetter)
end
end)
local ScrollList = Instance.new("ScrollingFrame", MainFrame)
ScrollList.Size = UDim2.new(1, -10, 1, -220)
ScrollList.Position = UDim2.new(0, 5, 0, 115)
ScrollList.BackgroundTransparency = 1
ScrollList.ScrollBarThickness = 3
ScrollList.ScrollBarImageColor3 = THEME.Accent
ScrollList.CanvasSize = UDim2.new(0,0,0,0)
local UIListLayout = Instance.new("UIListLayout", ScrollList)
UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
UIListLayout.Padding = UDim.new(0, 4)
local SettingsFrame = Instance.new("Frame", MainFrame)
SettingsFrame.BackgroundColor3 = THEME.ItemBG
SettingsFrame.BorderSizePixel = 0
SettingsFrame.ClipsDescendants = true
local SlidersFrame = Instance.new("Frame", SettingsFrame)
SlidersFrame.Size = UDim2.new(1, 0, 0, 125)
SlidersFrame.BackgroundTransparency = 1
local TogglesFrame = Instance.new("Frame", SettingsFrame)
TogglesFrame.Size = UDim2.new(1, 0, 0, 310)
TogglesFrame.Position = UDim2.new(0, 0, 0, 125)
TogglesFrame.BackgroundTransparency = 1
TogglesFrame.Visible = false
local sep = Instance.new("Frame", SettingsFrame)
sep.Size = UDim2.new(1, 0, 0, 1)
sep.BackgroundColor3 = Color3.fromRGB(45, 45, 50)
local settingsCollapsed = true
local function UpdateLayout()
if settingsCollapsed then
Tween(SettingsFrame, {Size = UDim2.new(1, 0, 0, 125), Position = UDim2.new(0, 0, 1, -125)})
Tween(ScrollList, {Size = UDim2.new(1, -10, 1, -245)})
TogglesFrame.Visible = false
else
Tween(SettingsFrame, {Size = UDim2.new(1, 0, 0, 435), Position = UDim2.new(0, 0, 1, -435)})
Tween(ScrollList, {Size = UDim2.new(1, -10, 1, -555)})
TogglesFrame.Visible = true
end
end
UpdateLayout()
local ExpandBtn = Instance.new("TextButton", SlidersFrame)
ExpandBtn.Text = "v Show Settings v"
ExpandBtn.Font = Enum.Font.GothamBold
ExpandBtn.TextSize = 14
ExpandBtn.TextColor3 = THEME.Accent
ExpandBtn.BackgroundColor3 = Color3.fromRGB(40, 40, 45)
ExpandBtn.BackgroundTransparency = 0.5
ExpandBtn.Size = UDim2.new(1, -10, 0, 30)
ExpandBtn.Position = UDim2.new(0, 5, 1, -35)
Instance.new("UICorner", ExpandBtn).CornerRadius = UDim.new(0, 6)
ExpandBtn.MouseButton1Click:Connect(function()
settingsCollapsed = not settingsCollapsed
ExpandBtn.Text = settingsCollapsed and "v Show Settings v" or "^ Hide Settings ^"
UpdateLayout()
end)
local function SetupSlider(btn, bg, fill, callback)
btn.MouseButton1Down:Connect(function()
local move, rel
local function Update()
local mousePos = UserInputService:GetMouseLocation()
local relX = math.clamp(mousePos.X - bg.AbsolutePosition.X, 0, bg.AbsoluteSize.X)
local pct = relX / bg.AbsoluteSize.X
callback(pct)
Config.CPM = currentCPM
Config.ErrorRate = errorRate
Config.ThinkDelay = thinkDelayCurrent
end
Update()
move = RunService.RenderStepped:Connect(Update)
rel = UserInputService.InputEnded:Connect(function(inp)
if inp.UserInputType == Enum.UserInputType.MouseButton1 or inp.UserInputType == Enum.UserInputType.Touch then
if move then move:Disconnect() move = nil end
if rel then rel:Disconnect() rel = nil end
SaveConfig()
end
end)
end)
end
local KeyboardFrame = Instance.new("Frame", ScreenGui)
KeyboardFrame.Name = "KeyboardFrame"
KeyboardFrame.Size = UDim2.new(0, 400, 0, 160)
KeyboardFrame.Position = UDim2.new(0.1, 0, 0.5, -80)
KeyboardFrame.BackgroundColor3 = THEME.Background
KeyboardFrame.Visible = showKeyboard
EnableDragging(KeyboardFrame)
Instance.new("UICorner", KeyboardFrame).CornerRadius = UDim.new(0, 8)
local KStroke = Instance.new("UIStroke", KeyboardFrame)
KStroke.Color = THEME.Accent
KStroke.Transparency = 0.6
KStroke.Thickness = 2
local Keys = {}
local function CreateKey(char, pos, size)
local k = Instance.new("Frame", KeyboardFrame)
k.Size = size or UDim2.new(0, 30, 0, 30)
k.Position = pos
k.BackgroundColor3 = THEME.ItemBG
Instance.new("UICorner", k).CornerRadius = UDim.new(0, 4)
local l = Instance.new("TextLabel", k)
l.Size = UDim2.new(1,0,1,0)
l.BackgroundTransparency = 1
l.Text = char:upper()
l.TextColor3 = THEME.Text
l.Font = Enum.Font.GothamBold
l.TextSize = 14
Keys[char:lower()] = k
return k
end
local function GenerateKeyboard()
for _, c in ipairs(KeyboardFrame:GetChildren()) do
if c:IsA("Frame") or c:IsA("TextLabel") then c:Destroy() end
end
Keys = {}
local rows
if keyboardLayout == "QWERTZ" then
rows = {
{"q","w","e","r","t","z","u","i","o","p"},
{"a","s","d","f","g","h","j","k","l"},
{"y","x","c","v","b","n","m"}
}
elseif keyboardLayout == "AZERTY" then
rows = {
{"a","z","e","r","t","y","u","i","o","p"},
{"q","s","d","f","g","h","j","k","l","m"},
{"w","x","c","v","b","n"}
}
else -- QWERTY
rows = {
{"q","w","e","r","t","y","u","i","o","p"},
{"a","s","d","f","g","h","j","k","l"},
{"z","x","c","v","b","n","m"}
}
end
local startY = 15
local spacing = 35
for r, rowChars in ipairs(rows) do
local rowWidth = #rowChars * 35
local startX = (400 - rowWidth) / 2
for i = 1, #rowChars do
local char = rowChars[i]
CreateKey(char, UDim2.new(0, startX + (i-1)*35, 0, startY + (r-1)*35))
end
end
local space = CreateKey(" ", UDim2.new(0.5, -100, 0, startY + 3*35), UDim2.new(0, 200, 0, 30))
space.FindFirstChild(space, "TextLabel").Text = "SPACE"
end
GenerateKeyboard()
local function CreateDropdown(parent, text, options, default, callback)
local container = Instance.new("Frame", parent)
container.Size = UDim2.new(0, 130, 0, 24)
container.BackgroundColor3 = THEME.Background
container.ZIndex = 10
Instance.new("UICorner", container).CornerRadius = UDim.new(0, 4)
local mainBtn = Instance.new("TextButton", container)
mainBtn.Size = UDim2.new(1, 0, 1, 0)
mainBtn.BackgroundTransparency = 1
mainBtn.Text = text .. ": " .. default
mainBtn.Font = Enum.Font.GothamMedium
mainBtn.TextSize = 11
mainBtn.TextColor3 = THEME.Accent
mainBtn.ZIndex = 11
local listFrame = Instance.new("Frame", container)
listFrame.Size = UDim2.new(1, 0, 0, #options * 24)
listFrame.Position = UDim2.new(0, 0, 1, 2)
listFrame.BackgroundColor3 = THEME.ItemBG
listFrame.Visible = false
listFrame.ZIndex = 20
Instance.new("UICorner", listFrame).CornerRadius = UDim.new(0, 4)
local isOpen = false
mainBtn.MouseButton1Click:Connect(function()
isOpen = not isOpen
listFrame.Visible = isOpen
end)
for i, opt in ipairs(options) do
local btn = Instance.new("TextButton", listFrame)
btn.Size = UDim2.new(1, 0, 0, 24)
btn.Position = UDim2.new(0, 0, 0, (i-1)*24)
btn.BackgroundTransparency = 1
btn.Text = opt
btn.Font = Enum.Font.Gotham
btn.TextSize = 11
btn.TextColor3 = THEME.Text
btn.ZIndex = 21
btn.MouseButton1Click:Connect(function()
mainBtn.Text = text .. ": " .. opt
isOpen = false
listFrame.Visible = false
callback(opt)
end)
end
return container
end
local LayoutDropdown = CreateDropdown(TogglesFrame, "Layout", {"QWERTY", "QWERTZ", "AZERTY"}, keyboardLayout, function(val)
keyboardLayout = val
Config.KeyboardLayout = keyboardLayout
GenerateKeyboard()
SaveConfig()
end)
LayoutDropdown.Position = UDim2.new(0, 150, 0, 145)
UserInputService.InputBegan:Connect(function(input)
if not showKeyboard then return end
if input.UserInputType == Enum.UserInputType.Keyboard then
local char = input.KeyCode.Name:lower()
if Keys[char] then
Tween(Keys[char], {BackgroundColor3 = THEME.Accent}, 0.1)
end
if input.KeyCode == Enum.KeyCode.Space then
Tween(Keys[" "], {BackgroundColor3 = THEME.Accent}, 0.1)
end
end
end)
UserInputService.InputEnded:Connect(function(input)
if not showKeyboard then return end
if input.UserInputType == Enum.UserInputType.Keyboard then
local char = input.KeyCode.Name:lower()
if Keys[char] then
Tween(Keys[char], {BackgroundColor3 = THEME.ItemBG}, 0.2)
end
if input.KeyCode == Enum.KeyCode.Space then
Tween(Keys[" "], {BackgroundColor3 = THEME.ItemBG}, 0.2)
end
end
end)
local SliderLabel = Instance.new("TextLabel", SlidersFrame)
SliderLabel.Text = "Speed: " .. currentCPM .. " CPM"
SliderLabel.Font = Enum.Font.GothamMedium
SliderLabel.TextSize = 12
SliderLabel.TextColor3 = THEME.SubText
SliderLabel.Size = UDim2.new(1, -30, 0, 20)
SliderLabel.Position = UDim2.new(0, 15, 0, 8)
SliderLabel.BackgroundTransparency = 1
SliderLabel.TextXAlignment = Enum.TextXAlignment.Left
local SliderBg = Instance.new("Frame", SlidersFrame)
SliderBg.Size = UDim2.new(1, -30, 0, 6)
SliderBg.Position = UDim2.new(0, 15, 0, 30)
SliderBg.BackgroundColor3 = THEME.Slider
Instance.new("UICorner", SliderBg).CornerRadius = UDim.new(1, 0)
local SliderFill = Instance.new("Frame", SliderBg)
SliderFill.Size = UDim2.new(0.5, 0, 1, 0)
SliderFill.BackgroundColor3 = THEME.Accent
Instance.new("UICorner", SliderFill).CornerRadius = UDim.new(1, 0)
local SliderBtn = Instance.new("TextButton", SliderBg)
SliderBtn.Size = UDim2.new(1,0,1,0)
SliderBtn.BackgroundTransparency = 1
SliderBtn.Text = ""
local ErrorLabel = Instance.new("TextLabel", SlidersFrame)
ErrorLabel.Text = "Error Rate: " .. errorRate .. "%"
ErrorLabel.Font = Enum.Font.GothamMedium
ErrorLabel.TextSize = 11
ErrorLabel.TextColor3 = THEME.SubText
ErrorLabel.Size = UDim2.new(1, -30, 0, 18)
ErrorLabel.Position = UDim2.new(0, 15, 0, 36)
ErrorLabel.BackgroundTransparency = 1
ErrorLabel.TextXAlignment = Enum.TextXAlignment.Left
local ErrorBg = Instance.new("Frame", SlidersFrame)
ErrorBg.Size = UDim2.new(1, -30, 0, 6)
ErrorBg.Position = UDim2.new(0, 15, 0, 56)
ErrorBg.BackgroundColor3 = THEME.Slider
Instance.new("UICorner", ErrorBg).CornerRadius = UDim.new(1, 0)
local ErrorFill = Instance.new("Frame", ErrorBg)
ErrorFill.Size = UDim2.new(errorRate/30, 0, 1, 0)
ErrorFill.BackgroundColor3 = Color3.fromRGB(200, 100, 100)
Instance.new("UICorner", ErrorFill).CornerRadius = UDim.new(1, 0)
local ErrorBtn = Instance.new("TextButton", ErrorBg)
ErrorBtn.Size = UDim2.new(1,0,1,0)
ErrorBtn.BackgroundTransparency = 1
ErrorBtn.Text = ""
SetupSlider(ErrorBtn, ErrorBg, ErrorFill, function(pct)
errorRate = math.floor(pct * 30)
Config.ErrorRate = errorRate
ErrorFill.Size = UDim2.new(pct, 0, 1, 0)
ErrorLabel.Text = "Error Rate: " .. errorRate .. "% (per-letter)"
end)
local ThinkLabel = Instance.new("TextLabel", SlidersFrame)
ThinkLabel.Text = string.format("Think: %.2fs", thinkDelayCurrent)
ThinkLabel.Font = Enum.Font.GothamMedium
ThinkLabel.TextSize = 11
ThinkLabel.TextColor3 = THEME.SubText
ThinkLabel.Size = UDim2.new(1, -30, 0, 18)
ThinkLabel.Position = UDim2.new(0, 15, 0, 62)
ThinkLabel.BackgroundTransparency = 1
ThinkLabel.TextXAlignment = Enum.TextXAlignment.Left
local ThinkBg = Instance.new("Frame", SlidersFrame)
ThinkBg.Size = UDim2.new(1, -30, 0, 6)
ThinkBg.Position = UDim2.new(0, 15, 0, 82)
ThinkBg.BackgroundColor3 = THEME.Slider
Instance.new("UICorner", ThinkBg).CornerRadius = UDim.new(1, 0)
local ThinkFill = Instance.new("Frame", ThinkBg)
local thinkPct = (thinkDelayCurrent - thinkDelayMin) / (thinkDelayMax - thinkDelayMin)
ThinkFill.Size = UDim2.new(thinkPct, 0, 1, 0)
ThinkFill.BackgroundColor3 = THEME.Accent
Instance.new("UICorner", ThinkFill).CornerRadius = UDim.new(1, 0)
local ThinkBtn = Instance.new("TextButton", ThinkBg)
ThinkBtn.Size = UDim2.new(1,0,1,0)
ThinkBtn.BackgroundTransparency = 1
ThinkBtn.Text = ""
SetupSlider(ThinkBtn, ThinkBg, ThinkFill, function(pct)
thinkDelayCurrent = thinkDelayMin + pct * (thinkDelayMax - thinkDelayMin)
Config.ThinkDelay = thinkDelayCurrent
ThinkFill.Size = UDim2.new(pct, 0, 1, 0)
ThinkLabel.Text = string.format("Think: %.2fs", thinkDelayCurrent)
end)
local function CreateToggle(text, pos, callback)
local btn = Instance.new("TextButton", TogglesFrame)
btn.Text = text
btn.Font = Enum.Font.GothamMedium
btn.TextSize = 11
btn.TextColor3 = THEME.Success
btn.BackgroundColor3 = THEME.Background
btn.Size = UDim2.new(0, 85, 0, 24)
btn.Position = pos
Instance.new("UICorner", btn).CornerRadius = UDim.new(0, 4)
btn.MouseButton1Click:Connect(function()
local newState, newText, newColor = callback()
btn.Text = newText
btn.TextColor3 = newColor
SaveConfig()
end)
return btn
end
local HumanizeBtn = CreateToggle("Humanize: "..(useHumanization and "ON" or "OFF"), UDim2.new(0, 15, 0, 5), function()
useHumanization = not useHumanization
Config.Humanize = useHumanization
return useHumanization, "Humanize: "..(useHumanization and "ON" or "OFF"), useHumanization and THEME.Success or Color3.fromRGB(255, 100, 100)
end)
HumanizeBtn.TextColor3 = useHumanization and THEME.Success or Color3.fromRGB(255, 100, 100)
local FingerBtn = CreateToggle("10-Finger: "..(useFingerModel and "ON" or "OFF"), UDim2.new(0, 105, 0, 5), function()
useFingerModel = not useFingerModel
Config.FingerModel = useFingerModel
return useFingerModel, "10-Finger: "..(useFingerModel and "ON" or "OFF"), useFingerModel and THEME.Success or Color3.fromRGB(255, 100, 100)
end)
FingerBtn.TextColor3 = useFingerModel and THEME.Success or Color3.fromRGB(255, 100, 100)
local KeyboardBtn = CreateToggle("Keyboard: "..(showKeyboard and "ON" or "OFF"), UDim2.new(0, 195, 0, 5), function()
showKeyboard = not showKeyboard
Config.ShowKeyboard = showKeyboard
KeyboardFrame.Visible = showKeyboard
return showKeyboard, "Keyboard: "..(showKeyboard and "ON" or "OFF"), showKeyboard and THEME.Success or Color3.fromRGB(255, 100, 100)
end)
KeyboardBtn.TextColor3 = showKeyboard and THEME.Success or Color3.fromRGB(255, 100, 100)
local SortBtn = CreateToggle("Sort: "..sortMode, UDim2.new(0, 15, 0, 33), function()
if sortMode == "Random" then sortMode = "Shortest"
elseif sortMode == "Shortest" then sortMode = "Longest"
elseif sortMode == "Longest" then sortMode = "Killer"
else sortMode = "Random" end
Config.SortMode = sortMode
lastDetected = "---"
return true, "Sort: "..sortMode, THEME.Accent
end)
SortBtn.TextColor3 = THEME.Accent
SortBtn.Size = UDim2.new(0, 130, 0, 24)
local AutoBtn = CreateToggle("Auto Play: "..(autoPlay and "ON" or "OFF"), UDim2.new(0, 150, 0, 33), function()
autoPlay = not autoPlay
Config.AutoPlay = autoPlay
return autoPlay, "Auto Play: "..(autoPlay and "ON" or "OFF"), autoPlay and THEME.Success or Color3.fromRGB(255, 100, 100)
end)
AutoBtn.TextColor3 = autoPlay and THEME.Success or Color3.fromRGB(255, 100, 100)
AutoBtn.Size = UDim2.new(0, 130, 0, 24)
local AutoJoinBtn = CreateToggle("Auto Join: "..(autoJoin and "ON" or "OFF"), UDim2.new(0, 15, 0, 61), function()
autoJoin = not autoJoin
Config.AutoJoin = autoJoin
return autoJoin, "Auto Join: "..(autoJoin and "ON" or "OFF"), autoJoin and THEME.Success or Color3.fromRGB(255, 100, 100)
end)
AutoJoinBtn.TextColor3 = autoJoin and THEME.Success or Color3.fromRGB(255, 100, 100)
AutoJoinBtn.Size = UDim2.new(0, 265, 0, 24)
local function CreateCheckbox(text, pos, key)
local container = Instance.new("TextButton", TogglesFrame)
container.Size = UDim2.new(0, 90, 0, 24)
container.Position = pos
container.BackgroundColor3 = THEME.ItemBG
container.AutoButtonColor = false
container.Text = ""
Instance.new("UICorner", container).CornerRadius = UDim.new(0, 4)
local box = Instance.new("Frame", container)
box.Size = UDim2.new(0, 14, 0, 14)
box.Position = UDim2.new(0, 5, 0.5, -7)
box.BackgroundColor3 = THEME.Slider
Instance.new("UICorner", box).CornerRadius = UDim.new(0, 3)
local check = Instance.new("Frame", box)
check.Size = UDim2.new(0, 8, 0, 8)
check.Position = UDim2.new(0.5, -4, 0.5, -4)
check.BackgroundColor3 = THEME.Success
check.Visible = Config.AutoJoinSettings[key]
Instance.new("UICorner", check).CornerRadius = UDim.new(0, 2)
local lbl = Instance.new("TextLabel", container)
lbl.Text = text
lbl.Font = Enum.Font.GothamMedium
lbl.TextSize = 11
lbl.TextColor3 = THEME.SubText
lbl.Size = UDim2.new(1, -25, 1, 0)
lbl.Position = UDim2.new(0, 25, 0, 0)
lbl.BackgroundTransparency = 1
lbl.TextXAlignment = Enum.TextXAlignment.Left
container.MouseButton1Click:Connect(function()
Config.AutoJoinSettings[key] = not Config.AutoJoinSettings[key]
check.Visible = Config.AutoJoinSettings[key]
if Config.AutoJoinSettings[key] then
lbl.TextColor3 = THEME.Text
Tween(box, {BackgroundColor3 = THEME.Accent}, 0.2)
else
lbl.TextColor3 = THEME.SubText
Tween(box, {BackgroundColor3 = THEME.Slider}, 0.2)
end
SaveConfig()
end)
if Config.AutoJoinSettings[key] then
lbl.TextColor3 = THEME.Text
box.BackgroundColor3 = THEME.Accent
end
return container
end
CreateCheckbox("1v1", UDim2.new(0, 15, 0, 88), "_1v1")
CreateCheckbox("4 Player", UDim2.new(0, 110, 0, 88), "_4p")
CreateCheckbox("8 Player", UDim2.new(0, 205, 0, 88), "_8p")
local BlatantBtn = CreateToggle("Blatant Mode: "..(isBlatant and "ON" or "OFF"), UDim2.new(0, 15, 0, 115), function()
isBlatant = not isBlatant
Config.Blatant = isBlatant
return isBlatant, "Blatant Mode: "..(isBlatant and "ON" or "OFF"), isBlatant and Color3.fromRGB(255, 80, 80) or THEME.SubText
end)
BlatantBtn.TextColor3 = isBlatant and Color3.fromRGB(255, 80, 80) or THEME.SubText
BlatantBtn.Size = UDim2.new(0, 130, 0, 24)
local RiskyBtn = CreateToggle("Risky Mistakes: "..(riskyMistakes and "ON" or "OFF"), UDim2.new(0, 150, 0, 115), function()
riskyMistakes = not riskyMistakes
Config.RiskyMistakes = riskyMistakes
return riskyMistakes, "Risky Mistakes: "..(riskyMistakes and "ON" or "OFF"), riskyMistakes and Color3.fromRGB(255, 80, 80) or THEME.SubText
end)
RiskyBtn.TextColor3 = riskyMistakes and Color3.fromRGB(255, 80, 80) or THEME.SubText
RiskyBtn.Size = UDim2.new(0, 130, 0, 24)
local ManageWordsBtn = Instance.new("TextButton", TogglesFrame)
ManageWordsBtn.Text = "Manage Custom Words"
ManageWordsBtn.Font = Enum.Font.GothamMedium
ManageWordsBtn.TextSize = 11
ManageWordsBtn.TextColor3 = THEME.Accent
ManageWordsBtn.BackgroundColor3 = THEME.Background
ManageWordsBtn.Size = UDim2.new(0, 130, 0, 24)
ManageWordsBtn.Position = UDim2.new(0, 15, 0, 145)
Instance.new("UICorner", ManageWordsBtn).CornerRadius = UDim.new(0, 4)
local WordBrowserBtn = Instance.new("TextButton", TogglesFrame)
WordBrowserBtn.Text = "Word Browser"
WordBrowserBtn.Font = Enum.Font.GothamMedium
WordBrowserBtn.TextSize = 11
WordBrowserBtn.TextColor3 = Color3.fromRGB(200, 150, 255)
WordBrowserBtn.BackgroundColor3 = THEME.Background
WordBrowserBtn.Size = UDim2.new(0, 265, 0, 24)
WordBrowserBtn.Position = UDim2.new(0, 15, 0, 175)
Instance.new("UICorner", WordBrowserBtn).CornerRadius = UDim.new(0, 4)
local ServerBrowserBtn = Instance.new("TextButton", TogglesFrame)
ServerBrowserBtn.Text = "Server Browser"
ServerBrowserBtn.Font = Enum.Font.GothamMedium
ServerBrowserBtn.TextSize = 11
ServerBrowserBtn.TextColor3 = Color3.fromRGB(100, 200, 255)
ServerBrowserBtn.BackgroundColor3 = THEME.Background
ServerBrowserBtn.Size = UDim2.new(0, 265, 0, 24)
ServerBrowserBtn.Position = UDim2.new(0, 15, 0, 205)
Instance.new("UICorner", ServerBrowserBtn).CornerRadius = UDim.new(0, 4)
local CustomWordsFrame = Instance.new("Frame", ScreenGui)
CustomWordsFrame.Name = "CustomWordsFrame"
CustomWordsFrame.Size = UDim2.new(0, 250, 0, 350)
CustomWordsFrame.Position = UDim2.new(0.5, -125, 0.5, -175)
CustomWordsFrame.BackgroundColor3 = THEME.Background
CustomWordsFrame.Visible = false
CustomWordsFrame.ClipsDescendants = true
EnableDragging(CustomWordsFrame)
Instance.new("UICorner", CustomWordsFrame).CornerRadius = UDim.new(0, 8)
local CWStroke = Instance.new("UIStroke", CustomWordsFrame)
CWStroke.Color = THEME.Accent
CWStroke.Transparency = 0.5
CWStroke.Thickness = 2
local CWHeader = Instance.new("TextLabel", CustomWordsFrame)
CWHeader.Text = "Custom Words Manager"
CWHeader.Font = Enum.Font.GothamBold
CWHeader.TextSize = 14
CWHeader.TextColor3 = THEME.Text
CWHeader.Size = UDim2.new(1, 0, 0, 35)
CWHeader.BackgroundTransparency = 1
local CWCloseBtn = Instance.new("TextButton", CustomWordsFrame)
CWCloseBtn.Text = "X"
CWCloseBtn.Font = Enum.Font.GothamBold
CWCloseBtn.TextSize = 14
CWCloseBtn.TextColor3 = Color3.fromRGB(255, 100, 100)
CWCloseBtn.Size = UDim2.new(0, 30, 0, 30)
CWCloseBtn.Position = UDim2.new(1, -30, 0, 2)
CWCloseBtn.BackgroundTransparency = 1
CWCloseBtn.MouseButton1Click:Connect(function() CustomWordsFrame.Visible = false end)
ManageWordsBtn.MouseButton1Click:Connect(function()
CustomWordsFrame.Visible = not CustomWordsFrame.Visible
CustomWordsFrame.Parent = nil
CustomWordsFrame.Parent = ScreenGui
end)
local function SetupPhantomBox(box, placeholder)
box.Text = placeholder
box.TextColor3 = THEME.SubText
box.Focused:Connect(function()
if box.Text == placeholder then
box.Text = ""
box.TextColor3 = THEME.Text
end
end)
box.FocusLost:Connect(function()
if box.Text == "" then
box.Text = placeholder
box.TextColor3 = THEME.SubText
end
end)
end
local CWSearchBox = Instance.new("TextBox", CustomWordsFrame)
CWSearchBox.Font = Enum.Font.Gotham
CWSearchBox.TextSize = 12
CWSearchBox.BackgroundColor3 = THEME.ItemBG
CWSearchBox.Size = UDim2.new(1, -20, 0, 24)
CWSearchBox.Position = UDim2.new(0, 10, 0, 35)
Instance.new("UICorner", CWSearchBox).CornerRadius = UDim.new(0, 4)
SetupPhantomBox(CWSearchBox, "Search words...")
local CWScroll = Instance.new("ScrollingFrame", CustomWordsFrame)
CWScroll.Size = UDim2.new(1, -10, 1, -110)
CWScroll.Position = UDim2.new(0, 5, 0, 65)
CWScroll.BackgroundTransparency = 1
CWScroll.ScrollBarThickness = 2
CWScroll.ScrollBarImageColor3 = THEME.Accent
CWScroll.CanvasSize = UDim2.new(0,0,0,0)
local CWListLayout = Instance.new("UIListLayout", CWScroll)
CWListLayout.SortOrder = Enum.SortOrder.LayoutOrder
CWListLayout.Padding = UDim.new(0, 2)
local CWAddBox = Instance.new("TextBox", CustomWordsFrame)
CWAddBox.Font = Enum.Font.Gotham
CWAddBox.TextSize = 12
CWAddBox.BackgroundColor3 = THEME.ItemBG
CWAddBox.Size = UDim2.new(0, 170, 0, 24)
CWAddBox.Position = UDim2.new(0, 10, 1, -35)
Instance.new("UICorner", CWAddBox).CornerRadius = UDim.new(0, 4)
SetupPhantomBox(CWAddBox, "Add new word...")
local CWAddBtn = Instance.new("TextButton", CustomWordsFrame)
CWAddBtn.Text = "Add"
CWAddBtn.Font = Enum.Font.GothamBold
CWAddBtn.TextSize = 11
CWAddBtn.TextColor3 = THEME.Success
CWAddBtn.BackgroundColor3 = THEME.ItemBG
CWAddBtn.Size = UDim2.new(0, 50, 0, 24)
CWAddBtn.Position = UDim2.new(1, -60, 1, -35)
Instance.new("UICorner", CWAddBtn).CornerRadius = UDim.new(0, 4)
local function RefreshCustomWords()
for _, c in ipairs(CWScroll:GetChildren()) do
if c:IsA("Frame") then c:Destroy() end
end
local queryRaw = CWSearchBox.Text
local query = (queryRaw == "Search words...") and "" or queryRaw:lower():gsub("[%s%c]+", "")
local list = Config.CustomWords or {}
local shownCount = 0
for i, w in ipairs(list) do
if query == "" or w:find(query, 1, true) then
shownCount = shownCount + 1
local row = Instance.new("TextButton", CWScroll)
row.Size = UDim2.new(1, -6, 0, 22)
row.BackgroundColor3 = (shownCount % 2 == 0) and Color3.fromRGB(25,25,30) or Color3.fromRGB(30,30,35)
row.BorderSizePixel = 0
row.Text = ""
row.AutoButtonColor = false
Instance.new("UICorner", row).CornerRadius = UDim.new(0, 4)
row.MouseButton1Click:Connect(function()
SmartType(w, lastDetected, true, true)
Tween(row, {BackgroundColor3 = THEME.Accent}, 0.2)
task.delay(0.2, function()
Tween(row, {BackgroundColor3 = (shownCount % 2 == 0) and Color3.fromRGB(25,25,30) or Color3.fromRGB(30,30,35)}, 0.2)
end)
end)
local lbl = Instance.new("TextLabel", row)
lbl.Text = w
lbl.Font = Enum.Font.Gotham
lbl.TextSize = 12
lbl.TextColor3 = THEME.Text
lbl.Size = UDim2.new(1, -30, 1, 0)
lbl.Position = UDim2.new(0, 5, 0, 0)
lbl.BackgroundTransparency = 1
lbl.TextXAlignment = Enum.TextXAlignment.Left
-- Removed nested invisible button to fix click handling
local del = Instance.new("TextButton", row)
del.Text = "X"
del.Font = Enum.Font.GothamBold
del.TextSize = 11
del.TextColor3 = Color3.fromRGB(255, 80, 80)
del.Size = UDim2.new(0, 22, 1, 0)
del.Position = UDim2.new(1, -22, 0, 0)
del.BackgroundTransparency = 1
del.MouseButton1Click:Connect(function()
table.remove(Config.CustomWords, i)
SaveConfig()
Blacklist[w] = true
RefreshCustomWords()
ShowToast("Removed: " .. w, "warning")
end)
end
end
CWScroll.CanvasSize = UDim2.new(0, 0, 0, shownCount * 24)
end
CWSearchBox:GetPropertyChangedSignal("Text"):Connect(RefreshCustomWords)
CWAddBtn.MouseButton1Click:Connect(function()
local text = CWAddBox.Text
if text == "Add new word..." then return end
text = text:gsub("[%s%c]+", ""):lower()
if #text < 2 then return end
if not Config.CustomWords then Config.CustomWords = {} end
for _, w in ipairs(Config.CustomWords) do
if w == text then
ShowToast("Word already in custom list!", "warning")
return
end
end
local existsInMain = false
local c = text:sub(1,1)
if Buckets and Buckets[c] then
for _, w in ipairs(Buckets[c]) do
if w == text then existsInMain = true break end
end
end
if existsInMain then
ShowToast("Word already in main dictionary!", "error")
return
end
table.insert(Config.CustomWords, text)
SaveConfig()
table.insert(Words, text)
if c == "" then c = "#" end
Buckets[c] = Buckets[c] or {}
table.insert(Buckets[c], text)
CWAddBox.Text = ""
CWAddBox:ReleaseFocus()
RefreshCustomWords()
ShowToast("Added custom word: " .. text, "success")
end)
RefreshCustomWords()
local ServerFrame = Instance.new("Frame", ScreenGui)
ServerFrame.Name = "ServerBrowser"
ServerFrame.Size = UDim2.new(0, 350, 0, 400)
ServerFrame.Position = UDim2.new(0.5, -175, 0.5, -200)
ServerFrame.BackgroundColor3 = THEME.Background
ServerFrame.Visible = false
ServerFrame.ClipsDescendants = true
EnableDragging(ServerFrame)
Instance.new("UICorner", ServerFrame).CornerRadius = UDim.new(0, 8)
local SBStroke = Instance.new("UIStroke", ServerFrame)
SBStroke.Color = THEME.Accent
SBStroke.Transparency = 0.5
SBStroke.Thickness = 2
local SBHeader = Instance.new("TextLabel", ServerFrame)
SBHeader.Text = "Server Browser"
SBHeader.Font = Enum.Font.GothamBold
SBHeader.TextSize = 16
SBHeader.TextColor3 = THEME.Text
SBHeader.Size = UDim2.new(1, 0, 0, 40)
SBHeader.BackgroundTransparency = 1
local SBClose = Instance.new("TextButton", ServerFrame)
SBClose.Text = "X"
SBClose.Font = Enum.Font.GothamBold
SBClose.TextSize = 16
SBClose.TextColor3 = Color3.fromRGB(255, 100, 100)
SBClose.Size = UDim2.new(0, 40, 0, 40)
SBClose.Position = UDim2.new(1, -40, 0, 0)
SBClose.BackgroundTransparency = 1
SBClose.MouseButton1Click:Connect(function() ServerFrame.Visible = false end)
local SBList = Instance.new("ScrollingFrame", ServerFrame)
SBList.Size = UDim2.new(1, -20, 1, -90)
SBList.Position = UDim2.new(0, 10, 0, 50)
SBList.BackgroundTransparency = 1
SBList.ScrollBarThickness = 3
SBList.ScrollBarImageColor3 = THEME.Accent
local SBLayout = Instance.new("UIListLayout", SBList)
SBLayout.Padding = UDim.new(0, 5)
SBLayout.SortOrder = Enum.SortOrder.LayoutOrder
local ServerSortMode = "Smallest"
local SBSortBtn = Instance.new("TextButton", ServerFrame)
SBSortBtn.Text = "Sort: Smallest"
SBSortBtn.Font = Enum.Font.GothamBold
SBSortBtn.TextSize = 12
SBSortBtn.BackgroundColor3 = THEME.ItemBG
SBSortBtn.TextColor3 = THEME.SubText
SBSortBtn.Size = UDim2.new(0.5, -15, 0, 30)
SBSortBtn.Position = UDim2.new(0, 10, 1, -40)
Instance.new("UICorner", SBSortBtn).CornerRadius = UDim.new(0, 6)
local SBRefresh = Instance.new("TextButton", ServerFrame)
SBRefresh.Text = "Refresh"
SBRefresh.Font = Enum.Font.GothamBold
SBRefresh.TextSize = 12
SBRefresh.BackgroundColor3 = THEME.Accent
SBRefresh.Size = UDim2.new(0.5, -15, 0, 30)
SBRefresh.Position = UDim2.new(0.5, 5, 1, -40)
Instance.new("UICorner", SBRefresh).CornerRadius = UDim.new(0, 6)
local function FetchServers()
SBRefresh.Text = "..."
for _, c in ipairs(SBList:GetChildren()) do
if c:IsA("Frame") then c:Destroy() end
end
task.spawn(function()
local success, result = pcall(function()
return request({
Url = "https://games.roblox.com/v1/games/" .. game.PlaceId .. "/servers/Public?sortOrder=Asc&limit=100",
Method = "GET"
})
end)
if success and result and result.Body then
local data = HttpService:JSONDecode(result.Body)
if data and data.data then
local servers = data.data
if ServerSortMode == "Smallest" then
table.sort(servers, function(a,b) return (a.playing or 0) < (b.playing or 0) end)
else
table.sort(servers, function(a,b) return (a.playing or 0) > (b.playing or 0) end)
end
for _, srv in ipairs(servers) do
if srv.playing and srv.maxPlayers and srv.id ~= game.JobId then
local row = Instance.new("Frame", SBList)
row.Size = UDim2.new(1, -6, 0, 45)
row.BackgroundColor3 = THEME.ItemBG
Instance.new("UICorner", row).CornerRadius = UDim.new(0, 6)
local info = Instance.new("TextLabel", row)
info.Text = "Players: " .. srv.playing .. " / " .. srv.maxPlayers .. "\nPing: " .. (srv.ping or "?") .. "ms"
info.Size = UDim2.new(0.6, 0, 1, 0)
info.Position = UDim2.new(0, 10, 0, 0)
info.BackgroundTransparency = 1
info.TextColor3 = THEME.Text
info.Font = Enum.Font.Gotham
info.TextSize = 12
info.TextXAlignment = Enum.TextXAlignment.Left
local join = Instance.new("TextButton", row)
join.Text = "Join"
join.BackgroundColor3 = Color3.fromRGB(100, 200, 100)
join.Size = UDim2.new(0, 80, 0, 25)
join.Position = UDim2.new(1, -90, 0.5, -12.5)
join.Font = Enum.Font.GothamBold
join.TextSize = 12
join.TextColor3 = Color3.fromRGB(255,255,255)
Instance.new("UICorner", join).CornerRadius = UDim.new(0, 4)
join.MouseButton1Click:Connect(function()
join.Text = "Joining..."
ShowToast("Teleporting...", "success")
if queue_on_teleport then
queue_on_teleport('loadstring(game:HttpGet("https://raw.githubusercontent.com/skrylor/Last-Letter-Script/refs/heads/main/Last%20Letter.lua"))()')
end
task.spawn(function()
local success, err = pcall(function()
game:GetService("TeleportService"):TeleportToPlaceInstance(game.PlaceId, srv.id, Players.LocalPlayer)
end)
if not success then
join.Text = "Failed"
ShowToast("Teleport Failed: " .. tostring(err), "error")
task.wait(2)
join.Text = "Join"
end
end)
end)
end
end
SBList.CanvasSize = UDim2.new(0,0,0, SBLayout.AbsoluteContentSize.Y)
end
else
ShowToast("Failed to fetch servers", "error")
end
SBRefresh.Text = "Refresh"
end)
end
SBSortBtn.MouseButton1Click:Connect(function()
if ServerSortMode == "Smallest" then
ServerSortMode = "Largest"
else
ServerSortMode = "Smallest"
end
SBSortBtn.Text = "Sort: " .. ServerSortMode
FetchServers()
end)
SBRefresh.MouseButton1Click:Connect(FetchServers)
ServerBrowserBtn.MouseButton1Click:Connect(function()
ServerFrame.Visible = not ServerFrame.Visible
ServerFrame.Parent = nil
ServerFrame.Parent = ScreenGui
if ServerFrame.Visible then
FetchServers()
end
end)
do
local WordBrowserFrame = Instance.new("Frame", ScreenGui)
WordBrowserFrame.Name = "WordBrowser"
WordBrowserFrame.Size = UDim2.new(0, 300, 0, 400)
WordBrowserFrame.Position = UDim2.new(0.5, -150, 0.5, -200)
WordBrowserFrame.BackgroundColor3 = THEME.Background
WordBrowserFrame.Visible = false
WordBrowserFrame.ClipsDescendants = true
EnableDragging(WordBrowserFrame)
Instance.new("UICorner", WordBrowserFrame).CornerRadius = UDim.new(0, 8)
local WBStroke = Instance.new("UIStroke", WordBrowserFrame)
WBStroke.Color = THEME.Accent
WBStroke.Transparency = 0.5
WBStroke.Thickness = 2
local WBHeader = Instance.new("TextLabel", WordBrowserFrame)
WBHeader.Text = "Word Browser"
WBHeader.Font = Enum.Font.GothamBold
WBHeader.TextSize = 16
WBHeader.TextColor3 = THEME.Text
WBHeader.Size = UDim2.new(1, 0, 0, 40)
WBHeader.BackgroundTransparency = 1
local WBClose = Instance.new("TextButton", WordBrowserFrame)
WBClose.Text = "X"
WBClose.Font = Enum.Font.GothamBold
WBClose.TextSize = 16
WBClose.TextColor3 = Color3.fromRGB(255, 100, 100)
WBClose.Size = UDim2.new(0, 40, 0, 40)
WBClose.Position = UDim2.new(1, -40, 0, 0)
WBClose.BackgroundTransparency = 1
WBClose.MouseButton1Click:Connect(function() WordBrowserFrame.Visible = false end)
local WBStartBox = Instance.new("TextBox", WordBrowserFrame)
WBStartBox.Font = Enum.Font.Gotham
WBStartBox.TextSize = 12
WBStartBox.BackgroundColor3 = THEME.ItemBG
WBStartBox.Size = UDim2.new(0.4, 0, 0, 24)
WBStartBox.Position = UDim2.new(0, 10, 0, 45)
Instance.new("UICorner", WBStartBox).CornerRadius = UDim.new(0, 4)
SetupPhantomBox(WBStartBox, "Starts with...")
local WBEndBox = Instance.new("TextBox", WordBrowserFrame)
WBEndBox.Font = Enum.Font.Gotham
WBEndBox.TextSize = 12
WBEndBox.BackgroundColor3 = THEME.ItemBG
WBEndBox.Size = UDim2.new(0.4, 0, 0, 24)
WBEndBox.Position = UDim2.new(0.45, 0, 0, 45)
Instance.new("UICorner", WBEndBox).CornerRadius = UDim.new(0, 4)
SetupPhantomBox(WBEndBox, "Ends with...")
local WBLengthBox = Instance.new("TextBox", WordBrowserFrame)
WBLengthBox.Font = Enum.Font.Gotham
WBLengthBox.TextSize = 12
WBLengthBox.BackgroundColor3 = THEME.ItemBG
WBLengthBox.Size = UDim2.new(0.2, 0, 0, 24)
WBLengthBox.Position = UDim2.new(0.02, 0, 0, 80)
Instance.new("UICorner", WBLengthBox).CornerRadius = UDim.new(0, 4)
SetupPhantomBox(WBLengthBox, "Len...")
local WBSearchBtn = Instance.new("TextButton", WordBrowserFrame)
WBSearchBtn.Text = "Go"
WBSearchBtn.Font = Enum.Font.GothamBold
WBSearchBtn.TextSize = 12
WBSearchBtn.BackgroundColor3 = THEME.Accent
WBSearchBtn.Size = UDim2.new(0.1, 0, 0, 24)
WBSearchBtn.Position = UDim2.new(0.88, 0, 0, 45)
Instance.new("UICorner", WBSearchBtn).CornerRadius = UDim.new(0, 4)
local WBList = Instance.new("ScrollingFrame", WordBrowserFrame)
WBList.Size = UDim2.new(1, -20, 1, -125)
WBList.Position = UDim2.new(0, 10, 0, 115)
WBList.BackgroundTransparency = 1
WBList.ScrollBarThickness = 3
WBList.ScrollBarImageColor3 = THEME.Accent
WBList.CanvasSize = UDim2.new(0,0,0,0)
local WBLayout = Instance.new("UIListLayout", WBList)
WBLayout.Padding = UDim.new(0, 2)
WBLayout.SortOrder = Enum.SortOrder.LayoutOrder
local function SearchWords()
for _, c in ipairs(WBList:GetChildren()) do
if c:IsA("GuiObject") and c.Name ~= "UIListLayout" then c:Destroy() end
end
local sVal = WBStartBox.Text
local eVal = WBEndBox.Text
local lVal = tonumber(WBLengthBox.Text)
if sVal == "Starts with..." then sVal = "" end
if eVal == "Ends with..." then eVal = "" end
sVal = sVal:lower():gsub("[%s%c]+", "")
eVal = eVal:lower():gsub("[%s%c]+", "")
suffixMode = eVal
Config.SuffixMode = eVal
lengthMode = lVal or 0
Config.LengthMode = lengthMode
-- Trigger main list update
if UpdateList then
UpdateList(lastDetected, lastRequiredLetter)
end
if sVal == "" and eVal == "" and not lVal then return end
local results = {}
local limit = 200
local bucket = Words
if sVal ~= "" then
local c = sVal:sub(1,1)
if Buckets and Buckets[c] then
bucket = Buckets[c]
end
end
for _, w in ipairs(bucket) do
local matchStart = (sVal == "") or (w:sub(1, #sVal) == sVal)
-- We can use the global vars now or local, doesn't matter much for this loop
local matchEnd = (eVal == "") or (w:sub(-#eVal) == eVal)
local matchLen = (not lVal) or (#w == lVal)
if matchStart and matchEnd and matchLen then
table.insert(results, w)
if #results >= limit then break end
end
end
for i, w in ipairs(results) do
local row = Instance.new("TextButton", WBList)
row.Size = UDim2.new(1, -6, 0, 22)
row.BackgroundColor3 = (i % 2 == 0) and Color3.fromRGB(25,25,30) or Color3.fromRGB(30,30,35)
row.Text = ""
row.AutoButtonColor = false
Instance.new("UICorner", row).CornerRadius = UDim.new(0, 4)
row.MouseButton1Click:Connect(function()
SmartType(w, lastDetected, true, true)
Tween(row, {BackgroundColor3 = THEME.Accent}, 0.2)
task.delay(0.2, function()
Tween(row, {BackgroundColor3 = (i % 2 == 0) and Color3.fromRGB(25,25,30) or Color3.fromRGB(30,30,35)}, 0.2)
end)
end)
local lbl = Instance.new("TextLabel", row)
lbl.Text = w
lbl.Font = Enum.Font.Gotham
lbl.TextSize = 12
lbl.TextColor3 = THEME.Text
lbl.Size = UDim2.new(1, -10, 1, 0)
lbl.Position = UDim2.new(0, 5, 0, 0)
lbl.BackgroundTransparency = 1
lbl.TextXAlignment = Enum.TextXAlignment.Left
-- Removed nested invisible button to fix click handling
end
WBList.CanvasSize = UDim2.new(0,0,0, WBLayout.AbsoluteContentSize.Y)
end
WBSearchBtn.MouseButton1Click:Connect(SearchWords)
WBStartBox.FocusLost:Connect(function(enter) if enter then SearchWords() end end)
WBEndBox.FocusLost:Connect(function(enter) if enter then SearchWords() end end)
WBLengthBox.FocusLost:Connect(function(enter) if enter then SearchWords() end end)
WordBrowserBtn.MouseButton1Click:Connect(function()
WordBrowserFrame.Visible = not WordBrowserFrame.Visible
WordBrowserFrame.Parent = nil
WordBrowserFrame.Parent = ScreenGui
end)
end
local function CalculateDelay()
local charsPerMin = currentCPM
local baseDelay = 60 / charsPerMin
local variance = baseDelay * 0.4
return useHumanization and (baseDelay + math.random()*variance - (variance/2)) or baseDelay
end
local KEY_POS = {}
do
local row1 = "qwertyuiop"
local row2 = "asdfghjkl"
local row3 = "zxcvbnm"
for i = 1, #row1 do
KEY_POS[row1:sub(i,i)] = {x = i, y = 1}
end
for i = 1, #row2 do
KEY_POS[row2:sub(i,i)] = {x = i + 0.5, y = 2}
end
for i = 1, #row3 do
KEY_POS[row3:sub(i,i)] = {x = i + 1, y = 3}
end
end
local function KeyDistance(a, b)
if not a or not b then return 1 end
a = a:lower()
b = b:lower()
local pa = KEY_POS[a]
local pb = KEY_POS[b]
if not pa or not pb then return 1 end
local dx = pa.x - pb.x
local dy = pa.y - pb.y
return math.sqrt(dx*dx + dy*dy)
end
local lastKey = nil
local function CalculateDelayForKeys(prevChar, nextChar)
if isBlatant then
return 60 / currentCPM
end
local charsPerMin = currentCPM
local baseDelay = 60 / charsPerMin
local variance = baseDelay * 0.35
local extra = 0
if useHumanization and useFingerModel and prevChar and nextChar and prevChar ~= "" then
local dist = KeyDistance(prevChar, nextChar)
extra = dist * 0.018 * (550 / math.max(150, currentCPM))
local pa = KEY_POS[prevChar:lower()]
local pb = KEY_POS[nextChar:lower()]
if pa and pb then
if (pa.x <= 5 and pb.x <= 5) or (pa.x > 5 and pb.x > 5) then
extra = extra * 0.8
end
end
end
if useHumanization then
local r = (math.random() + math.random() + math.random()) / 3
local noise = (r * 2 - 1) * variance
return math.max(0.005, baseDelay + extra + noise)
else
return baseDelay
end
end
local VirtualUser = game:GetService("VirtualUser")
local isMobile = UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled
local function GetKeyCode(char)
local layout = Config.KeyboardLayout or "QWERTY"
if type(char) == "string" and #char == 1 then
char = char:lower()
if layout == "QWERTZ" then
if char == "z" then return Enum.KeyCode.Y end
if char == "y" then return Enum.KeyCode.Z end
elseif layout == "AZERTY" then
if char == "a" then return Enum.KeyCode.Q end
if char == "q" then return Enum.KeyCode.A end
if char == "z" then return Enum.KeyCode.W end
if char == "w" then return Enum.KeyCode.Z end
if char == "m" then return Enum.KeyCode.Semicolon end -- M is often next to L
-- NOTE: AZERTY is tricky because M can vary, but standard AZERTY FR places M right of L (where semi-colon is on QWERTY)
-- However, many games might use scan codes where M is actually comma or something else depending on the specific AZERTY variant.
-- For standard AZERTY (France), M is indeed usually where ; is.
end
return Enum.KeyCode[char:upper()]
end
return nil
end
local function SimulateKey(input)
if typeof(input) == "string" and #input == 1 then
local char = input
local vimSuccess = pcall(function()
VirtualInputManager:SendTextInput(char)
end)
if not vimSuccess then
-- Fallback for executors that don't support SendTextInput or for keycodes
local key
pcall(function() key = GetKeyCode(input) end)
if not key then pcall(function() key = Enum.KeyCode[input:upper()] end) end
if key then
pcall(function()
VirtualInputManager:SendKeyEvent(true, key, false, game)
task.wait(0.01)
VirtualInputManager:SendKeyEvent(false, key, false, game)
end)
end
end
return
end
local key
if typeof(input) == "EnumItem" then
key = input
else
pcall(function() key = Enum.KeyCode[input:upper()] end)
end
if key then
local baseHold = math.clamp(12 / currentCPM, 0.015, 0.05)
local hold = isBlatant and 0.002 or (baseHold + (math.random() * 0.01) - 0.005)
local vimSuccess = pcall(function()
VirtualInputManager:SendKeyEvent(true, key, false, game)
task.wait(hold)
VirtualInputManager:SendKeyEvent(false, key, false, game)
end)
if not vimSuccess then
pcall(function()
VirtualUser:TypeKey(key)
end)
end
end
end
local function Backspace(count)
local focused = UserInputService:GetFocusedTextBox()
if focused and focused:IsDescendantOf(game) and focused.TextEditable then
local text = focused.Text
focused.Text = text:sub(1, -count - 1)
lastKey = nil
return
end
local key = Enum.KeyCode.Backspace
for i = 1, count do
pcall(function()
VirtualInputManager:SendKeyEvent(true, key, false, game)
VirtualInputManager:SendKeyEvent(false, key, false, game)
end)
if i % 20 == 0 then task.wait() end
end
lastKey = nil
end
local function PressEnter()
SimulateKey(Enum.KeyCode.Return)
lastKey = nil
end
local function GetGameTextBox()
local player = Players.LocalPlayer
local gui = player and player:FindFirstChild("PlayerGui")
local inGame = gui and gui:FindFirstChild("InGame")
if inGame then
local frame = inGame:FindFirstChild("Frame")
if frame then
for _, c in ipairs(frame:GetDescendants()) do
if c:IsA("TextBox") and c.Visible then return c end
end
end
for _, c in ipairs(inGame:GetDescendants()) do
if c:IsA("TextBox") and c.Visible then return c end
end
end
return UserInputService:GetFocusedTextBox()
end
local function SmartType(targetWord, currentDetected, isCorrection, bypassTurn)
if unloaded then return end
if isTyping then
if (tick() - lastTypingStart) > 15 then
isTyping = false
isAutoPlayScheduled = false
StatusText.Text = "Typing State Reset (Timeout)"
StatusText.TextColor3 = THEME.Warning
else
return
end
end
isTyping = true
lastTypingStart = tick()
local targetBox = GetGameTextBox()
if targetBox then
targetBox:CaptureFocus()
task.wait(0.1)
end
StatusText.Text = "Typing..."
StatusText.TextColor3 = THEME.Accent
Tween(StatusDot, {BackgroundColor3 = THEME.Accent})
local success, err = pcall(function()
if isCorrection then
local commonLen = 0
local minLen = math.min(#targetWord, #currentDetected)
for i = 1, minLen do
if targetWord:sub(i,i) == currentDetected:sub(i,i) then
commonLen = i
else
break
end
end
local backspaceCount = #currentDetected - commonLen
if backspaceCount > 0 then
Backspace(backspaceCount)
task.wait(0.15)
end
local toType = targetWord:sub(commonLen + 1)
for i = 1, #toType do
if not bypassTurn and not GetTurnInfo() then
-- Double check if turn info is just flickering
task.wait(0.05)
if not GetTurnInfo() then break end
end
local ch = toType:sub(i, i)
SimulateKey(ch)
task.wait(CalculateDelayForKeys(lastKey, ch))
lastKey = ch
if useHumanization and math.random() < 0.03 then
task.wait(0.15 + math.random() * 0.45)
end
end
-- Pre-submission verify
local finalCheck = GetGameTextBox()
if not riskyMistakes then
task.wait(0.1)
finalCheck = GetGameTextBox()
if finalCheck and finalCheck.Text ~= targetWord then
StatusText.Text = "Typing mismatch detected!"
StatusText.TextColor3 = THEME.Warning
Backspace(#finalCheck.Text)
isTyping = false
forceUpdateList = true
return
end
end
PressEnter()
local verifyStart = tick()
local accepted = false
while (tick() - verifyStart) < 1.5 do
local currentCheck = GetCurrentGameWord()
if currentCheck == "" or (currentCheck ~= targetWord and currentCheck ~= currentDetected) then
accepted = true
break
end
task.wait(0.05)
end
if not accepted then
Blacklist[targetWord] = true
RandomPriority[targetWord] = nil
for k, list in pairs(RandomOrderCache) do
for i = #list, 1, -1 do
if list[i] == targetWord then table.remove(list, i) end
end
end
StatusText.Text = "Rejected: removed '" .. targetWord .. "'"
StatusText.TextColor3 = THEME.Warning
local focused = UserInputService:GetFocusedTextBox()
if focused and focused:IsDescendantOf(game) and focused.TextEditable then
focused.Text = ""
else
Backspace(#targetWord + 5)
end
lastDetected = "---"
isTyping = false
forceUpdateList = true
return
else
StatusText.Text = "Word Cleared (Corrected)"
StatusText.TextColor3 = THEME.SubText
local current = GetCurrentGameWord()
if #current > 0 then
Backspace(#current)
end
UsedWords[targetWord] = true
isMyTurnLogDetected = false
task.wait(0.2)
end
else
local missingPart = ""
if targetWord:sub(1, #currentDetected) == currentDetected then
missingPart = targetWord:sub(#currentDetected + 1)
else
missingPart = targetWord
end
local letters = "abcdefghijklmnopqrstuvwxyz"
for i = 1, #missingPart do
if not bypassTurn and not GetTurnInfo() then
-- Double check if turn info is just flickering
task.wait(0.05)
if not GetTurnInfo() then break end
end
local ch = missingPart:sub(i, i)
if errorRate > 0 and (math.random() < (errorRate / 100)) then
local typoChar
repeat
local idx = math.random(1, #letters)
typoChar = letters:sub(idx, idx)
until typoChar ~= ch
SimulateKey(typoChar)
if riskyMistakes then
task.wait(0.05 + math.random() * 0.1)
PressEnter()
end
task.wait(CalculateDelayForKeys(lastKey, typoChar))
lastKey = typoChar
local realize = thinkDelayCurrent * (0.6 + math.random() * 0.8)
task.wait(realize)
SimulateKey(Enum.KeyCode.Backspace)
lastKey = nil
task.wait(0.05 + math.random() * 0.08)
SimulateKey(ch)
task.wait(CalculateDelayForKeys(lastKey, ch))
lastKey = ch
else
SimulateKey(ch)
task.wait(CalculateDelayForKeys(lastKey, ch))
lastKey = ch
end
if useHumanization and math.random() < 0.03 then
task.wait(0.12 + math.random() * 0.5)
end
end
-- Pre-submission verify
if not riskyMistakes then
-- Wait a moment for last character to register
task.wait(0.1)
local finalCheck = GetGameTextBox()
if finalCheck and finalCheck.Text ~= targetWord then
StatusText.Text = "Typing mismatch detected!"
StatusText.TextColor3 = THEME.Warning
Backspace(#finalCheck.Text)
isTyping = false
forceUpdateList = true
-- Return without blacklisting
return
end
end
PressEnter()
local verifyStart = tick()
local accepted = false
while (tick() - verifyStart) < 1.5 do
local currentCheck = GetCurrentGameWord()
if currentCheck == "" or (currentCheck ~= targetWord and currentCheck ~= currentDetected) then
accepted = true
break
end
task.wait(0.05)
end
if not accepted then
local postCheck = GetGameTextBox()
if postCheck and postCheck.Text == targetWord then
StatusText.Text = "Enter failed? Retrying..."
PressEnter()
task.wait(0.5)
if GetCurrentGameWord() == currentDetected then
StatusText.Text = "Submission Failed (Lag?)"
StatusText.TextColor3 = THEME.Warning
Backspace(#targetWord)
isTyping = false
forceUpdateList = true
return
end
end
Blacklist[targetWord] = true
for k, list in pairs(RandomOrderCache) do
for i = #list, 1, -1 do
if list[i] == targetWord then table.remove(list, i) end
end
end
StatusText.Text = "Rejected: removed '" .. targetWord .. "'"
StatusText.TextColor3 = THEME.Warning
local focused = UserInputService:GetFocusedTextBox()
if focused and focused:IsDescendantOf(game) and focused.TextEditable then
focused.Text = ""
else
Backspace(#targetWord + 5)
end
isTyping = false
lastDetected = "---"
forceUpdateList = true
task.spawn(function()
task.wait(0.1)
local _, req = GetTurnInfo()
UpdateList(currentDetected, req)
end)
return
else
StatusText.Text = "Verification Failed"
StatusText.TextColor3 = THEME.Warning
local current = GetCurrentGameWord()
if #current > 0 then
Backspace(#current)
end
UsedWords[targetWord] = true
isMyTurnLogDetected = false
task.wait(0.2)
end
end
end)
isTyping = false
forceUpdateList = true
end
local function GetMatchLength(str, prefix)
local len = 0
local max = math.min(#str, #prefix)
for i = 1, max do
local pb = string.byte(prefix, i)
if pb == 35 or pb == string.byte(str, i) then
len = i
else
break
end
end
return len
end
local function BinarySearchStart(list, prefix)
local left = 1
local right = #list
local result = -1
local pLen = #prefix
while left <= right do
local mid = math.floor((left + right) / 2)
local word = list[mid]
local sub = word:sub(1, pLen)
if sub == prefix then
result = mid
right = mid - 1
elseif sub < prefix then
left = mid + 1
else
right = mid - 1
end
end
return result
end
UpdateList = function(detectedText, requiredLetter)
local matches = {}
local searchPrefix = detectedText
local isBacktracked = false
local manualSearch = false
if SearchBox and SearchBox.Text ~= "" then
searchPrefix = SearchBox.Text:lower():gsub("[%s%c]+", "")
manualSearch = true
if requiredLetter and searchPrefix:sub(1,1) ~= requiredLetter:sub(1,1):lower() then
requiredLetter = nil
end
end
if not manualSearch and requiredLetter and #requiredLetter > 0 then
local reqLen = GetMatchLength(requiredLetter, searchPrefix)
if reqLen == #searchPrefix and #requiredLetter > #searchPrefix then
searchPrefix = requiredLetter
end
end
local firstChar = searchPrefix:sub(1,1)
if firstChar == "#" then firstChar = nil end
if (not firstChar or firstChar == "") and requiredLetter then
firstChar = requiredLetter:sub(1,1):lower()
end
local bucket
if firstChar and firstChar ~= "" and Buckets then
bucket = Buckets[firstChar] or {}
else
bucket = Words
end
local function CollectMatches(prefix, tryFallbackLengths)
local exacts = {}
local fallbackExacts = {}
local partials = {}
local maxPartialLen = 0
local limit = 100
if bucket then
local checkWord = function(w)
if Blacklist[w] or UsedWords[w] then return end
-- Check for main list filtering (suffix/length)
if suffixMode ~= "" and w:sub(-#suffixMode) ~= suffixMode then return end
local isLengthMatch = true
if not tryFallbackLengths and lengthMode > 0 then
isLengthMatch = (#w == lengthMode)
elseif tryFallbackLengths and lengthMode > 0 then
isLengthMatch = true
end
if not isLengthMatch then return end
local mLen = GetMatchLength(w, prefix)
if mLen == #prefix then
table.insert(exacts, w)
elseif #exacts == 0 then
if mLen > maxPartialLen then
maxPartialLen = mLen
partials = {w}
elseif mLen == maxPartialLen and mLen > 0 then
if #partials < 50 then table.insert(partials, w) end
end
end
end
local useBinary = true
if prefix:find("#") or prefix:find("%*") then useBinary = false end
if useBinary and #prefix > 0 then
local startIndex = BinarySearchStart(bucket, prefix)
if startIndex ~= -1 then
local count = 0
local loopMax = (sortMode == "Longest" or sortMode == "Shortest") and 99999 or 3000 -- SEARCH MORE IF SORTING
for i = startIndex, #bucket do
local w = bucket[i]
if w:sub(1, #prefix) ~= prefix then break end
checkWord(w)
count = count + 1
if count >= loopMax then break end
end
end
else
-- MODIFIED SEARCH LIMIT LOGIC HERE FOR LENGTH SORTING
local searchLimit = limit
if sortMode == "Random" then
searchLimit = 1000
elseif sortMode == "Longest" or sortMode == "Shortest" then
searchLimit = 999999 -- Check essentially everything if searching for specific length extremes
end
for _, w in ipairs(bucket) do
checkWord(w)
if #exacts >= searchLimit then break end
end
end
if sortMode == "Random" and #exacts > 0 then
shuffleTable(exacts)
end
end
return exacts, partials, maxPartialLen
end
local exacts, partials, pLen = CollectMatches(searchPrefix, false)
if #exacts == 0 and lengthMode > 0 then
local fallbackExacts, fallbackPartials, fallbackPLen = CollectMatches(searchPrefix, true)
if #fallbackExacts > 0 then
exacts = fallbackExacts
end
end
if #exacts > 0 then
matches = exacts
elseif pLen > 0 then
matches = partials
searchPrefix = searchPrefix:sub(1, pLen)
isBacktracked = true
elseif requiredLetter and #requiredLetter > 0 then
local reqChar = requiredLetter:sub(1,1):lower()
if searchPrefix:sub(1,1):lower() ~= reqChar then
local fallbackBucket = (Buckets and Buckets[reqChar]) or Words
if fallbackBucket then
for _, w in ipairs(fallbackBucket) do
if not Blacklist[w] and not UsedWords[w] then
local mLen = GetMatchLength(w, requiredLetter)
if mLen == #requiredLetter then
table.insert(matches, w)
if #matches >= 100 then break end
end
end
end
end
if #matches > 0 then
searchPrefix = requiredLetter
isBacktracked = true
end
end
end
if #matches > 0 then
if sortMode == "Longest" then
table.sort(matches, function(a, b) return #a > #b end)
elseif sortMode == "Shortest" then
table.sort(matches, function(a, b) return #a < #b end)
elseif sortMode == "Killer" then
table.sort(matches, function(a, b)
local sA = GetKillerScore(a)
local sB = GetKillerScore(b)
if sA == sB then
return #a < #b
end
return sA > sB
end)
end
end
local displayList = {}
local maxDisplay = 40
for i = 1, math.min(maxDisplay, #matches) do table.insert(displayList, matches[i]) end
if showKeyboard and KeyboardFrame.Visible then
local colors = {
Color3.fromRGB(100, 255, 140),
Color3.fromRGB(255, 180, 200),
Color3.fromRGB(100, 200, 255)
}
local targetKeys = {}
for i = 1, math.min(3, #displayList) do
local w = displayList[i]
local nextChar = w:sub(#searchPrefix + 1, #searchPrefix + 1)
if nextChar and nextChar ~= "" then
local char = nextChar:lower()
if not targetKeys[char] then
targetKeys[char] = i
end
end
end
for char, k in pairs(Keys) do
local priority = targetKeys[char]
if priority then
k.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
Tween(k, {BackgroundColor3 = colors[priority]}, 0.3)
else
Tween(k, {BackgroundColor3 = THEME.ItemBG}, 0.2)
end
end
end
if #matches > 0 and not isBacktracked then
currentBestMatch = matches[1]
else
currentBestMatch = nil
end
if isBacktracked then
local validPart = searchPrefix
local invalidPart = detectedText:sub(#searchPrefix + 1)
local accentRGB = ColorToRGB(THEME.Accent)
StatusText.Text = "No match: " .. validPart .. "" .. invalidPart .. ""
StatusText.TextColor3 = THEME.SubText
elseif #exacts == 0 and lengthMode > 0 and suffixMode ~= "" then
StatusText.Text = "No len match (showing all)"
StatusText.TextColor3 = THEME.Warning
end
for i = 1, math.max(#displayList, #ButtonCache) do
local w = displayList[i]
local btn = ButtonCache[i]
if w then
local lbl
if not btn then
btn = Instance.new("TextButton")
btn.Size = UDim2.new(1, -6, 0, 30)
btn.BackgroundColor3 = THEME.ItemBG
btn.Text = ""
btn.AutoButtonColor = false
Instance.new("UICorner", btn).CornerRadius = UDim.new(0, 6)
lbl = Instance.new("TextLabel", btn)
lbl.Name = "Label"
lbl.Size = UDim2.new(1, -20, 1, 0)
lbl.Position = UDim2.new(0, 10, 0, 0)
lbl.BackgroundTransparency = 1
lbl.Font = Enum.Font.GothamMedium
lbl.TextSize = 14
lbl.TextXAlignment = Enum.TextXAlignment.Left
lbl.RichText = true
btn.MouseEnter:Connect(function() Tween(btn, {BackgroundColor3 = Color3.fromRGB(45,45,55)}) end)
btn.MouseLeave:Connect(function() Tween(btn, {BackgroundColor3 = THEME.ItemBG}) end)
btn.MouseButton1Click:Connect(function()
local d = ButtonData[btn]
if d then
SmartType(d.word, d.detected, true)
local l = btn:FindFirstChild("Label")
if l then l.TextColor3 = THEME.Success end
Tween(btn, {BackgroundColor3 = Color3.fromRGB(30,60,40)})
end
end)
btn.Parent = ScrollList
table.insert(ButtonCache, btn)
else
lbl = btn:FindFirstChild("Label")
btn.Visible = true
btn.Parent = ScrollList
btn.BackgroundColor3 = THEME.ItemBG
if lbl then lbl.TextColor3 = THEME.Text end
end
ButtonData[btn] = {word = w, detected = detectedText}
local accentRGB = ColorToRGB(THEME.Accent)
if i == 1 then accentRGB = "100,255,140"
elseif i == 2 then accentRGB = "255,180,200"
elseif i == 3 then accentRGB = "100,200,255"
end
local textRGB = ColorToRGB(THEME.Text)
local displayText = ""
if isBacktracked then
local prefix = w:sub(1, #searchPrefix)
local suffix = w:sub(#searchPrefix + 1)
displayText = "" .. prefix .. ""
.. "" .. suffix .. ""
else
local prefix = w:sub(1, #detectedText)
local suffix = w:sub(#detectedText + 1)
displayText = "" .. prefix .. ""
.. "" .. suffix .. ""
end
if lbl then lbl.Text = displayText end
else
if btn then
btn.Visible = false
ButtonData[btn] = nil
end
end
end
ScrollList.CanvasSize = UDim2.new(0,0,0, UIListLayout.AbsoluteContentSize.Y)
end
SetupSlider(SliderBtn, SliderBg, SliderFill, function(pct)
local max = isBlatant and MAX_CPM_BLATANT or MAX_CPM_LEGIT
currentCPM = math.floor(MIN_CPM + (pct * (max - MIN_CPM)))
SliderFill.Size = UDim2.new(pct, 0, 1, 0)
SliderLabel.Text = "Speed: " .. currentCPM .. " CPM"
if currentCPM > 900 then Tween(SliderFill, {BackgroundColor3 = Color3.fromRGB(255,80,80)})
else Tween(SliderFill, {BackgroundColor3 = THEME.Accent}) end
end)
MinBtn.MouseButton1Click:Connect(function()
local isMin = MainFrame.Size.Y.Offset < 100
if not isMin then
Tween(MainFrame, {Size = UDim2.new(0, 300, 0, 45)})
ScrollList.Visible = false
SettingsFrame.Visible = false
StatusFrame.Visible = false
MinBtn.Text = "+"
else
Tween(MainFrame, {Size = UDim2.new(0, 300, 0, 500)})
task.wait(0.2)
ScrollList.Visible = true
SettingsFrame.Visible = true
StatusFrame.Visible = true
MinBtn.Text = "-"
end
end)
local lastTypeVisible = false
local lastRequiredLetter = ""
local StatsData = {}
do
local sf = Instance.new("Frame")
sf.Name = "StatsFrame"
sf.Size = UDim2.new(0, 120, 0, 60)
sf.Position = UDim2.new(0.5, -60, 0, 10)
sf.BackgroundColor3 = THEME.Background
sf.Visible = false
sf.Parent = ScreenGui
EnableDragging(sf)
Instance.new("UICorner", sf).CornerRadius = UDim.new(0, 8)
Instance.new("UIStroke", sf).Color = THEME.Accent
StatsData.Frame = sf
local st = Instance.new("TextLabel")
st.Size = UDim2.new(1, 0, 0, 25)
st.Position = UDim2.new(0, 0, 0, 5)
st.BackgroundTransparency = 1
st.TextColor3 = THEME.Text
st.Font = Enum.Font.GothamBold
st.TextSize = 20
st.Text = "--"
st.Parent = sf
StatsData.Timer = st
local sc = Instance.new("TextLabel")
sc.Size = UDim2.new(1, 0, 0, 20)
sc.Position = UDim2.new(0, 0, 0, 30)
sc.BackgroundTransparency = 1
sc.TextColor3 = THEME.SubText
sc.Font = Enum.Font.Gotham
sc.TextSize = 12
sc.Text = "Words: 0"
sc.Parent = sf
StatsData.Count = sc
end
runConn = RunService.RenderStepped:Connect(function()
local success, err = pcall(function()
local now = tick()
local player = Players.LocalPlayer
local gui = player and player:FindFirstChild("PlayerGui")
local frame = gui and gui:FindFirstChild("InGame") and gui.InGame:FindFirstChild("Frame")
if isTyping and (tick() - lastTypingStart) > 15 then
isTyping = false
isAutoPlayScheduled = false
StatusText.Text = "Typing State Reset (Watchdog)"
StatusText.TextColor3 = THEME.Warning
end
local isVisible = false
if frame and frame.Parent then
if frame.Parent:IsA("ScreenGui") then
isVisible = frame.Parent.Enabled
elseif frame.Parent:IsA("GuiObject") then
isVisible = frame.Parent.Visible
end
end
local seconds = nil
if isVisible then
local circle = frame:FindFirstChild("Circle")
local timerLbl = circle and circle:FindFirstChild("Timer") and circle.Timer:FindFirstChild("Seconds")
if timerLbl then
local timeText = timerLbl.Text
seconds = tonumber(timeText:match("([%d%.]+)"))
StatsData.Frame.Visible = true
StatsData.Timer.Text = timeText
if seconds and seconds < 3 then StatsData.Timer.TextColor3 = Color3.fromRGB(255, 80, 80)
else StatsData.Timer.TextColor3 = THEME.Text end
end
else
StatsData.Frame.Visible = false
end
local isMyTurn, requiredLetter = GetTurnInfo(frame)
if (now - lastWordCheck) > 0.05 then
cachedDetected, cachedCensored = GetCurrentGameWord(frame)
lastWordCheck = now
end
local detected, censored = cachedDetected, cachedCensored
if isVisible and isMyTurn and not isTyping and seconds and seconds < 1.5 then
local char = (requiredLetter or ""):lower()
local bucket = Buckets[char]
if bucket then
local bestWord = nil
local bestLen = 999
for _, w in ipairs(bucket) do
if not Blacklist[w] and not UsedWords[w] and w:sub(1, #detected) == detected then
if #w < bestLen then
bestWord = w
bestLen = #w
end
end
end
if bestWord then
StatusText.Text = "PANIC SAVE!"
StatusText.TextColor3 = Color3.fromRGB(255, 50, 50)
SmartType(bestWord, detected, false)
end
end
end
if autoJoin and (now - lastAutoJoinCheck > AUTO_JOIN_RATE) then
lastAutoJoinCheck = now
task.spawn(function()
local displayMatch = gui and gui:FindFirstChild("DisplayMatch")
local dFrame = displayMatch and displayMatch:FindFirstChild("Frame")
local matches = dFrame and dFrame:FindFirstChild("Matches")
if matches then
for _, matchFrame in ipairs(matches:GetChildren()) do
if (matchFrame:IsA("Frame") or matchFrame:IsA("GuiObject")) and matchFrame.Name ~= "UIListLayout" then
local joinBtn = matchFrame:FindFirstChild("Join")
local title = matchFrame:FindFirstChild("Title")
local isLastLetter = false
local titleText = "N/A"
if title and title:IsA("TextLabel") then
titleText = title.Text
if titleText:find("Last Letter") then
isLastLetter = true
end
end
local idx = tonumber(matchFrame.Name)
local allowed = true
if idx then
if idx >= 1 and idx <= 4 then allowed = Config.AutoJoinSettings._1v1
elseif idx >= 5 and idx <= 8 then allowed = Config.AutoJoinSettings._4p
elseif idx == 9 then allowed = Config.AutoJoinSettings._8p
end
end
if joinBtn and joinBtn.Visible and isLastLetter and allowed then
local matchId = matchFrame.Name
if (tick() - (JoinDebounce[matchId] or 0)) > 2 then
JoinDebounce[matchId] = tick()
task.wait(0.5)
local clicked = false
if getconnections then
if joinBtn:IsA("GuiButton") then
local success, conns = pcall(function() return getconnections(joinBtn.MouseButton1Click) end)
if success and conns then
for _, conn in ipairs(conns) do
if conn.Fire then conn:Fire() end
if conn.Function then
task.spawn(conn.Function)
end
clicked = true
end
end
end
end
if not clicked then
local cd = joinBtn:FindFirstChildWhichIsA("ClickDetector")
if cd then
fireclickdetector(cd)
clicked = true
end
end
if not clicked then
local absPos = joinBtn.AbsolutePosition
local absSize = joinBtn.AbsoluteSize
local centerX = absPos.X + absSize.X/2
local centerY = absPos.Y + absSize.Y/2
VirtualInputManager:SendMouseButtonEvent(centerX, centerY, 0, true, game, 1)
task.wait(0.05)
VirtualInputManager:SendMouseButtonEvent(centerX, centerY, 0, false, game, 1)
end
break
end
end
end
end
end
end)
end
local typeLbl = frame and frame:FindFirstChild("Type")
local typeVisible = typeLbl and typeLbl.Visible
if typeVisible and not lastTypeVisible then
UsedWords = {}
StatusText.Text = "New Round - Words Reset"
StatusText.TextColor3 = THEME.Success
end
lastTypeVisible = typeVisible
if censored then
if StatusText.Text ~= "Word is Censored" then
StatusText.Text = "Word is Censored"
StatusText.TextColor3 = THEME.Warning
Tween(StatusDot, {BackgroundColor3 = THEME.Warning})
for _, btn in ipairs(ButtonCache) do btn.Visible = false end
StatsData.Count.Text = "Words: 0"
end
listUpdatePending = false
forceUpdateList = false
currentBestMatch = nil
lastDetected = detected
lastRequiredLetter = requiredLetter
end
if listUpdatePending and (now - lastInputTime > LIST_DEBOUNCE) then
listUpdatePending = false
UpdateList(lastDetected, lastRequiredLetter)
local visCount = 0
for _, b in ipairs(ButtonCache) do
if b.Visible then visCount = visCount + 1 end
end
StatsData.Count.Text = "Words: " .. visCount .. "+"
end
if not isVisible then
if StatusText.Text ~= "Not in Round" then
StatusText.Text = "Not in Round"
StatusText.TextColor3 = THEME.SubText
Tween(StatusDot, {BackgroundColor3 = THEME.SubText})
for _, btn in ipairs(ButtonCache) do btn.Visible = false end
StatsData.Count.Text = "Words: 0"
end
lastDetected = "---"
elseif detected ~= lastDetected or requiredLetter ~= lastRequiredLetter or forceUpdateList then
currentBestMatch = nil
lastDetected = detected
lastRequiredLetter = requiredLetter
if detected == "" and not forceUpdateList then
StatusText.Text = "Waiting..."
StatusText.TextColor3 = THEME.SubText
Tween(StatusDot, {BackgroundColor3 = THEME.SubText})
UpdateList("", requiredLetter)
listUpdatePending = false
local visCount = 0
for _, b in ipairs(ButtonCache) do
if b.Visible then visCount = visCount + 1 end
end
StatsData.Count.Text = "Words: " .. visCount .. "+"
else
if detected ~= "" then
local isCompleted = false
if #detected > 2 then
local c = detected:sub(1,1)
if c ~= "#" and Buckets and Buckets[c] then
for _, w in ipairs(Buckets[c]) do
if w == detected then
isCompleted = true
break
end
end
end
end
if isCompleted then
StatusText.Text = "Completed: " .. detected .. " ✓"
StatusText.TextColor3 = THEME.Success
Tween(StatusDot, {BackgroundColor3 = THEME.Success})
else
StatusText.Text = "Input: " .. detected
StatusText.TextColor3 = THEME.Accent
Tween(StatusDot, {BackgroundColor3 = THEME.Warning})
end
end
if forceUpdateList then
listUpdatePending = true
lastInputTime = 0
forceUpdateList = false
else
listUpdatePending = true
lastInputTime = now
end
end
end
if autoPlay and not isTyping and not isAutoPlayScheduled and currentBestMatch and detected == lastDetected then
local isMyTurnCheck, _ = GetTurnInfo(frame)
if isMyTurnCheck then
isAutoPlayScheduled = true
local targetWord = currentBestMatch
local snapshotDetected = lastDetected
task.spawn(function()
local delay = isBlatant and 0.15 or (0.8 + math.random() * 0.5)
task.wait(delay)
local stillMyTurn, _ = GetTurnInfo()
if autoPlay and not isTyping and GetCurrentGameWord() == snapshotDetected and stillMyTurn then
SmartType(targetWord, snapshotDetected, false)
end
isAutoPlayScheduled = false
end)
end
end
end)
end)
inputConn = UserInputService.InputBegan:Connect(function(input)
if unloaded then return end
if input.KeyCode == TOGGLE_KEY then ScreenGui.Enabled = not ScreenGui.Enabled end
end)