[
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing to Lua Main Menu\n=============\n\nHere's what you need to know if you wish to submit Pull Requests to this repository.\n\nCode Formatting\n=============\n\nYour code formatting must be consistent with the rest of the code:\n* Use tabulation to indent your code - TAB size = 4 spaces\n* Use all of the C style Lua in Garry's Mod\n* Use UpperCamelCase for function names\n* Use lowerCamelCase for variable names\n* Do not include variable type in variable names\n\nExamples\n=============\n\nThese examples are of CODE FORMATTING, not examples of GOOD CODE.\n\nGood:\n```\nlocal myTable = {\n\tmeem = \"no\",\n\ttest = true,\n\tfoo = 1,\n\tbar = \"yes\"\n}\n\nif ( type( myTable ) != \"table\" ) then error( \"bad\" ) end\n\nfunction Test( myVariable1, myVariable2 )\n\tif ( !myVariable2 ) then return \"hax\" end\n\n\tif ( myTable[ myVariable1 ] ) then\n\t\treturn myTable[ myVariable1 ]\n\tend\n\n\treturn myVariable2\nend\n```\n\nBad:\n```\nlocal myTable =\n{\n meem =\t\t\t\"no\",\n  test =true,\n   foo= 1,\n    bar\t\t\t\t= \"yes\"\n}\n\nif type(myTable) ~= \"table\" then error \"bad\" end\n\nfunction Test( myVariable1, myVariable2 )\n if not myVariable2 then return \"hax\" end\n\n if myTable[myVariable1] then\n  return myTable[myVariable1]\n\t\tend\n\n return myVariable2\nend\n```"
  },
  {
    "path": "README.md",
    "content": "Garry's Mod Lua Main Menu\n=============\n\nA Lua powered ( No HTML ) main menu for Garry's Mod.\nIt is meant for those who do not have main menu in Garry's Mod by default.\nNote that this is a personal project, and it is not going to be included into Garry's Mod.\nIt does not have some features that I don't use.\nSome other features that are not part of the standard menu might be added in the future.\n\nMissing/Broken Features\n=============\n\n* Server browser - This menu uses the default Source Engine server browser\n* Limited Demos and Saves functionality - No workshop, sorting or filtering\n* Good looks\n* You can't browse through new/top rated/ect addons in main menu. You should use the Open Workshop button anyway.\n\nNew/Fixed Features\n=============\n\n* I think it's faster then the default one\n* Achievements menu\n* More functionality for New Game and Addons menus\n* No HTML\n\nInstalling\n=============\n\nTo install this, download the ZIP and extract contents of ```gmod-lua-menu-master``` folder ( folders ```lua``` and ```materials``` ) to your ```SteamApps/common/GarrysMod/garrysmod/``` folder.\n\nUninstalling\n=============\n\nTo uninstall this, open ```SteamApps/common/GarrysMod/garrysmod/lua/menu/menu.lua``` and follow instructions inside.\nAlternatively, you can simply verify game cache integrity of Garry's Mod and the custom menu will be gone.\n"
  },
  {
    "path": "lua/menu/custom/_errors.lua",
    "content": "\nlocal Errors = {}\n\nlocal matAlert = Material( \"icon16/error.png\" )\n\nhook.Add( \"DrawOverlay\", \"MenuErrors\", function()\n\n\tif ( GetConVarNumber( \"mat_dxlevel\" ) < 90 ) then\n\t\ttable.insert( Errors, {\n\t\t\tlast\t= SysTime(),\n\t\t\ttext\t= \"mat_dxlevel is less than 90!\"\n\t\t} )\n\tend\n\n\tif ( GetConVarNumber( \"lookstrafe\" ) >= 1 or GetConVarNumber( \"lookstrafe\" ) <= -1 ) then\n\t\ttable.insert( Errors, {\n\t\t\tlast\t= SysTime(),\n\t\t\ttext\t= \"Console varible \\\"lookstrafe\\\" is not 0, expect movement oddities!\"\n\t\t} )\n\tend\n\n\tif ( table.Count( Errors ) == 0 ) then return end\n\n\tlocal idealy = 32\n\tlocal height = 30\n\tlocal Recent = SysTime() - 0.5\n\n\tfor k, v in SortedPairsByMemberValue( Errors, \"last\" ) do\n\n\t\tsurface.SetFont( \"DermaDefaultBold\" )\n\t\tif ( v.y == nil ) then v.y = idealy end\n\t\tif ( v.w == nil ) then v.w = surface.GetTextSize( v.text ) + 44 end\n\n\t\tlocal tw, th = surface.GetTextSize( v.text )\n\t\tv.x = ScrW() - tw - 76\n\n\t\tdraw.RoundedBox( 2, v.x + 2, v.y + 2, v.w, height, Color( 40, 40, 40, 255 ) )\n\t\tdraw.RoundedBox( 2, v.x, v.y, v.w, height, Color( 240, 240, 240, 255 ) )\n\n\t\tif ( v.last > Recent ) then\n\n\t\t\tdraw.RoundedBox( 2, v.x, v.y, v.w, height, Color( 255, 200, 0, ( v.last - Recent ) * 510 ) )\n\n\t\tend\n\n\t\tsurface.SetTextColor( 90, 90, 90, 255 )\n\t\tsurface.SetTextPos( v.x + 30, v.y + 8 )\n\t\tsurface.DrawText( v.text )\n\n\t\tsurface.SetDrawColor( 255, 255, 255, 150 + math.sin( v.y + SysTime() * 30 ) * 100 )\n\t\tsurface.SetMaterial( matAlert )\n\t\tsurface.DrawTexturedRect( v.x + 6, v.y + 6, 16, 16 )\n\n\t\tv.y = idealy\n\n\t\tidealy = idealy + 40\n\n\t\tErrors[k] = nil\n\n\tend\n\nend )\n"
  },
  {
    "path": "lua/menu/custom/achievements.lua",
    "content": "\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\tself.AchID = 0\n\n\tself:SetTall( 72 )\n\n\tself.Icon = vgui.Create( \"AchievementIcon\", self )\n\tself.Icon:SetPos( 4, 4 )\n\tself.Icon:SetSize( 64, 64 )\nend\n\nfunction PANEL:SetAchievementID( num )\n\tself.AchID = num\n\tself.Icon:SetAchievement( num )\nend\n\nfunction PANEL:Paint()\n\tlocal text_col = Color( 217, 217, 217 )\n\tif ( achievements.IsAchieved( self.AchID ) ) then\n\t\tdraw.RoundedBox( 4, 0, 0, self:GetWide(), self:GetTall(), Color( 78, 78, 78 ) )\n\telse\n\t\tdraw.RoundedBox( 4, 0, 0, self:GetWide(), self:GetTall(), Color( 52, 52, 52 ) )\n\t\ttext_col = Color( 131, 131, 131 )\n\tend\n\n\tdraw.SimpleText( achievements.GetName( self.AchID ), \"Default\", self:GetTall(), 4, text_col )\n\tdraw.SimpleText( achievements.GetDesc( self.AchID ), \"Default\", self:GetTall(), 20, text_col )\n\n\tlocal goal = achievements.GetGoal( self.AchID )\n\tlocal count = achievements.GetCount( self.AchID )\n\tif ( goal > 1 ) then\n\t\tlocal text = count .. \"/\" .. goal\n\n\t\tsurface.SetFont( \"Default\" )\n\t\tlocal h = 16\n\n\t\tdraw.RoundedBox( 0, self:GetTall(), self:GetTall() - h - 4, self:GetWide() - self:GetTall() - 4, h, Color( 64, 64, 64, 255 ) )\n\t\tdraw.RoundedBox( 0, self:GetTall(), self:GetTall() - h - 4, ( self:GetWide() - self:GetTall() - 4 ) * ( count / goal ), h, Color( 201, 185, 149, 255 ) )\n\t\tdraw.SimpleText( text, \"Default\", self:GetWide() - surface.GetTextSize( text ) - 4, self:GetTall() - h * 2 - 4, text_col )\n\tend\nend\n\nvgui.Register( \"RAchievement\", PANEL, \"Panel\" )\n\nlanguage.Add( \"rb655.achievement_viewer.total\", \"Total Achievements Earned\" )\n\n--------------------------------- --------------------------------- --------------------------------- ---------------------------------\n\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\n\tself:Dock( FILL )\n\n\t--------------------------------- CATEGORIES ---------------------------------\n\n\tlocal frame = vgui.Create( \"DPanel\", self )\n\tself.frame = frame\n\n\tlocal achieved = 0\n\tlocal count = achievements.Count() - 1\n\n\tfor achid = 1, count do\n\t\tif ( achievements.IsAchieved( achid ) ) then\n\t\t\tachieved = achieved + 1\n\t\tend\n\tend\n\n\tlocal ach_total = vgui.Create( \"DPanel\", frame )\n\tach_total:Dock( TOP )\n\tach_total:SetTall( 40 )\n\tach_total:DockMargin( 5, 5, 5, 5 )\n\tfunction ach_total:Paint()\n\t\tdraw.RoundedBox( 4, 0, 0, self:GetWide(), self:GetTall(), Color( 26, 26, 26, 255 ) )\n\n\t\tlocal text = achieved .. \" / \" .. count .. \" ( \" .. math.floor( ( achieved / count ) * 100 ) .. \"% )\"\n\t\tsurface.SetFont( \"Default\" )\n\t\tlocal w = surface.GetTextSize( text ) + 4\n\n\t\tdraw.SimpleText( \"#rb655.achievement_viewer.total\", \"Default\", 4, 4, Color( 217, 217, 217 ) )\n\t\tdraw.SimpleText( text, \"Default\", self:GetWide() - w, 4, Color( 217, 217, 217 ) )\n\n\t\tdraw.RoundedBox( 0, 4, 20, self:GetWide() - 8, 16, Color( 78, 78, 78 ) )\n\t\tdraw.RoundedBox( 0, 4, 20, math.floor( ( achieved / count ) * self:GetWide() ) - 8, 16, Color( 158, 195, 79, 255 ) )\n\tend\n\n\tlocal ach_list = vgui.Create( \"DPanelList\", frame )\n\tach_list:Dock( FILL )\n\tach_list:DockMargin( 5, 0, 5, 5 )\n\tach_list:SetSpacing( 5 )\n\tach_list:SetPadding( 5 )\n\tach_list:EnableHorizontal( false )\n\tach_list:EnableVerticalScrollbar()\n\tfunction ach_list:Paint()\n\t\tdraw.RoundedBox( 4, 0, 0, self:GetWide(), self:GetTall(), Color( 16, 16, 16, 255 ) )\n\tend\n\n\tfor achid = 1, count do\n\t\tlocal ach = vgui.Create( \"RAchievement\", ach_list )\n\t\tach:SetAchievementID( achid )\n\t\tach_list:AddItem( ach )\n\tend\n\nend\n\nfunction PANEL:Paint( w, h )\n\tself.frame:SetSize( self:GetWide() / 2, self:GetTall() / 1.5 )\n\tself.frame:SetPos( self:GetWide() / 2 - self.frame:GetWide() / 2, self:GetTall() / 2 - self.frame:GetTall() / 2 )\n\n\tdraw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 150 ) )\nend\n\nvgui.Register( \"AchievementsPanel\", PANEL, \"EditablePanel\" )\n\n"
  },
  {
    "path": "lua/menu/custom/addons.lua",
    "content": "\nsurface.CreateFont( \"rb655_AddonName\", {\n\tsize = ScreenScale( 12 ),\n\tfont = \"Tahoma\"\n} )\n\nsurface.CreateFont( \"rb655_AddonDesc\", {\n\tsize = ScreenScale( 8 ),\n\tfont = \"Tahoma\"\n} )\n\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\tself:SetTall( 200 )\n\tself:SetWide( 200 )\n\n\tself.Selected = false\n\n\tlocal DermaCheckbox = vgui.Create( \"DCheckBox\", self )\n\tDermaCheckbox:SetPos( 10, 10 )\n\tDermaCheckbox:SetValue( 0 )\n\tself.DermaCheckbox = DermaCheckbox\n\nend\n\nfunction PANEL:OnMouseReleased( mousecode )\n\n\tif ( mousecode == MOUSE_RIGHT ) then\n\n\t\tlocal m = DermaMenu()\n\n\t\tif ( !self.panel.ToggleMounted:GetDisabled() ) then\n\t\t\tm:AddOption( \"Invert Selection\", function() self.panel:InvertSelection() end )\n\n\t\t\tm:AddSpacer()\n\t\tend\n\n\t\tm:AddOption( \"Open Workshop Page\", function() if ( !self.Addon ) then return end steamworks.ViewFile( self.Addon.wsid ) end )\n\t\tm:AddSpacer()\n\t\tif ( steamworks.ShouldMountAddon( self.Addon.wsid ) ) then\n\t\t\tm:AddOption( \"Disable\", function() if ( !self.Addon ) then return end steamworks.SetShouldMountAddon( self.Addon.wsid, false ) steamworks.ApplyAddons() end )\n\t\telse\n\t\t\tm:AddOption( \"Enable\", function() if ( !self.Addon ) then return end steamworks.SetShouldMountAddon( self.Addon.wsid, true ) steamworks.ApplyAddons() end )\n\t\tend\n\t\tm:AddOption( \"Uninstall\", function() if ( !self.Addon ) then return end steamworks.Unsubscribe( self.Addon.wsid ) steamworks.ApplyAddons() end ) -- Do we need ApplyAddons here?\n\t\tm:AddSpacer()\n\t\tm:AddOption( \"Cancel\", function() end )\n\t\tm:Open()\n\tend\n\nend\n\nfunction PANEL:Toggle()\nend\n\nfunction PANEL:SetSelected( b )\n\tself.DermaCheckbox:SetChecked( b )\nend\n\nfunction PANEL:GetSelected()\n\treturn self.DermaCheckbox:GetChecked()\nend\n\ngDataTable = gDataTable or {}\nfunction PANEL:SetAddon( data )\n\tself.Addon = data\n\tif ( gDataTable[ data.wsid ] ) then self.AdditionalData = gDataTable[ data.wsid ] return end\n\n\tsteamworks.FileInfo( data.wsid, function( result )\n\n\t\tgDataTable[ data.wsid ] = result\n\n\t\tif ( !file.Exists( \"cache/workshop/\" .. result.previewid .. \".cache\", \"MOD\" ) ) then\n\t\t\tsteamworks.Download( result.previewid, false, function( name ) end )\n\t\tend\n\n\t\tif ( !IsValid( self ) ) then return end\n\n\t\tself.panel:RefreshAddons()\n\t\tself.AdditionalData = result\n\n\tend )\nend\n\nlocal missingMat = Material( \"../html/img/addonpreview.png\", \"nocull smooth\" )\nlocal lastBuild = 0\nlocal imageCache = {}\nfunction PANEL:Paint( w, h )\n\n\tif ( IsValid( self.DermaCheckbox ) ) then\n\t\tself.DermaCheckbox:SetVisible( self.Hovered or self.DermaCheckbox.Hovered or self:GetSelected() )\n\tend\n\n\tif ( self.AdditionalData and imageCache[ self.AdditionalData.previewid ] ) then\n\t\tself.Image = imageCache[ self.AdditionalData.previewid ]\n\tend\n\n\tif ( !self.Image and self.AdditionalData and file.Exists( \"cache/workshop/\" .. self.AdditionalData.previewid .. \".cache\", \"MOD\" ) and CurTime() - lastBuild > 0.1 ) then\n\t\tself.Image = AddonMaterial( \"cache/workshop/\" .. self.AdditionalData.previewid .. \".cache\" )\n\t\timageCache[ self.AdditionalData.previewid ] = self.Image\n\t\tlastBuild = CurTime()\n\tend\n\n\tif ( self:GetSelected() ) then\n\t\tdraw.RoundedBox( 4, 0, 0, w, h, Color( 0, 150, 255, 200 ) )\n\telseif ( self.Addon and steamworks.ShouldMountAddon( self.Addon.wsid ) ) then\n\t\tdraw.RoundedBox( 4, 0, 0, w, h, Color( 255, 255, 255, 200 ) )\n\telse\n\t\tdraw.RoundedBox( 4, 0, 0, w, h, Color( 0, 0, 0, 255 ) )\n\tend\n\n\tif ( self.Image ) then\n\t\tsurface.SetMaterial( self.Image )\n\telse\n\t\tsurface.SetMaterial( missingMat )\n\tend\n\tlocal imageSize = self:GetTall() - 10\n\tsurface.SetDrawColor( color_white )\n\tsurface.DrawTexturedRect( 5, 5, imageSize, imageSize )\n\n\tif ( gDataTable[ self.Addon.wsid ] ) then\n\t\tlocal ratio = gDataTable[ self.Addon.wsid ].score\n\t\tlocal x = math.floor( ( self:GetWide() - 10 ) * ratio )\n\n\t\tfor i = -5, -1 do\n\t\t\tsurface.SetDrawColor( Color( 255, 0, 0, 128 ) )\n\t\t\tsurface.DrawLine( 5 + x, self:GetTall() - 5 + i, 4 + ( self:GetWide() - 10 ), self:GetTall() - 5 + i )\n\n\t\t\tsurface.SetDrawColor( Color( 0, 255, 0, 128 ) )\n\t\t\tsurface.DrawLine( 5, self:GetTall() - 5 + i, 5 + x, self:GetTall() - 5 + i )\n\t\tend\n\tend\n\n\t--[[if ( self.Addon and !steamworks.ShouldMountAddon( self.Addon.wsid ) ) then\n\t\tdraw.RoundedBox( 4, 0, 0, w, h, Color( 0, 0, 0, 180 ) )\n\tend]]\n\n\tif ( self.Addon and self.Hovered ) then\n\t\tdraw.RoundedBox( 0, 5, h - 25, w - 10, 15, Color( 0, 0, 0, 180 ) )\n\t\tdraw.SimpleText( self.Addon.title, \"Default\", 8, h - 24, Color( 255, 255, 255 ) )\n\tend\n\nend\n\nvgui.Register( \"MenuAddon\", PANEL, \"Panel\" )\n\n--------------------------------------------------------------------------------------------------------------------------------\n\nlocal AddonFilters = {\n\tnone = {\n\t\tlabel = \"None\",\n\t\tfunc = function( mod )\n\t\t\treturn true\n\t\tend\n\t},\n\tenabled = {\n\t\tlabel = \"Enabled\",\n\t\tfunc = function( mod )\n\t\t\treturn mod.mounted\n\t\tend\n\t},\n\tdisabled = {\n\t\tlabel = \"Disabled\",\n\t\tfunc = function( mod )\n\t\t\treturn !mod.mounted\n\t\tend\n\t},\n}\n\nlocal Grouping = {\n\tnone = {\n\t\tlabel = \"None\",\n\t\tfunc = function( addons )\n\t\t\treturn { { addons = addons } }\n\t\tend\n\t},\n\tenabled = {\n\t\tlabel = \"Enabled\",\n\t\tfunc = function( addons )\n\t\t\tlocal t = {\n\t\t\t\tenabled = {\n\t\t\t\t\ttitle = \"Enabled\",\n\t\t\t\t\taddons = {}\n\t\t\t\t},\n\t\t\t\tdisabled = {\n\t\t\t\t\ttitle = \"Disabled\",\n\t\t\t\t\taddons = {}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, addon in pairs( engine.GetAddons() ) do\n\t\t\t\tif ( addon.mounted ) then\n\t\t\t\t\ttable.insert( t.enabled.addons, addon )\n\t\t\t\telse\n\t\t\t\t\ttable.insert( t.disabled.addons, addon )\n\t\t\t\tend\n\t\t\tend\n\n\t\t\treturn t\n\t\tend\n\t},\n\tptags = {\n\t\tlabel = \"Primary Tags\",\n\t\tfunc = function( addons )\n\t\t\tlocal t = {\n\t\t\t\tnoinfo = {\n\t\t\t\t\ttitle = \"Information not loaded yet!\",\n\t\t\t\t\taddons = {}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, addon in pairs( engine.GetAddons() ) do\n\t\t\t\tif ( !gDataTable[ addon.wsid ] ) then\n\t\t\t\t\ttable.insert( t.noinfo.addons, addon )\n\t\t\t\telse\n\t\t\t\t\tlocal Ptags = { servercontent = \"Server Content\", effects = \"Effects\", model = \"Model\", gamemode = \"Gamemode\", npc = \"NPC\", tool = \"Tool\", vehicle = \"Vehicle\", weapon = \"Weapon\", map = \"Map\" }\n\t\t\t\t\tlocal tags = string.Explode( \",\", gDataTable[ addon.wsid ].tags )\n\t\t\t\t\tfor _, tag in pairs( tags ) do\n\t\t\t\t\t\tif ( tag == \"Addon\" ) then continue end -- Don't duplicate ALL addons\n\t\t\t\t\t\tif ( !Ptags[ tag:lower() ] ) then tag = \"Other\" end\n\t\t\t\t\t\ttag = Ptags[ tag:lower() ] or tag\n\t\t\t\t\t\tif ( !t[ tag ] ) then t[ tag ] = { title = tag, addons = {} } end\n\n\t\t\t\t\t\ttable.insert( t[ tag ].addons, addon )\n\t\t\t\t\t\tbreak\n\t\t\t\t\tend\n\t\t\t\tend\n\t\t\tend\n\n\t\t\treturn t\n\t\tend\n\t},\n\t--[[models = {\n\t\tlabel = \"Models\",\n\t\tfunc = function( addons )\n\t\t\tlocal t = {\n\t\t\t\tmodels = {\n\t\t\t\t\ttitle = \"Has Models\",\n\t\t\t\t\taddons = {}\n\t\t\t\t},\n\t\t\t\tnomodels = {\n\t\t\t\t\ttitle = \"Doesn't Have Models\",\n\t\t\t\t\taddons = {}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, addon in pairs( engine.GetAddons() ) do\n\t\t\t\tif ( addon.models > 0 ) then\n\t\t\t\t\ttable.insert( t.models.addons, addon )\n\t\t\t\telse\n\t\t\t\t\ttable.insert( t.nomodels.addons, addon )\n\t\t\t\tend\n\t\t\tend\n\n\t\t\treturn t\n\t\tend\n\t}]] -- Disabled models are reported as \"no models\" :(\n}\n\nlocal BackgroundColor = Color( 200, 200, 200, 128 )\nlocal BackgroundColor2 = Color( 200, 200, 200, 255 ) --Color( 0, 0, 0, 100 )\n\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\n\tself:Dock( FILL )\n\n\tlocal Categories = vgui.Create( \"DListLayout\", self )\n\tCategories:DockPadding( 5, 200, 5, 5 )\n\tCategories:Dock( LEFT )\n\tCategories:SetWide( 200 )\n\n\t--[[ ------------------------------------------------------------------------- ]]\n\n\tlocal Groups = vgui.Create( \"DComboBox\", Categories )\n\tGroups:Dock( TOP )\n\tGroups:SetTall( 30 )\n\tGroups:DockMargin( 0, 0, 0, 5 )\n\tfor id, group in pairs( Grouping ) do Groups:AddChoice( \"Group by: \" .. group.label, id, !Groups:GetSelectedID() ) end\n\tGroups.OnSelect = function( index, value, data ) self:RefreshAddons() end\n\tself.Groups = Groups\n\n\tlocal Filters = vgui.Create( \"DComboBox\", Categories )\n\tFilters:Dock( TOP )\n\tFilters:SetTall( 30 )\n\tFilters:DockMargin( 0, 0, 0, 40 )\n\tfor id, f in pairs( AddonFilters ) do Filters:AddChoice( \"Filter by: \" .. f.label, id, !Filters:GetSelectedID() ) end\n\tFilters.OnSelect = function( index, value, data ) self:RefreshAddons() end\n\tself.Filters = Filters\n\n\t--[[ ------------------------------------------------------------------------- ]]\n\n\tlocal ToggleMounted = vgui.Create( \"DButton\", Categories )\n\tToggleMounted:Dock( TOP )\n\tToggleMounted:SetText( \"#Toggle Selected\" )\n\tToggleMounted:SetTall( 30 )\n\tToggleMounted:DockMargin( 0, 0, 0, 5 )\n\tToggleMounted.DoClick = function() self:ToggleSelected() end\n\tself.ToggleMounted = ToggleMounted\n\n\tlocal EnableSelection = vgui.Create( \"DButton\", Categories )\n\tEnableSelection:Dock( TOP )\n\tEnableSelection:SetText( \"#Enable Selected\" )\n\tEnableSelection:SetTall( 30 )\n\tEnableSelection:DockMargin( 0, 0, 0, 5 )\n\tEnableSelection.DoClick = function() self:EnableSelected() end\n\tself.EnableSelection = EnableSelection\n\n\tlocal DisableSelection = vgui.Create( \"DButton\", Categories )\n\tDisableSelection:Dock( TOP )\n\tDisableSelection:SetText( \"#Disable Selected\" )\n\tDisableSelection:SetTall( 30 )\n\tDisableSelection:DockMargin( 0, 0, 0, 5 )\n\tDisableSelection.DoClick = function() self:DisableSelected() end\n\tself.DisableSelection = DisableSelection\n\n\t--[[ ------------------------------------------------------------------------- ]]\n\n\tlocal SelectAll = vgui.Create( \"DButton\", Categories )\n\tSelectAll:Dock( TOP )\n\tSelectAll:SetText( \"#Select All\" )\n\tSelectAll:SetTall( 16 )\n\tSelectAll:DockMargin( 0, 0, 0, 5 )\n\tSelectAll.DoClick = function() self:SelectAll() end\n\tself.SelectAllButton = SelectAll\n\n\tlocal DeselectAll = vgui.Create( \"DButton\", Categories )\n\tDeselectAll:Dock( TOP )\n\tDeselectAll:SetText( \"#Deselect All\" )\n\tDeselectAll:SetTall( 16 )\n\tDeselectAll:DockMargin( 0, 0, 0, 5 )\n\tDeselectAll.DoClick = function() self:DeselectAll() end\n\tself.DeselectAllButton = DeselectAll\n\n\tlocal InvertAll = vgui.Create( \"DButton\", Categories )\n\tInvertAll:Dock( TOP )\n\tInvertAll:SetText( \"#Invert Selection\" )\n\tInvertAll:SetTall( 16 )\n\tInvertAll:DockMargin( 0, 0, 0, 40 )\n\tInvertAll.DoClick = function() self:InvertSelection() end\n\n\t--[[ ------------------------------------------------------------------------- ]]\n\n\tlocal OpenWorkshop = vgui.Create( \"DButton\", Categories )\n\tOpenWorkshop:Dock( TOP )\n\tOpenWorkshop:SetText( \"#Open Workshop\" )\n\tOpenWorkshop:SetTall( 30 )\n\tOpenWorkshop:DockMargin( 0, 40, 0, 0 )\n\tOpenWorkshop.DoClick = function() steamworks.OpenWorkshop() end\n\n\t------------------- Addon List\n\n\tlocal Scroll = vgui.Create( \"DScrollPanel\", self )\n\tScroll:Dock( FILL )\n\tScroll:DockMargin( 0, 5, 5, 5 )\n\n\tlocal AddonList = vgui.Create( \"DIconLayout\", Scroll )\n\tAddonList:SetSpaceX( 5 )\n\tAddonList:SetSpaceY( 5 )\n\tAddonList:Dock( FILL )\n\tAddonList:DockMargin( 5, 5, 5, 5 )\n\tAddonList:DockPadding( 5, 5, 5, 10 )\n\n\tfunction Scroll:Paint( w, h )\n\t\tdraw.RoundedBoxEx( 4, 0, 0, w, h, BackgroundColor, false, true, false, true )\n\t\tdraw.RoundedBoxEx( 4, 0, 0, w, h, BackgroundColor2, false, true, false, true )\n\tend\n\n\tself.AddonList = AddonList\n\tself:RefreshAddons()\n\nend\n\nfunction PANEL:Think()\n\tlocal anySelected = false\n\tlocal allSelected = true\n\tlocal onlyEnabled = true\n\tlocal onlyDisabled = true\n\tfor id, pnl in pairs( self.AddonList:GetChildren() ) do\n\t\tif ( pnl.GetSelected and pnl:GetSelected() ) then anySelected = true end\n\t\tif ( pnl.GetSelected and !pnl:GetSelected() ) then allSelected = false end\n\t\tif ( pnl.Addon and !steamworks.ShouldMountAddon( pnl.Addon.wsid ) ) then onlyEnabled = false end\n\t\tif ( pnl.Addon and steamworks.ShouldMountAddon( pnl.Addon.wsid ) ) then onlyDisabled = false end\n\tend\n\tself.ToggleMounted:SetDisabled( !anySelected )\n\tself.EnableSelection:SetDisabled( !anySelected or onlyEnabled )\n\tself.DisableSelection:SetDisabled( !anySelected or onlyDisabled )\n\n\tself.SelectAllButton:SetDisabled( allSelected )\n\tself.DeselectAllButton:SetDisabled( !anySelected )\nend\n\nfunction PANEL:ToggleSelected()\n\tfor id, pnl in pairs( self.AddonList:GetChildren() ) do\n\t\tif ( !pnl.GetSelected or !pnl:GetSelected() ) then continue end\n\t\tsteamworks.SetShouldMountAddon( pnl.Addon.wsid, !steamworks.ShouldMountAddon( pnl.Addon.wsid ) )\n\tend\n\tsteamworks.ApplyAddons()\nend\n\nfunction PANEL:DisableSelected()\n\tfor id, pnl in pairs( self.AddonList:GetChildren() ) do\n\t\tif ( !pnl.GetSelected or !pnl:GetSelected() ) then continue end\n\t\tsteamworks.SetShouldMountAddon( pnl.Addon.wsid, false )\n\tend\n\tsteamworks.ApplyAddons()\nend\n\nfunction PANEL:EnableSelected()\n\tfor id, pnl in pairs( self.AddonList:GetChildren() ) do\n\t\tif ( !pnl.GetSelected or !pnl:GetSelected() ) then continue end\n\t\tsteamworks.SetShouldMountAddon( pnl.Addon.wsid, true )\n\tend\n\tsteamworks.ApplyAddons()\nend\n\nfunction PANEL:InvertSelection()\n\tfor id, pnl in pairs( self.AddonList:GetChildren() ) do\n\t\tif ( !pnl.GetSelected ) then continue end\n\t\tpnl:SetSelected( !pnl:GetSelected() )\n\tend\nend\n\nfunction PANEL:DeselectAll()\n\tfor id, pnl in pairs( self.AddonList:GetChildren() ) do\n\t\tif ( !pnl.GetSelected ) then continue end\n\t\tpnl:SetSelected( false )\n\tend\nend\n\nfunction PANEL:SelectAll()\n\tfor id, pnl in pairs( self.AddonList:GetChildren() ) do\n\t\tif ( !pnl.GetSelected ) then continue end\n\t\tpnl:SetSelected( true )\n\tend\nend\n\nfunction PANEL:Update()\n\tself:RefreshAddons()\nend\n\nfunction PANEL:RefreshAddons()\n\n\tself.AddonList:Clear()\n\n\tlocal grp = self.Groups:GetOptionData( self.Groups:GetSelectedID() )\n\tlocal filter = self.Filters:GetOptionData( self.Filters:GetSelectedID() )\n\n\tlocal addons = Grouping[ grp ].func( engine.GetAddons() )\n\n\tfor id, group in SortedPairsByMemberValue( addons, \"title\" ) do\n\t\tif ( #group.addons < 1 ) then continue end\n\n\t\tlocal addns = {}\n\t\tfor k, mod in pairs( group.addons ) do\n\t\t\tif ( !AddonFilters[ filter ].func( mod ) ) then continue end\n\t\t\ttable.insert( addns, mod )\n\t\tend\n\n\t\tif ( #addns < 1 ) then continue end\n\n\t\tif ( group.title ) then\n\t\t\tlocal pnl = self.AddonList:Add( \"DLabel\" )\n\t\t\tpnl.OwnLine = true\n\t\t\tpnl:SetFont( \"rb655_AddonName\" )\n\t\t\tpnl:SetText( group.title )\n\t\t\tpnl:SetDark( true )\n\t\t\tpnl:SizeToContents()\n\t\tend\n\n\t\tfor k, mod in SortedPairsByMemberValue( addns, \"title\" ) do\n\n\t\t\tlocal pnl = self.AddonList:Add( \"MenuAddon\" )\n\t\t\tpnl.panel = self\n\t\t\tpnl:SetAddon( mod )\n\t\t\tpnl:DockMargin( 0, 0, 5, 5 )\n\n\t\tend\n\n\tend\n\nend\n\nvgui.Register( \"AddonsPanel\", PANEL, \"EditablePanel\" )\n"
  },
  {
    "path": "lua/menu/custom/getmaps.lua",
    "content": "\nlocal RefreshMaps\n\n--\n-- Favourites\n--\n\nlocal MapFavourites\n\nlocal function LoadFavourites()\n\n\tlocal cookiestr = cookie.GetString( \"favmaps\" )\n\tMapFavourites = MapFavourites or ( cookiestr and string.Explode( \";\", cookiestr ) or {} )\n\nend\n\nfunction IsMapFavourite( map )\n\n\tLoadFavourites()\n\n\treturn table.HasValue( MapFavourites, map )\n\nend\n\nfunction ToggleFavourite( map )\n\n\tLoadFavourites()\n\n\tif ( table.HasValue( MapFavourites, map ) ) then -- is favourite, remove it\n\t\ttable.remove( MapFavourites, table.KeysFromValue( MapFavourites, map )[ 1 ] )\n\telse -- not favourite, add it\n\t\ttable.insert( MapFavourites, map )\n\tend\n\n\tcookie.Set( \"favmaps\", table.concat( MapFavourites, \";\" ) )\n\n\tRefreshMaps( true )\n\n\tUpdateMapList()\n\nend\n\n--\n-- Map Gamemodes\n--\n\nlocal MapPatterns = {}\n\nlocal MapNames = {}\nMapNames[ \"bhop_\" ] = \"Bunny Hop\"\nMapNames[ \"cinema_\" ] = \"Cinema\"\nMapNames[ \"theater_\" ] = \"Cinema\"\nMapNames[ \"xc_\" ] = \"Climb\"\nMapNames[ \"deathrun_\" ] = \"Deathrun\"\nMapNames[ \"dr_\" ] = \"Deathrun\"\nMapNames[ \"fm_\" ] = \"Flood\"\nMapNames[ \"gmt_\" ] = \"GMod Tower\"\nMapNames[ \"gg_\" ] = \"Gun Game\"\nMapNames[ \"scoutzknivez\" ] = \"Gun Game\"\nMapNames[ \"ba_\" ] = \"Jailbreak\"\nMapNames[ \"jail_\" ] = \"Jailbreak\"\nMapNames[ \"jb_\" ] = \"Jailbreak\"\nMapNames[ \"mg_\" ] = \"Minigames\"\nMapNames[ \"pw_\" ] = \"Pirate Ship Wars\"\nMapNames[ \"ph_\" ] = \"Prop Hunt\"\nMapNames[ \"rp_\" ] = \"Roleplay\"\nMapNames[ \"slb_\" ] = \"Sled Build\"\nMapNames[ \"sb_\" ] = \"Spacebuild\"\nMapNames[ \"slender_\" ] = \"Stop it Slender\"\nMapNames[ \"gms_\" ] = \"Stranded\"\nMapNames[ \"surf_\" ] = \"Surf\"\nMapNames[ \"ts_\" ] = \"The Stalker\"\nMapNames[ \"zm_\" ] = \"Zombie Master\"\nMapNames[ \"zombiesurvival_\" ] = \"Zombie Survival\"\nMapNames[ \"zs_\" ] = \"Zombie Survival\"\nMapNames[ \"ze_\" ] = \"Zombie Escape\"\nMapNames[ \"gd_\" ] = \"Guardian\"\nMapNames[ \"dz_\" ] = \"Danger Zone\"\nMapNames[ \"cm_\" ] = \"Custom\"\nMapNames[ \"gt_\" ] = \"Ghost Town\"\nMapNames[ \"tp_\" ] = \"Team Play\"\nMapNames[ \"vs_\" ] = \"Versus\"\nMapNames[ \"coop_\" ] = \"Cooperative\"\nMapNames[ \"vsh_\" ] = \"Versus Saxton Hale\"\nMapNames[ \"zi_\" ] = \"Zombie Infection\"\n\nMapNames[ \"am_\" ] = \"Aim Multi (1v1)\"\nMapNames[ \"de_\" ] = \"Bomb Defuse\"\nMapNames[ \"cs_\" ] = \"Hostage Rescue\"\nMapNames[ \"dm_\" ] = \"Deathmatch\"\nMapNames[ \"ar_\" ] = \"Arms Race\"\nMapNames[ \"aim_\" ] = \"Aim Arena\"\nMapNames[ \"awp_\" ] = \"AWP Arena\"\nMapNames[ \"arena_\" ] = \"Arena\"\nMapNames[ \"ctf_\" ] = \"Capture The Flag\"\nMapNames[ \"cp_\" ] = \"Control Point\"\nMapNames[ \"koth_\" ] = \"King Of The Hill\"\nMapNames[ \"mvm_\" ] = \"Mann Versus Machine\"\nMapNames[ \"pass_\" ] = \"PASS time\"\nMapNames[ \"pl_\" ] = \"Payload\"\nMapNames[ \"plr_\" ] = \"Payload Race\"\nMapNames[ \"tow_\" ] = \"Tug of War\"\nMapNames[ \"pd_\" ] = \"Player Destruction\"\nMapNames[ \"rd_\" ] = \"Robot Destruction\"\nMapNames[ \"kz_\" ] = \"Kreedz Climbing\"\nMapNames[ \"sd_\" ] = \"Special Delivery\"\nMapNames[ \"tc_\" ] = \"Territorial Control\"\nMapNames[ \"tr_\" ] = \"Training\"\nMapNames[ \"dod_\" ] = \"Control Point\"\nMapNames[ \"fof_\" ] = \"Fistful of Frags\"\nMapNames[ \"bm_\" ] = \"Black Mesa\"\n-- MapNames[ \"phys_\" ] = \"Physics Sandbox\" -- Defined by Sandbox gamemode\n\nMapNames[ \"halls3\" ] = \"Deathmatch\"\n\n-- HL1: DM\nMapNames[ \"boot_camp\" ] = \"Deathmatch\"\nMapNames[ \"bounce\" ] = \"Deathmatch\"\nMapNames[ \"crossfire\" ] = \"Deathmatch\"\nMapNames[ \"datacore\" ] = \"Deathmatch\"\nMapNames[ \"frenzy\" ] = \"Deathmatch\"\nMapNames[ \"lambda_bunker\" ] = \"Deathmatch\"\nMapNames[ \"rapidcore\" ] = \"Deathmatch\"\nMapNames[ \"snarkpit\" ] = \"Deathmatch\"\nMapNames[ \"stalkyard\" ] = \"Deathmatch\"\nMapNames[ \"subtransit\" ] = \"Deathmatch\"\nMapNames[ \"undertow\" ] = \"Deathmatch\"\n\nlocal MapGamemodes = {}\n\nlocal function UpdateGamemodeMaps()\n\n\tlocal GamemodeList = engine.GetGamemodes()\n\n\tfor id, gm in ipairs( GamemodeList ) do\n\n\t\tlocal name = gm.title or \"Unnammed Gamemode\"\n\t\tlocal maps = string.Split( gm.maps, \"|\" )\n\n\t\tif ( maps and gm.maps != \"\" ) then\n\n\t\t\tfor k, pattern in ipairs( maps ) do\n\t\t\t\t-- When in doubt, just try to match it with string.find\n\t\t\t\tMapGamemodes[ string.lower( pattern ) ] = name\n\t\t\tend\n\n\t\tend\n\n\tend\n\nend\n\n--\n-- Sub Categories ( For single player games )\n--\n\nlocal MapSubCategories = {\n\n\t-- HL1:S\n\t[ \"c1a0c\" ] = \"c. Unforeseen Consequences\",\n\t[ \"c2a4d\" ] = \"k. Questionable Ethics\",\n\t[ \"c2a4e\" ] = \"k. Questionable Ethics\",\n\t[ \"c2a4f\" ] = \"k. Questionable Ethics\",\n\t[ \"c2a4g\" ] = \"k. Questionable Ethics\",\n\t[ \"c4a1\" ] = \"o. Xen\",\n\t[ \"c4a1z\" ] = \"z. Unreleased Content\", -- Not part of the campagn\n\t[ \"c4a1y\" ] = \"z. Unreleased Content\",\n\n\t-- HL2: LC\n\t[ \"d2_lostcoast\" ] = \"h. Lost Coast\",\n\n\t-- L4D\n\t[ \"l4d_sv_lighthouse\" ] = \"f. The Last Stand\",\n\n}\n\nlocal MapPatternSubCategories = {\n\n\t-- Random, TODO: Move to Gamemode list?\n\t[ \"^hns_\" ] = \"Hide and Seek\",\n\t[ \"^pf_\" ] = \"Parkour Fortress\",\n\t[ \"^fy_\" ] = \"Fight Yard\",\n\t[ \"^hg_\" ] = \"Hunger Games\",\n\t[ \"^trade_\" ] = \"Trade\",\n\t[ \"^35hp\" ] = \"35HP Knife Only\",\n\n\t-- Alien Swarm\n\t[ \"^asi[-]jac\" ] = \"Jacob's Rest\",\n\n\t-- Left 4 Dead 1\n\t[ \"^l4d_hospital0\" ] = \"No Mercy\",\n\t[ \"^l4d_garage0\" ] = \"Crash Course\",\n\t[ \"^l4d_smalltown0\" ] = \"Death Toll\",\n\t[ \"^l4d_airport0\" ] = \"Dead Air\",\n\t[ \"^l4d_farm0\" ] = \"Blood Harvest\",\n\t[ \"^l4d_river0\" ] = \"The Sacrifice\",\n\t[ \"^l4d_vs_hospital0\" ] = \"No Mercy (Versus)\",\n\t[ \"^l4d_vs_garage0\" ] = \"Crash Course (Versus)\",\n\t[ \"^l4d_vs_smalltown0\" ] = \"Death Toll (Versus)\",\n\t[ \"^l4d_vs_airport0\" ] = \"Dead Air (Versus)\",\n\t[ \"^l4d_vs_farm0\" ] = \"Blood Harvest (Versus)\",\n\t[ \"^l4d_vs_river0\" ] = \"The Sacrifice (Versus)\",\n\n\t-- Left 4 Dead 2\n\t[ \"^c1m\" ] = \"Dead Center\",\n\t[ \"^c2m\" ] = \"Dark Carnival\",\n\t[ \"^c3m\" ] = \"Swamp Fever\",\n\t[ \"^c4m\" ] = \"Hard Rain\",\n\t[ \"^c5m\" ] = \"The Parish\",\n\t[ \"^c6m\" ] = \"The Passing\",\n\t[ \"^c7m\" ] = \"The Sacrifice (L4D1)\",\n\t[ \"^c8m\" ] = \"No Mercy (L4D1)\",\n\t[ \"^c9m\" ] = \"Crash Course (L4D1)\",\n\t[ \"^c10m\" ] = \"Death Toll (L4D1)\",\n\t[ \"^c11m\" ] = \"Dead Air (L4D1)\",\n\t[ \"^c12m\" ] = \"Blood Harvest (L4D1)\",\n\t[ \"^c13m\" ] = \"Cold Stream\",\n\t[ \"^c14m\" ] = \"The Last Stand\",\n\n\t-- Portal\n\t[ \"^testchmb_a_(%d+)$\" ] = \"a. Test Chambers\",\n\t[ \"^testchmb_(.*)_advanced$\" ] = \"c. Advanced Test Chambers\",\n\t[ \"^escape_\" ] = \"b. GLaDOS Escape\",\n\n\t-- Portal 2, TODO: Most of these should be moved up\n\t[ \"sp_a1_intro\" ] = \"a. The Courtesy Call\",\n\t[ \"sp_a1_wakeup\" ] = \"a. The Courtesy Call\",\n\t[ \"sp_a2_intro\" ] = \"a. The Courtesy Call\",\n\n\t[ \"sp_a2_laser_intro\" ] = \"b. The Cold Boot\",\n\t[ \"sp_a2_laser_stairs\" ] = \"b. The Cold Boot\",\n\t[ \"sp_a2_dual_lasers\" ] = \"b. The Cold Boot\",\n\t[ \"sp_a2_laser_over_goo\" ] = \"b. The Cold Boot\",\n\t[ \"sp_a2_catapult_intro\" ] = \"b. The Cold Boot\",\n\t[ \"sp_a2_trust_fling\" ] = \"b. The Cold Boot\",\n\t[ \"sp_a2_pit_flings\" ] = \"b. The Cold Boot\",\n\t[ \"sp_a2_fizzler_intro\" ] = \"b. The Cold Boot\",\n\n\t[ \"sp_a2_sphere_peek\" ] = \"c. The Return\",\n\t[ \"sp_a2_ricochet\" ] = \"c. The Return\",\n\t[ \"sp_a2_bridge_intro\" ] = \"c. The Return\",\n\t[ \"sp_a2_bridge_the_gap\" ] = \"c. The Return\",\n\t[ \"sp_a2_turret_intro\" ] = \"c. The Return\",\n\t[ \"sp_a2_laser_relays\" ] = \"c. The Return\",\n\t[ \"sp_a2_turret_blocker\" ] = \"c. The Return\",\n\t[ \"sp_a2_laser_vs_turret\" ] = \"c. The Return\",\n\t[ \"sp_a2_pull_the_rug\" ] = \"c. The Return\",\n\n\t[ \"sp_a2_column_blocker\" ] = \"d. The Surprise\",\n\t[ \"sp_a2_laser_chaining\" ] = \"d. The Surprise\",\n\t[ \"sp_a2_triple_laser\" ] = \"d. The Surprise\",\n\t[ \"sp_a2_bts1\" ] = \"d. The Surprise\",\n\t[ \"sp_a2_bts2\" ] = \"d. The Surprise\",\n\n\t[ \"sp_a2_bts3\" ] = \"e. The Escape\",\n\t[ \"sp_a2_bts4\" ] = \"e. The Escape\",\n\t[ \"sp_a2_bts5\" ] = \"e. The Escape\",\n\t[ \"sp_a2_bts6\" ] = \"e. The Escape\",\n\t[ \"sp_a2_core\" ] = \"e. The Escape\",\n\n\t[ \"sp_a3_0\" ] = \"f. The Fall\",\n\t[ \"sp_a3_jump_intro\" ] = \"f. The Fall\",\n\t[ \"sp_a3_bomb_flings\" ] = \"f. The Fall\",\n\t[ \"sp_a3_crazy_box\" ] = \"f. The Fall\",\n\t[ \"sp_a3_transition01\" ] = \"f. The Fall\",\n\n\t[ \"sp_a3_speed_ramp\" ] = \"g. The Reunion\",\n\t[ \"sp_a3_speed_flings\" ] = \"g. The Reunion\",\n\t[ \"sp_a3_portal_intro\" ] = \"g. The Reunion\",\n\t[ \"sp_a3_end\" ] = \"g. The Reunion\",\n\n\t[ \"sp_a4_intro\" ] = \"h. The Itch\",\n\t[ \"sp_a4_tb_intro\" ] = \"h. The Itch\",\n\t[ \"sp_a4_tb_trust_drop\" ] = \"h. The Itch\",\n\t[ \"sp_a4_tb_wall_button\" ] = \"h. The Itch\",\n\t[ \"sp_a4_tb_polarity\" ] = \"h. The Itch\",\n\t[ \"sp_a4_tb_catch\" ] = \"h. The Itch\",\n\t[ \"sp_a4_stop_the_box\" ] = \"h. The Itch\",\n\t[ \"sp_a4_laser_catapult\" ] = \"h. The Itch\",\n\t[ \"sp_a4_laser_platform\" ] = \"h. The Itch\",\n\t[ \"sp_a4_speed_tb_catch\" ] = \"h. The Itch\",\n\t[ \"sp_a4_jump_polarity\" ] = \"h. The Itch\",\n\n\t[ \"sp_a4_finale\" ] = \"i. The Part Where...\",\n\t[ \"sp_a5_credits\" ] = \"i. The Part Where...\",\n\n\t[ \"e1912\" ] = \"j. Promotional\",\n\n\t[ \"mp_coop_start\" ] = \"k. Coop Calibration & Hubs\",\n\t[ \"mp_coop_lobby_\" ] = \"k. Coop Calibration & Hubs\",\n\n\t[ \"mp_coop_doors\" ] = \"l. Coop Course 1: Team Building\",\n\t[ \"mp_coop_race_2\" ] = \"l. Coop Course 1: Team Building\",\n\t[ \"mp_coop_laser_2\" ] = \"l. Coop Course 1: Team Building\",\n\t[ \"mp_coop_rat_maze\" ] = \"l. Coop Course 1: Team Building\",\n\t[ \"mp_coop_laser_crusher\" ] = \"l. Coop Course 1: Team Building\",\n\t[ \"mp_coop_teambts\" ] = \"l. Coop Course 1: Team Building\",\n\n\t[ \"mp_coop_fling_3\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\t[ \"mp_coop_infinifling_train\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\t[ \"mp_coop_come_along\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\t[ \"mp_coop_fling_1\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\t[ \"mp_coop_catapult_1\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\t[ \"mp_coop_multifling_1\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\t[ \"mp_coop_fling_crushers\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\t[ \"mp_coop_fan\" ] = \"m. Coop Course 2: Mass and Velocity\",\n\n\t[ \"^mp_coop_wall\" ] = \"n. Coop Course 3: Hard-Light Surfaces\",\n\t[ \"mp_coop_catapult_wall_intro\" ] = \"n. Coop Course 3: Hard-Light Surfaces\",\n\t[ \"mp_coop_catapult_2\" ] = \"n. Coop Course 3: Hard-Light Surfaces\",\n\t[ \"^mp_coop_turret_\" ] = \"n. Coop Course 3: Hard-Light Surfaces\",\n\n\t[ \"^mp_coop_tbeam_\" ] = \"o. Coop Course 4: Excursion Funnels\",\n\n\t[ \"mp_coop_paint_come_along\" ] = \"p. Coop Course 5: Mobility Gels\",\n\t[ \"mp_coop_paint_redirect\" ] = \"p. Coop Course 5: Mobility Gels\",\n\t[ \"mp_coop_paint_bridge\" ] = \"p. Coop Course 5: Mobility Gels\",\n\t[ \"mp_coop_paint_walljumps\" ] = \"p. Coop Course 5: Mobility Gels\",\n\t[ \"mp_coop_paint_speed_fling\" ] = \"p. Coop Course 5: Mobility Gels\",\n\t[ \"mp_coop_paint_red_racer\" ] = \"p. Coop Course 5: Mobility Gels\",\n\t[ \"mp_coop_paint_speed_catch\" ] = \"p. Coop Course 5: Mobility Gels\",\n\t[ \"mp_coop_paint_longjump_intro\" ] = \"p. Coop Course 5: Mobility Gels\",\n\n\t[ \"^mp_coop_separation_1\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_tripleaxis\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_catapult_catch\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_2paints_1bridge\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_paint_conversion\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_bridge_catch\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_laser_tbeam\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_paint_rat_maze\" ] = \"q. Additional Coop Course: Art Therapy\",\n\t[ \"^mp_coop_paint_crazy_box\" ] = \"q. Additional Coop Course: Art Therapy\",\n\n\t-- Half-Life: Source\n\t[ \"^t0a0\" ] = \"_. Hazard Course\",\n\t[ \"^c0a0\" ] = \"a. Black Mesa Inbound\",\n\t[ \"^c1a0\" ] = \"b. Anomalous Materials\",\n\t[ \"^c1a1\" ] = \"c. Unforeseen Consequences\",\n\t[ \"^c1a2\" ] = \"d. Office Complex\",\n\t[ \"^c1a3\" ] = \"e. \\\"We've Got Hostiles\\\"\",\n\t[ \"^c1a4\" ] = \"f. Blast Pit\",\n\t[ \"^c2a1\" ] = \"g. Power Up\",\n\t[ \"^c2a2\" ] = \"h. On A Rail\",\n\t[ \"^c2a3\" ] = \"i. Apprehension\",\n\t[ \"^c2a4\" ] = \"j. Residue Processing\",\n\n\t[ \"^c2a5\" ] = \"l. Surface Tension\",\n\t[ \"^c3a1\" ] = \"m. \\\"Forget About Freeman!\\\"\",\n\t[ \"^c3a2\" ] = \"n. Lambda Core\",\n\t[ \"^c4a2\" ] = \"p. Gonarch's Lair\",\n\t[ \"^c4a1(.+)$\" ] = \"r. Interloper\",\n\t[ \"^c4a3\" ] = \"s. Nihilanth\",\n\t[ \"^c5a1\" ] = \"t. Endgame\",\n\n\t-- Half-Life 2\n\t[ \"^d1_trainstation_0[1-4]\" ] = \"a. Point Insertion\",\n\t[ \"^d1_trainstation_0[5-6]\" ] = \"b. \\\"A Red Letter Day\\\"\",\n\n\t[ \"^d1_canals_0[1-5]\" ] = \"c. Route Kanal\",\n\n\t[ \"^d1_canals_0[6-9]\" ] = \"d. Water Hazard\",\n\t[ \"^d1_canals_1[0-3]\" ] = \"d. Water Hazard\",\n\n\t[ \"^d1_eli\" ] = \"e. Black Mesa East\",\n\t[ \"^d1_town\" ] = \"f. \\\"We Don't Go To Ravenholm...\\\"\",\n\t[ \"^d2_coast_0[1-8]\" ] = \"g. Highway 17\",\n\n\t[ \"^d2_coast_09\" ] = \"h. Sandtraps\",\n\t[ \"^d2_coast_1\" ] = \"h. Sandtraps\",\n\t[ \"^d2_prison_01\" ] = \"h. Sandtraps\",\n\n\t[ \"^d2_prison_0[2-5]\" ] = \"i. Nova Prospekt\",\n\t[ \"^d2_prison_0[6-8]\" ] = \"j. Entaglement\",\n\n\t[ \"^d3_c17_01\" ] = \"j. Entaglement\",\n\n\t[ \"^d3_c17_0[2-8]\" ] = \"k. Anticitizen One\",\n\n\t[ \"^d3_c17_09\" ] = \"l. \\\"Follow Freeman!\\\"\",\n\t[ \"^d3_c17_1\" ] = \"l. \\\"Follow Freeman!\\\"\",\n\n\t[ \"^d3_citadel\" ] = \"m. Our Benefactors\",\n\t[ \"^d3_breen\" ] = \"n. Dark Energy\",\n\n\t-- Half-Life 2: Episode 1\n\t[ \"^ep1_citadel_0[0-2]\" ] = \"o. Undue Alarm\",\n\t[ \"^ep1_citadel_0[3-4]\" ] = \"p. Direct Intervention\",\n\t[ \"^ep1_c17_00\" ] = \"q. Lowlife\",\n\t[ \"^ep1_c17_0[1-2]\" ] = \"r. Urban Flight\",\n\t[ \"^ep1_c17_0[5-6]\" ] = \"s. Exit 17\",\n\n\t-- Half-Life 2: Episode 2\n\t[ \"^ep2_outland_01\" ] = \"t. To the White Forest\",\n\t[ \"^ep2_outland_0[2-4]\" ] = \"u. This Vortal Coil\",\n\t[ \"^ep2_outland_0[5-6]$\" ] = \"v. Freeman Pontifex\",\n\t[ \"^ep2_outland_06a\" ] = \"w. Riding Shotgun\",\n\t[ \"^ep2_outland_0[7-8]\" ] = \"w. Riding Shotgun\",\n\n\t[ \"^ep2_outland_09\" ] = \"x. Under the Radar\",\n\t[ \"^ep2_outland_10\" ] = \"x. Under the Radar\",\n\t[ \"^ep2_outland_1[1-2]$\" ] = \"y. Our Mutual Fiend\",\n\t[ \"^ep2_outland_11a\" ] = \"y. Our Mutual Fiend\",\n\t[ \"^ep2_outland_11b\" ] = \"y. Our Mutual Fiend\",\n\t[ \"^ep2_outland_12a\" ] = \"z. T-Minus One\",\n\n\t-- Half-Life 2 backgrounds\n\t[ \"^background\" ] = \"z. Backgrounds\",\n\t[ \"^ep1_background\" ] = \"z. Backgrounds\",\n\t[ \"^ep2_background\" ] = \"z. Backgrounds\",\n}\n\n--\n-- Hidden maps\n--\n\nlocal IgnorePatterns = {\n\t\"^background\",\n\t\"^ep1_background\",\n\t\"^ep2_background\",\n\t\"^devtest\",\n\t\"^test_\",\n\t\"^styleguide\",\n\t\"^sdk_\",\n\t\"^vst_\",\n}\n\nlocal IgnoreMaps = {\n\tc4a1y = true, -- Doesn't load\n\tcredits = true,\n\td2_coast_02 = true, -- Doesn't load\n\td3_c17_02_camera = true,\n\tep1_citadel_00_demo = true,\n\tc5m1_waterfront_sndscape = true,\n\tintro = true,\n\ttest = true,\n}\n\n-- Hide single player games from gamemode map list, their maps have their own game category\nlocal IgnoreGames = {\n\t[ 220 ] = true, -- HL2\n\t[ 280 ] = true, -- HL:S\n\t[ 340 ] = true, -- HL2:LC\n\t[ 380 ] = true, -- HL2:EP1\n\t[ 400 ] = true, -- P\n\t[ 420 ] = true, -- HL2:EP2\n\t[ 500 ] = true, -- L4D\n\t[ 550 ] = true, -- L4D2\n\t[ 620 ] = true, -- P2\n\t[ 630 ] = true, -- Alien Swarm\n\t[ 251110 ] = true, -- INFRA\n\t[ 221910 ] = true, -- Stanley Parable\n\t[ 362890 ] = true, -- Black Mesa\n}\n\n-- Maps from these games cannot be loaded in Garry's Mod\nlocal IncompatibleGames = {\n\t--[ 550 ] = true, -- L4D2\n\t--[ 620 ] = true, -- P2\n\t--[ 730 ] = true, -- CSGO\n}\n\n--\n-- Map lists\n--\n\nlocal MapList = {}\nlocal GameMapList = {}\n\n-- TODO: ConVar for hiding bad maps\n\nlocal function IsUselessMap( map_name )\n\tlocal Ignore = IgnoreMaps[ map_name ]\n\tif ( Ignore ) then return true end\n\n\tfor _, ignore in ipairs( IgnorePatterns ) do\n\t\tif ( string.find( map_name, ignore ) ) then\n\t\t\treturn true\n\t\tend\n\tend\n\n\treturn false\nend\n\nlocal function AddMapInfo( map_info, cat, cat_name, cat_table )\n\tif ( !cat_table[ cat ] ) then cat_table[ cat ] = { name = cat_name, maps = {} } end\n\n\t-- I hate this, I hate that CS:GO and CS:S have same map names!\n\tfor id, t in pairs( cat_table[ cat ].maps ) do\n\t\tif ( t.name == map_info.name ) then return end\n\tend\n\n\ttable.insert( cat_table[ cat ].maps, map_info ) -- TODO: Perhaps make the key the map name?\nend\n\nRefreshMaps = function( skip )\n\n\tif ( !skip ) then UpdateGamemodeMaps() end\n\n\tMapList = {}\n\tGameMapList = {}\n\tlocal ExistingMaps = {}\n\n\tlocal games = engine.GetGames()\n\ttable.insert( games, { title = \"Garry's Mod\", depot = 4000, folder = \"MOD\", mounted = true } )\n\ttable.insert( games, { title = \"Addons\", depot = 0, folder = \"thirdparty\", mounted = true } )\n\ttable.insert( games, { title = \"Downloaded Maps\", depot = -1, folder = \"DOWNLOAD\", mounted = true } )\n\ttable.insert( games, { title = \"mount.cfg\", depot = -2, folder = \"GAME\", mounted = true } ) -- Must be last!\n\t-- Note: \"Games\" map categories are bundled by depotID, not folder/title!\n\n\t-- Can't do this unfortunately\n\t--[[for pathid, path in pairs( util.KeyValuesToTable( file.Read( \"cfg/mount.cfg\", \"MOD\" ) ) ) do\n\t\tprint( pathid, path )\n\t\tPrintTable( file.Find( \"maps/*.bsp\", pathid ) )\n\t\ttable.insert( games, { title = pathid .. \" (mount.cfg)\", depot = 0, folder = pathid, mounted = true } )\n\tend]]\n\n\tfor id, tab in pairs( games ) do\n\t\tif ( !tab.mounted ) then continue end\n\n\t\tlocal maps = file.Find( \"maps/*.bsp\", tab.folder )\n\n\t\tfor k, v in ipairs( maps ) do\n\t\t\tlocal map_name = string.gsub( v, \"%.bsp$\", \"\" ):lower()\n\t\t\tlocal prefix = string.match( map_name, \"^(.-_)\" )\n\n\t\t\tif ( tab.folder == \"GAME\" ) then\n\t\t\t\tif ( ExistingMaps[ map_name ] ) then continue end\n\t\t\telse\n\t\t\t\tExistingMaps[ map_name ] = true\n\t\t\tend\n\n\t\t\t-- Don't add useless maps\n\t\t\tif ( IsUselessMap( map_name ) ) then continue end\n\n\t\t\t-- Map info\n\t\t\tlocal map_info = {\n\t\t\t\tname = map_name,\n\t\t\t\tincompatible = IncompatibleGames[ tab.depot ], -- Ideally this should be replaced with BSP version numbers\n\t\t\t\t--useless = IsUselessMap( map_name ) -- Maybe it should be done like this instead?\n\t\t\t}\n\n\t\t\t-- Add map to the game list\n\t\t\tAddMapInfo( map_info, tab.depot, tab.title, GameMapList )\n\n\t\t\t-- Ignore maps from certain games\n\t\t\tif ( IgnoreGames[ tab.depot ] ) then continue end\n\n\t\t\t-- For a full list of maps we don't want to process already processed maps\n\t\t\t--[[if ( tab.folder == \"GAME\" ) then\n\t\t\t\tif ( ExistingMaps[ map_name ] ) then continue end\n\t\t\tend]]\n\n\t\t\t-- Give the map a category\n\t\t\tlocal Category = MapNames[ map_name ] or MapNames[ prefix ]\n\t\t\tif ( !Category ) then\n\t\t\t\tlocal patterns = table.Merge( table.Copy( MapGamemodes ), MapPatterns )\n\t\t\t\tfor pattern, category in pairs( patterns ) do\n\t\t\t\t\tif ( string.find( map_name, pattern ) ) then\n\t\t\t\t\t\tCategory = category\n\t\t\t\t\tend\n\t\t\t\tend\n\t\t\tend\n\n\t\t\t-- Throw all uncategorised maps into \"Other\"\n\t\t\tCategory = Category or \"Other\"\n\n\t\t\t-- Favourite maps\n\t\t\tif ( IsMapFavourite( map_name ) ) then\n\t\t\t\tAddMapInfo( map_info, \"Favourites\", \"Favourites\", MapList )\n\t\t\tend\n\n\t\t\tAddMapInfo( map_info, Category, Category, MapList )\n\t\tend\n\tend\n\n\tUpdateMapList()\n\nend\n\nhook.Add( \"MenuStart\", \"FindMaps\", RefreshMaps )\nhook.Add( \"GameContentChanged\", \"RefreshMaps\", RefreshMaps )\n\nfunction GetMapCategories( catType )\n\tlocal output = {}\n\n\t-- This could be done better, but I will leave it like this for now\n\tif ( catType == \"game\" ) then\n\t\tfor cat, tab in pairs( GameMapList ) do\n\t\t\tif ( !tab or !tab.maps or #tab.maps < 1 ) then continue end\n\t\t\toutput[ cat ] = tab.name\n\t\tend\n\telse\n\t\tfor cat, tab in pairs( MapList ) do\n\t\t\tif ( !tab or !tab.maps or #tab.maps < 1 ) then continue end\n\t\t\toutput[ cat ] = tab.name\n\t\tend\n\tend\n\n\treturn output\nend\n\nlocal function map_cat_helper( map, search_t )\n\tfor cat, tab in pairs( search_t ) do\n\t\tif ( !tab or !tab.maps or #tab.maps < 1 ) then continue end\n\n\t\tfor _, map_t in pairs( tab.maps ) do\n\t\t\tif ( map_t.name == map:lower() ) then\n\t\t\t\treturn cat\n\t\t\tend\n\t\tend\n\tend\nend\n\nfunction GetMapCategory( map )\n\tlocal r = map_cat_helper( map, MapList )\n\tif ( !r ) then r = map_cat_helper( map, GameMapList ) end\n\treturn r\nend\n\nfunction GetMapsFromCategory( cat )\n\tif ( !DoesCategoryExist( cat ) ) then return {} end\n\n\tlocal maps = MapList[ cat ] and MapList[ cat ].maps or {}\n\tif ( #maps < 1 ) then maps = GameMapList[ tonumber( cat ) ] and GameMapList[ tonumber( cat ) ].maps or {} end\n\treturn maps\nend\n\nfunction DoesCategoryExist( cat )\n\tif ( !MapList[ cat ] and !GameMapList[ tonumber( cat ) ] ) then return false end\n\treturn true\nend\n\nfunction DoesMapExist( map )\n\treturn file.Exists( \"maps/\" .. map .. \".bsp\", \"GAME\" )\nend\n\nfunction GetMapSubCategories()\n\tlocal subCats = table.Copy( MapSubCategories )\n\tlocal subCatPatterns = table.Copy( MapPatternSubCategories )\n\n\tfor pattern, catName in pairs( MapPatterns ) do\n\t\tsubCatPatterns[ pattern ] = catName\n\tend\n\n\tfor pattern, catName in pairs( MapGamemodes ) do\n\t\tsubCatPatterns[ pattern ] = catName\n\tend\n\n\tfor prefix, catName in pairs( MapNames ) do\n\t\tif ( prefix:EndsWith( \"_\" ) ) then\n\t\t\tif ( subCatPatterns[ \"^\" .. prefix ] ) then print( \"Prefix \" .. prefix .. \" has 2 categories '\" .. subCatPatterns[ \"^\" .. prefix ] .. \"' and '\" .. catName .. \"'!\" ) end\n\t\t\tsubCatPatterns[ \"^\" .. prefix ] = catName\n\t\telse\n\t\t\tif ( subCatPatterns[ prefix ] ) then print( \"Map \" .. prefix .. \" has 2 categories '\" .. subCatPatterns[ prefix ] .. \"' and '\" .. catName .. \"'!\" ) end\n\t\t\tsubCats[ prefix ] = catName\n\t\tend\n\tend\n\n\treturn subCats, subCatPatterns\nend\n\n--\n-- Last Map\n--\n\nfunction SaveLastMap( map, cat )\n\n\tlocal t = string.Explode( \";\", cookie.GetString( \"lastmap\", \"\" ) )\n\tif ( !map ) then map = t[ 1 ] or \"gm_flatgrass\" end\n\tif ( !cat ) then cat = t[ 2 ] or \"Sandbox\" end\n\n\tcookie.Set( \"lastmap\", map .. \";\" .. cat )\n\nend\n\nfunction LoadLastMap()\n\n\tlocal t = string.Explode( \";\", cookie.GetString( \"lastmap\", \"\" ) )\n\n\tlocal map = t[ 1 ] or \"gm_flatgrass\"\n\tlocal cat = t[ 2 ] or \"Sandbox\"\n\n\t-- Game categories are stored as numbers!\n\tcat = tonumber( cat ) or cat\n\n\tif ( !DoesMapExist( map ) ) then\n\t\tmap = \"gm_flatgrass\"\n\t\tcat = \"Sandbox\"\n\tend\n\n\treturn map, cat\n\nend\n"
  },
  {
    "path": "lua/menu/custom/main.lua",
    "content": "\n-- Developer stuff\nconcommand.Add( \"lua\", function( ply, cmd, args, str )\n\tif ( IsInGame() ) then return end\n\tRunString( str )\nend )\n\nlocal PANEL = {}\n\nlanguage.Add( \"achievements\", \"Achievements\" )\n\nsurface.CreateFont( \"MenuButton\", {\n\tfont\t= \"Helvetica\",\n\tsize\t= 24,\n\tweight\t= 600\n} )\n\nlocal DLabel = baseclass.Get( \"DLabel\" )\n\nfunction PANEL:Init()\n\tself:SetFont( \"MenuButton\" )\n\tself:SetCursor( \"hand\" )\n\tself:SetMouseInputEnabled( true )\n\tself:SetTextColor( Color( 255, 255, 255 ) )\nend\n\nfunction PANEL:SetText( ... )\n\tDLabel.SetText( self, ... )\n\tself:SizeToContents()\nend\n\nfunction PANEL:SetDisabled( b )\n\tself.Disabled = b\n\tself:SetCursor( b and \"none\" or \"hand\" )\nend\n\nfunction PANEL:Paint()\n\tif ( self.Disabled == true ) then self:SetFGColor( Color( 120, 120, 120 ) ) return end\n\tself:SetFGColor( self.Hovered and Color( 255, 255, 128 ) or Color( 255, 255, 255 ) )\nend\n\nfunction PANEL:OnCursorEntered()\n\tself.Hovered = true\n\tif ( !self.Disabled ) then surface.PlaySound( \"garrysmod/ui_hover.wav\" ) end\nend\nfunction PANEL:OnCursorExited()\n\tself.Hovered = false\nend\n\nfunction PANEL:OnMousePressed()\n\tif self.Disabled then return end\n\tDLabel.OnMousePressed( self )\n\tsurface.PlaySound( \"garrysmod/ui_click.wav\" )\nend\n\nvgui.Register( \"MenuButton\", PANEL, \"DLabel\" )\n\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\n\tself:Dock( FILL )\n\n\tlocal mainButtons = vgui.Create( \"DPanel\", self )\n\tfunction mainButtons:Paint( w, h )\n\t\t---draw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 200 ) )\n\t\tself:SetPos( ScrW() / 20, math.max( ScrH() / 2 - self:GetTall() / 2, 150 ) )\n\tend\n\tmainButtons:SetSize( 250, 350 )\n\tself.MenuButtons = mainButtons\n\n\tlocal Resume = vgui.Create( \"MenuButton\", mainButtons )\n\tResume:Dock( TOP )\n\tResume:DockMargin( 5, 5, 5, 20 )\n\tResume:SetText( \"#resume_game\" )\n\tResume.DoClick = function()\n\t\tgui.HideGameUI()\n\tend\n\tself.Resume = Resume\n\n\tlocal NewGame = vgui.Create( \"MenuButton\", mainButtons )\n\tNewGame:Dock( TOP )\n\tNewGame:DockMargin( 5, 5, 5, 0 )\n\tNewGame:SetText( \"#new_game\" )\n\tNewGame.DoClick = function()\n\t\tself:GetParent():OpenNewGameMenu()\n\tend\n\n\tlocal PlayMP = vgui.Create( \"MenuButton\", mainButtons )\n\tPlayMP:Dock( TOP )\n\tPlayMP:DockMargin( 5, 0, 5, 0 )\n\tPlayMP:SetText( \"#find_mp_game\" )\n\tPlayMP.DoClick = function()\n\t\tRunGameUICommand( \"OpenServerBrowser\" )\n\tend\n\n\tlocal Addons = vgui.Create( \"MenuButton\", mainButtons )\n\tAddons:Dock( TOP )\n\tAddons:DockMargin( 5, 20, 5, 0 )\n\tAddons:SetText( \"#addons\" )\n\tAddons.DoClick = function()\n\t\tself:GetParent():OpenAddonsMenu()\n\tend\n\n\tlocal Saves = vgui.Create( \"MenuButton\", mainButtons )\n\tSaves:Dock( TOP )\n\tSaves:DockMargin( 5, 0, 5, 0 )\n\tSaves:SetText( \"#saves\" )\n\tSaves.DoClick = function()\n\t\tself:GetParent():OpenCreationMenu( false, \"saves\" )\n\tend\n\n\tlocal Demos = vgui.Create( \"MenuButton\", mainButtons )\n\tDemos:Dock( TOP )\n\tDemos:DockMargin( 5, 0, 5, 0 )\n\tDemos:SetText( \"#demos\" )\n\tDemos.DoClick = function()\n\t\tself:GetParent():OpenCreationMenu( false, \"demos\" )\n\tend\n\n\tlocal Achievements = vgui.Create( \"MenuButton\", mainButtons )\n\tAchievements:Dock( TOP )\n\tAchievements:DockMargin( 5, 0, 5, 0 )\n\tAchievements:SetText( \"#achievements\" )\n\tAchievements.DoClick = function()\n\t\tself:GetParent():OpenAchievementsMenu()\n\tend\n\n\tlocal Options = vgui.Create( \"MenuButton\", mainButtons )\n\tOptions:Dock( TOP )\n\tOptions:SetText( \"#options\" )\n\tOptions:DockMargin( 5, 20, 5, 20 )\n\tOptions.DoClick = function()\n\t\tRunGameUICommand( \"OpenOptionsDialog\" )\n\tend\n\n\tlocal Disconnect = vgui.Create( \"MenuButton\", mainButtons )\n\tDisconnect:Dock( TOP )\n\tDisconnect:SetText( \"#disconnect\" )\n\tDisconnect:DockMargin( 5, 5, 5, 0 )\n\tDisconnect.DoClick = function()\n\t\tRunGameUICommand( \"Disconnect\" )\n\tend\n\tself.Disconnect = Disconnect\n\n\tlocal Quit = vgui.Create( \"MenuButton\", mainButtons )\n\tQuit:Dock( TOP )\n\tQuit:SetText( \"#quit\" )\n\tQuit:DockMargin( 5, 0, 5, 0 )\n\tQuit.DoClick = function()\n\t\tRunGameUICommand( \"quit\" )\n\tend\n\nend\n\nlocal old = 0\nfunction PANEL:Paint()\n\n\tif ScrH() != old then\n\t\told = ScrH()\n\tend\n\n\tif ( !self.Image or self.Image:GetName() != \"../gamemodes/\" .. engine.ActiveGamemode() .. \"/logo\" ) then\n\t\tself.Image = Material( \"../gamemodes/\" .. engine.ActiveGamemode() .. \"/logo.png\", \"nocull smooth\" )\n\tend\n\n\tif ( self.Image and !self.Image:IsError() ) then\n\t\tsurface.SetMaterial( self.Image )\n\t\tlocal x, y = self.MenuButtons:GetPos()\n\t\tlocal w, h = self.Image:GetInt( \"$realwidth\" ), self.Image:GetInt( \"$realheight\" )\n\t\tsurface.DrawTexturedRect( x, y - h, w, h )\n\tend\n\n\tif ( self.IsInGame != IsInGame() ) then\n\n\t\tself.IsInGame = IsInGame()\n\n\t\tif ( self.IsInGame ) then\n\t\t\tself.Disconnect:SetVisible( true )\n\t\t\tself.Resume:SetVisible( true )\n\t\telse\n\t\t\tself.Disconnect:SetVisible( false )\n\t\t\tself.Resume:SetVisible( false )\n\t\tend\n\n\tend\n\nend\n\nvgui.Register( \"MainMenuScreenPanel\", PANEL, \"EditablePanel\" )\n"
  },
  {
    "path": "lua/menu/custom/mainmenu.lua",
    "content": "\nScreenScale = function( size ) return size * ( ScrW() / 640.0 ) end\n\ninclude( \"getmaps.lua\" )\ninclude( \"addons.lua\" )\ninclude( \"new_game.lua\" )\ninclude( \"saves.lua\" )\ninclude( \"achievements.lua\" )\ninclude( \"main.lua\" )\ninclude( \"_errors.lua\" )\ninclude( \"../background.lua\" )\ninclude( \"../crosshair_setup.lua\" )\n\npnlMainMenu = nil\n\nlocal PANEL = {}\n\nfunction PANEL:SetSpecial( b )\n\tself.Special = b\nend\n\nlocal matGradientUp = Material( \"gui/gradient_up\" )\nfunction PANEL:Paint( w, h )\n\tif ( !self.Special ) then\n\t\tself:SetFGColor( color_black )\n\t\tlocal clr = color_white\n\t\tif ( self.Hovered ) then clr = Color( 255, 255, 220 ) end\n\t\tif ( self.Depressed ) then self:SetFGColor( color_white ) clr = Color( 35, 150, 255 ) end\n\t\tdraw.RoundedBox( 4, 0, 0, w, h, clr )\n\telse\n\t\tself:SetFGColor( color_white )\n\t\tlocal clr = Color( 0, 134, 204 )\n\t\tif ( self.Hovered ) then clr = Color( 34, 168, 238 ) end\n\t\tif ( self.Depressed ) then clr = Color( 0, 134, 204 ) end\n\t\t--draw.RoundedBox( 4, 0, 0, w, h, clr )\n\n\t\tsurface.SetDrawColor( clr )\n\t\tsurface.DrawRect( 1, 1, w - 2, h - 2 )\n\n\t\tsurface.SetDrawColor( Color( 0, 85, 204 ) )\n\t\tif ( self.Hovered ) then clr = surface.SetDrawColor( Color( 34, 119, 238 ) ) end\n\t\tsurface.SetMaterial( matGradientUp )\n\t\tsurface.DrawTexturedRect( 1, 1, w - 2, h - 2 )\n\n\t\tsurface.SetDrawColor( Color( 0, 85, 204 ) )\n\t\t--surface.DrawOutlinedRect( 0, 0, w, h )\n\n\t\tsurface.DrawLine( 1, 0, w-1, 0 ) -- top\n\t\tsurface.DrawLine( 0, 1, 0, h - 1 ) -- left\n\t\tsurface.DrawLine( w - 1, 1, w - 1, h - 1 ) -- right\n\n\t\tsurface.SetDrawColor( Color( 0, 53, 128 ) )\n\t\tsurface.DrawLine( 1, h - 1, w-1, h - 1 ) -- bottom\n\n\t\tlocal clr2 = Color( 52, 160, 214 )\n\t\tif ( self.Hovered ) then clr2 = Color( 79, 187, 241 ) end\n\t\tif ( self.Depressed ) then clr2 = Color( 52, 160, 214 ) end\n\t\tsurface.SetDrawColor( clr2 )\n\t\tsurface.DrawLine( 1, 1, w - 1, 1 )\n\tend\nend\n\nfunction PANEL:PerformLayout( w, h )\n\tif ( IsValid( self.m_Image ) ) then\n\t\tself.m_Image:SetPos( 5, ( self:GetTall() - self.m_Image:GetTall() ) * 0.5 )\n\t\tself:SetTextInset( 10, 0 )\n\tend\n\tDLabel.PerformLayout( self )\nend\n\n\nvgui.Register( \"DMenuButton\", PANEL, \"DButton\" )\n\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\n\tself:Dock( FILL )\n\tself:SetKeyboardInputEnabled( true )\n\tself:SetMouseInputEnabled( true )\n\n\tlocal lowerPanel = vgui.Create( \"DPanel\", self )\n\tfunction lowerPanel:Paint( w, h )\n\t\tdraw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 220 ) )\n\tend\n\tlowerPanel:SetTall( 50 )\n\tlowerPanel:Dock( BOTTOM )\n\n\tlocal BackButton = vgui.Create( \"DMenuButton\", lowerPanel )\n\tBackButton:Dock( LEFT )\n\tBackButton:SetText( \"#back_to_main_menu\" )\n\tBackButton:SetIcon( \"icon16/arrow_left.png\" )\n\tBackButton:SetTextInset( BackButton.m_Image:GetWide() + 20, 0 )\n\tBackButton:DockMargin( 5, 5, 5, 5 )\n\tBackButton:SetContentAlignment( 6 )\n\tBackButton:SizeToContents()\n\tBackButton:SetVisible( false )\n\tBackButton.DoClick = function() self:Back() end\n\tself.BackButton = BackButton\n\n\n\n\tlocal Gamemodes = vgui.Create( \"DMenuButton\", lowerPanel )\n\tGamemodes:Dock( RIGHT )\n\tGamemodes:DockMargin( 5, 5, 5, 5 )\n\tGamemodes:SetContentAlignment( 6 )\n\tGamemodes.DoClick = function() self:OpenGamemodesList( Gamemodes ) end\n\tself.GamemodeList = Gamemodes\n\tself:RefreshGamemodes()\n\n\tlocal MountedGames = vgui.Create( \"DMenuButton\", lowerPanel )\n\tMountedGames:Dock( RIGHT )\n\tMountedGames:DockMargin( 5, 5, 0, 5 )\n\tMountedGames:SetContentAlignment( 6 )\n\tMountedGames:SetText( \"#games\" )\n\tMountedGames:SetWide( 88 )\n\tMountedGames:SetIcon( \"../html/img/back_to_game.png\" )\n\tMountedGames.DoClick = function() self:OpenMountedGamesList( MountedGames ) end\n\tself.MountedGames = MountedGames\n\n\tlocal Languages = vgui.Create( \"DMenuButton\", lowerPanel )\n\tLanguages:Dock( RIGHT )\n\tLanguages:DockMargin( 5, 5, 0, 5 )\n\tLanguages:SetContentAlignment( 6 )\n\tLanguages:SetText( \"\" )\n\tLanguages:SetWide( 40 )\n\tLanguages:SetIcon( \"../resource/localization/\" .. GetConVarString( \"gmod_language\" ) .. \".png\" )\n\tLanguages.DoClick = function() self:OpenLanguages( Languages ) end\n\tfunction Languages:PerformLayout()\n\t\tif ( IsValid( self.m_Image ) ) then\n\t\t\tself.m_Image:SetPos( ( self:GetWide() - self.m_Image:GetWide() ) * 0.5, ( self:GetTall() - self.m_Image:GetTall() ) * 0.5 )\n\t\t\tself.m_Image:SetSize( 16, 11 )\n\t\tend\n\t\tDLabel.PerformLayout( self )\n\tend\n\tself.Languages = Languages\n\n\tlocal Problems = vgui.Create( \"DMenuButton\", lowerPanel )\n\tProblems:Dock( RIGHT )\n\tProblems:DockMargin( 5, 5, 0, 5 )\n\tProblems:SetContentAlignment( 6 )\n\tProblems:SetText( \"#problems\" )\n\tProblems:SetWide( 88 )\n\tProblems:SetIcon( \"../html/img/error.png\" )\n\tProblems.DoClick = function() OpenProblemsPanel() end\n\tself.ProblemsBtn = Problems\n\n\n\n\tself:MakePopup()\n\tself:SetPopupStayAtBack( true )\n\n\tself:OpenMainMenu()\n\nend\n\nfunction PANEL:Paint()\n\n\tif ( !IsValid( self.NewGameFrame ) and !IsValid( self.AddonsFrame ) and !IsValid( self.AchievementsFrame ) and !IsValid( self.SavesFrame ) ) then\n\t\tself.BackButton:SetVisible( false )\n\telse\n\t\tself.BackButton:SetVisible( true )\n\tend\n\n\tif ( self.IsInGame != IsInGame() ) then\n\n\t\tself.IsInGame = IsInGame()\n\n\t\tself:OpenMainMenu() -- To update the buttons\n\n\tend\n\n\tDrawBackground()\n\nend\n\nfunction PANEL:ClosePopups( b )\n\tif ( IsValid( self.LanguageList ) ) then self.LanguageList:Remove() end\n\tif ( !b and IsValid( self.MountedGamesList ) ) then self.MountedGamesList:Remove() end -- The ugly 'b' hack\n\tif ( IsValid( self.GamemodesList ) ) then self.GamemodesList:Remove() end\nend\n\nfunction PANEL:CloseAllMenus()\n\tif ( IsValid( self.MainMenuPanel ) ) then self.MainMenuPanel:Remove() end\n\tif ( IsValid( self.NewGameFrame ) ) then self.NewGameFrame:Remove() end\n\tif ( IsValid( self.AddonsFrame ) ) then self.AddonsFrame:Remove() end\n\tif ( IsValid( self.AchievementsFrame ) ) then self.AchievementsFrame:Remove() end\n\tif ( IsValid( self.SavesFrame ) ) then self.SavesFrame:Remove() end\nend\n\nfunction PANEL:Back()\n\tself:CloseAllMenus()\n\tself:OpenMainMenu()\nend\n\nfunction PANEL:OpenMainMenu( b )\n\tself:CloseAllMenus()\n\tself:ClosePopups( b )\n\n\tlocal frame = vgui.Create( \"MainMenuScreenPanel\", self )\n\tself.MainMenuPanel = frame\nend\n\nfunction PANEL:OpenAddonsMenu( b )\n\tself:CloseAllMenus()\n\tself:ClosePopups( b )\n\n\tlocal frame = vgui.Create( \"AddonsPanel\", self )\n\tself.AddonsFrame = frame\nend\n\nfunction PANEL:OpenCreationMenu( b, typ )\n\tself:CloseAllMenus()\n\tself:ClosePopups( b )\n\n\tlocal frame = vgui.Create( \"SavesPanel\", self )\n\tself.SavesFrame = frame\n\tself.SavesFrame:SetType( typ )\nend\n\nfunction PANEL:OpenAchievementsMenu( b )\n\tself:CloseAllMenus()\n\tself:ClosePopups( b )\n\n\tlocal frame = vgui.Create( \"AchievementsPanel\", self )\n\tself.AchievementsFrame = frame\nend\n\nfunction PANEL:OpenNewGameMenu( b )\n\tself:CloseAllMenus()\n\tself:ClosePopups( b )\n\n\tlocal frame = vgui.Create( \"NewGamePanel\", self )\n\tself.NewGameFrame = frame\n\n\thook.Run( \"MenuStart\" )\nend\n\nfunction PANEL:OpenLanguages( pnl )\n\tif ( IsValid( self.LanguageList ) ) then self.LanguageList:Remove() return end\n\tself:ClosePopups()\n\n\tlocal perRow = 8\n\n\tlocal panel = vgui.Create( \"DScrollPanel\", self )\n\tpanel:SetSize( perRow * 16 + ( perRow + 1 ) * 10, 90 )\n\tpanel:SetPos( pnl:GetPos() - panel:GetWide() / 2 + pnl:GetWide() / 2, ScrH() - 55 - panel:GetTall() )\n\tself.LanguageList = panel\n\n\tfunction panel:Paint( w, h )\n\t\tdraw.RoundedBox( 0, 0, 0, w - 5, h, Color( 0, 0, 0, 220 ) )\n\tend\n\n\tlocal p = vgui.Create( \"DIconLayout\", panel )\n\tp:Dock( FILL )\n\tp:SetBorder( 10 )\n\tp:SetSpaceY( 10 )\n\tp:SetSpaceX( 10 )\n\n\tfor id, flag in pairs( file.Find( \"resource/localization/*.png\", \"GAME\" ) ) do\n\t\tlocal f = p:Add( \"DImageButton\" )\n\t\tf:SetImage( \"../resource/localization/\" .. flag )\n\t\tf:SetSize( 16, 12 )\n\t\tf.DoClick = function()\n\t\t\tRunConsoleCommand( \"gmod_language\", string.StripExtension( flag ) )\n\t\t\t--LanguageChanged( string.StripExtension( flag ) )\n\t\tend\n\tend\n\nend\n\n\nfunction PANEL:OpenMountedGamesList( pnl )\n\tif ( IsValid( self.MountedGamesList ) ) then self.MountedGamesList:Remove() return end\n\tself:ClosePopups()\n\n\tlocal p = vgui.Create( \"DPanelList\", self )\n\tp:EnableVerticalScrollbar()\n\tp:SetSize( 276, 256 )\n\tp:SetPos( math.min( pnl:GetPos() - p:GetWide() / 2 + pnl:GetWide() / 2, ScrW() - p:GetWide() - 5 ), ScrH() - 55 - p:GetTall() )\n\tp:SetSpacing( 5 )\n\tp:SetPadding( 5 )\n\tself.MountedGamesList = p\n\n\tfunction p:Paint( w, h )\n\t\tdraw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 220 ) )\n\tend\n\n\tlocal function add( t )\n\t\tlocal a = p:Add( \"DCheckBoxLabel\" )\n\t\ta:SetText( t.title )\n\t\tif ( !t.installed ) then a:SetText( t.title .. \" ( not installed )\" ) end\n\t\tif ( !t.owned ) then a:SetText( t.title .. \" ( not owned )\" ) end\n\n\t\tp:AddItem( a )\n\t\ta:SetChecked( t.mounted )\n\t\ta.OnChange = function( panel ) engine.SetMounted( t.depot, a:GetChecked() ) end\n\t\tif ( !t.owned or !t.installed ) then\n\t\t\ta:SetDisabled( true )\n\t\tend\n\tend\n\n\tfor id, t in SortedPairsByMemberValue( engine.GetGames(), \"title\" ) do\n\t\tadd( t )\n\tend\n\t--[[for id, t in SortedPairsByMemberValue( engine.GetGames(), \"title\" ) do\n\t\tif ( t.installed and t.owned ) then add( t ) end\n\tend\n\n\tfor id, t in SortedPairsByMemberValue( engine.GetGames(), \"title\" ) do\n\t\tif ( !t.installed and t.owned ) then add( t ) end\n\tend\n\n\tfor id, t in SortedPairsByMemberValue( engine.GetGames(), \"title\" ) do\n\t\tif ( !t.installed and !t.owned ) then add( t ) end\n\tend]]\n\nend\n\nfunction PANEL:OpenGamemodesList( pnl )\n\tif ( IsValid( self.GamemodesList ) ) then self.GamemodesList:Remove() return end\n\tself:ClosePopups()\n\n\tlocal p = vgui.Create( \"DPanelList\", self )\n\tp:EnableVerticalScrollbar()\n\tp:SetSpacing( 5 )\n\tp:SetPadding( 5 )\n\tself.GamemodesList = p\n\n\tfunction p:Paint( w, h )\n\t\tdraw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 220 ) )\n\tend\n\n\tlocal w = 100\n\tlocal h = 5\n\n\tfor id, t in SortedPairsByMemberValue( engine.GetGamemodes(), \"title\" ) do\n\t\tif ( !t.menusystem ) then continue end\n\t\tlocal Gamemode = p:Add( \"DMenuButton\" )\n\t\tGamemode:SetContentAlignment( 6 )\n\t\tGamemode:SetText( t.title )\n\t\tif ( Material( \"../gamemodes/\" .. t.name .. \"/icon24.png\" ):IsError() ) then\n\t\t\tGamemode:SetIcon( \"../gamemodes/base/icon24.png\" )\n\t\telse\n\t\t\tGamemode:SetIcon( \"../gamemodes/\" .. t.name .. \"/icon24.png\" )\n\t\tend\n\t\tGamemode:SetTextInset( Gamemode.m_Image:GetWide() + 25, 0 )\n\t\tGamemode:SizeToContents()\n\t\tGamemode:SetTall( 40 )\n\t\tGamemode.DoClick = function()\n\t\t\tRunConsoleCommand( \"gamemode\", t.name )\n\t\t\tself:ClosePopups()\n\t\tend\n\n\t\tp:AddItem( Gamemode )\n\n\t\tw = math.max( w, Gamemode:GetWide() + 20 )\n\t\th = h + 45\n\tend\n\n\t--p:SetWide( w, h )\n\n\tp:SetSize( w, math.min( h, ScrH() / 1.5 ) )\n\tp:SetPos( math.min( pnl:GetPos() - p:GetWide() / 2 + pnl:GetWide() / 2, ScrW() - p:GetWide() - 5 ), ScrH() - 55 - p:GetTall() )\nend\n\nfunction PANEL:RefreshGamemodes( b )\n\n\tfor id, gm in pairs( engine.GetGamemodes() ) do\n\t\tif ( gm.name == engine.ActiveGamemode() ) then self.GamemodeList:SetText( gm.title ) end\n\tend\n\n\tif ( Material( \"../gamemodes/\" .. engine.ActiveGamemode() .. \"/icon24.png\" ):IsError() ) then\n\t\tself.GamemodeList:SetIcon( \"../gamemodes/base/icon24.png\" )\n\telse\n\t\tself.GamemodeList:SetIcon( \"../gamemodes/\" .. engine.ActiveGamemode() .. \"/icon24.png\" )\n\tend\n\n\tself.GamemodeList:SetTextInset( self.GamemodeList.m_Image:GetWide() + 25, 0 )\n\tself.GamemodeList:SizeToContents()\n\n\tself:UpdateBackgroundImages()\n\n\tif ( IsValid( self.NewGameFrame ) ) then self.NewGameFrame:Update() end\n\tif ( IsValid( self.AddonsFrame ) ) then self.AddonsFrame:Update() end\n\t--if ( IsValid( self.NewGameFrame ) ) then self:OpenNewGameMenu( b ) end\n\t--if ( IsValid( self.AddonsFrame ) ) then self:OpenAddonsMenu( b ) end\n\t--if ( IsValid( self.MainMenuPanel ) ) then self:OpenMainMenu( b ) end\n\t--if ( IsValid( self.AchievementsFrame ) ) then self:OpenAchievementsMenu( b ) end\n\n\tif ( IsValid( self.MountedGamesList ) ) then self.MountedGamesList:MoveToFront() end\n\nend\n\nfunction PANEL:RefreshAddons()\n\tif ( !IsValid( self.AddonsFrame ) ) then return end\n\n\tself.AddonsFrame:RefreshAddons()\n\nend\n\nfunction PANEL:RefreshContent()\n\n\tself:RefreshGamemodes( true )\n\tself:RefreshAddons()\n\nend\n\nfunction PANEL:SetProblemCount( problems, severity )\n\t\n\t-- The lua menu doesn't have a problems menu. This function is only here to shut any errors up.\nend\n\nfunction PANEL:ScreenshotScan( folder )\n\n\tlocal bReturn = false\n\n\tlocal Screenshots = file.Find( folder .. \"*.jpg\", \"GAME\" )\n\tfor k, v in RandomPairs( Screenshots ) do\n\n\t\tAddBackgroundImage( folder .. v )\n\t\tbReturn = true\n\n\tend\n\n\treturn bReturn\n\nend\n\n\nfunction PANEL:UpdateBackgroundImages()\n\n\tClearBackgroundImages()\n\n\t--\n\t-- If there's screenshots in gamemodes/<gamemode>/backgrounds/*.jpg use them\n\t--\n\tif ( !self:ScreenshotScan( \"gamemodes/\" .. engine.ActiveGamemode() .. \"/backgrounds/\" ) ) then\n\n\t\t--\n\t\t-- If there's no gamemode specific here we'll use the default backgrounds\n\t\t--\n\t\tself:ScreenshotScan( \"backgrounds/\" )\n\n\tend\n\n\tChangeBackground( engine.ActiveGamemode() )\n\nend\n\nfunction PANEL:Call( str )\n\tprint( \"Not Implemented: \", str )\nend\n\nvgui.Register( \"MainMenuPanel\", PANEL, \"EditablePanel\" )\n\n--\n-- Called from the engine any time the language changes\n--\nfunction LanguageChanged( lang )\n\tif ( !IsValid( pnlMainMenu ) ) then return end\n\n\tlocal pnl = pnlMainMenu\n\tif ( IsValid( pnl.NewGameFrame ) ) then pnl.NewGameFrame:UpdateLanguage() end\n\tif ( IsValid( pnl.AddonsFrame ) ) then pnl:OpenAddonsMenu() end\n\tif ( IsValid( pnl.MainMenuPanel ) ) then pnl:OpenMainMenu() end\n\tif ( IsValid( pnl.AchievementsFrame ) ) then pnl:OpenAchievementsMenu() end\n\tif ( IsValid( pnl.SavesFrame ) ) then pnl:OpenCreationMenu() end\n\n\tpnl.Languages:SetIcon( \"../resource/localization/\" .. lang .. \".png\" )\n\n\tpnl.ProblemsBtn:SetText( \"#problems\" )\n\tpnl.MountedGames:SetText( \"#games\" )\n\n\tpnl.BackButton:SetTextInset( pnl.BackButton.m_Image:GetWide() + 20, 0 )\n\tpnl.BackButton:SetText( \"#back_to_main_menu\" )\n\tpnl.BackButton:SizeToContents()\nend\n\nfunction UpdateMapList()\n\tif ( !IsValid( pnlMainMenu ) ) then return end\n\n\tlocal pnl = pnlMainMenu\n\n\tif ( IsValid( pnl.NewGameFrame ) ) then pnl.NewGameFrame:Update() end\n\t--[[if ( IsValid( pnl.NewGameFrame ) ) then pnl:OpenNewGameMenu() end\n\tif ( IsValid( pnl.AddonsFrame ) ) then pnl:OpenAddonsMenu() end\n\tif ( IsValid( pnl.MainMenuPanel ) ) then pnl:OpenMainMenu() end\n\tif ( IsValid( pnl.AchievementsFrame ) ) then pnl:OpenAchievementsMenu() end]]\nend\n\nhook.Add( \"GameContentChanged\", \"RefreshMainMenu\", function()\n\tif ( !IsValid( pnlMainMenu ) ) then return end\n\n\tpnlMainMenu:RefreshContent()\nend )\n\ntimer.Simple( 0, function()\n\tif ( IsValid( pnlMainMenu ) ) then pnlMainMenu:Remove() end\n\n\tpnlMainMenu = vgui.Create( \"MainMenuPanel\" )\n\n\thook.Run( \"GameContentChanged\" )\nend )\n\n-- A hack to bring the console to front when menu_reload is ran\ntimer.Simple( 1, function()\n\tif ( gui.IsConsoleVisible() ) then gui.ShowConsole() end\nend )\n\n--[[\n\n--\n-- Get the player list for this server\n--\nfunction GetPlayerList( serverip )\n\n\tserverlist.PlayerList( serverip, function( tbl )\n\n\t\tlocal json = util.TableToJSON( tbl )\n\t\tpnlMainMenu:Call( \"SetPlayerList( '\"..serverip..\"', \"..json..\")\" )\n\n\tend )\n\nend\n\nlocal Servers = {}\n\nfunction GetServers( type, id )\n\n\n\tlocal data =\n\t{\n\t\tFinished = function()\n\n\t\tend,\n\n\t\tCallback = function( ping , name, desc, map, players, maxplayers, botplayers, pass, lastplayed, address, gamemode, workshopid )\n\n\t\t\tname\t= string.JavascriptSafe( name )\n\t\t\tdesc\t= string.JavascriptSafe( desc )\n\t\t\tmap\t\t= string.JavascriptSafe( map )\n\t\t\taddress = string.JavascriptSafe( address )\n\t\t\tgamemode = string.JavascriptSafe( gamemode )\n\t\t\tworkshopid = string.JavascriptSafe( workshopid )\n\n\t\t\tif ( pass ) then pass = \"true\" else pass = \"false\" end\n\n\t\t\tpnlMainMenu:Call( \"AddServer( '\"..type..\"', '\"..id..\"', \"..ping..\", \\\"\"..name..\"\\\", \\\"\"..desc..\"\\\", \\\"\"..map..\"\\\", \"..players..\", \"..maxplayers..\", \"..botplayers..\", \"..pass..\", \"..lastplayed..\", \\\"\"..address..\"\\\", \\\"\"..gamemode..\"\\\", \\\"\"..workshopid..\"\\\" )\" )\n\n\t\tend,\n\n\t\tType = type,\n\t\tGameDir = 'garrysmod',\n\t\tAppID = 4000,\n\t}\n\n\tserverlist.Query( data )\n\nend\n\n]]\n"
  },
  {
    "path": "lua/menu/custom/new_game.lua",
    "content": "\ninclude( \"new_game_panels.lua\" )\n\nCreateConVar( \"cl_maxplayers\", \"1\", FCVAR_ARCHIVE )\n\n--[[\nTODO:\nmake sure the text of categories / multiplayer settings does not overflow, especially on lower resolutions\nFix reloading the panels resetting the scrolling for categories and server settings?\n\nAuto scroll to select map on first open or something?\n\nBetter map icon visuals?\nAllow people to create their own categories?\nFigure out fonts? The current ones look neat but blurry\n]]\n\nsurface.CreateFont( \"StartNewGameFont\", {\n\tfont = \"Roboto Lt\",\n\tsize = 18,\n} )\n\nsurface.CreateFont( \"SingleMultiPlayer\", {\n\tfont = \"Roboto Lt\",\n\tsize = 17,\n} )\n\nsurface.CreateFont( \"DermaRobotoDefault\", {\n\tfont = \"Roboto Lt\",\n\tsize = 13\n} )\n\nsurface.CreateFont( \"StartNewGame\", {\n\tfont = \"Roboto\",\n\tsize = 30,\n} )\n\nsurface.CreateFont( \"rb655_MapList\", {\n\tsize = 12,\n\tfont = \"Tahoma\"\n} )\n\nsurface.CreateFont( \"rb655_MapSubCat\", {\n\tsize = 30,\n\t--weight = 900,\n\tfont = \"Roboto Lt\"\n} )\n\nlocal noise = Material( \"gui/noise.png\", \"nocull noclamp smooth\" )\nlocal function DrawHUDBox( x, y, w, h, mat, clr )\n\tsurface.SetDrawColor( clr or Color( 255, 255, 255, 255 ) )\n\n\tsurface.SetMaterial( mat or noise )\n\tsurface.DrawTexturedRectUV( x, y, w, h, 0, 0, w / 128, h / 128 )\nend\n\nlocal function EnableMouseScroll( s )\n\tlocal mousePressed = input.IsMouseDown( MOUSE_RIGHT ) or input.IsMouseDown( MOUSE_LEFT )\n\tif ( !mousePressed ) then s.start = nil s.EnableMouseScrollEnabled = false return end\n\n\tif ( !s.start and s:IsChildHovered() and !s:GetVBar():IsChildHovered() and !s.EnableMouseScrollEnabled ) then\n\t\ts.start = s:GetVBar():GetScroll()\n\t\tlocal x, y = input.GetCursorPos()\n\t\ts.startY = y\n\t\ts.EnableMouseScrollEnabled = true\n\tend\n\ts.EnableMouseScrollEnabled = true\n\n\tif ( s.start ) then\n\t\tlocal x, y = input.GetCursorPos()\n\t\ts:GetVBar():SetScroll( s.start + ( s.startY - y ) )\n\tend\nend\n\nlocal matGradientUp = Material( \"gui/gradient_up\" )\nlocal function DrawScrollDarkGradients( self, w, h )\n\tif ( self.VBar:GetScroll() + self:GetTall() < self.pnlCanvas:GetTall() ) then\n\t\tlocal height = math.min( ( self.pnlCanvas:GetTall() - ( self.VBar:GetScroll() + self:GetTall() ) ) / 3, 30 )\n\t\theight = math.floor( height )\n\n\t\tsurface.SetMaterial( matGradientUp )\n\t\tsurface.SetDrawColor( Color( 0, 0, 0, 200 ) )\n\t\tsurface.DrawTexturedRect( 0, h - height, w, height )\n\tend\n\n\tif ( self.VBar:GetScroll() > 0 ) then\n\t\tlocal height = math.min( self.VBar:GetScroll() / 3, 30 )\n\t\theight = math.floor( height )\n\n\t\tsurface.SetMaterial( matGradientUp )\n\t\tsurface.SetDrawColor( Color( 0, 0, 0, 200 ) )\n\t\tsurface.DrawTexturedRectUV( 0, 0, w, height, 0, 1, 1, 0 )\n\tend\nend\n\nlocal LocalizedShit = {}\nlocal function SetLocalizedString( self, txt )\n\tself:SetText( language.GetPhrase( txt ) )\n\ttable.insert( LocalizedShit, { panel = self, text = txt } )\nend\n\nlocal HeaderColor = color_black\nlocal HeaderColor_mid = HeaderColor\n\nlocal g_CurrentScroll\n\nfunction GetMapsFromCategorySearch( cat, searchText )\n\tlocal maps = GetMapsFromCategory( cat )\n\tif ( !maps or #maps < 1 ) then return {} end\n\n\tlocal output = {}\n\tfor _, map in SortedPairs( maps ) do\n\t\tif ( searchText and !map.name:find( searchText:lower() ) ) then continue end\n\n\t\ttable.insert( output, map )\n\tend\n\n\treturn output\nend\n\nlocal PANEL = {}\n\ngMapIcons = gMapIcons or {}\n\nlocal matIncompat = Material( \"html/img/incompatible.png\" )\nlocal matNoIcon = Material( \"gui/noicon.png\", \"nocull smooth\" )\n\nfunction PANEL:Init()\n\n\tg_CurrentScroll = nil\n\tself.SearchText = nil\n\n\tself:Dock( FILL )\n\n\t--------------------------------- CATEGORIES ---------------------------------\n\n\tlocal MapCategories = vgui.Create( \"DPanel\", self )\n\tMapCategories:Dock( LEFT )\n\tMapCategories:SetWide( math.Clamp( ScrW() / 6, 150, 200 ) )\n\tMapCategories:DockMargin( 5, 5, 0, 5 )\n\tMapCategories:DockPadding( 5, 5, 0, 5 )\n\tfunction MapCategories:Paint( w, h )\n\t\tDrawHUDBox( 0, 0, w, h )\n\tend\n\n\tlocal searchBar = vgui.Create( \"DFancyTextEntry\", MapCategories )\n\tsearchBar:Dock( TOP )\n\tsearchBar:SetFont( \"DermaRobotoDefault\" )\n\tsearchBar:SetPlaceholderText( \"searchbar_placeholer\" )\n\tsearchBar:DockMargin( 0, 0, 0, 0 )\n\tsearchBar:SetZPos( -1 )\n\tsearchBar:SetHeight( 24 )\n\tsearchBar:SetUpdateOnType( true )\n\tsearchBar.OnValueChange = function() self:DoSearch( searchBar:GetText() ) end\n\n\tself.Categories = {}\n\tlocal cat_pnl = self:AddCategoryButton( MapCategories, \"Favourites\", \"Favourites\" )\n\tcat_pnl:SetZPos( 0 )\n\n\tlocal CategoriesScroll = vgui.Create( \"DScrollPanel\", MapCategories )\n\tCategoriesScroll:Dock( FILL )\n\tCategoriesScroll:DockMargin( 0, 5, 0, 0 )\n\tCategoriesScroll:GetVBar():SetWide( 0 )\n\tCategoriesScroll.Think = EnableMouseScroll\n\tCategoriesScroll.PaintOver = DrawScrollDarkGradients\n\n\tself.CategoriesPanel = CategoriesScroll\n\n\t---------------------------- CONTAINER FOR MAPS ----------------------------\n\n\tlocal Scroll = vgui.Create( \"DScrollPanel\", self )\n\tScroll:Dock( FILL )\n\tScroll:DockMargin( 0, 5, 5, 5 )\n\tfunction Scroll:Paint( w, h )\n\t\tDrawHUDBox( 0, 0, w, h )\n\tend\n\tScroll.Think = EnableMouseScroll\n\n\tlocal sbar = Scroll:GetVBar()\n\tsbar:SetWide( 8 )\n\tif ( sbar.SetHideButtons ) then sbar:SetHideButtons( true ) end\n\n\t-- HACK!!!!\n\tsbar.OldSetScroll = sbar.SetScroll\n\tfunction sbar:SetScroll( scroll )\n\t\tg_CurrentScroll = scroll\n\t\tself:OldSetScroll( scroll )\n\tend\n\n\tfunction sbar:Paint( w, h )\n\t\tsurface.SetDrawColor( 100, 100, 100, 100 )\n\t\tsurface.DrawRect( 0, 0, w, h )\n\tend\n\tfunction sbar.btnGrip:Paint( w, h )\n\t\tsurface.SetDrawColor( 0, 0, 0, 128 )\n\t\tsurface.DrawRect( 0, 0, w, h )\n\tend\n\n\tlocal CategoryMaps = vgui.Create( \"DIconLayout\", Scroll )\n\tCategoryMaps:SetSpaceX( 5 )\n\tCategoryMaps:SetSpaceY( 5 )\n\tCategoryMaps:Dock( TOP )\n\tCategoryMaps:DockMargin( 5, 5, 5, 5 )\n\tCategoryMaps:DockPadding( 5, 5, 5, 5 )\n\tself.CategoryMaps = CategoryMaps\n\n\t--------------------------------- SETTINGS ---------------------------------\n\n\tlocal Settings = vgui.Create( \"DListLayout\", self )\n\tSettings:Dock( RIGHT )\n\tSettings:SetWide( math.max( ScrW() / 6, 180 ) )\n\tSettings:DockMargin( 0, 5, 5, 5 )\n\tSettings:DockPadding( 5, 5, 5, 5 )\n\tfunction Settings:Paint( w, h )\n\t\tDrawHUDBox( 0, 0, w, h )\n\tend\n\tself.Settings = Settings\n\n\t--------------------------------- SINGLE / MULTIPLAYER ---------------------------------\n\n\tlocal SingleMultiPlayer = vgui.Create( \"DButton\", Settings )\n\tSingleMultiPlayer:SetFont( \"SingleMultiPlayer\" )\n\tSingleMultiPlayer:SetTall( 32 )\n\tSingleMultiPlayer:SetZPos( -3 )\n\tSingleMultiPlayer:Dock( TOP )\n\tSingleMultiPlayer:DockMargin( 0, 0, 0, 5 )\n\tSingleMultiPlayer:SetColor( color_white )\n\n\tSingleMultiPlayer.SetTextGenerated = function( s, n ) s:SetText( language.GetPhrase( \"maxplayers_\" .. n ) ) end\n\n\tSingleMultiPlayer.SetValue = function( s, n ) s.PlayerCount = tonumber( n ) RunConsoleCommand( \"cl_maxplayers\", n ) s:DoUpdateText() end\n\tSingleMultiPlayer.GetValue = function( s ) return s.PlayerCount or 1 end\n\n\tSingleMultiPlayer.DoUpdateText = function( s )\n\t\ts:SetTextGenerated( s:GetValue() )\n\t\ts:DoUpdatePanels( Settings )\n\t\tif ( self.GamemodeSettings ) then\n\t\t\ts:DoUpdatePanels( self.GamemodeSettings:GetCanvas() )\n\n\t\t\t-- Hack\n\t\t\tlocal hasVisibleChildren = false\n\t\t\tfor id, pnl in pairs( self.GamemodeSettings:GetCanvas():GetChildren() ) do\n\t\t\t\tif ( pnl:IsVisible() ) then hasVisibleChildren = true break end\n\t\t\tend\n\t\t\tself.GamemodeSettingsLabel:SetVisible( hasVisibleChildren )\n\t\tend\n\tend\n\tSingleMultiPlayer.DoUpdatePanels = function( s, parent )\n\t\tif ( !IsValid( parent ) ) then return end\n\t\tfor id, pnl in pairs( parent:GetChildren() ) do\n\t\t\tif ( pnl.Singleplayer == nil ) then continue end\n\n\t\t\tpnl:SetVisible( ( s:GetValue() < 2 ) == pnl.Singleplayer or pnl.Singleplayer )\n\t\t\tif ( !pnl.OldHeight ) then pnl.OldHeight = pnl:GetTall() end\n\t\t\tpnl:SetHeight( pnl:IsVisible() and pnl.OldHeight or 0 )\n\t\tend\n\t\tparent:InvalidateLayout( true )\n\tend\n\tSingleMultiPlayer.CloseDropDown = function( s )\n\t\tif ( s.Butts and #s.Butts > 0 ) then\n\t\t\tfor id, p in pairs( s.Butts ) do p:Remove() end\n\t\t\ts.Butts = {}\n\t\t\treturn true\n\t\tend\n\tend\n\n\thook.Add( \"VGUIMousePressed\", \"NewGameMenu_FuyckingHack\", function( pnl, mc )\n\t\tif ( !IsValid( SingleMultiPlayer ) or !SingleMultiPlayer.Butts or vgui.GetHoveredPanel() == SingleMultiPlayer ) then return end\n\t\tfor id, p in pairs( SingleMultiPlayer.Butts ) do if ( vgui.GetHoveredPanel() == p ) then return end end\n\n\t\tSingleMultiPlayer:CloseDropDown()\n\tend )\n\n\tSingleMultiPlayer.DoClick = function( s )\n\t\tif ( s:CloseDropDown() ) then return end\n\n\t\ts.Butts = {}\n\t\tlocal alt = false\n\t\tlocal x, y = s:LocalToScreen( 0, 0 )\n\t\tfor id, v in pairs( { 1, 2, 4, 8, 16, 32, 64 } ) do\n\t\t\talt = !alt\n\t\t\ty = y + s:GetTall()\n\t\t\tlocal but = vgui.Create( \"DButton\", self )\n\t\t\tbut:SetPos( x, y )\n\t\t\tbut:SetSize( s:GetSize() )\n\t\t\ts.SetTextGenerated( but, v )\n\t\t\tbut.Bottom = (v == 64)\n\t\t\tbut.Value = v\n\t\t\tbut.Alt = alt\n\t\t\tbut:SetFont( \"SingleMultiPlayer\" )\n\t\t\tbut:SetColor( color_white )\n\t\t\tbut.DoClick = function( buttt ) s:SetValue( buttt.Value ) s:CloseDropDown() end\n\t\t\tbut.Paint = function( buttt, w, h )\n\t\t\t\tlocal clr = Color( 30, 190, 30 )\n\t\t\t\tif ( but.Alt ) then clr = Color( 32, 196, 32 ) end\n\t\t\t\tif ( but.Hovered ) then clr = Color( 48, 210, 48 ) end\n\t\t\t\tif ( but.Depressed ) then clr = Color( 24, 180, 24 ) end\n\t\t\t\tsurface.SetDrawColor( clr )\n\t\t\t\tif ( !buttt.Bottom ) then\n\t\t\t\t\tsurface.DrawRect( 0, 0, w, h )\n\t\t\t\telse\n\t\t\t\t\tsurface.DrawRect( 0, 0, w, h - 1 )\n\t\t\t\tend\n\n\t\t\t\tsurface.SetDrawColor( Color( 34, 170, 34 ) )\n\t\t\t\tif ( !buttt.Bottom ) then\n\t\t\t\t\t--surface.DrawLine( 0, 0, 0, h ) -- left\n\t\t\t\t\t--surface.DrawLine( w - 1, 0, w - 1, h ) -- right -- Doesn't show bottom pixel??\n\t\t\t\t\tsurface.DrawRect( 0, 0, 1, h )\n\t\t\t\t\tsurface.DrawRect( w - 1, 0, 1, h )\n\t\t\t\telse\n\t\t\t\t\tsurface.DrawLine( 0, 0, 0, h - 1 ) -- left\n\t\t\t\t\tsurface.DrawLine( w - 1, 0, w - 1, h - 1 ) -- right\n\n\t\t\t\t\tsurface.SetDrawColor( Color( 17, 136, 17 ) )\n\t\t\t\t\tsurface.DrawLine( 1, h - 1, w - 1, h - 1 ) -- bottom\n\t\t\t\tend\n\t\t\tend\n\t\t\ttable.insert( s.Butts, but )\n\t\tend\n\tend\n\tSingleMultiPlayer.Paint = function( s, w, h )\n\t\tlocal menuOpen = s.Butts and #s.Butts > 0\n\n\t\tlocal clr = Color( 82, 204, 82 )\n\t\tif ( s.Hovered ) then clr = Color( 86, 210, 86 ) end\n\t\tif ( s.Depressed ) then clr = Color( 82, 204, 82 ) end\n\n\t\tsurface.SetDrawColor( clr )\n\t\tsurface.DrawRect( 1, 1, w-2, h-2 )\n\n\t\tsurface.SetDrawColor( Color( 30, 190, 30 ) )\n\t\tif ( s.Hovered ) then surface.SetDrawColor( Color( 36, 200, 36 ) ) end\n\t\tsurface.SetMaterial( matGradientUp )\n\t\tsurface.DrawTexturedRect( 1, 1, w-2, h-2 )\n\n\t\tsurface.SetDrawColor( Color( 34, 170, 34 ) )\n\t\tsurface.DrawLine( 1, 0, w-1, 0 ) -- top\n\t\tif ( menuOpen ) then\n\t\t\tsurface.DrawRect( 0, 1, 1, h ) -- left\n\t\t\tsurface.DrawRect( w - 1, 1, 1, h ) -- right\n\n\t\t\tsurface.SetDrawColor( Color( 30, 190, 30 ) )\n\t\t\tif ( s.Hovered ) then surface.SetDrawColor( Color( 36, 200, 36 ) ) end\n\t\t\tsurface.DrawRect( 1, h-2, w-2, 2 )\n\t\telse\n\t\t\tsurface.DrawLine( 0, 1, 0, h - 1 ) -- left\n\t\t\tsurface.DrawLine( w - 1, 1, w - 1, h - 1 ) -- right\n\n\t\tend\n\n\t\tsurface.SetDrawColor( Color( 17, 136, 17 ) )\n\t\tsurface.DrawLine( 1, h - 1, w - 1, h - 1 ) -- bottom\n\n\t\tlocal clr2 = Color( 118, 214, 118 )\n\t\tif ( s.Hovered ) then clr2 = Color( 128, 220, 128 ) end\n\t\t--if ( s.Depressed ) then clr2 = Color( 118, 214, 118 ) end\n\t\tsurface.SetDrawColor( clr2 )\n\t\tsurface.DrawLine( 1, 1, w - 1, 1 )\n\n\t\tlocal size = 9\n\t\tsurface.SetDrawColor( Color( 255, 255, 255 ) )\n\t\tdraw.NoTexture()\n\t\tsurface.DrawPoly( {\n\t\t\t{ x = w - ( h / 2 + size / 2 ), y = h / 2 - size / 4 },\n\t\t\t{ x = w - ( h / 2 - size / 2 ), y = h / 2 - size / 4 },\n\t\t\t{ x = w - ( h / 2 ), y = h / 2 + size / 4 }\n\t\t} )\n\tend\n\tself.SingleMultiPlayer = SingleMultiPlayer\n\n\t--------------------------------- TOP CONTENT ---------------------------------\n\n\tlocal ServerName = self:ServerSettings_AddTextEntry( {\n\t\tname = \"hostname\",\n\t\ttext = \"server_name\",\n\t\tzOrder = -2,\n\t\thelp = \"The name of your server that will appear in the server browser\"\n\t}, Settings )\n\tSettings.ServerName = ServerName\n\n\tself:ServerSettings_AddTextEntry( {\n\t\tname = \"sv_password\",\n\t\ttext = \"server_password\",\n\t\tzOrder = -1,\n\t\thelp = \"The password for your server that other people have to enter before they can join your server\"\n\t}, Settings )\n\n\tlocal sv_lan = self:ServerSettings_AddCheckbox( {\n\t\ttext = \"lan_server\",\n\t\tname = \"sv_lan\",\n\t\thelp = \"Only people on your Local Area Network can connect to the server\",\n\t}, Settings )\n\n\tlocal p2p_enabled = self:ServerSettings_AddCheckbox( {\n\t\ttext = \"p2p_server\",\n\t\tname = \"p2p_enabled\",\n\t\thelp = \"Allow people to connect to your Listen Server using Steam P2P networking\",\n\t}, Settings )\n\n\tlocal p2p_friendsonly = self:ServerSettings_AddCheckbox( {\n\t\ttext = \"p2p_server_friendsonly\",\n\t\tname = \"p2p_friendsonly\",\n\t\thelp = \"Only allow people on your friends list to join your P2P server\",\n\t}, Settings )\n\n\tsv_lan.OnValueChanged = function( pnl, checked )\n\t\tif ( checked ) then\n\t\t\tp2p_enabled:SetChecked( false )\n\t\t\tp2p_friendsonly:SetChecked( false )\n\t\tend\n\tend\n\tp2p_enabled.OnValueChanged = function( pnl, checked )\n\t\tif ( checked ) then\n\t\t\tsv_lan:SetChecked( false )\n\t\tend\n\tend\n\tp2p_friendsonly.OnValueChanged = function( pnl, checked )\n\t\tif ( checked ) then\n\t\t\tsv_lan:SetChecked( false )\n\t\t\tp2p_enabled:SetChecked( true )\n\t\tend\n\tend\n\n\t--------------------------------- MIDDLE CONTENT - LABEL ---------------------------------\n\n\tlocal GamemodeSettingsLabel = Settings:Add( \"DLabel\" )\n\tGamemodeSettingsLabel:Dock( TOP )\n\tGamemodeSettingsLabel:SetText( \"Gamemode Settings\" )\n\tGamemodeSettingsLabel:SetFont( \"StartNewGameFont\" )\n\tGamemodeSettingsLabel:SetContentAlignment( 5 )\n\tGamemodeSettingsLabel:DockMargin( 0, 4, 0, 4 )\n\tGamemodeSettingsLabel:SetTextColor( HeaderColor )\n\tself.GamemodeSettingsLabel = GamemodeSettingsLabel\n\n\t--------------------------------- MIDDLE CONTENT ---------------------------------\n\n\tlocal GamemodeSettings = vgui.Create( \"DScrollPanel\", Settings )\n\tGamemodeSettings:Dock( FILL )\n\tGamemodeSettings:DockMargin( -5, 0, -5, 5 )\n\tGamemodeSettings:GetCanvas():DockPadding( 5, 0, 5, 0 )\n\tGamemodeSettings:GetVBar():SetWide( 0 )\n\tself.GamemodeSettings = GamemodeSettings\n\tfunction GamemodeSettings:Paint( w, h )\n\t\t--surface.SetDrawColor( 0, 0, 0, 32 )\n\t\t--surface.DrawRect( 0, 0, w, h )\n\tend\n\tGamemodeSettings.Think = EnableMouseScroll\n\tGamemodeSettings.PaintOver = DrawScrollDarkGradients\n\n\t--------------------------------- END CONTENT ---------------------------------\n\n\tlocal StartGame = Settings:Add( \"DMenuButton\" )\n\tStartGame:Dock( BOTTOM )\n\tStartGame:SetFont( \"StartNewGame\" )\n\tSetLocalizedString( StartGame, \"start_game\" )\n\tStartGame:SetTall( 48 )\n\tStartGame.DoClick = function()\n\t\tself:LoadMap()\n\tend\n\tStartGame:SetSpecial( true )\n\n\t--------------------------------- Update Content ---------------------------------\n\n\tself:Update()\n\nend\n\nfunction PANEL:Paint( w, h )\n\tsurface.SetDrawColor( 0, 0, 0, 150 )\n\tsurface.DrawRect( 0, 0, w, h )\n\n\tif ( self.CurrentCategory and IsValid( self.Categories[ self.CurrentCategory ] ) ) then\n\t\t--if ( !self.Categories[ self.CurrentCategory ] ) then self:SelectCat( \"Sandbox\" ) return end\n\t\tself.Categories[ self.CurrentCategory ].Depressed = true\n\tend\nend\n\nfunction PANEL:SelectMap( map )\n\tself.CurrentMap = map\nend\n\nfunction PANEL:AddCategoryButton( parent, catClass, name )\n\tlocal button = parent:Add( \"MenuCategoryButton\" )\n\tbutton:Dock( TOP )\n\tbutton:DockMargin( 0, 1, 0, 0 )\n\tbutton:SetText( name )\n\tbutton.DoClick = function()\n\t\tg_CurrentScroll = nil\n\t\tself:SelectCat( catClass )\n\tend\n\tbutton:SetContentAlignment( 4 )\n\tbutton:SetTextInset( 5, 0 )\n\tbutton:SetCategory( catClass )\n\t--button:SetAlt( alt )\n\tbutton.NewGameMenu = self\n\n\tself.Categories[ catClass ] = button\n\treturn button\nend\n\nfunction PANEL:DoSearch( txt )\n\tself.SearchText = txt\n\tif ( self.SearchText:Trim() == \"\" ) then self.SearchText = nil end\n\n\tself:SelectCat( self.CurrentCategory ) -- Refreshes the map list\nend\n\nfunction PANEL:ServerSettings_AddTextEntry( v, parent )\n\n\tlocal DTextEntry = vgui.Create( \"MenuSettingsTextEntry\", parent )\n\tDTextEntry:Dock( TOP )\n\tDTextEntry:SetFont( \"DermaRobotoDefault\" )\n\tDTextEntry:SetTall( 22 )\n\tDTextEntry:DockMargin( 0, 0, 0, 1 )\n\tif ( v.text ) then DTextEntry:SetText( v.text ) end\n\tif ( v.name ) then DTextEntry:SetConVar( v.name ) end\n\tif ( v.zOrder ) then DTextEntry:SetZPos( v.zOrder + 1 ) end\n\tif ( v.help ) then DTextEntry:SetTooltip( v.help ) end\n\tif ( v.singleplayer ) then DTextEntry.Singleplayer = true else DTextEntry.Singleplayer = false end\n\treturn DTextEntry\n\nend\n\nfunction PANEL:ServerSettings_AddCheckbox( v, parent )\n\n\tlocal CheckBox = vgui.Create( \"MenuSettingsCheckbox\", parent )\n\tCheckBox:Dock( TOP )\n\tCheckBox:SetFont( \"DermaRobotoDefault\" )\n\tCheckBox:SetTall( 22 )\n\tCheckBox:DockMargin( 0, 0, 0, 1 )\n\tif ( v.name ) then CheckBox:SetConVar( v.name ) end\n\tif ( v.text ) then CheckBox:SetText( v.text ) end\n\tif ( v.zOrder ) then CheckBox:SetZPos( v.zOrder ) end\n\tif ( v.help ) then CheckBox:SetTooltip( v.help ) end\n\tif ( v.singleplayer ) then CheckBox.Singleplayer = true else CheckBox.Singleplayer = false end\n\n\treturn CheckBox\n\nend\n\nfunction PANEL:ServerSettings_AddSlider( v, parent )\n\tlocal Slider = vgui.Create( \"MenuSettingsSlider\", parent )\n\tSlider:Dock( TOP )\n\tif ( v.name ) then Slider:SetConVar( v.name ) end\n\tif ( v.text ) then Slider:SetText( v.text ) end\n\tSlider:SetFont( \"DermaRobotoDefault\" )\n\tSlider:SetTall( 22 )\n\tSlider:DockMargin( 0, 0, 0, 1 )\n\tif ( v.zOrder ) then Slider:SetZPos( v.zOrder ) end\n\tif ( v.help ) then Slider:SetTooltip( v.help ) end\n\tif ( v.singleplayer ) then Slider.Singleplayer = true else Slider.Singleplayer = false end\n\n\treturn Slider\nend\n\nfunction PANEL:UpdateLanguage()\n\tself.SingleMultiPlayer:SetTextGenerated( self.SingleMultiPlayer:GetValue() )\n\n\tfor id, t in pairs( LocalizedShit ) do\n\t\tif ( !IsValid( t.panel ) ) then table.remove( LocalizedShit, id ) continue end -- Not too sure about the removal of the element inside the loop. Is Lua OK with this?\n\t\tt.panel:SetText( language.GetPhrase( t.text ) )\n\tend\n\n\t-- Update Favourites?\n\t-- Update whatever\nend\n\nfunction PANEL:Update()\n\n\t---------------------------------- Build Categories ----------------------------------\n\n\tlocal Categories = self.CategoriesPanel\n\tCategories:Clear()\n\n\t--self.Categories = {}\n\n\tlocal pergamemode = Categories:Add( \"DLabel\" )\n\tpergamemode:Dock( TOP )\n\tpergamemode:SetText( \"Gamemodes\" )\n\tpergamemode:SetFont( \"StartNewGameFont\" )\n\tpergamemode:SetContentAlignment( 5 )\n\tpergamemode:SetTextColor( HeaderColor )\n\tpergamemode:DockMargin( 0, 0, 0, 3 )\n\n\tfor cat, name in SortedPairsByValue( GetMapCategories() ) do\n\t\tif ( cat == \"Favourites\" ) then continue end -- We have custom handling of this category\n\t\tself:AddCategoryButton( Categories, cat, name )\n\tend\n\n\tlocal games = Categories:Add( \"DLabel\" )\n\tgames:Dock( TOP )\n\tgames:SetText( \"Games\" )\n\tgames:SetFont( \"StartNewGameFont\" )\n\tgames:SetContentAlignment( 5 )\n\tgames:SetTextColor( HeaderColor )\n\tgames:DockMargin( 0, 5, 0, 3 )\n\n\tfor cat, name in SortedPairsByValue( GetMapCategories( \"game\" ) ) do\n\t\tself:AddCategoryButton( Categories, cat, name )\n\tend\n\n\t--for i = 0, 10 do self:AddCategoryButton( Categories, \"Filler \" .. i, \"Filler \" .. i, i % 2 ) end\n\n\t---------------------------------- Build server settigns ----------------------------------\n\n\tlocal GamemodeSettings = self.GamemodeSettings\n\tGamemodeSettings:Clear()\n\n\tlocal settings_file = file.Read( \"gamemodes/\" .. engine.ActiveGamemode() .. \"/\" .. engine.ActiveGamemode() .. \".txt\", true )\n\n\tif ( settings_file ) then\n\n\t\tlocal SettingsFile = util.KeyValuesToTable( settings_file )\n\n\t\tif ( SettingsFile.settings ) then\n\t\t\tlocal zOrder = 0\n\n\t\t\tfor k, v in pairs( SettingsFile.settings ) do\n\t\t\t\tif ( v.type == \"CheckBox\" ) then\n\t\t\t\t\tv.zOrder = zOrder\n\t\t\t\t\tself:ServerSettings_AddCheckbox( v, GamemodeSettings )\n\t\t\t\telseif ( v.type == \"Text\" ) then\n\t\t\t\t\tv.zOrder = zOrder\n\t\t\t\t\tself:ServerSettings_AddTextEntry( v, GamemodeSettings )\n\t\t\t\t\tzOrder = zOrder + 1 -- Account for the label\n\t\t\t\telseif ( v.type == \"Numeric\" ) then\n\t\t\t\t\tv.zOrder = zOrder\n\t\t\t\t\tself:ServerSettings_AddSlider( v, GamemodeSettings )\n\t\t\t\tend\n\n\t\t\t\tzOrder = zOrder + 1\n\t\t\tend\n\t\tend\n\tend\n\n\t--------------------------------- Update Singleplayer / Multiplayer selector ---------------------------------\n\n\tself.SingleMultiPlayer:SetValue( GetConVarNumber( \"cl_maxplayers\" ) )\n\n\t--------------------------------- LOAD LAST MAP ---------------------------------\n\n\tlocal map, cat = LoadLastMap()\n\n\tif ( self.CurrentMap and self.CurrentCategory ) then -- We had some map selected, switch back to it!\n\t\tmap = self.CurrentMap\n\t\tcat = self.CurrentCategory\n\tend\n\n\tif ( !DoesCategoryExist( cat ) ) then\n\t\t-- Try to find the category the map is in\n\t\tcat = GetMapCategory( map )\n\tend\n\n\tif ( !cat or !map ) then\n\t\tmap = \"gm_flatgrass\"\n\t\tcat = \"Sandbox\"\n\tend\n\n\tself:SelectCat( cat )\n\tself:SelectMap( map )\n\nend\n\nfunction PANEL:BuildIconList()\n\tself.IconListCache = {}\n\n\tlocal files = file.Find( \"maps/thumb/*.png\", \"GAME\" )\n\tfor id, filename in pairs( files ) do\n\t\tself.IconListCache[ filename:sub( 0, filename:len() - 4 ) ] = \"maps/thumb/\" .. filename\n\tend\n\n\t-- Stupid ass addons that didn't update yet\n\tlocal files2 = file.Find( \"maps/*.png\", \"GAME\" )\n\tfor id, filename in pairs( files2 ) do\n\t\tself.IconListCache[ filename:sub( 0, filename:len() - 4 ) ] = \"maps/\" .. filename\n\tend\nend\n\nfunction PANEL:CacheIcon( map )\n\tif ( !self.IconListCache ) then self:BuildIconList() end\n\n\tmap = map:Trim() -- Duplicate CS:GO maps have spaces on the end! ( When loaded from the HTML menu )\n\t--[[local mat = Material( \"maps/thumb/\" .. map .. \".png\" )\n\tif ( mat:IsError() ) then mat = Material( \"maps/\" .. map .. \".png\" ) end -- Stupid ass addons that didn't update yet\n\tif ( mat:IsError() ) then mat = matNoIcon end]]\n\tif ( !self.IconListCache[ map ] ) then return matNoIcon end\n\treturn Material( self.IconListCache[ map ] )\nend\n\nlocal border = 4\nlocal border_w = 5\nlocal matHover = Material( \"gui/sm_hover.png\", \"nocull\" )\nlocal boxHover = GWEN.CreateTextureBorder( border, border, 64 - border * 2, 64 - border * 2, border_w, border_w, border_w, border_w, matHover )\n\nfunction PANEL:SelectCat( cat )\n\n\tif ( self.CurrentCategory and self.Categories[ self.CurrentCategory ] ) then self.Categories[ self.CurrentCategory ].Depressed = false end\n\tself.CurrentCategory = cat\n\n\tself.CategoryMaps:Clear()\n\n\tlocal maps = GetMapsFromCategorySearch( cat, self.SearchText )\n\tif ( !maps or #maps < 1 ) then return end\n\n\tlocal subCategories, subCategorieyPatterns = GetMapSubCategories()\n\n\tlocal categories = {}\n\tfor _, map in SortedPairs( maps ) do\n\t\tlocal c = subCategories[ map.name ] or \"Other\"\n\n\t\tif ( !subCategories[ map.name ] ) then\n\t\t\tfor pattern, cate in SortedPairs( subCategorieyPatterns ) do\n\t\t\t\tif ( string.find( map.name, pattern ) ) then\n\t\t\t\t\tif ( c != \"Other\" ) then print( \"Multiple categories for 1 map!!!\", map.name, c, cate ) end\n\t\t\t\t\tc = cate\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\n\t\tcategories[ c ] = categories[ c ] or {}\n\t\ttable.insert( categories[ c ], map )\n\tend\n\n\tfor cat_name, cat_maps in SortedPairs( categories ) do\n\n\t\tlocal catText = cat_name\n\t\tif ( catText:sub( 2, 3 ) == \". \" ) then catText = catText:sub( 4 ) end\n\n\t\tlocal label = self.CategoryMaps:Add( \"DLabel\" )\n\t\tlabel.OwnLine = true\n\t\tlabel:SetTextColor( HeaderColor_mid )\n\t\tlabel:SetText( catText )\n\t\tlabel:SetFont( \"rb655_MapSubCat\" )\n\t\tlabel:SizeToContents()\n\t\tlabel:SetBright( true )\n\n\t\tfor _, map in SortedPairsByMemberValue( cat_maps, \"name\" ) do\n\n\t\t\tlocal button = self.CategoryMaps:Add( \"DImageButton\" )\n\t\t\tbutton:SetText( map.name )\n\n\t\t\t-- Get rid of the shitty \"clicled on\" animation\n\t\t\t--button.OnMousePressed = function( s, mc ) DButton.OnMousePressed( s, mc ) end\n\n\t\t\t-- Handles above stuff too\n\t\t\tMenu_InstallDButtonScrollProtection( button, 2, true )\n\n\t\t\tif ( map.incompatible ) then\n\t\t\t\tbutton.m_Image:SetMaterial( matIncompat )\n\t\t\telse\n\t\t\t\tif ( !gMapIcons[ map.name ] ) then gMapIcons[ map.name ] = self:CacheIcon( map.name ) end\n\t\t\t\tbutton.m_Image:SetMaterial( gMapIcons[ map.name ] )\n\t\t\tend\n\n\t\t\tbutton:SetSize( 128, 128 )\n\t\t\tbutton.DoClick = function()\n\t\t\t\tself:SelectMap( map.name )\n\t\t\tend\n\t\t\tbutton.DoDoubleClick = function()\n\t\t\t\tself:SelectMap( map.name )\n\t\t\t\tself:LoadMap()\n\t\t\tend\n\t\t\tbutton.PaintOver = function( pnl, w, h )\n\n\t\t\t\tif ( pnl:GetText() == self.CurrentMap ) then\n\t\t\t\t\tboxHover( 0, 0, w, h, color_white )\n\t\t\t\tend\n\n\t\t\t\tif ( pnl.Hovered ) then return end\n\n\t\t\t\tsurface.SetDrawColor( Color( 0, 0, 0, 150 ) )\n\t\t\t\tsurface.DrawRect( 0, h - 20, w, 20 )\n\n\t\t\t\tsurface.SetFont( \"rb655_MapList\" )\n\n\t\t\t\tlocal tw = surface.GetTextSize( pnl:GetText() )\n\t\t\t\tif ( tw > w ) then\n\t\t\t\t\tdraw.SimpleText( pnl:GetText(), \"rb655_MapList\", w / 2 - tw / 2 + ( ( w - tw ) * math.sin( CurTime() ) ), h - 16, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )\n\t\t\t\telse\n\t\t\t\t\tdraw.SimpleText( pnl:GetText(), \"rb655_MapList\", w / 2 - tw / 2, h - 16, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )\n\t\t\t\tend\n\n\t\t\tend\n\n\t\t\tbutton.DoRightClick = function()\n\t\t\t\tlocal m = DermaMenu()\n\t\t\t\tm:AddOption( \"Toggle Favourite\", function() ToggleFavourite( map.name ) end ):SetIcon( IsMapFavourite( map.name ) and \"icon16/heart_delete.png\" or \"icon16/heart_add.png\" )\n\t\t\t\tm:AddOption( \"Copy to Clipboard\", function() SetClipboardText( map.name ) end ):SetIcon( \"icon16/page_copy.png\" )\n\t\t\t\tm:AddOption( \"Cancel\", function() end )\n\t\t\t\tm:Open()\n\t\t\tend\n\n\t\tend\n\tend\n\n\t-- Scroll back to the top of the map list\n\tself.CategoryMaps:GetParent():GetParent():GetVBar():SetScroll( g_CurrentScroll or 0 )\n\nend\n\nfunction PANEL:LoadMap()\n\n\tlocal maxplayers = GetConVarNumber( \"cl_maxplayers\" ) or 1\n\n\tSaveLastMap( self.CurrentMap:Trim(), self.CurrentCategory )\n\n\thook.Run( \"StartGame\" )\n\tRunConsoleCommand( \"progress_enable\" )\n\n\tRunConsoleCommand( \"disconnect\" )\n\n\tif ( maxplayers > 0 ) then\n\n\t\tRunConsoleCommand( \"sv_cheats\", \"0\" )\n\t\t--RunConsoleCommand( \"commentary\", \"0\" )\n\n\tend\n\n\tRunConsoleCommand( \"maxplayers\", maxplayers )\n\tRunConsoleCommand( \"map\", self.CurrentMap:Trim() )\n\t--RunConsoleCommand( \"hostname\", self.Settings.ServerName.TextEntry:GetText() )\n\n\tpnlMainMenu:Back()\n\nend\n\nvgui.Register( \"NewGamePanel\", PANEL, \"EditablePanel\" )\n"
  },
  {
    "path": "lua/menu/custom/new_game_panels.lua",
    "content": "\nfunction Menu_InstallDButtonScrollProtection( pnl, depth, allowM2 )\n\tdepth = depth or 1\n\tallowM2 = allowM2 or false\n\n\tfunction pnl:OnMousePressed( mc )\n\t\tDLabel.OnMousePressed( self, mc ) -- Should use baseclass here tbh\n\n\t\t-- Only left mouse button can cause the animations and shit\n\t\tif ( mc != MOUSE_LEFT and !allowM2 ) then\n\t\t\tself.Depressed = nil\n\t\tend\n\n\t\t-- This is a shitty hack, but I dont see another way\n\t\tlocal parent = self\n\t\tfor i = 1, depth do parent = parent:GetParent() end\n\t\tself.ClickStartX, self.ClickStartY = parent:GetPos()\n\tend\n\n\tfunction pnl:Think()\n\t\tlocal parent = self\n\t\tfor i = 1, depth do parent = parent:GetParent() end\n\t\tlocal x, y = parent:GetPos()\n\t\tif ( self.ClickStartY and ( self.Hovered or self.Depressed ) and math.abs( self.ClickStartY - y ) > self:GetTall() / 2 ) then\n\t\t\tself.Depressed = nil -- Disable animations, stop DoClick from working\n\t\t\tself.ClickStartX, self.ClickStartY = nil, nil\n\t\tend\n\tend\n\n\tfunction pnl:OnMouseReleased( mc )\n\t\tself.ClickStartX, self.ClickStartY = nil, nil\n\n\t\tDLabel.OnMouseReleased( self, mc ) -- Should use baseclass here tbh\n\tend\nend\n\n-- TODO: Localisation\nlocal function DrawToolTip( self, w, h )\n\tif ( !self:GetTooltip() ) then return end\n\tif ( !( self.Hovered or self.IsHovered and self:IsHovered() ) ) then return end\n\n\tlocal font = self.GetFont and self:GetFont() or \"DermaRobotoDefault\"\n\tsurface.SetFont( font )\n\n\tlocal texts = { tostring( self:GetTooltip() ) }\n\n\tlocal tW, tH = surface.GetTextSize( texts[ #texts ] )\n\tlocal x = -tW - 25\n\tlocal screenX = self:LocalToScreen( x, 0 )\n\tlocal minX = ScrW() / 4\n\twhile ( screenX < minX ) do -- Probably could do with caching\n\t\tlocal LastText = texts[ #texts ]\n\n\t\tlocal LastSpace = 0\n\t\tfor i = 1, #LastText do\n\t\t\tif ( LastText:sub( i, i ) == \" \" ) then LastSpace = i end\n\n\t\t\tlocal txtW, txtH = surface.GetTextSize( LastText:sub( 0, i ) )\n\t\t\tlocal tempX = self:LocalToScreen( -txtW - 25, 0 )\n\t\t\tif ( tempX < minX ) then -- This is probably wrong. But it works in my tests\n\t\t\t\tif ( LastSpace == 0 ) then LastSpace = i end\n\n\t\t\t\ttexts[ #texts ] = LastText:sub( 0, LastSpace )\n\t\t\t\ttable.insert( texts, LastText:sub( LastSpace + 1 ) )\n\n\t\t\t\tlocal txtW2, txtH2 = surface.GetTextSize( texts[ #texts ] )\n\t\t\t\tscreenX = self:LocalToScreen( -txtW2 - 25, 0 )\n\t\t\t\tbreak\n\t\t\tend\n\t\tend\n\tend\n\n\tDisableClipping( true )\n\tdraw.NoTexture()\n\tsurface.SetDrawColor( Color( 0, 128, 255 ) )\n\tsurface.DrawPoly( {\n\t\t{ x = -15, y = 0 },\n\t\t{ x = -5, y = h / 2 },\n\t\t{ x = -15, y = h }\n\t} )\n\n\tlocal targetW = 0\n\tfor id, txt in pairs( texts ) do\n\t\tlocal txtW, txtH = surface.GetTextSize( txt )\n\t\ttargetW = math.max( targetW, txtW )\n\tend\n\tlocal targetX = -targetW - 25\n\n\tlocal boxH = math.max( h, ( h - tH ) + tH * #texts )\n\tsurface.DrawRect( targetX, 0, -15 - targetX, boxH )\n\tfor id, txt in pairs( texts ) do\n\t\tdraw.SimpleText( txt, font, targetX + 5, h / 2 + ( id - 1 ) * tH, color_white, 0, 1 )\n\tend\n\tDisableClipping( false )\nend\n\n---------------------------------------------------------------------------------------------------------------------------------------------\n------------------------------------------------------------- MenuCategoryButton ------------------------------------------------------------\n---------------------------------------------------------------------------------------------------------------------------------------------\n\nlocal PANEL = {}\n\nfunction PANEL:GetMapCount()\n\tif ( !self.Category ) then return -1 end\n\n\tif ( !self.LastCache or self.LastCache < CurTime() or self.NewGameMenu.SearchText != self.SearchText ) then\n\t\tself.CachedMapCount = #GetMapsFromCategorySearch( self.Category, self.NewGameMenu.SearchText )\n\t\tself.LastCache = CurTime() + 1\n\t\tself.SearchText = self.NewGameMenu.SearchText\n\tend\n\n\treturn self.CachedMapCount\nend\n\n--[[function PANEL:SetAlt( b )\n\tself.Alt = b\nend]]\n\nMenu_InstallDButtonScrollProtection( PANEL )\n\nfunction PANEL:SetCategory( cat )\n\tself.Category = cat\n\tself:SetFont( \"DermaRobotoDefault\" )\n\tself:SetTextInset( 5, 1 )\nend\n\nfunction PANEL:Paint( w, h )\n\tlocal count = self:GetMapCount()\n\n\tlocal clr = Color( 255, 255, 255 )\n\tlocal clr2 = Color( 245, 245, 245 )\n\tlocal clr_t = Color( 85, 85, 85 )\n\t--[[if ( self.Alt ) then\n\t\tclr = Color( 253, 253, 253 )\n\tend]]\n\tif ( self.Hovered ) then\n\t\tclr2 = Color( 230, 230, 230 )\n\t\tclr = Color( 240, 240, 240 )\n\tend\n\tif ( self.Depressed ) then\n\t\tclr_t = color_white\n\t\tclr = Color( 35, 150, 255 )\n\t\tclr2 = Color( 26, 112, 191 )\n\tend\n\tself:SetFGColor( clr_t )\n\n\tif ( count and count > 0 ) then\n\t\tsurface.SetFont( self:GetFont() )\n\t\tlocal tW, tH = surface.GetTextSize( tostring( count ) )\n\t\tlocal bW = math.max( tW, 30 ) + 6\n\t\tlocal tX = w - bW + bW / 2\n\n\t\tsurface.SetDrawColor( clr )\n\t\tsurface.DrawRect( 0, 0, w - bW, h )\n\n\t\tsurface.SetDrawColor( clr2 )\n\t\tsurface.DrawRect( w - bW, 0, bW, h )\n\n\t\tdraw.SimpleText( count, self:GetFont(), tX, h / 2, clr_t, 1, 1 )\n\telse\n\t\tsurface.SetDrawColor( clr )\n\t\tsurface.DrawRect( 0, 0, w, h )\n\tend\nend\n\nvgui.Register( \"MenuCategoryButton\", PANEL, \"DButton\" )\n\n---------------------------------------------------------------------------------------------------------------------------------------------\n------------------------------------------------------------- MenuSettingsCheckbox ----------------------------------------------------------\n---------------------------------------------------------------------------------------------------------------------------------------------\n\nlocal PANEL = {}\n\nAccessorFunc( PANEL, \"m_bChecked\", \"Checked\", FORCE_BOOL )\nAccessorFunc( PANEL, \"m_sConVar\", \"ConVar\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sText\", \"Text\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sFont\", \"Font\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sToolTip\", \"Tooltip\", FORCE_STRING )\n\nfunction PANEL:Init()\n\tself:SetMouseInputEnabled( true )\n\tself:SetChecked( false )\n\n\tself.ThinkBlock = 0 -- HACK\nend\n\nlocal width = 40\nfunction PANEL:OnMousePressed( mcode )\n\tif ( mcode != MOUSE_LEFT ) then return end\n\n\tlocal x, y = self:LocalCursorPos()\n\tif ( self:GetWide() - width > x ) then return end\n\n\tself.Depressed = true\nend\n\nfunction PANEL:OnMouseReleased( mcode )\n\tif ( mcode != MOUSE_LEFT ) then return end\n\n\tlocal x, y = self:LocalCursorPos()\n\tif ( self:GetWide() - width > x ) then return end\n\n\tself.Depressed = false\n\n\tself:SetChecked( !self:GetChecked() )\nend\n\nfunction PANEL:Think()\n\tif ( self:GetConVar() and self.ThinkBlock < CurTime() ) then\n\t\tif ( GetConVarNumber( self:GetConVar() ) > 0 ) then self:SetChecked( true ) else self:SetChecked( false ) end\n\tend\nend\n\nfunction PANEL:SetChecked( b )\n\tif ( self.m_bChecked == b ) then return end\n\n\tself.m_bChecked = b\n\tif ( self:GetConVar() ) then\n\t\tRunConsoleCommand( self:GetConVar(), self:GetChecked() and \"1\" or \"0\" )\n\t\tself.ThinkBlock = CurTime() + 1 -- HACK: we gotta let the command buffer to go through..\n\tend\n\n\tif ( self.OnValueChanged ) then self:OnValueChanged( b ) end\nend\n\nlocal checkboxMat = Material( \"gui/check.png\" )\nfunction PANEL:Paint( w, h )\n\tlocal x, y = self:LocalCursorPos()\n\n\tsurface.SetDrawColor( Color( 255, 255, 255, 255 ) )\n\tif ( self.Hovered and self:GetWide() - width > x ) then surface.SetDrawColor( Color( 253, 253, 253, 255 ) ) end\n\tsurface.DrawRect( 0, 0, w - width - 1, h )\n\n\tsurface.SetDrawColor( Color( 245, 245, 245, 255 ) )\n\tif ( self:GetChecked() ) then surface.SetDrawColor( Color( 240, 255, 240, 200 ) ) end\n\n\tif ( self.Hovered and self:GetWide() - width < x ) then surface.SetDrawColor( Color( 230, 230, 230, 255 ) ) end\n\tif ( self.Depressed and self:GetWide() - width < x ) then surface.SetDrawColor( Color( 210, 210, 210, 255 ) ) end\n\n\tsurface.DrawRect( w - width, 0, width, h )\n\n\tsurface.SetDrawColor( Color( 0, 0, 0, 10 ) )\n\tif ( self:GetChecked() ) then surface.SetDrawColor( Color( 0, 200, 0, 255 ) ) end\n\tsurface.SetMaterial( checkboxMat )\n\tsurface.DrawTexturedRect( w - width / 2- h / 2, 0, h, h )\n\n\tif ( self:GetText() ) then\n\t\tdraw.SimpleText( language.GetPhrase( self:GetText() ), self:GetFont(), 5, h / 2, color_black, 0, 1 )\n\tend\n\n\tDrawToolTip( self, w, h )\nend\n\nvgui.Register( \"MenuSettingsCheckbox\", PANEL, \"Panel\" )\n\n---------------------------------------------------------------------------------------------------------------------------------------------\n-------------------------------------------------------------- MenuSettingsSlider -----------------------------------------------------------\n---------------------------------------------------------------------------------------------------------------------------------------------\n\nlocal PANEL = {}\n\nAccessorFunc( PANEL, \"m_sConVar\", \"ConVar\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sText\", \"Text\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sFont\", \"Font\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sToolTip\", \"Tooltip\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_nMin\", \"Min\", FORCE_NUMBER )\nAccessorFunc( PANEL, \"m_nMax\", \"Max\", FORCE_NUMBER )\n\nfunction PANEL:Init()\n\tself:SetMouseInputEnabled( true )\n\tself:SetKeyboardInputEnabled( true )\n\n\tself.TextEntry = vgui.Create( \"DTextEntry\", self )\n\tself.TextEntry:Dock( RIGHT )\n\tself.TextEntry:SetUpdateOnType( true )\n\tself.TextEntry:SetNumeric( true )\n\tself.TextEntry:SetWide( 40 )\n\tself.TextEntry.OnValueChange = function( s )\n\t\tif ( self:GetConVar() ) then RunConsoleCommand( self:GetConVar(), s:GetText() ) end\n\tend\n\tfunction self.TextEntry:Paint( w, h )\n\n\t\tsurface.SetDrawColor( Color( 245, 245, 245, 255 ) )\n\t\tif ( self.Hovered ) then surface.SetDrawColor( Color( 230, 230, 230, 255 ) ) end\n\t\tsurface.DrawRect( 0, 0, w, h )\n\n\t\tself:DrawTextEntryText( self:GetTextColor(), self:GetHighlightColor(), self:GetCursorColor() )\n\tend\nend\n\nfunction PANEL:IsHovered()\n\treturn self.Hovered or self.TextEntry:IsHovered()\nend\n\nfunction PANEL:SetFont( font )\n\tself.m_sFont = font\n\tself.TextEntry:SetFont( font )\nend\nfunction PANEL:SetMinMax( min, max ) self:SetMin( min ) self:SetMax( max ) end\nfunction PANEL:Think()\n\tif ( !self.TextEntry:IsEditing() and self:GetConVar() and GetConVarNumber( self:GetConVar() ) and GetConVarNumber( self:GetConVar() ) != tonumber( self.TextEntry:GetText() ) ) then\n\t\tself.TextEntry:SetText( GetConVarNumber( self:GetConVar() ) )\n\tend\nend\n\nfunction PANEL:Paint( w, h )\n\tlocal x, y = self:LocalCursorPos()\n\tsurface.SetDrawColor( Color( 255, 255, 255, 255 ) )\n\tif ( self.Hovered and self:GetWide() - width > x ) then surface.SetDrawColor( Color( 253, 253, 253, 255 ) ) end\n\tsurface.DrawRect( 0, 0, w - self.TextEntry:GetWide() - 1, h )\n\n\tif ( self:GetText() ) then\n\t\tdraw.SimpleText( language.GetPhrase( self:GetText() ), self:GetFont(), 5, h / 2, color_black, 0, 1 )\n\tend\n\n\tDrawToolTip( self, w, h )\nend\n\nvgui.Register( \"MenuSettingsSlider\", PANEL, \"Panel\" )\n\n---------------------------------------------------------------------------------------------------------------------------------------------\n------------------------------------------------------------ MenuSettingsTextEntry ----------------------------------------------------------\n---------------------------------------------------------------------------------------------------------------------------------------------\n\nlocal PANEL = {}\n\nAccessorFunc( PANEL, \"m_sConVar\", \"ConVar\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sText\", \"Text\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sFont\", \"Font\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sToolTip\", \"Tooltip\", FORCE_STRING )\n\nfunction PANEL:Init()\n\tself:SetMouseInputEnabled( true )\n\n\tself.TextEntry = vgui.Create( \"DTextEntry\", self )\n\tself.TextEntry:Dock( RIGHT )\n\tself.TextEntry:SetUpdateOnType( true )\n\tself.TextEntry.OnValueChange = function( s )\n\t\tif ( self:GetConVar() ) then RunConsoleCommand( self:GetConVar(), s:GetText() ) end\n\tend\n\tfunction self.TextEntry:Paint( w, h )\n\t\tsurface.SetDrawColor( Color( 245, 245, 245, 255 ) )\n\t\tif ( self.Hovered ) then surface.SetDrawColor( Color( 230, 230, 230, 255 ) ) end\n\t\tsurface.DrawRect( 0, 0, w, h )\n\n\t\tself:DrawTextEntryText( self:GetTextColor(), self:GetHighlightColor(), self:GetCursorColor() )\n\tend\nend\n\nfunction PANEL:IsHovered()\n\treturn self.Hovered or self.TextEntry:IsHovered()\nend\n\nfunction PANEL:SetFont( font )\n\tself.m_sFont = font\n\tself.TextEntry:SetFont( font )\nend\n\nfunction PANEL:Think()\n\tif ( !self.TextEntry:IsEditing() and self:GetConVar() and GetConVarString( self:GetConVar() ) and GetConVarString( self:GetConVar() ) != self.TextEntry:GetText() ) then\n\t\tself.TextEntry:SetText( GetConVarString( self:GetConVar() ) )\n\tend\nend\n\nfunction PANEL:Paint( w, h )\n\tlocal x, y = self:LocalCursorPos()\n\tsurface.SetDrawColor( Color( 255, 255, 255, 255 ) )\n\tif ( self.Hovered and self:GetWide() - width > x ) then surface.SetDrawColor( Color( 253, 253, 253, 255 ) ) end\n\tsurface.DrawRect( 0, 0, w - self.TextEntry:GetWide() - 1, h )\n\n\tif ( self:GetText() ) then\n\t\tlocal tW = draw.SimpleText( language.GetPhrase( self:GetText() ), self:GetFont(), 5, h / 2, color_black, 0, 1 )\n\t\tself.TextEntry:SetWide( self:GetWide() - tW - 12 )\n\tend\n\n\tDrawToolTip( self, w, h )\nend\n\nvgui.Register( \"MenuSettingsTextEntry\", PANEL, \"Panel\" )\n\n---------------------------------------------------------------------------------------------------------------------------------------------\n-------------------------------------------------------------- DFancyTextEntry --------------------------------------------------------------\n---------------------------------------------------------------------------------------------------------------------------------------------\n\nlocal PANEL = {}\n\nAccessorFunc( PANEL, \"m_sPlaceholder\", \"PlaceholderText\", FORCE_STRING )\nAccessorFunc( PANEL, \"m_sToolTip\", \"Tooltip\", FORCE_STRING )\n\nfunction PANEL:Init()\n\tself:SetHighlightColor( Color( 35, 150, 255 ) )\nend\n\nfunction PANEL:Paint( w, h )\n\tsurface.SetDrawColor( Color( 245, 245, 245, 255 ) )\n\tif ( self.Hovered ) then surface.SetDrawColor( Color( 230, 230, 230, 255 ) ) end\n\tsurface.DrawRect( 0, 0, w, h )\n\n\tself:DrawTextEntryText( self:GetTextColor(), self:GetHighlightColor(), self:GetCursorColor() )\n\n\tif ( !self:GetText() or self:GetText():Trim():len() < 1 ) then\n\t\tdraw.SimpleText( language.GetPhrase( self:GetPlaceholderText() ), self:GetFont(), 5, h / 2, Vector( 1, 1, 1 ) * 150, nil, 1 )\n\tend\n\n\tDrawToolTip( self, w, h )\nend\n\nvgui.Register( \"DFancyTextEntry\", PANEL, \"DTextEntry\" )\n"
  },
  {
    "path": "lua/menu/custom/saves.lua",
    "content": "\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\tself:Dock( FILL )\nend\n\nfunction PANEL:SetType( typ )\n\tself.Type = typ\n\n\tself:UpdateList()\nend\n\nfunction PANEL:UpdateList()\n\tself:Clear()\n\n\tlocal Scroll = vgui.Create( \"DScrollPanel\", self )\n\tScroll:Dock( FILL )\n\tScroll:DockMargin( 5, 5, 5, 5 )\n\n\tlocal List = vgui.Create( \"DIconLayout\", Scroll )\n\tList:Dock( FILL )\n\tList:SetSpaceY( 5 )\n\tList:SetSpaceX( 5 )\n\n\tlocal f = nil\n\tif ( self.Type == \"saves\" ) then\n\t\tf = file.Find( \"saves/*.gms\", \"MOD\", \"datedesc\" )\n\telseif ( self.Type == \"demos\" ) then\n\t\tf = file.Find( \"demos/*.dem\", \"MOD\", \"datedesc\" )\n\telseif ( self.Type == \"dupes\" ) then\n\t\tf = file.Find( \"dupes/*.dupe\", \"MOD\", \"datedesc\" )\n\tend\n\n\tfor k, v in pairs( f ) do\n\t\tlocal ListItem = List:Add( \"DImageButton\" )\n\t\tListItem:SetSize( 128, 128 )\n\t\tListItem:SetImage( self.Type .. \"/\" .. v:StripExtension() .. \".jpg\" )\n\t\tListItem.DoDoubleClick = function()\n\t\t\tif ( self.Type == \"saves\" ) then\n\t\t\t\tRunConsoleCommand( \"gm_load\", \"saves/\" .. v )\n\t\t\telseif ( self.Type == \"demos\" ) then\n\t\t\t\tRunConsoleCommand( \"playdemo\", \"demos/\" .. v )\n\t\t\tend\n\t\tend\n\t\tListItem.DoRightClick = function()\n\t\t\tlocal m = DermaMenu()\n\n\t\t\tif ( self.Type == \"saves\" ) then\n\t\t\t\tm:AddOption( \"Load\", function() RunConsoleCommand( \"gm_load\", \"saves/\" .. v ) end )\n\t\t\telseif ( self.Type == \"demos\" ) then\n\t\t\t\tm:AddOption( \"Play\", function() RunConsoleCommand( \"playdemo\", \"demos/\" .. v ) end )\n\t\t\tend\n\n\t\t\tif ( self.Type == \"demos\" ) then\n\t\t\t\tm:AddOption( \"Demo To Video\", function() RunConsoleCommand( \"gm_demo_to_video\", \"demos/\" .. v ) end )\n\t\t\tend\n\t\t\tm:AddOption( \"Delete\", function()\n\t\t\t\tfile.Delete( self.Type .. \"/\" .. v, \"MOD\" )\n\t\t\t\tfile.Delete( self.Type .. \"/\" .. v:StripExtension() .. \".jpg\", \"MOD\" )\n\t\t\t\tself:UpdateList()\n\t\t\tend )\n\t\t\tm:AddOption( \"Cancel\" )\n\t\t\tm:Open()\n\t\tend\n\tend\nend\n\nfunction PANEL:Paint( w, h )\n\tsurface.SetDrawColor( 0, 0, 0, 150 )\n\tsurface.DrawRect( 0, 0, w, h )\nend\n\nvgui.Register( \"SavesPanel\", PANEL, \"EditablePanel\" )\n"
  },
  {
    "path": "lua/menu/menu.lua",
    "content": "\ninclude( \"mount/mount.lua\" )\ninclude( \"getmaps.lua\" )\ninclude( \"loading.lua\" )\n\n-- To uninstall, change the 1 to 0 below\nlocal useNewMenu = 1\n\n-- Do not touch anything below\nif ( useNewMenu == 1 ) then\n\tinclude( \"custom/mainmenu.lua\" )\nelse\n\tinclude( \"mainmenu.lua\" )\nend\n\ninclude( \"video.lua\" )\ninclude( \"demo_to_video.lua\" )\n\ninclude( \"menu_save.lua\" )\ninclude( \"menu_demo.lua\" )\ninclude( \"menu_addon.lua\" )\ninclude( \"menu_dupe.lua\" )\ninclude( \"errors.lua\" )\ninclude( \"problems/problems.lua\" )\n\ninclude( \"motionsensor.lua\" )\ninclude( \"util.lua\" )\n"
  }
]