function ShoulderCamera.applyInput(e,X,F)local D=UserGameSettings:GetCameraYInvertValue()e.yaw=e.yaw+X e.pitch=math.clamp(e.pitch+F*D,e.minPitch,e.maxPitch)end function ShoulderCamera.processGamepadInput(F,X)local e=F.gamepadPan if e then e=gamepadLinearToCurve(e)if e.X==0 and e.Y==0 then F.lastThumbstickTime=nil if F.lastThumbstickPos.X==0 and F.lastThumbstickPos.Y==0 then F.currentGamepadSpeed=0 end end local D=0 local j=tick()if F.lastThumbstickTime then local w=(j-F.lastThumbstickTime)*10 F.currentGamepadSpeed=F.currentGamepadSpeed+6*(w^2/.7)if F.currentGamepadSpeed>6 then F.currentGamepadSpeed=6 end if F.lastGamepadVelocity then local X=(e-F.lastThumbstickPos)/(j-F.lastThumbstickTime)local D=(X-F.lastGamepadVelocity).Magnitude if D>12 then F.currentGamepadSpeed=F.currentGamepadSpeed*(20/D)if F.currentGamepadSpeed>6 then F.currentGamepadSpeed=6 end end end D=(GameSettings.GamepadCameraSensitivity*F.currentGamepadSpeed)*X F.lastGamepadVelocity=(e-F.lastThumbstickPos)/(j-F.lastThumbstickTime)end F.lastThumbstickPos=e F.lastThumbstickTime=j local w=(-e.X*D)*F.gamepadSensitivityModifier.X local A=((D*e.Y)*GameSettings:GetCameraYInvertValue())*F.gamepadSensitivityModifier.Y F:applyInput(w,A)end end function ShoulderCamera.handleTouchToolFiring(X)if X.touchObj then if X.lastTapEndTime then local F=tick()-X.lastTapEndTime if F<X.touchDelayTime and(X.currentTool and(X.touchPanAccumulator.Magnitude<.5 and(not X.firingTool and not X.applyingTouchPan)))then X.firingTool=true X.currentTool:Activate()end end else if X.currentTool and X.firingTool then X.currentTool:Deactivate()end X.firingTool=false end end function ShoulderCamera.isTouchPositionForCamera(F,X)if LocalPlayer then local F=LocalPlayer.PlayerGui:GetGuiObjectsAtPosition(X.X,X.Y)for X,F in ipairs(F)do if F.Name=="\068\121\110\097\109\105\099\084\104\117\109\098\115\116\105\099\107\070\114\097\109\101"then return false end end return true end return false end function ShoulderCamera.onInputBegan(e,X,F)if e.touchObj then e.touchObj=nil F=false end if X.KeyCode==Enum.KeyCode.Thumbstick2 then e.gamepadPan=Vector2.new(X.Position.X,X.Position.Y)elseif X.KeyCode==Enum.KeyCode.Thumbstick1 then e.movementPan=Vector2.new(X.Position.X,X.Position.Y)elseif X.UserInputType==Enum.UserInputType.Touch then local D=Vector2.new(X.Position.X,X.Position.Y)if not F and(e:isTouchPositionForCamera(D)and not e.touchObj)then e.touchObj=X e.touchStartTime=tick()e.eventConnections.touchChanged=X.Changed:Connect(function(F)if F=="\080\111\115\105\116\105\111\110"then local F=tick()-e.touchStartTime local j=Vector2.new(X.Position.X,X.Position.Y)local w=(j-D)*e.currentTouchSensitivity local A=-w.X local E=-w.Y if e.touchPanAccumulator.Magnitude>.01 and F>e.touchDelayTime then if not e.applyingTouchPan then e.applyingTouchPan=true e.touchPanAccumulator=Vector2.new(0,0)end end e:applyInput(A,E)e.touchPanAccumulator=e.touchPanAccumulator+Vector2.new(A,E)D=j end end)end end end function ShoulderCamera.onInputChanged(e,X,F)if X.UserInputType==Enum.UserInputType.MouseMovement then local F=-X.Delta.X*e.currentMouseRadsPerPixel.X local D=-X.Delta.Y*e.currentMouseRadsPerPixel.Y e:applyInput(F,D)elseif X.KeyCode==Enum.KeyCode.Thumbstick2 then e.gamepadPan=Vector2.new(X.Position.X,X.Position.Y)elseif X.KeyCode==Enum.KeyCode.Thumbstick1 then e.movementPan=Vector2.new(X.Position.X,X.Position.Y)end end function ShoulderCamera.onInputEnded(e,X,F)if X.KeyCode==Enum.KeyCode.Thumbstick2 then e.gamepadPan=Vector2.new(0,0)elseif X.KeyCode==Enum.KeyCode.Thumbstick1 then e.movementPan=Vector2.new(0,0)elseif X.UserInputType==Enum.UserInputType.Touch then if e.touchObj==X then if e.eventConnections and e.eventConnections.touchChanged then e.eventConnections.touchChanged:Disconnect()e.eventConnections.touchChanged=nil end local X=tick()-e.touchStartTime if e.currentTool and e.firingTool then e.currentTool:Deactivate()elseif e.zoomState and(e.hasScope and(X<e.touchDelayTime and not e.applyingTouchPan))then e.currentTool:Activate()e.currentTool:Deactivate()end e.firingTool=false e.touchPanAccumulator=Vector2.new(0,0)if X<e.touchDelayTime and not e.applyingTouchPan then e.lastTapEndTime=tick()else e.lastTapEndTime=nil end e.applyingTouchPan=false e.gamepadPan=Vector2.new(0,0)e.touchObj=nil end end end return ShoulderCamera


