Enemy Activate Player Abilities and Attack The Characters

Whats The Issues?

I have a bug with the enemy and player characters when they both have the same ability equipped. When the enemy presses ‘E’, the character’s Blood Ball attack targets the owner instead of firing projectiles as intended.


                           Footage


                           Code

Module :

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage.Remotes:WaitForChild("BallPosition")
local rs = game:GetService("RunService")
local ContextActionService = game:GetService("ContextActionService")

local BallFollower = {}
BallFollower.__index = BallFollower

function BallFollower.new(player)
	return setmetatable({ 
		Player = player,
		projectilesSpawned = false,
		Count = 0,
		ballActive = false -- Flag to track if the ball is active
	}, BallFollower)
end

-- Mechanics

function BallFollower:CreateBall()
	local ball = script.Blood:Clone()
	ball.Anchored = false
	ball.CanCollide = false
	ball.Parent = workspace.FX

	local attachmentBall = Instance.new("Attachment", ball)

	local alignPos = Instance.new("AlignPosition", ball)
	alignPos.Attachment0 = attachmentBall
	alignPos.ReactionForceEnabled = false
	alignPos.MaxForce = 10000
	alignPos.Responsiveness = 35

	self:TrackCharacter(ball, alignPos)
	self.ballActive = true -- Set ball active flag
	
	
	return ball
end

function BallFollower:StartFollowing()
	self.ball = self:CreateBall()
	RemoteEvent.OnServerEvent:Connect(function(player, types, mousePos)
		if types == "Ability" and not self.projectilesSpawned then -- Check if projectiles have been spawned
			local character = player.Character or player.CharacterAdded:Wait()
			
			if not self.ball or not self.ball.Parent then
				return
			end
			
			self.Count += 1
			self.projectilesSpawned = true
			
			local projectile = script.Arrow:Clone()
			projectile.CFrame = self.ball.CFrame
			projectile.Anchored = true
			projectile.Parent = workspace.FX

			local nearestEnemy = self:GetNearestEnemy(character)
			if nearestEnemy then
				local direction = (nearestEnemy.HumanoidRootPart.Position - projectile.Position).Unit
				local lookAtCFrame = CFrame.new(projectile.Position, projectile.Position + direction)
				projectile.CFrame = lookAtCFrame * CFrame.Angles(math.rad(180), math.rad(-90), 0)

				local speed = 130
				local timeout = 0.5
				local startTime = tick()

				self:LoadSound(workspace.FX, 1300216167)

				task.spawn(function()
					while (projectile.Position - nearestEnemy.HumanoidRootPart.Position).Magnitude >= 1 do

						local elapsedTime = tick() - startTime
						if elapsedTime > timeout then
							break
						end

						local newPosition = projectile.Position + direction * speed * rs.Heartbeat:Wait()
						projectile.Position = newPosition
						task.wait()
					end
					nearestEnemy.Humanoid:TakeDamage(2)
				end)
			end
			
			game:GetService("Debris"):AddItem(projectile, 1)
			self.projectilesSpawned = false -- Reset the flag to allow next projectile to be spawned

			if self.Count == 5 then
				self:Stop()
			end
		end
	end)
end

-- Properties

function BallFollower:TrackCharacter(ball, alignPosition)
	local character = self.Player.Character or self.Player.CharacterAdded:Wait()
	local attachmentCharacter = Instance.new("Attachment", character.HumanoidRootPart)
	attachmentCharacter.CFrame = CFrame.new(0,0,5)

	task.spawn(function()
		while ball do
			if character then
				alignPosition.Attachment1 = attachmentCharacter
			end
			task.wait(0.01)
		end
	end)
end

function BallFollower:GetNearestEnemy(Character)
	local character = Character
	if not character then return end

	local nearestDistance = math.huge
	local nearestEnemy = nil

	for _, enemy in pairs(workspace.Entities:GetChildren()) do
		if enemy ~= character then
			local distance = (enemy.HumanoidRootPart.Position - self.ball.Position).magnitude
			if distance < nearestDistance then
				nearestDistance = distance
				nearestEnemy = enemy
			end
		end
	end

	return nearestEnemy
end

function BallFollower:Stop()
	local poof : ParticleEmitter = self.ball.Attachment.Blood
	poof:Emit(200)
	
	self.ball.Transparency = 1
	self:LoadSound(workspace.FX, 7837535984)
	
	task.wait(0.4)
	
	if self.ball and self.ball.Parent then
		self.ball:Destroy()
	end

	-- Clean up any remaining projectiles
	for _, projectile in ipairs(workspace:GetChildren()) do
		if projectile.Name == "Arrow" then
			projectile:Destroy()
		end
	end

	self.projectilesSpawned = false
	self.ballActive = false -- Reset ball active flag
	self.Count = 0 -- Reset the count
end

function BallFollower:LoadSound(character, id)
	local Sound = Instance.new("Sound", character)
	local Chorus = Instance.new("ChorusSoundEffect", Sound)
	Sound.SoundId = "rbxassetid://"..tostring(id)
	Sound.Volume = 4
	Sound:Play()

	Sound.Ended:Connect(function()
		task.wait(1)
		Sound:Destroy()
	end)
end

return BallFollower

Another Module Script:

local rp = game:GetService("ReplicatedStorage")
local slicing = require(rp.Modules:WaitForChild("PlayerMouse"))

local Skill2 = {}
Skill2.__index = Skill2

