Task.Spawn function only works in ModuleScript

I want my npcs to be able to attack players asynchronously. To solve this without dealing with closing coroutines when the function finishes, I call the attack functions with task.spawn. Problem is, the function runs once then the script errors out.

Error in text form:

02:09:49.593  ServerScriptService.AI.Main.Zombie:91: invalid argument #1 to 'spawn' (function or thread expected)  -  Server - Zombie:91
  02:09:49.593  Stack Begin  -  Studio
  02:09:49.593  Script 'ServerScriptService.AI.Main.Zombie', Line 91 - function attack  -  Studio - Zombie:91
  02:09:49.593  Script 'ServerScriptService.AI.Main', Line 180 - function tick  -  Studio - Main:180
  02:09:49.593  Script 'ServerScriptService.EntityHandler', Line 24  -  Studio - EntityHandler:24
  02:09:49.593  Stack End  -  Studio

The ModuleScript:

local moveset = {}

moveset.__index = moveset

function moveset.new(entity)
	local self = {
		debounces = {
			["Attack"] = false,
			["Punch"] = false,
			["Bite"] = false,
			["Lunge"] = false,
		},
		cooldowns = {
			["Attack"] = .3,
			["Punch"] = .1,
			["Bite"] = 1,
			["Lunge"] = 2,
		},
		attacks = {},
		loadedAnimations = false,
		entity = entity,
		animationTracks = {},
	}
	setmetatable(self, moveset)
	self:loadAnimations()

	return self
end

function moveset:punch()
	if self.debounces.Punch == false then
		self.debounces.Punch = true
		self.animationTracks.Punch:Play()
		self.animationTracks.Punch.Ended:Wait()
		self.debounces.Punch = false
		if (self.entity.humanoidRootPart.Position - self.entity.targets[1].HumanoidRootPart.Position).Magnitude <= 3 then
			
		end
		task.wait(self.cooldowns.Attack)
		self.debounces.Attack = false
	end
end

function moveset:bite()
	if self.debounces.Bite == false then
		self.debounces.Bite = true
		self.animationTracks.Bite:Play()
		self.animationTracks.Bite.Ended:Wait()
		self.debounces.Bite = false
		if (self.entity.humanoidRootPart.Position - self.entity.targets[1].HumanoidRootPart.Position).Magnitude <= 3 then
			self.entity.humanoid.Health += 10
		end
		task.wait(self.cooldowns.Attack)
		self.debounces.Attack = false
	end
end

function moveset:lunge()
	if self.debounces.Lunge == false then
		self.debounces.Lunge = true
		self.animationTracks.Lunge:Play()
		self.animationTracks.Lunge.Ended:Wait()
		self.debounces.Lunge = false
		if (self.entity.humanoidRootPart.Position - self.entity.targets[1].HumanoidRootPart.Position).Magnitude <= 3 then
			
		end
		task.wait(self.cooldowns.Attack)
		self.debounces.Attack = false
	end
end

function moveset:attack()
	
	--print(self.debounces)
	if self.debounces.Attack == false then
		--print("attack "..self.entity.targets[1].Name)
		if self.entity.humanoidRootPart and self.entity.humanoid.Health > 0 and self.entity.targets[1] ~= nil then
			local targetDistance = (self.entity.humanoidRootPart.Position - self.entity.targets[1].HumanoidRootPart.Position).Magnitude

			if targetDistance <= 3 then
				self.debounces.Attack = true
				task.spawn(self:bite())
			elseif targetDistance <= 7 then
				self.debounces.Attack = true
				task.spawn(self:punch())
			elseif targetDistance <= 16 then
				self.debounces.Attack = true
				task.spawn(self:lunge())
			end
		end
	end
end

function moveset:loadAnimations()
	if self.loadedAnimations then
		return
	end

	self.loadedAnimations = true

	local animationsFolder = self.entity.character.Animations
	local animator = self.entity.humanoid.Animator

	local animationTracks = {}
	for _, animation in animationsFolder:GetChildren() do
		local animationTrack = animator:LoadAnimation(animation)
		animationTracks[animation.Name] = animationTrack
	end

	self.animationTracks = animationTracks
end

return moveset

try

if targetDistance <= 3 then
				self.debounces.Attack = true
				task.spawn(self.bite, self)
			elseif targetDistance <= 7 then
				self.debounces.Attack = true
				task.spawn(self.punch, self)
			elseif targetDistance <= 16 then
				self.debounces.Attack = true
				task.spawn(self.lunge, self)
			end
2 Likes