Problem on tower targetting system happening unintentionally in unison

The way the towers in my tower defense game use their targetting system uses it in a way which makes it in unison; and it is hard to manage in separate scripts as the towers, when placed, are cloned with their script inside each tower.

Is there a way to make it so the towers do not achieve this simultaneous behavior?

This is the targetting function used to fire to the zombie parented in the tower(server side):

while task.wait(tower_cooldown.Value) do
		local target = getzombie()
		if target and target:FindFirstChild("Humanoid") and target.Humanoid.Health > 0 then
			tower_shoot:FireAllClients(tower, "Shoot", nil, target)
			task.spawn(facetarget, tower, target, 0.1)
			task.wait(0.1)
			if target:FindFirstChild("Humanoid") then
				target:FindFirstChild("Humanoid"):TakeDamage(tower_damage.Value)
				target:FindFirstChild("Humanoid").HealthChanged:Connect(function(health)
					if health == 0 then
						game.Players[tower:FindFirstChild("PlayerPlaced").Value].Cash.Value += math.ceil(target:FindFirstChild("Humanoid").MaxHealth/2)
					end
				end)
			end
		end
	end

Yes, So I am going to do a quick overview of your code clean some thing sup.

But, the first thing you may want to consider looking at OOP and instead of managing them via scripts inside of each one, which is kind of like OOP, you manage it with a module and OOP style. Basically it will achieve the same effect, but you wont need to manage like a ton of scripts.

--[[
STEP one lets clean this code up, will make notes on changes

NOTE due to not having full code, consider this a psudo code it should work in your situation but 
you may need to take some time with it. 
]]

--[[OLD CODE
while task.wait(tower_cooldown.Value) do
	local target = getzombie()
	if target and target:FindFirstChild("Humanoid") and target.Humanoid.Health > 0 then
		tower_shoot:FireAllClients(tower, "Shoot", nil, target)
		task.spawn(facetarget, tower, target, 0.1)
		task.wait(0.1)
		if target:FindFirstChild("Humanoid") then
			target:FindFirstChild("Humanoid"):TakeDamage(tower_damage.Value)
			target:FindFirstChild("Humanoid").HealthChanged:Connect(function(health)
				if health == 0 then
					game.Players[tower:FindFirstChild("PlayerPlaced").Value].Cash.Value += math.ceil(target:FindFirstChild("Humanoid").MaxHealth/2)
				end
			end)
		end
	end
end
--]]

--[[
We get rid of your 3 depth "and" in MOST cases I do not suggest doing 3 depth ANDS
if you do, I suggest a dropping format BUT a general more effecient easier to read is
to treat them as predicates -> as you see below we do all the same checks 
you used to do, but if any of them fail on teh way, wthen we immedantly return false

again this is EXACTLY waht will happen in code, except when you use an AND it has to check to make sure aLL
of the conditions meet it.   In this case, they do not.  
STeer clear of using  " if thing and " <-- its just not reading well better to do  "if thing ~= nil" or use 'not' 
]]
local function getValidTarget(target)
	
	if not target then return false end
	if not target:FindFirstChild("Humanoid") then return false end
	if target.Humanoid.Health <= 0 then return false end 

	return true
end

local function InitiateTowerBehaviors()
	task.spawn(
		facetarget,
		tower, 
		target, 
		0.1
	)
end

--[[
TODO
]]
local function _towerHealthChangedEvent(health)
	-- See we dont want to do anything if our health is still greator then 0
	-- again this is example of a predicte 
	if health > 0 then return end
	-- Doing some of this just to icnreas readability.  this could be reorganized for a few less calls but i doubt a perf prob
	local TargetHumanoid = target:FindFirstChild("Humanoid")
	
	local PlayerPlaced = tower:FindFirstChild("PlayerPlaced").Value
	local PlayerOwner = game.Players[PlayerPlaced.Value]
	
	PlayerOwner.Cash.Value += math.ceil(TargetHumanoid.MaxHealth/2)
end

local function DamageEvent(target)
	-- We should only call this once at the start and use as more effecient 
	-- as well as readable
	-- And we will do our first predicate check which will bounce us out if nil
	-- Reduces our if blocks more and now since we have a reusable vvar 
	--TargetHumanoid makes everything more readable
	local TargetHumanoid = target:FindFirstChild("Humanoid")
	if TargetHumanoid == nil then return end
	
	TargetHumanoid:TakeDamage(tower_damage.Value)
	
	-- You need to manage this event somewhere right now you are like making events every time 
	-- unless this only triggers off once 
	-- So basically if this only happens ONCE then sure but if not you need to memory clean up these connections 
	TargetHumanoid.HealthChanged:Connect(_towerHealthChangedEvent)	
end


-- So I don't particular undersatnd this pattern you have here 
-- It looks like you should want to use 
-- It looks liek we should replace the while wait with
task.delay(
	tower_coolDown.Value,
	function()
		-- Now we have a predicate function we can easily add more conditions too easy to debug or break out
		local target = getzombie()	
		if not getValidTarget(target) then return end

		tower_shoot:FireAllClients(
			tower, 
			"Shoot",
			nil, 
			target
		)
		
		InitiateTowerBehaviors()
		
		task.delay(0.1, DamageEvent(target))		
	end
)

--[[ OK 
so now its a bit easier to diagnose waht is going on. 

So while i changed it and its hard to decern, I am going to guess your WHILE Loop 
somehow RESETS in some way that you have done things. 

So that every "period of time" they then do something. 

The deal is that when you make that setting it looks like they are all pointing to that value.
So any targeting and watiing is always uniform between them because of the detection time.

I suggest looking for some kind of recuring timer that you can use for towers that on creation it starts checking each time. 

OR you need some random value that is either initilized on finding a target OR on each turret that add a little bit of warm up time 
before tarcking onto the target.

Essentially they are all uniformally using the same value for detection time, on the while loop, so after the first or second runs thats just going 
to flat line out and they all be in sync. 

If you care about rotation and target aquistion times, you could always speed that up based on what the warm up time was that way 
in the end they will still have the same balanced target aquistiion time
]]

I know my code is slightly unreadable but after some tweaking to your script to adjust it to my game, it wouldnt work with multiple functions working like this.

I’d suggest maybe a way from my script to be able to communicate with towers that the zombie has been dealt with and that they should target the next zombie.