Loot Drop Script Error

This script controls my loot drops from NPC’s. The loot drops fine, but for some reason it gives an error every time it drops some loot.


while true do -- Loop
	wait(.1)
	if (script.Parent.Humanoid.Health <=0) then -- If the Enemy dies (Change Enemy to whatever the enemys Humanoid is named)
		drop() -- calling the drop function
	end
end

The issue is coming from these two lines. Ill attach an error photo regarding line 57, which is the line with drop()

if (script.Parent.Humanoid.Health <=0)
drop()

The character or NPC model does not exist, therefore the Humanoid does not exist. Working with Humanoids is a tad tedious, so have that loop check some conditions to ensure the both NPC model exists and the Humanoid exists.

while true do
     local character = script.Parent
     if not character then
          warn(“Did not find the Character!”)
          continue
     end

     local humanoid = character:FindFirstChildOfClass(“Humanoid”)
     if not humanoid then
          warn(“Did not find the Humanoid!”
          continue
     end

     — do stuff with it
end

Thanks Ill give this a try as soon as I get a chance. Gota go to work for a few days.

Maybe try this:

if (script.Parent.Humanoid.Health <=0) then -- If the Enemy dies (Change Enemy to whatever the enemys Humanoid is named)
	drop() -- calling the drop function
end
local Character = script.Parent

local Humanoid = Character:WaitForChild("Humanoid", 5)

while task.wait() do

if Humanoid.Health <= 0 then
  drop()
task.wait(game.Players.RespawnTime - 1)
break
  end
end

You dont need to add parenthesis

All of these solutions created and endless loop that timed out and froze the client.

Your solution timed out and crashed the client for some reason. Here is my entire script so you can have a better idea of what I have. Ignore the mess up top, it is a work in progress and has a lot of testing drops in it. The end is the only part that isnt working.

function drop() 
	local maths = math.random(1, 6) -- change 6 to however many nothings and tools you have (Right now its a 1 in 6 chance of dropping the tool)
	local tool = game.ReplicatedStorage.Tools:FindFirstChild("Goldlow") -- Finding the tool
	local nothing = game.ReplicatedStorage.Tools:FindFirstChild("Nothing") -- Finding Nothing
	local goldmed = game.ReplicatedStorage.Tools:FindFirstChild("Goldmed")
	local gem = game.ReplicatedStorage.Tools:FindFirstChild("Gem")
	local goldsound = script.Parent.Tool.Handle.coindrop
	local gemsound = script.Parent.Tool.Handle.gemdrop
	local healthpotion = game.ReplicatedStorage.Tools:FindFirstChild("Healing Potion")
	local potionsound = script.Parent.Tool.Handle.potionsound

	if maths == 1 then -- The rest of the lines determin which is chosen
		local toolc = tool:Clone()
		toolc.Parent = game.Workspace
		toolc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- Making the "Tool" Spawn near the Enemy
		script:remove()
		goldsound:Play()
	else if maths == 2 then
			local nothingc = nothing:Clone()
			nothingc.Parent = game.Workspace
			nothingc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- making the "Nothing" Spawn under the map
			script:remove()
		else if maths == 3 then
				local toolc = tool:Clone()
				toolc.Parent = game.Workspace
				toolc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0)
				script:remove()
				goldsound:Play()
			else if maths == 4 then
					local nothingc = nothing:Clone()
					nothingc.Parent = game.Workspace
					nothingc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0)
					script:remove()
				else if maths == 5 then
						local goldmedc = goldmed:Clone()
						goldmedc.Parent = game.Workspace
						goldmedc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- (5,4,0) 
						script:remove()
						goldsound:Play()
					else if maths == 6 then
							local gemc = gem:Clone()
							gemc.Parent = game.Workspace
							gemc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- (0,-200,0) for nothing under the ground.
							script:remove()
							gemsound:Play()
						end
					end
				end
			end
		end
	end
end



while task.wait() do	
		
	if (script.Parent.Humanoid.Health <=0) then -- If the Enemy dies (Change Enemy to whatever the enemys Humanoid is named)
		drop() -- calling the drop function
	end
end

Well you’ll need to add a task.wait() or some sort of “delay” on every step before or after the code block is ran lol

