local function d(d)local l=Instance.new("\073\109\097\103\101\076\097\098\101\108")l.Image=d l.BackgroundTransparency=1 l.Size=UDim2.new(0,100,0,100)return l end local l={}l.__index=l function l.setOnDisabled(l,d)l.onDisabled=d end function l.new()local R=setmetatable({},l)R.enabled=false R.enabledTime=0 R.straightDive=false R.character=nil R.humanoid=nil R.humanoidRootPart=nil R.autoDeploy=true R.onlyAutoDeployOnce=true R.waitingForJump=false R.didJump=false R.Jumped=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")R.freefallAnimation=nil R.fallAnimationAsset=Instance.new("\065\110\105\109\097\116\105\111\110")R.fallAnimationAsset.AnimationId="\114\098\120\097\115\115\101\116\105\100\058\047\047\054\049\054\048\056\055\048\056\057"R.onClientEventConn=nil local z=localPlayer.Character if z then R:onCharacterAdded(z)end localPlayer.CharacterAdded:Connect(function(d)R:onCharacterAdded(d)end)if l.ActionPromptGui then local z={keyboard=d("\114\098\120\097\115\115\101\116\105\100\058\047\047\050\048\051\050\049\050\055\057\048\055"),gamepad=d("\114\098\120\097\115\115\101\116\105\100\058\047\047\050\048\051\050\052\051\056\057\051\053"),touch=d("\114\098\120\097\115\115\101\116\105\100\058\047\047\051\056\054\057\051\057\052\057\056\052")}R.actionPromptGui=l.ActionPromptGui.new("","\084\111 \083\107\121\100\105\118\101",z)end return R end function l.createContrail(l,d)local R=BeamTemplate:Clone()R.Name=d.Name R.BeamHolder.Position=d.Position R.BeamPart.Position=d.Position R.WeldConstraint.Part1=d R.BeamPart.HeightBodyPosition.Position=d.Position+Vector3.new(0,30,0)R.Parent=l.character return R end function l.setupContrails(d)if not d.humanoidRootPart then return end d.LeftFootBeam=d:createContrail(d.character:WaitForChild("\076\101\102\116\070\111\111\116"))d.RightFootBeam=d:createContrail(d.character:WaitForChild("\082\105\103\104\116\070\111\111\116"))d.LeftHandBeam=d:createContrail(d.character:WaitForChild("\076\101\102\116\072\097\110\100"))d.RightHandBeam=d:createContrail(d.character:WaitForChild("\082\105\103\104\116\072\097\110\100"))end function l.destroyContrails(d)if d.LeftFootBeam then d.LeftFootBeam:Destroy()d.LeftFootBeam=nil end if d.RightFootBeam then d.RightFootBeam:Destroy()d.RightFootBeam=nil end if d.LeftHandBeam then d.LeftHandBeam:Destroy()d.LeftHandBeam=nil end if d.RightHandBeam then d.RightHandBeam:Destroy()d.RightHandBeam=nil end end function l.disableContrails(d)d.LeftFootBeam.Beam.Enabled=false d.RightFootBeam.Beam.Enabled=false d.LeftHandBeam.Beam.Enabled=false d.RightHandBeam.Beam.Enabled=false end function l.enableContrails(d)d.LeftFootBeam.Beam.Enabled=true d.RightFootBeam.Beam.Enabled=true d.LeftHandBeam.Beam.Enabled=true d.RightHandBeam.Beam.Enabled=true end function l.updateContrails(d)local l=(d.character:WaitForChild("\076\101\102\116\070\111\111\116")).Position local R=(d.character:WaitForChild("\082\105\103\104\116\070\111\111\116")).Position local z=(d.character:WaitForChild("\076\101\102\116\072\097\110\100")).Position local Q=(d.character:WaitForChild("\082\105\103\104\116\072\097\110\100")).Position d.LeftFootBeam.BeamPart.HeightBodyPosition.Position=l+Vector3.new(0,30,0)d.RightFootBeam.BeamPart.HeightBodyPosition.Position=R+Vector3.new(0,30,0)d.LeftHandBeam.BeamPart.HeightBodyPosition.Position=z+Vector3.new(0,30,0)d.RightHandBeam.BeamPart.HeightBodyPosition.Position=Q+Vector3.new(0,30,0)d.LeftFootBeam.BeamPart.XZBodyPosition.Position=l+d.character.LeftFoot.CFrame.RightVector*Vector3.new(-5,0,-7)d.RightFootBeam.BeamPart.XZBodyPosition.Position=R+d.character.RightFoot.CFrame.RightVector*Vector3.new(5,0,7)d.LeftHandBeam.BeamPart.XZBodyPosition.Position=z+d.character.LeftHand.CFrame.RightVector*Vector3.new(-7,0,-5)d.RightHandBeam.BeamPart.XZBodyPosition.Position=Q+d.character.RightHand.CFrame.RightVector*Vector3.new(7,0,5)end function l.setWaitingForJump(l,d)if d==l.waitingForJump then return end l.waitingForJump=d if l.waitingForJump then ContextActionService:BindActionAtPriority("\069\120\105\116\068\101\108\105\118\101\114\121\086\101\104\105\099\108\101",function(...)l:onJumpAction(...)end,false,1000000,Enum.KeyCode.Space,Enum.KeyCode.ButtonA,Enum.UserInputType.Touch)if l.actionPromptGui then l.actionPromptGui:setVisible(true)end else ContextActionService:UnbindAction("\069\120\105\116\068\101\108\105\118\101\114\121\086\101\104\105\099\108\101")if l.actionPromptGui then l.actionPromptGui:setVisible(false)end end end function l.waitForJumped(d)if not d.didJump then d.Jumped.Event:Wait()end end function l.setEnabled(l,d)if d==l.enabled then return end l.enabled=d if d then l.enabledTime=tick()if l.humanoid then l.humanoid:ChangeState(Enum.HumanoidStateType.Physics)local d=l.humanoid:GetPlayingAnimationTracks()for d,l in pairs(d)do l:Stop()end end if l.character and l.humanoidRootPart then l:setupSkydivingForCharacter()end RunService:BindToRenderStep("\083\107\121\100\105\118\101\114\085\112\100\097\116\101",Enum.RenderPriority.Last.Value,function(d)l:onUpdate(d)end)else if l.onlyAutoDeployOnce then l.autoDeploy=false end if l.freefallAnimation then l.freefallAnimation:Stop()l.freefallAnimation:Destroy()l.freefallAnimation=nil end if l.PitchAttachment then l.PitchAttachment:Destroy()l.PitchAttachment=nil end if l.RootRigAttachment then l.RootRigAttachment:Destroy()l.RootRigAttachment=nil end if l.SkydivePart then l.SkydivePart:Destroy()l.SkydivePart=nil end if l.BodyVelocity then l.BodyVelocity:Destroy()l.BodyVelocity=nil end if l.humanoid then l.humanoid:ChangeState(Enum.HumanoidStateType.Running)end if l.onClientEventConn then l.onClientEventConn:Disconnect()l.onClientEventConn=nil end l:destroyContrails()if l.onDisabled then l:onDisabled()end RunService:UnbindFromRenderStep("\083\107\121\100\105\118\101\114\085\112\100\097\116\101")end end function l.onCharacterAdded(l,d)l.character=d l.humanoid=l.character:WaitForChild("\072\117\109\097\110\111\105\100")l.humanoidRootPart=l.character:WaitForChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")if l.enabled then l:setupSkydivingForCharacter()end l.onClientEventConn=EventData.OnClientEvent:Connect(function(d)if d=="\069\120\105\116\101\100\068\101\108\105\118\101\114\121\086\101\104\105\099\108\101"then if not l.didJump then l:setWaitingForJump(false)l.didJump=true l.Jumped:Fire()end end end)end function l.setupSkydivingForCharacter(d)if not d.humanoidRootPart then return end if d.humanoid and not d.freefallAnimation then d.freefallAnimation=d.humanoid:LoadAnimation(d.fallAnimationAsset)d.freefallAnimation.Looped=true d.freefallAnimation.Priority=Enum.AnimationPriority.Action d.freefallAnimation:Play()end if not d.PitchAttachment then d.PitchAttachment=Instance.new("\065\116\116\097\099\104\109\101\110\116")d.PitchAttachment.Orientation=Vector3.new(0,-90,0)d.PitchAttachment.Position=Vector3.new(0,-0.35,0)d.PitchAttachment.Axis=Vector3.new(0,0,1)d.PitchAttachment.SecondaryAxis=Vector3.new(0,1,0)d.PitchAttachment.Parent=d.humanoidRootPart end if not d.RootRigAttachment then d.RootRigAttachment=Instance.new("\065\116\116\097\099\104\109\101\110\116")d.RootRigAttachment.Orientation=Vector3.new(0,0,0)d.RootRigAttachment.Position=Vector3.new(0,-0.35,0)d.RootRigAttachment.Axis=Vector3.new(1,0,0)d.RootRigAttachment.SecondaryAxis=Vector3.new(0,1,0)d.RootRigAttachment.Parent=d.humanoidRootPart end if not d.SkydivePart then d.SkydivePart=SkydivePartTemplate:Clone()d.SkydivePart.PitchAndRollOrientation.Attachment1=d.PitchAttachment d.SkydivePart.YawOrientation.Attachment0=d.RootRigAttachment d.SkydivePart.Parent=workspace end if not d.BodyVelocity then d.BodyVelocity=Instance.new("\066\111\100\121\086\101\108\111\099\105\116\121")d.BodyVelocity.P=6000 d.BodyVelocity.MaxForce=Vector3.new(1000,2000,1000)d.BodyVelocity.Parent=d.humanoidRootPart end d:setupContrails()end function l.doJump(d)if not d.waitingForJump then return end EventData:FireServer("\069\120\105\116\068\101\108\105\118\101\114\121\086\101\104\105\099\108\101")end function l.onJumpAction(R,d,l)if l==Enum.UserInputState.Begin then R:doJump()end end function l.getAltitudeAboveGround(d)if not d.humanoidRootPart then return 0 end debug.profilebegin("\103\101\116\065\108\116\105\116\117\100\101\065\098\111\118\101\071\114\111\117\110\100")local l={workspace.CurrentCamera;d.SkydivePart;workspace:FindFirstChild("\068\101\108\105\118\101\114\121\086\101\104\105\099\108\101"..tostring(PlayerMatchInfo.GetField(localPlayer,"\116\101\097\109\078\117\109\098\101\114")))}for d,R in pairs(Players:GetPlayers())do if R.Character then table.insert(l,R.Character)end end local R=Ray.new(d.humanoidRootPart.Position,Vector3.new(0,-ALTITUDE_TEST_LENGTH,0))local z,Q=workspace:FindPartOnRayWithIgnoreList(R,l,false,false)debug.profileend()if not z then return ALTITUDE_TEST_LENGTH else return math.abs(R.Origin.Y-Q.Y)end end function l.onUpdate(l,d)if not l.enabled then return end local R=tick()-l.enabledTime local z=l:getAltitudeAboveGround()if z<DISABLE_ALTITUDE and(l.enabledTime~=0 and R>.5)then l:setEnabled(false)return end if not l.humanoidRootPart or not l.humanoid then return end local Q=FALLING_PITCH_RANGE local e=0 local o=FALLING_ROLL_RANGE local Z=.3 local B=workspace.CurrentCamera.CFrame local O=l.humanoid.MoveDirection local G=B:vectorToObjectSpace(O)local v=B.lookVector local K=math.atan2(-v.X,-v.Z)local a=math.asin(v.Y)l.straightDive=v.Y<-0.95 and-G.Z>.1 local f=(Z*a+Q*G.Z)+e local Y=o*-G.X local I=((CFrame.new(l.humanoidRootPart.Position)*CFrame.Angles(0,K,0))*CFrame.Angles(l.straightDive and DIVE_PITCH or f,0,0))*CFrame.Angles(0,0,Y)l.SkydivePart.CFrame=I local A=Vector3.new(O.x,0,O.z)local U=Vector3.new(v.x,0,v.z)local N=A:Dot(U)local c=Vector3.new(0,1,0)local D=(((((A.x*U.y)*c.z+(U.x*c.y)*A.z)+(c.x*A.y)*U.z)-(A.z*U.y)*c.x)-(U.z*c.y)*A.x)-(c.z*A.y)*U.x local q=math.atan2(D,N)+math.pi/2 local s=XZ_VELOCITY if q<-math.pi*.05 or q>math.pi*1.05 then s=s*.3 end local X=FREEFALL_VELOCITY if l.straightDive then X=DIVE_VELOCITY end l.BodyVelocity.Velocity=Vector3.new(A.x*s,X,A.z*s)l:updateContrails()end return l

