208 lines
5.4 KiB
Lua
208 lines
5.4 KiB
Lua
AddCSLuaFile()
|
|
DEFINE_BASECLASS( "base_wire_entity" )
|
|
ENT.PrintName = "Wire Constraint Latch"
|
|
ENT.Purpose = "Controllable weld and nocollide between two selected entities"
|
|
ENT.WireDebugName = "Latch"
|
|
|
|
if CLIENT then return end -- No more client
|
|
|
|
function ENT:Initialize()
|
|
self:PhysicsInit( SOLID_VPHYSICS )
|
|
self:SetMoveType( MOVETYPE_VPHYSICS )
|
|
self:SetSolid( SOLID_VPHYSICS )
|
|
|
|
self.Inputs = Wire_CreateInputs( self, { "Activate", "NoCollide", "Strength" } )
|
|
self.Outputs = Wire_CreateOutputs( self, { "Welded" } )
|
|
|
|
-- masks containing all current states
|
|
self.nocollide_masks = {
|
|
-- Ent1, Ent2 , nocollide between the two
|
|
{ false, false, true }, -- 1 nocollide between the two
|
|
{ true , false, false }, -- 2 nocollide Ent1 with all
|
|
{ false, true , false }, -- 3 nocollide Ent2 with all
|
|
{ true , true , false } -- 4 nocollide both with all
|
|
-- all other values: { false, false, false }
|
|
}
|
|
|
|
self.nocollide_description = {
|
|
"NoCollided",
|
|
"Ent1 has collisions disabled",
|
|
"Ent2 has collisions disabled",
|
|
"All collisions disabled"
|
|
}
|
|
|
|
self.Nocollide = nil
|
|
self:TriggerInput("NoCollide", 0)
|
|
end
|
|
|
|
-- Run if weld is removed (will run *after* Create_Weld)
|
|
local function Weld_Removed( weld, ent )
|
|
if IsValid(ent) then
|
|
if !ent.Constraint or ent.Constraint == weld then
|
|
ent.Constraint = nil
|
|
Wire_TriggerOutput( ent, "Welded", 0 )
|
|
ent:UpdateOverlay()
|
|
end
|
|
end
|
|
end
|
|
|
|
function ENT:Remove_Weld()
|
|
if self.Constraint then
|
|
if self.Constraint:IsValid() then
|
|
self.Constraint:Remove()
|
|
end
|
|
self.Constraint = nil
|
|
end
|
|
end
|
|
|
|
function ENT:Create_Weld()
|
|
self:Remove_Weld()
|
|
self.Constraint = MakeWireLatch( self.Ent1, self.Ent2, self.Bone1, self.Bone2, self.weld_strength or 0 )
|
|
|
|
if self.Constraint then
|
|
self.Constraint:CallOnRemove( "Weld Latch Removed", Weld_Removed, self )
|
|
end
|
|
end
|
|
|
|
-- This function is called by the STOOL
|
|
function ENT:SendVars( Ent1, Ent2, Bone1, Bone2, const )
|
|
self.Ent1 = Ent1
|
|
self.Ent2 = Ent2
|
|
self.Bone1 = Bone1
|
|
self.Bone2 = Bone2
|
|
self.Constraint = const
|
|
end
|
|
|
|
function ENT:TriggerInput( iname, value )
|
|
if iname == "Activate" then
|
|
if value == 0 and self.Constraint then
|
|
self:Remove_Weld()
|
|
|
|
elseif value ~= 0 and not self.Constraint then
|
|
self:Create_Weld()
|
|
Wire_TriggerOutput( self, "Welded", 1 )
|
|
end
|
|
|
|
elseif iname == "NoCollide" then
|
|
self.nocollide_status = value
|
|
local mask = self.nocollide_masks[value] or {false, false, false}
|
|
|
|
if IsValid( self.Ent1 ) then
|
|
local phys = self.Ent1:GetPhysicsObject()
|
|
if phys:IsValid() then phys:EnableCollisions(not mask[1]) end
|
|
end
|
|
|
|
if IsValid( self.Ent2 ) then
|
|
local phys = self.Ent2:GetPhysicsObject()
|
|
if phys:IsValid() then phys:EnableCollisions(not mask[2]) end
|
|
end
|
|
|
|
if mask[3] then
|
|
if not self.Nocollide then
|
|
if self.Ent1 and self.Ent2 then
|
|
-- enable NoCollide between the two entities
|
|
self.Nocollide = constraint.NoCollide( self.Ent1, self.Ent2, self.Bone1, self.Bone2 )
|
|
end
|
|
end
|
|
else
|
|
if self.Nocollide then
|
|
if self.Nocollide:IsValid() then
|
|
-- disable NoCollide between the two entities
|
|
self.Nocollide:Input("EnableCollisions", nil, nil, nil)
|
|
self.Nocollide:Remove()
|
|
end
|
|
self.Nocollide = nil
|
|
end
|
|
end
|
|
|
|
elseif iname == "Strength" then
|
|
local newvalue = math.max( value, 0 )
|
|
if newvalue ~= self.weld_strength then
|
|
self.weld_strength = newvalue
|
|
|
|
if self.Constraint then
|
|
self:Create_Weld()
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
self:UpdateOverlay()
|
|
end
|
|
|
|
function ENT:OnRemove()
|
|
self:TriggerInput("Activate", 0)
|
|
self:TriggerInput("NoCollide", 0)
|
|
end
|
|
|
|
function ENT:UpdateOverlay()
|
|
local desc = self.nocollide_description[self.nocollide_status]
|
|
if not desc then
|
|
if IsValid( self.Constraint ) then
|
|
self:SetOverlayText( "Welded" )
|
|
else
|
|
self:SetOverlayText( "Deactivated" )
|
|
end
|
|
return
|
|
end
|
|
local text = self.Constraint and "Welded and " or "Not welded but "
|
|
text = text .. desc
|
|
self:SetOverlayText( text )
|
|
end
|
|
|
|
-- duplicator support
|
|
function ENT:BuildDupeInfo()
|
|
local info = BaseClass.BuildDupeInfo(self) or {}
|
|
if IsValid( self.Ent1 ) then
|
|
info.Ent1 = self.Ent1:EntIndex()
|
|
info.Bone1 = self.Bone1
|
|
end
|
|
if IsValid( self.Ent2 ) then
|
|
info.Ent2 = self.Ent2:EntIndex()
|
|
info.Bone2 = self.Bone2
|
|
end
|
|
|
|
info.Activate = self.Constraint and 1 or 0
|
|
info.NoCollide = self.nocollide_status
|
|
info.weld_strength = self.weld_strength
|
|
|
|
return info
|
|
end
|
|
|
|
function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID)
|
|
BaseClass.ApplyDupeInfo(self, ply, ent, info, GetEntByID)
|
|
|
|
self.Ent1 = GetEntByID(info.Ent1, game.GetWorld())
|
|
if IsValid(self.Ent1) then
|
|
self.Bone1 = info.Bone1
|
|
end
|
|
|
|
self.Ent2 = GetEntByID(info.Ent2, game.GetWorld())
|
|
if IsValid(self.Ent2) then
|
|
self.Bone2 = info.Bone2
|
|
end
|
|
|
|
self:TriggerInput("Strength", info.weld_strength or 0)
|
|
self:TriggerInput("Activate", info.Activate)
|
|
self:TriggerInput("NoCollide", info.NoCollide)
|
|
end
|
|
|
|
duplicator.RegisterEntityClass("gmod_wire_latch", WireLib.MakeWireEnt, "Data")
|
|
|
|
function MakeWireLatch( Ent1, Ent2, Bone1, Bone2, forcelimit )
|
|
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 )
|
|
|
|
if ( Phys1 == Phys2 ) then return false end
|
|
|
|
local const = constraint.Weld( Ent1, Ent2, Bone1, Bone2, forcelimit or 0 )
|
|
|
|
if !IsValid(const) then return nil end
|
|
|
|
const.Type = "" -- prevents the duplicator from copying this weld
|
|
|
|
return const
|
|
end
|