You’ve got a lot of stuff going on here to be running this function every step. I recommend this:

local ReplicatedStorage = game:GetService('ReplicatedStorage')
local RunService = game:GetService('RunService')

local tools = ReplicatedStorage:FindFirstChild('Tools')
local tool = tools:FindFirstChild('Goldlow')
local nothing = tools:FindFirstChild('Nothing')
local goldMed = tools:FindFirstChild('Goldmed')
local gem = tools:FindFirstChild('Gem')
local healthPotion = tools:FindFirstChild('Healing Potion')

local scriptTool = script.Parent:FindFirstChild('Tool'):FindFirstChild('Handle')
local goldSound = scriptTool:FindFirstChild('coindrop')
local gemSound = scriptTool:FindFirstChild('gemdrop')
local potionSound = scriptTool:FindFirstChild('potionSound')

function drop()
	local maths = math.random(1, 6) -- change 6 to however many nothings and tools you have (Right now its a 1 in 6 chance of dropping the tool)

    local characterHead = script.Parent:FindFirstChild('Head')
    if not characterHead then
        warn("Did not find Character's Head")
        return
    end

	if maths == 1 then -- The rest of the lines determin which is chosen
		local toolc = tool:Clone()
		toolc.Parent = game.Workspace
		toolc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- Making the "Tool" Spawn near the Enemy
		goldSound:Play()
		script:Destroy()
	else
		if maths == 2 then
			local nothingc = nothing:Clone()
			nothingc.Parent = game.Workspace
			nothingc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- making the "Nothing" Spawn under the map
			script:Destroy()
		else
			if maths == 3 then
				local toolc = tool:Clone()
				toolc.Parent = game.Workspace
				toolc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0)
				goldSound:Play()
				script:Destroy()
			else
				if maths == 4 then
					local nothingc = nothing:Clone()
					nothingc.Parent = game.Workspace
					nothingc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0)
					script:Destroy()
				else
					if maths == 5 then
						local goldmedc = goldMed:Clone()
						goldmedc.Parent = game.Workspace
						goldmedc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- (5,4,0)
						goldSound:Play()
						script:Destroy()
					else
						if maths == 6 then
							local gemc = gem:Clone()
							gemc.Parent = game.Workspace
							gemc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- (0,-200,0) for nothing under the ground.
							gemSound:Play()
							script:Destroy()
						end
					end
				end
			end
		end
	end
end

RunService.Heartbeat:Connect(function()
    RunService.RenderStepped.Wait()

     local character = script.Parent
     if not character then
        warn('Did not find Character')
        return
     end

     local humanoid = character:FindFirstChildOfClass('Humanoid')
     if not humanoid then
        warn('Did not find Humanoid')
        return
     end

     if humanoid.Health <= 0 then
        drop()
     end
end)

1.) I moved most the object references within the script outside the scope of the the drop() function so that they aren’t being re-referenced everytime the function is run. This should result in minimal performance increase.

2.) Instead of using while true do on the client, you can use connect a callback to RunService.Heartbeat and check your conditions then. When scripting server-side, it’s not the worst idea to use a while true loop sometimes, but on the client, it’s much nicer to utilize the RunService Service.

Other than some other minor changes to your script, I think those two are the most important. I don’t see anything in the script block I’ve changed for you that should cause any issues for you at all. There could be some improvements to the conditions being ran within the drop function, but those wouldn’t necessarily impact your performance, they’d just make the script nicer lol

Thanks I appreciate this. I have been experimenting with this script for months. I am taking a look at this now.

So I plugged this script in to test and it caused a infinite loop of errors that made the game run extremely laggy. I was not able to test the actual drops because the error would not let it get that far. Ill attach a photo.

The error is referring to this line.

RunService.RenderStepped.Wait()

