"Attempt to index nil with 'defense'" on dictionary

I’m coding an attack and debuff handler that will story players stats and debuffs in order to apply them per tick. However, it is erroring and stopping after 1 loop when it arrives at line 45.
Here’s the code:

fx = game.Lighting.Effects
rs = game:GetService("RunService")

playerlist = {
	scout = {
		chr = game.Workspace.Scout,
		maxhp = 100,
		speed = 16,
		defense = 0,
		immunity = 0,
		synth = 0,
	},
	owwy = {
		chr = game.Workspace.Owwy,
		maxhp = 100,
		speed = 16,
		defense = 0,
		immunity = 0,
		synth = 0,
	}
}

debuffs = {
	poison = {
		subjects = {
			scout = {[1] = "scout",dmg = 0.2,ticksleft = 0,length = 20, per = 5},
			owwy = {[1] = "owwy",dmg = 5,ticksleft = 0,length = 100, per = 20}
		},
		starttick = function(plr)

		end,

		endtick = function(plr)

		end,

		runtick = function()
			for i,b in pairs(debuffs["poison"]["subjects"]) do

				b["ticksleft"] -= 1
				b["length"] -= 1
				if b["ticksleft"] <= 0 then
					b["ticksleft"] = b["per"]
				
					if playerlist[b[1]]["defense"]~=nil then
						local defs = tonumber(playerlist[b[1]]["defense"])
						attack(b[1],b["dmg"],defs, playerlist[b[1]]["immunity"],"ticks")
					end
				end
				if b["length"] and b["length"] <= 0 then

					table.remove(b)
				end
			end

		end,

	}
}

function attack(plr,dmg,def,imm,typ)
	local hm = playerlist[plr]["chr"].Humanoid
	if typ == "hit" then
		hm.Health -= dmg-(dmg*(def/100))
	elseif typ == "ticks" then
		local att = dmg
		if imm > 0 then
			local roll = math.random(1,100)
			if roll < imm then
				att = 0
			end
		elseif imm<0 then
			local roll = math.random(1,100)
			if roll < -imm then
				att = dmg*2
			end
		end
		hm.Health -= att
	end
end

function heal()

end

function generate()

end

function clear()

end


script.Input.Event:connect(function()

end)

while rs.Heartbeat:Wait() do
	debuffs["poison"].runtick()
end

Two problems. One, you need to define attack before calling it. Two, not really a problem, but just use i instead of b[1]

fx = game.Lighting.Effects
rs = game:GetService("RunService")

function attack(plr,dmg,def,imm,typ)
	local hm = playerlist[plr]["chr"].Humanoid
	if typ == "hit" then
		hm.Health -= dmg-(dmg*(def/100))
	elseif typ == "ticks" then
		local att = dmg
		if imm > 0 then
			local roll = math.random(1,100)
			if roll < imm then
				att = 0
			end
		elseif imm<0 then
			local roll = math.random(1,100)
			if roll < -imm then
				att = dmg*2
			end
		end
		hm.Health -= att
	end
end

playerlist = {
	scout = {
		chr = game.Workspace.Scout,
		maxhp = 100,
		speed = 16,
		defense = 0,
		immunity = 0,
		synth = 0,
	},
	owwy = {
		chr = game.Workspace.Owwy,
		maxhp = 100,
		speed = 16,
		defense = 0,
		immunity = 0,
		synth = 0,
	}
}

debuffs = {
	poison = {
		subjects = {
			scout = {[1] = "scout",dmg = 0.2,ticksleft = 0,length = 20, per = 5},
			owwy = {[1] = "owwy",dmg = 5,ticksleft = 0,length = 100, per = 20}
		},
		starttick = function(plr)

		end,

		endtick = function(plr)

		end,

		runtick = function()
			for i,b in pairs(debuffs["poison"]["subjects"]) do

				b["ticksleft"] -= 1
				b["length"] -= 1
				if b["ticksleft"] <= 0 then
					b["ticksleft"] = b["per"]
				
					if playerlist[i]["defense"]~=nil then
						local defs = tonumber(playerlist[b[1]]["defense"])
						attack(i,b["dmg"],defs, playerlist[b[1]]["immunity"],"ticks")
					end
				end
				if b["length"] and b["length"] <= 0 then

					table.remove(b)
				end
			end

		end,

	}
}

function heal()

end

function generate()

end

function clear()

end


script.Input.Event:connect(function()

end)

while rs.Heartbeat:Wait() do
	debuffs["poison"].runtick()
end

Hopefully I’m understanding your intentions with the code correctly, but I think the issue stems from here.

Instead of removing the subject from the subjects table, you are removing the first index, in this case the name, from the subject description. Then later since the subject still exists within the subjects table, it loops through again and it tries to index the name which you removed, causing an error: "attempt to index nil with ‘defense’ "

So instead, I would replace the above with this:

if b["length"] and b["length"] <= 0 then
	debuffs["poison"]["subjects"][i] = nil
end

This should remove the subject from the subjects table.

Hope this helps!

1 Like