local M={wave=false;point=false;dance=true,dance2=true,dance3=true;laugh=false;cheer=false}math.randomseed(tick())function findExistingAnimationInSet(M,B)if M==nil or B==nil then return 0 end for A=1,M.count,1 do if M[A].anim.AnimationId==B.AnimationId then return A end end return 0 end local function B()for M,B in pairs(strafingLocomotionMap)do if B.track then B.track:Stop()B.track:Destroy()B.track=nil end end for M,B in pairs(fallbackLocomotionMap)do if B.track then B.track:Stop()B.track:Destroy()B.track=nil end end cachedRunningSpeed=0 end local A,d,Q,i local function u(M)d=0 A=0 i=0 Q=0 end local function L(M)if M then if M.x>A then A=M.x end if M.y>Q then Q=M.y end if M.x<d then d=M.x end if M.y<i then i=M.y end end end local function P(M)if A==0 or d==0 or Q==0 or i==0 then if locomotionMap==strafingLocomotionMap then warn("\083\116\114\097\102\101 \098\108\101\110\100\105\110\103 \100\105\115\097\098\108\101\100\046  \078\111\116 \097\108\108 \113\117\097\100\114\097\110\116\115 \111\102 \109\111\116\105\111\110 \114\101\112\114\101\115\101\110\116\101\100\046")end locomotionMap=fallbackLocomotionMap elseif not strafingLocomotionMap.run or not strafingLocomotionMap.walk then if locomotionMap==strafingLocomotionMap then warn("\083\116\114\097\102\101 \098\108\101\110\100\105\110\103 \100\105\115\097\098\108\101\100\046  \082\117\110 \097\110\100 \119\097\108\107 \109\117\115\116 \098\101 \115\116\114\097\102\105\110\103-\102\114\105\101\110\100\108\121\046")end locomotionMap=fallbackLocomotionMap else if locomotionMap~=strafingLocomotionMap then locomotionMap=strafingLocomotionMap warn("\083\116\114\097\102\105\110\103 \114\101\101\110\097\098\108\101\100")end end end local function s()u()for M,B in pairs(strafingLocomotionMap)do L(B.lv)end P()for M,B in pairs(locomotionMap)do B.track=Humanoid:LoadAnimation(animTable[M][1].anim)B.track.Priority=Enum.AnimationPriority.Core end end local function a(M,A)local d=false if currentAnim=="\119\097\108\107"and locomotionMap[M]then B()d=true end if A then strafingLocomotionMap[M]={lv=A;speed=A.Magnitude}else strafingLocomotionMap[M]=nil end if M=="\114\117\110"or M=="\119\097\108\107"then if A then fallbackLocomotionMap[M]=strafingLocomotionMap[M]else local B=M=="\114\117\110"and RUN_SPEED or WALK_SPEED fallbackLocomotionMap[M]={lv=Vector2.new(.0,B),speed=B}strafingLocomotionMap[M]=nil end end if d then s()lastBlendTime=0 end end function configureAnimationSet(M,B)if animTable[M]~=nil then for M,B in pairs(animTable[M].connections)do B:disconnect()end end animTable[M]={}animTable[M].count=0 animTable[M].totalWeight=0 animTable[M].connections={}local A=script:FindFirstChild(M)if A~=nil then table.insert(animTable[M].connections,A.ChildAdded:connect(function(A)configureAnimationSet(M,B)end))table.insert(animTable[M].connections,A.ChildRemoved:connect(function(A)configureAnimationSet(M,B)end))local d=0 for A,Q in pairs(A:GetChildren())do if Q:IsA("\065\110\105\109\097\116\105\111\110")then local A=1 local i=Q:FindFirstChild("\087\101\105\103\104\116")if i~=nil then A=i.Value end animTable[M].count=animTable[M].count+1 d=animTable[M].count animTable[M][d]={}animTable[M][d].anim=Q animTable[M][d].weight=A animTable[M].totalWeight=animTable[M].totalWeight+animTable[M][d].weight table.insert(animTable[M].connections,Q.Changed:connect(function(A)configureAnimationSet(M,B)end))table.insert(animTable[M].connections,Q.ChildAdded:connect(function(A)configureAnimationSet(M,B)end))table.insert(animTable[M].connections,Q.ChildRemoved:connect(function(A)configureAnimationSet(M,B)end))local u=Q:GetAttribute("\076\105\110\101\097\114\086\101\108\111\099\105\116\121")a(M,u)end end end if animTable[M].count<=0 then for B,A in pairs(B)do animTable[M][B]={}animTable[M][B].anim=Instance.new("\065\110\105\109\097\116\105\111\110")animTable[M][B].anim.Name=M animTable[M][B].anim.AnimationId=A.id animTable[M][B].weight=A.weight animTable[M].count=animTable[M].count+1 animTable[M].totalWeight=animTable[M].totalWeight+A.weight end end for M,B in pairs(animTable)do for M=1,B.count,1 do if PreloadedAnims[B[M].anim.AnimationId]==nil then Humanoid:LoadAnimation(B[M].anim)PreloadedAnims[B[M].anim.AnimationId]=true end end end end
-- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
local emoteNames =
	{ wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false }

math.randomseed(tick())

function findExistingAnimationInSet(set, anim)
	if set == nil or anim == nil then
		return 0
	end

	for idx = 1, set.count, 1 do
		if set[idx].anim.AnimationId == anim.AnimationId then
			return idx
		end
	end

	return 0
end

