
if ( SERVER ) then

	// If you're a server admin and you want your physics to spazz out less you can
	// use the convar. The higher you set it the more accurate physics will be.
	// This is set to 2 by default, since we are a physics mod.

	CreateConVar( "gmod_physiterations", "2", { FCVAR_REPLICATED, FCVAR_ARCHIVE } )
	
end


module( "constraint", package.seeall )

// Clients don't need this module.
if ( CLIENT ) then return end


// ! NOTE !
// The constraint systems don't get deleted yet. Don't do anything about it yet.
// ! NOTE !

// I think 128 constraints is around the max that causes the crash
// So at this number we'll refuse to add more to the system
local MAX_CONSTRAINTS_PER_SYSTEM 	= 100 

local function CreateConstraintSystem()

		local iterations = GetConVarNumber( "gmod_physiterations" )
		
		local System = ents.Create("phys_constraintsystem")
			System:SetKeyValue( "additionaliterations", iterations )
		System:Spawn()
		System:Activate()
		
		return System
		
end

/*----------------------------------------------------------------------
	FindOrCreateConstraintSystem
	
	Takes 2 entities. If the entities don't have a constraint system
	associated with them it creates one and associates it with them.
	
	It then returns the constraint system
----------------------------------------------------------------------*/
local function FindOrCreateConstraintSystem( Ent1, Ent2 )

	local System = nil
	
	Ent2 = Ent2 or Ent1

	// Does Ent1 have a constraint system?
	if ( !Ent1:IsWorld() && Ent1:GetTable().ConstraintSystem && Ent1:GetTable().ConstraintSystem:IsValid() ) then 
		System = Ent1:GetTable().ConstraintSystem
	end
	
	// Don't add to this system - we have too many constraints on it already.
	if ( System && System:IsValid() && System:GetVar( "constraints", 0 ) > MAX_CONSTRAINTS_PER_SYSTEM ) then System = nil end
	
	// Does Ent2 have a constraint system?
	if ( !System && !Ent2:IsWorld() && Ent2:GetTable().ConstraintSystem && Ent2:GetTable().ConstraintSystem:IsValid() ) then 
		System = Ent2:GetTable().ConstraintSystem
	end
	
	// Don't add to this system - we have too many constraints on it already.
	if ( System && System:IsValid() && System:GetVar( "constraints", 0 ) > MAX_CONSTRAINTS_PER_SYSTEM ) then System = nil end
	
	// No constraint system yet (Or they're both full) - make a new one
	if ( !System || !System:IsValid() ) then
	
		//Msg("New Constrant System\n")
		System = CreateConstraintSystem()
		
	end
	
	Ent1:GetTable().ConstraintSystem = System
	Ent2:GetTable().ConstraintSystem = System
	
	local ConstraintNum = System:GetVar( "constraints", 0 )
	System:SetVar( "constraints", ConstraintNum + 1 )
	
	//Msg("System has "..tostring( System:GetVar( "constraints", 0 ) ).." constraints\n")
	
	return System

end


/*----------------------------------------------------------------------
	onStartConstraint( Ent1, Ent2 )
	Should be called before creating a constraint
----------------------------------------------------------------------*/
local function onStartConstraint( Ent1, Ent2 )

	// Get constraint system
	local system = FindOrCreateConstraintSystem( Ent1, Ent2 )
	
	// Any constraints called after this call will use this system
	SetPhysConstraintSystem( system )

end

/*----------------------------------------------------------------------
	onFinishConstraint( Ent1, Ent2 )
	Should be called before creating a constraint
----------------------------------------------------------------------*/
local function onFinishConstraint( Ent1, Ent2 )

	// Turn off constraint system override
	SetPhysConstraintSystem( NULL )

end

local function SetPhysicsCollisions( Ent, b )

	if (!Ent || !Ent:IsValid() || !Ent:GetPhysicsObject()) then return end
	
	Ent:GetPhysicsObject():EnableCollisions( b )

end

/*----------------------------------------------------------------------
	RemoveConstraints( Ent, Type )
	Removes all constraints of type from entity
----------------------------------------------------------------------*/
function RemoveConstraints( Ent, Type )

	if ( !Ent:GetTable().Constraints ) then return end
	
	local c = Ent:GetTable().Constraints
	i = 0

	for k, v in pairs( c ) do
	
		if ( !v:IsValid() ) then
		
			c[ k ] = nil
	
		elseif (  v:GetTable().Type == Type ) then
		
			// Make sure physics collisions are on!
			// If we don't the unconstrained objects will fall through the world forever.
			SetPhysicsCollisions( v:GetTable().Ent1, true )
			SetPhysicsCollisions( v:GetTable().Ent2, true )
		
			c[ k ] = nil
			v:Remove()			
			
			i = i + 1
		end
		
	end

	if (table.Count(c) == 0) then
		// Update the network var and clear the constraints table.
		Ent:IsConstrained()
	end

	local  bool = i != 0
	return bool, i

end


/*----------------------------------------------------------------------
	RemoveConstraints( Ent )
	Removes all constraints from entity
----------------------------------------------------------------------*/
function RemoveAll( Ent )

	if ( !Ent:GetTable().Constraints ) then return end
	
	local c = Ent:GetTable().Constraints
	local i = 0
	for k, v in pairs( c ) do
	
		if ( v:IsValid() ) then
		
			// Make sure physics collisions are on!
			// If we don't the unconstrained objects will fall through the world forever.
			SetPhysicsCollisions( v:GetTable().Ent1, true )
			SetPhysicsCollisions( v:GetTable().Ent2, true )
		
			v:Remove()
			i = i + 1
		end
	end

	// Update the network var and clear the constraints table.
	Ent:IsConstrained()

	local  bool = i != 0
	return bool, i

end