local function createIndicatorImage(imageId)
	local image = Instance.new("ImageLabel")
	image.Image = imageId
	image.BackgroundTransparency = 1
	image.Size = UDim2.new(0, 100, 0, 100)
	return image
end

local Skydiver = {}
Skydiver.__index = Skydiver

function Skydiver:setOnDisabled(cb)
	self.onDisabled = cb
end

function Skydiver.new()
	local self = setmetatable({}, Skydiver)

	self.enabled = false
	self.enabledTime = 0

	self.straightDive = false

	self.character = nil
	self.humanoid = nil
	self.humanoidRootPart = nil

	self.autoDeploy = true
	self.onlyAutoDeployOnce = true

	self.waitingForJump = false
	self.didJump = false
	self.Jumped = Instance.new("BindableEvent")

	self.freefallAnimation = nil
	self.fallAnimationAsset = Instance.new("Animation")
	self.fallAnimationAsset.AnimationId = "rbxassetid://616087089"

	self.onClientEventConn = nil

	--[[
		Character management
	]]

	local character = localPlayer.Character
	if character then
		self:onCharacterAdded(character)
	end

	localPlayer.CharacterAdded:Connect(function(char)
		self:onCharacterAdded(char)
	end)

	--[[
		User Interface
	]]

	-- The skydiver prompt is an optional dependency.
	-- Only create a skydiver prompt if the depedency was provided.
	if Skydiver.ActionPromptGui then
		local actionPromptImages = {
			keyboard = createIndicatorImage("rbxassetid://2032127907"),
			gamepad = createIndicatorImage("rbxassetid://2032438935"),
			touch = createIndicatorImage("rbxassetid://3869394984"),
		}

		self.actionPromptGui = Skydiver.ActionPromptGui.new("", "To Skydive", actionPromptImages)
	end

	return self