local function destroyWalkAnimations()
	for _, v in pairs(strafingLocomotionMap) do
		if v.track then
			v.track:Stop()
			v.track:Destroy()
			v.track = nil
		end
	end
	for _, v in pairs(fallbackLocomotionMap) do
		if v.track then
			v.track:Stop()
			v.track:Destroy()
			v.track = nil
		end
	end
	cachedRunningSpeed = 0
end

local maxVeloX, minVeloX, maxVeloY, minVeloY

local function resetVelocityBounds(velo)
	minVeloX = 0
	maxVeloX = 0
	minVeloY = 0
	maxVeloY = 0
end

local function updateVelocityBounds(velo)
	if velo then
		if velo.x > maxVeloX then
			maxVeloX = velo.x
		end
		if velo.y > maxVeloY then
			maxVeloY = velo.y
		end
		if velo.x < minVeloX then
			minVeloX = velo.x
		end
		if velo.y < minVeloY then
			minVeloY = velo.y
		end
	end
end

local function checkStrafingEnabled(velo)
	if maxVeloX == 0 or minVeloX == 0 or maxVeloY == 0 or minVeloY == 0 then
		if locomotionMap == strafingLocomotionMap then
			warn("Strafe blending disabled.  Not all quadrants of motion represented.")
		end
		locomotionMap = fallbackLocomotionMap
	elseif not strafingLocomotionMap["run"] or not strafingLocomotionMap["walk"] then
		if locomotionMap == strafingLocomotionMap then
			warn("Strafe blending disabled.  Run and walk must be strafing-friendly.")
		end
		locomotionMap = fallbackLocomotionMap
	else
		if locomotionMap ~= strafingLocomotionMap then
			locomotionMap = strafingLocomotionMap
			warn("Strafing reenabled")
		end
	end
end

local function setupWalkAnimations()
	resetVelocityBounds()
	-- check to see if we need to blend a walk/run animation
	for n, v in pairs(strafingLocomotionMap) do
		updateVelocityBounds(v.lv)
	end
	checkStrafingEnabled()
	for n, v in pairs(locomotionMap) do
		v.track = Humanoid:LoadAnimation(animTable[n][1].anim)
		v.track.Priority = Enum.AnimationPriority.Core
	end
end

local function replaceLocomotionTrack(name, lv)
	local restartWalks = false
	if currentAnim == "walk" and locomotionMap[name] then
		-- Need to tear down and startup locomotion
		destroyWalkAnimations()
		restartWalks = true
	end

	if lv then
		strafingLocomotionMap[name] = { lv = lv, speed = lv.Magnitude }
	else
		strafingLocomotionMap[name] = nil
	end
	if name == "run" or name == "walk" then
		if lv then
			fallbackLocomotionMap[name] = strafingLocomotionMap[name]
		else
			local speed = name == "run" and RUN_SPEED or WALK_SPEED
			fallbackLocomotionMap[name] = { lv = Vector2.new(0.0, speed), speed = speed }
			strafingLocomotionMap[name] = nil
		end
	end
	if restartWalks then
		setupWalkAnimations()
		lastBlendTime = 0
	end
end

function configureAnimationSet(name, fileList)
	if animTable[name] ~= nil then
		for _, connection in pairs(animTable[name].connections) do
			connection:disconnect()
		end
	end
	animTable[name] = {}
	animTable[name].count = 0
	animTable[name].totalWeight = 0
	animTable[name].connections = {}

	-- check for config values
	local config = script:FindFirstChild(name)
	if config ~= nil then
		table.insert(
			animTable[name].connections,
			config.ChildAdded:connect(function(child)
				configureAnimationSet(name, fileList)
			end)
		)
		table.insert(
			animTable[name].connections,
			config.ChildRemoved:connect(function(child)
				configureAnimationSet(name, fileList)
			end)
		)

		local idx = 0

		for _, childPart in pairs(config:GetChildren()) do
			if childPart:IsA("Animation") then
				local newWeight = 1
				local weightObject = childPart:FindFirstChild("Weight")
				if weightObject ~= nil then
					newWeight = weightObject.Value
				end
				animTable[name].count = animTable[name].count + 1
				idx = animTable[name].count
				animTable[name][idx] = {}
				animTable[name][idx].anim = childPart
				animTable[name][idx].weight = newWeight
				animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
				table.insert(
					animTable[name].connections,
					childPart.Changed:connect(function(property)
						configureAnimationSet(name, fileList)
					end)
				)
				table.insert(
					animTable[name].connections,
					childPart.ChildAdded:connect(function(property)
						configureAnimationSet(name, fileList)
					end)
				)
				table.insert(
					animTable[name].connections,
					childPart.ChildRemoved:connect(function(property)
						configureAnimationSet(name, fileList)
					end)
				)
				local lv = childPart:GetAttribute("LinearVelocity")
				replaceLocomotionTrack(name, lv)
			end
		end
	end

	-- fallback to defaults
	if animTable[name].count <= 0 then
		for idx, anim in pairs(fileList) do
			animTable[name][idx] = {}
			animTable[name][idx].anim = Instance.new("Animation")
			animTable[name][idx].anim.Name = name
			animTable[name][idx].anim.AnimationId = anim.id
			animTable[name][idx].weight = anim.weight
			animTable[name].count = animTable[name].count + 1
			animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
		end
	end

	-- preload anims
	for i, animType in pairs(animTable) do
		for idx = 1, animType.count, 1 do
			if PreloadedAnims[animType[idx].anim.AnimationId] == nil then
				Humanoid:LoadAnimation(animType[idx].anim)
				PreloadedAnims[animType[idx].anim.AnimationId] = true
			end
		end
	end
end
