--Made by Luckymaxer

Model = script.Parent

Players = game:GetService("Players")
Debris = game:GetService("Debris")
RunService = game:GetService("RunService")

RbxUtility = require(game.ReplicatedStorage.LoadLibrary.RbxUtility)
Create = RbxUtility.Create

Functions = require(script:WaitForChild("Functions"))

BasePart = Create("Part"){
	Shape = Enum.PartType.Block,
	Material = Enum.Material.Plastic,
	FormFactor = Enum.FormFactor.Custom,
	TopSurface = Enum.SurfaceType.Smooth,
	BottomSurface = Enum.SurfaceType.Smooth,
	Size = Vector3.new(0.2, 0.2, 0.2),
	Locked = true,
	CanCollide = true,
	Anchored = false,
}

Humanoid = Model:WaitForChild("Humanoid")
Humanoid.Health = Humanoid.MaxHealth
Humanoid.AutoRotate = false
Seat = Model:WaitForChild("Seat")
Head = Model:WaitForChild("Head")
Torso = Model:WaitForChild("Torso")

InteractiveControl = script:WaitForChild("InteractiveControl")

Animations = {
	Ride = {Animation = Model:WaitForChild("Ride"), FadeTime = 0, Weight = nil, Speed = nil},
}

Rider = nil

DefaultSpeed = 40
Gravity = 196.20

Humanoid.WalkSpeed = DefaultSpeed

for i, v in pairs(Torso:GetChildren()) do
	if string.find(string.lower(v.ClassName), string.lower("Body")) then
		v:Destroy()
	end
end

Gyro = Create("BodyGyro"){
	Name = "BodyGyro",
	D = 100,
	P = 10000,
	maxTorque = Vector3.new(math.huge, 0, math.huge),
	cframe = Torso.CFrame,
	Parent = Torso,
}

Velocity = Create("BodyVelocity"){
	Name = "BodyVelocity",
	maxForce = Vector3.new(math.huge, 0, math.huge),
	velocity = Vector3.new(0, 0, 0),
	Parent = Torso,
}

BodyAngularVelocity = Create("BodyAngularVelocity"){
	Name = "BodyAngularVelocity",
	maxTorque = Vector3.new(0, math.huge, 0),
	angularvelocity = Vector3.new(0, 0, 0),
	Parent = Torso,
}

Remotes = script:WaitForChild("Remotes")
Remotes:ClearAllChildren()

LastJump = 0
JumpCoolDown = 2
LastLaserFire = 0
LaserCoolDown = 2
MaxLaserDistance = 120
Disabled = false

ServerControl = (Remotes:FindFirstChild("ServerControl") or Create("RemoteFunction"){
	Name = "ServerControl",
	Parent = Remotes,
})

ClientControl = (Remotes:FindFirstChild("ClientControl") or Create("RemoteFunction"){
	Name = "ClientControl",
	Parent = Remotes,
})

function OnServerInvoke(player, Mode, Value)
	if player ~= Rider or not Mode or Disabled then
		return
	end
	if Mode == "Jump" then
		local Now = tick()
		local State = Humanoid:GetState().Name
		if (Now - LastJump) >= JumpCoolDown and State ~= "Freefall" then
			LastJump = Now
			Humanoid.Jump = true
			wait(JumpCoolDown)
			Humanoid.Jump = false
		end
	elseif Mode == "Dismount" then
		Dismount()
	elseif Mode == "Sprint" then
		local Down = Value.Down
		Humanoid.WalkSpeed = (Down and 70 or DefaultSpeed)
	end
end

ServerControl.OnServerInvoke = OnServerInvoke

Humanoid.Changed:connect(function(Property)
	if Property == "Sit" and Humanoid.Sit then
		Humanoid.Sit = false
	end
end)

Humanoid.Died:connect(function()
	Disabled = true
	Debris:AddItem(Model, 3)
	Model:BreakJoints()
end)

function InvokeClient(Mode, Value)
	local ClientReturn = nil
	pcall(function()
		ClientReturn = ClientControl:InvokeClient(Rider, Mode, Value)
	end)
	return ClientReturn
end

function Animate(Time)
	local Occupant = Seat.Occupant
	if not Occupant or not Occupant.Parent or not Occupant:IsA("Humanoid") then
		return
	end
	local character = Occupant.Parent
	local player = Players:GetPlayerFromCharacter(character)
	if not player or Rider ~= player then
		return
	end
	if Humanoid.Health == 0 or Disabled then
		return
	end
	--Motion
	local velocity = (Torso.CFrame.lookVector * Seat.Throttle * Humanoid.WalkSpeed)
	Velocity.velocity = Vector3.new(velocity.X, 0, velocity.Z)
	Velocity.maxForce = Vector3.new(math.huge, 0, math.huge)
	BodyAngularVelocity.angularvelocity = Vector3.new(0, (0.95 * -Seat.Steer), 0)
end

function Dismount()
	if Rider and Rider.Parent then
		local Character = Rider.Character
		if Character then
			local humanoid = nil
			for i, v in pairs(Character:GetChildren()) do
				if v:IsA("Humanoid") then
					humanoid = v
					break
				end
			end
			humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
			humanoid.Jump = true
		end
	end
end

function PlayerSeated(Child)
	local function BreakWeld()
		Debris:AddItem(Child, 0.5)
		if Child and Child.Parent then
			Child:Destroy()
		end
	end
	if not Child:IsA("Weld") or not Child.Name == "SeatWeld" then
		return
	end
	if Child.Part0 ~= Seat or not Child.Part1 or not Child.Part1.Parent then
		return
	end
	Child.C1 = (Child.C1 * CFrame.new(0, -0.5, 0.75))
	local character = Child.Part1.Parent
	local humanoid = character:FindFirstChild("Humanoid")
	if humanoid then
		local Animation = Animations.Ride
		RideTrack = humanoid:LoadAnimation(Animation.Animation)
		RideTrack:Play(Animation.FadeTime, Animation.Weight, Animation.Speed)
	end
	local Player = Players:GetPlayerFromCharacter(character)
	if not Player then
		BreakWeld()
		return
	end
	local PlayerGui = Player:FindFirstChild("PlayerGui")
	if not PlayerGui then
		BreakWeld()
		return
	end
	InteractiveControlCopy = InteractiveControl:Clone()
	local ServerCommunication = Instance.new("ObjectValue")
	ServerCommunication.Name = "ServerControl"
	ServerCommunication.Value = ServerControl
	ServerCommunication.Parent = InteractiveControlCopy
	InteractiveControlCopy.Disabled = false
	InteractiveControlCopy.Parent = PlayerGui
	Rider = Player
end

function PlayerDismounted(Child)
	if not Child:IsA("Weld") or not Child.Name == "SeatWeld" or not Child.Part1 or not Child.Part1.Parent then
		return
	end
	local Player = Players:GetPlayerFromCharacter(Child.Part1.Parent)
	if not Player or Player ~= Rider then
		return
	end
	if InteractiveControlCopy and InteractiveControlCopy.Parent then
		InteractiveControlCopy:Destroy()
	end
	if RideTrack then
		RideTrack:Stop()
	end
	Rider = nil
	Humanoid.WalkSpeed = DefaultSpeed
end

RunService.Heartbeat:connect(Animate)
Seat.ChildAdded:connect(PlayerSeated)
Seat.ChildRemoved:connect(PlayerDismounted)