When player changes the textbox name it changes for all

Hello developers, I am making a script that spawns NPCs when they click in the area. The problem I am having is the name of the NPC changing to every single one of them when the player changes its name.

Here is the video showing this:

Please scroll down until you see the function that changes the textbox (spawnNPC)

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")


local localPlayer = Players.LocalPlayer
local mouse = localPlayer:GetMouse()

local placeButton = script.Parent


local modelToPlace = ReplicatedStorage:WaitForChild("Noob")

local placingEnabled = false
local previewModel = nil
local connection = nil

local baseMinX = workspace:WaitForChild("Boundary_MinX", 5)
local baseMaxX = workspace:WaitForChild("Boundary_MaxX", 5)
local baseMinZ = workspace:WaitForChild("Boundary_MinZ", 5)
local baseMaxZ = workspace:WaitForChild("Boundary_MaxZ", 5)

if not baseMinX then
	warn("Boundary_MinX failed to load!")
end
if not baseMaxX then
	warn("Boundary_MaxX failed to load!")
end
if not baseMinZ then
	warn("Boundary_MinZ failed to load!")
end
if not baseMaxZ then
	warn("Boundary_MaxZ failed to load!")
end

print("baseMinX:", baseMinX)
print("baseMaxX:", baseMaxX)
print("baseMinZ:", baseMinZ)
print("baseMaxZ:", baseMaxZ)


local function isInsideBase(position)

	if not baseMinX or not baseMaxX or not baseMinZ or not baseMaxZ then
		warn("One or more boundary parts were not found. Placement checks may not work correctly.")
		return true
	end

	local minX = baseMinX.Position.X
	local maxX = baseMaxX.Position.X
	local minZ = baseMinZ.Position.Z
	local maxZ = baseMaxZ.Position.Z


	return position.X >= minX and position.X <= maxX and position.Z >= minZ and position.Z <= maxZ
end

local maxPlacementHeight = 5

local function updatePreviewModel()
	if previewModel then
		local mousePos = UserInputService:GetMouseLocation()
		local ray = workspace.CurrentCamera:ViewportPointToRay(mousePos.X, mousePos.Y)
		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		raycastParams.FilterDescendantsInstances = {previewModel}
		for _, part in ipairs(previewModel:GetDescendants()) do
			if part:IsA("BasePart") then
				part.CanCollide = false
			end
		end

		local raycastResult = workspace:Raycast(ray.Origin, ray.Direction * 1000, raycastParams)

		if raycastResult then
			local groundPosition = raycastResult.Position
			local previewOffset = 3
			local potentialPosition = groundPosition + Vector3.new(0, previewOffset, 0)

			if potentialPosition.Y <= maxPlacementHeight then
				if isInsideBase(potentialPosition) then
					previewModel:SetPrimaryPartCFrame(CFrame.new(potentialPosition))
				end
			else
				local clampedPosition = Vector3.new(potentialPosition.X, maxPlacementHeight, potentialPosition.Z)
				if isInsideBase(clampedPosition) then
					previewModel:SetPrimaryPartCFrame(CFrame.new(clampedPosition))
				end
			end
		else
			previewModel:SetPrimaryPartCFrame(CFrame.new(Vector3.new(0, -1000, 0)))
		end
	end
end

local function onPlaceButtonClicked()
	placingEnabled = not placingEnabled
	if previewModel then
		previewModel:Destroy()
		previewModel = nil
	end
	if connection then
		connection:Disconnect()
		connection = nil
	end


	if placingEnabled then
		script.Parent.UIStroke.Enabled = true
		if modelToPlace then
			previewModel = modelToPlace:Clone()
			previewModel.Parent = workspace
			for _, part in ipairs(previewModel:GetDescendants()) do
				if part:IsA("BasePart") then
					part.Transparency = 0.5
					part.CanCollide = false
					part.Anchored = true
				end
			end
			updatePreviewModel()
			connection = RunService.RenderStepped:Connect(updatePreviewModel)
		else
			warn("Model to place not found in ReplicatedStorage: Noob")
			placingEnabled = false
		end
	else
		script.Parent.UIStroke.Enabled = false
	end
end



local clickThreshold = 0.3

local isMouseButtonDown = false
local mouseDownTime = 0
local currentlyInteractingNPC = nil