/*----------------------------------------------------------------------
	Find( Ent1, Ent2, Type, Bone1, Bone2 )
	Removes all constraints from entity
----------------------------------------------------------------------*/
function Find( Ent1, Ent2, Type, Bone1, Bone2  )

	if ( !Ent1:GetTable().Constraints ) then return end
	
	local c = Ent1:GetTable().Constraints

	for k, v in pairs( Ent1:GetTable().Constraints ) do
	
		if ( v:IsValid() ) then
	
			local CTab = v:GetTable()
			
			if ( CTab.Type == Type && CTab.Ent1 == Ent1 && CTab.Ent2 == Ent2 && CTab.Bone1 == Bone1 && CTab.Bone2 == Bone2 ) then
				return v
			end
			
			if ( CTab.Type == Type && CTab.Ent2 == Ent1 && CTab.Ent1 == Ent2 && CTab.Bone2 == Bone1 && CTab.Bone1 == Bone2 ) then
				return v
			end

		end
		
	end

	return nil

end

/*----------------------------------------------------------------------
	CanConstrain( Ent, Bone )
	Returns false if we shouldn't be constraining this entity
----------------------------------------------------------------------*/
function CanConstrain( Ent, Bone )

	if ( !Ent )	then return false end
	if ( !Ent:IsWorld() && !Ent:IsValid() )	then return false end
	if ( !Ent:GetPhysicsObjectNum( Bone ):IsValid() )	then return false end
	
	return true

end

/*----------------------------------------------------------------------
	CalcElasticConsts( ... )
	This attempts to scale the elastic constraints such as the winch
	to keep a stable but responsive constraint..
----------------------------------------------------------------------*/
local function CalcElasticConsts( Phys1, Phys2, Ent1, Ent2, iFixed )
	
	local minMass = 0;
	
	if ( Ent1:IsWorld() ) then minMass = Phys2:GetMass()
	elseif ( Ent2:IsWorld() ) then minMass = Phys1:GetMass()
	else 
		minMass = math.min( Phys1:GetMass(), Phys2:GetMass() )
	end
		
	// const, damp
	local const = minMass * 100
	local damp = const * 0.2
	
	if ( iFixed == 0 ) then
	
		const = minMass * 50
		damp = const * 0.1
	
	end
	
	return const, damp
	
end


/*----------------------------------------------------------------------
	CreateKeyframeRope( ... )
	Creates a rope without any constraint
----------------------------------------------------------------------*/
function CreateKeyframeRope( Pos, width, material, Constraint, Ent1, LPos1, Bone1, Ent2, LPos2, Bone2, kv )

	// No rope if 0 or minus
	if ( width < 1 ) then return nil end
	
	// Clamp the rope to a sensible width
	width = math.Clamp( width, 1, 100 )

	local rope = ents.Create( "keyframe_rope" )
		
		rope:SetPos( Pos )
		rope:SetKeyValue( "Width", 			width )
		if (material) then rope:SetKeyValue( "RopeMaterial", material ) end
		
		// Attachment point 1
		rope:SetEntity( "StartEntity", 		Ent1 )
		rope:SetKeyValue( "StartOffset", 	tostring(LPos1) )
		rope:SetKeyValue( "StartBone", 		Bone1 )
		
		// Attachment point 2
		rope:SetEntity( "EndEntity", 		Ent2 )
		rope:SetKeyValue( "EndOffset", 		tostring(LPos2) )
		rope:SetKeyValue( "EndBone", 		Bone2 )
			
		if (kv ) then
			for k, v in pairs( kv ) do
			
				rope:SetKeyValue( k, tostring(v) )
		
			end
		end
			
		rope:Spawn()
		rope:Activate()
		
	// Delete the rope if the attachments get killed
	Ent1:DeleteOnRemove( rope )
	Ent2:DeleteOnRemove( rope )
	if ( Constraint && Constraint:IsValid() ) then Constraint:DeleteOnRemove( rope ) end
		
	return rope

end

/*----------------------------------------------------------------------
	AddConstraintTable( Ent, Constraint )
	Stores info about the constraints on the entity's table
----------------------------------------------------------------------*/
function AddConstraintTable(  Ent, Constraint, Ent2, Ent3, Ent4 )

	if ( !constraint || !Constraint:IsValid() ) then return end

	if ( Ent:IsValid() ) then

		Ent:GetTable().Constraints = Ent:GetTable().Constraints or {}
		table.insert( Ent:GetTable().Constraints, Constraint )
		Ent:DeleteOnRemove( Constraint )
	
	end
	
	if (Ent2 && Ent2!=Ent) then
		AddConstraintTable( Ent2, Constraint, Ent3, Ent4 )
	end

end

	
/*----------------------------------------------------------------------
	Weld( ... )
	Creates a solid weld constraint
----------------------------------------------------------------------*/
function Weld( Ent1, Ent2, Bone1, Bone2, forcelimit, nocollide, deleteonbreak )
	
	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	if ( Find( Ent1, Ent2, "Weld", Bone1, Bone2 ) ) then 
	
		// A weld already exists between these two physics objects.
		// There's totally no point in re-creating it. It doesn't make 
		// the weld any stronger - that's just an urban ledgend.
		return false
	
	end
	
	local Phys1		= Ent1:GetPhysicsObjectNum( Bone1 ) 
	local Phys2		= Ent2:GetPhysicsObjectNum( Bone2 )

	if (Ent1 == Ent2 && Bone1 == Bone2) then return false end
	
	onStartConstraint( Ent1, Ent2 )

		// Create the constraint 
		local Constraint = ents.Create("phys_constraint")
			if ( forcelimit)	then Constraint:SetKeyValue( "forcelimit", forcelimit )	end
			if ( nocollide )	then Constraint:SetKeyValue( "spawnflags", 1 )		end
			Constraint:SetPhysConstraintObjects( Phys2, Phys1 )
		Constraint:Spawn()
		Constraint:Activate()

	onFinishConstraint( Ent1, Ent2 )
	AddConstraintTable( Ent1, Constraint, Ent2 )
	
	// Optionally delete Ent1 when the weld is broken
	// This is to fix bug #310
	if ( deleteonbreak ) then
		Ent2:DeleteOnRemove( Ent1 )
	end

	// Make a constraints table
	local ctable  = 
		{
			Type  = "Weld",
			Ent1  = Ent1, 	Ent2  = Ent2,
			Bone1 = Bone1,	Bone2 = Bone2,
			forcelimit	= forcelimit,
			nocollide	= nocollide,
			deleteonbreak = deleteonbreak
		}

	Constraint:SetTable( ctable )
	
	
	Phys1:Wake()
	Phys2:Wake()


	return Constraint
	
