local l=script.Parent.Parent.Parent local u,k,T,N,q,S,e,h,w,V,E,H,Y,B,y,D,U,J,G,o,W,f,g local i,z,M=0,0,0 local C local O={}local a,R,X,m,n,L,I,Q=false,false,false,false,true,0,0,false local K=script.Parent local s=K.Panel local c=1 local p=0 local P=math.abs local j={engine={key};landing={key};spdup={byte=0,down=false},spddwn={byte=0;down=false}}function waitFor(l,u)if u then for u,k in pairs(u)do while not l:findFirstChild(k)do wait()end end elseif l:IsA("\079\098\106\101\099\116\086\097\108\117\101")then while not l.Value do wait()end end end function fixVars()y=y<-90 and-90 or y>90 and 90 or y G=G<.01 and.01 or G>1 and 1 or G J=J>D and D or J V=V<.01 and.01 or V>D and D or V f=f-100<W and W+100 or f f=g and f+q.Position.y or f W=g and W+q.Position.y or W j.engine.key=j.engine.key==""and"\101"or j.engine.key j.spdup.byte=j.spdup.byte==0 and 17 or j.spdup.byte j.spddwn.byte=j.spddwn.byte==0 and 18 or j.spddwn.byte j.landing.key=j.landing.key==""and"\103"or j.landing.key end function getVars()u=script.Parent.Plane.Value waitFor(u,{"\077\097\105\110\080\097\114\116\115";"\079\116\104\101\114\080\097\114\116\115","\069\068\073\084\095\084\072\069\083\069";"\068\101\097\100"})k,N=u.MainParts,u.EDIT_THESE waitFor(u.Parent,{"\065\110\105\109\097\116\105\111\110\080\097\114\116\115"})T=u.Parent.AnimationParts waitFor(k,{"\077\097\105\110","\077\097\105\110\083\101\097\116","\076\097\110\100\105\110\103\071\101\097\114"})q,h,w=k.Main,k.MainSeat,k.LandingGear waitFor(q,{"\077\111\118\101","\071\121\114\111"})S,gyro=q.Move,q.Gyro V,E,H,Y,B,y,D,U,J,G,o,W,f,g=P(N.Acceleration.Value),N.CanCrash.Value,P(N.CanCrash.Force.Value),N.CanCrash.SpinSpeed.Value,N.CanCrash.VisualFX.Value,N.MaxBank.Value,P(N.MaxSpeed.Value),P(N.SpeedDifferential.Value),P(N.StallSpeed.Value),P(N.ThrottleIncrease.Value),N.AltitudeRestrictions.Value,N.AltitudeRestrictions.MinAltitude.Value,N.AltitudeRestrictions.MaxAltitude.Value,N.AltitudeRestrictions.SetByOrigin.Value j.engine.key=((N.Hotkeys.Engine.Value:gmatch("\037\097"))()):lower()j.landing.key=((N.Hotkeys.Gear.Value:gmatch("\037\097"))()):lower()local l,e=N.Hotkeys.SpeedUp.Value:lower(),N.Hotkeys.SpeedDown.Value:lower()j.spdup.byte=l=="\097\114\114\111\119\107\101\121\117\112"and 17 or l=="\097\114\114\111\119\107\101\121\100\111\119\110"and 18 or((l:gmatch("\037\097"))()):byte()j.spddwn.byte=e=="\097\114\114\111\119\107\101\121\117\112"and 17 or e=="\097\114\114\111\119\107\101\121\100\111\119\110"and 18 or((e:gmatch("\037\097"))()):byte()fixVars()u.Dead.Changed:connect(function()if u.Dead.Value and not m then m,R,X=true,false,false q.Fire.Enabled,q.Smoke.Enabled=N.CanCrash.VisualFX.Value,N.CanCrash.VisualFX.Value S.maxForce=Vector3.new(0,0,0)gyro.D=1000.0 while a and not u.Dead.Stop.Value do gyro.cframe=gyro.cframe*CFrame.Angles(0,0,math.rad(Y))wait()end end end)end function getGear(l)for l,u in pairs(l:GetChildren())do if u:IsA("\066\097\115\101\080\097\114\116")then local l,k,T=Instance.new("\078\117\109\098\101\114\086\097\108\117\101",u),Instance.new("\078\117\109\098\101\114\086\097\108\117\101",u),Instance.new("\066\111\111\108\086\097\108\117\101",u)l.Name,k.Name,T.Name="\084\114\097\110\115","\082\101\102","\067\111\108\108\105\100\101"l.Value,k.Value,T.Value=u.Transparency,u.Reflectance,u.CanCollide table.insert(O,u)end getGear(u)end end function getLowestPoint()if#O==0 then p=(q.Position.y+5)+q.Size.y/2 return end for l,u in pairs(O)do local k=q.Position.y-(u.CFrame*CFrame.new(u.Size.x/2,0,0)).y local T=q.Position.y-(u.CFrame*CFrame.new(-(u.Size.x/2),0,0)).y local N=q.Position.y-(u.CFrame*CFrame.new(0,u.Size.y/2,0)).y local S=q.Position.y-(u.CFrame*CFrame.new(0,-(u.Size.y/2),0)).y local e=q.Position.y-(u.CFrame*CFrame.new(0,0,u.Size.z/2)).y local h=q.Position.y-(u.CFrame*CFrame.new(0,0,-(u.Size.z/2))).y local w=math.max(k,T,N,S,e,h)+5 p=w>p and w or p end end function guiSetup()local l=0 s.Controls.Position=UDim2.new(0,0,0,-(s.Controls.AbsolutePosition.y+s.Controls.AbsoluteSize.y))s.ControlsButton.MouseButton1Click:connect(function()l=l==0 and 1 or 0 if l==0 then s.Controls:TweenPosition(UDim2.new(0,0,0,-(s.Controls.AbsolutePosition.y+s.Controls.AbsoluteSize.y)),"\073\110","\083\105\110\101",.35)else s.Controls.Visible=true s.Controls:TweenPosition(UDim2.new(0,0,1.5,0),"\079\117\116","\066\097\099\107",.5)end end)s.Controls.C1.Text=j.engine.key:upper().." \075\101\121"s.Controls.C2.Text=j.spdup.byte==17 and"\085\080 \065\114\114\111\119 \075\101\121"or j.spdup.byte==18 and"\068\079\087\078 \065\114\114\111\119 \075\101\121"or(string.char(j.spdup.byte)):upper().." \075\101\121"s.Controls.C3.Text=j.spddwn.byte==17 and"\085\080 \065\114\114\111\119 \075\101\121"or j.spddwn.byte==18 and"\068\079\087\078 \065\114\114\111\119 \075\101\121"or(string.char(j.spddwn.byte)):upper().." \075\101\121"s.Controls.C4.Text=j.landing.key:upper().." \075\101\121"end waitFor(script.Parent,{"\080\108\097\110\101","\068\101\115\101\108\101\099\116\048";"\068\101\115\101\108\101\099\116\049";"\067\117\114\114\101\110\116\083\101\108\101\099\116"})waitFor(script.Parent.Plane)getVars()getGear(w)getLowestPoint()guiSetup()

