My game mode is crashing when I make NPCs run, help?

Hello, short introduction: I just signed up on these forums about 5 minutes ago and just started trying to script GMod about 2 days ago, so I’m a bit of a noob. I have been trying to make a custom game mode for me and my friend to play, and for the most part it works pretty well. There is only one problem though, one feature that is causing problems.

The game mode is in the gm_bigcity map, and simply spawns a bunch of combine enemies with weapons all around the map continually (so as one dies, a new one spawns farther away), and the old ragdolls get cleaned up when players are far away and not looking at them. All that works great, but it’s just one thing I added that messes up. See, a big part of my strategy when fighting enemies is simply using a sniper rifle (from an addon), so I did that, boom the enemy is dead… but then what? Nothing. All the NPCs around give little to no shit. To fix this, I made a feature using the OnNPCKilled callback which makes it so when one NPC dies, all the nearby NPCs will rush towards the position of the player that killed that NPC and also set them as an enemy.

It works pretty well, well up until it fucking crashes the entire game. After a whole ton of experimentation, I find the issue! Sort of. By using to -condebug option, I find that this is always the last thing in the log whenever the game crashes. “Bad SetLocalOrigin(1.#QNAN0,1.#QNAN0,1.#QNAN0) on npc_ak47”. It can actually be any weapon though, as I’ve tested it with all the weapons in the pack I got. So I think… it must be an issue with the weapons then, right? Not my fault? Well no, because it doesn’t ever normally happen until I added that feature that makes the NPCs go after the killers. Also, it won’t crash until I’ve shot and killed about 3 enemies. So… perhaps, I’m just setting the task on too many NPCs? I know it has to be related to this feature somehow because if you comment the function out, there won’t be any crashes.

Well, speaking of the task, I also notice that before it crashes if I wait, they’ll run right past me! Now the best way I see of fixing this is by clearing their task schedule when they get near me, but it just seems like there might be a better way… better than using this debug run schedule. So maybe, there is a better way to make NPCs run?

Maybe one of you kind souls can help me, I’ll post my init.lua below (nothing in cl_init.lua), and I’ll also post the addons it uses incase any of you are really kind enough to actually test it to get it working. Note I use the term “Ped” to refer to “NPC” simply because of my history with modding other games that refer to NPCs as Peds (short for pedestrian). The function that makes the nearby NPCs go towards the killers starts on line 201.

Addons used:


-- Setup tables:
gPlayerWeapons = {"fas2_ak47","fas2_m4a1","fas2_m82"}
gNpcWeapons = {"NPC_AK47","NPC_FAL","NPC_Mossberg590","NPC_M1911","NPC_UMP45","NPC_MP5","NPC_P90","NPC_M249","NPC_HK416"}
gNpcTypes = {"npc_combine_s","npc_metropolice"}

-- Get counts:
gPlayerWeapons.n = table.getn(gPlayerWeapons)
gNpcWeapons.n = table.getn(gNpcWeapons)
gNpcTypes.n = table.getn(gNpcTypes)

-- Setup spawns:
gSpawns = {
	{
		{950,-3444,-11135},
		{946,-847,-11135},
		{-1079,-832,-11135},
		{-1074,-3424,-11135},
	},
	{
		{-5199,3369,-10671},
		{-5186,3826,-10671},
		{11871,3859,-10671},
		{11577,3403,-10671},
	},
	{
		{12149,6619,-10671},
		{12155,4458,-10671},
		{12522,4327,-10671},
		{12532,6508,-10671},
	},
	{
		{10103,6263,-11143},
		{10119,5957,-11143},
		{-1301,5983,-11143},
		{-1402,6281,-11143},
	},
	{
		{4464,6433,-11135},
		{5369,6433,-11135},
		{5357,12798,-11135},
		{4780,12802,-11135},
	},
	{
		{5461,4217,-11400},
		{5368,5022,-11392},
		{9862,5035,-11387},
		{9831,4161,-11381},
	},
	{
		{7462,3973,-11407},
		{8242,3968,-11407},
		{8251,-1888,-11407},
		{7455,-1920,-11407},
	},
	{
		{7389,-2350,-11407},
		{8261,-2360,-11407},
		{8297,-8733,-11407},
		{7350,-8862,-11407},
	},
	{
		{5930,-5767,-11135},
		{5999,-6126,-11143},
		{-3699,-6123,-11143},
		{-3705,-5805,-11143},
	},
	{
		{-3926,-3760,-11143},
		{-4298,-3691,-11143},
		{-4307,-10496,-11135},
		{-3895,-10554,-11135},
	},
	{
		{425,1327,-11135},
		{470,487,-11135},
		{-3134,505,-11135},
		{-3166,1289,-11135},
	},
	{
		{1427,-2420,-11143},
		{1410,-2005,-11135},
		{3638,-2026,-11135},
		{3673,-2471,-11135},
	},
}
for i,c in ipairs(gSpawns) do
	local minx,maxx,miny,maxy,z
	for i,v in ipairs(c) do
		if not minx or v[1] < minx then
			minx = v[1]
		end
		if not maxx or v[1] > maxx then
			maxx = v[1]
		end
		if not miny or v[2] < miny then
			miny = v[2]
		end
		if not maxy or v[2] > maxy then
			maxy = v[2]
		end
		if not z or v[3] > z then
			z = v[3]
		end
	end
	c[1],c[2],c[3],c[4],c[5] = minx,maxx,miny,maxy,z
end
gSpawns.n = table.getn(gSpawns)

-- Setup models:
gPlayerModels = {}
for k,m in pairs(player_manager.AllValidModels()) do
	util.PrecacheModel(m)
	table.insert(gPlayerModels,m)
end
gPlayerModels.n = table.getn(gPlayerModels)

-- Player spawn:
function GM:PlayerSpawn(player)
	-- Set position:
	player:SetPos(Vector(math.random(11832,12595),math.random(-3523,-2976),-11136))
	player:SetEyeAngles(Angle(1.14,-166.11,0))
	
	-- Give weapons:
	for i,w in ipairs(gPlayerWeapons) do
		F_GiveWeapon(player,w,3)
	end
	
	-- Set model:
	player:SetModel(gPlayerModels[math.random(1,gPlayerModels.n)])
end

-- Main:
function GM:Tick()
	if gStarted then
		-- Get players:
		gPlayers = player.GetHumans()
		
		-- Spawn/clean:
		if gPeds.n < 180 then
			F_Spawn()
		end
		if gDeadPeds.n > 20 then
			F_Clean()
		end
	end
end

-- Spawn enemies:
gPeds = {n = 0}
function F_Spawn()
	local loc = gSpawns[math.random(1,gSpawns.n)]
	local spawn = Vector(math.random(loc[1],loc[2]),math.random(loc[3],loc[4]),loc[5])
	local canSpawn = true
	for i,player in ipairs(gPlayers) do
		if spawn:Distance(player:GetPos()) < 6000 or player:VisibleVec(spawn) then
			canSpawn = false
			break
		end
	end
	if canSpawn then
		local model = gNpcTypes[math.random(1,gNpcTypes.n)]
		local ped = ents.Create(model)
		if IsValid(ped) then
			ped:SetPos(spawn)
			ped:Spawn()
			ped:Give(gNpcWeapons[math.random(1,gNpcWeapons.n)])
			table.insert(gPeds,ped)
			gPeds.n = gPeds.n + 1
		end
	end
end

-- Clean dead enemies:
gDeadPeds = {n = 0}
hook.Add("OnEntityCreated","F_AddPeds",function(ped)
	if IsValid(ped) and ped:GetClass() == "prop_ragdoll" then
		table.insert(gDeadPeds,ped)
		gDeadPeds.n = gDeadPeds.n + 1
	end
end)
function F_Clean()
	for i,ped in ipairs(gDeadPeds) do
		if IsValid(ped) then
			local pos,notVisible = ped:GetPos(),true
			for i,player in ipairs(gPlayers) do
				if pos:Distance(player:GetPos()) < 4000 or player:Visible(ped) then
					notVisible = false
					break
				end
			end
			if notVisible then
				ped:Remove()
				table.remove(gDeadPeds,i)
				gDeadPeds.n = gDeadPeds.n - 1
				break
			end
		end
	end
end

-- Alert nearby peds when one dies:
function GM:OnNPCKilled(victim,killer)
	if IsValid(victim) and IsValid(killer) and (killer:IsPlayer() or killer:IsNPC()) then
		local pos1,pos2 = victim:GetPos(),killer:GetPos()
		if pos1:Distance(pos2) > 1500 then
			for i,ped in ipairs(gPeds) do
				if ped == victim then
					table.remove(gPeds,i)
					gPeds.n = gPeds.n - 1
					i = i - 1
				elseif ped ~= killer and IsValid(ped) and ped:IsNPC() and pos1:Distance(ped:GetPos()) < 1500 then
					local enemy = ped:GetEnemy()
					if not IsValid(enemy) or ped:GetPos():Distance(enemy:GetPos()) > 2000 then -- not already near an enemy
						ped:ClearSchedule()
						ped:SetEnemy(killer)
						ped:SetLastPosition(pos2)
						ped:SetSchedule(SCHED_FORCED_GO_RUN)
					end
				end
			end
		end
	end
end

-- Wait for entities to initialize:
function GM:InitPostEntity()
	gStarted = true
end

-- New give weapon function:
function F_GiveWeapon(player,name,mags)
	-- Give weapon and ammo:
	local weapon = player:Give(name)
	local ammo = weapon:GetMaxClip1()
	player:SetAmmo(ammo*mags,weapon:GetPrimaryAmmoType())
end

Would you guys hate me for bumping this? Any ideas…? Please? I just wanna know why it’s crashing or if there’s a better way to make NPCs run.