function ShoulderCamera:applyInput(yaw, pitch)
	local yInvertValue = UserGameSettings:GetCameraYInvertValue()
	self.yaw = self.yaw + yaw
	self.pitch = math.clamp(self.pitch + pitch * yInvertValue, self.minPitch, self.maxPitch)
end

function ShoulderCamera:processGamepadInput(dt)
	local gamepadPan = self.gamepadPan
	if gamepadPan then
		gamepadPan = gamepadLinearToCurve(gamepadPan)
		if gamepadPan.X == 0 and gamepadPan.Y == 0 then
			self.lastThumbstickTime = nil
			if self.lastThumbstickPos.X == 0 and self.lastThumbstickPos.Y == 0 then
				self.currentGamepadSpeed = 0
			end
		end

		local finalConstant = 0
		local currentTime = tick()

		if self.lastThumbstickTime then
			local elapsed = (currentTime - self.lastThumbstickTime) * 10
			self.currentGamepadSpeed = self.currentGamepadSpeed + (6 * ((elapsed ^ 2) / 0.7))

			if self.currentGamepadSpeed > 6 then self.currentGamepadSpeed = 6 end

			if self.lastGamepadVelocity then
				local velocity = (gamepadPan - self.lastThumbstickPos) / (currentTime - self.lastThumbstickTime)
				local velocityDeltaMag = (velocity - self.lastGamepadVelocity).Magnitude

				if velocityDeltaMag > 12 then
					self.currentGamepadSpeed = self.currentGamepadSpeed * (20 / velocityDeltaMag)
					if self.currentGamepadSpeed > 6 then
						self.currentGamepadSpeed = 6
					end
				end
			end

			finalConstant = GameSettings.GamepadCameraSensitivity * self.currentGamepadSpeed * dt
			self.lastGamepadVelocity = (gamepadPan - self.lastThumbstickPos) / (currentTime - self.lastThumbstickTime)
		end
		self.lastThumbstickPos = gamepadPan
		self.lastThumbstickTime = currentTime

		local yawInput = -gamepadPan.X * finalConstant * self.gamepadSensitivityModifier.X
		local pitchInput = finalConstant * gamepadPan.Y * GameSettings:GetCameraYInvertValue() * self.gamepadSensitivityModifier.Y

		self:applyInput(yawInput, pitchInput)
	end
end

function ShoulderCamera:handleTouchToolFiring()
	if self.touchObj then
		if self.lastTapEndTime then -- and not (self.zoomState and self.hasScope) then
			local touchTime = tick() - self.lastTapEndTime
			if touchTime < self.touchDelayTime and self.currentTool and self.touchPanAccumulator.Magnitude < 0.5 and not self.firingTool and not self.applyingTouchPan then
				self.firingTool = true
				self.currentTool:Activate()
			end
		end
	else
		if self.currentTool and self.firingTool then
			self.currentTool:Deactivate()
		end
		self.firingTool = false
	end
end