end

function Skydiver:createContrail(part)
	local contrail = BeamTemplate:Clone()
	contrail.Name = part.Name
	contrail.BeamHolder.Position = part.Position
	contrail.BeamPart.Position = part.Position
	contrail.WeldConstraint.Part1 = part
	contrail.BeamPart.HeightBodyPosition.Position = part.Position + Vector3.new(0,30,0)
	contrail.Parent = self.character
	return contrail
end

function Skydiver:setupContrails()
	if not self.humanoidRootPart then return end

	self.LeftFootBeam = self:createContrail(self.character:WaitForChild("LeftFoot"))
	self.RightFootBeam = self:createContrail(self.character:WaitForChild("RightFoot"))
	self.LeftHandBeam = self:createContrail(self.character:WaitForChild("LeftHand"))
	self.RightHandBeam = self:createContrail(self.character:WaitForChild("RightHand"))
end

function Skydiver:destroyContrails()
	if self.LeftFootBeam then
		self.LeftFootBeam:Destroy()
		self.LeftFootBeam = nil
	end
	if self.RightFootBeam then
		self.RightFootBeam:Destroy()
		self.RightFootBeam = nil
	end
	if self.LeftHandBeam then
		self.LeftHandBeam:Destroy()
		self.LeftHandBeam = nil
	end
	if self.RightHandBeam then
		self.RightHandBeam:Destroy()
		self.RightHandBeam = nil
	end
