local function e(e,C,D,m,S)return((e-C)*(S-m))/(D-C)+m end local function C(e)e.TimePosition=0 e.Playing=true end local function D(e)e.Playing=false e.TimePosition=0 end local function m(D,m)local S={}for e,C in pairs(SOUND_DATA)do local D=Instance.new("\083\111\117\110\100")D.Name=e D.Archivable=false D.EmitterSize=5 D.MaxDistance=150 D.Volume=.65 for e,C in pairs(C)do D[e]=C end D.Parent=m S[e]=D end local I={}local function j(e)for C in pairs(I)do if C~=e then C.Playing=false I[C]=nil end end end local h={[Enum.HumanoidStateType.FallingDown]=function()j()end;[Enum.HumanoidStateType.GettingUp]=function()j()C(S.GettingUp)end,[Enum.HumanoidStateType.Jumping]=function()j()C(S.Jumping)end;[Enum.HumanoidStateType.Swimming]=function()local D=math.abs(m.Velocity.Y)if D>.1 then S.Splash.Volume=math.clamp(e(D,100,350,.28,1),0,1)C(S.Splash)end j(S.Swimming)S.Swimming.Playing=true I[S.Swimming]=true end,[Enum.HumanoidStateType.Freefall]=function()S.FreeFalling.Volume=0 j(S.FreeFalling)I[S.FreeFalling]=true end;[Enum.HumanoidStateType.Landed]=function()j()local D=math.abs(m.Velocity.Y)if D>75 then S.Landing.Volume=math.clamp(e(D,50,100,0,1),0,1)C(S.Landing)end end;[Enum.HumanoidStateType.Running]=function()j(S.Running)S.Running.Playing=true I[S.Running]=true end,[Enum.HumanoidStateType.Climbing]=function()local e=S.Climbing if math.abs(m.Velocity.Y)>.1 then e.Playing=true j(e)else j()end I[e]=true end,[Enum.HumanoidStateType.Seated]=function()j()end;[Enum.HumanoidStateType.Dead]=function()j()C(S.Died)end}local P={[S.Climbing]=function(e,C,D)C.Playing=D.Magnitude>.1 end;[S.FreeFalling]=function(e,C,D)if D.Magnitude>75 then C.Volume=math.clamp(C.Volume+.9*e,0,1)else C.Volume=0 end end;[S.Running]=function(e,C,m)C.Playing=m.Magnitude>.5 and D.MoveDirection.Magnitude>.5 end}local b={[Enum.HumanoidStateType.RunningNoPhysics]=Enum.HumanoidStateType.Running}local V=b[D:GetState()]or D:GetState()local U={}local Q=D.StateChanged:Connect(function(e,C)C=b[C]or C if C~=V then local e=h[C]if e then e()end V=C end end)local l=RunService.Stepped:Connect(function(e,C)for e in pairs(I)do local D=P[e]if D then D(C,e,m.Velocity)end end end)local o local E local function f()Q:Disconnect()l:Disconnect()o:Disconnect()E:Disconnect()end o=D.AncestryChanged:Connect(function(e,C)if not C then f()end end)E=m.AncestryChanged:Connect(function(e,C)if not C then f()end end)end local S=script.Parent local I=S:WaitForChild("\072\117\109\097\110\111\105\100")local j=S:WaitForChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")return m(I,j)
-- map a value from one range to another
local function map(x, inMin, inMax, outMin, outMax)
	return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin
end

local function playSound(sound)
	sound.TimePosition = 0
	sound.Playing = true
end

local function stopSound(sound)
	sound.Playing = false
	sound.TimePosition = 0
end

