TOOL.Category = "Wire - Physics" TOOL.Name = "Motor" TOOL.Command = nil TOOL.ConfigName = "" TOOL.ClientConVar[ "torque" ] = "500" TOOL.ClientConVar[ "friction" ] = "1" TOOL.ClientConVar[ "nocollide" ] = "1" TOOL.ClientConVar[ "forcelimit" ] = "0" TOOL.ClientConVar[ "model" ] = "models/jaanus/wiretool/wiretool_siren.mdl" local controlmodels = { ["models/jaanus/wiretool/wiretool_siren.mdl"] = {}, ["models/jaanus/wiretool/wiretool_controlchip.mdl"] = {}}; if CLIENT then language.Add( "Tool_wire_motor_name", "Motor Tool (Wire)" ) language.Add( "Tool_wire_motor_desc", "Makes a controllable motor" ) language.Add( "Tool_wire_motor_0", "Primary: Place motor" ) language.Add( "Tool_wire_motor_1", "Left click on the second point" ) language.Add( "Tool_wire_motor_2", "Left click to place the controller" ) language.Add( "WireMotorTool_torque", "Torque:" ) language.Add( "WireMotorTool_friction", "Friction:" ) language.Add( "WireMotorTool_nocollide", "No Collide" ) language.Add( "WireMotorTool_forcelimit", "Force Limit:" ) language.Add( "WireMotorTool_model", "Choose a Model:" ) language.Add( "undone_wiremotor", "Undone Wire Motor" ) end function TOOL:LeftClick( trace ) if ( trace.Entity:IsValid() && trace.Entity:IsPlayer() ) then return end // If there's no physics object then we can't constraint it! if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end local iNum = self:NumObjects() local Phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone ) // Don't allow us to choose the world as the first object if (iNum == 0 && !trace.Entity:IsValid()) then return end // Don't allow us to choose the same object if (iNum == 1 && trace.Entity == self:GetEnt(1) ) then return end self:SetObject( iNum + 1, trace.Entity, trace.HitPos, Phys, trace.PhysicsBone, trace.HitNormal ) if ( iNum > 1 ) then if ( CLIENT ) then self:ClearObjects() return true end local ply = self:GetOwner() local Ent1, Ent2, Ent3 = self:GetEnt(1), self:GetEnt(2), trace.Entity local const, axis = self.constraint, self.axis if ( !const ) or ( !const:IsValid() ) then self:GetOwner():SendLua( "GAMEMODE:AddNotify('Wire Motor Invalid!', NOTIFY_GENERIC, 7);" ) self:ClearObjects() self:SetStage(0) return end local model = self:GetClientInfo( "model" ) // Attach our Controller to the Motor constraint local Ang = trace.HitNormal:Angle() Ang.pitch = Ang.pitch + 90 local controller = MakeWireMotorController(ply, trace.HitPos, Ang, nil, model, const, axis) local min = controller:OBBMins() controller:SetPos( trace.HitPos - trace.HitNormal * min.z ) local const2 = WireLib.Weld(controller, trace.Entity, trace.PhysicsBone, true) undo.Create("WireMotor") undo.AddEntity( controller ) undo.AddEntity( const ) undo.AddEntity( axis ) undo.AddEntity( const2 ) undo.SetPlayer( ply ) undo.Finish() ply:AddCleanup( "constraints", controller ) ply:AddCleanup( "constraints", const2 ) if const then controller:DeleteOnRemove( const ) end if axis then controller:DeleteOnRemove( axis ) end self:ClearObjects() self:SetStage(0) elseif ( iNum == 1 ) then if ( CLIENT ) then self:ClearObjects() self:ReleaseGhostEntity() return true end // Get client's CVars local torque = self:GetClientNumber( "torque" ) local friction = self:GetClientNumber( "friction" ) local nocollide = self:GetClientNumber( "nocollide" ) local forcelimit = self:GetClientNumber( "forcelimit" ) local Ent1, Ent2 = self:GetEnt(1), self:GetEnt(2) local Bone1, Bone2 = self:GetBone(1), self:GetBone(2) local WPos1, WPos2 = self:GetPos(1), self:GetPos(2) local LPos1, LPos2 = self:GetLocalPos(1),self:GetLocalPos(2) local Norm1, Norm2 = self:GetNormal(1), self:GetNormal(2) local Phys1, Phys2 = self:GetPhys(1), self:GetPhys(2) // Note: To keep stuff ragdoll friendly try to treat things as physics objects rather than entities local Ang1, Ang2 = Norm1:Angle(), (Norm2 * -1):Angle() local TargetAngle = Phys1:AlignAngles( Ang1, Ang2 ) Phys1:SetAngle( TargetAngle ) // Move the object so that the hitpos on our object is at the second hitpos local TargetPos = WPos2 + (Phys1:GetPos() - self:GetPos(1)) // Offset slightly so it can rotate TargetPos = TargetPos + (2*Norm2) // Set the position Phys1:SetPos( TargetPos ) // Wake up the physics object so that the entity updates Phys1:Wake() // Set the hinge Axis perpendicular to the trace hit surface LPos1 = Phys1:WorldToLocal( WPos2 + Norm2 * 64 ) --local constraint, axis = constraint.Motor( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, friction, torque, 0, nocollide, 0, self:GetOwner(), 0) local constraint, axis = MakeWireMotor( self:GetOwner(), Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, friction, torque, nocollide, forcelimit ) self.constraint, self.axis = constraint, axis undo.Create("WireMotor") if axis then undo.AddEntity( axis ) end if constraint then undo.AddEntity( constraint ) end undo.SetPlayer( self:GetOwner() ) undo.Finish() if axis then self:GetOwner():AddCleanup( "constraints", axis ) end if constraint then self:GetOwner():AddCleanup( "constraints", constraint ) end self:ReleaseGhostEntity() self:SetStage(2) else self:StartGhostEntity( trace.Entity ) self:SetStage( iNum+1 ) end return true end function TOOL:RightClick( trace ) return false end if SERVER then //need for the const to find the controller after being duplicator pasted WireMotorTracking = {} function MakeWireMotorController( pl, Pos, Ang, MyEntId, model, const, axis ) local controller = ents.Create("gmod_wire_motor") controller:SetPos( Pos ) controller:SetAngles( Ang ) controller:SetModel( model ) controller:SetPlayer(pl) if (!const) then WireMotorTracking[ MyEntId ] = controller else controller.MyId = controller:EntIndex() const.MyCrtl = controller:EntIndex() controller:SetConstraint( const ) controller:DeleteOnRemove( const ) end if (axis) then controller:SetAxis( axis ) controller:DeleteOnRemove( axis ) end controller:Spawn() return controller end duplicator.RegisterEntityClass("gmod_wire_motor", MakeWireMotorController, "Pos", "Ang", "MyId", "model") function MakeWireMotor( pl, Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, friction, torque, nocollide, forcelimit, MyCrtl ) if ( !constraint.CanConstrain( Ent1, Bone1 ) ) then return false end if ( !constraint.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, axis = constraint.Motor( Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, friction, torque, 0, nocollide, 0, pl, forcelimit) if ( !const ) then return nil, axis end local ctable = { Type = "WireMotor", pl = pl, Ent1 = Ent1, Ent2 = Ent2, Bone1 = Bone1, Bone2 = Bone2, LPos1 = LPos1, LPos2 = LPos2, friction = friction, torque = torque, nocollide = nocollide, forcelimit = forcelimit } const:SetTable( ctable ) if (MyCrtl) then Msg("finding crtl for this wired mot const\n") local controller = WireMotorTracking[ MyCrtl ] const.MyCrtl = controller:EntIndex() controller.MyId = controller:EntIndex() controller:SetConstraint( const ) controller:DeleteOnRemove( const ) if (axis) then controller:SetAxis( axis ) controller:DeleteOnRemove( axis ) end Ent1:DeleteOnRemove( controller ) Ent2:DeleteOnRemove( controller ) const:DeleteOnRemove( controller ) end return const, axis end duplicator.RegisterConstraint( "WireMotor", MakeWireMotor, "pl", "Ent1", "Ent2", "Bone1", "Bone2", "LPos1", "LPos2", "friction", "torque", "nocollide", "forcelimit", "MyCrtl" ) end function TOOL:Reload( trace ) if (!trace.Entity:IsValid() || trace.Entity:IsPlayer() ) then return false end if ( CLIENT ) then return true end local bool = constraint.RemoveConstraints( trace.Entity, "WireMotor" ) return bool end function TOOL:Think() if (self:NumObjects() != 1) then return end self:UpdateGhostEntity() end function TOOL.BuildCPanel(panel) panel:AddControl( "PropSelect", { Label = "#WireMotorTool_model", ConVar = "wire_motor_model", Category = "Wire Motor", Models = controlmodels } ) panel:AddControl("Slider", { Label = "#WireMotorTool_torque", Type = "Float", Min = "0", Max = "10000", Command = "wire_motor_torque" }) panel:AddControl("Slider", { Label = "#WireMotorTool_forcelimit", Type = "Float", Min = "0", Max = "50000", Command = "wire_motor_forcelimit" }) panel:AddControl("Slider", { Label = "#WireMotorTool_friction", Type = "Float", Min = "0", Max = "100", Command = "wire_motor_friction" }) panel:AddControl("CheckBox", { Label = "#WireMotorTool_nocollide", Command = "wire_motor_nocollide" }) end