plugins/mapmanager.sp
author David Anderson <dvander@alliedmods.net>
Sat May 24 06:48:35 2008 +0000 (2008-05-24)
changeset 2072 82d3186b9fa4
parent 2027 887d7271f947
permissions -rw-r--r--
added quick tool for fetching dlls of mdmps
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Map Management Plugin
     5  * Provides all map related functionality, including map changing, map voting,
     6  * and nextmap.
     7  *
     8  * SourceMod (C)2004-2008 AlliedModders LLC.  All rights reserved.
     9  * =============================================================================
    10  *
    11  * This program is free software; you can redistribute it and/or modify it under
    12  * the terms of the GNU General Public License, version 3.0, as published by the
    13  * Free Software Foundation.
    14  * 
    15  * This program is distributed in the hope that it will be useful, but WITHOUT
    16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    18  * details.
    19  *
    20  * You should have received a copy of the GNU General Public License along with
    21  * this program.  If not, see <http://www.gnu.org/licenses/>.
    22  *
    23  * As a special exception, AlliedModders LLC gives you permission to link the
    24  * code of this program (as well as its derivative works) to "Half-Life 2," the
    25  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    26  * by the Valve Corporation.  You must obey the GNU General Public License in
    27  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    28  * this exception to all derivative works.  AlliedModders LLC defines further
    29  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    30  * or <http://www.sourcemod.net/license.php>.
    31  *
    32  * Version: $Id$
    33  */
    34 
    35 #pragma semicolon 1
    36 #include <sourcemod>
    37 #undef REQUIRE_PLUGIN
    38 #include <adminmenu>
    39 
    40 public Plugin:myinfo =
    41 {
    42 	name = "Map Manager",
    43 	author = "AlliedModders LLC",
    44 	description = "Map Management",
    45 	version = SOURCEMOD_VERSION,
    46 	url = "http://www.sourcemod.net/"
    47 };
    48 
    49 #include "mapmanager/globals.sp"
    50 #include "mapmanager/commands.sp"
    51 #include "mapmanager/events.sp"
    52 #include "mapmanager/functions.sp"
    53 #include "mapmanager/functions_menu.sp"
    54 #include "mapmanager/menus.sp"
    55 #include "mapmanager/timers.sp"
    56 #include "mapmanager/votes.sp"
    57 
    58 public OnPluginStart()
    59 {	
    60 	LoadTranslations("mapmanager.phrases");
    61 
    62 	// Prepare nextmap functionality.	
    63 	g_VGUIMenu = GetUserMessageId("VGUIMenu");
    64 	if (g_VGUIMenu == INVALID_MESSAGE_ID)
    65 	{
    66 		LogError("FATAL: Cannot find VGUIMenu user message id. MapManager crippled.");
    67 		g_NextMapEnabled = false;
    68 	}
    69 	HookUserMessage(g_VGUIMenu, UserMsg_VGUIMenu);
    70 
    71 	// Create all of the arrays, sized for a 64 character string.
    72 	new arraySize = ByteCountToCells(64);
    73 	g_MapCycle = CreateArray(arraySize);
    74 	g_MapList = CreateArray(arraySize);
    75 	g_MapHistory = CreateArray(arraySize);
    76 	g_NextVoteMaps = CreateArray(arraySize);
    77 	g_SelectedMaps = CreateArray(arraySize);
    78 	g_NominatedMaps = CreateArray(arraySize);
    79 	
    80 	g_TeamScores = CreateArray(2);
    81 
    82 	// Hook say
    83 	RegConsoleCmd("say", Command_Say);
    84 	RegConsoleCmd("say_team", Command_Say);	
    85 
    86 	// Register all commands.
    87 	RegAdminCmd("sm_map", Command_Map, ADMFLAG_CHANGEMAP, "sm_map <map> [r/e]");
    88 	RegAdminCmd("sm_setnextmap", Command_SetNextmap, ADMFLAG_CHANGEMAP, "sm_setnextmap <map>");
    89 	RegAdminCmd("sm_votemap", Command_Votemap, ADMFLAG_VOTE|ADMFLAG_CHANGEMAP, "sm_votemap <mapname> [mapname2] ... [mapname5] ");
    90 	RegAdminCmd("sm_maplist", Command_List, ADMFLAG_GENERIC, "sm_maplist");
    91 	RegAdminCmd("sm_nominate", Command_Nominate, ADMFLAG_CHANGEMAP, "sm_nominate <mapname> - Nominates a map for RockTheVote and MapChooser. Overrides existing nominations.");
    92 	RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces the MapChooser vote to occur.");
    93 	
    94 	if (GetCommandFlags("nextmap") == INVALID_FCVAR_FLAGS)
    95 	{
    96 		RegServerCmd("nextmap", Command_Nextmap);
    97 	}	
    98 	
    99 	// Register all convars
   100 	g_Cvar_NextMap = CreateConVar("sm_nextmap", "", "Sets the Next Map", FCVAR_NOTIFY);
   101 	
   102 	g_Cvar_MapCount = CreateConVar("sm_mm_maps", "4", "Number of maps to be voted on at end of map or RTV. 2 to 6. (Def 4)", 0, true, 2.0, true, 6.0);	
   103 	g_Cvar_Excludes = CreateConVar("sm_mm_exclude", "5", "Specifies how many past maps to exclude from end of map vote and RTV.", _, true, 0.0);
   104 	
   105 	g_Cvar_MapChooser = CreateConVar("sm_mm_mapchooser", "0", "Enables MapChooser (End of Map voting)", 0, true, 0.0, true, 1.0);
   106 	g_Cvar_RockTheVote = CreateConVar("sm_mm_rockthevote", "0", "Enables RockTheVote (Player initiated map votes)", 0, true, 0.0, true, 1.0);
   107 	g_Cvar_Randomize = CreateConVar("sm_mm_randomize", "0", "Enabled Randomizer (Randomly picks the next map)", 0, true, 0.0, true, 1.0);
   108 	g_Cvar_Nominate = CreateConVar("sm_mm_nominate", "1", "Enables nomination system.", 0, true, 0.0, true, 1.0);
   109 	
   110 	g_Cvar_VoteMap = CreateConVar("sm_mm_votemap", "0.60", "Percentage required for successful sm_votemap.", 0, true, 0.05, true, 1.0);
   111 	g_Cvar_RTVLimit = CreateConVar("sm_mm_rtvlimit", "0.60", "Required percentage of players needed to rockthevote", 0, true, 0.05, true, 1.0);
   112 	g_Cvar_MinPlayers = CreateConVar("sm_mm_minplayers", "0", "Number of players required before RTV will be enabled.", 0, true, 0.0, true, float(MAXPLAYERS));
   113 	
   114 	g_Cvar_StartTime = CreateConVar("sm_mapvote_start", "3.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0);
   115 	g_Cvar_StartRounds = CreateConVar("sm_mapvote_startround", "2.0", "Specifies when to start the vote based on rounds remaining.", _, true, 1.0);
   116 	g_Cvar_StartFrags = CreateConVar("sm_mapvote_startfrags", "5.0", "Specifies when to start the vote base on frags remaining.", _, true, 1.0);
   117 	g_Cvar_ExtendTimeMax = CreateConVar("sm_extendmap_maxtime", "90", "Specifies the maximum amount of time a map can be extended", _, true, 0.0);
   118 	g_Cvar_ExtendTimeStep = CreateConVar("sm_extendmap_timestep", "15", "Specifies how much many more minutes each extension makes", _, true, 5.0);
   119 	g_Cvar_ExtendRoundMax = CreateConVar("sm_extendmap_maxrounds", "30", "Specfies the maximum amount of rounds a map can be extended", _, true, 0.0);
   120 	g_Cvar_ExtendRoundStep = CreateConVar("sm_extendmap_roundstep", "5", "Specifies how many more rounds each extension makes", _, true, 5.0);
   121 	g_Cvar_ExtendFragMax = CreateConVar("sm_extendmap_maxfrags", "150", "Specfies the maximum frags allowed that a map can be extended.", _, true, 0.0);
   122 	g_Cvar_ExtendFragStep = CreateConVar("sm_extendmap_fragstep", "10", "Specifies how many more frags are allowed when map is extended.", _, true, 5.0);	
   123 	g_Cvar_Mapfile = CreateConVar("sm_mapvote_file", "configs/maps.ini", "Map file to use. (Def sourcemod/configs/maps.ini)");
   124 	g_Cvar_ExcludeMaps = CreateConVar("sm_mapvote_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0);
   125 	g_Cvar_IncludeMaps = CreateConVar("sm_mapvote_include", "5", "Specifies how many maps to include in the vote.", _, true, 2.0, true, 6.0);
   126 	g_Cvar_NoVoteMode = CreateConVar("sm_mapvote_novote", "1", "Specifies whether or not MapChooser should pick a map if no votes are received.", _, true, 0.0, true, 1.0);
   127 	g_Cvar_Extend = CreateConVar("sm_mapvote_extend", "1", "Specifies whether or not MapChooser will allow the map to be extended.", _, true, 0.0, true, 1.0);
   128 	
   129 	
   130 	// Find game convars
   131 	g_Cvar_Chattime = FindConVar("mp_chattime");
   132 	g_Cvar_Winlimit = FindConVar("mp_winlimit");
   133 	g_Cvar_Maxrounds = FindConVar("mp_maxrounds");
   134 	g_Cvar_Fraglimit = FindConVar("mp_fraglimit");	
   135 
   136 	if (GetCommandFlags("nextmap") == INVALID_FCVAR_FLAGS)
   137 	{
   138 		RegServerCmd("nextmap", Command_Nextmap);
   139 	}
   140 	
   141 	// Hook events
   142 	HookEvent("round_end", Event_RoundEnd);	// We always require round_end
   143 	if (g_Cvar_Fraglimit != INVALID_HANDLE)
   144 	{
   145 		HookEvent("player_death", Event_PlayerDeath);		
   146 	}	
   147 	
   148 	// Set to the current map so OnMapStart() will know what to do
   149 	decl String:currentMap[64];
   150 	GetCurrentMap(currentMap, 64);
   151 	SetNextMap(currentMap);	
   152 
   153 	// Create necessary menus for TopMenu
   154 	g_Menu_Map = CreateMenu(MenuHandler_Map);
   155 	SetMenuTitle(g_Menu_Map, "Please select a map");
   156 	SetMenuExitBackButton(g_Menu_Map, true);
   157 	
   158 	g_Menu_Votemap = CreateMenu(MenuHandler_VoteMap, MenuAction_DrawItem);
   159 	SetMenuTitle(g_Menu_Votemap, "Please select a map");
   160 	SetMenuExitBackButton(g_Menu_Votemap, true);	
   161 	
   162 	// Bind TopMenu commands to adminmenu_maplist.ini, in cases it doesn't exist in maplists.cfg
   163 	decl String:mapListPath[PLATFORM_MAX_PATH];
   164 	BuildPath(Path_SM, mapListPath, sizeof(mapListPath), "configs/adminmenu_maplist.ini");
   165 	SetMapListCompatBind("sm_map menu", mapListPath);
   166 	SetMapListCompatBind("sm_votemap menu", mapListPath);
   167 
   168 	// Account for late loading
   169 	new Handle:topmenu;
   170 	if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
   171 	{
   172 		OnAdminMenuReady(topmenu);
   173 	}	
   174 	
   175 	AutoExecConfig(true, "mapmanager");
   176 }
   177 
   178 public OnAdminMenuReady(Handle:topmenu)
   179 {
   180 	/* Block us from being called twice */
   181 	if (topmenu == hTopMenu)
   182 	{
   183 		return;
   184 	}
   185 	
   186 	/* Save the Handle */
   187 	hTopMenu = topmenu;
   188 	
   189 	new TopMenuObject:server_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_SERVERCOMMANDS);
   190 
   191 	if (server_commands != INVALID_TOPMENUOBJECT)
   192 	{
   193 		AddToTopMenu(hTopMenu,
   194 			"sm_map",
   195 			TopMenuObject_Item,
   196 			AdminMenu_Map,
   197 			server_commands,
   198 			"sm_map",
   199 			ADMFLAG_CHANGEMAP);
   200 	}
   201 
   202 	new TopMenuObject:voting_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_VOTINGCOMMANDS);
   203 
   204 	if (voting_commands != INVALID_TOPMENUOBJECT)
   205 	{
   206 		AddToTopMenu(hTopMenu,
   207 			"sm_votemap",
   208 			TopMenuObject_Item,
   209 			AdminMenu_VoteMap,
   210 			voting_commands,
   211 			"sm_votemap",
   212 			ADMFLAG_VOTE|ADMFLAG_CHANGEMAP);
   213 	}
   214 }
   215 
   216 public OnLibraryRemoved(const String:name[])
   217 {
   218 	if (strcmp(name, "adminmenu") == 0)
   219 	{
   220 		hTopMenu = INVALID_HANDLE;
   221 	}
   222 }
   223 
   224 public OnConfigsExecuted()
   225 {
   226 	// Add map logic here
   227 	
   228 	// Get the current and last maps.
   229 	decl String:lastMap[64], String:currentMap[64];
   230 	GetConVarString(g_Cvar_NextMap, lastMap, 64);
   231 	GetCurrentMap(currentMap, 64);
   232 	
   233 	// Why am I doing this? If we switched to a new map, but it wasn't what we expected (Due to sm_map, sm_votemap, or
   234 	// some other plugin/command), we don't want to scramble the map cycle. Or for example, admin switches to a custom map
   235 	// not in mapcyclefile. So we keep it set to the last expected nextmap. - ferret
   236 	if (strcmp(lastMap, currentMap) == 0)
   237 	{
   238 		FindAndSetNextMap();
   239 	}
   240 	
   241 	// Build map menus for sm_map, sm_votemap, and RTV.
   242 	/* TODO: Figure out wtf I'm supposed to do here */
   243 	BuildMapMenu(g_Menu_Map);
   244 	BuildMapMenu(g_Menu_Votemap);
   245 
   246 	
   247 	// If the Randomize option is on, randomize!
   248 	if (GetConVarBool(g_Cvar_Randomize))
   249 	{
   250 		CreateTimer(5.0, Timer_RandomizeNextmap);
   251 	}
   252 	
   253 	// If MapChooser is active, start it up!
   254 	if (GetConVarBool(g_Cvar_MapChooser))
   255 	{
   256 		SetupTimeleftTimer();
   257 		SetConVarString(g_Cvar_NextMap, "Pending Vote");
   258 	}
   259 	
   260 	/*
   261 	// If RockTheVote is active, start it up!
   262 	if (GetConVarBool(g_Cvar_RockTheVote))
   263 	{
   264 		BuildMapMenu(g_Menu_RTV, list);
   265 		CreateTimer(30.0, Timer_DelayRTV);
   266 	}
   267 	*/
   268 }
   269 
   270 // Reinitialize all our various globals
   271 public OnMapStart()
   272 {
   273 	if (g_Menu_Nominate != INVALID_HANDLE)
   274 	{
   275 		ClearArray(g_Menu_Nominate);
   276 	}
   277 	
   278 	if (g_TeamScores != INVALID_HANDLE)
   279 	{
   280 		ClearArray(g_TeamScores);
   281 	}
   282 
   283 	g_TotalRounds = 0;	
   284 	
   285 	g_RTV_Voters = 0;
   286 	g_RTV_Votes = 0;
   287 	g_RTV_VotesNeeded = 0;
   288 	g_RTV_Started = false;
   289 	g_RTV_Ended = false;
   290 }
   291 
   292 // Reset globals as necessary and kill timers
   293 public OnMapEnd()
   294 {
   295 	g_IntermissionCalled = false;
   296 	g_HasVoteStarted = false;
   297 		
   298 	g_RTV_Allowed = false;	
   299 	
   300 	if (g_VoteTimer != INVALID_HANDLE)
   301 	{
   302 		KillTimer(g_VoteTimer);
   303 		g_VoteTimer = INVALID_HANDLE;
   304 	}
   305 	
   306 	if (g_RetryTimer != INVALID_HANDLE)
   307 	{
   308 		KillTimer(g_RetryTimer);
   309 		g_RetryTimer = INVALID_HANDLE;
   310 	}
   311 }
   312 
   313 public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
   314 {
   315 	if (IsFakeClient(client))
   316 	{
   317 		return true;
   318 	}
   319 	
   320 	// If RTV is active, deal with vote counting.
   321 	if (GetConVarBool(g_Cvar_RockTheVote))
   322 	{
   323 		g_RTV_Voted[client] = false;
   324 		g_RTV_Voters++;
   325 		g_RTV_VotesNeeded = RoundToFloor(float(g_RTV_Voters) * GetConVarFloat(g_Cvar_RTVLimit));
   326 	}
   327 
   328 	// If Nominate is active, let the new client nominate
   329 	if (GetConVarBool(g_Cvar_Nominate))
   330 	{
   331 		g_Nominated[client] = false;
   332 	}
   333 	
   334 	return true;
   335 }
   336 
   337 public OnClientDisconnect(client)
   338 {
   339 	if (IsFakeClient(client))
   340 	{
   341 		return;
   342 	}
   343 	
   344 	// If RTV is active, deal with vote counting.
   345 	if (GetConVarBool(g_Cvar_RockTheVote))
   346 	{
   347 		if(g_RTV_Voted[client])
   348 		{
   349 			g_RTV_Votes--;
   350 		}
   351 
   352 		g_RTV_Voters--;
   353 		g_RTV_VotesNeeded = RoundToFloor(float(g_RTV_Voters) * GetConVarFloat(g_Cvar_RTVLimit));
   354 		
   355 		// If this client caused us to fall below the RTV threshold and its allowed be started, start it.	
   356 		if (g_RTV_Votes && g_RTV_Voters && g_RTV_Votes >= g_RTV_VotesNeeded && g_RTV_Allowed && !g_RTV_Started) 
   357 		{
   358 			g_RTV_Started = true;
   359 			CreateTimer(2.0, Timer_StartRTV, TIMER_FLAG_NO_MAPCHANGE);
   360 		}	
   361 	}
   362 }
   363 
   364 public OnMapTimeLeftChanged()
   365 {
   366 	if (GetConVarBool(g_Cvar_MapChooser))
   367 	{
   368 		SetupTimeleftTimer();
   369 	}
   370 }