
Keyless

-- Arcane Lineage | Halloween Horse Race Farm (Potassium)
-- Auto Quest : clicks the Horse Race paper on the quest board when no quest is active
-- Auto Race : teleports through every gate in order and fires the game's own gate remote
-- UI: draggable panel with two toggles + status. F6 toggles both together.
local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
local LocalPlayer = Players.LocalPlayer
-- stop any previous copy
if getgenv().HorseFarm and getgenv().HorseFarm.Stop then
pcall(getgenv().HorseFarm.Stop)
end
--------------------------------------------------------------------
-- CONFIG
--------------------------------------------------------------------
local CFG = {
AutoQuest = false,
AutoRace = false,
GateDelay = 0.15, -- pause after each gate is accepted
GateTimeout = 3, -- seconds to wait for the server to accept a gate
MaxRetries = 8, -- retries on a single gate before the race bot gives up
QuestRetry = 10, -- min seconds between quest click attempts
QuestTimeout = 300, -- if no FinishQuest after this long, assume the quest is over
BoardOffset = Vector3.new(7, 0, 0), -- where to stand next to the paper
}
local function log(...) print("[HorseFarm]", ...) end
--------------------------------------------------------------------
-- STATE
--------------------------------------------------------------------
local alive = true
local busy = false -- race runner busy
local state = {
questActive = false,
questSince = 0,
finishedAt = 0,
lastClick = 0,
completed = 0,
questText = "idle",
raceText = "waiting",
}
local conns = {}
--------------------------------------------------------------------
-- GAME CONFIG (read from the game's own module)
--------------------------------------------------------------------
local okReq, HS = pcall(function()
return require(RS:WaitForChild("Libraries"):WaitForChild("HalloweenStory"))
end)
if not okReq or type(HS) ~= "table" then
warn("[HorseFarm] Could not load HalloweenStory module:", tostring(HS))
return
end
local Gates = HS.Race.Gates
local Attr = HS.Race.Attributes
local GateRemote = RS:WaitForChild("Remotes"):WaitForChild("Information"):WaitForChild(HS.Remote)
--------------------------------------------------------------------
-- HELPERS
--------------------------------------------------------------------
local function getRoot()
local char = LocalPlayer.Character
return char and char:FindFirstChild("HumanoidRootPart")
end
local function raceActive()
return type(LocalPlayer:GetAttribute(Attr.Gate)) == "number"
and type(LocalPlayer:GetAttribute(Attr.Gates)) == "number"
and type(LocalPlayer:GetAttribute(Attr.Place)) == "string"
end
local function coursesFolder()
local f = workspace
for _, name in ipairs(Gates.CoursePath) do
f = f and f:FindFirstChild(name)
end
return f
end
local function findCourse(folder, place)
if not folder or type(place) ~= "string" then return nil end
for _, child in ipairs(folder:GetChildren()) do
if child.Name == place or child:GetAttribute("Label") == place then
return child
end
end
return nil
end
--------------------------------------------------------------------
-- QUEST EVENTS (track StartQuest / FinishQuest from the server)
--------------------------------------------------------------------
for _, d in ipairs(RS:GetDescendants()) do
if d:IsA("RemoteEvent") and d.Name == "Quest" then
table.insert(conns, d.OnClientEvent:Connect(function(action, data)
if action == "StartQuest" then
state.questActive = true
state.questSince = tick()
log("Quest started")
elseif action == "FinishQuest" then
state.questActive = false
state.finishedAt = tick()
-- the game sends FinishQuest twice; only the one with a table counts
if type(data) == "table" then
state.completed = state.completed + 1
log("Quest finished (total " .. state.completed .. ")")
end
end
end))
end
end
--------------------------------------------------------------------
-- AUTO QUEST
--------------------------------------------------------------------
local function acceptQuest()
state.lastClick = tick()
local board = workspace:FindFirstChild("QuestBoards")
board = board and board:FindFirstChild("Halloween")
board = board and board:FindFirstChild("Board")
local papers = board and board:FindFirstChild("Papers")
local paper = papers and papers:FindFirstChild("HW_HorseRace")
local cd = paper and paper:FindFirstChildOfClass("ClickDetector")
if not (paper and cd) then
state.questText = "Horse Race paper not on board"
return
end
local root = getRoot()
if not root then
state.questText = "no character"
return
end
local original = root.CFrame
state.questText = "clicking board..."
root.CFrame = CFrame.new(paper.Position + CFG.BoardOffset)
task.wait(0.5)
local ok, err = pcall(fireclickdetector, cd)
if not ok then warn("[HorseFarm] fireclickdetector error:", tostring(err)) end
local t = tick()
while alive and not state.questActive and (tick() - t) < 4 do
task.wait(0.1)
end
if state.questActive then
state.questText = "quest active"
else
state.questText = "no reply from board (retrying)"
local r = getRoot()
if r then r.CFrame = original end
end
end
task.spawn(function()
while alive do
task.wait(1)
if CFG.AutoQuest then
if state.questActive and (tick() - state.questSince) > CFG.QuestTimeout then
state.questActive = false
state.questText = "quest timed out, retrying"
end
if not state.questActive and not raceActive() and not busy
and (tick() - state.lastClick) >= CFG.QuestRetry
and (tick() - state.finishedAt) >= 3 then
local ok, err = pcall(acceptQuest)
if not ok then warn("[HorseFarm] quest error:", tostring(err)) end
end
end
end
end)
--------------------------------------------------------------------
-- AUTO RACE
--------------------------------------------------------------------
local function runRace()
if busy then return end
busy = true
local place = LocalPlayer:GetAttribute(Attr.Place)
local course = findCourse(coursesFolder(), place)
if not course then
warn("[HorseFarm] Course not found for:", tostring(place))
state.raceText = "course not found"
busy = false
return
end
log("Race detected:", tostring(place))
local retries, lastGate = 0, nil
while alive and CFG.AutoRace and raceActive() do
if LocalPlayer:GetAttribute(Attr.Place) ~= place then break end
local gate = LocalPlayer:GetAttribute(Attr.Gate)
local total = LocalPlayer:GetAttribute(Attr.Gates)
state.raceText = place .. " " .. gate .. "/" .. total
if gate == lastGate then
retries = retries + 1
if retries > CFG.MaxRetries then
warn("[HorseFarm] Gate " .. gate .. " not accepted after " .. CFG.MaxRetries .. " tries - race bot stopped")
state.raceText = "stuck on gate " .. gate
CFG.AutoRace = false
break
end
else
retries, lastGate = 0, gate
end
local marker = course:FindFirstChild(tostring(gate))
local root = getRoot()
if marker and marker:IsA("BasePart") and root then
root.CFrame = marker.CFrame * CFrame.new(0, (Gates.Height or 10) / 2, 0)
pcall(function()
root.AssemblyLinearVelocity = Vector3.zero
root.AssemblyAngularVelocity = Vector3.zero
end)
task.wait(0.1)
pcall(function() GateRemote:FireServer(Gates.Remote, gate) end)
local t = tick()
while alive and CFG.AutoRace and LocalPlayer:GetAttribute(Attr.Gate) == gate
and raceActive() and (tick() - t) < CFG.GateTimeout do
task.wait(0.05)
end
else
warn("[HorseFarm] Missing gate marker or character for gate", tostring(gate))
task.wait(0.5)
end
task.wait(CFG.GateDelay)
end
if state.raceText:find("stuck") == nil then state.raceText = "waiting" end
log("Race loop finished")
busy = false
end
task.spawn(function()
while alive do
if CFG.AutoRace and raceActive() and not busy then
local ok, err = pcall(runRace)
if not ok then
busy = false
warn("[HorseFarm] race error:", tostring(err))
end
end
task.wait(0.5)
end
end)
--------------------------------------------------------------------
-- UI
--------------------------------------------------------------------
local gui = Instance.new("ScreenGui")
gui.Name = "HorseFarmGui"
gui.ResetOnSpawn = false
pcall(function() gui.Parent = (gethui and gethui()) or game:GetService("CoreGui") end)
local frame = Instance.new("Frame")
frame.Size = UDim2.new(0, 230, 0, 170)
frame.Position = UDim2.new(0, 20, 0.4, 0)
frame.BackgroundColor3 = Color3.fromRGB(25, 25, 30)
frame.BorderSizePixel = 0
frame.Parent = gui
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, 0, 0, 26)
title.BackgroundColor3 = Color3.fromRGB(45, 30, 70)
title.BorderSizePixel = 0
title.TextColor3 = Color3.new(1, 1, 1)
title.Font = Enum.Font.GothamBold
title.TextSize = 13
title.Text = "Horse Race Farm (drag me)"
title.Parent = frame
local function makeButton(text, y)
local b = Instance.new("TextButton")
b.Size = UDim2.new(1, -16, 0, 28)
b.Position = UDim2.new(0, 8, 0, y)
b.BorderSizePixel = 0
b.TextColor3 = Color3.new(1, 1, 1)
b.Font = Enum.Font.GothamBold
b.TextSize = 13
b.Text = text
b.Parent = frame
return b
end
local btnQuest = makeButton("", 34)
local btnRace = makeButton("", 68)
local statusLabel = Instance.new("TextLabel")
statusLabel.Size = UDim2.new(1, -16, 0, 60)
statusLabel.Position = UDim2.new(0, 8, 0, 102)
statusLabel.BackgroundTransparency = 1
statusLabel.TextColor3 = Color3.fromRGB(210, 210, 220)
statusLabel.Font = Enum.Font.Gotham
statusLabel.TextSize = 12
statusLabel.TextXAlignment = Enum.TextXAlignment.Left
statusLabel.TextYAlignment = Enum.TextYAlignment.Top
statusLabel.TextWrapped = true
statusLabel.Text = ""
statusLabel.Parent = frame
local function refreshButtons()
btnQuest.Text = "Auto Quest: " .. (CFG.AutoQuest and "ON" or "OFF")
btnQuest.BackgroundColor3 = CFG.AutoQuest and Color3.fromRGB(40, 150, 70) or Color3.fromRGB(150, 40, 40)
btnRace.Text = "Auto Race: " .. (CFG.AutoRace and "ON" or "OFF")
btnRace.BackgroundColor3 = CFG.AutoRace and Color3.fromRGB(40, 150, 70) or Color3.fromRGB(150, 40, 40)
end
refreshButtons()
btnQuest.MouseButton1Click:Connect(function()
CFG.AutoQuest = not CFG.AutoQuest
refreshButtons()
end)
btnRace.MouseButton1Click:Connect(function()
CFG.AutoRace = not CFG.AutoRace
if CFG.AutoRace and state.raceText:find("stuck") then state.raceText = "waiting" end
refreshButtons()
end)
-- dragging
do
local dragging, dragStart, startPos
table.insert(conns, title.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
dragging, dragStart, startPos = true, input.Position, frame.Position
end
end))
table.insert(conns, UIS.InputChanged:Connect(function(input)
if dragging and input.UserInputType == Enum.UserInputType.MouseMovement then
local d = input.Position - dragStart
frame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + d.X,
startPos.Y.Scale, startPos.Y.Offset + d.Y)
end
end))
table.insert(conns, UIS.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then dragging = false end
end))
end
-- F6 = toggle both
table.insert(conns, UIS.InputBegan:Connect(function(input, processed)
if not processed and input.KeyCode == Enum.KeyCode.F6 then
local on = not (CFG.AutoQuest or CFG.AutoRace)
CFG.AutoQuest, CFG.AutoRace = on, on
refreshButtons()
end
end))
-- status text
task.spawn(function()
while alive do
statusLabel.Text = "Quest: " .. state.questText
.. "\nRace: " .. state.raceText
.. "\nCompleted: " .. state.completed .. " (F6 = both)"
task.wait(0.5)
end
end)
getgenv().HorseFarm = {
Stop = function()
alive = false
CFG.AutoQuest, CFG.AutoRace = false, false
for _, c in ipairs(conns) do pcall(function() c:Disconnect() end) end
gui:Destroy()
end,
}
log("Loaded. Turn on Auto Quest and Auto Race (or press F6).")No comments yet for this script.