--Runtime Loop

wait(2)
car.Wheels.FL:WaitForChild('SQ')
local Distance = car.Wheels.FL.Size.Y/2+0.1

function LocalUpdate(v, material, color, objn)
	if v == 'StopGravel' then 
		car.DriveSeat.Gravel.Volume = 0
		return
	end
	if v == 'StopSnow' then 
		car.DriveSeat.SnowSound.Volume = 0
		return
	end
	if (material == Enum.Material.Asphalt or material == Enum.Material.Slate or material == Enum.Material.Concrete 
		or material == Enum.Material.Basalt or material == Enum.Material.Brick or material == Enum.Material.Cobblestone or material == Enum.Material.Rock
		or material == Enum.Material.Sandstone or material == Enum.Material.Concrete or material == Enum.Material.Pavement or material == Enum.Material.Limestone
		or material == Enum.Material.Wood or material == Enum.Material.Salt) then
		if v.stress > 0.6 then
			v.wheel.SQ.Volume = (v.stress-0.1)*3
			v.wheel.SQ.PlaybackSpeed = v.stress+0.15
			v.wheel.Smoke.Rate = v.stress*5
		else
			v.wheel.SQ.Volume = v.stress-0.1
			v.wheel.SQ.PlaybackSpeed = v.stress+0.15
			v.wheel.Smoke.Rate = 0
		end
		v.wheel.Dirt.Rate = 0
		v.wheel.Sand.Rate = 0
		v.wheel.Snow.Rate = 0
		v.wheel.GravelEmitter.Rate = 0
	elseif (material == Enum.Material.Marble or material == Enum.Material.Plastic or material == Enum.Material.SmoothPlastic
		 or material == Enum.Material.Metal or material == Enum.Material.DiamondPlate or material == Enum.Material.CorrodedMetal) then
		if v.stress > 0.6 then
			v.wheel.SQ.Volume = (v.stress-0.1)*3
			v.wheel.SQ.PlaybackSpeed = v.stress+0.15
			v.wheel.Smoke.Rate = 0
		else
			v.wheel.SQ.Volume = v.stress-0.1
			v.wheel.SQ.PlaybackSpeed = v.stress+0.15
			v.wheel.Smoke.Rate = 0
		end
		v.wheel.Dirt.Rate = 0
		v.wheel.Sand.Rate = 0
		v.wheel.Snow.Rate = 0
		v.wheel.GravelEmitter.Rate = 0
	elseif (material == Enum.Material.Grass or material == Enum.Material.LeafyGrass) then
		v.wheel.Dirt.Rate = (v.stress*10)
		v.wheel.SQ.Volume = 0
		v.wheel.SQ.PlaybackSpeed = 0
		v.wheel.Smoke.Rate = 0
		v.wheel.Sand.Rate = 0
		v.wheel.Snow.Rate = 0
		v.wheel.GravelEmitter.Rate = 0
		local fixmultiply = 1
		if car.DriveSeat.Velocity.Magnitude <= 0.9 then
			fixmultiply = 0
		end
		local pitch = ((v.stress*2) + (car.DriveSeat.Velocity.Magnitude/80))+(0.5*fixmultiply)
		if pitch > 2.1 then
			pitch = 2.1
		end
		car.DriveSeat.Gravel.PlaybackSpeed = pitch
		car.DriveSeat.Gravel.Volume = pitch*8
		car.DriveSeat.Gravel.PitchShiftSoundEffect.Octave = 1-(pitch/4)
	elseif (material == Enum.Material.Ground or material == Enum.Material.Mud) then
		if car.DriveSeat.Velocity.Magnitude >= 30 then
			v.wheel.Dirt.Rate = (v.stress*10) + (car.DriveSeat.Velocity.Magnitude/10)
		else
			v.wheel.Dirt.Rate = (v.stress*10)
		end
		v.wheel.SQ.Volume = 0
		v.wheel.SQ.PlaybackSpeed = 0
		v.wheel.Smoke.Rate = 0
		v.wheel.Sand.Rate = 0
		v.wheel.Snow.Rate = 0
		v.wheel.GravelEmitter.Rate = 0
		local fixmultiply = 1
		if car.DriveSeat.Velocity.Magnitude <= 0.9 then
			fixmultiply = 0
		end
		local pitch = ((v.stress*2) + (car.DriveSeat.Velocity.Magnitude/80))+(0.5*fixmultiply)
		if pitch > 2.1 then
			pitch = 2.1
		end
		car.DriveSeat.Gravel.PlaybackSpeed = pitch
		car.DriveSeat.Gravel.Volume = pitch*8
		car.DriveSeat.Gravel.PitchShiftSoundEffect.Octave = 1-(pitch/4)
	elseif material == Enum.Material.Sand then
		if car.DriveSeat.Velocity.Magnitude >= 30 then
			v.wheel.Sand.Rate = (v.stress*10) + (car.DriveSeat.Velocity.Magnitude/10)
		else
			v.wheel.Sand.Rate = (v.stress*10)
		end
		if objn ~= 'Terrain' then
			v.wheel.Sand.Color = ColorSequence.new(color)
		else
			v.wheel.Sand.Color = ColorSequence.new(Color3.fromRGB(143, 126, 95))
		end
		v.wheel.SQ.Volume = 0
		v.wheel.SQ.PlaybackSpeed = 0
		v.wheel.Smoke.Rate = 0
		v.wheel.Dirt.Rate = 0
		v.wheel.Snow.Rate = 0
		v.wheel.GravelEmitter.Rate = 0
		local fixmultiply = 1
		if car.DriveSeat.Velocity.Magnitude <= 0.9 then
			fixmultiply = 0
		end
		local pitch = ((v.stress*2) + (car.DriveSeat.Velocity.Magnitude/80))+(0.5*fixmultiply)
		if pitch > 2.1 then
			pitch = 2.1
		end
		if ( (color.r>=color.g and color.r-color.b < 0.11) or (color.g>=color.r and color.g-color.b < 0.11) ) and objn ~= 'Terrain' then
			car.DriveSeat.SnowSound.PlaybackSpeed = pitch
			car.DriveSeat.SnowSound.Volume = pitch*20
			car.DriveSeat.SnowSound.PitchShiftSoundEffect.Octave = 1-(pitch/4)
		else
			car.DriveSeat.Gravel.PlaybackSpeed = pitch
			car.DriveSeat.Gravel.Volume = pitch*8
			car.DriveSeat.Gravel.PitchShiftSoundEffect.Octave = 1-(pitch/4)
		end
	elseif material == Enum.Material.Snow then
		if car.DriveSeat.Velocity.Magnitude >= 30 then
			v.wheel.Snow.Rate = (v.stress*10) + (car.DriveSeat.Velocity.Magnitude/10)
		else
			v.wheel.Snow.Rate = (v.stress*10)
		end
		v.wheel.SQ.Volume = 0
		v.wheel.SQ.PlaybackSpeed = 0
		v.wheel.Smoke.Rate = 0
		v.wheel.Dirt.Rate = 0
		v.wheel.Sand.Rate = 0
		v.wheel.GravelEmitter.Rate = 0
		local fixmultiply = 1
		if car.DriveSeat.Velocity.Magnitude <= 0.9 then
			fixmultiply = 0
		end
		local pitch = ((v.stress*2) + (car.DriveSeat.Velocity.Magnitude/80))+(0.5*fixmultiply)
		if pitch > 2.1 then
			pitch = 2.1
		end
		car.DriveSeat.SnowSound.PlaybackSpeed = pitch
		car.DriveSeat.SnowSound.Volume = pitch*20
		car.DriveSeat.SnowSound.PitchShiftSoundEffect.Octave = 1-(pitch/4)
	elseif (material == Enum.Material.Pebble) then
		if car.DriveSeat.Velocity.Magnitude >= 30 then
			v.wheel.GravelEmitter.Rate = (v.stress*10) + (car.DriveSeat.Velocity.Magnitude/10)
		else
			v.wheel.GravelEmitter.Rate = (v.stress*10)
		end
		v.wheel.GravelEmitter.Color = ColorSequence.new(color)
		local fixmultiply = 1
		if car.DriveSeat.Velocity.Magnitude <= 0.9 then
			fixmultiply = 0
		end
		local pitch = ((v.stress*2) + (car.DriveSeat.Velocity.Magnitude/80))+(0.5*fixmultiply)
		if pitch > 2.1 then
			pitch = 2.1
		end
		car.DriveSeat.Gravel.PlaybackSpeed = pitch
		car.DriveSeat.Gravel.Volume = pitch*8
		car.DriveSeat.Gravel.PitchShiftSoundEffect.Octave = 1-(pitch/4)
		v.wheel.Dirt.Rate = 0
		v.wheel.Sand.Rate = 0
		v.wheel.Snow.Rate = 0
		v.wheel.SQ.Volume = 0
		v.wheel.SQ.PlaybackSpeed = 0
		v.wheel.Smoke.Rate = 0
	else
		v.wheel.Dirt.Rate = 0
		v.wheel.GravelEmitter.Rate = 0
		v.wheel.Sand.Rate = 0
		v.wheel.SQ.Volume = 0
		v.wheel.SQ.PlaybackSpeed = 0
		v.wheel.Smoke.Rate = 0
		v.wheel.Snow.Rate = 0
	end
