Thunder's Status Effect System
☆⸻●⸻☆
Apply status effects such as 🔥 Fire, 🧊 Ice, ⚡ Stun, ❓ Confusion, etc... to targets and have them affected by various conditions. These effects can deal damage over time, restrict movement, alter behavior, reduce defense or apply other unique mechanics depending on the effect type.
Asset file: Thunder’s Status Effect System.rbxm (39.3 KB)
Introduction
Introduction
Hi, it’s me, that one modeler again!
Last time I made this very cool FreezeModule & I revamped Roblox’s TagHumanoid function
So this time I combined the both of them in order to make a system that lets you apply certain elemental status effects on characters (Players/NPCs). I hope this might help you learn something new even if you don’t use it!
Besides, this system allows you to easily set Defense and Immunities for characters using Attributes. You can add an effect from a script whose parent might be destroyed later, doing so does not stop the ongoing effect.
I’ll provide updates once in a while to fix bugs or improve the system (Any help would be appreciated!), especially during special occasions like Halloween or Christmas, you can expect to see even more premade status effects themed around those events, which are free for use (Basically similar to game events)
How this system works:
- When an effect is applied to a target, the said target is tagged using CollectionService and some additional Attributes are set on a Configuration object, which is parented in the target.
- In the main script, when there's a new target added to to the CollectionService, it checks for the Humanoid object, HumanoidRootPart, type of status effect, damage, tick, variant as well as the defense amount and immunities of the target before applying the effect.
- The status effect is applied with visual effects using a repeat until loop until the duration runs out, at which point the target is untagged. Duration is check every frame using a loop, this allows us to change the duration while an effect is active, unlike my previous method using Debris Service and ChildAdded() event
- If a target has Defense attribute, it will receive less damage from an effect, same goes for its Immunities, but an immunity can also shorten the effective duration. Ex: You apply 🔥 Fire with 100 damage per tick for 5 seconds to a Noob who has Defense = 50(%), FireImmunity = 50, he will only take 25 damage every tick for 2.5 seconds.
Free Status Effect Examples (8 Presets/Templates)
Free Status Effect Examples (8 Presets/Templates)
Free status effects:
I tried making each effect as unique as possible, take a look here to see what they do. These examples are placed within the folder or one of the main scripts.-
Fire: Burns to deal DoT and melt defense, can set damage and tick, can set color with variant, target turns to coal on death
-
Ice: Freezes target to reduces defense, stops any movements or animations while retaining physics, creates a thin ice layer on the character. Utilizes my FreezeModule
-
Stun: Stuns and stops the target from moving with a strong force. For heavy targets or those with Stun Immunity, the target is not stunned but rather slowed down along with their animation speed. Can set tick, can set stunning type (Zap/Shock/Paralyze) or color with variant. Effect emits once every tick. Tick, Force and AnimationSpeed factor are affected by Stun Immunity
-
Poison: Deals DoT while bypassing defense, damage depends on the MaxHealth of the target, can set tick and variant
-
Acid: Corrodes to deal DoT and melt defense, can set damage, tick and variant, target fades away on death.
-
Radiation: Deals DoT, also melts and ignores defense, can set damage, tick and variant, target breaks into pieces on death
-
Confusion: If the target is a Player, their control is inverted (all devices), otherwise, the movement of the target is reversed
-
Void: Halves the damage that the target can deal when applied
-
Love-Link: (Will be added soon after Valentines): Electrocuts targets near the main target who is being affected by this effect, lightning strikes will link the affected targets together
-
Chill: (Will be added on Xmas): Slows down chilled targets
-
Explosion: (Will be added on New Year Eve): Instantly kills the target and then creates an explosion afterwards
-
Bleed: (Will be added on ??? event): Deals DoT while bypassing defense, damage depends on the remaining Health of the target, can set tick. Effect color depends on the color of the target
-
Teleportation: (Will be added on ??? event): Randomly teleports the target to a random location at random time
Explanation:
-
DoT: Damage over time. Damage is applied every Tick
-
Defense: How many % of damage that a character can block. The effective damage dealt towards a character is decreased if its defense amount is higher than 0. However, Poison & Radiation can both bypass/ignore defense
-
Immunity:: How many % of damage that a character can block from the same type of effect they are immune to, can stack with Defense (Full Damage → Reduced by Defense → Reduced by Immunity)
-
Defense-melting: Reduce defense, each type of elemental status effect can only drop up to a certain amount of defense and does not stack with the same type of status effect
-
Tick: The rate at which the effect deals damage or activates. Basically firerate
-
Duration: How long the effect will be applied for. This timespan can be shorten by an immunity (0%-100%). If the immunity is higher than 100%, then the duration is not changed. Else if the immunity is lower than 0%, then the duration is increased. Duration is also stackable if an effect allows it
-
Creator: The Player instance or the character of a player (Module auto checks), is used to tag targets and recognize total damage contributed and the final hit dealer. Does not tag if the Creator is not a player
-
Variant: Customize an effect or give it a different mechanic. This is because you can’t send info to the CollectionService
Examples:
- You apply
Fire with 100 damage per tick for 5 seconds to a Noob who has Defense = 50(%), FireImmunity = 50, he will only take 25 damage every tick for 2.5 seconds.
- You apply
Ice for 2 seconds to a Snowman that has IceImmunity = 100, it will not be frozen at all.
- You apply
Poison with 1% MaxHealth as damage per tick for 10 seconds to a Zombie who has Defense = 90, PoisonImmunity = 150, it will not take any damage, but heal up by 1.5% of its MaxHealth per tick for 10 seconds. Poison ignores Defense
- You apply
Acid with 100 damage per tick for 5 seconds to a Robot that has Defense = 50, AcidImmunity = -50, it will take 75 damage every tick for 7.5 seconds.
- You apply
Radiation with 100 damage per tick for 5 seconds to a Golem that has Defense = 100, no RadiationImmunity, it will take 100 damage every tick for 5 seconds. Radiation ignores Defense
- You apply
Confusion for 5 seconds to a Player without ConfusionImmunity, their control will be inverted during that time (WASD → SDWA on PC, opposite movement direction on all devices)
- You apply
Failure with infinite emotional damage per tick to a Player forever, they will not be happy and will most likely dislike your game
Code examples from the model:
local FunctionBank = require(script.Parent.Parent.FunctionBank)
local Effects = FunctionBank.Effects
for _, v in pairs(workspace:GetChildren()) do
if v:IsA("Model") and v:FindFirstChild("HumanoidRootPart") then
FunctionBank:AddEffect(v, Effects[math.random(1, #Effects)], 10, 5, script.Parent, nil) -- You don't have to put nil unless if you want to reach the next argument
end
end
Source code
Source code
Script 1 (All available status effects):
-- By ThunderDaNub. More info in the Notes script
local CS = game:GetService("CollectionService")
local SS = game:GetService("ServerStorage")
local SSS = game:GetService("ServerScriptService")
local Players = game:GetService("Players")
local FireEffect = script.Fire
local PoisonEffect = script.Poison
local ElectricityEffect = script.Electricity
local HealEffect = script.Healing.HealFx
local AcidEffect = script.Acid
local RadiationEffect = script.Radiation
local VoidEffect = script.Void
local ConfusionEffect = script.Confusion
local FunctionBank = require(script.Parent.FunctionBank)
--local DeathEffects = require(SSS.Main.Game.DeathEffects) -- Custom death effect, not ready for this system yet wait for me to update
local function CheckForEffectConfig(Target, Effect)
for i, v in ipairs(Target:GetChildren()) do
if v.Name == Effect and v:IsA("Configuration") then
return v
end
end
end
local function DealDamage(Damage, Effect, Creator, Target, Humanoid, IgnoreDefense, IgnoreImmunity, DeathEffect)
if Humanoid.Health > Damage then
if Creator and Players:FindFirstChild(Creator) and Players:FindFirstChild(Creator):IsA("Player") then
local Player = Players:FindFirstChild(Creator)
if Player and Player:IsA("Player") then
FunctionBank:Damage(Player, Target, math.round(Damage), IgnoreDefense, IgnoreImmunity, Effect)
end
else
Humanoid.Health = Humanoid.Health - math.round(Damage)
end
else
if Creator and Players:FindFirstChild(Creator) and Players:FindFirstChild(Creator):IsA("Player") then
local Player = Players:FindFirstChild(Creator)
if Player and Player:IsA("Player") then
FunctionBank:Damage(Player, Target, Humanoid.Health, IgnoreDefense, IgnoreImmunity, Effect)
end
else
Humanoid.Health = 0
end
--DeathEffects.Play(Target, DeathEffect) -- Play a custom death effect, not ready for this system yet wait for me to update
end
end
CS:GetInstanceAddedSignal("Stun"):Connect(function(Character)
local Effect = "Stun"
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
local EffectConfig = CheckForEffectConfig(Character, Effect)
if Root and Humanoid and EffectConfig then
local VisualEffect = ElectricityEffect:Clone()
VisualEffect.Parent = Root
local Damage = EffectConfig:GetAttribute("Damage") or 0
local Tick = EffectConfig:GetAttribute("Tick") or 0.1
local Creator = EffectConfig:GetAttribute("Creator")
local Variant = EffectConfig:GetAttribute("Variant")
local Force = Vector3.one * 1e9
local AnimationSpeed = 0.2
if Character:GetAttribute(Effect .. "Immunity") then
Damage = Damage - Damage * (Character:GetAttribute(Effect .. "Immunity") / 100)
Tick = Tick + Tick * (Character:GetAttribute(Effect .. "Immunity") / 100)
Force = Force / Force * (Character:GetAttribute(Effect .. "Immunity") / 100)
AnimationSpeed = AnimationSpeed + AnimationSpeed * (Character:GetAttribute(Effect .. "Immunity") / 100)
if Tick <= 0.05 then
Tick = 0.05
end
if AnimationSpeed <= 0.05 then
AnimationSpeed = 0.05
end
end
if Variant then
if typeof(Variant) == "Color3" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Variant),
ColorSequenceKeypoint.new(1, Variant)
}
Character:SetAttribute(Effect .. "Variant", nil)
elseif Variant == "Paralyze" then
Humanoid:ChangeState(Enum.HumanoidStateType.Ragdoll)
elseif Variant == "Shock" then
Humanoid:ChangeState(Enum.HumanoidStateType.FallingDown)
end
end
task.spawn(function()
local BV
if not Root:FindFirstChild("Stunned") then
BV = Instance.new("BodyVelocity")
BV.Name = "Stunned"
BV.MaxForce = Force
BV.Velocity = Root.Position.Unit * 0 + Vector3.new(0, -0.1, 0)
BV.Parent = Root
end
repeat
VisualEffect:Emit(1)
if BV then
BV.Velocity = Root.Position.Unit * 0 + Vector3.new(0, -0.1, 0)
if Character:GetAttribute(Effect .. "Immunity") then
if Character:GetAttribute(Effect .. "Immunity") < 100 then
FunctionBank:MeltDefense(Character, "Lightning", 1)
end
else
FunctionBank:MeltDefense(Character, "Lightning", 1)
end
end
if Humanoid and Humanoid:FindFirstChildOfClass("Animator") then
local Animator = Humanoid:FindFirstChildOfClass("Animator")
for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
v:AdjustSpeed(AnimationSpeed)
end
end
task.wait(Tick)
until not CS:HasTag(Character, "Stun")
if Humanoid:FindFirstChildOfClass("Animator") then
local Animator = Humanoid:FindFirstChildOfClass("Animator")
for i, v in pairs(Animator:GetPlayingAnimationTracks()) do
v:AdjustSpeed(1)
end
end
Humanoid:ChangeState(Enum.HumanoidStateType.Freefall)
if BV then
BV:Destroy()
BV = nil
end
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
Creator = nil
end)
end
end)
CS:GetInstanceAddedSignal("Fire"):Connect(function(Character)
local Effect = "Fire"
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
local EffectConfig = CheckForEffectConfig(Character, Effect)
if Root and EffectConfig then
local VisualEffect = FireEffect:Clone()
VisualEffect.Parent = Root
VisualEffect.Enabled = true
local Damage = EffectConfig:GetAttribute("Damage") or 5
local Tick = EffectConfig:GetAttribute("Tick") or 1
local Creator = EffectConfig:GetAttribute("Creator")
local Variant = EffectConfig:GetAttribute("Variant")
if Variant then
if typeof(Variant) == "Color3" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Variant),
ColorSequenceKeypoint.new(1, Variant)
}
elseif Variant == "OverseerBurn" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Color3.fromRGB(0, 85, 0)),
ColorSequenceKeypoint.new(1, Color3.fromRGB(0, 170, 0))
}
end
end
task.spawn(function()
repeat
if Humanoid and Humanoid.Health > 0 then
DealDamage(Damage, Effect, Creator, Character, Humanoid, false, false, "Burn")
FunctionBank:MeltDefense(Character, Effect, 2)
else
break
end
task.wait(Tick)
until not CS:HasTag(Character, Effect)
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
Creator = nil
end)
end
end)
CS:GetInstanceAddedSignal("Acid"):Connect(function(Character)
local Effect = "Acid"
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
local EffectConfig = CheckForEffectConfig(Character, Effect)
if Root and EffectConfig then
local VisualEffect = AcidEffect:Clone()
VisualEffect.Parent = Root
VisualEffect.Enabled = true
local Damage = EffectConfig:GetAttribute("Damage") or 5
local Tick = EffectConfig:GetAttribute("Tick") or 1
local Creator = EffectConfig:GetAttribute("Creator")
local Variant = EffectConfig:GetAttribute("Variant")
if Variant then
if typeof(Variant) == "Color3" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Variant),
ColorSequenceKeypoint.new(1, Variant)
}
end
end
task.spawn(function()
repeat
if Humanoid and Humanoid.Health > 0 then
DealDamage(Damage, Effect, Creator, Character, Humanoid, false, false, "Fade")
FunctionBank:MeltDefense(Character, Effect, 2)
else
break
end
task.wait(Tick)
until not CS:HasTag(Character, Effect)
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
Creator = nil
end)
end
end)
CS:GetInstanceAddedSignal("Radiation"):Connect(function(Character)
local Effect = "Radiation"
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
local EffectConfig = CheckForEffectConfig(Character, Effect)
if Root and EffectConfig then
local VisualEffect = RadiationEffect:Clone()
VisualEffect.Parent = Root
VisualEffect.Enabled = true
local Damage = EffectConfig:GetAttribute("Damage") or 5
local Tick = EffectConfig:GetAttribute("Tick") or 1
local Creator = EffectConfig:GetAttribute("Creator")
local Variant = EffectConfig:GetAttribute("Variant")
if Variant then
if typeof(Variant) == "Color3" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Variant),
ColorSequenceKeypoint.new(1, Variant)
}
end
end
task.spawn(function()
repeat
if Humanoid and Humanoid.Health > 0 then
DealDamage(Damage, Effect, Creator, Character, Humanoid, true, false, "JointBreak")
FunctionBank:MeltDefense(Character, Effect, 2)
else
break
end
task.wait(Tick)
until not CS:HasTag(Character, Effect)
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
Creator = nil
end)
end
end)
local FreezeModule = require(script.FreezeModuleModified)
CS:GetInstanceAddedSignal("Ice"):Connect(function(Character)
local Effect = "Ice"
if Character:GetAttribute(Effect .. "Immunity") and Character:GetAttribute(Effect .. "Immunity") >= 100 then
return
end
if Character and Character:FindFirstChildOfClass("Humanoid") then
FreezeModule.Freeze(Character)
Character:SetAttribute("Frozen", true)
FunctionBank:MeltDefense(Character, Effect, 5)
end
end)
CS:GetInstanceRemovedSignal("Ice"):Connect(function(Character)
if Character and Character:FindFirstChildOfClass("Humanoid") then
FreezeModule.Unfreeze(Character)
Character:SetAttribute("Frozen", nil)
end
end)
CS:GetInstanceAddedSignal("Void"):Connect(function(Character)
local Effect = "Void"
if Character:GetAttribute(Effect .. "Immunity") and Character:GetAttribute(Effect .. "Immunity") >= 100 then
return
end
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
if Root then
local VisualEffect = VoidEffect:Clone()
VisualEffect.Parent = Root
VisualEffect.Enabled = true
task.spawn(function()
repeat
if Humanoid and Humanoid.Health > 0 then
if not Character:GetAttribute("Voided") then
Character:SetAttribute("Voided", true)
end
FunctionBank:MeltDefense(Character, Effect, 5)
else
break
end
task.wait(1)
until not CS:HasTag(Character, Effect)
if Character and Character:GetAttribute("Voided") then
Character:SetAttribute("Voided", nil)
end
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
end)
end
end)
CS:GetInstanceAddedSignal("Poison"):Connect(function(Character)
local Effect = "Poison"
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
local EffectConfig = CheckForEffectConfig(Character, Effect)
if Root and EffectConfig then
local VisualEffect = PoisonEffect:Clone()
VisualEffect.Parent = Root
VisualEffect.Enabled = true
local Damage = math.round(Humanoid.MaxHealth * EffectConfig:GetAttribute("Damage")) or math.round(Humanoid.MaxHealth * 0.025)
local Tick = EffectConfig:GetAttribute("Tick") or 0.5
local Creator = EffectConfig:GetAttribute("Creator")
local Variant = EffectConfig:GetAttribute("Variant")
if Variant then
if typeof(Variant) == "Color3" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Variant),
ColorSequenceKeypoint.new(1, Variant)
}
end
end
task.spawn(function()
repeat
if Humanoid and Humanoid.Health > 0 then
DealDamage(Damage, Effect, Creator, Character, Humanoid, true, false, nil)
else
break
end
task.wait(Tick)
until not CS:HasTag(Character, Effect)
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
Creator = nil
end)
end
end)
CS:GetInstanceAddedSignal("Heal"):Connect(function(Character)
local Effect = "Heal"
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
local EffectConfig = CheckForEffectConfig(Character, Effect)
if Root and EffectConfig then
local VisualEffect = HealEffect:Clone()
VisualEffect.Parent = Root
for _, v in pairs(VisualEffect:GetChildren()) do
if v:IsA("ParticleEmitter") then
v.Enabled = true
end
end
local Damage = EffectConfig:GetAttribute("Damage") or 5
local Tick = EffectConfig:GetAttribute("Tick") or 0.5
local Variant = EffectConfig:GetAttribute("Variant")
if Variant then
if typeof(Variant) == "Color3" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Variant),
ColorSequenceKeypoint.new(1, Variant)
}
end
end
task.spawn(function()
repeat
if Humanoid and Humanoid.Health > 0 then
if Humanoid.Health < Humanoid.MaxHealth then
Humanoid.Health += Damage
elseif Humanoid.Health > Humanoid.MaxHealth then
Humanoid.Health = Humanoid.MaxHealth
end
else
break
end
task.wait(Tick)
until not CS:HasTag(Character, Effect)
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
end)
end
end)
CS:GetInstanceAddedSignal("Confusion"):Connect(function(Character)
local Effect = "Confusion"
if Character:GetAttribute(Effect .. "Immunity") and Character:GetAttribute(Effect .. "Immunity") >= 100 then
return
end
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local Root = Character:FindFirstChild("HumanoidRootPart")
local EffectConfig = CheckForEffectConfig(Character, Effect)
if Root and EffectConfig then
local VisualEffect = ConfusionEffect:Clone()
VisualEffect.Parent = Root
VisualEffect.Enabled = true
local Tick = EffectConfig:GetAttribute("Tick") or 0.01
local Creator = EffectConfig:GetAttribute("Creator")
local Variant = EffectConfig:GetAttribute("Variant")
if Variant then
if typeof(Variant) == "Color3" then
VisualEffect.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, Variant),
ColorSequenceKeypoint.new(1, Variant)
}
end
end
task.spawn(function()
local InvertControls = nil
local BV = nil
if Character and Humanoid then
if Players:GetPlayerFromCharacter(Character) and not Character:FindFirstChild("InvertControls") then
InvertControls = script.InvertControls:Clone()
InvertControls.Parent = Character
InvertControls.Enabled = true
end
repeat
if not Players:GetPlayerFromCharacter(Character) and Root and Humanoid and Humanoid.Health > 0 then
if not Root:FindFirstChild("Reverse") then
BV = Instance.new("BodyVelocity")
BV.Name = "Reverse"
BV.MaxForce = Vector3.one * 1e6
BV.Velocity = Root.Velocity * -1
BV.Parent = Root
end
BV.Velocity = Root.Velocity * -1
end
task.wait(Tick)
until not CS:HasTag(Character, Effect)
end
if BV then
BV:Destroy()
BV = nil
end
if VisualEffect then
VisualEffect:Destroy()
VisualEffect = nil
end
if InvertControls then
InvertControls:Destroy()
InvertControls = nil
local Reset = script.Reset:Clone()
Reset.Parent = Character
Reset.Enabled = true
task.delay(1, function()
if Reset then
Reset:Destroy()
Reset = nil
end
end)
end
Creator = nil
end)
end
end)
Script 2 (StatusEffectHandler):
-- By ThunderDaNub. More info in the Notes script
local RS = game:GetService("ReplicatedStorage")
local CS = game:GetService("CollectionService")
local SS = game:GetService("ServerStorage")
local SSS = game:GetService("ServerScriptService")
local Running = game:GetService("RunService")
local AddEffect = script:FindFirstChild("AddEffect")
local FunctionBank = require(script.Parent.FunctionBank)
local Effects = FunctionBank.Effects
local ActiveEffects = {}
local function TableFind(Table, Value)
for i, v in ipairs(Table) do
if string.match(v, Value) then
return v
end
end
end
local function IncreaseEffectDuration(Target, Effect, ExtraDuration)
for _, v in ipairs(ActiveEffects) do
if v.Target == Target and v.Effect == Effect then
v.Duration = v.Duration + ExtraDuration
return true
end
end
return false
end
local Signal
local function StartEffectLoop()
if Signal then return end
Signal = Running.Heartbeat:Connect(function()
local t = os.clock()
for i = #ActiveEffects, 1, -1 do
local v = ActiveEffects[i]
if v then
local EffectConfig = v.EffectConfig
local Target = v.Target
local Effect = v.Effect
if (t - v.Tick) >= v.Duration or (EffectConfig and (not EffectConfig.Parent or not EffectConfig.Parent.Parent)) then
if CS:HasTag(Target, Effect) then
CS:RemoveTag(Target, Effect)
end
if EffectConfig then
EffectConfig:Destroy()
end
table.remove(ActiveEffects, i)
end
end
end
-- Stop the loop if no effects remain
if #ActiveEffects == 0 then
Signal:Disconnect()
Signal = nil
end
end)
end
local function AddNewEffect(Arg)
table.insert(ActiveEffects, Arg)
StartEffectLoop()
end
AddEffect.Event:Connect(function(Target, Effect, Duration, Damage, Creator, Tick, Variant, Stackable)
if Target and Effect and Duration then
for i, v in ipairs(Target:GetChildren()) do
if v.Name == Effect and v:IsA("Configuration") then
if Stackable then
IncreaseEffectDuration(Target, Effect, Duration)
end
return
end
end
local Effect = TableFind(Effects, Effect)
if Effect then
local EffectConfig = script.EffectTemplate:Clone()
EffectConfig.Name = Effect
if Damage and tonumber(Damage) ~= nil then
EffectConfig:SetAttribute("Damage", tonumber(Damage))
end
if Tick and tonumber(Tick) ~= nil then
EffectConfig:SetAttribute("Tick", tonumber(Tick))
end
if Creator then
if typeof(Creator) == "string" then
EffectConfig:SetAttribute("Creator", Creator)
else
EffectConfig:SetAttribute("Creator", Creator.Name)
end
end
if Variant then
EffectConfig:SetAttribute("Variant", Variant)
end
Duration = tonumber(Duration)
if Target:GetAttribute(Effect .. "Immunity") then
if Target:GetAttribute(Effect .. "Immunity") <= 100 then
Duration = Duration - Duration * (Target:GetAttribute(Effect .. "Immunity") / 100)
end
end
task.defer(function()
if Duration > 0 then
AddNewEffect({Target = Target, Effect = Effect, EffectConfig = EffectConfig, Tick = os.clock(), Duration = Duration})
EffectConfig.Parent = Target
if not CS:HasTag(Target, Effect) then
CS:AddTag(Target, Effect)
end
else
EffectConfig:Destroy()
EffectConfig = nil
end
end)
end
end
end)
Module script (Configuration/settings and other functions):
-- By ThunderDaNub. More info in the Notes script
local Module = {}
local Players = game:GetService("Players")
Module.DefaultStats = {
["MaxHealth"] = 100,
["WalkSpeed"] = 16,
["JumpPower"] = 50,
}
Module.Effects = {"Stun", "Fire", "Poison", "Heal", "Ice", "Acid", "Radiation", "Confusion", "Void"}
Module.Elements = {
["Fire"] = {Limit = 15},
["Ice"] = {Limit = 15},
["Lightning"] = {Limit = 15},
["Acid"] = {Limit = 15},
["Radiation"] = {Limit = 15},
["Void"] = {Limit = 15},
}
Module.Immunities = {
"FireImmunity",
"IceImmunity",
"PoisonImmunity",
"StunImmunity",
"AquaImmunity",
"ExplosiveImmunity",
"AcidImmunity",
"RadiationImmunity",
}
local AddEffect = script.Parent.StatusEffectHandler:FindFirstChild("AddEffect")
function Module:AddEffect(Target, Effect, Duration, Damage, Creator, Tick, Variant, Stackable)
AddEffect:Fire(Target, Effect, Duration, Damage, Creator, Tick, Variant, Stackable)
end
function Module:MeltDefense(Target, Element, Amount)
if Target and Target:GetAttribute("Defense") and Target:GetAttribute("Defense") > 0 then
local MeltedAmount = Target:GetAttribute(Element .. "DefenseMelting")
if MeltedAmount then
local Limit = Module.Elements[Element].Limit
if MeltedAmount < Limit then
if Limit - MeltedAmount >= Amount then
Target:SetAttribute(Element .. "DefenseMelting", MeltedAmount + Amount)
Target:SetAttribute("Defense", Target:GetAttribute("Defense") - Amount)
else
Target:SetAttribute(Element .. "DefenseMelting", Limit)
Target:SetAttribute("Defense", Target:GetAttribute("Defense") - (Limit - MeltedAmount))
end
end
else
Target:SetAttribute(Element .. "DefenseMelting", Amount)
Target:SetAttribute("Defense", Target:GetAttribute("Defense") - Amount)
end
end
end
function Module:TagForDamage(Player: Player, Target, Damage: number)
local Humanoid = Target:FindFirstChildOfClass("Humanoid")
if not Humanoid or Humanoid.Health <= 0 then return end
local PlayerTags = Target:FindFirstChild("PlayerTags")
if not PlayerTags then
PlayerTags = Instance.new("Configuration")
PlayerTags.Name = "PlayerTags"
PlayerTags.Parent = Target
end
local ExistingTag = PlayerTags:GetAttribute(Player.UserId)
if ExistingTag then
PlayerTags:SetAttribute(Player.UserId, ExistingTag + Damage)
else
PlayerTags:SetAttribute(Player.UserId, Damage)
end
if Damage >= Humanoid.Health then
PlayerTags:SetAttribute("LastHit", Player.UserId)
end
end
function Module:Damage(Player: Player, Target, Damage, IgnoreDefense, IgnoreImmunity, AttackType, Cooldown)
if Player and Target and Target:FindFirstChildOfClass("Humanoid") and tonumber(Damage) ~= nil then
local TargetHum = Target:FindFirstChildOfClass("Humanoid")
if TargetHum.Health <= 0 then return end
local Character = Player
if Player:IsA("Player") then
Character = Player.Character
else
Player = Players:GetPlayerFromCharacter(Player)
Character = Player.Character
end
if Cooldown then
if Target:GetAttribute(Player.UserId) then return end
Target:SetAttribute(Player.UserId, true)
task.delay(Cooldown, function()
Target:SetAttribute(Player.UserId, nil)
end)
end
if Character and Character:GetAttribute("Voided") then
Damage = Damage / 2
end
if not IgnoreDefense and Target:GetAttribute("Defense") then
Damage = Damage - (Damage * Target:GetAttribute("Defense") / 100)
end
if not IgnoreImmunity and AttackType and Target:GetAttribute(AttackType .. "Immunity") then
Damage = Damage - Damage * (Target:GetAttribute(AttackType .. "Immunity") / 100)
end
Damage = math.clamp(Damage, 0, TargetHum.Health)
Module:TagForDamage(Player, Target, Damage)
TargetHum:TakeDamage(Damage)
return Damage
end
end
return Module
Features
Features
-
Many free presets to choose from (Literally everything you will ever need)
-
Any targets can have any amount of status effects being applied at once
-
Status effect duration is stackable
-
The same type of effect may look or function differently by setting Variant (Green fire, ragdoll stun, etc…)
Limitations
Limitations
-
I’m a modeler, so my coding skill is limited. HOWEVER, the models I make are also not really good (Jack of
all trades, master of none moment) -
No support for duration-stacking (Using Debris service)- Actually, I just found out an alternative way using BindableEvent as I was making this post -
No colored text formatting here
Story
Story
One day while looking through the code in free models to see if I could learn something interesting, I came across CollectionService and learnt how to use it
As I was developing my game, Mega Boss Battles, I made this open-sourced FreezeModule for everyone to use with my little scripting knowledge
After a while, I realized there was a problem. If I called this function to freeze players from a projectile script or any tools but they get destroyed before the effect is over, they would be stuck. That’s why I decided to spend months on making and improving this system
Update Logs
Update Logs
cricket noises
Support Me - Check the game below to see this system in effect!
No puns intended
Mega Boss Battles (Showcase) | Clothing Store |
Youtube Channel
Support Me - Check the game below to see this system in effect!
No puns intended
Roblox Model
Asset file: Thunder’s Status Effect System.rbxm (39.3 KB)