local G={}do local N=script.Parent.Parent Head=N:WaitForChild("\072\101\097\100")while not Humanoid do for G,N in pairs(N:GetChildren())do if N:IsA("\072\117\109\097\110\111\105\100")then Humanoid=N break end end N.ChildAdded:wait()end G[SFX.Died]=Head:WaitForChild("\068\105\101\100")G[SFX.Running]=Head:WaitForChild("\082\117\110\110\105\110\103")G[SFX.Swimming]=Head:WaitForChild("\083\119\105\109\109\105\110\103")G[SFX.Climbing]=Head:WaitForChild("\067\108\105\109\098\105\110\103")G[SFX.Jumping]=Head:WaitForChild("\074\117\109\112\105\110\103")G[SFX.GettingUp]=Head:WaitForChild("\071\101\116\116\105\110\103\085\112")G[SFX.FreeFalling]=Head:WaitForChild("\070\114\101\101\070\097\108\108\105\110\103")G[SFX.Landing]=Head:WaitForChild("\076\097\110\100\105\110\103")G[SFX.Splash]=Head:WaitForChild("\083\112\108\097\115\104")end local N N={YForLineGivenXAndTwoPts=function(G,N,t,c,j)local W=(t-j)/(N-c)local v=t-W*N return W*G+v end;Clamp=function(G,N,t)return math.min(t,math.max(N,G))end;HorizontalSpeed=function(G)local N=G.Velocity+Vector3.new(0,-G.Velocity.Y,0)return N.magnitude end;VerticalSpeed=function(G)return math.abs(G.Velocity.Y)end;Play=function(G)if G.TimePosition~=0 then G.TimePosition=0 end if not G.IsPlaying then G.Playing=true end end;Pause=function(G)if G.IsPlaying then G.Playing=false end end;Resume=function(G)if not G.IsPlaying then G.Playing=true end end;Stop=function(G)if G.IsPlaying then G.Playing=false end if G.TimePosition~=0 then G.TimePosition=0 end end}do local t={}local c=nil function setSoundInPlayingLoopedSounds(G)for N=1,#t,1 do if t[N]==G then return end end table.insert(t,G)end function stopPlayingLoopedSoundsExcept(G)for c=#t,1,-1 do if t[c]~=G then N.Pause(t[c])table.remove(t,c)end end end local j={[Enum.HumanoidStateType.Dead]=function()stopPlayingLoopedSoundsExcept()local t=G[SFX.Died]N.Play(t)end;[Enum.HumanoidStateType.RunningNoPhysics]=function()stateUpdated(Enum.HumanoidStateType.Running)end,[Enum.HumanoidStateType.Running]=function()local t=G[SFX.Running]stopPlayingLoopedSoundsExcept(t)if N.HorizontalSpeed(Head)>.5 then N.Resume(t)setSoundInPlayingLoopedSounds(t)else stopPlayingLoopedSoundsExcept()end end;[Enum.HumanoidStateType.Swimming]=function()if c~=Enum.HumanoidStateType.Swimming and N.VerticalSpeed(Head)>.1 then local t=G[SFX.Splash]t.Volume=N.Clamp(N.YForLineGivenXAndTwoPts(N.VerticalSpeed(Head),100,.28,350,1),0,1)N.Play(t)end do local t=G[SFX.Swimming]stopPlayingLoopedSoundsExcept(t)N.Resume(t)setSoundInPlayingLoopedSounds(t)end end;[Enum.HumanoidStateType.Climbing]=function()local t=G[SFX.Climbing]if N.VerticalSpeed(Head)>.1 then N.Resume(t)stopPlayingLoopedSoundsExcept(t)else stopPlayingLoopedSoundsExcept()end setSoundInPlayingLoopedSounds(t)end,[Enum.HumanoidStateType.Jumping]=function()if c==Enum.HumanoidStateType.Jumping then return end stopPlayingLoopedSoundsExcept()local t=G[SFX.Jumping]N.Play(t)end,[Enum.HumanoidStateType.GettingUp]=function()stopPlayingLoopedSoundsExcept()local t=G[SFX.GettingUp]N.Play(t)end,[Enum.HumanoidStateType.Freefall]=function()if c==Enum.HumanoidStateType.Freefall then return end local N=G[SFX.FreeFalling]N.Volume=0 stopPlayingLoopedSoundsExcept()end,[Enum.HumanoidStateType.FallingDown]=function()stopPlayingLoopedSoundsExcept()end,[Enum.HumanoidStateType.Landed]=function()stopPlayingLoopedSoundsExcept()if N.VerticalSpeed(Head)>75 then local t=G[SFX.Landing]t.Volume=N.Clamp(N.YForLineGivenXAndTwoPts(N.VerticalSpeed(Head),50,0,100,1),0,1)N.Play(t)end end}function stateUpdated(G)if j[G]~=nil then j[G]()end c=G end Humanoid.Died:connect(function()stateUpdated(Enum.HumanoidStateType.Dead)end)Humanoid.Running:connect(function()stateUpdated(Enum.HumanoidStateType.Running)end)Humanoid.Swimming:connect(function()stateUpdated(Enum.HumanoidStateType.Swimming)end)Humanoid.Climbing:connect(function()stateUpdated(Enum.HumanoidStateType.Climbing)end)Humanoid.Jumping:connect(function()stateUpdated(Enum.HumanoidStateType.Jumping)end)Humanoid.GettingUp:connect(function()stateUpdated(Enum.HumanoidStateType.GettingUp)end)Humanoid.FreeFalling:connect(function()stateUpdated(Enum.HumanoidStateType.Freefall)end)Humanoid.FallingDown:connect(function()stateUpdated(Enum.HumanoidStateType.FallingDown)end)Humanoid.StateChanged:connect(function(G,N)stateUpdated(N)end)function onUpdate(t,j)local W=t/j do local t=G[SFX.FreeFalling]if c==Enum.HumanoidStateType.Freefall then if Head.Velocity.Y<0 and N.VerticalSpeed(Head)>75 then N.Resume(t)local G=1.1 local c=j/G t.Volume=N.Clamp(t.Volume+c*W,0,1)else t.Volume=0 end else N.Pause(t)end end do local t=G[SFX.Running]if c==Enum.HumanoidStateType.Running then if N.HorizontalSpeed(Head)<.5 then N.Pause(t)end end end end local W=tick()local v=.25 while true do onUpdate(tick()-W,v)W=tick()wait(v)end end
--SFX ID to Sound object
local Sounds = {}

