Tower Defense Mob Emotion System Not Working

Okay so, for context, I’m making a tower defense game based on the hit RPGMaker game OMORI (I know very creative).

Similarly to the actual RPG, I am recreating the emotion system mechanic as seen in the game. Basically, the player uses an item to inflict one of four emotions onto a tower of their own. These emotions consists of:

NEUTRAL – The default emotion, returns the tower’s default stats.
ANGRY – 25% more tower damage, 25% longer attack cooldown.
HAPPY – 25% more tower range, 25% less attack cooldown, 25% more enemy speed.
SAD – 25% less tower damage, 25% less enemy speed.

I’ve already implemented everything about the tower stat changes. The system works fine there, HOWEVER, I can’t seem to figure out how to successfully implement the WalkSpeed changes for the enemies/mobs when they’re in the range of a HAPPY or SAD tower. I can get close yet so far.

(Note: To create the tower defense system, I’ve followed GnomeCode’s tower defense game tutorial series. Although, the emotion system is entirely my own code.)

(Also note: I am not new to scripting, so I do know a little about what I’m doing although I would like another person’s input on this topic before I start growing gray hairs.)

MobEmotionHandler (ServerScript in ServerScriptService)

local CollectionService = game:GetService("CollectionService")

local function applyEffect(mob, outlineColor, fillColor)
	for _, child in ipairs(mob:GetChildren()) do
		if child:IsA("Highlight") and child.Name == "EffectHighlight" then
			child:Destroy()
		end
	end
	
	if outlineColor and fillColor then
		local effect = Instance.new("Highlight")
		effect.Name = "EffectHighlight"
		effect.OutlineColor = outlineColor
		effect.FillColor = fillColor
		effect.FillTransparency = 0.75
		effect.DepthMode = Enum.HighlightDepthMode.Occluded
		effect.Parent = mob
	end
end

game:GetService("RunService").Heartbeat:Connect(function()
	for _, v in pairs(workspace:WaitForChild("CurrentTowers"):GetChildren()) do
		for _, c in pairs(workspace:WaitForChild("CurrentMobs"):GetChildren()) do
			local origSpeed = c:WaitForChild("Humanoid").WalkSpeed
			if CollectionService:HasTag(c, "IsHappy") then
				origSpeed = origSpeed / 1.25
			elseif CollectionService:HasTag(c, "IsSad") then
				origSpeed = origSpeed / 0.75
			end
			local happySpeed = origSpeed * 1.25
			local sadSpeed = origSpeed * 0.75
			local range = v:WaitForChild("Config").Range.Value
			local distance = (c.PrimaryPart.Position - v.PrimaryPart.Position).Magnitude
			if distance <= range then
				
				if v:WaitForChild("Config").IsHappy.Value == true and not CollectionService:HasTag(c, "IsHappy") then
					print(v.Name.." made "..c.Name.." HAPPY with a new speed of ["..happySpeed.."]")
					CollectionService:AddTag(c, "IsHappy")
					applyEffect(c, Color3.new(0.8, 0.8, 0.2), Color3.new(1, 1, 0))
					c:WaitForChild("Humanoid").WalkSpeed = happySpeed
					
				elseif v:WaitForChild("Config").IsSad.Value == true and not CollectionService:HasTag(c, "IsSad") then
					print(v.Name.." made "..c.Name.." SAD with a new speed of ["..sadSpeed.."]")
					CollectionService:AddTag(c, "IsSad")
					applyEffect(c, Color3.new(0.1, 0.2, 0.8), Color3.new(0, 0, 1))
					c:WaitForChild("Humanoid").WalkSpeed = sadSpeed
				end
				
			elseif distance > range then
				if CollectionService:HasTag(c, "IsHappy") then
					CollectionService:RemoveTag(c, "IsHappy")
					applyEffect(c)
					c:WaitForChild("Humanoid").WalkSpeed = origSpeed
				elseif CollectionService:HasTag(c, "IsSad") then
					CollectionService:RemoveTag(c, "IsSad")
					applyEffect(c)
					c:WaitForChild("Humanoid").WalkSpeed = origSpeed
				end
			end
		end
	end
	task.wait(0.1)
end)

I hope I provided enough info for someone to help although if there is more you wish to see please comment and I’ll see if I could show more.

Could you show the output for this?

1 Like


Basically, I use the toys menu to inflict the HAPPY and SAD emotions on two towers. On wave 2, the Hand-Kun mob that I selected only was affected by the SAD WalkSpeed, ignoring the HAPPY tower that was first on the path.


Also, in this video the tags for the mobs (again I used the Hand-Kun for example) only appeared until the intersection of the two tower’s ranges. Only then did the “IsHappy” and “IsSad” tags get placed on the mob, which is odd because a mob is not supposed to have both tags at once.

I also noticed that the output spams the print checks that I implemented which I do not want, I only wish for the script to check each mob’s state right when it enters a new tower’s range.
(My apologies if the script is a mess btw and is hard to read :sob::sob:)

1 Like

I almost forgot, but I should also mention that the mob emotion system works fine when there’s only one tower that’s affected by HAPPY or SAD. The script only becomes weird when there’s multiple HAPPY and or SAD towers.

1 Like

Probably because they are overriding each other
I’m still unsure of what you’re trying to do?

Change the speed when the mob is being attacked by the unit? if so, if 2 units are attacked 1, it could probably cause some weird bugs.

1 Like

What I’m trying to do here is that when a mob enters the range of a HAPPY tower, the mob gets a 1.25 speed multiplier; when a mob enter the range of a SAD tower, the mob get a 0.75 speed multiplier.

