Ragdoll Solution -- R15/Customizable ragdolls for use with Layered Clothing

I’ve converted this into a module for easy use and removed the use of the client events as they weren’t needed.

All you need to do is stick this in ReplicatedStorage and require it in the server.
You still need the CharacterSetupScript labeled HumanoidStarterSet in StarterCharacterScripts

Hope this helps :slight_smile:

Heres the source:

local Ragdoll = {}

local RunService = game:GetService("RunService")

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

if RunService:IsServer() then
	local ServerStorage = game:GetService("ServerStorage")
	local RagdollCounterSys = ServerStorage.RagdollCounterSys
	local character = script.Parent
	local lDModeOn
	local diedCounted = false
	
	function Ragdoll:ragdollMe(character)	
		local humanoid = character:WaitForChild("Humanoid")
		humanoid.AutoRotate = false	
		character.HumanoidRootPart.CollisionGroup = "Body"
		character.HumanoidRootPart.CanCollide = false

		if RagdollCounterSys.ragdollsExisted.Value > RagdollCounterSys.ragdollsLdMax.Value then
			lDModeOn = true
		else
			lDModeOn = false
		end

		if RagdollCounterSys.charactersDied.Value >= RagdollCounterSys.charactersDiedMax.Value then
			task.wait(0.1 * RagdollCounterSys.charactersDied.Value) --Activate ragdoll delay, tenth x per character
		end

		if RagdollCounterSys.ragdollsLdEnable.Value == true and lDModeOn == true then --If LD mode is on
			if character.UpperTorso then
				for i,motor6d in pairs(character.UpperTorso:GetChildren()) do
					if motor6d:IsA("Motor6D") then	
						motor6d.Parent.CollisionGroup = "Body"
						motor6d.Parent.CanTouch = false
						motor6d:Destroy()
					end	
				end		
			end

			if character.LeftFoot then
				for i,motor6d in pairs(character.LeftFoot:GetChildren()) do
					if motor6d:IsA("Motor6D") then	
						motor6d.Parent.CollisionGroup = "Body"
						motor6d.Parent.CanTouch = true
						motor6d:Destroy()
					end	
				end		
			end

			if character.RightFoot then
				for i,motor6d in pairs(character.RightFoot:GetChildren()) do
					if motor6d:IsA("Motor6D") then	
						motor6d.Parent.CollisionGroup = "Body"
						motor6d.Parent.CanTouch = true
						motor6d:Destroy()
					end	
				end		
			end

			if character.Head then
				for i,motor6d in pairs(character.Head:GetChildren()) do
					if motor6d:IsA("Motor6D") then	--Getting motor6D joints as joints. Their parents are the parts. 
						motor6d.Parent.CollisionGroup = "Body"
						motor6d.Parent.CanTouch = true
						motor6d:Destroy()
					end	
				end		
			end
		else --If LD mode is off
			RagdollCounterSys.ragdollsExisted.Value += 1
			for i,limbs in pairs(character:GetChildren()) do
				for i,motor6d in pairs(limbs:GetChildren()) do
					if motor6d:IsA("Motor6D") then	--Getting motor6D joints as joints. Their parents are the parts. 
						motor6d.Parent.CollisionGroup = "Body"
						--print("Rookstun ", motor6d.Parent.CollisionGroup, " ", motor6d.Parent.CollisionGroupId, " ", motor6d.Parent)
						motor6d.Parent.CanCollide = true
						motor6d:Destroy()
					end	
				end
			end
		end
	end

	function Ragdoll:activateVelocity(player)
		player.character.HumanoidRootPart.AngularVelocity.Enabled = true
		player.character.HumanoidRootPart.LinearVelocity.Enabled = true
		if player.character:FindFirstChild("LeftUpperLeg") and player.character:FindFirstChild("RightUpperLeg") then
			player.character.LeftUpperLeg.AngularVelocity.Enabled = true
			player.character.RightUpperLeg.AngularVelocity.Enabled = true
		end
	end

	function Ragdoll:deactivateVelocity(player)
		player.character.HumanoidRootPart.AngularVelocity.Enabled = false
		player.character.HumanoidRootPart.LinearVelocity.Enabled = false
		if player.character:FindFirstChild("LeftUpperLeg") and player.character:FindFirstChild("RightUpperLeg") then
			player.character.LeftUpperLeg.AngularVelocity.Enabled = false
			player.character.RightUpperLeg.AngularVelocity.Enabled = false
		end
	end

	function Ragdoll:ragdollFreeze(character, state)
		if character and RagdollCounterSys.ragdollFreezeEnable.Value and state == Enum.HumanoidStateType.Dead then
			local upperTorso = character:WaitForChild("UpperTorso")
			repeat 
				local lastPos = upperTorso.Position
				wait(RagdollCounterSys.ragdollFreezeTime.Value) --Time left before it checks body.
				local newPos = upperTorso.Position
				local distanceDiff = (lastPos - newPos).magnitude 		--print("DistanceDiff", distanceDiff)
			until distanceDiff < 2 		--Distance a body must be close from its original check to be anchored

			for i,v in pairs(character:GetChildren()) do
				if v:IsA("MeshPart") then
					v.Anchored = true
				end
			end
			character.HumanoidRootPart.Anchored = true
		end
		if RagdollCounterSys.ragdollsExisted.Value ~= 0  then
			RagdollCounterSys.ragdollsExisted.Value -= 1
		end
	end

	function Ragdoll:resyncClothes(player)
		for i,v in pairs(player.character:GetChildren()) do --Hack. Refreshes and resyncs layered clothing.
			if v:IsA("Accessory") then
				for i2,v2 in pairs(v.Handle:GetChildren()) do 
					if v2:IsA("WrapLayer") then
						local refWT = Instance.new("WrapTarget")
						refWT.Parent = v2.Parent
						refWT:Destroy()
						refWT.Parent = nil
					end
				end
			end
		end
	end

	function Ragdoll:stopAnims(humanoid)
		local AnimTrack = humanoid:GetPlayingAnimationTracks()
		for i, track in pairs (AnimTrack) do
			track:Stop()
		end
	end
	
	function Ragdoll.DiedCountDecay()
		if RagdollCounterSys.charactersDied.Value > 0 and diedCounted == false then
			diedCounted = true
			repeat
				task.wait(RagdollCounterSys.characterDiedDecay.Value)
				RagdollCounterSys.charactersDied.Value -= 1
			until RagdollCounterSys.charactersDied.Value <= 0 
			diedCounted = false
		end
	end
	
	function Ragdoll.RagdollExistedReset()
		if RagdollCounterSys.ragdollsExisted.Value ~= 0 and diedCounted == false then
			diedCounted = true
			repeat
				RagdollCounterSys.ragdollsExisted.Value -= 1
				task.wait(2)
			until RagdollCounterSys.ragdollsExisted.Value <= 0 
			task.wait(120)
			diedCounted = false
		end
	end
	
	RagdollCounterSys.charactersDied:GetPropertyChangedSignal("Value"):Connect(Ragdoll.DiedCountDecay)
	
	if RagdollCounterSys.ragdollsLdEnable.Value == true  then
		RagdollCounterSys.ragdollsExisted:GetPropertyChangedSignal("Value"):Connect(Ragdoll.RagdollExistedReset)
	end
	
	Players.PlayerAdded:Connect(function(player)
		player.CharacterAdded:Connect(function(character)
			local humanoid = character:WaitForChild("Humanoid")

			humanoid.Died:Connect(function()
				Ragdoll:activateVelocity(player)
				humanoid:UnequipTools()
				for i, tool in pairs(player.Backpack:GetChildren()) do
					tool:Destroy()
				end	
				
				RagdollCounterSys.charactersDied.Value += 1
				Ragdoll:stopAnims(humanoid)
				Ragdoll:activateVelocity(player)
				Ragdoll:ragdollMe(player.character)
				Ragdoll:resyncClothes(player)
				task.wait()
				Ragdoll:deactivateVelocity(player)
				Ragdoll:ragdollFreeze(player.character, humanoid:GetState())
			end)
		end)
	end)
end

return Ragdoll
6 Likes

I was lookign for a replacement ragdoll that didn’t need events. And all-in-one but i noticed some bugs.

Going in water makes the character spam the swim emote and they just fall down in the water with no ability to swim or control the character.

3 Likes

Are you able to ragdoll a player without killing them?

3 Likes

Is it possible to toggle the ragdoll on and off. Your example only shows how to turn on ragdoll on death.

1 Like

I have exactly the same problem in water, any solution?

1 Like

Hi I got an idea about the freeze ragdoll, you could maybe just use AssemblyLinearVelocity (but be aware, I removed the variables)

local function ragdollFreeze(character, state)
	local upperTorso = character:WaitForChild("UpperTorso")
	
	task.wait(1) --Time left before it checks body.

	while upperTorso.AssemblyLinearVelocity.Magnitude > 5 do -- it should stop moving before anchoring
		task.wait(0.5)
	end

	task.wait(0.5)

	for i,v in pairs(character:GetChildren()) do
		if v:IsA("MeshPart") then
			v.Anchored = true
		end
	end
	character.HumanoidRootPart.Anchored = true
end