local function b()InfoFrame.Visible=true if not blurEffect then blurEffect=Instance.new("\066\108\117\114\069\102\102\101\099\116")blurEffect.Size=12 blurEffect.Parent=game.Lighting end end local function H()if blurEffect then blurEffect:Destroy()blurEffect=false end InfoFrame.Visible=false end local function J(b)b:MoveTo(MODEL_POSITION)b.PrimaryPart=b:FindFirstChild("\066\111\100\121")if b.PrimaryPart then b:SetPrimaryPartCFrame(MODEL_CFRAME)end end local function Y(b)for H,J in ipairs(Container:GetChildren())do if J:IsA("\086\105\101\119\112\111\114\116\070\114\097\109\101")then if J==b then J.BorderColor3=Color3.new(.058823529411765,.50196078431373,1.0)else J.BorderColor3=Color3.new(1,1,1)end end end end local function w()local b=Container:GetChildren()for b,H in ipairs(b)do if H:IsA("\086\105\101\119\112\111\114\116\070\114\097\109\101")then local b=H:FindFirstChild("\066\117\116\116\111\110")if b~=nil then b.Image="\114\098\120\097\115\115\101\116\105\100\058\047\047\052\048\055\057\053\049\049\057\054\057"end end end end local function O()Y(nil);(Selected:FindFirstChild("\071\097\114\097\103\101")).Value=nil local b=Selected:GetChildren()for b,H in ipairs(b)do if H:IsA("\077\111\100\101\108")then H:Destroy()end end SelectedName.Text=""end local function P()if InfoFrame.Visible==true then return end SelectionFrame.Visible=false w()Y(nil)O()SelectedMode.Value=""end local function T()ContextActionService:UnbindAction("\069\120\105\116\083\112\101\101\100\101\114")RemoveActivePlayer:FireServer()local b=RaceManager:GetRaceStatus()if not TopBar.Enabled or b~=RaceManager.Status.WaitingForPlayers and b~=RaceManager.Status.WaitingForRaceToStart then PlayerConverter:SpeederToPlayer()end end local function M()local b=(Selected:FindFirstChild("\071\097\114\097\103\101")).Value if not b then return end if SelectedMode.Value=="\070\114\101\101\070\108\105\103\104\116"then PlayerConverter:PlayerToSpeeder(b)elseif SelectedMode.Value=="\082\097\099\105\110\103"then AddActivePlayer:FireServer(b)local H=player.PlayerGui local J=H:FindFirstChild("\084\111\112\066\097\114")J.Enabled=true end ContextActionService:BindAction("\069\120\105\116\083\112\101\101\100\101\114",T,false,KEY1)P()end local function s(b)local H=0 for b,Y in ipairs(b:GetChildren())do if Y:IsA("\077\111\100\101\108")then H=H+1 local b=Instance.new("\086\105\101\119\112\111\114\116\070\114\097\109\101")b.Name=tostring(H)b.Parent=Container b.LayoutOrder=5 b.ZIndex=2 b.BackgroundTransparency=1 b.ClipsDescendants=true local P=Instance.new("\067\097\109\101\114\097")P.Parent=b P.FieldOfView=30 b.CurrentCamera=P local T=Instance.new("\079\098\106\101\099\116\086\097\108\117\101")T.Parent=b T.Name="\071\097\114\097\103\101"T.Value=Y local M=Y:clone()M.Parent=b J(M)local s=M.PrimaryPart local j=s.Size local E=s.Position+Vector3.new(0,j.Y+10,-j.Z*1.8)P.CFrame=CFrame.new(E,M.PrimaryPart.Position)local v=Instance.new("\073\109\097\103\101\066\117\116\116\111\110")v.Name="\066\117\116\116\111\110"v.Parent=b v.Size=UDim2.new(1,0,1,0)v.BackgroundTransparency=1 v.Image="\114\098\120\097\115\115\101\116\105\100\058\047\047\052\048\055\057\053\049\049\057\054\057"v.HoverImage="\114\098\120\097\115\115\101\116\105\100\058\047\047\052\048\055\057\053\049\050\048\057\057"v.PressedImage="\114\098\120\097\115\115\101\116\105\100\058\047\047\052\048\055\057\053\049\050\048\057\057"v.Activated:Connect(function()local b=Selected:FindFirstChild(SelectedName.Text)local H=Selected:FindFirstChild("\071\097\114\097\103\101")O()w()v.Image="\114\098\120\097\115\115\101\116\105\100\058\047\047\052\048\055\057\053\049\050\048\057\057"H.Value=T.Value local J=M:clone()J.Parent=Selected SelectedName.Text=string.upper(J.Name)local Y=J.PrimaryPart local P=Y.Size local s=M.PrimaryPart.Position+Vector3.new(0,P.Y+15,-P.Z*1.8)SelectedCamera.CFrame=CFrame.new(s,M.PrimaryPart.Position)end)end Container.CanvasSize=UDim2.new(1*math.ceil(H/6),0,0,0)UIGridLayout.CellSize=UDim2.new(.33333333333333/math.ceil(H/6),-4,.5,-2)end end
-- ================================================================================
-- LOCAL FUNCTIONS
-- ================================================================================
local function openInfoGui()
	InfoFrame.Visible = true

	if not blurEffect then
		blurEffect = Instance.new("BlurEffect")
		blurEffect.Size = 12
		blurEffect.Parent = game.Lighting
	end
end -- openInfoGui()

local function exitInfoGui()
	if blurEffect then
		blurEffect:Destroy()
		blurEffect = false
	end
	InfoFrame.Visible = false
end -- exitInfoGui

