Why weapons should use TakeDamage instead of setting Health
Setting Humanoid.Health ignores ForceFields, so spawn protection stops working. How to route every weapon's damage through TakeDamage.
What it looks like
The game protects players with a ForceField, usually the one given on spawn, but weapons or abilities lower Humanoid.Health directly instead of calling Humanoid:TakeDamage. Setting Health ignores every ForceField, so protected players still take damage.
Luau
humanoid.Health -= damage
How to detect it
- Find where the game uses
ForceFields:SpawnLocation.Durationabove 0 gives one on every spawn, and scripts may add them for safe zones, respawn protection or round starts. - Find every place a weapon, ability, projectile or hazard hurts another player. Damage written as
humanoid.Health -= amount,humanoid.Health = humanoid.Health - amountorhumanoid.Health = 0ignoresForceFields.Humanoid:TakeDamage(amount)respects them. - Damage aimed only at the player who caused it, such as fall damage or a lava pool, is the game's choice, but say so if it kills players during spawn protection.
- Custom protection, such as an
Invulnerableattribute, must be checked in every damage path. One path that skips it is a finding under this check. - Healing with a negative
TakeDamageamount is blocked by aForceField. SetHealthdirectly for healing, capped atMaxHealth.
What an exploiter could do
Players can be killed the moment they spawn, so they never get a chance to move. Combined with any weapon problem, such as Hits not checked against who may be attacked or Fire rate, ammo or reloads kept on the client, an exploiter can keep whole teams dead at their spawn. Even without exploits, ordinary players can spawn-kill.
How to fix it
- Deal damage through one server function that calls
Humanoid:TakeDamage, and use it for every weapon and ability. - If the game has its own protection, check it in that same function before applying damage.
- Keep
Healthassignments for healing and deliberate resets only.
Vulnerable example
Vulnerable
local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local damage = 30 local reach = 12 local cooldown = 0.6 local lastPunch: { [Player]: number } = {} ReplicatedStorage.Remotes.Punch.OnServerEvent:Connect(function(player: Player, target: unknown) if typeof(target) ~= "Instance" or not target:IsA("Player") or target == player then return end local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart") local targetRoot = target.Character and target.Character:FindFirstChild("HumanoidRootPart") local humanoid = target.Character and target.Character:FindFirstChildOfClass("Humanoid") if not root or not root:IsA("BasePart") or not targetRoot or not targetRoot:IsA("BasePart") or not humanoid then return end local now = os.clock() if now - (lastPunch[player] or 0) < cooldown then return end lastPunch[player] = now if (root.Position - targetRoot.Position).Magnitude <= reach then humanoid.Health -= damage end end) Players.PlayerRemoving:Connect(function(player) lastPunch[player] = nil end)
Fixed example
Fixed
local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local damage = 30 local reach = 12 local cooldown = 0.6 local lastPunch: { [Player]: number } = {} ReplicatedStorage.Remotes.Punch.OnServerEvent:Connect(function(player: Player, target: unknown) if typeof(target) ~= "Instance" or not target:IsA("Player") or target == player then return end local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart") local targetRoot = target.Character and target.Character:FindFirstChild("HumanoidRootPart") local humanoid = target.Character and target.Character:FindFirstChildOfClass("Humanoid") if not root or not root:IsA("BasePart") or not targetRoot or not targetRoot:IsA("BasePart") or not humanoid then return end local now = os.clock() if now - (lastPunch[player] or 0) < cooldown then return end lastPunch[player] = now if (root.Position - targetRoot.Position).Magnitude <= reach then humanoid:TakeDamage(damage) end end) Players.PlayerRemoving:Connect(function(player) lastPunch[player] = nil end)
Common false positives
- Games with no
ForceFields at all, no spawn protection andSpawnLocation.Durationset to 0, lose nothing by settingHealth. Check the spawns before reporting. - Setting
Healthto heal, to reset a character on purpose, or to kill a player who used a reset or a kill-brick meant to ignore protection, is a design choice. - Damage that checks the target for a
ForceFielditself, withFindFirstChildOfClass("ForceField"), before settingHealth, is fine.