end

duplicator.RegisterConstraint( "Weld", Weld, "Ent1", "Ent2", "Bone1", "Bone2", "forcelimit", "nocollide", "deleteonbreak" )


/*----------------------------------------------------------------------
	Rope( ... )
	Creates a rope constraint - with rope!
----------------------------------------------------------------------*/
function Rope( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, length, addlength, forcelimit, width, material, rigid )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end

	local Phys1 		= Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 		= Ent2:GetPhysicsObjectNum( Bone2 )
	local WPos1 		= Phys1:LocalToWorld( LPos1 )
	local WPos2 		= Phys2:LocalToWorld( LPos2 )
	local addlength		= addlength or 0
	local Constraint	= nil

	length = length + addlength - (WPos1-WPos2):Length()
	
	// Make Constraint
	if ( Phys1 != Phys2 ) then
			
		onStartConstraint( Ent1, Ent2 )

			// Create the constraint
			Constraint = ents.Create("phys_lengthconstraint")
				Constraint:SetPos( WPos1 )		
				Constraint:SetKeyValue( "attachpoint", tostring(WPos2) )
				Constraint:SetKeyValue( "minlength", "0.0" )
				if (length)	 		then Constraint:SetKeyValue( "addlength", length ) end
				if (forcelimit)	 	then Constraint:SetKeyValue( "forcelimit", forcelimit )	  end
				if (rigid) 			then Constraint:SetKeyValue( "spawnflags", 2 ) end
				Constraint:SetPhysConstraintObjects( Phys1, Phys2 )
			Constraint:Spawn()
			Constraint:Activate()

		onFinishConstraint( Ent1, Ent2 )

	end

	// Make Rope
	local kv = 
	{ 
		Slack 		= length, 
		Collide 	= 1
	}
	if ( rigid ) then kv.Type = 2 end
	
	local rope = CreateKeyframeRope( WPos1, width, material, Constraint, Ent1, LPos1, Bone1, Ent2, LPos2, Bone2, kv )

	// What the fuck
	if (!Constraint) then Constraint, rope = rope, nil end

	local ctable = 
		{
			Type 		= "Rope",
			Ent1 		= Ent1,		Ent2 		= Ent2,
			Bone1 		= Bone1,	Bone2 		= Bone2,
			LPos1 		= LPos1,	LPos2 		= LPos2,
			length 		= (WPos1 - WPos2):Length(),
			addlength 	= addlength,
			forcelimit 	= forcelimit,
			width 		= width,
			material 	= material,
			rigid		= rigid
		}
		
	Constraint:SetTable( ctable )

	AddConstraintTable( Ent1, Constraint, Ent2 )

	return Constraint, rope
	
end

duplicator.RegisterConstraint( "Rope", Rope, "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "length", "addlength", "forcelimit", "width", "material", "rigid" )

/*----------------------------------------------------------------------
	Elastic( ... )
	Creates an elastic constraint
----------------------------------------------------------------------*/
function Elastic( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, constant, damping, rdamping, material, width, stretchonly )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end

	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2)
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )

	local Constraint 	= nil

	// Make Constraint
	if ( Phys1 != Phys2 ) then
	
		onStartConstraint( Ent1, Ent2 )
		
			Constraint = ents.Create("phys_spring")
			
				Constraint:SetPos( WPos1 )		
				Constraint:SetKeyValue( "springaxis", tostring(WPos2) )
				Constraint:SetKeyValue( "constant", constant )
				Constraint:SetKeyValue( "damping", damping )
				Constraint:SetKeyValue( "relativedamping", rdamping )
				Constraint:SetPhysConstraintObjects( Phys1, Phys2 )
				if (stretchonly == 1 || stretchonly == true) then
					Constraint:SetKeyValue( "spawnflags", 1 )					
				end
	
			Constraint:Spawn()
			Constraint:Activate()
		
		onFinishConstraint( Ent1, Ent2 )
		AddConstraintTable( Ent1, Constraint, Ent2 )
		
		local ctable = 
		{
			Type = "Elastic",

			Ent1	= Ent1,
			Ent2	= Ent2,
			Bone1	= Bone1,
			Bone2	= Bone2,
			LPos1	= LPos1,
			LPos2	= LPos2,

			constant	= constant,
			damping		= damping,
			rdamping	= rdamping,
			material	= material,
			width		= width,
			length  	= (WPos1-WPos2):Length(),
			stretchonly = stretchonly,
		}

		Constraint:SetTable( ctable )
	
	end

	// Make Rope
	local kv = 
	{ 
		Collide 	= 1,
		Type 		= 0
	}
	
	local rope = CreateKeyframeRope( WPos1, width, material, Constraint, Ent1, LPos1, Bone1, Ent2, LPos2, Bone2, kv )
	

	return Constraint, rope
end

