Can my Status Effect Main Code be Improved?

Hey, so I’m currently making a status effect system in, and I was wondering if the base code I wrote for it can be improved:

local StatusEffectManager = {}

local Players = game:GetService("Players")

local activeEffects = {} --table for holding active status effects for each target
local uiRefs = {} --track the UI elements for each target

------------------------------------------------------------------------------------------------------------------




--//Apply a status effect to a target
function StatusEffectManager.ApplyEffect(target, effectName, params)
	if not activeEffects[target] then
		activeEffects[target] = {}
		uiRefs[target] = {}
	end	

	--load the status effect module
	local effectModule = require(script.StatusEffects:FindFirstChild(effectName))
	if not effectModule then
		warn("Effect module for " .. effectName .. " not found!")
		return
	end
	
	local effects = activeEffects[target]
	local uiElements = uiRefs[target]

	if effects[effectName] then
		--effect is already applied so extend the duration
		local activeEffect = effects[effectName]
		activeEffect.Params.Duration = (activeEffect.Params.Duration or 0) + (params.Duration or 5) --add new duration
		
		--update the UI countdown
		if uiElements[effectName] then
			uiElements[effectName].Timer.Text = string.format("%.1f", activeEffect.Params.Duration) .. "s"
		end
		
		print(effectName .. " duration extended for " .. target.Name)
		return
	end

	--initialize the effect
	local effect = {
		Name = effectName,
		Params = params,
		Module = effectModule,
		Target = target,
	}

	if effectModule.OnApply then
		effectModule.OnApply(target, params)
	end
	
	local plr = Players:FindFirstChild(target.Name)
	if plr then --only create ui's for player oviously ^^
		StatusEffectManager.CreateEffectUI(plr, effectName, params.Duration)
	end

	effects[effectName] = effect
end

--//Remove a status effect from a target
function StatusEffectManager.RemoveEffect(target, effectName)
	if not activeEffects[target] or not activeEffects[target][effectName] then
		warn("Effect " .. effectName .. " is not active on this target!")
		return
	end

	local effect = activeEffects[target][effectName]
	if effect.Module.OnRemove then
		effect.Module.OnRemove(effect.Target, effect.Params)
	end
	
	StatusEffectManager.RemoveEffectUI(target, effectName)

	activeEffects[target][effectName] = nil
end

--//Update all active effects (tick system)
function StatusEffectManager.Tick(deltaTime)
	for target, effects in activeEffects do
		for name, effect in effects do
			if effect.Module.OnTick then
				local isFinished = effect.Module.OnTick(effect.Target, deltaTime, effect.Params)
				if isFinished then
					StatusEffectManager.RemoveEffect(target, name)
				end
				if uiRefs[target] and uiRefs[target][name] then
					uiRefs[target][name].Timer.Text = string.format("%.1f", effect.Params.Duration) .. "s"
				end
			end
		end
	end
end

--//Create a UI element for an effect
function StatusEffectManager.CreateEffectUI(player, effectName, duration)
	local playerGui = player:FindFirstChild("PlayerGui")
	if not playerGui then return end

	local effectHolder = playerGui:FindFirstChild("StatusEffectHolder")

	--creating the UI frame for the effects
	local effectModule = require(script.StatusEffects:FindFirstChild(effectName))
	local uiPreset = effectModule.UiPreset()
		
	local effectFrame = script.ExampleFrame:Clone()
	effectFrame.Name = effectName
	effectFrame.Parent = effectHolder.Holder
	
	effectFrame.BackgroundColor3 = uiPreset.BackgroundColor
	effectFrame.UIStroke.Color = uiPreset.UiStrokeColor
	
	effectFrame.BackgroundImage.Image = uiPreset.Image
	effectFrame.BackgroundImage.ImageTransparency = uiPreset.ImageTransparency
	effectFrame.BackgroundImage.Size = uiPreset.ImageSize
	effectFrame.BackgroundImage.Position = uiPreset.ImagePosition			

	local nameLabel = effectFrame.EffectName
	nameLabel.Text = uiPreset.Titel

	local timerLabel = effectFrame.Timer
	timerLabel.Text = string.format("%.1f", duration) .. "s"

	--track the UI elements and stuff
	if not uiRefs[player] then
		uiRefs[player] = {}
	end
	uiRefs[player.Character][effectName] = {
		Frame = effectFrame,
		Timer = timerLabel,
	}
end

--//remove a UI frame thing for an effect
function StatusEffectManager.RemoveEffectUI(player, effectName)
	if uiRefs[player] and uiRefs[player][effectName] then
		local frame = uiRefs[player][effectName].Frame
		if frame then
			frame:Destroy()
		end
		uiRefs[player][effectName] = nil
	end
end

--//remove all active status effects from a target
function StatusEffectManager.RemoveAllEffects(target)
	if not activeEffects[target] then
		warn("No active effects to remove for this target!")
		return
	end

	local effects = activeEffects[target]

	--go through all active effects and remove them
	for effectName, effect in pairs(effects) do
		if effect.Module.OnRemove then
			effect.Module.OnRemove(effect.Target, effect.Params)
		end

		--remove associated UI
		StatusEffectManager.RemoveEffectUI(target, effectName)
	end

	--clear the active effects table for the target
	activeEffects[target] = nil
end


return StatusEffectManager

I’m still also not sure if it’s actually better to just leave out the pairs or Ipairs for the loops because someone once said that it is actually better to let just Roblox do that.

What I mean as an example is this:

--//Update all active effects (tick system)
function StatusEffectManager.Tick(deltaTime)
	for target, effects in activeEffects do
		for name, effect in effects do
			if effect.Module.OnTick then
				local isFinished = effect.Module.OnTick(effect.Target, deltaTime, effect.Params)
				if isFinished then
					StatusEffectManager.RemoveEffect(target, name)
				end
				if uiRefs[target] and uiRefs[target][name] then
					uiRefs[target][name].Timer.Text = string.format("%.1f", effect.Params.Duration) .. "s"
				end
			end
		end
	end
end

or

--//Update all active effects (tick system)
function StatusEffectManager.Tick(deltaTime)
	for target, effects in pairs(activeEffects) do
		for name, effect in pairs(effects) do
			if effect.Module.OnTick then
				local isFinished = effect.Module.OnTick(effect.Target, deltaTime, effect.Params)
				if isFinished then
					StatusEffectManager.RemoveEffect(target, name)
				end
				if uiRefs[target] and uiRefs[target][name] then
					uiRefs[target][name].Timer.Text = string.format("%.1f", effect.Params.Duration) .. "s"
				end
			end
		end
	end
end
2 Likes

bump I guess

(uii random text here hehe)

1 Like