CCCPaste

00e96fcbef542

--// services used in this script
local Players = game:GetService("Players") -- service for players
local UIS = game:GetService("UserInputService") -- service for input
local RS = game:GetService("RunService") -- service for heartbeat/renderstep
local TweenService = game:GetService("TweenService") -- service for tweens
local ReplicatedStorage = game:GetService("ReplicatedStorage") -- service for replicated data
local StarterGui = game:GetService("StarterGui") -- service for ui
local Debris = game:GetService("Debris") -- service for cleanup

--// player references
local player = Players.LocalPlayer -- variable for local player
repeat task.wait() until player.Character -- wait for character to exist
local character = player.Character -- variable for character
local humanoid = character:WaitForChild("Humanoid") -- variable for humanoid
local HRP = character:WaitForChild("HumanoidRootPart") -- variable for root part
if character.PrimaryPart.Name ~= "HumanoidRootPart" then -- check if primary part is not hrp
	character.PrimaryPart = HRP -- set hrp as primary part
end
local primaryP = character.PrimaryPart -- variable for primary part
local animator = humanoid:WaitForChild("Animator") -- variable for animator

--// required modules
local controlModule = require(player:WaitForChild("PlayerScripts"):WaitForChild("PlayerModule"):WaitForChild("ControlModule")) -- module for movement
local PlayerStats = require(ReplicatedStorage:WaitForChild("PlayerStats")) -- module for player stats

--// animations
local FlyIdle = script:WaitForChild("FlyIdle") -- idle animation asset
local FlyForward = script:WaitForChild("FlyForward") -- forward animation asset
local FlyLeft = script:WaitForChild("FlyLeft") -- left animation asset
local FlyRight = script:WaitForChild("FlyRight") -- right animation asset
local FlyBackward = script:WaitForChild("FlyBackward") -- backward animation asset

--// animation tracks
local IdleTrack = animator:LoadAnimation(FlyIdle) -- track for idle
local ForwardTrack = animator:LoadAnimation(FlyForward) -- track for forward

--// trails
local trailL = script:WaitForChild("leftTrail") -- left trail
local trailR = script:WaitForChild("rightTrail") -- right trail

--// constraints
local vector = script:WaitForChild("VectorForce") -- vector force
local align = script:WaitForChild("AlignOrientation") -- align orientation
vector.Attachment0 = primaryP.RootAttachment -- set attachment for vector
align.Attachment0 = primaryP.RootAttachment -- set attachment for align

--// camera
local camera = workspace.CurrentCamera -- variable for camera

--// ui
local UI = StarterGui:WaitForChild("Stamina") -- variable for stamina ui

--// fx + event
local FX = ReplicatedStorage.Effects:WaitForChild("FlightEffects") -- variable for flight effects
local event = ReplicatedStorage:WaitForChild("FlightEvent") -- variable for remote event

--// flight variables
local gravity = Vector3.new(0, workspace.Gravity, 0) -- vector for gravity
local IsFlying = false -- bool for flying state
local IsHyper = false -- bool for hyper state
local Flight = nil -- connection for heartbeat
local FOV = 120 -- target fov
local momentum = 5 -- momentum value
local drag = 0.7 -- drag constant
local force = PlayerStats.DefaultFlySpeed -- current fly speed
local stamina = 100 -- starting stamina
local maxStamina = PlayerStats.MaxStamina -- max stamina
local hyperSpeed = PlayerStats.MaxFlySpeed -- boosted fly speed
local canBoost = true -- bool for boost state
local IsADown = false -- bool for A key
local IsDDown = false -- bool for D key
local IsSDown = false -- bool for S key
local sidetrack -- variable for side animation track
local backtrack -- variable for back animation track

--// helper function: tween camera fov
local function tweenFOV(targetFOV, duration)
	local info = TweenInfo.new(duration or 0.4, Enum.EasingStyle.Back, Enum.EasingDirection.Out) -- tween info
	local goals = { FieldOfView = targetFOV } -- goal for fov
	local tween = TweenService:Create(camera, info, goals) -- create tween
	tween:Play() -- play tween
end

--// helper function: stop all flight animations
local function stopAllFlightAnimations()
	if IdleTrack then IdleTrack:Stop() end -- stop idle
	if ForwardTrack then ForwardTrack:Stop() end -- stop forward
	if sidetrack then sidetrack:Stop() end -- stop side
	if backtrack then backtrack:Stop() end -- stop back
end