duplicator.RegisterConstraint("Elastic", Elastic, "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "constant", "damping", "rdamping", "material", "width", "stretchonly")


/*----------------------------------------------------------------------
	Keepupright( ... )
	Creates a KeepUpright constraint
----------------------------------------------------------------------*/
function Keepupright( Ent, Ang, Bone, angularlimit )

	if ( !CanConstrain( Ent, Bone ) ) then return false end
	if ( Ent:GetClass() != "prop_physics" && Ent:GetClass() != "prop_ragdoll" ) then return false end
	if ( !angularlimit or angularlimit < 0 ) then return end
	
	local Phys = Ent:GetPhysicsObjectNum(Bone)

	// Remove any KU's already on entity
	RemoveConstraints( Ent, "Keepupright" )
	
	onStartConstraint( Ent )

		local Constraint = ents.Create( "phys_keepupright" )
			Constraint:SetAngles( Ang )
			Constraint:SetKeyValue( "angularlimit", angularlimit )
			Constraint:SetPhysConstraintObjects( Phys, Phys )
		Constraint:Spawn()
		Constraint:Activate()
	
	onFinishConstraint( Ent )
	AddConstraintTable( Ent, Constraint )
	
	local ctable = 
	{
		Type 			= "Keepupright",
		Ent 			= Ent,
		Ang 			= Ang,
		Bone 			= Bone,
		angularlimit 	= angularlimit
	}
	Constraint:SetTable( ctable )
	
	return Constraint
	
end

duplicator.RegisterConstraint( "Keepupright", Keepupright, "Ent", "Ang", "Bone", "angularlimit" )


function CreateStaticAnchorPoint( Pos )

	// Creates an invisible frozen, not interactive prop.
	Anchor = ents.Create( "gmod_anchor" )
		Anchor:SetPos( Pos )
	Anchor:Spawn()
	Anchor:Activate()
	
	return Anchor, Anchor:GetPhysicsObject(), 0, Vector(0,0,0)

end


/*----------------------------------------------------------------------
	Slider( ... )
	Creates a slider constraint
----------------------------------------------------------------------*/
function Slider( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, width )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2)
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )
	local StaticAnchor = nil

	// Make Constraint
	if ( Phys1 == Phys2 ) then return end
	
	// Make Rope
	local kv = 
	{ 
		Collide 	= 0,
		Type 		= 2,
		Subdiv		= 1,
	}
	
	// Start World Hack.
	// Attaching a slider to the world makes it really sucks so we make
	// a prop and attach to that.
	
	if ( Ent1:IsWorld() ) then
		
		Ent1, Phys1, Bone1, LPos1 = CreateStaticAnchorPoint( WPos1 );
		StaticAnchor = Ent1
	
	end
	
	if ( Ent2:IsWorld() ) then
		
		Ent2, Phys2, Bone2, LPos2 = CreateStaticAnchorPoint( WPos2 );
		StaticAnchor = Ent2
	
	end
	
	// End World Hack.
	
	onStartConstraint( Ent1, Ent2 )

		local Constraint = ents.Create("phys_slideconstraint")
			Constraint:SetPos( WPos1 )
			Constraint:SetKeyValue( "slideaxis", tostring(WPos2) ) 
			Constraint:SetPhysConstraintObjects( Phys1, Phys2 )
		Constraint:Spawn()
		Constraint:Activate()
		
	onFinishConstraint( Ent1, Ent2 )
	AddConstraintTable( Ent1, Constraint, Ent2 )
	
	
	local rope = CreateKeyframeRope( WPos1, width, material, Constraint, Ent1, LPos1, Bone1, Ent2, LPos2, Bone2, kv )
	
	// If we have a static anchor - delete it when we die.
	if ( StaticAnchor ) then
	
		Constraint:DeleteOnRemove( StaticAnchor )
	
	end
	
	local ctable = 
	{
		Type 	= "Slider",
		Ent1  	= Ent1,
		Ent2  	= Ent2,
		Bone1 	= Bone1,
		Bone2 	= Bone2,
		LPos1 	= LPos1,
		LPos2 	= LPos2,
		width 	= width
	}

	Constraint:SetTable( ctable )	
	
	return Constraint, rope
	
end
duplicator.RegisterConstraint( "Slider", Slider, "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "width" )

/*----------------------------------------------------------------------
	Axis( ... )
	Creates an axis constraint
----------------------------------------------------------------------*/
function Axis( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, forcelimit, torquelimit, friction, nocollide )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2)
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )

	if ( Phys1 == Phys2 ) then return false end

	onStartConstraint( Ent1, Ent2 )
	
		local Constraint = ents.Create("phys_hinge")
			Constraint:SetPos( WPos1 )
			Constraint:SetKeyValue( "hingeaxis", tostring( WPos2 ) ) 
			if (forcelimit && forcelimit > 0)	then Constraint:SetKeyValue( "forcelimit", forcelimit )		 end
			if (torquelimit && torquelimit > 0)	then Constraint:SetKeyValue( "torquelimit", torquelimit )	 end
			if (friction && friction > 0)		then Constraint:SetKeyValue( "hingefriction", friction )	 end
			if (nocollide && nocollide > 0)		then Constraint:SetKeyValue( "spawnflags", 1 )			 end
			Constraint:SetPhysConstraintObjects( Phys1, Phys2 )
		Constraint:Spawn()
		Constraint:Activate()
	
	onFinishConstraint( Ent1, Ent2 )
	AddConstraintTable( Ent1, Constraint, Ent2 )
	
	local ctable = {
		Type 			= "Axis",
		Ent1  			= Ent1,
		Ent2  			= Ent2,
		Bone1 			= Bone1,
		Bone2 			= Bone2,
		LPos1 			= LPos1,
		LPos2 			= LPos2,
		forcelimit  	= forcelimit, 
		torquelimit 	= torquelimit,
		friction    	= friction,
		nocollide   	= nocollide
	}

	Constraint:SetTable( ctable )

	return Constraint
	
end

