Try this:
TOOL.Category = "Construction"
TOOL.Name = "#Stacker"
TOOL.Command = nil
TOOL.ConfigName = ""
TOOL.ClientConVar[ "freeze" ] = "0"
TOOL.ClientConVar[ "weld" ] = "0"
TOOL.ClientConVar[ "nocollide" ] = "0"
TOOL.ClientConVar[ "mode" ] = "1"
TOOL.ClientConVar[ "dir" ] = "1"
TOOL.ClientConVar[ "count" ] = "1"
TOOL.ClientConVar[ "model" ] = ""
TOOL.ClientConVar[ "offsetx" ] = "0"
TOOL.ClientConVar[ "offsety" ] = "0"
TOOL.ClientConVar[ "offsetz" ] = "0"
TOOL.ClientConVar[ "rotp" ] = "0"
TOOL.ClientConVar[ "roty" ] = "0"
TOOL.ClientConVar[ "rotr" ] = "0"
TOOL.ClientConVar[ "recalc" ] = "0"
function Echoer( ply, props, entity )
for k,v in pairs( player.GetAll() ) do
if v:IsAdmin() then
v:PrintMessage( HUD_PRINTCONSOLE, ply:Nick().."("..ply:SteamID()..") stacked "..tostring(props).." "..entity:GetModel() )
end
end
if ( SERVER ) then
filex.Append("ulx_logs/".. tostring(os.date("%m-%d-%y")) ..".txt", os.date("[%H:%M:%S]") .." ".. ply:Nick() .."<".. ply:SteamID() .."> has stacked ".. tostring(props) .." with the model ".. entity:GetModel() .."\n" )
end
end
// Add Default Language translation (saves adding it to the txt files)
if ( CLIENT ) then
language.Add( "Tool_ol_stacker_name", "Stacker" )
language.Add( "Tool_ol_stacker_desc", "Stacks Props Easily" )
language.Add( "Tool_ol_stacker_0", "Click To Stack The Prop You're Pointing At." )
language.Add( "Undone_ol_stacker", "Undone Stack" )
end
function TOOL:LeftClick( trace )
if !trace.Entity then return false end
if !trace.Entity:IsValid() then return false end
if trace.Entity:GetClass() != "prop_physics" then return false end
if CLIENT then return true end
local freeze = self:GetClientNumber( "freeze" ) == 1
local weld = self:GetClientNumber( "weld" ) == 1
local nocollide = self:GetClientNumber( "nocollide" ) == 1
local mode = self:GetClientNumber( "mode" )
local dir = self:GetClientNumber( "dir" )
local count = self:GetClientNumber( "count" )
local offsetx = self:GetClientNumber( "offsetx" )
local offsety = self:GetClientNumber( "offsety" )
local offsetz = self:GetClientNumber( "offsetz" )
local rotp = self:GetClientNumber( "rotp" )
local roty = self:GetClientNumber( "roty" )
local rotr = self:GetClientNumber( "rotr" )
local recalc = self:GetClientNumber( "recalc" ) == 1
local offset = Vector(offsetx, offsety, offsetz)
local rot = Angle(rotp, roty, rotr)
-- local model = self:GetClientInfo( "model" )
-- if !model || !util.IsValidModel(model) then return false end
local player = self:GetOwner()
if count>10 then
player:ChatPrint( "You are not allowed to stack more then 10 props!" )
return
end
local ent = trace.Entity
local newvec = ent:GetPos()
local newang = ent:GetAngles()
local lastent = ent
undo.Create("ol_stacker")
for i=1, count, 1 do
if ( !self:GetSWEP():CheckLimit( "props" ) ) then break end
// ********************
// POSITION CALCULATION
// ********************
if i == 1 || (mode == 2 && recalc == true) then
// We only calculate this stuff if it's the first item in the stack OR
// if recalc is turned on
stackdir, height, thisoffset = self:OLStackerCalcPos(lastent, mode, dir, offset)
end
newvec = newvec + stackdir * height + thisoffset
newang = newang + rot
// Test to make sure this is inside the level
if !util:IsInWorld(newvec) then
// This check is currently disabled because of a bug in gmod causing
// util:IsInWorld to always return false.
--break
end
// Find out if there is an entity on this spot
local entlist = ents.FindInSphere(newvec,1)
local bFound = false
for k, v in pairs(entlist) do
if v:IsValid() && v != lastent && v:GetClass() == "prop_physics" && v:GetPos() == newvec && v != self.GhostEntity then
bFound = true
end
end
if bFound then break end
newent = ents.Create("prop_physics")
newent:SetModel(ent:GetModel())
newent:SetColor(ent:GetColor())
newent:SetMaterial(ent:GetMaterial())
newent:SetPos(newvec)
newent:SetAngles(newang)
newent:Spawn()
if freeze then
newent:GetPhysicsObject():EnableMotion( false )
end
if weld then
local weldent = constraint.Weld( lastent, newent, 0, 0, 0 )
undo.AddEntity( weldent )
end
if nocollide then
local nocollideent = constraint.NoCollide(lastent, newent, 0, 0)
undo.AddEntity( nocollideent )
end
lastent = newent
undo.AddEntity( newent )
player:AddCount( "props", newent )
player:AddCleanup( "props", newent )
if PropDefender && PropDefender.Player && PropDefender.Player.Give then
PropDefender.Player.Give(player, newent, false)
end
end
Echoer(player,count,ent)
undo.SetPlayer( player )
undo.Finish()
return true
end
function TOOL:OLStackerCalcPos(lastent, mode, dir, offset)
local forward = Vector(1,0,0):Angle()
local pos = lastent:GetPos()
local ang = lastent:GetAngles()
local lower, upper = lastent:WorldSpaceAABB( )
local glower = lastent:OBBMins()
local gupper = lastent:OBBMaxs()
local stackdir = Vector(0,0,1)
local height = math.abs(upper.z - lower.z)
if mode == 1 then // Relative to world
if dir == 1 then
stackdir = forward:Up()
height = math.abs(upper.z - lower.z)
elseif dir == 2 then
stackdir = forward:Up() * -1
height = math.abs(upper.z - lower.z)
elseif dir == 3 then
stackdir = forward:Forward()
height = math.abs(upper.x - lower.x)
elseif dir == 4 then
stackdir = forward:Forward() * -1
height = math.abs(upper.x - lower.x)
elseif dir == 5 then
stackdir = forward:Right()
height = math.abs(upper.y - lower.y)
elseif dir == 6 then
stackdir = forward:Right() * -1
height = math.abs(upper.y - lower.y)
end
elseif mode == 2 then // Relative to prop
forward = ang
if dir == 1 then
stackdir = forward:Up()
offset = forward:Up() * offset.X + forward:Forward() * -1 * offset.Z + forward:Right() * offset.Y
height = math.abs(gupper.z - glower.z)
elseif dir == 2 then
stackdir = forward:Up() * -1
offset = forward:Up() * -1 * offset.X + forward:Forward() * offset.Z + forward:Right() * offset.Y
height = math.abs(gupper.z - glower.z)
elseif dir == 3 then
stackdir = forward:Forward()
offset = forward:Forward() * offset.X + forward:Up() * offset.Z + forward:Right() * offset.Y
height = math.abs(gupper.x - glower.x)
elseif dir == 4 then
stackdir = forward:Forward() * -1
offset = forward:Forward() * -1 * offset.X + forward:Up() * offset.Z + forward:Right() * -1 * offset.Y
height = math.abs(gupper.x - glower.x)
elseif dir == 5 then
stackdir = forward:Right()
offset = forward:Right() * offset.X + forward:Up() * offset.Z + forward:Forward() * -1 * offset.Y
height = math.abs(gupper.y - glower.y)
elseif dir == 6 then
stackdir = forward:Right() * -1
offset = forward:Right() * -1 * offset.X + forward:Up() * offset.Z + forward:Forward() * offset.Y
height = math.abs(gupper.y - glower.y)
end
-- offset = (stackdir:Angle():Up() * offset.Z) + (stackdir:Angle():Forward() * offset.X) + (stackdir:Angle():Right() * offset.Y)
end
return stackdir, height, offset
end
function TOOL:RightClick( trace )
return self:LeftClick( trace )
// Maybe I'll add this later...
/*
if !trace.Entity then return false end
local ent = trace.Entity
local ply = self:GetOwner()
if ent:GetClass() != "prop_physics" then return false end
local model = ent:GetModel()
if !model then
ply:ConCommand("ol_stacker_model \"\"\n")
else
ply:ConCommand("ol_stacker_model "..model.."\n")
end
return true
*/
end
function TOOL.BuildCPanel( CPanel )
// HEADER
CPanel:AddControl( "Header", { Text = "#Tool_ol_stacker_name", Description = "#Tool_ol_stacker_desc" } )
CPanel:AddControl( "Checkbox", { Label = "Freeze Props", Command = "ol_stacker_freeze" } )
CPanel:AddControl( "Checkbox", { Label = "Weld Props", Command = "ol_stacker_weld" } )
CPanel:AddControl( "Checkbox", { Label = "No Collide Props", Command = "ol_stacker_nocollide" } )
local params = {Label = "Relative To:", MenuButton = "0", Options = {}}
params.Options["World"] = {ol_stacker_mode = "1"}
params.Options["Prop"] = {ol_stacker_mode = "2"}
CPanel:AddControl( "ComboBox", params )
local params = {Label = "Stack Direction", MenuButton = "0", Options = {}}
params.Options["Up"] = {ol_stacker_dir = "1"}
params.Options["Down"] = {ol_stacker_dir = "2"}
params.Options["Front"] = {ol_stacker_dir = "3"}
params.Options["Behind"] = {ol_stacker_dir = "4"}
params.Options["Right"] = {ol_stacker_dir = "5"}
params.Options["Left"] = {ol_stacker_dir = "6"}
CPanel:AddControl( "ComboBox", params )
CPanel:AddControl( "Slider", { Label = "Count",
Type = "Integer",
Min = 0,
Max = 10,
Command = "ol_stacker_count",
Description = "How many props to stack."} )
CPanel:AddControl( "Header", { Text = "Advanced Options", Description = "These options are for advanced users. Leave them all default (0) if you don't understand what they do." } )
CPanel:AddControl( "Button", { Label = "Reset Advanced Options",
Command = "olstacker_resetoffsets",
Text = "Reset"} )
CPanel:AddControl( "Slider", { Label = "Offset X (forward/back)",
Type = "Float",
Min = 0,
Max = 1000,
Command = "ol_stacker_offsetx"} )
CPanel:AddControl( "Slider", { Label = "Offset Y (right/left)",
Type = "Float",
Min = 0,
Max = 1000,
Command = "ol_stacker_offsety"} )
CPanel:AddControl( "Slider", { Label = "Offset Z (up/down)",
Type = "Float",
Min = 0,
Max = 1000,
Command = "ol_stacker_offsetz"} )
CPanel:AddControl( "Slider", { Label = "Rotate Pitch",
Type = "Float",
Min = 0,
Max = 360,
Command = "ol_stacker_rotp"} )
CPanel:AddControl( "Slider", { Label = "Rotate Yaw",
Type = "Float",
Min = 0,
Max = 360,
Command = "ol_stacker_roty"} )
CPanel:AddControl( "Slider", { Label = "Rotate Roll",
Type = "Float",
Min = 0,
Max = 360,
Command = "ol_stacker_rotr"} )
CPanel:AddControl( "Checkbox", { Label = "Stack relative to new rotation", Command = "ol_stacker_recalc", Description = "If this is checked, each item in the stack will be stacked relative to the previous item in the stack. This allows you to create curved stacks." } )
end
if (CLIENT) then
local function ResetOffsets( player, command, arguments )
-- Reset all of the offset options to 0
LocalPlayer():ConCommand("ol_stacker_offsetx 0\n")
LocalPlayer():ConCommand("ol_stacker_offsety 0\n")
LocalPlayer():ConCommand("ol_stacker_offsetz 0\n")
LocalPlayer():ConCommand("ol_stacker_rotp 0\n")
LocalPlayer():ConCommand("ol_stacker_roty 0\n")
LocalPlayer():ConCommand("ol_stacker_rotr 0\n")
LocalPlayer():ConCommand("ol_stacker_recalc 0\n")
end
concommand.Add( "olstacker_resetoffsets", ResetOffsets )
end
function TOOL:UpdateGhostStack( ghost, player, ent )
if ( !ent || !ghost ) then return end
if ( !ent:IsValid() || !ghost:IsValid() ) then return end
local mode = self:GetClientNumber( "mode" )
local dir = self:GetClientNumber( "dir" )
local offsetx = self:GetClientNumber( "offsetx" )
local offsety = self:GetClientNumber( "offsety" )
local offsetz = self:GetClientNumber( "offsetz" )
local rotp = self:GetClientNumber( "rotp" )
local roty = self:GetClientNumber( "roty" )
local rotr = self:GetClientNumber( "rotr" )
local offset = Vector(offsetx, offsety, offsetz)
local rot = Angle(rotp, roty, rotr)
local stackdir, height, thisoffset = self:OLStackerCalcPos(ent, mode, dir, offset)
local newvec = ent:GetPos() + stackdir * height + thisoffset
local newang = ent:GetAngles() + rot
ghost:SetAngles(newang)
ghost:SetPos( newvec )
ghost:SetNoDraw( false )
end
function TOOL:Think()
local player = self:GetOwner()
local tr = utilx.GetPlayerTrace( player, player:GetCursorAimVector() )
local trace = util.TraceLine( tr )
if trace.Hit then
local newent = trace.Entity
if newent:IsValid() && newent:GetClass() == "prop_physics" && (newent != self.lastent || !self.GhostEntity) then
-- Time to change our ghost
self:MakeGhostEntity( newent:GetModel(), Vector(0,0,0), Angle(0,0,0) )
self.lastent = newent
end
if (!self.lastent || !self.lastent:IsValid()) && self.GhostEntity then
self:ReleaseGhostEntity()
end
end
if self.lastent != nil && self.lastent:IsValid() then
self:UpdateGhostStack( self.GhostEntity, player, self.lastent )
end
endI limited it myself back when I still hosted a server.