mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
72
gamemodes/sandbox/gamemode/cl_hints.lua
Normal file
72
gamemodes/sandbox/gamemode/cl_hints.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
CreateClientConVar( "cl_showhints", "1", true, false, "Whether to display popup hints." )
|
||||
|
||||
-- A list of hints we've already done so we don't repeat ourselves`
|
||||
local ProcessedHints = {}
|
||||
|
||||
--
|
||||
-- Throw's a Hint to the screen
|
||||
--
|
||||
local function ThrowHint( name )
|
||||
|
||||
local show = GetConVarNumber( "cl_showhints" )
|
||||
if ( show == 0 ) then return end
|
||||
|
||||
if ( engine.IsPlayingDemo() ) then return end
|
||||
|
||||
local text = language.GetPhrase( "Hint_" .. name )
|
||||
|
||||
local s, e, group = string.find( text, "%%([^%%]+)%%" )
|
||||
while ( s ) do
|
||||
local key = input.LookupBinding( group )
|
||||
if ( !key ) then key = "<NOT BOUND>" end
|
||||
|
||||
text = string.gsub( text, "%%([^%%]+)%%", "'" .. key:upper() .. "'" )
|
||||
s, e, group = string.find( text, "%%([^%%]+)%%" )
|
||||
end
|
||||
|
||||
GAMEMODE:AddNotify( text, NOTIFY_HINT, 20 )
|
||||
|
||||
surface.PlaySound( "ambient/water/drip" .. math.random( 1, 4 ) .. ".wav" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Adds a hint to the queue
|
||||
--
|
||||
function GM:AddHint( name, delay )
|
||||
|
||||
if ( ProcessedHints[ name ] ) then return end
|
||||
|
||||
timer.Create( "HintSystem_" .. name, delay, 1, function() ThrowHint( name ) end )
|
||||
ProcessedHints[ name ] = true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Removes a hint from the queue
|
||||
--
|
||||
function GM:SuppressHint( name )
|
||||
|
||||
timer.Remove( "HintSystem_" .. name )
|
||||
|
||||
end
|
||||
|
||||
-- Show opening menu hint if they haven't opened the menu within 30 seconds
|
||||
GM:AddHint( "OpeningMenu", 30 )
|
||||
|
||||
-- Tell them how to turn the hints off after 1 minute
|
||||
GM:AddHint( "Annoy1", 5 )
|
||||
GM:AddHint( "Annoy2", 7 )
|
||||
188
gamemodes/sandbox/gamemode/cl_init.lua
Normal file
188
gamemodes/sandbox/gamemode/cl_init.lua
Normal file
@@ -0,0 +1,188 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Sandbox Gamemode
|
||||
|
||||
This is GMod's default gamemode
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
include( "shared.lua" )
|
||||
include( "cl_spawnmenu.lua" )
|
||||
include( "cl_notice.lua" )
|
||||
include( "cl_hints.lua" )
|
||||
include( "cl_worldtips.lua" )
|
||||
include( "cl_search_models.lua" )
|
||||
include( "gui/IconEditor.lua" )
|
||||
|
||||
--
|
||||
-- Make BaseClass available
|
||||
--
|
||||
DEFINE_BASECLASS( "gamemode_base" )
|
||||
|
||||
|
||||
local physgun_halo = CreateConVar( "physgun_halo", "1", { FCVAR_ARCHIVE }, "Draw the Physics Gun grab effect?" )
|
||||
|
||||
function GM:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
|
||||
end
|
||||
|
||||
function GM:LimitHit( name )
|
||||
|
||||
local str = "#SBoxLimit_" .. name
|
||||
local translated = language.GetPhrase( str )
|
||||
if ( str == translated ) then
|
||||
-- No translation available, apply our own
|
||||
translated = string.format( language.GetPhrase( "hint.hitXlimit" ), language.GetPhrase( name ) )
|
||||
end
|
||||
|
||||
self:AddNotify( translated, NOTIFY_ERROR, 6 )
|
||||
surface.PlaySound( "buttons/button10.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnUndo( name, strCustomString )
|
||||
|
||||
local text = strCustomString
|
||||
|
||||
if ( !text ) then
|
||||
local strId = "#Undone_" .. name
|
||||
text = language.GetPhrase( strId )
|
||||
if ( strId == text ) then
|
||||
-- No translation available, generate our own
|
||||
text = string.format( language.GetPhrase( "hint.undoneX" ), language.GetPhrase( name ) )
|
||||
end
|
||||
end
|
||||
|
||||
-- This is a hack for SWEPs, Tools, etc, that already have hardcoded English only translations
|
||||
-- TODO: Do this for non English languages only
|
||||
local strMatch = string.match( text, "^Undone (.*)$" )
|
||||
if ( strMatch ) then
|
||||
text = string.format( language.GetPhrase( "hint.undoneX" ), language.GetPhrase( strMatch ) )
|
||||
end
|
||||
|
||||
self:AddNotify( text, NOTIFY_UNDO, 2 )
|
||||
|
||||
-- Find a better sound :X
|
||||
surface.PlaySound( "buttons/button15.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnCleanup( name )
|
||||
|
||||
local str = "#Cleaned_" .. name
|
||||
local translated = language.GetPhrase( str )
|
||||
if ( str == translated ) then
|
||||
-- No translation available, apply our own
|
||||
translated = string.format( language.GetPhrase( "hint.cleanedX" ), language.GetPhrase( name ) )
|
||||
end
|
||||
|
||||
self:AddNotify( translated, NOTIFY_CLEANUP, 5 )
|
||||
|
||||
-- Find a better sound :X
|
||||
surface.PlaySound( "buttons/button15.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:UnfrozeObjects( num )
|
||||
|
||||
self:AddNotify( string.format( language.GetPhrase( "hint.unfrozeX" ), num ), NOTIFY_GENERIC, 3 )
|
||||
|
||||
-- Find a better sound :X
|
||||
surface.PlaySound( "npc/roller/mine/rmine_chirp_answer1.wav" )
|
||||
|
||||
end
|
||||
|
||||
function GM:HUDPaint()
|
||||
|
||||
self:PaintWorldTips()
|
||||
|
||||
-- Draw all of the default stuff
|
||||
BaseClass.HUDPaint( self )
|
||||
|
||||
self:PaintNotes()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Draws on top of VGUI..
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PostRenderVGUI()
|
||||
|
||||
BaseClass.PostRenderVGUI( self )
|
||||
|
||||
end
|
||||
|
||||
local PhysgunHalos = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:DrawPhysgunBeam()
|
||||
Desc: Return false to override completely
|
||||
-----------------------------------------------------------]]
|
||||
function GM:DrawPhysgunBeam( ply, weapon, bOn, target, boneid, pos )
|
||||
|
||||
if ( physgun_halo:GetInt() == 0 ) then return true end
|
||||
|
||||
if ( IsValid( target ) ) then
|
||||
PhysgunHalos[ ply ] = target
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PreDrawHalos", "AddPhysgunHalos", function()
|
||||
|
||||
if ( !PhysgunHalos || table.IsEmpty( PhysgunHalos ) ) then return end
|
||||
|
||||
for k, v in pairs( PhysgunHalos ) do
|
||||
|
||||
if ( !IsValid( k ) ) then continue end
|
||||
|
||||
local size = math.random( 1, 2 )
|
||||
local colr = k:GetWeaponColor() + VectorRand() * 0.3
|
||||
|
||||
halo.Add( PhysgunHalos, Color( colr.x * 255, colr.y * 255, colr.z * 255 ), size, size, 1, true, false )
|
||||
|
||||
end
|
||||
|
||||
PhysgunHalos = {}
|
||||
|
||||
end )
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:NetworkEntityCreated()
|
||||
Desc: Entity is created over the network
|
||||
-----------------------------------------------------------]]
|
||||
function GM:NetworkEntityCreated( ent )
|
||||
|
||||
--
|
||||
-- If the entity wants to use a spawn effect
|
||||
-- then create a propspawn effect if the entity was
|
||||
-- created within the last second (this function gets called
|
||||
-- on every entity when joining a server)
|
||||
--
|
||||
|
||||
if ( ent:GetSpawnEffect() && ent:GetCreationTime() > ( CurTime() - 1.0 ) ) then
|
||||
|
||||
local ed = EffectData()
|
||||
ed:SetOrigin( ent:GetPos() )
|
||||
ed:SetEntity( ent )
|
||||
util.Effect( "propspawn", ed, true, true )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
19
gamemodes/sandbox/gamemode/cl_notice.lua
Normal file
19
gamemodes/sandbox/gamemode/cl_notice.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function GM:AddNotify( str, type, length )
|
||||
|
||||
notification.AddLegacy( str, type, length )
|
||||
|
||||
end
|
||||
|
||||
function GM:PaintNotes()
|
||||
end
|
||||
174
gamemodes/sandbox/gamemode/cl_search_models.lua
Normal file
174
gamemodes/sandbox/gamemode/cl_search_models.lua
Normal file
@@ -0,0 +1,174 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local sbox_search_maxresults = CreateClientConVar( "sbox_search_maxresults", "1024", true, false, "The maximum amount of results the spawnmenu search should show. Model amount limited to 1/2 of this value, entities are limited to 1/4", 1024 )
|
||||
|
||||
local totalCalls = 0
|
||||
local expectedCalls = 1
|
||||
|
||||
local queuedSearch = {}
|
||||
|
||||
local function GetAllFiles( tab, folder, extension, path )
|
||||
|
||||
totalCalls = totalCalls + 1
|
||||
|
||||
local files, folders = file.Find( folder .. "*", path )
|
||||
|
||||
if ( !files ) then
|
||||
MsgN( "Warning! Ignoring '" .. folder .. "' because we cannot search in it!" )
|
||||
return
|
||||
end
|
||||
|
||||
for k, v in ipairs( files ) do
|
||||
|
||||
if ( v:EndsWith( extension ) ) then
|
||||
table.insert( tab, ( folder .. v ):lower() )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for k, v in ipairs( folders ) do
|
||||
expectedCalls = expectedCalls + 1
|
||||
table.insert( queuedSearch, { tab, folder .. v .. "/", extension, path } )
|
||||
end
|
||||
|
||||
notification.AddProgress( "SandboxSearchIndexing", "#spawnmenu.searchindex", totalCalls / expectedCalls )
|
||||
if ( totalCalls >= expectedCalls ) then notification.Kill( "SandboxSearchIndexing" ) end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "Think", "sandbox_queued_search", function()
|
||||
|
||||
if ( #queuedSearch < 1 ) then return end
|
||||
|
||||
local call = queuedSearch[ 1 ]
|
||||
GetAllFiles( unpack( call ) )
|
||||
table.remove( queuedSearch, 1 )
|
||||
|
||||
if ( !timer.Exists( "search_models_update" ) || #queuedSearch < 1 ) then
|
||||
timer.Create( "search_models_update", 1, 1, function() hook.Run( "SearchUpdate" ) end )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--
|
||||
-- Model Search
|
||||
--
|
||||
local model_list = nil
|
||||
search.AddProvider( function( str )
|
||||
|
||||
if ( model_list == nil ) then
|
||||
|
||||
model_list = {}
|
||||
GetAllFiles( model_list, "models/", ".mdl", "GAME" )
|
||||
|
||||
end
|
||||
|
||||
local models = {}
|
||||
|
||||
for k, v in ipairs( model_list ) do
|
||||
|
||||
-- Don't search in the models/ and .mdl bit of every model, because every model has this bit, unless they are looking for direct model path
|
||||
local modelpath = v
|
||||
if ( modelpath:StartsWith( "models/" ) && modelpath:EndsWith( ".mdl" ) && !str:EndsWith( ".mdl" ) ) then modelpath = modelpath:sub( 8, modelpath:len() - 4 ) end
|
||||
|
||||
if ( modelpath:find( str, nil, true ) ) then
|
||||
|
||||
if ( IsUselessModel( v ) ) then continue end
|
||||
|
||||
local entry = {
|
||||
text = v:GetFileFromFilename(),
|
||||
func = function() RunConsoleCommand( "gm_spawn", v ) end,
|
||||
icon = spawnmenu.CreateContentIcon( "model", g_SpawnMenu.SearchPropPanel, { model = v } ),
|
||||
words = { v }
|
||||
}
|
||||
|
||||
table.insert( models, entry )
|
||||
|
||||
end
|
||||
|
||||
if ( #models >= sbox_search_maxresults:GetInt() / 2 ) then break end
|
||||
|
||||
end
|
||||
|
||||
return models
|
||||
|
||||
end, "props" )
|
||||
|
||||
hook.Add( "GameContentChanged", "ResetModelSearchCache", function()
|
||||
|
||||
-- Addons got remounted, reset the model search cache
|
||||
model_list = nil
|
||||
|
||||
-- Reset any ongoing search process
|
||||
totalCalls = 0
|
||||
expectedCalls = 1
|
||||
queuedSearch = {}
|
||||
|
||||
end )
|
||||
|
||||
|
||||
--
|
||||
-- Entity, vehicles
|
||||
--
|
||||
local function AddSearchProvider( listname, ctype, stype )
|
||||
search.AddProvider( function( str )
|
||||
|
||||
local results = {}
|
||||
local entities = {}
|
||||
|
||||
for k, v in pairs( list.Get( listname ) ) do
|
||||
if ( listname == "Weapon" && !v.Spawnable ) then continue end
|
||||
|
||||
v.ClassName = k
|
||||
v.PrintName = v.PrintName or v.Name
|
||||
v.ScriptedEntityType = ctype
|
||||
table.insert( entities, v )
|
||||
end
|
||||
|
||||
for k, v in ipairs( entities ) do
|
||||
|
||||
local name = v.PrintName
|
||||
local name_c = v.ClassName
|
||||
if ( !isstring( name ) && !isstring( name_c ) ) then continue end
|
||||
|
||||
if ( ( isstring( name ) && name:lower():find( str, nil, true ) ) || ( isstring( name_c ) && name_c:lower():find( str, nil, true ) ) ) then
|
||||
|
||||
local entry = {
|
||||
text = v.PrintName or v.ClassName,
|
||||
icon = spawnmenu.CreateContentIcon( v.ScriptedEntityType or "entity", nil, {
|
||||
nicename = v.PrintName or v.ClassName,
|
||||
spawnname = v.ClassName,
|
||||
material = "entities/" .. v.ClassName .. ".png",
|
||||
|
||||
admin = v.AdminOnly
|
||||
} ),
|
||||
words = { v }
|
||||
}
|
||||
|
||||
table.insert( results, entry )
|
||||
|
||||
end
|
||||
|
||||
if ( #results >= sbox_search_maxresults:GetInt() / 4 ) then break end
|
||||
|
||||
end
|
||||
|
||||
table.SortByMember( results, "text", true )
|
||||
return results
|
||||
|
||||
end, stype )
|
||||
end
|
||||
|
||||
AddSearchProvider( "SpawnableEntities", "entity", "entities" )
|
||||
AddSearchProvider( "Vehicles", "vehicle", "vehicles" )
|
||||
AddSearchProvider( "NPC", "npc", "npcs" )
|
||||
AddSearchProvider( "Weapon", "weapon", "weapons" )
|
||||
146
gamemodes/sandbox/gamemode/cl_spawnmenu.lua
Normal file
146
gamemodes/sandbox/gamemode/cl_spawnmenu.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "spawnmenu/spawnmenu.lua" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
If false is returned then the spawn menu is never created.
|
||||
This saves load times if your mod doesn't actually use the
|
||||
spawn menu for any reason.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:SpawnMenuEnabled()
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called when spawnmenu is trying to be opened.
|
||||
Return false to dissallow it.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:SpawnMenuOpen()
|
||||
return true
|
||||
end
|
||||
|
||||
function GM:SpawnMenuOpened()
|
||||
self:SuppressHint( "OpeningMenu" )
|
||||
self:AddHint( "OpeningContext", 20 )
|
||||
self:AddHint( "EditingSpawnlists", 5 )
|
||||
end
|
||||
|
||||
function GM:SpawnMenuClosed()
|
||||
end
|
||||
|
||||
function GM:SpawnMenuCreated(spawnmenu)
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
If false is returned then the context menu is never created.
|
||||
This saves load times if your mod doesn't actually use the
|
||||
context menu for any reason.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:ContextMenuEnabled()
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called when context menu is trying to be opened.
|
||||
Return false to dissallow it.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:ContextMenuOpen()
|
||||
return true
|
||||
end
|
||||
|
||||
function GM:ContextMenuOpened()
|
||||
self:SuppressHint( "OpeningContext" )
|
||||
self:AddHint( "ContextClick", 20 )
|
||||
end
|
||||
|
||||
function GM:ContextMenuClosed()
|
||||
end
|
||||
|
||||
function GM:ContextMenuCreated()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Backwards compatibility. Do Not Use!!!
|
||||
-----------------------------------------------------------]]
|
||||
function GM:GetSpawnmenuTools( name )
|
||||
return spawnmenu.GetToolMenu( name )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Backwards compatibility. Do Not Use!!!
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddSTOOL( category, itemname, text, command, controls, cpanelfunction )
|
||||
self:AddToolMenuOption( "Main", category, itemname, text, command, controls, cpanelfunction )
|
||||
end
|
||||
|
||||
function GM:PreReloadToolsMenu()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Don't hook or override this function.
|
||||
Hook AddToolMenuTabs instead!
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddGamemodeToolMenuTabs()
|
||||
|
||||
-- This is named like this to force it to be the first tab
|
||||
spawnmenu.AddToolTab( "Main", "#spawnmenu.tools_tab", "icon16/wrench.png" )
|
||||
spawnmenu.AddToolTab( "Utilities", "#spawnmenu.utilities_tab", "icon16/page_white_wrench.png" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add your custom tabs here.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddToolMenuTabs()
|
||||
|
||||
-- Hook me!
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add categories to your tabs
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddGamemodeToolMenuCategories()
|
||||
|
||||
spawnmenu.AddToolCategory( "Main", "Constraints", "#spawnmenu.tools.constraints" )
|
||||
spawnmenu.AddToolCategory( "Main", "Construction", "#spawnmenu.tools.construction" )
|
||||
spawnmenu.AddToolCategory( "Main", "Poser", "#spawnmenu.tools.posing" )
|
||||
spawnmenu.AddToolCategory( "Main", "Render", "#spawnmenu.tools.render" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add categories to your tabs
|
||||
-----------------------------------------------------------]]
|
||||
function GM:AddToolMenuCategories()
|
||||
|
||||
-- Hook this function to add custom stuff
|
||||
|
||||
end
|
||||
|
||||
function GM:PopulateToolMenu()
|
||||
end
|
||||
|
||||
function GM:PostReloadToolsMenu()
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add categories to your tabs
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PopulatePropMenu()
|
||||
|
||||
-- This function makes the engine load the spawn menu text files.
|
||||
-- We call it here so that any gamemodes not using the default
|
||||
-- spawn menu can totally not call it.
|
||||
spawnmenu.PopulateFromEngineTextFiles()
|
||||
|
||||
end
|
||||
103
gamemodes/sandbox/gamemode/cl_worldtips.lua
Normal file
103
gamemodes/sandbox/gamemode/cl_worldtips.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
surface.CreateFont( "GModWorldtip",
|
||||
{
|
||||
font = "Helvetica",
|
||||
size = 20,
|
||||
weight = 700
|
||||
})
|
||||
|
||||
local cl_drawworldtooltips = CreateConVar( "cl_drawworldtooltips", "1", { FCVAR_ARCHIVE }, "Whether tooltips should draw when looking at certain Sandbox entities." )
|
||||
local WorldTip = nil
|
||||
|
||||
local TipColor = Color( 250, 250, 200, 255 )
|
||||
|
||||
--
|
||||
-- Adds a hint to the queue
|
||||
--
|
||||
function AddWorldTip( unused1, text, unused2, pos, ent )
|
||||
|
||||
WorldTip = {}
|
||||
|
||||
WorldTip.dietime = SysTime() + 0.05
|
||||
WorldTip.text = text
|
||||
WorldTip.pos = pos
|
||||
WorldTip.ent = ent
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function DrawWorldTip( tip )
|
||||
|
||||
if ( IsValid( tip.ent ) ) then
|
||||
tip.pos = tip.ent:GetPos()
|
||||
end
|
||||
|
||||
local pos = tip.pos:ToScreen()
|
||||
|
||||
local black = Color( 0, 0, 0, 255 )
|
||||
local tipcol = Color( TipColor.r, TipColor.g, TipColor.b, 255 )
|
||||
|
||||
local x = 0
|
||||
local y = 0
|
||||
local padding = 10
|
||||
local offset = 50
|
||||
|
||||
surface.SetFont( "GModWorldtip" )
|
||||
local w, h = surface.GetTextSize( tip.text )
|
||||
|
||||
x = pos.x - w
|
||||
y = pos.y - h
|
||||
|
||||
x = x - offset
|
||||
y = y - offset
|
||||
|
||||
draw.RoundedBox( 8, x-padding-2, y-padding-2, w+padding*2+4, h+padding*2+4, black )
|
||||
|
||||
|
||||
local verts = {}
|
||||
verts[1] = { x=x+w/1.5-2, y=y+h+2 }
|
||||
verts[2] = { x=x+w+2, y=y+h/2-1 }
|
||||
verts[3] = { x=pos.x-offset/2+2, y=pos.y-offset/2+2 }
|
||||
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor( 0, 0, 0, tipcol.a )
|
||||
surface.DrawPoly( verts )
|
||||
|
||||
|
||||
draw.RoundedBox( 8, x-padding, y-padding, w+padding*2, h+padding*2, tipcol )
|
||||
|
||||
local verts = {}
|
||||
verts[1] = { x=x+w/1.5, y=y+h }
|
||||
verts[2] = { x=x+w, y=y+h/2 }
|
||||
verts[3] = { x=pos.x-offset/2, y=pos.y-offset/2 }
|
||||
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor( tipcol.r, tipcol.g, tipcol.b, tipcol.a )
|
||||
surface.DrawPoly( verts )
|
||||
|
||||
|
||||
draw.DrawText( tip.text, "GModWorldtip", x + w/2, y, black, TEXT_ALIGN_CENTER )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function GM:PaintWorldTips()
|
||||
|
||||
if ( !cl_drawworldtooltips:GetBool() ) then return end
|
||||
|
||||
if ( WorldTip && WorldTip.dietime > SysTime() ) then
|
||||
DrawWorldTip( WorldTip )
|
||||
end
|
||||
|
||||
end
|
||||
1122
gamemodes/sandbox/gamemode/commands.lua
Normal file
1122
gamemodes/sandbox/gamemode/commands.lua
Normal file
File diff suppressed because it is too large
Load Diff
307
gamemodes/sandbox/gamemode/editor_player.lua
Normal file
307
gamemodes/sandbox/gamemode/editor_player.lua
Normal file
@@ -0,0 +1,307 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
local default_animations = { "idle_all_01", "menu_walk" }
|
||||
|
||||
list.Set( "DesktopWindows", "PlayerEditor", {
|
||||
|
||||
title = "#smwidget.playermodel",
|
||||
icon = "icon64/playermodel.png",
|
||||
width = 960,
|
||||
height = 700,
|
||||
onewindow = true,
|
||||
init = function( icon, window )
|
||||
|
||||
window:SetTitle( "#smwidget.playermodel_title" )
|
||||
window:SetSize( math.min( ScrW() - 16, window:GetWide() ), math.min( ScrH() - 16, window:GetTall() ) )
|
||||
window:SetSizable( true )
|
||||
window:SetMinWidth( window:GetWide() )
|
||||
window:SetMinHeight( window:GetTall() )
|
||||
window:Center()
|
||||
|
||||
local mdl = window:Add( "DModelPanel" )
|
||||
mdl:Dock( FILL )
|
||||
mdl:SetFOV( 36 )
|
||||
mdl:SetCamPos( vector_origin )
|
||||
mdl:SetDirectionalLight( BOX_RIGHT, Color( 255, 160, 80, 255 ) )
|
||||
mdl:SetDirectionalLight( BOX_LEFT, Color( 80, 160, 255, 255 ) )
|
||||
mdl:SetAmbientLight( Vector( -64, -64, -64 ) )
|
||||
mdl:SetAnimated( true )
|
||||
mdl.Angles = angle_zero
|
||||
mdl:SetLookAt( Vector( -100, 0, -22 ) )
|
||||
|
||||
local sheet = window:Add( "DPropertySheet" )
|
||||
sheet:Dock( RIGHT )
|
||||
sheet:SetSize( 430, 0 )
|
||||
|
||||
local modelListPnl = window:Add( "DPanel" )
|
||||
modelListPnl:DockPadding( 8, 8, 8, 8 )
|
||||
|
||||
local SearchBar = modelListPnl:Add( "DTextEntry" )
|
||||
SearchBar:Dock( TOP )
|
||||
SearchBar:DockMargin( 0, 0, 0, 8 )
|
||||
SearchBar:SetUpdateOnType( true )
|
||||
SearchBar:SetPlaceholderText( "#spawnmenu.quick_filter" )
|
||||
|
||||
local PanelSelect = modelListPnl:Add( "DPanelSelect" )
|
||||
PanelSelect:Dock( FILL )
|
||||
|
||||
for name, model in SortedPairs( player_manager.AllValidModels() ) do
|
||||
|
||||
local icon = vgui.Create( "SpawnIcon" )
|
||||
icon:SetModel( model )
|
||||
icon:SetSize( 64, 64 )
|
||||
icon:SetTooltip( name )
|
||||
icon.playermodel = name
|
||||
icon.model_path = model
|
||||
icon.OpenMenu = function( button )
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.copy", function() SetClipboardText( model ) end ):SetIcon( "icon16/page_copy.png" )
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
PanelSelect:AddPanel( icon, { cl_playermodel = name } )
|
||||
|
||||
end
|
||||
|
||||
SearchBar.OnValueChange = function( s, str )
|
||||
for id, pnl in pairs( PanelSelect:GetItems() ) do
|
||||
if ( !pnl.playermodel:find( str, 1, true ) && !pnl.model_path:find( str, 1, true ) ) then
|
||||
pnl:SetVisible( false )
|
||||
else
|
||||
pnl:SetVisible( true )
|
||||
end
|
||||
end
|
||||
PanelSelect:InvalidateLayout()
|
||||
end
|
||||
|
||||
sheet:AddSheet( "#smwidget.model", modelListPnl, "icon16/user.png" )
|
||||
|
||||
local controls = window:Add( "DPanel" )
|
||||
controls:DockPadding( 8, 8, 8, 8 )
|
||||
|
||||
local lbl = controls:Add( "DLabel" )
|
||||
lbl:SetText( "#smwidget.color_plr" )
|
||||
lbl:SetTextColor( Color( 0, 0, 0, 255 ) )
|
||||
lbl:Dock( TOP )
|
||||
|
||||
local plycol = controls:Add( "DColorMixer" )
|
||||
plycol:SetAlphaBar( false )
|
||||
plycol:SetPalette( false )
|
||||
plycol:Dock( TOP )
|
||||
plycol:SetSize( 200, math.min( window:GetTall() / 3, 260 ) )
|
||||
|
||||
local lbl = controls:Add( "DLabel" )
|
||||
lbl:SetText( "#smwidget.color_wep" )
|
||||
lbl:SetTextColor( Color( 0, 0, 0, 255 ) )
|
||||
lbl:DockMargin( 0, 32, 0, 0 )
|
||||
lbl:Dock( TOP )
|
||||
|
||||
local wepcol = controls:Add( "DColorMixer" )
|
||||
wepcol:SetAlphaBar( false )
|
||||
wepcol:SetPalette( false )
|
||||
wepcol:Dock( TOP )
|
||||
wepcol:SetSize( 200, math.min( window:GetTall() / 3, 260 ) )
|
||||
wepcol:SetVector( Vector( GetConVarString( "cl_weaponcolor" ) ) )
|
||||
|
||||
sheet:AddSheet( "#smwidget.colors", controls, "icon16/color_wheel.png" )
|
||||
|
||||
local bdcontrols = window:Add( "DPanel" )
|
||||
bdcontrols:DockPadding( 8, 8, 8, 8 )
|
||||
|
||||
local bdcontrolspanel = bdcontrols:Add( "DPanelList" )
|
||||
bdcontrolspanel:EnableVerticalScrollbar()
|
||||
bdcontrolspanel:Dock( FILL )
|
||||
|
||||
local bgtab = sheet:AddSheet( "#smwidget.bodygroups", bdcontrols, "icon16/cog.png" )
|
||||
|
||||
-- Helper functions
|
||||
local function PlayPreviewAnimation( panel, playermodel )
|
||||
|
||||
if ( !panel or !IsValid( panel.Entity ) ) then return end
|
||||
|
||||
local anims = list.Get( "PlayerOptionsAnimations" )
|
||||
|
||||
local anim = default_animations[ math.random( 1, #default_animations ) ]
|
||||
if ( anims[ playermodel ] ) then
|
||||
anims = anims[ playermodel ]
|
||||
anim = anims[ math.random( 1, #anims ) ]
|
||||
end
|
||||
|
||||
local iSeq = panel.Entity:LookupSequence( anim )
|
||||
if ( iSeq > 0 ) then panel.Entity:ResetSequence( iSeq ) end
|
||||
|
||||
end
|
||||
|
||||
-- Updating
|
||||
local function UpdateBodyGroups( pnl, val )
|
||||
if ( pnl.type == "bgroup" ) then
|
||||
|
||||
mdl.Entity:SetBodygroup( pnl.typenum, math.Round( val ) )
|
||||
|
||||
local str = string.Explode( " ", GetConVarString( "cl_playerbodygroups" ) )
|
||||
if ( #str < pnl.typenum + 1 ) then for i = 1, pnl.typenum + 1 do str[ i ] = str[ i ] or 0 end end
|
||||
str[ pnl.typenum + 1 ] = math.Round( val )
|
||||
RunConsoleCommand( "cl_playerbodygroups", table.concat( str, " " ) )
|
||||
|
||||
elseif ( pnl.type == "skin" ) then
|
||||
|
||||
mdl.Entity:SetSkin( math.Round( val ) )
|
||||
RunConsoleCommand( "cl_playerskin", math.Round( val ) )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
local function RebuildBodygroupTab()
|
||||
bdcontrolspanel:Clear()
|
||||
|
||||
bgtab.Tab:SetVisible( false )
|
||||
|
||||
local nskins = mdl.Entity:SkinCount() - 1
|
||||
if ( nskins > 0 ) then
|
||||
local skins = vgui.Create( "DNumSlider" )
|
||||
skins:Dock( TOP )
|
||||
skins:SetText( "Skin" )
|
||||
skins:SetDark( true )
|
||||
skins:SetTall( 50 )
|
||||
skins:SetDecimals( 0 )
|
||||
skins:SetMax( nskins )
|
||||
skins:SetValue( GetConVarNumber( "cl_playerskin" ) )
|
||||
skins.type = "skin"
|
||||
skins.OnValueChanged = UpdateBodyGroups
|
||||
|
||||
bdcontrolspanel:AddItem( skins )
|
||||
|
||||
mdl.Entity:SetSkin( GetConVarNumber( "cl_playerskin" ) )
|
||||
|
||||
bgtab.Tab:SetVisible( true )
|
||||
end
|
||||
|
||||
local groups = string.Explode( " ", GetConVarString( "cl_playerbodygroups" ) )
|
||||
for k = 0, mdl.Entity:GetNumBodyGroups() - 1 do
|
||||
if ( mdl.Entity:GetBodygroupCount( k ) <= 1 ) then continue end
|
||||
|
||||
local bgroup = vgui.Create( "DNumSlider" )
|
||||
bgroup:Dock( TOP )
|
||||
bgroup:SetText( string.NiceName( mdl.Entity:GetBodygroupName( k ) ) )
|
||||
bgroup:SetDark( true )
|
||||
bgroup:SetTall( 50 )
|
||||
bgroup:SetDecimals( 0 )
|
||||
bgroup.type = "bgroup"
|
||||
bgroup.typenum = k
|
||||
bgroup:SetMax( mdl.Entity:GetBodygroupCount( k ) - 1 )
|
||||
bgroup:SetValue( groups[ k + 1 ] or 0 )
|
||||
bgroup.OnValueChanged = UpdateBodyGroups
|
||||
|
||||
bdcontrolspanel:AddItem( bgroup )
|
||||
|
||||
mdl.Entity:SetBodygroup( k, groups[ k + 1 ] or 0 )
|
||||
|
||||
bgtab.Tab:SetVisible( true )
|
||||
end
|
||||
|
||||
sheet.tabScroller:InvalidateLayout()
|
||||
end
|
||||
|
||||
local function UpdateFromConvars()
|
||||
|
||||
local model = LocalPlayer():GetInfo( "cl_playermodel" )
|
||||
local modelname = player_manager.TranslatePlayerModel( model )
|
||||
util.PrecacheModel( modelname )
|
||||
mdl:SetModel( modelname )
|
||||
mdl.Entity.GetPlayerColor = function() return Vector( GetConVarString( "cl_playercolor" ) ) end
|
||||
mdl.Entity:SetPos( Vector( -100, 0, -61 ) )
|
||||
|
||||
plycol:SetVector( Vector( GetConVarString( "cl_playercolor" ) ) )
|
||||
wepcol:SetVector( Vector( GetConVarString( "cl_weaponcolor" ) ) )
|
||||
|
||||
PlayPreviewAnimation( mdl, model )
|
||||
RebuildBodygroupTab()
|
||||
|
||||
end
|
||||
|
||||
local function UpdateFromControls()
|
||||
|
||||
RunConsoleCommand( "cl_playercolor", tostring( plycol:GetVector() ) )
|
||||
RunConsoleCommand( "cl_weaponcolor", tostring( wepcol:GetVector() ) )
|
||||
|
||||
end
|
||||
|
||||
plycol.ValueChanged = UpdateFromControls
|
||||
wepcol.ValueChanged = UpdateFromControls
|
||||
|
||||
UpdateFromConvars()
|
||||
|
||||
function PanelSelect:OnActivePanelChanged( old, new )
|
||||
|
||||
if ( old != new ) then -- Only reset if we changed the model
|
||||
RunConsoleCommand( "cl_playerbodygroups", "0" )
|
||||
RunConsoleCommand( "cl_playerskin", "0" )
|
||||
end
|
||||
|
||||
timer.Simple( 0.1, function() UpdateFromConvars() end )
|
||||
|
||||
end
|
||||
|
||||
-- Hold to rotate
|
||||
|
||||
function mdl:DragMousePress()
|
||||
self.PressX, self.PressY = input.GetCursorPos()
|
||||
self.Pressed = true
|
||||
end
|
||||
|
||||
function mdl:DragMouseRelease() self.Pressed = false end
|
||||
|
||||
function mdl:LayoutEntity( ent )
|
||||
if ( self.bAnimated ) then self:RunAnimation() end
|
||||
|
||||
if ( self.Pressed ) then
|
||||
local mx, my = input.GetCursorPos()
|
||||
self.Angles = self.Angles - Angle( 0, ( ( self.PressX or mx ) - mx ) / 2, 0 )
|
||||
|
||||
self.PressX, self.PressY = mx, my
|
||||
end
|
||||
|
||||
ent:SetAngles( self.Angles )
|
||||
end
|
||||
|
||||
end
|
||||
} )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "gman", { "menu_gman" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "hostage01", { "idle_all_scared" } )
|
||||
list.Set( "PlayerOptionsAnimations", "hostage02", { "idle_all_scared" } )
|
||||
list.Set( "PlayerOptionsAnimations", "hostage03", { "idle_all_scared" } )
|
||||
list.Set( "PlayerOptionsAnimations", "hostage04", { "idle_all_scared" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "zombine", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "corpse", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "zombiefast", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "zombie", { "menu_zombie_01" } )
|
||||
list.Set( "PlayerOptionsAnimations", "skeleton", { "menu_zombie_01" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "combine", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "combineprison", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "combineelite", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "police", { "menu_combine" } )
|
||||
list.Set( "PlayerOptionsAnimations", "policefem", { "menu_combine" } )
|
||||
|
||||
list.Set( "PlayerOptionsAnimations", "css_arctic", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_gasmask", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_guerilla", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_leet", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_phoenix", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_riot", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_swat", { "pose_standing_02", "idle_fist" } )
|
||||
list.Set( "PlayerOptionsAnimations", "css_urban", { "pose_standing_02", "idle_fist" } )
|
||||
654
gamemodes/sandbox/gamemode/gui/iconeditor.lua
Normal file
654
gamemodes/sandbox/gamemode/gui/iconeditor.lua
Normal file
@@ -0,0 +1,654 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_strModel", "Model" )
|
||||
AccessorFunc( PANEL, "m_pOrigin", "Origin" )
|
||||
AccessorFunc( PANEL, "m_bCustomIcon", "CustomIcon" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetSize( 762, 502 )
|
||||
self:SetTitle( "#smwidget.icon_editor" )
|
||||
|
||||
local left = self:Add( "Panel" )
|
||||
left:Dock( LEFT )
|
||||
left:SetWide( 400 )
|
||||
self.LeftPanel = left
|
||||
|
||||
local bg = left:Add( "DPanel" )
|
||||
bg:Dock( FILL )
|
||||
bg:DockMargin( 0, 0, 0, 4 )
|
||||
bg.Paint = function( s, w, h ) draw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 128 ) ) end
|
||||
|
||||
self.SpawnIcon = bg:Add( "SpawnIcon" )
|
||||
--self.SpawnIcon.DoClick = function() self:RenderIcon() end
|
||||
|
||||
self.ModelPanel = bg:Add( "DAdjustableModelPanel" )
|
||||
self.ModelPanel:Dock( FILL )
|
||||
self.ModelPanel.FarZ = 32768
|
||||
|
||||
local mat_wireframe = Material( "models/wireframe" )
|
||||
function self.ModelPanel.PostDrawModel( mdlpnl, ent )
|
||||
if ( self.ShowOriginPnl:GetChecked() ) then
|
||||
render.DrawLine( vector_origin, Vector( 0, 0, 100 ), Color( 0, 0, 255 ) )
|
||||
render.DrawLine( vector_origin, Vector( 0, 100, 0 ), Color( 0, 255, 0 ) )
|
||||
render.DrawLine( vector_origin, Vector( 100, 0, 0 ), Color( 255, 0, 0 ) )
|
||||
end
|
||||
|
||||
if ( self.ShowBBoxPnl:GetChecked() ) then
|
||||
local mins, maxs = ent:GetRenderBounds()
|
||||
local scale = 1
|
||||
mat_wireframe:SetVector( "$color", Vector( 1, 1, 1 ) )
|
||||
render.SetMaterial( mat_wireframe )
|
||||
|
||||
render.DrawBox( ent:GetPos(), ent:GetAngles(), mins * scale, maxs * scale )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local controls = left:Add( "Panel" )
|
||||
controls:SetTall( 64 )
|
||||
controls:Dock( BOTTOM )
|
||||
|
||||
local controls_anim = controls:Add( "Panel" )
|
||||
controls_anim:SetTall( 20 )
|
||||
controls_anim:Dock( TOP )
|
||||
controls_anim:DockMargin( 0, 0, 0, 4 )
|
||||
controls_anim:MoveToBack()
|
||||
|
||||
self.AnimTrack = controls_anim:Add( "DSlider" )
|
||||
self.AnimTrack:Dock( FILL )
|
||||
self.AnimTrack:SetNotches( 100 )
|
||||
self.AnimTrack:SetTrapInside( true )
|
||||
self.AnimTrack:SetLockY( 0.5 )
|
||||
|
||||
self.AnimPause = controls_anim:Add( "DImageButton" )
|
||||
self.AnimPause:SetImage( "icon16/control_pause_blue.png" )
|
||||
self.AnimPause:SetStretchToFit( false )
|
||||
self.AnimPause:SetPaintBackground( true )
|
||||
self.AnimPause:SetIsToggle( true )
|
||||
self.AnimPause:SetToggle( false )
|
||||
self.AnimPause:Dock( LEFT )
|
||||
self.AnimPause:SetWide( 32 )
|
||||
|
||||
local BestGuess = controls:Add( "DImageButton" )
|
||||
BestGuess:SetImage( "icon32/wand.png" )
|
||||
BestGuess:SetStretchToFit( false )
|
||||
BestGuess:SetPaintBackground( true )
|
||||
BestGuess.DoClick = function() self:BestGuessLayout() end
|
||||
BestGuess:Dock( LEFT )
|
||||
BestGuess:DockMargin( 0, 0, 0, 0 )
|
||||
BestGuess:SetWide( 50 )
|
||||
BestGuess:SetTooltip( "Best Guess" )
|
||||
|
||||
local FullFrontal = controls:Add( "DImageButton" )
|
||||
FullFrontal:SetImage( "icon32/hand_point_090.png" )
|
||||
FullFrontal:SetStretchToFit( false )
|
||||
FullFrontal:SetPaintBackground( true )
|
||||
FullFrontal.DoClick = function() self:FullFrontalLayout() end
|
||||
FullFrontal:Dock( LEFT )
|
||||
FullFrontal:DockMargin( 2, 0, 0, 0 )
|
||||
FullFrontal:SetWide( 50 )
|
||||
FullFrontal:SetTooltip( "Front" )
|
||||
|
||||
local Above = controls:Add( "DImageButton" )
|
||||
Above:SetImage( "icon32/hand_property.png" )
|
||||
Above:SetStretchToFit( false )
|
||||
Above:SetPaintBackground( true )
|
||||
Above.DoClick = function() self:AboveLayout() end
|
||||
Above:Dock( LEFT )
|
||||
Above:DockMargin( 2, 0, 0, 0 )
|
||||
Above:SetWide( 50 )
|
||||
Above:SetTooltip( "Above" )
|
||||
|
||||
local Right = controls:Add( "DImageButton" )
|
||||
Right:SetImage( "icon32/hand_point_180.png" )
|
||||
Right:SetStretchToFit( false )
|
||||
Right:SetPaintBackground( true )
|
||||
Right.DoClick = function() self:RightLayout() end
|
||||
Right:Dock( LEFT )
|
||||
Right:DockMargin( 2, 0, 0, 0 )
|
||||
Right:SetWide( 50 )
|
||||
Right:SetTooltip( "Right" )
|
||||
|
||||
local Origin = controls:Add( "DImageButton" )
|
||||
Origin:SetImage( "icon32/hand_point_090.png" )
|
||||
Origin:SetStretchToFit( false )
|
||||
Origin:SetPaintBackground( true )
|
||||
Origin.DoClick = function() self:OriginLayout() end
|
||||
Origin:Dock( LEFT )
|
||||
Origin:DockMargin( 2, 0, 0, 0 )
|
||||
Origin:SetWide( 50 )
|
||||
Origin:SetTooltip( "Center" )
|
||||
|
||||
local Render = controls:Add( "DButton" )
|
||||
Render:SetText( "RENDER" )
|
||||
Render.DoClick = function() self:RenderIcon() end
|
||||
Render:Dock( RIGHT )
|
||||
Render:DockMargin( 2, 0, 0, 0 )
|
||||
Render:SetWide( 50 )
|
||||
Render:SetTooltip( "Render Icon" )
|
||||
|
||||
local Picker = controls:Add( "DImageButton" )
|
||||
Picker:SetImage( "icon32/color_picker.png" )
|
||||
Picker:SetStretchToFit( false )
|
||||
Picker:SetPaintBackground( true )
|
||||
Picker:Dock( RIGHT )
|
||||
Picker:DockMargin( 2, 0, 0, 0 )
|
||||
Picker:SetWide( 50 )
|
||||
Picker:SetTooltip( "Pick a new model from an entity" )
|
||||
Picker.DoClick = function()
|
||||
|
||||
self:SetVisible( false )
|
||||
|
||||
util.worldpicker.Start( function( tr )
|
||||
|
||||
self:SetVisible( true )
|
||||
|
||||
if ( !IsValid( tr.Entity ) ) then return end
|
||||
|
||||
self:SetFromEntity( tr.Entity )
|
||||
|
||||
end )
|
||||
end
|
||||
|
||||
local right = self:Add( "DPropertySheet" )
|
||||
right:Dock( FILL )
|
||||
right:SetPadding( 0 )
|
||||
right:DockMargin( 4, 0, 0, 0 )
|
||||
self.PropertySheet = right
|
||||
|
||||
-- Animations
|
||||
|
||||
local anims = right:Add( "Panel" )
|
||||
anims:Dock( FILL )
|
||||
anims:DockPadding( 2, 0, 2, 2 )
|
||||
right:AddSheet( "#smwidget.animations", anims, "icon16/monkey.png" )
|
||||
|
||||
self.AnimList = anims:Add( "DListView" )
|
||||
self.AnimList:AddColumn( "name" )
|
||||
self.AnimList:Dock( FILL )
|
||||
self.AnimList:SetMultiSelect( false )
|
||||
self.AnimList:SetHideHeaders( true )
|
||||
|
||||
-- Bodygroups
|
||||
|
||||
local pnl = right:Add( "Panel" )
|
||||
pnl:Dock( FILL )
|
||||
pnl:DockPadding( 7, 0, 7, 7 )
|
||||
|
||||
self.BodygroupTab = right:AddSheet( "#smwidget.bodygroups", pnl, "icon16/brick.png" )
|
||||
|
||||
self.BodyList = pnl:Add( "DScrollPanel" )
|
||||
self.BodyList:Dock( FILL )
|
||||
|
||||
--This kind of works but they don't move their stupid mouths. So fuck off.
|
||||
--[[
|
||||
self.Scenes = pnl:Add( "DTree" )
|
||||
self.Scenes:Dock( BOTTOM )
|
||||
self.Scenes:SetSize( 200, 200 )
|
||||
self.Scenes.DoClick = function( _, node )
|
||||
|
||||
if ( !node.FileName ) then return end
|
||||
local ext = string.GetExtensionFromFilename( node.FileName )
|
||||
if( ext != "vcd" ) then return end
|
||||
|
||||
self.ModelPanel:StartScene( node.FileName )
|
||||
MsgN( node.FileName )
|
||||
|
||||
end
|
||||
|
||||
local materials = self.Scenes.RootNode:AddFolder( "Scenes", "scenes/", true )
|
||||
materials:SetIcon( "icon16/photos.png" )--]]
|
||||
|
||||
-- Settings
|
||||
|
||||
local settings = right:Add( "Panel" )
|
||||
settings:Dock( FILL )
|
||||
settings:DockPadding( 7, 0, 7, 7 )
|
||||
right:AddSheet( "#smwidget.settings", settings, "icon16/cog.png" )
|
||||
|
||||
local bbox = settings:Add( "DCheckBoxLabel" )
|
||||
bbox:SetText( "Show Bounding Box" )
|
||||
bbox:Dock( TOP )
|
||||
bbox:DockMargin( 0, 0, 0, 3 )
|
||||
bbox:SetDark( true )
|
||||
bbox:SetCookieName( "model_editor_bbox" )
|
||||
self.ShowBBoxPnl = bbox
|
||||
|
||||
local origin = settings:Add( "DCheckBoxLabel" )
|
||||
origin:SetText( "Show Origin" )
|
||||
origin:Dock( TOP )
|
||||
origin:SetDark( true )
|
||||
origin:SetCookieName( "model_editor_origin" )
|
||||
self.ShowOriginPnl = origin
|
||||
|
||||
local playSpeed = settings:Add( "DNumSlider" )
|
||||
playSpeed:SetText( "Playback Speed" )
|
||||
playSpeed:Dock( TOP )
|
||||
playSpeed:SetValue( 1 )
|
||||
playSpeed:SetMinMax( -1, 2 )
|
||||
playSpeed:SetDark( true )
|
||||
playSpeed.OnValueChanged = function( s, value )
|
||||
self.ModelPanel:GetEntity():SetPlaybackRate( value )
|
||||
end
|
||||
|
||||
local moveSpeed = settings:Add( "DNumSlider" )
|
||||
moveSpeed:SetText( "Move Speed" )
|
||||
moveSpeed:Dock( TOP )
|
||||
moveSpeed:SetMinMax( 0.5, 8 )
|
||||
moveSpeed:SetValue( 1 )
|
||||
moveSpeed:SetDark( true )
|
||||
moveSpeed.OnValueChanged = function( p )
|
||||
self.ModelPanel:SetMovementScale( p:GetValue() )
|
||||
end
|
||||
moveSpeed:SetCookieName( "iconeditor_movespeed" )
|
||||
|
||||
local angle = settings:Add( "DTextEntry" )
|
||||
angle:SetTooltip( "Entity Angles" )
|
||||
angle:Dock( TOP )
|
||||
angle:DockMargin( 0, 0, 0, 3 )
|
||||
angle:SetZPos( 100 )
|
||||
angle.OnChange = function( p )
|
||||
self.ModelPanel:GetEntity():SetAngles( Angle( p:GetText() ) )
|
||||
end
|
||||
self.TargetAnglePanel = angle
|
||||
|
||||
local cam_angle = settings:Add( "DTextEntry" )
|
||||
cam_angle:SetTooltip( "Camera Angles" )
|
||||
cam_angle:Dock( TOP )
|
||||
cam_angle:DockMargin( 0, 0, 0, 3 )
|
||||
cam_angle:SetZPos( 101 )
|
||||
cam_angle.OnChange = function( p )
|
||||
self.ModelPanel:SetLookAng( Angle( p:GetText() ) )
|
||||
end
|
||||
self.TargetCamAnglePanel = cam_angle
|
||||
|
||||
local cam_pos = settings:Add( "DTextEntry" )
|
||||
cam_pos:SetTooltip( "Camera Position" )
|
||||
cam_pos:Dock( TOP )
|
||||
cam_pos:DockMargin( 0, 0, 0, 3 )
|
||||
cam_pos:SetZPos( 102 )
|
||||
cam_pos.OnChange = function( p )
|
||||
self.ModelPanel:SetCamPos( Vector( p:GetText() ) )
|
||||
end
|
||||
self.TargetCamPosPanel = cam_pos
|
||||
|
||||
local cam_fov = settings:Add( "DNumSlider" )
|
||||
cam_fov:SetText( "Camera FOV" )
|
||||
cam_fov:Dock( TOP )
|
||||
cam_fov:DockMargin( 0, 0, 0, 3 )
|
||||
cam_fov:SetZPos( 103 )
|
||||
cam_fov:SetMinMax( 0.001, 179 )
|
||||
cam_fov:SetDark( true )
|
||||
cam_fov.OnValueChanged = function( p )
|
||||
self.ModelPanel:SetFOV( p:GetValue() )
|
||||
end
|
||||
self.TargetCamFOVPanel = cam_fov
|
||||
|
||||
local copypaste_cam = settings:Add( "Panel" )
|
||||
copypaste_cam:SetTall( 20 )
|
||||
copypaste_cam:Dock( TOP )
|
||||
copypaste_cam:SetZPos( 104 )
|
||||
copypaste_cam:DockMargin( 0, 0, 0, 4 )
|
||||
|
||||
local copy = copypaste_cam:Add( "DButton" )
|
||||
copy:Dock( FILL )
|
||||
copy:SetText( "Copy Camera Settings" )
|
||||
copy:DockMargin( 0, 0, 3, 0 )
|
||||
copy.DoClick = function() SetClipboardText( util.TableToJSON( {
|
||||
pos = self.ModelPanel:GetCamPos(),
|
||||
ang = self.ModelPanel:GetLookAng(),
|
||||
fov = self.ModelPanel:GetFOV(),
|
||||
mdl_ang = self.ModelPanel:GetEntity():GetAngles()
|
||||
} ) ) end
|
||||
|
||||
local paste = copypaste_cam:Add( "DTextEntry" )
|
||||
paste:SetWide( 140 ) -- Ew
|
||||
paste:Dock( RIGHT )
|
||||
paste:SetPlaceholderText( "Paste Camera Settings Here" )
|
||||
paste.OnChange = function( p )
|
||||
local tabl = util.JSONToTable( p:GetText() )
|
||||
if ( tabl ) then
|
||||
self.ModelPanel:SetCamPos( tabl.pos )
|
||||
self.ModelPanel:SetLookAng( tabl.ang )
|
||||
self.ModelPanel:SetFOV( tabl.fov )
|
||||
self.ModelPanel:GetEntity():SetAngles( tabl.mdl_ang )
|
||||
end
|
||||
p:SetText( "" )
|
||||
end
|
||||
|
||||
local labels = { "Pitch", "Yaw", "Roll" }
|
||||
for i = 1, 3 do
|
||||
local rotate45 = settings:Add( "DButton" )
|
||||
rotate45:SetText( "Rotate Entity +/-45 " .. labels[ i ] )
|
||||
rotate45:Dock( TOP )
|
||||
rotate45:DockMargin( 0, 0, 0, 3 )
|
||||
rotate45:SetZPos( 110 + i )
|
||||
rotate45.DoClick = function( p )
|
||||
local aang = self.ModelPanel:GetEntity():GetAngles()
|
||||
aang[ i ] = aang[ i ] + 45
|
||||
self.ModelPanel:GetEntity():SetAngles( aang )
|
||||
end
|
||||
rotate45.DoRightClick = function( p )
|
||||
local aang = self.ModelPanel:GetEntity():GetAngles()
|
||||
aang[ i ] = aang[ i ] - 45
|
||||
self.ModelPanel:GetEntity():SetAngles( aang )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetDefaultLighting()
|
||||
|
||||
self.ModelPanel:SetAmbientLight( Color( 255 * 0.3, 255 * 0.3, 255 * 0.3 ) )
|
||||
|
||||
self.ModelPanel:SetDirectionalLight( BOX_FRONT, Color( 255 * 1.3, 255 * 1.3, 255 * 1.3 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_BACK, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_RIGHT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_LEFT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_TOP, Color( 255 * 2.3, 255 * 2.3, 255 * 2.3 ) )
|
||||
self.ModelPanel:SetDirectionalLight( BOX_BOTTOM, Color( 255 * 0.1, 255 * 0.1, 255 * 0.1 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:BestGuessLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local ang = ent:GetAngles()
|
||||
|
||||
local tab = PositionSpawnIcon( ent, pos, true )
|
||||
|
||||
ent:SetAngles( ang )
|
||||
if ( tab ) then
|
||||
self.ModelPanel:SetCamPos( tab.origin )
|
||||
self.ModelPanel:SetFOV( tab.fov )
|
||||
self.ModelPanel:SetLookAng( tab.angles )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FullFrontalLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + Vector( -200, 0, 0 )
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AboveLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + Vector( 0, 0, 200 )
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RightLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + Vector( 0, 200, 0 )
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OriginLayout()
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local pos = ent:GetPos()
|
||||
local campos = pos + vector_origin
|
||||
|
||||
self.ModelPanel:SetCamPos( campos )
|
||||
self.ModelPanel:SetFOV( 45 )
|
||||
self.ModelPanel:SetLookAng( Angle( 0, -180, 0 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateEntity( ent )
|
||||
|
||||
ent:SetEyeTarget( self.ModelPanel:GetCamPos() )
|
||||
|
||||
if ( IsValid( self.TargetAnglePanel ) && !self.TargetAnglePanel:IsEditing() && !self.TargetAnglePanel:IsHovered() ) then
|
||||
self.TargetAnglePanel:SetText( tostring( ent:GetAngles() ) )
|
||||
end
|
||||
if ( IsValid( self.TargetCamAnglePanel ) && !self.TargetCamAnglePanel:IsEditing() && !self.TargetCamAnglePanel:IsHovered() ) then
|
||||
self.TargetCamAnglePanel:SetText( tostring( self.ModelPanel:GetLookAng() ) )
|
||||
end
|
||||
if ( IsValid( self.TargetCamPosPanel ) && !self.TargetCamPosPanel:IsEditing() && !self.TargetCamPosPanel:IsHovered() ) then
|
||||
self.TargetCamPosPanel:SetText( tostring( self.ModelPanel:GetCamPos() ) )
|
||||
end
|
||||
if ( IsValid( self.TargetCamFOVPanel ) && !self.TargetCamFOVPanel:IsEditing() && !self.TargetCamFOVPanel:IsHovered() ) then
|
||||
self.TargetCamFOVPanel:SetValue( self.ModelPanel:GetFOV() )
|
||||
end
|
||||
|
||||
if ( self.AnimTrack:GetDragging() ) then
|
||||
|
||||
ent:SetCycle( self.AnimTrack:GetSlideX() )
|
||||
self.AnimPause:SetToggle( true )
|
||||
|
||||
elseif ( ent:GetCycle() != self.AnimTrack:GetSlideX() ) then
|
||||
|
||||
local cyc = ent:GetCycle()
|
||||
if ( cyc < 0 ) then cyc = cyc + 1 end
|
||||
self.AnimTrack:SetSlideX( cyc )
|
||||
|
||||
end
|
||||
|
||||
if ( !self.AnimPause:GetToggle() ) then
|
||||
ent:FrameAdvance( FrameTime() )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RenderIcon()
|
||||
|
||||
local tab = {}
|
||||
tab.ent = self.ModelPanel:GetEntity()
|
||||
tab.cam_pos = self.ModelPanel:GetCamPos()
|
||||
tab.cam_ang = self.ModelPanel:GetLookAng()
|
||||
tab.cam_fov = self.ModelPanel:GetFOV()
|
||||
|
||||
self.SpawnIcon:RebuildSpawnIconEx( tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetIcon( icon )
|
||||
|
||||
if ( !IsValid( icon ) ) then return end
|
||||
|
||||
local model = icon:GetModelName()
|
||||
self:SetOrigin( icon )
|
||||
|
||||
self.SpawnIcon:SetSize( icon:GetSize() )
|
||||
self.SpawnIcon:InvalidateLayout( true )
|
||||
|
||||
local w, h = icon:GetSize()
|
||||
if ( w / h < 1 ) then
|
||||
self:SetSize( 700, 502 + 400 )
|
||||
self.LeftPanel:SetWide( 400 )
|
||||
elseif ( w / h > 1 ) then
|
||||
self:SetSize( 900, 502 - 100 )
|
||||
self.LeftPanel:SetWide( 600 )
|
||||
else
|
||||
self:SetSize( 700, 502 )
|
||||
self.LeftPanel:SetWide( 400 )
|
||||
end
|
||||
|
||||
if ( !model or model == "" ) then
|
||||
|
||||
self:SetModel( "error.mdl" )
|
||||
self.SpawnIcon:SetSpawnIcon( icon:GetIconName() )
|
||||
self:SetCustomIcon( true )
|
||||
|
||||
else
|
||||
|
||||
self:SetModel( model )
|
||||
self.SpawnIcon:SetModel( model, icon:GetSkinID(), icon:GetBodyGroup() )
|
||||
self:SetCustomIcon( false )
|
||||
|
||||
end
|
||||
|
||||
-- Keep the spawnmenu open
|
||||
g_SpawnMenu:HangOpen( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Refresh()
|
||||
|
||||
if ( !self:GetModel() ) then return end
|
||||
|
||||
self.ModelPanel:SetModel( self:GetModel() )
|
||||
self.ModelPanel.LayoutEntity = function() self:UpdateEntity( self.ModelPanel:GetEntity() ) end
|
||||
|
||||
local ent = self.ModelPanel:GetEntity()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
ent:SetSkin( self.SpawnIcon:GetSkinID() )
|
||||
ent:SetBodyGroups( self.SpawnIcon:GetBodyGroup() )
|
||||
ent:SetLOD( 0 )
|
||||
|
||||
self:BestGuessLayout()
|
||||
self:FillAnimations( ent )
|
||||
self:SetDefaultLighting()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FillAnimations( ent )
|
||||
|
||||
self.AnimList:Clear()
|
||||
|
||||
for k, v in SortedPairsByValue( ent:GetSequenceList() or {} ) do
|
||||
|
||||
local line = self.AnimList:AddLine( string.lower( v ) )
|
||||
|
||||
line.OnSelect = function()
|
||||
|
||||
local speed = ent:GetPlaybackRate()
|
||||
ent:ResetSequence( v )
|
||||
ent:SetCycle( 0 )
|
||||
ent:SetPlaybackRate( speed )
|
||||
if ( speed < 0 ) then ent:SetCycle( 1 ) end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.BodyList:Clear()
|
||||
local newItems = 0
|
||||
|
||||
if ( ent:SkinCount() > 1 ) then
|
||||
|
||||
local skinSlider = self.BodyList:Add( "DNumSlider" )
|
||||
skinSlider:Dock( TOP )
|
||||
skinSlider:DockMargin( 0, 0, 0, 3 )
|
||||
skinSlider:SetText( "Skin" )
|
||||
skinSlider:SetDark( true )
|
||||
skinSlider:SetDecimals( 0 )
|
||||
skinSlider:SetMinMax( 0, ent:SkinCount() - 1 )
|
||||
skinSlider:SetValue( ent:GetSkin() )
|
||||
skinSlider.OnValueChanged = function( s, newVal )
|
||||
newVal = math.Round( newVal )
|
||||
|
||||
ent:SetSkin( newVal )
|
||||
|
||||
if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():SkinChanged( newVal ) end
|
||||
|
||||
-- If we're not using a custom, change our spawnicon
|
||||
-- so we save the new skin in the right place...
|
||||
if ( !self:GetCustomIcon() ) then
|
||||
self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), newVal, self.SpawnIcon:GetBodyGroup() )
|
||||
end
|
||||
end
|
||||
newItems = newItems + 1
|
||||
|
||||
end
|
||||
|
||||
for k = 0, ent:GetNumBodyGroups() - 1 do
|
||||
|
||||
if ( ent:GetBodygroupCount( k ) <= 1 ) then continue end
|
||||
|
||||
local bgSlider = self.BodyList:Add( "DNumSlider" )
|
||||
bgSlider:Dock( TOP )
|
||||
bgSlider:DockMargin( 0, 0, 0, 3 )
|
||||
bgSlider:SetDark( true )
|
||||
bgSlider:SetDecimals( 0 )
|
||||
bgSlider:SetText( ent:GetBodygroupName( k ) )
|
||||
bgSlider:SetMinMax( 0, ent:GetBodygroupCount( k ) - 1 )
|
||||
bgSlider:SetValue( ent:GetBodygroup( k ) )
|
||||
bgSlider.BodyGroupID = k
|
||||
bgSlider.OnValueChanged = function( s, newVal )
|
||||
newVal = math.Round( newVal )
|
||||
|
||||
ent:SetBodygroup( s.BodyGroupID, newVal )
|
||||
|
||||
if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():BodyGroupChanged( s.BodyGroupID, newVal ) end
|
||||
|
||||
-- If we're not using a custom, change our spawnicon
|
||||
-- so we save the new skin in the right place...
|
||||
if ( !self:GetCustomIcon() ) then
|
||||
self.SpawnIcon:SetBodyGroup( s.BodyGroupID, newVal )
|
||||
self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), self.SpawnIcon:GetSkinID(), self.SpawnIcon:GetBodyGroup() )
|
||||
end
|
||||
end
|
||||
newItems = newItems + 1
|
||||
|
||||
end
|
||||
|
||||
if ( newItems > 0 ) then
|
||||
self.BodygroupTab.Tab:SetVisible( true )
|
||||
else
|
||||
self.BodygroupTab.Tab:SetVisible( false )
|
||||
end
|
||||
local propertySheet = self.PropertySheet
|
||||
propertySheet.tabScroller:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetFromEntity( ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local bodyStr = ""
|
||||
for i = 0, 8 do
|
||||
bodyStr = bodyStr .. math.min( ent:GetBodygroup( i ) or 0, 9 )
|
||||
end
|
||||
|
||||
self.SpawnIcon:SetModel( ent:GetModel(), ent:GetSkin(), bodyStr )
|
||||
self:SetModel( ent:GetModel() )
|
||||
self:Refresh()
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "IconEditor", PANEL, "DFrame" )
|
||||
185
gamemodes/sandbox/gamemode/init.lua
Normal file
185
gamemodes/sandbox/gamemode/init.lua
Normal file
@@ -0,0 +1,185 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Sandbox Gamemode
|
||||
|
||||
This is GMod's default gamemode
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
-- These files get sent to the client
|
||||
|
||||
AddCSLuaFile( "cl_hints.lua" )
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "cl_notice.lua" )
|
||||
AddCSLuaFile( "cl_search_models.lua" )
|
||||
AddCSLuaFile( "cl_spawnmenu.lua" )
|
||||
AddCSLuaFile( "cl_worldtips.lua" )
|
||||
AddCSLuaFile( "persistence.lua" )
|
||||
AddCSLuaFile( "player_extension.lua" )
|
||||
AddCSLuaFile( "save_load.lua" )
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
AddCSLuaFile( "gui/IconEditor.lua" )
|
||||
|
||||
include( 'shared.lua' )
|
||||
include( 'commands.lua' )
|
||||
include( 'player.lua' )
|
||||
include( 'spawnmenu/init.lua' )
|
||||
|
||||
--
|
||||
-- Make BaseClass available
|
||||
--
|
||||
DEFINE_BASECLASS( "gamemode_base" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawn()
|
||||
Desc: Called when a player spawns
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawn( pl, transiton )
|
||||
|
||||
player_manager.SetPlayerClass( pl, "player_sandbox" )
|
||||
|
||||
BaseClass.PlayerSpawn( self, pl, transiton )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:OnPhysgunFreeze( weapon, phys, ent, player )
|
||||
Desc: The physgun wants to freeze a prop
|
||||
-----------------------------------------------------------]]
|
||||
function GM:OnPhysgunFreeze( weapon, phys, ent, ply )
|
||||
|
||||
-- Don't freeze persistent props (should already be frozen)
|
||||
if ( ent:GetPersistent() && GetConVarString( "sbox_persist" ):Trim() != "" ) then return false end
|
||||
|
||||
BaseClass.OnPhysgunFreeze( self, weapon, phys, ent, ply )
|
||||
|
||||
ply:SendHint( "PhysgunUnfreeze", 0.3 )
|
||||
ply:SuppressHint( "PhysgunFreeze" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:OnPhysgunReload( weapon, player )
|
||||
Desc: The physgun wants to unfreeze
|
||||
-----------------------------------------------------------]]
|
||||
function GM:OnPhysgunReload( weapon, ply )
|
||||
|
||||
local num = ply:PhysgunUnfreeze()
|
||||
|
||||
if ( num > 0 ) then
|
||||
ply:SendLua( string.format( "GAMEMODE:UnfrozeObjects(%d)", num ) )
|
||||
end
|
||||
|
||||
ply:SuppressHint( "PhysgunUnfreeze" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerShouldTakeDamage
|
||||
Return true if this player should take damage from this attacker
|
||||
Note: This is a shared function - the client will think they can
|
||||
damage the players even though they can't. This just means the
|
||||
prediction will show blood.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerShouldTakeDamage( ply, attacker )
|
||||
|
||||
-- Global godmode, players can't be damaged in any way
|
||||
if ( cvars.Bool( "sbox_godmode", false ) ) then return false end
|
||||
|
||||
-- No player vs player damage
|
||||
if ( attacker:IsValid() && attacker:IsPlayer() && ply != attacker ) then
|
||||
return cvars.Bool( "sbox_playershurtplayers", true )
|
||||
end
|
||||
|
||||
-- Default, let the player be hurt
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Show the search when f1 is pressed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:ShowHelp( ply )
|
||||
|
||||
ply:SendLua( "hook.Run( 'StartSearch' )" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called once on the player's first spawn
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerInitialSpawn( ply, transiton )
|
||||
|
||||
BaseClass.PlayerInitialSpawn( self, ply, transiton )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A ragdoll of an entity has been created
|
||||
-----------------------------------------------------------]]
|
||||
function GM:CreateEntityRagdoll( entity, ragdoll )
|
||||
|
||||
-- Replace the entity with the ragdoll in cleanups etc
|
||||
undo.ReplaceEntity( entity, ragdoll )
|
||||
cleanup.ReplaceEntity( entity, ragdoll )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Player unfroze an object
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerUnfrozeObject( ply, entity, physobject )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( physobject:GetPos() )
|
||||
effectdata:SetEntity( entity )
|
||||
util.Effect( "phys_unfreeze", effectdata, true, true )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Player froze an object
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerFrozeObject( ply, entity, physobject )
|
||||
|
||||
if ( DisablePropCreateEffect ) then return end
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( physobject:GetPos() )
|
||||
effectdata:SetEntity( entity )
|
||||
util.Effect( "phys_freeze", effectdata, true, true )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Who can edit variables?
|
||||
-- If you're writing prop protection or something, you'll
|
||||
-- probably want to hook or override this function.
|
||||
--
|
||||
function GM:CanEditVariable( ent, ply, key, val, editor )
|
||||
|
||||
-- Only allow admins to edit admin only variables!
|
||||
local isAdmin = ply:IsAdmin() || game.SinglePlayer()
|
||||
if ( editor.AdminOnly && !isAdmin ) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- This entity decides who can edit its variables
|
||||
if ( isfunction( ent.CanEditVariables ) ) then
|
||||
return ent:CanEditVariables( ply )
|
||||
end
|
||||
|
||||
-- default in sandbox is.. anyone can edit anything.
|
||||
return true
|
||||
|
||||
end
|
||||
100
gamemodes/sandbox/gamemode/persistence.lua
Normal file
100
gamemodes/sandbox/gamemode/persistence.lua
Normal file
@@ -0,0 +1,100 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
local CurrentlyActivePersistencePage = ""
|
||||
|
||||
hook.Add( "InitPostEntity", "PersistenceInit", function()
|
||||
|
||||
local PersistPage = GetConVarString( "sbox_persist" ):Trim()
|
||||
if ( PersistPage == "" ) then return end
|
||||
|
||||
hook.Run( "PersistenceLoad", PersistPage )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "ShutDown", "SavePersistenceOnShutdown", function() hook.Run( "PersistenceSave" ) end )
|
||||
|
||||
hook.Add( "PersistenceSave", "PersistenceSave", function( name )
|
||||
|
||||
local PersistPage = ( name or GetConVarString( "sbox_persist" ) ):Trim()
|
||||
if ( PersistPage == "" ) then return end
|
||||
|
||||
local Ents = ents.GetAll()
|
||||
|
||||
for k, v in ipairs( Ents ) do
|
||||
|
||||
if ( !v:GetPersistent() ) then
|
||||
Ents[ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local tab = duplicator.CopyEnts( Ents )
|
||||
if ( !tab ) then return end
|
||||
|
||||
local out = util.TableToJSON( tab )
|
||||
|
||||
file.CreateDir( "persist" )
|
||||
file.Write( "persist/" .. game.GetMap() .. "_" .. PersistPage .. ".txt", out )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "PersistenceLoad", "PersistenceLoad", function( name )
|
||||
|
||||
CurrentlyActivePersistencePage = name
|
||||
|
||||
local data = file.Read( "persist/" .. game.GetMap() .. "_" .. name .. ".txt" )
|
||||
if ( !data ) then return end
|
||||
|
||||
local tab = util.JSONToTable( data )
|
||||
if ( !tab ) then return end
|
||||
if ( !tab.Entities ) then return end
|
||||
if ( !tab.Constraints ) then return end
|
||||
|
||||
local entities = duplicator.Paste( nil, tab.Entities, tab.Constraints )
|
||||
|
||||
for k, v in pairs( entities ) do
|
||||
v:SetPersistent( true )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
cvars.AddChangeCallback( "sbox_persist", function( name, old, new )
|
||||
|
||||
-- A timer in case someone tries to rapidly change the convar, such as addons with "live typing" or whatever
|
||||
timer.Create( "sbox_persist_change_timer", 2, 1, function()
|
||||
|
||||
local newPage = new:Trim()
|
||||
|
||||
if ( CurrentlyActivePersistencePage == newPage ) then return end
|
||||
|
||||
-- old:Trim() would be incorrect for more than 1 convar change within the 2 second timer window
|
||||
hook.Run( "PersistenceSave", CurrentlyActivePersistencePage )
|
||||
|
||||
CurrentlyActivePersistencePage = ""
|
||||
|
||||
if ( newPage == "" ) then return end
|
||||
|
||||
-- Addons are forcing us to use this hook
|
||||
hook.Add( "PostCleanupMap", "GMod_Sandbox_PersistanceLoad", function()
|
||||
hook.Remove( "PostCleanupMap", "GMod_Sandbox_PersistanceLoad" )
|
||||
|
||||
hook.Run( "PersistenceLoad", newPage )
|
||||
end )
|
||||
|
||||
-- Maybe this game.CleanUpMap call should be moved to PersistenceLoad?
|
||||
game.CleanUpMap( false, nil, function() end )
|
||||
|
||||
end )
|
||||
|
||||
end, "sbox_persist_load" )
|
||||
227
gamemodes/sandbox/gamemode/player.lua
Normal file
227
gamemodes/sandbox/gamemode/player.lua
Normal file
@@ -0,0 +1,227 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnObject( ply )
|
||||
Desc: Called to ask whether player is allowed to spawn any objects
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnObject( ply )
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:CanPlayerUnfreeze( )
|
||||
Desc: Can the player unfreeze this entity & physobject
|
||||
-----------------------------------------------------------]]
|
||||
function GM:CanPlayerUnfreeze( ply, entity, physobject )
|
||||
|
||||
if ( entity:GetPersistent() && GetConVarString( "sbox_persist" ):Trim() != "" ) then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: LimitReachedProcess
|
||||
-----------------------------------------------------------]]
|
||||
local function LimitReachedProcess( ply, str )
|
||||
|
||||
if ( !IsValid( ply ) ) then return true end
|
||||
|
||||
return ply:CheckLimit( str )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnRagdoll( ply, model )
|
||||
Desc: Return true if it's allowed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnRagdoll( ply, model )
|
||||
|
||||
return LimitReachedProcess( ply, "ragdolls" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnProp( ply, model )
|
||||
Desc: Return true if it's allowed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnProp( ply, model )
|
||||
|
||||
return LimitReachedProcess( ply, "props" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnEffect( ply, model )
|
||||
Desc: Return true if it's allowed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnEffect( ply, model )
|
||||
|
||||
return LimitReachedProcess( ply, "effects" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnVehicle( ply, model, vname, vtable )
|
||||
Desc: Return true if it's allowed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnVehicle( ply, model, vname, vtable )
|
||||
|
||||
return LimitReachedProcess( ply, "vehicles" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnSWEP( ply, wname, wtable )
|
||||
Desc: Return true if it's allowed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnSWEP( ply, wname, wtable )
|
||||
|
||||
return LimitReachedProcess( ply, "sents" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerGiveSWEP( ply, wname, wtable )
|
||||
Desc: Return true if it's allowed
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerGiveSWEP( ply, wname, wtable )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnSENT( ply, name )
|
||||
Desc: Return true if player is allowed to spawn the SENT
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnSENT( ply, name )
|
||||
|
||||
return LimitReachedProcess( ply, "sents" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnNPC( ply, npc_type )
|
||||
Desc: Return true if player is allowed to spawn the NPC
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnNPC( ply, npc_type, equipment )
|
||||
|
||||
return LimitReachedProcess( ply, "npcs" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnedRagdoll( ply, model, ent )
|
||||
Desc: Called after the player spawned a ragdoll
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnedRagdoll( ply, model, ent )
|
||||
|
||||
ply:AddCount( "ragdolls", ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnedProp( ply, model, ent )
|
||||
Desc: Called after the player spawned a prop
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnedProp( ply, model, ent )
|
||||
|
||||
ply:AddCount( "props", ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnedEffect( ply, model, ent )
|
||||
Desc: Called after the player spawned an effect
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnedEffect( ply, model, ent )
|
||||
|
||||
ply:AddCount( "effects", ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnedVehicle( ply, ent )
|
||||
Desc: Called after the player spawned a vehicle
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnedVehicle( ply, ent )
|
||||
|
||||
ply:AddCount( "vehicles", ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnedNPC( ply, ent )
|
||||
Desc: Called after the player spawned an NPC
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnedNPC( ply, ent )
|
||||
|
||||
ply:AddCount( "npcs", ent )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnedSENT( ply, ent )
|
||||
Desc: Called after the player has spawned a SENT
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnedSENT( ply, ent )
|
||||
|
||||
ply:AddCount( "sents", ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerSpawnedWeapon( ply, ent )
|
||||
Desc: Called after the player has spawned a Weapon
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerSpawnedSWEP( ply, ent )
|
||||
|
||||
-- This is on purpose..
|
||||
ply:AddCount( "sents", ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerEnteredVehicle( player, vehicle, role )
|
||||
Desc: Player entered the vehicle fine
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerEnteredVehicle( player, vehicle, role )
|
||||
|
||||
player:SendHint( "VehicleView", 2 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
These are buttons that the client is pressing. They're used
|
||||
in Sandbox mode to control things like wheels, thrusters etc.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerButtonDown( ply, btn )
|
||||
|
||||
numpad.Activate( ply, btn )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
These are buttons that the client is pressing. They're used
|
||||
in Sandbox mode to control things like wheels, thrusters etc.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerButtonUp( ply, btn )
|
||||
|
||||
numpad.Deactivate( ply, btn )
|
||||
|
||||
end
|
||||
209
gamemodes/sandbox/gamemode/player_class/player_sandbox.lua
Normal file
209
gamemodes/sandbox/gamemode/player_class/player_sandbox.lua
Normal file
@@ -0,0 +1,209 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
DEFINE_BASECLASS( "player_default" )
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
CreateConVar( "cl_playercolor", "0.24 0.34 0.41", { FCVAR_ARCHIVE, FCVAR_USERINFO, FCVAR_DONTRECORD }, "The value is a Vector - so between 0-1 - not between 0-255" )
|
||||
CreateConVar( "cl_weaponcolor", "0.30 1.80 2.10", { FCVAR_ARCHIVE, FCVAR_USERINFO, FCVAR_DONTRECORD }, "The value is a Vector - so between 0-1 - not between 0-255" )
|
||||
CreateConVar( "cl_playerskin", "0", { FCVAR_ARCHIVE, FCVAR_USERINFO, FCVAR_DONTRECORD }, "The skin to use, if the model has any" )
|
||||
CreateConVar( "cl_playerbodygroups", "0", { FCVAR_ARCHIVE, FCVAR_USERINFO, FCVAR_DONTRECORD }, "The bodygroups to use, if the model has any" )
|
||||
|
||||
end
|
||||
|
||||
local PLAYER = {}
|
||||
|
||||
PLAYER.DuckSpeed = 0.1 -- How fast to go from not ducking, to ducking
|
||||
PLAYER.UnDuckSpeed = 0.1 -- How fast to go from ducking, to not ducking
|
||||
|
||||
--
|
||||
-- Creates a Taunt Camera
|
||||
--
|
||||
PLAYER.TauntCam = TauntCamera()
|
||||
|
||||
--
|
||||
-- See gamemodes/base/player_class/player_default.lua for all overridable variables
|
||||
--
|
||||
PLAYER.SlowWalkSpeed = 100
|
||||
PLAYER.WalkSpeed = 200
|
||||
PLAYER.RunSpeed = 400
|
||||
|
||||
--
|
||||
-- Set up the network table accessors
|
||||
--
|
||||
function PLAYER:SetupDataTables()
|
||||
|
||||
BaseClass.SetupDataTables( self )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function PLAYER:Loadout()
|
||||
|
||||
self.Player:RemoveAllAmmo()
|
||||
|
||||
if ( cvars.Bool( "sbox_weapons", true ) ) then
|
||||
|
||||
self.Player:GiveAmmo( 256, "Pistol", true )
|
||||
self.Player:GiveAmmo( 256, "SMG1", true )
|
||||
self.Player:GiveAmmo( 5, "grenade", true )
|
||||
self.Player:GiveAmmo( 64, "Buckshot", true )
|
||||
self.Player:GiveAmmo( 32, "357", true )
|
||||
self.Player:GiveAmmo( 32, "XBowBolt", true )
|
||||
self.Player:GiveAmmo( 6, "AR2AltFire", true )
|
||||
self.Player:GiveAmmo( 100, "AR2", true )
|
||||
|
||||
self.Player:Give( "weapon_crowbar" )
|
||||
self.Player:Give( "weapon_pistol" )
|
||||
self.Player:Give( "weapon_smg1" )
|
||||
self.Player:Give( "weapon_frag" )
|
||||
self.Player:Give( "weapon_physcannon" )
|
||||
self.Player:Give( "weapon_crossbow" )
|
||||
self.Player:Give( "weapon_shotgun" )
|
||||
self.Player:Give( "weapon_357" )
|
||||
self.Player:Give( "weapon_rpg" )
|
||||
self.Player:Give( "weapon_ar2" )
|
||||
|
||||
-- The only reason I'm leaving this out is because
|
||||
-- I don't want to add too many weapons to the first
|
||||
-- row because that's where the gravgun is.
|
||||
--pl:Give( "weapon_stunstick" )
|
||||
|
||||
end
|
||||
|
||||
self.Player:Give( "gmod_tool" )
|
||||
self.Player:Give( "gmod_camera" )
|
||||
self.Player:Give( "weapon_physgun" )
|
||||
|
||||
self.Player:SwitchToDefaultWeapon()
|
||||
|
||||
end
|
||||
|
||||
function PLAYER:SetModel()
|
||||
|
||||
BaseClass.SetModel( self )
|
||||
|
||||
local skin = self.Player:GetInfoNum( "cl_playerskin", 0 )
|
||||
self.Player:SetSkin( skin )
|
||||
|
||||
local bodygroups = self.Player:GetInfo( "cl_playerbodygroups" )
|
||||
if ( bodygroups == nil ) then bodygroups = "" end
|
||||
|
||||
local groups = string.Explode( " ", bodygroups )
|
||||
for k = 0, self.Player:GetNumBodyGroups() - 1 do
|
||||
self.Player:SetBodygroup( k, tonumber( groups[ k + 1 ] ) or 0 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called when the player spawns
|
||||
--
|
||||
function PLAYER:Spawn()
|
||||
|
||||
BaseClass.Spawn( self )
|
||||
|
||||
local plyclr = self.Player:GetInfo( "cl_playercolor" )
|
||||
self.Player:SetPlayerColor( Vector( plyclr ) )
|
||||
|
||||
local wepclr = Vector( self.Player:GetInfo( "cl_weaponcolor" ) )
|
||||
if ( wepclr:Length() < 0.001 ) then
|
||||
wepclr = Vector( 0.001, 0.001, 0.001 )
|
||||
end
|
||||
self.Player:SetWeaponColor( wepclr )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Return true to draw local (thirdperson) camera - false to prevent - nothing to use default behaviour
|
||||
--
|
||||
function PLAYER:ShouldDrawLocal()
|
||||
|
||||
if ( self.TauntCam:ShouldDrawLocalPlayer( self.Player, self.Player:IsPlayingTaunt() ) ) then return true end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Allow player class to create move
|
||||
--
|
||||
function PLAYER:CreateMove( cmd )
|
||||
|
||||
if ( self.TauntCam:CreateMove( cmd, self.Player, self.Player:IsPlayingTaunt() ) ) then return true end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Allow changing the player's view
|
||||
--
|
||||
function PLAYER:CalcView( view )
|
||||
|
||||
if ( self.TauntCam:CalcView( view, self.Player, self.Player:IsPlayingTaunt() ) ) then return true end
|
||||
|
||||
-- Your stuff here
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Reproduces the jump boost from HL2 singleplayer
|
||||
--
|
||||
local JUMPING
|
||||
|
||||
function PLAYER:StartMove( move )
|
||||
|
||||
-- Only apply the jump boost in FinishMove if the player has jumped during this frame
|
||||
-- Using a global variable is safe here because nothing else happens between SetupMove and FinishMove
|
||||
if bit.band( move:GetButtons(), IN_JUMP ) ~= 0 and bit.band( move:GetOldButtons(), IN_JUMP ) == 0 and self.Player:OnGround() then
|
||||
JUMPING = true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PLAYER:FinishMove( move )
|
||||
|
||||
-- If the player has jumped this frame
|
||||
if ( JUMPING ) then
|
||||
-- Get their orientation
|
||||
local forward = move:GetAngles()
|
||||
forward.p = 0
|
||||
forward = forward:Forward()
|
||||
|
||||
-- Compute the speed boost
|
||||
|
||||
-- HL2 normally provides a much weaker jump boost when sprinting
|
||||
-- For some reason this never applied to GMod, so we won't perform
|
||||
-- this check here to preserve the "authentic" feeling
|
||||
local speedBoostPerc = ( ( not self.Player:Crouching() ) and 0.5 ) or 0.1
|
||||
|
||||
local speedAddition = math.abs( move:GetForwardSpeed() * speedBoostPerc )
|
||||
local maxSpeed = move:GetMaxSpeed() * ( 1 + speedBoostPerc )
|
||||
local newSpeed = speedAddition + move:GetVelocity():Length2D()
|
||||
|
||||
-- Clamp it to make sure they can't bunnyhop to ludicrous speed
|
||||
if newSpeed > maxSpeed then
|
||||
speedAddition = speedAddition - ( newSpeed - maxSpeed )
|
||||
end
|
||||
|
||||
-- Reverse it if the player is running backwards
|
||||
if move:GetVelocity():Dot( forward ) < 0 then
|
||||
speedAddition = -speedAddition
|
||||
end
|
||||
|
||||
-- Apply the speed boost
|
||||
move:SetVelocity( forward * speedAddition + move:GetVelocity() )
|
||||
end
|
||||
|
||||
JUMPING = nil
|
||||
|
||||
end
|
||||
|
||||
player_manager.RegisterClass( "player_sandbox", PLAYER, "player_default" )
|
||||
149
gamemodes/sandbox/gamemode/player_extension.lua
Normal file
149
gamemodes/sandbox/gamemode/player_extension.lua
Normal file
@@ -0,0 +1,149 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !meta ) then return end
|
||||
|
||||
g_SBoxObjects = {}
|
||||
|
||||
function meta:CheckLimit( str )
|
||||
|
||||
-- No limits in single player
|
||||
if ( game.SinglePlayer() ) then return true end
|
||||
|
||||
local c = cvars.Number( "sbox_max" .. str, 0 )
|
||||
local count = self:GetCount( str )
|
||||
|
||||
local ret = hook.Run( "PlayerCheckLimit", self, str, count, c )
|
||||
if ( ret != nil ) then
|
||||
if ( !ret && SERVER ) then self:LimitHit( str ) end
|
||||
return ret
|
||||
end
|
||||
|
||||
if ( c < 0 ) then return true end
|
||||
|
||||
if ( count > c - 1 ) then
|
||||
if ( SERVER ) then self:LimitHit( str ) end
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function meta:GetCount( str, minus )
|
||||
|
||||
if ( CLIENT ) then
|
||||
return self:GetNWInt( "Count." .. str, 0 )
|
||||
end
|
||||
|
||||
minus = minus or 0
|
||||
|
||||
if ( !self:IsValid() ) then return end
|
||||
|
||||
local key = self:UniqueID()
|
||||
local tab = g_SBoxObjects[ key ]
|
||||
|
||||
if ( !tab || !tab[ str ] ) then
|
||||
|
||||
self:SetNWInt( "Count." .. str, 0 )
|
||||
return 0
|
||||
|
||||
end
|
||||
|
||||
local c = 0
|
||||
|
||||
for k, v in pairs( tab[ str ] ) do
|
||||
|
||||
if ( IsValid( v ) && !v:IsMarkedForDeletion() ) then
|
||||
c = c + 1
|
||||
else
|
||||
tab[ str ][ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:SetNWInt( "Count." .. str, math.max( c - minus, 0 ) )
|
||||
|
||||
return c
|
||||
|
||||
end
|
||||
|
||||
function meta:AddCount( str, ent )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
local key = self:UniqueID()
|
||||
g_SBoxObjects[ key ] = g_SBoxObjects[ key ] or {}
|
||||
g_SBoxObjects[ key ][ str ] = g_SBoxObjects[ key ][ str ] or {}
|
||||
|
||||
local tab = g_SBoxObjects[ key ][ str ]
|
||||
|
||||
table.insert( tab, ent )
|
||||
|
||||
-- Update count (for client)
|
||||
self:GetCount( str )
|
||||
|
||||
ent:CallOnRemove( "GetCountUpdate", function( ent, ply, str ) ply:GetCount( str ) end, self, str )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:LimitHit( str )
|
||||
|
||||
self:SendLua( string.format( 'hook.Run("LimitHit",%q)', str ) )
|
||||
|
||||
end
|
||||
|
||||
function meta:AddCleanup( type, ent )
|
||||
|
||||
cleanup.Add( self, type, ent )
|
||||
|
||||
end
|
||||
|
||||
function meta:GetTool( mode )
|
||||
|
||||
local wep = self:GetWeapon( "gmod_tool" )
|
||||
if ( !IsValid( wep ) || !wep.GetToolObject ) then return nil end
|
||||
|
||||
local tool = wep:GetToolObject( mode )
|
||||
if ( !tool ) then return nil end
|
||||
|
||||
return tool
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function meta:SendHint( str, delay )
|
||||
|
||||
self.Hints = self.Hints or {}
|
||||
if ( self.Hints[ str ] ) then return end
|
||||
|
||||
self:SendLua( string.format( 'hook.Run("AddHint",%q,%d)', str, delay ) )
|
||||
self.Hints[ str ] = true
|
||||
|
||||
end
|
||||
|
||||
function meta:SuppressHint( str )
|
||||
|
||||
self.Hints = self.Hints or {}
|
||||
if ( self.Hints[ str ] ) then return end
|
||||
|
||||
self:SendLua( string.format( 'hook.Run("SuppressHint",%q)', str ) )
|
||||
self.Hints[ str ] = true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
55
gamemodes/sandbox/gamemode/prop_tools.lua
Normal file
55
gamemodes/sandbox/gamemode/prop_tools.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
If the entity is colliding with something this function
|
||||
will make it non solid and call a timer to itself.
|
||||
|
||||
If it isn't colliding with anything it will make it solid
|
||||
and the timer will end.
|
||||
-----------------------------------------------------------]]
|
||||
function CheckPropSolid( e, solidtype, nonsolidtype, SolidCallback )
|
||||
|
||||
if ( !IsValid( e ) ) then return end
|
||||
|
||||
-- Trace our entity to check for collisions
|
||||
local trace = { start = e:GetPos(), endpos = e:GetPos(), filter = e }
|
||||
local tr = util.TraceEntity( trace, e )
|
||||
|
||||
-- If it collides mark it non solid and test again in 0.5 seconds
|
||||
if ( tr.Hit ) then
|
||||
|
||||
e:SetCollisionGroup( nonsolidtype )
|
||||
|
||||
-- Check later and later every time.
|
||||
--timerlast = timerlast + 0.1
|
||||
timer.Simple( 0.5, function() CheckPropSolid( e, solidtype, nonsolidtype, SolidCallback ) end )
|
||||
|
||||
else
|
||||
|
||||
e:SetCollisionGroup( solidtype )
|
||||
|
||||
-- If we have a solid callback function call it
|
||||
if ( SolidCallback ) then
|
||||
SolidCallback( e )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function DoPropSpawnedEffect( e )
|
||||
|
||||
if ( DisablePropCreateEffect ) then return end
|
||||
|
||||
e:SetSpawnEffect( true );
|
||||
|
||||
end
|
||||
147
gamemodes/sandbox/gamemode/save_load.lua
Normal file
147
gamemodes/sandbox/gamemode/save_load.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--
|
||||
-- Pool the shared network string
|
||||
--
|
||||
util.AddNetworkString( "GModSave" )
|
||||
|
||||
--
|
||||
-- Console command to trigger the save serverside (and send the save to the client)
|
||||
--
|
||||
concommand.Add( "gm_save", function( ply, cmd, args )
|
||||
|
||||
if ( !IsValid( ply ) ) then return end
|
||||
|
||||
-- gmsave.SaveMap is very expensive for big maps/lots of entities. Do not allow random ppl to save the map in multiplayer!
|
||||
-- TODO: Actually do proper hooks for this
|
||||
if ( !game.SinglePlayer() && !ply:IsAdmin() ) then return end
|
||||
|
||||
if ( ply.m_NextSave && ply.m_NextSave > CurTime() && !game.SinglePlayer() ) then
|
||||
ServerLog( tostring( ply ) .. " tried to save too quickly!\n" )
|
||||
return
|
||||
end
|
||||
|
||||
ply.m_NextSave = CurTime() + 10
|
||||
|
||||
ServerLog( tostring( ply ) .. " requested a save.\n" )
|
||||
|
||||
local save = gmsave.SaveMap( ply )
|
||||
if ( !save ) then return end
|
||||
|
||||
local compressed_save = util.Compress( save )
|
||||
if ( !compressed_save ) then compressed_save = save end
|
||||
|
||||
local len = string.len( compressed_save )
|
||||
local send_size = 60000
|
||||
local parts = math.ceil( len / send_size )
|
||||
|
||||
local ShowSave = false
|
||||
if ( args[ 1 ] == "spawnmenu" ) then ShowSave = true end
|
||||
|
||||
local start = 0
|
||||
for i = 1, parts do
|
||||
|
||||
local endbyte = math.min( start + send_size, len )
|
||||
local size = endbyte - start
|
||||
|
||||
net.Start( "GModSave" )
|
||||
net.WriteBool( i == parts )
|
||||
net.WriteBool( ShowSave )
|
||||
|
||||
net.WriteUInt( size, 16 )
|
||||
net.WriteData( compressed_save:sub( start + 1, endbyte + 1 ), size )
|
||||
net.Send( ply )
|
||||
|
||||
start = endbyte
|
||||
end
|
||||
|
||||
end, nil, "", { FCVAR_DONTRECORD } )
|
||||
|
||||
local function LoadGModSave( savedata )
|
||||
|
||||
-- If we loaded the save from main menu and the player entity is not ready yet
|
||||
if ( game.SinglePlayer() && !IsValid( Entity( 1 ) ) ) then
|
||||
|
||||
timer.Create( "LoadGModSave_WaitForPlayer", 0.1, 0, function()
|
||||
if ( !IsValid( Entity( 1 ) ) ) then return end
|
||||
|
||||
timer.Remove( "LoadGModSave_WaitForPlayer" )
|
||||
LoadGModSave( savedata )
|
||||
end )
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
local ply = nil
|
||||
if ( IsValid( Entity( 1 ) ) && ( game.SinglePlayer() || Entity( 1 ):IsListenServerHost() ) ) then ply = Entity( 1 ) end
|
||||
if ( !IsValid( ply ) && #player.GetHumans() == 1 ) then ply = player.GetHumans()[ 1 ] end
|
||||
|
||||
gmsave.LoadMap( savedata, ply )
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "LoadGModSave", "LoadGModSave", function( savedata, mapname, maptime )
|
||||
|
||||
savedata = util.Decompress( savedata )
|
||||
|
||||
if ( !isstring( savedata ) ) then
|
||||
MsgN( "gm_load: Couldn't load save!" )
|
||||
return
|
||||
end
|
||||
|
||||
LoadGModSave( savedata )
|
||||
|
||||
end )
|
||||
|
||||
else
|
||||
|
||||
local buffer = ""
|
||||
net.Receive( "GModSave", function( len, client )
|
||||
local done = net.ReadBool()
|
||||
local showsave = net.ReadBool()
|
||||
|
||||
local length = net.ReadUInt( 16 )
|
||||
local data = net.ReadData( length )
|
||||
|
||||
buffer = buffer .. data
|
||||
|
||||
if ( !done ) then return end
|
||||
|
||||
MsgN( "Received save. Size: " .. buffer:len() )
|
||||
|
||||
local uncompressed = util.Decompress( buffer )
|
||||
if ( !uncompressed ) then
|
||||
MsgN( "Received save - but couldn't decompress!?" )
|
||||
buffer = ""
|
||||
return
|
||||
end
|
||||
|
||||
local MapAddon = nil
|
||||
for id, addon in pairs( engine.GetAddons() ) do
|
||||
if ( file.Exists( "maps/" .. game.GetMap() .. ".bsp", addon.title ) ) then
|
||||
MapAddon = addon.wsid
|
||||
end
|
||||
end
|
||||
|
||||
engine.WriteSave( buffer, game.GetMap() .. " " .. util.DateStamp(), CurTime(), game.GetMap(), MapAddon )
|
||||
buffer = ""
|
||||
|
||||
if ( showsave ) then
|
||||
hook.Run( "PostGameSaved" )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
333
gamemodes/sandbox/gamemode/shared.lua
Normal file
333
gamemodes/sandbox/gamemode/shared.lua
Normal file
@@ -0,0 +1,333 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Sandbox Gamemode
|
||||
|
||||
This is GMod's default gamemode
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
include( "player_extension.lua" )
|
||||
include( "persistence.lua" )
|
||||
include( "save_load.lua" )
|
||||
include( "player_class/player_sandbox.lua" )
|
||||
include( "drive/drive_sandbox.lua" )
|
||||
include( "editor_player.lua" )
|
||||
|
||||
--
|
||||
-- Make BaseClass available
|
||||
--
|
||||
DEFINE_BASECLASS( "gamemode_base" )
|
||||
|
||||
GM.Name = "Sandbox"
|
||||
GM.Author = "TEAM GARRY"
|
||||
GM.Email = "teamgarry@garrysmod.com"
|
||||
GM.Website = "www.garrysmod.com"
|
||||
|
||||
--[[
|
||||
Note: This is so that in addons you can do stuff like
|
||||
|
||||
if ( !GAMEMODE.IsSandboxDerived ) then return end
|
||||
|
||||
--]]
|
||||
|
||||
GM.IsSandboxDerived = true
|
||||
|
||||
cleanup.Register( "props" )
|
||||
cleanup.Register( "ragdolls" )
|
||||
cleanup.Register( "effects" )
|
||||
cleanup.Register( "npcs" )
|
||||
cleanup.Register( "constraints" )
|
||||
cleanup.Register( "ropeconstraints" )
|
||||
cleanup.Register( "sents" )
|
||||
cleanup.Register( "vehicles" )
|
||||
|
||||
|
||||
local physgun_limited = CreateConVar( "physgun_limited", "0", FCVAR_REPLICATED, "Prevent the Physics Gun from picking up certain map entities." )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:CanTool( ply, trace, mode, tool, button )
|
||||
Return true if the player is allowed to use this tool
|
||||
-----------------------------------------------------------]]
|
||||
function GM:CanTool( ply, trace, mode, tool, button )
|
||||
|
||||
-- The jeep spazzes out when applying something
|
||||
-- todo: Find out what it's reacting badly to and change it in _physprops
|
||||
if ( mode == "physprop" && trace.Entity:IsValid() && trace.Entity:GetClass() == "prop_vehicle_jeep" ) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- If we have a toolsallowed table, check to make sure the toolmode is in it
|
||||
if ( trace.Entity.m_tblToolsAllowed ) then
|
||||
|
||||
local vFound = false
|
||||
for k, v in pairs( trace.Entity.m_tblToolsAllowed ) do
|
||||
if ( mode == v ) then vFound = true end
|
||||
end
|
||||
|
||||
if ( !vFound ) then return false end
|
||||
|
||||
end
|
||||
|
||||
-- Give the entity a chance to decide
|
||||
if ( trace.Entity.CanTool ) then
|
||||
return trace.Entity:CanTool( ply, trace, mode, tool, button )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:GravGunPunt( )
|
||||
Desc: We're about to punt an entity (primary fire).
|
||||
Return true if we're allowed to.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:GravGunPunt( ply, ent )
|
||||
|
||||
if ( ent:IsValid() && ent.GravGunPunt ) then
|
||||
return ent:GravGunPunt( ply )
|
||||
end
|
||||
|
||||
return BaseClass.GravGunPunt( self, ply, ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:GravGunPickupAllowed( )
|
||||
Desc: Return true if we're allowed to pickup entity
|
||||
-----------------------------------------------------------]]
|
||||
function GM:GravGunPickupAllowed( ply, ent )
|
||||
|
||||
if ( ent:IsValid() && ent.GravGunPickupAllowed ) then
|
||||
return ent:GravGunPickupAllowed( ply )
|
||||
end
|
||||
|
||||
return BaseClass.GravGunPickupAllowed( self, ply, ent )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PhysgunPickup( )
|
||||
Desc: Return true if player can pickup entity
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PhysgunPickup( ply, ent )
|
||||
|
||||
-- Don't pick up persistent props
|
||||
if ( ent:GetPersistent() && GetConVarString( "sbox_persist" ):Trim() != "" ) then return false end
|
||||
|
||||
if ( ent:IsValid() && ent.PhysgunPickup ) then
|
||||
return ent:PhysgunPickup( ply )
|
||||
end
|
||||
|
||||
-- Some entities specifically forbid physgun interaction
|
||||
if ( ent.PhysgunDisabled ) then return false end
|
||||
|
||||
local EntClass = ent:GetClass()
|
||||
|
||||
-- Never pick up players
|
||||
if ( EntClass == "player" ) then return false end
|
||||
|
||||
if ( physgun_limited:GetBool() ) then
|
||||
|
||||
if ( string.find( EntClass, "prop_dynamic" ) ) then return false end
|
||||
if ( string.find( EntClass, "prop_door" ) ) then return false end
|
||||
|
||||
-- Don't move physboxes if the mapper logic says no
|
||||
if ( EntClass == "func_physbox" && ent:HasSpawnFlags( SF_PHYSBOX_MOTIONDISABLED ) ) then return false end
|
||||
|
||||
-- If the physics object is frozen by the mapper, don't allow us to move it.
|
||||
if ( string.find( EntClass, "prop_" ) && ( ent:HasSpawnFlags( SF_PHYSPROP_MOTIONDISABLED ) || ent:HasSpawnFlags( SF_PHYSPROP_PREVENT_PICKUP ) ) ) then return false end
|
||||
|
||||
-- Allow physboxes, but get rid of all other func_'s (ladder etc)
|
||||
if ( EntClass != "func_physbox" && string.find( EntClass, "func_" ) ) then return false end
|
||||
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
ply:SendHint( "PhysgunFreeze", 2 )
|
||||
ply:SendHint( "PhysgunUse", 8 )
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:EntityKeyValue( ent, key, value )
|
||||
Desc: Called when an entity has a keyvalue set
|
||||
Returning a string it will override the value
|
||||
-----------------------------------------------------------]]
|
||||
function GM:EntityKeyValue( ent, key, value )
|
||||
|
||||
-- Physgun not allowed on this prop..
|
||||
if ( key == "gmod_allowphysgun" && value == '0' ) then
|
||||
ent.PhysgunDisabled = true
|
||||
end
|
||||
|
||||
-- Prop has a list of tools that are allowed on it.
|
||||
if ( key == "gmod_allowtools" ) then
|
||||
ent.m_tblToolsAllowed = string.Explode( " ", value )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:PlayerNoClip( player, bool )
|
||||
Desc: Player pressed the noclip key, return true if
|
||||
the player is allowed to noclip, false to block
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerNoClip( pl, on )
|
||||
|
||||
-- Don't allow if player is in vehicle
|
||||
if ( !IsValid( pl ) || pl:InVehicle() || !pl:Alive() ) then return false end
|
||||
|
||||
-- Always allow to turn off noclip, and in single player
|
||||
if ( !on || game.SinglePlayer() ) then return true end
|
||||
|
||||
return GetConVarNumber( "sbox_noclip" ) > 0
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:CanProperty( pl, property, ent )
|
||||
Desc: Can the player do this property, to this entity?
|
||||
-----------------------------------------------------------]]
|
||||
function GM:CanProperty( pl, property, ent )
|
||||
|
||||
--
|
||||
-- Always a chance some bastard got through
|
||||
--
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
|
||||
|
||||
--
|
||||
-- If we have a toolsallowed table, check to make sure the toolmode is in it
|
||||
-- This is used by things like map entities
|
||||
--
|
||||
if ( ent.m_tblToolsAllowed ) then
|
||||
|
||||
local vFound = false
|
||||
for k, v in pairs( ent.m_tblToolsAllowed ) do
|
||||
if ( property == v ) then vFound = true end
|
||||
end
|
||||
|
||||
if ( !vFound ) then return false end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Who can who bone manipulate?
|
||||
--
|
||||
if ( property == "bonemanipulate" ) then
|
||||
|
||||
if ( game.SinglePlayer() ) then return true end
|
||||
|
||||
if ( ent:IsNPC() ) then return GetConVarNumber( "sbox_bonemanip_npc" ) != 0 end
|
||||
if ( ent:IsPlayer() ) then return GetConVarNumber( "sbox_bonemanip_player" ) != 0 end
|
||||
|
||||
return GetConVarNumber( "sbox_bonemanip_misc" ) != 0
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Weapons can only be property'd if nobody is holding them
|
||||
--
|
||||
if ( ent:IsWeapon() and IsValid( ent:GetOwner() ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Give the entity a chance to decide
|
||||
if ( ent.CanProperty ) then
|
||||
return ent:CanProperty( pl, property )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode:CanDrive( pl, ent )
|
||||
Desc: Return true to let the entity drive.
|
||||
-----------------------------------------------------------]]
|
||||
function GM:CanDrive( pl, ent )
|
||||
|
||||
local classname = ent:GetClass();
|
||||
|
||||
--
|
||||
-- Only let physics based NPCs be driven for now
|
||||
--
|
||||
if ( ent:IsNPC() ) then
|
||||
|
||||
if ( classname == "npc_cscanner" ) then return true end
|
||||
if ( classname == "npc_clawscanner" ) then return true end
|
||||
if ( classname == "npc_manhack" ) then return true end
|
||||
if ( classname == "npc_turret_floor" ) then return true end
|
||||
if ( classname == "npc_rollermine" ) then return true end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
if ( classname == "prop_dynamic" ) then return false end
|
||||
if ( classname == "prop_door" ) then return false end
|
||||
|
||||
--
|
||||
-- I'm guessing we'll find more things we don't want the player to fly around during development
|
||||
--
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
To update the player's animation during a drive
|
||||
-----------------------------------------------------------]]
|
||||
function GM:PlayerDriveAnimate( ply )
|
||||
|
||||
local driving = ply:GetDrivingEntity()
|
||||
if ( !IsValid( driving ) ) then return end
|
||||
|
||||
ply:SetPlaybackRate( 1 )
|
||||
ply:ResetSequence( ply:SelectWeightedSequence( ACT_HL2MP_IDLE_MAGIC ) )
|
||||
|
||||
--
|
||||
-- Work out the direction from the player to the entity, and set parameters
|
||||
--
|
||||
local DirToEnt = driving:GetPos() - ( ply:GetPos() + Vector( 0, 0, 50 ) )
|
||||
local AimAng = DirToEnt:Angle()
|
||||
|
||||
if ( AimAng.p > 180 ) then
|
||||
AimAng.p = AimAng.p - 360
|
||||
end
|
||||
|
||||
ply:SetPoseParameter( "aim_yaw", 0 )
|
||||
ply:SetPoseParameter( "aim_pitch", AimAng.p )
|
||||
ply:SetPoseParameter( "move_x", 0 )
|
||||
ply:SetPoseParameter( "move_y", 0 )
|
||||
ply:SetPoseParameter( "move_yaw", 0 )
|
||||
ply:SetPoseParameter( "move_scale", 0 )
|
||||
|
||||
AimAng.p = 0;
|
||||
AimAng.r = 0;
|
||||
|
||||
ply:SetRenderAngles( AimAng )
|
||||
ply:SetEyeTarget( driving:GetPos() )
|
||||
|
||||
end
|
||||
251
gamemodes/sandbox/gamemode/spawnmenu/contextmenu.lua
Normal file
251
gamemodes/sandbox/gamemode/spawnmenu/contextmenu.lua
Normal file
@@ -0,0 +1,251 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_bHangOpen", "HangOpen" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
--
|
||||
-- This makes it so that when you're hovering over this panel
|
||||
-- you can `click` on the world. Your viewmodel will aim etc.
|
||||
--
|
||||
self:SetWorldClicker( true )
|
||||
|
||||
self.Canvas = vgui.Create( "DCategoryList", self )
|
||||
self.m_bHangOpen = false
|
||||
|
||||
self:Dock( FILL )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Open()
|
||||
|
||||
self:SetHangOpen( false )
|
||||
|
||||
-- If the spawn menu is open, try to close it..
|
||||
if ( IsValid( g_SpawnMenu ) && g_SpawnMenu:IsVisible() ) then
|
||||
g_SpawnMenu:Close( true )
|
||||
end
|
||||
|
||||
if ( self:IsVisible() ) then return end
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:MakePopup()
|
||||
self:SetVisible( true )
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
RestoreCursorPosition()
|
||||
|
||||
local bShouldShow = hook.Run( "ContextMenuShowTool" )
|
||||
local bShow = bShouldShow == nil or bShouldShow
|
||||
|
||||
-- Set up the active panel..
|
||||
if ( bShow && IsValid( spawnmenu.ActiveControlPanel() ) ) then
|
||||
|
||||
self.OldParent = spawnmenu.ActiveControlPanel():GetParent()
|
||||
self.OldPosX, self.OldPosY = spawnmenu.ActiveControlPanel():GetPos()
|
||||
spawnmenu.ActiveControlPanel():SetParent( self )
|
||||
self.Canvas:Clear()
|
||||
self.Canvas:AddItem( spawnmenu.ActiveControlPanel() )
|
||||
self.Canvas:Rebuild()
|
||||
self.Canvas:SetVisible( true )
|
||||
|
||||
else
|
||||
|
||||
self.Canvas:SetVisible( false )
|
||||
|
||||
end
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Close( bSkipAnim )
|
||||
|
||||
if ( self:GetHangOpen() ) then
|
||||
self:SetHangOpen( false )
|
||||
return
|
||||
end
|
||||
|
||||
RememberCursorPosition()
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( false )
|
||||
|
||||
self:SetAlpha( 255 )
|
||||
self:SetVisible( false )
|
||||
self:RestoreControlPanel()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
if ( IsValid( spawnmenu.ActiveControlPanel() ) ) then
|
||||
|
||||
spawnmenu.ActiveControlPanel():InvalidateLayout( true )
|
||||
|
||||
local Tall = math.min( spawnmenu.ActiveControlPanel():GetTall() + 10, ScrH() * 0.8 )
|
||||
if ( self.Canvas:GetTall() != Tall ) then self.Canvas:SetTall( Tall ) end
|
||||
if ( self.Canvas:GetWide() != 320 ) then self.Canvas:SetWide( 320 ) end
|
||||
|
||||
self.Canvas:SetPos( ScrW() - self.Canvas:GetWide() - 50, ScrH() - 50 - Tall )
|
||||
self.Canvas:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:StartKeyFocus( pPanel )
|
||||
|
||||
self:SetKeyboardInputEnabled( true )
|
||||
self:SetHangOpen( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EndKeyFocus( pPanel )
|
||||
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RestoreControlPanel()
|
||||
|
||||
-- Restore the active panel
|
||||
if ( !spawnmenu.ActiveControlPanel() ) then return end
|
||||
if ( !self.OldParent ) then return end
|
||||
|
||||
spawnmenu.ActiveControlPanel():SetParent( self.OldParent )
|
||||
spawnmenu.ActiveControlPanel():SetPos( self.OldPosX, self.OldPosY )
|
||||
|
||||
self.OldParent = nil
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Note here: EditablePanel is important! Child panels won't be able to get
|
||||
-- keyboard input if it's a DPanel or a Panel. You need to either have an EditablePanel
|
||||
-- or a DFrame (which is derived from EditablePanel) as your first panel attached to the system.
|
||||
--
|
||||
vgui.Register( "ContextMenu", PANEL, "EditablePanel" )
|
||||
|
||||
function CreateContextMenu()
|
||||
|
||||
if ( !hook.Run( "ContextMenuEnabled" ) ) then return end
|
||||
|
||||
if ( IsValid( g_ContextMenu ) ) then
|
||||
g_ContextMenu:Remove()
|
||||
g_ContextMenu = nil
|
||||
end
|
||||
|
||||
g_ContextMenu = vgui.Create( "ContextMenu" )
|
||||
|
||||
if ( !IsValid( g_ContextMenu ) ) then return end
|
||||
|
||||
g_ContextMenu:SetVisible( false )
|
||||
|
||||
--
|
||||
-- We're blocking clicks to the world - but we don't want to
|
||||
-- so feed clicks to the proper functions..
|
||||
--
|
||||
g_ContextMenu.OnMousePressed = function( p, code )
|
||||
hook.Run( "GUIMousePressed", code, gui.ScreenToVector( input.GetCursorPos() ) )
|
||||
end
|
||||
g_ContextMenu.OnMouseReleased = function( p, code )
|
||||
hook.Run( "GUIMouseReleased", code, gui.ScreenToVector( input.GetCursorPos() ) )
|
||||
end
|
||||
|
||||
hook.Run( "ContextMenuCreated", g_ContextMenu )
|
||||
|
||||
local IconLayout = g_ContextMenu:Add( "DIconLayout" )
|
||||
IconLayout:SetBorder( 8 )
|
||||
IconLayout:SetSpaceX( 8 )
|
||||
IconLayout:SetSpaceY( 8 )
|
||||
IconLayout:SetLayoutDir( LEFT )
|
||||
IconLayout:SetWorldClicker( true )
|
||||
IconLayout:SetStretchWidth( true )
|
||||
IconLayout:SetStretchHeight( false ) -- No infinite re-layouts
|
||||
IconLayout:Dock( LEFT )
|
||||
|
||||
-- This overrides DIconLayout's OnMousePressed (which is inherited from DPanel), but we don't care about that in this case
|
||||
IconLayout.OnMousePressed = function( s, ... ) s:GetParent():OnMousePressed( ... ) end
|
||||
|
||||
for k, v in pairs( list.Get( "DesktopWindows" ) ) do
|
||||
|
||||
local icon = IconLayout:Add( "DButton" )
|
||||
icon:SetText( "" )
|
||||
icon:SetSize( 80, 82 )
|
||||
icon.Paint = function() end
|
||||
|
||||
local image = icon:Add( "DImage" )
|
||||
image:SetImage( v.icon )
|
||||
image:SetSize( 64, 64 )
|
||||
image:Dock( TOP )
|
||||
image:DockMargin( 8, 0, 8, 0 )
|
||||
|
||||
local label = icon:Add( "DLabel" )
|
||||
label:Dock( BOTTOM )
|
||||
label:SetText( v.title )
|
||||
label:SetContentAlignment( 5 )
|
||||
label:SetTextColor( color_white )
|
||||
label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
|
||||
icon.DoClick = function()
|
||||
|
||||
--
|
||||
-- v might have changed using autorefresh so grab it again
|
||||
--
|
||||
local newv = list.Get( "DesktopWindows" )[ k ]
|
||||
|
||||
if ( v.onewindow and IsValid( icon.Window ) ) then
|
||||
icon.Window:Center()
|
||||
return
|
||||
end
|
||||
|
||||
-- Make the window
|
||||
icon.Window = g_ContextMenu:Add( "DFrame" )
|
||||
icon.Window:SetSize( newv.width, newv.height )
|
||||
icon.Window:SetTitle( newv.title )
|
||||
icon.Window:Center()
|
||||
|
||||
newv.init( icon, icon.Window )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function GM:OnContextMenuOpen()
|
||||
|
||||
-- Let the gamemode decide whether we should open or not..
|
||||
if ( !hook.Call( "ContextMenuOpen", self ) ) then return end
|
||||
|
||||
if ( IsValid( g_ContextMenu ) && !g_ContextMenu:IsVisible() ) then
|
||||
g_ContextMenu:Open()
|
||||
menubar.ParentTo( g_ContextMenu )
|
||||
end
|
||||
|
||||
hook.Call( "ContextMenuOpened", self )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnContextMenuClose()
|
||||
|
||||
if ( IsValid( g_ContextMenu ) ) then g_ContextMenu:Close() end
|
||||
hook.Call( "ContextMenuClosed", self )
|
||||
|
||||
end
|
||||
443
gamemodes/sandbox/gamemode/spawnmenu/controlpanel.lua
Normal file
443
gamemodes/sandbox/gamemode/spawnmenu/controlpanel.lua
Normal file
@@ -0,0 +1,443 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- Note: This is only really here as a layer between the spawnmenu
|
||||
-- and the DForm Derma control. You shouldn't ever really be
|
||||
-- calling AddControl. If you're writing new code - don't call
|
||||
-- AddControl!! Add stuff directly using the DForm member functions!
|
||||
--
|
||||
|
||||
include( "controls/manifest.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_bInitialized", "Initialized" )
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetInitialized( false )
|
||||
end
|
||||
|
||||
function PANEL:ClearControls()
|
||||
self:Clear()
|
||||
end
|
||||
|
||||
function PANEL:GetEmbeddedPanel()
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddPanel( pnl )
|
||||
|
||||
self:AddItem( pnl, nil )
|
||||
self:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:MatSelect( strConVar, tblOptions, bAutoStretch, iWidth, iHeight )
|
||||
|
||||
local MatSelect = vgui.Create( "MatSelect", self )
|
||||
Derma_Hook( MatSelect.List, "Paint", "Paint", "Panel" )
|
||||
|
||||
MatSelect:SetConVar( strConVar )
|
||||
|
||||
if ( bAutoStretch != nil ) then MatSelect:SetAutoHeight( bAutoStretch ) end
|
||||
if ( iWidth != nil ) then MatSelect:SetItemWidth( iWidth ) end
|
||||
if ( iHeight != nil ) then MatSelect:SetItemHeight( iHeight ) end
|
||||
|
||||
if ( tblOptions != nil ) then
|
||||
for k, v in pairs( tblOptions ) do
|
||||
local nam = isnumber( k ) and v or k
|
||||
MatSelect:AddMaterial( nam, v )
|
||||
end
|
||||
end
|
||||
|
||||
self:AddPanel( MatSelect )
|
||||
return MatSelect
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ToolPresets( group, cvarlist )
|
||||
|
||||
local preset = vgui.Create( "ControlPresets", self )
|
||||
|
||||
preset:SetPreset( group )
|
||||
preset:AddOption( "#preset.default", cvarlist )
|
||||
|
||||
for k, v in pairs( cvarlist ) do
|
||||
preset:AddConVar( k )
|
||||
end
|
||||
|
||||
self:AddItem( preset )
|
||||
|
||||
return preset
|
||||
|
||||
end
|
||||
|
||||
function PANEL:KeyBinder( label1, convar1, label2, convar2 )
|
||||
|
||||
local binder = vgui.Create( "CtrlNumPad", self )
|
||||
|
||||
binder:SetLabel1( label1 )
|
||||
binder:SetConVar1( convar1 )
|
||||
|
||||
if ( label2 != nil and convar2 != nil ) then
|
||||
binder:SetLabel2( label2 )
|
||||
binder:SetConVar2( convar2 )
|
||||
end
|
||||
|
||||
self:AddPanel( binder )
|
||||
|
||||
return binder
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ColorPicker( label, convarR, convarG, convarB, convarA )
|
||||
|
||||
local color = vgui.Create( "CtrlColor", self )
|
||||
|
||||
color:Dock( TOP )
|
||||
color:SetLabel( label )
|
||||
|
||||
color:SetConVarR( convarR )
|
||||
color:SetConVarG( convarG )
|
||||
color:SetConVarB( convarB )
|
||||
|
||||
if ( convarA != nil ) then
|
||||
color:SetConVarA( convarA )
|
||||
end
|
||||
|
||||
self:AddPanel( color )
|
||||
|
||||
return color
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FillViaTable( Table )
|
||||
|
||||
self:SetInitialized( true )
|
||||
|
||||
self:SetName( Table.Text )
|
||||
|
||||
--
|
||||
-- If we have a function to create the control panel, use that
|
||||
--
|
||||
if ( Table.ControlPanelBuildFunction ) then
|
||||
|
||||
Table.ControlPanelBuildFunction( self )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FillViaFunction( func )
|
||||
|
||||
func( self )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ControlValues( data )
|
||||
if ( data.label) then
|
||||
self:SetLabel( data.label )
|
||||
end
|
||||
if ( data.closed ) then
|
||||
self:SetExpanded( false )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function PANEL:AddControl( control, data )
|
||||
|
||||
local data = table.LowerKeyNames( data )
|
||||
local original = control
|
||||
control = string.lower( control )
|
||||
|
||||
-- Retired
|
||||
if ( control == "header" ) then
|
||||
|
||||
if ( data.description ) then
|
||||
local ctrl = self:Help( data.description )
|
||||
return ctrl
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if ( control == "textbox" ) then
|
||||
|
||||
local ctrl = self:TextEntry( data.label or "Untitled", data.command )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "label" ) then
|
||||
|
||||
local ctrl = self:Help( data.text )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "checkbox" or control == "toggle" ) then
|
||||
|
||||
local ctrl = self:CheckBox( data.label or "Untitled", data.command )
|
||||
|
||||
if ( data.help ) then
|
||||
self:ControlHelp( data.label .. ".help" )
|
||||
end
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "slider" ) then
|
||||
|
||||
local Decimals = 0
|
||||
if ( data.type && string.lower(data.type) == "float" ) then Decimals = 2 end
|
||||
|
||||
local ctrl = self:NumSlider( data.label or "Untitled", data.command, data.min or 0, data.max or 100, Decimals )
|
||||
|
||||
if ( data.help ) then
|
||||
self:ControlHelp( data.label .. ".help" )
|
||||
end
|
||||
|
||||
if ( data.default ) then
|
||||
ctrl:SetDefaultValue( data.default )
|
||||
elseif ( data.command ) then
|
||||
local cvar = GetConVar( data.command )
|
||||
if ( cvar ) then
|
||||
ctrl:SetDefaultValue( cvar:GetDefault() )
|
||||
end
|
||||
end
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "propselect" ) then
|
||||
|
||||
local ctrl = vgui.Create( "PropSelect", self )
|
||||
ctrl:ControlValues( data ) -- Yack.
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "matselect" ) then
|
||||
|
||||
local ctrl = vgui.Create( "MatSelect", self )
|
||||
ctrl:ControlValues( data ) -- Yack.
|
||||
self:AddPanel( ctrl )
|
||||
|
||||
Derma_Hook( ctrl.List, "Paint", "Paint", "Panel" )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "ropematerial" ) then
|
||||
|
||||
local ctrl = vgui.Create( "RopeMaterial", self )
|
||||
ctrl:SetConVar( data.convar )
|
||||
self:AddPanel( ctrl )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "button" ) then
|
||||
|
||||
local ctrl = vgui.Create( "DButton", self )
|
||||
|
||||
-- Note: Buttons created this way use the old method of calling commands,
|
||||
-- via LocalPlayer:ConCommand. This way is flawed. This way is legacy.
|
||||
-- The new way is to make buttons via controlpanel:Button( name, command, commandarg1, commandarg2 ) etc
|
||||
if ( data.command ) then
|
||||
function ctrl:DoClick() LocalPlayer():ConCommand( data.command ) end
|
||||
end
|
||||
|
||||
ctrl:SetText( data.label or data.text or "No Label" )
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "numpad" ) then
|
||||
|
||||
local ctrl = vgui.Create( "CtrlNumPad", self )
|
||||
ctrl:SetConVar1( data.command )
|
||||
ctrl:SetConVar2( data.command2 )
|
||||
ctrl:SetLabel1( data.label )
|
||||
ctrl:SetLabel2( data.label2 )
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "color" ) then
|
||||
|
||||
local ctrl = vgui.Create( "CtrlColor", self )
|
||||
ctrl:SetLabel( data.label )
|
||||
ctrl:SetConVarR( data.red )
|
||||
ctrl:SetConVarG( data.green )
|
||||
ctrl:SetConVarB( data.blue )
|
||||
ctrl:SetConVarA( data.alpha )
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
|
||||
if ( control == "combobox" ) then
|
||||
|
||||
if ( tostring( data.menubutton ) == "1" ) then
|
||||
|
||||
local ctrl = vgui.Create( "ControlPresets", self )
|
||||
ctrl:SetPreset( data.folder )
|
||||
if ( data.options ) then
|
||||
for k, v in pairs( data.options ) do
|
||||
ctrl:AddOption( k, v )
|
||||
end
|
||||
end
|
||||
|
||||
if ( data.cvars ) then
|
||||
for k, v in pairs( data.cvars ) do
|
||||
ctrl:AddConVar( v )
|
||||
end
|
||||
end
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
control = "listbox"
|
||||
|
||||
end
|
||||
|
||||
if ( control == "listbox" ) then
|
||||
|
||||
if ( data.height ) then
|
||||
|
||||
local ctrl = vgui.Create( "DListView" )
|
||||
ctrl:SetMultiSelect( false )
|
||||
ctrl:AddColumn( data.label or "unknown" )
|
||||
|
||||
if ( data.options ) then
|
||||
|
||||
for k, v in pairs( data.options ) do
|
||||
|
||||
local line = ctrl:AddLine( k )
|
||||
line.data = v
|
||||
|
||||
-- This is kind of broken because it only checks one convar
|
||||
-- instead of all of them. But this is legacy. It will do for now.
|
||||
for k, v in pairs( line.data ) do
|
||||
if ( GetConVarString( k ) == tostring( v ) ) then
|
||||
line:SetSelected( true )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
ctrl:SetTall( data.height )
|
||||
ctrl:SortByColumn( 1, false )
|
||||
|
||||
function ctrl:OnRowSelected( LineID, Line )
|
||||
for k, v in pairs( Line.data ) do
|
||||
RunConsoleCommand( k, v )
|
||||
end
|
||||
end
|
||||
|
||||
self:AddItem( ctrl )
|
||||
|
||||
return ctrl
|
||||
|
||||
else
|
||||
|
||||
local ctrl = vgui.Create( "CtrlListBox", self )
|
||||
|
||||
if ( data.options ) then
|
||||
for k, v in pairs( data.options ) do
|
||||
ctrl:AddOption( k, v )
|
||||
end
|
||||
end
|
||||
|
||||
local left = vgui.Create( "DLabel", self )
|
||||
left:SetText( data.label )
|
||||
left:SetDark( true )
|
||||
ctrl:SetHeight( 25 )
|
||||
ctrl:Dock( TOP )
|
||||
|
||||
self:AddItem( left, ctrl )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( control == "materialgallery" ) then
|
||||
|
||||
local ctrl = vgui.Create( "MatSelect", self )
|
||||
--ctrl:ControlValues( data ) -- Yack.
|
||||
|
||||
ctrl:SetItemWidth( data.width or 32 )
|
||||
ctrl:SetItemHeight( data.height or 32 )
|
||||
ctrl:SetNumRows( data.rows or 4 )
|
||||
ctrl:SetConVar( data.convar or nil )
|
||||
|
||||
Derma_Hook( ctrl.List, "Paint", "Paint", "Panel" )
|
||||
|
||||
for name, tab in pairs( data.options ) do
|
||||
|
||||
local mat = tab.material
|
||||
local value = tab.value
|
||||
|
||||
tab.material = nil
|
||||
tab.value = nil
|
||||
|
||||
ctrl:AddMaterialEx( name, mat, value, tab )
|
||||
|
||||
end
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
local ctrl = vgui.Create( original, self )
|
||||
-- Fallback for scripts that relied on the old behaviour
|
||||
if ( !ctrl ) then
|
||||
ctrl = vgui.Create( control, self )
|
||||
end
|
||||
if ( ctrl ) then
|
||||
|
||||
if ( ctrl.ControlValues ) then
|
||||
ctrl:ControlValues( data )
|
||||
end
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
MsgN( "UNHANDLED CONTROL: ", control )
|
||||
PrintTable( data )
|
||||
MsgN( "\n\n" )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ControlPanel", PANEL, "DForm" )
|
||||
@@ -0,0 +1,173 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "preset_editor.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.DropDown = vgui.Create( "DComboBox", self )
|
||||
self.DropDown.OnSelect = function( dropdown, index, value, data ) self:OnSelect( index, value, data ) end
|
||||
self.DropDown:SetText( "Presets" )
|
||||
self.DropDown:Dock( FILL )
|
||||
|
||||
self.Button = vgui.Create( "DImageButton", self )
|
||||
self.Button.DoClick = function() self:OpenPresetEditor() end
|
||||
self.Button:Dock( RIGHT )
|
||||
self.Button:SetToolTip( "#preset.edit" )
|
||||
self.Button:SetImage( "icon16/wrench.png" )
|
||||
self.Button:SetStretchToFit( false )
|
||||
self.Button:SetSize( 20, 20 )
|
||||
self.Button:DockMargin( 0, 0, 0, 0 )
|
||||
|
||||
self.AddButton = vgui.Create( "DImageButton", self )
|
||||
self.AddButton.DoClick = function()
|
||||
if ( !IsValid( self ) ) then return end
|
||||
|
||||
self:QuickSavePreset()
|
||||
end
|
||||
self.AddButton:Dock( RIGHT )
|
||||
self.AddButton:SetToolTip( "#preset.add" )
|
||||
self.AddButton:SetImage( "icon16/add.png" )
|
||||
self.AddButton:SetStretchToFit( false )
|
||||
self.AddButton:SetSize( 20, 20 )
|
||||
self.AddButton:DockMargin( 2, 0, 0, 0 )
|
||||
|
||||
self:SetTall( 20 )
|
||||
|
||||
self.Options = {}
|
||||
self.ConVars = {}
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetLabel( strName )
|
||||
|
||||
self.Label:SetText( strName )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddOption( strName, data )
|
||||
|
||||
self.DropDown:AddChoice( strName, data )
|
||||
|
||||
self.Options[ strName ] = data
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetOptions( Options )
|
||||
if ( Options ) then
|
||||
table.Merge( self.Options, Options )
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnSelect( index, value, data )
|
||||
|
||||
if ( !data ) then return end
|
||||
|
||||
for k, v in pairs( data ) do
|
||||
RunConsoleCommand( k, v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:QuickSaveInternal( text )
|
||||
local tabValues = {}
|
||||
for k, v in pairs( self:GetConVars() ) do
|
||||
tabValues[ v ] = GetConVarString( v )
|
||||
end
|
||||
|
||||
presets.Add( self.m_strPreset, text, tabValues )
|
||||
self:Update()
|
||||
end
|
||||
|
||||
function PANEL:QuickSavePreset()
|
||||
Derma_StringRequest( "#preset.saveas_title", "#preset.saveas_desc", "", function( text )
|
||||
if ( !text || text:Trim() == "" ) then presets.BadNameAlert() return end
|
||||
|
||||
if ( presets.Exists( self.m_strPreset, text ) ) then
|
||||
presets.OverwritePresetPrompt( function()
|
||||
self:QuickSaveInternal( text )
|
||||
end )
|
||||
return
|
||||
end
|
||||
|
||||
self:QuickSaveInternal( text )
|
||||
end )
|
||||
end
|
||||
|
||||
function PANEL:OpenPresetEditor()
|
||||
|
||||
if ( !self.m_strPreset ) then return end
|
||||
|
||||
self.Window = vgui.Create( "PresetEditor" )
|
||||
self.Window:MakePopup()
|
||||
self.Window:Center()
|
||||
self.Window:SetType( self.m_strPreset )
|
||||
self.Window:SetConVars( self:GetConVars() )
|
||||
self.Window:SetPresetControl( self )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddConVar( convar )
|
||||
|
||||
table.insert( self.ConVars, convar )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetConVars()
|
||||
|
||||
return self.ConVars
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetPreset( strName )
|
||||
|
||||
self.m_strPreset = strName
|
||||
self:ReloadPresets()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ReloadPresets()
|
||||
|
||||
self:Clear()
|
||||
|
||||
for name, data in pairs( self.Options ) do
|
||||
self:AddOption( name, data )
|
||||
end
|
||||
|
||||
local Presets = presets.GetTable( self.m_strPreset )
|
||||
local sortedPresets, i = {}, 1
|
||||
for name in pairs( Presets ) do
|
||||
sortedPresets[ i ] = name
|
||||
i = i + 1
|
||||
end
|
||||
table.sort( sortedPresets )
|
||||
|
||||
for _, name in ipairs( sortedPresets ) do
|
||||
self.DropDown:AddChoice( name, Presets[ name ] )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Update()
|
||||
|
||||
self:ReloadPresets()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Clear()
|
||||
|
||||
self.DropDown:Clear()
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ControlPresets", PANEL, "Panel" )
|
||||
59
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlcolor.lua
Normal file
59
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlcolor.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.Mixer = vgui.Create( "DColorMixer", self )
|
||||
self.Mixer:Dock( FILL )
|
||||
|
||||
self:SetTall( 245 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( x, y )
|
||||
|
||||
-- Magic number, the target width for self.Mixer
|
||||
-- Number picked to that Palette would not have a gap, at button size 17
|
||||
local targetWidth = 272
|
||||
|
||||
-- Don't scale the Mixer in width, keep it to the target width
|
||||
local s = math.max( ( self:GetWide() - targetWidth ) / 2, 0 )
|
||||
self.Mixer:DockMargin( s, 8, s, 0 )
|
||||
|
||||
-- Ugly hack, because of the docking system
|
||||
self.OldMixerW = self.OldMixerW or self.Mixer:GetWide()
|
||||
|
||||
-- Number of panels in one row
|
||||
local ColorRows = math.ceil( #self.Mixer.Palette:GetChildren() / 3 )
|
||||
|
||||
-- Set the button size closest to fill the Mixer width
|
||||
local bSize = math.floor( self:GetWide() / ColorRows )
|
||||
self.Mixer.Palette:SetButtonSize( math.min( bSize, 17 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint()
|
||||
-- Invisible background!
|
||||
end
|
||||
|
||||
function PANEL:SetLabel( text ) self.Mixer:SetLabel( text ) end
|
||||
function PANEL:SetConVarR( cvar ) self.Mixer:SetConVarR( cvar ) end
|
||||
function PANEL:SetConVarG( cvar ) self.Mixer:SetConVarG( cvar ) end
|
||||
function PANEL:SetConVarB( cvar ) self.Mixer:SetConVarB( cvar ) end
|
||||
function PANEL:SetConVarA( cvar ) self.Mixer:SetConVarA( cvar ) end
|
||||
function PANEL:GetConVarR() return self.Mixer:GetConVarR() end
|
||||
function PANEL:GetConVarG() return self.Mixer:GetConVarG() end
|
||||
function PANEL:GetConVarB() return self.Mixer:GetConVarB() end
|
||||
function PANEL:GetConVarA() return self.Mixer:GetConVarA() end
|
||||
|
||||
vgui.Register( "CtrlColor", PANEL, "DPanel" )
|
||||
118
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrllistbox.lua
Normal file
118
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrllistbox.lua
Normal file
@@ -0,0 +1,118 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--AccessorFunc( PANEL, "m_ConVarR", "ConVarR" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self.ConVars = {}
|
||||
self.Options = {}
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AddOption
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:AddOption( strName, tabConVars )
|
||||
|
||||
self:AddChoice( strName, tabConVars )
|
||||
|
||||
for k, v in pairs( tabConVars ) do
|
||||
self.ConVars[ k ] = 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: OnSelect
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:OnSelect( index, value, data )
|
||||
|
||||
for k, v in pairs( data ) do
|
||||
|
||||
RunConsoleCommand( k, tostring( v ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Think
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Think( CheckConvarChanges )
|
||||
|
||||
self:CheckConVarChanges()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ConVarsChanged
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:ConVarsChanged()
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
|
||||
if ( self[ k ] == nil ) then return true end
|
||||
if ( self[ k ] != GetConVarString( k ) ) then return true end
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CheckForMatch
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:CheckForMatch( cvars )
|
||||
|
||||
if ( table.IsEmpty( cvars ) ) then return false end
|
||||
|
||||
for k, v in pairs( cvars ) do
|
||||
|
||||
if ( tostring(v) != GetConVarString( k ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CheckConVarChanges
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:CheckConVarChanges()
|
||||
|
||||
if (!self:ConVarsChanged()) then return end
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
self[ k ] = GetConVarString( k )
|
||||
end
|
||||
|
||||
for k, v in pairs( self.Data ) do
|
||||
|
||||
if ( self:CheckForMatch( v ) ) then
|
||||
self:SetText( self:GetOptionText(k) )
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "CtrlListBox", PANEL, "DComboBox" )
|
||||
117
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlnumpad.lua
Normal file
117
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlnumpad.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_ConVar1", "ConVar1" )
|
||||
AccessorFunc( PANEL, "m_ConVar2", "ConVar2" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self.NumPad1 = vgui.Create( "DBinder", self )
|
||||
self.Label1 = vgui.Create( "DLabel", self )
|
||||
self.Label1:SetDark( true )
|
||||
|
||||
self.NumPad2 = vgui.Create( "DBinder", self )
|
||||
self.Label2 = vgui.Create( "DLabel", self )
|
||||
self.Label2:SetDark( true )
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
self:SetHeight( 200 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetLabel1
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetLabel1( txt )
|
||||
if ( !txt ) then return end
|
||||
self.Label1:SetText( txt )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetLabel2
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetLabel2( txt )
|
||||
if ( !txt ) then return end
|
||||
self.Label2:SetText( txt )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetConVar1
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetConVar1( cvar )
|
||||
self.NumPad1:SetConVar( cvar )
|
||||
self.m_ConVar1 = cvar
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetConVar2
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetConVar2( cvar )
|
||||
self.NumPad2:SetConVar( cvar )
|
||||
self.m_ConVar2 = cvar
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
self:SetTall( 70 )
|
||||
|
||||
self.NumPad1:InvalidateLayout( true )
|
||||
self.NumPad1:SetSize( 100, 50 )
|
||||
|
||||
if ( self.m_ConVar2 ) then
|
||||
self.NumPad2:InvalidateLayout( true )
|
||||
self.NumPad2:SetSize( 100, 50 )
|
||||
end
|
||||
|
||||
if ( !self.m_ConVar2 ) then
|
||||
|
||||
self.Label1:SizeToContents()
|
||||
|
||||
self.NumPad2:SetVisible( false )
|
||||
self.Label2:SetVisible( false )
|
||||
|
||||
self.NumPad1:CenterHorizontal( 0.5 )
|
||||
self.NumPad1:AlignTop( 20 )
|
||||
|
||||
self.Label1:CenterHorizontal()
|
||||
self.Label1:AlignTop( 0 )
|
||||
|
||||
else
|
||||
|
||||
self.Label1:SizeToContents()
|
||||
self.Label2:SizeToContents()
|
||||
|
||||
self.NumPad2:SetVisible( true )
|
||||
self.Label2:SetVisible( true )
|
||||
|
||||
self.NumPad1:CenterHorizontal( 0.25 )
|
||||
self.Label1:CenterHorizontal( 0.25 )
|
||||
self.NumPad1:AlignTop( 20 )
|
||||
|
||||
self.NumPad2:CenterHorizontal( 0.75 )
|
||||
self.Label2:CenterHorizontal( 0.75 )
|
||||
self.NumPad2:AlignTop( 20 )
|
||||
self.Label2:AlignTop( 0 )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "CtrlNumPad", PANEL, "DPanel" )
|
||||
17
gamemodes/sandbox/gamemode/spawnmenu/controls/manifest.lua
Normal file
17
gamemodes/sandbox/gamemode/spawnmenu/controls/manifest.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "control_presets.lua" )
|
||||
include( "ropematerial.lua" )
|
||||
|
||||
include( "ctrlnumpad.lua" )
|
||||
include( "ctrlcolor.lua" )
|
||||
include( "ctrllistbox.lua" )
|
||||
272
gamemodes/sandbox/gamemode/spawnmenu/controls/preset_editor.lua
Normal file
272
gamemodes/sandbox/gamemode/spawnmenu/controls/preset_editor.lua
Normal file
@@ -0,0 +1,272 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_strType", "Type" )
|
||||
AccessorFunc( PANEL, "m_ConVars", "ConVars" )
|
||||
AccessorFunc( PANEL, "m_PresetControl", "PresetControl" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetSize( 450, 350 )
|
||||
self:SetMinWidth( 450 )
|
||||
self:SetMinHeight( 350 )
|
||||
self:SetSizable( true )
|
||||
self:SetTitle( "#preset.editor" )
|
||||
self:DockPadding( 6, 29, 6, 6 )
|
||||
|
||||
local pnlTop = vgui.Create( "Panel", self )
|
||||
pnlTop:Dock( FILL )
|
||||
pnlTop:DockMargin( 0, 0, 0, 5 )
|
||||
|
||||
self.PresetList = vgui.Create( "DListView", pnlTop )
|
||||
self.PresetList:Dock( LEFT )
|
||||
self.PresetList:DockMargin( 0, 0, 5, 0 )
|
||||
self.PresetList:SetWide( 150 )
|
||||
self.PresetList:SetMultiSelect( false )
|
||||
self.PresetList:SetSortable( false )
|
||||
self.PresetList.OnRowSelected = function( s, idx, pnl ) self:OnPresetSelected( pnl ) end
|
||||
|
||||
local pnlEditor = vgui.Create( "DPanel", pnlTop )
|
||||
pnlEditor:Dock( FILL )
|
||||
|
||||
self.pnlDetails = vgui.Create( "DProperties", pnlEditor )
|
||||
self.pnlDetails:Dock( FILL )
|
||||
self.pnlDetails:DockMargin( 5, 5, 5, 5 )
|
||||
|
||||
----------
|
||||
|
||||
local pnlModify = vgui.Create( "Panel", pnlEditor )
|
||||
pnlModify:Dock( BOTTOM )
|
||||
pnlModify:SetTall( 20 )
|
||||
pnlModify:DockMargin( 5, 0, 5, 5 )
|
||||
|
||||
local btnDelete = vgui.Create( "DButton", pnlModify )
|
||||
btnDelete.DoClick = function() self:Delete() end
|
||||
btnDelete:SetTooltip( "#preset.delete" )
|
||||
btnDelete:SetImage( "icon16/bin.png" )
|
||||
btnDelete:SetText( "" )
|
||||
btnDelete:Dock( RIGHT )
|
||||
btnDelete:SetWide( 25 )
|
||||
btnDelete:SetEnabled( false )
|
||||
|
||||
self.txtRename = vgui.Create( "DTextEntry", pnlModify )
|
||||
self.txtRename:Dock( FILL )
|
||||
self.txtRename:SetEnabled( false )
|
||||
self.txtRename:SetTooltip( "#preset.rename" )
|
||||
|
||||
local btnRename = vgui.Create( "DButton", pnlModify )
|
||||
btnRename:SetTooltip( "#preset.save" )
|
||||
btnRename:SetImage( "icon16/disk.png" )
|
||||
btnRename:SetText( "" )
|
||||
btnRename:Dock( RIGHT )
|
||||
btnRename:DockMargin( 5, 0, 5, 0 )
|
||||
btnRename:SetWide( 24 )
|
||||
btnRename.DoClick = function() self:SaveChanges() end
|
||||
btnRename:SetEnabled( false )
|
||||
|
||||
----------
|
||||
|
||||
local bottom = vgui.Create( "Panel", self )
|
||||
bottom:Dock( BOTTOM )
|
||||
bottom:SetTall( 30 )
|
||||
|
||||
self.pnlAdd = vgui.Create( "DPanel", bottom )
|
||||
self.pnlAdd:Dock( FILL )
|
||||
self.pnlAdd:DockPadding( 5, 5, 5, 5 )
|
||||
self.pnlAdd:DockMargin( 0, 0, 5, 0 )
|
||||
|
||||
self.txtName = vgui.Create( "DTextEntry", self.pnlAdd )
|
||||
self.txtName:SetTooltip( "#preset.addnew_field" )
|
||||
self.txtName:Dock( FILL )
|
||||
self.txtName:DockMargin( 0, 0, 5, 0 )
|
||||
self.txtName.OnChange = function( s ) self.btnAdd:SetEnabled( s:GetText():Trim() != "" ) end
|
||||
|
||||
self.btnAdd = vgui.Create( "DButton", self.pnlAdd )
|
||||
self.btnAdd:SetText( "#preset.addnew" )
|
||||
self.btnAdd:Dock( RIGHT )
|
||||
self.btnAdd:SetEnabled( false )
|
||||
self.btnAdd.DoClick = function() self:Add() end
|
||||
|
||||
----------
|
||||
|
||||
local pnlClose = vgui.Create( "DPanel", bottom )
|
||||
pnlClose:Dock( RIGHT )
|
||||
pnlClose:SetWide( 100 )
|
||||
pnlClose:DockPadding( 5, 5, 5, 5 )
|
||||
|
||||
local btnCloseIt = vgui.Create( "DButton", pnlClose )
|
||||
btnCloseIt:SetText( "#preset.close" )
|
||||
btnCloseIt:Dock( FILL )
|
||||
btnCloseIt.DoClick = function() self:Remove() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetType( strType )
|
||||
|
||||
self.m_strType = strType
|
||||
|
||||
self.PresetList:AddColumn( self:GetType() )
|
||||
self:Update()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnPresetSelected( item )
|
||||
|
||||
local name = item:GetValue( 1 )
|
||||
|
||||
self.txtRename:SetText( name )
|
||||
for id, pnl in ipairs( self.txtRename:GetParent():GetChildren() ) do pnl:SetEnabled( true ) end
|
||||
|
||||
self.pnlDetails:Clear()
|
||||
for cvar, val in SortedPairs( item:GetTable().Data ) do
|
||||
local Row = self.pnlDetails:CreateRow( name, cvar:lower() )
|
||||
|
||||
if ( tonumber( val ) != nil && false ) then
|
||||
Row:Setup( "Float", { min = 0, max = 1000 } )
|
||||
Row:SetValue( val )
|
||||
else
|
||||
Row:Setup( "Generic" )
|
||||
end
|
||||
|
||||
Row:SetValue( val )
|
||||
Row.__Value = val
|
||||
Row.DataChanged = function( s, value ) Row.__Value = value end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Update()
|
||||
|
||||
self.PresetList:Clear()
|
||||
self.pnlDetails:Clear()
|
||||
self.txtRename:SetText( "" )
|
||||
|
||||
local Presets = presets.GetTable( self:GetType() )
|
||||
local sortedPresets, i = {}, 1
|
||||
for name in pairs( Presets ) do
|
||||
sortedPresets[i] = name
|
||||
i = i + 1
|
||||
end
|
||||
table.sort( sortedPresets )
|
||||
|
||||
for _, name in ipairs( sortedPresets ) do
|
||||
local item = self.PresetList:AddLine( name )
|
||||
item.Data = Presets[ name ]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SelectPresetByName( name )
|
||||
|
||||
for id, line in pairs( self.PresetList:GetLines() ) do
|
||||
if ( line:GetValue( 1 ) != name ) then continue end
|
||||
self.PresetList:SelectItem( line )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Delete()
|
||||
|
||||
if ( !self.PresetList:GetSelectedLine() || !IsValid( self.PresetList:GetLine( self.PresetList:GetSelectedLine() ) ) ) then return end
|
||||
|
||||
local Selected = self.PresetList:GetLine( self.PresetList:GetSelectedLine() ):GetValue( 1 ):Trim()
|
||||
if ( Selected == "" ) then return end
|
||||
|
||||
presets.Remove( self:GetType(), Selected )
|
||||
self:Update()
|
||||
|
||||
if ( self:GetPresetControl() ) then self:GetPresetControl():Update() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SaveChangesInternal( Selected, ToName )
|
||||
|
||||
local tabValues = {}
|
||||
local cat = self.pnlDetails:GetCategory( Selected )
|
||||
|
||||
-- WARNING: This will discard ConVars in the preset that no longer exist on the tool/whatever this preset is for
|
||||
for k, v in pairs( self:GetConVars() ) do
|
||||
if ( cat:GetRow( v:lower() ) ) then
|
||||
tabValues[ v:lower() ] = cat:GetRow( v:lower() ).__Value
|
||||
end
|
||||
end
|
||||
|
||||
presets.Rename( self:GetType(), Selected, ToName ) -- Raname the preset if necessary
|
||||
presets.Add( self:GetType(), ToName, tabValues ) -- Update the values
|
||||
|
||||
self:Update()
|
||||
|
||||
self.txtRename:SetText( "" )
|
||||
self:SelectPresetByName( ToName )
|
||||
|
||||
if ( self:GetPresetControl() ) then self:GetPresetControl():Update() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SaveChanges()
|
||||
|
||||
if ( !self.PresetList:GetSelectedLine() || !IsValid( self.PresetList:GetLine( self.PresetList:GetSelectedLine() ) ) ) then return end
|
||||
|
||||
local Selected = self.PresetList:GetLine( self.PresetList:GetSelectedLine() ):GetValue( 1 ):Trim()
|
||||
if ( Selected == "" ) then return end
|
||||
|
||||
local ToName = self.txtRename:GetValue():Trim()
|
||||
if ( !ToName || ToName == "" ) then presets.BadNameAlert() return end
|
||||
|
||||
if ( presets.Exists( self:GetType(), ToName ) && Selected != ToName ) then
|
||||
presets.OverwritePresetPrompt( function()
|
||||
self:SaveChangesInternal( Selected, ToName )
|
||||
end )
|
||||
return
|
||||
end
|
||||
|
||||
self:SaveChangesInternal( Selected, ToName )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:InternalAdd( ToName )
|
||||
|
||||
local tabValues = {}
|
||||
for k, v in pairs( self:GetConVars() ) do
|
||||
tabValues[ v ] = GetConVarString( v:lower() )
|
||||
end
|
||||
|
||||
presets.Add( self:GetType(), ToName, tabValues )
|
||||
self:Update()
|
||||
|
||||
self.txtName:SetText( "" )
|
||||
self:SelectPresetByName( ToName )
|
||||
|
||||
if ( self:GetPresetControl() ) then self:GetPresetControl():Update() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Add()
|
||||
|
||||
if ( !self:GetConVars() ) then return end
|
||||
|
||||
local ToName = self.txtName:GetValue():Trim()
|
||||
if ( !ToName || ToName == "" ) then presets.BadNameAlert() return end
|
||||
|
||||
if ( presets.Exists( self:GetType(), ToName ) ) then
|
||||
presets.OverwritePresetPrompt( function()
|
||||
self:InternalAdd( ToName )
|
||||
end )
|
||||
return
|
||||
end
|
||||
|
||||
self:InternalAdd( ToName )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "PresetEditor", PANEL, "DFrame" )
|
||||
@@ -0,0 +1,46 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
list.Set( "RopeMaterials", "#ropematerial.rope", "cable/rope" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.cable", "cable/cable2" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.xbeam", "cable/xbeam" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.laser", "cable/redlaser" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.electric", "cable/blue_elec" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.physbeam", "cable/physbeam" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.hydra", "cable/hydra" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetItemWidth( 0.14 )
|
||||
self:SetItemHeight( 0.3 )
|
||||
self:SetAutoHeight( true )
|
||||
|
||||
local mats = list.Get( "RopeMaterials" )
|
||||
for k, v in pairs( mats ) do
|
||||
|
||||
self:AddMaterial( k, v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
draw.RoundedBox( 4, 0, 0, w, h, Color( 128, 128, 128, 255 ) )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "RopeMaterial", PANEL, "MatSelect" )
|
||||
67
gamemodes/sandbox/gamemode/spawnmenu/creationmenu.lua
Normal file
67
gamemodes/sandbox/gamemode/spawnmenu/creationmenu.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "creationmenu/manifest.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.CreationTabs = {}
|
||||
|
||||
self:SetFadeTime( 0 )
|
||||
self:Populate()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetCreationTab( id )
|
||||
|
||||
return self.CreationTabs[ id ]
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetCreationTabs()
|
||||
|
||||
return self.CreationTabs
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Populate()
|
||||
|
||||
local tabs = spawnmenu.GetCreationTabs()
|
||||
|
||||
for k, v in SortedPairsByMemberValue( tabs, "Order" ) do
|
||||
|
||||
--
|
||||
-- Here we create a panel and populate it on the first paint
|
||||
-- that way everything is created on the first view instead of
|
||||
-- being created on load.
|
||||
--
|
||||
local pnl = vgui.Create( "Panel" )
|
||||
|
||||
local tab = self:AddSheet( k, pnl, v.Icon, nil, nil, v.Tooltip )
|
||||
self.CreationTabs[ k ] = tab
|
||||
|
||||
-- Populate the panel
|
||||
-- We have to add the timer to make sure g_Spawnmenu is available
|
||||
-- in case some addon needs it ready when populating the creation tab.
|
||||
timer.Simple( 0, function()
|
||||
if ( !IsValid( pnl ) ) then return end
|
||||
local childpnl = v.Function()
|
||||
childpnl:SetParent( pnl )
|
||||
childpnl:Dock( FILL )
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "CreationMenu", PANEL, "DPropertySheet" )
|
||||
@@ -0,0 +1,110 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "contenticon.lua" )
|
||||
include( "postprocessicon.lua" )
|
||||
|
||||
include( "contentcontainer.lua" )
|
||||
include( "contentsidebar.lua" )
|
||||
|
||||
include( "contenttypes/custom.lua" )
|
||||
include( "contenttypes/npcs.lua" )
|
||||
include( "contenttypes/weapons.lua" )
|
||||
include( "contenttypes/entities.lua" )
|
||||
include( "contenttypes/postprocess.lua" )
|
||||
include( "contenttypes/vehicles.lua" )
|
||||
include( "contenttypes/saves.lua" )
|
||||
include( "contenttypes/dupes.lua" )
|
||||
|
||||
include( "contenttypes/gameprops.lua" )
|
||||
include( "contenttypes/addonprops.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_pSelectedPanel", "SelectedPanel" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
self.CategoryTable = {}
|
||||
|
||||
self.HorizontalDivider = vgui.Create( "DHorizontalDivider", self )
|
||||
self.HorizontalDivider:Dock( FILL )
|
||||
self.HorizontalDivider:SetLeftWidth( 192 )
|
||||
self.HorizontalDivider:SetLeftMin( 100 )
|
||||
self.HorizontalDivider:SetRightMin( 100 )
|
||||
if ( ScrW() >= 1024 ) then self.HorizontalDivider:SetLeftMin( 192 ) self.HorizontalDivider:SetRightMin( 400 ) end
|
||||
self.HorizontalDivider:SetDividerWidth( 6 )
|
||||
self.HorizontalDivider:SetCookieName( "SpawnMenuCreationMenuDiv" )
|
||||
|
||||
self.ContentNavBar = vgui.Create( "ContentSidebar", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetLeft( self.ContentNavBar )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EnableModify()
|
||||
self.ContentNavBar:EnableModify()
|
||||
end
|
||||
|
||||
function PANEL:EnableSearch( ... )
|
||||
self.ContentNavBar:EnableSearch( ... )
|
||||
end
|
||||
|
||||
function PANEL:CallPopulateHook( HookName )
|
||||
|
||||
hook.Call( HookName, GAMEMODE, self, self.ContentNavBar.Tree, self.OldSpawnlists )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SwitchPanel( panel )
|
||||
|
||||
if ( IsValid( self.SelectedPanel ) ) then
|
||||
self.SelectedPanel:SetVisible( false )
|
||||
self.SelectedPanel = nil
|
||||
end
|
||||
|
||||
self.SelectedPanel = panel
|
||||
|
||||
if ( !IsValid( panel ) ) then return end
|
||||
|
||||
self.HorizontalDivider:SetRight( self.SelectedPanel )
|
||||
self.HorizontalDivider:InvalidateLayout( true )
|
||||
|
||||
self.SelectedPanel:SetVisible( true )
|
||||
self:InvalidateParent()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnSizeChanged()
|
||||
self.HorizontalDivider:LoadCookies()
|
||||
end
|
||||
|
||||
vgui.Register( "SpawnmenuContentPanel", PANEL, "DPanel" )
|
||||
|
||||
local function CreateContentPanel()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
|
||||
ctrl.OldSpawnlists = ctrl.ContentNavBar.Tree:AddNode( "#spawnmenu.category.browse", "icon16/cog.png" )
|
||||
|
||||
ctrl:EnableModify()
|
||||
hook.Call( "PopulatePropMenu", GAMEMODE )
|
||||
ctrl:CallPopulateHook( "PopulateContent" )
|
||||
|
||||
ctrl.OldSpawnlists:MoveToFront()
|
||||
ctrl.OldSpawnlists:SetExpanded( true )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.content_tab", CreateContentPanel, "icon16/application_view_tile.png", -10 )
|
||||
@@ -0,0 +1,224 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
DEFINE_BASECLASS( "DScrollPanel" )
|
||||
|
||||
AccessorFunc( PANEL, "m_pControllerPanel", "ControllerPanel" )
|
||||
AccessorFunc( PANEL, "m_strCategoryName", "CategoryName" )
|
||||
AccessorFunc( PANEL, "m_bTriggerSpawnlistChange", "TriggerSpawnlistChange" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
self.IconList = vgui.Create( "DTileLayout", self:GetCanvas() )
|
||||
self.IconList:SetBaseSize( 64 )
|
||||
self.IconList:MakeDroppable( "SandboxContentPanel", true )
|
||||
self.IconList:SetSelectionCanvas( true )
|
||||
--self.IconList:SetUseLiveDrag( true )
|
||||
self.IconList:Dock( TOP )
|
||||
self.IconList.OnModified = function() self:OnModified() end
|
||||
self.IconList.OnMousePressed = function( s, btn )
|
||||
|
||||
-- A bit of a hack
|
||||
s:EndBoxSelection()
|
||||
if ( btn != MOUSE_RIGHT ) then DPanel.OnMousePressed( s, btn ) end
|
||||
|
||||
end
|
||||
self.IconList.OnMouseReleased = function( s, btn )
|
||||
|
||||
DPanel.OnMouseReleased( s, btn )
|
||||
|
||||
if ( btn != MOUSE_RIGHT || s:GetReadOnly() ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.newlabel", function()
|
||||
|
||||
local label = vgui.Create( "ContentHeader" )
|
||||
self:Add( label )
|
||||
|
||||
-- Move the label to player's cursor, but make sure it's per line, not per icon
|
||||
local x, y = self.IconList:ScreenToLocal( input.GetCursorPos() )
|
||||
label:MoveToAfter( self.IconList:GetClosestChild( self:GetCanvas():GetWide(), y ) )
|
||||
|
||||
self:OnModified()
|
||||
|
||||
-- Scroll to the newly added item
|
||||
--[[timer.Simple( 0, function()
|
||||
local x, y = label:GetPos()
|
||||
self.VBar:AnimateTo( y - self:GetTall() / 2 + label:GetTall() / 2, 0.5, 0, 0.5 )
|
||||
end )]]
|
||||
|
||||
end ):SetIcon( "icon16/text_heading_1.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
self.IconList.ContentContainer = self
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Add( pnl )
|
||||
|
||||
self.IconList:Add( pnl )
|
||||
|
||||
if ( pnl.InstallMenu ) then
|
||||
pnl:InstallMenu( self )
|
||||
end
|
||||
|
||||
self:Layout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Layout()
|
||||
|
||||
self.IconList:Layout()
|
||||
self:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
BaseClass.PerformLayout( self, w, h )
|
||||
self.IconList:SetMinHeight( self:GetTall() - 16 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RebuildAll
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:RebuildAll( proppanel )
|
||||
|
||||
for k, v in ipairs( self.IconList:GetChildren() ) do
|
||||
|
||||
v:RebuildSpawnIcon()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCount
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:GetCount()
|
||||
|
||||
return #self.IconList:GetChildren()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Clear()
|
||||
|
||||
self.IconList:Clear()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetTriggerSpawnlistChange( bTrigger )
|
||||
|
||||
self.m_bTriggerSpawnlistChange = bTrigger
|
||||
self.IconList:SetReadOnly( !bTrigger )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnModified()
|
||||
|
||||
if ( !self:GetTriggerSpawnlistChange() ) then return end
|
||||
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ContentsToTable( contentpanel )
|
||||
|
||||
local tab = {}
|
||||
|
||||
for k, v in ipairs( self.IconList:GetChildren() ) do
|
||||
|
||||
v:ToTable( tab )
|
||||
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "ContentContainer", self:GetParent() )
|
||||
copy:CopyBase( self )
|
||||
|
||||
copy.IconList:CopyContents( self.IconList )
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentContainer", PANEL, "DScrollPanel" )
|
||||
|
||||
hook.Add( "SpawnlistOpenGenericMenu", "DragAndDropSelectionMenu", function( canvas )
|
||||
|
||||
if ( canvas:GetReadOnly() ) then return end
|
||||
|
||||
local selected = canvas:GetSelectedChildren()
|
||||
|
||||
local menu = DermaMenu()
|
||||
|
||||
-- This is less than ideal
|
||||
local spawnicons = 0
|
||||
local icon = nil
|
||||
for id, pnl in pairs( selected ) do
|
||||
if ( pnl.InternalAddResizeMenu ) then
|
||||
spawnicons = spawnicons + 1
|
||||
icon = pnl
|
||||
end
|
||||
end
|
||||
|
||||
if ( spawnicons > 0 ) then
|
||||
icon:InternalAddResizeMenu( menu, function( w, h )
|
||||
|
||||
for id, pnl in pairs( selected ) do
|
||||
if ( !pnl.InternalAddResizeMenu ) then continue end
|
||||
pnl:SetSize( w, h )
|
||||
pnl:InvalidateLayout( true )
|
||||
pnl:GetParent():OnModified()
|
||||
pnl:GetParent():Layout()
|
||||
pnl:SetModel( pnl:GetModelName(), pnl:GetSkinID(), pnl:GetBodyGroup() )
|
||||
end
|
||||
|
||||
end, language.GetPhrase( "spawnmenu.menu.resizex" ):format( spawnicons ) )
|
||||
|
||||
menu:AddOption( language.GetPhrase( "spawnmenu.menu.rerenderx" ):format( spawnicons ), function()
|
||||
for id, pnl in pairs( selected ) do
|
||||
if ( !pnl.RebuildSpawnIcon ) then continue end
|
||||
pnl:RebuildSpawnIcon()
|
||||
end
|
||||
end ):SetIcon( "icon16/picture.png" )
|
||||
end
|
||||
|
||||
menu:AddSpacer()
|
||||
|
||||
menu:AddOption( language.GetPhrase( "spawnmenu.menu.deletex" ):format( #selected ), function()
|
||||
|
||||
for k, v in pairs( selected ) do
|
||||
v:Remove()
|
||||
end
|
||||
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end ):SetIcon( "icon16/bin_closed.png" )
|
||||
|
||||
menu:Open()
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,140 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
surface.CreateFont( "ContentHeader", {
|
||||
font = "Helvetica",
|
||||
size = 50,
|
||||
weight = 1000
|
||||
} )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetFont( "ContentHeader" )
|
||||
self:SetBright( true )
|
||||
self:SetExpensiveShadow( 2, Color( 0, 0, 0, 130 ) )
|
||||
|
||||
self:SetSize( 64, 64 )
|
||||
|
||||
self.OwnLine = true
|
||||
self:SetAutoStretch( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
self:SizeToContents()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
|
||||
local w = self:GetContentSize()
|
||||
|
||||
-- Don't let the text overflow the parent's width
|
||||
if ( IsValid( self:GetParent() ) ) then
|
||||
w = math.min( w, self:GetParent():GetWide() - 32 )
|
||||
end
|
||||
|
||||
-- Add a bit more room so it looks nice as a textbox :)
|
||||
-- And make sure it has at least some width
|
||||
self:SetSize( math.max( w, 64 ) + 16, 64 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ToTable( bigtable )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = "header"
|
||||
tab.text = self:GetText()
|
||||
|
||||
table.insert( bigtable, tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "ContentHeader", self:GetParent() )
|
||||
copy:SetText( self:GetText() )
|
||||
copy:CopyBounds( self )
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PaintOver( w, h )
|
||||
|
||||
self:DrawSelections()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnLabelTextChanged( txt )
|
||||
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
return txt
|
||||
|
||||
end
|
||||
|
||||
function PANEL:IsEnabled()
|
||||
|
||||
-- This is a hack!
|
||||
return !IsValid( self:GetParent() ) || !self:GetParent().GetReadOnly || !self:GetParent():GetReadOnly()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
|
||||
local pCanvas = self:GetSelectionCanvas()
|
||||
if ( IsValid( pCanvas ) && pCanvas:NumSelectedChildren() > 0 && self:IsSelected() ) then
|
||||
return hook.Run( "SpawnlistOpenGenericMenu", pCanvas )
|
||||
end
|
||||
|
||||
self:OpenMenu()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateColours( skin )
|
||||
|
||||
if ( self:GetHighlight() ) then return self:SetTextStyleColor( skin.Colours.Label.Highlight ) end
|
||||
if ( self:GetBright() ) then return self:SetTextStyleColor( skin.Colours.Label.Bright ) end
|
||||
if ( self:GetDark() ) then return self:SetTextStyleColor( skin.Colours.Label.Dark ) end
|
||||
|
||||
return self:SetTextStyleColor( skin.Colours.Label.Default )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OpenMenu()
|
||||
|
||||
-- Do not allow removal from read only panels
|
||||
if ( IsValid( self:GetParent() ) && self:GetParent().GetReadOnly && self:GetParent():GetReadOnly() ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() self:Remove() hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/bin_closed.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentHeader", PANEL, "DLabelEditable" )
|
||||
|
||||
spawnmenu.AddContentType( "header", function( container, obj )
|
||||
|
||||
if ( !obj.text || !isstring( obj.text ) ) then return end
|
||||
|
||||
local label = vgui.Create( "ContentHeader", container )
|
||||
label:SetText( obj.text )
|
||||
|
||||
container:Add( label )
|
||||
|
||||
return label
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,449 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
local matOverlay_Normal = Material( "gui/ContentIcon-normal.png" )
|
||||
local matOverlay_Hovered = Material( "gui/ContentIcon-hovered.png" )
|
||||
|
||||
local matOverlay_AdminOnly = Material( "icon16/shield.png" )
|
||||
local matOverlay_NPCWeapon = Material( "icon16/monkey.png" )
|
||||
local matOverlay_NPCWeaponSelected = Material( "icon16/monkey_tick.png" )
|
||||
|
||||
AccessorFunc( PANEL, "m_Color", "Color" )
|
||||
AccessorFunc( PANEL, "m_Type", "ContentType" )
|
||||
AccessorFunc( PANEL, "m_SpawnName", "SpawnName" )
|
||||
AccessorFunc( PANEL, "m_NPCWeapon", "NPCWeapon" )
|
||||
AccessorFunc( PANEL, "m_bAdminOnly", "AdminOnly" )
|
||||
AccessorFunc( PANEL, "m_bIsNPCWeapon", "IsNPCWeapon" )
|
||||
|
||||
local function DoGenericSpawnmenuRightclickMenu( self )
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.copy", function() SetClipboardText( self:GetSpawnName() ) end ):SetIcon( "icon16/page_copy.png" )
|
||||
if ( isfunction( self.OpenMenuExtra ) ) then
|
||||
self:OpenMenuExtra( menu )
|
||||
end
|
||||
|
||||
if ( !IsValid( self:GetParent() ) || !self:GetParent().GetReadOnly || !self:GetParent():GetReadOnly() ) then
|
||||
menu:AddSpacer()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() self:Remove() hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/bin_closed.png" )
|
||||
end
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
self:SetSize( 128, 128 )
|
||||
self:SetText( "" )
|
||||
self:SetDoubleClickingEnabled( false )
|
||||
|
||||
self.Image = self:Add( "DImage" )
|
||||
self.Image:SetPos( 3, 3 )
|
||||
self.Image:SetSize( 128 - 6, 128 - 6 )
|
||||
self.Image:SetVisible( false )
|
||||
|
||||
self.Label = self:Add( "DLabel" )
|
||||
self.Label:Dock( BOTTOM )
|
||||
self.Label:SetTall( 18 )
|
||||
self.Label:SetContentAlignment( 5 )
|
||||
self.Label:DockMargin( 4, 0, 4, 6 )
|
||||
self.Label:SetTextColor( color_white )
|
||||
self.Label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
|
||||
self.Border = 0
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetName( name )
|
||||
|
||||
self:SetTooltip( name )
|
||||
self.Label:SetText( name )
|
||||
self.m_NiceName = name
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetMaterial( name )
|
||||
|
||||
self.m_MaterialName = name
|
||||
|
||||
local mat = Material( name )
|
||||
|
||||
-- Look for the old style material
|
||||
if ( !mat || mat:IsError() ) then
|
||||
|
||||
name = name:Replace( "entities/", "VGUI/entities/" )
|
||||
name = name:Replace( ".png", "" )
|
||||
mat = Material( name )
|
||||
|
||||
end
|
||||
|
||||
-- Couldn't find any material.. just return
|
||||
if ( !mat || mat:IsError() ) then
|
||||
return
|
||||
end
|
||||
|
||||
self.Image:SetMaterial( mat )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
|
||||
local pCanvas = self:GetSelectionCanvas()
|
||||
if ( IsValid( pCanvas ) && pCanvas:NumSelectedChildren() > 0 && self:IsSelected() ) then
|
||||
return hook.Run( "SpawnlistOpenGenericMenu", pCanvas )
|
||||
end
|
||||
|
||||
self:OpenMenu()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoClick()
|
||||
end
|
||||
|
||||
function PANEL:OpenMenu()
|
||||
end
|
||||
|
||||
function PANEL:OnDepressionChanged( b )
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
if ( self.Depressed && !self.Dragging ) then
|
||||
if ( self.Border != 8 ) then
|
||||
self.Border = 8
|
||||
self:OnDepressionChanged( true )
|
||||
end
|
||||
else
|
||||
if ( self.Border != 0 ) then
|
||||
self.Border = 0
|
||||
self:OnDepressionChanged( false )
|
||||
end
|
||||
end
|
||||
|
||||
render.PushFilterMag( TEXFILTER.ANISOTROPIC )
|
||||
render.PushFilterMin( TEXFILTER.ANISOTROPIC )
|
||||
|
||||
self.Image:PaintAt( 3 + self.Border, 3 + self.Border, 128 - 8 - self.Border * 2, 128 - 8 - self.Border * 2 )
|
||||
|
||||
render.PopFilterMin()
|
||||
render.PopFilterMag()
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
|
||||
if ( !dragndrop.IsDragging() && ( self:IsHovered() || self.Depressed || self:IsChildHovered() ) ) then
|
||||
|
||||
surface.SetMaterial( matOverlay_Hovered )
|
||||
self.Label:Hide()
|
||||
|
||||
else
|
||||
|
||||
surface.SetMaterial( matOverlay_Normal )
|
||||
self.Label:Show()
|
||||
|
||||
end
|
||||
|
||||
surface.DrawTexturedRect( self.Border, self.Border, w-self.Border*2, h-self.Border*2 )
|
||||
|
||||
if ( self:GetAdminOnly() ) then
|
||||
surface.SetMaterial( matOverlay_AdminOnly )
|
||||
surface.DrawTexturedRect( self.Border + 8, self.Border + 8, 16, 16 )
|
||||
end
|
||||
|
||||
-- This whole thing could be more dynamic
|
||||
if ( self:GetIsNPCWeapon() ) then
|
||||
surface.SetMaterial( matOverlay_NPCWeapon )
|
||||
|
||||
if ( self:GetSpawnName() == GetConVarString( "gmod_npcweapon" ) ) then
|
||||
surface.SetMaterial( matOverlay_NPCWeaponSelected )
|
||||
end
|
||||
|
||||
surface.DrawTexturedRect( w - self.Border - 24, self.Border + 8, 16, 16 )
|
||||
end
|
||||
self:ScanForNPCWeapons()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ScanForNPCWeapons()
|
||||
if ( self.HasScanned ) then return end
|
||||
self.HasScanned = true
|
||||
|
||||
for _, v in pairs( list.Get( "NPCUsableWeapons" ) ) do
|
||||
if ( v.class == self:GetSpawnName() ) then
|
||||
self:SetIsNPCWeapon( true )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PaintOver( w, h )
|
||||
|
||||
self:DrawSelections()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ToTable( bigtable )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = self:GetContentType()
|
||||
tab.nicename = self.m_NiceName
|
||||
tab.material = self.m_MaterialName
|
||||
tab.admin = self:GetAdminOnly()
|
||||
tab.spawnname = self:GetSpawnName()
|
||||
tab.weapon = self:GetNPCWeapon()
|
||||
|
||||
table.insert( bigtable, tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "ContentIcon", self:GetParent() )
|
||||
|
||||
copy:SetContentType( self:GetContentType() )
|
||||
copy:SetSpawnName( self:GetSpawnName() )
|
||||
copy:SetName( self.m_NiceName )
|
||||
copy:SetMaterial( self.m_MaterialName )
|
||||
copy:SetNPCWeapon( self:GetNPCWeapon() )
|
||||
copy:SetAdminOnly( self:GetAdminOnly() )
|
||||
copy:CopyBase( self )
|
||||
copy.DoClick = self.DoClick
|
||||
copy.OpenMenu = self.OpenMenu
|
||||
copy.OpenMenuExtra = self.OpenMenuExtra
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentIcon", PANEL, "DButton" )
|
||||
|
||||
spawnmenu.AddContentType( "entity", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "entity" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetColor( Color( 205, 92, 92, 255 ) )
|
||||
|
||||
-- Generate a nice tooltip with extra info.
|
||||
local ENTinfo = scripted_ents.Get( obj.spawnname )
|
||||
local toolTip = language.GetPhrase( obj.nicename )
|
||||
if ( !ENTinfo ) then ENTinfo = list.Get( "SpawnableEntities" )[ obj.spawnname ] end
|
||||
if ( ENTinfo ) then
|
||||
local extraInfo = ""
|
||||
if ( ENTinfo.Information and ENTinfo.Information != "" ) then extraInfo = extraInfo .. "\n" .. ENTinfo.Information end
|
||||
if ( ENTinfo.Author and ENTinfo.Author != "" ) then extraInfo = extraInfo .. "\nAuthor: " .. ENTinfo.Author end
|
||||
if ( #extraInfo > 0 ) then toolTip = toolTip .. "\n" .. extraInfo end
|
||||
end
|
||||
|
||||
icon:SetTooltip( toolTip )
|
||||
|
||||
icon.DoClick = function()
|
||||
RunConsoleCommand( "gm_spawnsent", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
end
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function() RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "0" ) RunConsoleCommand( "creator_name", obj.spawnname ) end ):SetIcon( "icon16/brick_add.png" )
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddContentType( "vehicle", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "vehicle" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetColor( Color( 0, 0, 0, 255 ) )
|
||||
icon.DoClick = function()
|
||||
RunConsoleCommand( "gm_spawnvehicle", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
end
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function() RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "1" ) RunConsoleCommand( "creator_name", obj.spawnname ) end ):SetIcon( "icon16/brick_add.png" )
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
local gmod_npcweapon = CreateConVar( "gmod_npcweapon", "", { FCVAR_ARCHIVE }, "Overrides the weapon all spawnmenu NPCs will spawn with. Set to \"\" to not override." )
|
||||
|
||||
spawnmenu.AddContentType( "npc", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
if ( !obj.weapon ) then obj.weapon = {} end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "npc" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetNPCWeapon( obj.weapon )
|
||||
icon:SetColor( Color( 244, 164, 96, 255 ) )
|
||||
|
||||
icon.DoClick = function()
|
||||
local weapon = table.Random( obj.weapon ) or ""
|
||||
if ( gmod_npcweapon:GetString() != "" ) then weapon = gmod_npcweapon:GetString() end
|
||||
|
||||
RunConsoleCommand( "gmod_spawnnpc", obj.spawnname, weapon )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
end
|
||||
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
local weapon = table.Random( obj.weapon ) or ""
|
||||
if ( gmod_npcweapon:GetString() != "" ) then weapon = gmod_npcweapon:GetString() end
|
||||
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function()
|
||||
RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "2" )
|
||||
RunConsoleCommand( "creator_name", obj.spawnname ) RunConsoleCommand( "creator_arg", weapon )
|
||||
end ):SetIcon( "icon16/brick_add.png" )
|
||||
|
||||
-- Quick access to spawning NPCs with a spcific weapon without the need to change gmod_npcweapon
|
||||
if ( table.IsEmpty( obj.weapon ) ) then return end
|
||||
|
||||
local subMenu, swg = menu:AddSubMenu( "#spawnmenu.menu.spawn_with_weapon" )
|
||||
swg:SetIcon( "icon16/gun.png" )
|
||||
|
||||
subMenu:AddOption( "#menubar.npcs.noweapon", function() RunConsoleCommand( "gmod_spawnnpc", obj.spawnname, "" ) end ):SetIcon( "icon16/cross.png" )
|
||||
|
||||
-- Kind of a hack!
|
||||
local function addWeps( subm, weps )
|
||||
if ( table.Count( weps ) < 1 ) then return end
|
||||
|
||||
subMenu:AddSpacer()
|
||||
for title, class in SortedPairs( weps ) do
|
||||
subMenu:AddOption( title, function() RunConsoleCommand( "gmod_spawnnpc", obj.spawnname, class ) end ):SetIcon( "icon16/gun.png" )
|
||||
end
|
||||
end
|
||||
|
||||
local weaps = {}
|
||||
for _, class in pairs( obj.weapon ) do
|
||||
if ( class == "" ) then continue end
|
||||
weaps[ language.GetPhrase( class ) ] = class
|
||||
end
|
||||
addWeps( subMenu, weaps )
|
||||
|
||||
local weaps = {}
|
||||
for _, t in pairs( list.Get( "NPCUsableWeapons" ) ) do
|
||||
if ( table.HasValue( obj.weapon, t.class ) ) then continue end
|
||||
weaps[ language.GetPhrase( t.title ) ] = t.class
|
||||
end
|
||||
addWeps( subMenu, weaps )
|
||||
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddContentType( "weapon", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "weapon" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetColor( Color( 135, 206, 250, 255 ) )
|
||||
|
||||
-- Generate a nice tooltip with extra info.
|
||||
local SWEPinfo = weapons.Get( obj.spawnname )
|
||||
local toolTip = language.GetPhrase( obj.nicename )
|
||||
if ( !SWEPinfo ) then SWEPinfo = list.Get( "Weapon" )[ obj.spawnname ] end
|
||||
if ( SWEPinfo ) then
|
||||
toolTip = toolTip .. "\n"
|
||||
-- These 2 really should be one
|
||||
if ( SWEPinfo.Purpose and SWEPinfo.Purpose != "" ) then toolTip = toolTip .. "\n" .. SWEPinfo.Purpose end
|
||||
if ( SWEPinfo.Instructions and SWEPinfo.Instructions != "" ) then toolTip = toolTip .. "\n" .. SWEPinfo.Instructions end
|
||||
|
||||
if ( SWEPinfo.Author and SWEPinfo.Author != "" ) then toolTip = toolTip .. "\nAuthor: " .. SWEPinfo.Author end
|
||||
end
|
||||
|
||||
toolTip = toolTip .. "\n\n" .. language.GetPhrase( "spawnmenu.mmb_weapons" )
|
||||
|
||||
icon:SetTooltip( toolTip )
|
||||
|
||||
icon.DoClick = function()
|
||||
|
||||
RunConsoleCommand( "gm_giveswep", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
|
||||
end
|
||||
|
||||
icon.DoMiddleClick = function()
|
||||
|
||||
RunConsoleCommand( "gm_spawnswep", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
|
||||
end
|
||||
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function() RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "3" ) RunConsoleCommand( "creator_name", obj.spawnname ) end ):SetIcon( "icon16/brick_add.png" )
|
||||
|
||||
if ( self:GetIsNPCWeapon() ) then
|
||||
local opt = menu:AddOption( "#spawnmenu.menu.use_as_npc_gun", function() RunConsoleCommand( "gmod_npcweapon", self:GetSpawnName() ) end )
|
||||
if ( self:GetSpawnName() == GetConVarString( "gmod_npcweapon" ) ) then
|
||||
opt:SetIcon( "icon16/monkey_tick.png" )
|
||||
else
|
||||
opt:SetIcon( "icon16/monkey.png" )
|
||||
end
|
||||
end
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,161 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
PANEL.Base = "Panel"
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.CurrentSearch = ""
|
||||
self.OldResults = -1
|
||||
self.RebuildResults = false
|
||||
|
||||
self:Dock( TOP )
|
||||
self:SetHeight( 20 )
|
||||
self:DockMargin( 0, 0, 0, 3 )
|
||||
|
||||
self.Search = self:Add( "DTextEntry" )
|
||||
self.Search:Dock( FILL )
|
||||
self.Search:SetPlaceholderText( "#spawnmenu.search" )
|
||||
|
||||
self.Search.OnEnter = function() self:RefreshResults() end
|
||||
self.Search.OnFocusChanged = function( _, b ) if ( b ) then self.ContentPanel:SwitchPanel( self.PropPanel ) end end
|
||||
self.Search:SetTooltip( "#spawnmenu.enter_search" )
|
||||
|
||||
local btn = self.Search:Add( "DImageButton" )
|
||||
|
||||
btn:SetImage( "icon16/magnifier.png" )
|
||||
btn:SetText( "" )
|
||||
btn:Dock( RIGHT )
|
||||
btn:DockMargin( 4, 2, 4, 2 )
|
||||
btn:SetSize( 16, 16 )
|
||||
btn:SetTooltip( "#spawnmenu.press_search" )
|
||||
btn.DoClick = function()
|
||||
self:RefreshResults()
|
||||
end
|
||||
|
||||
self.Search.OnKeyCode = function( p, code )
|
||||
|
||||
if ( code == KEY_F1 ) then hook.Run( "OnSpawnMenuClose" ) end
|
||||
if ( code == KEY_ESCAPE ) then hook.Run( "OnSpawnMenuClose" ) end
|
||||
|
||||
end
|
||||
|
||||
self.PropPanel = vgui.Create( "ContentContainer", self )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
-- Some sort of placeholder
|
||||
local Header = self:Add( "ContentHeader" )
|
||||
Header:SetText( "#spawnmenu.enter_search" )
|
||||
self.PropPanel:Add( Header )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint()
|
||||
-- This is a bit of a hack, if there was a request to rebuild the results from the search indexer
|
||||
-- Do it when the player next sees the search panel, in case they got the spawnmenu closed
|
||||
-- Think hook causes unexpected 1 frame duplication of all the elements
|
||||
if ( self.RebuildResults ) then
|
||||
self.RebuildResults = false
|
||||
self:RefreshResults( self.CurrentSearch )
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetSearchType( stype, hookname )
|
||||
self.m_strSearchType = stype
|
||||
hook.Add( hookname, "AddSearchContent_" .. hookname, function( pnlContent, tree, node )
|
||||
self.ContentPanel = pnlContent
|
||||
end )
|
||||
hook.Add( "SearchUpdate", "SearchUpdate_" .. hookname, function()
|
||||
if ( !g_SpawnMenu:IsVisible() ) then self.RebuildResults = true return end
|
||||
self:RefreshResults( self.CurrentSearch )
|
||||
end )
|
||||
|
||||
-- This stuff is only for the primary search
|
||||
if ( hookname != "PopulateContent" ) then return end
|
||||
|
||||
g_SpawnMenu.SearchPropPanel = self.PropPanel
|
||||
hook.Add( "StartSearch", "StartSearch", function()
|
||||
|
||||
if ( g_SpawnMenu:IsVisible() ) then return hook.Run( "OnSpawnMenuClose" ) end
|
||||
|
||||
hook.Run( "OnSpawnMenuOpen" )
|
||||
hook.Run( "OnTextEntryGetFocus", self.Search )
|
||||
|
||||
self.Search:RequestFocus()
|
||||
self.Search:SetText( "" )
|
||||
|
||||
--
|
||||
-- If we don't call this we'd have to press F1 twice to close it!
|
||||
-- It's in a timer because of some good reason that!
|
||||
--
|
||||
timer.Simple( 0.1, function() g_SpawnMenu:HangOpen( false ) end )
|
||||
|
||||
self.ContentPanel:SwitchPanel( self.PropPanel )
|
||||
|
||||
end )
|
||||
end
|
||||
|
||||
function PANEL:RefreshResults( str )
|
||||
|
||||
if ( !str ) then -- User tried to search for something
|
||||
self.CurrentSearch = self.Search:GetText()
|
||||
str = self.CurrentSearch
|
||||
self.OldResults = -1
|
||||
else
|
||||
-- Don't force open the search when you click away from search while this function is called from cl_search_models.lua
|
||||
if ( self.ContentPanel.SelectedPanel != self.PropPanel ) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if ( !str or str == "" ) then return end
|
||||
|
||||
local results = search.GetResults( str, self.m_strSearchType, GetConVarNumber( "sbox_search_maxresults" ) )
|
||||
for id, result in ipairs( results ) do
|
||||
if ( !IsValid( result.icon ) ) then ErrorNoHalt( "Failed to create icon for " .. ( result.words && isstring( result.words[ 1 ] ) && result.words[ 1 ] || result.text ).. "\n" ) continue end
|
||||
result.icon:SetParent( vgui.GetWorldPanel() ) -- Don't parent the icons to search panel prematurely
|
||||
end
|
||||
|
||||
-- I know this is not perfect, but this is the best I am willing to do with how the search library was set up
|
||||
if ( self.OldResults == #results ) then -- No updates, don't rebuild
|
||||
for id, result in ipairs( results ) do
|
||||
if ( IsValid( result.icon ) ) then result.icon:Remove() end -- Kill all icons
|
||||
end
|
||||
return
|
||||
end
|
||||
self.OldResults = #results
|
||||
|
||||
self.PropPanel:Clear()
|
||||
|
||||
local Header = self:Add( "ContentHeader" )
|
||||
Header:SetText( #results .. " Results for \"" .. str .. "\"" )
|
||||
self.PropPanel:Add( Header )
|
||||
|
||||
for k, v in ipairs( results ) do
|
||||
self:AddSearchResult( v.text, v.func, v.icon )
|
||||
end
|
||||
|
||||
self.PropPanel:SetParent( self.ContentPanel )
|
||||
self.ContentPanel:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddSearchResult( text, func, icon )
|
||||
|
||||
if ( !IsValid( icon ) ) then return end
|
||||
|
||||
icon:SetParent( self.PropPanel )
|
||||
self.PropPanel:Add( icon )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "contentsidebartoolbox.lua" )
|
||||
|
||||
local pnlSearch = vgui.RegisterFile( "contentsearch.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.Tree = vgui.Create( "DTree", self )
|
||||
self.Tree:SetClickOnDragHover( true )
|
||||
self.Tree.OnNodeSelected = function( Tree, Node ) hook.Call( "ContentSidebarSelection", GAMEMODE, self:GetParent(), Node ) end
|
||||
self.Tree:Dock( FILL )
|
||||
self.Tree:SetBackgroundColor( Color( 240, 240, 240, 255 ) )
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EnableSearch( stype, hookname )
|
||||
self.Search = vgui.CreateFromTable( pnlSearch, self )
|
||||
self.Search:SetSearchType( stype, hookname or "PopulateContent" )
|
||||
end
|
||||
|
||||
function PANEL:EnableModify()
|
||||
|
||||
self:EnableSearch()
|
||||
self:CreateSaveNotification()
|
||||
|
||||
self.Toolbox = vgui.Create( "ContentSidebarToolbox", self )
|
||||
|
||||
hook.Add( "OpenToolbox", "OpenToolbox", function()
|
||||
|
||||
if ( !IsValid( self.Toolbox ) ) then return end
|
||||
|
||||
self.Toolbox:Open()
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:CreateSaveNotification()
|
||||
|
||||
local SavePanel = vgui.Create( "Panel", self )
|
||||
SavePanel:Dock( TOP )
|
||||
SavePanel:SetVisible( false )
|
||||
SavePanel:DockMargin( 8, 1, 8, 4 )
|
||||
|
||||
local SaveButton = vgui.Create( "DButton", SavePanel )
|
||||
SaveButton:Dock( FILL )
|
||||
SaveButton:SetIcon( "icon16/disk.png" )
|
||||
SaveButton:SetText( "#spawnmenu.savechanges" )
|
||||
SaveButton.DoClick = function()
|
||||
|
||||
SavePanel:SlideUp( 0.2 )
|
||||
hook.Run( "OnSaveSpawnlist" )
|
||||
|
||||
end
|
||||
|
||||
local RevertButton = vgui.Create( "DButton", SavePanel )
|
||||
RevertButton:Dock( RIGHT )
|
||||
RevertButton:SetIcon( "icon16/arrow_rotate_clockwise.png" )
|
||||
RevertButton:SetText( "" )
|
||||
RevertButton:SetTooltip( "#spawnmenu.revert_tooptip" )
|
||||
RevertButton:SetWide( 26 )
|
||||
RevertButton:DockMargin( 4, 0, 0, 0 )
|
||||
RevertButton.DoClick = function()
|
||||
|
||||
SavePanel:SlideUp( 0.2 )
|
||||
hook.Run( "OnRevertSpawnlist" )
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "SpawnlistContentChanged", "ShowSaveButton", function()
|
||||
|
||||
if ( SavePanel:IsVisible() ) then return end
|
||||
|
||||
SavePanel:SlideDown( 0.2 )
|
||||
|
||||
GAMEMODE:AddHint( "EditingSpawnlistsSave", 5 )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentSidebar", PANEL, "DPanel" )
|
||||
@@ -0,0 +1,115 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "contentheader.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
Derma_Hook( PANEL, "Paint", "Paint", "Tree" )
|
||||
PANEL.m_bBackground = true -- Hack for above
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetOpenSize( 200 )
|
||||
self:DockPadding( 5, 5, 5, 5 )
|
||||
|
||||
local label = vgui.Create( "DTextEntry", self )
|
||||
label:Dock( TOP )
|
||||
label:SetZPos( 1 )
|
||||
label:DockMargin( 0, 0, 0, 2 )
|
||||
label:SetTooltip( "#spawnmenu.listname_tooltip" )
|
||||
|
||||
local panel = vgui.Create( "DPanel", self )
|
||||
panel:Dock( TOP )
|
||||
panel:SetZPos( 2 )
|
||||
panel:SetSize( 24, 24 )
|
||||
panel:DockPadding( 2, 2, 2, 2 )
|
||||
|
||||
local Button = vgui.Create( "DImageButton", panel )
|
||||
Button:SetImage( "icon16/text_heading_1.png" )
|
||||
Button:Dock( LEFT )
|
||||
Button:SetStretchToFit( false )
|
||||
Button:SetSize( 20, 20 )
|
||||
Button:SetCursor( "sizeall" )
|
||||
Button:SetTooltip( "#spawnmenu.header_tooltip" )
|
||||
Button:Droppable( "SandboxContentPanel" )
|
||||
|
||||
Button.OnDrop = function( s, target )
|
||||
|
||||
local label = vgui.Create( "ContentHeader", target )
|
||||
return label
|
||||
|
||||
end
|
||||
|
||||
local panel = vgui.Create( "Panel", self )
|
||||
panel:Dock( FILL )
|
||||
panel:SetZPos( 3 )
|
||||
|
||||
local icon_filter = vgui.Create( "DTextEntry", panel )
|
||||
icon_filter:Dock( TOP )
|
||||
icon_filter:SetUpdateOnType( true )
|
||||
icon_filter:SetPlaceholderText( "#spawnmenu.quick_filter" )
|
||||
icon_filter:DockMargin( 0, 2, 0, 1 )
|
||||
|
||||
local icons = vgui.Create( "DIconBrowser", panel )
|
||||
icons:Dock( FILL )
|
||||
|
||||
icon_filter.OnValueChange = function( s, str )
|
||||
icons:FilterByText( str )
|
||||
end
|
||||
|
||||
local overlay = vgui.Create( "DPanel", self )
|
||||
overlay:SetZPos( 9999 )
|
||||
overlay.Paint = function( s, w, h )
|
||||
surface.SetDrawColor( 0, 0, 0, 200 )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
end
|
||||
self.Overlay = overlay
|
||||
|
||||
--
|
||||
-- If we select a node from the sidebar, update the text/icon/actions in the toolbox (at the bottom)
|
||||
--
|
||||
hook.Add( "ContentSidebarSelection", "SidebarToolboxSelection", function( pnlContent, node )
|
||||
|
||||
if ( !IsValid( node ) || !IsValid( label ) || !IsValid( icons ) ) then return end
|
||||
|
||||
if ( node.CustomSpawnlist ) then
|
||||
label:SetText( node:GetText() )
|
||||
icons:SelectIcon( node:GetIcon() )
|
||||
icons:ScrollToSelected()
|
||||
overlay:SetVisible( false )
|
||||
else
|
||||
label:SetText( "" )
|
||||
overlay:SetVisible( true )
|
||||
end
|
||||
|
||||
label.OnChange = function()
|
||||
if ( !node.CustomSpawnlist ) then return end
|
||||
node:SetText( label:GetText() )
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
icons.OnChange = function()
|
||||
if ( !node.CustomSpawnlist ) then return end
|
||||
node:SetIcon( icons:GetSelectedIcon() )
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
-- Not using docking because it will mess up other elements using docking!
|
||||
self.Overlay:SetSize( self:GetSize() )
|
||||
end
|
||||
|
||||
vgui.Register( "ContentSidebarToolbox", PANEL, "DDrawer" )
|
||||
@@ -0,0 +1,172 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local function AddRecursive( pnl, folder, path, wildcard )
|
||||
|
||||
local files, folders = file.Find( folder .. "*", path )
|
||||
if ( !files ) then MsgN( "Warning! Not opening '" .. folder .. "' because we cannot search in it!" ) return false end
|
||||
|
||||
local added = false
|
||||
|
||||
for k, v in ipairs( files ) do
|
||||
|
||||
if ( !string.EndsWith( v, ".mdl" ) ) then continue end
|
||||
|
||||
local cp = spawnmenu.GetContentType( "model" )
|
||||
if ( cp ) then
|
||||
cp( pnl, { model = folder .. v } )
|
||||
added = true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for k, v in ipairs( folders ) do
|
||||
|
||||
local added_rec = AddRecursive( pnl, folder .. v .. "/", path, wildcard )
|
||||
added = added || added_rec
|
||||
|
||||
end
|
||||
|
||||
return added
|
||||
|
||||
end
|
||||
|
||||
local function recurseAddFilesSpawnlist( folder, pathid, list )
|
||||
|
||||
local addedLabel = false
|
||||
|
||||
local files, folders = file.Find( folder .. "/*", pathid )
|
||||
for id, file in pairs( files or {} ) do
|
||||
if ( file:EndsWith( ".mdl" ) ) then
|
||||
if ( !addedLabel ) then
|
||||
table.insert( list, { type = "header", text = folder } )
|
||||
addedLabel = true
|
||||
end
|
||||
|
||||
table.insert( list, { type = "model", model = folder .. "/" .. file } )
|
||||
end
|
||||
end
|
||||
|
||||
for id, fold in pairs( folders or {} ) do
|
||||
recurseAddFilesSpawnlist( folder .. "/" .. fold, pathid, list )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function GenerateSpawnlistFromAddon( folder, path, name )
|
||||
|
||||
local contents = {}
|
||||
recurseAddFilesSpawnlist( folder, path, contents )
|
||||
|
||||
AddPropsOfParent( g_SpawnMenu.CustomizableSpawnlistNode.SMContentPanel, g_SpawnMenu.CustomizableSpawnlistNode, 0, { [ folder ] = {
|
||||
icon = "icon16/page.png",
|
||||
id = math.random( 0, 999999 ), -- Eeehhhh
|
||||
name = name or folder,
|
||||
parentid = 0,
|
||||
contents = contents
|
||||
} } )
|
||||
|
||||
-- We added a new spawnlist, show the save changes button
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end
|
||||
|
||||
local function AddonsRightClick( self )
|
||||
|
||||
if ( !IsValid( self ) || !self.wsid || self.wsid == "0" ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.openaddononworkshop", function()
|
||||
steamworks.ViewFile( self.wsid )
|
||||
end ):SetIcon( "icon16/link_go.png" )
|
||||
|
||||
menu:AddOption( "#spawnmenu.createautospawnlist", function()
|
||||
|
||||
GenerateSpawnlistFromAddon( "models", self.searchPath, self.searchPath )
|
||||
|
||||
end ):SetIcon( "icon16/page_add.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function RefreshAddons( MyNode )
|
||||
|
||||
local ViewPanel = MyNode.ViewPanel
|
||||
|
||||
for _, addon in SortedPairsByMemberValue( engine.GetAddons(), "title" ) do
|
||||
|
||||
if ( !addon.downloaded || !addon.mounted ) then continue end
|
||||
if ( addon.models <= 0 ) then continue end
|
||||
|
||||
local models = MyNode:AddNode( addon.title .. " (" .. addon.models .. ")", "icon16/bricks.png" )
|
||||
models.DoClick = function()
|
||||
|
||||
ViewPanel:Clear()
|
||||
|
||||
local anyAdded = AddRecursive( ViewPanel, "models/", addon.title, "*.mdl" )
|
||||
if ( !anyAdded ) then
|
||||
local text = "<font=ContentHeader>" .. language.GetPhrase( "spawnmenu.failedtofindmodels" ) .. "\n\n" .. tostring( addon.title ) .. " (ID: " .. tostring( addon.wsid ) .. ")" .. "</font>"
|
||||
|
||||
local msg = vgui.Create( "Panel", ViewPanel )
|
||||
msg.Paint = function( s, w, h )
|
||||
-- Shadow. Ew.
|
||||
local parsedShadow = markup.Parse( "<colour=0,0,0,130>" .. text .. "</colour>", s:GetParent():GetWide() )
|
||||
parsedShadow:Draw( 2, 2 )
|
||||
|
||||
-- The actual text
|
||||
local parsed = markup.Parse( text, s:GetParent():GetWide() )
|
||||
parsed:Draw( 0, 0 )
|
||||
|
||||
-- Size to contents. Ew.
|
||||
s:SetSize( parsed:GetWidth(), parsed:GetHeight() )
|
||||
end
|
||||
ViewPanel:Add( msg )
|
||||
end
|
||||
|
||||
MyNode.pnlContent:SwitchPanel( ViewPanel )
|
||||
|
||||
end
|
||||
models.DoRightClick = AddonsRightClick
|
||||
models.wsid = addon.wsid
|
||||
models.searchPath = addon.title
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local myAddonsNode
|
||||
hook.Add( "PopulateContent", "AddonProps", function( pnlContent, tree, node )
|
||||
|
||||
local myViewPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
myViewPanel:SetVisible( false )
|
||||
myViewPanel.IconList:SetReadOnly( true )
|
||||
|
||||
myAddonsNode = node:AddNode( "#spawnmenu.category.addons", "icon16/folder_database.png" )
|
||||
myAddonsNode.ViewPanel = myViewPanel
|
||||
myAddonsNode.pnlContent = pnlContent
|
||||
|
||||
RefreshAddons( myAddonsNode )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "GameContentChanged", "RefreshSpawnmenuAddons", function()
|
||||
|
||||
if ( !IsValid( myAddonsNode ) ) then return end
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
myAddonsNode:Clear()
|
||||
myAddonsNode.ViewPanel:Clear()
|
||||
|
||||
RefreshAddons( myAddonsNode )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,296 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local AddCustomizableNode = nil
|
||||
|
||||
local function SetupCustomNode( node, pnlContent, needsapp )
|
||||
|
||||
node.CustomSpawnlist = !node.AddonSpawnlist -- Used to determine which nodes ContentSidebarToolBox can edit
|
||||
|
||||
-- This spawnlist needs a certain app mounted before it will show up.
|
||||
if ( needsapp && needsapp != "" ) then
|
||||
node:SetVisible( IsMounted( needsapp ) )
|
||||
node.NeedsApp = needsapp
|
||||
|
||||
if ( !IsMounted( needsapp ) ) then
|
||||
-- Make it look different
|
||||
node:SetAlpha( 200 )
|
||||
|
||||
-- Give a detailed tooltip explaining why it looks different
|
||||
local name = language.GetPhrase( "spawnmenu.mountablegame" )
|
||||
for id, t in pairs( engine.GetGames() ) do
|
||||
if ( needsapp == t.folder ) then name = t.title break end
|
||||
end
|
||||
node:SetTooltip( string.format( language.GetPhrase( "spawnmenu.spawnlistnocontent" ), name ) )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
node.SetupCopy = function( self, copy )
|
||||
|
||||
SetupCustomNode( copy, pnlContent, needsapp )
|
||||
|
||||
self:DoPopulate()
|
||||
|
||||
copy.PropPanel = self.PropPanel:Copy()
|
||||
|
||||
copy.PropPanel:SetVisible( false )
|
||||
copy.PropPanel:SetTriggerSpawnlistChange( true )
|
||||
|
||||
copy.DoPopulate = function() end
|
||||
|
||||
end
|
||||
|
||||
if ( !node.AddonSpawnlist ) then
|
||||
node.OnModified = function()
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
node.DoRightClick = function( self )
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.edit", function() self:InternalDoClick() hook.Run( "OpenToolbox" ) end ):SetIcon( "icon16/folder_edit.png" )
|
||||
menu:AddOption( "#spawnmenu.menu.add_subcategory", function() AddCustomizableNode( pnlContent, "New Category", "", self ) self:SetExpanded( true ) hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/folder_add.png" )
|
||||
menu:AddSpacer()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() node:Remove() hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/folder_delete.png" )
|
||||
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
if ( IsValid( self.PropPanel ) ) then return end
|
||||
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( true )
|
||||
|
||||
end
|
||||
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
AddCustomizableNode = function( pnlContent, name, icon, parent, needsapp )
|
||||
|
||||
local node = parent:AddNode( name, icon )
|
||||
node.AddonSpawnlist = parent.AddonSpawnlist
|
||||
|
||||
SetupCustomNode( node, pnlContent, needsapp )
|
||||
|
||||
return node
|
||||
|
||||
end
|
||||
|
||||
local function ReadSpawnlists( node, parentid )
|
||||
|
||||
local tab = {}
|
||||
tab.name = node:GetText()
|
||||
tab.icon = node:GetIcon()
|
||||
tab.parentid = parentid
|
||||
tab.id = SPAWNLIST_ID
|
||||
tab.version = 3
|
||||
tab.needsapp = node.NeedsApp
|
||||
|
||||
node:DoPopulate()
|
||||
|
||||
if ( IsValid( node.PropPanel ) ) then
|
||||
tab.contents = node.PropPanel:ContentsToTable()
|
||||
end
|
||||
|
||||
if ( SPAWNLIST_ID > 0 ) then
|
||||
SPAWNLISTS[ string.format( "%03d", tab.id ) .. "-" .. tab.name ] = util.TableToKeyValues( tab )
|
||||
end
|
||||
|
||||
SPAWNLIST_ID = SPAWNLIST_ID + 1
|
||||
|
||||
if ( node.ChildNodes ) then
|
||||
|
||||
for k, v in ipairs( node.ChildNodes:GetChildren() ) do
|
||||
|
||||
ReadSpawnlists( v, tab.id )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function ConstructSpawnlist( node )
|
||||
|
||||
SPAWNLIST_ID = 0
|
||||
SPAWNLISTS = {}
|
||||
|
||||
ReadSpawnlists( node, 0 )
|
||||
local tab = SPAWNLISTS
|
||||
|
||||
SPAWNLISTS = nil
|
||||
SPAWNLIST_ID = nil
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function AddPropsOfParent( pnlContent, node, parentid, customProps )
|
||||
|
||||
local Props = customProps or spawnmenu.GetPropTable()
|
||||
|
||||
for FileName, Info in SortedPairs( Props ) do
|
||||
|
||||
if ( parentid != Info.parentid ) then continue end
|
||||
|
||||
local pnlnode = AddCustomizableNode( pnlContent, Info.name, Info.icon, node, Info.needsapp )
|
||||
pnlnode:SetExpanded( true )
|
||||
pnlnode.OnRemove = function( self ) if ( IsValid( self.PropPanel ) ) then self.PropPanel:Remove() end end
|
||||
pnlnode.DoPopulate = function( self )
|
||||
|
||||
if ( IsValid( self.PropPanel ) ) then return end
|
||||
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( true )
|
||||
if ( node.AddonSpawnlist ) then self.PropPanel.IconList:SetReadOnly( true ) end
|
||||
|
||||
for i, object in SortedPairs( Info.contents ) do
|
||||
|
||||
local cp = spawnmenu.GetContentType( object.type )
|
||||
if ( cp ) then cp( self.PropPanel, object ) end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
AddPropsOfParent( pnlContent, pnlnode, Info.id, customProps )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- This helps avoid empty spawnlist list when you delete some but the hidden ones remain so the default spawnlists never regenerate
|
||||
-- TODO: Maybe show spawnlists that need games when any spawnlist was changed? Allow to set needed game from in-game?
|
||||
local function CheckIfAnyVisible( node )
|
||||
local pnlContent = node.SMContentPanel
|
||||
|
||||
if ( node:GetChildNodeCount() < 1 ) then
|
||||
spawnmenu.PopulateFromEngineTextFiles()
|
||||
AddPropsOfParent( pnlContent, node, 0 )
|
||||
node:SetExpanded( true )
|
||||
return
|
||||
end
|
||||
|
||||
local visible = 0
|
||||
for id, pnl in pairs( node:GetChildNodes() ) do
|
||||
if ( pnl:IsVisible() ) then visible = visible + 1 end
|
||||
end
|
||||
|
||||
if ( visible < 1 ) then
|
||||
for id, pnl in pairs( node:GetChildNodes() ) do
|
||||
pnl:SetVisible( true )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add( "PopulateContent", "AddCustomContent", function( pnlContent, tree, node )
|
||||
|
||||
local node = AddCustomizableNode( pnlContent, "#spawnmenu.category.your_spawnlists", "", tree )
|
||||
node:SetDraggableName( "CustomContent" )
|
||||
node:SetExpanded( true )
|
||||
node.CustomSpawnlist = nil
|
||||
node.SMContentPanel = pnlContent
|
||||
|
||||
node.DoRightClick = function( self )
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "New Category", function() AddCustomizableNode( pnlContent, "New Category", "", node ) node:SetExpanded( true ) hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/folder_add.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
-- Save the spawnlist when children drag and dropped
|
||||
node.OnModified = function()
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
AddPropsOfParent( pnlContent, node, 0 )
|
||||
|
||||
CheckIfAnyVisible( node )
|
||||
|
||||
node:MoveToBack()
|
||||
|
||||
g_SpawnMenu.CustomizableSpawnlistNode = node
|
||||
|
||||
-- Select the first visible panel
|
||||
for id, pnl in pairs( node:GetChildNodes() ) do
|
||||
if ( pnl:IsVisible() ) then
|
||||
pnl:InternalDoClick()
|
||||
pnl:SetExpanded( true )
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Custom stuff from addons
|
||||
local CustomProps = spawnmenu.GetCustomPropTable()
|
||||
if ( !table.IsEmpty( CustomProps ) ) then
|
||||
local node = AddCustomizableNode( pnlContent, "#spawnmenu.category.addon_spawnlists", "", tree )
|
||||
node:SetExpanded( true )
|
||||
--node:SetDraggableName( "CustomContent" )
|
||||
node.DoRightClick = function() end
|
||||
node.OnModified = function() end
|
||||
node.AddonSpawnlist = true
|
||||
node.CustomSpawnlist = nil
|
||||
|
||||
AddPropsOfParent( pnlContent, node, 0, CustomProps )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "OnSaveSpawnlist", "DoSaveSpawnlist", function()
|
||||
|
||||
local Spawnlist = ConstructSpawnlist( g_SpawnMenu.CustomizableSpawnlistNode )
|
||||
|
||||
spawnmenu.DoSaveToTextFiles( Spawnlist )
|
||||
|
||||
CheckIfAnyVisible( g_SpawnMenu.CustomizableSpawnlistNode )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "OnRevertSpawnlist", "DoRevertSpawnlists", function()
|
||||
|
||||
-- First delete all of the existing spawnlists
|
||||
g_SpawnMenu.CustomizableSpawnlistNode:Clear()
|
||||
|
||||
-- Next load all the custom spawnlists again
|
||||
spawnmenu.PopulateFromEngineTextFiles()
|
||||
AddPropsOfParent( g_SpawnMenu.CustomizableSpawnlistNode.SMContentPanel, g_SpawnMenu.CustomizableSpawnlistNode, 0 )
|
||||
|
||||
-- Select the first visible panel. TODO: why this requires a timer?
|
||||
timer.Simple( 0, function()
|
||||
CheckIfAnyVisible( g_SpawnMenu.CustomizableSpawnlistNode )
|
||||
|
||||
for id, pnl in pairs( g_SpawnMenu.CustomizableSpawnlistNode:GetChildNodes() ) do
|
||||
if ( pnl:IsVisible() ) then
|
||||
pnl:InternalDoClick()
|
||||
pnl:SetExpanded( true )
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
g_SpawnMenu.CustomizableSpawnlistNode:SetExpanded( true )
|
||||
end )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,125 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local HTML = nil
|
||||
local DupeInClipboard = false
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.dupes", function()
|
||||
|
||||
HTML = vgui.Create( "DHTML" )
|
||||
JS_Language( HTML )
|
||||
JS_Workshop( HTML )
|
||||
|
||||
ws_dupe = WorkshopFileBase( "dupe", { "dupe" } )
|
||||
ws_dupe.HTML = HTML
|
||||
|
||||
function ws_dupe:FetchLocal( offset, perpage )
|
||||
|
||||
local f = file.Find( "dupes/*.dupe", "MOD", "datedesc" )
|
||||
|
||||
local saves = {}
|
||||
|
||||
for k, v in ipairs( f ) do
|
||||
|
||||
if ( k <= offset ) then continue end
|
||||
if ( k > offset + perpage ) then break end
|
||||
|
||||
local entry = {
|
||||
file = "dupes/" .. v,
|
||||
name = v:StripExtension(),
|
||||
preview = "dupes/" .. v:StripExtension() .. ".jpg",
|
||||
description = "Local duplication stored on your computer. Local content can be deleted in the main menu."
|
||||
}
|
||||
|
||||
table.insert( saves, entry )
|
||||
|
||||
end
|
||||
|
||||
local results = {
|
||||
totalresults = #f,
|
||||
results = saves
|
||||
}
|
||||
|
||||
local json = util.TableToJSON( results, false )
|
||||
HTML:Call( "dupe.ReceiveLocal( " .. json .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function ws_dupe:Arm( filename )
|
||||
|
||||
RunConsoleCommand( "dupe_arm", filename )
|
||||
|
||||
end
|
||||
|
||||
function ws_dupe:DownloadAndArm( id )
|
||||
|
||||
-- Server doesn't allow us to arm dupes, don't even try to download anything
|
||||
local res, msg = hook.Run( "CanArmDupe", LocalPlayer() )
|
||||
if ( res == false ) then LocalPlayer():ChatPrint( msg or "Refusing to download Workshop dupe, server has blocked usage of the Duplicator tool!" ) return end
|
||||
|
||||
MsgN( "Downloading Dupe..." )
|
||||
steamworks.DownloadUGC( id, function( name )
|
||||
|
||||
MsgN( "Finished - arming!" )
|
||||
ws_dupe:Arm( name )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function ws_dupe:Publish( filename, imagename )
|
||||
|
||||
RunConsoleCommand( "dupe_publish", filename, imagename )
|
||||
|
||||
end
|
||||
|
||||
HTML:OpenURL( "asset://garrysmod/html/dupes.html" )
|
||||
HTML:Call( "SetDupeSaveState( " .. tostring( DupeInClipboard ) .. " );" )
|
||||
|
||||
return HTML
|
||||
|
||||
end, "icon16/control_repeat_blue.png", 200 )
|
||||
|
||||
hook.Add( "DupeSaveAvailable", "UpdateDupeSpawnmenuAvailable", function()
|
||||
|
||||
DupeInClipboard = true
|
||||
|
||||
if ( !IsValid( HTML ) ) then return end
|
||||
|
||||
HTML:Call( "SetDupeSaveState( true );" )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "DupeSaveUnavailable", "UpdateDupeSpawnmenuUnavailable", function()
|
||||
|
||||
DupeInClipboard = false
|
||||
|
||||
if ( !IsValid( HTML ) ) then return end
|
||||
|
||||
HTML:Call( "SetDupeSaveState( false );" )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "DupeSaved", "DuplicationSavedSpawnMenu", function()
|
||||
|
||||
if ( !IsValid( HTML ) ) then return end
|
||||
|
||||
HTML:Call( "ShowLocalDupes();" )
|
||||
|
||||
end )
|
||||
|
||||
concommand.Add( "dupe_show", function()
|
||||
|
||||
g_SpawnMenu:OpenCreationMenuTab( "#spawnmenu.category.dupes" )
|
||||
|
||||
timer.Simple( 1.0, function() if ( !IsValid( HTML ) ) then return end HTML:Call( "ShowLocalDupes();" ) end )
|
||||
|
||||
end, nil, "", { FCVAR_DONTRECORD } )
|
||||
@@ -0,0 +1,94 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
list.Set( "ContentCategoryIcons", "Half-Life: Source", "games/16/hl1.png" )
|
||||
list.Set( "ContentCategoryIcons", "Half-Life 2", "games/16/hl2.png" )
|
||||
list.Set( "ContentCategoryIcons", "Portal", "games/16/portal.png" )
|
||||
|
||||
hook.Add( "PopulateEntities", "AddEntityContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
local Categorised = {}
|
||||
|
||||
-- Add this list into the tormoil
|
||||
local SpawnableEntities = list.Get( "SpawnableEntities" )
|
||||
if ( SpawnableEntities ) then
|
||||
for k, v in pairs( SpawnableEntities ) do
|
||||
|
||||
local Category = v.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
|
||||
v.SpawnName = k
|
||||
table.insert( Categorised[ Category ], v )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Add a tree node for each category
|
||||
--
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/bricks.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", self.PropPanel, {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.SpawnName,
|
||||
material = ent.IconOverride or "entities/" .. ent.SpawnName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.entities", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "entities", "PopulateEntities" )
|
||||
ctrl:CallPopulateHook( "PopulateEntities" )
|
||||
|
||||
return ctrl
|
||||
|
||||
end, "icon16/bricks.png", 20 )
|
||||
@@ -0,0 +1,188 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local function recurseAddFiles( folder, pathid, list )
|
||||
|
||||
local addedLabel = false
|
||||
|
||||
local files, folders = file.Find( folder .. "/*", pathid )
|
||||
for id, file in pairs( files or {} ) do
|
||||
if ( file:EndsWith( ".mdl" ) ) then
|
||||
if ( !addedLabel ) then
|
||||
table.insert( list, { type = "header", text = folder } )
|
||||
addedLabel = true
|
||||
end
|
||||
|
||||
table.insert( list, { type = "model", model = folder .. "/" .. file } )
|
||||
end
|
||||
end
|
||||
|
||||
for id, fold in pairs( folders or {} ) do
|
||||
recurseAddFiles( folder .. "/" .. fold, pathid, list )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function GenerateSpawnlistFromPath( folder, path, name, icon, appid )
|
||||
|
||||
local contents = {}
|
||||
recurseAddFiles( folder, path, contents )
|
||||
|
||||
AddPropsOfParent( g_SpawnMenu.CustomizableSpawnlistNode.SMContentPanel, g_SpawnMenu.CustomizableSpawnlistNode, 0, { [ folder ] = {
|
||||
icon = icon or "icon16/page.png",
|
||||
id = math.random( 0, 999999 ), -- Eeehhhh
|
||||
name = name or folder,
|
||||
parentid = 0,
|
||||
needsapp = appid,
|
||||
contents = contents
|
||||
} } )
|
||||
|
||||
-- We added a new spawnlist, show the save changes button
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end
|
||||
|
||||
local function GamePropsRightClick( self )
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.createautospawnlist", function()
|
||||
|
||||
-- Find the "root" node for this game
|
||||
local parent = self
|
||||
local icon = parent:GetIcon()
|
||||
while ( !icon:StartsWith( "games" ) ) do
|
||||
parent = parent:GetParentNode()
|
||||
if ( !IsValid( parent ) ) then break end
|
||||
icon = parent:GetIcon()
|
||||
end
|
||||
|
||||
local name = parent:GetText()
|
||||
if ( self:GetFolder() != "models" ) then
|
||||
name = name .. " - " .. self:GetFolder():sub( 8 )
|
||||
end
|
||||
|
||||
GenerateSpawnlistFromPath( self:GetFolder(), self:GetPathID(), name, icon, parent.GamePathID )
|
||||
|
||||
end ):SetIcon( "icon16/page_add.png" )
|
||||
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
local function InstallNodeRightclick( self, newNode )
|
||||
newNode.DoRightClick = GamePropsRightClick
|
||||
newNode.OnNodeAdded = InstallNodeRightclick
|
||||
end
|
||||
|
||||
local function AddBrowseContent( ViewPanel, node, name, icon, path, pathid, pnlContent )
|
||||
|
||||
local models = node:AddFolder( name, path .. "models", pathid, false )
|
||||
models:SetIcon( icon )
|
||||
models.BrowseContentType = "models"
|
||||
models.BrowseExtension = "*.mdl"
|
||||
models.ContentType = "model"
|
||||
models.ViewPanel = ViewPanel
|
||||
models.GamePathID = pathid
|
||||
|
||||
-- If we click on a subnode of this tree, it gets reported upwards (to us)
|
||||
models.OnNodeSelected = function( slf, node )
|
||||
|
||||
-- Already viewing this panel
|
||||
if ( ViewPanel && ViewPanel.CurrentNode && ViewPanel.CurrentNode == node ) then
|
||||
if ( pnlContent.SelectedPanel != ViewPanel ) then pnlContent:SwitchPanel( ViewPanel ) end
|
||||
return
|
||||
end
|
||||
|
||||
-- Clear the viewpanel in preperation for displaying it
|
||||
ViewPanel:Clear()
|
||||
ViewPanel.CurrentNode = node
|
||||
|
||||
-- Fill the viewpanel with models that are in this node's folder
|
||||
local node_path = node:GetFolder()
|
||||
local SearchString = node_path .. "/*.mdl"
|
||||
|
||||
local mdls = file.Find( SearchString, node:GetPathID() )
|
||||
if ( mdls ) then
|
||||
for k, v in ipairs( mdls ) do
|
||||
local cp = spawnmenu.GetContentType( "model" )
|
||||
if ( cp ) then
|
||||
cp( ViewPanel, { model = node_path .. "/" .. v } )
|
||||
end
|
||||
end
|
||||
else
|
||||
MsgN( "Warning! Not opening '" .. node_path .. "' because we cannot search in it!" )
|
||||
end
|
||||
|
||||
-- Switch to it
|
||||
pnlContent:SwitchPanel( ViewPanel )
|
||||
ViewPanel.CurrentNode = node
|
||||
|
||||
end
|
||||
|
||||
InstallNodeRightclick( node, models )
|
||||
|
||||
end
|
||||
|
||||
local function RefreshGames( MyNode )
|
||||
|
||||
local games = engine.GetGames()
|
||||
table.insert( games, {
|
||||
title = "All",
|
||||
folder = "GAME",
|
||||
icon = "all",
|
||||
mounted = true
|
||||
} )
|
||||
table.insert( games, {
|
||||
title = "Garry's Mod",
|
||||
folder = "garrysmod",
|
||||
mounted = true
|
||||
} )
|
||||
|
||||
-- Create a list of mounted games, allowing us to browse them
|
||||
for _, game in SortedPairsByMemberValue( games, "title" ) do
|
||||
|
||||
if ( !game.mounted ) then continue end
|
||||
|
||||
AddBrowseContent( MyNode.ViewPanel, MyNode, game.title, "games/16/" .. ( game.icon or game.folder ) .. ".png", "", game.folder, MyNode.pnlContent )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Called when setting up the sidebar on the spawnmenu - to populate the tree
|
||||
local myGamesNode
|
||||
hook.Add( "PopulateContent", "GameProps", function( pnlContent, tree, node )
|
||||
|
||||
-- Create a node in the `other` category on the tree
|
||||
myGamesNode = node:AddNode( "#spawnmenu.category.games", "icon16/folder_database.png" )
|
||||
myGamesNode.pnlContent = pnlContent
|
||||
|
||||
local ViewPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
ViewPanel:SetVisible( false )
|
||||
ViewPanel.IconList:SetReadOnly( true )
|
||||
myGamesNode.ViewPanel = ViewPanel
|
||||
|
||||
RefreshGames( myGamesNode )
|
||||
|
||||
end )
|
||||
|
||||
|
||||
hook.Add( "GameContentChanged", "RefreshSpawnmenuGames", function()
|
||||
|
||||
if ( !IsValid( myGamesNode ) ) then return end
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
myGamesNode:Clear()
|
||||
myGamesNode.ViewPanel:Clear()
|
||||
|
||||
RefreshGames( myGamesNode )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,159 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulateNPCs", "AddNPCContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
-- Get a list of available NPCs
|
||||
local NPCList = list.Get( "NPC" )
|
||||
|
||||
-- Categorize them
|
||||
local Categories = {}
|
||||
for k, v in pairs( NPCList ) do
|
||||
|
||||
local Category = v.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
|
||||
local Tab = Categories[ Category ] or {}
|
||||
Tab[ k ] = v
|
||||
Categories[ Category ] = Tab
|
||||
|
||||
end
|
||||
|
||||
-- Create an icon for each one and put them on the panel
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categories ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/monkey.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for name, ent in SortedPairsByMemberValue( v, "Name" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "npc", self.PropPanel, {
|
||||
nicename = ent.Name or name,
|
||||
spawnname = name,
|
||||
material = ent.IconOverride or "entities/" .. name .. ".png",
|
||||
weapon = ent.Weapons,
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
Derma_Hook( PANEL, "Paint", "Paint", "Tree" )
|
||||
PANEL.m_bBackground = true -- Hack for above
|
||||
|
||||
function PANEL:AddCheckbox( text, cvar )
|
||||
local DermaCheckbox = self:Add( "DCheckBoxLabel", self )
|
||||
DermaCheckbox:Dock( TOP )
|
||||
DermaCheckbox:SetText( text )
|
||||
DermaCheckbox:SetDark( true )
|
||||
DermaCheckbox:SetConVar( cvar)
|
||||
DermaCheckbox:SizeToContents()
|
||||
DermaCheckbox:DockMargin( 0, 5, 0, 0 )
|
||||
end
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetOpenSize( 150 )
|
||||
self:DockPadding( 15, 10, 15, 10 )
|
||||
|
||||
self:AddCheckbox( "#menubar.npcs.disableai", "ai_disabled" )
|
||||
self:AddCheckbox( "#menubar.npcs.ignoreplayers", "ai_ignoreplayers" )
|
||||
self:AddCheckbox( "#menubar.npcs.keepcorpses", "ai_serverragdolls" )
|
||||
self:AddCheckbox( "#menubar.npcs.autoplayersquad", "npc_citizen_auto_player_squad" )
|
||||
|
||||
local label = vgui.Create( "DLabel", self )
|
||||
label:Dock( TOP )
|
||||
label:DockMargin( 0, 5, 0, 0 )
|
||||
label:SetDark( true )
|
||||
label:SetText( "#menubar.npcs.weapon" )
|
||||
|
||||
local DComboBox = vgui.Create( "DComboBox", self )
|
||||
DComboBox:Dock( TOP )
|
||||
DComboBox:DockMargin( 0, 0, 0, 0 )
|
||||
DComboBox:SetConVar( "gmod_npcweapon" )
|
||||
DComboBox:SetSortItems( false )
|
||||
|
||||
DComboBox:AddChoice( "#menubar.npcs.defaultweapon", "" )
|
||||
DComboBox:AddChoice( "#menubar.npcs.noweapon", "none" )
|
||||
|
||||
-- Sort the items by name, and group by category
|
||||
local groupedWeps = {}
|
||||
for _, v in pairs( list.Get( "NPCUsableWeapons" ) ) do
|
||||
local cat = (v.category or ""):lower()
|
||||
groupedWeps[ cat ] = groupedWeps[ cat ] or {}
|
||||
groupedWeps[ cat ][ v.class ] = language.GetPhrase( v.title )
|
||||
end
|
||||
|
||||
for group, items in SortedPairs( groupedWeps ) do
|
||||
DComboBox:AddSpacer()
|
||||
for class, title in SortedPairsByValue( items ) do
|
||||
DComboBox:AddChoice( title, class )
|
||||
end
|
||||
end
|
||||
|
||||
function DComboBox:OnSelect( index, value )
|
||||
self:ConVarChanged( self.Data[ index ] )
|
||||
end
|
||||
|
||||
self:Open()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
end
|
||||
|
||||
vgui.Register( "SpawnmenuNPCSidebarToolbox", PANEL, "DDrawer" )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.npcs", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "npcs", "PopulateNPCs" )
|
||||
ctrl:CallPopulateHook( "PopulateNPCs" )
|
||||
|
||||
local sidebar = ctrl.ContentNavBar
|
||||
sidebar.Options = vgui.Create( "SpawnmenuNPCSidebarToolbox", sidebar )
|
||||
|
||||
return ctrl
|
||||
|
||||
end, "icon16/monkey.png", 20 )
|
||||
@@ -0,0 +1,93 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulatePostProcess", "AddPostProcess", function( pnlContent, tree, node )
|
||||
|
||||
-- Get a list of postproceess effects
|
||||
-- and organise them into categories
|
||||
local Categorised = {}
|
||||
local PostProcess = list.Get( "PostProcess" )
|
||||
|
||||
if ( PostProcess ) then
|
||||
|
||||
for k, v in pairs( PostProcess ) do
|
||||
|
||||
local Category = v.category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
|
||||
v.name = k
|
||||
table.insert( Categorised[ Category ], v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Create an entry for each category
|
||||
--
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, "icon16/picture.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, pp in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
if ( pp.func ) then
|
||||
pp.func( self.PropPanel )
|
||||
continue
|
||||
end
|
||||
|
||||
spawnmenu.CreateContentIcon( "postprocess", self.PropPanel, {
|
||||
name = pp.name,
|
||||
icon = pp.icon
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.postprocess", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:CallPopulateHook( "PopulatePostProcess" )
|
||||
return ctrl
|
||||
|
||||
end, "icon16/picture.png", 100 )
|
||||
@@ -0,0 +1,81 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local HTML = nil
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.saves", function()
|
||||
|
||||
HTML = vgui.Create( "DHTML" )
|
||||
JS_Language( HTML )
|
||||
JS_Workshop( HTML )
|
||||
|
||||
ws_save = WorkshopFileBase( "save", { "save" } )
|
||||
ws_save.HTML = HTML
|
||||
|
||||
function ws_save:FetchLocal( offset, perpage )
|
||||
|
||||
local f = file.Find( "saves/*.gms", "MOD", "datedesc" )
|
||||
|
||||
local saves = {}
|
||||
|
||||
for k, v in ipairs( f ) do
|
||||
|
||||
if ( k <= offset ) then continue end
|
||||
if ( k > offset + perpage ) then break end
|
||||
|
||||
local entry = {
|
||||
file = "saves/" .. v,
|
||||
name = v:StripExtension(),
|
||||
preview = "saves/" .. v:StripExtension() .. ".jpg",
|
||||
description = "Local map saves stored on your computer. Local content can be deleted in the main menu."
|
||||
}
|
||||
|
||||
table.insert( saves, entry )
|
||||
|
||||
end
|
||||
|
||||
local results = {
|
||||
totalresults = #f,
|
||||
results = saves
|
||||
}
|
||||
|
||||
local json = util.TableToJSON( results, false )
|
||||
HTML:Call( "save.ReceiveLocal( " .. json .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function ws_save:DownloadAndLoad( id )
|
||||
|
||||
steamworks.DownloadUGC( id, function( name )
|
||||
|
||||
ws_save:Load( name )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function ws_save:Load( filename ) RunConsoleCommand( "gm_load", filename ) end
|
||||
function ws_save:Publish( filename, imagename ) RunConsoleCommand( "save_publish", filename, imagename ) end
|
||||
|
||||
HTML:OpenURL( "asset://garrysmod/html/saves.html" )
|
||||
HTML:Call( "SetMap( '" .. game.GetMap() .. "' );" )
|
||||
|
||||
return HTML
|
||||
|
||||
end, "icon16/disk_multiple.png", 200 )
|
||||
|
||||
hook.Add( "PostGameSaved", "OnCreationsSaved", function()
|
||||
|
||||
if ( !HTML ) then return end
|
||||
|
||||
HTML:Call( "OnGameSaved()" )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,91 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulateVehicles", "AddEntityContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
local Categorised = {}
|
||||
|
||||
-- Add this list into the tormoil
|
||||
local Vehicles = list.Get( "Vehicles" )
|
||||
if ( Vehicles ) then
|
||||
for k, v in pairs( Vehicles ) do
|
||||
|
||||
local Category = v.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
|
||||
v.ClassName = k
|
||||
v.PrintName = v.Name
|
||||
v.ScriptedEntityType = "vehicle"
|
||||
table.insert( Categorised[ Category ], v )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Add a tree node for each category
|
||||
--
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/bricks.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", self.PropPanel, {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.ClassName,
|
||||
material = ent.IconOverride or "entities/" .. ent.ClassName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.vehicles", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "vehicles", "PopulateVehicles" )
|
||||
ctrl:CallPopulateHook( "PopulateVehicles" )
|
||||
return ctrl
|
||||
|
||||
end, "icon16/car.png", 50 )
|
||||
@@ -0,0 +1,87 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulateWeapons", "AddWeaponContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
-- Loop through the weapons and add them to the menu
|
||||
local Weapons = list.Get( "Weapon" )
|
||||
local Categorised = {}
|
||||
|
||||
-- Build into categories
|
||||
for k, weapon in pairs( Weapons ) do
|
||||
|
||||
if ( !weapon.Spawnable ) then continue end
|
||||
|
||||
local Category = weapon.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
table.insert( Categorised[ Category ], weapon )
|
||||
|
||||
end
|
||||
|
||||
-- Loop through each category
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/gun.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "weapon", self.PropPanel, {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.ClassName,
|
||||
material = ent.IconOverride or "entities/" .. ent.ClassName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.weapons", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "weapons", "PopulateWeapons" )
|
||||
ctrl:CallPopulateHook( "PopulateWeapons" )
|
||||
return ctrl
|
||||
|
||||
end, "icon16/gun.png", 10 )
|
||||
@@ -0,0 +1,192 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
self:SetSize( 128, 128 )
|
||||
self:SetText( "" )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnDepressionChanged( b )
|
||||
|
||||
if ( IsValid( self.checkbox ) ) then
|
||||
self.checkbox:SetVisible( !b )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Setup( name, icon, label )
|
||||
|
||||
self.label = label
|
||||
self.name = name
|
||||
self.icon = icon
|
||||
|
||||
self:SetMaterial( icon )
|
||||
self:SetName( label or name )
|
||||
|
||||
self.PP = list.Get( "PostProcess" )[ name ]
|
||||
if ( !self.PP ) then return end
|
||||
|
||||
self.DoClick = function()
|
||||
|
||||
if ( self.PP.onclick ) then
|
||||
return self.PP.onclick()
|
||||
end
|
||||
|
||||
if ( !self.PP.cpanel ) then return end
|
||||
|
||||
if ( !IsValid( self.cp ) ) then
|
||||
|
||||
self.cp = vgui.Create( "ControlPanel" )
|
||||
self.cp:SetName( name )
|
||||
self.PP.cpanel( self.cp )
|
||||
|
||||
end
|
||||
|
||||
spawnmenu.ActivateToolPanel( 1, self.cp )
|
||||
|
||||
end
|
||||
|
||||
if ( self.PP.convar ) then
|
||||
|
||||
self.checkbox = self:Add( "DCheckBox" )
|
||||
self.checkbox:SetConVar( self.PP.convar )
|
||||
self.checkbox:SetSize( 20, 20 )
|
||||
self.checkbox:SetPos( self:GetWide() - 20 - 8, 8 )
|
||||
|
||||
self.Enabled = function() return self.checkbox:GetChecked() end
|
||||
|
||||
elseif ( self.ConVars ) then
|
||||
|
||||
self.checkbox = self:Add( "DCheckBox" )
|
||||
self.checkbox:SetSize( 20, 20 )
|
||||
self.checkbox:SetPos( self:GetWide() - 20 - 8, 8 )
|
||||
|
||||
self.checkbox.OnChange = function( pnl, on )
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
|
||||
if ( on ) then
|
||||
RunConsoleCommand( k, v.on )
|
||||
else
|
||||
RunConsoleCommand( k, v.off or "" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.checkbox.Think = function( pnl, on )
|
||||
|
||||
local good = true
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
|
||||
if ( GetConVarString( k ) != v.on ) then
|
||||
good = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
pnl:SetChecked( good )
|
||||
|
||||
end
|
||||
|
||||
self.Enabled = function() return self.checkbox:GetChecked() end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
|
||||
local pCanvas = self:GetSelectionCanvas()
|
||||
if ( IsValid( pCanvas ) && pCanvas:NumSelectedChildren() > 0 && self:IsSelected() ) then
|
||||
return hook.Run( "SpawnlistOpenGenericMenu", pCanvas )
|
||||
end
|
||||
|
||||
self:OpenMenu()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoClick()
|
||||
end
|
||||
|
||||
function PANEL:OpenMenu()
|
||||
|
||||
-- Do not allow removal from read only panels
|
||||
if ( IsValid( self:GetParent() ) && self:GetParent().GetReadOnly && self:GetParent():GetReadOnly() ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function()
|
||||
self:Remove()
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end ):SetIcon( "icon16/bin_closed.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Enabled()
|
||||
return false
|
||||
end
|
||||
|
||||
function PANEL:ToTable( bigtable )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = "postprocess"
|
||||
tab.name = self.name
|
||||
tab.label = self.label
|
||||
tab.icon = self.icon
|
||||
tab.convars = self.ConVars
|
||||
|
||||
table.insert( bigtable, tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "PostProcessIcon", self:GetParent() )
|
||||
copy:CopyBounds( self )
|
||||
copy.ConVars = self.ConVars
|
||||
copy:Setup( self.name, self.icon, self.label )
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "PostProcessIcon", PANEL, "ContentIcon" )
|
||||
|
||||
spawnmenu.AddContentType( "postprocess", function( container, obj )
|
||||
|
||||
if ( !obj.name ) then return end
|
||||
if ( !obj.icon ) then return end
|
||||
|
||||
local icon = vgui.Create( "PostProcessIcon", container )
|
||||
|
||||
if ( obj.convars ) then
|
||||
icon.ConVars = obj.convars
|
||||
end
|
||||
|
||||
icon:Setup( obj.name, obj.icon, obj.label )
|
||||
|
||||
container:Add( icon )
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,12 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "content/content.lua" )
|
||||
43
gamemodes/sandbox/gamemode/spawnmenu/init.lua
Normal file
43
gamemodes/sandbox/gamemode/spawnmenu/init.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/manifest.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/control_presets.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/preset_editor.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ropematerial.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ctrlnumpad.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ctrlcolor.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ctrllistbox.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/contextmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/spawnmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/toolmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controlpanel.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/toolpanel.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/manifest.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/content.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentcontainer.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentheader.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenticon.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentsearch.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentsidebar.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentsidebartoolbox.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/postprocessicon.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/addonprops.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/custom.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/entities.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/gameprops.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/npcs.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/postprocess.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/weapons.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/vehicles.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/saves.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/dupes.lua" )
|
||||
406
gamemodes/sandbox/gamemode/spawnmenu/spawnmenu.lua
Normal file
406
gamemodes/sandbox/gamemode/spawnmenu/spawnmenu.lua
Normal file
@@ -0,0 +1,406 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local spawnmenu_border = CreateConVar( "spawnmenu_border", "0.1", { FCVAR_ARCHIVE }, "Amount of empty space around the Sandbox spawn menu." )
|
||||
|
||||
include( "toolmenu.lua" )
|
||||
include( "contextmenu.lua" )
|
||||
include( "creationmenu.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( FILL )
|
||||
|
||||
self.HorizontalDivider = vgui.Create( "DHorizontalDivider", self )
|
||||
self.HorizontalDivider:Dock( FILL )
|
||||
self.HorizontalDivider:SetLeftWidth( ScrW() ) -- It will be automatically resized by DHorizontalDivider to account for GetRightMin/GetLeftMin
|
||||
self.HorizontalDivider:SetDividerWidth( 6 )
|
||||
self.HorizontalDivider:SetCookieName( "SpawnMenuDiv" )
|
||||
self.HorizontalDivider:SetRightMin( 300 )
|
||||
if ( ScrW() >= 1024 ) then self.HorizontalDivider:SetRightMin( 460 ) end
|
||||
|
||||
self.ToolMenu = vgui.Create( "ToolMenu", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetRight( self.ToolMenu )
|
||||
|
||||
self.CreateMenu = vgui.Create( "CreationMenu", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetLeft( self.CreateMenu )
|
||||
|
||||
self.m_bHangOpen = false
|
||||
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
self.ToolToggle = vgui.Create( "DImageButton", self )
|
||||
self.ToolToggle:SetImage( "gui/spawnmenu_toggle" )
|
||||
self.ToolToggle:SetSize( 16, 16 )
|
||||
self.ToolToggle.DoClick = function()
|
||||
|
||||
self.ToolMenu:SetVisible( !self.ToolMenu:IsVisible() )
|
||||
self:InvalidateLayout()
|
||||
|
||||
if ( self.ToolMenu:IsVisible() ) then
|
||||
self.ToolToggle:SetImage( "gui/spawnmenu_toggle" )
|
||||
self.CreateMenu:Dock( NODOCK ) -- What an ugly hack
|
||||
self.HorizontalDivider:SetRight( self.ToolMenu )
|
||||
self.HorizontalDivider:SetLeft( self.CreateMenu )
|
||||
else
|
||||
self.ToolToggle:SetImage( "gui/spawnmenu_toggle_back" )
|
||||
self.HorizontalDivider:SetRight( nil ) -- What an ugly hack
|
||||
self.HorizontalDivider:SetLeft( nil )
|
||||
self.CreateMenu:SetParent( self.HorizontalDivider )
|
||||
self.CreateMenu:Dock( FILL )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OpenCreationMenuTab( name )
|
||||
|
||||
self.CreateMenu:SwitchToName( name )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetToolMenu()
|
||||
|
||||
return self.ToolMenu
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetCreationMenu()
|
||||
|
||||
return self.CreateMenu
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: OnClick
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:OnMousePressed()
|
||||
|
||||
self:Close()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HangOpen
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:HangOpen( bHang )
|
||||
|
||||
self.m_bHangOpen = bHang
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HangingOpen
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:HangingOpen()
|
||||
|
||||
return self.m_bHangOpen
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Open()
|
||||
|
||||
RestoreCursorPosition()
|
||||
|
||||
self.m_bHangOpen = false
|
||||
|
||||
-- If the context menu is open, try to close it..
|
||||
if ( IsValid( g_ContextMenu ) && g_ContextMenu:IsVisible() ) then
|
||||
g_ContextMenu:Close( true )
|
||||
end
|
||||
|
||||
if ( self:IsVisible() ) then return end
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:MakePopup()
|
||||
self:SetVisible( true )
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( true )
|
||||
self:SetAlpha( 255 )
|
||||
|
||||
achievements.SpawnMenuOpen()
|
||||
|
||||
if ( IsValid( self.StartupTool ) && self.StartupTool.Name ) then
|
||||
self.StartupTool:SetSelected( true )
|
||||
spawnmenu.ActivateTool( self.StartupTool.Name, true )
|
||||
self.StartupTool = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Close( bSkipAnim )
|
||||
|
||||
if ( self.m_bHangOpen ) then
|
||||
self.m_bHangOpen = false
|
||||
return
|
||||
end
|
||||
|
||||
if ( self:IsVisible() ) then RememberCursorPosition() end
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( false )
|
||||
self:SetVisible( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
local MarginX = math.Clamp( ( ScrW() - 1024 ) * spawnmenu_border:GetFloat(), 25, 256 )
|
||||
local MarginY = math.Clamp( ( ScrH() - 768 ) * spawnmenu_border:GetFloat(), 25, 256 )
|
||||
|
||||
-- At this size we can't spare any space for emptiness
|
||||
if ( ScrW() < 1024 || ScrH() < 768 ) then
|
||||
MarginX = 0
|
||||
MarginY = 0
|
||||
end
|
||||
|
||||
self:DockPadding( 0, 0, 0, 0 )
|
||||
self.HorizontalDivider:DockMargin( MarginX, MarginY, MarginX, MarginY )
|
||||
self.HorizontalDivider:SetLeftMin( self.HorizontalDivider:GetWide() / 3 )
|
||||
|
||||
self.ToolToggle:AlignRight( 6 )
|
||||
self.ToolToggle:AlignTop( 6 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:StartKeyFocus( pPanel )
|
||||
|
||||
self.m_pKeyFocus = pPanel
|
||||
self:SetKeyboardInputEnabled( true )
|
||||
self:HangOpen( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EndKeyFocus( pPanel )
|
||||
|
||||
if ( self.m_pKeyFocus != pPanel ) then return end
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnSizeChanged( newW, newH )
|
||||
local divW = self.HorizontalDivider:GetWide()
|
||||
local divL = self.HorizontalDivider:GetLeftWidth()
|
||||
self:InvalidateLayout( true )
|
||||
local divWnew = self.HorizontalDivider:GetWide()
|
||||
|
||||
if ( divW > divL && divW < divWnew ) then
|
||||
local ratio = divL / divW
|
||||
self.HorizontalDivider:SetLeftWidth( ratio * divWnew )
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register( "SpawnMenu", PANEL, "EditablePanel" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called to create the spawn menu..
|
||||
-----------------------------------------------------------]]
|
||||
local function CreateSpawnMenu()
|
||||
|
||||
if ( !hook.Run( "SpawnMenuEnabled" ) ) then return end
|
||||
|
||||
-- If we have an old spawn menu remove it.
|
||||
if ( IsValid( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:Remove()
|
||||
g_SpawnMenu = nil
|
||||
end
|
||||
|
||||
hook.Run( "PreReloadToolsMenu" )
|
||||
|
||||
-- Start Fresh
|
||||
spawnmenu.ClearToolMenus()
|
||||
|
||||
-- Add defaults for the gamemode. In sandbox these defaults
|
||||
-- are the Main/Postprocessing/Options tabs.
|
||||
-- They're added first in sandbox so they're always first
|
||||
hook.Run( "AddGamemodeToolMenuTabs" )
|
||||
|
||||
-- Use this hook to add your custom tools
|
||||
-- This ensures that the default tabs are always
|
||||
-- first.
|
||||
hook.Run( "AddToolMenuTabs" )
|
||||
|
||||
-- Use this hook to add your custom tools
|
||||
-- We add the gamemode tool menu categories first
|
||||
-- to ensure they're always at the top.
|
||||
hook.Run( "AddGamemodeToolMenuCategories" )
|
||||
hook.Run( "AddToolMenuCategories" )
|
||||
|
||||
-- Add the tabs to the tool menu before trying
|
||||
-- to populate them with tools.
|
||||
hook.Run( "PopulateToolMenu" )
|
||||
|
||||
g_SpawnMenu = vgui.Create( "SpawnMenu" )
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:SetVisible( false )
|
||||
hook.Run( "SpawnMenuCreated", g_SpawnMenu )
|
||||
end
|
||||
|
||||
CreateContextMenu()
|
||||
|
||||
hook.Run( "PostReloadToolsMenu" )
|
||||
|
||||
end
|
||||
-- Hook to create the spawnmenu at the appropriate time (when all sents and sweps are loaded)
|
||||
hook.Add( "OnGamemodeLoaded", "CreateSpawnMenu", CreateSpawnMenu )
|
||||
concommand.Add( "spawnmenu_reload", CreateSpawnMenu )
|
||||
|
||||
function GM:OnSpawnMenuOpen()
|
||||
|
||||
-- Let the gamemode decide whether we should open or not..
|
||||
if ( !hook.Call( "SpawnMenuOpen", self ) ) then return end
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:Open()
|
||||
menubar.ParentTo( g_SpawnMenu )
|
||||
end
|
||||
|
||||
hook.Call( "SpawnMenuOpened", self )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnSpawnMenuClose()
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) ) then g_SpawnMenu:Close() end
|
||||
hook.Call( "SpawnMenuClosed", self )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuKeyboardFocusOn
|
||||
Called when text entry needs keyboard focus
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuKeyboardFocusOn( pnl )
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) && IsValid( pnl ) && pnl:HasParent( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:StartKeyFocus( pnl )
|
||||
end
|
||||
if ( IsValid( g_ContextMenu ) && IsValid( pnl ) && pnl:HasParent( g_ContextMenu ) ) then
|
||||
g_ContextMenu:StartKeyFocus( pnl )
|
||||
end
|
||||
|
||||
end
|
||||
hook.Add( "OnTextEntryGetFocus", "SpawnMenuKeyboardFocusOn", SpawnMenuKeyboardFocusOn )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuKeyboardFocusOff
|
||||
Called when text entry stops needing keyboard focus
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuKeyboardFocusOff( pnl )
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) && IsValid( pnl ) && pnl:HasParent( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:EndKeyFocus( pnl )
|
||||
end
|
||||
|
||||
if ( IsValid( g_ContextMenu ) && IsValid( pnl ) && pnl:HasParent( g_ContextMenu ) ) then
|
||||
g_ContextMenu:EndKeyFocus( pnl )
|
||||
end
|
||||
|
||||
end
|
||||
hook.Add( "OnTextEntryLoseFocus", "SpawnMenuKeyboardFocusOff", SpawnMenuKeyboardFocusOff )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuOpenGUIMousePressed
|
||||
Don't do context screen clicking if spawnmenu is open
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuOpenGUIMousePressed()
|
||||
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
if ( !g_SpawnMenu:IsVisible() ) then return end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
hook.Add( "GUIMousePressed", "SpawnMenuOpenGUIMousePressed", SpawnMenuOpenGUIMousePressed )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuOpenGUIMousePressed
|
||||
Close spawnmenu if it's open
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuOpenGUIMouseReleased()
|
||||
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
if ( !g_SpawnMenu:IsVisible() ) then return end
|
||||
|
||||
g_SpawnMenu:Close()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "GUIMouseReleased", "SpawnMenuOpenGUIMouseReleased", SpawnMenuOpenGUIMouseReleased )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Handle spawn menu language switching
|
||||
|
||||
- The spawn menu needs to be recreated ("refreshed") after a language switch
|
||||
|
||||
- We SHOULDN'T refresh it if the user has unsaved changes to their spawn list (these would be lost!)
|
||||
- We SHOULDN'T refresh it if the user has the spawn menu open (that would be bad user experience)
|
||||
- But, we SHOULD refresh it if the user saves or reverts any changes and closes the spawn menu
|
||||
|
||||
- What if the user switches BACK to the original language they were using? Surely, a refresh is not needed now?
|
||||
- No, in this case we should still refresh the spawn menu because some text and labels do actually update during use of the spawn menu and might be left "dirty"
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuLanguageChanged()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
if ( g_SpawnMenu.m_UnsavedModifications || g_SpawnMenu:IsVisible() ) then
|
||||
-- If there are unsaved modifications, or the spawn menu is somehow open, mark the spawn menu for recreation when the opportunity arises
|
||||
g_SpawnMenu.m_NeedsLanguageRefresh = true
|
||||
else
|
||||
-- If there are no unsaved modifications, and the spawn menu isn't open, we can go ahead and safely refresh the spawn menu
|
||||
CreateSpawnMenu()
|
||||
end
|
||||
end
|
||||
-- When gmod_language changes, call SpawnMenuLanguageChanged
|
||||
cvars.AddChangeCallback( "gmod_language", SpawnMenuLanguageChanged, "spawnmenu_reload" )
|
||||
|
||||
local function ProtectSpawnMenuChanges()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
-- Mark the spawn menu as having unsaved modifications
|
||||
g_SpawnMenu.m_UnsavedModifications = true
|
||||
end
|
||||
hook.Add( "SpawnlistContentChanged", "ProtectSpawnMenuChanges", ProtectSpawnMenuChanges )
|
||||
|
||||
local function SpawnMenuChangesFinished()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
-- Mark the spawn menu as no longer having unsaved modifications
|
||||
g_SpawnMenu.m_UnsavedModifications = nil
|
||||
end
|
||||
hook.Add( "OnRevertSpawnlist", "SpawnMenuChangesFinished", SpawnMenuChangesFinished )
|
||||
hook.Add( "OnSaveSpawnlist", "SpawnMenuChangesFinished", SpawnMenuChangesFinished )
|
||||
|
||||
local function SpawnMenuLanguageRefresh()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
-- When the spawn menu is closed, check if it needs a language refresh. If it has no unsaved modifications, refresh it!
|
||||
if ( !g_SpawnMenu.m_UnsavedModifications && g_SpawnMenu.m_NeedsLanguageRefresh ) then
|
||||
g_SpawnMenu.m_NeedsLanguageRefresh = nil
|
||||
CreateSpawnMenu()
|
||||
end
|
||||
end
|
||||
hook.Add( "OnSpawnMenuClose", "SpawnMenuLanguageRefresh", SpawnMenuLanguageRefresh )
|
||||
80
gamemodes/sandbox/gamemode/spawnmenu/toolmenu.lua
Normal file
80
gamemodes/sandbox/gamemode/spawnmenu/toolmenu.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "toolpanel.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self.ToolPanels = {}
|
||||
|
||||
self:LoadTools()
|
||||
|
||||
self:SetFadeTime( 0 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
LoadTools
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:LoadTools()
|
||||
|
||||
local tools = spawnmenu.GetTools()
|
||||
|
||||
for strName, pTable in pairs( tools ) do
|
||||
|
||||
self:AddToolPanel( strName, pTable )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
AddToolPanel
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:AddToolPanel( Name, ToolTable )
|
||||
|
||||
-- I hate relying on a table's internal structure
|
||||
-- but this isn't really that avoidable.
|
||||
|
||||
local Panel = vgui.Create( "ToolPanel" )
|
||||
Panel:SetTabID( Name )
|
||||
Panel:LoadToolsFromTable( ToolTable.Items )
|
||||
Panel.PropertySheet = self
|
||||
Panel.PropertySheetTab = self:AddSheet( ToolTable.Label, Panel, ToolTable.Icon ).Tab
|
||||
|
||||
self.ToolPanels[ Name ] = Panel
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
DPropertySheet.Paint( self, w, h )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetToolPanel
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:GetToolPanel( id )
|
||||
|
||||
return self.ToolPanels[ id ]
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ToolMenu", PANEL, "DPropertySheet" )
|
||||
268
gamemodes/sandbox/gamemode/spawnmenu/toolpanel.lua
Normal file
268
gamemodes/sandbox/gamemode/spawnmenu/toolpanel.lua
Normal file
@@ -0,0 +1,268 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "controlpanel.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_TabID", "TabID" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.HorizontalDivider = vgui.Create( "DHorizontalDivider", self )
|
||||
self.HorizontalDivider:Dock( FILL )
|
||||
self.HorizontalDivider:SetLeftWidth( 130 )
|
||||
self.HorizontalDivider:SetLeftMin( 130 )
|
||||
self.HorizontalDivider:SetRightMin( 200 )
|
||||
if ( ScrW() >= 1024 ) then self.HorizontalDivider:SetRightMin( 256 ) end
|
||||
self.HorizontalDivider:SetDividerWidth( 6 )
|
||||
self.HorizontalDivider:SetCookieName( "SpawnMenuToolMenuDiv" )
|
||||
|
||||
local leftContainer = vgui.Create( "Panel", self.HorizontalDivider )
|
||||
|
||||
self.SearchBar = vgui.Create( "DTextEntry", leftContainer )
|
||||
self.SearchBar:SetWidth( 130 )
|
||||
self.SearchBar:SetPlaceholderText( "#spawnmenu.quick_filter" )
|
||||
self.SearchBar:DockMargin( 0, 0, 0, 5 )
|
||||
self.SearchBar:Dock( TOP )
|
||||
self.SearchBar:SetUpdateOnType( true )
|
||||
self.SearchBar.OnValueChange = function( s, text )
|
||||
self:PerformToolFiltering( text:Trim():lower() )
|
||||
end
|
||||
|
||||
self.List = vgui.Create( "DCategoryList", leftContainer )
|
||||
self.List:SetWidth( 130 )
|
||||
self.List:Dock( FILL )
|
||||
|
||||
self.HorizontalDivider:SetLeft( leftContainer )
|
||||
|
||||
self.Content = vgui.Create( "DCategoryList", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetRight( self.Content )
|
||||
|
||||
self.LastUpdate = 0
|
||||
self.IsToolTab = false
|
||||
|
||||
local label = vgui.Create( "Panel", self )
|
||||
label:Dock( BOTTOM )
|
||||
label:SetVisible( false )
|
||||
label:SetTall( 72 )
|
||||
label.Text = ""
|
||||
label.Paint = function( s, w, h )
|
||||
local parsed = markup.Parse( "<font=DermaLarge>" .. s.Text .. "</font>", w )
|
||||
parsed:Draw( w / 2, h / 2, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 255, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
self.WarningLabel = label
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
|
||||
if ( self.LastUpdate + 0.5 < SysTime() ) then
|
||||
self.LastUpdate = SysTime()
|
||||
|
||||
self:UpdateToolDisabledStatus()
|
||||
|
||||
if ( !self.IsToolTab ) then return end
|
||||
|
||||
local disabled = false
|
||||
local noToolgun = IsValid( LocalPlayer() ) && !LocalPlayer():HasWeapon( "gmod_tool" )
|
||||
if ( self.ActiveCPName ) then
|
||||
local cvar = GetConVar( "toolmode_allow_" .. self.ActiveCPName )
|
||||
if ( cvar ) then disabled = !cvar:GetBool() end
|
||||
end
|
||||
|
||||
self.WarningLabel.Text = noToolgun and "You do not have the Tool Gun to use tools!" or "Currently selected tool is disabled by the server!"
|
||||
if ( ( disabled or noToolgun ) != self.WarningLabel:IsVisible() ) then
|
||||
self.WarningLabel:SetVisible( disabled or noToolgun )
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformToolFiltering( text )
|
||||
|
||||
for cid, category in ipairs( self.List.pnlCanvas:GetChildren() ) do
|
||||
local count = 0
|
||||
local category_matched = false
|
||||
|
||||
if ( string.find( category.Header:GetText():lower(), text, nil, true ) ) then
|
||||
category_matched = true
|
||||
end
|
||||
|
||||
for id, item in ipairs( category:GetChildren() ) do
|
||||
if ( item == category.Header ) then continue end
|
||||
|
||||
local str = item.Text
|
||||
if ( str:StartsWith( "#" ) ) then str = str:sub( 2 ) end
|
||||
str = language.GetPhrase( str )
|
||||
|
||||
if ( !category_matched && !string.find( str:lower(), text, nil, true ) ) then
|
||||
item:SetVisible( false )
|
||||
else
|
||||
item:SetVisible( true )
|
||||
count = count + 1
|
||||
end
|
||||
item:InvalidateLayout()
|
||||
end
|
||||
|
||||
if ( count < 1 && !category_matched ) then
|
||||
category:SetVisible( false )
|
||||
else
|
||||
category:SetVisible( true )
|
||||
|
||||
-- Make sure the category is expanded, but restore the state when we quit searching
|
||||
if ( text == "" ) then
|
||||
if ( category._preSearchState != nil ) then
|
||||
category:SetExpanded( category._preSearchState )
|
||||
category._preSearchState = nil
|
||||
end
|
||||
else
|
||||
if ( category._preSearchState == nil ) then category._preSearchState = category:GetExpanded() end
|
||||
category:SetExpanded( true )
|
||||
end
|
||||
end
|
||||
category:InvalidateLayout()
|
||||
end
|
||||
self.List.pnlCanvas:InvalidateLayout()
|
||||
self.List:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateToolDisabledStatus()
|
||||
|
||||
for cid, category in ipairs( self.List.pnlCanvas:GetChildren() ) do
|
||||
|
||||
for id, item in ipairs( category:GetChildren() ) do
|
||||
if ( item == category.Header ) then continue end
|
||||
|
||||
local cvar = GetConVar( "toolmode_allow_" .. item.Name )
|
||||
if ( !cvar ) then continue end
|
||||
|
||||
local enabled = cvar:GetBool()
|
||||
if ( enabled == item:IsEnabled() ) then continue end
|
||||
|
||||
item:SetEnabled( enabled )
|
||||
|
||||
if ( enabled ) then
|
||||
item:SetTooltip()
|
||||
else
|
||||
item:SetTooltip( "This tool is disabled by the server!" )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:LoadToolsFromTable( inTable )
|
||||
|
||||
for k, v in pairs( table.Copy( inTable ) ) do
|
||||
|
||||
if ( istable( v ) ) then
|
||||
|
||||
-- Remove these from the table so we can
|
||||
-- send the rest of the table to the other
|
||||
-- function
|
||||
|
||||
local Name = v.ItemName
|
||||
local Label = v.Text
|
||||
v.ItemName = nil
|
||||
v.Text = nil
|
||||
|
||||
if ( v[ 1 ] && v[ 1 ].Command and v[ 1 ].Command:StartsWith( "gmod_tool " ) ) then
|
||||
self.IsToolTab = true
|
||||
end
|
||||
|
||||
self:AddCategory( Name, Label, v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddCategory( name, catName, tItems )
|
||||
|
||||
local Category = self.List:Add( catName )
|
||||
|
||||
Category:SetCookieName( "ToolMenu." .. tostring( self:GetTabID() ) .. "." .. tostring( name ) )
|
||||
|
||||
local tools = {}
|
||||
for k, v in pairs( tItems ) do
|
||||
local name = v.Text or v.ItemName or v.Controls or v.Command or tostring( k )
|
||||
tools[ language.GetPhrase( name ) ] = v
|
||||
end
|
||||
|
||||
local currentMode = GetConVar( "gmod_toolmode" ):GetString()
|
||||
for k, v in SortedPairs( tools ) do
|
||||
|
||||
local item = Category:Add( v.Text or k )
|
||||
|
||||
item.DoClick = function( button )
|
||||
|
||||
spawnmenu.ActivateTool( button.Name )
|
||||
|
||||
end
|
||||
|
||||
item.ControlPanelBuildFunction = v.CPanelFunction
|
||||
item.Command = v.Command
|
||||
item.Name = v.ItemName
|
||||
item.Controls = v.Controls
|
||||
item.Text = v.Text
|
||||
|
||||
-- Mark this button as the one to select on first spawnmenu open
|
||||
if ( currentMode == v.ItemName ) then
|
||||
timer.Simple( 0, function() -- Have to wait a frame to get the g_SpawnMenu global, ew
|
||||
g_SpawnMenu.StartupTool = item
|
||||
end )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
-- Internal, makes the given tool highlighted in its DCategoryList
|
||||
function PANEL:SetActiveToolText( str )
|
||||
|
||||
for cid, category in ipairs( self.List.pnlCanvas:GetChildren() ) do
|
||||
|
||||
for id, item in ipairs( category:GetChildren() ) do
|
||||
if ( item == category.Header ) then continue end
|
||||
|
||||
if ( item.Name == str ) then
|
||||
self.List:UnselectAll()
|
||||
item:SetSelected( true )
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetActive( cp )
|
||||
|
||||
local kids = self.Content:GetCanvas():GetChildren()
|
||||
for k, v in pairs( kids ) do
|
||||
v:SetVisible( false )
|
||||
end
|
||||
|
||||
self.Content:AddItem( cp )
|
||||
self.ActiveCPName = cp.Name
|
||||
cp:SetVisible( true )
|
||||
cp:Dock( TOP )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ToolPanel", PANEL, "Panel" )
|
||||
Reference in New Issue
Block a user