local function initializeSoundSystem(humanoid, rootPart)
	local sounds = {}

	-- initialize sounds
	for name, props in pairs(SOUND_DATA) do
		local sound = Instance.new("Sound")
		sound.Name = name

		-- set default values
		sound.Archivable = false
		sound.EmitterSize = 5
		sound.MaxDistance = 150
		sound.Volume = 0.65

		for propName, propValue in pairs(props) do
			sound[propName] = propValue
		end

		sound.Parent = rootPart
		sounds[name] = sound
	end

	local playingLoopedSounds = {}

	local function stopPlayingLoopedSounds(except)
		for sound in pairs(playingLoopedSounds) do
			if sound ~= except then
				sound.Playing = false
				playingLoopedSounds[sound] = nil
			end
		end
	end

	-- state transition callbacks
	local stateTransitions = {
		[Enum.HumanoidStateType.FallingDown] = function()
			stopPlayingLoopedSounds()
		end,

		[Enum.HumanoidStateType.GettingUp] = function()
			stopPlayingLoopedSounds()
			playSound(sounds.GettingUp)
		end,

		[Enum.HumanoidStateType.Jumping] = function()
			stopPlayingLoopedSounds()
			playSound(sounds.Jumping)
		end,

		[Enum.HumanoidStateType.Swimming] = function()
			local verticalSpeed = math.abs(rootPart.Velocity.Y)
			if verticalSpeed > 0.1 then
				sounds.Splash.Volume = math.clamp(map(verticalSpeed, 100, 350, 0.28, 1), 0, 1)
				playSound(sounds.Splash)
			end
			stopPlayingLoopedSounds(sounds.Swimming)
			sounds.Swimming.Playing = true
			playingLoopedSounds[sounds.Swimming] = true
		end,

		[Enum.HumanoidStateType.Freefall] = function()
			sounds.FreeFalling.Volume = 0
			stopPlayingLoopedSounds(sounds.FreeFalling)
			playingLoopedSounds[sounds.FreeFalling] = true
		end,

		[Enum.HumanoidStateType.Landed] = function()
			stopPlayingLoopedSounds()
			local verticalSpeed = math.abs(rootPart.Velocity.Y)
			if verticalSpeed > 75 then
				sounds.Landing.Volume = math.clamp(map(verticalSpeed, 50, 100, 0, 1), 0, 1)
				playSound(sounds.Landing)
			end
		end,

		[Enum.HumanoidStateType.Running] = function()
			stopPlayingLoopedSounds(sounds.Running)
			sounds.Running.Playing = true
			playingLoopedSounds[sounds.Running] = true
		end,

		[Enum.HumanoidStateType.Climbing] = function()
			local sound = sounds.Climbing
			if math.abs(rootPart.Velocity.Y) > 0.1 then
				sound.Playing = true
				stopPlayingLoopedSounds(sound)
			else
				stopPlayingLoopedSounds()
			end
			playingLoopedSounds[sound] = true
		end,

		[Enum.HumanoidStateType.Seated] = function()
			stopPlayingLoopedSounds()
		end,

		[Enum.HumanoidStateType.Dead] = function()
			stopPlayingLoopedSounds()
			playSound(sounds.Died)
		end,
	}

	-- updaters for looped sounds
	local loopedSoundUpdaters = {
		[sounds.Climbing] = function(dt, sound, vel)
			sound.Playing = vel.Magnitude > 0.1
		end,

		[sounds.FreeFalling] = function(dt, sound, vel)
			if vel.Magnitude > 75 then
				sound.Volume = math.clamp(sound.Volume + 0.9 * dt, 0, 1)
			else
				sound.Volume = 0
			end
		end,

		[sounds.Running] = function(dt, sound, vel)
			sound.Playing = vel.Magnitude > 0.5 and humanoid.MoveDirection.Magnitude > 0.5
		end,
	}

	-- state substitutions to avoid duplicating entries in the state table
	local stateRemap = {
		[Enum.HumanoidStateType.RunningNoPhysics] = Enum.HumanoidStateType.Running,
	}

	local activeState = stateRemap[humanoid:GetState()] or humanoid:GetState()
	local activeConnections = {}

	local stateChangedConn = humanoid.StateChanged:Connect(function(_, state)
		state = stateRemap[state] or state

		if state ~= activeState then
			local transitionFunc = stateTransitions[state]

			if transitionFunc then
				transitionFunc()
			end

			activeState = state
		end
	end)

	local steppedConn = RunService.Stepped:Connect(function(_, worldDt)
		-- update looped sounds on stepped
		for sound in pairs(playingLoopedSounds) do
			local updater = loopedSoundUpdaters[sound]

			if updater then
				updater(worldDt, sound, rootPart.Velocity)
			end
		end
	end)

	local humanoidAncestryChangedConn
	local rootPartAncestryChangedConn

	local function terminate()
		stateChangedConn:Disconnect()
		steppedConn:Disconnect()
		humanoidAncestryChangedConn:Disconnect()
		rootPartAncestryChangedConn:Disconnect()
	end

	humanoidAncestryChangedConn = humanoid.AncestryChanged:Connect(function(_, parent)
		if not parent then
			terminate()
		end
	end)

	rootPartAncestryChangedConn = rootPart.AncestryChanged:Connect(function(_, parent)
		if not parent then
			terminate()
		end
	end)
end

local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")

return initializeSoundSystem(humanoid, rootPart)