local player = script.Parent.Parent.Parent
local plane,mainParts,animationParts,info,main,move,gryo,seat,landingGear,accel,canCrash,crashForce,crashSpin,crashVisual,maxBank,maxSpeed,speedVary,stallSpeed,throttleInc,altRestrict,altMin,altMax,altSet
local desiredSpeed,currentSpeed,realSpeed = 0,0,0
local mouseSave
local gearParts = {}
local selected,flying,on,dead,gear,throttle,feThrottle,cruising = false,false,false,false,true,0,0,false
local gui = script.Parent
local panel = gui.Panel
local camtype = 1
local lowestPoint = 0
local A = math.abs	-- Creating a shortcut for the function

local keys = {
	engine={key};
	landing = {key};
	spdup={byte=0;down=false};
	spddwn={byte=0;down=false};
}

function waitFor(parent,array)	-- Backup system to wait for objects to 'load'
	if (array) then
		for _,name in pairs(array) do
			while (not parent:findFirstChild(name)) do wait() end	-- If the object is found right away, no time will be spent waiting. That's why 'while' loops work better than 'repeat' in this case
		end
	elseif (parent:IsA("ObjectValue")) then
		while (not parent.Value) do wait() end
	end
end

function fixVars()	-- Correct your mistakes to make sure the plane still flies correctly!
	maxBank = (maxBank < -90 and -90 or maxBank > 90 and 90 or maxBank)
	throttleInc = (throttleInc < 0.01 and 0.01 or throttleInc > 1 and 1 or throttleInc)
	stallSpeed = (stallSpeed > maxSpeed and maxSpeed or stallSpeed)
	accel = (accel < 0.01 and 0.01 or accel > maxSpeed and maxSpeed or accel)
	altMax = ((altMax-100) < altMin and (altMin+100) or altMax)
	altMax = (altSet and (altMax+main.Position.y) or altMax)
	altMin = (altSet and (altMin+main.Position.y) or altMin)
	keys.engine.key = (keys.engine.key == "" and "e" or keys.engine.key)
	keys.spdup.byte = (keys.spdup.byte == 0 and 17 or keys.spdup.byte)
	keys.spddwn.byte = (keys.spddwn.byte == 0 and 18 or keys.spddwn.byte)
	keys.landing.key = (keys.landing.key == "" and "g" or keys.landing.key)
