local p=require((game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):WaitForChild("\078\101\118\101\114\109\111\114\101"))local N=p("\065\099\099\101\108\084\119\101\101\110")local q={}q.__index=q q.ClassName="\071\097\109\101\112\097\100\082\111\116\097\116\101\077\111\100\101\108"function q.new()local p=setmetatable({},q)p.DEADZONE=.1 p.SpeedMultiplier=Vector2.new(.1,.1)p.RampVelocityX=N.new(5)p.RampVelocityY=N.new(5)p.IsRotating=Instance.new("\066\111\111\108\086\097\108\117\101")p.IsRotating.Value=false return p end do local p=.35 local N=.8 function q._sCurveTranform(k,q)q=math.clamp(q,-1,1)if q>=0 then return(p*q)/((p-q)+1)end return-((N*-q)/((N+q)+1))end end function q._toSCurveSpace(N,p)return(1+N.DEADZONE)*(2*math.abs(p)-1)-N.DEADZONE end function q._fromSCurveSpace(N,p)return p/2+.5 end function q._gamepadLinearToCurve(N,p)local function q(p)local q=math.sign(p)local k=N:_fromSCurveSpace(N:_sCurveTranform(N:_toSCurveSpace(math.abs(p))))return math.clamp(k*q,-1,1)end return Vector2.new(q(p.x),q(p.y))end function q.OutOfDeadzone(N,p)local q=p.Position return q.Magnitude>=N.DEADZONE end function q.GetThumbstickDeltaAngle(p)if not p._lastInputObject then return Vector2.new()end return Vector2.new(p.RampVelocityX.p,p.RampVelocityY.p)end function q.StopRotate(p)p._lastInputObject=nil p.RampVelocityX.t=0 p.RampVelocityX.p=p.RampVelocityX.t p.RampVelocityY.t=0 p.RampVelocityY.p=p.RampVelocityY.t p.IsRotating.Value=false end function q.HandleThumbstickInput(N,p)local q=N:OutOfDeadzone(p)if q then N._lastInputObject=p local q=N._lastInputObject.Position q=Vector2.new(q.x,-q.y)local k=N:_gamepadLinearToCurve(q)N.RampVelocityX.t=k.x*N.SpeedMultiplier.x N.RampVelocityY.t=k.y*N.SpeedMultiplier.y N.IsRotating.Value=true else N:StopRotate()end end return q
--- Rotation model for gamepad controls
-- @classmod GamepadRotateModel
-- @author Quenty

local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

local AccelTween = require("AccelTween")

local GamepadRotateModel = {}
GamepadRotateModel.__index = GamepadRotateModel
GamepadRotateModel.ClassName = "GamepadRotateModel"

function GamepadRotateModel.new()
	local self = setmetatable({}, GamepadRotateModel)

	self.DEADZONE = 0.1
	self.SpeedMultiplier = Vector2.new(0.1, 0.1)

	self.RampVelocityX = AccelTween.new(5)
	self.RampVelocityY = AccelTween.new(5)

	self.IsRotating = Instance.new("BoolValue")
	self.IsRotating.Value = false

	return self
end

do
	-- See: https://github.com/Roblox/Core-Scripts/blob/cad3a477e39b93ecafdd610b1d8b89d239ab18e2/PlayerScripts/StarterPlayerScripts/CameraScript/RootCamera.lua#L395
	-- K is a tunable parameter that changes the shape of the S-curve
	-- the larger K is the more straight/linear the curve gets
	local k = 0.35
	local lowerK = 0.8
	function GamepadRotateModel:_sCurveTranform(t)
		t = math.clamp(t, -1, 1)
		if t >= 0 then
			return (k*t) / (k - t + 1)
		end
		return -((lowerK*-t) / (lowerK + t + 1))
	end
end

function GamepadRotateModel:_toSCurveSpace(t)
	return (1 + self.DEADZONE) * (2*math.abs(t) - 1) - self.DEADZONE
end

function GamepadRotateModel:_fromSCurveSpace(t)
	return t/2 + 0.5
end

function GamepadRotateModel:_gamepadLinearToCurve(ThumbstickPosition)
	local function OnAxis(AxisValue)
		local sign = math.sign(AxisValue)
		local point = self:_fromSCurveSpace(self:_sCurveTranform(self:_toSCurveSpace(math.abs(AxisValue))))
		return math.clamp(point * sign, -1, 1)
	end
	return Vector2.new(OnAxis(ThumbstickPosition.x), OnAxis(ThumbstickPosition.y))
end

function GamepadRotateModel:OutOfDeadzone(inputObject)
	local stickOffset = inputObject.Position
	return stickOffset.Magnitude >= self.DEADZONE
end

function GamepadRotateModel:GetThumbstickDeltaAngle()
	if not self._lastInputObject then
		return Vector2.new()
	end

	return Vector2.new(self.RampVelocityX.p, self.RampVelocityY.p)
end

function GamepadRotateModel:StopRotate()
	self._lastInputObject = nil
	self.RampVelocityX.t = 0
	self.RampVelocityX.p = self.RampVelocityX.t

	self.RampVelocityY.t = 0
	self.RampVelocityY.p = self.RampVelocityY.t

	self.IsRotating.Value = false
end

function GamepadRotateModel:HandleThumbstickInput(inputObject)
	local outOfDeadZone = self:OutOfDeadzone(inputObject)

	if outOfDeadZone then
		self._lastInputObject = inputObject


		local stickOffset = self._lastInputObject.Position
		stickOffset = Vector2.new(stickOffset.x, -stickOffset.y)  -- Invert axis!

		local adjustedStickOffset = self:_gamepadLinearToCurve(stickOffset)
		self.RampVelocityX.t = adjustedStickOffset.x * self.SpeedMultiplier.x
		self.RampVelocityY.t = adjustedStickOffset.y * self.SpeedMultiplier.y

		self.IsRotating.Value = true
	else
		self:StopRotate()
	end
end

return GamepadRotateModel