local UserInputService = game:GetService("UserInputService") local VirtualInputManager = game:GetService("VirtualInputManager") local RunService = game:GetService("RunService") local Players = game:GetService("Players") local PathfindingService = game:GetService("PathfindingService") local thisScript = script local spamEnabled = false local spamThread local player = Players.LocalPlayer local heldKeys = {} local lastSteerDir = nil local hysteresisTimer = 0 local hysteresisCooldown = 0.15 -- Faster response local steerSmoothing = 0.1 -- Smoother transitions local stuckTimer = 0 local stuckStage = 0 -- Multi-stage stuck recovery local lastPos = nil local waypoints = {} local currentWaypoint = nil local asphaltBias = 2 -- Stronger asphalt preference local maxSpeed = 1 -- Max throttle local minSpeed = 0.4 -- Min throttle for tight turns -- Input Helpers local function holdKey(key, intensity) if not heldKeys[key] or heldKeys[key] < intensity then VirtualInputManager:SendKeyEvent(true, Enum.KeyCode[key], false, game) heldKeys[key] = intensity end end local function releaseKey(key) if heldKeys[key] then VirtualInputManager:SendKeyEvent(false, Enum.KeyCode[key], false, game) heldKeys[key] = nil end end local function releaseAllKeys() for key, _ in pairs(heldKeys) do releaseKey(key) end end -- Vehicle Finder local function getVehicle() local character = player.Character if not character then return nil end local root = character:FindFirstChild("HumanoidRootPart") if not root then return nil end return root:FindFirstAncestorWhichIsA("VehicleSeat") or root:FindFirstAncestorWhichIsA("Seat") end -- Raycast Parameters local function getRaycastParams() local params = RaycastParams.new() params.FilterType = Enum.RaycastFilterType.Exclude local ignoreList = {} local vehicle = getVehicle() if vehicle then for _, obj in ipairs(vehicle:GetDescendants()) do table.insert(ignoreList, obj) end table.insert(ignoreList, vehicle) end if player.Character then table.insert(ignoreList, player.Character) end params.FilterDescendantsInstances = ignoreList params.IgnoreWater = true return params end -- Enhanced Pathfinding local function findPathToWaypoint(startPos, endPos) local path = PathfindingService:CreatePath({ AgentRadius = 6, -- Slightly larger for safer paths AgentHeight = 5, AgentCanJump = false, Costs = { Water = 200, -- Stronger avoidance Grass = 3, Sand = 4, Asphalt = 1, Concrete = 1.2 -- New terrain type } }) path:ComputeAsync(startPos, endPos) if path.Status == Enum.PathStatus.Success then return path:GetWaypoints() else -- Fallback: Try a simpler path path:ComputeAsync(startPos, endPos + Vector3.new(0, 5, 0)) return path.Status == Enum.PathStatus.Success and path:GetWaypoints() or nil end end -- Generate Smarter Waypoints local function generateWaypoint(currentPos) local maxDist = 120 local minDist = 60 local attempts = 0 local maxAttempts = 5 while attempts < maxAttempts do local angle = math.random() * 2 * math.pi local distance = math.random(minDist, maxDist) local newPos = currentPos + Vector3.new(math.cos(angle) * distance, 0, math.sin(angle) * distance) -- Check for asphalt and open space local raycastParams = getRaycastParams() local result = workspace:Raycast(newPos + Vector3.new(0, 50, 0), Vector3.new(0, -100, 0), raycastParams) if result and (result.Material == Enum.Material.Asphalt or result.Material == Enum.Material.Concrete) then -- Verify open space with additional raycasts local isClear = true for angle = 0, 360, 45 do local rad = math.rad(angle) local dir = Vector3.new(math.cos(rad), 0, math.sin(rad)) local checkResult = workspace:Raycast(newPos, dir * 20, raycastParams) if checkResult and checkResult.Distance < 15 then isClear = false break end end if isClear then return result.Position end end attempts += 1 end return nil end -- Update Waypoints local function updateWaypoints() local vehicle = getVehicle() if not vehicle then return end local currentPos = vehicle.Position if not currentWaypoint or (currentPos - currentWaypoint).Magnitude < 15 then local newWaypoint = generateWaypoint(currentPos) if newWaypoint then currentWaypoint = newWaypoint waypoints = findPathToWaypoint(currentPos, currentWaypoint) or {} else -- Fallback: Clear waypoints to avoid looping waypoints = {} end end end -- Enhanced Steering Logic local function getSteeringInput() local character = player.Character if not character then return nil, 0 end local root = character:FindFirstChild("HumanoidRootPart") if not root then return nil, 0 end local vehicle = getVehicle() local velocity = vehicle and vehicle.AssemblyLinearVelocity.Magnitude or 30 local origin = root.Position local forward = root.CFrame.LookVector local right = root.CFrame.RightVector local upOffsets = {0, 2, 4, 6} -- More granular checks local maxDist = math.clamp(velocity * 2.5, 25, 250) local rayDirs = {} -- Dynamic raycasting angles based on speed local angleStep = velocity > 40 and 4 or 3 for angle = -90, 90, angleStep do local rad = math.rad(angle) for _, up in ipairs(upOffsets) do local dir = CFrame.fromAxisAngle(Vector3.new(0, 1, 0), rad) * forward local finalDir = (dir + Vector3.new(0, up / maxDist, 0)).Unit table.insert(rayDirs, {dir = finalDir, angle = rad}) end end local params = getRaycastParams() local avoidanceVector = Vector3.new(0, 0, 0) local totalWeight = 0 local futureOffset = forward * velocity * 0.5 local predictedOrigin = origin + futureOffset -- Terrain-based speed and steering adjustment local surfaceWeight = 1 local groundResult = workspace:Raycast(predictedOrigin + Vector3.new(0, 5, 0), Vector3.new(0, -10, 0), params) if groundResult then if groundResult.Material == Enum.Material.Asphalt or groundResult.Material == Enum.Material.Concrete then surfaceWeight = asphaltBias elseif groundResult.Material == Enum.Material.Grass then surfaceWeight = 0.8 maxSpeed = 0.8 elseif groundResult.Material == Enum.Material.Sand then surfaceWeight = 0.6 maxSpeed = 0.6 end end for _, ray in ipairs(rayDirs) do local result = workspace:Raycast(predictedOrigin, ray.dir * maxDist, params) if result then local distanceFactor = (maxDist - result.Distance) / maxDist local weight = distanceFactor ^ 3 * surfaceWeight -- Stronger avoidance if math.abs(math.deg(ray.angle)) < 10 then weight = weight * 0.3 -- Prefer straighter paths end avoidanceVector = avoidanceVector - ray.dir * weight totalWeight = totalWeight + weight end end -- Waypoint guidance with dynamic weighting if waypoints and #waypoints > 0 then local nextPoint = waypoints[1].Position local toWaypoint = (nextPoint - origin).Unit local distanceToWaypoint = (nextPoint - origin).Magnitude local waypointWeight = math.clamp(50 / distanceToWaypoint, 0.5, 2) avoidanceVector = avoidanceVector + toWaypoint * waypointWeight totalWeight = totalWeight + waypointWeight end if totalWeight > 0 then avoidanceVector = avoidanceVector / totalWeight end avoidanceVector = Vector3.new(avoidanceVector.X, 0, avoidanceVector.Z) local mag = avoidanceVector.Magnitude if mag < 0.02 then lastSteerDir = nil return nil, 0 end local steerDot = avoidanceVector.Unit:Dot(right) local steerDir = steerDot > 0 and "D" or "A" local steerPower = math.clamp(mag * 3, 0.4, 1) -- Obstacle-aware steering local proposedDir = steerDir == "D" and right or -right local secondaryDist = maxDist * 0.5 local secondaryResult = workspace:Raycast(origin, proposedDir * secondaryDist, params) if secondaryResult and secondaryResult.Distance < secondaryDist * 0.25 then steerPower = steerPower * 0.5 if secondaryResult.Distance < secondaryDist * 0.15 then steerDir = steerDir == "D" and "A" or "D" end end -- Hysteresis for stability if lastSteerDir and lastSteerDir ~= steerDir then if tick() - hysteresisTimer < hysteresisCooldown then steerDir = lastSteerDir steerPower = steerPower * 0.7 else lastSteerDir = steerDir hysteresisTimer = tick() end end -- Smooth steering if lastSteerDir == steerDir then steerPower = steerPower * (1 - steerSmoothing) + (heldKeys[steerDir] or 0) * steerSmoothing end lastSteerDir = steerDir return steerDir, steerPower end -- Main Loop local function steerVehicle() while spamEnabled do updateWaypoints() local steerDir, steerIntensity = getSteeringInput() -- Dynamic speed control local throttle = maxSpeed if steerDir and steerIntensity > 0.7 then throttle = math.clamp(maxSpeed * (1 - steerIntensity), minSpeed, maxSpeed) end holdKey("W", throttle) -- Steering if steerDir then holdKey(steerDir, steerIntensity) local oppositeDir = steerDir == "A" and "D" or "A" releaseKey(oppositeDir) else releaseKey("A") releaseKey("D") end -- Multi-stage stuck detection and recovery local vehicle = getVehicle() if vehicle then local currentPos = vehicle.Position if lastPos and (currentPos - lastPos).Magnitude < 0.3 then stuckTimer += 0.03 else stuckTimer = 0 stuckStage = 0 end lastPos = currentPos if stuckTimer > 1 then if stuckStage == 0 then -- Stage 1: Reverse holdKey("S", 1) task.wait(0.5) releaseKey("S") stuckStage = 1 elseif stuckStage == 1 then -- Stage 2: Reverse and turn holdKey("S", 1) holdKey(math.random() > 0.5 and "A" or "D", 1) task.wait(0.8) releaseKey("S") releaseKey("A") releaseKey("D") stuckStage = 2 else -- Stage 3: Reset waypoints and try new path waypoints = {} currentWaypoint = nil stuckTimer = 0 stuckStage = 0 end end end -- Adaptive delay local delay = 0.015 - steerIntensity * 0.005 task.wait(math.clamp(delay, 0.01, 0.015)) end releaseAllKeys() end -- Input Controls local connection connection = UserInputService.InputBegan:Connect(function(input, gameProcessed) if gameProcessed then return end if input.KeyCode == Enum.KeyCode.Z then spamEnabled = not spamEnabled if spamEnabled then spamThread = task.spawn(steerVehicle) end elseif input.KeyCode == Enum.KeyCode.X then spamEnabled = false if connection then connection:Disconnect() end releaseAllKeys() thisScript:Destroy() end end)