
KeylessUniversal

local plr = game:GetService("Players").LocalPlayer
function RunCustomAnimation(Char)
if Char:WaitForChild("Animate") ~= nil then
Char.Animate.Disabled = true
end
Char:WaitForChild("Humanoid")
for i,v in next, Char.Humanoid:GetPlayingAnimationTracks() do
v:Stop()
end
--fake script
local script = Char.Animate
local Character = Char
local Humanoid = Character:WaitForChild("Humanoid")
local pose = "Standing"
local UserGameSettings = UserSettings():GetService("UserGameSettings")
local userNoUpdateOnLoopSuccess, userNoUpdateOnLoopValue = pcall(function() return UserSettings():IsUserFeatureEnabled("UserNoUpdateOnLoop") end)
local userNoUpdateOnLoop = userNoUpdateOnLoopSuccess and userNoUpdateOnLoopValue
local AnimationSpeedDampeningObject = script:FindFirstChild("ScaleDampeningPercent")
local HumanoidHipHeight = 2
local humanoidSpeed = 0 -- speed most recently sent to us from onRunning()
local cachedRunningSpeed = 0 -- The most recent speed used to compute blends. Tiny variations from cachedRunningSpeed will not cause animation updates.
local cachedLocalDirection = {x=0.0, y=0.0} -- unit 2D object space direction of motion
local smallButNotZero = 0.0001 -- We want weights to be small but not so small the animation stops
local runBlendtime = 0.2
local lastLookVector = Vector3.new(0.0, 0.0, 0.0) -- used to track whether rootPart orientation is changing.
local lastBlendTime = 0 -- The last time we blended velocities
local WALK_SPEED = 6.4
local RUN_SPEED = 12.8
local EMOTE_TRANSITION_TIME = 0.1
local currentAnim = ""
local currentAnimInstance = nil
local currentAnimTrack = nil
local currentAnimKeyframeHandler = nil
local currentAnimSpeed = 1.0
local PreloadedAnims = {}
local animTable = {}
local animNames = {
idle = {
{ id = "http://www.roblox.com/asset/?id=12521158637", weight = 9 },
{ id = "http://www.roblox.com/asset/?id=12521162526", weight = 1 },
},
walk = {
{ id = "http://www.roblox.com/asset/?id=12518152696", weight = 10 }
},
run = {
{ id = "http://www.roblox.com/asset/?id=12518152696", weight = 10 }
},
jump = {
{ id = "http://www.roblox.com/asset/?id=12520880485", weight = 10 }
},
fall = {
{ id = "http://www.roblox.com/asset/?id=12520972571", weight = 10 }
},
climb = {
{ id = "http://www.roblox.com/asset/?id=12520982150", weight = 10 }
},
sit = {
{ id = "http://www.roblox.com/asset/?id=12520993168", weight = 10 }
},
toolnone = {
{ id = "http://www.roblox.com/asset/?id=12520996634", weight = 10 }
},
toolslash = {
{ id = "http://www.roblox.com/asset/?id=12520999032", weight = 10 }
},
toollunge = {
{ id = "http://www.roblox.com/asset/?id=12521002003", weight = 10 }
},
wave = {
{ id = "http://www.roblox.com/asset/?id=12521004586", weight = 10 }
},
point = {
{ id = "http://www.roblox.com/asset/?id=12521007694", weight = 10 }
},
dance = {
{ id = "http://www.roblox.com/asset/?id=12521009666", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=12521151637", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=12521015053", weight = 10 }
},
dance2 = {
{ id = "http://www.roblox.com/asset/?id=12521169800", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=12521173533", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=12521027874", weight = 10 }
},
dance3 = {
{ id = "http://www.roblox.com/asset/?id=12521178362", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=12521181508", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=12521184133", weight = 10 }
},
laugh = {
{ id = "http://www.roblox.com/asset/?id=12521018724", weight = 10 }
},
cheer = {
{ id = "http://www.roblox.com/asset/?id=12521021991", weight = 10 }
},
}
local strafingLocomotionMap = {}
local fallbackLocomotionMap = {}
local locomotionMap = strafingLocomotionMap
-- 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
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 = {}
-- uncomment this section to allow players to load with their
-- own (non-classic) animations
--[[
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")
if lv then
strafingLocomotionMap[name] = {lv=lv, speed = lv.Magnitude}
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}
locomotionMap = fallbackLocomotionMap
-- If you don't have a linear velocity with your run or walk, you can't blend/strafe
--warn("Strafe blending disabled. No linear velocity information for "..'"'.."walk"..'"'.." and "..'"'.."run"..'"'..".")
end
end
end
end
end
]]
-- if you uncomment the above section, comment out this "if"-block
if name == "run" or name == "walk" then
local speed = name == "run" and RUN_SPEED or WALK_SPEED
fallbackLocomotionMap[name] = {lv=Vector2.new(0.0, speed), speed = speed}
locomotionMap = fallbackLocomotionMap
-- If you don't have a linear velocity with your run or walk, you can't blend/strafe
--warn("Strafe blending disabled. No linear velocity information for "..'"'.."walk"..'"'.." and "..'"'.."run"..'"'..".")
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
-- Setup animation objects
function scriptChildModified(child)
local fileList = animNames[child.Name]
if (fileList ~= nil) then
configureAnimationSet(child.Name, fileList)
else
if child:isA("StringValue") then
animNames[child.Name] = {}
configureAnimationSet(child.Name, animNames[child.Name])
end
end
end
script.ChildAdded:connect(scriptChildModified)
script.ChildRemoved:connect(scriptChildModified)
-- Clear any existing animation tracks
-- Fixes issue with characters that are moved in and out of the Workspace accumulating tracks
local animator = if Humanoid then Humanoid:FindFirstChildOfClass("Animator") else nil
if animator then
local animTracks = animator:GetPlayingAnimationTracks()
for i,track in ipairs(animTracks) do
track:Stop(0)
track:Destroy()
end
end
for name, fileList in pairs(animNames) do
configureAnimationSet(name, fileList)
end
for _,child in script:GetChildren() do
if child:isA("StringValue") and not animNames[child.name] then
animNames[child.Name] = {}
configureAnimationSet(child.Name, animNames[child.Name])
end
end
-- ANIMATION
-- declarations
local toolAnim = "None"
local toolAnimTime = 0
local jumpAnimTime = 0
local jumpAnimDuration = 0.31
local toolTransitionTime = 0.1
local fallTransitionTime = 0.2
local currentlyPlayingEmote = false
-- functions
function stopAllAnimations()
local oldAnim = currentAnim
-- return to idle if finishing an emote
if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
oldAnim = "idle"
end
if currentlyPlayingEmote then
oldAnim = "idle"
currentlyPlayingEmote = false
end
currentAnim = ""
currentAnimInstance = nil
if (currentAnimKeyframeHandler ~= nil) then
currentAnimKeyframeHandler:disconnect()
end
if (currentAnimTrack ~= nil) then
currentAnimTrack:Stop()
currentAnimTrack:Destroy()
currentAnimTrack = nil
end
for _,v in pairs(locomotionMap) do
if v.track then
v.track:Stop()
v.track:Destroy()
v.track = nil
end
end
return oldAnim
end
function getHeightScale()
if Humanoid then
if not Humanoid.AutomaticScalingEnabled then
return 1
end
local scale = Humanoid.HipHeight / HumanoidHipHeight
if AnimationSpeedDampeningObject == nil then
AnimationSpeedDampeningObject = script:FindFirstChild("ScaleDampeningPercent")
end
if AnimationSpeedDampeningObject ~= nil then
scale = 1 + (Humanoid.HipHeight - HumanoidHipHeight) * AnimationSpeedDampeningObject.Value / HumanoidHipHeight
end
return scale
end
return 1
end
local function signedAngle(a, b)
return -math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y)
end
local angleWeight = 2.0
local function get2DWeight(px, p1, p2, sx, s1, s2)
local avgLength = 0.5 * (s1 + s2)
local p_1 = {x = (sx - s1)/avgLength, y = (angleWeight * signedAngle(p1, px))}
local p12 = {x = (s2 - s1)/avgLength, y = (angleWeight * signedAngle(p1, p2))}
local denom = smallButNotZero + (p12.x*p12.x + p12.y*p12.y)
local numer = p_1.x * p12.x + p_1.y * p12.y
local r = math.clamp(1.0 - numer/denom, 0.0, 1.0)
return r
end
local function blend2D(targetVelo, targetSpeed)
local h = {}
local sum = 0.0
for n,v1 in pairs(locomotionMap) do
if targetVelo.x * v1.lv.x < 0.0 or targetVelo.y * v1.lv.y < 0 then
-- Require same quadrant as target
h[n] = 0.0
continue
end
h[n] = math.huge
for j,v2 in pairs(locomotionMap) do
if targetVelo.x * v2.lv.x < 0.0 or targetVelo.y * v2.lv.y < 0 then
-- Require same quadrant as target
continue
end
h[n] = math.min(h[n], get2DWeight(targetVelo, v1.lv, v2.lv, targetSpeed, v1.speed, v2.speed))
end
sum += h[n]
end
--truncates below 10% contribution
local sum2 = 0.0
local weightedVeloX = 0
local weightedVeloY = 0
for n,v in pairs(locomotionMap) do
if (h[n] / sum > 0.1) then
sum2 += h[n]
weightedVeloX += h[n] * v.lv.x
weightedVeloY += h[n] * v.lv.y
else
h[n] = 0.0
end
end
local animSpeed
local weightedSpeedSquared = weightedVeloX * weightedVeloX + weightedVeloY * weightedVeloY
if weightedSpeedSquared > smallButNotZero then
animSpeed = math.sqrt(targetSpeed * targetSpeed / weightedSpeedSquared)
else
animSpeed = 0
end
animSpeed = animSpeed / getHeightScale()
local groupTimePosition = 0
for n,v in pairs(locomotionMap) do
if v.track.IsPlaying then
groupTimePosition = v.track.TimePosition
break
end
end
for n,v in pairs(locomotionMap) do
-- if not loco
if h[n] > 0.0 then
if not v.track.IsPlaying then
v.track:Play(runBlendtime)
v.track.TimePosition = groupTimePosition
end
local weight = math.max(smallButNotZero, h[n] / sum2)
v.track:AdjustWeight(weight, runBlendtime)
v.track:AdjustSpeed(animSpeed)
else
v.track:Stop(runBlendtime)
end
end
end
local function getWalkDirection()
local walkToPoint = Humanoid.WalkToPoint
local walkToPart = Humanoid.WalkToPart
if Humanoid.MoveDirection ~= Vector3.zero then
return Humanoid.MoveDirection
elseif walkToPart or walkToPoint ~= Vector3.zero then
local destination
if walkToPart then
destination = walkToPart.CFrame:PointToWorldSpace(walkToPoint)
else
destination = walkToPoint
end
local moveVector = Vector3.zero
if Humanoid.RootPart then
moveVector = destination - Humanoid.RootPart.CFrame.Position
moveVector = Vector3.new(moveVector.x, 0.0, moveVector.z)
local mag = moveVector.Magnitude
if mag > 0.01 then
moveVector /= mag
end
end
return moveVector
else
return Humanoid.MoveDirection
end
end
local function updateVelocity(currentTime)
local tempDir
if locomotionMap == strafingLocomotionMap then
local moveDirection = getWalkDirection()
if not Humanoid.RootPart then
return
end
local cframe = Humanoid.RootPart.CFrame
if math.abs(cframe.UpVector.Y) < smallButNotZero or pose ~= "Running" or humanoidSpeed < 0.001 then
-- We are horizontal! Do something (turn off locomotion)
for n,v in pairs(locomotionMap) do
if v.track then
v.track:AdjustWeight(smallButNotZero, runBlendtime)
end
end
return
end
local lookat = cframe.LookVector
local direction = Vector3.new(lookat.X, 0.0, lookat.Z)
direction = direction / direction.Magnitude --sensible upVector means this is non-zero.
local ly = moveDirection:Dot(direction)
if ly <= 0.0 and ly > -0.05 then
ly = smallButNotZero -- break quadrant ties in favor of forward-friendly strafes
end
local lx = direction.X*moveDirection.Z - direction.Z*moveDirection.X
local tempDir = Vector2.new(lx, ly) -- root space moveDirection
local delta = Vector2.new(tempDir.x-cachedLocalDirection.x, tempDir.y-cachedLocalDirection.y)
-- Time check serves the purpose of the old keyframeReached sync check, as it syncs anim timePosition
if delta:Dot(delta) > 0.001 or math.abs(humanoidSpeed - cachedRunningSpeed) > 0.01 or currentTime - lastBlendTime > 1 then
cachedLocalDirection = tempDir
cachedRunningSpeed = humanoidSpeed
lastBlendTime = currentTime
blend2D(cachedLocalDirection, cachedRunningSpeed)
end
else
if math.abs(humanoidSpeed - cachedRunningSpeed) > 0.01 or currentTime - lastBlendTime > 1 then
cachedRunningSpeed = humanoidSpeed
lastBlendTime = currentTime
blend2D(Vector2.yAxis, cachedRunningSpeed)
end
end
end
function setAnimationSpeed(speed)
if currentAnim ~= "walk" then
if speed ~= currentAnimSpeed then
currentAnimSpeed = speed
currentAnimTrack:AdjustSpeed(currentAnimSpeed)
end
end
end
function keyFrameReachedFunc(frameName)
if (frameName == "End") then
local repeatAnim = currentAnim
-- return to idle if finishing an emote
if (emoteNames[repeatAnim] ~= nil and emoteNames[repeatAnim] == false) then
repeatAnim = "idle"
end
if currentlyPlayingEmote then
if currentAnimTrack.Looped then
-- Allow the emote to loop
return
end
repeatAnim = "idle"
currentlyPlayingEmote = false
end
local animSpeed = currentAnimSpeed
playAnimation(repeatAnim, 0.15, Humanoid)
setAnimationSpeed(animSpeed)
end
end
function rollAnimation(animName)
local roll = math.random(1, animTable[animName].totalWeight)
local origRoll = roll
local idx = 1
while (roll > animTable[animName][idx].weight) do
roll = roll - animTable[animName][idx].weight
idx = idx + 1
end
return idx
end
local maxVeloX, minVeloX, maxVeloY, minVeloY
local function destroyRunAnimations()
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 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 checkVelocityBounds(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
else
locomotionMap = strafingLocomotionMap
end
end
local function setupWalkAnimation(anim, animName, transitionTime, humanoid)
resetVelocityBounds()
-- check to see if we need to blend a walk/run animation
for n,v in pairs(locomotionMap) do
v.track = humanoid:LoadAnimation(animTable[n][1].anim)
v.track.Priority = Enum.AnimationPriority.Core
updateVelocityBounds(v.lv)
end
checkVelocityBounds()
end
local function switchToAnim(anim, animName, transitionTime, humanoid)
-- switch animation
if (anim ~= currentAnimInstance) then
if (currentAnimTrack ~= nil) then
currentAnimTrack:Stop(transitionTime)
currentAnimTrack:Destroy()
end
if (currentAnimKeyframeHandler ~= nil) then
currentAnimKeyframeHandler:disconnect()
end
currentAnimSpeed = 1.0
currentAnim = animName
currentAnimInstance = anim -- nil in the case of locomotion
if animName == "walk" then
setupWalkAnimation(anim, animName, transitionTime, humanoid)
else
destroyRunAnimations()
-- load it to the humanoid; get AnimationTrack
currentAnimTrack = humanoid:LoadAnimation(anim)
currentAnimTrack.Priority = Enum.AnimationPriority.Core
currentAnimTrack:Play(transitionTime)
-- set up keyframe name triggers
currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
end
end
end
function playAnimation(animName, transitionTime, humanoid)
local idx = rollAnimation(animName)
local anim = animTable[animName][idx].anim
switchToAnim(anim, animName, transitionTime, humanoid)
currentlyPlayingEmote = falseNo comments yet for this script.