end

function Skydiver:disableContrails()
	self.LeftFootBeam.Beam.Enabled = false
	self.RightFootBeam.Beam.Enabled = false
	self.LeftHandBeam.Beam.Enabled = false
	self.RightHandBeam.Beam.Enabled = false
end

function Skydiver:enableContrails()
	self.LeftFootBeam.Beam.Enabled = true
	self.RightFootBeam.Beam.Enabled = true
	self.LeftHandBeam.Beam.Enabled = true
	self.RightHandBeam.Beam.Enabled = true
end

function Skydiver:updateContrails()
	local leftFootPos = self.character:WaitForChild("LeftFoot").Position
	local rightFootPos = self.character:WaitForChild("RightFoot").Position
	local leftHandPos = self.character:WaitForChild("LeftHand").Position
	local rightHandPos = self.character:WaitForChild("RightHand").Position

	self.LeftFootBeam.BeamPart.HeightBodyPosition.Position = leftFootPos + Vector3.new(0,30,0)
	self.RightFootBeam.BeamPart.HeightBodyPosition.Position = rightFootPos + Vector3.new(0,30,0)
	self.LeftHandBeam.BeamPart.HeightBodyPosition.Position = leftHandPos + Vector3.new(0,30,0)
	self.RightHandBeam.BeamPart.HeightBodyPosition.Position = rightHandPos + Vector3.new(0,30,0)

	self.LeftFootBeam.BeamPart.XZBodyPosition.Position = leftFootPos + (self.character.LeftFoot.CFrame.RightVector * Vector3.new(-5,0,-7))
	self.RightFootBeam.BeamPart.XZBodyPosition.Position = rightFootPos + (self.character.RightFoot.CFrame.RightVector  * Vector3.new(5,0,7))
	self.LeftHandBeam.BeamPart.XZBodyPosition.Position = leftHandPos + (self.character.LeftHand.CFrame.RightVector * Vector3.new(-7,0,-5))
	self.RightHandBeam.BeamPart.XZBodyPosition.Position = rightHandPos + (self.character.RightHand.CFrame.RightVector * Vector3.new(7,0,5))
