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