script.Parent.Humanoid.Died:Connect(function()

function drop() 
	local maths = math.random(1, 6) -- change 6 to however many nothings and tools you have (Right now its a 1 in 6 chance of dropping the tool)
	local tool = game.ReplicatedStorage.Tools:FindFirstChild("Goldlow") -- Finding the tool
	local nothing = game.ReplicatedStorage.Tools:FindFirstChild("Nothing") -- Finding Nothing
	local goldmed = game.ReplicatedStorage.Tools:FindFirstChild("Goldmed")
	local gem = game.ReplicatedStorage.Tools:FindFirstChild("Gem")
	local goldsound = script.Parent.Tool.Handle.coindrop
	local gemsound = script.Parent.Tool.Handle.gemdrop
	local healthpotion = game.ReplicatedStorage.Tools:FindFirstChild("Healing Potion")
	local potionsound = script.Parent.Tool.Handle.potionsound

	if maths == 1 then -- The rest of the lines determin which is chosen
		local toolc = tool:Clone()
		toolc.Parent = game.Workspace
		toolc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- Making the "Tool" Spawn near the Enemy
		goldsound:Play()
	else if maths == 2 then
			local nothingc = nothing:Clone()
			nothingc.Parent = game.Workspace
			nothingc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- making the "Nothing" Spawn under the map
		else if maths == 3 then
				local toolc = tool:Clone()
				toolc.Parent = game.Workspace
				toolc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0)

				goldsound:Play()
			else if maths == 4 then
					local nothingc = nothing:Clone()
					nothingc.Parent = game.Workspace
					nothingc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0)
				else if maths == 5 then
						local goldmedc = goldmed:Clone()
						goldmedc.Parent = game.Workspace
						goldmedc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- (5,4,0) 
						goldsound:Play()
					else if maths == 6 then
							local gemc = gem:Clone()
							gemc.Parent = game.Workspace
							gemc.CFrame = script.Parent.Head.CFrame + Vector3.new(5,4,0) -- (0,-200,0) for nothing under the ground
							gemsound:Play()
						end
					end
				end
			end
		end
	end
end

drop()
script:Destroy()
end)

Might’ve made a typo. Try replacing the detecting part with this.
It detects when the humanoid dies instead of checking every second.

1 Like

Been using typescript too much haha.

It’s RunService.RenderStepped:Wait()

Another method of course would be to connect to the .Died event on the Humanoid as @Redluo suggested.

local ReplicatedStorage = game:GetService('ReplicatedStorage')

local tools = ReplicatedStorage:FindFirstChild('Tools')
local tool = tools:FindFirstChild('Goldlow')
local nothing = tools:FindFirstChild('Nothing')
local goldMed = tools:FindFirstChild('Goldmed')
local gem = tools:FindFirstChild('Gem')
local healthPotion = tools:FindFirstChild('Healing Potion')

local scriptTool = script.Parent:FindFirstChild('Tool'):FindFirstChild('Handle')
local goldSound = scriptTool:FindFirstChild('coindrop')
local gemSound = scriptTool:FindFirstChild('gemdrop')
local potionSound = scriptTool:FindFirstChild('potionSound')

function drop()
	local maths = math.random(1, 6) -- change 6 to however many nothings and tools you have (Right now its a 1 in 6 chance of dropping the tool)

    local characterHead = script.Parent:FindFirstChild('Head')
    if not characterHead then
        warn("Did not find Character's Head")
        return
    end

	if maths == 1 then -- The rest of the lines determin which is chosen
		local toolc = tool:Clone()
		toolc.Parent = game.Workspace
		toolc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- Making the "Tool" Spawn near the Enemy
		goldSound:Play()
		script:Destroy()
	else
		if maths == 2 then
			local nothingc = nothing:Clone()
			nothingc.Parent = game.Workspace
			nothingc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- making the "Nothing" Spawn under the map
			script:Destroy()
		else
			if maths == 3 then
				local toolc = tool:Clone()
				toolc.Parent = game.Workspace
				toolc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0)
				goldSound:Play()
				script:Destroy()
			else
				if maths == 4 then
					local nothingc = nothing:Clone()
					nothingc.Parent = game.Workspace
					nothingc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0)
					script:Destroy()
				else
					if maths == 5 then
						local goldmedc = goldMed:Clone()
						goldmedc.Parent = game.Workspace
						goldmedc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- (5,4,0)
						goldSound:Play()
						script:Destroy()
					else
						if maths == 6 then
							local gemc = gem:Clone()
							gemc.Parent = game.Workspace
							gemc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- (0,-200,0) for nothing under the ground.
							gemSound:Play()
							script:Destroy()
						end
					end
				end
			end
		end
	end
end

