.ChildRemoved only runs upon one specific instance being deleted and if statement inside runs twice

i’ve been working on scavenging and waves i made a post on

but it’s just, working really weirdly

wave and difficulty will increment twice for some reason, i just don’t know how to explain it

not to mention the fact the enemies have to be killed in a specific order in order to even get deleted from a folder (this runs in a seperate script, i’ll include it aswell)

visual presentation:


module script

function RNG(enemy)
	local totalChance = 0

	for _,chance in enemy do
		totalChance += chance
	end

	local rng = math.random(1, totalChance)

	for option,chance in enemy do
		rng -= chance
		if rng <= 0 then return option end
	end
end


function SpawnEnemies(enemies, part)
	while enemies < spawnCap.Value do
		local size = part.Size
		local position = part.Position
		local halfSize = size * 0.5

		local randomX = math.random(-halfSize.X, halfSize.X)
		local randomZ = math.random(-halfSize.Z, halfSize.Z)

		local randomPosition = position + Vector3.new(randomX, 0, randomZ)

		local enemy = RNG(meleeEnemies) -- meleeEnemies is a table of enemies, for now it only has 1 enemy with a 100% spawn chance so don't worry about it
		local enemyClone = enemy:Clone()
		enemyClone.Parent = workspace.Enemies
		enemyClone.HumanoidRootPart.CFrame = CFrame.new(randomPosition)
		enemyClone.DetectionPart.Size = Vector3.new(1000,250,1000)

		enemies += 1
		task.wait()
	end

	return enemies
end


local wave = {}

-- // SPAWNING ENEMIES FUNCTION

function wave.SpawnEnemies()
	if ongoing.Value then return end

	ongoing.Value = true

	if difficulty.Value >= 5 and waveNumber.Value >= 5 then
		-- // SPAWN RANGED AND MELEE ENEMIES (this is unused for now so don't worry)
	else
		for _,part in spawnParts:GetChildren() do
			local enemies = 0

			if part.Name == "WaveSpawn" then
				if #workspace.Enemies:GetChildren() > 0 then
					workspace.Enemies:ClearAllChildren()

					enemies = SpawnEnemies(enemies, part)

					print(enemies)
					return enemies
				end		
			end
		end
	end
end

-- // REDUCING ENEMY COUNT FUNCTION

function wave.ReduceEnemyCount(storm, stormStart, stormMoving, scavenging)
	local enemyCount = workspace.Enemies

	enemyCount.ChildRemoved:Connect(function()
		if #enemyCount:GetChildren() > 0 then
			local enemies = wave.SpawnEnemies()
			enemies -= 1 -- this will NOT subtract
			print("Enemies remaining: " .. enemies) -- this will NOT print
		else
			print("The wave is ending...") -- this will run twice

			if waveNumber.Value <= 3 then
				spawnCap.Value += 3
			else
				if difficulty.Value > 12 then
					spawnCap.Value *= 2
				else
					spawnCap.Value += 5
				end
			end

			task.wait(3)

			waveNumber.Value += 1 -- this will run twice
			difficulty.Value += math.random(1,3) -- this will run twice

			print("Current wave: " .. waveNumber.Value)
			print("Current difficulty: " .. difficulty.Value)
			storm.CFrame = stormStart.CFrame

			stormMoving.Value = false
			scavenging.Value = true
			ongoing.Value = false
		end
	end)
end

return wave

not to mention the fact the enemies have to be killed in a specific order in order to even get deleted from a folder (this runs in a seperate script, i’ll include it aswell)

this script is inside each enemy

local Dummy = script.Parent
local Humanoid = Dummy.Humanoid
local Animator = Humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", Humanoid)

local Idle = Dummy:WaitForChild("Idle")
local Walk = Dummy:WaitForChild("Walk")
local mouth = script.Parent:WaitForChild("Mouth")

local IdleAnim = Animator:LoadAnimation(Idle)
local WalkAnim = Animator:LoadAnimation(Walk)
IdleAnim:Play()