duplicator.RegisterConstraint( "Axis", Axis, "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "forcelimit", "torquelimit", "friction", "nocollide" )


/*----------------------------------------------------------------------
	AdvBallsocket( ... )
	Creates an advanced ballsocket (ragdoll) constraint
----------------------------------------------------------------------*/
function AdvBallsocket(Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, forcelimit, torquelimit, xmin, ymin, zmin, xmax, ymax, zmax, xfric, yfric, zfric, onlyrotation, nocollide)

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2 )
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )

	if ( Phys1 == Phys2 ) then return false end
	
	// Make Constraint
	onStartConstraint( Ent1, Ent2 )
	
		local flags = 0
		if (onlyrotation && onlyrotation > 0) 	then flags = flags + 2 end
		if (nocollide && nocollide > 0) 		then flags = flags + 1 end
	
		local Constraint = ents.Create("phys_ragdollconstraint")
			Constraint:SetPos( WPos1 )
			Constraint:SetKeyValue( "xmin", xmin )
			Constraint:SetKeyValue( "xmax", xmax )
			Constraint:SetKeyValue( "ymin", ymin )
			Constraint:SetKeyValue( "ymax", ymax )
			Constraint:SetKeyValue( "zmin", zmin )
			Constraint:SetKeyValue( "zmax", zmax )
			if (xfric && xfric > 0) then Constraint:SetKeyValue( "xfriction", xfric ) end
			if (yfric && yfric > 0) then Constraint:SetKeyValue( "yfriction", yfric ) end
			if (zfric && zfric > 0) then Constraint:SetKeyValue( "zfriction", zfric ) end
			if (forcelimit && forcelimit > 0) then Constraint:SetKeyValue( "forcelimit", forcelimit ) end
			if (torquelimit && torquelimit > 0) then Constraint:SetKeyValue( "torquelimit", torquelimit ) end
			Constraint:SetKeyValue("spawnflags", flags)
			Constraint:SetPhysConstraintObjects( Phys1, Phys2 )
		Constraint:Spawn()
		Constraint:Activate()
	
	onFinishConstraint( Ent1, Ent2 )
	AddConstraintTable( Ent1, Constraint, Ent2 )
	
	local ctable = 
	{
		Type 			= "AdvBallsocket",
		Ent1  			= Ent1,
		Ent2 			= Ent2,
		Bone1 			= Bone1,
		Bone2 			= Bone2,
		LPos1 			= LPos1,
		LPos2 			= LPos2,
		forcelimit  	= forcelimit, 
		torquelimit 	= torquelimit,
		xmin 			= xmin,
		ymin 			= ymin,
		zmin 			= zmin,
		xmax 			= xmax,
		ymax 			= ymax,
		zmax 			= zmax,
		xfric 			= xfric,
		yfric 			= yfric,
		zfric 			= zfric,
		onlyrotation 	= onlyrotation,
		nocollide   	= nocollide
	}

	Constraint:SetTable( ctable )

	return Constraint
	
end

duplicator.RegisterConstraint( "AdvBallsocket", AdvBallsocket, "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "forcelimit", "torquelimit", "xmin", "ymin", "zmin", "xmax", "ymax", "zmax", "xfric", "yfric", "zfric", "onlyrotation", "nocollide")


/*----------------------------------------------------------------------
	NoCollide( ... )
	Creates an nocollide `constraint'
----------------------------------------------------------------------*/
function NoCollide( Ent1, Ent2, Bone1, Bone2 )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2 )

	if ( Phys1 == Phys2 ) then return false end

	if ( Find( Ent1, Ent2, "NoCollide", Bone1, Bone2 ) ) then 

		return false
	
	end

	// Make Constraint
	onStartConstraint( Ent1, Ent2 )
	
		local Constraint = ents.Create("logic_collision_pair")
			Constraint:SetKeyValue( "startdisabled", 1 )
			Constraint:SetPhysConstraintObjects( Phys1, Phys2 )
		Constraint:Spawn()
		Constraint:Activate()
		Constraint:Input( "DisableCollisions", nil, nil, nil )
	
	onFinishConstraint( Ent1, Ent2 )
	AddConstraintTable( Ent1, Constraint, Ent2 )
	
	local ctable  = 
	{
		Type  = "NoCollide",
		Ent1  = Ent1,
		Ent2  = Ent2,
		Bone1 = Bone1,
		Bone2 = Bone2,
	}

	Constraint:SetTable( ctable )

	return Constraint

end
duplicator.RegisterConstraint( "NoCollide", NoCollide, "Ent1", "Ent2", "Bone1", "Bone2" )


/*----------------------------------------------------------------------
	MotorControl( pl, motor, onoff, dir )
	Numpad controls for the motor constraints
----------------------------------------------------------------------*/
local function MotorControl( pl, motor, onoff, dir )

	if (!motor:IsValid()) then return false end

	local activate = false
	
	if (motor:GetTable().toggle == 1) then
		
		// Toggle mode, only do something when the key is pressed
		// if the motor is off, turn it on, and vice-versa.
		// This only happens if the same key as the current
		// direction is pressed, otherwise the direction is changed
		// with the motor being left on.
		
		if (onoff) then
		
			if (motor:GetTable().direction == dir or !motor:GetTable().is_on) then
			
				// Direction is the same, Activate if the motor is off
				// Deactivate if the motor is on.

				motor:GetTable().is_on = !motor:GetTable().is_on

				activate = motor:GetTable().is_on

			else
			
				// Change of direction, make sure it's activated
			
				activate = true
				
			end
			
		else
		
			return
			
		end
		
	else
	
		// normal mode: activate is based on the key status
		// (down = on, up = off)
		
		activate = onoff
		
	end
	
	if (activate) then
	
		motor:Fire( "Activate", "", 0 )		// Turn on the motor
		motor:Fire( "Scale", dir, 0)		// This makes the direction change
		
	else
		motor:Fire( "Deactivate", "", 0 )	// Turn off the motor
	end
	
	motor:GetTable().direction = dir
	
	return true
	
end

numpad.Register( "MotorControl", MotorControl )

