function Chassis.UpdateSteering(e,S)local c=e local Y=0 local R=Chassis.GetDriverSeat()local w=VehicleParameters.MaxSpeed local f=VehicleParameters.MaxSteer local y=R.Velocity if LimitSteerAtHighVel then local c=SteerLimit*(math.abs(S)/VehicleParameters.MaxSpeed)+1 e=e/c end SteeringPrismatic.TargetPosition=((e*e)*e)*f end function Chassis.UpdateThrottle(e,S)local c=0 local Y=false local R=0 if math.abs(S)<.1 then setMotorMaxAcceleration(math.huge)setMotorTorque(2000)elseif math.sign(S*e)>0 or math.abs(e)<.5 then setMotorMaxAcceleration(math.huge)local w=Chassis.driverSeat.Velocity local f=w.Unit local y=Chassis.driverSeat.CFrame.lookVector local Z=f:Dot(y)setMotorTorqueDamped((ActualDrivingTorque*S)*S,Z,math.sign(S))local F=Z<0 local h=S<0 local O=F and h local G=O and VehicleParameters.ReverseSpeed or VehicleParameters.MaxSpeed c=math.sign(S)*G local t=c local z=(t-e)/t local function N(e)return math.sign(e)*e^2 end local m=math.abs((w.Magnitude/G)*2.5)local o=math.exp((-3*m)*m)R=o if R>0 then Y=true end else setMotorMaxAcceleration(100)setMotorTorque((ActualBrakingTorque*S)*S)c=math.sign(S)*500 end Chassis.SetMotorVelocity(c)end local e=false local S function Chassis.Redress()if e then return end e=true local c=Chassis.driverSeat.CFrame.Position+Vector3.new(0,10,0)local Y=Chassis.driverSeat.CFrame.RightVector Y=Vector3.new(Y.x,0,Y.z)Y=Y.Unit local R=Vector3.new(0,1,0)if not S then S=RedressMount.RedressTarget end S.Parent=Workspace.Terrain S.Position=c S.Axis=Y S.SecondaryAxis=R RedressMount.RedressOrientation.Enabled=true RedressMount.RedressPosition.Enabled=true wait(1.5)RedressMount.RedressOrientation.Enabled=false RedressMount.RedressPosition.Enabled=false S.Parent=RedressMount wait(2)e=false end function Chassis.Reset()Chassis.UpdateThrottle(1,1)Chassis.UpdateSteering(1,0)Chassis.EnableHandbrake()setMotorTorque(ActualBrakingTorque)Chassis.SetMotorVelocity(0)Chassis.UpdateSteering(0,0)RedressMount.RedressOrientation.Enabled=true RedressMount.RedressPosition.Enabled=true RedressMount.RedressOrientation.Enabled=false RedressMount.RedressPosition.Enabled=false e=false end return Chassis

function Chassis.UpdateSteering(steer, currentVel)
	local baseSteer = steer
	local targetSteer = 0
	
	local vehicleSeat = Chassis.GetDriverSeat()
	local maxSpeed = VehicleParameters.MaxSpeed
	local maxSteer = VehicleParameters.MaxSteer
	
	local currentVelocity = vehicleSeat.Velocity
	
	if LimitSteerAtHighVel then
		local c = SteerLimit * (math.abs(currentVel)/VehicleParameters.MaxSpeed) + 1
		--decrease steer value as speed increases to prevent tipping (handbrake cancels this)
		steer = steer/c
	end
	SteeringPrismatic.TargetPosition = steer * steer * steer * maxSteer
end

function Chassis.UpdateThrottle(currentSpeed, throttle)
	local targetVel = 0
	local effectsThrottleState = false
	local gainModifier = 0
	
	if math.abs(throttle) < 0.1 then
		-- Idling
		setMotorMaxAcceleration(math.huge)
		setMotorTorque(2000)
	elseif math.sign(throttle * currentSpeed) > 0 or math.abs(currentSpeed) < 0.5 then
		setMotorMaxAcceleration(math.huge)
		
		local velocity = Chassis.driverSeat.Velocity
		local velocityVector = velocity.Unit
		local directionalVector = Chassis.driverSeat.CFrame.lookVector
		local dotProd = velocityVector:Dot(directionalVector) -- Dot product is a measure of how similar two vectors are; if they're facing the same direction, it is 1, if they are facing opposite directions, it is -1, if perpendicular, it is 0
		
		setMotorTorqueDamped(ActualDrivingTorque * throttle * throttle, dotProd, math.sign(throttle))
		-- Arbitrary large number
		local movingBackwards = dotProd < 0
		local acceleratingBackwards = throttle < 0
		local useReverse = (movingBackwards and acceleratingBackwards)
		
		local maxSpeed = (useReverse and VehicleParameters.ReverseSpeed or VehicleParameters.MaxSpeed)
		targetVel = math.sign(throttle) * maxSpeed
		
		-- if we are approaching max speed, we should take that as an indication of throttling down, even if not from input
		local maxAccelSpeed = targetVel
		local speedPercent = ((maxAccelSpeed-currentSpeed)/maxAccelSpeed) -- 0 if max speed, 1 if stopped
		
		-- lets say we start throttling down after reaching 75% of max speed, then linearly drop to 0
		local function quad(x)
			return math.sign(x)*(x^2)
		end
		
		
		local r = math.abs(velocity.Magnitude / maxSpeed*2.5) -- adding a bit to the max speed so that it sounds better (always trying to rev engines)
		local desiredRPM = math.exp(-3*r*r)
		
		
		gainModifier = desiredRPM
		
		if gainModifier > 0 then
			effectsThrottleState = true
		end
	else
		-- Braking
		setMotorMaxAcceleration(100)
		setMotorTorque(ActualBrakingTorque * throttle * throttle)
		targetVel = math.sign(throttle) * 500
	end
	
	Chassis.SetMotorVelocity(targetVel)
end

local redressingState = false
local targetAttachment
function Chassis.Redress()
	if redressingState then
		return
	end
	redressingState = true
	local p = Chassis.driverSeat.CFrame.Position + Vector3.new( 0,10,0 )
	local xc = Chassis.driverSeat.CFrame.RightVector
	xc = Vector3.new(xc.x,0,xc.z)
	xc = xc.Unit
	local yc = Vector3.new(0,1,0)

	if not targetAttachment then
		targetAttachment = RedressMount.RedressTarget
	end

	targetAttachment.Parent = Workspace.Terrain
	targetAttachment.Position = p
	targetAttachment.Axis = xc
	targetAttachment.SecondaryAxis = yc
	RedressMount.RedressOrientation.Enabled = true
	RedressMount.RedressPosition.Enabled = true
	wait(1.5)
	RedressMount.RedressOrientation.Enabled = false
	RedressMount.RedressPosition.Enabled = false
	targetAttachment.Parent = RedressMount
	wait(2)
	redressingState = false
end

function Chassis.Reset() --Reset user inputs and redress (For when a player exits the vehicle)
	Chassis.UpdateThrottle(1, 1) --Values must  be changed to replicate to client.
	Chassis.UpdateSteering(1, 0) --i.e. setting vel to 0 when it is 0 wont update to clients
	Chassis.EnableHandbrake()
	setMotorTorque(ActualBrakingTorque)
	Chassis.SetMotorVelocity(0)
	Chassis.UpdateSteering(0, 0)
	RedressMount.RedressOrientation.Enabled = true
	RedressMount.RedressPosition.Enabled = true
	RedressMount.RedressOrientation.Enabled = false
	RedressMount.RedressPosition.Enabled = false
	redressingState = false
end

return Chassis