end

function getVars()	-- Since this plane kit is supposed to make you avoid scripting altogether, I have to go the extra mile and write a messy function to account for all those object variables
	plane = script.Parent.Plane.Value
	waitFor(plane,{"MainParts","OtherParts","EDIT_THESE","Dead"})
	mainParts,info = plane.MainParts,plane.EDIT_THESE
	waitFor(plane.Parent,{"AnimationParts"})
	animationParts = plane.Parent.AnimationParts
	waitFor(mainParts,{"Main","MainSeat","LandingGear"})
	main,seat,landingGear = mainParts.Main,mainParts.MainSeat,mainParts.LandingGear
	waitFor(main,{"Move","Gyro"})
	move,gyro = main.Move,main.Gyro
	accel,canCrash,crashForce,crashSpin,crashVisual,maxBank,maxSpeed,speedVary,stallSpeed,throttleInc,altRestrict,altMin,altMax,altSet =	-- Quickest way to assign tons of variables
		A(info.Acceleration.Value),info.CanCrash.Value,A(info.CanCrash.Force.Value),info.CanCrash.SpinSpeed.Value,info.CanCrash.VisualFX.Value,
		info.MaxBank.Value,A(info.MaxSpeed.Value),A(info.SpeedDifferential.Value),A(info.StallSpeed.Value),A(info.ThrottleIncrease.Value),
		info.AltitudeRestrictions.Value,info.AltitudeRestrictions.MinAltitude.Value,info.AltitudeRestrictions.MaxAltitude.Value,info.AltitudeRestrictions.SetByOrigin.Value
	keys.engine.key = info.Hotkeys.Engine.Value:gmatch("%a")():lower()
	keys.landing.key = info.Hotkeys.Gear.Value:gmatch("%a")():lower()
	local sU,sD = info.Hotkeys.SpeedUp.Value:lower(),info.Hotkeys.SpeedDown.Value:lower()
	keys.spdup.byte = (sU == "arrowkeyup" and 17 or sU == "arrowkeydown" and 18 or sU:gmatch("%a")():byte())	-- Ternary operations use logical figures to avoid 'if' statements
	keys.spddwn.byte = (sD == "arrowkeyup" and 17 or sD == "arrowkeydown" and 18 or sD:gmatch("%a")():byte())
	fixVars()
	plane.Dead.Changed:connect(function()
		if ((plane.Dead.Value) and (not dead)) then	-- DIE!
			dead,flying,on = true,false,false
			main.Fire.Enabled,main.Smoke.Enabled = info.CanCrash.VisualFX.Value,info.CanCrash.VisualFX.Value
			move.maxForce = Vector3.new(0,0,0)
			gyro.D = 1e3
			while ((selected) and (not plane.Dead.Stop.Value)) do
				gyro.cframe = (gyro.cframe*CFrame.Angles(0,0,math.rad(crashSpin)))
				wait()
			end
		end
	end)