local dService = game:GetService("Debris")

local function changeParent()
	if Humanoid.Health <= 0 then
		Dummy.Parent = workspace
		mouth.DeathSound:Play()
		WalkAnim:Stop()
		IdleAnim:Stop()
		
		dService:AddItem(Dummy, 10)
	end
end

Humanoid.Running:Connect(function(speed)
	if speed > 1 then
		if not WalkAnim.IsPlaying then
			WalkAnim:Play()
			IdleAnim:Stop()
		end
	else
		if not IdleAnim.IsPlaying then
			WalkAnim:Stop()
			IdleAnim:Play()
		end
	end
end)

while IdleAnim.IsPlaying do
	mouth.IdleSound:Play()
	local randomCooldown = math.random(3,10)
	task.wait(randomCooldown)
end

Humanoid:GetPropertyChangedSignal("Health"):Connect(changeParent)
1 Like

unsolved post?!?!?!?

BUMP! :point_right:

okay so a bit of progress has been made

here are the things that have been fixed:

  • Specific kill order (this was caused by an entirely different script lmao
  • Wave end triggering twice (this will trigger once now)

buuuuttt

the SpawnEnemies function will always return nil, looking into this but help would be appreciated

current code:

function RNG(enemy)
	local totalChance = 0

	for _,chance in enemy do
		totalChance += chance
	end

	local rng = math.random(1, totalChance)

	for option,chance in enemy do
		rng -= chance
		if rng <= 0 then return option end
	end
end


function SpawnEnemies(enemies, part)
	while enemies < spawnCap.Value do
		local size = part.Size
		local position = part.Position
		local halfSize = size * 0.5

		local randomX = math.random(-halfSize.X, halfSize.X)
		local randomZ = math.random(-halfSize.Z, halfSize.Z)

		local randomPosition = position + Vector3.new(randomX, 0, randomZ)

		local enemy = RNG(meleeEnemies)
		local enemyClone = enemy:Clone()
		enemyClone.Parent = workspace.Enemies
		enemyClone.HumanoidRootPart.CFrame = CFrame.new(randomPosition)
		enemyClone.DetectionPart.Size = Vector3.new(1000,250,1000)

		enemies += 1
		task.wait()
	end

	return enemies
end


local wave = {}

-- // SPAWNING ENEMIES FUNCTION

function wave.SpawnEnemies()
	if ongoing.Value then return end

	ongoing.Value = true

	if difficulty.Value >= 5 and waveNumber.Value >= 5 then
		-- // SPAWN RANGED AND MELEE ENEMIES 
	else
		for _,part in spawnParts:GetChildren() do
			local enemies = 0

			if part.Name == "WaveSpawn" then
				if #workspace.Enemies:GetChildren() > 0 then
					workspace.Enemies:ClearAllChildren()

					enemies = SpawnEnemies(enemies, part)

					print(enemies)
					return enemies
				end		
			end
		end
	end
end

-- // REDUCING ENEMY COUNT FUNCTION

function wave.ReduceEnemyCount(storm, stormStart, stormMoving, scavenging)
	local enemies = wave.SpawnEnemies()
	print(enemies) -- this is nil frown frown

	local enemyCount = workspace.Enemies

	if #enemyCount:GetChildren() > 0 then
		print("abc")
		enemies -= 1 -- tries to subtract from nil! error!!!!
		print("Enemies remaining: " .. enemies)
	else
		print("The wave is ending...")

		if waveNumber.Value <= 3 then
			spawnCap.Value += 3
		else
			if difficulty.Value > 12 then
				spawnCap.Value *= 2
			else
				spawnCap.Value += 5
			end
		end

		task.wait(3)

		waveNumber.Value += 1
		difficulty.Value += math.random(1,3)

		print("Current wave: " .. waveNumber.Value)
		print("Current difficulty: " .. difficulty.Value)
		storm.CFrame = stormStart.CFrame

		stormMoving.Value = false
		scavenging.Value = true
		ongoing.Value = false
	end
end

return wave

okay, a lot has happened

i kept calling a function that kept adding +1 to the enemy count, which would result in an endless loop of subtracting 1 and adding 1 lol

had to create a variable outside the spawning enemies function and change + return that instead of having a enemiesvariable inside the function

the code looks like this now

local enemyStats = require(game:GetService("ServerScriptService"):WaitForChild("Enemies").EnemyStats)

local difficulty = game:GetService("ServerScriptService"):WaitForChild("Phases"):WaitForChild("Waves").Difficulty
local waveNumber = game:GetService("ServerScriptService"):WaitForChild("Phases"):WaitForChild("Waves").Wave
local spawnCap = game:GetService("ServerScriptService"):WaitForChild("Phases"):WaitForChild("Waves").SpawnCap
local spawnParts = workspace:WaitForChild("SpawnParts")

local SS = game:GetService("ServerStorage")

local meleeEnemies = {
	[SS.Enemies.WaveEnemies.Shambler] = 100
}

local rangedEnemies = { -- UNUSED FOR NOW

}

function RNG(enemy)
	local totalChance = 0

	for _,chance in enemy do
		totalChance += chance
	end

	local rng = math.random(1, totalChance)

	for option,chance in enemy do
		rng -= chance
		if rng <= 0 then return option end
	end
end

local wave = {}

-- // SPAWNING ENEMIES FUNCTION

local totalEnemies = 0

function wave.SpawnEnemies()
	totalEnemies = 0
	workspace.Enemies:ClearAllChildren()

	if difficulty.Value >= 5 and waveNumber.Value >= 5 then
		-- // SPAWN RANGED AND MELEE ENEMIES 
	end

	for _,part in spawnParts:GetChildren() do
		if part.Name == "WaveSpawn" then
			while totalEnemies < spawnCap.Value do
				local size = part.Size
				local position = part.Position
				local halfSize = size * 0.5

				local randomX = math.random(-halfSize.X, halfSize.X)
				local randomZ = math.random(-halfSize.Z, halfSize.Z)

				local randomPosition = position + Vector3.new(randomX, 0, randomZ)

				local enemy = RNG(meleeEnemies)
				local enemyClone = enemy:Clone()
				enemyClone.Parent = workspace.Enemies
				enemyClone.HumanoidRootPart.CFrame = CFrame.new(randomPosition)
				enemyClone.DetectionPart.Size = Vector3.new(1000,250,1000)

				totalEnemies += 1
				print("Spawned enemy, total enemies: " .. totalEnemies)
				task.wait()
			end

			return totalEnemies
		end
	end
end

-- // REDUCING ENEMY COUNT FUNCTION


function wave.ReduceEnemyCount(storm, stormStart, stormMoving, scavenging)
	local enemyCount = workspace.Enemies

	if #enemyCount:GetChildren() > 0 then
		totalEnemies -= 1
		print("Enemies remaining: " .. totalEnemies)		
	else
		print("The wave is ending...")

		if waveNumber.Value <= 3 then
			spawnCap.Value += 3
		else
			if difficulty.Value > 12 then
				spawnCap.Value *= 2
			else
				spawnCap.Value += 5
			end
		end

		task.wait(3)

		waveNumber.Value += 1
		difficulty.Value += math.random(1,3)

		print("Current wave: " .. waveNumber.Value)
		print("Current difficulty: " .. difficulty.Value)
		storm.CFrame = stormStart.CFrame

		stormMoving.Value = false
		scavenging.Value = true
	end
end

-- // DESTROY LOOTABLES FUNCTION
function wave.DestroyLootables()
	for _,lootable in workspace.SpawnParts:GetChildren() do
		if lootable.Name == "Locker" or lootable.Name == "Crate" then
			lootable:Destroy()
		end
	end
end

return wave

if anyone ever gets a genius idea to code something like this i hope they find this helpful lol