local C=_Tune.FinalDrive*_Tune.FDMult local l=(C*30)/math.pi local x=(workspace.Gravity*_Tune.InclineComp)/32.2 local p=(wDia*math.pi)/60 local j=CFrame.Angles(math.pi/2,-math.pi/2,0)local v=CFrame.Angles(0,math.pi,0)local b=.70710678118655 local I=_Tune.Horsepower/100 local t=_Tune.PeakRPM/1000 local U=_Tune.PeakSharpness local d=_Tune.CurveMult function FGC(C)C=C/1000 return(-(C-t)^2*math.min(I/t^2,d^(t/I))+I)*(C-C^U/(U*t)^(U-1))end local G=FGC(_Tune.PeakRPM)function GetCurve(l,x)local p=math.max((FGC(l)*_Tune.Horsepower)/G,0)return p,(((p*(_Tune.EqPoint/l))*_Tune.Ratios[x+2])*C)*hpScaling end local D=true local k={}local g=100 if D then for C,l in pairs(_Tune.Ratios)do local x={}for l=math.floor(_Tune.IdleRPM/g),math.ceil((_Tune.Redline+100)/g),1 do local p={}p.Horsepower,p.Torque=GetCurve(l*g,C-2)hp1,tq1=GetCurve((l+1)*g,C-2)p.HpSlope=(hp1-p.Horsepower)/(g/1000)p.TqSlope=(tq1-p.Torque)/(g/1000)x[l]=p end table.insert(k,x)end end function RPM()if _CGear==0 then _ClutchOn=false end local C=_Tune.IdleRPM if not _IsOn then C=0 _CGear=0 _ClutchOn=false _GThrot=_Tune.IdleThrottle/100 end if math.floor(script.Parent.Values.Velocity.Value.Magnitude)==0 and(_GThrot==1 and(_GBrake==1 and(_IsOn==true and _CGear>0)))then if _GThrot==1 and _GBrake==1 then if LaunchBuild<_Tune.LaunchBuildup then LaunchBuild=LaunchBuild+50 end _RPM=LaunchBuild else if LaunchBuild>_Tune.IdleRPM then LaunchBuild=LaunchBuild-50 end _RPM=LaunchBuild end return else if LaunchBuild>_Tune.IdleRPM then LaunchBuild=LaunchBuild-50 end end local x=0 for C,l in pairs(Drive)do if l.RotVelocity.Magnitude>x then x=l.RotVelocity.Magnitude end end if _ClutchOn then local p=math.max(math.min((x*_Tune.Ratios[_CGear+2])*l,_Tune.Redline+100),C)local j=math.min(math.abs(p-_RPM)/_Tune.ClutchTol,.9)_RPM=_RPM*j+p*(1-j)else if _GThrot-_Tune.IdleThrottle/100>0 then if _RPM>_Tune.Redline then _RPM=_RPM-(_Tune.RevBounce*2)*(LaunchBuild/_Tune.IdleRPM)else _RPM=math.min(_RPM+_Tune.RevAccel*_GThrot,_Tune.Redline+100)end else _RPM=math.max(_RPM-_Tune.RevDecay,C)end end _spLimit=(_Tune.Redline+100)/(l*_Tune.Ratios[_CGear+2])if _RPM>_Tune.Redline then if _CGear<#_Tune.Ratios-2 then _RPM=_RPM-_Tune.RevBounce else _RPM=_RPM-_Tune.RevBounce*.5 end end end function Engine()local b=_IsOn==true and 1 or 0 local I=0 for C,l in pairs(Drive)do if l.RotVelocity.Magnitude>I then I=l.RotVelocity.Magnitude end end if _ClutchOn then if D then local C=k[_CGear+2][math.floor(math.min(_Tune.Redline,math.max(_Tune.IdleRPM,_RPM))/g)]_HP=C.Horsepower+(C.HpSlope*(_RPM-math.floor(_RPM/g)))/1000 _OutTorque=C.Torque+(((C.TqSlope*(_RPM-math.floor(_RPM/g)))/1000)*LaunchBuild)/_Tune.IdleRPM else _HP,_OutTorque=GetCurve(_RPM,_CGear)end local C=car.DriveSeat.CFrame.lookVector.y*x if _CGear==-1 then C=-C end _OutTorque=(_OutTorque*math.max(1,1+C))*(LaunchBuild/_Tune.IdleRPM)else _HP,_OutTorque=0,0 end if _TMode=="\065\117\116\111"and _IsOn then _ClutchOn=true if _CGear>=1 then if _GBrake>0 and car.DriveSeat.Velocity.Magnitude<5 then _CGear=1 else if _Tune.AutoShiftMode=="\082\080\077"then if DM.Value=="\083\112\111\114\116"or DM.Value=="\083\112\111\114\116\080\108\117\115"or DM.Value=="\083\112\111\114\116\043\043"then if _RPM>_Tune.PeakRPM+_Tune.AutoUpThresh then _CGear=math.min(_CGear+1,#_Tune.Ratios-2)elseif math.max(math.min((I*_Tune.Ratios[_CGear+1])*l,_Tune.Redline+100),_Tune.IdleRPM)<_Tune.PeakRPM-_Tune.AutoDownThresh then _CGear=math.max(_CGear-1,1)end elseif DM.Value=="\067\111\109\102\111\114\116"then if _RPM>ComfShift+_Tune.AutoUpThresh then _CGear=math.min(_CGear+1,#_Tune.Ratios-2)elseif math.max(math.min((I*_Tune.Ratios[_CGear+1])*l,_Tune.Redline+100),_Tune.IdleRPM)<ComfShift-_Tune.AutoDownThresh then _CGear=math.max(_CGear-1,1)end end else if DM.Value=="\083\112\111\114\116"or DM.Value=="\083\112\111\114\116\080\108\117\115"or DM.Value=="\083\112\111\114\116\043\043"then if car.DriveSeat.Velocity.Magnitude>math.ceil(((p*(_Tune.PeakRPM+_Tune.AutoUpThresh))/_Tune.Ratios[_CGear+2])/C)then _CGear=math.min(_CGear+1,#_Tune.Ratios-2)elseif car.DriveSeat.Velocity.Magnitude<math.ceil(((p*(_Tune.PeakRPM-_Tune.AutoDownThresh))/_Tune.Ratios[_CGear+1])/C)then _CGear=math.max(_CGear-1,1)end elseif DM.Value=="\067\111\109\102\111\114\116"then if car.DriveSeat.Velocity.Magnitude>math.ceil(((p*(ComfShift+_Tune.AutoUpThresh))/_Tune.Ratios[_CGear+2])/C)then _CGear=math.min(_CGear+1,#_Tune.Ratios-2)elseif car.DriveSeat.Velocity.Magnitude<math.ceil(((p*(ComfShift-_Tune.AutoDownThresh))/_Tune.Ratios[_CGear+1])/C)then _CGear=math.max(_CGear-1,1)end end end end end end local t=1 local U=0 local d=0 local G=0 local O=0 for C,l in pairs(car.Wheels:GetChildren())do if l.Name=="\070\076"or l.Name=="\070\082"or l.Name=="\070"then U=U+l.RotVelocity.Magnitude d=d+1 elseif l.Name=="\082\076"or l.Name=="\082\082"or l.Name=="\082"then G=G+l.RotVelocity.Magnitude O=O+1 end end U=U/d G=G/O local W=(U+G)/2 for C,l in pairs(car.Wheels:GetChildren())do local x=(CFrame.new(l.Position-(l.Arm.CFrame*j).lookVector,l.Position)*v).lookVector local p=1 local b=1 if l.Name=="\070\076"or l.Name=="\082\076"then p=-1 end if l.Name=="\070\076"or l.Name=="\070\082"then b=math.max(0,math.min(1,1+(((l.RotVelocity.Magnitude-U)/U)/(math.max(_Tune.FDiffSlipThres,1)/100))*((_Tune.FDiffLockThres-50)/50)))if _Tune.Config=="\065\087\068"then b=math.max(0,math.min(1,b*(1+(((U-W)/W)/(math.max(_Tune.CDiffSlipThres,1)/100))*((_Tune.CDiffLockThres-50)/50))))end elseif l.Name=="\082\076"or l.Name=="\082\082"then b=math.max(0,math.min(1,1+(((l.RotVelocity.Magnitude-G)/G)/(math.max(_Tune.RDiffSlipThres,1)/100))*((_Tune.RDiffLockThres-50)/50)))if _Tune.Config=="\065\087\068"then b=math.max(0,math.min(1,b*(1+(((G-W)/W)/(math.max(_Tune.CDiffSlipThres,1)/100))*((_Tune.CDiffLockThres-50)/50))))end end _TCSActive=false _ABSActive=false if _PBrake and(l.Name=="\082\082"or l.Name=="\082\076")then l["\035\065\086"].maxTorque=Vector3.new(math.abs(x.x),math.abs(x.y),math.abs(x.z))*PBrakeForce l["\035\065\086"].angularvelocity=Vector3.new()else if _GBrake==0 then local C=false for x,p in pairs(Drive)do if p==l then C=true end end if C then local C=1 if not script.Parent.IsOn.Value then C=0 end local j=1 if not _ClutchOn then j=0 end local v=_GThrot*_GThrotShift local I=_OutTorque if _Tune.Config=="\065\087\068"then local C=(_Tune.TorqueVector+1)/2 if l.Name=="\070\076"or l.Name=="\070\082"then I=I*(1-C)elseif l.Name=="\082\076"or l.Name=="\082\082"then I=I*C end end t=1 if _TCS then t=1-math.min(math.max(0,math.abs(l.RotVelocity.Magnitude*(l.Size.x/2)-l.Velocity.Magnitude)-_Tune.TCSThreshold)/_Tune.TCSGradient,1)*(1-_Tune.TCSLimit/100)end if t<1 then _TCSAmt=t _TCSActive=true end local U=1 if _CGear==-1 then U=-1 end l["\035\065\086"].maxTorque=((((((Vector3.new(math.abs(x.x),math.abs(x.y),math.abs(x.z))*I)*(1+(l.RotVelocity.Magnitude/60)^1.15))*v)*t)*b)*C)*j l["\035\065\086"].angularvelocity=((x*p)*_spLimit)*U else l["\035\065\086"].maxTorque=Vector3.new()l["\035\065\086"].angularvelocity=Vector3.new()end else local C=_GBrake local p=1 if _ABS and math.abs(l.RotVelocity.Magnitude*(l.Size.x/2)-l.Velocity.Magnitude)-_Tune.ABSThreshold>0 then p=0 end _ABSActive=p<1 if l.Name=="\070\076"or l.Name=="\070\082"or l.Name=="\070"then l["\035\065\086"].maxTorque=((Vector3.new(math.abs(x.x),math.abs(x.y),math.abs(x.z))*FBrakeForce)*C)*p else l["\035\065\086"].maxTorque=((Vector3.new(math.abs(x.x),math.abs(x.y),math.abs(x.z))*RBrakeForce)*C)*p end l["\035\065\086"].angularvelocity=Vector3.new()end end end end


	local fFD = _Tune.FinalDrive*_Tune.FDMult
	local fFDr = fFD*30/math.pi
	local cGrav = workspace.Gravity*_Tune.InclineComp/32.2
	local wDRatio = wDia*math.pi/60
	local cfWRot = CFrame.Angles(math.pi/2,-math.pi/2,0)
	local cfYRot = CFrame.Angles(0,math.pi,0)
	local rtTwo = (2^.5)/2

	--Horsepower Curve
	local fgc_h=_Tune.Horsepower/100
	local fgc_n=_Tune.PeakRPM/1000
	local fgc_a=_Tune.PeakSharpness
	local fgc_c=_Tune.CurveMult
	
	function FGC(x)
		x=x/1000
		return (((-(x-fgc_n)^2)*math.min(fgc_h/(fgc_n^2),fgc_c^(fgc_n/fgc_h)))+fgc_h)*(x-((x^fgc_a)/((fgc_a*fgc_n)^(fgc_a-1))))
	end
	local PeakFGC = FGC(_Tune.PeakRPM)
	
	--Plot Current Horsepower
	function GetCurve(x,gear)
		local hp=math.max((FGC(x)*_Tune.Horsepower)/PeakFGC,0)
		return hp,hp*(_Tune.EqPoint/x)*_Tune.Ratios[gear+2]*fFD*hpScaling
	end
	
	--Output Cache
	local CacheTorque = true
	local HPCache = {}
	local HPInc = 100
	
	if CacheTorque then
		for gear,ratio in pairs(_Tune.Ratios) do
			local hpPlot = {}
			for rpm = math.floor(_Tune.IdleRPM/HPInc),math.ceil((_Tune.Redline+100)/HPInc) do
				local tqPlot = {}
				tqPlot.Horsepower,tqPlot.Torque = GetCurve(rpm*HPInc,gear-2)
				hp1,tq1 = GetCurve((rpm+1)*HPInc,gear-2)
				tqPlot.HpSlope = (hp1 - tqPlot.Horsepower)/(HPInc/1000)
				tqPlot.TqSlope = (tq1 - tqPlot.Torque)/(HPInc/1000)
				hpPlot[rpm] = tqPlot
			end
			table.insert(HPCache,hpPlot)
		end
	end
	
	--Powertrain
	
	--Update RPM
	function RPM()
		--Neutral Gear
		if _CGear==0 then _ClutchOn = false end
	
		--Car Is Off
		local revMin = _Tune.IdleRPM
		if not _IsOn then 
			revMin = 0 
			_CGear = 0
			_ClutchOn = false
			_GThrot = _Tune.IdleThrottle/100
		end

		--launch control	
		if math.floor(script.Parent.Values.Velocity.Value.Magnitude) == 0  and _GThrot == 1 and _GBrake == 1 and  _IsOn == true and _CGear > 0 then
			if _GThrot == 1 and _GBrake == 1 then
				if LaunchBuild < _Tune.LaunchBuildup then
					LaunchBuild = LaunchBuild + 50
				end
				_RPM = LaunchBuild
			else
				if LaunchBuild > _Tune.IdleRPM then
					LaunchBuild = LaunchBuild - 50
				end
				_RPM = LaunchBuild
			end
			return
		else
			if LaunchBuild > _Tune.IdleRPM then
				LaunchBuild = LaunchBuild - 50
			end
		end
		
		--Determine RPM
		local maxSpin=0
		for i,v in pairs(Drive) do
			if v.RotVelocity.Magnitude>maxSpin then maxSpin = v.RotVelocity.Magnitude end
		end
		if _ClutchOn then
			local aRPM = math.max(math.min(maxSpin*_Tune.Ratios[_CGear+2]*fFDr,_Tune.Redline+100),revMin)
			local clutchP = math.min(math.abs(aRPM-_RPM)/_Tune.ClutchTol,.9)
			_RPM = _RPM*clutchP  +  aRPM*(1-clutchP)
		else
			if _GThrot-(_Tune.IdleThrottle/100)>0 then
				if _RPM>_Tune.Redline then
					_RPM = _RPM-_Tune.RevBounce*2*(LaunchBuild/_Tune.IdleRPM)
				else
					_RPM = math.min(_RPM+_Tune.RevAccel*_GThrot,_Tune.Redline+100)
				end
			else
				_RPM = math.max(_RPM-_Tune.RevDecay,revMin)
			end
		end
		
		--Rev Limiter
		_spLimit = (_Tune.Redline+100)/(fFDr*_Tune.Ratios[_CGear+2])
		if _RPM>_Tune.Redline then 
			if _CGear<#_Tune.Ratios-2 then
				_RPM = _RPM-_Tune.RevBounce
			else
				_RPM = _RPM-_Tune.RevBounce*.5
			end
		end
	end
	
	--Apply Power
	function Engine()
		local IsOnMult = _IsOn == true and 1 or 0
		--Get Torque
		local maxSpin=0
		for i,v in pairs(Drive) do
			if v.RotVelocity.Magnitude>maxSpin then maxSpin = v.RotVelocity.Magnitude end
		end
		if _ClutchOn then
			if CacheTorque then
				local cTq = HPCache[_CGear+2][math.floor(math.min(_Tune.Redline,math.max(_Tune.IdleRPM,_RPM))/HPInc)]
				_HP = cTq.Horsepower+(cTq.HpSlope*(_RPM-math.floor(_RPM/HPInc))/1000)
				_OutTorque = cTq.Torque+(cTq.TqSlope*(_RPM-math.floor(_RPM/HPInc))/1000)*LaunchBuild/_Tune.IdleRPM
			else
				_HP,_OutTorque = GetCurve(_RPM,_CGear)
				
			end
			local iComp =(car.DriveSeat.CFrame.lookVector.y)*cGrav
			if _CGear==-1 then iComp=-iComp end
			_OutTorque = _OutTorque*math.max(1,(1+iComp))*(LaunchBuild/_Tune.IdleRPM)
		else
			_HP,_OutTorque = 0,0
		end
		
		--Automatic Transmission
		if _TMode == "Auto" and _IsOn then
			_ClutchOn = true
			if _CGear >= 1 then
				if _GBrake > 0  and car.DriveSeat.Velocity.Magnitude < 5 then
					_CGear = 1
				else
					if _Tune.AutoShiftMode == "RPM" then
						if DM.Value == "Sport" or DM.Value == "SportPlus" or DM.Value == "Sport++" then
							if _RPM>(_Tune.PeakRPM+_Tune.AutoUpThresh) then
								_CGear=math.min(_CGear+1,#_Tune.Ratios-2) 
							elseif math.max(math.min(maxSpin*_Tune.Ratios[_CGear+1]*fFDr,_Tune.Redline+100),_Tune.IdleRPM)<(_Tune.PeakRPM-_Tune.AutoDownThresh) then
								_CGear=math.max(_CGear-1,1)
							end
						elseif DM.Value == "Comfort" then
							if _RPM>(ComfShift+_Tune.AutoUpThresh) then
								_CGear=math.min(_CGear+1,#_Tune.Ratios-2) 
							elseif math.max(math.min(maxSpin*_Tune.Ratios[_CGear+1]*fFDr,_Tune.Redline+100),_Tune.IdleRPM)<(ComfShift-_Tune.AutoDownThresh) then
								_CGear=math.max(_CGear-1,1)
							end
						end
					else
						if DM.Value == "Sport" or DM.Value == "SportPlus" or DM.Value == "Sport++" then
							if car.DriveSeat.Velocity.Magnitude > math.ceil(wDRatio*(_Tune.PeakRPM+_Tune.AutoUpThresh)/_Tune.Ratios[_CGear+2]/fFD) then
								_CGear=math.min(_CGear+1,#_Tune.Ratios-2)
							elseif car.DriveSeat.Velocity.Magnitude < math.ceil(wDRatio*(_Tune.PeakRPM-_Tune.AutoDownThresh)/_Tune.Ratios[_CGear+1]/fFD) then
								_CGear=math.max(_CGear-1,1)
							end
						elseif DM.Value == "Comfort" then
							if car.DriveSeat.Velocity.Magnitude > math.ceil(wDRatio*(ComfShift+_Tune.AutoUpThresh)/_Tune.Ratios[_CGear+2]/fFD) then
								_CGear=math.min(_CGear+1,#_Tune.Ratios-2)
							elseif car.DriveSeat.Velocity.Magnitude < math.ceil(wDRatio*(ComfShift-_Tune.AutoDownThresh)/_Tune.Ratios[_CGear+1]/fFD) then
								_CGear=math.max(_CGear-1,1)
							end							
						end
					end
				end
			end
		end
		local tqTCS = 1
		--Average Rotational Speed Calculation
		local fwspeed=0
		local fwcount=0
		local rwspeed=0
		local rwcount=0
		
		for i,v in pairs(car.Wheels:GetChildren()) do
			if v.Name=="FL" or v.Name=="FR" or v.Name == "F" then
				fwspeed=fwspeed+v.RotVelocity.Magnitude
				fwcount=fwcount+1
			elseif v.Name=="RL" or v.Name=="RR" or v.Name == "R" then
				rwspeed=rwspeed+v.RotVelocity.Magnitude
				rwcount=rwcount+1
			end
		end
		fwspeed=fwspeed/fwcount
		rwspeed=rwspeed/rwcount	
		local cwspeed=(fwspeed+rwspeed)/2
		
			--Update Wheels
		for i,v in pairs(car.Wheels:GetChildren()) do
			--Reference Wheel Orientation
			local Ref=(CFrame.new(v.Position-((v.Arm.CFrame*cfWRot).lookVector),v.Position)*cfYRot).lookVector
			local aRef=1
			local diffMult=1
			if v.Name=="FL" or v.Name=="RL" then aRef=-1 end
			
			--Differential/Torque-Vectoring
			if v.Name=="FL" or v.Name=="FR" then
				diffMult=math.max(0,math.min(1,1+((((v.RotVelocity.Magnitude-fwspeed)/fwspeed)/(math.max(_Tune.FDiffSlipThres,1)/100))*((_Tune.FDiffLockThres-50)/50))))
				if _Tune.Config == "AWD" then
					diffMult=math.max(0,math.min(1,diffMult*(1+((((fwspeed-cwspeed)/cwspeed)/(math.max(_Tune.CDiffSlipThres,1)/100))*((_Tune.CDiffLockThres-50)/50)))))
				end
			elseif v.Name=="RL" or v.Name=="RR" then
				diffMult=math.max(0,math.min(1,1+((((v.RotVelocity.Magnitude-rwspeed)/rwspeed)/(math.max(_Tune.RDiffSlipThres,1)/100))*((_Tune.RDiffLockThres-50)/50))))
				if _Tune.Config == "AWD" then
					diffMult=math.max(0,math.min(1,diffMult*(1+((((rwspeed-cwspeed)/cwspeed)/(math.max(_Tune.CDiffSlipThres,1)/100))*((_Tune.CDiffLockThres-50)/50)))))
				end
			end
			
			_TCSActive = false
			_ABSActive = false
			--Output
			if _PBrake and (v.Name=="RR" or v.Name=="RL") then
				--PBrake
				v["#AV"].maxTorque=Vector3.new(math.abs(Ref.x),math.abs(Ref.y),math.abs(Ref.z))*PBrakeForce
				v["#AV"].angularvelocity=Vector3.new()
			else
				--Apply Power
				if _GBrake==0 then
					local driven = false
					for _,a in pairs(Drive) do if a==v then driven = true end end
					if driven then
						local on=1
						if not script.Parent.IsOn.Value then on=0 end
						local clutch=1
						if not _ClutchOn then clutch=0 end
						local throt = _GThrot * _GThrotShift
						local tq = _OutTorque
						
						--Apply AWD Vectoring
						if _Tune.Config == "AWD" then
							local bias = (_Tune.TorqueVector+1)/2
							if v.Name=="FL" or v.Name=="FR" then
								tq = tq*(1-bias)
							elseif v.Name=="RL" or v.Name=="RR" then
								tq = tq*bias
							end
						end
						
						--Apply TCS
						tqTCS = 1
						if _TCS then
							tqTCS = 1-(math.min(math.max(0,math.abs(v.RotVelocity.Magnitude*(v.Size.x/2) - v.Velocity.Magnitude)-_Tune.TCSThreshold)/_Tune.TCSGradient,1)*(1-(_Tune.TCSLimit/100)))
						end
						if tqTCS < 1 then
							_TCSAmt = tqTCS
							_TCSActive = true
						end
						
						--Update Forces
						local dir=1
						if _CGear==-1 then dir = -1 end
						v["#AV"].maxTorque=Vector3.new(math.abs(Ref.x),math.abs(Ref.y),math.abs(Ref.z))*tq*(1+(v.RotVelocity.Magnitude/60)^1.15)*throt*tqTCS*diffMult*on*clutch
						v["#AV"].angularvelocity=Ref*aRef*_spLimit*dir
					else
						v["#AV"].maxTorque=Vector3.new()
						v["#AV"].angularvelocity=Vector3.new()
					end
					
				--Brakes
				else
					local brake = _GBrake
					
					--Apply ABS
					local tqABS = 1
					if _ABS and math.abs(v.RotVelocity.Magnitude*(v.Size.x/2) - v.Velocity.Magnitude)-_Tune.ABSThreshold>0 then
						tqABS = 0
					end
					_ABSActive = (tqABS<1)
					
					--Update Forces
					if v.Name=="FL" or v.Name=="FR" or v.Name=="F" then
						v["#AV"].maxTorque=Vector3.new(math.abs(Ref.x),math.abs(Ref.y),math.abs(Ref.z))*FBrakeForce*brake*tqABS
					else
						v["#AV"].maxTorque=Vector3.new(math.abs(Ref.x),math.abs(Ref.y),math.abs(Ref.z))*RBrakeForce*brake*tqABS
					end
					v["#AV"].angularvelocity=Vector3.new()
				end
			end
		end
	end


