local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UIS = game:GetService("UserInputService") local PathfindingService = game:GetService("PathfindingService") local Workspace = game:GetService("Workspace") local player = Players.LocalPlayer local character = player.Character or player.CharacterAdded:Wait() local humanoid = character:WaitForChild("Humanoid") local root = character:WaitForChild("HumanoidRootPart") -- SETTINGS local botActive = false local attackRange = 30 -- you can change this if you want local walkSpeed = 30 local strafeRadius = 5 -- now strafes exactly 5 studs away local strafeSpeed = 0.5 local voidLevel = -10 local lockedTarget = nil local orbitAngle = 0 local strafeDirection = 1 humanoid.WalkSpeed = walkSpeed -- TOGGLE BOT UIS.InputBegan:Connect(function(input, processed) if processed then return end if input.KeyCode == Enum.KeyCode.M then botActive = not botActive if not botActive then lockedTarget = nil end end end) -- FIND NEAREST PLAYER local function pickTarget() local nearestDist = math.huge local nearestChar = nil for _,plr in pairs(Players:GetPlayers()) do if plr ~= player then local char = plr.Character if char then local hum = char:FindFirstChild("Humanoid") local hrp = char:FindFirstChild("HumanoidRootPart") if hum and hum.Health > 0 and hrp then local dist = (hrp.Position - root.Position).Magnitude if dist < nearestDist then nearestDist = dist nearestChar = char end end end end end lockedTarget = nearestChar end -- VOID RECOVERY local function fixVoid() if root.Position.Y < voidLevel then local rayOrigin = root.Position + Vector3.new(0,100,0) local rayDir = Vector3.new(0,-500,0) local params = RaycastParams.new() params.FilterDescendantsInstances = {character} params.FilterType = Enum.RaycastFilterType.Blacklist local result = Workspace:Raycast(rayOrigin, rayDir, params) if result then root.CFrame = CFrame.new(result.Position + Vector3.new(0,5,0)) else root.CFrame = CFrame.new(0,10,0) end end end -- CHECK GROUND BELOW local function groundBelow(pos) local rayOrigin = pos + Vector3.new(0,2,0) local rayDir = Vector3.new(0,-12,0) local params = RaycastParams.new() params.FilterDescendantsInstances = {character} params.FilterType = Enum.RaycastFilterType.Blacklist local result = Workspace:Raycast(rayOrigin, rayDir, params) return result ~= nil end -- STRAFE AROUND PLAYER AT 5 STUDS local function safeStrafe(targetPos) orbitAngle += strafeSpeed * strafeDirection local offset = Vector3.new( math.cos(orbitAngle) * strafeRadius, 0, math.sin(orbitAngle) * strafeRadius ) local strafePos = targetPos + offset local frontSafe = groundBelow(strafePos) local leftPos = targetPos + Vector3.new( math.cos(orbitAngle + math.pi/2) * strafeRadius, 0, math.sin(orbitAngle + math.pi/2) * strafeRadius ) local rightPos = targetPos + Vector3.new( math.cos(orbitAngle - math.pi/2) * strafeRadius, 0, math.sin(orbitAngle - math.pi/2) * strafeRadius ) local leftSafe = groundBelow(leftPos) local rightSafe = groundBelow(rightPos) if not frontSafe then strafeDirection *= -1 elseif not leftSafe and not rightSafe then humanoid:MoveTo(Vector3.new(0, root.Position.Y, 0)) return end local moveDir = strafePos - root.Position moveDir = Vector3.new(moveDir.X,0,moveDir.Z) if moveDir.Magnitude > 0 then humanoid:Move(moveDir.Unit,false) end -- always face the player root.CFrame = CFrame.new(root.Position, Vector3.new(targetPos.X, root.Position.Y, targetPos.Z)) end -- PATHFIND TO TARGET local moving = false local function moveToTarget(targetPos) if moving then return end moving = true local path = PathfindingService:CreatePath() path:ComputeAsync(root.Position,targetPos) for _,wp in ipairs(path:GetWaypoints()) do if not botActive then break end if wp.Action == Enum.PathWaypointAction.Jump then humanoid:ChangeState(Enum.HumanoidStateType.Jumping) end humanoid:MoveTo(wp.Position) humanoid.MoveToFinished:Wait() end moving = false end -- MAIN LOOP RunService.RenderStepped:Connect(function() if not botActive then return end fixVoid() pickTarget() if lockedTarget and lockedTarget:FindFirstChild("HumanoidRootPart") then local targetRoot = lockedTarget.HumanoidRootPart local hum = lockedTarget:FindFirstChild("Humanoid") if hum and hum.Health > 0 then local dist = (targetRoot.Position - root.Position).Magnitude if dist > strafeRadius then moveToTarget(targetRoot.Position) else safeStrafe(targetRoot.Position) end if dist <= attackRange then local sword = character:FindFirstChildOfClass("Tool") if sword then sword:Activate() end end else lockedTarget = nil end end end)