/*----------------------------------------------------------------------
	Motor( ... )
	Creates a motor constraint
----------------------------------------------------------------------*/
function Motor( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, friction, torque, forcetime, nocollide, toggle, pl, forcelimit, numpadkey_fwd, numpadkey_bwd, direction )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	// Get information we're about to use
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2)
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )
	
	if ( Phys1 == Phys2 ) then return false end

	local axis = Axis( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, 0, 0, friction, nocollide )

	// Why do we do this? - Garry 15:59 27/07/2006
	//AddConstraintTable( Ent1, axis, Ent2 )

	// Create the constraint 
	onStartConstraint( Ent1, Ent2 )
	
		local Constraint = ents.Create("phys_torque")
			Constraint:SetPos( WPos1 )
			Constraint:SetKeyValue( "axis", tostring( WPos2 ) ) 
			Constraint:SetKeyValue( "force", torque )
			Constraint:SetKeyValue( "forcetime", forcetime )
			Constraint:SetKeyValue( "spawnflags", 4 )
			Constraint:SetPhysConstraintObjects( Phys1, Phys1 )
		Constraint:Spawn()
		Constraint:Activate()

	onFinishConstraint( Ent1, Ent2 )
	
	// Note - Ent2 is removed here so the wheel will still have torque applied even when the axis
	// constraint is broken. This constraint is only applied to this entity anyway so there's really
	// no need for Ent2 to know anything about it.
	AddConstraintTable( Ent1, Constraint/*, Ent2*/ )
	
	direction = direction or 1
	
	local ctable = 
	{
		Type 		= "Motor",
		Ent1  		= Ent1,
		Ent2  		= Ent2,
		Bone1 		= Bone1,
		Bone2 		= Bone2,
		LPos1 		= LPos1,
		LPos2 		= LPos2,
		friction 	= friction,
		torque 		= torque,
		forcetime 	= forcetime,
		nocollide 	= nocollide,
		toggle 		= toggle,
		pl 		= pl,
		forcelimit 	= forcelimit,
		forcescale 	= 0,
		direction 	= direction,
		is_on		= false,
		numpadkey_fwd 	= numpadkey_fwd,
		numpadkey_bwd 	= numpadkey_bwd
	}

	Constraint:SetTable( ctable )

	if (numpadkey_fwd) then
	
		numpad.OnDown( 	 pl, 	numpadkey_fwd, 	"MotorControl", 	Constraint,		true,	1 )
		numpad.OnUp( 	 pl, 	numpadkey_fwd, 	"MotorControl", 	Constraint,		false,	1 )
	end
		
	if (numpadkey_bwd) then

		numpad.OnDown( 	 pl, 	numpadkey_bwd, 	"MotorControl", 	Constraint,		true,	-1 )
		numpad.OnUp( 	 pl, 	numpadkey_bwd, 	"MotorControl", 	Constraint,		false,	-1 )

	end
	
	return Constraint, axis
	
end
duplicator.RegisterConstraint( "Motor", Motor, "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "friction", "torque", "forcetime", "nocollide", "toggle", "pl", "forcelimit", "numpadkey_fwd", "numpadkey_bwd", "direction" )


/*----------------------------------------------------------------------
	Pulley( ... )
	Creates a pulley constraint
----------------------------------------------------------------------*/
function Pulley( Ent1, Ent4, Bone1, Bone4, LPos1, LPos4, WPos2, WPos3, forcelimit, rigid, width, material )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent4, Bone4 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys4 = Ent4:GetPhysicsObjectNum( Bone4 )
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos4 = Phys4:LocalToWorld( LPos4 )
	
	if ( Phys1 == Phys2 ) then return false end

	// Make Constraint
	onStartConstraint( Ent1, Ent4 )

		local Constraint = ents.Create( "phys_pulleyconstraint" )
			Constraint:SetPos( WPos2 )
			Constraint:SetKeyValue( "position2", tostring( WPos3 ) )
			Constraint:SetKeyValue( "ObjOffset1", tostring( LPos1 ) )
			Constraint:SetKeyValue( "ObjOffset2", tostring( LPos4 ) )
			Constraint:SetKeyValue( "forcelimit", forcelimit )
			Constraint:SetKeyValue( "addlength", (WPos3-WPos4):Length() )
			if ( rigid ) then Constraint:SetKeyValue( "spawnflags", 2 ) end
			Constraint:SetPhysConstraintObjects( Phys1, Phys4 )
		Constraint:Spawn()
		Constraint:Activate()
		
	onFinishConstraint( Ent1, Ent4 )
	AddConstraintTable( Ent1, Constraint, Ent4 )

	local ctable = 
	{
		Type 		= "Pulley",
		Ent1  		= Ent1,
		Ent4  		= Ent4,
		Bone1 		= Bone1,
		Bone4 		= Bone4,
		LPos1 		= LPos1,
		LPos4 		= LPos4,
		WPos2 		= WPos2,
		WPos3 		= WPos3,
		forcelimit 	= forcelimit,
		rigid 		= rigid,
		width 		= width,
		material 	= material
	}
	Constraint:SetTable( ctable )
	
	// make Rope
	local World = GetWorldEntity()
	
	local kv = 
	{ 
		Collide 	= 1,
		Type 		= 2,
		Subdiv		= 1,
	}
	
	CreateKeyframeRope( WPos1, width, material, Constraint, 	Ent1, LPos1, Bone1, 	World, WPos2, 0, 		kv )
	CreateKeyframeRope( WPos1, width, material, Constraint, 	World, WPos3, 0, 		World, WPos2, 0, 		kv )
	CreateKeyframeRope( WPos1, width, material, Constraint, 	World, WPos3, 0, 		Ent4, LPos4, Bone4, 	kv )

	return Constraint
	
end

duplicator.RegisterConstraint( "Pulley", Pulley, "Ent1", "Ent4", "Bone1", "Bone4", "LPos1", "LPos4", "WPos2", "WPos3", "forcelimit", "rigid", "width", "material" )


/*----------------------------------------------------------------------
	Ballsocket( ... )
	Creates a Ballsocket constraint
----------------------------------------------------------------------*/
function Ballsocket( Ent1, Ent2, Bone1, Bone2, LPos, forcelimit, torquelimit, nocollide )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	// Get information we're about to use
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2 )
	local WPos = Phys2:LocalToWorld( LPos )
	
	if ( Phys1 == Phys2 ) then return false end

	onStartConstraint( Ent1, Ent2 )
	
		local Constraint = ents.Create("phys_ballsocket")
			Constraint:SetPos( WPos )
			if (forcelimit && forcelimit > 0)	then Constraint:SetKeyValue( "forcelimit", forcelimit )				end
			if (torquelimit && torquelimit > 0)	then Constraint:SetKeyValue( "torquelimit", torquelimit )			end
			if (nocollide && nocollide > 0)		then Constraint:SetKeyValue( "spawnflags", 1 )						end
			Constraint:SetPhysConstraintObjects( Phys1, Phys2 )
		Constraint:Spawn()
		Constraint:Activate()
	
	onFinishConstraint( Ent1, Ent2 )
	AddConstraintTable( Ent1, Constraint, Ent2 )
	
	local ctable = 
	{
		Type = "Ballsocket",
		Ent1  = Ent1,
		Ent2  = Ent2,
		Bone1 = Bone1,
		Bone2 = Bone2,
		LPos = LPos,
		forcelimit  = forcelimit, 
		torquelimit = torquelimit,
		nocollide   = nocollide
	}

	Constraint:SetTable( ctable )

	return Constraint
	
