local K="\069\118\101\110\116"local l="\095\095\082\097\103\100\111\108\108\095\065\099\116\105\118\101"local c=game:GetService("\080\108\097\121\101\114\115")local F=game:GetService("\082\117\110\083\101\114\118\105\099\101")local e=game:GetService("\067\111\108\108\101\099\116\105\111\110\083\101\114\118\105\099\101")local w=game:GetService("\083\116\097\114\116\101\114\071\117\105")local G=require(script:WaitForChild("\082\105\103\084\121\112\101\115"))if F:IsServer()then local F=Instance.new("\082\101\109\111\116\101\069\118\101\110\116")F.Name=K F.Parent=script local w=false local function p(K,w)assert(w:IsDescendantOf(K))if e:HasTag(K,l)then return end e:AddTag(K,l)local p=G:GetAttachments(K,w)local H=c:GetPlayerFromCharacter(K)if H then F:FireClient(H,true,K,w)elseif K.PrimaryPart then F:FireAllClients(false,K,w)end w:ChangeState(Enum.HumanoidStateType.Physics)for l,c in pairs(p)do local F=K:FindFirstChild(l)if F then local K=Instance.new("\066\097\108\108\083\111\099\107\101\116\067\111\110\115\116\114\097\105\110\116")K.Attachment0=c[1]K.Attachment1=c[2]if F.Name=="\072\101\097\100"then K.LimitsEnabled=true K.UpperAngle=60 K.TwistLimitsEnabled=true K.TwistLowerAngle=-60 K.TwistUpperAngle=60 end K.Parent=F end end for K,l in pairs(K:GetDescendants())do if l:IsA("\077\111\116\111\114\054\068")then l:Destroy()end end end local function H(K,l)l.BreakJointsOnDeath=not w l.Died:Connect(function()if w then l.BreakJointsOnDeath=false p(K,l)end end)end local function O(K)local l=K:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if l then H(K,l)else K.ChildAdded:Connect(function(l)if l:IsA("\072\117\109\097\110\111\105\100")then H(K,l)end end)end end local function B(K)K.CharacterAdded:Connect(O)if K.Character then O(K.Character)end end c.PlayerAdded:Connect(B)for K,l in pairs(c:GetPlayers())do B(l)end function Ragdoll.Activate(l,K)if typeof(K)~="\073\110\115\116\097\110\099\101"or not K:IsA("\077\111\100\101\108")then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\065\099\116\105\118\097\116\101\' \040\077\111\100\101\108 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(K).."\041"),2)end local c=K:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if not c then return warn("\091\082\097\103\100\111\108\108\093 \067\111\117\108\100 \110\111\116 \114\097\103\100\111\108\108 "..(K:GetFullName().." \098\101\099\097\117\115\101 \105\116 \104\097\115 \110\111 \072\117\109\097\110\111\105\100"))end p(K,c)end function Ragdoll.SetPlayerDefault(l,K)if K~=nil and typeof(K)~="\098\111\111\108\101\097\110"then error("\098\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \'\083\101\116\080\108\097\121\101\114\068\101\102\097\117\108\116\' \040\098\111\111\108\101\097\110 \101\120\112\101\099\116\101\100\044 \103\111\116 "..(typeof(K).."\041"),2)end w=K for K,l in pairs(c:GetPlayers())do if l.Character then local K=l.Character:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if K then K.BreakJointsOnDeath=not w end end end end else(script:WaitForChild(K)).OnClientEvent:Connect(function(K,l,c)if K then local K=l:FindFirstChild("\072\101\097\100")if K then workspace.CurrentCamera.CameraSubject=K end end c:ChangeState(Enum.HumanoidStateType.Physics)end)function Ragdoll.Activate(K)error("\082\097\103\100\111\108\108\058\058\065\099\116\105\118\097\116\101 \099\097\110\110\111\116 \098\101 \117\115\101\100 \102\114\111\109 \116\104\101 \099\108\105\101\110\116",2)end function Ragdoll.SetPlayerDefault(K)error("\082\097\103\100\111\108\108\058\058\083\101\116\080\108\097\121\101\114\068\101\102\097\117\108\116 \099\097\110\110\111\116 \098\101 \117\115\101\100 \102\114\111\109 \116\104\101 \099\108\105\101\110\116",2)end end return Ragdoll


local EVENT_NAME = "Event"
local RAGDOLLED_TAG = "__Ragdoll_Active"

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")
local StarterGui = game:GetService("StarterGui")
local RigTypes = require(script:WaitForChild("RigTypes"))

