--Apply Power

function Engine(dt)
	local deltaTime = (60/(1/dt))
	--Determine Clutch Slip
	if _TMode~="Manual" and _Tune.SlipClutch then
		if _Tune.ABS and _ABS then
			if _SlipCount >= _Tune.SlipABSThres then _ClutchSlip = true else _ClutchSlip = false end
		else
			if tick()-bticc >= _Tune.SlipTimeThres then _ClutchSlip = true else _ClutchSlip = false end
		end
	else
		_ClutchSlip = false
	end

	--Neutral Gear
	if ((_CGear == 0 or _Shifting) and _IsOn) then 
		_ClPressing = true
		_Clutch = 1
		_StallOK = false
	end

	local revMin = _Tune.IdleRPM 
	local goalMin = _Tune.IdleRPM 
	if _Tune.Stall and _Tune.Clutch then revMin = 0 end

	if _Shifting and _ShiftUp then 
		_GThrot = 0
	elseif _Shifting and _ShiftDn then
		_GThrot = (_Tune.ShiftThrot/100)
	else
		_GThrot = _InThrot
	end
	_GBrake = _InBrake

	if not _IsOn then 
		ticc = tick()
		revMin = 0 
		goalMin = 0
		_GThrot = _Tune.IdleThrottle/100
		if _TMode~="Manual" then 
			_CGear = 0 
			_ClPressing = true 
			_Clutch = 1 
		end
	end

	--Determine RPM
	local maxSpin=0
	if Rear.Wheel.RotVelocity.Magnitude>maxSpin then maxSpin = Rear.Wheel.RotVelocity.Magnitude end
	local _GoalRPM=0

	if _Tune.Engine or _Tune.Electric then
		_GoalRPM = math.max(math.min((_RPM-_Tune.RevDecay*deltaTime)+((_Tune.RevDecay+_Tune.RevAccel)*_GThrot*deltaTime),_Tune.Redline+100),goalMin)
	end

	if _GoalRPM>_Tune.Redline then 
		if _CGear<#_Tune.Ratios-2 then
			_GoalRPM = _GoalRPM-_Tune.RevBounce
		else
			_GoalRPM = _GoalRPM-_Tune.RevBounce*.5
		end
	end

	local _WheelRPM = maxSpin*_Tune.Ratios[_CGear+1]*fFDr

	--Clutch Calculation
	if _Tune.Clutch then
		if script.Parent.Values.AutoClutch.Value and _IsOn then
			if _Tune.ClutchType == "Clutch" then
				if _ClPressing or _ClutchSlip then _ClutchKick = 1 end
				_ClutchKick = _ClutchKick*(_Tune.ClutchEngage/100)		
				local ClRPMInfluence = math.max((_RPM-_Tune.IdleRPM)*_Tune.ClutchRPMMult/(_Tune.Redline-_Tune.IdleRPM),0)
				if _Tune.ClutchMode == "New" then ClRPMInfluence = 0 end
				_ClutchModulate = math.min(((((script.Parent.Values.Velocity.Value.Magnitude/_Tune.SpeedEngage)/math.abs(_CGear)) + ClRPMInfluence) - _ClutchKick), 1)
			elseif _Tune.ClutchType == "CVT" or (_Tune.ClutchType == "TorqueConverter" and _Tune.TQLock) then
				if (_GThrot-(_Tune.IdleThrottle/100)==0 and script.Parent.Values.Velocity.Value.Magnitude<_Tune.SpeedEngage) or (_GThrot-(_Tune.IdleThrottle/100)~=0 and (_RPM < _Tune.RPMEngage and _WheelRPM < _Tune.RPMEngage)) then
					_ClutchModulate = math.min(_ClutchModulate*(_Tune.ClutchEngage/100), 1)
				else
					_ClutchModulate = math.min(_ClutchModulate*(_Tune.ClutchEngage/100)+(1-(_Tune.ClutchEngage/100)), 1)
				end
			elseif _Tune.ClutchType == "TorqueConverter" and not _Tune.TQLock then
				_ClutchModulate = math.min((_RPM/_Tune.Redline)*0.7, 1)
			end
			if not _ClPressing and not _ClutchSlip then _Clutch = math.min(1-_ClutchModulate,1) else _Clutch = 1 end
			_StallOK = (_Clutch<=0.01) or _StallOK
		else
			_StallOK = _Tune.Stall
			_Clutch = script.Parent.Values.Clutch.Value
		end
	else
		_StallOK = false
		if (not _ClPressing and not _ClutchSlip) and not _Shifting then _Clutch = 0 else _Clutch = 1 end
	end

	local aRPM = math.max(math.min((_GoalRPM*_Clutch) + (_WheelRPM*(1-_Clutch)),_Tune.Redline+100),revMin)
	local clutchP = math.min(math.abs(aRPM-_RPM)/(_Tune.Flywheel*deltaTime),.9)
	if _ClPressing or _ClutchSlip then clutchP = 0 end
	_RPM = _RPM*clutchP  +  aRPM*(1-clutchP)

	if _RPM<=(_Tune.IdleRPM/4) and _StallOK and (tick()-ticc>=0.2) then script.Parent.IsOn.Value = not _Tune.Stall end

	--Rev Limiter
	_spLimit = -((_Tune.Redline+100)/(fFDr*_Tune.Ratios[_CGear+1]))
	if _Tune.Limiter then _spLimit = math.min(_spLimit,-_Tune.SpeedLimit) end
	if _RPM>_Tune.Redline then 
		if _CGear<#_Tune.Ratios-2 then
			_RPM = _RPM-_Tune.RevBounce
		else
			_RPM = _RPM-_Tune.RevBounce*.5
		end
	end

	--Aspiration
	local TPsi = _TPsi/_TCount

	local _BThrot = _GThrot

	if _Tune.Engine then
		if _TCount~=0 then
			_TBoost = _TBoost + ((((((_HP*(_BThrot*1.2)/_Tune.Horsepower)/8)-(((_TBoost/TPsi*(TPsi/15)))))*((8/(_Tune.T_Size/(deltaTime)))*2))/TPsi)*15)
			if _TBoost < 0.05 then _TBoost = 0.05 elseif _TBoost > 2 then _TBoost = 2 end
		else
			_TBoost = 0
		end
		if _SCount~=0 then
			if _BThrot>sthrot then
				sthrot=math.min(_BThrot,sthrot+_Tune.S_Sensitivity*deltaTime)
			elseif _BThrot<sthrot then
				sthrot=math.max(_BThrot,sthrot-_Tune.S_Sensitivity*deltaTime)
			end
			_SBoost = (_RPM/_Tune.Redline)*(.5+(1.5*sthrot))
		else
			_SBoost = 0
		end
	else
		_TBoost = 0
		_SBoost = 0
	end

	--Torque calculations
	if _Tune.Engine then
		local cTq = NCache[_CGear+1][math.floor(math.min(_Tune.Redline,math.max(0,_RPM))/100)]
		_NH = cTq.Horsepower+(cTq.HpSlope*(((_RPM-math.floor(_RPM/100))/100)%1))
		_NT = cTq.Torque+(cTq.TqSlope*(((_RPM-math.floor(_RPM/100))/100)%1))
		if _TCount~=0 then
			local tTq = TCache[_CGear+1][math.floor(math.min(_Tune.Redline,math.max(0,_RPM))/100)]
			_TH = (tTq.Horsepower+(tTq.HpSlope*(((_RPM-math.floor(_RPM/100))/100)%1)))*(_TBoost/2)
			_TT = (tTq.Torque+(tTq.TqSlope*(((_RPM-math.floor(_RPM/100))/100)%1)))*(_TBoost/2)
		else
			_TH,_TT = 0,0
		end
		if _SCount~=0 then
			local sTq = SCache[_CGear+1][math.floor(math.min(_Tune.Redline,math.max(0,_RPM))/100)]
			_SH = (sTq.Horsepower+(sTq.HpSlope*(((_RPM-math.floor(_RPM/100))/100)%1)))*(_SBoost/2)
			_ST = (sTq.Torque+(sTq.TqSlope*(((_RPM-math.floor(_RPM/100))/100)%1)))*(_SBoost/2)
		else
			_SH,_ST = 0,0
		end
		_BH = _TH+_SH
		_BT = _TT+_ST
	else
		_NH,_NT = 0,0
		_TH,_TT = 0,0
		_SH,_ST = 0,0
		_BH,_BT = 0,0
	end

	if _Tune.Electric and _CGear~=0 then
		local eTq = ECache[_CGear+1][math.floor(math.min(_Tune.Redline,math.max(100,_RPM))/100)]
		_EH = eTq.Horsepower+(eTq.HpSlope*(((_RPM-math.floor(_RPM/100))/100)%1))
		_ET = eTq.Torque+(eTq.TqSlope*(((_RPM-math.floor(_RPM/100))/100)%1))
	else
		_EH,_ET = 0,0
	end

	_HP = _NH + _BH + _EH
	_OutTorque = _NT + _BT + _ET
	
	local iComp =(bike.DriveSeat.CFrame.lookVector.y)*cGrav
	if _CGear==-1 then iComp=-iComp end
	_OutTorque = _OutTorque*math.max(1,(1+iComp))
	--Update Wheels

	--Front

	_fABSActive = false
	--Output
	if _PBrake and bike.DriveSeat.Velocity.Magnitude<20 then
		--PBrake
		Front.Axle.HingeConstraint.MotorMaxTorque=PBrakeForce*(60/workspace:GetRealPhysicsFPS())
	else
		if _CGear == 0 and bike.DriveSeat.Velocity.Magnitude <= 10 and _Tune.NeutralRev then
			Front.Axle.HingeConstraint.MotorMaxTorque=FBrakeForce*_GThrot*(60/workspace:GetRealPhysicsFPS())
		else
			--Apply ABS
			local ftqABS = 1
			if _ABS and math.abs(Front.Wheel.RotVelocity.Magnitude*(Front.Wheel.Size.Y/2) - Front.Wheel.Velocity.Magnitude)-_Tune.ABSThreshold>0 then ftqABS = 0 end
			if ftqABS < 1 then _fABSActive = true end
			local brake = FBrakeForce
			if _Tune.LinkedBrakes then
				local bias = _Tune.BrakesRatio/100
				brake = brake*bias
			end
			Front.Axle.HingeConstraint.MotorMaxTorque=brake*_GBrake*ftqABS*(60/workspace:GetRealPhysicsFPS())
		end
	end

	--Rear

	_TCSActive = false
	_rABSActive = false
	--Output
	if _PBrake and bike.DriveSeat.Velocity.Magnitude>=20 then
		--PBrake
		_SlipCount = _Tune.SlipABSThres
		bticc = tick()-_Tune.SlipTimeThres
		Rear.Axle.HingeConstraint.MotorMaxTorque=PBrakeForce*(60/workspace:GetRealPhysicsFPS())
		Rear.Axle.HingeConstraint.MotorMaxAcceleration=9e9
		Rear.Axle.HingeConstraint.AngularVelocity=0
	else
		--Apply Power
		if _CGear == 0 and bike.DriveSeat.Velocity.Magnitude <= 10 and _Tune.NeutralRev then
			bticc = tick()
			_SlipCount = 0
			Rear.Axle.HingeConstraint.MotorMaxTorque=math.min((500*_GBrake)+(RBrakeForce*_GThrot),500)*(60/workspace:GetRealPhysicsFPS())
			Rear.Axle.HingeConstraint.AngularVelocity=7*_GBrake*(1-_GThrot)
		elseif _GBrake==0 then
			bticc = tick()
			_SlipCount = 0
			local on=1
			if not script.Parent.IsOn.Value then on=0 end
			local throt = _GThrot
			local clutch=1
			if _ClPressing then clutch=0 end

			--Apply TCS
			local tqTCS = 1
			if _TCS then tqTCS = 1-(math.min(math.max(0,math.abs(Rear.Wheel.RotVelocity.Magnitude*(wDia/2) - Rear.Wheel.Velocity.Magnitude)-_Tune.TCSThreshold)/_Tune.TCSGradient,1)*(1-(_Tune.TCSLimit/100))) end
			_TCSAmt = tqTCS
			if tqTCS < 1 then
				_TCSAmt = tqTCS
				_TCSActive = true
			end

			--Update Forces
			Rear.Axle.HingeConstraint.MotorMaxTorque=_OutTorque*throt*tqTCS*on*clutch*(60/workspace:GetRealPhysicsFPS())*(1+(Rear.Wheel.RotVelocity.Magnitude/(120-workspace:GetRealPhysicsFPS()))^(1.15+(.07*(1-(60/workspace:GetRealPhysicsFPS())))))
			Rear.Axle.HingeConstraint.AngularVelocity=_spLimit
			--Brakes
		else
			--Apply ABS
			local rtqABS = 1
			if math.abs(Rear.Wheel.RotVelocity.Magnitude*(wDia/2) - Rear.Wheel.Velocity.Magnitude)-_Tune.ABSThreshold>0 then 
				if _ABS then rtqABS = 0 _SlipCount = _SlipCount + 1 end
			else
				bticc = tick()
			end
			if rtqABS < 1 then _rABSActive = true end
			local brake = RBrakeForce
			if _Tune.LinkedBrakes then
				local bias = _Tune.BrakesRatio/100
				brake = brake*(1-bias)
			end

			Rear.Axle.HingeConstraint.MotorMaxTorque=brake*_GBrake*rtqABS*(60/workspace:GetRealPhysicsFPS())
			Rear.Axle.HingeConstraint.AngularVelocity=0
		end
	end
end
