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/<gamemode>/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" )
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
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (116K chars).
[
{
"path": "CONTRIBUTING.md",
"chars": 1202,
"preview": "Contributing to Lua Main Menu\n=============\n\nHere's what you need to know if you wish to submit Pull Requests to this re"
},
{
"path": "README.md",
"chars": 1349,
"preview": "Garry's Mod Lua Main Menu\n=============\n\nA Lua powered ( No HTML ) main menu for Garry's Mod.\nIt is meant for those who "
},
{
"path": "lua/menu/custom/_errors.lua",
"chars": 1561,
"preview": "\nlocal Errors = {}\n\nlocal matAlert = Material( \"icon16/error.png\" )\n\nhook.Add( \"DrawOverlay\", \"MenuErrors\", function()\n\n"
},
{
"path": "lua/menu/custom/achievements.lua",
"chars": 3722,
"preview": "\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\tself.AchID = 0\n\n\tself:SetTall( 72 )\n\n\tself.Icon = vgui.Create( \"AchievementIco"
},
{
"path": "lua/menu/custom/addons.lua",
"chars": 14097,
"preview": "\nsurface.CreateFont( \"rb655_AddonName\", {\n\tsize = ScreenScale( 12 ),\n\tfont = \"Tahoma\"\n} )\n\nsurface.CreateFont( \"rb655_Ad"
},
{
"path": "lua/menu/custom/getmaps.lua",
"chars": 20968,
"preview": "\nlocal RefreshMaps\n\n--\n-- Favourites\n--\n\nlocal MapFavourites\n\nlocal function LoadFavourites()\n\n\tlocal cookiestr = cookie"
},
{
"path": "lua/menu/custom/main.lua",
"chars": 4776,
"preview": "\n-- Developer stuff\nconcommand.Add( \"lua\", function( ply, cmd, args, str )\n\tif ( IsInGame() ) then return end\n\tRunString"
},
{
"path": "lua/menu/custom/mainmenu.lua",
"chars": 15844,
"preview": "\nScreenScale = function( size ) return size * ( ScrW() / 640.0 ) end\n\ninclude( \"getmaps.lua\" )\ninclude( \"addons.lua\" )\ni"
},
{
"path": "lua/menu/custom/new_game.lua",
"chars": 25936,
"preview": "\ninclude( \"new_game_panels.lua\" )\n\nCreateConVar( \"cl_maxplayers\", \"1\", FCVAR_ARCHIVE )\n\n--[[\nTODO:\nmake sure the text of"
},
{
"path": "lua/menu/custom/new_game_panels.lua",
"chars": 14212,
"preview": "\nfunction Menu_InstallDButtonScrollProtection( pnl, depth, allowM2 )\n\tdepth = depth or 1\n\tallowM2 = allowM2 or false\n\n\tf"
},
{
"path": "lua/menu/custom/saves.lua",
"chars": 1969,
"preview": "\nlocal PANEL = {}\n\nfunction PANEL:Init()\n\tself:Dock( FILL )\nend\n\nfunction PANEL:SetType( typ )\n\tself.Type = typ\n\n\tself:U"
},
{
"path": "lua/menu/menu.lua",
"chars": 550,
"preview": "\ninclude( \"mount/mount.lua\" )\ninclude( \"getmaps.lua\" )\ninclude( \"loading.lua\" )\n\n-- To uninstall, change the 1 to 0 belo"
}
]
About this extraction
This page contains the full source code of the robotboy655/gmod-lua-menu GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (103.7 KB), approximately 33.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.