Shield damage detection - how to check for damage when humanoid is at low health?

Hi there!

I’m currently in the process of making a new shield system for my game, and for the most part it works fine. The shield keeps track of its own “HP” and when the player is damaged, subtracts that damage from the shield and heals the player accordingly.

However, the problem comes when the player is at low health, as because the script detects damage to the shield by subtracting the current health from the last detected health of the player, when the player’s health reaches something like 5 and is damaged by an attack that deals 500 or so damage, the shield would only receive 5 points of damage.

I’m stuck on how to fix this at the moment, I’d appreciate some help. Here is the script I’m using.

local Tool = script.Parent

local CanEquip = true  -- Control the equipping cooldown
local debounce = false 
local originalToolName = Tool.Name 

local character = Tool.Parent.Parent

local model = game.Workspace:FindFirstChild(character.Name)
local humanoid = model.Humanoid

local ShieldHealth = humanoid.MaxHealth - 1
local CurrentShieldHealth = ShieldHealth

local lastHealth = humanoid.Health

function OnEquipped(mouse)


	if CurrentShieldHealth > 0 then 
		
                --these just disable the visual effects for damage 
		humanoid.Parent:FindFirstChild("Z1").Middle.sparks.Enabled = false 
		humanoid.Parent:FindFirstChild("Z1").Middle.Sound.Enabled = false 
		humanoid.Parent:FindFirstChild("Z1").Middle.spark1.Enabled = false 
		humanoid.Parent:FindFirstChild("Z1").Middle.spark2.Enabled = false 
		humanoid.Parent:FindFirstChild("Z1").Middle.spark3.Enabled = false 
		humanoid.Parent:FindFirstChild("Z1").Middle.spark4.Enabled = false 
		
		
		humanoid.HealthChanged:Connect(function()
			local currentHealth = humanoid.Health
			local damage = lastHealth - currentHealth

			if damage > 0 then
			if CurrentShieldHealth > damage then 
				
					CurrentShieldHealth = CurrentShieldHealth - damage
					humanoid.Health = currentHealth + damage
					if CurrentShieldHealth <= 350 and CurrentShieldHealth > 200 then
						script.Parent.Shield.FrontDecal1.Transparency = 0.4
						script.Parent.Shield.BackDecal1.Transparency = 0.4
						Tool.Shield.Crack:Play()
					elseif CurrentShieldHealth <= 200 and CurrentShieldHealth > 100 then
						script.Parent.Shield.FrontDecal2.Transparency = 0.4
						script.Parent.Shield.BackDecal2.Transparency = 0.4
						script.Parent.Shield.FrontDecal1.Transparency = 0.4
						script.Parent.Shield.BackDecal1.Transparency = 0.4
						Tool.Shield.Crack:Play()
					elseif CurrentShieldHealth <= 100 then
						script.Parent.Shield.FrontDecal2.Transparency = 0.4
						script.Parent.Shield.BackDecal2.Transparency = 0.4
						script.Parent.Shield.FrontDecal1.Transparency = 0.4
						script.Parent.Shield.BackDecal1.Transparency = 0.4
						script.Parent.Shield.FrontDecal3.Transparency = 0.4
						script.Parent.Shield.BackDecal3.Transparency = 0.4
						Tool.Shield.Crack:Play()
					end
				else
					if CurrentShieldHealth < damage or damage > lastHealth then 
						if debounce == false then 
							debounce = true
							humanoid.Health = currentHealth + CurrentShieldHealth
							CurrentShieldHealth = 0

							print("Shield destroyed")

							if CurrentShieldHealth == 0 then 
								
								Tool.Shield.ShatterSound:Play()
								
								Tool.Shield.FrontDecal1.Transparency = 1
								Tool.Shield.FrontDecal2.Transparency = 1
								Tool.Shield.FrontDecal3.Transparency = 1
								Tool.Shield.BackDecal1.Transparency = 1
								Tool.Shield.BackDecal2.Transparency = 1
								Tool.Shield.BackDecal3.Transparency = 1
								
								Tool.Shield.CanCollide = false 
								Tool.Shield.ParticleEmitter.Enabled = false 
								Tool.Particle.Thingy.Enabled = false 
								Tool.Shield.Transparency = 1
								Tool.Ring.Transparency = 1
								Tool.ZTimer.Transparency = 1

								humanoid.Parent:FindFirstChild("Z1").Middle.sparks.Enabled = true  
								humanoid.Parent:FindFirstChild("Z1").Middle.Sound.Enabled = true 

								print("Sparks enabled!")
								Tool.Shield.Shatter.Enabled = true 
								wait(0.2)
								Tool.Shield.Shatter.Enabled = false 
								wait(1)
								
							Tool.Name = "Barrier [COOLDOWN]"

								-- Unequip the shield and start cooldown
								debounce = false 
								humanoid:UnequipTools()
					
								wait(45)  
								CurrentShieldHealth = ShieldHealth
								Tool.Shield.CanCollide = true 
								Tool.Shield.ParticleEmitter.Enabled = true  
								Tool.Particle.Thingy.Enabled = true  
								Tool.Shield.Transparency = 0
								Tool.Ring.Transparency = 0
								Tool.ZTimer.Transparency = 0
								Tool.Name = originalToolName
							end
						end
				end
			end 
			end 
			
		end)
	
	else if CurrentShieldHealth <= 0 then 
			task.wait()
			print("Route two!")
			humanoid:UnequipTools()
		end
	end
