--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| 	Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]


AddCSLuaFile()

properties.Add( "rb655_make_animatable", {
	MenuLabel = "#tool.rb655_easy_animation.property",
	Order = 654,
	MenuIcon = "icon16/tick.png",
	Filter = function( self, ent, ply )
		if ( !IsValid( ent ) or !gamemode.Call( "CanProperty", ply, "rb655_make_animatable", ent ) ) then return false end
		if ( ent:GetClass() == "prop_animatable" ) then return false end
		if ( ent:IsPlayer() or !ent:GetModel() or ent:GetModel():StartWith( "*" ) ) then return false end
		--if ( string.find( ent:GetClass(), "prop_physics" ) or string.find( ent:GetClass(), "prop_ragdoll" ) ) then return true end
		return true
	end,
	Action = function( self, ent )
		self:MsgStart()
		net.WriteEntity( ent )
		self:MsgEnd()
	end,
	Receive = function( self, len, ply )
		local ent = net.ReadEntity()

		if ( !IsValid( ply ) or !IsValid( ent ) or !self:Filter( ent, ply ) ) then return false end

		local entActual = ent
		if ( IsValid( ent.AttachedEntity ) ) then
			ent = ent.AttachedEntity
		end

		local ragPos = ent:GetPos()

		-- Try to not make entity fly
		if ( ent:IsRagdoll() ) then
			for i = 0, ent:GetPhysicsObjectCount() - 1 do
				local bone = ent:GetPhysicsObjectNum( i )
				if ( IsValid( bone ) ) then
					local pos = bone:GetPos()

					-- Yes I like my pyramids
					if ( pos.z < ragPos.z ) then
						ragPos.z = pos.z
					end
				end
			end
		end

		local prop_animatable = ents.Create( "prop_animatable" )
		prop_animatable:SetModel( ent:GetModel() )
		prop_animatable:SetPos( ragPos )
		prop_animatable:SetAngles( ent:GetAngles() )
		prop_animatable:SetSequence( ent:GetSequence() )
		prop_animatable:SetCycle( ent:GetCycle() )
		--prop_animatable:SetPlaybackRate( ent:GetPlaybackRate() )

		if ( IsValid( ply ) ) then
			ply:AddCount( "prop_animatable", prop_animatable )
			ply:AddCleanup( "prop_animatable", prop_animatable )
			prop_animatable:SetPlayer( ply )
		end

		prop_animatable:SetSkin( ent:GetSkin() or 0 )
		prop_animatable:SetFlexScale( ent:GetFlexScale() )
		for i = 0, ent:GetFlexNum() - 1 do prop_animatable:SetFlexWeight( i, ent:GetFlexWeight( i ) ) end
		for i = 0, ( ent:GetNumBodyGroups() or 0 ) - 1 do prop_animatable:SetBodygroup( i, ent:GetBodygroup( i ) ) end
		for i = 0, ent:GetNumPoseParameters() - 1 do prop_animatable:SetPoseParameter( ent:GetPoseParameterName( i ) , ent:GetPoseParameter( i ) ) end
		for i = 0, ent:GetBoneCount() do
			prop_animatable:ManipulateBoneScale( i, ent:GetManipulateBoneScale( i ) )
			prop_animatable:ManipulateBoneAngles( i, ent:GetManipulateBoneAngles( i ) )
			prop_animatable:ManipulateBonePosition( i, ent:GetManipulateBonePosition( i ) )
			prop_animatable:ManipulateBoneJiggle( i, ent:GetManipulateBoneJiggle( i ) )
		end
		-- prop_animatable:InvalidateBoneCache()

		prop_animatable:Spawn()
		prop_animatable:Activate()

		prop_animatable.EntityMods = ent.EntityMods
		prop_animatable.BoneMods = ent.BoneMods
		duplicator.ApplyEntityModifiers( ply, prop_animatable )
		duplicator.ApplyBoneModifiers( ply, prop_animatable )

		-- We use string find because there are might be subclasses, like prop_ragdoll_multiplayer or something
		if ( string.find( entActual:GetClass(), "prop_ragdoll" ) or entActual:IsNPC() ) then
			prop_animatable:FixRagdoll() -- This WILL have false-positives, but it will have to do for now
		end

		undo.ReplaceEntity( entActual, prop_animatable )
		cleanup.ReplaceEntity( entActual, prop_animatable )

		constraint.RemoveAll( entActual ) -- Remove all constraints ( this stops ropes from hanging around )
		entActual:Remove()
	end
} )

properties.Add( "rb655_make_ragdoll", {
	MenuLabel = "#tool.rb655_easy_animation.property_ragdoll",
	Order = 653,
	MenuIcon = "icon16/tick.png",
	Filter = function( self, ent, ply )
		if ( !IsValid( ent ) or !gamemode.Call( "CanProperty", ply, "rb655_make_ragdoll", ent ) ) then return false end
		if ( ent:GetClass() != "prop_animatable" ) then return false end
		if ( !ent.GetIsRagdoll or !ent:GetIsRagdoll() ) then return false end
		return true
	end,
	Action = function( self, ent )
		self:MsgStart()
		net.WriteEntity( ent )
		self:MsgEnd()
	end,
	Receive = function( self, len, ply )
		local ent = net.ReadEntity()

		if ( !IsValid( ply ) or !IsValid( ent ) or !self:Filter( ent, ply ) ) then return false end

		ent:BecomeRagdollLua()
	end
} )

local function MakeDTVarToggleProperty( class, tab )

	local origTab = {
		Type = "toggle",

		Filter = function( self, ent, ply )

			if ( !IsValid( ent ) ) then return false end
			if ( !gamemode.Call( "CanProperty", ply, class, ent ) ) then return false end

			if ( self.ClassRestrict and ent:GetClass() != self.ClassRestrict ) then return false end

			return true

		end,

		Checked = function( self, ent, ply )

			-- This should never happen
			if ( !isfunction( ent[ "Get" .. self.DTVariable ] ) ) then return false end

			return ent[ "Get" .. self.DTVariable ]( ent )

		end,

		Action = function( self, ent )

			self:MsgStart()
				net.WriteEntity( ent )
			self:MsgEnd()

		end,

		Receive = function( self, length, ply )

			local ent = net.ReadEntity()
			if ( !properties.CanBeTargeted( ent, ply ) ) then return end
			if ( !self:Filter( ent, ply ) ) then return end

			if ( !isfunction( ent[ "Get" .. self.DTVariable ] ) ) then return end
			if ( !isfunction( ent[ "Set" .. self.DTVariable ] ) ) then return end

			ent[ "Set" .. self.DTVariable ]( ent, !ent[ "Get" .. self.DTVariable ]( ent ) )

		end

	}

	properties.Add( class, table.Merge( origTab, tab ) )

end

MakeDTVarToggleProperty( "rb655_animatable_body_xy", {
	MenuLabel = "#tool.rb655_easy_animation.property_bodyxy",
	Order = 600,

	ClassRestrict = "prop_animatable",
	DTVariable = "AnimateBodyXY"
} )

MakeDTVarToggleProperty( "rb655_animatable_ragdoll_on_dmg", {
	MenuLabel = "#tool.rb655_easy_animation.property_damageragdoll",
	Order = 601,

	ClassRestrict = "prop_animatable",
	DTVariable = "BecomeRagdoll"
} )
