Turning ServerScripts into LocalScripts, but successfully

Hello, everybody!
Recently, I ran into this one bug, well, rather several ones. I was trying to turn a server-sided AI into a client-sided AI, so I just did the first thing that came to my head, just make all the scripts local-sided, there shouldn’t be anything Server-specific in them, but well. It didn’t work, the NPC doesn’t even bother moving. I’ve checked whether is anything anchored and if I copied all the Values and stuff, I did. So here I am, asking for help on the DevForum. Thanks in advance.

Are you viewing it from the server or from the client?

The client, of course. It doesn’t do anything in either of them.

Can you please provide your code so we can have a look at it? You may have missed something that needed to be modified in moving from server to local

Of course, here:
The AI script (movement and stuff, credits go to the respective owner):

--@ItsBasicallyDenis 2022 (contact me on Discord (Benis#0800) or on Twitter (@basicallyrbx) if you experience any issues!)
--This is a very customizable & easy-to-use pathfinding script, can be used for anything that follows players around!

-------- NOTE: If you changed any of the "IMPORTANT SETTINGS" and want to reset all to default, set resetSettingsToDefault to true!
----- Please don't change any parts of the code unless you know what you're doing!
-- DO NOT COPY THIS SCRIPT AND USE IT AS YOUR OWN!


--[[ Update log V1.01:
	- Added stopNearPlayer, moveIfNoPath, waitBeforeStart, requiresSight and createWaypointParts settings;
	- Significantly optimised the script by cleaning up threads & more;
	- Bug fixes.
]]

local t = tick()
local pathFindingService = game:GetService("PathfindingService")

-- Set-up variables (change them to your custom needs!):
local maxDistance = 1000 -- Max distance that the NPC looks for targets in, if maxDistance is 150 and a player is 151 studs away, it will not target it!
local npc = script.Parent
local hum = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
-----------------

-- Character Variables:
local Health = 100 -- default is 100
local WalkSpeed = 12 -- default is 16
local JumpPower = 0 -- default is 50
-----------------

-- IMPORTANT SETTINGS!
local printNotifications = true -- Set to true if you want this script to print when the NPC moves, jumps, etc. (useful for debugging!)
-----------------
local stopNearPlayer = false -- Stops if closer than 3 studs of the target (might stun the NPC for a few seconds when changing directions fast!)
-----------------
local createWaypointParts = true -- Creates a semi-transparent green part for every waypoint (parts are destroyed after 2.5 seconds!)
-----------------
local requiresSight = true -- In order for the NPC to go towards the target, it needs to see it first (also automatically reduces maxDistance!)
-----------------
local moveIfNoPath = true -- Set to true to move 15 studs away if path.Status is not Success (might break movement if npc can't get to target!)
-----------------
local moveToWait = false -- Set to false if you don't want to wait for the MoveTo function to finish everytime (smoother npc movement but broken pathfinding!)
-----------------
local waitBeforeStart = false -- Wait 5-10 seconds before starting the AI (might prevent some start lag!)
-----------------
local resetSettingsToDefault = false -- Set to true to reset all settings to default once the NPC starts!
-----------------

-- Boring part:
-------------------------------------------------------------------------------------

local function CanSeeTarget(target)
	local ray = Ray.new(hrp.Position,(target.HumanoidRootPart.Position - hrp.Position).unit * 100) -- create the ray
	local hit,pos = workspace:FindPartOnRay(ray,npc) -- find parts that the ray hit

	if hit then -- if the ray hit a part then
		if hit:IsDescendantOf(target) then -- if the part is part of the target's character then
			return true -- return true
		end
	end

	return false -- if no target was found, return false
end

local function FindTarget()
	local target
	local maxDis = maxDistance

	if game.Players.LocalPlayer.Character then
		local distance = (hrp.Position - game.Players.LocalPlayer.Character.HumanoidRootPart.Position).Magnitude -- check the distance between npc and player

		if requiresSight then
			if distance <= maxDis and CanSeeTarget(game.Players.LocalPlayer.Character) then
				target = game.Players.LocalPlayer.Character
				maxDis = distance
				if script.Parent.State.Value ~= "Chasing" then
					script.Parent.State.Value = "Chasing"
				end
			end
		else
			if distance <= maxDis then -- if the distance is less than the maxDistance variable then
				target = game.Players.LocalPlayer.Character -- target acquired
				maxDis = distance -- set the new maxDis to the current distance, so if a player is closer than this one, we choose him instead
			end
		end

		return target -- return the target
	end
end


if resetSettingsToDefault then
	printNotifications = false 
	stopNearPlayer = false
	requiresSight = false 
	moveToWait = true
	createWaypointParts = false
	moveIfNoPath = false
	waitBeforeStart = false
end

-----------------
hum.UseJumpPower = true
hum.JumpPower = JumpPower
hum.WalkSpeed = WalkSpeed
hum.MaxHealth = Health
hum.Health = Health

npc.PrimaryPart = hrp
-----------------

if waitBeforeStart then task.wait(math.random(5,10)) end

local oldPath

task.spawn(function() -- start the function
	while task.wait(.1) do -- every .1 seconds do
		local target = FindTarget() -- find the target

		if target then -- if there is a target, proceed with following it
			if target:FindFirstChild("HumanoidRootPart") then target = target.HumanoidRootPart end
			if printNotifications then print("Found target: "..target.Parent.Name) end

			local path = pathFindingService:CreatePath() -- create a new path
			path:ComputeAsync(hrp.Position,target.Position) -- compute the best path from the NPC to the TARGET

			if oldPath then -- if there's an old path, we destroy it and we replace it with the new one
				if path ~= oldPath then
					oldPath:Destroy()
					oldPath = path
					if printNotifications then print("Destroyed old path and replaced it with a new one!") end
				end
			else
				oldPath = path -- if this is the first ever path, we set the old path to the current one
			end

			local waypoints = path:GetWaypoints() -- we get the path's waypoints
			local cor

			if path and waypoints then -- if we have waypoints then
				if path.Status == Enum.PathStatus.Success then	-- if the path is a success then
					for i, waypoint in pairs(waypoints) do -- loop through the waypoints
						cor = coroutine.resume(coroutine.create(function() -- create a seperate thread for each waypoint
							-----------------
							if createWaypointParts then -- if createWaypointParts is set to true, then we create a part for each waypoint!
								local part = Instance.new("Part")
								part.Anchored = true
								part.CanCollide = false
								part.Color = Color3.fromRGB(119, 255, 8)
								part.Transparency = .75
								part.Position = waypoint.Position
								part.Parent = workspace
								task.delay(2.5,function()
									part:Destroy()
								end)
							end
							-----------------

							if waypoint.Action == Enum.PathWaypointAction.Jump then -- if the waypoint requires the NPC to jump
								if printNotifications then print("Jumped!") end
								hum.Jump = true -- jump
							end
							if waypoint.Action == Enum.PathWaypointAction.Walk then -- if the waypoint requires the NPC to walk
								hum:ChangeState(Enum.HumanoidStateType.Running) -- walk
							end

							if printNotifications then print("Walking to "..tostring(waypoint.Position).."!") end

							if (hrp.Position - target.Position).Magnitude <= 3 and stopNearPlayer then  -- if stopNearPlayer is on, then stop the NPC
								hum:MoveTo(hrp.Position)
								if moveToWait then hum.MoveToFinished:Wait() end
								cor = nil -- clean up the thread
							else -- else, move the NPC normally towards the target
								hum:MoveTo(waypoint.Position)
								if moveToWait then hum.MoveToFinished:Wait() end
								cor = nil -- clean up the thread
							end
						end))
					end
				else -- if path was not a success, and moveIfNoPath is set to true, then we move the NPC 15 studs away
					if moveIfNoPath then
						if printNotifications then print("Path was not succsessful, moving 15 studs away!") end
						hum:MoveTo(target.Position - (hrp.CFrame.LookVector * 15))
					end
				end
			end
		else
			script.Parent.State.Value = "Idle"
		end
	end
end)

if printNotifications then print("Benis' Pathfinding AI script has successfully loaded in "..tostring(tick() - t).." seconds!") end

Animate, also doesn’t work, unfortunately:

local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local pose = "Standing"

local currentAnim = ""
local currentAnimInstance = nil
local currentAnimTrack = nil
local currentAnimKeyframeHandler = nil
local currentAnimSpeed = 1.0

local runAnimTrack = nil
local runAnimKeyframeHandler = nil

local animTable = {}
local animNames = { 
	idle = 	{	
				{ id = "http://www.roblox.com/asset/?id=507766666", weight = 1 },
				{ id = "http://www.roblox.com/asset/?id=507766951", weight = 1 },
				{ id = "http://www.roblox.com/asset/?id=507766388", weight = 9 }
			},
	walk = 	{ 	
				{ id = "http://www.roblox.com/asset/?id=507777826", weight = 10 } 
			}, 
	run = 	{
				{ id = "http://www.roblox.com/asset/?id=507767714", weight = 10 } 
			}, 
	swim = 	{
				{ id = "http://www.roblox.com/asset/?id=507784897", weight = 10 } 
			}, 
	swimidle = 	{
				{ id = "http://www.roblox.com/asset/?id=507785072", weight = 10 } 
			}, 
	jump = 	{
				{ id = "http://www.roblox.com/asset/?id=507765000", weight = 10 } 
			}, 
	fall = 	{
				{ id = "http://www.roblox.com/asset/?id=507767968", weight = 10 } 
			}, 
	climb = {
				{ id = "http://www.roblox.com/asset/?id=507765644", weight = 10 } 
			}, 
	sit = 	{
				{ id = "http://www.roblox.com/asset/?id=507768133", weight = 10 } 
			},	
	toolnone = {
				{ id = "http://www.roblox.com/asset/?id=507768375", weight = 10 } 
			},
	toolslash = {
				{ id = "http://www.roblox.com/asset/?id=522635514", weight = 10 } 
			},
	toollunge = {
				{ id = "http://www.roblox.com/asset/?id=522638767", weight = 10 } 
			},
	wave = {
				{ id = "http://www.roblox.com/asset/?id=507770239", weight = 10 } 
			},
	point = {
				{ id = "http://www.roblox.com/asset/?id=507770453", weight = 10 } 
			},
	dance = {
				{ id = "http://www.roblox.com/asset/?id=507771019", weight = 10 }, 
				{ id = "http://www.roblox.com/asset/?id=507771955", weight = 10 }, 
				{ id = "http://www.roblox.com/asset/?id=507772104", weight = 10 } 
			},
	dance2 = {
				{ id = "http://www.roblox.com/asset/?id=507776043", weight = 10 }, 
				{ id = "http://www.roblox.com/asset/?id=507776720", weight = 10 }, 
				{ id = "http://www.roblox.com/asset/?id=507776879", weight = 10 } 
			},
	dance3 = {
				{ id = "http://www.roblox.com/asset/?id=507777268", weight = 10 }, 
				{ id = "http://www.roblox.com/asset/?id=507777451", weight = 10 }, 
				{ id = "http://www.roblox.com/asset/?id=507777623", weight = 10 } 
			},
	laugh = {
				{ id = "http://www.roblox.com/asset/?id=507770818", weight = 10 } 
			},
	cheer = {
				{ id = "http://www.roblox.com/asset/?id=507770677", weight = 10 } 
			},
}

-- 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 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 = {}

	local allowCustomAnimations = true
	local AllowDisableCustomAnimsUserFlag = false

	local success, msg = pcall(function()
		AllowDisableCustomAnimsUserFlag = UserSettings():IsUserFeatureEnabled("UserAllowDisableCustomAnims2")
	end)

	if (AllowDisableCustomAnimsUserFlag) then
		local success, msg = pcall(function() allowCustomAnimations = game:GetService("StarterPlayer").AllowCustomAnimations end)
		if not success then
			allowCustomAnimations = true
		end
	end

	-- check for config values
	local config = script:FindFirstChild(name)
	if (allowCustomAnimations and 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 = 1
		for _, childPart in pairs(config:GetChildren()) do
			if (childPart:IsA("Animation")) then
				table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
				animTable[name][idx] = {}
				animTable[name][idx].anim = childPart
				local weightObject = childPart:FindFirstChild("Weight")
				if (weightObject == nil) then
					animTable[name][idx].weight = 1
				else
					animTable[name][idx].weight = weightObject.Value
				end
				animTable[name].count = animTable[name].count + 1
				animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
				idx = idx + 1
			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
--			print(name .. " [" .. idx .. "] " .. anim.id .. " (" .. anim.weight .. ")")
		end
	end
end

-- Setup animation objects
function scriptChildModified(child)
	local fileList = animNames[child.Name]
	if (fileList ~= nil) then
		configureAnimationSet(child.Name, fileList)
	end	
end

script.ChildAdded:connect(scriptChildModified)
script.ChildRemoved:connect(scriptChildModified)


for name, fileList in pairs(animNames) do 
	configureAnimationSet(name, fileList)
end	

-- ANIMATION

-- declarations
local toolAnim = "None"
local toolAnimTime = 0

local jumpAnimTime = 0
local jumpAnimDuration = 0.31

local toolTransitionTime = 0.1
local fallTransitionTime = 0.2

-- 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

	currentAnim = ""
	currentAnimInstance = nil
	if (currentAnimKeyframeHandler ~= nil) then
		currentAnimKeyframeHandler:disconnect()
	end

	if (currentAnimTrack ~= nil) then
		currentAnimTrack:Stop()
		currentAnimTrack:Destroy()
		currentAnimTrack = nil
	end

	-- clean up walk if there is one
	if (runAnimKeyframeHandler ~= nil) then
		runAnimKeyframeHandler:disconnect()
	end
	
	if (runAnimTrack ~= nil) then
		runAnimTrack:Stop()
		runAnimTrack:Destroy()
		runAnimTrack = nil
	end
	
	return oldAnim
end

function getHeightScale()
	if Humanoid then
		local bodyHeightScale = Humanoid:FindFirstChild("BodyHeightScale")
		if bodyHeightScale and bodyHeightScale:IsA("NumberValue") then
			return bodyHeightScale.Value
		end
	end
	
	return 1
end

local smallButNotZero = 0.0001
function setRunSpeed(speed)
	if speed < 0.33 then
		currentAnimTrack:AdjustWeight(1.0)		
		runAnimTrack:AdjustWeight(smallButNotZero)
	elseif speed < 0.66 then
		local weight = ((speed - 0.33) / 0.33)
		currentAnimTrack:AdjustWeight(1.0 - weight + smallButNotZero)
		runAnimTrack:AdjustWeight(weight + smallButNotZero)
	else
		currentAnimTrack:AdjustWeight(smallButNotZero)
		runAnimTrack:AdjustWeight(1.0)
	end
	
	local speedScaled = speed * 1.25

	local heightScale = getHeightScale()	
	
	runAnimTrack:AdjustSpeed(speedScaled / heightScale)
	currentAnimTrack:AdjustSpeed(speedScaled / heightScale)
end


function setAnimationSpeed(speed)
	if speed ~= currentAnimSpeed then
		currentAnimSpeed = speed
		if currentAnim == "walk" then
			setRunSpeed(speed)
		else
			currentAnimTrack:AdjustSpeed(currentAnimSpeed)
		end
	end
end

function keyFrameReachedFunc(frameName)
	if (frameName == "End") then
		if currentAnim == "walk" then
			runAnimTrack.TimePosition = 0.0
			currentAnimTrack.TimePosition = 0.0
		else
			local repeatAnim = currentAnim
			-- return to idle if finishing an emote
			if (emoteNames[repeatAnim] ~= nil and emoteNames[repeatAnim] == false) then
				repeatAnim = "idle"
			end
			
			local animSpeed = currentAnimSpeed
			playAnimation(repeatAnim, 0.15, Humanoid)
			setAnimationSpeed(animSpeed)
		end
	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

function playAnimation(animName, transitionTime, humanoid) 	
	local idx = rollAnimation(animName)
	local anim = animTable[animName][idx].anim

	-- switch animation		
	if (anim ~= currentAnimInstance) then
		
		if (currentAnimTrack ~= nil) then
			currentAnimTrack:Stop(transitionTime)
			currentAnimTrack:Destroy()
		end

		if (runAnimTrack ~= nil) then
			runAnimTrack:Stop(transitionTime)
			runAnimTrack:Destroy()
		end

		currentAnimSpeed = 1.0
	
		-- load it to the humanoid; get AnimationTrack
		currentAnimTrack = humanoid:LoadAnimation(anim)
		currentAnimTrack.Priority = Enum.AnimationPriority.Core
		 
		-- play the animation
		currentAnimTrack:Play(transitionTime)
		currentAnim = animName
		currentAnimInstance = anim

		-- set up keyframe name triggers
		if (currentAnimKeyframeHandler ~= nil) then
			currentAnimKeyframeHandler:disconnect()
		end
		currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
		
		-- check to see if we need to blend a walk/run animation
		if animName == "walk" then
			local runAnimName = "run"
			local runIdx = rollAnimation(runAnimName)

			runAnimTrack = humanoid:LoadAnimation(animTable[runAnimName][runIdx].anim)
			runAnimTrack.Priority = Enum.AnimationPriority.Core
			runAnimTrack:Play(transitionTime)		
			
			if (runAnimKeyframeHandler ~= nil) then
				runAnimKeyframeHandler:disconnect()
			end
			runAnimKeyframeHandler = runAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)	
		end
	end

end

-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------

local toolAnimName = ""
local toolAnimTrack = nil
local toolAnimInstance = nil
local currentToolAnimKeyframeHandler = nil

function toolKeyFrameReachedFunc(frameName)
	if (frameName == "End") then
		playToolAnimation(toolAnimName, 0.0, Humanoid)
	end
end


function playToolAnimation(animName, transitionTime, humanoid, priority)	 		
		local idx = rollAnimation(animName)
		local anim = animTable[animName][idx].anim

		if (toolAnimInstance ~= anim) then
			
			if (toolAnimTrack ~= nil) then
				toolAnimTrack:Stop()
				toolAnimTrack:Destroy()
				transitionTime = 0
			end
					
			-- load it to the humanoid; get AnimationTrack
			toolAnimTrack = humanoid:LoadAnimation(anim)
			if priority then
				toolAnimTrack.Priority = priority
			end
			 
			-- play the animation
			toolAnimTrack:Play(transitionTime)
			toolAnimName = animName
			toolAnimInstance = anim

			currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
		end
end

function stopToolAnimations()
	local oldAnim = toolAnimName

	if (currentToolAnimKeyframeHandler ~= nil) then
		currentToolAnimKeyframeHandler:disconnect()
	end

	toolAnimName = ""
	toolAnimInstance = nil
	if (toolAnimTrack ~= nil) then
		toolAnimTrack:Stop()
		toolAnimTrack:Destroy()
		toolAnimTrack = nil
	end

	return oldAnim
end

-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- STATE CHANGE HANDLERS

function onRunning(speed)
	if speed > 0.5 then
		local scale = 16.0
		playAnimation("walk", 0.2, Humanoid)
		setAnimationSpeed(speed / scale)
		pose = "Running"
	else
		if emoteNames[currentAnim] == nil then
			playAnimation("idle", 0.2, Humanoid)
			pose = "Standing"
		end
	end
end

function onDied()
	pose = "Dead"
end

function onJumping()
	playAnimation("jump", 0.1, Humanoid)
	jumpAnimTime = jumpAnimDuration
	pose = "Jumping"
end

function onClimbing(speed)
	local scale = 5.0
	playAnimation("climb", 0.1, Humanoid)
	setAnimationSpeed(speed / scale)
	pose = "Climbing"
end

function onGettingUp()
	pose = "GettingUp"
end

function onFreeFall()
	if (jumpAnimTime <= 0) then
		playAnimation("fall", fallTransitionTime, Humanoid)
	end
	pose = "FreeFall"
end

function onFallingDown()
	pose = "FallingDown"
end

function onSeated()
	pose = "Seated"
end

function onPlatformStanding()
	pose = "PlatformStanding"
end

-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------

function onSwimming(speed)
	if speed > 1.00 then
		local scale = 10.0
		playAnimation("swim", 0.4, Humanoid)
		setAnimationSpeed(speed / scale)
		pose = "Swimming"
	else
		playAnimation("swimidle", 0.4, Humanoid)
		pose = "Standing"
	end
end

function animateTool()
	if (toolAnim == "None") then
		playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle)
		return
	end

	if (toolAnim == "Slash") then
		playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action)
		return
	end

	if (toolAnim == "Lunge") then
		playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action)
		return
	end