end

function Skydiver:setWaitingForJump(waiting)
	if waiting == self.waitingForJump then
		return
	end
	self.waitingForJump = waiting

	if self.waitingForJump then
		ContextActionService:BindActionAtPriority("ExitDeliveryVehicle", function(...) self:onJumpAction(...) end, false, 1000000, Enum.KeyCode.Space, Enum.KeyCode.ButtonA, Enum.UserInputType.Touch)

		if self.actionPromptGui then
			self.actionPromptGui:setVisible(true)
		end
	else
		ContextActionService:UnbindAction("ExitDeliveryVehicle")

		if self.actionPromptGui then
			self.actionPromptGui:setVisible(false)
		end
	end
end

function Skydiver:waitForJumped()
	if not self.didJump then
		self.Jumped.Event:Wait()
	end
end

function Skydiver:setEnabled(enabled)
	if enabled == self.enabled then
		return
	end
	self.enabled = enabled
	if enabled then
		self.enabledTime = tick()

		if self.humanoid then -- make sure player is in correct state to start skydiving
			self.humanoid:ChangeState(Enum.HumanoidStateType.Physics)
			local activeTracks = self.humanoid:GetPlayingAnimationTracks() -- stop any previous animations
			for i, v in pairs(activeTracks) do
				v:Stop()
			end
		end

		if self.character and self.humanoidRootPart then
			self:setupSkydivingForCharacter()
		end

		RunService:BindToRenderStep("SkydiverUpdate", Enum.RenderPriority.Last.Value, function(dt) self:onUpdate(dt) end)
	else
		if self.onlyAutoDeployOnce then
			self.autoDeploy = false
		end

		if self.freefallAnimation then
			self.freefallAnimation:Stop()
			self.freefallAnimation:Destroy()
			self.freefallAnimation = nil
		end

		if self.PitchAttachment then
			self.PitchAttachment:Destroy()
			self.PitchAttachment = nil
		end

		if self.RootRigAttachment then
			self.RootRigAttachment:Destroy()
			self.RootRigAttachment = nil
		end

		if self.SkydivePart then
			self.SkydivePart:Destroy()
			self.SkydivePart = nil
		end

		if self.BodyVelocity then
			self.BodyVelocity:Destroy()
			self.BodyVelocity = nil
		end

		if self.humanoid then
			self.humanoid:ChangeState(Enum.HumanoidStateType.Running)
		end

		if self.onClientEventConn then
			self.onClientEventConn:Disconnect()
			self.onClientEventConn = nil
		end

		self:destroyContrails()

		if self.onDisabled then
			self:onDisabled()
		end

		RunService:UnbindFromRenderStep("SkydiverUpdate")
	end
