plugins/mapmanager.sp
changeset 1952 b7aa2b626807
child 2027 887d7271f947
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/plugins/mapmanager.sp	Sun Mar 30 07:00:22 2008 +0000
     1.3 @@ -0,0 +1,362 @@
     1.4 +/**
     1.5 + * vim: set ts=4 :
     1.6 + * =============================================================================
     1.7 + * SourceMod Map Management Plugin
     1.8 + * Provides all map related functionality, including map changing, map voting,
     1.9 + * and nextmap.
    1.10 + *
    1.11 + * SourceMod (C)2004-2008 AlliedModders LLC.  All rights reserved.
    1.12 + * =============================================================================
    1.13 + *
    1.14 + * This program is free software; you can redistribute it and/or modify it under
    1.15 + * the terms of the GNU General Public License, version 3.0, as published by the
    1.16 + * Free Software Foundation.
    1.17 + * 
    1.18 + * This program is distributed in the hope that it will be useful, but WITHOUT
    1.19 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.20 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.21 + * details.
    1.22 + *
    1.23 + * You should have received a copy of the GNU General Public License along with
    1.24 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.25 + *
    1.26 + * As a special exception, AlliedModders LLC gives you permission to link the
    1.27 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.28 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.29 + * by the Valve Corporation.  You must obey the GNU General Public License in
    1.30 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.31 + * this exception to all derivative works.  AlliedModders LLC defines further
    1.32 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.33 + * or <http://www.sourcemod.net/license.php>.
    1.34 + *
    1.35 + * Version: $Id$
    1.36 + */
    1.37 +
    1.38 +#pragma semicolon 1
    1.39 +#include <sourcemod>
    1.40 +
    1.41 +public Plugin:myinfo =
    1.42 +{
    1.43 +	name = "Map Manager",
    1.44 +	author = "AlliedModders LLC",
    1.45 +	description = "Map Management",
    1.46 +	version = SOURCEMOD_VERSION,
    1.47 +	url = "http://www.sourcemod.net/"
    1.48 +};
    1.49 +
    1.50 +#include "mapmanagement/globals.sp"
    1.51 +#include "mapmanagement/commands.sp"
    1.52 +#include "mapmanagement/events.sp"
    1.53 +#include "mapmanagement/functions.sp"
    1.54 +#include "mapmanagement/menus.sp"
    1.55 +#include "mapmanagement/timers.sp"
    1.56 +#include "mapmanagement/votes.sp"
    1.57 +
    1.58 +public OnPluginStart()
    1.59 +{	
    1.60 +	LoadTranslations("mapmanager.phrases");
    1.61 +
    1.62 +	// Prepare nextmap functionality.	
    1.63 +	g_VGUIMenu = GetUserMessageId("VGUIMenu");
    1.64 +	if (g_VGUIMenu == INVALID_MESSAGE_ID)
    1.65 +	{
    1.66 +		LogError("FATAL: Cannot find VGUIMenu user message id. MapManager crippled.");
    1.67 +		g_NextMapEnabled = false;
    1.68 +	}
    1.69 +	HookUserMessage(g_VGUIMenu, UserMsg_VGUIMenu);
    1.70 +
    1.71 +	// Create all of the arrays, sized for a 64 character string.
    1.72 +	new arraySize = ByteCountToCells(64);
    1.73 +	g_MapCycle = CreateArray(arraySize);
    1.74 +	g_MapList = CreateArray(arraySize);
    1.75 +	g_MapHistory = CreateArray(arraySize);
    1.76 +	g_NextVoteMaps = CreateArray(arraySize);
    1.77 +	g_SelectedMaps = CreateArray(arraySize);
    1.78 +	g_NominatedMaps = CreateArray(arraySize);
    1.79 +	
    1.80 +	g_TeamScores = CreateArray(2);
    1.81 +
    1.82 +	// Hook say
    1.83 +	RegConsoleCmd("say", Command_Say);
    1.84 +	RegConsoleCmd("say_team", Command_Say);	
    1.85 +
    1.86 +	// Register all commands.
    1.87 +	RegAdminCmd("sm_map", Command_Map, ADMFLAG_CHANGEMAP, "sm_map <map> [r/e]");
    1.88 +	RegAdminCmd("sm_setnextmap", Command_SetNextmap, ADMFLAG_CHANGEMAP, "sm_setnextmap <map>");
    1.89 +	RegAdminCmd("sm_votemap", Command_Votemap, ADMFLAG_VOTE|ADMFLAG_CHANGEMAP, "sm_votemap <mapname> [mapname2] ... [mapname5] ");
    1.90 +	RegAdminCmd("sm_maplist", Command_List, ADMFLAG_GENERIC, "sm_maplist");
    1.91 +	RegAdminCmd("sm_nominate", Command_Addmap, ADMFLAG_CHANGEMAP, "sm_nominate <mapname> - Nominates a map for RockTheVote and MapChooser. Overrides existing nominations.");
    1.92 +	RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces the MapChooser vote to occur.");
    1.93 +	
    1.94 +	if (GetCommandFlags("nextmap") == INVALID_FCVAR_FLAGS)
    1.95 +	{
    1.96 +		RegServerCmd("nextmap", Command_Nextmap);
    1.97 +	}	
    1.98 +	
    1.99 +	// Register all convars
   1.100 +	g_Cvar_Nextmap = CreateConVar("sm_nextmap", "", "Sets the Next Map", FCVAR_NOTIFY);
   1.101 +	
   1.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);	
   1.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);
   1.104 +	
   1.105 +	g_Cvar_MapChooser = CreateConVar("sm_mm_mapchooser", "0", "Enables MapChooser (End of Map voting)", 0, true, 0.0, true, 1.0);
   1.106 +	g_Cvar_RockTheVote = CreateConVar("sm_mm_rockthevote", "0", "Enables RockTheVote (Player initiated map votes)", 0, true, 0.0, true, 1.0);
   1.107 +	g_Cvar_Randomize = CreateConVar("sm_mm_randomize", "0", "Enabled Randomizer (Randomly picks the next map)", 0, true, 0.0, true, 1.0);
   1.108 +	g_Cvar_Nominate = CreateConVar("sm_mm_nominate", "1", "Enables nomination system.", 0, true, 0.0, true, 1.0);
   1.109 +	
   1.110 +	g_Cvar_VoteMap = CreateConVar("sm_mm_votemap", "0.60", "Percentage required for successful sm_votemap.", 0, true, 0.05, true, 1.0);
   1.111 +	g_Cvar_RTVLimit = CreateConVar("sm_mm_rtvlimit", "0.60", "Required percentage of players needed to rockthevote", 0, true, 0.05, true, 1.0);
   1.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));
   1.113 +	
   1.114 +	g_Cvar_StartTime = CreateConVar("sm_mapvote_start", "3.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0);
   1.115 +	g_Cvar_StartRounds = CreateConVar("sm_mapvote_startround", "2.0", "Specifies when to start the vote based on rounds remaining.", _, true, 1.0);
   1.116 +	g_Cvar_StartFrags = CreateConVar("sm_mapvote_startfrags", "5.0", "Specifies when to start the vote base on frags remaining.", _, true, 1.0);
   1.117 +	g_Cvar_ExtendTimeMax = CreateConVar("sm_extendmap_maxtime", "90", "Specifies the maximum amount of time a map can be extended", _, true, 0.0);
   1.118 +	g_Cvar_ExtendTimeStep = CreateConVar("sm_extendmap_timestep", "15", "Specifies how much many more minutes each extension makes", _, true, 5.0);
   1.119 +	g_Cvar_ExtendRoundMax = CreateConVar("sm_extendmap_maxrounds", "30", "Specfies the maximum amount of rounds a map can be extended", _, true, 0.0);
   1.120 +	g_Cvar_ExtendRoundStep = CreateConVar("sm_extendmap_roundstep", "5", "Specifies how many more rounds each extension makes", _, true, 5.0);
   1.121 +	g_Cvar_ExtendFragMax = CreateConVar("sm_extendmap_maxfrags", "150", "Specfies the maximum frags allowed that a map can be extended.", _, true, 0.0);
   1.122 +	g_Cvar_ExtendFragStep = CreateConVar("sm_extendmap_fragstep", "10", "Specifies how many more frags are allowed when map is extended.", _, true, 5.0);	
   1.123 +	g_Cvar_Mapfile = CreateConVar("sm_mapvote_file", "configs/maps.ini", "Map file to use. (Def sourcemod/configs/maps.ini)");
   1.124 +	g_Cvar_ExcludeMaps = CreateConVar("sm_mapvote_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0);
   1.125 +	g_Cvar_IncludeMaps = CreateConVar("sm_mapvote_include", "5", "Specifies how many maps to include in the vote.", _, true, 2.0, true, 6.0);
   1.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);
   1.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);
   1.128 +	
   1.129 +	// Find game convars
   1.130 +	g_Cvar_Chattime = FindConVar("mp_chattime");
   1.131 +	g_Cvar_Winlimit = FindConVar("mp_winlimit");
   1.132 +	g_Cvar_Maxrounds = FindConVar("mp_maxrounds");
   1.133 +	g_Cvar_Fraglimit = FindConVar("mp_fraglimit");	
   1.134 +
   1.135 +	if (GetCommandFlags("nextmap") == INVALID_FCVAR_FLAGS)
   1.136 +	{
   1.137 +		RegServerCmd("nextmap", Command_Nextmap);
   1.138 +	}
   1.139 +	
   1.140 +	// Hook events
   1.141 +	HookEvent("round_end", Event_RoundEnd);	// We always require round_end
   1.142 +	if (g_Cvar_Fraglimit != INVALID_HANDLE)
   1.143 +	{
   1.144 +		HookEvent("player_death", Event_PlayerDeath);		
   1.145 +	}	
   1.146 +	
   1.147 +	// Set to the current map so OnMapStart() will know what to do
   1.148 +	decl String:currentMap[64];
   1.149 +	GetCurrentMap(currentMap, 64);
   1.150 +	SetNextmap(currentMap);	
   1.151 +
   1.152 +	// Create necessary menus for TopMenu
   1.153 +	g_Menu_Map = CreateMenu(MenuHandler_Map);
   1.154 +	SetMenuTitle(g_Menu_Map, "Please select a map");
   1.155 +	SetMenuExitBackButton(g_Menu_Map, true);
   1.156 +	
   1.157 +	g_Menu_Votemap = CreateMenu(MenuHandler_VoteMap, MenuAction_DrawItem);
   1.158 +	SetMenuTitle(g_Menu_Votemap, "Please select a map");
   1.159 +	SetMenuExitBackButton(g_Menu_Votemap, true);	
   1.160 +	
   1.161 +	// Bind TopMenu commands to adminmenu_maplist.ini, in cases it doesn't exist in maplists.cfg
   1.162 +	decl String:mapListPath[PLATFORM_MAX_PATH];
   1.163 +	BuildPath(Path_SM, mapListPath, sizeof(mapListPath), "configs/adminmenu_maplist.ini");
   1.164 +	SetMapListCompatBind("sm_map menu", mapListPath);
   1.165 +	SetMapListCompatBind("sm_votemap menu", mapListPath);
   1.166 +
   1.167 +	// Account for late loading
   1.168 +	new Handle:topmenu;
   1.169 +	if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
   1.170 +	{
   1.171 +		OnAdminMenuReady(topmenu);
   1.172 +	}	
   1.173 +	
   1.174 +	AutoExecConfig(true, "mapmanager");
   1.175 +}
   1.176 +
   1.177 +public OnAdminMenuReady(Handle:topmenu)
   1.178 +{
   1.179 +	/* Block us from being called twice */
   1.180 +	if (topmenu == hTopMenu)
   1.181 +	{
   1.182 +		return;
   1.183 +	}
   1.184 +	
   1.185 +	/* Save the Handle */
   1.186 +	hTopMenu = topmenu;
   1.187 +	
   1.188 +	new TopMenuObject:server_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_SERVERCOMMANDS);
   1.189 +
   1.190 +	if (server_commands != INVALID_TOPMENUOBJECT)
   1.191 +	{
   1.192 +		AddToTopMenu(hTopMenu,
   1.193 +			"sm_map",
   1.194 +			TopMenuObject_Item,
   1.195 +			AdminMenu_Map,
   1.196 +			server_commands,
   1.197 +			"sm_map",
   1.198 +			ADMFLAG_CHANGEMAP);
   1.199 +	}
   1.200 +
   1.201 +	new TopMenuObject:voting_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_VOTINGCOMMANDS);
   1.202 +
   1.203 +	if (voting_commands != INVALID_TOPMENUOBJECT)
   1.204 +	{
   1.205 +		AddToTopMenu(hTopMenu,
   1.206 +			"sm_votemap",
   1.207 +			TopMenuObject_Item,
   1.208 +			AdminMenu_VoteMap,
   1.209 +			voting_commands,
   1.210 +			"sm_votemap",
   1.211 +			ADMFLAG_VOTE|ADMFLAG_CHANGEMAP);
   1.212 +	}
   1.213 +}
   1.214 +
   1.215 +public OnLibraryRemoved(const String:name[])
   1.216 +{
   1.217 +	if (strcmp(name, "adminmenu") == 0)
   1.218 +	{
   1.219 +		hTopMenu = INVALID_HANDLE;
   1.220 +	}
   1.221 +}
   1.222 +
   1.223 +public OnConfigsExecuted()
   1.224 +{
   1.225 +	// Add map logic here
   1.226 +	
   1.227 +	// Get the current and last maps.
   1.228 +	decl String:lastMap[64], String:currentMap[64];
   1.229 +	GetConVarString(g_Cvar_Nextmap, lastMap, 64);
   1.230 +	GetCurrentMap(currentMap, 64);
   1.231 +	
   1.232 +	// 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
   1.233 +	// some other plugin/command), we don't want to scramble the map cycle. Or for example, admin switches to a custom map
   1.234 +	// not in mapcyclefile. So we keep it set to the last expected nextmap. - ferret
   1.235 +	if (strcmp(lastMap, currentMap) == 0)
   1.236 +	{
   1.237 +		FindAndSetNextMap();
   1.238 +	}
   1.239 +	
   1.240 +	// Build map menus for sm_map, sm_votemap, and RTV.
   1.241 +	BuildMapMenu(g_Menu_Map, list);
   1.242 +	BuildMapMenu(g_Menu_VoteMap, list);
   1.243 +	
   1.244 +	// If the Randomize option is on, randomize!
   1.245 +	if (GetConVarBool(g_Cvar_Randomize))
   1.246 +	{
   1.247 +		CreateTimer(5.0, Timer_RandomizeNextmap);
   1.248 +	}
   1.249 +	
   1.250 +	// If MapChooser is active, start it up!
   1.251 +	if (GetConVarBool(g_Cvar_MapChooser))
   1.252 +	{
   1.253 +		SetupTimeleftTimer();
   1.254 +		SetConVarString(g_Cvar_Nextmap, "Pending Vote");
   1.255 +	}
   1.256 +	
   1.257 +	// If RockTheVote is active, start it up!
   1.258 +	if (GetConVarBool(g_Cvar_RockTheVote))
   1.259 +	{
   1.260 +		BuildMapMenu(g_Menu_RTV, list);
   1.261 +		CreateTimer(30.0, Timer_DelayRTV);
   1.262 +	}	
   1.263 +}
   1.264 +
   1.265 +// Reinitialize all our various globals
   1.266 +public OnMapStart()
   1.267 +{
   1.268 +	if (g_Nominate != INVALID_HANDLE)
   1.269 +	{
   1.270 +		ClearArray(g_Nominate);
   1.271 +	}
   1.272 +	
   1.273 +	if (g_TeamScores != INVALID_HANDLE)
   1.274 +	{
   1.275 +		ClearArray(g_TeamScores);
   1.276 +	}
   1.277 +
   1.278 +	g_TotalRounds = 0;	
   1.279 +	
   1.280 +	g_RTV_Voters = 0;
   1.281 +	g_RTV_Votes = 0;
   1.282 +	g_RTV_VotesNeeded = 0;
   1.283 +	g_RTV_Started = false;
   1.284 +	g_RTV_Ended = false;
   1.285 +}
   1.286 +
   1.287 +// Reset globals as necessary and kill timers
   1.288 +public OnMapEnd()
   1.289 +{
   1.290 +	g_IntermissionCalled = false;
   1.291 +	g_HasVoteStarted = false;
   1.292 +		
   1.293 +	g_RTV_Allowed = false;	
   1.294 +	
   1.295 +	if (g_VoteTimer != INVALID_HANDLE)
   1.296 +	{
   1.297 +		KillTimer(g_VoteTimer);
   1.298 +		g_VoteTimer = INVALID_HANDLE;
   1.299 +	}
   1.300 +	
   1.301 +	if (g_RetryTimer != INVALID_HANDLE)
   1.302 +	{
   1.303 +		KillTimer(g_RetryTimer);
   1.304 +		g_RetryTimer = INVALID_HANDLE;
   1.305 +	}
   1.306 +}
   1.307 +
   1.308 +public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
   1.309 +{
   1.310 +	if (IsFakeClient(client))
   1.311 +	{
   1.312 +		return true;
   1.313 +	}
   1.314 +	
   1.315 +	// If RTV is active, deal with vote counting.
   1.316 +	if (GetConVarBool(g_Cvar_RockTheVote))
   1.317 +	{
   1.318 +		g_RTV_Voted[client] = false;
   1.319 +		g_RTV_Voters++;
   1.320 +		g_RTV_VotesNeeded = RoundToFloor(float(g_Voters) * GetConVarFloat(g_Cvar_Needed));
   1.321 +	}
   1.322 +
   1.323 +	// If Nominate is active, let the new client nominate
   1.324 +	if (GetConVarBool(g_Cvar_Nominate))
   1.325 +	{
   1.326 +		g_Nominated[client] = false;
   1.327 +	}
   1.328 +	
   1.329 +	return true;
   1.330 +}
   1.331 +
   1.332 +public OnClientDisconnect(client)
   1.333 +{
   1.334 +	if (IsFakeClient(client))
   1.335 +	{
   1.336 +		return;
   1.337 +	}
   1.338 +	
   1.339 +	// If RTV is active, deal with vote counting.
   1.340 +	if (GetConVarBool(g_Cvar_RockTheVote))
   1.341 +	{
   1.342 +		if(g_RTV_Voted[client])
   1.343 +		{
   1.344 +			g_RTV_Votes--;
   1.345 +		}
   1.346 +
   1.347 +		g_RTV_Voters--;
   1.348 +		g_RTV_VotesNeeded = RoundToFloor(float(g_RTV_Voters) * GetConVarFloat(g_Cvar_RTVLimit));
   1.349 +		
   1.350 +		// If this client caused us to fall below the RTV threshold and its allowed be started, start it.	
   1.351 +		if (g_RTV_Votes && g_RTV_Voters && g_RTV_Votes >= g_RTV_VotesNeeded && g_RTV_Allowed && !g_RTV_Started) 
   1.352 +		{
   1.353 +			g_RTV_Started = true;
   1.354 +			CreateTimer(2.0, Timer_StartRTV, TIMER_FLAG_NO_MAPCHANGE);
   1.355 +		}	
   1.356 +	}
   1.357 +}
   1.358 +
   1.359 +public OnMapTimeLeftChanged()
   1.360 +{
   1.361 +	if (GetConVarBool(g_Cvar_MapChooser))
   1.362 +	{
   1.363 +		SetupTimeleftTimer();
   1.364 +	}
   1.365 +}
   1.366 \ No newline at end of file