end

function getToolAnim(tool)
	for _, c in ipairs(tool:GetChildren()) do
		if c.Name == "toolanim" and c.className == "StringValue" then
			return c
		end
	end
	return nil
end

local lastTick = 0

function stepAnimate(currentTime)
	local amplitude = 1
	local frequency = 1
  	local deltaTime = currentTime - lastTick
  	lastTick = currentTime

	local climbFudge = 0
	local setAngles = false

  	if (jumpAnimTime > 0) then
  		jumpAnimTime = jumpAnimTime - deltaTime
  	end

	if (pose == "FreeFall" and jumpAnimTime <= 0) then
		playAnimation("fall", fallTransitionTime, Humanoid)
	elseif (pose == "Seated") then
		playAnimation("sit", 0.5, Humanoid)
		return
	elseif (pose == "Running") then
		playAnimation("walk", 0.2, Humanoid)
	elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
		stopAllAnimations()
		amplitude = 0.1
		frequency = 1
		setAngles = true
	end

	-- Tool Animation handling
	local tool = Character:FindFirstChildOfClass("Tool")
	local requireHandleCheck = not UserSettings():IsUserFeatureEnabled("UserToolR15Fix")
	if tool and ((requireHandleCheck and tool.RequiresHandle) or tool:FindFirstChild("Handle")) then
		local animStringValueObject = getToolAnim(tool)

		if animStringValueObject then
			toolAnim = animStringValueObject.Value
			-- message recieved, delete StringValue
			animStringValueObject.Parent = nil
			toolAnimTime = currentTime + .3
		end

		if currentTime > toolAnimTime then
			toolAnimTime = 0
			toolAnim = "None"
		end

		animateTool()		
	else
		stopToolAnimations()
		toolAnim = "None"
		toolAnimInstance = nil
		toolAnimTime = 0
	end