function ShoulderCamera:isTouchPositionForCamera(pos)
	if LocalPlayer then
		local guiObjects = LocalPlayer.PlayerGui:GetGuiObjectsAtPosition(pos.X, pos.Y)
		for _, guiObject in ipairs(guiObjects) do
			if guiObject.Name == "DynamicThumbstickFrame" then
				return false
			end
		end
		return true
	end
	return false
end

function ShoulderCamera:onInputBegan(inputObj, wasProcessed)
	if self.touchObj then
		self.touchObj = nil
		wasProcessed = false
	end

	if inputObj.KeyCode == Enum.KeyCode.Thumbstick2 then
		self.gamepadPan = Vector2.new(inputObj.Position.X, inputObj.Position.Y)
	elseif inputObj.KeyCode == Enum.KeyCode.Thumbstick1 then
		self.movementPan = Vector2.new(inputObj.Position.X, inputObj.Position.Y)
	elseif inputObj.UserInputType == Enum.UserInputType.Touch then
		local touchStartPos = Vector2.new(inputObj.Position.X, inputObj.Position.Y)
		if not wasProcessed and self:isTouchPositionForCamera(touchStartPos) and not self.touchObj then
			self.touchObj = inputObj
			self.touchStartTime = tick()
			self.eventConnections.touchChanged = inputObj.Changed:Connect(function(prop)
				if prop == "Position" then
					local touchTime = tick() - self.touchStartTime

					local newTouchPos = Vector2.new(inputObj.Position.X, inputObj.Position.Y)
					local delta = (newTouchPos - touchStartPos) * self.currentTouchSensitivity
					local yawInput = -delta.X
					local pitchInput = -delta.Y
					if self.touchPanAccumulator.Magnitude > 0.01 and touchTime > self.touchDelayTime then
						if not self.applyingTouchPan then
							self.applyingTouchPan = true
							self.touchPanAccumulator = Vector2.new(0, 0)
						end
					end
					self:applyInput(yawInput, pitchInput)
					self.touchPanAccumulator = self.touchPanAccumulator + Vector2.new(yawInput, pitchInput)
					touchStartPos = newTouchPos
				end
			end)
		end
	end
end

function ShoulderCamera:onInputChanged(inputObj, wasProcessed)
	if inputObj.UserInputType == Enum.UserInputType.MouseMovement then
		local yawInput = -inputObj.Delta.X * self.currentMouseRadsPerPixel.X
		local pitchInput = -inputObj.Delta.Y * self.currentMouseRadsPerPixel.Y

		self:applyInput(yawInput, pitchInput)
	elseif inputObj.KeyCode == Enum.KeyCode.Thumbstick2 then
		self.gamepadPan = Vector2.new(inputObj.Position.X, inputObj.Position.Y)
	elseif inputObj.KeyCode == Enum.KeyCode.Thumbstick1 then
		self.movementPan = Vector2.new(inputObj.Position.X, inputObj.Position.Y)
	end
end

function ShoulderCamera:onInputEnded(inputObj, wasProcessed)
	if inputObj.KeyCode == Enum.KeyCode.Thumbstick2 then
		self.gamepadPan = Vector2.new(0, 0)
	elseif inputObj.KeyCode == Enum.KeyCode.Thumbstick1 then
		self.movementPan = Vector2.new(0, 0)
	elseif inputObj.UserInputType == Enum.UserInputType.Touch then
		if self.touchObj == inputObj then
			if self.eventConnections and self.eventConnections.touchChanged then
				self.eventConnections.touchChanged:Disconnect()
				self.eventConnections.touchChanged = nil
			end

			local touchTime = tick() - self.touchStartTime
			if self.currentTool and self.firingTool then
				self.currentTool:Deactivate()
			elseif self.zoomState and self.hasScope and touchTime < self.touchDelayTime and not self.applyingTouchPan then
				self.currentTool:Activate() -- this makes sure to shoot the sniper with a single tap when it is zoomed in
				self.currentTool:Deactivate()
			end
			self.firingTool = false

			self.touchPanAccumulator = Vector2.new(0, 0)
			if touchTime < self.touchDelayTime and not self.applyingTouchPan then
				self.lastTapEndTime = tick()
			else
				self.lastTapEndTime = nil
			end
			self.applyingTouchPan = false

			self.gamepadPan = Vector2.new(0, 0)
			self.touchObj = nil
		end
	end
end

return ShoulderCamera