end

while wait() do
	GravelSound = false
	SnowSound = false
	for i,v in pairs(Wheels) do
		--Vars
		local speed = car.DriveSeat.Velocity.Magnitude
		local wheel = v.wheel.RotVelocity.Magnitude
		local z = 0		
		local deg = 0.000126
		
		--Tire Wear
		local cspeed = (speed/1.298)*(2.6/v.wheel.Size.Y) 
		local wdif = math.abs(wheel-cspeed)
		if _WHEELTUNE.TireWearOn then
			if speed < 4 then
				--Wear Regen
				v.Heat = math.min(v.Heat + _WHEELTUNE.RegenSpeed/10000,v.BaseHeat)
			else
				--Tire Wear
				if wdif > 1 then
					v.Heat = v.Heat - wdif*deg*v.WearSpeed/28
				elseif v.Heat >= v.BaseHeat then
					v.Heat = v.BaseHeat
				end
			end
		end
		
		--Apply Friction
		if v.wheel.Name == "FL" or v.wheel.Name == "FR" or v.wheel.Name == "F" then
			z = _WHEELTUNE.FMinFriction+v.Heat
			deg = ((deg - 0.0001188*cValues.Brake.Value)*(1-math.abs(cValues.SteerC.Value))) + 0.00000126*math.abs(cValues.SteerC.Value)
		else
			z = _WHEELTUNE.RMinFriction+v.Heat
		end
		
		--Tire Slip
		if math.ceil((wheel/0.774/speed)*100) < 8 then
			--Lock Slip
			v.wheel.CustomPhysicalProperties = PhysicalProperties.new(v.x,z*_WHEELTUNE.WheelLockRatio,v.elast,v.fWeight,v.eWeight)
			v.Heat = math.max(v.Heat,0)
		elseif (_Tune.TCSEnabled and cValues.TCS.Value == false and math.ceil((wheel/0.774/speed)*100) > 80) then
			--TCS Off
			v.wheel.CustomPhysicalProperties = PhysicalProperties.new(v.x,z*_WHEELTUNE.TCSOffRatio,v.elast,v.fWeight,v.eWeight)
			v.Heat = math.max(v.Heat,0)
		elseif math.ceil((wheel/0.774/speed)*100) > 130 then
			--Wheelspin
			v.wheel.CustomPhysicalProperties = PhysicalProperties.new(v.x,z*_WHEELTUNE.WheelspinRatio,v.elast,v.fWeight,v.eWeight)		
			v.Heat = math.max(v.Heat,0)
		else
			--No Slip
			v.wheel.CustomPhysicalProperties = PhysicalProperties.new(v.x,z,v.elast,v.fWeight,v.eWeight)
			v.Heat = math.min(v.Heat,v.BaseHeat)
		end 
		
		--Update UI
		local vstress = math.abs(((((wdif+cspeed)/0.774)*0.774)-cspeed)/15)
		if vstress > 0.05 and vstress > v.stress then 
			v.stress = math.min(v.stress + 0.03,1)
		else
			v.stress = math.max(v.stress - 0.03,vstress)	
		end
		local UI = script.Parent.Tires[v.wheel.Name]
		UI.First.Second.Image.ImageColor3 = Color3.new(math.min((v.stress*2),1), 1-v.stress, 0)
		UI.First.Position = UDim2.new(0,0,1-v.Heat/v.BaseHeat,0)
		UI.First.Second.Position = UDim2.new(0,0,v.Heat/v.BaseHeat,0)
		
		local detectionRay = Ray.new(v.wheel.Position + Vector3.new(0, 5, 0), Vector3.new(0,-5,0)*Distance)
		local objecthit, hitposition, surface, material = workspace:FindPartOnRay(detectionRay, car, false, true)
		if not material then
			material = Enum.Material.Air
		end
		if (material == Enum.Material.Pebble or material == Enum.Material.Mud or material == Enum.Material.Ground or (material == Enum.Material.Sand and ((objecthit.Color.r>=objecthit.Color.g and objecthit.Color.r-objecthit.Color.b >= 0.11) or (objecthit.Color.g>=objecthit.Color.r and objecthit.Color.g-objecthit.Color.b >= 0.11) or objecthit.Name == 'Terrain') )
			or material == Enum.Material.Grass or material == Enum.Material.LeafyGrass) then
			GravelSound = true
		end
		if (material == Enum.Material.Snow) or (material == Enum.Material.Sand and (((objecthit.Color.r>=objecthit.Color.g and objecthit.Color.r-objecthit.Color.b < 0.11) or (objecthit.Color.g>=objecthit.Color.r and objecthit.Color.g-objecthit.Color.b < 0.11)) and objecthit.Name ~= 'Terrain' ) ) then
			SnowSound = true
		end
		if not objecthit then
			LocalUpdate(v, material, BrickColor.Black())
			car.TireStress:FireServer(v, material, BrickColor.Black())
		else
			LocalUpdate(v, material, objecthit.Color,objecthit.Name)
			car.TireStress:FireServer(v, material, objecthit.Color,objecthit.Name)
		end
	end
	if GravelSound == false then
		car.TireStress:FireServer('StopGravel')
		LocalUpdate('StopGravel')
	end
	if SnowSound == false then
		car.TireStress:FireServer('StopSnow')
		LocalUpdate('StopSnow')
	end
end