do
	local Figure = script.Parent.Parent
	Head = Figure:WaitForChild("Head")
	while not Humanoid do
		for _, NewHumanoid in pairs(Figure:GetChildren()) do
			if NewHumanoid:IsA("Humanoid") then
				Humanoid = NewHumanoid
				break
			end
		end
		Figure.ChildAdded:wait()
	end

	Sounds[SFX.Died] = Head:WaitForChild("Died")
	Sounds[SFX.Running] = Head:WaitForChild("Running")
	Sounds[SFX.Swimming] = Head:WaitForChild("Swimming")
	Sounds[SFX.Climbing] = Head:WaitForChild("Climbing")
	Sounds[SFX.Jumping] = Head:WaitForChild("Jumping")
	Sounds[SFX.GettingUp] = Head:WaitForChild("GettingUp")
	Sounds[SFX.FreeFalling] = Head:WaitForChild("FreeFalling")
	Sounds[SFX.Landing] = Head:WaitForChild("Landing")
	Sounds[SFX.Splash] = Head:WaitForChild("Splash")
end

local Util
Util = {

	--Define linear relationship between (pt1x,pt2x) and (pt2x,pt2y). Evaluate this at x.
	YForLineGivenXAndTwoPts = function(x, pt1x, pt1y, pt2x, pt2y)
		--(y - y1)/(x - x1) = m
		local m = (pt1y - pt2y) / (pt1x - pt2x)
		--float b = pt1.y - m * pt1.x;
		local b = (pt1y - m * pt1x)
		return m * x + b
	end,

	--Clamps the value of "val" between the "min" and "max"
	Clamp = function(val, min, max)
		return math.min(max, math.max(min, val))
	end,

	--Gets the horizontal (x,z) velocity magnitude of the given part
	HorizontalSpeed = function(Head)
		local hVel = Head.Velocity + Vector3.new(0, -Head.Velocity.Y, 0)
		return hVel.magnitude
	end,

	--Gets the vertical (y) velocity magnitude of the given part
	VerticalSpeed = function(Head)
		return math.abs(Head.Velocity.Y)
	end,

	--Setting Playing/TimePosition values directly result in less network traffic than Play/Pause/Resume/Stop
	--If these properties are enabled, use them.
	Play = function(sound)
		if sound.TimePosition ~= 0 then
			sound.TimePosition = 0
		end
		if not sound.IsPlaying then
			sound.Playing = true
		end
	end,
	Pause = function(sound)
		if sound.IsPlaying then
			sound.Playing = false
		end
	end,
	Resume = function(sound)
		if not sound.IsPlaying then
			sound.Playing = true
		end
	end,
	Stop = function(sound)
		if sound.IsPlaying then
			sound.Playing = false
		end
		if sound.TimePosition ~= 0 then
			sound.TimePosition = 0
		end
	end,
}