--// helper function: reset boost
local function resetBoost()
	IsHyper = false -- set hyper to false
	force = 3000 -- reset force
	trailL.Enabled = false -- disable left trail
	trailR.Enabled = false -- disable right trail
end

--// helper function: play idle animation
local function playIdle()
	for _,v in pairs(animator:GetPlayingAnimationTracks()) do -- loop all tracks
		v:Stop() -- stop track
	end
	IdleTrack:Play() -- play idle
end

--// helper function: update stamina values
local function updateStamina()
	if IsHyper and canBoost and stamina > 0 then -- if boosting and has stamina
		stamina -= 0.25 -- drain stamina
		humanoid:SetAttribute("Stamina", stamina) -- update attribute
	elseif stamina < maxStamina and not IsHyper then -- if not boosting and not full
		stamina += 0.25 -- regen stamina
		humanoid:SetAttribute("Stamina", stamina) -- update attribute
	end
	if stamina == 0 then -- if stamina empty
		tweenFOV(70) -- reset fov
		resetBoost() -- reset boost state
		canBoost = false -- disable boosting
	end
	if not canBoost and stamina > 10 then -- if regen over threshold
		canBoost = true -- enable boost again
	end
end

--// helper function: calculate force vectors
local function calculateFlightForce()
	align.CFrame = camera.CFrame -- align with camera
	vector.Force = gravity * primaryP.AssemblyMass -- apply gravity

	local movevector = controlModule:GetMoveVector() -- get movement input
	local direction = camera.CFrame.RightVector * movevector.X + camera.CFrame.LookVector * (movevector.Z * -1) -- calculate direction
	if direction:Dot(direction) > 0 then -- if not zero
		direction = direction.Unit -- normalize direction
	end
	vector.Force += direction * force * primaryP.AssemblyMass -- apply directional force

	if primaryP.AssemblyLinearVelocity.Magnitude > 0 then -- if moving
		local dragVector = -primaryP.AssemblyLinearVelocity.Unit -- drag opposite velocity
		local v2 = primaryP.AssemblyLinearVelocity.Magnitude ^ 1.6 -- drag power
		vector.Force += dragVector * drag * primaryP.AssemblyMass * v2 -- apply drag
	end
end

--// helper function: handle animation switching
local function handleAnimationState()
	if humanoid.MoveDirection ~= Vector3.new() then -- if moving
		momentum = 5 -- reset momentum
		if not ForwardTrack.IsPlaying then -- if forward not playing
			IdleTrack:Stop() -- stop idle
			ForwardTrack:Play() -- play forward
		end
	else -- if idle
		momentum = 0 -- reset momentum
		if ForwardTrack.IsPlaying then -- if forward is playing
			ForwardTrack:Stop() -- stop forward
			IdleTrack:Play() -- play idle
		end
	end
end

--// helper function: start flying
local function startFlight()
	humanoid:SetAttribute("IsFlying", true) -- set attribute
	if humanoid.FloorMaterial ~= Enum.Material.Air then -- if grounded
		humanoid:ChangeState("Jumping") -- jump state
		event:FireServer("Jump") -- fire event
		task.wait(0.09) -- small delay
	end
	IsFlying = true -- set flying
	align.Enabled = true -- enable align
	vector.Enabled = true -- enable vector
	playIdle() -- play idle animation
	humanoid:ChangeState("Physics") -- physics state
	UI.Background.Visible = true -- show stamina ui
	Flight = RS.Heartbeat:Connect(function() -- connect heartbeat
		updateStamina() -- update stamina
		calculateFlightForce() -- calculate force
		handleAnimationState() -- handle animations
	end)
end

--// helper function: stop flying
local function stopFlight()
	humanoid:SetAttribute("IsFlying", false) -- set attribute
	vector.Enabled = false -- disable vector
	align.Enabled = false -- disable align
	humanoid:ChangeState("Freefall") -- set freefall
	if Flight then -- if connection exists
		Flight:Disconnect() -- disconnect
		Flight = nil -- reset connection
	end
	IsFlying = false -- set flying false
	stopAllFlightAnimations() -- stop animations
	if camera.FieldOfView == FOV then -- if boosted fov
		tweenFOV(70) -- reset fov
	end
end

--// input: toggle flight
UIS.InputBegan:Connect(function(input, typing)
	if typing then return end -- ignore typing
	if input.KeyCode == Enum.KeyCode.Q then -- q pressed
		if IsFlying then -- if already flying
			stopFlight() -- stop
		else -- else not flying
			startFlight() -- start
		end
	end
end)