function Skill2.new(plr)
	return setmetatable({
		Player = plr
	}, Skill2)
end

function Skill2:Play()
	self:LoadAnimation(self.Player.Character, 17693442204)
	self:LoadSound(self.Player.Character, 17693484524)
	self:VFX()
end

function Skill2:VFX()
	local new = slicing.new(self.Player)
	new:StartFollowing()
end

function Skill2:LoadAnimation(character, id)
	local Humanoid = character:WaitForChild("Humanoid")
	local Animator : Animator = Humanoid:WaitForChild('Animator')
	local animation = Instance.new("Animation", character)
	animation.AnimationId = "rbxassetid://"..tostring(id)
	local at = Animator:LoadAnimation(animation)
	at:Play()
	
	game.Debris:AddItem(animation, 2)
end

function Skill2:LoadSound(character, id)
	local Humanoid = character:WaitForChild("Humanoid")
	local Animator : Animator = Humanoid:WaitForChild('Animator')
	local Sound = Instance.new("Sound", character)
	local Chorus = Instance.new("ChorusSoundEffect", Sound)
	Sound.SoundId = "rbxassetid://"..tostring(id)
	Sound.Volume = 2
	Sound:Play()
	
	Sound.Ended:Connect(function()
		task.wait(1)
		Sound:Destroy()
	end)
end


return Skill2

Server:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")

local sendkey = ReplicatedStorage.Remotes:WaitForChild("SendKeys")
local getchar = ReplicatedStorage.Remotes:WaitForChild("GetChar")
local bindFunction = ReplicatedStorage.Remotes:WaitForChild("BindFunction")
local skillsUtils = ReplicatedStorage:WaitForChild("SkillUtils")
local charData = skillsUtils:WaitForChild("CharacterData")

local hotboxCache = {}
local barCache = {}

local function getHotbox(player)
	if not hotboxCache[player] then
		hotboxCache[player] = player.PlayerGui:WaitForChild("Hotbox")
	end
	return hotboxCache[player]
end

local function getAwakeningBar(player)
	if not barCache[player] then
		barCache[player] = player.PlayerGui:WaitForChild("AwakeningBar")
	end
	return barCache[player]
end

local debounces = {}

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		character:SetAttribute("Character", "None")
		character:SetAttribute("CombatState", "Unused")
		character:SetAttribute("Awakening", 0)
		character.Parent = workspace.Entities
	end)
end)

sendkey.OnServerEvent:Connect(function(player, input)
	local character = player.Character or player.CharacterAdded:Wait()
	local selected = character:GetAttribute("Character")
	if debounces[player] and debounces[player][input] then return end
	debounces[player] = debounces[player] or {}
	debounces[player][input] = true

	local hotbox = getHotbox(player)
	
	for _, child in pairs(charData:GetChildren()) do
		if selected == child.Name then
			local requireChar = require(child)
			for _, abilityData in pairs(requireChar.List) do
				if selected and input then
					local characterFolder = script:FindFirstChild(selected)
					if characterFolder then
						local ability = characterFolder:FindFirstChild(input)
						if ability and abilityData.Key == input then
							local abilityInstance = require(ability).new(player)
							local cooldown = hotbox:WaitForChild(input).Cooldown
							if cooldown and not cooldown.Visible then
								local startSize = cooldown.Size
								local endSize = UDim2.new(0, 54, 0, -0)
								cooldown.Size = UDim2.new(0, 54, 0, 66)
								cooldown.Visible = true
								local tweenInfo = TweenInfo.new(abilityData.Cooldown, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
								local tween = TweenService:Create(cooldown, tweenInfo, { Size = endSize })
								tween:Play()
								abilityInstance:Play()
								tween.Completed:Wait()
								local resetTween = TweenService:Create(cooldown, tweenInfo, { Size = startSize })
								resetTween:Play()
								cooldown.Visible = false
							end
						end
					end
				end
			end
		end
	end
	debounces[player][input] = nil
end)

getchar.OnServerEvent:Connect(function(player, name)
	local hotbox = getHotbox(player)
	local bar = getAwakeningBar(player)
	local character = player.Character or player.CharacterAdded:Wait()
	if not character then
		warn("Character not found for player:", player.Name)
		return
	end

	if character.Humanoid.Health == 100 then
		local character_Attribute = character:GetAttribute("Character")
		character:SetAttribute("Character", name)

		local characterFolder = script:FindFirstChild(name)

		local availableModules = {}
		for _, child in pairs(characterFolder:GetChildren()) do
			if child:IsA("ModuleScript") then
				table.insert(availableModules, child.Name)
			end
		end

		for _, child in pairs(charData:GetChildren()) do
			if child:IsA("ModuleScript") and child.Name == name then
				local requireChar = require(child)
				
				for _, abilityData in pairs(requireChar.List) do
					local hotboxChar = hotbox:FindFirstChild(abilityData.Key)
					hotboxChar.SkillName.Text = abilityData.SkillName

					if requireChar.Awakening then
						local Charbar = bar:WaitForChild("Awakening")
						Charbar.Text = requireChar.Awakening
						Charbar.TextLabel.Text = requireChar.Awakening
					end
				end
			end
		end
		bindFunction:InvokeClient(player, availableModules)
	end
end)

Another Module Script is fired on the Server Handler.

1 Like

A bit lengthy; to read, i’m not very good at organising >:

This bug is a bit weird. I made the script check if the enemy isn’t a character, but it doesn’t work either.