codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
--[[ Filename: "smartwelder.lua". Author(s): "Duncan Stead, TheBlackShadowOfGod (GMod 13)". --]] TOOL.Category = "Constraints" TOOL.Name = "#Weld - Smart" TOOL.Command = nil TOOL.ConfigName = "" TOOL.busy =false --the default smartweld settings TOOL.ClientConVar["radius"]=128 TOOL.ClientConVar["nocollideradius"]=128 TOOL.ClientConVar["maxweldspp"]=3 TOOL.ClientConVar["randomwelds"]=1 TOOL.ClientConVar["nocollide"]=1 TOOL.ClientConVar["unfreeze"]=1 TOOL.ClientConVar["autofreeze"]=0 TOOL.ClientConVar["refreshwelds"]=1 TOOL.ClientConVar["weldstrength"]=0 -- edit these variables to customise your install --when welding over time, weldtime is the gap between successive welds/nocollides WELDTIME=0.01 --notifygap is the multiple of which the player will be informed of the smartweld progress (ie. weld 50, 100, 150 placed) NOTIFYGAP=50 --slowmode is welding over time. Turning this off will make smart welder perform the weld in one go, making it more likely to crash with big contraptions SLOWMODE=true --if you have this on, the script will attempt to follow Conna's prop protection scheme USEPROPPROTECTION=false if CLIENT then language.Add( "Tool.smartwelder.name", "Smart Welder" ) language.Add( "Tool.smartwelder.desc", "Automatically welds selected props" ) language.Add( "Tool.smartwelder.0", "Select props with left click (hold use key to auto-select). Smart-weld with right click (hold use to weld to one prop). Reload clears selection." ) language.Add( "Undone_smartweld", "Undone Smart Weld" ) end function TOOL:LeftClick( trace ) if !self.busy then if self.props==nil then self.props={} end for a,v in ipairs(self.props) do if !v.ent:IsValid() then table.remove(self.props,a) end end if !trace.HitPos then return false end if trace.Entity:IsPlayer() then return false end if SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) then return false end if CLIENT then return true end // Get client's CVars local ply = self:GetOwner() local radius=self:GetClientNumber("radius") local nocollideradius=self:GetClientNumber("nocollideradius") local randomwelds = self:GetClientNumber("randomwelds") local smartnocollide = self:GetClientNumber("nocollide") == 1 local weldsperprop = self:GetClientNumber("maxweldspp") if trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() then if ply:KeyDown(IN_USE)||ply:KeyDown(IN_SPEED) then local selectedcount=self:Autoselect(trace.Entity,radius) if selectedcount>1 then self:GetOwner():PrintMessage(HUD_PRINTCENTER,selectedcount.." props auto-selected") end else self:ChooseEnt(trace.Entity) end end return true else return false end end function TOOL:Autoselect(ent,radius) local counted=0 if ent:IsValid() && ent:GetPhysicsObject():IsValid() && !ent:IsPlayer() then if !self:IsSelected(ent) then if self:IsPropOwner(self:GetOwner(),ent) then --add to list, try adding everything near it to list self:SelectEnt(ent,false) counted=1 local close_ents = ents.FindInSphere( ent:GetPos(), radius ) for i,v in ipairs(close_ents) do if v!=ent then counted=counted+self:Autoselect(v,radius) end end end end end return counted end function TOOL:IsSelected(ent) local selected=-1 for i,v in ipairs(self.props) do if v.ent==ent then selected=i break end end if selected==-1 then return false else return true end end --Based on a function by Conna function TOOL:IsPropOwner(ply, ent) if USEPROPPROTECTION then for k, v in pairs(g_SBoxObjects) do for b, j in pairs(v) do for _, e in pairs(j) do if e == ent then if k == ply:UniqueID() then return true end end end end end for k, v in pairs(GAMEMODE.CameraList) do for b, j in pairs(v) do if j == ent then if k == ply:UniqueID() then return true end end end end return false else return true end end function TOOL:ChooseEnt(ent) if self:IsPropOwner(self:GetOwner(),ent) then local selected=-1 for i,v in ipairs(self.props) do if v.ent==ent then selected=i break end end if selected==-1 then local r,g,b,a = ent:GetColor(); table.insert(self.props,{ent=ent,r=r,g=g,b=b,a=a}) ent:SetColor(0,255,0,255) else ent:SetColor(self.props[selected].r,self.props[selected].g,self.props[selected].b,self.props[selected].a) table.remove(self.props,selected) end end end function TOOL:DeselectEnt(ent) if self:IsPropOwner(self:GetOwner(),ent) then local selected=-1 for i,v in ipairs(self.props) do if v.ent==ent then selected=i break end end if selected==-1 then else ent:SetColor(self.props[selected].r,self.props[selected].g,self.props[selected].b,self.props[selected].a) table.remove(self.props,selected) end end end function TOOL:SelectEnt(ent) if self:IsPropOwner(self:GetOwner(),ent) then local r,g,b,a = ent:GetColor(); table.insert(self.props,{ent=ent,r=r,g=g,b=b,a=a}) ent:SetColor(0,255,0,255) end end function TOOL:WeldingFinished(unfreeze, weldcount, holdinguse, proptable,ply) undo.SetPlayer( ply ) undo.Finish() --if set to auto unfreeze if unfreeze then for a,v in ipairs(proptable) do if v.ent:IsValid() then local entphys=v.ent:GetPhysicsObject() if entphys:IsValid() then entphys:EnableMotion(true) entphys:Wake() end end end end if holdinguse then if weldcount!=1 then self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Weld to prop complete! "..weldcount.." welds placed") else self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Weld to prop complete! "..weldcount.." weld placed") end else if weldcount!=1 then self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Smart-weld complete! "..weldcount.." welds placed") else self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Smart-weld complete! "..weldcount.." weld placed") end end --deselect self.busy=false self:ResetSelection() end function TOOL:WeldEnts(ent1, ent2, bone1, bone2, weldstrength, smartnocollide, weldcount) if ent1:IsValid() and ent2:IsValid() then local const = constraint.Weld( ent1, ent2, bone1, bone2, weldstrength, smartnocollide ) undo.AddEntity( const ) if (weldcount+1)%NOTIFYGAP==0 then self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Weld "..(weldcount+1).." placed") end end end function TOOL:NoCollideEnts(ent1, ent2,bone1,bone2,nocollidecount) if ent1:IsValid() and ent2:IsValid() then local nocoll=constraint.NoCollide(ent1,ent2,bone1,bone2) --setup their undo undo.AddEntity(nocoll) if (nocollidecount+1)%NOTIFYGAP==0 then self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Nocollide "..(nocollidecount+1).." placed") end end end function TOOL:RightClick( trace ) if self.busy then else local ply = self:GetOwner() local randomwelds = self:GetClientNumber("randomwelds") local smartnocollide = self:GetClientNumber("nocollide") == 1 local autofreeze = self:GetClientNumber("autofreeze") == 1 local unfreeze = self:GetClientNumber("unfreeze") == 1 local refreshwelds = self:GetClientNumber("refreshwelds") == 1 local weldsperprop = self:GetClientNumber("maxweldspp") local nocollideradius=self:GetClientNumber("nocollideradius") local weldstrength=self:GetClientNumber("weldstrength") if self.props!=nil then for a,v in ipairs(self.props) do if !v.ent:IsValid() then table.remove(self.props,a) end end if #self.props>1 then self.busy=true --prefreeze if autofreeze then for a,v in ipairs(self.props) do local entphys=v.ent:GetPhysicsObject() if entphys:IsValid() then entphys:EnableMotion(false) entphys:Sleep() end end end if refreshwelds then --get rid of old contraints for a,v in ipairs(self.props) do local constrs = constraint.FindConstraints( v.ent, "Weld" ) --for every weld, see if it is welded to a selected prop, in which case remove it for b,w in ipairs(constrs) do for c,p in ipairs(self.props) do if w.Entity[2].Entity==p.ent then if p.ent==v.ent then else --remove the weld w.Constraint:Remove() end end end end end end undo.Create("smartweld") local welds={} for a,v in ipairs(self.props) do welds[a]={} end local weldcount=0 local holdinguse=false if ply:KeyDown(IN_USE)||ply:KeyDown(IN_SPEED) then if !trace.HitPos then return false end if trace.Entity:IsPlayer() then return false end if SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) then return false end if CLIENT then return true end if trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() then local weldtarget=trace.Entity holdinguse=true self:DeselectEnt(trace.Entity) for a,v in ipairs(self.props) do if v.ent==weldtarget then else local const = constraint.Weld( v.ent, weldtarget, 0, 0, weldstrength, smartnocollide ) undo.AddEntity( const ) weldcount=weldcount+1 end end end else for a,v in ipairs(self.props) do for x=1,weldsperprop do local closestdistance=99999999 local closestprop=-1 for b,w in ipairs(self.props) do if a!=b then local linked=false for i,val in ipairs(welds[a]) do if val==b then linked=true break end end if !linked then local distance=(v.ent:GetPos()-w.ent:GetPos()):Length() if distance<closestdistance then closestdistance=distance closestprop=b end end end end if closestprop!=-1 then --weld to this prop and add to weld list if SLOWMODE then timer.Simple(WELDTIME*weldcount, function() self.WeldEnts ( self, v.ent, self.props[closestprop].ent, 0, 0, weldstrength, smartnocollide, weldcount) end ) else self:WeldEnts(v.ent,self.props[closestprop].ent,0, 0, weldstrength, smartnocollide, weldcount) end weldcount=weldcount+1 table.insert(welds[a],closestprop) table.insert(welds[closestprop],a) else break end end end for a,v in ipairs(self.props) do for x=1,randomwelds do --randomly pick a prop if #self.props>1 then local b=math.random(#self.props) if b!=a then --test if it has been welded to already local linked=false for i,val in ipairs(welds[a]) do if val==b then linked=true break end end --if not, weld to it if !linked then if SLOWMODE then timer.Simple(WELDTIME*weldcount, function() self.WeldEnts (self, v.ent,self.props[b].ent,0, 0, weldstrength, smartnocollide,weldcount) end ) else self:WeldEnts(v.ent,self.props[closestprop].ent,0, 0, weldstrength, smartnocollide,weldcount) end weldcount=weldcount+1 table.insert(welds[a],b) table.insert(welds[b],a) end end end end end end local nocollidecount=0 for a,v in ipairs(self.props) do for b,w in ipairs(self.props) do if a!=b then local linked=false for i,val in ipairs(welds[a]) do if val==b then linked=true break end end if !linked || !smartnocollide then local distance=(v.ent:GetPos()-w.ent:GetPos()):Length() if distance<nocollideradius then --nocollide the ents together if SLOWMODE then timer.Simple(WELDTIME*(nocollidecount+weldcount), function() self.NoCollideEnts ( self, v.ent,w.ent,0, 0,nocollidecount ) end ) else self:NoCollideEnts(v.ent,w.ent,0, 0,nocollidecount) end nocollidecount=nocollidecount+1 end end end end end if refreshwelds then self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Refreshed Smart-weld running...") else self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Smart-weld running...") end if SLOWMODE then timer.Simple(WELDTIME*(weldcount+nocollidecount), function() self.WeldingFinished ( self,unfreeze,weldcount, holdinguse, self.props,ply ) end ) else self:WeldingFinished(unfreeze,weldcount,holdinguse, self.props,ply) end end end end end function TOOL:ResetSelection() local ply=self:GetOwner() local propscleared=false --clear the selection if self.props==nil then self.props={} end for a,v in ipairs(self.props) do if !v.ent:IsValid() then table.remove(self.props,a) end end if #self.props>0 then for a,v in ipairs(self.props) do if v.ent:IsValid() then v.ent:SetColor(v.r,v.g,v.b,v.a) end end propscleared=true end self.props={} return propscleared end function TOOL:Reload( trace ) if !self.busy then local cleared=self:ResetSelection() if cleared then self:GetOwner():PrintMessage(HUD_PRINTCENTER,"Selection cleared!") end end end function TOOL.BuildCPanel(cp) cp:AddControl( "Header", { Text = "#Tool.smartwelder.name", Description = "#Tool.smartwelder.desc" } ) cp:AddControl( "Slider", { Label = "Auto-select Radius:", Description = "The autoselecting radius (hold use and left click to autoselect)",Type = "float", Min = "0", Max = "1000", Command = "smartwelder_radius" } ) cp:AddControl( "Slider", { Label = "Auto-Nocollide Radius:", Description = "Each prop will nocollide with any props within its radius (set to 0 to disable auto-nocolliding)",Type = "float", Min = "0", Max = "1000", Command = "smartwelder_nocollideradius" } ) cp:AddControl( "Slider", { Label = "Max welds per prop:", Description = "How many welds each prop will make to its nearest neighbours",Type = "integer", Min = "0", Max = "10", Command = "smartwelder_maxweldspp" } ) cp:AddControl( "Slider", { Label = "Stability welds per prop:", Description = "How many welds each prop will make to random neighbours to increase stability",Type = "integer", Min = "0", Max = "10", Command = "smartwelder_randomwelds" } ) cp:AddControl( "Slider", { Label = "Weld forcelimit:", Description = "The strength of the welds created. Use 0 for unbreakable welds.",Type = "float", Min = "0", Max = "10000", Command = "smartwelder_weldstrength" } ) cp:AddControl( "Checkbox", { Label = "No collide:", Description = "Whether pairs of props should be nocollided when welded", Command = "smartwelder_nocollide" } ) cp:AddControl( "Checkbox", { Label = "Auto freeze:", Description = "Whether all selected props should be frozen before the weld (Warning! Very slow!)", Command = "smartwelder_autofreeze" } ) cp:AddControl( "Checkbox", { Label = "Auto unfreeze:", Description = "Whether all selected props should be unfrozen after the weld", Command = "smartwelder_unfreeze" } ) cp:AddControl( "Checkbox", { Label = "Refresh welds:", Description = "Removes old welds inside the selection before smart welding", Command = "smartwelder_refreshwelds" } ) end
Private
[
?
]
Run code
Submit