local function E(E)local l=math_min(Utility.ViewSizeY()*.33,250)local i=l return E.X<=i and E.Y>Utility.ViewSizeY()-l end local function l(E)local l=math_min(Utility.ViewSizeY()*.33,250)local i=l return E.X>=Utility.ViewSizeX()-i and E.Y>Utility.ViewSizeY()-l end local function i(E)local l=findPlayerHumanoid(Player)return l~=nil and l.Health>0 end local function h(E)if E~=nil then for E,l in pairs(E:GetChildren())do if l:IsA("\084\111\111\108")then return l end end end end local q=nil local z=nil local y=nil local Q=nil local function Z()DrivingTo=nil if q then q:Cancel()end if y then y:disconnect()y=nil end if Q then Q:disconnect()Q=nil end if z then local E=z local l=E:TweenOut()local i=nil i=l.Completed:connect(function()i:disconnect()E.Model:Destroy()end)z=nil end end local function P(E)local l,i,h=-math.huge,-math.huge,-math.huge local q,z,y=math.huge,math.huge,math.huge for Q=1,#E,1 do l,i,h=math_max(l,E[Q].Position.X),math_max(i,E[Q].Position.Y),math_max(h,E[Q].Position.Z)q,z,y=math_min(q,E[Q].Position.X),math_min(z,E[Q].Position.Y),math_min(y,E[Q].Position.Z)end return Region3.new(Vector3_new(q,z,y),Vector3_new(l,i,h))end local function Y(E,l)if l.X<E.CFrame.p.X-E.Size.X/2 or l.X>E.CFrame.p.X+E.Size.X/2 then return false end if l.Z<E.CFrame.p.Z-E.Size.Z/2 or l.Z>E.CFrame.p.Z+E.Size.Z/2 then return false end return true end local v=0 local function k(E,l)local e=workspace.CurrentCamera local p=Player.Character if not i(p)then return end if#E==1 or l then if e then local i=e:ScreenPointToRay(E[1].x,E[1].y)local L=Ray.new(i.Origin,i.Direction*1000)local V=getIgnoreList()local A=InvisicamModule and InvisicamModule:GetObscuredParts()or{}local g={}for E,l in pairs(A)do g[#g+1]=E end for E=1,#V,1 do g[#g+1]=V[E]end local C=findPlayerHumanoid(Player)local c,t,N,G=Utility.Raycast(L,true,g)local U,b=Utility.FindChacterAncestor(c)local a=GetTorso()local O=a.CFrame.p if l then t=l U=nil end if U and(b and(b.Torso and(b.Torso.CFrame.p-a.CFrame.p).magnitude<7))then Z()if C then C:MoveTo(t)end local E=h(p)if E then E:Activate()LastFired=tick()end elseif t and(p and not CurrentSeatPart)then local E=Pather(p,t,N)if E:IsValidPath()then v=0 E:Start()if BindableEvent_OnFailStateChanged then BindableEvent_OnFailStateChanged:Fire(false)end Z()local l=createNewPopup("\068\101\115\116\105\110\097\116\105\111\110\080\111\112\117\112")l:Place(t,Vector3_new(0,t.y,0))local i=createNewPopup("\070\097\105\108\117\114\101\080\111\112\117\112")local P=l:TweenIn()q=E z=l y=E.Finished:connect(function()if l then if z==l then z=nil end local E=l:TweenOut()local i=nil i=E.Completed:connect(function()i:disconnect()l.Model:Destroy()l=nil end)end if U then local E=findPlayerHumanoid(Player)local l=h(p)if l then l:Activate()LastFired=tick()end if E then E:MoveTo(t)end end end)Q=E.PathFailed:connect(function()if i then i:Place(t,Vector3_new(0,t.y,0))local E=i:TweenIn()E.Completed:wait()local l=i:TweenOut()l.Completed:wait()i.Model:Destroy()i=nil end end)else if t then local E=false if(t-O).Magnitude<25 and O.y-t.y>-3 then if C then if C.Sit then C.Jump=true end local l C:MoveTo(t)E=true end end spawn(function()local l=createNewPopup(E and"\068\105\114\101\099\116\087\097\108\107\080\111\112\117\112"or"\070\097\105\108\117\114\101\080\111\112\117\112")l:Place(t,Vector3_new(0,t.y,0))local i=l:TweenIn()i.Completed:wait()local h=l:TweenOut()h.Completed:wait()l.Model:Destroy()l=nil end)end end elseif t and(p and CurrentSeatPart)then local l=createNewPopup("\068\101\115\116\105\110\097\116\105\111\110\080\111\112\117\112")z=l l:Place(t,Vector3_new(0,t.y,0))l:TweenIn()DrivingTo=t local i=CurrentSeatPart:GetConnectedParts(true)while wait()do if CurrentSeatPart and z==l then local E=P(i)if Y(E,t)then local E=l spawn(function()local l=E:TweenOut()l.Completed:wait()E.Model:Destroy()end)l=nil DrivingTo=nil break end else if CurrentSeatPart==nil and l==z then DrivingTo=nil k(E,t)end local i=l spawn(function()local E=i:TweenOut()E.Completed:wait()i.Model:Destroy()end)l=nil break end end end end elseif#E>=2 then if e then local l=Utility.AveragePoints(E)local i=e:ScreenPointToRay(l.x,l.y)local q=h(p)if q then q:Activate()LastFired=tick()end end end end local function e()local i={}local h=0 local q=Enum.HumanoidStateType.Running local y={}local Q=0 local P=tick()local Y=Vector2_new()local v=tick()local e=Vector2_new()local p=tick()local L={[Enum.KeyCode.W]=true,[Enum.KeyCode.A]=true;[Enum.KeyCode.S]=true;[Enum.KeyCode.D]=true,[Enum.KeyCode.Up]=true;[Enum.KeyCode.Down]=true}local V=nil local A=nil local g=nil local C=nil local c=nil local t=nil local N=nil local G=nil local U=nil local b=nil local function a(E)if E then E:disconnect()end end local function O()a(V)a(A)a(g)a(C)a(c)a(t)a(N)a(U)a(G)pcall(function()RunService:UnbindFromRenderStep("\067\108\105\099\107\084\111\077\111\118\101\082\101\110\100\101\114\085\112\100\097\116\101")end)a(b)end local function K(E)return E==E and(E~=1/0 and E~=-1/0)end local function n(E,l)return math_atan2(l.X*E.Z-l.Z*E.X,l.X*E.X+l.Z*E.Z)end local function F(E,l)if y[E]==nil and not l then Q=Q+1 end y[E]=l end local function B(E,l)if y[E]==nil then y[E]=l if not l then Q=Q+1 end end end local function M(E,l)if y[E]~=nil and y[E]==false then Q=Q-1 end y[E]=nil end local function J(i)O()A=UIS.InputBegan:connect(function(i,h)if i.UserInputType==Enum.UserInputType.Touch then F(i,h)local q=E(i.Position)local z=l(i.Position)if z or q then for h,y in pairs(y)do if h~=i then local i=E(h.Position)local y=l(h.Position)if h.UserInputState~=Enum.UserInputState.End and(q and y or z and i)then if BindableEvent_OnFailStateChanged then BindableEvent_OnFailStateChanged:Fire(true)end return end end end end end if h==false and(i.UserInputType==Enum.UserInputType.Keyboard and L[i.KeyCode])then Z()end if i.UserInputType==Enum.UserInputType.MouseButton1 then P=tick()Y=i.Position end if i.UserInputType==Enum.UserInputType.MouseButton2 then v=tick()e=i.Position end end)g=UIS.InputChanged:connect(function(E,l)if E.UserInputType==Enum.UserInputType.Touch then B(E,l)end end)C=UIS.InputEnded:connect(function(E,l)if E.UserInputType==Enum.UserInputType.Touch then M(E,l)end if E.UserInputType==Enum.UserInputType.MouseButton2 then p=tick()local l=E.Position if p-v<.25 and(l-e).magnitude<5 then local E={l}k(E)end end end)V=UIS.TouchTap:connect(function(E,l)if not l then k(E)end end)local function h(E)if E>.2 then return.5+E^2/2 else return 0 end end local q=0 local Q=1 local N=.5 local function U(E,l)local i,z=0,0 local y=E.CFrame local Z=y:pointToObjectSpace(l)local P=-Z.z local Y=Z.magnitude i=h(math_min(1,Y/50))*math.sign(P)local v=-math_atan2(-Z.x,-Z.z)z=v/(math_pi/4)local k=z-q q=z local e=Q*z+N*z return i,e end local function K()if CurrentSeatPart then if DrivingTo then local E,l=U(CurrentSeatPart,DrivingTo)CurrentSeatPart.ThrottleFloat=E CurrentSeatPart.SteerFloat=l else CurrentSeatPart.ThrottleFloat=0 CurrentSeatPart.SteerFloat=0 end end end RunService:BindToRenderStep("\067\108\105\099\107\084\111\077\111\118\101\082\101\110\100\101\114\085\112\100\097\116\101",Enum.RenderPriority.Camera.Value-1,K)local function n(E,l,i)if l then if TouchJump and UIS.TouchEnabled then TouchJump:Enable()end if i and i.ClassName=="\086\101\104\105\099\108\101\083\101\097\116"then CurrentSeatPart=i end else CurrentSeatPart=nil if TouchJump and UIS.TouchEnabled then TouchJump:Disable()end end end local function J(E)if UIS.TouchEnabled then if E:IsA("\084\111\111\108")then E.ManualActivationOnly=true end end if E:IsA("\072\117\109\097\110\111\105\100")then a(c)c=E.Died:connect(function()if z then DebrisService:AddItem(z.Model,1)end end)b=E.Seated:connect(function(l,i)n(E,l,i)end)if E.SeatPart then n(E,true,E.SeatPart)end end end t=i.ChildAdded:connect(function(E)J(E)end)G=i.ChildRemoved:connect(function(E)if UIS.TouchEnabled then if E:IsA("\084\111\111\108")then E.ManualActivationOnly=false end end end)for E,l in pairs(i:GetChildren())do J(l)end end local r=false function i.Stop(E)if r then O()Z()if UIS.TouchEnabled then local E=Player.Character if E then for E,l in pairs(E:GetChildren())do if l:IsA("\084\111\111\108")then l.ManualActivationOnly=false end end end end DrivingTo=nil r=false end end function i.Start(E)if not r then if Player.Character then J(Player.Character)end N=Player.CharacterAdded:connect(J)r=true end end function i.Enable(E)E:Start()end function i.Disable(E)E:Stop()end function i.GetName(E)return DEBUG_NAME end return i end return e()