end 


Tool.Unequipped:Connect(function()


	local character = Tool.Parent.Parent
	
	local model = game.Workspace:FindFirstChild(character.Name)
	local humanoid = model.Humanoid
	local sparks = model.Z1.Middle.sparks
	local sound = model.Z1.Middle.Sound

	sound.Enabled = true
	sparks.Enabled = true
	humanoid.HealthChanged:Connect(function()
		if humanoid.Health < lastHealth then
			lastHealth = humanoid.Health
		end
	end)
	
end)


Tool.Equipped:connect(OnEquipped)


2 Likes

I admit I’m not a very good scripter so pointing out redundancies and stuff that slows down the code here is also appreciated, thanks a bunch!

2 Likes

If your scripting framework allows it, it would be best to do the calculations when the damage is given, rather than using .HealthChanged. In this case, you wouldn’t be modifying the player health until appropriate and will give you the best result. It would also prevent the player from dying since the damage goes to the shield first and not the player.

One problem with your code is that if the player dies even with the shield on, it will still kill the player. (solution above) would solve this. To sum it up, create a universal damageFunction() that will check for any shields BEFORE damage is applied to the player.

I don’t think your problem is fixable with the information you currently have. If you were able to give the script the amount of damage that was applied (that is not coming from lastHealth - currentHealth) then it would be fixable.

The only potential solution I can think of given the current information in the script is to add the ShieldHealth to the character’s MaxHealth and work from there.

Here are some tips that won’t solve your solution but you can improve upon.

  1. You are connecting the humanoid.HealthChanged function every time the shield is equipped. This is not necessary and uses more memory than necessary. Instead, put it outside of the OnEquipped() function. Same for the Unequipped function.

  2. Make sure not to wait and yield the code when dealing with important things, this decreases accuracy. For example, in this segment you can you task.spawn() or coroutines to run it separately.

task.spawn(function() -- Won't yield the rest of the script
  Tool.Shield.Shatter.Enabled = true 
  wait(0.2)
  Tool.Shield.Shatter.Enabled = false 
  wait(1)
end)
  1. When pasting your code on here try to delete any code that isn’t related or necessary towards solving your problem. For example, all of the transparency and particles lines can be removed. It will attract more people towards your post and they’ll want to help more since it’s not a code glob.
1 Like

Thanks so much for the help! I’ll try integrating shield detection into the different attacks, and probably make the Shield’s HP a NumberValue within the tool so that it can be changed by the attacks without computing for the player’s damage.

1 Like

Okay, I’ve managed to let the shield calculate damage externally by putting a Humanoid within the tool. I feel it’s a very unorthodox situation but it does serve my purposes well.

This is an excerpt of the new script that deals with what happens when the Humanoid reaches a certain health threshold. It works fine, EXCEPT for the last one when I want it to reach zero. After that point, there’s no output from the script.

ShieldHuman:GetPropertyChangedSignal("Health"):Connect(function()

		if  ShieldHuman.Health <= 350 and  ShieldHuman.Health > 200 then
			-- insert visual and audio effects here
		elseif  ShieldHuman.Health <= 200 and  ShieldHuman.Health > 100 then
			-- insert visual and audio effects here
		elseif  ShieldHuman.Health <= 100 then
		-- insert visual and audio effects here
			Tool.Shield.Crack:Play()

		elseif ShieldHuman.Health < 1 then 
	-- insert visual and audio effects here
1 Like