-------------------------------------------------------------------------------------------------------------------------------------------------------
local P = script.Parent
local Run = game:GetService('RunService')
local wheels = P.System.Wheels
local seat = P.System.VehicleSeat
local vars = seat.ATSVariables

local exclude = {"Wheels"}

function WeldPair(x, y)
	local weld = Instance.new("Weld",x) 
	weld.Part0 = x
	weld.Part1 = y
	weld.C1 = y.CFrame:toObjectSpace(x.CFrame);
end

function WeldAll(model, main) -- model can be anything
	for i,v in pairs(exclude) do if (model.Name == v) then return end end
	if model:IsA("BasePart") then WeldPair(main, model) end
	for _,v in pairs(model:GetChildren()) do WeldAll(v, main) end	
end

function UnanchorAll(model) -- model can be anything
	if (model:IsA("BasePart")) then model.Anchored = false end
	for _,v in pairs(model:GetChildren()) do UnanchorAll(v) end
end

function Joint(x,y, c0, c1, type)
	local W = Instance.new(type, x)
	W.Part0 = x
	W.Part1 = y
	W.C0 = c0
	W.C1 = c1
	return W
end

function CreateWheelPart()
	local p = Instance.new("Part")
	p.FormFactor = Enum.FormFactor.Custom
	p.Transparency = 1
	p.Anchored = true
	p.CanCollide = false
	p.TopSurface = Enum.SurfaceType.Unjoinable
	p.BottomSurface = Enum.SurfaceType.Unjoinable
	p.LeftSurface = Enum.SurfaceType.Unjoinable
	p.RightSurface = Enum.SurfaceType.Unjoinable
	p.FrontSurface = Enum.SurfaceType.Unjoinable
	p.BackSurface = Enum.SurfaceType.Unjoinable
	return p
end

for i,v in pairs(wheels:GetChildren()) do
	if (v:IsA("BasePart")) then
		local diameter = v.Size.x
		local M = Instance.new("Model",wheels)
		M.Name = v.Name
		v.Parent = M
		v.Name = "Wheel"
		for j,w in pairs(v:GetChildren()) do
			if (w:IsA("BasePart")) then
				w.Parent = M
				WeldPair(v,w)
				w.CanCollide = false
			end
		end
		if (v:FindFirstChild("Steer")) then
			local A = CreateWheelPart()
			A.Name = "Steer"
			A.Size = Vector3.new(diameter, 1, 0.6)
			A.CFrame = v.CFrame
			A.Parent = M
		end
		local B = CreateWheelPart()
		B.Name = "Suspension"
		B.Size = Vector3.new(0.8, 1, diameter)
		B.CFrame = v.CFrame * CFrame.new(-1,0,0)
		B.Parent = M
		local BB = Instance.new("BodyGyro")
		BB.Name = "BG"
		if (v:FindFirstChild("Steer")) then
			BB.D = vars.SuspensionDampeningFront.Value
		else
			BB.D = vars.SuspensionDampeningRear.Value
		end
		BB.P = vars.SuspensionPower.Value
		BB.maxTorque = Vector3.new()
		BB.Parent = B
		local C = CreateWheelPart()
		C.Name = "BodyHinge"
		C.Size = Vector3.new(0.8, 1, diameter)
		C.CFrame = v.CFrame * CFrame.new(1,0,0)
		C.Parent = M
		if (v:FindFirstChild("Powered")) then
			local CC = Instance.new("BodyAngularVelocity")
			CC.Name = "BAV"
			CC.angularvelocity = Vector3.new()
			CC.maxTorque = Vector3.new(20000, 0, 20000)
			CC.P = 800
			CC.Parent = v
		end
	end
end

for i,v in pairs(wheels:GetChildren()) do
	if (v:FindFirstChild("Wheel")) and (v:FindFirstChild("Suspension")) then
		local isSteeringWheel = (v:FindFirstChild("Steer") ~= nil)
		if (v:FindFirstChild("Mesh")) then
			WeldAll(v.Mesh, v.Wheel)
		end
		if (isSteeringWheel) then
			Joint(v.Wheel, v.Steer, CFrame.Angles(math.pi / 2,0,0), v.Steer.CFrame:toObjectSpace(v.Wheel.CFrame) * CFrame.Angles(math.pi / 2,0,0), "Rotate")
			local M = Joint(v.Steer, v.Suspension, CFrame.Angles(math.pi,0,0), v.Suspension.CFrame:toObjectSpace(v.Steer.CFrame) * CFrame.Angles(math.pi,0,0), "Motor")
			M.MaxVelocity = 0.03
		else
			Joint(v.Wheel, v.Suspension, CFrame.Angles(math.pi / 2,0,0), v.Suspension.CFrame:toObjectSpace(v.Wheel.CFrame) * CFrame.Angles(math.pi / 2,0,0), "Rotate")
		end
		Joint(v.Suspension, v.BodyHinge, CFrame.new(Vector3.new(2,0,0)) * CFrame.Angles(math.pi/2,0,0), v.BodyHinge.CFrame:toObjectSpace(v.Suspension.CFrame) * CFrame.new(Vector3.new(2,0,0)) * CFrame.Angles(math.pi/2,0,0), "Rotate")
		Joint(v.BodyHinge, seat, CFrame.new(), seat.CFrame:toObjectSpace(v.BodyHinge.CFrame), "Weld")
	else
		print("Invalid wheel: Missing Wheel or Suspension part!")
	end
end

WeldAll(P, seat)

wait(0.5)

UnanchorAll(P)

function UpdateWheels()
	if (not wheels) or (not seat) or (not vars) then return end
	for i,v in pairs(wheels:GetChildren()) do
		if (v:FindFirstChild("Suspension")) then
			v.Suspension.BG.CFrame = seat.CFrame * CFrame.Angles(-math.pi/2,-math.rad(vars.SuspensionAngle.Value),0) 
		end
	end
end

UpdateWheels()
for i,v in pairs(wheels:GetChildren()) do
	if (v:FindFirstChild("Suspension")) then
		local isSteeringWheel = (v:FindFirstChild("Steer") ~= nil)
		if(isSteeringWheel) then
			v.Suspension.BG.maxTorque = Vector3.new(0,3000000,0)
		else
			v.Suspension.BG.maxTorque = Vector3.new(0,9000000,0)
		end
	end
end
	
Run.Heartbeat:connect(UpdateWheels)