mirror of
https://github.com/Mista-Tea/improved-stacker.git
synced 2025-03-04 03:12:57 -05:00
Initial commit
This commit is contained in:
commit
4b472ef194
22
.gitattributes
vendored
Normal file
22
.gitattributes
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# Custom for Visual Studio
|
||||||
|
*.cs diff=csharp
|
||||||
|
*.sln merge=union
|
||||||
|
*.csproj merge=union
|
||||||
|
*.vbproj merge=union
|
||||||
|
*.fsproj merge=union
|
||||||
|
*.dbproj merge=union
|
||||||
|
|
||||||
|
# Standard to msysgit
|
||||||
|
*.doc diff=astextplain
|
||||||
|
*.DOC diff=astextplain
|
||||||
|
*.docx diff=astextplain
|
||||||
|
*.DOCX diff=astextplain
|
||||||
|
*.dot diff=astextplain
|
||||||
|
*.DOT diff=astextplain
|
||||||
|
*.pdf diff=astextplain
|
||||||
|
*.PDF diff=astextplain
|
||||||
|
*.rtf diff=astextplain
|
||||||
|
*.RTF diff=astextplain
|
215
.gitignore
vendored
Normal file
215
.gitignore
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
#################
|
||||||
|
## Eclipse
|
||||||
|
#################
|
||||||
|
|
||||||
|
*.pydevproject
|
||||||
|
.project
|
||||||
|
.metadata
|
||||||
|
bin/
|
||||||
|
tmp/
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*~.nib
|
||||||
|
local.properties
|
||||||
|
.classpath
|
||||||
|
.settings/
|
||||||
|
.loadpath
|
||||||
|
|
||||||
|
# External tool builders
|
||||||
|
.externalToolBuilders/
|
||||||
|
|
||||||
|
# Locally stored "Eclipse launch configurations"
|
||||||
|
*.launch
|
||||||
|
|
||||||
|
# CDT-specific
|
||||||
|
.cproject
|
||||||
|
|
||||||
|
# PDT-specific
|
||||||
|
.buildpath
|
||||||
|
|
||||||
|
|
||||||
|
#################
|
||||||
|
## Visual Studio
|
||||||
|
#################
|
||||||
|
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
|
||||||
|
[Dd]ebug/
|
||||||
|
[Rr]elease/
|
||||||
|
x64/
|
||||||
|
build/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.log
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
*.ncrunch*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.Publish.xml
|
||||||
|
*.pubxml
|
||||||
|
|
||||||
|
# NuGet Packages Directory
|
||||||
|
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||||
|
#packages/
|
||||||
|
|
||||||
|
# Windows Azure Build Output
|
||||||
|
csx
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
sql/
|
||||||
|
*.Cache
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file to a newer
|
||||||
|
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
App_Data/*.mdf
|
||||||
|
App_Data/*.ldf
|
||||||
|
|
||||||
|
#############
|
||||||
|
## Windows detritus
|
||||||
|
#############
|
||||||
|
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Mac crap
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
## Python
|
||||||
|
#############
|
||||||
|
|
||||||
|
*.py[co]
|
||||||
|
|
||||||
|
# Packages
|
||||||
|
*.egg
|
||||||
|
*.egg-info
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
eggs/
|
||||||
|
parts/
|
||||||
|
var/
|
||||||
|
sdist/
|
||||||
|
develop-eggs/
|
||||||
|
.installed.cfg
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
.coverage
|
||||||
|
.tox
|
||||||
|
|
||||||
|
#Translations
|
||||||
|
*.mo
|
||||||
|
|
||||||
|
#Mr Developer
|
||||||
|
.mr.developer.cfg
|
48
addon.txt
Normal file
48
addon.txt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
"AddonInfo"
|
||||||
|
{
|
||||||
|
"name" "Improved Stacker"
|
||||||
|
"author_name" "Original - OverloadUT, Edited by - Marii, Edited by - Mista Tea"
|
||||||
|
"info" "Mista Tea's version (this one)
|
||||||
|
Cleaned, organized, and optimized code.
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
- Prevents crash from players using very high X/Y/Z offset values.
|
||||||
|
- Prevents crash from players using very high P/Y/R rotate values.
|
||||||
|
- Fixed the halo option for ghosted props not working.
|
||||||
|
Tweaks:
|
||||||
|
- Added convenience functions to retrieve the client convars.
|
||||||
|
- Added option to enable/disable automatically applying materials to the stacked props.
|
||||||
|
- Added option to enable/disable automatically applying colors to the stacked props.
|
||||||
|
- Added console variables for server operators to limit various parts of stacker.
|
||||||
|
> stacker_max_count
|
||||||
|
> stacker_max_offsetx
|
||||||
|
> stacker_max_offsety
|
||||||
|
> stacker_max_offsetz
|
||||||
|
- Added console commands for server admins to control the console variables that limit stacker.
|
||||||
|
> stacker_set_maxcount #
|
||||||
|
> stacker_set_maxoffset #
|
||||||
|
> stacker_set_maxoffsetx #
|
||||||
|
> stacker_set_maxoffsety #
|
||||||
|
> stacker_set_maxoffsetz #
|
||||||
|
|
||||||
|
|
||||||
|
Marii's version (the one this is based on): http://www.steamcommunity.com/sharedfiles/filedetails/?id=104479831
|
||||||
|
Fixed for GM13, with other minor tweaks, by me. Not originally my work.
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
- Fixes ghosting errors.
|
||||||
|
- Fix InWorld() check.
|
||||||
|
- Fix bug with checking if prop is valid.
|
||||||
|
- Fix check to see if count is less then or zero.
|
||||||
|
Tweaks:
|
||||||
|
- Allows mass unfreezing of stacked props with physgun.
|
||||||
|
- Allows full ghosting of props (Shows entire stack).
|
||||||
|
- Ghosts can have halos!
|
||||||
|
- Tweak menu values and sliders to be ALOT more useful.
|
||||||
|
- Add Ghost All option.
|
||||||
|
|
||||||
|
Todo:
|
||||||
|
Clean ALL of the code!
|
||||||
|
|
||||||
|
GM12 Version (reupped by: sYcore, original author: OverlordUT): http://www.garrysmod.org/downloads/?a=view&id=64848"
|
||||||
|
}
|
721
lua/weapons/gmod_tool/stools/stacker.lua
Normal file
721
lua/weapons/gmod_tool/stools/stacker.lua
Normal file
@ -0,0 +1,721 @@
|
|||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
Stacker Tool
|
||||||
|
|
||||||
|
File name:
|
||||||
|
stacker.lua
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Original - OverloadUT
|
||||||
|
Updated for GMod 13 - Marii
|
||||||
|
Cleaned and optimized - Mista Tea
|
||||||
|
|
||||||
|
Changelog:
|
||||||
|
- Edited May 27th, 2014
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------]]
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- Tool Settings
|
||||||
|
--------------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
TOOL.Category = "Construction"
|
||||||
|
TOOL.Name = "#Tool.stacker.name"
|
||||||
|
TOOL.Command = nil
|
||||||
|
TOOL.ConfigName = ""
|
||||||
|
|
||||||
|
TOOL.ClientConVar[ "mode" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "dir" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "count" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "freeze" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "weld" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "nocollide" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "ghostall" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "material" ] = "1"
|
||||||
|
TOOL.ClientConVar[ "color" ] = "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"
|
||||||
|
TOOL.ClientConVar[ "halo" ] = "0"
|
||||||
|
TOOL.ClientConVar[ "halo_r" ] = "0"
|
||||||
|
TOOL.ClientConVar[ "halo_g" ] = "200"
|
||||||
|
TOOL.ClientConVar[ "halo_b" ] = "190"
|
||||||
|
TOOL.ClientConVar[ "halo_a" ] = "255"
|
||||||
|
|
||||||
|
if ( CLIENT ) then
|
||||||
|
|
||||||
|
language.Add( "Tool.stacker.name", "Stacker" )
|
||||||
|
language.Add( "Tool.stacker.desc", "Allows you to easily stack props" )
|
||||||
|
language.Add( "Tool.stacker.0", "Click to stack the prop you're pointing at." )
|
||||||
|
language.Add( "Undone_stacker", "Undone stacked prop(s)" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- Console Variables
|
||||||
|
--------------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
CreateConVar( "stacker_max_count", "30", bit.bor( FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE ) ) -- defines the max amount of props that can be stacked at a time
|
||||||
|
CreateConVar( "stacker_max_offsetx", "500", bit.bor( FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE ) ) -- defines the max distance on the x plane that stacked props can be offset (for individual control)
|
||||||
|
CreateConVar( "stacker_max_offsety", "500", bit.bor( FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE ) ) -- defines the max distance on the y plane that stacked props can be offset (for individual control)
|
||||||
|
CreateConVar( "stacker_max_offsetz", "500", bit.bor( FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_SERVER_CAN_EXECUTE ) ) -- defines the max distance on the z plane that stacked props can be offset (for individual control)
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- Console Commands
|
||||||
|
--------------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
if ( CLIENT ) then
|
||||||
|
|
||||||
|
local function ResetOffsets( ply, command, arguments )
|
||||||
|
-- Reset all of the offset options to 0
|
||||||
|
LocalPlayer():ConCommand( "stacker_offsetx 0\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_offsety 0\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_offsetz 0\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_rotp 0\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_roty 0\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_rotr 0\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_recalc 1\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_ghostall 1\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_material 1\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_color 1\n" )
|
||||||
|
LocalPlayer():ConCommand( "stacker_halo 1\n" )
|
||||||
|
end
|
||||||
|
concommand.Add( "stacker_resetoffsets", ResetOffsets )
|
||||||
|
|
||||||
|
elseif ( SERVER ) then
|
||||||
|
|
||||||
|
concommand.Add( "stacker_set_maxcount", function( ply, cmd, args )
|
||||||
|
if ( IsValid( ply ) and !ply:IsAdmin() ) then return false end
|
||||||
|
local count = tonumber( args[1] )
|
||||||
|
if ( !count or count < 0 ) then return false end
|
||||||
|
|
||||||
|
RunConsoleCommand( "stacker_max_count", count )
|
||||||
|
end, nil, "Sets the max amount of props that can be stacked at one time", FCVAR_CLIENTCMD_CAN_EXECUTE )
|
||||||
|
|
||||||
|
concommand.Add( "stacker_set_maxoffset", function( ply, cmd, args )
|
||||||
|
if ( IsValid( ply ) and !ply:IsAdmin() ) then return false end
|
||||||
|
local count = tonumber( args[1] )
|
||||||
|
if ( !count or count < 0 ) then return false end
|
||||||
|
|
||||||
|
RunConsoleCommand( "stacker_max_offsetx", count )
|
||||||
|
RunConsoleCommand( "stacker_max_offsety", count )
|
||||||
|
RunConsoleCommand( "stacker_max_offsetz", count )
|
||||||
|
end, nil, "Sets the max distance that stacked props can be offset in the xyz planes", FCVAR_CLIENTCMD_CAN_EXECUTE )
|
||||||
|
|
||||||
|
concommand.Add( "stacker_set_maxoffsetx", function( ply, cmd, args )
|
||||||
|
if ( IsValid( ply ) and !ply:IsAdmin() ) then return false end
|
||||||
|
local count = tonumber( args[1] )
|
||||||
|
if ( !count or count < 0 ) then return false end
|
||||||
|
|
||||||
|
RunConsoleCommand( "stacker_max_offsetx", count )
|
||||||
|
end, nil, "Sets the max distance that stacked props can be offset on the x plane", FCVAR_CLIENTCMD_CAN_EXECUTE )
|
||||||
|
|
||||||
|
concommand.Add( "stacker_set_maxoffsety", function( ply, cmd, args )
|
||||||
|
if ( IsValid( ply ) and !ply:IsAdmin() ) then return false end
|
||||||
|
local count = tonumber( args[1] )
|
||||||
|
if ( !count or count < 0 ) then return false end
|
||||||
|
|
||||||
|
RunConsoleCommand( "stacker_max_offsety", count )
|
||||||
|
end, nil, "Sets the max distance that stacked props can be offset on the y plane", FCVAR_CLIENTCMD_CAN_EXECUTE )
|
||||||
|
|
||||||
|
concommand.Add( "stacker_set_maxoffsetz", function( ply, cmd, args )
|
||||||
|
if ( IsValid( ply ) and !ply:IsAdmin() ) then return false end
|
||||||
|
local count = tonumber( args[1] )
|
||||||
|
if ( !count or count < 0 ) then return false end
|
||||||
|
|
||||||
|
RunConsoleCommand( "stacker_max_offsetz", count )
|
||||||
|
end, nil, "Sets the max distance that stacked props can be offset on the z plane", FCVAR_CLIENTCMD_CAN_EXECUTE )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- Enumerations
|
||||||
|
--------------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
local MODE_WORLD = 1 -- stacking relative to the world
|
||||||
|
local MODE_PROP = 2 -- stacking relative to the prop
|
||||||
|
|
||||||
|
local DIRECTION_UP = 1
|
||||||
|
local DIRECTION_DOWN = 2
|
||||||
|
local DIRECTION_FRONT = 3
|
||||||
|
local DIRECTION_BEHIND = 4
|
||||||
|
local DIRECTION_RIGHT = 5
|
||||||
|
local DIRECTION_LEFT = 6
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- Localized Functions & Variables
|
||||||
|
--------------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
-- localizing globals is an encouraged practice that inproves code efficiency,
|
||||||
|
-- accessing a local value is considerably faster than a global value
|
||||||
|
local util = util
|
||||||
|
local math = math
|
||||||
|
local undo = undo
|
||||||
|
local halo = halo
|
||||||
|
local game = game
|
||||||
|
local pairs = pairs
|
||||||
|
local table = table
|
||||||
|
local Angle = Angle
|
||||||
|
local Vector = Vector
|
||||||
|
local IsValid = IsValid
|
||||||
|
local language = language
|
||||||
|
|
||||||
|
local MOVETYPE_NONE = MOVETYPE_NONE
|
||||||
|
local SOLID_VPHYSICS = SOLID_VPHYSICS
|
||||||
|
local RENDERMODE_TRANSALPHA = RENDERMODE_TRANSALPHA
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- Convenience Functions
|
||||||
|
--------------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:GetCount()
|
||||||
|
--
|
||||||
|
-- Gets the maximum amount of props that can be stacked at a time
|
||||||
|
--]]--
|
||||||
|
function TOOL:GetCount()
|
||||||
|
return math.Clamp( self:GetClientNumber( "count" ), 0, GetConVarNumber( "stacker_max_count" ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:GetDirection()
|
||||||
|
--
|
||||||
|
-- Gets the direction to stack the props
|
||||||
|
--]]--
|
||||||
|
function TOOL:GetDirection() return self:GetClientNumber( "dir" ) end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:GetStackerMode()
|
||||||
|
--
|
||||||
|
-- Gets the stacker mode (1 = MODE_WORLD, 2 = MODE_PROP)
|
||||||
|
--]]--
|
||||||
|
function TOOL:GetStackerMode() return self:GetClientNumber( "mode" ) end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:GetOffsetX(), TOOL:GetOffsetY(), TOOL:GetOffsetZ(), TOOL:GetOffsetVector()
|
||||||
|
--
|
||||||
|
-- Gets the distance to offset the position of the stacked props.
|
||||||
|
-- These values are clamped to prevent server crashes from players
|
||||||
|
-- using very high offset values.
|
||||||
|
--]]--
|
||||||
|
function TOOL:GetOffsetX() return math.Clamp( self:GetClientNumber( "offsetx" ), - GetConVarNumber( "stacker_max_offsetx" ), GetConVarNumber( "stacker_max_offsetx" ) ) end
|
||||||
|
function TOOL:GetOffsetY() return math.Clamp( self:GetClientNumber( "offsety" ), - GetConVarNumber( "stacker_max_offsety" ), GetConVarNumber( "stacker_max_offsety" ) ) end
|
||||||
|
function TOOL:GetOffsetZ() return math.Clamp( self:GetClientNumber( "offsetz" ), - GetConVarNumber( "stacker_max_offsetz" ), GetConVarNumber( "stacker_max_offsetz" ) ) end
|
||||||
|
|
||||||
|
function TOOL:GetOffsetVector() return Vector( self:GetOffsetX(), self:GetOffsetY(), self:GetOffsetZ() ) end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:GetRotateP(), TOOL:GetRotateY(), TOOL:GetRotateR(), TOOL:GetRotateAngle()
|
||||||
|
--
|
||||||
|
-- Gets the value to rotate the angle of the stacked props.
|
||||||
|
-- These values are clamped to prevent server crashes from players
|
||||||
|
-- using very high rotation values.
|
||||||
|
--]]--
|
||||||
|
function TOOL:GetRotateP() return math.Clamp( self:GetClientNumber( "rotp" ), -360, 360 ) end
|
||||||
|
function TOOL:GetRotateY() return math.Clamp( self:GetClientNumber( "roty" ), -360, 360 ) end
|
||||||
|
function TOOL:GetRotateR() return math.Clamp( self:GetClientNumber( "rotz" ), -360, 360 ) end
|
||||||
|
|
||||||
|
function TOOL:GetRotateAngle() return Angle( self:GetRotateP(), self:GetRotateY(), self:GetRotateR() ) end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:GetGhostStack(), TOOL:SetGhostStack( table )
|
||||||
|
--
|
||||||
|
-- Gets and sets the table of ghosted props in the stack.
|
||||||
|
--]]--
|
||||||
|
function TOOL:GetGhostStack() return self.GhostStack end
|
||||||
|
|
||||||
|
function TOOL:SetGhostStack( tbl ) self.GhostStack = tbl end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldFreeze()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should be spawned frozen.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldFreeze() return self:GetClientNumber( "freeze" ) == 1 end
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldWeld()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should be welded together.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldWeld() return self:GetClientNumber( "weld" ) == 1 end
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldNoCollide()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should be nocollided with each other.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldNoCollide() return self:GetClientNumber( "nocollide" ) == 1 end
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldStackRelative()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should be stacked relative to the new rotation.
|
||||||
|
-- Using this setting will allow you to create curved structures out of props.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldStackRelative() return self:GetClientNumber( "recalc" ) == 1 end
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldGhostAll()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should all be ghosted or if only the
|
||||||
|
-- first stacked prop should be ghosted.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldGhostAll() return self:GetClientNumber( "ghostall" ) == 1 end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldAddHalos(), TOOL:GetHaloR(), TOOL:GetHaloG(), TOOL:GetHaloB() TOOL:GetHaloA() TOOL:GetHaloColor()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should have halos drawn on them for added visibility.
|
||||||
|
-- Gets the RGBA values of the halo color.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldAddHalos() return self:GetClientNumber( "halo" ) == 1 end
|
||||||
|
|
||||||
|
function TOOL:GetHaloR() return math.Clamp( self:GetClientNumber( "halo_r" ), 0, 255 ) end
|
||||||
|
function TOOL:GetHaloG() return math.Clamp( self:GetClientNumber( "halo_g" ), 0, 255 ) end
|
||||||
|
function TOOL:GetHaloB() return math.Clamp( self:GetClientNumber( "halo_b" ), 0, 255 ) end
|
||||||
|
function TOOL:GetHaloA() return math.Clamp( self:GetClientNumber( "halo_a" ), 0, 255 ) end
|
||||||
|
|
||||||
|
function TOOL:GetHaloColor()
|
||||||
|
return Color( self:GetHaloR(), self:GetHaloG(), self:GetHaloB(), self:GetHaloA() )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldApplyMaterial()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should have the original prop's material applied.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldApplyMaterial() return self:GetClientNumber( "material" ) == 1 end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- TOOL:ShouldApplyColor()
|
||||||
|
--
|
||||||
|
-- Returns true if the stacked props should have the original prop's color applied.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ShouldApplyColor() return self:GetClientNumber( "color" ) == 1 end
|
||||||
|
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
-- Tool Functions
|
||||||
|
--------------------------------------------------------------------------]]--
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:Holster()
|
||||||
|
--
|
||||||
|
-- Called when the player switches to a different weapon or tool.
|
||||||
|
--]]--
|
||||||
|
function TOOL:Holster()
|
||||||
|
self:ReleaseGhostStack()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:Init()
|
||||||
|
--
|
||||||
|
-- Creates two net message receivers on the client that control the stack
|
||||||
|
-- of ghosted props.
|
||||||
|
--]]--
|
||||||
|
function TOOL:Init()
|
||||||
|
if ( SERVER ) then
|
||||||
|
util.AddNetworkString( "Stacker.StackGhost" )
|
||||||
|
util.AddNetworkString( "Stacker.UnstackGhost" )
|
||||||
|
elseif ( CLIENT ) then
|
||||||
|
net.Receive( "Stacker.StackGhost", function( bits )
|
||||||
|
self:SetGhostStack( net.ReadTable() )
|
||||||
|
end )
|
||||||
|
|
||||||
|
net.Receive( "Stacker.UnstackGhost", function( bits )
|
||||||
|
if ( !self:GetGhostStack() ) then return end
|
||||||
|
table.Empty( self:GetGhostStack() )
|
||||||
|
end )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:LeftClick( table )
|
||||||
|
--
|
||||||
|
-- Attempts to create a stack of props relative to the entity being left clicked.
|
||||||
|
--]]--
|
||||||
|
function TOOL:LeftClick( trace )
|
||||||
|
if ( !IsValid( trace.Entity ) or trace.Entity:GetClass() ~= "prop_physics" ) then return false end
|
||||||
|
if ( CLIENT ) then return true end
|
||||||
|
|
||||||
|
local count = self:GetCount()
|
||||||
|
|
||||||
|
if ( count <= 0 ) then return false end
|
||||||
|
|
||||||
|
local dir = self:GetDirection()
|
||||||
|
local mode = self:GetStackerMode()
|
||||||
|
local offset = self:GetOffsetVector()
|
||||||
|
local rotate = self:GetRotateAngle()
|
||||||
|
|
||||||
|
local applyFreeze = self:ShouldFreeze()
|
||||||
|
local applyWeld = self:ShouldWeld()
|
||||||
|
local applyNoCollide = self:ShouldNoCollide()
|
||||||
|
local stackRelative = self:ShouldStackRelative()
|
||||||
|
|
||||||
|
local applyMaterial = self:ShouldApplyMaterial()
|
||||||
|
local applyColor = self:ShouldApplyColor()
|
||||||
|
|
||||||
|
local ply = self:GetOwner()
|
||||||
|
local ent = trace.Entity
|
||||||
|
|
||||||
|
local entPos = ent:GetPos()
|
||||||
|
local entAng = ent:GetAngles()
|
||||||
|
local entMat = ent:GetMaterial()
|
||||||
|
local entCol = ent:GetColor()
|
||||||
|
|
||||||
|
local lastEnt = ent
|
||||||
|
local newEnt
|
||||||
|
|
||||||
|
undo.Create( "stacker" )
|
||||||
|
|
||||||
|
for i = 1, count, 1 do
|
||||||
|
if ( !self:GetSWEP():CheckLimit( "props" ) ) then break end
|
||||||
|
|
||||||
|
if ( i == 1 or ( mode == MODE_PROP and stackRelative ) ) then
|
||||||
|
stackdir, height, thisoffset = self:StackerCalcPos( lastEnt, mode, dir, offset )
|
||||||
|
end
|
||||||
|
|
||||||
|
entPos = entPos + stackdir * height + thisoffset
|
||||||
|
entAng = entAng + rotate
|
||||||
|
|
||||||
|
newEnt = ents.Create( "prop_physics" )
|
||||||
|
|
||||||
|
newEnt["IsFromStacker"] = true -- this is for external prop protections or anti-spam addons
|
||||||
|
|
||||||
|
newEnt:SetModel( ent:GetModel() )
|
||||||
|
newEnt:SetPos( entPos )
|
||||||
|
newEnt:SetAngles( entAng )
|
||||||
|
if ( applyMaterial ) then newEnt:SetMaterial( entMat ) end
|
||||||
|
if ( applyColor ) then newEnt:SetColor( entCol ) end
|
||||||
|
newEnt:Spawn()
|
||||||
|
|
||||||
|
if ( applyFreeze ) then
|
||||||
|
--ply:AddFrozenPhysicsObject( newEnt, newEnt:GetPhysicsObject() ) -- fix so you can mass-unfreeze
|
||||||
|
newEnt:GetPhysicsObject():EnableMotion( false )
|
||||||
|
else
|
||||||
|
newEnt:GetPhysicsObject():Wake()
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( applyWeld ) then undo.AddEntity( constraint.Weld( lastEnt, newEnt, 0, 0, 0 ) ) end
|
||||||
|
if ( applyNoCollide ) then undo.AddEntity( constraint.NoCollide( lastEnt, newEnt, 0, 0 ) ) end
|
||||||
|
|
||||||
|
lastEnt = newEnt
|
||||||
|
|
||||||
|
undo.AddEntity( newEnt )
|
||||||
|
ply:AddCount( "props", newEnt )
|
||||||
|
ply:AddCleanup( "props", newEnt )
|
||||||
|
end
|
||||||
|
|
||||||
|
undo.SetPlayer( ply )
|
||||||
|
undo.Finish()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:StackerCalcPos( entity, number, number, number )
|
||||||
|
--
|
||||||
|
-- Calculates the positions and angles of the entity being created in the stack.
|
||||||
|
-- This function uses a lookup table for added optimization as opposed to an if-else block.
|
||||||
|
--]]--
|
||||||
|
local CALC_POS = {
|
||||||
|
[MODE_WORLD] = {
|
||||||
|
[DIRECTION_UP] = function( forward, upper, lower ) return forward:Up(), math.abs( upper.z - lower.z ) end,
|
||||||
|
[DIRECTION_DOWN] = function( forward, upper, lower ) return forward:Up() * -1, math.abs( upper.z - lower.z ) end,
|
||||||
|
[DIRECTION_FRONT] = function( forward, upper, lower ) return forward:Forward(), math.abs( upper.x - lower.x ) end,
|
||||||
|
[DIRECTION_BEHIND] = function( forward, upper, lower ) return forward:Forward() * -1, math.abs( upper.x - lower.x ) end,
|
||||||
|
[DIRECTION_RIGHT] = function( forward, upper, lower ) return forward:Right(), math.abs( upper.y - lower.y ) end,
|
||||||
|
[DIRECTION_LEFT] = function( forward, upper, lower ) return forward:Right() * -1, math.abs( upper.y - lower.y ) end,
|
||||||
|
},
|
||||||
|
|
||||||
|
[MODE_PROP] = {
|
||||||
|
[DIRECTION_UP] = function( forward, offset, gupper, glower ) return forward:Up(), math.abs( gupper.z - glower.z ), forward:Up() * offset.X + forward:Forward() * -1 * offset.Z + forward:Right() * offset.Y end,
|
||||||
|
[DIRECTION_DOWN] = function( forward, offset, gupper, glower ) return forward:Up() * -1, math.abs( gupper.z - glower.z ), forward:Up() * -1 * offset.X + forward:Forward() * offset.Z + forward:Right() * offset.Y end,
|
||||||
|
[DIRECTION_FRONT] = function( forward, offset, gupper, glower ) return forward:Forward(), math.abs( gupper.x - glower.x ), forward:Forward() * offset.X + forward:Up() * offset.Z + forward:Right() * offset.Y end,
|
||||||
|
[DIRECTION_BEHIND] = function( forward, offset, gupper, glower ) return forward:Forward() * -1, math.abs( gupper.x - glower.x ), forward:Forward() * -1 * offset.X + forward:Up() * offset.Z + forward:Right() * -1 * offset.Y end,
|
||||||
|
[DIRECTION_RIGHT] = function( forward, offset, gupper, glower ) return forward:Right(), math.abs( gupper.y - glower.y ), forward:Right() * offset.X + forward:Up() * offset.Z + forward:Forward() * -1 * offset.Y end,
|
||||||
|
[DIRECTION_LEFT] = function( forward, offset, gupper, glower ) return forward:Right() * -1, math.abs( gupper.y - glower.y ), forward:Right() * -1 * offset.X + forward:Up() * offset.Z + forward:Forward() * offset.Y end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local VECX = Vector( 1, 0, 0 )
|
||||||
|
local VECZ = Vector( 0, 0, 1 )
|
||||||
|
|
||||||
|
function TOOL:StackerCalcPos( ent, mode, dir, offset )
|
||||||
|
local forward = VECX:Angle()
|
||||||
|
local entAng = ent:GetAngles()
|
||||||
|
|
||||||
|
local lower = ent:WorldSpaceAABB()
|
||||||
|
local upper = ent:WorldSpaceAABB()
|
||||||
|
local glower = ent:OBBMins()
|
||||||
|
local gupper = ent:OBBMaxs()
|
||||||
|
|
||||||
|
local stackdir = VECZ
|
||||||
|
local height = math.abs( upper.z - lower.z )
|
||||||
|
|
||||||
|
if ( mode == MODE_WORLD ) then -- get the position relative to the world's directions
|
||||||
|
|
||||||
|
stackdir, height = CALC_POS[ mode ][ dir ]( forward, upper, lower )
|
||||||
|
|
||||||
|
elseif ( mode == MODE_PROP ) then -- get the position relative to the prop's directions
|
||||||
|
|
||||||
|
stackdir, height, offset = CALC_POS[ mode ][ dir ]( entAng, offset, gupper, glower )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return stackdir, height, offset
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:UpdateGhostStack( entity )
|
||||||
|
--
|
||||||
|
-- Attempts to update the positions and angles of all ghosted props in the stack.
|
||||||
|
--]]--
|
||||||
|
function TOOL:UpdateGhostStack( ent )
|
||||||
|
if ( !IsValid( ent ) or !self:CheckGhostStack() ) then return end
|
||||||
|
|
||||||
|
local count = self:GetCount()
|
||||||
|
local mode = self:GetStackerMode()
|
||||||
|
local dir = self:GetDirection()
|
||||||
|
local offset = self:GetOffsetVector()
|
||||||
|
local rotate = self:GetRotateAngle()
|
||||||
|
local recalc = self:ShouldStackRelative()
|
||||||
|
|
||||||
|
local newEnt = ent
|
||||||
|
local entPos = newEnt:GetPos()
|
||||||
|
local entAng = newEnt:GetAngles()
|
||||||
|
|
||||||
|
local stackdir, height, thisoffset
|
||||||
|
|
||||||
|
for k,v in pairs( self:GetGhostStack() ) do
|
||||||
|
if ( k == 1 or ( mode == MODE_PROP and recalc ) ) then
|
||||||
|
stackdir, height, thisoffset = self:StackerCalcPos( newEnt, mode, dir, offset )
|
||||||
|
end
|
||||||
|
|
||||||
|
entPos = entPos + stackdir * height + thisoffset
|
||||||
|
entAng = entAng + rotate
|
||||||
|
|
||||||
|
v:SetAngles( entAng )
|
||||||
|
v:SetPos( entPos )
|
||||||
|
v:SetNoDraw( false )
|
||||||
|
newEnt = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:CheckGhostStack()
|
||||||
|
--
|
||||||
|
-- Attempts to validate the status of the ghosted props in the stack.
|
||||||
|
--]]--
|
||||||
|
function TOOL:CheckGhostStack()
|
||||||
|
local ghoststack = self:GetGhostStack()
|
||||||
|
if ( !ghoststack ) then return false end
|
||||||
|
|
||||||
|
local count = self:GetCount()
|
||||||
|
local ghostAll = self:ShouldGhostAll()
|
||||||
|
|
||||||
|
for k, v in pairs( ghoststack ) do
|
||||||
|
if ( !IsValid( v ) ) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( #ghoststack ~= count and ghostAll ) then return false
|
||||||
|
elseif ( #ghoststack ~= 1 and !ghostAll ) then return false end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:CreateGhostStack( entity, vector, angle )
|
||||||
|
--
|
||||||
|
-- Attempts to create a stack of ghosted props on the prop the player is currently
|
||||||
|
-- looking at before they actually left click to create the stack. This acts
|
||||||
|
-- as a visual aid for the player so they can see the results without actually creating
|
||||||
|
-- the entities yet (if in multiplayer).
|
||||||
|
--]]--
|
||||||
|
local TRANSPARENT = Color( 255, 255, 255, 150 )
|
||||||
|
|
||||||
|
function TOOL:CreateGhostStack( ent, pos, ang )
|
||||||
|
if ( self:GetGhostStack() ) then self:ReleaseGhostStack() end
|
||||||
|
local ghoststack = {}
|
||||||
|
|
||||||
|
if ( SERVER and !game.SinglePlayer() ) then return false; end
|
||||||
|
if ( CLIENT and game.SinglePlayer() ) then return false; end
|
||||||
|
|
||||||
|
local count = self:GetCount()
|
||||||
|
local addHalos = self:ShouldAddHalos()
|
||||||
|
local ghostAll = self:ShouldGhostAll()
|
||||||
|
|
||||||
|
local applyMaterial = self:ShouldApplyMaterial()
|
||||||
|
local applyColor = self:ShouldApplyColor()
|
||||||
|
|
||||||
|
local entMod = ent:GetModel()
|
||||||
|
local entMat = ent:GetMaterial() or ""
|
||||||
|
local entCol = ent:GetColor() or TRANSPARENT
|
||||||
|
entCol.a = 150
|
||||||
|
|
||||||
|
if ( !ghostAll and count ~= 0 ) then
|
||||||
|
count = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, count, 1 do
|
||||||
|
local ghost
|
||||||
|
|
||||||
|
if ( CLIENT ) then ghost = ents.CreateClientProp( entMod )
|
||||||
|
else ghost = ents.Create( "prop_physics" ) end
|
||||||
|
|
||||||
|
if ( !IsValid( ghost ) ) then ghost = nil continue end
|
||||||
|
|
||||||
|
ghost:SetModel( entMod )
|
||||||
|
ghost:SetPos( pos )
|
||||||
|
ghost:SetAngles( ang )
|
||||||
|
ghost:Spawn()
|
||||||
|
|
||||||
|
ghost:SetSolid( SOLID_VPHYSICS )
|
||||||
|
ghost:SetMoveType( MOVETYPE_NONE )
|
||||||
|
ghost:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||||
|
ghost:SetNotSolid( true )
|
||||||
|
ghost:SetMaterial( ( applyMaterial and entMat ) or "" )
|
||||||
|
ghost:SetColor( ( applyColor and entCol ) or TRANSPARENT )
|
||||||
|
|
||||||
|
table.insert( ghoststack, ghost )
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( SERVER and addHalos ) then
|
||||||
|
net.Start( "Stacker.StackGhost" )
|
||||||
|
net.WriteTable( ghoststack )
|
||||||
|
net.Send( self:GetOwner() )
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetGhostStack( ghoststack )
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:ReleaseGhostStack()
|
||||||
|
--
|
||||||
|
-- Attempts to remove all ghosted props in the stack on the server (if singleplayer)
|
||||||
|
-- or on the client (in multiplayer). This occurs when the player stops looking at
|
||||||
|
-- a prop with the stacker tool equipped.
|
||||||
|
--]]--
|
||||||
|
function TOOL:ReleaseGhostStack()
|
||||||
|
local ghoststack = self:GetGhostStack()
|
||||||
|
if ( !ghoststack ) then return end
|
||||||
|
|
||||||
|
for k,v in pairs( ghoststack ) do
|
||||||
|
if ( !IsValid( v ) ) then continue end
|
||||||
|
v:Remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
net.Start( "Stacker.UnstackGhost" )
|
||||||
|
net.Send( self:GetOwner() )
|
||||||
|
end
|
||||||
|
|
||||||
|
table.Empty( ghoststack )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL:Think()
|
||||||
|
--
|
||||||
|
-- While the stacker tool is equipped, this function will check to see if
|
||||||
|
-- the player is looking at any props and attempt to create the stack of
|
||||||
|
-- ghosted props before the players actually left clicks.
|
||||||
|
--]]--
|
||||||
|
local VEC = Vector( 0, 0, 0 )
|
||||||
|
local ANG = Angle( 0, 0, 0 )
|
||||||
|
local HaloColor = Color( 181, 0, 217 )
|
||||||
|
|
||||||
|
function TOOL:Think()
|
||||||
|
local ply = self:GetOwner()
|
||||||
|
local trace = ply:GetEyeTrace()
|
||||||
|
local traceValid = IsValid( trace.Entity )
|
||||||
|
|
||||||
|
if ( traceValid and trace.Entity:GetClass() == "prop_physics" ) then
|
||||||
|
self.NewEnt = trace.Entity
|
||||||
|
|
||||||
|
if ( self.NewEnt ~= self.LastEnt ) then
|
||||||
|
if ( self:CreateGhostStack( self.NewEnt, VEC, ANG ) ) then self.LastEnt = self.NewEnt end
|
||||||
|
end
|
||||||
|
if ( !self:CheckGhostStack() ) then
|
||||||
|
self:ReleaseGhostStack()
|
||||||
|
self.LastEnt = nil
|
||||||
|
end
|
||||||
|
elseif ( ( traceValid and trace.Entity:GetClass() ~= "prop_physics" and self.LastEnt ~= nil ) or !traceValid ) then
|
||||||
|
self:ReleaseGhostStack()
|
||||||
|
self.LastEnt = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( IsValid( self.LastEnt ) ) then
|
||||||
|
self:UpdateGhostStack( self.LastEnt )
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( CLIENT ) then
|
||||||
|
if ( !self:ShouldAddHalos() ) then return end
|
||||||
|
|
||||||
|
local ghoststack = self:GetGhostStack()
|
||||||
|
if ( !ghoststack or #ghoststack <= 0 ) then return end
|
||||||
|
|
||||||
|
halo.Add( ghoststack, self:GetHaloColor() )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- TOOL.BuildCPanel( panel )
|
||||||
|
--
|
||||||
|
-- Builds the control panel menu that can be seen when holding Q and accessing
|
||||||
|
-- the stacker menu.
|
||||||
|
--]]--
|
||||||
|
function TOOL.BuildCPanel( CPanel )
|
||||||
|
CPanel:AddControl( "Header", { Text = "#Tool.stacker.name", Description = "#Tool.stacker.desc" } )
|
||||||
|
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "Freeze Props", Command = "stacker_freeze" } )
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "Weld Props", Command = "stacker_weld" } )
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "No Collide Props", Command = "stacker_nocollide" } )
|
||||||
|
|
||||||
|
local params = { Label = "Relative To:", MenuButton = "0", Options = {} }
|
||||||
|
params.Options[ "World" ] = { stacker_mode = "1" }
|
||||||
|
params.Options[ "Prop" ] = { stacker_mode = "2" }
|
||||||
|
CPanel:AddControl( "ComboBox", params )
|
||||||
|
|
||||||
|
local params = { Label = "Stack Direction", MenuButton = "0", Options = {} }
|
||||||
|
params.Options[ "Up" ] = { stacker_dir = "1" }
|
||||||
|
params.Options[ "Down" ] = { stacker_dir = "2" }
|
||||||
|
params.Options[ "Front" ] = { stacker_dir = "3" }
|
||||||
|
params.Options[ "Behind" ] = { stacker_dir = "4" }
|
||||||
|
params.Options[ "Right" ] = { stacker_dir = "5" }
|
||||||
|
params.Options[ "Left" ] = { stacker_dir = "6" }
|
||||||
|
CPanel:AddControl( "ComboBox", params )
|
||||||
|
|
||||||
|
|
||||||
|
CPanel:AddControl( "Slider", { Label = "Count",Type = "Integer", Min = 1, Max = GetConVarNumber( "stacker_max_count" ), Command = "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 = "stacker_resetoffsets", Text = "Reset" } )
|
||||||
|
|
||||||
|
CPanel:AddControl( "Slider", { Label = "Offset X ( forward/back )", Type = "Float", Min = - GetConVarNumber( "stacker_max_offsetx" ), Max = GetConVarNumber( "stacker_max_offsetx" ), Value = 0, Command = "stacker_offsetx" } )
|
||||||
|
CPanel:AddControl( "Slider", { Label = "Offset Y ( right/left )", Type = "Float", Min = - GetConVarNumber( "stacker_max_offsety" ), Max = GetConVarNumber( "stacker_max_offsety" ), Value = 0, Command = "stacker_offsety" } )
|
||||||
|
CPanel:AddControl( "Slider", { Label = "Offset Z ( up/down )", Type = "Float", Min = - GetConVarNumber( "stacker_max_offsetz" ), Max = GetConVarNumber( "stacker_max_offsetz" ), Value = 0, Command = "stacker_offsetz" } )
|
||||||
|
CPanel:AddControl( "Slider", { Label = "Rotate Pitch", Type = "Float", Min = -360, Max = 360, Value = 0, Command = "stacker_rotp" } )
|
||||||
|
CPanel:AddControl( "Slider", { Label = "Rotate Yaw", Type = "Float", Min = -360, Max = 360, Value = 0, Command = "stacker_roty" } )
|
||||||
|
CPanel:AddControl( "Slider", { Label = "Rotate Roll", Type = "Float", Min = -360, Max = 360, Value = 0, Command = "stacker_rotr" } )
|
||||||
|
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "Stack props relative to new rotation", Command = "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." } )
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "Ghost all of the props in the stack", Command = "stacker_ghostall", Description = "Creates every ghost prop in the stack instead of just the first ghost prop" } )
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "Apply material to the stacked props", Command = "stacker_material", Description = "Applies the material of the original prop to all stacked props" } )
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "Apply color to the stacked props", Command = "stacker_color", Description = "Applies the color of the original prop to all stacked props" } )
|
||||||
|
CPanel:AddControl( "Checkbox", { Label = "Add halos to the ghost props", Command = "stacker_halo", Description = "Give the ghost a halo" } )
|
||||||
|
CPanel:AddControl( "Color", { Label = "Halo color", Red = "stacker_halo_r", Green = "stacker_halo_g", Blue = "stacker_halo_b", Alpha = "" } )
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user