local StaminaManager = require(script.Parent:WaitForChild("StaminaModule"))

local defaultSpeed = 16
local sprintSpeed = 22
local normalFov = 70
local sprintFov = 80
local crouchFov = 65
local crouchSpeed = 8
local staminaDrainRate = 17

local Settings = {
	Lifetime = 0.15,
	DashVelocity = 55,
	Cooldown = 3,
	DashStaminaCost = 20,
	JumpCooldown = 1.1
}

local Services = setmetatable({}, {
	__index = function(Self, Index)
		local NewService = game:GetService(Index)
		if NewService then
			Self[Index] = NewService
		end
		return NewService
	end
})

local UserInputService = Services.UserInputService
local TweenService = Services.TweenService
local RunService = Services.RunService
local Players = Services.Players
local ReplicatedStorage = Services.ReplicatedStorage

local sprintKey = Enum.KeyCode.LeftShift
local crouchKey = Enum.KeyCode.C
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local Camera = workspace.CurrentCamera
local healthBar = Player:WaitForChild("PlayerGui"):WaitForChild("StaminaAndHealthBar"):WaitForChild("Frame"):WaitForChild("HealthBar"):WaitForChild("Bar")
local staminaBar = Player:WaitForChild("PlayerGui"):WaitForChild("StaminaAndHealthBar"):WaitForChild("Frame"):WaitForChild("StaminaBar"):WaitForChild("Bar")

local sprintAnim = ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("SprintAnim")
local animTrack = Humanoid:LoadAnimation(sprintAnim)
local movementKeys = {Enum.KeyCode.W, Enum.KeyCode.A, Enum.KeyCode.S, Enum.KeyCode.D}
local movementKeysPressed = {}
local shiftPressed, sprinting, isCrouching, isMoving, isSliding = false, false, false, false, false
local canJump = true

local Animations = {
	Forward = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("FrontDash")),
	Backward = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("BackDash")),
	Left = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("LeftDash")),
	Right = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("RightDash")),
}
local BV = Instance.new("BodyVelocity")

local function tweenFov(duration, fov)
	local tween = TweenService:Create(Camera, TweenInfo.new(duration, Enum.EasingStyle.Quad), { FieldOfView = fov })
	tween:Play()
	tween.Completed:Wait()
	tween:Destroy()
end

local function updateStaminaBar()
	local stamina = StaminaManager.GetStamina()
	local tween = TweenService:Create(staminaBar, TweenInfo.new(0.25, Enum.EasingStyle.Quad), { Size = UDim2.new(stamina / StaminaManager.maxStamina, 0, 1, 0) })
	tween:Play()
end

local function startSprinting()
	if not sprinting and StaminaManager.GetStamina() > 0 and not isCrouching then
		sprinting = true
		StaminaManager.ReduceStamina(staminaDrainRate * RunService.RenderStepped:Wait())
		Humanoid.WalkSpeed = sprintSpeed
		if Humanoid:GetState() ~= Enum.HumanoidStateType.Freefall then
			animTrack:Play()
		end
		tweenFov(0.25, sprintFov)
		updateStaminaBar()
	end
end

local function stopSprinting()
	if sprinting then
		sprinting = false
		Humanoid.WalkSpeed = defaultSpeed
		animTrack:Stop()
		tweenFov(0.25, normalFov)
		updateStaminaBar()
	end
end

local function crouch()
	if not isCrouching and not sprinting then
		if animTrack.IsPlaying then animTrack:Stop() end
		isCrouching, Humanoid.WalkSpeed = true, crouchSpeed
		tweenFov(0.25, crouchFov)
	end
end

local function stand()
	if isCrouching then
		isCrouching, Humanoid.WalkSpeed = false, defaultSpeed
		tweenFov(0.25, normalFov)
	end
end


local function startSliding()
	print("SLIDE TIME")
end


Character.Humanoid:GetPropertyChangedSignal("Health"):Connect(function()
	healthBar.Size = UDim2.new(Humanoid.Health / Humanoid.MaxHealth, 0, 1, 0)
end)