local function handleNPCDamage(npcModel)
	local humanoid = npcModel:FindFirstChild("Humanoid")
	if not humanoid then
		warn("Humanoid not found in NPC:", npcModel:GetFullName())
		return
	end
	print("Connected HealthChanged event for:", npcModel:GetFullName())

	local originalColor = {}
	local partsToColor = {}

	for _, part in ipairs(npcModel:GetDescendants()) do
		if part:IsA("MeshPart") or part:IsA("BasePart") then
			partsToColor[part] = true
			originalColor[part] = part.Color
		end
	end

	humanoid.HealthChanged:Connect(function(oldHealth, newHealth)
		print("HealthChanged event fired for:", npcModel:GetFullName(), "Old Health:", oldHealth, "New Health:", newHealth)
			print("Damage detected for:", npcModel:GetFullName())
			local startOffset = 0.2
			local shakeTweenInfo = TweenInfo.new(0.1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 3, false, 0)


			for part in pairs(partsToColor) do
				part.Color = Color3.fromRGB(255, 0, 0)
				
			end

			task.wait(0.5)

			for part in pairs(partsToColor) do
				if originalColor[part] then
					part.Color = originalColor[part]
				end

		end
	end)
end





FUNCTION THAT CHANGES THE TEXTBOX




local function spawnNPC()
	if placingEnabled and previewModel then
		local previewPosition = previewModel:GetPrimaryPartCFrame().Position
		if isInsideBase(previewPosition) then
			local newModel = modelToPlace:Clone()
			local torso = newModel.Torso
			newModel.Parent = workspace
			newModel:SetPrimaryPartCFrame(previewModel:GetPrimaryPartCFrame())

			local genders ={"Male", "Female"}
			local maleNames = {"Liam", "Noah", "Oliver", "James", "Elijah", "Mateo", "Theodore", "Henry", "Lucas", "William", "Benjamin", "Levi", "Sebastian", "Jack", "Ezra", "Michael", "Daniel", "Leo", "Owen", "Samuel", "Hudson", "Alaxander", "Asher", "Luca", "Ethan", "John", "David", "Jackson", "Joseph", "Mason", "Luke", "Matthew", "Julian", "Dylan", "Elias", "Jacob", "Maverick", "Gabriel", "Logan", "Aiden", "Thomas", "Isaac", "Miles", "Grayson", "Santiago", "Anthony", "Wyatt", "Carter", "Jayden", "Ezekiel"}
			local femaleNames = {"Olivia", "Emma", "Charlotte", "Amelia", "Sophia", "Mia", "Isabella", "Ava", "Evelyn", "Luna", "Harper", "Sofia", "Camila", "Eleanor", "Elizabeth", "Violet", "Scarlett", "Emily", "Hazel", "Lily", "Gianna", "Aurora", "Nora", "Chloe", "Ellie", "Mila", "Avery", "Layla", "Abigail", "Ella", "Isla", "Eliana", "Nova", "Madison", "Zoe", "Ivy", "Lucy", "Willow", "Emilia", "Riley", "Naomi", "Victoria", "Stella", "Elena", "Hannah", "Valentina", "Maya", "Zoey"}

			local randomGender = math.random(1, #genders)
			local randomGender2 = genders[randomGender]
			if randomGender2 == "Male" then
				local randomNames = math.random(1, #maleNames)
				local randomNames2 = maleNames[randomNames]

				local configuration = newModel:FindFirstChild("Configuration")
				if configuration then
					local genderValue = configuration:FindFirstChild("Gender")
					local nameValue = configuration:FindFirstChild("Names")
					if genderValue and genderValue:IsA("StringValue") then
						genderValue.Value = "Male"
					else
						warn("Gender StringValue not found or is not a StringValue")
					end
					if nameValue and nameValue:IsA("StringValue") then
						nameValue.Value = randomNames2
					else
						warn("Name StringValue not found or is not a StringValue")
					end
				else
					warn("Configuration folder not found")
				end
			elseif randomGender2 == "Female" then
				local randomNames = math.random(1, #femaleNames)
				local randomNames2 = femaleNames[randomNames]

				local configuration = newModel:FindFirstChild("Configuration")
				if configuration then
					local genderValue = configuration:FindFirstChild("Gender")
					local nameValue = configuration:FindFirstChild("Names")
					if genderValue and genderValue:IsA("StringValue") then
						genderValue.Value = "Female"
					else
						warn("Gender StringValue not found or is not a StringValue")
					end
					if nameValue and nameValue:IsA("StringValue") then
						nameValue.Value = randomNames2
					else
						warn("Name StringValue not found or is not a StringValue")
					end
				else
					warn("Configuration folder not found")
				end
			end
			
			local interactionPoint = Instance.new("Part")
			interactionPoint.Name = "InteractionPoint"
			interactionPoint.Size = Vector3.new(6, 5, 3)
			interactionPoint.CFrame = newModel:GetPrimaryPartCFrame() * CFrame.new(0, 1, 0)
			interactionPoint.Transparency = 1
			interactionPoint.CanCollide = false
			interactionPoint.Parent = newModel
			if torso then
				interactionPoint.CFrame = torso.CFrame * CFrame.new(0, torso.Size.Y / 2 + 1, 0)
				local weldConstraint = Instance.new("WeldConstraint")
				weldConstraint.Part0 = interactionPoint
				weldConstraint.Part1 = torso
				weldConstraint.Parent = interactionPoint
			end
	
			local clickDetector = Instance.new("ClickDetector")
			clickDetector.Parent = interactionPoint
			clickDetector.MaxActivationDistance = 100000
			clickDetector.CursorIcon = "rbxasset://0"

			local frame = script.Parent.Parent:WaitForChild("Frame")
			local textBox = frame:WaitForChild("TextBox")


			clickDetector.MouseClick:Connect(function(player, target)
				if player == localPlayer then
					local clickedDetector = interactionPoint:FindFirstChild("ClickDetector")
					local currentNPC = clickedDetector.Parent.Parent
					if currentlyInteractingNPC and currentlyInteractingNPC ~= currentNPC and
						currentlyInteractingNPC.Configuration:FindFirstChild("Names").Value == currentNPC.Configuration:FindFirstChild("Names").Value then
						return
					end
					local humanoid = currentNPC:FindFirstChild("Humanoid")
					if humanoid then
						humanoid:TakeDamage(5)
					end
					currentlyInteractingNPC = currentNPC
					local TweenService = game:GetService("TweenService")
					if frame then
						frame.Visible = true
						textBox.Text = newModel.Configuration.Names.Value

						local targetPosition = UDim2.new(0.52, 0, 0.4, 0)
						if frame.Position ~= targetPosition then
							local initialPosition = UDim2.new(1.4, 0, 0.4, 0)
							frame.Position = initialPosition
							local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
							local positionTween = TweenService:Create(frame, tweenInfo, {Position = targetPosition})
							positionTween:Play()
						end
						frame.Size = UDim2.new(0, 342, 0, 426)



						textBox.FocusLost:Connect(function(enter)
							currentlyInteractingNPC = currentNPC
							local currentText = textBox.Text
							if currentText and currentText ~= "" then
								if currentlyInteractingNPC == currentNPC then
									local config = newModel:FindFirstChild("Configuration")
									if config then
										local nameVal = config:FindFirstChild("Names")
										if nameVal and nameVal:IsA("StringValue") then
											nameVal.Value = currentText
										end
									end
								end
							end
						end)
					end
				end
			end)

			local skinColours = {
				Color3.fromRGB(255, 204, 153),
				Color3.fromRGB(182, 146, 109),
				Color3.fromRGB(79, 63, 47),
				Color3.fromRGB(84, 67, 50),
				Color3.fromRGB(255, 232, 185),
				Color3.fromRGB(255, 232, 187),
				Color3.fromRGB(63, 50, 37),
				Color3.fromRGB(100, 90, 57),
				Color3.fromRGB(173, 141, 113),
			}
			local pantsColours = {
				Color3.fromRGB(172, 172, 172),
				Color3.fromRGB(213, 213, 213),
				Color3.fromRGB(156, 250, 255),
				Color3.fromRGB(70, 51, 38),
				Color3.fromRGB(202, 213, 168),
				Color3.fromRGB(172, 123, 163),
				Color3.fromRGB(134, 144, 172),
				Color3.fromRGB(58, 51, 41),
				Color3.fromRGB(26, 26, 26),
			}
			local shirtsColours = {
				Color3.fromRGB(172, 172, 172),
				Color3.fromRGB(157, 131, 172),
				Color3.fromRGB(75, 75, 75),
				Color3.fromRGB(128, 172, 121),
				Color3.fromRGB(67, 60, 45),
			}
			local randomSkinColor = skinColours[math.random(1, #skinColours)]
			local randomPantsColor = pantsColours[math.random(1, #pantsColours)]
			local randomShirtsColor = shirtsColours[math.random(1, #shirtsColours)]

			local torso = newModel:FindFirstChild("Torso")
			local leftArm = newModel:FindFirstChild("Left Arm")
			local rightArm = newModel:FindFirstChild("Right Arm")
			local leftLeg = newModel:FindFirstChild("Left Leg")
			local rightLeg = newModel:FindFirstChild("Right Leg")
			local head = newModel:FindFirstChild("Head")

			if leftArm then leftArm.Color = randomSkinColor end
			if rightArm then rightArm.Color = randomSkinColor end
			if head then head.Color = randomSkinColor end
			if rightLeg then rightLeg.Color = randomPantsColor end
			if leftLeg then leftLeg.Color = randomPantsColor end
			if torso then torso.Color = randomShirtsColor end



			local particle = ReplicatedStorage.SpawnEffect:Clone()
			particle.Parent = newModel
			particle.CFrame = newModel:GetPrimaryPartCFrame()
			particle.CanCollide = false
			
			for _, part in ipairs(newModel:GetDescendants()) do
				if part:IsA("BasePart") then
					part.CanCollide = false
					part.Anchored = false
				end
			end
			
			handleNPCDamage(newModel)
			
			task.delay(1, function()
				if particle and particle.Parent == newModel then
					particle:Destroy()
					newModel.Torso.CanCollide = false
				end
			end)
		else
			print("Cannot place model outside the base!")
		end
	end
end

local boolean = game.Workspace.Configuration:WaitForChild("Spawning")

mouse.Button1Down:Connect(function()
	isMouseButtonDown = true
	mouseDownTime = tick()
	if placingEnabled and UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) then
		game.Workspace.Configuration.Spawning.Value = true
		while isMouseButtonDown and UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) and placingEnabled and previewModel do
			spawnNPC()
			task.wait(0.1)
		end
	else
		game.Workspace.Configuration.Spawning.Value = false
	end
end)

mouse.Button1Up:Connect(function()
	isMouseButtonDown = false
	local timeHeld = tick() - mouseDownTime
	if placingEnabled and previewModel and timeHeld < clickThreshold then
		spawnNPC()
	end
end)

placeButton.MouseButton1Click:Connect(onPlaceButtonClicked)```

And if you’re wondering, it is not because you cannot click the others, both of the NPCs have the same name property

I’m pretty sure that’s happening because you’re always creating a new NPC under the same name (and/or possibly variable) being newModel.

1 Like

ok i’ve read for a bit and i think i found your problem. (:crossed_fingers:)

the FocusLost event changes the NameValue of the NPC in spawnNPC.

unfortunately, this means that whenever you change the name, this triggers the event for every single NPC you have spawned. they will all have the same name now.

sounds very confusing, but move the FocusLost event OUTSIDE of the spawnNPC function somehow, make sure that the NPC that has its name changed is the currentlyInteractingNPC (i think this will work)

i know exactly what the problem is but i can’t put it into good words :disappointed_relieved:

So I can create a part of the script that can detect which NPC is currently selected? Seems simple to do

I found a solution to this issue after idk how long now. The issue was resolved by making some modifications inside the clickdetector to detect which npc is selected.

clickDetector.MouseClick:Connect(function(player, target)
				if player == localPlayer then
					local clickedDetector = interactionPoint:FindFirstChild("ClickDetector")
					local currentNPC = clickedDetector.Parent.Parent
					if currentlyInteractingNPC and currentlyInteractingNPC ~= currentNPC and
						currentlyInteractingNPC.Configuration:FindFirstChild("Names").Value == currentNPC.Configuration:FindFirstChild("Names").Value then
						return
					end
					local humanoid = currentNPC:FindFirstChild("Humanoid")
					if humanoid then
						humanoid:TakeDamage(5)
					end
					currentlyInteractingNPC = currentNPC

					local TweenService = game:GetService("TweenService")
					if frame then
						frame.Visible = true
						textBox.Text = currentNPC.Configuration.Names.Value

						local targetPosition = UDim2.new(0.52, 0, 0.4, 0)
						if frame.Position ~= targetPosition then
							local initialPosition = UDim2.new(1.4, 0, 0.4, 0)
							frame.Position = initialPosition
							local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
							local positionTween = TweenService:Create(frame, tweenInfo, {Position = targetPosition})
							positionTween:Play()
						end
						frame.Size = UDim2.new(0, 342, 0, 426)

						textBox.FocusLost:Connect(function(enter)
							if currentlyInteractingNPC then 
								local currentText = textBox.Text
								if currentText and currentText ~= "" then
									local config = currentlyInteractingNPC:FindFirstChild("Configuration")
									if config then
										local nameVal = config:FindFirstChild("Names")
										if nameVal and nameVal:IsA("StringValue") then
											nameVal.Value = currentText
										end
									end
								end
							end
						end)
					end
				end
			end)