end

duplicator.RegisterConstraint( "Ballsocket", Ballsocket, "Ent1", "Ent2", "Bone1", "Bone2", "LPos", "forcelimit", "torquelimit", "nocollide" )


/*----------------------------------------------------------------------
	Winch( ... )
	Creates a Winch constraint
----------------------------------------------------------------------*/
function Winch( pl, Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, width, fwd_bind, bwd_bind, fwd_speed, bwd_speed, material, toggle )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2)
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )
	
	if ( Phys1 == Phys2 ) then return false end
				
	local const, dampen = CalcElasticConsts( Phys1, Phys2, Ent1, Ent2, false )

	local Constraint, rope = Elastic( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, const, dampen, 0, material, width, true )
	
	if ( !Constraint ) then return nil, rope end
	
	local ctable = 
	{
			Type 		= "Winch",
			pl			= pl,
			Ent1		= Ent1,
			Ent2		= Ent2,
			Bone1		= Bone1,
			Bone2		= Bone2,
			LPos1		= LPos1,
			LPos2		= LPos2,
			width		= width,
			fwd_bind	= fwd_bind,
			bwd_bind	= bwd_bind,
			fwd_speed	= fwd_speed,
			bwd_speed	= bwd_speed,
			material	= material,
			toggle 		= toggle,
	}
	Constraint:SetTable( ctable )
	

	// Attach our Controller to the Elastic constraint
	local controller = ents.Create("gmod_winch_controller")
		controller:GetTable():SetConstraint( Constraint )
		controller:GetTable():SetRope( rope )
	controller:Spawn()
	
	Constraint:DeleteOnRemove( controller )
	Ent1:DeleteOnRemove( controller )
	Ent2:DeleteOnRemove( controller )

	if (toggle) then
	
		numpad.OnDown( 	 pl, 	fwd_bind, 	"WinchToggle", 	controller, 1 )
		numpad.OnDown( 	 pl, 	bwd_bind, 	"WinchToggle", 	controller, -1 )
		
	else
	
		numpad.OnDown( 	 pl, 	fwd_bind, 	"WinchOn", 		controller, 1 )
		numpad.OnUp( 	 pl, 	fwd_bind, 	"WinchOff", 	controller )
		numpad.OnDown( 	 pl, 	bwd_bind, 	"WinchOn", 		controller, -1 )
		numpad.OnUp( 	 pl, 	bwd_bind, 	"WinchOff", 	controller )
		
	end
				
	return Constraint, rope, controller

end

duplicator.RegisterConstraint( "Winch", Winch, "pl", "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "width", "fwd_bind", "bwd_bind", "fwd_speed", "bwd_speed", "material", "toggle" )


/*----------------------------------------------------------------------
	Hydraulic( ... )
	Creates a Hydraulic constraint
----------------------------------------------------------------------*/
function Hydraulic( pl, Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, Length1, Length2, width, key, fixed, speed )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2 )
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )
	
	if ( Phys1 == Phys2 ) then return false end
	
	local const, dampn = CalcElasticConsts( Phys1, Phys2, Ent1, Ent2, fixed )

	local Constraint,rope = Elastic( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, const, dampn, 0, material, width, false )
	local ctable = {
			Type = "Hydraulic",
			pl	= pl,
			Ent1	= Ent1,
			Ent2	= Ent2,
			Bone1	= Bone1,
			Bone2	= Bone2,
			LPos1	= LPos1,
			LPos2	= LPos2,
			Length1	= Length1,
			Length2	= Length2,
			width	= width,
			key		= key,
			fixed	= fixed,
			fwd_speed	= speed,
			bwd_speed	= speed,
			toggle = true,
	}
	Constraint:SetTable( ctable )
	
	if (constraint && constraint != rope) then
	
		if fixed == 1 then 
			local slider = Slider( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, 0 )
			slider:SetTable( {} )
			Constraint:DeleteOnRemove( slider )
		end
		
		local controller = ents.Create("gmod_winch_controller")
		if (Length2 > Length1) then
			controller:SetKeyValue("minlength", Length1)
			controller:SetKeyValue("maxlength", Length2)
		else
			controller:SetKeyValue("minlength", Length2)
			controller:SetKeyValue("maxlength", Length1)
		end
		controller:GetTable():SetConstraint( Constraint )
		controller:Spawn()
			
		Ent1:DeleteOnRemove( controller )
		Ent2:DeleteOnRemove( controller )
		
		Constraint:DeleteOnRemove( controller )

		numpad.OnDown( 	 pl, 	key, 	"HydraulicToggle", 	controller )

		return Constraint,rope,controller,slider
	else
		return Constraint,rope
	end

end

