local function z(z)local p=math.min(Utility.ViewSizeY()*.33,250)local u=p return z.X<=u and z.Y>Utility.ViewSizeY()-p end local function p(z)local p=math.min(Utility.ViewSizeY()*.33,250)local u=p return z.X>=Utility.ViewSizeX()-u and z.Y>Utility.ViewSizeY()-p end local function u(z)local p=findPlayerHumanoid(Player)return p~=nil and p.Health>0 end local function P(z)if z~=nil then for z,p in pairs(z:GetChildren())do if p:IsA("\084\111\111\108")then return p end end end end local U=nil local d=nil local T=nil local D=nil local function B()DrivingTo=nil if U then U:Cancel()end if T then T:Disconnect()T=nil end if D then D:Disconnect()D=nil end if d then local z=d local p=z:TweenOut()local u=nil u=p.Completed:connect(function()u:Disconnect()z.Model:Destroy()end)d=nil end end local function k(z)local p,u,P=-math.huge,-math.huge,-math.huge local U,d,T=math.huge,math.huge,math.huge for D=1,#z,1 do p,u,P=math.max(p,z[D].Position.X),math.max(u,z[D].Position.Y),math.max(P,z[D].Position.Z)U,d,T=math.min(U,z[D].Position.X),math.min(d,z[D].Position.Y),math.min(T,z[D].Position.Z)end return Region3.new(Vector3.new(U,d,T),Vector3.new(p,u,P))end local function I(z,p)if p.X<z.CFrame.p.X-z.Size.X/2 or p.X>z.CFrame.p.X+z.Size.X/2 then return false end if p.Z<z.CFrame.p.Z-z.Size.Z/2 or p.Z>z.CFrame.p.Z+z.Size.Z/2 then return false end return true end local function H(z,p)local u=createNewPopup(p)u:Place(z,Vector3.new(0,z.y,0))local P=u:TweenIn()P.Completed:Wait()local U=u:TweenOut()U.Completed:Wait()u.Model:Destroy()u=nil end local L=0 local function m(z,p)local S=workspace.CurrentCamera local Q=Player.Character if not u(Q)then return end if#z==1 or p then if S then local u=S:ScreenPointToRay(z[1].x,z[1].y)local l=Ray.new(u.Origin,u.Direction*1000)local y=getIgnoreList()local t={}local w={}for z,p in pairs(t)do w[#w+1]=z end for z=1,#y,1 do w[#w+1]=y[z]end local E=findPlayerHumanoid(Player)local X,N,n,q=Utility.Raycast(l,true,w)local c,G=Utility.FindCharacterAncestor(X)local o=GetTorso()local v=o.CFrame.p if p then N=p c=nil end if c and(G and(G.RootPart and(G.Torso.CFrame.p-o.CFrame.p).magnitude<7))then B()if E then E:MoveTo(N)end local z=P(Q)if z then z:Activate()LastFired=tick()end elseif N and(Q and not CurrentSeatPart)then local z=Pather(Q,N,n)if z:IsValidPath()then L=0 z:Start()if BindableEvent_OnFailStateChanged then BindableEvent_OnFailStateChanged:Fire(false)end B()local p=createNewPopup("\068\101\115\116\105\110\097\116\105\111\110\080\111\112\117\112")p:Place(N,Vector3.new(0,N.y,0))local u=createNewPopup("\070\097\105\108\117\114\101\080\111\112\117\112")local k=p:TweenIn()U=z d=p T=z.Finished.Event:Connect(function()if p then if d==p then d=nil end local z=p:TweenOut()local u=nil u=z.Completed:Connect(function()u:Disconnect()p.Model:Destroy()p=nil end)end if c then local z=findPlayerHumanoid(Player)local p=P(Q)if p then p:Activate()LastFired=tick()end if z then z:MoveTo(N)end end end)D=z.PathFailed.Event:Connect(function()B()if u then u:Place(N,Vector3.new(0,N.y,0))local z=u:TweenIn()z.Completed:Wait()local p=u:TweenOut()p.Completed:Wait()u.Model:Destroy()u=nil end end)else if N then local z=false if(N-v).Magnitude<25 and v.y-N.y>-3 then if E then if E.Sit then E.Jump=true end E:MoveTo(N)z=true end end;(coroutine.wrap(H))(N,z 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")end end elseif N and(Q and CurrentSeatPart)then local p=createNewPopup("\068\101\115\116\105\110\097\116\105\111\110\080\111\112\117\112")d=p p:Place(N,Vector3.new(0,N.y,0))p:TweenIn()DrivingTo=N local u=CurrentSeatPart:GetConnectedParts(true)while wait()do if CurrentSeatPart and d==p then local z=k(u)if I(z,N)then local z=p spawn(function()local p=z:TweenOut()p.Completed:Wait()z.Model:Destroy()end)p=nil DrivingTo=nil break end else if CurrentSeatPart==nil and p==d then DrivingTo=nil m(z,N)end local u=p spawn(function()local z=u:TweenOut()z.Completed:Wait()u.Model:Destroy()end)p=nil break end end end end elseif#z>=2 then if S then local p=Utility.AveragePoints(z)local u=S:ScreenPointToRay(p.x,p.y)local U=P(Q)if U then U:Activate()LastFired=tick()end end end end local function S(z)return z==z and(z~=1/0 and z~=-1/0)end local function Q(z,p)return math.atan2(p.X*z.Z-p.Z*z.X,p.X*z.X+p.Z*z.Z)end local function l(z)if z then z:Disconnect()end end


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 function showQuickPopupAsync(position, popupType)
	local popup = createNewPopup(popupType)
	popup:Place(position, Vector3.new(0,position.y,0))
	local tweenIn = popup:TweenIn()
	tweenIn.Completed:Wait()
	local tweenOut = popup:TweenOut()
	tweenOut.Completed:Wait()
	popup.Model:Destroy()
	popup = nil
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.FindCharacterAncestor(hitPart)
			local torso = GetTorso()
			local startPos = torso.CFrame.p
			if goToPoint then
				hitPt = goToPoint
				hitChar = nil
			end
			if hitChar and hitHumanoid and hitHumanoid.RootPart 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.Event: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.Event:Connect(function()
						CleanupPath()
						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
								myHumanoid:MoveTo(hitPt)
								foundDirectPath = true
							end
						end		
						
						coroutine.wrap(showQuickPopupAsync)(hitPt, foundDirectPath and "DirectWalkPopup" or "FailurePopup")
					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 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 DisconnectEvent(event)
	if event then
		event:Disconnect()
	end
end