end

function Skydiver:onCharacterAdded(character)
	self.character = character

	self.humanoid = self.character:WaitForChild("Humanoid")
	self.humanoidRootPart = self.character:WaitForChild("HumanoidRootPart")

	if self.enabled then
		self:setupSkydivingForCharacter()
	end

	self.onClientEventConn = EventData.OnClientEvent:Connect(function(cmd)
		if cmd == "ExitedDeliveryVehicle" then
			if not self.didJump then
				self:setWaitingForJump(false)
				self.didJump = true
				self.Jumped:Fire()
			end
		end
	end)
end

function Skydiver:setupSkydivingForCharacter()
	if not self.humanoidRootPart then
		return
	end

	if self.humanoid and not self.freefallAnimation then
		self.freefallAnimation = self.humanoid:LoadAnimation(self.fallAnimationAsset)
		self.freefallAnimation.Looped = true
		self.freefallAnimation.Priority = Enum.AnimationPriority.Action
		self.freefallAnimation:Play()
	end

	if not self.PitchAttachment then
		self.PitchAttachment = Instance.new("Attachment")
		self.PitchAttachment.Orientation = Vector3.new(0,-90,0)
		self.PitchAttachment.Position = Vector3.new(0,-0.35,0)
		self.PitchAttachment.Axis = Vector3.new(0,0,1)
		self.PitchAttachment.SecondaryAxis = Vector3.new(0,1,0)
		self.PitchAttachment.Parent = self.humanoidRootPart
	end

	if not self.RootRigAttachment then
		self.RootRigAttachment = Instance.new("Attachment")
		self.RootRigAttachment.Orientation = Vector3.new(0,0,0)
		self.RootRigAttachment.Position = Vector3.new(0,-0.35,0)
		self.RootRigAttachment.Axis = Vector3.new(1,0,0)
		self.RootRigAttachment.SecondaryAxis = Vector3.new(0,1,0)
		self.RootRigAttachment.Parent = self.humanoidRootPart
	end

	if not self.SkydivePart then
		self.SkydivePart = SkydivePartTemplate:Clone()
		self.SkydivePart.PitchAndRollOrientation.Attachment1 = self.PitchAttachment
		self.SkydivePart.YawOrientation.Attachment0 = self.RootRigAttachment
		self.SkydivePart.Parent = workspace
	end

	if not self.BodyVelocity then
		self.BodyVelocity = Instance.new("BodyVelocity")
		self.BodyVelocity.P = 6000
		self.BodyVelocity.MaxForce = Vector3.new(1000,2000,1000)
		self.BodyVelocity.Parent = self.humanoidRootPart
	end

	self:setupContrails()
end

function Skydiver:doJump()
	if not self.waitingForJump then
		return
	end

	EventData:FireServer("ExitDeliveryVehicle")
end

function Skydiver:onJumpAction(actionName, inputState)
	if inputState == Enum.UserInputState.Begin then
		self:doJump()
	end
end

