-- 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).")