How to make function less cluttered

I am working on a advanced limb health system with additional effects and properties based on limb loss. It works fine but I was thinking of releasing this to the public later on and was wondering if I could make this function cleaner? Here is the function:

-- This function controls limb loss
-- Uses 2 properties to control who is losing the limb, and the specific limb to lose
-- This also controls the additional effects that happen when losing them

function LimbHandler.LoseLimb(char, limb)
	if limb == "Left Arm" and char.Torso:FindFirstChild("Left Shoulder") then
		char.Torso["Left Shoulder"]:Destroy()
		local sound = ScreamSounds[math.random(#ScreamSounds)]
		sound:Play()
		char.Torso.LArmGore.Transparency = 0
		game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char.Torso.LArmGore.Position)
		for i = 1,10 do
			char.Humanoid.Health = char.Humanoid.Health - 3
			game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char["Torso"].Position)
			wait(1)
		end
	elseif limb == "Right Arm" and char.Torso:FindFirstChild("Right Shoulder") then
		char.Torso["Right Shoulder"]:Destroy()
		local sound = ScreamSounds[math.random(#ScreamSounds)]
		sound:Play()
		char.Torso.RArmGore.Transparency = 0
		game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char.Torso.RArmGore.Position)
		for i = 1,10 do
			char.Humanoid.Health = char.Humanoid.Health - 3
			game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char["Torso"].Position)
			wait(1)
		end
	elseif limb == "Head" and char.Torso:FindFirstChild("Neck") then
		char.Torso["Neck"]:Destroy()
		local sound = ScreamSounds[math.random(#ScreamSounds)]
		sound:Play()
		char.Torso.HeadGore.Transparency = 0
		game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char.Torso.HeadGore.Position)
	elseif limb == "Left Leg" and char.Torso:FindFirstChild("Left Hip") then
		char.Torso["Left Hip"]:Destroy()
		local sound = ScreamSounds[math.random(#ScreamSounds)]
		sound:Play()
		char.Humanoid.WalkSpeed = 13
		char.Torso.LLegGore.Transparency = 0
		game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char.Torso.LLegGore.Position)
		if char.Torso:FindFirstChild("Right Hip") == nil then
			while char.Humanoid.Health > 0 do
				wait(.1)
				char.Humanoid.Health = char.Humanoid.Health - 5
				game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(1,2), char["Torso"].Position)
			end
		else
		for i = 1,5 do
			char.Humanoid.Health = char.Humanoid.Health - 3
				game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char["Torso"].Position)
				wait(1)
			end
		end
	elseif limb == "Right Leg" and char.Torso:FindFirstChild("Right Hip") then
		char.Torso["Right Hip"]:Destroy()
		local sound = ScreamSounds[math.random(#ScreamSounds)]
		sound:Play()
		char.Humanoid.WalkSpeed = 13
		char.Torso.RLegGore.Transparency = 0
		game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char.Torso.RLegGore.Position)
		if char.Torso:FindFirstChild("Left Hip") == nil then
			while char.Humanoid.Health > 0 do
				wait(.1)
				char.Humanoid.Health = char.Humanoid.Health - 5
				game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(1,2), char["Torso"].Position)
			end
		else
		for i = 1,5 do
			char.Humanoid.Health = char.Humanoid.Health - 3
				game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char["Torso"].Position)
				wait(1)
			end
		end
	end
end

I explained in the code block what it does, but if you want to know the additional properties Ill explain them:

If you lose both legs you bleed out quickly and are guaranteed to die
You bleed for a few seconds when you lose a limb
You bleed more if its an arm
You walk slower if you lose a leg

Maybe I should make a function for the bleeding? Sorry if the code is super awful I am still kinda new to scripting.

Also I forgot to mention the goreevent is just for blood coming out of the torso positioned where the limb was.

1 Like

There seems to be a lot of repetitive code, which is making the code cluttered. For example, the sound. It seems like all of the possible cases have the section

local sound = ScreamSounds[math.random(#ScreamSounds)]
sound:Play()

which you could instead have at the beginning or end of the function (probably the beginning, given the wait statements) as opposed to having it in every single case.
Alongside this, you could have the health removal loop as one seperate loop at the end of the function, and instead change a variable which determines the health loss.
So instead of:

		for i = 1,10 do
			char.Humanoid.Health = char.Humanoid.Health - 3
			game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char["Torso"].Position)
			wait(1)
		end

for every case, you could just have the same loop at the end, but isntead of a fixed -3 or -5, you could have it be a variable that is either assigned 3 or 5

TLDR: check your repetition

Edit 2: (Dont ask what edit 1 was)
Now, this is a cut down version. Basically, the limbDictionary is a dictionary that has the values of the Motor6D and the gore has FindFirstChild. Might be a bit worse in terms of performance because of FindFirstChild for the gore. Please reply if you have any issues with the code.

local limbDictionary = {
	["Left Arm"] = {"Left Shoulder", "LArmGore"},
	["Right Arm"] = {"Right Shoulder", "RArmGore"},
	["Head"] = {"Neck", "HeadGore"},
	["Left Leg"] = {"Left Hip", "LLegGore"},
	["Right Leg"] = {"Right Hip", "RLegGore"},}


function LimbHandler.LoseLimb(char, limb)
	local bleedDamage = 0
	local bleedTimer = 0
	local sound = ScreamSounds[math.random(#ScreamSounds)]
	sound:Play()
	local Motor6DSubject = char.Torso.FindFirstChild(limbDictionary[limb][1])
	if Motor6DSubject == nil then return end --check if the Motor6D exists
	local gore = char.Torso:FindFirstChild(limbDictionary[limb][2])
	if gore == nil then return end --check if the gore exists

	Motor6DSubject:Destroy()
	gore.Transparency = 0
	game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), gore.Position)

	if (limb == "Left Arm" or limb == "Right Arm") then
		bleedTimer = 10
		bleedDamage = 3
	elseif (limb == "Left Leg" or limb == "Right Leg") then
		
		char.Humanoid.WalkSpeed = 13		
		if (char.Torso:FindFirstChild("Right Hip") == nil  and limb == "Left Leg") or (char.Torso:FindFirstChild("Left Hip") == nil  and limb == "Right Leg") then
			while char.Humanoid.Health > 0 do
				wait(.1)
				char.Humanoid.Health = char.Humanoid.Health - 5
				game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(1,2), char["Torso"].Position)
			end
		else
			bleedTimer = 5
			bleedDamage = 5
		end
	end
	
	for i = 1, bleedTimer do
		char.Humanoid.Health = char.Humanoid.Health - bleedDamage
		game.ReplicatedStorage.Events.GoreEvent:FireAllClients(math.random(2,3), char["Torso"].Position)
		wait(1)
	end
end

Thank you so much! This is extremely helpful, although you did put a β€˜.’ instead of a β€˜:’ on local Motor6DSubject. Other than that it works perfectly! I will make sure to watch my repetition next time, thanks.

1 Like

One question, is it possible to make the limb CanCollide true? Currently when you lose a limb it just falls right through the floor, I want to try to make a collision part but I don’t know how to structure it to avoid repetition.

1 Like

You could just get the actual limb and then set CanCollide true. You could probably do this by either finding the limb from the char or use the motor6D to find the limb.

1 Like

I think I have to use a collider, cause even after setting them to CanCollide true they still fall through the ground, but thank you for your help!

1 Like