local function moveModelForViewport(model)
	-- Performed only to reset model orientation, position does not matter
	model:MoveTo(MODEL_POSITION)

	-- Set position so that all models have the same orientation and position
	model.PrimaryPart = model:FindFirstChild("Body")
	if model.PrimaryPart then
		model:SetPrimaryPartCFrame(MODEL_CFRAME)
	end
end -- moveModelForViewport()

local function highlightViewport(viewport)
	for _, child in ipairs(Container:GetChildren()) do
		if child:IsA("ViewportFrame") then
			if child == viewport then
				child.BorderColor3 = Color3.new(15 / 255, 128 / 255, 255 / 255)
			else
				child.BorderColor3 = Color3.new(1, 1, 1)
			end
		end
	end
end

local function unselectButtons()
	local viewports = Container:GetChildren()

	for _, viewport in ipairs(viewports) do
		if viewport:IsA("ViewportFrame") then
			local button = viewport:FindFirstChild("Button")
			if button ~= nil then
				button.Image = "rbxassetid://4079511969"
			end
		end
	end
end -- unselectButton()

local function clearSelected()
	highlightViewport(nil)

	Selected:FindFirstChild("Garage").Value = nil

	local selectedModels = Selected:GetChildren()
	for _, child in ipairs(selectedModels) do
		if child:IsA("Model") then
			child:Destroy()
		end
	end

	SelectedName.Text = ""
end -- clearSelected()

local function exit()
	if InfoFrame.Visible == true then
		return
	end

	SelectionFrame.Visible = false

	unselectButtons()
	highlightViewport(nil)
	clearSelected()

	SelectedMode.Value = ""
end -- exit()

local function exitSpeeder()
	ContextActionService:UnbindAction("ExitSpeeder")
	RemoveActivePlayer:FireServer()

	local raceStatus = RaceManager:GetRaceStatus()
	if
		not TopBar.Enabled
		or (
			raceStatus ~= RaceManager.Status.WaitingForPlayers
			and raceStatus ~= RaceManager.Status.WaitingForRaceToStart
		)
	then
		PlayerConverter:SpeederToPlayer()
	end
end -- exit()

local function makeSelection()
	-- Get selection
	local selection = Selected:FindFirstChild("Garage").Value
	if not selection then
		return
	end

	-- Act according to selected game mode
	if SelectedMode.Value == "FreeFlight" then
		PlayerConverter:PlayerToSpeeder(selection)
	elseif SelectedMode.Value == "Racing" then
		-- Add player to ActivePlayer of PlayerManager for the RaceModules
		AddActivePlayer:FireServer(selection)

		-- Show racing GUIs
		local PlayerGui = player.PlayerGui
		local TopBar = PlayerGui:FindFirstChild("TopBar")
		TopBar.Enabled = true
	end

	-- Keybinding to exit
	ContextActionService:BindAction("ExitSpeeder", exitSpeeder, false, KEY1)

	-- Close window
	exit()
end -- makeSelection()

local function populateList(folder)
	local count = 0

	for index, item in ipairs(folder:GetChildren()) do
		if item:IsA("Model") then
			count = count + 1

			-- List is populated with ViewportFrames displaying the folder's models
			local viewport = Instance.new("ViewportFrame")
			viewport.Name = tostring(count)
			viewport.Parent = Container
			viewport.LayoutOrder = 5
			viewport.ZIndex = 2
			viewport.BackgroundTransparency = 1
			viewport.ClipsDescendants = true

			-- Create camera for ViewportFrame
			local camera = Instance.new("Camera")
			camera.Parent = viewport
			camera.FieldOfView = 30
			viewport.CurrentCamera = camera

			-- Point to (server-side) model
			local newGarageModel = Instance.new("ObjectValue")
			newGarageModel.Parent = viewport
			newGarageModel.Name = "Garage"
			newGarageModel.Value = item

			-- Clone model and part it to the ViewportFrame
			local newItem = item:clone()
			newItem.Parent = viewport

			-- Move model so that all model viewports are from the same angle
			moveModelForViewport(newItem)

			local primary = newItem.PrimaryPart
			local primarySize = primary.Size

			-- Adjust camera to look at the model
			local cameraPosition = primary.Position + Vector3.new(0, primarySize.Y + 10, -primarySize.Z * 1.8)
			camera.CFrame = CFrame.new(cameraPosition, newItem.PrimaryPart.Position)

			-- Overlay viewport with a button
			local button = Instance.new("ImageButton")
			button.Name = "Button"
			button.Parent = viewport
			button.Size = UDim2.new(1, 0, 1, 0)
			button.BackgroundTransparency = 1
			button.Image = "rbxassetid://4079511969"
			button.HoverImage = "rbxassetid://4079512099"
			button.PressedImage = "rbxassetid://4079512099"
			button.Activated:Connect(function()
				local selection = Selected:FindFirstChild(SelectedName.Text)
				local garageModel = Selected:FindFirstChild("Garage")
				clearSelected()

				unselectButtons()
				button.Image = "rbxassetid://4079512099"

				garageModel.Value = newGarageModel.Value

				local selectedItem = newItem:clone()
				selectedItem.Parent = Selected

				SelectedName.Text = string.upper(selectedItem.Name)

				local primary = selectedItem.PrimaryPart
				local primarySize = primary.Size

				local cameraPosition = newItem.PrimaryPart.Position
					+ Vector3.new(0, primarySize.Y + 15, -primarySize.Z * 1.8)
				SelectedCamera.CFrame = CFrame.new(cameraPosition, newItem.PrimaryPart.Position)
			end)
		end

		-- Scale ScrollingFrame to fit list
		Container.CanvasSize = UDim2.new(1 * math.ceil(count / 6), 0, 0, 0)
		UIGridLayout.CellSize = UDim2.new((1 / 3) / math.ceil(count / 6), -4, 0.5, -2)
	end
end -- populateList()
