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.

warningLuaudit check: damage-ignores-forcefield

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.Duration above 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 - amount or humanoid.Health = 0 ignores ForceFields. 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 Invulnerable attribute, must be checked in every damage path. One path that skips it is a finding under this check.
  • Healing with a negative TakeDamage amount is blocked by a ForceField. Set Health directly for healing, capped at MaxHealth.

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 Health assignments 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 and SpawnLocation.Duration set to 0, lose nothing by setting Health. Check the spawns before reporting.
  • Setting Health to 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 ForceField itself, with FindFirstChildOfClass("ForceField"), before setting Health, is fine.