end

function getGear(parent)	-- Very common way to scan through every descendant of a model:
	for _,v in pairs(parent:GetChildren()) do
		if (v:IsA("BasePart")) then
			local t,r,c = Instance.new("NumberValue",v),Instance.new("NumberValue",v),Instance.new("BoolValue",v)	-- Saving original properties
			t.Name,r.Name,c.Name = "Trans","Ref","Collide"
			t.Value,r.Value,c.Value = v.Transparency,v.Reflectance,v.CanCollide
			table.insert(gearParts,v)
		end
		getGear(v)
	end
end

function getLowestPoint()	-- Plane will use LowestPoint to determine where to look to make sure the plane is either flying or on the ground
	if (#gearParts == 0) then
		lowestPoint = (main.Position.y+5+(main.Size.y/2))
		return
	end
	for _,v in pairs(gearParts) do	-- Not very efficient, but it basically does what I designed it to do:
		local _0 = (main.Position.y-(v.CFrame*CFrame.new((v.Size.x/2),0,0)).y)
		local _1 = (main.Position.y-(v.CFrame*CFrame.new(-(v.Size.x/2),0,0)).y)
		local _2 = (main.Position.y-(v.CFrame*CFrame.new(0,(v.Size.y/2),0)).y)
		local _3 = (main.Position.y-(v.CFrame*CFrame.new(0,-(v.Size.y/2),0)).y)
		local _4 = (main.Position.y-(v.CFrame*CFrame.new(0,0,(v.Size.z/2))).y)
		local _5 = (main.Position.y-(v.CFrame*CFrame.new(0,0,-(v.Size.z/2))).y)
		local n = (math.max(_0,_1,_2,_3,_4,_5)+5)
		lowestPoint = (n > lowestPoint and n or lowestPoint)
	end
end

function guiSetup()	-- Setting up the GUI buttons and such
	local cur = 0
	panel.Controls.Position = UDim2.new(0,0,0,-(panel.Controls.AbsolutePosition.y+panel.Controls.AbsoluteSize.y))
	panel.ControlsButton.MouseButton1Click:connect(function()
		cur = (cur == 0 and 1 or 0)
		if (cur == 0) then
			panel.Controls:TweenPosition(UDim2.new(0,0,0,-(panel.Controls.AbsolutePosition.y+panel.Controls.AbsoluteSize.y)),"In","Sine",0.35)
		else
			panel.Controls.Visible = true
			panel.Controls:TweenPosition(UDim2.new(0,0,1.5,0),"Out","Back",0.5)
		end
	end)
	panel.Controls.C1.Text = (keys.engine.key:upper() .. " Key")
	panel.Controls.C2.Text = (keys.spdup.byte == 17 and "UP Arrow Key" or keys.spdup.byte == 18 and "DOWN Arrow Key" or (string.char(keys.spdup.byte):upper() .. " Key"))
	panel.Controls.C3.Text = (keys.spddwn.byte == 17 and "UP Arrow Key" or keys.spddwn.byte == 18 and "DOWN Arrow Key" or (string.char(keys.spddwn.byte):upper() .. " Key"))
	panel.Controls.C4.Text = (keys.landing.key:upper() .. " Key")
end

waitFor(script.Parent,{"Plane","Deselect0","Deselect1","CurrentSelect"})
waitFor(script.Parent.Plane)
getVars()
getGear(landingGear)
getLowestPoint()
guiSetup()