local function B(B,a)return math_atan2(a.X*B.Z-a.Z*B.X,a.X*B.X+a.Z*B.Z)end local function a()local a=RootCameraCreator()local R=math_rad(220)local N=math_rad(0)local o=math_rad(250)local l=2 local L=tick()a.LastUserPanCamera=tick()function a.Update(w)a:ProcessTweens()local P=tick()local O=P-L local D=w.UserPanningTheCamera==true local Y=workspace.CurrentCamera local x=PlayersService.LocalPlayer local z=w:GetHumanoid()local s=Y and Y.CameraSubject local G=s and s:IsA("\086\101\104\105\099\108\101\083\101\097\116")local C=s and s:IsA("\083\107\097\116\101\098\111\097\114\100\080\108\097\116\102\111\114\109")if L==nil or P-L>1 then a:ResetCameraLook()w.LastCameraTransform=nil end if L then local B=w:UpdateGamepad()if w:ShouldUseVRRotation()then w.RotateInput=w.RotateInput+w:GetVRRotationInput()else local a=math_min(.1,P-L)if B~=ZERO_VECTOR2 then D=true w.RotateInput=w.RotateInput+B*a end local R=0 if not(G or C)then R=R+(w.TurningLeft and-120 or 0)R=R+(w.TurningRight and 120 or 0)end if R~=0 then w.RotateInput=w.RotateInput+Vector2.new(math_rad(R*a),0)D=true end end end if D then N=0 a.LastUserPanCamera=tick()end local c=P-a.LastUserPanCamera<l local J=w:GetSubjectPosition()if J and(x and Y)then local a=w:GetCameraZoom()if a<.5 then a=.5 end if w:GetShiftLock()and not w:IsInFirstPerson()then local B=w:RotateCamera(w:GetCameraLook(),w.RotateInput)local a=((B*XZ_VECTOR):Cross(UP_VECTOR)).unit*1.75 if IsFiniteVector3(a)then J=J+a end else if not D and w.LastCameraTransform then local a=w:IsInFirstPerson()if(G or C)and(L and(z and z.Torso))then if a then if w.LastSubjectCFrame and((G or C)and s:IsA("\066\097\115\101\080\097\114\116"))then local a=-B(w.LastSubjectCFrame.lookVector,s.CFrame.lookVector)if IsFinite(a)then w.RotateInput=w.RotateInput+Vector2.new(a,0)end N=0 end elseif not c then local a=z.Torso.CFrame.lookVector if C then a=s.CFrame.lookVector end N=clamp(0,o,N+R*O)local l=clamp(0,1,N*O)if w:IsInFirstPerson()then l=1 end local L=B(a,w:GetCameraLook())if IsFinite(L)and math_abs(L)>.0001 then w.RotateInput=w.RotateInput+Vector2.new(L*l,0)end end end end end local l=VRService.VREnabled Y.Focus=l and w:GetVRFocus(J,O)or CFrame_new(J)local P=Y.Focus.p if l and not w:IsInFirstPerson()then local B=w:GetCameraHeight()local R=J-Y.CFrame.p local N=R.magnitude if N>a or w.RotateInput.x~=0 then local o=math_min(N,a)R=w:RotateCamera(R.unit*XZ_VECTOR,Vector2.new(w.RotateInput.x,0))*o local l=P-R local L=Y.CFrame.lookVector if w.RotateInput.x~=0 then L=R end local O=Vector3.new(l.x+L.x,l.y,l.z+L.z)w.RotateInput=ZERO_VECTOR2 Y.CFrame=CFrame_new(l,O)+Vector3_new(0,B,0)end else local B=w:RotateCamera(w:GetCameraLook(),w.RotateInput)w.RotateInput=ZERO_VECTOR2 Y.CFrame=CFrame_new(P-a*B,P)end w.LastCameraTransform=Y.CFrame w.LastCameraFocus=Y.Focus if(G or C)and s:IsA("\066\097\115\101\080\097\114\116")then w.LastSubjectCFrame=s.CFrame else w.LastSubjectCFrame=nil end end L=P end return a end return a

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 CreateClassicCamera()
	local module = RootCameraCreator()
	
	local tweenAcceleration = math_rad(220)
	local tweenSpeed = math_rad(0)
	local tweenMaxSpeed = math_rad(250)
	local timeBeforeAutoRotate = 2
	
	local lastUpdate = tick()
	module.LastUserPanCamera = tick()
	function module:Update()
		module:ProcessTweens()
		local now = tick()
		local timeDelta = (now - lastUpdate)
		
		local userPanningTheCamera = (self.UserPanningTheCamera == true)
		local camera = 	workspace.CurrentCamera
		local player = PlayersService.LocalPlayer
		local humanoid = self:GetHumanoid()
		local cameraSubject = camera and camera.CameraSubject
		local isInVehicle = cameraSubject and cameraSubject:IsA('VehicleSeat')
		local isOnASkateboard = cameraSubject and cameraSubject:IsA('SkateboardPlatform')
		
		if lastUpdate == nil or now - lastUpdate > 1 then
			module:ResetCameraLook()
			self.LastCameraTransform = nil
		end	
		
		if lastUpdate then
			local gamepadRotation = self:UpdateGamepad()
			
			if self:ShouldUseVRRotation() then				
				self.RotateInput = self.RotateInput + self:GetVRRotationInput()
			else
				-- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
				local delta = math_min(0.1, now - lastUpdate)
				
				if gamepadRotation ~= ZERO_VECTOR2 then
					userPanningTheCamera = true
					self.RotateInput = self.RotateInput + (gamepadRotation * delta)
				end

				local angle = 0
				if not (isInVehicle or isOnASkateboard) then
					angle = angle + (self.TurningLeft and -120 or 0)
					angle = angle + (self.TurningRight and 120 or 0)
				end
				
				if angle ~= 0 then
					self.RotateInput = self.RotateInput +  Vector2.new(math_rad(angle * delta), 0)
					userPanningTheCamera = true
				end
			end
		end

		-- Reset tween speed if user is panning
		if userPanningTheCamera then
			tweenSpeed = 0
			module.LastUserPanCamera = tick()
		end
		
		local userRecentlyPannedCamera = now - module.LastUserPanCamera < timeBeforeAutoRotate
		local subjectPosition = self:GetSubjectPosition()
		
		if subjectPosition and player and camera then
			local zoom = self:GetCameraZoom()
			if zoom < 0.5 then
				zoom = 0.5
			end
			
			if self:GetShiftLock() and not self:IsInFirstPerson() then
				-- We need to use the right vector of the camera after rotation, not before
				local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput)
				local offset = ((newLookVector * XZ_VECTOR):Cross(UP_VECTOR).unit * 1.75)

				if IsFiniteVector3(offset) then
					subjectPosition = subjectPosition + offset
				end
			else
				if not userPanningTheCamera and self.LastCameraTransform then
					local isInFirstPerson = self:IsInFirstPerson()
					if (isInVehicle or isOnASkateboard) and lastUpdate and humanoid and humanoid.Torso then
						if isInFirstPerson then
							if self.LastSubjectCFrame and (isInVehicle or isOnASkateboard) and cameraSubject:IsA('BasePart') then
								local y = -findAngleBetweenXZVectors(self.LastSubjectCFrame.lookVector, cameraSubject.CFrame.lookVector)
								if IsFinite(y) then
									self.RotateInput = self.RotateInput + Vector2.new(y, 0)
								end
								tweenSpeed = 0
							end
						elseif not userRecentlyPannedCamera then
							local forwardVector = humanoid.Torso.CFrame.lookVector
							if isOnASkateboard then
								forwardVector = cameraSubject.CFrame.lookVector
							end
							
							tweenSpeed = clamp(0, tweenMaxSpeed, tweenSpeed + tweenAcceleration * timeDelta)
	
							local percent = clamp(0, 1, tweenSpeed * timeDelta)
							if self:IsInFirstPerson() then
								percent = 1
							end
							
							local y = findAngleBetweenXZVectors(forwardVector, self:GetCameraLook())
							if IsFinite(y) and math_abs(y) > 0.0001 then
								self.RotateInput = self.RotateInput + Vector2.new(y * percent, 0)
							end
						end
					end
				end
			end

			local VREnabled = VRService.VREnabled
			camera.Focus = VREnabled and self:GetVRFocus(subjectPosition, timeDelta) or CFrame_new(subjectPosition)

			local cameraFocusP = camera.Focus.p
			if VREnabled and not self:IsInFirstPerson() then
				local cameraHeight = self:GetCameraHeight()
				local vecToSubject = (subjectPosition - camera.CFrame.p)
				local distToSubject = vecToSubject.magnitude

				-- Only move the camera if it exceeded a maximum distance to the subject in VR
				if distToSubject > zoom or self.RotateInput.x ~= 0 then
					local desiredDist = math_min(distToSubject, zoom)
					vecToSubject = self:RotateCamera(vecToSubject.unit * XZ_VECTOR, Vector2.new(self.RotateInput.x, 0)) * desiredDist
					local newPos = cameraFocusP - vecToSubject
					local desiredLookDir = camera.CFrame.lookVector
					if self.RotateInput.x ~= 0 then
						desiredLookDir = vecToSubject
					end
					local lookAt = Vector3.new(newPos.x + desiredLookDir.x, newPos.y, newPos.z + desiredLookDir.z)
					self.RotateInput = ZERO_VECTOR2
					
					camera.CFrame = CFrame_new(newPos, lookAt) + Vector3_new(0, cameraHeight, 0)
				end
			else
				local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput)
				self.RotateInput = ZERO_VECTOR2
				camera.CFrame = CFrame_new(cameraFocusP - (zoom * newLookVector), cameraFocusP)
			end

			self.LastCameraTransform = camera.CFrame
			self.LastCameraFocus = camera.Focus
			if (isInVehicle or isOnASkateboard) and cameraSubject:IsA('BasePart') then
				self.LastSubjectCFrame = cameraSubject.CFrame
			else
				self.LastSubjectCFrame = nil
			end
		end
		
		lastUpdate = now
	end
	
	return module
end

return CreateClassicCamera
