--[[ | This file was obtained through the combined efforts | of Madbluntz & Plymouth Antiquarian Society. | | Credits: lifestorm, Gregory Wayne Rossel JR., | Maloy, DrPepper10 @ RIP, Atle! | | Visit for more: https://plymouth.thetwilightzone.ru/ --]] local MapPatterns = {} local MapNames = {} local AddonMaps = {} local function UpdateMaps() MapPatterns = {} MapNames = {} MapNames[ "aoc_" ] = "Age of Chivalry" MapNames[ "infra_" ] = "INFRA" MapPatterns[ "^asi-" ] = "Alien Swarm" MapNames[ "lobby" ] = "Alien Swarm" MapNames[ "cp_docks" ] = "Blade Symphony" MapNames[ "cp_parkour" ] = "Blade Symphony" MapNames[ "cp_sequence" ] = "Blade Symphony" MapNames[ "cp_terrace" ] = "Blade Symphony" MapNames[ "cp_test" ] = "Blade Symphony" MapNames[ "duel_" ] = "Blade Symphony" MapNames[ "ffa_community" ] = "Blade Symphony" MapNames[ "free_" ] = "Blade Symphony" MapNames[ "practice_box" ] = "Blade Symphony" MapNames[ "tut_training" ] = "Blade Symphony" MapNames[ "lightstyle_test" ] = "Blade Symphony" MapNames[ "ar_" ] = "Counter-Strike" MapNames[ "cs_" ] = "Counter-Strike" MapNames[ "de_" ] = "Counter-Strike" MapNames[ "es_" ] = "Counter-Strike" MapNames[ "fy_" ] = "Counter-Strike" MapNames[ "gd_" ] = "Counter-Strike" MapNames[ "dz_" ] = "Counter-Strike" MapNames[ "training1" ] = "Counter-Strike" MapNames[ "lobby_mapveto" ] = "Counter-Strike" -- Various custom cs maps MapNames[ "35hp_" ] = "Counter-Strike (Custom)" MapNames[ "aim_" ] = "Counter-Strike (Custom)" MapNames[ "awp_" ] = "Counter-Strike (Custom)" MapNames[ "am_" ] = "Counter-Strike (Custom)" MapNames[ "fy_" ] = "Counter-Strike (Custom)" MapNames[ "1v1_" ] = "Counter-Strike (Custom)" MapNames[ "dod_" ] = "Day Of Defeat" MapNames[ "ddd_" ] = "Dino D-Day" MapNames[ "de_dam" ] = "DIPRIP" MapNames[ "dm_city" ] = "DIPRIP" MapNames[ "dm_refinery" ] = "DIPRIP" MapNames[ "dm_supermarket" ] = "DIPRIP" MapNames[ "dm_village" ] = "DIPRIP" MapNames[ "ur_city" ] = "DIPRIP" MapNames[ "ur_refinery" ] = "DIPRIP" MapNames[ "ur_supermarket" ] = "DIPRIP" MapNames[ "ur_village" ] = "DIPRIP" MapNames[ "dys_" ] = "Dystopia" MapNames[ "pb_dojo" ] = "Dystopia" MapNames[ "pb_rooftop" ] = "Dystopia" MapNames[ "pb_round" ] = "Dystopia" MapNames[ "pb_urbandome" ] = "Dystopia" MapNames[ "sav_dojo6" ] = "Dystopia" MapNames[ "varena" ] = "Dystopia" -- Do these manually, so edits of these maps don't end up in the same category. local HL2Maps = { "d1_trainstation_01", "d1_trainstation_02", "d1_trainstation_03", "d1_trainstation_04", "d1_trainstation_05", "d1_trainstation_06", "d1_canals_01", "d1_canals_01a", "d1_canals_02", "d1_canals_03", "d1_canals_05", "d1_canals_06", "d1_canals_07", "d1_canals_08", "d1_canals_09", "d1_canals_10", "d1_canals_11","d1_canals_12", "d1_canals_13", "d1_eli_01", "d1_eli_02", "d1_town_01", "d1_town_01a", "d1_town_02", "d1_town_02a", "d1_town_03", "d1_town_04","d1_town_05", "d2_coast_01", "d2_coast_03", "d2_coast_04", "d2_coast_05","d2_coast_07", "d2_coast_08", "d2_coast_09", "d2_coast_10", "d2_coast_11", "d2_coast_12", "d2_prison_01", "d2_prison_02", "d2_prison_03", "d2_prison_04", "d2_prison_05", "d2_prison_06", "d2_prison_07", "d2_prison_08", "d3_c17_01", "d3_c17_02", "d3_c17_03", "d3_c17_04", "d3_c17_05", "d3_c17_06a", "d3_c17_06b", "d3_c17_07", "d3_c17_08", "d3_c17_09", "d3_c17_10a", "d3_c17_10b", "d3_c17_11", "d3_c17_12", "d3_c17_12b", "d3_c17_13", "d3_citadel_01", "d3_citadel_02", "d3_citadel_03", "d3_citadel_04", "d3_citadel_05", "d3_breen_01" } for _, map in ipairs( HL2Maps ) do MapNames[ map ] = "Half-Life 2" end local EP1Maps = { "ep1_citadel_00", "ep1_citadel_01", "ep1_citadel_02", "ep1_citadel_02b", "ep1_citadel_03", "ep1_citadel_04", "ep1_c17_00", "ep1_c17_00a", "ep1_c17_01", "ep1_c17_01a", "ep1_c17_02", "ep1_c17_02b", "ep1_c17_02a", "ep1_c17_05", "ep1_c17_06" } for _, map in ipairs( EP1Maps ) do MapNames[ map ] = "Half-Life 2: Episode 1" end local EP2Maps = { "ep2_outland_01", "ep2_outland_01a", "ep2_outland_02", "ep2_outland_03", "ep2_outland_04", "ep2_outland_05", "ep2_outland_06", "ep2_outland_06a", "ep2_outland_07", "ep2_outland_08", "ep2_outland_09", "ep2_outland_10", "ep2_outland_10a", "ep2_outland_11", "ep2_outland_11a", "ep2_outland_11b", "ep2_outland_12", "ep2_outland_12a" } for _, map in ipairs( EP2Maps ) do MapNames[ map ] = "Half-Life 2: Episode 2" end MapNames[ "dm_" ] = "Half-Life 2: Deathmatch" MapNames[ "halls3" ] = "Half-Life 2: Deathmatch" MapNames[ "d2_lostcoast" ] = "Half-Life 2: Lost Coast" MapPatterns[ "^c[%d]a" ] = "Half-Life" MapPatterns[ "^t0a" ] = "Half-Life" MapNames[ "boot_camp" ] = "Half-Life Deathmatch" MapNames[ "bounce" ] = "Half-Life Deathmatch" MapNames[ "crossfire" ] = "Half-Life Deathmatch" MapNames[ "datacore" ] = "Half-Life Deathmatch" MapNames[ "frenzy" ] = "Half-Life Deathmatch" MapNames[ "lambda_bunker" ] = "Half-Life Deathmatch" MapNames[ "rapidcore" ] = "Half-Life Deathmatch" MapNames[ "snarkpit" ] = "Half-Life Deathmatch" MapNames[ "stalkyard" ] = "Half-Life Deathmatch" MapNames[ "subtransit" ] = "Half-Life Deathmatch" MapNames[ "undertow" ] = "Half-Life Deathmatch" MapNames[ "ins_" ] = "Insurgency" MapNames[ "l4d_" ] = "Left 4 Dead" MapPatterns[ "^c[%d]m" ] = "Left 4 Dead 2" MapPatterns[ "^c1[%d]m" ] = "Left 4 Dead 2" MapNames[ "curling_stadium" ] = "Left 4 Dead 2" MapNames[ "tutorial_standards" ] = "Left 4 Dead 2" MapNames[ "tutorial_standards_vs" ] = "Left 4 Dead 2" MapNames[ "clocktower" ] = "Nuclear Dawn" MapNames[ "coast" ] = "Nuclear Dawn" MapNames[ "downtown" ] = "Nuclear Dawn" MapNames[ "gate" ] = "Nuclear Dawn" MapNames[ "hydro" ] = "Nuclear Dawn" MapNames[ "metro" ] = "Nuclear Dawn" MapNames[ "metro_training" ] = "Nuclear Dawn" MapNames[ "oasis" ] = "Nuclear Dawn" MapNames[ "oilfield" ] = "Nuclear Dawn" MapNames[ "silo" ] = "Nuclear Dawn" MapNames[ "sk_metro" ] = "Nuclear Dawn" MapNames[ "training" ] = "Nuclear Dawn" MapNames[ "bt_" ] = "Pirates, Vikings, & Knights II" MapNames[ "lts_" ] = "Pirates, Vikings, & Knights II" MapNames[ "te_" ] = "Pirates, Vikings, & Knights II" MapNames[ "tw_" ] = "Pirates, Vikings, & Knights II" MapNames[ "escape_" ] = "Portal" MapNames[ "testchmb_" ] = "Portal" MapNames[ "e1912" ] = "Portal 2" MapPatterns[ "^mp_coop_" ] = "Portal 2" MapPatterns[ "^sp_a" ] = "Portal 2" MapNames[ "achievement_" ] = "Team Fortress 2" MapNames[ "arena_" ] = "Team Fortress 2" MapNames[ "cp_" ] = "Team Fortress 2" MapNames[ "ctf_" ] = "Team Fortress 2" MapNames[ "itemtest" ] = "Team Fortress 2" MapNames[ "koth_" ] = "Team Fortress 2" MapNames[ "mvm_" ] = "Team Fortress 2" MapNames[ "pl_" ] = "Team Fortress 2" MapNames[ "plr_" ] = "Team Fortress 2" MapNames[ "rd_" ] = "Team Fortress 2" MapNames[ "pd_" ] = "Team Fortress 2" MapNames[ "sd_" ] = "Team Fortress 2" MapNames[ "tc_" ] = "Team Fortress 2" MapNames[ "tr_" ] = "Team Fortress 2" MapNames[ "trade_" ] = "Team Fortress 2" MapNames[ "pass_" ] = "Team Fortress 2" MapNames[ "vsh_" ] = "Team Fortress 2" MapNames[ "zi_" ] = "Team Fortress 2" MapNames[ "zpa_" ] = "Zombie Panic! Source" MapNames[ "zpl_" ] = "Zombie Panic! Source" MapNames[ "zpo_" ] = "Zombie Panic! Source" MapNames[ "zps_" ] = "Zombie Panic! Source" MapNames[ "zph_" ] = "Zombie Panic! Source" MapNames[ "fof_" ] = "Fistful of Frags" MapNames[ "fofhr_" ] = "Fistful of Frags" MapNames[ "cm_" ] = "Fistful of Frags" MapNames[ "gt_" ] = "Fistful of Frags" MapNames[ "tp_" ] = "Fistful of Frags" MapNames[ "vs_" ] = "Fistful of Frags" 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 Survival" MapNames[ "zombiesurvival_" ] = "Zombie Survival" MapNames[ "zs_" ] = "Zombie Survival" MapNames[ "coop_" ] = "Cooperative" local GamemodeList = engine.GetGamemodes() for k, 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 _, pattern in ipairs( Maps ) do -- When in doubt, just try to match it with string.find MapPatterns[ string.lower( pattern ) ] = Name end end end AddonMaps = {} for k, addon in ipairs( engine.GetAddons() ) do local name = addon.title or "Unnammed Addon" local files = file.Find( "maps/*.bsp", name ) if ( #files > 0 ) then AddonMaps[ name ] = files end end end local favmaps local function LoadFavourites() local cookiestr = cookie.GetString( "favmaps" ) favmaps = favmaps or ( cookiestr and string.Explode( ";", cookiestr ) or {} ) end function UpdateAddonMapList() local json = util.TableToJSON( AddonMaps ) if ( !json ) then return end pnlMainMenu:Call( "UpdateAddonMaps(" .. json .. ")" ) end -- Called from JS when starting a new game function UpdateMapList() UpdateAddonMapList() local mapList = GetMapList() if ( !mapList ) then return end local json = util.TableToJSON( mapList ) if ( !json ) then return end pnlMainMenu:Call( "UpdateMaps(" .. json .. ")" ) end local IgnorePatterns = { "^background", "^devtest", "^ep1_background", "^ep2_background", "^styleguide", } local IgnoreMaps = { -- Prefixes [ "sdk_" ] = true, [ "test_" ] = true, [ "vst_" ] = true, -- Maps [ "c4a1y" ] = true, [ "credits" ] = true, [ "d2_coast_02" ] = true, [ "d3_c17_02_camera" ] = true, [ "ep1_citadel_00_demo" ] = true, [ "c5m1_waterfront_sndscape" ] = true, [ "intro" ] = true, [ "test" ] = true } local MapList = {} local function RefreshMaps( skip ) if ( !skip ) then UpdateMaps() end MapList = {} local maps = file.Find( "maps/*.bsp", "GAME" ) LoadFavourites() for k, v in ipairs( maps ) do local name = string.lower( string.gsub( v, "%.bsp$", "" ) ) local prefix = string.match( name, "^(.-_)" ) local Ignore = IgnoreMaps[ name ] or IgnoreMaps[ prefix ] -- Don't loop if it's already ignored if ( Ignore ) then continue end for _, ignore in ipairs( IgnorePatterns ) do if ( string.find( name, ignore ) ) then Ignore = true break end end -- Don't add useless maps if ( Ignore ) then continue end -- Check if the map has a simple name or prefix local Category = MapNames[ name ] or MapNames[ prefix ] -- Check if the map has an embedded prefix, or is TTT/Sandbox if ( !Category ) then for pattern, category in pairs( MapPatterns ) do if ( string.find( name, pattern ) ) then Category = category end end end -- Throw all uncategorised maps into Other Category = Category or "Other" local fav if ( table.HasValue( favmaps, name ) ) then fav = true end local csgo = false if ( Category == "Counter-Strike" and file.Exists( "maps/" .. name .. ".bsp", "csgo" ) ) then if ( file.Exists( "maps/" .. name .. ".bsp", "cstrike" ) ) then -- Map also exists in CS:GO csgo = true else Category = "Counter-Strike: GO" end end if ( !MapList[ Category ] ) then MapList[ Category ] = {} end table.insert( MapList[ Category ], name ) if ( fav ) then if ( !MapList[ "Favourites" ] ) then MapList[ "Favourites" ] = {} end table.insert( MapList[ "Favourites" ], name ) end if ( csgo ) then if ( !MapList[ "Counter-Strike: GO" ] ) then MapList[ "Counter-Strike: GO" ] = {} end -- HACK: We have to make the CS:GO name different from the CS:S name to prevent Favourites conflicts table.insert( MapList[ "Counter-Strike: GO" ], name .. " " ) end end -- Send the new list to the HTML menu UpdateMapList() end -- Update only after a short while for when these hooks are called very rapidly back to back local function DelayedRefreshMaps() timer.Create( "menu_refreshmaps", 0.1, 1, RefreshMaps ) end hook.Add( "MenuStart", "FindMaps", DelayedRefreshMaps ) hook.Add( "GameContentChanged", "RefreshMaps", DelayedRefreshMaps ) -- Nice maplist accessor instead of a global table function GetMapList() return MapList end function ToggleFavourite( map ) LoadFavourites() if ( table.HasValue( favmaps, map ) ) then -- is favourite, remove it table.remove( favmaps, table.KeysFromValue( favmaps, map )[1] ) else -- not favourite, add it table.insert( favmaps, map ) end cookie.Set( "favmaps", table.concat( favmaps, ";" ) ) RefreshMaps( true ) UpdateMapList() end 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" cat = string.gsub( cat, "'", "\\'" ) if ( !file.Exists( "maps/" .. map .. ".bsp", "GAME" ) ) then return end pnlMainMenu:Call( "SetLastMap('" .. map:JavascriptSafe() .. "','" .. cat:JavascriptSafe() .. "')" ) end