end

-- connect events
Humanoid.Died:connect(onDied)
Humanoid.Running:connect(onRunning)
Humanoid.Jumping:connect(onJumping)
Humanoid.Climbing:connect(onClimbing)
Humanoid.GettingUp:connect(onGettingUp)
Humanoid.FreeFalling:connect(onFreeFall)
Humanoid.FallingDown:connect(onFallingDown)
Humanoid.Seated:connect(onSeated)
Humanoid.PlatformStanding:connect(onPlatformStanding)
Humanoid.Swimming:connect(onSwimming)



-- initialize to idle
playAnimation("idle", 0.1, Humanoid)
pose = "Standing"

-- loop to handle timed state transitions and tool animations
while Character.Parent ~= nil do
	local _, currentGameTime = wait(0.1)
	stepAnimate(currentGameTime)
end

The State Controller:

local TS = game:GetService("TweenService")
local Shaker = require(game.ReplicatedStorage.CameraShaker)
local ChaseOn = TS:Create(script.Parent.Head.Chase, TweenInfo.new(2, Enum.EasingStyle.Quad), {Volume = .5})
local ChaseOff = TS:Create(script.Parent.Head.Chase, TweenInfo.new(2, Enum.EasingStyle.Quad), {Volume = 0})
local ZoomOut = TS:Create(workspace.Camera, TweenInfo.new(1, Enum.EasingStyle.Quad), {FieldOfView = 90})
local ZoomIn = TS:Create(workspace.Camera, TweenInfo.new(1, Enum.EasingStyle.Quad), {FieldOfView = 70})
local camShake = Shaker.new(Enum.RenderPriority.Camera.Value, function(shakeCFrame)
	workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * shakeCFrame
end)

script.Parent.State.Changed:Connect(function(state)
	if state == "Chasing" then
		script.Parent.Head.Scream:Play()
		camShake:Shake(camShake.Presets.Explosion)
		TS:Create(game.Lighting.Blur, TweenInfo.new(.05), {Size = 30}):Play()
		ZoomOut:Play()
		ChaseOn:Play()
		wait(.6)
		TS:Create(game.Lighting.Blur, TweenInfo.new(5, Enum.EasingStyle.Sine), {Size = 0}):Play()
	end
	if state == "Idle" then
		print("a")
		ZoomOut:Cancel()
		ZoomIn:Play()
		ChaseOn:Cancel()
		ChaseOff:Play()
	end
end)

while true do
	wait(math.random(10,20))
	local number = math.random(1,2)
	script.Parent.Head["Help"..number]:Play()
end
1 Like