function Skydiver:getAltitudeAboveGround()
	if not self.humanoidRootPart then
		return 0
	end

	debug.profilebegin("getAltitudeAboveGround")
	local ignoreList = {
		workspace.CurrentCamera,
		self.SkydivePart,
		workspace:FindFirstChild("DeliveryVehicle" .. tostring(PlayerMatchInfo.GetField(localPlayer, "teamNumber")))
	}
	for _, player in pairs(Players:GetPlayers()) do
		if player.Character then
			table.insert(ignoreList, player.Character)
		end
	end

	local rayDown = Ray.new(self.humanoidRootPart.Position, Vector3.new(0, -ALTITUDE_TEST_LENGTH, 0))
	local hitObject, hitPoint = workspace:FindPartOnRayWithIgnoreList(rayDown, ignoreList, false, false)
	debug.profileend()
	if not hitObject then
		return ALTITUDE_TEST_LENGTH
	else
		return math.abs(rayDown.Origin.Y - hitPoint.Y)
	end
end

function Skydiver:onUpdate(dt)
	if not self.enabled then
		return
	end

	local timeSinceEnabled = tick() - self.enabledTime
	local altitude = self:getAltitudeAboveGround()

	if altitude < DISABLE_ALTITUDE and self.enabledTime ~= 0 and timeSinceEnabled > 0.5 then
		self:setEnabled(false)
		return
	end

	if not self.humanoidRootPart or not self.humanoid then return end

	local pitchRange = FALLING_PITCH_RANGE
	local pitchOffset = 0
	local rollRange = FALLING_ROLL_RANGE
	local cameraPitchContribution = 0.3

	local cameraCFrame = workspace.CurrentCamera.CFrame
	local globalMoveVector = self.humanoid.MoveDirection
	local relativeMoveVector = cameraCFrame:vectorToObjectSpace(globalMoveVector)

	local cameraLook = cameraCFrame.lookVector
	local cameraYaw = math.atan2(-cameraLook.X, -cameraLook.Z)
	local cameraPitch = math.asin(cameraLook.Y)

	self.straightDive = cameraLook.Y < -0.95 and -relativeMoveVector.Z > 0.1

	local desiredPitch = (cameraPitchContribution * cameraPitch) + (pitchRange * relativeMoveVector.Z) + pitchOffset
	local desiredRoll = (rollRange * -relativeMoveVector.X)
	local targetCFrame = CFrame.new(self.humanoidRootPart.Position) *
							CFrame.Angles(0, cameraYaw, 0) *
							CFrame.Angles(self.straightDive and DIVE_PITCH or desiredPitch, 0, 0) *
							CFrame.Angles(0, 0, desiredRoll)

	self.SkydivePart.CFrame = targetCFrame

	local globalForce = Vector3.new(globalMoveVector.x, 0, globalMoveVector.z)
	local cameraLookXZ = Vector3.new(cameraLook.x, 0, cameraLook.z)

	local dot = globalForce:Dot(cameraLookXZ)
	local planeNormal = Vector3.new(0,1,0)
	local det = globalForce.x*cameraLookXZ.y*planeNormal.z + cameraLookXZ.x*planeNormal.y*globalForce.z + planeNormal.x*globalForce.y*cameraLookXZ.z -
				globalForce.z*cameraLookXZ.y*planeNormal.x - cameraLookXZ.z*planeNormal.y*globalForce.x - planeNormal.z*globalForce.y*cameraLookXZ.x
	local angle = math.atan2(det,dot) + math.pi/2

	local XZVelocity = XZ_VELOCITY

	-- do not apply too much force when moving backwards
	if angle < -math.pi * 0.05 or angle > math.pi * 1.05 then
		XZVelocity = XZVelocity * 0.3
	end

	local yVelocity = FREEFALL_VELOCITY
	if self.straightDive then
		yVelocity = DIVE_VELOCITY
	end

	self.BodyVelocity.Velocity = Vector3.new(globalForce.x * XZVelocity, yVelocity, globalForce.z * XZVelocity)
	self:updateContrails()
end

return Skydiver