local function IsInBottomLeft(pt)
	local joystickHeight = math_min(Utility.ViewSizeY() * 0.33, 250)
	local joystickWidth = joystickHeight
	return pt.X <= joystickWidth and pt.Y > Utility.ViewSizeY() - joystickHeight
end

local function IsInBottomRight(pt)
	local joystickHeight = math_min(Utility.ViewSizeY() * 0.33, 250)
	local joystickWidth = joystickHeight
	return pt.X >= Utility.ViewSizeX() - joystickWidth and pt.Y > Utility.ViewSizeY() - joystickHeight
end

local function CheckAlive(character)
	local humanoid = findPlayerHumanoid(Player)
	return humanoid ~= nil and humanoid.Health > 0
end

local function GetEquippedTool(character)
	if character ~= nil then
		for _, child in pairs(character:GetChildren()) do
			if child:IsA('Tool') then
				return child
			end
		end
	end
end

local ExistingPather = nil
local ExistingIndicator = nil
local PathCompleteListener = nil
local PathFailedListener = nil

local function CleanupPath()
	DrivingTo = nil
	if ExistingPather then
		ExistingPather:Cancel()
	end
	if PathCompleteListener then
		PathCompleteListener:disconnect()
		PathCompleteListener = nil
	end
	if PathFailedListener then
		PathFailedListener:disconnect()
		PathFailedListener = nil
	end
	if ExistingIndicator then
		local obj = ExistingIndicator
		local tween = obj:TweenOut()
		local tweenCompleteEvent = nil
		tweenCompleteEvent = tween.Completed:connect(function()
			tweenCompleteEvent:disconnect()
			obj.Model:Destroy()
		end)
		ExistingIndicator = nil
	end