do
	-- List of all active Looped sounds
	local playingLoopedSounds = {}

	-- Last seen Enum.HumanoidStateType
	local activeState = nil

	-- Verify and set that "sound" is in "playingLoopedSounds".
	function setSoundInPlayingLoopedSounds(sound)
		for i = 1, #playingLoopedSounds do
			if playingLoopedSounds[i] == sound then
				return
			end
		end
		table.insert(playingLoopedSounds, sound)
	end

	-- Stop all active looped sounds except parameter "except". If "except" is not passed, all looped sounds will be stopped.
	function stopPlayingLoopedSoundsExcept(except)
		for i = #playingLoopedSounds, 1, -1 do
			if playingLoopedSounds[i] ~= except then
				Util.Pause(playingLoopedSounds[i])
				table.remove(playingLoopedSounds, i)
			end
		end
	end

	-- Table of Enum.HumanoidStateType to handling function
	local stateUpdateHandler = {
		[Enum.HumanoidStateType.Dead] = function()
			stopPlayingLoopedSoundsExcept()
			local sound = Sounds[SFX.Died]
			Util.Play(sound)
		end,

		[Enum.HumanoidStateType.RunningNoPhysics] = function()
			stateUpdated(Enum.HumanoidStateType.Running)
		end,

		[Enum.HumanoidStateType.Running] = function()
			local sound = Sounds[SFX.Running]
			stopPlayingLoopedSoundsExcept(sound)

			if Util.HorizontalSpeed(Head) > 0.5 then
				Util.Resume(sound)
				setSoundInPlayingLoopedSounds(sound)
			else
				stopPlayingLoopedSoundsExcept()
			end
		end,

		[Enum.HumanoidStateType.Swimming] = function()
			if activeState ~= Enum.HumanoidStateType.Swimming and Util.VerticalSpeed(Head) > 0.1 then
				local splashSound = Sounds[SFX.Splash]
				splashSound.Volume =
					Util.Clamp(Util.YForLineGivenXAndTwoPts(Util.VerticalSpeed(Head), 100, 0.28, 350, 1), 0, 1)
				Util.Play(splashSound)
			end

			do
				local sound = Sounds[SFX.Swimming]
				stopPlayingLoopedSoundsExcept(sound)
				Util.Resume(sound)
				setSoundInPlayingLoopedSounds(sound)
			end
		end,

		[Enum.HumanoidStateType.Climbing] = function()
			local sound = Sounds[SFX.Climbing]
			if Util.VerticalSpeed(Head) > 0.1 then
				Util.Resume(sound)
				stopPlayingLoopedSoundsExcept(sound)
			else
				stopPlayingLoopedSoundsExcept()
			end
			setSoundInPlayingLoopedSounds(sound)
		end,

		[Enum.HumanoidStateType.Jumping] = function()
			if activeState == Enum.HumanoidStateType.Jumping then
				return
			end
			stopPlayingLoopedSoundsExcept()
			local sound = Sounds[SFX.Jumping]
			Util.Play(sound)
		end,

		[Enum.HumanoidStateType.GettingUp] = function()
			stopPlayingLoopedSoundsExcept()
			local sound = Sounds[SFX.GettingUp]
			Util.Play(sound)
		end,

		[Enum.HumanoidStateType.Freefall] = function()
			if activeState == Enum.HumanoidStateType.Freefall then
				return
			end
			local sound = Sounds[SFX.FreeFalling]
			sound.Volume = 0
			stopPlayingLoopedSoundsExcept()
		end,

		[Enum.HumanoidStateType.FallingDown] = function()
			stopPlayingLoopedSoundsExcept()
		end,

		[Enum.HumanoidStateType.Landed] = function()
			stopPlayingLoopedSoundsExcept()
			if Util.VerticalSpeed(Head) > 75 then
				local landingSound = Sounds[SFX.Landing]
				landingSound.Volume =
					Util.Clamp(Util.YForLineGivenXAndTwoPts(Util.VerticalSpeed(Head), 50, 0, 100, 1), 0, 1)
				Util.Play(landingSound)
			end
		end,
	}

	-- Handle state event fired or OnChange fired
	function stateUpdated(state)
		if stateUpdateHandler[state] ~= nil then
			stateUpdateHandler[state]()
		end
		activeState = state
	end

	Humanoid.Died:connect(function()
		stateUpdated(Enum.HumanoidStateType.Dead)
	end)
	Humanoid.Running:connect(function()
		stateUpdated(Enum.HumanoidStateType.Running)
	end)
	Humanoid.Swimming:connect(function()
		stateUpdated(Enum.HumanoidStateType.Swimming)
	end)
	Humanoid.Climbing:connect(function()
		stateUpdated(Enum.HumanoidStateType.Climbing)
	end)
	Humanoid.Jumping:connect(function()
		stateUpdated(Enum.HumanoidStateType.Jumping)
	end)
	Humanoid.GettingUp:connect(function()
		stateUpdated(Enum.HumanoidStateType.GettingUp)
	end)
	Humanoid.FreeFalling:connect(function()
		stateUpdated(Enum.HumanoidStateType.Freefall)
	end)
	Humanoid.FallingDown:connect(function()
		stateUpdated(Enum.HumanoidStateType.FallingDown)
	end)

	-- required for proper handling of Landed event
	Humanoid.StateChanged:connect(function(old, new)
		stateUpdated(new)
	end)

	function onUpdate(stepDeltaSeconds, tickSpeedSeconds)
		local stepScale = stepDeltaSeconds / tickSpeedSeconds
		do
			local sound = Sounds[SFX.FreeFalling]
			if activeState == Enum.HumanoidStateType.Freefall then
				if Head.Velocity.Y < 0 and Util.VerticalSpeed(Head) > 75 then
					Util.Resume(sound)

					--Volume takes 1.1 seconds to go from volume 0 to 1
					local ANIMATION_LENGTH_SECONDS = 1.1

					local normalizedIncrement = tickSpeedSeconds / ANIMATION_LENGTH_SECONDS
					sound.Volume = Util.Clamp(sound.Volume + normalizedIncrement * stepScale, 0, 1)
				else
					sound.Volume = 0
				end
			else
				Util.Pause(sound)
			end
		end

		do
			local sound = Sounds[SFX.Running]
			if activeState == Enum.HumanoidStateType.Running then
				if Util.HorizontalSpeed(Head) < 0.5 then
					Util.Pause(sound)
				end
			end
		end
	end

	local lastTick = tick()
	local TICK_SPEED_SECONDS = 0.25
	while true do
		onUpdate(tick() - lastTick, TICK_SPEED_SECONDS)
		lastTick = tick()
		wait(TICK_SPEED_SECONDS)
	end
end