local function dash()
	local Now, DashCooldown = workspace:GetServerTimeNow(), Character:GetAttribute("DashCooldown") or 0
	if DashCooldown > Now or StaminaManager.GetStamina() < Settings.DashStaminaCost then return end

	Character:SetAttribute("DashCooldown", Now + Settings.Cooldown)
	StaminaManager.ReduceStamina(Settings.DashStaminaCost)

	local NewBV = BV:Clone()
	NewBV.MaxForce, NewBV.P = Vector3.new(1e5, 1e5, 1e5), 1250
	local Direction = Humanoid.MoveDirection.Magnitude > 0 and Humanoid.MoveDirection or HumanoidRootPart.CFrame.LookVector
	local RelativeDirection = (CFrame.lookAt(Camera.CFrame.LookVector, Camera.CFrame.LookVector + Direction)).LookVector
	local currentYVelocity = HumanoidRootPart.Velocity.Y / 2
	NewBV.Velocity = Vector3.new(RelativeDirection.X, 0, RelativeDirection.Z) * Settings.DashVelocity + Vector3.new(0, currentYVelocity, 0)
	NewBV.Parent = HumanoidRootPart

	for key, anim in {[Enum.KeyCode.W] = "Forward", [Enum.KeyCode.A] = "Left", [Enum.KeyCode.S] = "Backward", [Enum.KeyCode.D] = "Right"} do
		if UserInputService:IsKeyDown(key) then
			Animations[anim]:Play()
			break
		end
	end

	task.delay(Settings.Lifetime, function() NewBV:Destroy() end)
end

UserInputService.InputBegan:Connect(function(input, processed)
	if processed or Humanoid.Health == 0 then return end
	if input.KeyCode == sprintKey then
		shiftPressed = true
		if next(movementKeysPressed) then
			startSprinting()
		end
	elseif table.find(movementKeys, input.KeyCode) then
		movementKeysPressed[input.KeyCode] = true
		if shiftPressed and StaminaManager.GetStamina() > 0 and not isCrouching then
			startSprinting()
		end
	elseif input.KeyCode == crouchKey then
		if sprinting and StaminaManager.GetStamina() > 0 and isCrouching then
			startSliding()
		else
			crouch()
		end
	elseif input.KeyCode == Enum.KeyCode.E then
		dash()
	end
end)


UserInputService.InputEnded:Connect(function(input)
    if Humanoid.Health == 0 then return end
    if input.KeyCode == sprintKey then
        shiftPressed = false
        stopSprinting()
    elseif table.find(movementKeys, input.KeyCode) then
        movementKeysPressed[input.KeyCode] = nil
        if next(movementKeysPressed) == nil then
            stopSprinting()
        end
    elseif input.KeyCode == crouchKey and not sprinting then
        stand()
    end
end)

RunService.RenderStepped:Connect(function(deltaTime)
    if sprinting and not StaminaManager.ReduceStamina(staminaDrainRate * deltaTime) then
        stopSprinting()
    end
    updateStaminaBar()
end)

Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
    isMoving = Humanoid.MoveDirection.Magnitude > 0
end)

local playAnim = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("Land"))

Humanoid.StateChanged:Connect(function(oldState, newState)
	if (newState == Enum.HumanoidStateType.Jumping) then
		canJump = false
		Humanoid:SetStateEnabled("Jumping", false)
		task.wait(Settings.JumpCooldown)
		canJump = true
		Humanoid:SetStateEnabled("Jumping", true)
    elseif newState == Enum.HumanoidStateType.Freefall then
        animTrack:Stop()
    elseif newState == Enum.HumanoidStateType.Landed then
        animTrack:Stop()
    	playAnim:Play()
        playAnim.Stopped:Wait()
        if sprinting then
            animTrack:Play()
        end
    end
end)

jump delay doesnt count if you hit something above you. landing animation replays over and over if you hit something above you. do not give me the whole script back, instead tell me what to add or replace to the script.