How do i make ultimate drain like jjs?

Hi devs!

I am trying to make ult drain like jjs and i want to be able to add more ult points to my ult when it’s active, like in the Mahoraga ult from JJS. The reference:

But here’s the twist, my ult drain system doesn’t support this because I take the start time and subtract it from the current time, then divide it by the duration of the ult. I tried it, but everything I did was unsuccessful, and I didn’t find any specific topics about it on the forum.

There a function i use so far:

 function ServerUltMeter:Drain(plr: Player, Time: number)
	plr:SetAttribute("InAwk", true)
	local currentCharacter: string = plr.selectedCharacter.Value
	local maxPoints = tonumber(config.Characters[currentCharacter].MaxUltPoints)
	
	local startTime = tick()
	
	while tick() - startTime < Time do
		if not plr.Parent or not plr.Character.Parent or  plr.Character:FindFirstChildOfClass('Humanoid').Health <= 0 or plr.Character:GetAttribute('DrainAll') then break end
	
		local elapsed = tick() - startTime
		local progress = elapsed / Time
		local currentValue = math.round(maxPoints * (1 - progress))
		
		plr:SetAttribute("Awakening", math.round(currentValue))
		
		task.wait()
	end
	
	if plr and plr.Character then
		plr:SetAttribute("Awakening", 0)
	end
	
	plr:SetAttribute("InAwk", false)
end

Why are you creating a method just to never use self?

Yarik, it’s kinda off-topic, you know? Also, I just grabbed this method to hide my full script.

1 Like

How is that offtopic?
Critisizing code is now offtopic?
I don’t see any rule on the forum stating that.
Nonetheless, you still failed to provide a valid reason for creating the useless argument “self”.

What I would do is make an OOP for the ult meter

UltMeter.Charge: number
UltMeter.MaxCharge: number
UltMeter.DrainRate: number
UltMeter.IsDraining: boolean
UltMeter.Ready: boolean
UltMeter.Owner: Player

UltMeter:UpdateCharge(Amount:  number, Set: boolean?) -- also supports -Amount
UltMeter:StartDrain(State: boolean?) -- start / end drain
UltMeter:Reset() -- bc
UltMeter:StopDrain() -- basicall StartDrain(false)

and then for the UI just update an attribute on the Player

1 Like

depending on his coding style it doesn’t really matter

and yes, for the record it is off-topic, he asks how to make ultimate drain, you immediately resort to insulting/questioning his coding skills

2 Likes

ok but you should still use . instead of : if you’re not using self

1 Like

You could calculate a Displacement for your drain calculations

local drainRatePerSecond = maxPoints/Time
local displacement = drainRatePerSecond * DeltaTime

and then just subtract to your current points that displacement, that way it will have a constant drain rate no matter what points you have

function ServerUltMeter:Drain(plr: Player, Time: number)
	plr:SetAttribute("InAwk", true)
	local currentCharacter: string = plr.selectedCharacter.Value
	local maxPoints = tonumber(config.Characters[currentCharacter].MaxUltPoints)
	local currentpoints = plr:GetAttribute("Awakening")
		
	local DeltaTime = 0
	local elapsed = 0
	--You might also want to use coroutine.wrap to avoid pausing other script threads when calling this function
	while elapsed<Time and currentpoints >0 do--Added a check to see if the player still has points, not sure if you wanted that tho
		if not plr.Parent or not plr.Character.Parent or  plr.Character:FindFirstChildOfClass('Humanoid').Health <= 0 or plr.Character:GetAttribute('DrainAll') then break end
		
		local DeltaTime = task.wait()--you could also use runservice.heartbeat:wait() or stepped or even connect it to their events
		elapsed += DeltaTime
		currentpoints = plr:GetAttribute("Awakening")
		local drainRatePerSecond = maxPoints/Time -- you could choose another drain rate like for example 100 points per second
		local displacement = drainRatePerSecond * DeltaTime
			
		local newValue = math.max(currentpoints-displacement,0)//1--with math.max it wont go below 0, you couls use math.clamp too for both min and max limits, //1 is just a lazy way of flooring the number
		plr:SetAttribute("Awakening", newValue)--Changing the value

		
	end
	
	--[[if plr and plr.Character then
		plr:SetAttribute("Awakening", 0)
	end]]
		--Im not sure if you wanted to have all the points drained to 0 after the time passed no matter what
		--So I made this a comment just in case

	plr:SetAttribute("InAwk", false)
end

If you wanted to drain it all the way to 0 you could choose a drainRate of currentpoints/Time

maxPoints/Time just drains it based on your max points
Or you could use some other drain rate

1 Like

Thanks a lot! i just test it and its working great! And i rewrite code on oop cuz it good

That’s not a coding style if it affects bytecode negatively.
It’s an excuse to write bad code.
Such argument does not apply in this case as since it affects bytecode negatively, creating unneeded argument.