plugins/mapchooser.sp
author David Anderson <dvander@alliedmods.net>
Tue Oct 16 17:29:06 2007 +0000 (2007-10-16)
changeset 1591 3f28cc06e235
parent 1539 74121104e67d
child 1606 4fb3959c2c96
permissions -rw-r--r--
renamed fun commands on menu
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Mapchooser Plugin
     5  * Creates a map vote at appropriate times, setting sm_nextmap to the winning
     6  * vote
     7  *
     8  * SourceMod (C)2004-2007 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 
    38 public Plugin:myinfo =
    39 {
    40 	name = "MapChooser",
    41 	author = "AlliedModders LLC",
    42 	description = "Automated Map Voting",
    43 	version = SOURCEMOD_VERSION,
    44 	url = "http://www.sourcemod.net/"
    45 };
    46 
    47 new Handle:g_Cvar_Winlimit = INVALID_HANDLE;
    48 new Handle:g_Cvar_Maxrounds = INVALID_HANDLE;
    49 new Handle:g_Cvar_Fraglimit = INVALID_HANDLE;
    50 
    51 new Handle:g_Cvar_Nextmap = INVALID_HANDLE;
    52 
    53 new Handle:g_Cvar_StartTime = INVALID_HANDLE;
    54 new Handle:g_Cvar_StartRounds = INVALID_HANDLE;
    55 new Handle:g_Cvar_StartFrags = INVALID_HANDLE;
    56 new Handle:g_Cvar_ExtendTimeMax = INVALID_HANDLE;
    57 new Handle:g_Cvar_ExtendTimeStep = INVALID_HANDLE;
    58 new Handle:g_Cvar_ExtendRoundMax = INVALID_HANDLE;
    59 new Handle:g_Cvar_ExtendRoundStep = INVALID_HANDLE;
    60 new Handle:g_Cvar_ExtendFragMax = INVALID_HANDLE;
    61 new Handle:g_Cvar_ExtendFragStep = INVALID_HANDLE;
    62 new Handle:g_Cvar_Mapfile = INVALID_HANDLE;
    63 new Handle:g_Cvar_ExcludeMaps = INVALID_HANDLE;
    64 new Handle:g_Cvar_IncludeMaps = INVALID_HANDLE;
    65 new Handle:g_Cvar_NoVoteMode = INVALID_HANDLE;
    66 new Handle:g_Cvar_Extend = INVALID_HANDLE;
    67 
    68 new Handle:g_VoteTimer = INVALID_HANDLE;
    69 new Handle:g_RetryTimer = INVALID_HANDLE;
    70 
    71 new Handle:g_MapList = INVALID_HANDLE;
    72 new Handle:g_OldMapList = INVALID_HANDLE;
    73 new Handle:g_NextMapList = INVALID_HANDLE;
    74 new Handle:g_VoteMenu = INVALID_HANDLE;
    75 new Handle:g_TeamScores = INVALID_HANDLE;
    76 
    77 new bool:g_HasVoteStarted;
    78 new g_mapFileTime;
    79 
    80 #define VOTE_EXTEND "##extend##"
    81 
    82 public OnPluginStart()
    83 {
    84 	LoadTranslations("mapchooser.phrases");
    85 	
    86 	g_MapList = CreateArray(33);
    87 	g_OldMapList = CreateArray(33);
    88 	g_NextMapList = CreateArray(33);
    89 	g_TeamScores = CreateArray(2);
    90 
    91 	g_Cvar_StartTime = CreateConVar("sm_mapvote_start", "3.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0);
    92 	g_Cvar_StartRounds = CreateConVar("sm_mapvote_startround", "2.0", "Specifies when to start the vote based on rounds remaining.", _, true, 1.0);
    93 	g_Cvar_StartFrags = CreateConVar("sm_mapvote_startfrags", "5.0", "Specifies when to start the vote base on frags remaining.", _, true, 1.0);
    94 	g_Cvar_ExtendTimeMax = CreateConVar("sm_extendmap_maxtime", "90", "Specifies the maximum amount of time a map can be extended", _, true, 0.0);
    95 	g_Cvar_ExtendTimeStep = CreateConVar("sm_extendmap_timestep", "15", "Specifies how much many more minutes each extension makes", _, true, 5.0);
    96 	g_Cvar_ExtendRoundMax = CreateConVar("sm_extendmap_maxrounds", "30", "Specfies the maximum amount of rounds a map can be extended", _, true, 0.0);
    97 	g_Cvar_ExtendRoundStep = CreateConVar("sm_extendmap_roundstep", "5", "Specifies how many more rounds each extension makes", _, true, 5.0);
    98 	g_Cvar_ExtendFragMax = CreateConVar("sm_extendmap_maxfrags", "150", "Specfies the maximum frags allowed that a map can be extended.", _, true, 0.0);
    99 	g_Cvar_ExtendFragStep = CreateConVar("sm_extendmap_fragstep", "10", "Specifies how many more frags are allowed when map is extended.", _, true, 5.0);	
   100 	g_Cvar_Mapfile = CreateConVar("sm_mapvote_file", "configs/maps.ini", "Map file to use. (Def sourcemod/configs/maps.ini)");
   101 	g_Cvar_ExcludeMaps = CreateConVar("sm_mapvote_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0);
   102 	g_Cvar_IncludeMaps = CreateConVar("sm_mapvote_include", "5", "Specifies how many maps to include in the vote.", _, true, 2.0, true, 6.0);
   103 	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);
   104 	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);
   105 
   106 	RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces MapChooser to attempt to run a map vote now.");
   107 
   108 	g_Cvar_Winlimit = FindConVar("mp_winlimit");
   109 	g_Cvar_Maxrounds = FindConVar("mp_maxrounds");
   110 	g_Cvar_Fraglimit = FindConVar("mp_fraglimit");
   111 	
   112 	if (g_Cvar_Winlimit != INVALID_HANDLE || g_Cvar_Maxrounds != INVALID_HANDLE)
   113 	{
   114 		HookEvent("round_end", Event_RoundEnd);
   115 	}
   116 	
   117 	if (g_Cvar_Fraglimit != INVALID_HANDLE)
   118 	{
   119 		HookEvent("player_death", Event_PlayerDeath);		
   120 	}
   121 	
   122 	AutoExecConfig(true, "mapchooser");
   123 }
   124 
   125 public OnMapStart()
   126 {
   127 	g_Cvar_Nextmap = FindConVar("sm_nextmap");
   128 
   129 	if (g_Cvar_Nextmap == INVALID_HANDLE)
   130 	{
   131 		LogError("FATAL: Cannot find sm_nextmap cvar. Mapchooser not loaded.");
   132 		SetFailState("sm_nextmap not found");
   133 	}
   134 	
   135 	if (LoadMaps())
   136 	{
   137 		CreateNextVote();
   138 		SetupTimeleftTimer();
   139 		SetConVarString(g_Cvar_Nextmap, "Pending Vote");
   140 	}
   141 }
   142 
   143 public OnMapEnd()
   144 {
   145 	g_HasVoteStarted = false;
   146 	g_RetryTimer = INVALID_HANDLE;
   147 	g_VoteTimer = INVALID_HANDLE;
   148 }
   149 
   150 public OnMapTimeLeftChanged()
   151 {
   152 	if (GetArraySize(g_MapList))
   153 	{
   154 		SetupTimeleftTimer();
   155 	}
   156 }
   157 
   158 SetupTimeleftTimer()
   159 {
   160 	new time;
   161 	if (GetMapTimeLeft(time) && time > 0)
   162 	{
   163 		new startTime = GetConVarInt(g_Cvar_StartTime) * 60;
   164 		if (time - startTime < 0)
   165 		{
   166 			InitiateVote();		
   167 		}
   168 		else
   169 		{
   170 			if (g_VoteTimer != INVALID_HANDLE)
   171 			{
   172 				KillTimer(g_VoteTimer);
   173 				g_VoteTimer = INVALID_HANDLE;
   174 			}	
   175 			
   176 			g_VoteTimer = CreateTimer(float(time - startTime), Timer_StartMapVote, TIMER_FLAG_NO_MAPCHANGE);
   177 		}		
   178 	}
   179 }
   180 
   181 public Action:Timer_StartMapVote(Handle:timer)
   182 {
   183 	if (!GetArraySize(g_MapList))
   184 	{
   185 		return Plugin_Stop;
   186 	}		
   187 	
   188 	if (timer == g_RetryTimer)
   189 	{
   190 		g_RetryTimer = INVALID_HANDLE;
   191 	}
   192 	else
   193 	{
   194 		g_VoteTimer = INVALID_HANDLE;
   195 	}
   196 
   197 	InitiateVote();
   198 
   199 	return Plugin_Stop;
   200 }
   201 
   202 /* You ask, why don't you just use team_score event? And I answer... Because CSS doesn't. */
   203 public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
   204 {
   205 	if (!GetArraySize(g_MapList) || g_HasVoteStarted)
   206 	{
   207 		return;
   208 	}
   209 
   210 	new winner = GetEventInt(event, "winner");
   211 	
   212 	if (winner == 0 || winner == 1)
   213 	{
   214 		return;
   215 	}
   216 
   217 	static total;
   218 	total++;
   219 	
   220 	new team[2], teamPos = -1;
   221 	for (new i; i < GetArraySize(g_TeamScores); i++)
   222 	{
   223 		GetArrayArray(g_TeamScores, i, team);
   224 		if (team[0] == winner)
   225 		{
   226 			teamPos = i;
   227 			break;
   228 		}		
   229 	}
   230 	
   231 	if (teamPos == -1)
   232 	{
   233 		team[0] = winner;
   234 		team[1] = 1;
   235 		PushArrayArray(g_TeamScores, team);
   236 	}
   237 	else
   238 	{
   239 		team[1]++;
   240 		SetArrayArray(g_TeamScores, teamPos, team);
   241 	}	
   242 	
   243 	if (g_Cvar_Winlimit != INVALID_HANDLE)
   244 	{
   245 		new winlimit = GetConVarInt(g_Cvar_Winlimit);
   246 		if (winlimit)
   247 		{
   248 			if (team[1] >= (winlimit - GetConVarInt(g_Cvar_StartRounds)))
   249 			{
   250 				InitiateVote();
   251 			}
   252 		}
   253 	}
   254 	
   255 	if (g_Cvar_Maxrounds != INVALID_HANDLE)
   256 	{
   257 		new maxrounds = GetConVarInt(g_Cvar_Maxrounds);
   258 		if (maxrounds)
   259 		{
   260 			if (total >= (maxrounds - GetConVarInt(g_Cvar_StartRounds)))
   261 			{
   262 				InitiateVote();
   263 			}			
   264 		}
   265 	}
   266 }
   267 
   268 public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
   269 {
   270 	if (!GetArraySize(g_MapList) || g_Cvar_Fraglimit == INVALID_HANDLE || g_HasVoteStarted)
   271 	{
   272 		return;
   273 	}
   274 	
   275 	if (!GetConVarInt(g_Cvar_Fraglimit))
   276 	{
   277 		return;
   278 	}
   279 
   280 	new fragger = GetClientOfUserId(GetEventInt(event, "attacker"));
   281 	if (fragger && GetClientFrags(fragger) >= (GetConVarInt(g_Cvar_Fraglimit) - GetConVarInt(g_Cvar_StartFrags)))
   282 	{
   283 		InitiateVote();
   284 	}
   285 }
   286 
   287 public Action:Command_Mapvote(client, args)
   288 {
   289 	InitiateVote();
   290 
   291 	return Plugin_Handled;	
   292 }
   293 
   294 InitiateVote()
   295 {
   296 	if (g_HasVoteStarted || g_RetryTimer != INVALID_HANDLE)
   297 	{
   298 		return;
   299 	}
   300 	
   301 	if (IsVoteInProgress())
   302 	{
   303 		// Can't start a vote, try again in 5 seconds.
   304 		g_RetryTimer = CreateTimer(5.0, Timer_StartMapVote, TIMER_FLAG_NO_MAPCHANGE);
   305 		return;
   306 	}		
   307 	
   308 	g_HasVoteStarted = true;
   309 	g_VoteMenu = CreateMenu(Handler_MapVoteMenu, MenuAction:MENU_ACTIONS_ALL);
   310 	SetMenuTitle(g_VoteMenu, "Vote Nextmap");
   311 
   312 	decl String:map[32];
   313 	for (new i = 0; i < GetArraySize(g_NextMapList); i++)
   314 	{
   315 		GetArrayString(g_NextMapList, i, map, sizeof(map));
   316 		AddMenuItem(g_VoteMenu, map, map);
   317 	}
   318 
   319 	if (GetConVarBool(g_Cvar_Extend))
   320 	{
   321 		new bool:allowExtend, time;
   322 		if (GetMapTimeLimit(time) && time > 0 && time < GetConVarInt(g_Cvar_ExtendTimeMax))
   323 		{
   324 			allowExtend = true;
   325 		}
   326 
   327 		if (g_Cvar_Winlimit != INVALID_HANDLE && GetConVarInt(g_Cvar_Winlimit) < GetConVarInt(g_Cvar_ExtendRoundMax))
   328 		{
   329 			allowExtend = true;
   330 		}	
   331 	
   332 		if (g_Cvar_Maxrounds != INVALID_HANDLE && GetConVarInt(g_Cvar_Maxrounds) < GetConVarInt(g_Cvar_ExtendRoundMax))
   333 		{
   334 			allowExtend = true;
   335 		}
   336 	
   337 		if (g_Cvar_Fraglimit != INVALID_HANDLE && GetConVarInt(g_Cvar_Fraglimit) < GetConVarInt(g_Cvar_ExtendFragMax))
   338 		{
   339 			allowExtend = true;
   340 		}
   341 
   342 		if (allowExtend)
   343 		{
   344 			AddMenuItem(g_VoteMenu, VOTE_EXTEND, "Extend Map");
   345 		}
   346 	}
   347 
   348 	SetMenuExitButton(g_VoteMenu, false);
   349 	VoteMenuToAll(g_VoteMenu, 20);
   350 
   351 	LogMessage("Voting for next map has started.");
   352 	PrintToChatAll("[SM] %t", "Nextmap Voting Started");
   353 }
   354 
   355 public Handler_MapVoteMenu(Handle:menu, MenuAction:action, param1, param2)
   356 {
   357 	switch (action)
   358 	{
   359 		case MenuAction_End:
   360 		{
   361 			g_VoteMenu = INVALID_HANDLE;
   362 			CloseHandle(menu);
   363 		}
   364 		
   365 		case MenuAction_Display:
   366 		{
   367 	 		decl String:buffer[255];
   368 			Format(buffer, sizeof(buffer), "%T", "Vote Nextmap", param1);
   369 
   370 			new Handle:panel = Handle:param2;
   371 			SetPanelTitle(panel, buffer);
   372 		}		
   373 		
   374 		case MenuAction_DisplayItem:
   375 		{
   376 			if (GetMenuItemCount(menu) - 1 == param2)
   377 			{
   378 				decl String:map[64], String:buffer[255];
   379 				GetMenuItem(menu, param2, map, sizeof(map));
   380 				if (strcmp(map, VOTE_EXTEND, false) == 0)
   381 				{
   382 					Format(buffer, sizeof(buffer), "%T", "Extend Map", param1);
   383 					return RedrawMenuItem(buffer);
   384 				}
   385 			}
   386 		}		
   387 
   388 		// Why am I commented out? Because BAIL hasn't decided yet if
   389 		// vote notification will be built into the Vote API.
   390 		/*case MenuAction_Select:
   391 		{
   392 			decl String:Name[32], String:Map[32];
   393 			GetClientName(param1, Name, sizeof(Name));
   394 			GetMenuItem(menu, param2, Map, sizeof(Map));
   395 
   396 			PrintToChatAll("[SM] %s has voted for map '%s'", Name, Map);
   397 		}*/
   398 		
   399 		case MenuAction_VoteCancel:
   400 		{
   401 			// If we receive 0 votes, pick at random.
   402 			if (param1 == VoteCancel_NoVotes && GetConVarBool(g_Cvar_NoVoteMode))
   403 			{
   404 				new count = GetMenuItemCount(menu);
   405 				new item = GetRandomInt(0, count - 1);
   406 				decl String:map[32];
   407 				GetMenuItem(menu, item, map, sizeof(map));
   408 				
   409 				while (strcmp(map, VOTE_EXTEND, false) == 0)
   410 				{
   411 					item = GetRandomInt(0, count - 1);
   412 					GetMenuItem(menu, item, map, sizeof(map));
   413 				}
   414 				
   415 				SetNextMap(map);			
   416 			}
   417 			else
   418 			{
   419 				// We were actually cancelled. What should we do?
   420 			}
   421 		}
   422 
   423 		case MenuAction_VoteEnd:
   424 		{
   425 			decl String:map[32];
   426 			GetMenuItem(menu, param1, map, sizeof(map));
   427 
   428 			if (strcmp(map, VOTE_EXTEND, false) == 0)
   429 			{
   430 				new time;
   431 				if (GetMapTimeLimit(time))
   432 				{
   433 					if (time > 0 && time < GetConVarInt(g_Cvar_ExtendTimeMax))
   434 					{
   435 						ExtendMapTimeLimit(GetConVarInt(g_Cvar_ExtendTimeStep)*60);						
   436 					}
   437 				}
   438 				
   439 				if (g_Cvar_Winlimit != INVALID_HANDLE)
   440 				{
   441 					new winlimit = GetConVarInt(g_Cvar_Winlimit);
   442 					if (winlimit && winlimit < GetConVarInt(g_Cvar_ExtendRoundMax))
   443 					{
   444 						SetConVarInt(g_Cvar_Winlimit, winlimit + GetConVarInt(g_Cvar_ExtendRoundStep));
   445 					}					
   446 				}
   447 				
   448 				if (g_Cvar_Maxrounds != INVALID_HANDLE)
   449 				{
   450 					new maxrounds = GetConVarInt(g_Cvar_Maxrounds);
   451 					if (maxrounds && maxrounds < GetConVarInt(g_Cvar_ExtendRoundMax))
   452 					{
   453 						SetConVarInt(g_Cvar_Maxrounds, maxrounds + GetConVarInt(g_Cvar_ExtendRoundStep));
   454 					}
   455 				}
   456 				
   457 				if (g_Cvar_Fraglimit != INVALID_HANDLE)
   458 				{
   459 					new fraglimit = GetConVarInt(g_Cvar_Fraglimit);
   460 					if (fraglimit && fraglimit < GetConVarInt(g_Cvar_ExtendFragMax))
   461 					{
   462 						SetConVarInt(g_Cvar_Fraglimit, fraglimit + GetConVarInt(g_Cvar_ExtendFragStep));						
   463 					}
   464 				}
   465 
   466 				PrintToChatAll("[SM] %t", "Current Map Extended");
   467 				LogMessage("Voting for next map has finished. The current map has been extended.");
   468 				
   469 				// We extended, so we'll have to vote again.
   470 				g_HasVoteStarted = false;
   471 				CreateNextVote();
   472 				SetupTimeleftTimer();
   473 			}
   474 			else
   475 			{
   476 				SetNextMap(map);
   477 			}
   478 		}
   479 	}
   480 	
   481 	return 0;
   482 }
   483 
   484 SetNextMap(const String:map[])
   485 {
   486 	SetConVarString(g_Cvar_Nextmap, map);
   487 	PushArrayString(g_OldMapList, map);
   488 				
   489 	if (GetArraySize(g_OldMapList) > GetConVarInt(g_Cvar_ExcludeMaps))
   490 	{
   491 		RemoveFromArray(g_OldMapList, 0);
   492 	}
   493 		
   494 	PrintToChatAll("[SM] %t", "Nextmap Voting Finished", map);
   495 	LogMessage("Voting for next map has finished. Nextmap: %s.", map);	
   496 }
   497 
   498 CreateNextVote()
   499 {
   500 	if(g_NextMapList != INVALID_HANDLE)
   501 	{
   502 		ClearArray(g_NextMapList);
   503 	}
   504 	
   505 	new Handle:tempMaps  = CreateArray(33);
   506 	decl String:map[32];
   507 	for (new i = 0; i < GetArraySize(g_MapList); i++)
   508 	{
   509 		GetArrayString(g_MapList, i, map, sizeof(map));
   510 		PushArrayString(tempMaps, map);		
   511 	}
   512 	
   513 	if (GetArraySize(tempMaps) > GetConVarInt(g_Cvar_ExcludeMaps))
   514 	{
   515 		for (new i = 0; i < GetArraySize(g_OldMapList); i++)
   516 		{
   517 			GetArrayString(g_OldMapList, i, map, sizeof(map));
   518 			for (new j = 0; j < GetArraySize(tempMaps); j++)
   519 			{
   520 				decl String:temp[32];
   521 				GetArrayString(tempMaps, j, temp, sizeof(temp));
   522 				if (strcmp(temp, map) == 0)
   523 				{
   524 					RemoveFromArray(tempMaps, j);
   525 					break;
   526 				}				
   527 			}
   528 		}	
   529 	}
   530 
   531 	new limit = (GetConVarInt(g_Cvar_IncludeMaps) < GetArraySize(tempMaps) ? GetConVarInt(g_Cvar_IncludeMaps) : GetArraySize(tempMaps));
   532 	for (new i = 0; i < limit; i++)
   533 	{
   534 		new b = GetRandomInt(0, GetArraySize(tempMaps) - 1);
   535 		GetArrayString(tempMaps, b, map, sizeof(map));		
   536 		PushArrayString(g_NextMapList, map);
   537 		RemoveFromArray(tempMaps, b);
   538 	}
   539 }
   540 
   541 LoadMaps()
   542 {
   543 	new bool:fileFound;
   544 
   545 	decl String:mapPath[256], String:mapFile[64];
   546 	GetConVarString(g_Cvar_Mapfile, mapFile, 64);
   547 	BuildPath(Path_SM, mapPath, sizeof(mapPath), mapFile);
   548 	fileFound = FileExists(mapPath);
   549 	if (!fileFound)
   550 	{
   551 		new Handle:mapCycleFile = FindConVar("mapcyclefile");
   552 		GetConVarString(mapCycleFile, mapPath, sizeof(mapPath));
   553 		fileFound = FileExists(mapPath);
   554 	}
   555 	
   556 	if (!fileFound)
   557 	{
   558 		LogError("Unable to locate sm_mapvote_file or mapcyclefile, no maps loaded.");
   559 		
   560 		if (g_MapList != INVALID_HANDLE)
   561 		{
   562 			ClearArray(g_MapList);
   563 		}
   564 		
   565 		return 0;		
   566 	}
   567 
   568 	// If the file hasn't changed, there's no reason to reload
   569 	// all of the maps.
   570 	new fileTime =  GetFileTime(mapPath, FileTime_LastChange);
   571 	if (g_mapFileTime == fileTime)
   572 	{
   573 		return GetArraySize(g_MapList);
   574 	}
   575 	
   576 	g_mapFileTime = fileTime;
   577 	
   578 	// Reset the array
   579 	if (g_MapList != INVALID_HANDLE)
   580 	{
   581 		ClearArray(g_MapList);
   582 	}
   583 
   584 	LogMessage("[SM] Loading mapchooser map file [%s]", mapPath);
   585 
   586 	new Handle:file = OpenFile(mapPath, "rt");
   587 	if (file == INVALID_HANDLE)
   588 	{
   589 		LogError("[SM] Could not open file: %s", mapPath);
   590 		return 0;
   591 	}
   592 
   593 	decl String:currentMap[32];
   594 	GetCurrentMap(currentMap, sizeof(currentMap));	
   595 	
   596 	decl String:buffer[64], len;
   597 	while (!IsEndOfFile(file) && ReadFileLine(file, buffer, sizeof(buffer)))
   598 	{
   599 		TrimString(buffer);
   600 
   601 		if ((len = StrContains(buffer, ".bsp", false)) != -1)
   602 		{
   603 			buffer[len] = '\0';
   604 		}
   605 
   606 		if (buffer[0] == '\0' || !IsValidConVarChar(buffer[0]) || !IsMapValid(buffer)
   607 			|| strcmp(currentMap, buffer, false) == 0)
   608 		{
   609 			continue;
   610 		}
   611 
   612 		PushArrayString(g_MapList, buffer);
   613 	}
   614 
   615 	CloseHandle(file);
   616 	return GetArraySize(g_MapList);
   617 }