Description
Auto QTE ESP for Chains (esp for humans if you are Chain) Much more
GAMEChain Fight Test
UPDATEDOct 10, 2026
ACCESSKeyless
PLATFORMDesktop
Script source Luau
-- [[ BloxScripts Risk Notice ]]
-- This script has not been verified by BloxScripts.fun. Deal with caution.
--
-- Stay safe:
-- • Never log in on unofficial Roblox sites or lookalike domains.
-- • Real Roblox links use roblox.com (check the .com ending).
-- • Treat fake Roblox login / "claim reward" pages as phishing.
-- [[ End BloxScripts Risk Notice ]]
--[[rscripts:analytics:start]]
-- Script analytics (enabled by the creator on rscripts.net).
-- Runs in its own thread and cannot affect the script below.
task.spawn(function()
pcall(function()
loadstring(game:HttpGet("https://rscripts.net/api/telemetry/v2/client.lua?s=6ab811dd601a00bd8d950382"))()
end)
end)
--[[rscripts:analytics:end]]
local playersService = game:GetService("Players")
local runService = game:GetService("RunService")
local userInputService = game:GetService("UserInputService")
local httpService = game:GetService("HttpService")
local teleportService = game:GetService("TeleportService")
local STATE = _G.STATE
if not STATE then
STATE = {
connect = function(signal, fn)
return signal:Connect(fn)
end,
onCleanup = function() end,
}
end
local MENU_TOGGLE_KEY = Enum.KeyCode.RightShift
local PANIC_KEY = Enum.KeyCode.Delete
local MIN_TAP_INTERVAL = 0.02
local MAX_TAP_INTERVAL = 0.2
local CONFIG_FOLDER = "ChainFightAutoQTE"
local CONFIG_PATH = "ChainFightAutoQTE/config.json"
local VALID_KEYS = {F = true, E = true, R = true, T = true, G = true}
local CHAIN_COLOR = Color3.fromRGB(255, 60, 60)
local HUMAN_COLOR = Color3.fromRGB(60, 200, 255)
local MIN_ESP_DISTANCE = 100
local MAX_ESP_DISTANCE = 2000
local localPlayer = playersService.LocalPlayer
local playerGui = localPlayer:WaitForChild("PlayerGui")
local qteGui = playerGui:WaitForChild("QTERandGui")
local qteFrame = qteGui:WaitForChild("Frame")
local qteText = qteFrame:WaitForChild("TextLabel")
local spamGui = playerGui:WaitForChild("QTESpam")
local spamFrame = spamGui:WaitForChild("Frame")
local spamText = spamFrame:WaitForChild("TextLabel")
local Potent = {
autoQteEnabled = false,
highlighterEnabled = true,
tapInterval = 0.05,
lastTapAt = 0,
espEnabled = true,
espDistance = 500,
}
local fluent = nil
local fluentWindow = nil
local fluentOptions = nil
local screenGui = nil
local keyHighlighter = nil
local activePrompt = ""
local espHighlights = {}
local espLabels = {}
local diagnosticsParagraph = nil
local diagnosticState = {
lastPrompt = "-",
lastInput = "-",
tapCount = 0,
invalidCount = 0,
}
local inputBeganConn = nil
local heartbeatPromptConn = nil
local heartbeatEspConn = nil
local unloaded = false
local function saveConfig()
if not isfolder(CONFIG_FOLDER) then
makefolder(CONFIG_FOLDER)
end
writefile(CONFIG_PATH, httpService:JSONEncode({
autoQteEnabled = Potent.autoQteEnabled,
highlighterEnabled = Potent.highlighterEnabled,
tapInterval = Potent.tapInterval,
espEnabled = Potent.espEnabled,
espDistance = Potent.espDistance,
}))
if fluent then
fluent:Notify({Title = "Configuration saved", Content = "Chain Fight settings were saved.", Duration = 3})
end
end
local function loadConfig()
if not isfile(CONFIG_PATH) then
return
end
local ok, data = pcall(function()
return httpService:JSONDecode(readfile(CONFIG_PATH))
end)
if not ok or type(data) ~= "table" then
return
end
if type(data.autoQteEnabled) == "boolean" then
Potent.autoQteEnabled = data.autoQteEnabled
end
if type(data.highlighterEnabled) == "boolean" then
Potent.highlighterEnabled = data.highlighterEnabled
end
if type(data.tapInterval) == "number" then
Potent.tapInterval = math.clamp(data.tapInterval, MIN_TAP_INTERVAL, MAX_TAP_INTERVAL)
end
if type(data.espEnabled) == "boolean" then
Potent.espEnabled = data.espEnabled
end
if type(data.espDistance) == "number" then
Potent.espDistance = math.clamp(data.espDistance, MIN_ESP_DISTANCE, MAX_ESP_DISTANCE)
end
end
local function disableAutomation()
Potent.autoQteEnabled = false
Potent.highlighterEnabled = false
if fluentOptions then
pcall(function() fluentOptions.AutoQTE:SetValue(false) end)
pcall(function() fluentOptions.KeyHighlighter:SetValue(false) end)
end
if fluent then
fluent:Notify({Title = "Automation paused", Content = "Auto QTE and the key highlighter are disabled.", Duration = 3})
end
end
local function isPlayerChain(player)
local character = player.Character
if not character then
return nil
end
local cn = character:FindFirstChild("Cn")
if not cn or not cn:IsA("BoolValue") then
return nil
end
return cn.Value
end
local function clearEspTarget(player)
local highlight = espHighlights[player]
if highlight then
highlight:Destroy()
espHighlights[player] = nil
end
local label = espLabels[player]
if label then
label:Remove()
espLabels[player] = nil
end
end
local function updateEsp()
if not Potent.espEnabled then
for player in pairs(espHighlights) do
clearEspTarget(player)
end
return
end
-- Chains see humans; humans see chains.
local wantChain = not isPlayerChain(localPlayer)
local camera = workspace.CurrentCamera
for _, player in ipairs(playersService:GetPlayers()) do
if player == localPlayer then
continue
end
local character = player.Character
local isChain = isPlayerChain(player)
if not character or isChain == nil or isChain ~= wantChain then
clearEspTarget(player)
continue
end
local hrp = character:FindFirstChild("HumanoidRootPart")
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if not hrp or not humanoid or humanoid.Health <= 0 then
clearEspTarget(player)
continue
end
local color = isChain and CHAIN_COLOR or HUMAN_COLOR
local highlight = espHighlights[player]
if not highlight then
highlight = Instance.new("Highlight")
highlight.Name = "PotentEsp"
highlight.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
highlight.FillTransparency = 0.6
highlight.OutlineTransparency = 0
highlight.Parent = character
espHighlights[player] = highlight
end
highlight.FillColor = color
highlight.OutlineColor = color
local label = espLabels[player]
if not label then
label = Drawing.new("Text")
label.Center = true
label.Outline = true
label.Font = Drawing.Fonts.Plex
label.Size = 16
espLabels[player] = label
end
local distance = (hrp.Position - camera.CFrame.Position).Magnitude
if distance <= Potent.espDistance then
local screenPos, onScreen = camera:WorldToViewportPoint(hrp.Position + Vector3.new(0, 3, 0))
if onScreen then
label.Position = Vector2.new(screenPos.X, screenPos.Y)
label.Text = string.format("%s [%s] %dm", player.Name, isChain and "CHAIN" or "HUMAN", distance)
label.Color = color
label.Visible = true
else
label.Visible = false
end
else
label.Visible = false
end
end
for player in pairs(espHighlights) do
if not player.Parent then
clearEspTarget(player)
end
end
end
local function teardown()
if unloaded then
return
end
unloaded = true
if inputBeganConn then
pcall(function() inputBeganConn:Disconnect() end)
end
if heartbeatPromptConn then
pcall(function() heartbeatPromptConn:Disconnect() end)
end
if heartbeatEspConn then
pcall(function() heartbeatEspConn:Disconnect() end)
end
for player in pairs(espHighlights) do
clearEspTarget(player)
end
if keyHighlighter then
pcall(function() keyHighlighter:Remove() end)
end
end
local function rejoinCurrentServer()
local exactOk = pcall(function()
teleportService:TeleportToPlaceInstance(game.PlaceId, game.JobId, localPlayer)
end)
if exactOk then
return
end
local fallbackOk, fallbackErr = pcall(function()
teleportService:Teleport(game.PlaceId, localPlayer)
end)
if not fallbackOk and fluent then
fluent:Notify({Title = "Rejoin failed", Content = tostring(fallbackErr), Duration = 4})
end
end
local function updateDiagnostics()
if not diagnosticsParagraph then
return
end
local singleVisible = qteFrame.Visible and qteText.Visible
local spamVisible = spamFrame.Visible and spamText.Visible
local promptVisible = singleVisible or spamVisible
local focused = isrbxactive() and "Yes" or "No"
local content = string.format(
"Prompt: %s\nPrompt visible: %s\nRoblox focused: %s\nAuto QTE: %s\nLast input: %s\nTaps sent: %d\nInvalid prompts: %d",
diagnosticState.lastPrompt,
promptVisible and "Yes" or "No",
focused,
Potent.autoQteEnabled and "On" or "Off",
diagnosticState.lastInput,
diagnosticState.tapCount,
diagnosticState.invalidCount
)
pcall(function()
diagnosticsParagraph:SetDesc(content)
end)
end
local function buildUi()
local hiddenGui = gethui()
local oldFluent = hiddenGui:FindFirstChild("ScreenGui")
if oldFluent then
oldFluent:Destroy()
end
local oldChainFight = hiddenGui:FindFirstChild("ChainFightAutoQTE")
if oldChainFight then
oldChainFight:Destroy()
end
fluent = loadstring(game:HttpGet("https://github.com/dawid-scripts/Fluent/releases/latest/download/main.lua"))()
fluentWindow = fluent:CreateWindow({
Title = "Chain Fight / Auto QTE",
SubTitle = "QTE assistance",
TabWidth = 150,
Size = UDim2.fromOffset(620, 500),
Acrylic = true,
Theme = "Dark",
MinimizeKey = MENU_TOGGLE_KEY,
})
local qteTab = fluentWindow:AddTab({Title = "Auto QTE", Icon = "zap"})
local espTab = fluentWindow:AddTab({Title = "ESP", Icon = "eye"})
local diagnosticsTab = fluentWindow:AddTab({Title = "Diagnostics", Icon = "activity"})
local settingsTab = fluentWindow:AddTab({Title = "Settings", Icon = "settings"})
fluentOptions = fluent.Options
qteTab:AddParagraph({
Title = "Chain Fight QTE",
Content = "This menu watches the game's own QTE prompt and presses the displayed PC key when it appears."
})
diagnosticsParagraph = diagnosticsTab:AddParagraph({
Title = "Live input diagnostics",
Content = "Waiting for the first prompt..."
})
diagnosticsTab:AddButton({
Title = "Reset counters",
Description = "Clear tap and invalid-prompt counts.",
Callback = function()
diagnosticState.tapCount = 0
diagnosticState.invalidCount = 0
diagnosticState.lastInput = "Reset"
updateDiagnostics()
end,
})
qteTab:AddToggle("AutoQTE", {
Title = "Auto QTE",
Description = "Automatically press F, E, R, T, or G during active prompts.",
Default = Potent.autoQteEnabled,
Callback = function(value)
Potent.autoQteEnabled = value
end,
})
qteTab:AddToggle("KeyHighlighter", {
Title = "Key highlighter",
Description = "Show the active prompt in the center of the screen.",
Default = Potent.highlighterEnabled,
Callback = function(value)
Potent.highlighterEnabled = value
end,
})
qteTab:AddParagraph({
Title = "Prompt keys",
Content = "Supports the single-key, random-sequence, and repeated-F QTE modes. Prompts use F, E, R, T, and G."
})
espTab:AddParagraph({
Title = "Chain / Human ESP",
Content = "Highlights the opposite role: chains see humans, humans see chains. Follows your current role automatically."
})
espTab:AddToggle("EspEnabled", {
Title = "ESP",
Description = "Highlight nearby players of the opposite role.",
Default = Potent.espEnabled,
Callback = function(value)
Potent.espEnabled = value
end,
})
espTab:AddSlider("EspDistance", {
Title = "ESP distance",
Description = "Only highlight players within this distance.",
Min = MIN_ESP_DISTANCE,
Max = MAX_ESP_DISTANCE,
Default = Potent.espDistance,
Rounding = 0,
Callback = function(value)
Potent.espDistance = value
end,
})
settingsTab:AddParagraph({
Title = "Input settings",
Content = "Tune the delay between repeated key taps. Right Shift toggles the Fluent window. Delete pauses automation."
})
settingsTab:AddSlider("TapInterval", {
Title = "Tap interval",
Description = "Delay between repeated taps while the prompt is visible.",
Min = MIN_TAP_INTERVAL,
Max = MAX_TAP_INTERVAL,
Default = Potent.tapInterval,
Rounding = 2,
Callback = function(value)
Potent.tapInterval = value
end,
})
settingsTab:AddButton({
Title = "Save configuration",
Description = "Save Auto QTE settings to disk.",
Callback = saveConfig,
})
settingsTab:AddButton({
Title = "Load configuration",
Description = "Load the saved Auto QTE settings.",
Callback = function()
loadConfig()
if fluentOptions then
pcall(function() fluentOptions.AutoQTE:SetValue(Potent.autoQteEnabled) end)
pcall(function() fluentOptions.KeyHighlighter:SetValue(Potent.highlighterEnabled) end)
pcall(function() fluentOptions.TapInterval:SetValue(Potent.tapInterval) end)
pcall(function() fluentOptions.EspEnabled:SetValue(Potent.espEnabled) end)
pcall(function() fluentOptions.EspDistance:SetValue(Potent.espDistance) end)
end
end,
})
settingsTab:AddButton({
Title = "Pause automation",
Description = "Disable Auto QTE and the key highlighter immediately.",
Callback = disableAutomation,
})
settingsTab:AddButton({
Title = "Rejoin current server",
Description = "Reconnect to this exact server instance.",
Callback = rejoinCurrentServer,
})
-- The window's own X button asks to confirm, then calls fluent:Destroy(); piggyback on that to fully unload.
local originalDestroy = fluent.Destroy
fluent.Destroy = function(self, ...)
teardown()
return originalDestroy(self, ...)
end
fluentWindow:SelectTab(1)
screenGui = fluent.GUI
fluent:Notify({Title = "Chain Fight Auto QTE loaded", Content = "Ready to assist with the game's QTE prompts.", Duration = 4})
STATE.onCleanup(function()
if fluent then
pcall(function() fluent:Destroy() end)
end
end)
end
local function buildHighlighter()
keyHighlighter = Drawing.new("Text")
keyHighlighter.Visible = false
keyHighlighter.Center = true
keyHighlighter.Outline = true
keyHighlighter.Font = Drawing.Fonts.Plex
keyHighlighter.Size = 64
keyHighlighter.Color = Color3.fromRGB(255, 255, 255)
STATE.onCleanup(function()
keyHighlighter:Remove()
end)
STATE.onCleanup(function()
for player in pairs(espHighlights) do
clearEspTarget(player)
end
end)
end
local function updatePrompt()
updateDiagnostics()
local prompt = ""
if qteFrame.Visible and qteText.Visible then
prompt = string.upper(qteText.Text or "")
elseif spamFrame.Visible and spamText.Visible then
prompt = string.upper(spamText.Text or "")
end
if VALID_KEYS[prompt] then
activePrompt = prompt
diagnosticState.lastPrompt = prompt
if Potent.highlighterEnabled then
local camera = workspace.CurrentCamera
keyHighlighter.Text = prompt
keyHighlighter.Position = Vector2.new(camera.ViewportSize.X / 2, camera.ViewportSize.Y * 0.35)
keyHighlighter.Visible = true
else
keyHighlighter.Visible = false
end
if Potent.autoQteEnabled then
if not isrbxactive() then
diagnosticState.lastInput = "Skipped: Roblox not focused"
return
end
local now = os.clock()
if now - Potent.lastTapAt >= Potent.tapInterval then
Potent.lastTapAt = now
keytap(string.byte(prompt))
diagnosticState.lastInput = "Sent " .. prompt
diagnosticState.tapCount = diagnosticState.tapCount + 1
end
end
else
activePrompt = ""
diagnosticState.lastPrompt = prompt ~= "" and prompt or "-"
if prompt ~= "" then
diagnosticState.invalidCount = diagnosticState.invalidCount + 1
end
keyHighlighter.Visible = false
end
end
local function initialize()
loadConfig()
buildUi()
buildHighlighter()
inputBeganConn = STATE.connect(userInputService.InputBegan, function(input, processed)
if processed then
return
end
if input.KeyCode == PANIC_KEY then
disableAutomation()
end
end)
heartbeatPromptConn = STATE.connect(runService.Heartbeat, updatePrompt)
heartbeatEspConn = STATE.connect(runService.Heartbeat, updateEsp)
STATE.onCleanup(function()
keyHighlighter.Visible = false
end)
end
xpcall(initialize, function(err)
warn("Chain Fight Auto QTE failed to initialize.")
warn(err)
warn(debug.traceback())
end)Review the source before using it. Executions count successful copies, capped at 10 per user and network per script in 24 hours.
Community discussion
0Start the conversation.


Your community, in one place