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