How can I handle value changes for combat?

This question is probably extremely specific but I need to handle value changes in a way that doesn’t break other moves. Earlier this or last week, I made a forum post stating a problem I am having with my combat. I tried making a thread handler but it just doesn’t work as intended.

As shown in this video below, my friend gets hit by multiple attacks yet his movement and attribute value get reset back to normal due to a delay I put in the server code.

task.delay(1, function()
	print("CHANGING ISATTACKED")
	Player2:SetAttribute("IsAttacked", false)
	Player2.Humanoid.WalkSpeed = 16
	Player2.Humanoid.JumpHeight = 7.2
end)

This is the thread handler I made but the cancelation of threads doesn’t work.

local ThreadModule = {}
local Threads: {[string]: "function" | () -> ()} = {}

function ThreadModule.RegisterThread(ThreadName: string, Thread, ...)
	assert(type(ThreadName) == "string", "Argument 1 needs to be a string, got "..typeof(ThreadName))
	assert(type(Thread) == "function", "Argument 2 needs to be a function, got "..typeof(Thread))

	if Threads[ThreadName] ~= nil then
		ThreadModule.MutilateThread(ThreadName)
	else
		Threads[ThreadName] = coroutine.create(Thread, ...)
	end
end

function ThreadModule.CallThread(ThreadName: string)
	local FoundThread = Threads[ThreadName]

	if FoundThread then
		local status = coroutine.status(FoundThread)
		if status == "suspended" or status == "normal" then
			local success, error_message = coroutine.resume(FoundThread)
			if not success then
				warn("Error in thread: " .. error_message)
				ThreadModule.MutilateThread(ThreadName)
			end
		else
			ThreadModule.MutilateThread(ThreadName)
		end
	end
end

function ThreadModule.MutilateThread(ThreadName: string)
	local FoundThread = Threads[ThreadName]

	if FoundThread then
		coroutine.close(FoundThread) do
			Threads[ThreadName] = nil
			--coroutine.yield()
		end
	end
end

function ThreadModule.CheckThreadHealth(ThreadName: string): string
	local FoundThread = Threads[ThreadName]

	if FoundThread then
		return coroutine.status(FoundThread)
	end
end

return ThreadModule

If there is an alternative way of fixing my issues please lmk!

While I don’t quite have enough context from the code you posted, what I recommend you do is change how you handle the IsAttacked property.
One easy way to do this would be to turn it into a number instead of a boolean.
This way, instead of setting it to true or false, you can increment and decrement it.
Doing this will allow for it to retain it’s value even if the player is hit multiple times in quick succession.
The value will still be as easy to read, as you would then simply need to check if the value is non-zero.

2 Likes

I never even thought about this, I’ll try this a bit later today. However, I believe I’d need to make a connection for that attribute if I’m not mistaken.

I don’t quite understand the problem you’re trying to describe. I’m going to assume that you don’t want the player’s speed to return to normal in the middle of taking a hit combo.

stef above also recommended a good fix to the problem. There should be some kind of check before you reset the player’s speed.

I’m going to also recommend another solution, which is to use task.cancel to cancel any potential speed resets when a new hit is received by the user. task.cancel should be able to stop the function for task.delays and task.waits. See task | Documentation - Roblox Creator Hub.

I can technically just keep the task.delay thread into a table and cancel it but I was trying to make it a bit more efficient with a module but it didn’t work.

Also for context IsAttacked is a boolean attribute that if true, just tells the game that the specific player got attacked.