if RunService:IsServer() then
	
	-- Used for telling the client to set their own character to Physics mode:
	local event = Instance.new("RemoteEvent")
	event.Name = EVENT_NAME
	event.Parent = script
	
	-- Whether players ragdoll by default: (true = ragdoll, false = fall into pieces)
	local playerDefault = false
	
	-- Activating ragdoll on an arbitrary model with a Humanoid:
	local function activateRagdoll(model, humanoid)
		assert(humanoid:IsDescendantOf(model))
		if CollectionService:HasTag(model, RAGDOLLED_TAG) then
			return
		end
		CollectionService:AddTag(model, RAGDOLLED_TAG)

		local attachments = RigTypes:GetAttachments(model, humanoid)
		
		-- Propagate to player if applicable:
		local player = Players:GetPlayerFromCharacter(model)
		if player then
			event:FireClient(player, true, model, humanoid)
		elseif model.PrimaryPart then
			event:FireAllClients(false, model, humanoid)
		end
		
		-- Turn into loose body:
		humanoid:ChangeState(Enum.HumanoidStateType.Physics)
		
		-- Instantiate BallSocketConstraints:
		for name, objects in pairs(attachments) do
			local parent = model:FindFirstChild(name)
			if parent then
				local constraint = Instance.new("BallSocketConstraint")
				constraint.Attachment0 = objects[1]
				constraint.Attachment1 = objects[2]
				if parent.Name == "Head" then
					constraint.LimitsEnabled = true
					constraint.UpperAngle = 60
					constraint.TwistLimitsEnabled = true
					constraint.TwistLowerAngle = -60
					constraint.TwistUpperAngle = 60
				end
				constraint.Parent = parent
			end
		end
		
		-- Destroy all regular joints:
		for _, motor in pairs(model:GetDescendants()) do
			if motor:IsA("Motor6D") then
				motor:Destroy()
			end
		end
	end
	
	-- Set player Humanoid properties:
	local function onHumanoidAdded(character, humanoid)
		humanoid.BreakJointsOnDeath = not playerDefault
		humanoid.Died:Connect(
			function()
				if playerDefault then
					-- Ragdoll them:
					humanoid.BreakJointsOnDeath = false
					activateRagdoll(character, humanoid)
				end
			end
		)
	end
	
	-- Track existing and new player Humanoids:
	local function onCharacterAdded(character)
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		if humanoid then
			onHumanoidAdded(character, humanoid)
		else
			character.ChildAdded:Connect(
				function(child)
					if child:IsA("Humanoid") then
						onHumanoidAdded(character, child)
					end
				end
			)
		end
	end
	
	-- Track existing and new player characters:
	local function onPlayerAdded(player)
		player.CharacterAdded:Connect(onCharacterAdded)
		if player.Character then
			onCharacterAdded(player.Character)
		end
	end
	
	-- Track all players:
	Players.PlayerAdded:Connect(onPlayerAdded)
	for _, player in pairs(Players:GetPlayers()) do
		onPlayerAdded(player)
	end
	
	-- Activating the ragdoll on a specific model
	function Ragdoll:Activate(model)
		if typeof(model) ~= "Instance" or not model:IsA("Model") then
			error("bad argument #1 to 'Activate' (Model expected, got " .. typeof(model) .. ")", 2)
		end
		
		-- Model must have a humanoid:
		local humanoid = model:FindFirstChildOfClass("Humanoid")
		if not humanoid then
			return warn("[Ragdoll] Could not ragdoll " .. model:GetFullName() .. " because it has no Humanoid")
		end
		
		activateRagdoll(model, humanoid)
	end
	
	-- Setting whether players ragdoll when dying by default: (true = ragdoll, false = fall into pieces)
	function Ragdoll:SetPlayerDefault(enabled)
		if enabled ~= nil and typeof(enabled) ~= "boolean" then
			error("bad argument #1 to 'SetPlayerDefault' (boolean expected, got " .. typeof(enabled) .. ")", 2)
		end
		
		playerDefault = enabled
		
		-- Update BreakJointsOnDeath for all alive characters:
		for _, player in pairs(Players:GetPlayers()) do
			if player.Character then
				local humanoid = player.Character:FindFirstChildOfClass("Humanoid")
				if humanoid then
					humanoid.BreakJointsOnDeath = not playerDefault
				end
			end
		end
	end
	
else -- Client
	
	-- Client sets their own character to Physics mode when told to:
	script:WaitForChild(EVENT_NAME).OnClientEvent:Connect(
		function(isSelf, model, humanoid)
			if isSelf then
				local head = model:FindFirstChild("Head")
				if head then
					workspace.CurrentCamera.CameraSubject = head
				end
			end
			humanoid:ChangeState(Enum.HumanoidStateType.Physics)
		end
	)
	
	-- Other API not available from client-side:
	
	function Ragdoll:Activate()
		error("Ragdoll::Activate cannot be used from the client", 2)
	end
	
	function Ragdoll:SetPlayerDefault()
		error("Ragdoll::SetPlayerDefault cannot be used from the client", 2)
	end

end

return Ragdoll