local humanoid = script.Parent:FindFirstChildOfClass('Humanoid')
assert(humanoid, string.format('Failed to get Humanoid for "%s" character.', script.Parent.Name + "'s"))

humanoid.Died:Connect(drop)

I love this competition to get the solution lol.
But yeah, RunService is good but firing once when triggered is the most ideal and efficient.

could also cut out the redundant wall of elseif statements with a table lol

local ReplicatedStorage = game:GetService('ReplicatedStorage')

local tools = ReplicatedStorage:FindFirstChild('Tools')
local tool = tools:FindFirstChild('Goldlow')
local nothing = tools:FindFirstChild('Nothing')
local goldMed = tools:FindFirstChild('Goldmed')
local gem = tools:FindFirstChild('Gem')
local healthPotion = tools:FindFirstChild('Healing Potion')

local scriptTool = script.Parent:FindFirstChild('Tool'):FindFirstChild('Handle')
local goldSound = scriptTool:FindFirstChild('coindrop')
local gemSound = scriptTool:FindFirstChild('gemdrop')
local potionSound = scriptTool:FindFirstChild('potionSound')


local Sounds = {
	[1] = goldSound,
	[3] = goldSound,
	[5] = goldSound,
	[6] = gemSound
}
local ItemDrops = {
	[1] = tool,
	[2] = nothing,
	[3] = tool,
	[4] = nothing,
	[5] = goldMed,
	[6] = gem
}


function drop()
	local maths = math.random(1, 6) -- change 6 to however many nothings and tools you have (Right now its a 1 in 6 chance of dropping the tool)

    local characterHead = script.Parent:FindFirstChild('Head')
    if not characterHead then
        warn("Did not find Character's Head")
        return
    end

	local Item = ItemDrops[maths]:Clone() --grabs the item from its index in the item table rather than using a huge elseif statement lol
	local Sound = Sounds[maths] --grabs the correlating sound from its index in the sound table, if it exists

	Item.Parent = workspace
	Item.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0)
	if Sound then --if the item has a special sound, play it
		Sound:Play()
	end
	script:Destroy()

	--[[if maths == 1 then -- The rest of the lines determin which is chosen
		local toolc = tool:Clone()
		toolc.Parent = game.Workspace
		toolc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- Making the "Tool" Spawn near the Enemy
		goldSound:Play()
		script:Destroy()
	else
		if maths == 2 then
			local nothingc = nothing:Clone()
			nothingc.Parent = game.Workspace
			nothingc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- making the "Nothing" Spawn under the map
			script:Destroy()
		else
			if maths == 3 then
				local toolc = tool:Clone()
				toolc.Parent = game.Workspace
				toolc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0)
				goldSound:Play()
				script:Destroy()
			else
				if maths == 4 then
					local nothingc = nothing:Clone()
					nothingc.Parent = game.Workspace
					nothingc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0)
					script:Destroy()
				else
					if maths == 5 then
						local goldmedc = goldMed:Clone()
						goldmedc.Parent = game.Workspace
						goldmedc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- (5,4,0)
						goldSound:Play()
						script:Destroy()
					else
						if maths == 6 then
							local gemc = gem:Clone()
							gemc.Parent = game.Workspace
							gemc.CFrame = characterHead.CFrame + Vector3.new(5, 4, 0) -- (0,-200,0) for nothing under the ground.
							gemSound:Play()
							script:Destroy()
						end
					end
				end
			end
		end
	end]]
end

local humanoid = script.Parent:FindFirstChildOfClass('Humanoid')
assert(humanoid, string.format('Failed to get Humanoid for "%s" character.', script.Parent.Name + "'s"))

humanoid.Died:Connect(drop)
3 Likes

I was gonna suggest this but I feared it’d be too much spoonfeeding. Good on you

Haha ok ok I got a lot to go over here. Thanks I will check these suggestions out after I get off work. It’s not too much spoon feeding, I take the time to really get into what I am learning and seeing. This is beyond my comfort zone and I can feel my brain expanding. It’s slightly painful haha.

1 Like

Thanks, This solution worked well for me.

I added drop in the first line for function

script.Parent.Humanoid.Died:Connect(function(drop)
1 Like

I tried this one but it gave me another error. Thanks tho. I was able to get something that worked from this thread.