--[[ | 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/ --]] /*-------------------------------------------------- =============== VJ Spawn Menu =============== *** Copyright (c) 2012-2023 by DrVrej, All rights reserved. *** No parts of this code or any of its contents may be reproduced, copied, modified or adapted, without the prior written consent of the author, unless otherwise indicated for stand-alone materials. --------------------------------------------------*/ if (!file.Exists("autorun/vj_base_autorun.lua","LUA")) then return end AddCSLuaFile() ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Hooks ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ if CLIENT then hook.Add("PopulateVJBaseHome","AddVJBaseSpawnMenu_Home",function(pnlContent,tree,node) local hometree = tree:AddNode("Home", "icon16/monkey.png") hometree.PropPanel = vgui.Create("ContentContainer", pnlContent) hometree.PropPanel:SetVisible(false) hometree.PropPanel:SetTriggerSpawnlistChange(false) //hometree.PropPanel:MoveToFront() function hometree:DoClick() pnlContent:SwitchPanel(self.PropPanel) end local Header1 = vgui.Create("DLabel") Header1:SetPos(40, 40) Header1:SetSize(200, 70) Header1:SetTextColor(Color(255, 102, 0, 255)) Header1:SetText("Welcome to VJ Base!") hometree.PropPanel:Add(Header1) local Text1 = vgui.Create("DLabel") Header1:SetPos(80, 80) Text1:SetSize(100, 35) Text1:SetTextColor(Color(102, 204, 255, 255)) Text1:SetText("By: DrVrej") hometree.PropPanel:Add(Text1) hometree:InternalDoClick() end) --[-------------------------------------------------------]-- local function VJ_PopulateTrees(pnlContent, tree, node, vjTreeName, vjIcon, vjList) local roottree = tree:AddNode(vjTreeName, vjIcon) if vjTreeName == "SNPCs" then roottree:MoveToFront() -- Make this the main tree end roottree.PropPanel = vgui.Create("ContentContainer", pnlContent) roottree.PropPanel:SetVisible(false) roottree.PropPanel:SetTriggerSpawnlistChange(false) function roottree:DoClick() pnlContent:SwitchPanel(self.PropPanel) end local EntList = list.Get(vjList) local CatInfoList = list.Get("VJBASE_CATEGORY_INFO") -- Categorize them local Categories = {} for k, v in pairs(EntList) do local Category = v.Category or "Uncategorized" if Category == "VJ Base" then Category = "Default" 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 for CategoryName, v in SortedPairs(Categories) do -- Category icon local icon = vjIcon -- Make the default icon the category icon if list.HasEntry("VJBASE_CATEGORY_INFO", CategoryName) then icon = CatInfoList[CategoryName].icon elseif CategoryName == "Default" then icon = "vj_base/icons/vrejgaming.png" end local node = roottree:AddNode(CategoryName, icon) local CatPropPanel = vgui.Create("ContentContainer", pnlContent) CatPropPanel:SetVisible(false) -- Write the name of the categories in both the general menu and in its own menu local generalHeader = vgui.Create("ContentHeader", roottree.PropPanel) generalHeader:SetText(CategoryName) roottree.PropPanel:Add(generalHeader) local catHeader = vgui.Create("ContentHeader", CatPropPanel) catHeader:SetText(CategoryName) CatPropPanel:Add(catHeader) if vjTreeName == "SNPCs" then for name, ent in SortedPairsByMemberValue(v, "Name") do local t = { nicename = ent.Name or name, spawnname = name, material = "entities/" .. name .. ".png", weapon = ent.Weapons, admin = ent.AdminOnly } spawnmenu.CreateContentIcon("npc", CatPropPanel, t) spawnmenu.CreateContentIcon("npc", roottree.PropPanel, t) end elseif vjTreeName == "Weapons" then for _, ent in SortedPairsByMemberValue(v, "PrintName") do local t = { nicename = ent.PrintName or ent.ClassName, spawnname = ent.ClassName, material = "entities/" .. ent.ClassName .. ".png", admin = ent.AdminOnly } spawnmenu.CreateContentIcon(ent.ScriptedEntityType or "weapon", CatPropPanel, t) spawnmenu.CreateContentIcon(ent.ScriptedEntityType or "weapon", roottree.PropPanel, t) end elseif vjTreeName == "Entities" then for _, ent in SortedPairsByMemberValue(v, "PrintName") do local t = { nicename = ent.PrintName or ent.ClassName, spawnname = ent.ClassName, material = "entities/" .. ent.ClassName .. ".png", admin = ent.AdminOnly } spawnmenu.CreateContentIcon(ent.ScriptedEntityType or "entity", CatPropPanel, t) spawnmenu.CreateContentIcon(ent.ScriptedEntityType or "entity", roottree.PropPanel, t) end end function node:DoClick() pnlContent:SwitchPanel(CatPropPanel) end end roottree:SetExpanded(true) if vjTreeName == "SNPCs" then roottree:InternalDoClick() -- Automatically select this folder when the menu first opens end end --[-------------------------------------------------------]-- hook.Add("PopulateVJBaseNPC", "AddVJBaseSpawnMenu_NPC", function(pnlContent, tree, node) VJ_PopulateTrees(pnlContent, tree, node, "SNPCs", "icon16/monkey.png", "VJBASE_SPAWNABLE_NPC") end) --[-------------------------------------------------------]-- hook.Add("PopulateVJBaseWeapons","AddVJBaseSpawnMenu_Weapon", function(pnlContent, tree, node) VJ_PopulateTrees(pnlContent, tree, node, "Weapons", "icon16/gun.png", "VJBASE_SPAWNABLE_WEAPON") end) --[-------------------------------------------------------]-- hook.Add("PopulateVJBaseEntities","AddVJBaseSpawnMenu_Entity",function(pnlContent,tree,node) VJ_PopulateTrees(pnlContent, tree, node, "Entities", "icon16/bricks.png", "VJBASE_SPAWNABLE_ENTITIES") end) --[-------------------------------------------------------]-- hook.Add("PopulateVJBaseTools","AddVJBaseSpawnMenu_Tool",function(pnlContent,tree,node) local tooltree = tree:AddNode("Tools", "icon16/bullet_wrench.png") tooltree.PropPanel = vgui.Create("ContentContainer", pnlContent) tooltree.PropPanel:SetVisible(false) tooltree.PropPanel:SetTriggerSpawnlistChange(false) function tooltree:DoClick() pnlContent:SwitchPanel(self.PropPanel) end local ToolList = spawnmenu.GetTools() if (ToolList) then for _, nv in pairs(ToolList) do if nv.Name == "DrVrej" then for _, nv2 in pairs(nv.Items) do if nv2.ItemName == "Tools" then //local node = tooltree:AddNode("Default", "icon16/bullet_wrench.png") local CatPropPanel = vgui.Create("ContentContainer", pnlContent) CatPropPanel:SetVisible(false) local Header = vgui.Create("ContentHeader", tooltree.PropPanel) Header:SetText("Tools") tooltree.PropPanel:Add(Header) for _, nv3 in pairs(nv2) do if !istable(nv3) then continue end local t = { nicename = nv3.Text, spawnname = nv3.ItemName, //material = "entities/" .. ent.ClassName .. ".png", //admin = ent.AdminOnly } spawnmenu.CreateContentIcon("tool", CatPropPanel, t) spawnmenu.CreateContentIcon("tool", tooltree.PropPanel, t) end function tooltree:DoClick() pnlContent:SwitchPanel(CatPropPanel) end end end end end end tooltree:SetExpanded(true) end) --[-------------------------------------------------------]-- -- Adds the searching functionality for the VJ Base spawn menu. Note: This algorithm is based on the base GMod algorithm. search.AddProvider(function(str) local results = {} local entities = {} local function searchList(lname, lctype) for k, v in pairs(list.Get(lname)) do v.ClassName = k v.PrintName = v.PrintName or v.Name v.ScriptedEntityType = lctype table.insert(entities, v) end end searchList("VJBASE_SPAWNABLE_NPC", "npc") searchList("VJBASE_SPAWNABLE_WEAPON", "weapon") searchList("VJBASE_SPAWNABLE_ENTITIES", "entity") // searchList("VJBASE_SPAWNABLE_VEHICLES", "vehicle") -- vehicle (Not yet lol) for _, v in pairs(entities) do local name = v.PrintName local name_c = v.ClassName if (!name && !name_c) then continue end if ((name && name:lower():find(str, nil, true)) or (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 end table.SortByMember(results, "text", true) return results end, "vjbase_npcs") --[-------------------------------------------------------]-- spawnmenu.AddCreationTab("VJ Base", function() local ctrl = vgui.Create("SpawnmenuContentPanel") ctrl:EnableSearch("vjbase_npcs", "PopulateVJBaseNPC") //ctrl:CallPopulateHook("PopulateVJBaseHome") ctrl:CallPopulateHook("PopulateVJBaseNPC") ctrl:CallPopulateHook("PopulateVJBaseWeapons") ctrl:CallPopulateHook("PopulateVJBaseEntities") ctrl:CallPopulateHook("PopulateVJBaseTools") local sidebar = ctrl.ContentNavBar sidebar.Options = vgui.Create( "VJ_SpawnmenuNPCSidebarToolbox", sidebar ) return ctrl end, "vj_base/icons/vrejgaming.png", 60, "All VJ Base entities are located here!") // icon16/plugin.png --[-------------------------------------------------------]-- -- Based on GMod's SpawnmenuNPCSidebarToolbox but with some changes 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("#vjbase.spawn.menu.npc.disablethinking", "ai_disabled") self:AddCheckbox("#vjbase.spawn.menu.npc.ignoreplayers", "ai_ignoreplayers") self:AddCheckbox("#vjbase.spawn.menu.npc.keepcorpses", "ai_serverragdolls") self:AddCheckbox("#vjbase.spawn.menu.npc.guard", "vj_npc_spawn_guard") 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") DComboBox:AddSpacer() -- Sort the items by name, and group by category local groupedWeps = {} for _, v in pairs( list.Get( "VJBASE_SPAWNABLE_NPC_WEAPON" ) ) do local cat = (v.category or ""):lower() groupedWeps[ cat ] = groupedWeps[ cat ] or {} groupedWeps[ cat ][ v.class ] = language.GetPhrase( v.title ) end for _, 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 vgui.Register("VJ_SpawnmenuNPCSidebarToolbox", PANEL, "DDrawer") end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Spawn Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ local function CreateInternal_NPC(Player, Position, Normal, Class, Equipment, SpawnFlagsSaved) if CLIENT then return end print("Running VJ Base NPC duplicator internal...") local NPCList = list.Get("NPC") //VJBASE_SPAWNABLE_NPC local NPCData = NPCList[Class] if NPCData == nil then print("ERROR! VJ Base NPC duplicator internal failed, NPC not listed in the NPC menu!") return end //PrintTable(NPCData) //if !IsValid(NPCData) then print("VJ Base NPC Internal was unable to spawn the NPC, it didn't find any NPC Data to use") return end print("VJ Base NPC duplicator internal creating: " .. NPCData.Name .. " ( ".. NPCData.Class .. " ) --> ".. NPCData.Category) -- Don't let them spawn this entity if it isn't in our NPC Spawn list. /*if (!NPCData) then if (!IsValid(Player)) then Player:SendLua("Derma_Message(\"Hey, stop trying to spawn it, your not allowed to!\")") end return end*/ local isValidPly = IsValid(Player) if ( NPCData.AdminOnly && isValidPly && !Player:IsAdmin() ) then return end local bDropToFloor = false if ( NPCData.OnCeiling && Vector( 0, 0, -1 ):Dot( Normal ) < 0.95 ) then -- This NPC has to be spawned on a ceiling (Barnacle) return nil end if ( NPCData.OnFloor && Vector( 0, 0, 1 ):Dot( Normal ) < 0.95 ) then -- This NPC has to be spawned on a floor (Turrets) return nil else bDropToFloor = true end if ( NPCData.NoDrop ) then bDropToFloor = false end -- Offset the position local Offset = NPCData.Offset or 32 Position = Position + Normal * Offset -- Create NPC local NPC = ents.Create(NPCData.Class) if (!IsValid(NPC)) then print("ERROR! VJ Base NPC duplicator internal failed, NPC class does not exist!") return end NPC:SetPos(Position) -- Rotate to face player (expected behavior) local Angles = Angle( 0, 0, 0 ) if ( isValidPly ) then Angles = Player:GetAngles() end Angles.pitch = 0 Angles.roll = 0 Angles.yaw = Angles.yaw + 180 if ( NPCData.Rotate ) then Angles = Angles + NPCData.Rotate end NPC:SetAngles( Angles ) -- This NPC has a special model we want to define if ( NPCData.Model ) then NPC:SetModel( NPCData.Model ) end -- This NPC has a special texture we want to define if ( NPCData.Material ) then NPC:SetMaterial( NPCData.Material ) end -- Spawn Flags local SpawnFlags = bit.bor( SF_NPC_FADE_CORPSE, SF_NPC_ALWAYSTHINK ) if ( NPCData.SpawnFlags ) then SpawnFlags = bit.bor( SpawnFlags, NPCData.SpawnFlags ) end if ( NPCData.TotalSpawnFlags ) then SpawnFlags = NPCData.TotalSpawnFlags end if ( SpawnFlagsSaved ) then SpawnFlags = SpawnFlagsSaved end NPC:SetKeyValue( "spawnflags", SpawnFlags ) -- Optional Key Values if ( NPCData.KeyValues ) then for k, v in pairs( NPCData.KeyValues ) do NPC:SetKeyValue( k, v ) end end -- This NPC has a special skin we want to define if ( NPCData.Skin ) then NPC:SetSkin( NPCData.Skin ) end -- Body groups if (NPCData.BodyGroups) then for k, v in pairs(NPCData.BodyGroups) do NPC:SetBodygroup(k, v) end end -- Check if this is a valid entity from the list, or the user is trying to fool us. local valid = false for _, v in pairs( list.Get( "NPCUsableWeapons" ) ) do if v.class == Equipment then valid = true break end end if ( Equipment && Equipment != "none" && valid ) then NPC:SetKeyValue( "additionalequipment", Equipment ) NPC.Equipment = Equipment end DoPropSpawnedEffect(NPC) NPC:Spawn() NPC:Activate() if ( bDropToFloor && !NPCData.OnCeiling ) then NPC:DropToFloor() end print("VJ Base NPC duplicator internal successfully created the NPC!") return NPC end ------------------------------------------------------------------------------------------------------------------------- if !VJ then VJ = {} end -- If VJ isn't initialized, initialize it! -- local vecZ1 = Vector(0, 0, 1) -- VJ.CreateDupe_NPC = function(ply, class, equipment, spawnflags, data) -- Based on the GMod NPCs, had to recreate it here because it's not a global function //PrintTable(data) if IsValid(ply) && !gamemode.Call("PlayerSpawnNPC", ply, class, equipment) then return end -- Don't create if this player isn't allowed to spawn NPCs! local normal = vecZ1 local NPCList = list.Get("NPC") local NPCData = NPCList[class] if (NPCData && NPCData.OnCeiling) then normal = Vector(0, 0, -1) end local ent = CreateInternal_NPC(ply, data.Pos, normal, class, equipment, spawnflags) if (IsValid(ent)) then local pos = ent:GetPos() -- Prevents the NPCs from falling through the floor duplicator.DoGeneric(ent, data) -- Applies generic every-day entity stuff for ent from table data (wiki) if (!NPCData.OnCeiling && !NPCData.NoDrop) then ent:SetPos(pos) ent:DropToFloor() end if (IsValid(ply)) then gamemode.Call("PlayerSpawnedNPC", ply, ent) ply:AddCleanup("npcs", ent) end table.Add(ent:GetTable(), data) end return ent end