end

local function getExtentsSize(Parts)
	local maxX,maxY,maxZ = -math.huge,-math.huge,-math.huge
	local minX,minY,minZ = math.huge,math.huge,math.huge
	for i = 1, #Parts do
		maxX,maxY,maxZ = math_max(maxX, Parts[i].Position.X), math_max(maxY, Parts[i].Position.Y), math_max(maxZ, Parts[i].Position.Z)
		minX,minY,minZ = math_min(minX, Parts[i].Position.X), math_min(minY, Parts[i].Position.Y), math_min(minZ, Parts[i].Position.Z)
	end
	return Region3.new(Vector3_new(minX, minY, minZ), Vector3_new(maxX, maxY, maxZ))
end

local function inExtents(Extents, Position)
	if Position.X < (Extents.CFrame.p.X - Extents.Size.X/2) or Position.X > (Extents.CFrame.p.X + Extents.Size.X/2) then
		return false
	end
	if Position.Z < (Extents.CFrame.p.Z - Extents.Size.Z/2) or Position.Z > (Extents.CFrame.p.Z + Extents.Size.Z/2) then
		return false
	end
	--ignoring Y for now
	return true
end

local FailCount = 0
local function OnTap(tapPositions, goToPoint)
	-- Good to remember if this is the latest tap event
	local camera = workspace.CurrentCamera
	local character = Player.Character
	
	if not CheckAlive(character) then return end
	
	-- This is a path tap position
	if #tapPositions == 1 or goToPoint then
		if camera then
			local unitRay = camera:ScreenPointToRay(tapPositions[1].x, tapPositions[1].y)
			local ray = Ray.new(unitRay.Origin, unitRay.Direction*1000)
			
			-- inivisicam stuff
			local initIgnore = getIgnoreList()
			local invisicamParts = InvisicamModule and InvisicamModule:GetObscuredParts() or {}
			local ignoreTab = {}
			
			-- add to the ignore list
			for i, v in pairs(invisicamParts) do
				ignoreTab[#ignoreTab+1] = i
			end
			for i = 1, #initIgnore do
				ignoreTab[#ignoreTab+1] = initIgnore[i]
			end
			--			
			local myHumanoid = findPlayerHumanoid(Player)
			local hitPart, hitPt, hitNormal, hitMat = Utility.Raycast(ray, true, ignoreTab)

			local hitChar, hitHumanoid = Utility.FindChacterAncestor(hitPart)
			local torso = GetTorso()
			local startPos = torso.CFrame.p
			if goToPoint then
				hitPt = goToPoint
				hitChar = nil
			end
			if hitChar and hitHumanoid and hitHumanoid.Torso and (hitHumanoid.Torso.CFrame.p - torso.CFrame.p).magnitude < 7 then
				CleanupPath()
				
				if myHumanoid then
					myHumanoid:MoveTo(hitPt)
				end
				-- Do shoot
				local currentWeapon = GetEquippedTool(character)
				if currentWeapon then
					currentWeapon:Activate()
					LastFired = tick()
				end
			elseif hitPt and character and not CurrentSeatPart then
				local thisPather = Pather(character, hitPt, hitNormal)
				if thisPather:IsValidPath() then
					FailCount = 0
					
					thisPather:Start()
					if BindableEvent_OnFailStateChanged then
						BindableEvent_OnFailStateChanged:Fire(false)
					end
					CleanupPath()
					
					local destinationPopup = createNewPopup("DestinationPopup")	
					destinationPopup:Place(hitPt, Vector3_new(0,hitPt.y,0))
					local failurePopup = createNewPopup("FailurePopup")
					local currentTween = destinationPopup:TweenIn()
					
					
					ExistingPather = thisPather
					ExistingIndicator = destinationPopup

					PathCompleteListener = thisPather.Finished:connect(function()
						if destinationPopup then
							if ExistingIndicator == destinationPopup then
								ExistingIndicator = nil
							end
							local tween = destinationPopup:TweenOut()
							local tweenCompleteEvent = nil
							tweenCompleteEvent = tween.Completed:connect(function()
								tweenCompleteEvent:disconnect()
								destinationPopup.Model:Destroy()
								destinationPopup = nil
							end)
						end
						if hitChar then
							local humanoid = findPlayerHumanoid(Player)
							local currentWeapon = GetEquippedTool(character)
							if currentWeapon then
								currentWeapon:Activate()
								LastFired = tick()
							end
							if humanoid then
	
								humanoid:MoveTo(hitPt)
							end
						end
					end)
					PathFailedListener = thisPather.PathFailed:connect(function()
						if failurePopup then
							failurePopup:Place(hitPt, Vector3_new(0,hitPt.y,0))
							local failTweenIn = failurePopup:TweenIn()
							failTweenIn.Completed:wait()
							local failTweenOut = failurePopup:TweenOut()
							failTweenOut.Completed:wait()
							failurePopup.Model:Destroy()
							failurePopup = nil
						end
					end)
				else
					if hitPt then
						-- Feedback here for when we don't have a good path
						local foundDirectPath = false
						if (hitPt-startPos).Magnitude < 25 and (startPos.y-hitPt.y > -3) then
							-- move directly here
							if myHumanoid then
								if myHumanoid.Sit then
									myHumanoid.Jump = true
								end
								local currentPosition
								myHumanoid:MoveTo(hitPt)
								foundDirectPath = true
							end
						end						
						
						spawn(function()
							local directPopup = createNewPopup(foundDirectPath and "DirectWalkPopup" or "FailurePopup")
							directPopup:Place(hitPt, Vector3_new(0,hitPt.y,0))
							local directTweenIn = directPopup:TweenIn()
							directTweenIn.Completed:wait()
							local directTweenOut = directPopup:TweenOut()
							directTweenOut.Completed:wait()
							directPopup.Model:Destroy()
							directPopup = nil
						end)
					end
				end
			elseif hitPt and character and CurrentSeatPart then 
				local destinationPopup = createNewPopup("DestinationPopup")	
				ExistingIndicator = destinationPopup
				destinationPopup:Place(hitPt, Vector3_new(0,hitPt.y,0))
				destinationPopup:TweenIn()
				
				DrivingTo = hitPt
				local ConnectedParts = CurrentSeatPart:GetConnectedParts(true)
				
				while wait() do
					if CurrentSeatPart and ExistingIndicator == destinationPopup then
						local ExtentsSize = getExtentsSize(ConnectedParts)
						if inExtents(ExtentsSize, hitPt) then
							local popup = destinationPopup
							spawn(function()
								local tweenOut = popup:TweenOut()
								tweenOut.Completed:wait()
								popup.Model:Destroy()
							end)
							destinationPopup = nil
							DrivingTo = nil
							break
						end
					else
						if CurrentSeatPart == nil and destinationPopup == ExistingIndicator then
							DrivingTo = nil
							OnTap(tapPositions, hitPt)
						end
						local popup = destinationPopup
						spawn(function()
							local tweenOut = popup:TweenOut()
							tweenOut.Completed:wait()
							popup.Model:Destroy()
						end)
						destinationPopup = nil
						break
					end
				end
			end
		end
	elseif #tapPositions >= 2 then
		if camera then
			-- Do shoot
			local avgPoint = Utility.AveragePoints(tapPositions)
			local unitRay = camera:ScreenPointToRay(avgPoint.x, avgPoint.y)
			local currentWeapon = GetEquippedTool(character)
			if currentWeapon then
				currentWeapon:Activate()
				LastFired = tick()
			end
		end
	end
end


local function CreateClickToMoveModule()
	local this = {}

	local LastStateChange = 0
	local LastState = Enum.HumanoidStateType.Running
	local FingerTouches = {}
	local NumUnsunkTouches = 0
	-- PC simulation
	local mouse1Down = tick()
	local mouse1DownPos = Vector2_new()
	local mouse2Down = tick()
	local mouse2DownPos = Vector2_new()
	local mouse2Up = tick()

	local movementKeys = {
		[Enum.KeyCode.W] = true;
		[Enum.KeyCode.A] = true;
		[Enum.KeyCode.S] = true;
		[Enum.KeyCode.D] = true;
		[Enum.KeyCode.Up] = true;
		[Enum.KeyCode.Down] = true;
	}

	local TapConn = nil
	local InputBeganConn = nil
	local InputChangedConn = nil
	local InputEndedConn = nil
	local HumanoidDiedConn = nil
	local CharacterChildAddedConn = nil
	local OnCharacterAddedConn = nil
	local CharacterChildRemovedConn = nil
	local RenderSteppedConn = nil
	local HumanoidSeatedConn = nil

	local function disconnectEvent(event)
		if event then
			event:disconnect()
		end
	end

	local function DisconnectEvents()
		disconnectEvent(TapConn)
		disconnectEvent(InputBeganConn)
		disconnectEvent(InputChangedConn)
		disconnectEvent(InputEndedConn)
		disconnectEvent(HumanoidDiedConn)
		disconnectEvent(CharacterChildAddedConn)
		disconnectEvent(OnCharacterAddedConn)
		disconnectEvent(RenderSteppedConn)
		disconnectEvent(CharacterChildRemovedConn)
		pcall(function() RunService:UnbindFromRenderStep("ClickToMoveRenderUpdate") end)
		disconnectEvent(HumanoidSeatedConn)
	end



	local function IsFinite(num)
		return num == num and num ~= 1/0 and num ~= -1/0
	end
	
	local function findAngleBetweenXZVectors(vec2, vec1)
		return math_atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z)
	end

	local function OnTouchBegan(input, processed)
		if FingerTouches[input] == nil and not processed then
			NumUnsunkTouches = NumUnsunkTouches + 1
		end
		FingerTouches[input] = processed
	end

	local function OnTouchChanged(input, processed)
		if FingerTouches[input] == nil then
			FingerTouches[input] = processed
			if not processed then
				NumUnsunkTouches = NumUnsunkTouches + 1
			end
		end
	end

	local function OnTouchEnded(input, processed)
		if FingerTouches[input] ~= nil and FingerTouches[input] == false then
			NumUnsunkTouches = NumUnsunkTouches - 1
		end
		FingerTouches[input] = nil
	end


	local function OnCharacterAdded(character)
		DisconnectEvents()

		InputBeganConn = UIS.InputBegan:connect(function(input, processed)
			if input.UserInputType == Enum.UserInputType.Touch then
				OnTouchBegan(input, processed)

				-- Give back controls when they tap both sticks
				local wasInBottomLeft = IsInBottomLeft(input.Position)
				local wasInBottomRight = IsInBottomRight(input.Position)
				if wasInBottomRight or wasInBottomLeft then
					for otherInput, _ in pairs(FingerTouches) do
						if otherInput ~= input then
							local otherInputInLeft = IsInBottomLeft(otherInput.Position)
							local otherInputInRight = IsInBottomRight(otherInput.Position)
							if otherInput.UserInputState ~= Enum.UserInputState.End and ((wasInBottomLeft and otherInputInRight) or (wasInBottomRight and otherInputInLeft)) then
								if BindableEvent_OnFailStateChanged then
									BindableEvent_OnFailStateChanged:Fire(true)
								end
								return
							end
						end
					end
				end
			end

			 -- Cancel path when you use the keyboard controls.
			if processed == false and input.UserInputType == Enum.UserInputType.Keyboard and movementKeys[input.KeyCode] then
				CleanupPath()
			end
			if input.UserInputType == Enum.UserInputType.MouseButton1 then
				mouse1Down = tick()
				mouse1DownPos = input.Position
			end
			if input.UserInputType == Enum.UserInputType.MouseButton2 then
				mouse2Down = tick()
				mouse2DownPos = input.Position
			end
		end)

		InputChangedConn = UIS.InputChanged:connect(function(input, processed)
			if input.UserInputType == Enum.UserInputType.Touch then
				OnTouchChanged(input, processed)
			end
		end)

		InputEndedConn = UIS.InputEnded:connect(function(input, processed)
			if input.UserInputType == Enum.UserInputType.Touch then
				OnTouchEnded(input, processed)
			end

			if input.UserInputType == Enum.UserInputType.MouseButton2 then
				mouse2Up = tick()
				local currPos = input.Position
				if mouse2Up - mouse2Down < 0.25 and (currPos - mouse2DownPos).magnitude < 5 then
					local positions = {currPos}
					OnTap(positions)
				end
			end
		end)

		TapConn = UIS.TouchTap:connect(function(touchPositions, processed)
			if not processed then
				OnTap(touchPositions)
			end
		end)
		
		local function computeThrottle(dist)
			if dist > .2 then
				return 0.5+(dist^2)/2
			else
				return 0
			end
		end		

		local lastSteer = 0

		--kP = how much the steering corrects for the current error in driving angle
		--kD = how much the steering corrects for how quickly the error in driving angle is changing
		local kP = 1
		local kD = 0.5
		local function getThrottleAndSteer(object, point)
			local throttle, steer = 0, 0
			local oCF = object.CFrame
			
			local relativePosition = oCF:pointToObjectSpace(point)
			local relativeZDirection = -relativePosition.z
			local relativeDistance = relativePosition.magnitude
			
			-- throttle quadratically increases from 0-1 as distance from the selected point goes from 0-50, after 50, throttle is 1.
			-- this allows shorter distance travel to have more fine-tuned control.
			throttle = computeThrottle(math_min(1,relativeDistance/50))*math.sign(relativeZDirection)
			
			local steerAngle = -math_atan2(-relativePosition.x, -relativePosition.z)
			steer = steerAngle/(math_pi/4)

			local steerDelta = steer - lastSteer
			lastSteer = steer
			local pdSteer = kP * steer + kD * steer
			return throttle, pdSteer
		end
		
		local function Update()
			if CurrentSeatPart then
				if DrivingTo then
					local throttle, steer = getThrottleAndSteer(CurrentSeatPart, DrivingTo)
					CurrentSeatPart.ThrottleFloat = throttle
					CurrentSeatPart.SteerFloat = steer
				else
					CurrentSeatPart.ThrottleFloat = 0
					CurrentSeatPart.SteerFloat = 0
				end
			end
		end
		
		RunService:BindToRenderStep("ClickToMoveRenderUpdate",Enum.RenderPriority.Camera.Value - 1,Update)
	
		local function onSeated(child, active, currentSeatPart)
			if active then
				if TouchJump and UIS.TouchEnabled then
					TouchJump:Enable()
				end
				if currentSeatPart and currentSeatPart.ClassName == "VehicleSeat" then
					CurrentSeatPart = currentSeatPart
				end
			else
				CurrentSeatPart = nil
				if TouchJump and UIS.TouchEnabled then
					TouchJump:Disable()
				end
			end
		end

		local function OnCharacterChildAdded(child)
			if UIS.TouchEnabled then
				if child:IsA('Tool') then
					child.ManualActivationOnly = true
				end
			end
			if child:IsA('Humanoid') then
				disconnectEvent(HumanoidDiedConn)
				HumanoidDiedConn = child.Died:connect(function()
					if ExistingIndicator then
						DebrisService:AddItem(ExistingIndicator.Model, 1)
					end
				end)
				HumanoidSeatedConn = child.Seated:connect(function(active, seat) onSeated(child, active, seat) end)
				if child.SeatPart then
					onSeated(child, true, child.SeatPart)
				end
			end
		end

		CharacterChildAddedConn = character.ChildAdded:connect(function(child)
			OnCharacterChildAdded(child)
		end)
		CharacterChildRemovedConn = character.ChildRemoved:connect(function(child)
			if UIS.TouchEnabled then
				if child:IsA('Tool') then
					child.ManualActivationOnly = false
				end
			end
		end)
		for _, child in pairs(character:GetChildren()) do
			OnCharacterChildAdded(child)
		end
	end

	local Running = false

	function this:Stop()
		if Running then
			DisconnectEvents()
			CleanupPath()
			-- Restore tool activation on shutdown
			if UIS.TouchEnabled then
				local character = Player.Character
				if character then
					for _, child in pairs(character:GetChildren()) do
						if child:IsA('Tool') then
							child.ManualActivationOnly = false
						end
					end
				end
			end
			DrivingTo = nil
			Running = false
		end
	end

	function this:Start()
		if not Running then
			if Player.Character then -- retro-listen
				OnCharacterAdded(Player.Character)
			end
			OnCharacterAddedConn = Player.CharacterAdded:connect(OnCharacterAdded)
			Running = true
		end
	end

	function this:Enable()
		self:Start()
	end
	
	function this:Disable()
		self:Stop()
	end

	function this:GetName()
		return DEBUG_NAME
	end

	return this
end

return CreateClickToMoveModule()
