local d={}d.driverSeat=root:WaitForChild("\086\101\104\105\099\108\101\083\101\097\116")print("\114\097\110 \099\104\097\115\115\105\115 \109\111\100\117\108\101")function d.InitializeSeats()driverSeat=root:WaitForChild("\086\101\104\105\099\108\101\083\101\097\116")passengerSeats={root:FindFirstChild("\083\101\097\116\070\082"),root:FindFirstChild("\083\101\097\116\082\076"),root:FindFirstChild("\083\101\097\116\082\082")}local d=root.SuspensionFL.WheelFrontLeft.Size.y/2 driverSeat.MaxSpeed=maxSpeed*d end function d.InitializeDriving()print("\105\110\105\116\105\097\108\105\122\105\110\103 \099\104\097\115\115\105\115 \100\114\105\118\105\110\103")local d=root:WaitForChild("\067\111\110\115\116\114\097\105\110\116\115")local C=root:WaitForChild("\069\102\102\101\099\116\115")local G=root:WaitForChild("\083\099\114\105\112\116\115")motors={d:WaitForChild("\077\111\116\111\114\070\076");d:WaitForChild("\077\111\116\111\114\070\082"),d:WaitForChild("\077\111\116\111\114\082\076");d:WaitForChild("\077\111\116\111\114\082\082")}local W={d:WaitForChild("\083\116\114\117\116\083\112\114\105\110\103\070\076");d:WaitForChild("\083\116\114\117\116\083\112\114\105\110\103\070\082"),d:WaitForChild("\083\116\114\117\116\083\112\114\105\110\103\082\076");d:WaitForChild("\083\116\114\117\116\083\112\114\105\110\103\082\082")}local q={d:WaitForChild("\084\111\114\115\105\111\110\066\097\114\083\112\114\105\110\103\070\076"),d:WaitForChild("\084\111\114\115\105\111\110\066\097\114\083\112\114\105\110\103\070\082"),d:WaitForChild("\084\111\114\115\105\111\110\066\097\114\083\112\114\105\110\103\082\076"),d:WaitForChild("\084\111\114\115\105\111\110\066\097\114\083\112\114\105\110\103\082\082")}redressMount=root:WaitForChild("\082\101\100\114\101\115\115\077\111\117\110\116")steeringPrismatic=d:WaitForChild("\083\116\101\101\114\105\110\103\080\114\105\115\109\097\116\105\099")steerMax=steeringPrismatic.UpperLimit setMotorTorque(100000)for d,C in pairs(W)do end for d,C in pairs(q)do end print("\102\105\110\105\115\104\101\100 \105\110\105\116\105\097\108\105\122\105\110\103 \099\104\097\115\115\105\115 \100\114\105\118\105\110\103")end function d.GetDriverSeat()if not driverSeat then warn("\100\114\105\118\101\114\083\101\097\116 \117\110\105\110\105\116\105\097\108\105\122\101\100")end return driverSeat end function d.GetPassengerSeats()if not passengerSeats then warn("\112\097\115\115\101\110\103\101\114\083\101\097\116\115 \117\110\105\110\105\116\105\097\108\105\122\101\100")end return passengerSeats end function d.SetMotorVelocity(d)for C,G in pairs(motors)do G.AngularVelocity=d end end function d.GetAverageVelocity()local d=0 for C,G in pairs(motors)do d=d+getMotorVelocity(G)end return d*(1/#motors)end function d.EnableHandbrake()motors[3].AngularVelocity=0 motors[4].AngularVelocity=0 motors[3].MotorMaxTorque=breakingTorque motors[4].MotorMaxTorque=breakingTorque end function d.UpdateSteering(d,C)local G=.2*(math.abs(C)/maxSpeed)+1 d=d/G print(d)steeringPrismatic.TargetPosition=((d*d)*d)*steerMax end function d.UpdateThrottle(C,G)local W=0 local q=0 if math.abs(G)<.1 then q=100 setMotorTorque(q)elseif math.abs(G*C)>0 then q=(torque*G)*G setMotorTorqueDamped(q)W=math.sign(G)*10000 else q=(breakingTorque*G)*G setMotorTorque(q)end d.SetMotorVelocity(W)end local C=false function d.Redress()if C then return end C=true local d=driverSeat.CFrame.Position+Vector3.new(0,10,0)local G=driverSeat.CFrame.RightVector G=Vector3.new(G.x,0,G.z)G=G.Unit local W=Vector3.new(0,1,0)local q=G:Cross(W)local Y=CFrame.new(d.x,d.y,d.z,G.x,W.x,q.x,G.y,W.y,q.y,G.z,W.z,q.z)local D=redressMount.RedressTarget D.Parent=workspace.Terrain D.Position=d D.Axis=G D.SecondaryAxis=W redressMount.RedressOrientation.Enabled=true redressMount.RedressPosition.Enabled=true wait(1.5)redressMount.RedressOrientation.Enabled=false redressMount.RedressPosition.Enabled=false D.Parent=redressMount wait(2)C=false end return d
-- Module Functions --
local Chassis = {}

Chassis.driverSeat = root:WaitForChild("VehicleSeat")
print("ran chassis module")

function Chassis.InitializeSeats()
	driverSeat = root:WaitForChild("VehicleSeat")
	passengerSeats = {
		root:FindFirstChild("SeatFR"),
		root:FindFirstChild("SeatRL"),
		root:FindFirstChild("SeatRR"),
	}
	local wheelRadius = root.SuspensionFL.WheelFrontLeft.Size.y / 2
	driverSeat.MaxSpeed = maxSpeed * wheelRadius
end

function Chassis.InitializeDriving()
	print("initializing chassis driving")
	local constraints = root:WaitForChild("Constraints")
	local effects = root:WaitForChild("Effects")
	local scripts = root:WaitForChild("Scripts")

	-- Constraint tables always ordered FL, FR, RL, RR
	motors = {
		constraints:WaitForChild("MotorFL"),
		constraints:WaitForChild("MotorFR"),
		constraints:WaitForChild("MotorRL"),
		constraints:WaitForChild("MotorRR"),
	}
	local strutSprings = {
		constraints:WaitForChild("StrutSpringFL"),
		constraints:WaitForChild("StrutSpringFR"),
		constraints:WaitForChild("StrutSpringRL"),
		constraints:WaitForChild("StrutSpringRR"),
	}
	local torsionSprings = {
		constraints:WaitForChild("TorsionBarSpringFL"),
		constraints:WaitForChild("TorsionBarSpringFR"),
		constraints:WaitForChild("TorsionBarSpringRL"),
		constraints:WaitForChild("TorsionBarSpringRR"),
	}

	redressMount = root:WaitForChild("RedressMount")

	steeringPrismatic = constraints:WaitForChild("SteeringPrismatic")
	steerMax = steeringPrismatic.UpperLimit

	setMotorTorque(100000)

	for _, s in pairs(strutSprings) do
		--s.Stiffness = springStiffness
		--	s.Damping = springDamping
	end
	for _, s in pairs(torsionSprings) do
		--adjustStrutSpring(s, gravityChange)
	end
	print("finished initializing chassis driving")
end

function Chassis.GetDriverSeat()
	if not driverSeat then
		warn("driverSeat uninitialized")
	end
	return driverSeat
end

function Chassis.GetPassengerSeats()
	if not passengerSeats then
		warn("passengerSeats uninitialized")
	end
	return passengerSeats
end

function Chassis.SetMotorVelocity(vel)
	for _, m in pairs(motors) do
		m.AngularVelocity = vel
	end
end

function Chassis.GetAverageVelocity()
	local t = 0
	for _, m in pairs(motors) do
		t = t + getMotorVelocity(m)
	end
	return t * (1 / #motors)
end

function Chassis.EnableHandbrake()
	motors[3].AngularVelocity = 0
	motors[4].AngularVelocity = 0
	motors[3].MotorMaxTorque = breakingTorque
	motors[4].MotorMaxTorque = breakingTorque
end

function Chassis.UpdateSteering(steer, currentVel)
	local c = 0.2 * (math.abs(currentVel) / maxSpeed) + 1 --decrease steer value as speed increases to prevent tipping (handbrake cancels this)
	steer = steer / c
	print(steer)
	steeringPrismatic.TargetPosition = steer * steer * steer * steerMax
end

function Chassis.UpdateThrottle(currentVel, throttle)
	local targetVel = 0
	local motorTorque = 0
	if math.abs(throttle) < 0.1 then
		-- Idling
		motorTorque = 100
		setMotorTorque(motorTorque)
	elseif math.abs(throttle * currentVel) > 0 then
		motorTorque = torque * throttle * throttle
		setMotorTorqueDamped(motorTorque)
		-- Arbitrary large number
		targetVel = math.sign(throttle) * 10000
	else
		-- Breaking
		motorTorque = breakingTorque * throttle * throttle
		setMotorTorque(motorTorque)
	end
	Chassis.SetMotorVelocity(targetVel)
end

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

	local targetAttachment = redressMount.RedressTarget

	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

return Chassis