duplicator.RegisterConstraint( "Hydraulic", Hydraulic, "pl", "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "Length1", "Length2", "width", "key", "fixed", "fwd_speed" )


/*----------------------------------------------------------------------
	Hydraulic( ... )
	Creates a Hydraulic constraint
----------------------------------------------------------------------*/
function Muscle( pl, Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, Length1, Length2, width, key, fixed, period, amplitude )

	if ( !CanConstrain( Ent1, Bone1 ) ) then return false end
	if ( !CanConstrain( Ent2, Bone2 ) ) then return false end
	
	local Phys1 = Ent1:GetPhysicsObjectNum( Bone1 )
	local Phys2 = Ent2:GetPhysicsObjectNum( Bone2 )
	local WPos1 = Phys1:LocalToWorld( LPos1 )
	local WPos2 = Phys2:LocalToWorld( LPos2 )
	
	if ( Phys1 == Phys2 ) then return false end

	local const, dampn = CalcElasticConsts( Phys1, Phys2, Ent1, Ent2, fixed )

	local Constraint, rope = Elastic( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, const, dampn, 0, material, width, false )
	if (!constraint) then return false end
	
	local ctable = 
	{
			Type 		= "Muscle",
			pl		= pl,
			Ent1		= Ent1,
			Ent2		= Ent2,
			Bone1		= Bone1,
			Bone2		= Bone2,
			LPos1		= LPos1,
			LPos2		= LPos2,
			Length1		= Length1,
			Length2		= Length2,
			width		= width,
			key			= key,
			fixed		= fixed,
			period		= period,
			amplitude	= amplitude,
			toggle 		= true,
	}
	Constraint:SetTable( ctable )
	
	if fixed == 1 then  
		slider = Slider( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, 0 )
		slider:SetTable( {} ) // ??
		Constraint:DeleteOnRemove( slider )
	end
	
	local controller = ents.Create("gmod_winch_controller")
	if (Length2 > Length1) then
		controller:SetKeyValue("minlength", Length1)
		controller:SetKeyValue("maxlength", Length2)
	else
		controller:SetKeyValue("minlength", Length2)
		controller:SetKeyValue("maxlength", Length1)
	end
	controller:SetKeyValue("type", 1)
	controller:GetTable():SetConstraint( Constraint )
	controller:Spawn()
		
	Ent1:DeleteOnRemove( controller )
	Ent2:DeleteOnRemove( controller )
	
	Constraint:DeleteOnRemove( controller )

	numpad.OnDown( 	 pl, 	key, 	"MuscleToggle", 	controller )

	return Constraint,rope,controller,slider

end
duplicator.RegisterConstraint( "Muscle", Muscle, "pl", "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "Length1", "Length2", "width", "key", "fixed", "period", "amplitude" )


/*----------------------------------------------------------------------
	Returns true if this entity has valid constraints
----------------------------------------------------------------------*/
function HasConstraints( ent )

	if ( !ent ) then return false end
	if ( !ent.Constraints ) then return false end
		
	local count = 0
	for key, Constraint in pairs( ent.Constraints ) do
	
		if ( !constraint || !Constraint:IsValid() ) then
			
			ent.Constraints[ key ] = nil
			
		else
			
			count = count + 1
			
		end
	
	end

	return count != 0

end


/*----------------------------------------------------------------------
	Returns this entities constraints table
	This is for the future, because ideally the constraints table will eventually look like this - and we won't have to build it every time.
----------------------------------------------------------------------*/
function GetTable( ent )

	if ( !HasConstraints( ent ) ) then return {} end

	local RetTable = {}

	for key, ConstraintEntity in pairs( ent.Constraints ) do
	
		local con = {}
		
		table.Merge( con, ConstraintEntity:GetTable() )

		con.Constraint = ConstraintEntity
		con.Entity = {}
		
		for i=1, 6 do
		
			if ( con[ "Ent"..i ] && ( con[ "Ent"..i ]:IsWorld() || con[ "Ent"..i ]:IsValid() ) ) then
			
				con.Entity[ i ] = {}
				con.Entity[ i ].Index	 	= con[ "Ent"..i ]:EntIndex()
				con.Entity[ i ].Entity	 	= con[ "Ent"..i ]
				con.Entity[ i ].Bone 		= con[ "Bone"..i ]
				con.Entity[ i ].LPos 		= con[ "LPos"..i ]
				con.Entity[ i ].WPos 		= con[ "WPos"..i ]
				con.Entity[ i ].Length 		= con[ "Length"..i ]
				con.Entity[ i ].World		= con[ "Ent"..i ]:IsWorld()
				
			end
		
		end
					
		table.insert( RetTable, con )
	
	end
	
	return RetTable

end

/*----------------------------------------------------------------------
	Make this entity forget any constraints it knows about
----------------------------------------------------------------------*/
function ForgetConstraints( ent )

	ent.Constraints = {}

end


/*----------------------------------------------------------------------
	Returns a list of constraints, by name
----------------------------------------------------------------------*/
function FindConstraints( ent, name )

	local ConTable = GetTable( ent )
	
	local Found = {}
	
	for k, con in ipairs( ConTable ) do
	
		if ( con.Type == name ) then
			table.insert( Found, con )
		end
	
	end
	
	return Found

end

/*----------------------------------------------------------------------
	Returns the first constraint found by name
----------------------------------------------------------------------*/
function FindConstraint( ent, name )

	local ConTable = GetTable( ent )
	
	for k, con in ipairs( ConTable ) do
	
		if ( con.Type == name ) then
			return con
		end
	
	end
	
	return nil

end

/*----------------------------------------------------------------------
	Returns the first constraint found by name
----------------------------------------------------------------------*/
function FindConstraintEntity( ent, name )

	local ConTable = GetTable( ent )
	
	for k, con in ipairs( ConTable ) do
	
		if ( con.Type == name ) then
			return con.Constraint
		end
	
	end
	
	return NULL

end

/*----------------------------------------------------------------------
	Returns a table of all the entities constrained to ent
----------------------------------------------------------------------*/
function GetAllConstrainedEntities( ent, ResultTable )

	local ResultTable = ResultTable or {}
	
	if ( !ent ) then return end
	if ( !ent:IsValid() ) then return end
	if ( ResultTable[ ent ] ) then return end
	
	ResultTable[ ent ] = ent
	
	local ConTable = GetTable( ent )
	
	for k, con in ipairs( ConTable ) do
	
		for EntNum, Ent in pairs( con.Entity ) do
			GetAllConstrainedEntities( Ent.Entity, ResultTable )
		end
	
	end

	return ResultTable
	
end
