local sprintSpeed = 17
local sprintFov = 80
local normalFov = 70


local sprintKey = Enum.KeyCode.LeftShift
local movementKeys = {Enum.KeyCode.W, Enum.KeyCode.A, Enum.KeyCode.S, Enum.KeyCode.D}


local userInputService = game:GetService("UserInputService")
local tweenService = game:GetService("TweenService")
local runService = game:GetService("RunService")
local playersService = game:GetService("Players")
local player = playersService.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local defaultSpeed = 12
local camera = workspace.CurrentCamera
local sprintAnim = script:WaitForChild("SprintAnim")
local animTrack = humanoid:LoadAnimation(sprintAnim)
animTrack.Priority = Enum.AnimationPriority.Movement


local sprinting = false
local stamina = 100
local maxStamina = 100
local minStamina = 0
local staminaDrainRate = 30
local staminaFillRate = 50
local staminaRegenDelay = 0.5
local staminaBar = script.Parent.StaminaBar.Bar


script.Parent.PlayerName.Text = player.Name
script.Parent.PlayerThumb.Image = "rbxthumb://type=AvatarHeadShot&id=" .. player.UserId .. "&w=420&h=420"


local healthBar = script.Parent.HealthBar.Bar
character.Humanoid:GetPropertyChangedSignal("Health"):Connect(function()
	healthBar.Size = UDim2.new(character.Humanoid.Health / 100, 0, 1, 0)
end)


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 tweenStaminaBar()
	local tween = tweenService:Create(staminaBar, TweenInfo.new(0.25, Enum.EasingStyle.Quad), { Size = UDim2.new(stamina / maxStamina, 0, 1, 0) })
	tween:Play()
end


local function startSprinting()
	if not sprinting and stamina > minStamina then
		sprinting = true
		humanoid.WalkSpeed = sprintSpeed
		animTrack:Play()
		tweenFov(0.25, sprintFov)
	end
end

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


local shiftPressed = false
local movementKeysPressed = {}


userInputService.InputBegan:Connect(function(input, processed)
	if processed then return end
	if input.KeyCode == sprintKey then
		shiftPressed = true
		if next(movementKeysPressed) ~= nil then
			startSprinting()
		end
	elseif table.find(movementKeys, input.KeyCode) then
		movementKeysPressed[input.KeyCode] = true
		if shiftPressed then
			startSprinting()
		end
	end
end)

userInputService.InputEnded:Connect(function(input)
	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
	end
end)


local lastSprintTime = tick()
runService.RenderStepped:Connect(function(deltaTime)
	if sprinting then
		stamina = math.max(minStamina, stamina - staminaDrainRate * deltaTime)
		if stamina <= minStamina then
			stopSprinting()
		end
		lastSprintTime = tick()
	else
		if tick() - lastSprintTime >= staminaRegenDelay then
			stamina = math.min(maxStamina, stamina + staminaFillRate * deltaTime)
		end
	end
	tweenStaminaBar()
end)


if the player has no more stamina and holds shift and one of the movement keys, the sprinting stops. this is good! the script also waits for the delay time before sprinting again! however, if he stops pressing the movement key and then clicking it again, the sprinting starts again. this is a bit wrong: when the sprinting stops due to no stamina, i want the player to have to release both shift and the movement key and hold them again in order to start sprinting again.