My original plan is that the script should check every mob for every tower currently on the map, and when the mob is within any tower’s range, it’ll check to see if said tower is marked with a IsHappy or IsSad Boolean. If either are true then the script will tag the mob with a tag under the same name as the current true boolean on the tower, then apply the speed multiplier, only resetting the mob’s speed to it’s default after it leaves the tower’s range (if it did not get killed).

The script is supposed to use tags on the mob’s to track if it’s already affected by a tower’s mob WalkSpeed multiplier.

local function applyEffect(mob, outlineColor, fillColor)
	for _, child in ipairs(mob:GetChildren()) do
		if child:IsA("Highlight") and child.Name == "EffectHighlight" then
			child:Destroy()
		end
	end
	
	if outlineColor and fillColor then
		local effect = Instance.new("Highlight")
		effect.Name = "EffectHighlight"
		effect.OutlineColor = outlineColor
		effect.FillColor = fillColor
		effect.FillTransparency = 0.75
		effect.DepthMode = Enum.HighlightDepthMode.Occluded
		effect.Parent = mob
	end
end

This whole function is merely to add a visual for when a mob is affected by another tower’s emotion.

game:GetService("RunService").Heartbeat:Connect(function()
	for _, v in pairs(workspace:WaitForChild("CurrentTowers"):GetChildren()) do
		for _, c in pairs(workspace:WaitForChild("CurrentMobs"):GetChildren()) do
			local origSpeed = c:WaitForChild("Humanoid").WalkSpeed
			if CollectionService:HasTag(c, "IsHappy") then
				origSpeed = origSpeed / 1.25
			elseif CollectionService:HasTag(c, "IsSad") then
				origSpeed = origSpeed / 0.75
			end
			local happySpeed = origSpeed * 1.25
			local sadSpeed = origSpeed * 0.75

This part of the script checks every mob for every tower there is currently on the map. After that it gets the mob’s current WalkSpeed and calls it the original speed (origSpeed). HOWEVER, if a mob is already inflicted by an emotion then the origSpeed would be inaccurate so the script checks to see if a mob has any emotion tags, if so, the script reverses the multiplier, setting the origSpeed to what it should be.

After that, it then calculates what value the mob’s WalkSpeed will be if it were to be affected by the HAPPY multiplier or the SAD multiplier (written as happySpeed and sadSpeed).

local range = v:WaitForChild("Config").Range.Value
			local distance = (c.PrimaryPart.Position - v.PrimaryPart.Position).Magnitude
			if distance <= range then
				
				if v:WaitForChild("Config").IsHappy.Value == true and not CollectionService:HasTag(c, "IsHappy") then
					print(v.Name.." made "..c.Name.." HAPPY with a new speed of ["..happySpeed.."]")
					CollectionService:AddTag(c, "IsHappy")
					applyEffect(c, Color3.new(0.8, 0.8, 0.2), Color3.new(1, 1, 0))
					c:WaitForChild("Humanoid").WalkSpeed = happySpeed
					
				elseif v:WaitForChild("Config").IsSad.Value == true and not CollectionService:HasTag(c, "IsSad") then
					print(v.Name.." made "..c.Name.." SAD with a new speed of ["..sadSpeed.."]")
					CollectionService:AddTag(c, "IsSad")
					applyEffect(c, Color3.new(0.1, 0.2, 0.8), Color3.new(0, 0, 1))
					c:WaitForChild("Humanoid").WalkSpeed = sadSpeed
				end

In this section, the script gets the range stat of the current tower it’s checking then calculates the distance between the tower and the current mob it’s checking. If their distance is lesser or equal to the tower’s range, then the script will check inside the tower’s configuration folder and check to see if the tower is currently HAPPY or SAD and if the current mob is not already affected by an emotion multiplier of the same emotion (so a mob cannot have the HAPPY or SAD multiplier more than once at a time).

If so, it’ll print out a message (purely just for debugging purposes), then it’ll add a tag to the mob according to which emotion the tower has (the tags are merely just so the script can track what mobs are affected by what emotion), after that it then calls the applyEffect function to add a visual to the mob for the emotion, then FINALLY it changes the mob’s WalkSpeed to either the happySpeed or the sadSpeed value calculated eariler.

elseif distance > range then
				if CollectionService:HasTag(c, "IsHappy") then
					CollectionService:RemoveTag(c, "IsHappy")
					applyEffect(c)
					c:WaitForChild("Humanoid").WalkSpeed = origSpeed
				elseif CollectionService:HasTag(c, "IsSad") then
					CollectionService:RemoveTag(c, "IsSad")
					applyEffect(c)
					c:WaitForChild("Humanoid").WalkSpeed = origSpeed
				end
			end

This part of the script is just like the section above except it checks to see which emotion the mob currently has after it leaves the current tower’s range, then it removes the tag on the mob and sets the mob’s WalkSpeed back to it’s origSpeed value that was calculated earlier in the script.

I knew that it was probably a weird bug when there’s multiple HAPPY and or SAD towers, although I’m not sure how to patch it. The way I would want to handle it would be for a mob to only be affected by one emotion at a time and when a mob enters the range of a emotion affected tower, it’ll take on that tower’s mob speed multiplier.
So, what I want is for when a mob is in the range of, for example, a HAPPY tower then enters the range of a SAD tower, I want it to override the HAPPY speed multiplier with the SAD speed multiplier. Which I guess already happens although my script seems to ignore the first tower in line for some reason.

1 Like