--// input: boost
UIS.InputBegan:Connect(function(input, typing)
	if typing then return end -- ignore typing
	if input.KeyCode == Enum.KeyCode.Space and IsFlying and canBoost and stamina > 0 then -- space pressed
		if humanoid.MoveDirection ~= Vector3.new() then -- if moving
			event:FireServer("Boost") -- fire boost event
			tweenFOV(FOV) -- tween fov
			trailL.Enabled = true -- enable left trail
			trailR.Enabled = true -- enable right trail
		else -- if not moving
			tweenFOV(70) -- reset fov
			trailL.Enabled = false -- disable left trail
			trailR.Enabled = false -- disable right trail
		end
		IsHyper = true -- set hyper
		force = hyperSpeed -- set hyper speed
	end
end)

--// input: stop boost
UIS.InputEnded:Connect(function(input, typing)
	if typing then return end -- ignore typing
	if input.KeyCode == Enum.KeyCode.Space and IsFlying then -- space released
		tweenFOV(70) -- reset fov
		resetBoost() -- reset boost
	end
end)

--// input: left / right animations
UIS.InputBegan:Connect(function(input, typing)
	if typing then return end -- ignore typing
	if input.KeyCode == Enum.KeyCode.A and IsFlying then -- a pressed
		IsADown = true -- set a down
		if sidetrack then sidetrack:Stop() end -- stop current side
		if ForwardTrack.IsPlaying then ForwardTrack:Stop() end -- stop forward
		if IsSDown and backtrack then backtrack:Stop() end -- stop back if s pressed
		sidetrack = animator:LoadAnimation(FlyLeft) -- load left
		sidetrack:Play() -- play left
	elseif input.KeyCode == Enum.KeyCode.D and IsFlying then -- d pressed
		IsDDown = true -- set d down
		if sidetrack then sidetrack:Stop() end -- stop current side
		if ForwardTrack.IsPlaying then ForwardTrack:Stop() end -- stop forward
		if IsSDown and backtrack then backtrack:Stop() end -- stop back if s pressed
		sidetrack = animator:LoadAnimation(FlyRight) -- load right
		sidetrack:Play() -- play right
	end
end)

UIS.InputEnded:Connect(function(input, typing)
	if typing then return end -- ignore typing
	if input.KeyCode == Enum.KeyCode.A and IsFlying then -- a released
		IsADown = false -- set a false
		if sidetrack then sidetrack:Stop() end -- stop side
		if IsDDown then -- if d down
			sidetrack = animator:LoadAnimation(FlyRight) -- load right
			sidetrack:Play() -- play right
		end
	end
	if input.KeyCode == Enum.KeyCode.D and IsFlying then -- d released
		IsDDown = false -- set d false
		if sidetrack then sidetrack:Stop() end -- stop side
		if IsADown then -- if a down
			sidetrack = animator:LoadAnimation(FlyLeft) -- load left
			sidetrack:Play() -- play left
		end
	end
end)

--// input: backward animation
UIS.InputBegan:Connect(function(input, typing)
	if typing then return end -- ignore typing
	if input.KeyCode == Enum.KeyCode.S and IsFlying then -- s pressed
		IsSDown = true -- set s down
		backtrack = animator:LoadAnimation(FlyBackward) -- load backward
		backtrack:Play() -- play backward
	end
end)

UIS.InputEnded:Connect(function(input, typing)
	if typing then return end -- ignore typing
	if input.KeyCode == Enum.KeyCode.S and IsFlying then -- s released
		IsSDown = false -- set s false
		if backtrack then backtrack:Stop() end -- stop back
		backtrack = nil -- clear backtrack
	end
end)

--// event: effects
event.OnClientEvent:Connect(function(character, effect)
	if effect == "Jump" then -- if jump effect
		local jump = FX:WaitForChild("Jump"):Clone() -- clone jump fx
		jump.Parent = workspace.Effects -- parent to workspace
		jump.Position = HRP.Position - Vector3.new(0,3.75,0) -- set position
		local info = TweenInfo.new(0.4, Enum.EasingStyle.Quart, Enum.EasingDirection.Out) -- tween info
		local goals = { Size = jump.Size + Vector3.new(25,0,25), Transparency = 1 } -- tween goals
		local tween = TweenService:Create(jump, info, goals) -- create tween
		tween:Play() -- play tween
		Debris:AddItem(jump, 0.4) -- cleanup
	end
end)